Merge pull request #3153 from nextcloud/h264

Prefer H264 codec when it is available
This commit is contained in:
Joas Schilling 2020-03-31 15:50:13 +02:00 коммит произвёл GitHub
Родитель ed8a1c53c7 fae48f89ab
Коммит cc29be9c9e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 91 добавлений и 7 удалений

Просмотреть файл

@ -44,6 +44,7 @@ use OCP\AppFramework\Http\Template\PublicTemplateResponse;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\IRootFolder;
use OCP\Files\NotPermittedException;
use OCP\IConfig;
use OCP\IInitialStateService;
use OCP\ILogger;
use OCP\IRequest;
@ -78,7 +79,9 @@ class PageController extends Controller {
/** @var IRootFolder */
private $rootFolder;
/** @var Config */
private $config;
private $talkConfig;
/** @var IConfig */
private $serverConfig;
public function __construct(string $appName,
IRequest $request,
@ -94,7 +97,8 @@ class PageController extends Controller {
IAppManager $appManager,
IInitialStateService $initialStateService,
IRootFolder $rootFolder,
Config $config) {
Config $talkConfig,
IConfig $serverConfig) {
parent::__construct($appName, $request);
$this->eventDispatcher = $eventDispatcher;
$this->api = $api;
@ -108,7 +112,8 @@ class PageController extends Controller {
$this->appManager = $appManager;
$this->initialStateService = $initialStateService;
$this->rootFolder = $rootFolder;
$this->config = $config;
$this->talkConfig = $talkConfig;
$this->serverConfig = $serverConfig;
}
/**
@ -228,15 +233,20 @@ class PageController extends Controller {
}
}
$this->initialStateService->provideInitialState(
'talk', 'prefer_h264',
$this->serverConfig->getAppValue('spreed', 'prefer_h264', 'no') === 'yes'
);
$this->initialStateService->provideInitialState(
'talk', 'circles_enabled',
$this->appManager->isEnabledForUser('circles', $user)
);
$attachmentFolder = $this->config->getAttachmentFolder($user->getUID());
$attachmentFolder = $this->talkConfig->getAttachmentFolder($user->getUID());
$this->initialStateService->provideInitialState(
'talk', 'attachment_folder',
$this->config->getAttachmentFolder($user->getUID())
$this->talkConfig->getAttachmentFolder($user->getUID())
);
if ($attachmentFolder) {
@ -255,7 +265,7 @@ class PageController extends Controller {
$params = [
'token' => $token,
'signaling-settings' => $this->config->getSettings($this->userId),
'signaling-settings' => $this->talkConfig->getSettings($this->userId),
];
$response = new TemplateResponse($this->appName, 'index', $params);
$csp = new ContentSecurityPolicy();
@ -301,9 +311,14 @@ class PageController extends Controller {
}
}
$this->initialStateService->provideInitialState(
'talk', 'prefer_h264',
$this->serverConfig->getAppValue('spreed', 'prefer_h264', 'no') === 'yes'
);
$params = [
'token' => $token,
'signaling-settings' => $this->config->getSettings($this->userId),
'signaling-settings' => $this->talkConfig->getSettings($this->userId),
];
$response = new PublicTemplateResponse($this->appName, 'index', $params);
$response->setFooterVisible(false);

5
package-lock.json сгенерированный
Просмотреть файл

@ -18208,6 +18208,11 @@
"resolved": "https://registry.npmjs.org/sdp/-/sdp-2.12.0.tgz",
"integrity": "sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw=="
},
"sdp-transform": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/sdp-transform/-/sdp-transform-2.14.0.tgz",
"integrity": "sha512-8ZYOau/o9PzRhY0aMuRzvmiM6/YVQR8yjnBScvZHSdBnywK5oZzAJK+412ZKkDq29naBmR3bRw8MFu0C01Gehg=="
},
"select": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",

Просмотреть файл

@ -34,6 +34,7 @@
"lodash": "^4.17.15",
"mockconsole": "0.0.1",
"nextcloud-vue-collections": "^0.7.2",
"sdp-transform": "^2.14.0",
"url-parse": "^1.4.7",
"util": "^0.12.2",
"vue": "^2.6.11",

Просмотреть файл

@ -1,4 +1,6 @@
/* global module */
const initialState = require('@nextcloud/initial-state')
const sdpTransform = require('sdp-transform')
const util = require('util')
const webrtcSupport = require('webrtcsupport')
@ -85,8 +87,65 @@ function Peer(options) {
util.inherits(Peer, WildEmitter)
function preferH264VideoCodecIfAvailable(offer) {
const sdpInfo = sdpTransform.parse(offer.sdp)
if (!sdpInfo || !sdpInfo.media) {
return offer
}
// Find video media
let videoIndex = -1
sdpInfo.media.forEach((media, mediaIndex) => {
if (media.type === 'video') {
videoIndex = mediaIndex
}
})
if (videoIndex === -1 || !sdpInfo.media[videoIndex].rtp) {
return offer
}
// Find all H264 codec videos
const h264Rtps = []
sdpInfo.media[videoIndex].rtp.forEach((rtp, rtpIndex) => {
if (rtp.codec.toLowerCase() === 'h264') {
h264Rtps.push(rtp.payload)
}
})
if (!h264Rtps.length) {
// No H264 codecs found
return offer
}
// Sort the H264 codecs to the front in the payload (which defines the preferred order)
const payloads = sdpInfo.media[videoIndex].payloads.split(' ')
payloads.sort((a, b) => {
if (h264Rtps.indexOf(parseInt(a, 10)) !== -1) {
return -1
}
if (h264Rtps.indexOf(parseInt(b, 10)) !== -1) {
return 1
}
return 0
})
// Write new payload order into video media payload
sdpInfo.media[videoIndex].payloads = payloads.join(' ')
// Write back the sdpInfo into the offer
offer.sdp = sdpTransform.write(sdpInfo)
return offer
}
Peer.prototype.offer = function(options) {
this.pc.createOffer(options).then(function(offer) {
if (initialState.loadState('talk', 'prefer_h264')) {
console.debug('Preferring hardware codec H.264 as per global configuration')
offer = preferH264VideoCodecIfAvailable(offer)
}
this.pc.setLocalDescription(offer).then(function() {
if (this.parent.config.nick) {
// The offer is a RTCSessionDescription that only serializes
@ -117,6 +176,10 @@ Peer.prototype.handleOffer = function(offer) {
Peer.prototype.answer = function() {
this.pc.createAnswer().then(function(answer) {
if (initialState.loadState('talk', 'prefer_h264')) {
console.debug('Preferring hardware codec H.264 as per global configuration')
answer = preferH264VideoCodecIfAvailable(answer)
}
this.pc.setLocalDescription(answer).then(function() {
if (this.parent.config.nick) {
// The answer is a RTCSessionDescription that only serializes