Skip to content

Commit

Permalink
Add an API to limit the max subscribed video resolution and framerate (
Browse files Browse the repository at this point in the history
  • Loading branch information
jcague authored Sep 18, 2017
1 parent 9c06d19 commit 3fab39b
Show file tree
Hide file tree
Showing 12 changed files with 82 additions and 6 deletions.
16 changes: 15 additions & 1 deletion doc/client_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ It updates the audio and video maximum bandwidth for a publisher or a subscriber
It can also be used in remote streams to toggle `slideShowMode`

<example>
You can update the maximun bandwidth of video and audio. These values are defined in the object passed to the function. You can also pass a callback function to get the final result.
You can update the maximum bandwidth of video and audio. These values are defined in the object passed to the function. You can also pass a callback function to get the final result.
</example>

```
Expand Down Expand Up @@ -480,6 +480,20 @@ room.subscribe(stream, {audio: true, video: true, slideShowMode:true}, function(

`SlideShowMode` can also be toggled on or off using `stream.updateConfiguration`. Keep in mind this will only work on remote streams (subscriptions).

When we enable Simulcast it is also interesting to specify whether the subscriber should not receive a resolution or frame rate beyond a maximum. We
can configure it like in the example below:

```
room.subscribe(stream, {video: {height: {max: 480}, width: {max: 640}, frameRate: {max:20}}}, function(result, error){
if (result === undefined){
console.log("Error subscribing to stream", error);
} else {
console.log("Stream subscribed!");
}
});
```

It would help us not wasting CPU or bandwidth if, for instance, we will not render videos in a <video> element bigger than 640x480.

## Unsubscribe from a remote stream

Expand Down
6 changes: 6 additions & 0 deletions erizo/src/erizo/WebRtcConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,12 @@ void WebRtcConnection::muteStream(bool mute_video, bool mute_audio) {
});
}

void WebRtcConnection::setVideoConstraints(int max_video_width, int max_video_height, int max_video_frame_rate) {
asyncTask([max_video_width, max_video_height, max_video_frame_rate] (std::shared_ptr<WebRtcConnection> connection) {
connection->quality_manager_->setVideoConstraints(max_video_width, max_video_height, max_video_frame_rate);
});
}

void WebRtcConnection::setFeedbackReports(bool will_send_fb, uint32_t target_bitrate) {
if (slide_show_mode_) {
target_bitrate = 0;
Expand Down
1 change: 1 addition & 0 deletions erizo/src/erizo/WebRtcConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ class WebRtcConnection: public MediaSink, public MediaSource, public FeedbackSin
void setFeedbackReports(bool will_send_feedback, uint32_t target_bitrate = 0);
void setSlideShowMode(bool state);
void muteStream(bool mute_video, bool mute_audio);
void setVideoConstraints(int max_video_width, int max_video_height, int max_video_frame_rate);

void setMetadata(std::map<std::string, std::string> metadata);

Expand Down
6 changes: 6 additions & 0 deletions erizo/src/erizo/rtp/QualityManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,12 @@ void QualityManager::forceLayers(int spatial_layer, int temporal_layer) {
temporal_layer_ = temporal_layer;
}

void QualityManager::setVideoConstraints(int max_video_width, int max_video_height, int max_video_frame_rate) {
ELOG_DEBUG("Max: width (%d), height (%d), frameRate (%d)", max_video_width, max_video_height, max_video_frame_rate);

// TODO(javier): Actually apply constraints to current feed.
}

void QualityManager::setSpatialLayer(int spatial_layer) {
if (!forced_layers_) {
spatial_layer_ = spatial_layer;
Expand Down
2 changes: 1 addition & 1 deletion erizo/src/erizo/rtp/QualityManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class QualityManager: public Service, public std::enable_shared_from_this<Qualit
void setTemporalLayer(int temporal_layer);

void forceLayers(int spatial_layer, int temporal_layer);

void setVideoConstraints(int max_video_width, int max_video_height, int max_video_frame_rate);
void notifyEvent(MediaEventPtr event) override;
void notifyQualityUpdate();

Expand Down
10 changes: 10 additions & 0 deletions erizoAPI/WebRtcConnection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ NAN_MODULE_INIT(WebRtcConnection::Init) {
Nan::SetPrototypeMethod(tpl, "setSlideShowMode", setSlideShowMode);
Nan::SetPrototypeMethod(tpl, "muteStream", muteStream);
Nan::SetPrototypeMethod(tpl, "setQualityLayer", setQualityLayer);
Nan::SetPrototypeMethod(tpl, "setVideoConstraints", setVideoConstraints);
Nan::SetPrototypeMethod(tpl, "setMetadata", setMetadata);
Nan::SetPrototypeMethod(tpl, "enableHandler", enableHandler);
Nan::SetPrototypeMethod(tpl, "disableHandler", disableHandler);
Expand Down Expand Up @@ -271,6 +272,15 @@ NAN_METHOD(WebRtcConnection::muteStream) {
me->muteStream(mute_video, mute_audio);
}

NAN_METHOD(WebRtcConnection::setVideoConstraints) {
WebRtcConnection* obj = Nan::ObjectWrap::Unwrap<WebRtcConnection>(info.Holder());
std::shared_ptr<erizo::WebRtcConnection> me = obj->me;
int max_video_width = info[0]->IntegerValue();
int max_video_height = info[1]->IntegerValue();
int max_video_frame_rate = info[2]->IntegerValue();
me->setVideoConstraints(max_video_width, max_video_height, max_video_frame_rate);
}

NAN_METHOD(WebRtcConnection::setMetadata) {
WebRtcConnection* obj = Nan::ObjectWrap::Unwrap<WebRtcConnection>(info.Holder());
std::shared_ptr<erizo::WebRtcConnection> me = obj->me;
Expand Down
5 changes: 5 additions & 0 deletions erizoAPI/WebRtcConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ class WebRtcConnection : public MediaSink, public erizo::WebRtcConnectionEventLi
* Param: A boolean indicating what to do
*/
static NAN_METHOD(muteStream);
/*
* Sets constraints to the subscribing video
* Param: Max width, height and framerate.
*/
static NAN_METHOD(setVideoConstraints);
/*
* Gets Stats from this Wrtc
* Param: None
Expand Down
13 changes: 12 additions & 1 deletion erizo_controller/erizoClient/src/Room.js
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,17 @@ const Room = (altIo, altConnection, specInput) => {
});
};

const getVideoConstraints = (stream, video) => {
const hasVideo = video && stream.hasVideo();
const width = video && video.width;
const height = video && video.height;
const frameRate = video && video.frameRate;
if (width || height || frameRate) {
return { width, height, frameRate };
}
return hasVideo;
};

const subscribeErizo = (streamInput, optionsInput, callback = () => {}) => {
const stream = streamInput;
const options = optionsInput;
Expand All @@ -441,7 +452,7 @@ const Room = (altIo, altConnection, specInput) => {
stream.checkOptions(options);
const constraint = { streamId: stream.getID(),
audio: options.audio && stream.hasAudio(),
video: options.video && stream.hasVideo(),
video: getVideoConstraints(stream, options.video),
data: options.data && stream.hasData(),
browser: that.Connection.getBrowser(),
createOffer: options.createOffer,
Expand Down
3 changes: 1 addition & 2 deletions erizo_controller/erizoClient/src/Stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,8 @@ const Stream = (altConnection, specInput) => {
const config = configInput;
// TODO: Check for any incompatible options
if (isUpdate === true) { // We are updating the stream
if (config.video || config.audio || config.screen) {
if (config.audio || config.screen) {
Logger.warning('Cannot update type of subscription');
config.video = undefined;
config.audio = undefined;
config.screen = undefined;
}
Expand Down
4 changes: 3 additions & 1 deletion erizo_controller/erizoClient/src/webrtc-stacks/BaseStack.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,12 @@ const BaseStack = (specInput) => {
}
}
if (config.minVideoBW || (config.slideShowMode !== undefined) ||
(config.muteStream !== undefined) || (config.qualityLayer !== undefined)) {
(config.muteStream !== undefined) || (config.qualityLayer !== undefined) ||
(config.video !== undefined)) {
Logger.debug('MinVideo Changed to ', config.minVideoBW);
Logger.debug('SlideShowMode Changed to ', config.slideShowMode);
Logger.debug('muteStream changed to ', config.muteStream);
Logger.debug('Video Constraints', config.video);
specBase.callback({ type: 'updatestream', config });
}
};
Expand Down
10 changes: 10 additions & 0 deletions erizo_controller/erizoJS/erizoJSController.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,9 @@ exports.ErizoJSController = function (threadPool, ioThreadPool) {
if (msg.config.qualityLayer !== undefined) {
that.setQualityLayer (msg.config.qualityLayer, peerId, streamId);
}
if (msg.config.video !== undefined) {
that.setVideoConstraints(msg.config.video, peerId, streamId);
}
}
} else if (msg.type === 'control') {
processControlMessage(publisher, peerId, msg.action);
Expand Down Expand Up @@ -533,6 +536,13 @@ exports.ErizoJSController = function (threadPool, ioThreadPool) {
}
};

that.setVideoConstraints = function (video, from, to) {
var publisher = this.publishers[to];
if (publisher.hasSubscriber(from)) {
publisher.setVideoConstraints(from, video.width, video.height, video.frameRate);
}
};

const getWrtcStats = (label, stats, wrtc) => {
const promise = new Promise((resolve) => {
wrtc.getStats((statsString) => {
Expand Down
12 changes: 12 additions & 0 deletions erizo_controller/erizoJS/models/Publisher.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ class Source {
const muteVideo = (options.muteStream && options.muteStream.video) || false;
const muteAudio = (options.muteStream && options.muteStream.audio) || false;
this.muteSubscriberStream(id, muteVideo, muteAudio);
if (options.video) {
this.setVideoConstraints(id,
options.video.width, options.video.height, options.video.frameRate);
}
}

removeSubscriber(id) {
Expand Down Expand Up @@ -125,6 +129,14 @@ class Source {
this.muteAudio || muteAudio);
}

setVideoConstraints(id, width, height, frameRate) {
var subscriber = this.getSubscriber(id);
var maxWidth = (width && width.max) || -1;
var maxHeight = (height && height.max) || -1;
var maxFrameRate = (frameRate && frameRate.max) || -1;
subscriber.setVideoConstraints(maxWidth, maxHeight, maxFrameRate);
}

enableHandlers(id, handlers) {
var wrtc = this.wrtc;
if (id) {
Expand Down

0 comments on commit 3fab39b

Please sign in to comment.