diff --git a/labs/bbb-webrtc-sfu/config/default.example.yml b/labs/bbb-webrtc-sfu/config/default.example.yml index 565d12ea97d7aca479ddb84eeb91d9125cba45f6..e1b4497fe58bf0b2798611eac70688ff3c504257 100644 --- a/labs/bbb-webrtc-sfu/config/default.example.yml +++ b/labs/bbb-webrtc-sfu/config/default.example.yml @@ -18,9 +18,13 @@ to-akka: "to-akka-apps-redis-channel" from-akka: "from-akka-apps-redis-channel" common-message-version: "2.x" webcam-force-h264: true +# Target bitrate (kbps) for webcams. Value 0 leaves it unconstrained. +webcam-target-bitrate: 300000 screenshare-force-h264: true screenshare-preferred-h264-profile: "42e01f" screenshareKeyframeInterval: 2 +# Target bitrate (kbps) for screenshare. Value 0 leaves it unconstrained. +screenshare-target-bitrate: 0 recordScreenSharing: true recordWebcams: false diff --git a/labs/bbb-webrtc-sfu/lib/audio/audio.js b/labs/bbb-webrtc-sfu/lib/audio/audio.js index 8e6667e65adcd386940cdf5c6961b3e421b3f8be..385c7d8e304a0d3beee3695649d10bde8721e810 100644 --- a/labs/bbb-webrtc-sfu/lib/audio/audio.js +++ b/labs/bbb-webrtc-sfu/lib/audio/audio.js @@ -255,7 +255,7 @@ module.exports = class Audio extends BaseProvider { return Promise.resolve(); } catch (err) { - reject(this._handleError(LOG_PREFIX, err, "recv", this.userId)); + throw (this._handleError(LOG_PREFIX, err, "recv", this.userId)); } }; diff --git a/labs/bbb-webrtc-sfu/lib/mcs-core/lib/model/SdpSession.js b/labs/bbb-webrtc-sfu/lib/mcs-core/lib/model/SdpSession.js index a1eac49832889e4b81062107c9d48264a8b88617..7b1345fdb7ccf5e13e95513d6a84f1c70db8b325 100644 --- a/labs/bbb-webrtc-sfu/lib/mcs-core/lib/model/SdpSession.js +++ b/labs/bbb-webrtc-sfu/lib/mcs-core/lib/model/SdpSession.js @@ -60,13 +60,19 @@ module.exports = class SdpSession extends MediaSession { return reject(this._handleError(C.ERROR.MEDIA_NO_AVAILABLE_CODEC)); } + const { targetBitrate } = this._options; + + if (answer && targetBitrate && targetBitrate !== '0') { + this._answer.addBandwidth('video', targetBitrate); + } + if (this._type !== 'WebRtcEndpoint') { this._offer.replaceServerIpv4(kurentoIp); - return resolve(answer); + return resolve(this._answer? this._answer._plainSdp : null); } await this._MediaServer.gatherCandidates(this._mediaElement); - resolve(answer); + resolve(this._answer._plainSdp); } catch (err) { return reject(this._handleError(err)); diff --git a/labs/bbb-webrtc-sfu/lib/mcs-core/lib/utils/SdpWrapper.js b/labs/bbb-webrtc-sfu/lib/mcs-core/lib/utils/SdpWrapper.js index 6f35e3b7c7d64b083b752d6a62c8652da012d0b6..a19912bdba9d2002543a2f01d5e57d050c1c6169 100644 --- a/labs/bbb-webrtc-sfu/lib/mcs-core/lib/utils/SdpWrapper.js +++ b/labs/bbb-webrtc-sfu/lib/mcs-core/lib/utils/SdpWrapper.js @@ -54,6 +54,20 @@ module.exports = class SdpWrapper { return this._mediaCapabilities.hasAvailableAudioCodec; } + addBandwidth (type, bw) { + // Bandwidth format + // { type: 'TIAS or AS', limit: 2048000 } + for(var ml of this._jsonSdp.media) { + if(ml.type === type ) { + ml['bandwidth'] = []; + ml.bandwidth.push({ type: 'TIAS', limit: (bw >>> 0) * 1000 }); + ml.bandwidth.push({ type: 'AS', limit: bw }); + } + } + + this._plainSdp = transform.write(this._jsonSdp); + } + /** * Given a SDP, test if there is an audio description in it * @return {boolean} true if there is more than one video description, else false diff --git a/labs/bbb-webrtc-sfu/lib/screenshare/screenshare.js b/labs/bbb-webrtc-sfu/lib/screenshare/screenshare.js index f2eaa8cc957533ac649516f195c1612846a281ce..aeab9fc3afc1e2860d09a8697cdbcc0f2b12952c 100644 --- a/labs/bbb-webrtc-sfu/lib/screenshare/screenshare.js +++ b/labs/bbb-webrtc-sfu/lib/screenshare/screenshare.js @@ -21,6 +21,7 @@ const kurentoIp = config.get('kurentoIp'); const localIpAddress = config.get('localIpAddress'); const FORCE_H264 = config.get('screenshare-force-h264'); const PREFERRED_H264_PROFILE = config.get('screenshare-preferred-h264-profile'); +const SCREENSHARE_TARGET_BITRATE = config.get('screenshare-target-bitrate'); const SHOULD_RECORD = config.get('recordScreenSharing'); const KEYFRAME_INTERVAL = config.get('screenshareKeyframeInterval'); const LOG_PREFIX = "[screenshare]"; @@ -274,7 +275,7 @@ module.exports = class Screenshare extends BaseProvider { _startPresenter (sdpOffer) { return new Promise(async (resolve, reject) => { try { - const retSource = await this.mcs.publish(this.mcsUserId, this._meetingId, 'WebRtcEndpoint', {descriptor: sdpOffer}); + const retSource = await this.mcs.publish(this.mcsUserId, this._meetingId, 'WebRtcEndpoint', {descriptor: sdpOffer, targetBitrate: SCREENSHARE_TARGET_BITRATE }); this._presenterEndpoint = retSource.sessionId; sharedScreens[this._voiceBridge] = this._presenterEndpoint; diff --git a/labs/bbb-webrtc-sfu/lib/video/video.js b/labs/bbb-webrtc-sfu/lib/video/video.js index 9250d86d90774f12d12590a6f0526ffe9b28171e..be068de8beda19dafd62708f32faac32df79c4c3 100644 --- a/labs/bbb-webrtc-sfu/lib/video/video.js +++ b/labs/bbb-webrtc-sfu/lib/video/video.js @@ -9,6 +9,7 @@ const Messaging = require('../bbb/messages/Messaging'); const h264_sdp = require('../h264-sdp'); const BaseProvider = require('../base/BaseProvider'); const FORCE_H264 = config.get('webcam-force-h264'); +const WEBCAM_TARGET_BITRATE = config.get('webcam-target-bitrate'); const SHOULD_RECORD = config.get('recordWebcams'); const LOG_PREFIX = "[video]"; @@ -259,7 +260,7 @@ module.exports = class Video extends BaseProvider { return new Promise(async (resolve, reject) => { try { if (this.shared) { - let { answer, sessionId } = await this.mcs.publish(this.userId, this.meetingId, type, { descriptor }); + let { answer, sessionId } = await this.mcs.publish(this.userId, this.meetingId, type, { descriptor, targetBitrate: WEBCAM_TARGET_BITRATE }); this.mediaId = sessionId; sharedWebcams[this.id] = this.mediaId; return resolve(answer);