The Code
I’ve been working with a lot of developers on WebRTC solutions. One, in particular, needed screensharing for their next-generating proctoring solution, so I built a proof-of-concept (PoC) screensharing app using node-webkit.
A typical video call with Respoke starts with starting a call with another endpoint:
var otherEndpoint = client.getEndpoint({
id: theirName
});
otherEndpoint.startCall({
onConnect: onConnect,
onLocalMedia: onLocalVideo
});
To enable screensharing we just need to pass getUserMedia MediaStreamContraints:
var otherEndpoint = client.getEndpoint({
id: theirName
});
var constraints = {
audio: false,
video: {
mandatory: {
chromeMediaSource: 'screen',
maxHeight: 2000,
maxWidth: 2000
},
optional: []
}
};
otherEndpoint.startCall({
constraints: constraints,
onConnect: onConnect,
onLocalMedia: onLocalVideo
});
In addition, we need to enable usermedia screen capturing in node-webkit. To do this, we added the following chromium-args to our npm package.json file:
{
. . .
"chromium-args": "--enable-usermedia-screen-capturing"
. . .
}
The --enable-usermedia-screen-capturing
chromium flag replaces the media transmitted with your screen instead of your camera input.
Our Respoke screensharing demo is open source. To use it, head over to our Respoke Screensharing Node-Webkit GitHub repo. Then run the following commands from your terminal:
git clone https://github.com/respoke/respoke-screensharing-node-webkit.git
cd respoke-screensharing-node-webkit
npm install
Open Node Webkit Instance 1
./node_modules/nodewebkit/nodewebkit/node-webkit.app/Contents/MacOS/node-webkit .
Open Node Webkit Instance 2
./node_modules/nodewebkit/nodewebkit/node-webkit.app/Contents/MacOS/node-webkit .
Give it a try. If you find any issues, we welcome pull requests.
Media Stream Constraints
To make screensharing work, we had to pass a MediaStreamContraint object literal. But, where does all this come from? It all starts with a w3 spec. When specs are not final, vendor implementation typically starts from a draft spec. In this case, the Media Capture and Streams working draft. There is no current consensus on what every constraints should be. The working drafts acts a starting point so vendors like Google can start implementing real examples of how constraints are used.
For example, the working draft specifies constraints like width, height, frameRate and aspectRatio. But the Chromium MediaConstraints source code specifies so much more available constraints like minAspectRatio, maxAspectRatio, minWidth, maxWidth, minHeight, maxHeight, minFrameRate and maxFrameRate:
class MediaConstraintsInterface {
public:
. . .
// Constraint keys used by a local video source.
// Specified by draft-alvestrand-constraints-resolution-00b
static const char kMinAspectRatio[]; // minAspectRatio
static const char kMaxAspectRatio[]; // maxAspectRatio
static const char kMaxWidth[]; // maxWidth
static const char kMinWidth[]; // minWidth
static const char kMaxHeight[]; // maxHeight
static const char kMinHeight[]; // minHeight
static const char kMaxFrameRate[]; // maxFrameRate
static const char kMinFrameRate[]; // minFrameRate
. . .
};
The Chromium MediaConstraints even go on to define other interesting experimental contraints like echoCancellation, noiseReduction and cpuOveruseDetection:
class MediaConstraintsInterface {
public:
. . .
// Constraint keys used by a local audio source.
// These keys are google specific.
static const char kEchoCancellation[]; // googEchoCancellation
// Google-specific constraint keys for a local video source
static const char kNoiseReduction[]; // googNoiseReduction
. . .
// googTemporalLayeredScreencast
static const char kCpuOveruseDetection[];
};
Of course there is no guarantee that those features will make it to the final Media Capture and Streams spec.
Flags We had to use Chromium command line flags to enable screensharing. Chromium command line flags are another interesting piece of the puzzle.
For one they enable developers to take advantage of features not available to the general public. Another is peeking behind the covers is just really cool to see. Take for example the Chromium flag we used earlier: --enable-usermedia-screen-capturing
.
It’s source code is defined in Chromium’s content_switches.h header file:
// Defines all the "content" command-line switches.
. . .
namespace switches {
// All switches in alphabetical order. The switches should be documented
// alongside the definition of their values in the .cc file.
. . .
CONTENT_EXPORT extern const char kEnableUserMediaScreenCapturing[];
. . .
}
And implemented in Chromium’s content_switches.cc file:
#include "content/public/common/content_switches.h"
#include "base/command_line.h"
namespace switches {
. . .
// Enable screen capturing support for MediaStream API.
const char kEnableUserMediaScreenCapturing[] =
"enable-usermedia-screen-capturing";
. . .
}
We then use those flags as chromium-args in our node-webkit apps. You can pass chromium flags to chrome directly as well. On Mac OS X, you’d use:
open -a "Google Chrome" --args --enable-usermedia-screen-capturing
On Windows, something like:
chrome.exe --args --enable-usermedia-screen-capturing
I hope you’re as excited about the future of WebRTC as we are. It’s a great time to be a developer. Fork our demo screensharing app using Respoke and Node-Webkit. Play around and if you like it, share it with your friends.