Showing preview only (305K chars total). Download the full file or copy to clipboard to get everything.
Repository: vmolsa/webrtc-native
Branch: master
Commit: acf4abac9c10
Files: 67
Total size: 287.2 KB
Directory structure:
gitextract_5hvoxsbh/
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── binding.gyp
├── examples/
│ ├── node2browser/
│ │ ├── index.html
│ │ ├── index.js
│ │ └── package.json
│ └── node2browser_ws/
│ ├── index.html
│ ├── index.js
│ └── package.json
├── index.js
├── node_versions.json
├── package.json
├── scripts/
│ ├── build.js
│ ├── install.js
│ ├── multibuild.cmd
│ ├── multibuild.sh
│ ├── nvm.sh
│ └── upload.js
├── src/
│ ├── ArrayBuffer.h
│ ├── BackTrace.cc
│ ├── BackTrace.h
│ ├── Common.h
│ ├── DataChannel.cc
│ ├── DataChannel.h
│ ├── EventEmitter.cc
│ ├── EventEmitter.h
│ ├── GetSources.cc
│ ├── GetSources.h
│ ├── GetUserMedia.cc
│ ├── GetUserMedia.h
│ ├── Global.cc
│ ├── Global.h
│ ├── MediaCapturer.cc
│ ├── MediaCapturer.h
│ ├── MediaConstraints.cc
│ ├── MediaConstraints.h
│ ├── MediaStream.cc
│ ├── MediaStream.h
│ ├── MediaStreamTrack.cc
│ ├── MediaStreamTrack.h
│ ├── Module.cc
│ ├── Observers.cc
│ ├── Observers.h
│ ├── PeerConnection.cc
│ ├── PeerConnection.h
│ ├── Platform.cc
│ ├── Platform.h
│ ├── Stats.cc
│ ├── Stats.h
│ ├── Wrap.h
│ ├── addon.gypi
│ └── webrtc.gyp
└── test/
├── all.js
├── bwtest.js
├── core.js
├── dataChannel.js
├── getSources.js
├── getUserMedia.js
├── mediaStream.js
├── multiconnect.js
├── p2p-browser.html
├── p2p.js
├── p2p_stream.js
├── test.js
└── videoStream.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
build
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
third_party
config.gypi
nodejs.gypi
================================================
FILE: .npmignore
================================================
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
build
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
src
third_party
config.gypi
nodejs.gypi
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
[WebRTC](http://en.wikipedia.org/wiki/WebRTC) for NodeJS
### Chromium
webrtc-native is using [WebRTC](http://webrtc.org/) from chromium project. code is compiled with branch [50](https://chromium.googlesource.com/external/webrtc/+/branch-heads/50).
### Usage
For installing or building module from source go to page [Getting Started](https://github.com/vmolsa/webrtc-native/wiki/Getting-started)
### API
````
var WebRTC = require('webrtc-native');
````
#### WebRTC.[RTCPeerConnection](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection)
#### WebRTC.[RTCIceCandidate](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnectionIceEvent)
#### WebRTC.[RTCSessionDescription](https://developer.mozilla.org/en-US/docs/Web/API/RTCSessionDescription)
#### WebRTC.[RTCDataChannel](https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel)
#### WebRTC.[MediaStream](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream)
#### WebRTC.[MediaStreamTrack](https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack)
#### WebRTC.[getUserMedia](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getUserMedia)
#### WebRTC.[getSources](http://simpl.info/getusermedia/sources/index.html)
- Returns array of available device inputs
#### WebRTC.RTCGarbageCollect()
- Notify V8 Engine to attempt to free memory.
#### WebRTC.setDebug(boolean)
- Enable / Disable WebRTC log messages
================================================
FILE: binding.gyp
================================================
{
'targets': [
{
'target_name': 'action_before_build',
'dependencies': [],
'hard_dependency': 1,
'type': 'none',
'actions': [
{
'action_name': 'run_build_script',
'inputs': [],
'outputs': [''],
'action': [
'node', 'scripts/build.js', '-Dtarget-arch=<(target_arch)', '<(node_root_dir)', '<(node_lib_file)', '<(node_gyp_dir)'
],
}
]
},
],
}
================================================
FILE: examples/node2browser/index.html
================================================
<html>
<head>
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
</head>
<body>
<video></video>
<script>
var config = {
iceServers: [
{
url: 'stun:stun.l.google.com:19302',
},
],
};
var constraints = {
optional: [
{
DtlsSrtpKeyAgreement: true,
},
],
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true,
},
};
var socket = io.connect();
var peer = new window.webkitRTCPeerConnection(config, constraints);
socket.on('disconnect', function() {
peer.close();
});
socket.on('icecandidate', function(data) {
if (data && data.candidate && data.sdpMid && data.sdpMLineIndex) {
peer.addIceCandidate(new RTCIceCandidate(data));
}
});
socket.on('offer', function(data) {
peer.setRemoteDescription(new RTCSessionDescription(data), function() {
peer.createAnswer(function(sdp) {
peer.setLocalDescription(sdp, function() {
socket.emit('answer', sdp);
});
});
});
});
socket.on('answer', function (data) {
peer.setRemoteDescription(new RTCSessionDescription(data));
});
peer.onicecandidate = function(event) {
var candidate = event.candidate || event;
socket.emit('icecandidate', candidate);
};
peer.onnegotiationneeded = function() {
peer.createOffer(function(sdp) {
peer.setLocalDescription(sdp, function() {
socket.emit('offer', sdp);
});
});
};
peer.onaddstream = function(event) {
if (event.stream && event.stream.active) {
console.log('Peer Add mediaStream:', event.stream);
var video = document.querySelector('video');
video.src = window.URL.createObjectURL(event.stream);
video.onloadedmetadata = function(event) {
video.play();
};
event.stream.onaddtrack = function(track) {
console.log('Track Added!');
};
event.stream.onremovetrack = function (track) {
console.log('Track Removed!');
};
var audio_list = event.stream.getAudioTracks();
audio_list.forEach(function (track) {
console.log(track);
});
var video_list = event.stream.getVideoTracks();
video_list.forEach(function (track) {
console.log(track);
});
}
};
peer.onremovestream = function(event) {
console.log('Peer Remove mediaStream:', event.stream);
};
peer.ondatachannel = function(event) {
var channel = event ? event.channel || event : null;
var pingpong = null;
channel.onopen = function() {
console.log('Peer Channel opened!');
pingpong = setInterval(function() {
console.log('Peer: Sending PING');
channel.send('PING');
}, 5000);
};
channel.onclose = function() {
console.log('Peer Channel closed!');
if (pingpong) {
clearInterval(pingpong);
}
};
channel.onmessage = function(event) {
var data = event.data;
console.log('Peer Message:', data);
};
};
</script>
</body>
</html>
================================================
FILE: examples/node2browser/index.js
================================================
var express = require('express');
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var WebRTC = require('../../');
app.use(express.static(__dirname));
var io = require('socket.io')(server);
var config = {
iceServers: [
{
url: 'stun:stun.l.google.com:19302',
},
],
};
var constraints = {
audio: {
optional: [
{
googEchoCancellation: true,
googEchoCancellation2: true,
googDAEchoCancellation: true,
googAutoGainControl: true,
googAutoGainControl2: true,
googNoiseSuppression: true,
googNoiseSuppression2: true,
googHighpassFilter: true,
googTypingNoiseDetection: true,
googAudioMirroring: true,
},
],
},
video: true,
/*
video: {
optional: [
{
minAspectRatio: 1.333,
maxAspectRatio: 1.778,
maxWidth: 1920,
minWidth: 320,
maxHeight: 1080,
minHeight: 180,
maxFrameRate: 60,
minFrameRate: 30,
},
],
},
*/
optional: [
{
DtlsSrtpKeyAgreement: true,
},
],
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true,
},
};
io.on('connection', function(socket) {
console.log('Peer Connected');
var peer = new WebRTC.RTCPeerConnection(config, constraints);
socket.on('disconnect', function () {
console.log('Peer Disconnected');
peer.close();
});
socket.on('icecandidate', function(data) {
if (data && data.candidate && data.sdpMid && data.sdpMLineIndex) {
peer.addIceCandidate(new WebRTC.RTCIceCandidate(data));
}
});
socket.on('offer', function(data) {
peer.setRemoteDescription(new WebRTC.RTCSessionDescription(data), function() {
peer.createAnswer(function(sdp) {
peer.setLocalDescription(sdp, function() {
socket.emit('answer', sdp);
});
});
});
});
socket.on('answer', function(data) {
peer.setRemoteDescription(new WebRTC.RTCSessionDescription(data));
});
peer.onicecandidate = function(event) {
var candidate = event.candidate || event;
socket.emit('icecandidate', candidate);
};
peer.onnegotiationneeded = function() {
peer.createOffer(function(sdp) {
peer.setLocalDescription(sdp, function() {
socket.emit('offer', sdp);
});
});
};
peer.onaddstream = function(stream) {
console.log('Peer: add mediaStream');
};
peer.onremovestream = function(stream) {
console.log('Peer: remove mediaStream');
};
peer.ondatachannel = function(event) {
var channel = event ? event.channel || event : null;
channel.onopen = function() {
console.log('Peer Channel opened!');
};
channel.onclose = function() {
console.log('Peer Channel closed!');
};
channel.onmessage = function(event) {
var data = event.data;
if (data == 'PING') {
console.log('Peer: Sending PONG');
channel.send('PONG');
} else {
console.log('Peer Message:', data);
channel.send(data);
}
};
};
peer.ondatachannel(peer.createDataChannel('echo'));
WebRTC.getUserMedia(constraints, function(stream) {
console.log('Sending Stream to Peer');
peer.addStream(stream);
});
});
server.listen(8080, function() {
console.log('Open in browser: http://localhost:8080/');
});
================================================
FILE: examples/node2browser/package.json
================================================
{
"dependencies": {
"express": "^4.13.0",
"socket.io": "^1.3.5"
}
}
================================================
FILE: examples/node2browser_ws/index.html
================================================
<!DOCTYPE html>
<html>
<head>
</head>
<script language="javascript">
window.onload = function(e){
var config = {
iceServers: [
{
url: 'stun:stun.l.google.com:19302',
},
],
};
var constraints = {
optional: [
{
DtlsSrtpKeyAgreement: true,
},
],
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true,
},
};
navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
window.RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate || window.webkitRTCIceCandidate;
window.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription;
var peer = new RTCPeerConnection (config, constraints);
var connection = new WebSocket('ws://127.0.0.1:8181');
function peer_onConnect(connection)
{
peer.onicecandidate = function(event) {
var data = event.candidate || event;
if (event.candidate && peer.signalingState !== 'closed') {
connection.send(JSON.stringify(data));
}
};
peer.onnegotiationneeded = function() {
console.log ("onnegotiationneeded");
};
peer.onaddstream = function(event) {
if (event.stream && event.stream.active) {
console.log('Peer Add mediaStream:', event.stream);
var video = document.querySelector('video');
video.src = window.URL.createObjectURL(event.stream);
video.setAttribute( 'autoplay', 'autoplay' );
video.onloadedmetadata = function(event) {
video.play();
};
event.stream.onaddtrack = function(track) {
console.log('Track Added!');
};
event.stream.onremovetrack = function (track) {
console.log('Track Removed!');
};
var audio_list = event.stream.getAudioTracks();
audio_list.forEach(function (track) {
console.log(track);
});
var video_list = event.stream.getVideoTracks();
video_list.forEach(function (track) {
console.log(track);
});
}
};
peer.onremovestream = function(event) {
console.log('Peer Remove mediaStream:', event.stream);
};
peer.ondatachannel = function(event) {
var channel = event ? event.channel || event : null;
var pingpong = null;
channel.onopen = function() {
console.log('Peer Channel opened!');
pingpong = setInterval(function() {
console.log('Peer: Sending PING');
channel.send('PING');
}, 5000);
};
channel.onclose = function() {
console.log('Peer Channel closed!');
if (pingpong) {
clearInterval(pingpong);
}
};
channel.onmessage = function(event) {
var data = event.data;
console.log('Peer Message:', data);
};
};
}
// When the connection is open, send some data to the server
connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
peer_onConnect(connection);
};
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
var jmsg = JSON.parse(e.data);
if (jmsg.hasOwnProperty('type') == false)
{
return ;
}
if (jmsg.type == 'offer')
{
peer.setRemoteDescription(new RTCSessionDescription(jmsg), function() {
peer.createAnswer(function(answer) {
peer.setLocalDescription(answer, function(s) {
connection.send(JSON.stringify(answer));
console.log('Send Answer: %s',JSON.stringify(answer));
});
}, function (err)
{
console.log (err);
})
});
}
if (jmsg.type == 'answer')
{
peer.setRemoteDescription(new RTCSessionDescription(data));
}
if (jmsg.type == 'icecandidate')
{
if (jmsg.data && jmsg.candidate ) {
peer.addIceCandidate(new RTCIceCandidate(jmsg.data));
}
}
};
};
</script>
<body>
<video autoplay controls></video>
</body>
</html>
================================================
FILE: examples/node2browser_ws/index.js
================================================
var WebRTC = require('../../');
var WebSocketServer = require('ws').Server;
var express = require('express');
var app = express();
var server = require('http').Server(app);
WebRTC.setDebug(false);
app.use(express.static(__dirname));
var _sources = [];
var localstream =undefined;
var initialized = false;
var config = {
iceServers: [
{
url: 'stun:stun.l.google.com:19302',
},
],
};
var constraints = {
audio: true,
video: true,
};
function sourceSelected(audioSource, videoSource) {
_sources.push(videoSource);
}
WebRTC.getSources(function(sourceInfos) {
for (var i = 0; i != sourceInfos.length; ++i) {
var sourceInfo = sourceInfos[i];
if (sourceInfo.kind === 'audio') {
console.log(sourceInfo.id, sourceInfo.label || 'microphone');
audioSource = sourceInfo.id;
} else if (sourceInfo.kind === 'video') {
console.log(sourceInfo.id, sourceInfo.label || 'camera');
_sources.push (sourceInfo.id);
} else {
console.log('Some other kind of source: ', sourceInfo);
}
}
WebRTC.getUserMedia(constraints, getUserMedia_successCallback, getUserMedia_errorCallback);
});
function getUserMedia_successCallback(stream) {
localstream = stream;
var video_list = localstream.getVideoTracks();
video_list.forEach(function (track) {
console.log('Video Track %s', JSON.stringify(track));
track.readyState = "alive";
});
console.log('Sending Stream to Peer');
initialized = true;
init();
}
function getUserMedia_errorCallback(error) {
console.log ('error %s',error);
}
function setLocalSDP(p, callback){
if(p.iceGatheringState != 'complete'){
setTimeout(function(){
setLocalSDP(p, callback);
}, 10);
}else{
callback && callback();
}
}
function init()
{
ws = new WebSocketServer(
{
host: '127.0.0.1',
port: 8181
}); // start websocket server
ws.on('connection', onConnect_Handler);
function onConnect_Handler(connection)
{
var peer = new WebRTC.RTCPeerConnection(null, {audio: true, video: true});
peer.addStream(localstream);
peer.onicecandidate = function(event) {
var candidate = event.candidate || event;
connection.send(JSON.stringify({'type':'icecandidate', 'data':candidate}));
};
peer.createOffer(function(offer){
peer.setLocalDescription(new WebRTC.RTCSessionDescription(offer), function(){
setLocalSDP(peer, function(){
var offerSDP = JSON.stringify(peer.localDescription);
connection.send(offerSDP);
});
}, function(e){
console.log (e);
})
});
connection.on('message', function onWsMessage(message, flags)
{
console.log ("INCOMMING %s:", message);
var jmsg = undefined;
try
{
jmsg = JSON.parse(message);
}
catch (e)
{
return ;
}
if (jmsg.type=='answer')
{
console.log ('answer');
var clientRemoteSDP = new WebRTC.RTCSessionDescription(jmsg);
peer.setRemoteDescription(clientRemoteSDP, function(){
console.log('setRemoteDescription OK');
}, function(err){
console.log('setRemoteDescription error', err);
})
}
if (jmsg.hasOwnProperty('candidate'))
{
console.log ('icecandidate: jmsg: %s',JSON.stringify(jmsg));
peer.addIceCandidate(new WebRTC.RTCIceCandidate(jmsg));
}
});
peer.onnegotiationneeded = function() {
console.log ('onnegotiationneeded');
};
peer.onaddstream = function(stream) {
console.log('Peer: add mediaStream');
};
peer.onremovestream = function(stream) {
console.log('Peer: remove mediaStream');
};
peer.ondatachannel = function(event) {
var channel = event ? event.channel || event : null;
channel.onopen = function() {
console.log('Peer Channel opened!');
};
channel.onclose = function() {
console.log('Peer Channel closed!');
};
channel.onmessage = function(event) {
var data = event.data;
if (data == 'PING') {
console.log('Peer: Sending PONG');
channel.send('PONG');
} else {
console.log('Peer Message:', data);
channel.send(data);
}
};
};
peer.ondatachannel(peer.createDataChannel('echo'));
}
server.listen(8281, function() {
console.log('Open in browser: http://localhost:8281/index.html');
});
}
// */
================================================
FILE: examples/node2browser_ws/package.json
================================================
{
"dependencies": {
"express": "^4.13.0",
"ws": "^1.1.0"
}
}
================================================
FILE: index.js
================================================
module.exports = require('./build/Release/webrtc.node');
================================================
FILE: node_versions.json
================================================
[
"iojs-v2.3.2",
"iojs-v3.3.1",
"v0.10.38",
"v0.12.5",
"v4.2.1",
"v4.3.2",
"v4.4.0",
"v5.0.0",
"v5.1.1",
"v5.2.0",
"v5.3.0",
"v5.4.1",
"v5.5.0",
"v5.6.0",
"v5.7.1",
"v5.8.0",
"v5.9.1"
]
================================================
FILE: package.json
================================================
{
"name": "webrtc-native",
"version": "1.4.0",
"description": "WebRTC for NodeJS",
"homepage": "https://github.com/vmolsa/webrtc-native",
"author": "https://github.com/vmolsa",
"repository": {
"type": "git",
"url": "https://github.com/vmolsa/webrtc-native.git"
},
"bugs": {
"url": "https://github.com/vmolsa/webrtc-native/issues"
},
"keywords": [
"webrtc",
"p2p",
"streaming",
"dtls",
"srtp",
"rtp",
"capture",
"datachannel"
],
"license": "MIT",
"main": "index.js",
"scripts": {
"install": "node scripts/install.js",
"test": "node test/all.js"
},
"dependencies": {
"request": "^2.58.0"
},
"devDependencies": {
"nan": "^2.1.0",
"node-gyp": "^3.0.3",
"minimist": "^1.1.1",
"simple-peer": "^5.11.5",
"tape": "^4.0.0"
}
}
================================================
FILE: scripts/build.js
================================================
var fs = require('fs');
var os = require('os');
var spawn = require('child_process').spawn;
var path = require('path');
var request = require('request');
var ROOT = path.resolve(__dirname, '..');
if (!fs.existsSync(ROOT + path.sep + 'build' + path.sep + 'config.gypi')) {
throw new Error('Run node-gyp rebuild instead of node build.js');
}
var PACKAGE = require(path.resolve(ROOT, 'package.json'));
var CHROMIUM = 'https://chromium.googlesource.com/external/webrtc.git@ca4ec2c3b9331e8f054facf400ebaeb9681831e2';
var USE_OPENSSL = false;
var USE_GTK = false;
var USE_X11 = false;
var PLATFORM = os.platform();
var SYSTEM = os.release();
var ARCH = process.argv[2].substring(14);
var NODEJS = path.resolve(process.argv[3]);
var NODELIB = process.argv[4].substring(3).split('.')[0];
var NODEGYP = process.argv[5];
var URL = 'http://cide.cc:8080/webrtc/';
var NODEVER = process.version.split('.');
var NODE_ZERO = (NODEVER[0] === 'v0');
var CROSSCOMPILE = (ARCH !== process.arch);
NODEVER[2] = 'x';
NODEVER = NODEVER.join('.');
URL += 'webrtc-' + PACKAGE.version + '-' + PLATFORM + '-' + ARCH + '-' + NODEVER + '.node';
if (fs.existsSync(ROOT + path.sep + 'nodejs.gypi')) {
fs.unlinkSync(ROOT + path.sep + 'nodejs.gypi');
}
var COMMON = path.resolve(NODEJS, 'include', 'node', 'common.gypi');
if (fs.existsSync(COMMON)) {
fs.linkSync(COMMON, ROOT + path.sep + 'nodejs.gypi');
} else {
fs.linkSync(NODEJS + path.sep + 'common.gypi', ROOT + path.sep + 'nodejs.gypi');
}
var CONFIG = 'Release';
if (fs.existsSync(ROOT + path.sep + 'build' + path.sep + 'Debug')) {
CONFIG = 'Debug';
}
var THIRD_PARTY = path.resolve(ROOT, 'third_party');
var DEPOT_TOOLS_REPO = 'https://chromium.googlesource.com/chromium/tools/depot_tools.git';
var DEPOT_TOOLS = path.resolve(THIRD_PARTY, 'depot_tools');
var WEBRTC = path.resolve(THIRD_PARTY, 'webrtc');
var WEBRTC_SRC = path.resolve(WEBRTC, 'src');
var WEBRTC_OUT = path.resolve(WEBRTC_SRC, 'out', CONFIG);
var FETCH = path.resolve(DEPOT_TOOLS, (os.platform() == 'win32') ? 'fetch.bat' : 'fetch');
var GCLIENT = path.resolve(DEPOT_TOOLS, (os.platform() == 'win32') ? 'gclient.bat' : 'gclient');
if (os.platform() == 'win32' && ARCH == 'x64') {
WEBRTC_OUT = path.resolve(WEBRTC_SRC, 'out', CONFIG + '_x64');
}
function install() {
fs.linkSync(WEBRTC_OUT + path.sep + 'webrtc.node', path.resolve(ROOT, 'build', CONFIG, 'webrtc.node'));
if (process.env['CIDE_CREDENTIALS']) {
console.log('Uploading module.');
var credentials = {
'auth': {
'user': 'cIDE',
'pass': process.env['CIDE_CREDENTIALS'],
}
};
fs.createReadStream(path.resolve(ROOT, 'build', CONFIG, 'webrtc.node')).pipe(request.put(URL, credentials, function(error, response, body) {
if (!error && response.statusCode == 200) {
console.log('Done! :)');
} else {
console.log('Upload Failed! :(');
}
}));
} else {
setTimeout(function() {
console.log('Done! :)');
}, 200);
}
}
function compile() {
var res = spawn('ninja', [ '-C', WEBRTC_OUT ], {
cwd: WEBRTC_SRC,
env: process.env,
stdio: 'inherit',
});
res.on('close', function (code) {
if (!code) {
return install();
}
process.exit(1);
});
}
function build() {
if (fs.existsSync(WEBRTC_SRC)) {
var res = spawn('python', [ WEBRTC_SRC + path.sep + 'webrtc' + path.sep + 'build' + path.sep + 'gyp_webrtc', 'src' + path.sep + 'webrtc.gyp' ], {
cwd: ROOT,
env: process.env,
stdio: 'inherit',
});
res.on('close', function (code) {
if (!code) {
return compile();
}
process.exit(1);
});
}
}
function sync() {
if (!fs.existsSync(THIRD_PARTY + path.sep + 'webrtc_sync')) {
var res = spawn(GCLIENT, ['sync', '--with_branch_heads'], {
cwd: WEBRTC,
env: process.env,
stdio: 'inherit',
});
res.on('close', function (code) {
if (!code) {
fs.closeSync(fs.openSync(THIRD_PARTY + path.sep + 'webrtc_sync', 'w'));
return build();
}
process.exit(1);
});
} else {
build();
}
}
function configure() {
if (fs.existsSync(WEBRTC_OUT + path.sep + 'webrtc.node')) {
fs.unlinkSync(WEBRTC_OUT + path.sep + 'webrtc.node');
}
process.env['GYP_DEFINES'] += ' target_arch=' + ARCH;
process.env['GYP_DEFINES'] += ' host_arch=' + process.arch;
process.env['GYP_DEFINES'] += ' node_root_dir=' + NODEJS.replace(/\\/g, '\\\\');
process.env['GYP_DEFINES'] += ' node_lib_file=' + NODELIB;
process.env['GYP_DEFINES'] += ' node_gyp_dir=' + NODEGYP.replace(/\\/g, '\\\\');
process.env['GYP_DEFINES'] += ' build_with_chromium=0';
process.env['GYP_DEFINES'] += ' use_openssl=' + ((USE_OPENSSL) ? '1' : '0');
process.env['GYP_DEFINES'] += ' use_gtk='+ ((USE_GTK) ? '1' : '0');
process.env['GYP_DEFINES'] += ' use_x11=' + ((USE_X11) ? '1' : '0');
process.env['GYP_DEFINES'] += ' ConfigurationName=' + CONFIG;
process.env['GYP_DEFINES'] += ' include_tests=0';
switch (os.platform()) {
case 'darwin':
process.env['GYP_DEFINES'] += ' clang=1';
break;
case 'win32':
process.env['DEPOT_TOOLS_WIN_TOOLCHAIN'] = 0;
process.env['GYP_MSVS_VERSION'] = 2013;
break;
case 'linux':
if (CROSSCOMPILE) {
process.env['GYP_CROSSCOMPILE'] = 1;
process.env['GYP_DEFINES'] += ' clang=0 use_system_expat=0';
process.env['CXX'] = 'arm-linux-gnueabihf-g++-5';
var CPATH = process.env['CPATH'];
process.env['CPATH'] = '/usr/arm-linux-gnueabihf/include/c++/5/';
process.env['CPATH'] += '/usr/arm-linux-gnueabihf/include/c++/5/arm-linux-gnueabihf/';
process.env['CPATH'] += '/usr/arm-linux-gnueabihf/include/c++/5/backward/';
process.env['CPATH'] += CPATH ? ':' + CPATH : '';
} else {
if (NODE_ZERO) {
process.env['GYP_DEFINES'] += ' clang=0';
process.env['CXX'] = 'g++-4.8';
var CPATH = process.env['CPATH'];
process.env['CPATH'] = '/usr/include/c++/4.8/';
process.env['CPATH'] += '/usr/include/x86_64-linux-gnu/c++/4.8/';
process.env['CPATH'] += '/usr/include/c++/4.8/backward/';
process.env['CPATH'] += CPATH ? ':' + CPATH : '';
} else {
process.env['GYP_DEFINES'] += ' clang=1';
}
if (!process.env['JAVA_HOME']) {
if (fs.existsSync('/usr/lib/jvm/java')) {
process.env['JAVA_HOME'] = '/usr/lib/jvm/java';
} else {
process.env['JAVA_HOME'] = '/usr/lib/jvm/default-java';
}
}
}
break;
default:
break;
}
console.log('target_arch =', ARCH);
console.log('host_arch =', process.arch);
console.log('configuration =', CONFIG);
sync();
}
function config() {
if (!fs.existsSync(WEBRTC) || !fs.existsSync(path.resolve(WEBRTC, '.gclient')) || !fs.existsSync(WEBRTC_SRC)) {
if (!fs.existsSync(WEBRTC)) {
fs.mkdirSync(WEBRTC);
}
var res = spawn(GCLIENT, ['config', '--name=src', CHROMIUM], {
cwd: WEBRTC,
env: process.env,
stdio: 'inherit',
});
res.on('close', function (code) {
if (!code) {
return configure();
}
process.exit(1);
});
} else {
configure();
}
}
process.env['GYP_DEFINES'] = process.env['GYP_DEFINES'] ? process.env['GYP_DEFINES'] : '';
if (!fs.existsSync(THIRD_PARTY)) {
fs.mkdirSync(THIRD_PARTY);
}
process.env['PATH'] = process.env['PATH'] + path.delimiter + DEPOT_TOOLS;
if (!fs.existsSync(DEPOT_TOOLS)) {
var res = spawn('git', ['clone', DEPOT_TOOLS_REPO], {
cwd: THIRD_PARTY,
env: process.env,
stdio: 'inherit',
});
res.on('close', function (code) {
if (!code) {
return config();
}
process.exit(1);
});
} else {
config();
}
================================================
FILE: scripts/install.js
================================================
var fs = require('fs');
var os = require('os');
var spawn = require('child_process').spawn;
var path = require('path');
var request = require('request');
var PLATFORM = os.platform();
var ROOT = path.resolve(__dirname, '..');
var ARCH = os.arch();
var URL = 'http://cide.cc:8080/webrtc/';
var NODEVER = process.version.split('.');
var PACKAGE = require(path.resolve(ROOT, 'package.json'));
NODEVER[2] = 'x';
NODEVER = NODEVER.join('.');
URL += 'webrtc-' + PACKAGE.version + '-' + PLATFORM + '-' + ARCH + '-' + NODEVER + '.node';
function build() {
console.log('Building module...');
var nodegyp = path.resolve(ROOT, 'node_modules', 'node-gyp', 'bin', 'node-gyp.js');
if (!fs.existsSync(nodegyp)) {
nodegyp = path.resolve(ROOT, '..', 'node-gyp', 'bin', 'node-gyp.js');
if (!fs.existsSync(nodegyp)) {
throw new Error('Build Failed. Please follow instructions from https://github.com/vmolsa/webrtc-native/wiki/Getting-started#building-from-source');
}
}
var res = spawn('node', [ nodegyp, 'rebuild' ], {
cwd: ROOT,
env: process.env,
stdio: 'inherit',
});
res.on('error', function(error) {
var res = spawn('iojs', [ nodegyp, 'rebuild' ], {
cwd: ROOT,
env: process.env,
stdio: 'inherit',
});
});
}
function test() {
console.log('Loading module...');
try {
var WebRTC = require(path.resolve(ROOT, 'build', 'Release', 'webrtc.node'));
setTimeout(function() {
console.log('Done! :)');
}, 200);
} catch (ignored) {
throw new Error('prebuilt module not working. See the instructions from https://github.com/vmolsa/webrtc-native/wiki/Getting-started#building-from-source for building module from source.');
}
}
if (process.env['BUILD_WEBRTC'] == 'true') {
build();
} else {
console.log('Downloading module: webrtc-' + PACKAGE.version + '-' + PLATFORM + '-' + ARCH + '-' + NODEVER + '.node');
if (!fs.existsSync(path.resolve(ROOT, 'build', 'Release'))) {
if (!fs.existsSync(path.resolve(ROOT, 'build'))) {
fs.mkdirSync(path.resolve(ROOT, 'build'));
}
fs.mkdirSync(path.resolve(ROOT, 'build', 'Release'));
}
request.get(URL, function (error, response, body) {
if (!error && response.statusCode == 200) {
setTimeout(test, 200);
} else {
throw new Error('prebuilt module not found. See the instructions from https://github.com/vmolsa/webrtc-native/wiki/Getting-started#building-from-source for building module from source.');
}
}).pipe(fs.createWriteStream(path.resolve(ROOT, 'build', 'Release', 'webrtc.node')));
}
================================================
FILE: scripts/multibuild.cmd
================================================
nvmw install %1 & nvmw use %1 && npm install
================================================
FILE: scripts/multibuild.sh
================================================
#!/bin/sh
. ~/.nvm/nvm.sh
nvm install $1
nvm use $1
npm install
================================================
FILE: scripts/nvm.sh
================================================
#!/bin/sh
. ~/.nvm/nvm.sh
nvm $1 $2
================================================
FILE: scripts/upload.js
================================================
var os = require('os');
var spawn = require('child_process').spawn;
var versions = require('../node_versions.json');
var ROOT = process.cwd();
var MULTIBUILD = (os.platform() == 'win32') ? 'scripts\\multibuild.cmd' : 'scripts/multibuild.sh';
process.env['BUILD_WEBRTC'] = 'true';
function build(version, callback) {
var res = spawn(MULTIBUILD, [ version ], {
cwd: ROOT,
env: process.env,
stdio: 'inherit',
});
res.on('close', function (code) {
callback(code == 0);
});
}
function buildNext(index) {
if (index < versions.length) {
build(versions[index], function(result) {
if (result) {
buildNext(index + 1);
}
});
}
}
buildNext(0);
================================================
FILE: src/ArrayBuffer.h
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef NODE_ARRAYBUFFER_H
#define NODE_ARRAYBUFFER_H
#ifdef WIN32
#pragma warning( disable : 4267 )
#endif
#include <nan.h>
#include <string>
namespace node {
class ArrayBuffer {
public:
inline static ArrayBuffer* New(const char *str = 0) {
#if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION)
return ArrayBuffer::New(v8::Isolate::GetCurrent(), std::string(str));
#else
return ArrayBuffer::New(std::string(str));
#endif
}
inline static ArrayBuffer* New(const std::string &data) {
#if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION)
return ArrayBuffer::New(v8::Isolate::GetCurrent(), data.data(), data.size());
#else
return ArrayBuffer::New(data.data(), data.size());
#endif
}
#if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION)
template <class T = char> inline static ArrayBuffer* New(T *str, size_t length) {
return ArrayBuffer::New(v8::Isolate::GetCurrent(), reinterpret_cast<char*>(str), length);
}
inline static ArrayBuffer* New(const char *str, size_t length) {
return ArrayBuffer::New(v8::Isolate::GetCurrent(), str, length);
}
inline static ArrayBuffer* New(const v8::Local<v8::ArrayBuffer> &arrayBuffer) {
return ArrayBuffer::New(v8::Isolate::GetCurrent(), arrayBuffer);
}
inline static ArrayBuffer* New(const v8::Local<v8::Value> &arg) {
return ArrayBuffer::New(v8::Isolate::GetCurrent(), arg);
}
inline static ArrayBuffer* New(v8::Isolate *isolate, const std::string &data) {
return ArrayBuffer::New(isolate, data.data(), data.size());
}
inline static ArrayBuffer* New(v8::Isolate *isolate, const char *str = 0) {
return ArrayBuffer::New(isolate, std::string(str));
}
inline static ArrayBuffer* New(v8::Isolate *isolate, const char *str, size_t length) {
if (!isolate) {
isolate = v8::Isolate::GetCurrent();
}
ArrayBuffer *buffer = new ArrayBuffer();
v8::Local<v8::ArrayBuffer> arrayBuffer;
buffer->_data = 0;
buffer->_len = length;
if (length) {
buffer->_data = new char[length + 1];
buffer->_data[length] = '\0';
for (size_t index = 0; index < length; index++) {
buffer->_data[index] = str[index];
}
arrayBuffer = v8::ArrayBuffer::New(isolate, buffer->_data, length);
}
else {
arrayBuffer = v8::ArrayBuffer::New(isolate, length);
}
buffer->_arrayBuffer.Reset(isolate, arrayBuffer);
buffer->_arrayBuffer.SetWeak(buffer, ArrayBuffer::onDispose);
buffer->_arrayBuffer.MarkIndependent();
arrayBuffer->SetHiddenValue(v8::String::NewFromUtf8(isolate, "node::ArrayBuffer"), v8::External::New(isolate, buffer));
return buffer;
}
inline static ArrayBuffer* New(v8::Isolate *isolate, const v8::Local<v8::ArrayBuffer> &arrayBuffer) {
if (!isolate) {
isolate = v8::Isolate::GetCurrent();
}
if (arrayBuffer.IsEmpty()) {
return ArrayBuffer::New(isolate);
}
if (arrayBuffer->IsExternal()) {
v8::Local<v8::Value> ptr = arrayBuffer->GetHiddenValue(v8::String::NewFromUtf8(isolate, "node::ArrayBuffer"));
if (ptr.IsEmpty()) {
v8::Local<v8::Value> uintArray = v8::Uint8Array::New(arrayBuffer, 0, arrayBuffer->ByteLength());
return ArrayBuffer::New(isolate, uintArray);
} else {
v8::Local<v8::External> ext = v8::Local<v8::External>::Cast(ptr);
return static_cast<ArrayBuffer*>(ext->Value());
}
} else {
ArrayBuffer *buffer = new ArrayBuffer();
v8::ArrayBuffer::Contents content = arrayBuffer->Externalize();
buffer->_data = static_cast<char*>(content.Data());
buffer->_len = content.ByteLength();
buffer->_arrayBuffer.Reset(isolate, arrayBuffer);
buffer->_arrayBuffer.SetWeak(buffer, ArrayBuffer::onDispose);
buffer->_arrayBuffer.MarkIndependent();
arrayBuffer->SetHiddenValue(v8::String::NewFromUtf8(isolate, "node::ArrayBuffer"), v8::External::New(isolate, buffer));
return buffer;
}
return 0;
}
inline static ArrayBuffer* New(v8::Isolate *isolate, const v8::Local<v8::Value> &arg) {
if (!arg.IsEmpty()) {
if (arg->IsArrayBuffer() || arg->IsTypedArray()) {
v8::Local<v8::ArrayBuffer> arrayBuffer;
if (arg->IsArrayBuffer()) {
arrayBuffer = v8::Local<v8::ArrayBuffer>::Cast(arg);
}
else {
v8::Local<v8::ArrayBufferView> view = v8::Local<v8::ArrayBufferView>::Cast(arg);
arrayBuffer = view->Buffer();
}
return ArrayBuffer::New(isolate, arrayBuffer);
}
if (arg->IsString()) {
v8::String::Utf8Value str(arg->ToString());
return ArrayBuffer::New(isolate, *str, str.length());
}
}
return ArrayBuffer::New(isolate);
}
inline v8::Local<v8::ArrayBuffer> ToArrayBuffer(v8::Isolate *isolate = 0) const {
if (!isolate) {
isolate = v8::Isolate::GetCurrent();
}
v8::EscapableHandleScope scope(isolate);
return scope.Escape(v8::Local<v8::ArrayBuffer>::New(isolate, _arrayBuffer));
}
inline v8::Local<v8::String> ToString(v8::Isolate *isolate = 0) const {
if (!isolate) {
isolate = v8::Isolate::GetCurrent();
}
v8::EscapableHandleScope scope(isolate);
v8::Local<v8::String> retval = v8::String::NewFromUtf8(isolate, ArrayBuffer::ToUtf8(), v8::String::kNormalString, ArrayBuffer::Length());
return scope.Escape(retval);
}
#else
template <class T = char> inline static ArrayBuffer* New(T *str, size_t length) {
const char *ptr = reinterpret_cast<char*>(str);
return ArrayBuffer::New(ptr, length);
}
inline static ArrayBuffer* New(const char *str, size_t length) {
ArrayBuffer *buffer = new ArrayBuffer();
v8::Local<v8::Object> global = v8::Context::GetCurrent()->Global();
v8::Local<v8::Value> instance = global->Get(v8::String::New("ArrayBuffer"));
v8::Local<v8::Function> constructor = v8::Local<v8::Function>::Cast(instance);
v8::Local<v8::Object> arrayBuffer = constructor->NewInstance();
buffer->_data = 0;
buffer->_len = length;
if (length) {
buffer->_data = new char[length + 1];
buffer->_data[length] = '\0';
for (size_t index = 0; index < length; index++) {
buffer->_data[index] = str[index];
}
arrayBuffer->SetIndexedPropertiesToExternalArrayData(buffer->_data, v8::kExternalByteArray, buffer->_len);
}
buffer->_arrayBuffer = v8::Persistent<v8::Object>::New(arrayBuffer);
buffer->_arrayBuffer.MakeWeak(buffer, ArrayBuffer::onDispose);
buffer->_arrayBuffer.MarkIndependent();
arrayBuffer->SetHiddenValue(v8::String::New("node::ArrayBuffer"), v8::External::New(buffer));
return buffer;
}
inline static ArrayBuffer* New(const v8::Local<v8::Object> &arrayBuffer) {
if (!arrayBuffer.IsEmpty()) {
v8::Local<v8::Value> ptr = arrayBuffer->GetHiddenValue(v8::String::New("node::ArrayBuffer"));
if (!ptr.IsEmpty()) {
v8::Local<v8::External> ext = v8::Local<v8::External>::Cast(ptr);
return static_cast<ArrayBuffer*>(ext->Value());
} else {
if (arrayBuffer->HasIndexedPropertiesInExternalArrayData()) {
int length = arrayBuffer->GetIndexedPropertiesExternalArrayDataLength();
if (length > 0) {
char *data = static_cast<char*>(arrayBuffer->GetIndexedPropertiesExternalArrayData());
return ArrayBuffer::New(data, static_cast<size_t>(length));
}
}
}
}
return ArrayBuffer::New();
}
inline static ArrayBuffer* New(const v8::Local<v8::Value> &arg) {
if (!arg.IsEmpty()) {
if (arg->IsObject()) {
v8::Local<v8::Object> arrayBuffer = v8::Local<v8::Object>::Cast(arg);
return ArrayBuffer::New(arrayBuffer);
}
if (arg->IsString()) {
v8::String::Utf8Value str(arg->ToString());
return ArrayBuffer::New(*str, str.length());
}
}
return ArrayBuffer::New();
}
inline v8::Local<v8::Object> ToArrayBuffer() const {
v8::HandleScope scope;
v8::Local<v8::Object> arrayBuffer = v8::Local<v8::Object>::New(_arrayBuffer);
return scope.Close(arrayBuffer);
}
inline v8::Local<v8::String> ToString() const {
v8::HandleScope scope;
v8::Local<v8::String> str = v8::String::New(ArrayBuffer::ToUtf8(), ArrayBuffer::Length());
return scope.Close(str);
}
#endif
inline std::string ToCString() const {
return std::string(ArrayBuffer::ToUtf8(), ArrayBuffer::Length());
}
template <class T = char> inline T* To() {
return reinterpret_cast<T*>(_data);
}
template <class T = char> inline const T* To() const {
return reinterpret_cast<const T*>(_data);
}
inline char *ToUtf8() {
return _data;
}
inline const char *ToUtf8() const {
return _data;
}
inline void *Data() const {
return _data;
}
inline size_t Length() const {
return _len;
}
inline size_t ByteLength() const {
return _len;
}
#if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION)
static inline void onDispose(const v8::WeakCallbackData<v8::ArrayBuffer, ArrayBuffer> &info) {
v8::Isolate *isolate = info.GetIsolate();
v8::HandleScope scope(isolate);
ArrayBuffer *wrap = info.GetParameter();
if (wrap) {
v8::Local<v8::ArrayBuffer> arrayBuffer = v8::Local<v8::ArrayBuffer>::New(isolate, wrap->_arrayBuffer);
wrap->_arrayBuffer.Reset();
if (!arrayBuffer.IsEmpty()) {
arrayBuffer->DeleteHiddenValue(v8::String::NewFromUtf8(isolate, "node::ArrayBuffer"));
}
delete wrap;
}
}
#else
static inline void onDispose(v8::Persistent<v8::Value> value, void *data) {
v8::HandleScope scope;
ArrayBuffer *wrap = static_cast<ArrayBuffer*>(data);
if (wrap) {
v8::Local<v8::Object> arrayBuffer = v8::Local<v8::Object>::New(wrap->_arrayBuffer);
if (!arrayBuffer.IsEmpty()) {
arrayBuffer->DeleteHiddenValue(v8::String::New("node::ArrayBuffer"));
}
delete wrap;
}
}
#endif
private:
virtual ~ArrayBuffer() {
#if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION)
if (_len) {
delete [] _data;
}
#else
_arrayBuffer.ClearWeak();
_arrayBuffer.Dispose();
_arrayBuffer.Clear();
#endif
}
protected:
char* _data;
size_t _len;
#if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION)
v8::Persistent<v8::ArrayBuffer> _arrayBuffer;
#else
v8::Persistent<v8::Object> _arrayBuffer;
#endif
};
};
#endif
================================================
FILE: src/BackTrace.cc
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifdef USE_BACKTRACE
#include "BackTrace.h"
BackTrace BackTrace::landmine;
void BackTrace::Dump(const char *event, int skip) {
void *stack[50] = {0};
int count = 0, cur = 0;
count = backtrace(stack, sizeof(stack));
if (count) {
for (int index = (count - 1); index > skip && index >= 1; index--) {
char addr[128] = {0};
Dl_info info;
snprintf(addr, sizeof(addr), "%p", stack[index]);
if (dladdr(stack[index], &info) && info.dli_sname) {
char buffer[128] = {0};
size_t len = sizeof(buffer);
int status = 0;
(void) abi::__cxa_demangle(info.dli_sname, buffer, &len, &status);
if (!status) {
printf("%d: %s [%s] %s\n", cur, event, addr, buffer);
} else {
printf("%d: %s [%s] %s\n", cur, event, addr, info.dli_sname);
}
} else {
printf("%d: %s [%s] function()\n", cur, event, addr);
}
cur++;
}
}
}
void BackTrace::Close() {
_segv.sa_handler = SIG_DFL;
_bus.sa_handler = SIG_DFL;
_abrt.sa_handler = SIG_DFL;
_ill.sa_handler = SIG_DFL;
sigaction(SIGSEGV, &_segv, 0);
sigaction(SIGBUS, &_bus, 0);
sigaction(SIGABRT, &_abrt, 0);
sigaction(SIGILL, &_ill, 0);
}
void BackTrace::OnSegv(int sig) {
BackTrace::Dump("SIGSEGV", 2);
landmine.Close();
}
void BackTrace::OnBus(int sig) {
BackTrace::Dump("SIGBUS", 2);
landmine.Close();
}
void BackTrace::OnAbort(int sig) {
BackTrace::Dump("SIGABRT", 2);
landmine.Close();
}
void BackTrace::OnIll(int sig) {
BackTrace::Dump("SIGILL", 2);
landmine.Close();
}
BackTrace::BackTrace() {
sigemptyset(&_segv.sa_mask);
sigemptyset(&_bus.sa_mask);
sigemptyset(&_abrt.sa_mask);
sigemptyset(&_ill.sa_mask);
_segv.sa_flags = 0;
_segv.sa_handler = BackTrace::OnSegv;
_bus.sa_flags = 0;
_bus.sa_handler = BackTrace::OnBus;
_abrt.sa_flags = 0;
_abrt.sa_handler = BackTrace::OnAbort;
_ill.sa_flags = 0;
_ill.sa_handler = BackTrace::OnIll;
sigaction(SIGSEGV, &_segv, 0);
sigaction(SIGBUS, &_bus, 0);
sigaction(SIGABRT, &_abrt, 0);
sigaction(SIGILL, &_ill, 0);
}
BackTrace::~BackTrace() {
BackTrace::Close();
}
#endif
================================================
FILE: src/BackTrace.h
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef BACKTRACE_H
#define BACKTRACE_H
#ifdef USE_BACKTRACE
#include <stdio.h>
#include <signal.h>
#include <execinfo.h>
#include <dlfcn.h>
#include <cxxabi.h>
class BackTrace {
public:
static void Dump(const char *event = "NOEVENT", int skip = 1);
private:
explicit BackTrace();
virtual ~BackTrace();
void Close();
static void OnSegv(int sig);
static void OnBus(int sig);
static void OnAbort(int sig);
static void OnIll(int sig);
protected:
struct sigaction _segv;
struct sigaction _bus;
struct sigaction _abrt;
struct sigaction _ill;
static BackTrace landmine;
};
#else
#endif
#endif
================================================
FILE: src/Common.h
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef WEBRTC_COMMON_H
#define WEBRTC_COMMON_H
#include <nan.h>
#include "webrtc/video_frame.h"
#include "webrtc/base/atomicops.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/json.h"
#include "webrtc/base/basictypes.h"
#include "webrtc/base/common.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/ssladapter.h"
#include "webrtc/base/sslstreamadapter.h"
#include "webrtc/base/stringutils.h"
#include "webrtc/base/thread.h"
#include "webrtc/base/buffer.h"
#include "webrtc/base/scoped_ref_ptr.h"
#include "webrtc/base/refcount.h"
#include "webrtc/base/stringencode.h"
#include "webrtc/api/jsep.h"
#include "webrtc/api/jsepsessiondescription.h"
#include "webrtc/api/mediaconstraintsinterface.h"
#include "webrtc/api/mediastreaminterface.h"
#include "webrtc/api/peerconnectionfactory.h"
#include "webrtc/api/peerconnectioninterface.h"
#include "webrtc/api/test/fakeconstraints.h"
#include "webrtc/api/datachannelinterface.h"
#include "webrtc/api/videosourceinterface.h"
#include "webrtc/media/base/videosourceinterface.h"
#include "webrtc/media/engine/webrtcvideocapturerfactory.h"
#include "webrtc/modules/video_capture/video_capture_factory.h"
#ifdef WIN32
#ifndef __PRETTY_FUNCTION__
#define __PRETTY_FUNCTION__ __FUNCTION__
#endif
#endif
#include <queue>
#include <string>
#include <uv.h>
#include <node_object_wrap.h>
#endif
================================================
FILE: src/DataChannel.cc
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "DataChannel.h"
using namespace v8;
using namespace WebRTC;
Nan::Persistent<Function> DataChannel::constructor;
void DataChannel::Init() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::HandleScope scope;
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(DataChannel::New);
tpl->InstanceTemplate()->SetInternalFieldCount(1);
tpl->SetClassName(Nan::New("RTCDataChannel").ToLocalChecked());
Nan::SetPrototypeMethod(tpl, "close", DataChannel::Close);
Nan::SetPrototypeMethod(tpl, "send", DataChannel::Send);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("id").ToLocalChecked(), DataChannel::GetId);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("label").ToLocalChecked(), DataChannel::GetLabel);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("ordered").ToLocalChecked(), DataChannel::GetOrdered);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("protocol").ToLocalChecked(), DataChannel::GetProtocol);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("readyState").ToLocalChecked(), DataChannel::GetReadyState);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("bufferedAmount").ToLocalChecked(), DataChannel::GetBufferedAmount);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("binaryType").ToLocalChecked(), DataChannel::GetBinaryType, DataChannel::SetBinaryType);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("maxPacketLifeType").ToLocalChecked(), DataChannel::GetMaxPacketLifeType);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("maxRetransmits").ToLocalChecked(), DataChannel::GetMaxRetransmits);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("negotiated").ToLocalChecked(), DataChannel::GetNegotiated);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("reliable").ToLocalChecked(), DataChannel::GetReliable);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("onopen").ToLocalChecked(), DataChannel::GetOnOpen, DataChannel::SetOnOpen);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("onmessage").ToLocalChecked(), DataChannel::GetOnMessage, DataChannel::SetOnMessage);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("onclose").ToLocalChecked(), DataChannel::GetOnClose, DataChannel::SetOnClose);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("onerror").ToLocalChecked(), DataChannel::GetOnError, DataChannel::SetOnError);
constructor.Reset<Function>(tpl->GetFunction());
}
DataChannel::DataChannel() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
_observer = new rtc::RefCountedObject<DataChannelObserver>(this);
}
DataChannel::~DataChannel() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (_socket.get()) {
_socket->UnregisterObserver();
_observer->RemoveListener(this);
webrtc::DataChannelInterface::DataState state(_socket->state());
if (state != webrtc::DataChannelInterface::kClosing ||
state != webrtc::DataChannelInterface::kClosed)
{
_socket->Close();
}
}
}
void DataChannel::New(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (info.IsConstructCall()) {
DataChannel* dataChannel = new DataChannel();
dataChannel->Wrap(info.This(), "DataChannel");
return info.GetReturnValue().Set(info.This());
}
Nan::ThrowError("Internal Error");
info.GetReturnValue().SetUndefined();
}
Local<Value> DataChannel::New(rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::EscapableHandleScope scope;
Local<Function> instance = Nan::New(DataChannel::constructor);
if (instance.IsEmpty() || !dataChannel.get()) {
return scope.Escape(Nan::Null());
}
Local<Object> ret = instance->NewInstance();
DataChannel *self = RTCWrap::Unwrap<DataChannel>(ret, "DataChannel");
self->SetReference(true);
self->_socket = dataChannel;
self->_socket->RegisterObserver(self->_observer.get());
self->Emit(kDataChannelStateChange);
self->_binaryType.Reset(Nan::New("arraybuffer").ToLocalChecked());
return scope.Escape(ret);
}
webrtc::DataChannelInterface *DataChannel::GetSocket() const {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
return _socket.get();
}
void DataChannel::Close(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.This(), "DataChannel");
webrtc::DataChannelInterface *socket = self->GetSocket();
if (socket) {
webrtc::DataChannelInterface::DataState state(socket->state());
if (state != webrtc::DataChannelInterface::kClosing ||
state != webrtc::DataChannelInterface::kClosed)
{
socket->Close();
}
}
info.GetReturnValue().SetUndefined();
}
void DataChannel::Send(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.This(), "DataChannel");
webrtc::DataChannelInterface *socket = self->GetSocket();
bool retval = false;
if (socket) {
if(info[0]->IsString()) {
std::string data(*Nan::Utf8String(info[0]));
webrtc::DataBuffer buffer(data);
retval = socket->Send(buffer);
} else {
node::ArrayBuffer *container = node::ArrayBuffer::New(info[0]);
rtc::Buffer data(reinterpret_cast<uint8_t*>(container->Data()), container->Length());
//rtc::CopyOnWriteBuffer data(reinterpret_cast<uint8_t*>(container->Data()), container->Length());
webrtc::DataBuffer buffer(data, true);
retval = socket->Send(buffer);
}
}
return info.GetReturnValue().Set(Nan::New(retval));
}
void DataChannel::GetId(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
webrtc::DataChannelInterface *socket = self->GetSocket();
if (socket) {
return info.GetReturnValue().Set(Nan::New(socket->id()));
}
info.GetReturnValue().SetUndefined();
}
void DataChannel::GetLabel(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
webrtc::DataChannelInterface *socket = self->GetSocket();
if (socket) {
return info.GetReturnValue().Set(Nan::New(socket->label().c_str()).ToLocalChecked());
}
info.GetReturnValue().SetUndefined();
}
void DataChannel::GetOrdered(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
webrtc::DataChannelInterface *socket = self->GetSocket();
if (socket) {
return info.GetReturnValue().Set(Nan::New(socket->ordered()));
}
info.GetReturnValue().SetUndefined();
}
void DataChannel::GetProtocol(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
webrtc::DataChannelInterface *socket = self->GetSocket();
if (socket) {
return info.GetReturnValue().Set(Nan::New(socket->protocol().c_str()).ToLocalChecked());
}
info.GetReturnValue().SetUndefined();
}
void DataChannel::GetReadyState(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
webrtc::DataChannelInterface *socket = self->GetSocket();
if (socket) {
webrtc::DataChannelInterface::DataState state(socket->state());
switch (state) {
case webrtc::DataChannelInterface::kConnecting:
return info.GetReturnValue().Set(Nan::New("connecting").ToLocalChecked());
break;
case webrtc::DataChannelInterface::kOpen:
return info.GetReturnValue().Set(Nan::New("open").ToLocalChecked());
break;
case webrtc::DataChannelInterface::kClosing:
return info.GetReturnValue().Set(Nan::New("closing").ToLocalChecked());
break;
case webrtc::DataChannelInterface::kClosed:
return info.GetReturnValue().Set(Nan::New("closed").ToLocalChecked());
break;
}
}
info.GetReturnValue().SetUndefined();
}
void DataChannel::GetBufferedAmount(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
webrtc::DataChannelInterface *socket = self->GetSocket();
if (socket) {
return info.GetReturnValue().Set(Nan::New(static_cast<uint32_t>(socket->buffered_amount())));
}
info.GetReturnValue().SetUndefined();
}
void DataChannel::GetBinaryType(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
return info.GetReturnValue().Set(Nan::New(self->_binaryType));
}
void DataChannel::GetMaxPacketLifeType(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
webrtc::DataChannelInterface *socket = self->GetSocket();
if (socket) {
return info.GetReturnValue().Set(Nan::New(static_cast<uint32_t>(socket->maxRetransmitTime())));
}
info.GetReturnValue().SetUndefined();
}
void DataChannel::GetMaxRetransmits(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
webrtc::DataChannelInterface *socket = self->GetSocket();
if (socket) {
return info.GetReturnValue().Set(Nan::New(static_cast<uint32_t>(socket->maxRetransmits())));
}
info.GetReturnValue().SetUndefined();
}
void DataChannel::GetNegotiated(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
webrtc::DataChannelInterface *socket = self->GetSocket();
if (socket) {
return info.GetReturnValue().Set(Nan::New(socket->negotiated()));
}
return info.GetReturnValue().Set(Nan::False());
}
void DataChannel::GetReliable(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
webrtc::DataChannelInterface *socket = self->GetSocket();
if (socket) {
return info.GetReturnValue().Set(Nan::New(socket->reliable()));
}
return info.GetReturnValue().Set(Nan::False());
}
void DataChannel::GetOnOpen(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
return info.GetReturnValue().Set(Nan::New<Function>(self->_onopen));
}
void DataChannel::GetOnMessage(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
return info.GetReturnValue().Set(Nan::New<Function>(self->_onmessage));
}
void DataChannel::GetOnClose(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
return info.GetReturnValue().Set(Nan::New<Function>(self->_onclose));
}
void DataChannel::GetOnError(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
return info.GetReturnValue().Set(Nan::New<Function>(self->_onerror));
}
void DataChannel::ReadOnly(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
}
void DataChannel::SetBinaryType(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
if (!value.IsEmpty() && value->IsString()) {
self->_binaryType.Reset(value->ToString());
} else {
self->_binaryType.Reset(Nan::New("arraybuffer").ToLocalChecked());
}
}
void DataChannel::SetOnOpen(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
if (!value.IsEmpty() && value->IsFunction()) {
self->_onopen.Reset<Function>(Local<Function>::Cast(value));
} else {
self->_onopen.Reset();
}
}
void DataChannel::SetOnMessage(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
if (!value.IsEmpty() && value->IsFunction()) {
self->_onmessage.Reset<Function>(Local<Function>::Cast(value));
} else {
self->_onmessage.Reset();
}
}
void DataChannel::SetOnClose(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
if (!value.IsEmpty() && value->IsFunction()) {
self->_onclose.Reset<Function>(Local<Function>::Cast(value));
} else {
self->_onclose.Reset();
}
}
void DataChannel::SetOnError(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), "DataChannel");
if (!value.IsEmpty() && value->IsFunction()) {
self->_onerror.Reset<Function>(Local<Function>::Cast(value));
} else {
self->_onclose.Reset();
}
}
void DataChannel::On(Event *event) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::HandleScope scope;
DataChannelEvent type = event->Type<DataChannelEvent>();
node::ArrayBuffer *arrayBuffer = 0;
Local<Function> callback;
Local<Value> argv[1];
bool isError = false;
int argc = 0;
if (type == kDataChannelStateChange) {
webrtc::DataChannelInterface *socket = DataChannel::GetSocket();
if (socket) {
switch (socket->state()) {
case webrtc::DataChannelInterface::kConnecting:
break;
case webrtc::DataChannelInterface::kOpen:
callback = Nan::New<Function>(_onopen);
break;
case webrtc::DataChannelInterface::kClosing:
break;
case webrtc::DataChannelInterface::kClosed:
EventEmitter::SetReference(false);
callback = Nan::New<Function>(_onclose);
_onclose.Reset();
break;
}
}
} else {
callback = Nan::New<Function>(_onmessage);
rtc::Buffer buffer = event->Unwrap<rtc::Buffer>();
Local<Object> container = Nan::New<Object>();
argv[0] = container;
argc = 1;
if (type == kDataChannelData) {
container->Set(Nan::New("data").ToLocalChecked(), Nan::New(reinterpret_cast<char *>(buffer.data()), buffer.size()).ToLocalChecked());
} else {
arrayBuffer = node::ArrayBuffer::New(buffer.data(), buffer.size());
container->Set(Nan::New("data").ToLocalChecked(), arrayBuffer->ToArrayBuffer());
}
}
if (!callback.IsEmpty() && callback->IsFunction()) {
callback->Call(RTCWrap::This(), argc, argv);
} else if (isError) {
Nan::ThrowError(argv[0]);
}
}
================================================
FILE: src/DataChannel.h
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef WEBRTC_DATACHANNEL_H
#define WEBRTC_DATACHANNEL_H
#include "Common.h"
#include "Observers.h"
#include "EventEmitter.h"
#include "Wrap.h"
#include "ArrayBuffer.h"
namespace WebRTC {
enum DataChannelEvent {
kDataChannelStateChange,
kDataChannelBinary,
kDataChannelData,
};
class DataChannel : public RTCWrap, public EventEmitter {
public:
static void Init();
static v8::Local<v8::Value> New(rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel);
private:
DataChannel();
~DataChannel() final;
static void New(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void Close(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void Send(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void GetId(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetLabel(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetOrdered(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetProtocol(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetReadyState(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetBufferedAmount(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetBinaryType(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetMaxPacketLifeType(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetMaxRetransmits(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetNegotiated(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetReliable(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetOnOpen(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetOnMessage(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetOnClose(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetOnError(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void ReadOnly(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
static void SetBinaryType(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
static void SetOnOpen(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
static void SetOnMessage(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
static void SetOnClose(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
static void SetOnError(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
void On(Event *event) final;
webrtc::DataChannelInterface *GetSocket() const;
protected:
rtc::scoped_refptr<DataChannelObserver> _observer;
rtc::scoped_refptr<webrtc::DataChannelInterface> _socket;
Nan::Persistent<v8::String> _binaryType;
Nan::Persistent<v8::Function> _onopen;
Nan::Persistent<v8::Function> _onmessage;
Nan::Persistent<v8::Function> _onclose;
Nan::Persistent<v8::Function> _onerror;
static Nan::Persistent<v8::Function> constructor;
};
};
#endif
================================================
FILE: src/EventEmitter.cc
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "EventEmitter.h"
using namespace WebRTC;
EventEmitter::EventEmitter(uv_loop_t *loop, bool notify) : _notify(notify) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
uv_mutex_init(&_list);
if (!_notify) {
uv_mutex_init(&_lock);
_async = new uv_async_t();
_async->data = this;
if (!loop) {
loop = uv_default_loop();
}
uv_async_init(loop, _async, reinterpret_cast<uv_async_cb>(EventEmitter::onAsync));
EventEmitter::SetReference(false);
}
}
EventEmitter::~EventEmitter() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
EventEmitter::RemoveAllListeners();
EventEmitter::Dispose();
if (!_notify) {
_async->data = 0;
uv_close(reinterpret_cast<uv_handle_t*>(_async), EventEmitter::onEnded);
uv_mutex_destroy(&_lock);
}
uv_mutex_destroy(&_list);
}
void EventEmitter::AddListener(EventEmitter *listener) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
bool found = false;
std::vector<EventEmitter*>::iterator index;
if (listener && listener != this) {
uv_mutex_lock(&_list);
for (index = _listeners.begin(); index < _listeners.end(); index++) {
if ((*index) == listener) {
found = true;
break;
}
}
if (!found) {
_listeners.push_back(listener);
listener->AddParent(this);
}
uv_mutex_unlock(&_list);
}
}
void EventEmitter::RemoveListener(EventEmitter *listener) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
std::vector<EventEmitter*>::iterator index;
if (listener && listener != this) {
uv_mutex_lock(&_list);
for (index = _listeners.begin(); index < _listeners.end(); index++) {
if ((*index) == listener) {
_listeners.erase(index);
listener->RemoveParent(this);
break;
}
}
uv_mutex_unlock(&_list);
}
}
void EventEmitter::RemoveAllListeners() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
std::vector<EventEmitter*>::iterator index;
uv_mutex_lock(&_list);
for (index = _listeners.begin(); index < _listeners.end(); index++) {
(*index)->RemoveParent(this);
_listeners.erase(index);
}
uv_mutex_unlock(&_list);
}
void EventEmitter::Dispose() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (!_notify) {
while (!_events.empty()) {
rtc::scoped_refptr<Event> event = _events.front();
_events.pop();
}
}
}
void EventEmitter::SetReference(bool alive) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (!_notify) {
uv_mutex_lock(&_lock);
if (alive) {
uv_ref(reinterpret_cast<uv_handle_t*>(_async));
} else {
uv_unref(reinterpret_cast<uv_handle_t*>(_async));
}
uv_mutex_unlock(&_lock);
}
}
void EventEmitter::Emit(int event) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
EventEmitter::Emit(new rtc::RefCountedObject<Event>(event));
}
void EventEmitter::Emit(rtc::scoped_refptr<Event> event) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (event.get()) {
if (!_notify) {
uv_mutex_lock(&_lock);
_events.push(event);
uv_async_send(_async);
uv_mutex_unlock(&_lock);
}
uv_mutex_lock(&_list);
std::vector<EventEmitter*>::iterator index;
for (index = _listeners.begin(); index < _listeners.end(); index++) {
(*index)->Emit(event);
}
uv_mutex_unlock(&_list);
}
}
void EventEmitter::AddParent(EventEmitter *listener) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
uv_mutex_lock(&_list);
_parents.push_back(listener);
uv_mutex_unlock(&_list);
}
void EventEmitter::RemoveParent(EventEmitter *listener) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
std::vector<EventEmitter*>::iterator index;
uv_mutex_lock(&_list);
for (index = _listeners.begin(); index < _listeners.end(); index++) {
if ((*index) == listener) {
_listeners.erase(index);
}
}
uv_mutex_unlock(&_list);
}
void EventEmitter::onAsync(uv_async_t *handle, int status) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
EventEmitter *self = static_cast<EventEmitter*>(handle->data);
if (self) {
self->DispatchEvents();
}
}
void EventEmitter::onEnded(uv_handle_t *handle) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
uv_async_t* async = reinterpret_cast<uv_async_t*>(handle);
if (async) {
delete async;
}
}
void EventEmitter::DispatchEvents() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
uv_mutex_lock(&_lock);
while (!_events.empty()) {
rtc::scoped_refptr<Event> event = _events.front();
_events.pop();
uv_mutex_unlock(&_lock);
if (event.get()) {
On(event);
}
uv_mutex_lock(&_lock);
}
uv_mutex_unlock(&_lock);
}
NotifyEmitter::NotifyEmitter(EventEmitter *listener) : EventEmitter(0, true) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (listener) {
NotifyEmitter::AddListener(listener);
}
}
void NotifyEmitter::On(Event *event) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
}
================================================
FILE: src/EventEmitter.h
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef WEBRTC_EVENTEMITTER_H
#define WEBRTC_EVENTEMITTER_H
#include "Common.h"
namespace WebRTC {
template<class T> class EventWrapper;
class Event : public rtc::RefCountInterface {
template<class T> friend class EventWrapper;
friend class rtc::RefCountedObject<Event>;
friend class EventEmitter;
public:
inline bool HasWrap() const {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
return _wrap;
}
template <class T> inline T Type() const {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
return static_cast<T>(_event);
}
template<class T> const T &Unwrap() const {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
static T nowrap;
if (_wrap) {
const EventWrapper<T> *ptr = static_cast<const EventWrapper<T> *>(this);
return ptr->_content;
}
nowrap = T();
return nowrap;
}
private:
explicit Event(int event = 0) :
_event(event),
_wrap(false)
{
LOG(LS_INFO) << __PRETTY_FUNCTION__;
}
virtual ~Event() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
}
protected:
int _event;
bool _wrap;
};
template<class T> class EventWrapper : public Event {
friend class rtc::RefCountedObject<EventWrapper<T> >;
friend class Event;
friend class EventEmitter;
private:
explicit EventWrapper(int event, const T &content) :
Event(event),
_content(content)
{
_wrap = true;
}
virtual ~EventWrapper() { }
protected:
T _content;
};
class EventEmitter {
friend class NotifyEmitter;
public:
explicit EventEmitter(uv_loop_t *loop = 0, bool notify = false);
virtual ~EventEmitter();
void AddListener(EventEmitter *listener = 0);
void RemoveListener(EventEmitter *listener = 0);
void RemoveAllListeners();
void SetReference(bool alive = true);
void Emit(int event = 0);
void Emit(rtc::scoped_refptr<Event> event);
template <class T> inline void Emit(int event, const T &content) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
EventEmitter::Emit(new rtc::RefCountedObject<EventWrapper<T> >(event, content));
}
virtual void On(Event *event) = 0;
private:
static void onAsync(uv_async_t *handle, int status);
static void onEnded(uv_handle_t *handle);
void Dispose();
void DispatchEvents();
void AddParent(EventEmitter *listener = 0);
void RemoveParent(EventEmitter *listener = 0);
protected:
bool _notify;
uv_mutex_t _lock;
uv_mutex_t _list;
uv_async_t* _async;
std::queue<rtc::scoped_refptr<Event> > _events;
std::vector<EventEmitter*> _listeners;
std::vector<EventEmitter*> _parents;
};
class NotifyEmitter : public EventEmitter {
public:
NotifyEmitter(EventEmitter *listener = 0);
virtual void On(Event *event);
};
};
#endif
================================================
FILE: src/GetSources.cc
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include <ctype.h>
#include "Platform.h"
#include "MediaStreamTrack.h"
#include "GetSources.h"
using namespace v8;
using namespace WebRTC;
void GetSources::Init(Handle<Object> exports) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
exports->Set(Nan::New("getSources").ToLocalChecked(), Nan::New<FunctionTemplate>(GetSources::GetDevices)->GetFunction());
exports->Set(Nan::New("getVideoSource").ToLocalChecked(), Nan::New<FunctionTemplate>(GetSources::GetVideoSource2)->GetFunction());
}
rtc::scoped_refptr<webrtc::AudioTrackInterface> GetSources::GetAudioSource(const rtc::scoped_refptr<MediaConstraints> &constraints) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
rtc::scoped_refptr<webrtc::AudioTrackInterface> track;
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory = webrtc::CreatePeerConnectionFactory(rtc::Thread::Current(), Platform::GetWorker(), 0, 0, 0);
if (factory.get()) {
track = factory->CreateAudioTrack("audio", factory->CreateAudioSource(constraints->ToConstraints()));
}
return track;
}
rtc::scoped_refptr<webrtc::AudioTrackInterface> GetSources::GetAudioSource(const std::string id, const rtc::scoped_refptr<MediaConstraints> &constraints) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
return GetSources::GetAudioSource(constraints);
}
rtc::scoped_refptr<webrtc::VideoTrackInterface> GetSources::GetVideoSource(const rtc::scoped_refptr<MediaConstraints> &constraints) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
cricket::VideoCapturer* capturer = nullptr;
rtc::scoped_refptr<webrtc::VideoTrackInterface> track;
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory = webrtc::CreatePeerConnectionFactory(rtc::Thread::Current(), Platform::GetWorker(), 0, 0, 0);
std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> video_info(webrtc::VideoCaptureFactory::CreateDeviceInfo(0));
cricket::WebRtcVideoDeviceCapturerFactory device_factory;
if (factory.get()) {
if (video_info) {
int num_devices = video_info->NumberOfDevices();
for (int i = 0; i < num_devices; ++i) {
const uint32_t kSize = 256;
char name[kSize] = {0};
char id[kSize] = {0};
if (video_info->GetDeviceName(i, name, kSize, id, kSize) != -1) {
capturer = device_factory.Create(cricket::Device(name, 0));
if (capturer) {
for(int i = 0; name[i]; i++){
if (name[i]==' ') name[i] = '_';
name[i] = tolower(name[i]);
}
track = factory->CreateVideoTrack(name, factory->CreateVideoSource(capturer, constraints->ToConstraints()));
return track;
}
}
}
}
}
return track;
}
rtc::scoped_refptr<webrtc::VideoTrackInterface> GetSources::GetVideoSource(const std::string id_name, const rtc::scoped_refptr<MediaConstraints> &constraints) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
cricket::VideoCapturer* capturer = nullptr;
rtc::scoped_refptr<webrtc::VideoTrackInterface> track;
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory = webrtc::CreatePeerConnectionFactory(rtc::Thread::Current(), Platform::GetWorker(), 0, 0, 0);
std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> video_info(webrtc::VideoCaptureFactory::CreateDeviceInfo(0));
cricket::WebRtcVideoDeviceCapturerFactory device_factory;
if (factory.get()) {
if (video_info) {
int num_devices = video_info->NumberOfDevices();
for (int i = 0; i < num_devices; ++i) {
const uint32_t kSize = 256;
char name[kSize] = {0};
char id[kSize] = {0};
if (video_info->GetDeviceName(i, name, kSize, id, kSize) != -1) {
if (id_name.empty() || id_name.compare(name) == 0) {
capturer = device_factory.Create(cricket::Device(name, 0));
if (capturer) {
for(int i = 0; name[i]; i++){
if (name[i]==' ') name[i] = '_';
name[i] = tolower(name[i]);
}
track = factory->CreateVideoTrack(name, factory->CreateVideoSource(capturer, constraints->ToConstraints()));
return track;
}
}
}
}
}
}
return track;
}
Local<Value> GetSources::GetDevices() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::EscapableHandleScope scope;
Local<Array> list = Nan::New<Array>();
uint32_t index = 0;
std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> video_info(webrtc::VideoCaptureFactory::CreateDeviceInfo(0));
if (video_info) {
int num_devices = video_info->NumberOfDevices();
for (int i = 0; i < num_devices; ++i) {
const uint32_t kSize = 256;
char name[kSize] = {0};
char id[kSize] = {0};
if (video_info->GetDeviceName(i, name, kSize, id, kSize) != -1) {
Local<Object> device = Nan::New<Object>();
device->Set(Nan::New("kind").ToLocalChecked(), Nan::New("video").ToLocalChecked());
device->Set(Nan::New("label").ToLocalChecked(), Nan::New(name).ToLocalChecked());
device->Set(Nan::New("id").ToLocalChecked(), Nan::New(id).ToLocalChecked());
list->Set(index, device);
index++;
}
}
}
return scope.Escape(list);
}
void GetSources::GetVideoSource2(const Nan::FunctionCallbackInfo<Value> &info) {
Nan::Utf8String name_id(info[0]->ToString());
rtc::scoped_refptr<MediaConstraints> constraints = MediaConstraints::New(info[1]);
rtc::scoped_refptr<webrtc::VideoTrackInterface> track = GetSources::GetVideoSource(*name_id,constraints);
info.GetReturnValue().Set(MediaStreamTrack::New(track));
}
void GetSources::GetDevices(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (info.Length() == 1 && info[0]->IsFunction()) {
Local<Function> callback = Local<Function>::Cast(info[0]);
Local<Value> argv[1] = {
GetSources::GetDevices()
};
if (!callback.IsEmpty()) {
callback->Call(info.This(), 1, argv);
}
}
info.GetReturnValue().SetUndefined();
}
================================================
FILE: src/GetSources.h
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef WEBRTC_GETSOURCES_H
#define WEBRTC_GETSOURCES_H
#include "Common.h"
#include "MediaConstraints.h"
namespace WebRTC {
class GetSources {
public:
static void Init(v8::Handle<v8::Object> exports);
static rtc::scoped_refptr<webrtc::AudioTrackInterface> GetAudioSource(const rtc::scoped_refptr<MediaConstraints> &constraints);
static rtc::scoped_refptr<webrtc::AudioTrackInterface> GetAudioSource(const std::string id, const rtc::scoped_refptr<MediaConstraints> &constraints);
static rtc::scoped_refptr<webrtc::VideoTrackInterface> GetVideoSource(const rtc::scoped_refptr<MediaConstraints> &constraints);
static rtc::scoped_refptr<webrtc::VideoTrackInterface> GetVideoSource(const std::string id, const rtc::scoped_refptr<MediaConstraints> &constraints);
static v8::Local<v8::Value> GetDevices();
private:
static void GetVideoSource2(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void GetDevices(const Nan::FunctionCallbackInfo<v8::Value> &info);
};
};
#endif
================================================
FILE: src/GetUserMedia.cc
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "Platform.h"
#include "GetUserMedia.h"
#include "GetSources.h"
#include "MediaStream.h"
#include "MediaConstraints.h"
using namespace v8;
using namespace WebRTC;
void GetUserMedia::Init(Handle<Object> exports) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
exports->Set(Nan::New("getUserMedia").ToLocalChecked(), Nan::New<FunctionTemplate>(GetUserMedia::GetMediaStream)->GetFunction());
}
void GetUserMedia::GetMediaStream(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream;
rtc::scoped_refptr<MediaConstraints> constraints = MediaConstraints::New(info[0]);
const char *error = 0;
bool have_source = false;
std::string audioId = constraints->AudioId();
std::string videoId = constraints->VideoId();
if (constraints->UseAudio() || constraints->UseVideo()) {
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory = webrtc::CreatePeerConnectionFactory(rtc::Thread::Current(), Platform::GetWorker(), 0, 0, 0);
if (factory.get()) {
stream = factory->CreateLocalMediaStream("stream");
if (stream.get()) {
if (constraints->UseAudio()) {
rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track;
if (audioId.empty()) {
audio_track = GetSources::GetAudioSource(constraints);
} else {
audio_track = GetSources::GetAudioSource(audioId, constraints);
}
if (audio_track.get()) {
if (!stream->AddTrack(audio_track)) {
error = "Invalid Audio Input";
} else {
have_source = true;
}
} else {
if (!audioId.empty()) {
error = "Invalid Audio Input";
}
}
}
if (constraints->UseVideo()) {
rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track;
if (videoId.empty()) {
video_track = GetSources::GetVideoSource(constraints);
} else {
video_track = GetSources::GetVideoSource(videoId, constraints);
}
if (video_track.get()) {
if (!stream->AddTrack(video_track)) {
error = "Invalid Video Input";
} else {
have_source = true;
}
} else {
if (!videoId.empty()) {
error = "Invalid Video Input";
}
}
}
} else {
error = "Internal Error";
}
}
}
if (!have_source) {
error = "No available inputs";
}
Handle<Value> argv[1];
if (!error) {
if (stream.get()) {
argv[0] = MediaStream::New(stream);
} else {
error = "Invalid MediaStream";
}
}
if (error) {
if (!info[2].IsEmpty() && info[2]->IsFunction()) {
Local<Function> onerror = Local<Function>::Cast(info[2]);
argv[0] = Nan::Error(error);
onerror->Call(info.This(), 1, argv);
} else {
Nan::ThrowError(error);
}
} else {
if (!info[1].IsEmpty() && info[1]->IsFunction()) {
Local<Function> onsuccess = Local<Function>::Cast(info[1]);
onsuccess->Call(info.This(), 1, argv);
}
}
info.GetReturnValue().SetUndefined();
}
================================================
FILE: src/GetUserMedia.h
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef WEBRTC_GETUSERMEDIA_H
#define WEBRTC_GETUSERMEDIA_H
#include "Common.h"
namespace WebRTC {
class GetUserMedia {
public:
static void Init(v8::Handle<v8::Object> exports);
private:
static void GetMediaStream(const Nan::FunctionCallbackInfo<v8::Value> &info);
};
};
#endif
================================================
FILE: src/Global.cc
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "Global.h"
using namespace v8;
using namespace WebRTC;
Nan::Persistent<Function> _require;
#if (NODE_MODULE_VERSION <= NODE_0_10_MODULE_VERSION)
Nan::Persistent<Function> _parse;
#endif
void WebRTC::Global::Init(Handle<Object> exports) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::HandleScope scope;
Local<Object> global = Nan::GetCurrentContext()->Global();
_require.Reset(Local<Function>::Cast(global->Get(Nan::New("require").ToLocalChecked())));
#if (NODE_MODULE_VERSION <= NODE_0_10_MODULE_VERSION)
Local<Object> json = Local<Object>::Cast(global->Get(Nan::New("JSON").ToLocalChecked()));
_parse.Reset(Local<Function>::Cast(json->Get(Nan::New("parse").ToLocalChecked())));
#endif
}
Local<Function> WebRTC::Global::Require(Local<String> library) {
Nan::EscapableHandleScope scope;
Local<Value> argv[] = { library };
Local<Value> retval = Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(_require), 1, argv);
return scope.Escape(Local<Function>::Cast(retval));
}
#if (NODE_MODULE_VERSION <= NODE_0_10_MODULE_VERSION)
Local<Value> JSON::Parse(Local<Value> str) {
Nan::EscapableHandleScope scope;
Local<Value> argv[] = { str };
return scope.Escape(Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(_parse), 1, argv));
};
#endif
================================================
FILE: src/Global.h
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef WEBRTC_GLOBAL_H
#define WEBRTC_GLOBAL_H
#include "Common.h"
namespace WebRTC {
class Global {
public:
static void Init(v8::Handle<v8::Object> exports);
static v8::Local<v8::Function> Require(v8::Local<v8::String> library);
};
};
#if (NODE_MODULE_VERSION <= NODE_0_10_MODULE_VERSION)
namespace v8 {
class JSON {
public:
static v8::Local<v8::Value> Parse(v8::Local<v8::Value> str);
};
};
#endif
#endif
================================================
FILE: src/MediaCapturer.cc
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "MediaCapturer.h"
using namespace v8;
using namespace WebRTC;
Nan::Persistent<Function> MediaCapturer::constructor;
void MediaCapturer::Init() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::HandleScope scope;
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(MediaCapturer::New);
tpl->InstanceTemplate()->SetInternalFieldCount(1);
tpl->SetClassName(Nan::New("MediaCapturer").ToLocalChecked());
Nan::SetPrototypeMethod(tpl, "stop", MediaCapturer::Stop);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("data").ToLocalChecked(), MediaStreamTrack::GetOnData, MediaStreamTrack::SetOnData);
constructor.Reset<Function>(tpl->GetFunction());
}
Local<Value> MediaCapturer::New(webrtc::AudioSourceInterface *track) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::EscapableHandleScope scope;
Local<Value> argv[1];
Local<Function> instance = Nan::New(MediaCapturer::constructor);
if (instance.IsEmpty() || !track) {
return scope.Escape(Nan::Null());
}
Local<Object> ret = instance->NewInstance(0, argv);
MediaCapturer *self = RTCWrap::Unwrap<MediaCapturer>(ret, "MediaCapturer");
self->_audio = track;
self->_source = track;
self->_source->RegisterObserver(self->_observer.get());
self->_audio->AddSink(self);
if (self->_audio->state() == webrtc::MediaSourceInterface::kLive) {
self->SetReference(true);
}
return scope.Escape(ret);
}
Local<Value> MediaCapturer::New(webrtc::VideoSourceInterface *track) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::EscapableHandleScope scope;
Local<Value> argv[1];
Local<Function> instance = Nan::New(MediaCapturer::constructor);
if (instance.IsEmpty() || !track) {
return scope.Escape(Nan::Null());
}
Local<Object> ret = instance->NewInstance(0, argv);
MediaCapturer *self = RTCWrap::Unwrap<MediaCapturer>(ret, "MediaCapturer");
self->_video = track;
self->_source = track;
self->_source->RegisterObserver(self->_observer.get());
self->_video->AddOrUpdateSink(self, rtc::VideoSinkWants());
if (self->_video->state() == webrtc::MediaSourceInterface::kLive) {
self->SetReference(true);
}
return scope.Escape(ret);
}
MediaCapturer::MediaCapturer() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
_observer = new rtc::RefCountedObject<MediaStreamTrackObserver>(this);
}
MediaCapturer::~MediaCapturer() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (_video.get()) {
_video->RemoveSink(this);
}
if (_audio.get()) {
_audio->RemoveSink(this);
}
if (_source.get()) {
_source->UnregisterObserver(_observer.get());
}
_observer->RemoveListener(this);
}
void MediaCapturer::New(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::HandleScope scope;
if (info.IsConstructCall()) {
MediaCapturer* MediaCapturer = new MediaCapturer();
MediaCapturer->Wrap(info.This(), "MediaCapturer");
return info.GetReturnValue().Set(info.This());
}
Nan::ThrowError("Internal Error");
info.GetReturnValue().SetUndefined();
}
void MediaCapturer::Stop(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaCapturer *self = RTCWrap::Unwrap<MediaCapturer>(info.This(), "MediaCapturer");
self->SetReference(false);
return info.GetReturnValue().SetUndefined();
}
void MediaCapturer::GetOnData(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaCapturer *self = RTCWrap::Unwrap<MediaCapturer>(info.Holder(), "MediaCapturer");
return info.GetReturnValue().Set(Nan::New<Function>(self->_ondata));
}
void MediaCapturer::SetOnData(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaCapturer *self = RTCWrap::Unwrap<MediaCapturer>(info.Holder(), "MediaCapturer");
if (!value.IsEmpty() && value->IsFunction()) {
self->_ondata.Reset<Function>(Local<Function>::Cast(value));
} else {
self->_ondata.Reset();
}
}
void MediaCapturer::OnFrame(const cricket::VideoFrame &frame) {
printf("Got Video Frame!\n");
}
void MediaCapturer::OnData(const void* audio_data, int bits_per_sample, int sample_rate, size_t number_of_channels, size_t number_of_frames) {
printf("Got Audio Frame!\n");
}
void MediaCapturer::On(Event *event) {
if (_source.get()) {
if (_source->state() != webrtc::MediaSourceInterface::kLive) {
EventEmitter::SetReference(false);
}
}
}
================================================
FILE: src/MediaCapturer.h
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef WEBRTC_MEDIACAPTURER_H
#define WEBRTC_MEDIACAPTURER_H
#include "Common.h"
#include "Observers.h"
#include "EventEmitter.h"
#include "Wrap.h"
namespace WebRTC {
class MediaCapturer :
public RTCWrap,
public EventEmitter,
public rtc::VideoSourceInterface<cricket::VideoFrame>,
public webrtc::AudioTrackSinkInterface
{
public:
static void Init();
static v8::Local<v8::Value> New(webrtc::AudioSourceInterface *track = 0);
static v8::Local<v8::Value> New(webrtc::VideoSourceInterface *track = 0);
private:
MediaCapturer();
~MediaCapturer() final;
static void New(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void Stop(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void GetOnData(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void SetOnData(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
void OnFrame(const cricket::VideoFrame &frame) final;
void OnData(const void* audio_data, int bits_per_sample, int sample_rate, size_t number_of_channels, size_t number_of_frames) final;
void On(Event *event) final;
protected:
rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> _video;
rtc::scoped_refptr<webrtc::AudioSourceInterface> _audio;
rtc::scoped_refptr<webrtc::MediaSourceInterface> _source;
rtc::scoped_refptr<MediaStreamTrackObserver> _observer;
Nan::Persistent<v8::Function> _ondata;
static Nan::Persistent<v8::Function> constructor;
};
};
#endif
================================================
FILE: src/MediaConstraints.cc
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "MediaConstraints.h"
using namespace v8;
using namespace WebRTC;
MediaConstraints::MediaConstraints() :
_audio(false),
_video(false)
{
LOG(LS_INFO) << __PRETTY_FUNCTION__;
}
MediaConstraints::~MediaConstraints() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
}
rtc::scoped_refptr<MediaConstraints> MediaConstraints::New() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
return new rtc::RefCountedObject<MediaConstraints>();
}
rtc::scoped_refptr<MediaConstraints> MediaConstraints::New(const Local<Object> &constraints) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::HandleScope scope;
rtc::scoped_refptr<MediaConstraints> self = MediaConstraints::New();
if (constraints.IsEmpty()) {
return self;
}
Local<Value> optional_value = constraints->Get(Nan::New("optional").ToLocalChecked());
if (!optional_value.IsEmpty() && optional_value->IsArray()) {
Local<Array> options = Local<Array>::Cast(optional_value);
for (unsigned int index = 0; index < options->Length(); index++) {
Local<Value> option_value = options->Get(index);
if (!option_value.IsEmpty() && option_value->IsObject()) {
Local<Object> option = Local<Object>::Cast(option_value);
Local<Value> DtlsSrtpKeyAgreement = option->Get(Nan::New("DtlsSrtpKeyAgreement").ToLocalChecked());
Local<Value> RtpDataChannels = option->Get(Nan::New("RtpDataChannels").ToLocalChecked());
Local<Value> googDscp = option->Get(Nan::New("googDscp").ToLocalChecked());
Local<Value> googIPv6 = option->Get(Nan::New("googIPv6").ToLocalChecked());
Local<Value> googSuspendBelowMinBitrate = option->Get(Nan::New("googSuspendBelowMinBitrate").ToLocalChecked());
Local<Value> googCombinedAudioVideoBwe = option->Get(Nan::New("googCombinedAudioVideoBwe").ToLocalChecked());
Local<Value> googScreencastMinBitrate = option->Get(Nan::New("googScreencastMinBitrate").ToLocalChecked());
Local<Value> googCpuOveruseDetection = option->Get(Nan::New("googCpuOveruseDetection").ToLocalChecked());
Local<Value> googPayloadPadding = option->Get(Nan::New("googPayloadPadding").ToLocalChecked());
self->SetOptional(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, DtlsSrtpKeyAgreement);
self->SetOptional(webrtc::MediaConstraintsInterface::kEnableRtpDataChannels, RtpDataChannels);
self->SetOptional(webrtc::MediaConstraintsInterface::kEnableDscp, googDscp);
self->SetOptional(webrtc::MediaConstraintsInterface::kEnableIPv6, googIPv6);
self->SetOptional(webrtc::MediaConstraintsInterface::kEnableVideoSuspendBelowMinBitrate, googSuspendBelowMinBitrate);
self->SetOptional(webrtc::MediaConstraintsInterface::kCombinedAudioVideoBwe, googCombinedAudioVideoBwe);
self->SetOptional(webrtc::MediaConstraintsInterface::kScreencastMinBitrate, googScreencastMinBitrate);
self->SetOptional(webrtc::MediaConstraintsInterface::kCpuOveruseDetection, googCpuOveruseDetection);
self->SetOptional(webrtc::MediaConstraintsInterface::kPayloadPadding, googPayloadPadding);
}
}
}
Local<Value> mandatory_value = constraints->Get(Nan::New("mandatory").ToLocalChecked());
if (!mandatory_value.IsEmpty() && mandatory_value->IsObject()) {
Local<Object> mandatory = Local<Object>::Cast(mandatory_value);
Local<Value> OfferToReceiveAudio = mandatory->Get(Nan::New("OfferToReceiveAudio").ToLocalChecked());
Local<Value> OfferToReceiveVideo = mandatory->Get(Nan::New("OfferToReceiveVideo").ToLocalChecked());
Local<Value> VoiceActivityDetection = mandatory->Get(Nan::New("VoiceActivityDetection").ToLocalChecked());
Local<Value> IceRestart = mandatory->Get(Nan::New("IceRestart").ToLocalChecked());
Local<Value> googUseRtpMUX = mandatory->Get(Nan::New("googUseRtpMUX").ToLocalChecked());
self->SetMandatory(webrtc::MediaConstraintsInterface::kOfferToReceiveAudio, OfferToReceiveAudio);
self->SetMandatory(webrtc::MediaConstraintsInterface::kOfferToReceiveVideo, OfferToReceiveVideo);
self->SetMandatory(webrtc::MediaConstraintsInterface::kVoiceActivityDetection, VoiceActivityDetection);
self->SetMandatory(webrtc::MediaConstraintsInterface::kIceRestart, IceRestart);
self->SetMandatory(webrtc::MediaConstraintsInterface::kUseRtpMux, googUseRtpMUX);
}
Local<Value> audio_value = constraints->Get(Nan::New("audio").ToLocalChecked());
if (!audio_value.IsEmpty()) {
if (audio_value->IsTrue() || audio_value->IsFalse()) {
self->_audio = true;
} else if (audio_value->IsObject()) {
Local<Object> audio = Local<Object>::Cast(audio_value);
optional_value = audio->Get(Nan::New("optional").ToLocalChecked());
if (!optional_value.IsEmpty() && optional_value->IsArray()) {
Local<Array> options = Local<Array>::Cast(optional_value);
for (unsigned int index = 0; index < options->Length(); index++) {
Local<Value> option_value = options->Get(index);
if (!option_value.IsEmpty() && option_value->IsObject()) {
Local<Object> option = Local<Object>::Cast(option_value);
Local<Value> EchoCancellation = option->Get(Nan::New("echoCancellation").ToLocalChecked());
Local<Value> googEchoCancellation = option->Get(Nan::New("googEchoCancellation").ToLocalChecked());
Local<Value> googEchoCancellation2 = option->Get(Nan::New("googEchoCancellation2").ToLocalChecked());
Local<Value> googDAEchoCancellation = option->Get(Nan::New("googDAEchoCancellation").ToLocalChecked());
Local<Value> googAutoGainControl = option->Get(Nan::New("googAutoGainControl").ToLocalChecked());
Local<Value> googAutoGainControl2 = option->Get(Nan::New("googAutoGainControl2").ToLocalChecked());
Local<Value> googNoiseSuppression = option->Get(Nan::New("googNoiseSuppression").ToLocalChecked());
Local<Value> googNoiseSuppression2 = option->Get(Nan::New("googNoiseSuppression2").ToLocalChecked());
Local<Value> googHighpassFilter = option->Get(Nan::New("googHighpassFilter").ToLocalChecked());
Local<Value> googTypingNoiseDetection = option->Get(Nan::New("googTypingNoiseDetection").ToLocalChecked());
Local<Value> googAudioMirroring = option->Get(Nan::New("googAudioMirroring").ToLocalChecked());
Local<Value> noiseReduction = option->Get(Nan::New("googNoiseReduction").ToLocalChecked());
Local<Value> sourceId = option->Get(Nan::New("sourceId").ToLocalChecked());
self->SetOptional(webrtc::MediaConstraintsInterface::kEchoCancellation, EchoCancellation);
self->SetOptional(webrtc::MediaConstraintsInterface::kGoogEchoCancellation, googEchoCancellation);
self->SetOptional(webrtc::MediaConstraintsInterface::kExtendedFilterEchoCancellation, googEchoCancellation2);
self->SetOptional(webrtc::MediaConstraintsInterface::kDAEchoCancellation, googDAEchoCancellation);
self->SetOptional(webrtc::MediaConstraintsInterface::kAutoGainControl, googAutoGainControl);
self->SetOptional(webrtc::MediaConstraintsInterface::kExperimentalAutoGainControl, googAutoGainControl2);
self->SetOptional(webrtc::MediaConstraintsInterface::kNoiseSuppression, googNoiseSuppression);
self->SetOptional(webrtc::MediaConstraintsInterface::kExperimentalNoiseSuppression, googNoiseSuppression2);
self->SetOptional(webrtc::MediaConstraintsInterface::kHighpassFilter, googHighpassFilter);
self->SetOptional(webrtc::MediaConstraintsInterface::kTypingNoiseDetection, googTypingNoiseDetection);
self->SetOptional(webrtc::MediaConstraintsInterface::kAudioMirroring, googAudioMirroring);
self->SetOptional(webrtc::MediaConstraintsInterface::kNoiseReduction, noiseReduction);
if (!sourceId.IsEmpty() && sourceId->IsString()) {
String::Utf8Value sourceId_str(sourceId->ToString());
self->_audioId = *sourceId_str;
}
}
}
}
self->_audio = true;
}
}
Local<Value> video_value = constraints->Get(Nan::New("video").ToLocalChecked());
if (!video_value.IsEmpty()) {
if (video_value->IsTrue() || video_value->IsFalse()) {
self->_video = true;
} else if (video_value->IsObject()) {
Local<Object> video = Local<Object>::Cast(audio_value);
optional_value = video->Get(Nan::New("optional").ToLocalChecked());
if (!optional_value.IsEmpty() && optional_value->IsArray()) {
Local<Array> options = Local<Array>::Cast(optional_value);
for (unsigned int index = 0; index < options->Length(); index++) {
Local<Value> option_value = options->Get(index);
if (!option_value.IsEmpty() && option_value->IsObject()) {
Local<Object> option = Local<Object>::Cast(option_value);
Local<Value> minAspectRatio = option->Get(Nan::New("minAspectRatio").ToLocalChecked());
Local<Value> maxAspectRatio = option->Get(Nan::New("maxAspectRatio").ToLocalChecked());
Local<Value> maxWidth = option->Get(Nan::New("maxWidth").ToLocalChecked());
Local<Value> minWidth = option->Get(Nan::New("minWidth").ToLocalChecked());
Local<Value> maxHeight = option->Get(Nan::New("maxHeight").ToLocalChecked());
Local<Value> minHeight = option->Get(Nan::New("minHeight").ToLocalChecked());
Local<Value> maxFrameRate = option->Get(Nan::New("maxFrameRate").ToLocalChecked());
Local<Value> minFrameRate = option->Get(Nan::New("minFrameRate").ToLocalChecked());
Local<Value> sourceId = option->Get(Nan::New("sourceId").ToLocalChecked());
self->SetOptional(webrtc::MediaConstraintsInterface::kMinAspectRatio, minAspectRatio);
self->SetOptional(webrtc::MediaConstraintsInterface::kMaxAspectRatio, maxAspectRatio);
self->SetOptional(webrtc::MediaConstraintsInterface::kMaxWidth, maxWidth);
self->SetOptional(webrtc::MediaConstraintsInterface::kMinWidth, minWidth);
self->SetOptional(webrtc::MediaConstraintsInterface::kMaxHeight, maxHeight);
self->SetOptional(webrtc::MediaConstraintsInterface::kMinHeight, minHeight);
self->SetOptional(webrtc::MediaConstraintsInterface::kMaxFrameRate, maxFrameRate);
self->SetOptional(webrtc::MediaConstraintsInterface::kMinFrameRate, minFrameRate);
if (!sourceId.IsEmpty() && sourceId->IsString()) {
String::Utf8Value sourceId_str(sourceId->ToString());
self->_videoId = *sourceId_str;
}
}
}
}
self->_video = true;
}
}
return self;
}
rtc::scoped_refptr<MediaConstraints> MediaConstraints::New(const Local<Value> &constraints) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::HandleScope scope;
if (!constraints.IsEmpty() && constraints->IsObject()) {
Local<Object> obj = Local<Object>::Cast(constraints);
return MediaConstraints::New(obj);
}
return MediaConstraints::New();
}
void MediaConstraints::SetOptional(std::string key, Local<Value> value) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (!value.IsEmpty() && !value->IsNull() && !value->IsUndefined()) {
if (value->IsTrue() || value->IsFalse()) {
MediaConstraints::SetOptional(key, value->IsTrue() ?
std::string(webrtc::MediaConstraintsInterface::kValueTrue) :
std::string(webrtc::MediaConstraintsInterface::kValueFalse));
} else if (value->IsNumber()) {
MediaConstraints::SetOptional(key, value->NumberValue());
} else if (value->IsInt32()) {
MediaConstraints::SetOptional(key, value->Int32Value());
} else if (value->IsUint32()) {
MediaConstraints::SetOptional(key, value->Uint32Value());
} else {
Nan::ThrowError("Unknown MediaConstraints Type");
}
}
}
void MediaConstraints::SetMandatory(std::string key, Local<Value> value) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (!value.IsEmpty() && !value->IsNull() && !value->IsUndefined()) {
if (value->IsTrue() || value->IsFalse()) {
MediaConstraints::SetMandatory(key, value->IsTrue() ?
std::string(webrtc::MediaConstraintsInterface::kValueTrue) :
std::string(webrtc::MediaConstraintsInterface::kValueFalse));
} else if (value->IsNumber()) {
MediaConstraints::SetMandatory(key, value->NumberValue());
} else if (value->IsInt32()) {
MediaConstraints::SetMandatory(key, value->Int32Value());
} else if (value->IsUint32()) {
MediaConstraints::SetMandatory(key, value->Uint32Value());
} else {
Nan::ThrowError("Unknown MediaConstraints Type");
}
}
}
bool MediaConstraints::IsMandatory(const std::string& key) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
std::string value;
if (_mandatory.FindFirst(key, &value)) {
return true;
}
return false;
}
bool MediaConstraints::GetMandatory(const std::string& key) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
std::string value;
if (_mandatory.FindFirst(key, &value)) {
if (!value.compare("true")) {
return true;
}
}
return false;
}
void MediaConstraints::RemoveMandatory(const std::string& key) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
std::string value;
if (_mandatory.FindFirst(key, &value)) {
for (webrtc::MediaConstraintsInterface::Constraints::iterator iter = _mandatory.begin(); iter != _mandatory.end(); ++iter) {
if (iter->key == key) {
_mandatory.erase(iter);
break;
}
}
}
}
void MediaConstraints::AddMandatory(const std::string &key, const std::string &value) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
_mandatory.push_back(webrtc::MediaConstraintsInterface::Constraint(key, value));
}
void MediaConstraints::SetMandatory(const std::string &key, const std::string &value) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaConstraints::RemoveMandatory(key);
MediaConstraints::AddMandatory(key, value);
}
bool MediaConstraints::IsOptional(const std::string& key) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
std::string value;
if (_mandatory.FindFirst(key, &value)) {
return true;
}
return false;
}
bool MediaConstraints::GetOptional(const std::string& key) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
std::string value;
if (_optional.FindFirst(key, &value)) {
if (!value.compare("true")) {
return true;
}
}
return false;
}
void MediaConstraints::RemoveOptional(const std::string& key) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
std::string value;
if (_optional.FindFirst(key, &value)) {
for (webrtc::MediaConstraintsInterface::Constraints::iterator iter = _optional.begin(); iter != _optional.end(); ++iter) {
if (iter->key == key) {
_optional.erase(iter);
break;
}
}
}
}
void MediaConstraints::AddOptional(const std::string &key, const std::string &value) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
_optional.push_back(webrtc::MediaConstraintsInterface::Constraint(key, value));
}
void MediaConstraints::SetOptional(const std::string &key, const std::string &value) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaConstraints::RemoveOptional(key);
MediaConstraints::AddOptional(key, value);
}
bool MediaConstraints::UseAudio() const {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
return _audio;
}
bool MediaConstraints::UseVideo() const {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
return _video;
}
std::string MediaConstraints::AudioId() const {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
return _audioId;
}
std::string MediaConstraints::VideoId() const {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
return _videoId;
}
const webrtc::MediaConstraintsInterface *MediaConstraints::ToConstraints() const {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
return this;
}
const webrtc::MediaConstraintsInterface::Constraints &MediaConstraints::GetMandatory() const {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
return _mandatory;
}
const webrtc::MediaConstraintsInterface::Constraints &MediaConstraints::GetOptional() const {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
return _optional;
}
================================================
FILE: src/MediaConstraints.h
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef WEBRTC_MEDIACONSTRAINTS_H
#define WEBRTC_MEDIACONSTRAINTS_H
#include "Common.h"
namespace WebRTC {
class MediaConstraints : public webrtc::MediaConstraintsInterface, public rtc::RefCountInterface {
friend class rtc::RefCountedObject<MediaConstraints>;
public:
static rtc::scoped_refptr<MediaConstraints> New();
static rtc::scoped_refptr<MediaConstraints> New(const v8::Local<v8::Object> &constraints);
static rtc::scoped_refptr<MediaConstraints> New(const v8::Local<v8::Value> &constraints);
bool UseAudio() const;
bool UseVideo() const;
std::string AudioId() const;
std::string VideoId() const;
bool IsMandatory(const std::string& key);
bool GetMandatory(const std::string& key);
void RemoveMandatory(const std::string& key);
void AddMandatory(const std::string &key, const std::string &value);
void SetMandatory(const std::string &key, const std::string &value);
template <class T> void SetMandatory(const std::string& key, const T& value) {
SetMandatory(key, rtc::ToString<T>(value));
}
bool IsOptional(const std::string& key);
bool GetOptional(const std::string& key);
void RemoveOptional(const std::string& key);
void AddOptional(const std::string &key, const std::string &value);
void SetOptional(const std::string &key, const std::string &value);
template <class T> void SetOptional(const std::string& key, const T& value) {
SetOptional(key, rtc::ToString<T>(value));
}
const webrtc::MediaConstraintsInterface *ToConstraints() const;
const webrtc::MediaConstraintsInterface::Constraints &GetMandatory() const final;
const webrtc::MediaConstraintsInterface::Constraints &GetOptional() const final;
private:
explicit MediaConstraints();
~MediaConstraints() override;
void SetOptional(std::string key, v8::Local<v8::Value> value);
void SetMandatory(std::string key, v8::Local<v8::Value> value);
protected:
bool _audio;
bool _video;
std::string _audioId;
std::string _videoId;
webrtc::MediaConstraintsInterface::Constraints _mandatory;
webrtc::MediaConstraintsInterface::Constraints _optional;
};
};
#endif
================================================
FILE: src/MediaStream.cc
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "MediaStream.h"
#include "MediaStreamTrack.h"
using namespace v8;
using namespace WebRTC;
Nan::Persistent<Function> MediaStream::constructor;
void MediaStream::Init() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::HandleScope scope;
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(MediaStream::New);
tpl->InstanceTemplate()->SetInternalFieldCount(1);
tpl->SetClassName(Nan::New("MediaStream").ToLocalChecked());
Nan::SetPrototypeMethod(tpl, "addTrack", MediaStream::AddTrack);
Nan::SetPrototypeMethod(tpl, "removeTrack", MediaStream::RemoveTrack);
Nan::SetPrototypeMethod(tpl, "clone", MediaStream::Clone);
Nan::SetPrototypeMethod(tpl, "getAudioTracks", MediaStream::GetAudioTracks);
Nan::SetPrototypeMethod(tpl, "getTrackById", MediaStream::GetTrackById);
Nan::SetPrototypeMethod(tpl, "getVideoTracks", MediaStream::GetVideoTracks);
Nan::SetPrototypeMethod(tpl, "getTracks", MediaStream::GetTracks);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("active").ToLocalChecked(), MediaStream::GetActive);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("ended").ToLocalChecked(), MediaStream::GetEnded);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("id").ToLocalChecked(), MediaStream::GetId);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("onaddtrack").ToLocalChecked(), MediaStream::GetOnAddTrack, MediaStream::SetOnAddTrack);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("onremovetrack").ToLocalChecked(), MediaStream::GetOnRemoveTrack, MediaStream::SetOnRemoveTrack);
constructor.Reset(tpl->GetFunction());
}
Local<Value> MediaStream::New(rtc::scoped_refptr<webrtc::MediaStreamInterface> mediaStream) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::EscapableHandleScope scope;
Local<Value> empty;
Local<Function> instance = Nan::New(MediaStream::constructor);
if (instance.IsEmpty() || !mediaStream.get()) {
return scope.Escape(Nan::Null());
}
Local<Object> ret = instance->NewInstance();
MediaStream *self = RTCWrap::Unwrap<MediaStream>(ret, "MediaStream");
if (self) {
self->_stream = mediaStream;
self->_audio_tracks = self->_stream->GetAudioTracks();
self->_video_tracks = self->_stream->GetVideoTracks();
self->_stream->RegisterObserver(self->_observer.get());
self->CheckState();
return scope.Escape(ret);
}
return scope.Escape(Nan::Null());
}
MediaStream::MediaStream() :
_active(false),
_ended(true)
{
LOG(LS_INFO) << __PRETTY_FUNCTION__;
_observer = new rtc::RefCountedObject<MediaStreamObserver>(this);
}
MediaStream::~MediaStream() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (_stream.get()) {
_stream->UnregisterObserver(_observer.get());
}
_observer->RemoveListener(this);
}
void MediaStream::New(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::HandleScope scope;
if (info.IsConstructCall()) {
MediaStream* mediaStream = new MediaStream();
mediaStream->Wrap(info.This(), "MediaStream");
return info.GetReturnValue().Set(info.This());
}
Nan::ThrowError("Internal Error");
info.GetReturnValue().SetUndefined();
}
rtc::scoped_refptr<webrtc::MediaStreamInterface> MediaStream::Unwrap(Local<Object> value) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (!value.IsEmpty()) {
MediaStream *self = RTCWrap::Unwrap<MediaStream>(value, "MediaStream");
if (self) {
return self->_stream;
}
}
return 0;
}
rtc::scoped_refptr<webrtc::MediaStreamInterface> MediaStream::Unwrap(Local<Value> value) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (!value.IsEmpty() && value->IsObject()) {
Local<Object> stream = Local<Object>::Cast(value);
return MediaStream::Unwrap(stream);
}
return 0;
}
void MediaStream::AddTrack(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = MediaStream::Unwrap(info.This());
bool retval = false;
if (stream.get()) {
if (info.Length() >= 1 && info[0]->IsObject()) {
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track = MediaStreamTrack::Unwrap(info[0]);
if (track.get()) {
std::string kind = track->kind();
if (kind.compare("audio") == 0) {
rtc::scoped_refptr<webrtc::AudioTrackInterface> audio(static_cast<webrtc::AudioTrackInterface*>(track.get()));
retval = stream->AddTrack(audio);
} else {
rtc::scoped_refptr<webrtc::VideoTrackInterface> video(static_cast<webrtc::VideoTrackInterface*>(track.get()));
retval = stream->AddTrack(video);
}
}
}
} else {
Nan::ThrowError("Internal Error");
}
return info.GetReturnValue().Set(Nan::New(retval));
}
void MediaStream::RemoveTrack(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = MediaStream::Unwrap(info.This());
bool retval = false;
if (stream.get()) {
if (info.Length() >= 1 && info[0]->IsObject()) {
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track = MediaStreamTrack::Unwrap(info[0]);
if (track.get()) {
std::string kind = track->kind();
if (kind.compare("audio") == 0) {
rtc::scoped_refptr<webrtc::AudioTrackInterface> audio(static_cast<webrtc::AudioTrackInterface*>(track.get()));
retval = stream->RemoveTrack(audio);
} else {
rtc::scoped_refptr<webrtc::VideoTrackInterface> video(static_cast<webrtc::VideoTrackInterface*>(track.get()));
retval = stream->RemoveTrack(video);
}
}
}
} else {
Nan::ThrowError("Internal Error");
}
return info.GetReturnValue().Set(Nan::New(retval));
}
void MediaStream::Clone(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
rtc::scoped_refptr<webrtc::MediaStreamInterface> self = MediaStream::Unwrap(info.This());
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory = webrtc::CreatePeerConnectionFactory();
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream;
if (self.get() && factory.get()) {
stream = factory->CreateLocalMediaStream("stream");
if (stream.get()) {
webrtc::AudioTrackVector audio_list = self->GetAudioTracks();
std::vector<rtc::scoped_refptr<webrtc::AudioTrackInterface> >::iterator audio_it;
for (audio_it = audio_list.begin(); audio_it != audio_list.end(); audio_it++) {
rtc::scoped_refptr<webrtc::AudioTrackInterface> track(*audio_it);
if (track.get()) {
stream->AddTrack(track.get());
}
}
webrtc::VideoTrackVector video_list = self->GetVideoTracks();
std::vector<rtc::scoped_refptr<webrtc::VideoTrackInterface> >::iterator video_it;
for (video_it = video_list.begin(); video_it != video_list.end(); video_it++) {
rtc::scoped_refptr<webrtc::VideoTrackInterface> track(*video_it);
if (track.get()) {
stream->AddTrack(track.get());
}
}
return info.GetReturnValue().Set(MediaStream::New(stream));
}
}
Nan::ThrowError("Internal Error");
info.GetReturnValue().SetUndefined();
}
void MediaStream::GetTrackById(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = MediaStream::Unwrap(info.This());
if (stream.get()) {
if (info.Length() >= 1 && info[0]->IsString()) {
v8::String::Utf8Value idValue(info[0]->ToString());
std::string id(*idValue);
rtc::scoped_refptr<webrtc::AudioTrackInterface> audio = stream->FindAudioTrack(id);
if (audio.get()) {
return info.GetReturnValue().Set(MediaStreamTrack::New(audio.get()));
}
rtc::scoped_refptr<webrtc::VideoTrackInterface> video = stream->FindVideoTrack(id);
if (video.get()) {
return info.GetReturnValue().Set(MediaStreamTrack::New(video.get()));
}
}
return info.GetReturnValue().Set(Nan::Null());
} else {
Nan::ThrowError("Internal Error");
}
info.GetReturnValue().SetUndefined();
}
void MediaStream::GetAudioTracks(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
rtc::scoped_refptr<webrtc::MediaStreamInterface> self = MediaStream::Unwrap(info.This());
if (self.get()) {
webrtc::AudioTrackVector audio_list = self->GetAudioTracks();
std::vector<rtc::scoped_refptr<webrtc::AudioTrackInterface> >::iterator audio_it;
Local<Array> list = Nan::New<Array>();
uint32_t index = 0;
for (audio_it = audio_list.begin(); audio_it != audio_list.end(); audio_it++) {
rtc::scoped_refptr<webrtc::AudioTrackInterface> track(*audio_it);
if (track.get()) {
list->Set(index, MediaStreamTrack::New(track.get()));
index++;
}
}
return info.GetReturnValue().Set(list);
} else {
Nan::ThrowError("Internal Error");
}
info.GetReturnValue().SetUndefined();
}
void MediaStream::GetVideoTracks(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
rtc::scoped_refptr<webrtc::MediaStreamInterface> self = MediaStream::Unwrap(info.This());
if (self.get()) {
webrtc::VideoTrackVector video_list = self->GetVideoTracks();
std::vector<rtc::scoped_refptr<webrtc::VideoTrackInterface> >::iterator video_it;
Local<Array> list = Nan::New<Array>();
uint32_t index = 0;
for (video_it = video_list.begin(); video_it != video_list.end(); video_it++) {
rtc::scoped_refptr<webrtc::VideoTrackInterface> track(*video_it);
if (track.get()) {
list->Set(index, MediaStreamTrack::New(track.get()));
index++;
}
}
return info.GetReturnValue().Set(list);
} else {
Nan::ThrowError("Internal Error");
}
info.GetReturnValue().SetUndefined();
}
void MediaStream::GetTracks(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
rtc::scoped_refptr<webrtc::MediaStreamInterface> self = MediaStream::Unwrap(info.This());
if (self.get()) {
webrtc::AudioTrackVector audio_list = self->GetAudioTracks();
webrtc::VideoTrackVector video_list = self->GetVideoTracks();
std::vector<rtc::scoped_refptr<webrtc::AudioTrackInterface> >::iterator audio_it;
std::vector<rtc::scoped_refptr<webrtc::VideoTrackInterface> >::iterator video_it;
Local<Array> list = Nan::New<Array>();
uint32_t index = 0;
for (audio_it = audio_list.begin(); audio_it != audio_list.end(); audio_it++) {
rtc::scoped_refptr<webrtc::AudioTrackInterface> track(*audio_it);
if (track.get()) {
list->Set(index, MediaStreamTrack::New(track.get()));
index++;
}
}
for (video_it = video_list.begin(); video_it != video_list.end(); video_it++) {
rtc::scoped_refptr<webrtc::VideoTrackInterface> track(*video_it);
if (track.get()) {
list->Set(index, MediaStreamTrack::New(track.get()));
index++;
}
}
return info.GetReturnValue().Set(list);
} else {
Nan::ThrowError("Internal Error");
}
info.GetReturnValue().SetUndefined();
}
void MediaStream::GetActive(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStream *self = RTCWrap::Unwrap<MediaStream>(info.Holder(), "MediaStream");
return info.GetReturnValue().Set(Nan::New(self->_active));
}
void MediaStream::GetEnded(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStream *self = RTCWrap::Unwrap<MediaStream>(info.Holder(), "MediaStream");
return info.GetReturnValue().Set(Nan::New(self->_ended));
}
void MediaStream::GetId(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = MediaStream::Unwrap(info.Holder());
if (stream.get()) {
return info.GetReturnValue().Set(Nan::New(stream->label().c_str()).ToLocalChecked());
} else {
Nan::ThrowError("Internal Error");
}
info.GetReturnValue().SetUndefined();
}
void MediaStream::GetOnAddTrack(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStream *self = RTCWrap::Unwrap<MediaStream>(info.Holder(), "MediaStream");
return info.GetReturnValue().Set(Nan::New<Function>(self->_onaddtrack));
}
void MediaStream::GetOnRemoveTrack(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStream *self = RTCWrap::Unwrap<MediaStream>(info.Holder(), "MediaStream");
return info.GetReturnValue().Set(Nan::New<Function>(self->_onremovetrack));
}
void MediaStream::ReadOnly(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
}
void MediaStream::SetOnAddTrack(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStream *self = RTCWrap::Unwrap<MediaStream>(info.Holder(), "MediaStream");
if (!value.IsEmpty() && value->IsFunction()) {
self->_onaddtrack.Reset<Function>(Local<Function>::Cast(value));
} else {
self->_onaddtrack.Reset();
}
}
void MediaStream::SetOnRemoveTrack(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStream *self = RTCWrap::Unwrap<MediaStream>(info.Holder(), "MediaStream");
if (!value.IsEmpty() && value->IsFunction()) {
self->_onremovetrack.Reset<Function>(Local<Function>::Cast(value));
} else {
self->_onremovetrack.Reset();
}
}
void MediaStream::CheckState() {
_active = false;
_ended = true;
webrtc::AudioTrackVector new_audio_tracks = _stream->GetAudioTracks();
webrtc::VideoTrackVector new_video_tracks = _stream->GetVideoTracks();
for (const auto& cached_track : _audio_tracks) {
auto it = std::find_if(
new_audio_tracks.begin(), new_audio_tracks.end(),
[cached_track](const webrtc::AudioTrackVector::value_type& new_track) {
return new_track->id().compare(cached_track->id()) == 0;
});
if (it == new_audio_tracks.end()) {
Local<Function> callback = Nan::New<Function>(_onremovetrack);
Local<Value> argv[] = {
MediaStreamTrack::New(cached_track.get())
};
if (!callback.IsEmpty() && callback->IsFunction()) {
callback->Call(RTCWrap::This(), 1, argv);
}
}
}
for (const auto& new_track : new_audio_tracks) {
if (new_track->state() == webrtc::MediaStreamTrackInterface::kLive) {
_active = true;
_ended = false;
}
auto it = std::find_if(
_audio_tracks.begin(), _audio_tracks.end(),
[new_track](const webrtc::AudioTrackVector::value_type& cached_track) {
return new_track->id().compare(cached_track->id()) == 0;
});
if (it == _audio_tracks.end()) {
Local<Function> callback = Nan::New<Function>(_onaddtrack);
Local<Value> argv[] = {
MediaStreamTrack::New(new_track.get())
};
if (!callback.IsEmpty() && callback->IsFunction()) {
callback->Call(RTCWrap::This(), 1, argv);
}
}
}
for (const auto& cached_track : _video_tracks) {
auto it = std::find_if(
new_video_tracks.begin(), new_video_tracks.end(),
[cached_track](const webrtc::VideoTrackVector::value_type& new_track) {
return new_track->id().compare(cached_track->id()) == 0;
});
if (it == new_video_tracks.end()) {
Local<Function> callback = Nan::New<Function>(_onremovetrack);
Local<Value> argv[] = {
MediaStreamTrack::New(cached_track.get())
};
if (!callback.IsEmpty() && callback->IsFunction()) {
callback->Call(RTCWrap::This(), 1, argv);
}
}
}
for (const auto& new_track : new_video_tracks) {
if (new_track->state() == webrtc::MediaStreamTrackInterface::kLive) {
_active = true;
_ended = false;
}
auto it = std::find_if(
_video_tracks.begin(), _video_tracks.end(),
[new_track](const webrtc::VideoTrackVector::value_type& cached_track) {
return new_track->id().compare(cached_track->id()) == 0;
});
if (it == _video_tracks.end()) {
Local<Function> callback = Nan::New<Function>(_onaddtrack);
Local<Value> argv[] = {
MediaStreamTrack::New(new_track.get())
};
if (!callback.IsEmpty() && callback->IsFunction()) {
callback->Call(RTCWrap::This(), 1, argv);
}
}
}
_audio_tracks = new_audio_tracks;
_video_tracks = new_video_tracks;
}
void MediaStream::On(Event *event) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::HandleScope scope;
MediaStreamEvent type = event->Type<MediaStreamEvent>();
if (type != kMediaStreamChanged) {
Nan::ThrowError("Internal Error");
return;
}
MediaStream::CheckState();
}
================================================
FILE: src/MediaStream.h
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef WEBRTC_MEDIASTREAM_H
#define WEBRTC_MEDIASTREAM_H
#include "Common.h"
#include "Observers.h"
#include "EventEmitter.h"
#include "Wrap.h"
namespace WebRTC {
enum MediaStreamEvent {
kMediaStreamChanged
};
class MediaStream : public RTCWrap, public EventEmitter {
public:
static void Init();
static v8::Local<v8::Value> New(rtc::scoped_refptr<webrtc::MediaStreamInterface> mediaStream);
static rtc::scoped_refptr<webrtc::MediaStreamInterface> Unwrap(v8::Local<v8::Object> value);
static rtc::scoped_refptr<webrtc::MediaStreamInterface> Unwrap(v8::Local<v8::Value> value);
private:
MediaStream();
~MediaStream() final;
static void New(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void AddTrack(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void Clone(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void GetTrackById(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void GetAudioTracks(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void GetVideoTracks(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void GetTracks(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void RemoveTrack(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void GetActive(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetEnded(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetId(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetOnAddTrack(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetOnRemoveTrack(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void ReadOnly(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
static void SetOnAddTrack(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
static void SetOnRemoveTrack(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
void CheckState();
void On(Event *event) final;
protected:
bool _active;
bool _ended;
Nan::Persistent<v8::Function> _onaddtrack;
Nan::Persistent<v8::Function> _onremovetrack;
rtc::scoped_refptr<MediaStreamObserver> _observer;
rtc::scoped_refptr<webrtc::MediaStreamInterface> _stream;
webrtc::AudioTrackVector _audio_tracks;
webrtc::VideoTrackVector _video_tracks;
static Nan::Persistent<v8::Function> constructor;
};
};
#endif
================================================
FILE: src/MediaStreamTrack.cc
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "MediaStreamTrack.h"
using namespace v8;
using namespace WebRTC;
Nan::Persistent<Function> MediaStreamTrack::constructor;
void MediaStreamTrack::Init() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::HandleScope scope;
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(MediaStreamTrack::New);
tpl->InstanceTemplate()->SetInternalFieldCount(1);
tpl->SetClassName(Nan::New("MediaStreamTrack").ToLocalChecked());
Nan::SetPrototypeMethod(tpl, "getConstraints", MediaStreamTrack::GetConstraints);
Nan::SetPrototypeMethod(tpl, "applyConstraints", MediaStreamTrack::ApplyConstraints);
Nan::SetPrototypeMethod(tpl, "setSettings", MediaStreamTrack::GetSettings);
Nan::SetPrototypeMethod(tpl, "getCapabilities", MediaStreamTrack::GetCapabilities);
Nan::SetPrototypeMethod(tpl, "clone", MediaStreamTrack::Clone);
Nan::SetPrototypeMethod(tpl, "stop", MediaStreamTrack::Stop);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("enabled").ToLocalChecked(), MediaStreamTrack::GetEnabled, MediaStreamTrack::SetEnabled);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("id").ToLocalChecked(), MediaStreamTrack::GetId);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("kind").ToLocalChecked(), MediaStreamTrack::GetKind);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("label").ToLocalChecked(), MediaStreamTrack::GetLabel);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("muted").ToLocalChecked(), MediaStreamTrack::GetMuted);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("readonly").ToLocalChecked(), MediaStreamTrack::GetReadOnly);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("readyState").ToLocalChecked(), MediaStreamTrack::GetReadyState);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("remote").ToLocalChecked(), MediaStreamTrack::GetRemote);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("onstarted").ToLocalChecked(), MediaStreamTrack::GetOnStarted, MediaStreamTrack::SetOnStarted);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("onmute").ToLocalChecked(), MediaStreamTrack::GetOnMute, MediaStreamTrack::SetOnMute);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("onunmute").ToLocalChecked(), MediaStreamTrack::GetOnUnMute, MediaStreamTrack::SetOnUnMute);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("onoverconstrained").ToLocalChecked(), MediaStreamTrack::GetOnOverConstrained, MediaStreamTrack::SetOnOverConstrained);
Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("onended").ToLocalChecked(), MediaStreamTrack::GetOnEnded, MediaStreamTrack::SetOnEnded);
constructor.Reset<Function>(tpl->GetFunction());
}
Local<Value> MediaStreamTrack::New(rtc::scoped_refptr<webrtc::AudioTrackInterface> audioTrack) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::EscapableHandleScope scope;
Local<Value> argv[1];
Local<Function> instance = Nan::New(MediaStreamTrack::constructor);
if (instance.IsEmpty() || !audioTrack.get()) {
return scope.Escape(Nan::Null());
}
Local<Object> ret = instance->NewInstance(0, argv);
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(ret, "MediaStreamTrack");
self->isAudioTrack = true;
self->_track = audioTrack;
self->_source = audioTrack->GetSource();
self->_track_state = self->_track->state();
self->_source_state = self->_source->state();
self->_track->RegisterObserver(self->_observer.get());
self->_source->RegisterObserver(self->_observer.get());
self->CheckState();
return scope.Escape(ret);
}
Local<Value> MediaStreamTrack::New(rtc::scoped_refptr<webrtc::VideoTrackInterface> videoTrack) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::EscapableHandleScope scope;
Local<Value> argv[1];
Local<Function> instance = Nan::New(MediaStreamTrack::constructor);
if (instance.IsEmpty() || !videoTrack.get()) {
return scope.Escape(Nan::Null());
}
Local<Object> ret = instance->NewInstance(0, argv);
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(ret, "MediaStreamTrack");
self->isVideoTrack = true;
self->_track = videoTrack;
self->_source = videoTrack->GetSource();
self->_track_state = self->_track->state();
self->_source_state = self->_source->state();
self->_track->RegisterObserver(self->_observer.get());
self->_source->RegisterObserver(self->_observer.get());
self->CheckState();
return scope.Escape(ret);
}
MediaStreamTrack::MediaStreamTrack() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
_observer = new rtc::RefCountedObject<MediaStreamTrackObserver>(this);
}
MediaStreamTrack::~MediaStreamTrack() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (_track.get()) {
_track->UnregisterObserver(_observer.get());
}
if (_source.get()) {
_source->UnregisterObserver(_observer.get());
}
_observer->RemoveListener(this);
}
void MediaStreamTrack::New(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::HandleScope scope;
if (info.IsConstructCall()) {
MediaStreamTrack* mediaStreamTrack = new MediaStreamTrack();
mediaStreamTrack->Wrap(info.This(), "MediaStreamTrack");
return info.GetReturnValue().Set(info.This());
}
Nan::ThrowError("Internal Error");
info.GetReturnValue().SetUndefined();
}
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> MediaStreamTrack::Unwrap(Local<Object> value) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (!value.IsEmpty()) {
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(value, "MediaStreamTrack");
if (self) {
return self->_track;
}
}
return 0;
}
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> MediaStreamTrack::Unwrap(Local<Value> value) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (!value.IsEmpty() && value->IsObject()) {
Local<Object> track = Local<Object>::Cast(value);
return MediaStreamTrack::Unwrap(track);
}
return 0;
}
void MediaStreamTrack::GetConstraints(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
//MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.This(), "MediaStreamTrack");
info.GetReturnValue().SetUndefined();
}
void MediaStreamTrack::ApplyConstraints(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
//MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.This(), "MediaStreamTrack");
info.GetReturnValue().SetUndefined();
}
void MediaStreamTrack::GetSettings(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
//MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.This(), "MediaStreamTrack");
info.GetReturnValue().SetUndefined();
}
void MediaStreamTrack::GetCapabilities(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
//MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.This(), "MediaStreamTrack");
info.GetReturnValue().SetUndefined();
}
void MediaStreamTrack::Clone(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
//MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.This(), "MediaStreamTrack");
info.GetReturnValue().SetUndefined();
}
void MediaStreamTrack::Stop(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.This(), "MediaStreamTrack");
info.GetReturnValue().Set(Nan::New(self->_track->set_state(webrtc::MediaStreamTrackInterface::kEnded)));
}
void MediaStreamTrack::GetEnabled(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.This(), "MediaStreamTrack");
info.GetReturnValue().Set(Nan::New(self->_track->enabled()));
}
void MediaStreamTrack::GetId(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
info.GetReturnValue().Set(Nan::New(self->_track->id().c_str()).ToLocalChecked());
}
void MediaStreamTrack::GetKind(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
info.GetReturnValue().Set(Nan::New(self->_track->kind().c_str()).ToLocalChecked());
}
void MediaStreamTrack::GetLabel(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
info.GetReturnValue().Set(Nan::New("").ToLocalChecked());
}
void MediaStreamTrack::GetMuted(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
info.GetReturnValue().Set(Nan::New((self->_source->state() == webrtc::MediaSourceInterface::kMuted) ? true : false));
}
void MediaStreamTrack::GetReadOnly(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
return info.GetReturnValue().Set(Nan::New(true));
}
void MediaStreamTrack::GetReadyState(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
if (self->_track->state() == webrtc::MediaStreamTrackInterface::kLive) {
return info.GetReturnValue().Set(Nan::New("live").ToLocalChecked());
}
info.GetReturnValue().Set(Nan::New("ended").ToLocalChecked());
}
void MediaStreamTrack::GetRemote(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
info.GetReturnValue().Set(Nan::New(self->_source->remote()));
}
void MediaStreamTrack::GetOnStarted(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
return info.GetReturnValue().Set(Nan::New<Function>(self->_onstarted));
}
void MediaStreamTrack::GetOnMute(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
return info.GetReturnValue().Set(Nan::New<Function>(self->_onmute));
}
void MediaStreamTrack::GetOnUnMute(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
return info.GetReturnValue().Set(Nan::New<Function>(self->_onunmute));
}
void MediaStreamTrack::GetOnOverConstrained(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
return info.GetReturnValue().Set(Nan::New<Function>(self->_onoverconstrained));
}
void MediaStreamTrack::GetOnEnded(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
return info.GetReturnValue().Set(Nan::New<Function>(self->_onended));
}
void MediaStreamTrack::ReadOnly(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
//MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
// TODO(): Implement This
}
void MediaStreamTrack::SetEnabled(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
if (!value.IsEmpty() && value->IsBoolean()) {
self->_track->set_enabled(value->IsTrue() ? true : false);
}
}
void MediaStreamTrack::SetOnStarted(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
if (!value.IsEmpty() && value->IsFunction()) {
self->_onstarted.Reset<Function>(Local<Function>::Cast(value));
} else {
self->_onstarted.Reset();
}
}
void MediaStreamTrack::SetOnMute(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
if (!value.IsEmpty() && value->IsFunction()) {
self->_onmute.Reset<Function>(Local<Function>::Cast(value));
} else {
self->_onmute.Reset();
}
}
void MediaStreamTrack::SetOnUnMute(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
if (!value.IsEmpty() && value->IsFunction()) {
self->_onunmute.Reset<Function>(Local<Function>::Cast(value));
} else {
self->_onunmute.Reset();
}
}
void MediaStreamTrack::SetOnOverConstrained(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
if (!value.IsEmpty() && value->IsFunction()) {
self->_onoverconstrained.Reset<Function>(Local<Function>::Cast(value));
} else {
self->_onoverconstrained.Reset();
}
}
void MediaStreamTrack::SetOnEnded(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), "MediaStreamTrack");
if (!value.IsEmpty() && value->IsFunction()) {
self->_onended.Reset<Function>(Local<Function>::Cast(value));
} else {
self->_onended.Reset();
}
}
void MediaStreamTrack::CheckState() {
webrtc::MediaStreamTrackInterface::TrackState new_state = _track->state();
webrtc::MediaSourceInterface::SourceState new_source = _source->state();
if (_track_state != new_state) {
if (new_state == webrtc::MediaStreamTrackInterface::kEnded || new_state == webrtc::MediaStreamTrackInterface::kFailed) {
Local<Function> callback = Nan::New<Function>(_onended);
Local<Value> argv[1];
if (!callback.IsEmpty() && callback->IsFunction()) {
callback->Call(RTCWrap::This(), 0, argv);
}
} else if (_track_state == webrtc::MediaStreamTrackInterface::kInitializing && new_state == webrtc::MediaStreamTrackInterface::kLive) {
Local<Function> callback = Nan::New<Function>(_onstarted);
Local<Value> argv[1];
if (!callback.IsEmpty() && callback->IsFunction()) {
callback->Call(RTCWrap::This(), 0, argv);
}
}
}
if (_source_state != new_source) {
if (new_source == webrtc::MediaSourceInterface::kMuted) {
Local<Function> callback = Nan::New<Function>(_onmute);
Local<Value> argv[1];
if (!callback.IsEmpty() && callback->IsFunction()) {
callback->Call(RTCWrap::This(), 0, argv);
}
} else {
Local<Function> callback = Nan::New<Function>(_onunmute);
Local<Value> argv[1];
if (!callback.IsEmpty() && callback->IsFunction()) {
callback->Call(RTCWrap::This(), 0, argv);
}
}
}
_source_state = new_source;
_track_state = new_state;
}
void MediaStreamTrack::On(Event *event) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::HandleScope scope;
MediaStreamTrackEvent type = event->Type<MediaStreamTrackEvent>();
if (type != kMediaStreamTrackChanged) {
return;
}
MediaStreamTrack::CheckState();
}
================================================
FILE: src/MediaStreamTrack.h
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef WEBRTC_MEDIASTREAMTRACK_H
#define WEBRTC_MEDIASTREAMTRACK_H
#include "Common.h"
#include "Observers.h"
#include "EventEmitter.h"
#include "Wrap.h"
namespace WebRTC {
enum MediaStreamTrackEvent {
kMediaStreamTrackChanged
};
class MediaStreamTrack : public RTCWrap, public EventEmitter {
public:
static void Init();
static v8::Local<v8::Value> New(rtc::scoped_refptr<webrtc::AudioTrackInterface> audioTrack);
static v8::Local<v8::Value> New(rtc::scoped_refptr<webrtc::VideoTrackInterface> videoTrack);
static rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> Unwrap(v8::Local<v8::Object> value);
static rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> Unwrap(v8::Local<v8::Value> value);
private:
MediaStreamTrack();
~MediaStreamTrack() final;
static void New(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void GetConstraints(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void ApplyConstraints(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void GetSettings(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void GetCapabilities(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void Clone(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void Stop(const Nan::FunctionCallbackInfo<v8::Value> &info);
static void GetEnabled(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetId(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetKind(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetLabel(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetMuted(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetReadOnly(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetReadyState(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetRemote(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetOnStarted(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetOnMute(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetOnUnMute(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetOnOverConstrained(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void GetOnEnded(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);
static void ReadOnly(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
static void SetEnabled(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
static void SetOnStarted(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
static void SetOnMute(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
static void SetOnUnMute(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
static void SetOnOverConstrained(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
static void SetOnEnded(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);
void CheckState();
void On(Event *event) final;
protected:
bool isAudioTrack;
bool isVideoTrack;
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> _track;
rtc::scoped_refptr<webrtc::MediaSourceInterface> _source;
rtc::scoped_refptr<MediaStreamTrackObserver> _observer;
webrtc::MediaStreamTrackInterface::TrackState _track_state;
webrtc::MediaSourceInterface::SourceState _source_state;
Nan::Persistent<v8::Function> _onstarted;
Nan::Persistent<v8::Function> _onmute;
Nan::Persistent<v8::Function> _onunmute;
Nan::Persistent<v8::Function> _onoverconstrained;
Nan::Persistent<v8::Function> _onended;
static Nan::Persistent<v8::Function> constructor;
};
};
#endif
================================================
FILE: src/Module.cc
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "Common.h"
#include "Global.h"
#include "Platform.h"
#include "Stats.h"
#include "PeerConnection.h"
#include "DataChannel.h"
#include "BackTrace.h"
#include "GetSources.h"
#include "GetUserMedia.h"
#include "MediaStream.h"
#include "MediaStreamTrack.h"
using namespace v8;
void SetDebug(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (info.Length() && !info[0].IsEmpty()) {
if (info[0]->IsTrue()) {
rtc::LogMessage::LogToDebug(rtc::LS_VERBOSE);
} else {
rtc::LogMessage::LogToDebug(rtc::LS_NONE);
}
}
info.GetReturnValue().SetUndefined();
}
void RTCGarbageCollect(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::LowMemoryNotification();
info.GetReturnValue().SetUndefined();
}
void RTCIceCandidate(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (info.Length() == 1 && info[0]->IsObject() && info.IsConstructCall()) {
Local<Object> arg = info[0]->ToObject();
Local<Object> retval = Nan::New<Object>();
retval->Set(Nan::New("candidate").ToLocalChecked(), arg->Get(Nan::New("candidate").ToLocalChecked()));
retval->Set(Nan::New("sdpMLineIndex").ToLocalChecked(), arg->Get(Nan::New("sdpMLineIndex").ToLocalChecked()));
retval->Set(Nan::New("sdpMid").ToLocalChecked(), arg->Get(Nan::New("sdpMid").ToLocalChecked()));
return info.GetReturnValue().Set(retval);
} else {
return info.GetReturnValue().Set(info[0]);
}
}
void RTCSessionDescription(const Nan::FunctionCallbackInfo<Value> &info) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (info.Length() == 1 && info[0]->IsObject() && info.IsConstructCall()) {
Local<Object> arg = info[0]->ToObject();
Local<Object> retval = Nan::New<Object>();
retval->Set(Nan::New("type").ToLocalChecked(), arg->Get(Nan::New("type").ToLocalChecked()));
retval->Set(Nan::New("sdp").ToLocalChecked(), arg->Get(Nan::New("sdp").ToLocalChecked()));
return info.GetReturnValue().Set(retval);
} else {
return info.GetReturnValue().Set(info[0]);
}
}
void WebrtcModuleDispose(void *arg) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
WebRTC::Platform::Dispose();
}
void WebrtcModuleInit(Handle<Object> exports) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Nan::HandleScope scope;
WebRTC::Global::Init(exports);
WebRTC::Platform::Init();
WebRTC::RTCStatsResponse::Init();
WebRTC::RTCStatsReport::Init();
WebRTC::PeerConnection::Init(exports);
WebRTC::DataChannel::Init();
WebRTC::GetSources::Init(exports);
WebRTC::GetUserMedia::Init(exports);
WebRTC::MediaStream::Init();
WebRTC::MediaStreamTrack::Init();
exports->Set(Nan::New("RTCGarbageCollect").ToLocalChecked(), Nan::New<FunctionTemplate>(RTCGarbageCollect)->GetFunction());
exports->Set(Nan::New("RTCIceCandidate").ToLocalChecked(), Nan::New<FunctionTemplate>(RTCIceCandidate)->GetFunction());
exports->Set(Nan::New("RTCSessionDescription").ToLocalChecked(), Nan::New<FunctionTemplate>(RTCSessionDescription)->GetFunction());
exports->Set(Nan::New("setDebug").ToLocalChecked(), Nan::New<FunctionTemplate>(SetDebug)->GetFunction());
node::AtExit(WebrtcModuleDispose);
}
NODE_MODULE(webrtc, WebrtcModuleInit)
================================================
FILE: src/Observers.cc
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "Observers.h"
#include "PeerConnection.h"
#include "DataChannel.h"
#include "MediaStream.h"
#include "MediaStreamTrack.h"
using namespace WebRTC;
OfferObserver::OfferObserver(EventEmitter *listener) :
NotifyEmitter(listener) { }
void OfferObserver::OnSuccess(webrtc::SessionDescriptionInterface* desc) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Json::StyledWriter writer;
Json::Value msg;
std::string sdp;
if (desc->ToString(&sdp)) {
msg["type"] = desc->type();
msg["sdp"] = sdp;
Emit(kPeerConnectionCreateOffer, writer.write(msg));
}
}
void OfferObserver::OnFailure(const std::string &error) {
LOG(LS_ERROR) << __PRETTY_FUNCTION__;
Emit(kPeerConnectionCreateOfferError, error);
}
AnswerObserver::AnswerObserver(EventEmitter *listener) :
NotifyEmitter(listener) { }
void AnswerObserver::OnSuccess(webrtc::SessionDescriptionInterface* desc) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Json::StyledWriter writer;
Json::Value msg;
std::string sdp;
if (desc->ToString(&sdp)) {
msg["type"] = desc->type();
msg["sdp"] = sdp;
Emit(kPeerConnectionCreateAnswer, writer.write(msg));
}
}
void AnswerObserver::OnFailure(const std::string &error) {
LOG(LS_ERROR) << __PRETTY_FUNCTION__;
Emit(kPeerConnectionCreateAnswerError, error);
}
LocalDescriptionObserver::LocalDescriptionObserver(EventEmitter *listener) :
NotifyEmitter(listener) { }
void LocalDescriptionObserver::OnSuccess() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Emit(kPeerConnectionSetLocalDescription);
}
void LocalDescriptionObserver::OnFailure(const std::string &error) {
LOG(LS_ERROR) << __PRETTY_FUNCTION__;
Emit(kPeerConnectionSetLocalDescriptionError, error);
}
RemoteDescriptionObserver::RemoteDescriptionObserver(EventEmitter *listener) :
NotifyEmitter(listener) { }
void RemoteDescriptionObserver::OnSuccess() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Emit(kPeerConnectionSetRemoteDescription);
}
void RemoteDescriptionObserver::OnFailure(const std::string &error) {
LOG(LS_ERROR) << __PRETTY_FUNCTION__;
Emit(kPeerConnectionSetRemoteDescriptionError, error);
}
PeerConnectionObserver::PeerConnectionObserver(EventEmitter *listener) :
NotifyEmitter(listener) { }
void PeerConnectionObserver::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState state) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Emit(kPeerConnectionSignalChange);
if (state == webrtc::PeerConnectionInterface::kClosed) {
Emit(kPeerConnectionCreateClosed);
}
}
void PeerConnectionObserver::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState state) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Emit(kPeerConnectionIceChange);
}
void PeerConnectionObserver::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState state) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Emit(kPeerConnectionIceGathering);
if (state == webrtc::PeerConnectionInterface::kIceGatheringComplete) {
Emit(kPeerConnectionIceCandidate, std::string());
}
}
void PeerConnectionObserver::OnStateChange(webrtc::PeerConnectionObserver::StateType state) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
}
void PeerConnectionObserver::OnDataChannel(webrtc::DataChannelInterface *channel) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel = channel;
if (dataChannel.get()) {
Emit(kPeerConnectionDataChannel, dataChannel);
}
}
void PeerConnectionObserver::OnAddStream(webrtc::MediaStreamInterface *stream) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
rtc::scoped_refptr<webrtc::MediaStreamInterface> mediaStream = stream;
if (mediaStream.get()) {
Emit(kPeerConnectionAddStream, mediaStream);
}
}
void PeerConnectionObserver::OnRemoveStream(webrtc::MediaStreamInterface *stream) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
rtc::scoped_refptr<webrtc::MediaStreamInterface> mediaStream = stream;
if (mediaStream.get()) {
Emit(kPeerConnectionRemoveStream, mediaStream);
}
}
void PeerConnectionObserver::OnRenegotiationNeeded() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Emit(kPeerConnectionRenegotiation);
}
void PeerConnectionObserver::OnIceCandidate(const webrtc::IceCandidateInterface* candidate) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Json::StyledWriter writer;
Json::Value msg;
std::string sdp;
if (candidate->ToString(&sdp)) {
msg["sdpMid"] = candidate->sdp_mid();
msg["sdpMLineIndex"] = candidate->sdp_mline_index();
msg["candidate"] = sdp;
Emit(kPeerConnectionIceCandidate, writer.write(msg));
}
}
DataChannelObserver::DataChannelObserver(EventEmitter *listener) :
NotifyEmitter(listener) { }
void DataChannelObserver::OnStateChange() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Emit(kDataChannelStateChange);
}
void DataChannelObserver::OnMessage(const webrtc::DataBuffer& buffer) {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
if (buffer.binary) {
Emit(kDataChannelBinary, buffer.data);
} else {
Emit(kDataChannelData, buffer.data);
}
}
MediaStreamObserver::MediaStreamObserver(EventEmitter *listener) :
NotifyEmitter(listener) { }
void MediaStreamObserver::OnChanged() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Emit(kMediaStreamChanged);
}
MediaStreamTrackObserver::MediaStreamTrackObserver(EventEmitter *listener) :
NotifyEmitter(listener) { }
void MediaStreamTrackObserver::OnChanged() {
LOG(LS_INFO) << __PRETTY_FUNCTION__;
Emit(kMediaStreamTrackChanged);
}
StatsObserver::StatsObserver(EventEmitter *listener) :
NotifyEmitter(listener) { }
void StatsObserver::OnComplete(const webrtc::StatsReports &reports) {
LOG(LS_INFO) << "StatsObserver::OnComplete()";
Emit(kPeerConnectionStats, reports);
}
================================================
FILE: src/Observers.h
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef WEBRTC_OBSERVERS_H
#define WEBRTC_OBSERVERS_H
#include "EventEmitter.h"
namespace WebRTC {
class OfferObserver : public webrtc::CreateSessionDescriptionObserver, public NotifyEmitter {
public:
OfferObserver(EventEmitter *listener = 0);
void OnSuccess(webrtc::SessionDescriptionInterface* sdp) final;
void OnFailure(const std::string &error) final;
};
class AnswerObserver : public webrtc::CreateSessionDescriptionObserver, public NotifyEmitter {
public:
AnswerObserver(EventEmitter *listener = 0);
void OnSuccess(webrtc::SessionDescriptionInterface* sdp) final;
void OnFailure(const std::string &error) final;
};
class LocalDescriptionObserver : public webrtc::SetSessionDescriptionObserver, public NotifyEmitter {
public:
LocalDescriptionObserver(EventEmitter *listener = 0);
void OnSuccess() final;
void OnFailure(const std::string &error) final;
};
class RemoteDescriptionObserver : public webrtc::SetSessionDescriptionObserver, public NotifyEmitter {
public:
RemoteDescriptionObserver(EventEmitter *listener = 0);
void OnSuccess() final;
void OnFailure(const std::string &error) final;
};
class PeerConnectionObserver :
public webrtc::PeerConnectionObserver,
public rtc::RefCountInterface,
public NotifyEmitter
{
public:
PeerConnectionObserver(EventEmitter *listener = 0);
void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState state) final;
void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState state) final;
void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState state) final;
void OnStateChange(webrtc::PeerConnectionObserver::StateType state);
void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) final;
void OnDataChannel(webrtc::DataChannelInterface* channel) final;
void OnRenegotiationNeeded() final;
void OnAddStream(webrtc::MediaStreamInterface* stream) final;
void OnRemoveStream(webrtc::MediaStreamInterface* stream) final;
};
class DataChannelObserver :
public webrtc::DataChannelObserver,
public rtc::RefCountInterface,
public NotifyEmitter
{
public:
DataChannelObserver(EventEmitter *listener = 0);
void OnStateChange() final;
void OnMessage(const webrtc::DataBuffer& buffer) final;
};
class MediaStreamObserver :
public webrtc::ObserverInterface,
public rtc::RefCountInterface,
public NotifyEmitter
{
public:
MediaStreamObserver(EventEmitter *listener = 0);
void OnChanged() final;
};
class MediaStreamT
gitextract_5hvoxsbh/
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── binding.gyp
├── examples/
│ ├── node2browser/
│ │ ├── index.html
│ │ ├── index.js
│ │ └── package.json
│ └── node2browser_ws/
│ ├── index.html
│ ├── index.js
│ └── package.json
├── index.js
├── node_versions.json
├── package.json
├── scripts/
│ ├── build.js
│ ├── install.js
│ ├── multibuild.cmd
│ ├── multibuild.sh
│ ├── nvm.sh
│ └── upload.js
├── src/
│ ├── ArrayBuffer.h
│ ├── BackTrace.cc
│ ├── BackTrace.h
│ ├── Common.h
│ ├── DataChannel.cc
│ ├── DataChannel.h
│ ├── EventEmitter.cc
│ ├── EventEmitter.h
│ ├── GetSources.cc
│ ├── GetSources.h
│ ├── GetUserMedia.cc
│ ├── GetUserMedia.h
│ ├── Global.cc
│ ├── Global.h
│ ├── MediaCapturer.cc
│ ├── MediaCapturer.h
│ ├── MediaConstraints.cc
│ ├── MediaConstraints.h
│ ├── MediaStream.cc
│ ├── MediaStream.h
│ ├── MediaStreamTrack.cc
│ ├── MediaStreamTrack.h
│ ├── Module.cc
│ ├── Observers.cc
│ ├── Observers.h
│ ├── PeerConnection.cc
│ ├── PeerConnection.h
│ ├── Platform.cc
│ ├── Platform.h
│ ├── Stats.cc
│ ├── Stats.h
│ ├── Wrap.h
│ ├── addon.gypi
│ └── webrtc.gyp
└── test/
├── all.js
├── bwtest.js
├── core.js
├── dataChannel.js
├── getSources.js
├── getUserMedia.js
├── mediaStream.js
├── multiconnect.js
├── p2p-browser.html
├── p2p.js
├── p2p_stream.js
├── test.js
└── videoStream.js
SYMBOL INDEX (58 symbols across 28 files)
FILE: examples/node2browser_ws/index.js
function sourceSelected (line 28) | function sourceSelected(audioSource, videoSource) {
function getUserMedia_successCallback (line 58) | function getUserMedia_successCallback(stream) {
function getUserMedia_errorCallback (line 72) | function getUserMedia_errorCallback(error) {
function setLocalSDP (line 76) | function setLocalSDP(p, callback){
function init (line 87) | function init()
FILE: scripts/build.js
function install (line 67) | function install() {
function compile (line 94) | function compile() {
function build (line 110) | function build() {
function sync (line 128) | function sync() {
function configure (line 149) | function configure() {
function config (line 224) | function config() {
FILE: scripts/install.js
function build (line 19) | function build() {
function test (line 47) | function test() {
FILE: scripts/upload.js
function build (line 10) | function build(version, callback) {
function buildNext (line 22) | function buildNext(index) {
FILE: src/ArrayBuffer.h
function namespace (line 36) | namespace node {
function onDispose (line 314) | static inline void onDispose(const v8::WeakCallbackData<v8::ArrayBuffer,...
function onDispose (line 332) | static inline void onDispose(v8::Persistent<v8::Value> value, void *data) {
FILE: src/BackTrace.h
function class (line 36) | class BackTrace {
FILE: src/DataChannel.h
function namespace (line 35) | namespace WebRTC {
FILE: src/EventEmitter.h
function namespace (line 31) | namespace WebRTC {
FILE: src/GetSources.h
function namespace (line 32) | namespace WebRTC {
FILE: src/GetUserMedia.h
function namespace (line 31) | namespace WebRTC {
FILE: src/Global.h
function namespace (line 31) | namespace WebRTC {
function namespace (line 40) | namespace v8 {
FILE: src/MediaCapturer.h
function namespace (line 34) | namespace WebRTC {
FILE: src/MediaConstraints.h
function namespace (line 32) | namespace WebRTC {
FILE: src/MediaStream.h
function namespace (line 34) | namespace WebRTC {
FILE: src/MediaStreamTrack.h
function namespace (line 34) | namespace WebRTC {
FILE: src/Module.cc
function SetDebug (line 41) | void SetDebug(const Nan::FunctionCallbackInfo<Value> &info) {
function RTCGarbageCollect (line 55) | void RTCGarbageCollect(const Nan::FunctionCallbackInfo<Value> &info) {
function RTCIceCandidate (line 62) | void RTCIceCandidate(const Nan::FunctionCallbackInfo<Value> &info) {
function RTCSessionDescription (line 79) | void RTCSessionDescription(const Nan::FunctionCallbackInfo<Value> &info) {
function WebrtcModuleDispose (line 95) | void WebrtcModuleDispose(void *arg) {
function WebrtcModuleInit (line 101) | void WebrtcModuleInit(Handle<Object> exports) {
FILE: src/Observers.h
function namespace (line 31) | namespace WebRTC {
FILE: src/PeerConnection.h
function namespace (line 35) | namespace WebRTC {
FILE: src/Platform.h
function namespace (line 31) | namespace WebRTC {
FILE: src/Stats.h
function namespace (line 34) | namespace WebRTC {
FILE: src/Wrap.h
function namespace (line 31) | namespace WebRTC {
FILE: test/bwtest.js
function main (line 21) | function main() {
function bwtape (line 35) | function bwtape() {
function bwtest (line 82) | function bwtest(options, callback) {
FILE: test/dataChannel.js
function P2P (line 5) | function P2P(alice, bob) {
function sctpTest (line 130) | function sctpTest() {
function rtpTest (line 172) | function rtpTest() {
FILE: test/getUserMedia.js
function dumpTrack (line 5) | function dumpTrack(track) {
function onSuccess (line 15) | function onSuccess(stream) {
function onError (line 49) | function onError(error) {
FILE: test/mediaStream.js
function P2P (line 53) | function P2P(alice, bob) {
function onSuccess (line 145) | function onSuccess(stream) {
function onError (line 157) | function onError(error) {
FILE: test/multiconnect.js
function callback (line 33) | function callback(err) {
function callback (line 46) | function callback(err) {
function connect (line 53) | function connect(callback) {
function connectLoop (line 115) | function connectLoop(count, callback) {
FILE: test/p2p.js
function P2P (line 3) | function P2P(alice, bob) {
FILE: test/videoStream.js
function onSuccess (line 5) | function onSuccess(stream) {
Condensed preview — 67 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (308K chars).
[
{
"path": ".gitignore",
"chars": 570,
"preview": "# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nl"
},
{
"path": ".npmignore",
"chars": 575,
"preview": "# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nl"
},
{
"path": "LICENSE",
"chars": 1126,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa) \n\nPermission is here"
},
{
"path": "README.md",
"chars": 1432,
"preview": "[WebRTC](http://en.wikipedia.org/wiki/WebRTC) for NodeJS\n\n### Chromium\n\nwebrtc-native is using [WebRTC](http://webrtc.or"
},
{
"path": "binding.gyp",
"chars": 465,
"preview": "{\n 'targets': [\n {\n 'target_name': 'action_before_build',\n 'dependencies': [],\n 'hard_dependency': 1,"
},
{
"path": "examples/node2browser/index.html",
"chars": 3141,
"preview": "<html>\n<head>\n <script src=\"https://cdn.socket.io/socket.io-1.2.0.js\"></script>\n</head>\n<body>\n <video></video>\n<scrip"
},
{
"path": "examples/node2browser/index.js",
"chars": 3435,
"preview": "var express = require('express');\nvar app = express();\nvar server = require('http').Server(app);\nvar io = require('socke"
},
{
"path": "examples/node2browser/package.json",
"chars": 80,
"preview": "{\n \"dependencies\": {\n \"express\": \"^4.13.0\",\n \"socket.io\": \"^1.3.5\"\n }\n}\n"
},
{
"path": "examples/node2browser_ws/index.html",
"chars": 4494,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n </head>\n\n<script language=\"javascript\">\n\n\nwindow.onload = function(e){ \n\n var config = "
},
{
"path": "examples/node2browser_ws/index.js",
"chars": 4674,
"preview": "var WebRTC = require('../../');\nvar WebSocketServer = require('ws').Server;\nvar express = require('express');\nvar app = "
},
{
"path": "examples/node2browser_ws/package.json",
"chars": 72,
"preview": "{\n \"dependencies\": {\n \"express\": \"^4.13.0\",\n \"ws\": \"^1.1.0\"\n }\n}"
},
{
"path": "index.js",
"chars": 58,
"preview": "\nmodule.exports = require('./build/Release/webrtc.node');\n"
},
{
"path": "node_versions.json",
"chars": 219,
"preview": "[\n \"iojs-v2.3.2\",\n \"iojs-v3.3.1\",\n \"v0.10.38\",\n \"v0.12.5\",\n \"v4.2.1\",\n \"v4.3.2\",\n \"v4.4.0\",\n \"v5.0.0\",\n \"v5.1.1"
},
{
"path": "package.json",
"chars": 832,
"preview": "{\n \"name\": \"webrtc-native\",\n \"version\": \"1.4.0\",\n \"description\": \"WebRTC for NodeJS\",\n \"homepage\": \"https://github.c"
},
{
"path": "scripts/build.js",
"chars": 7893,
"preview": "var fs = require('fs');\nvar os = require('os');\nvar spawn = require('child_process').spawn;\nvar path = require('path');\n"
},
{
"path": "scripts/install.js",
"chars": 2601,
"preview": "var fs = require('fs');\nvar os = require('os');\nvar spawn = require('child_process').spawn;\nvar path = require('path');\n"
},
{
"path": "scripts/multibuild.cmd",
"chars": 44,
"preview": "nvmw install %1 & nvmw use %1 && npm install"
},
{
"path": "scripts/multibuild.sh",
"chars": 66,
"preview": "#!/bin/sh\n\n. ~/.nvm/nvm.sh\n\nnvm install $1\nnvm use $1\nnpm install\n"
},
{
"path": "scripts/nvm.sh",
"chars": 38,
"preview": "#!/bin/sh\n\n. ~/.nvm/nvm.sh\n\nnvm $1 $2\n"
},
{
"path": "scripts/upload.js",
"chars": 694,
"preview": "var os = require('os');\nvar spawn = require('child_process').spawn;\nvar versions = require('../node_versions.json');\n\nva"
},
{
"path": "src/ArrayBuffer.h",
"chars": 12104,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/BackTrace.cc",
"chars": 3368,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/BackTrace.h",
"chars": 1804,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/Common.h",
"chars": 2528,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/DataChannel.cc",
"chars": 17197,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/DataChannel.h",
"chars": 4978,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/EventEmitter.cc",
"chars": 6120,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/EventEmitter.h",
"chars": 4130,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/GetSources.cc",
"chars": 7283,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/GetSources.h",
"chars": 2195,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/GetUserMedia.cc",
"chars": 4445,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/GetUserMedia.h",
"chars": 1471,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/Global.cc",
"chars": 2477,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/Global.h",
"chars": 1604,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/MediaCapturer.cc",
"chars": 5699,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/MediaCapturer.h",
"chars": 2802,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/MediaConstraints.cc",
"chars": 17525,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/MediaConstraints.h",
"chars": 3371,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/MediaStream.cc",
"chars": 18391,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/MediaStream.h",
"chars": 3921,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/MediaStreamTrack.cc",
"chars": 17501,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/MediaStreamTrack.h",
"chars": 5660,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/Module.cc",
"chars": 4473,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/Observers.cc",
"chars": 6955,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/Observers.h",
"chars": 4288,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/PeerConnection.cc",
"chars": 40844,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/PeerConnection.h",
"chars": 7820,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/Platform.cc",
"chars": 2546,
"preview": "\n/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permiss"
},
{
"path": "src/Platform.h",
"chars": 1401,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/Stats.cc",
"chars": 8258,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/Stats.h",
"chars": 2645,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/Wrap.h",
"chars": 2498,
"preview": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permissi"
},
{
"path": "src/addon.gypi",
"chars": 1486,
"preview": "{\n 'target_defaults': {\n 'type': 'loadable_module',\n 'product_prefix': '',\n 'product_extension': 'node',\n '"
},
{
"path": "src/webrtc.gyp",
"chars": 2179,
"preview": "{\n 'includes': [\n '../third_party/webrtc/src/talk/build/common.gypi',\n '../third_party/webrtc/src/webrtc/build/co"
},
{
"path": "test/all.js",
"chars": 55,
"preview": "require('./multiconnect');\nrequire('./bwtest').tape();\n"
},
{
"path": "test/bwtest.js",
"chars": 7173,
"preview": "'use strict';\n\nvar wrtc = require('..');\nvar tape = require('tape');\nvar args = require('minimist')(process.argv.slice(2"
},
{
"path": "test/core.js",
"chars": 93,
"preview": "var WebRTC = require('../');\n\nconsole.log('WebRTC Module Loaded!');\n\n//WebRTC.setDebug(true);"
},
{
"path": "test/dataChannel.js",
"chars": 4801,
"preview": "var WebRTC = require('../');\n\n//WebRTC.setDebug(true);\n\nfunction P2P(alice, bob) {\n alice.onicecandidate = function(eve"
},
{
"path": "test/getSources.js",
"chars": 96,
"preview": "var WebRTC = require('../');\n\nWebRTC.getSources(function(sources) {\n console.log(sources);\n});\n"
},
{
"path": "test/getUserMedia.js",
"chars": 1400,
"preview": "var WebRTC = require('../');\n\n//WebRTC.setDebug(true);\n\nfunction dumpTrack(track) {\n console.log('MediaStreamTrack Enab"
},
{
"path": "test/mediaStream.js",
"chars": 3424,
"preview": "var WEBRTC = require('../');\n\nvar config = {\n iceServers: [\n {\n url: 'stun:stun.l.google.com:19302',\n },\n ]"
},
{
"path": "test/multiconnect.js",
"chars": 3004,
"preview": "'use strict';\n\nvar tape = require('tape');\nvar SimplePeer = require('simple-peer');\nvar wrtc = require('..');\n\n//wrtc.se"
},
{
"path": "test/p2p-browser.html",
"chars": 2383,
"preview": "<html>\n<body>\n<script>\nfunction P2P(alice, bob) {\n alice.onicecandidate = function(event) {\n var candidate = event.c"
},
{
"path": "test/p2p.js",
"chars": 2843,
"preview": "var WEBRTC = require('../');\n\nfunction P2P(alice, bob) {\n alice.onicecandidate = function(event) {\n var candidate = "
},
{
"path": "test/p2p_stream.js",
"chars": 2911,
"preview": "var WEBRTC = require('../');\n\nWEBRTC.setDebug(true);\n\nvar config = {\n iceServers: [\n {\n url: 'stun:stun.l.googl"
},
{
"path": "test/test.js",
"chars": 268,
"preview": "var WebRTC = require('../');\n\n//WebRTC.setDebug(true);\n\nvar renderer = new WebRTC.MediaSource('window');\nvar capturer = "
},
{
"path": "test/videoStream.js",
"chars": 1151,
"preview": "var WebRTC = require('../');\n\nWebRTC.setDebug(true);\n\nfunction onSuccess(stream) {\n var video_list = stream.getVideoTra"
}
]
About this extraction
This page contains the full source code of the vmolsa/webrtc-native GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 67 files (287.2 KB), approximately 75.2k tokens, and a symbol index with 58 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.