├── scripts ├── multibuild.cmd ├── nvm.sh ├── multibuild.sh ├── upload.js ├── install.js └── build.js ├── index.js ├── test ├── all.js ├── core.js ├── getSources.js ├── test.js ├── videoStream.js ├── getUserMedia.js ├── p2p-browser.html ├── p2p.js ├── p2p_stream.js ├── multiconnect.js ├── mediaStream.js ├── dataChannel.js └── bwtest.js ├── examples ├── node2browser_ws │ ├── package.json │ ├── index.html │ └── index.js └── node2browser │ ├── package.json │ ├── index.html │ └── index.js ├── node_versions.json ├── binding.gyp ├── .gitignore ├── .npmignore ├── package.json ├── LICENSE ├── src ├── Platform.h ├── GetUserMedia.h ├── addon.gypi ├── Global.h ├── BackTrace.h ├── GetSources.h ├── webrtc.gyp ├── Global.cc ├── Wrap.h ├── Common.h ├── Platform.cc ├── Stats.h ├── MediaCapturer.h ├── MediaConstraints.h ├── BackTrace.cc ├── MediaStream.h ├── Observers.h ├── EventEmitter.h ├── Module.cc ├── GetUserMedia.cc ├── DataChannel.h ├── MediaStreamTrack.h ├── MediaCapturer.cc ├── EventEmitter.cc ├── Observers.cc ├── GetSources.cc ├── PeerConnection.h ├── Stats.cc ├── ArrayBuffer.h └── DataChannel.cc └── README.md /scripts/multibuild.cmd: -------------------------------------------------------------------------------- 1 | nvmw install %1 & nvmw use %1 && npm install -------------------------------------------------------------------------------- /scripts/nvm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | . ~/.nvm/nvm.sh 4 | 5 | nvm $1 $2 6 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = require('./build/Release/webrtc.node'); 3 | -------------------------------------------------------------------------------- /test/all.js: -------------------------------------------------------------------------------- 1 | require('./multiconnect'); 2 | require('./bwtest').tape(); 3 | -------------------------------------------------------------------------------- /scripts/multibuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | . ~/.nvm/nvm.sh 4 | 5 | nvm install $1 6 | nvm use $1 7 | npm install 8 | -------------------------------------------------------------------------------- /test/core.js: -------------------------------------------------------------------------------- 1 | var WebRTC = require('../'); 2 | 3 | console.log('WebRTC Module Loaded!'); 4 | 5 | //WebRTC.setDebug(true); -------------------------------------------------------------------------------- /examples/node2browser_ws/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "express": "^4.13.0", 4 | "ws": "^1.1.0" 5 | } 6 | } -------------------------------------------------------------------------------- /examples/node2browser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "express": "^4.13.0", 4 | "socket.io": "^1.3.5" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/getSources.js: -------------------------------------------------------------------------------- 1 | var WebRTC = require('../'); 2 | 3 | WebRTC.getSources(function(sources) { 4 | console.log(sources); 5 | }); 6 | -------------------------------------------------------------------------------- /node_versions.json: -------------------------------------------------------------------------------- 1 | [ 2 | "iojs-v2.3.2", 3 | "iojs-v3.3.1", 4 | "v0.10.38", 5 | "v0.12.5", 6 | "v4.2.1", 7 | "v4.3.2", 8 | "v4.4.0", 9 | "v5.0.0", 10 | "v5.1.1", 11 | "v5.2.0", 12 | "v5.3.0", 13 | "v5.4.1", 14 | "v5.5.0", 15 | "v5.6.0", 16 | "v5.7.1", 17 | "v5.8.0", 18 | "v5.9.1" 19 | ] -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var WebRTC = require('../'); 2 | 3 | //WebRTC.setDebug(true); 4 | 5 | var renderer = new WebRTC.MediaSource('window'); 6 | var capturer = new WebRTC.MediaSource('webcam'); 7 | 8 | capturer.connect(renderer); 9 | 10 | setTimeout(function() { 11 | console.log('Closing...'); 12 | 13 | capturer.end(); 14 | }, 10000); -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'targets': [ 3 | { 4 | 'target_name': 'action_before_build', 5 | 'dependencies': [], 6 | 'hard_dependency': 1, 7 | 'type': 'none', 8 | 'actions': [ 9 | { 10 | 'action_name': 'run_build_script', 11 | 'inputs': [], 12 | 'outputs': [''], 13 | 'action': [ 14 | 'node', 'scripts/build.js', '-Dtarget-arch=<(target_arch)', '<(node_root_dir)', '<(node_lib_file)', '<(node_gyp_dir)' 15 | ], 16 | } 17 | ] 18 | }, 19 | ], 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | build 25 | 26 | # Dependency directory 27 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 28 | node_modules 29 | 30 | third_party 31 | 32 | config.gypi 33 | nodejs.gypi 34 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | build 25 | 26 | # Dependency directory 27 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 28 | node_modules 29 | 30 | src 31 | third_party 32 | 33 | config.gypi 34 | nodejs.gypi 35 | 36 | -------------------------------------------------------------------------------- /scripts/upload.js: -------------------------------------------------------------------------------- 1 | var os = require('os'); 2 | var spawn = require('child_process').spawn; 3 | var versions = require('../node_versions.json'); 4 | 5 | var ROOT = process.cwd(); 6 | var MULTIBUILD = (os.platform() == 'win32') ? 'scripts\\multibuild.cmd' : 'scripts/multibuild.sh'; 7 | 8 | process.env['BUILD_WEBRTC'] = 'true'; 9 | 10 | function build(version, callback) { 11 | var res = spawn(MULTIBUILD, [ version ], { 12 | cwd: ROOT, 13 | env: process.env, 14 | stdio: 'inherit', 15 | }); 16 | 17 | res.on('close', function (code) { 18 | callback(code == 0); 19 | }); 20 | } 21 | 22 | function buildNext(index) { 23 | if (index < versions.length) { 24 | build(versions[index], function(result) { 25 | if (result) { 26 | buildNext(index + 1); 27 | } 28 | }); 29 | } 30 | } 31 | 32 | buildNext(0); 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webrtc-native", 3 | "version": "1.4.0", 4 | "description": "WebRTC for NodeJS", 5 | "homepage": "https://github.com/vmolsa/webrtc-native", 6 | "author": "https://github.com/vmolsa", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/vmolsa/webrtc-native.git" 10 | }, 11 | "bugs": { 12 | "url": "https://github.com/vmolsa/webrtc-native/issues" 13 | }, 14 | "keywords": [ 15 | "webrtc", 16 | "p2p", 17 | "streaming", 18 | "dtls", 19 | "srtp", 20 | "rtp", 21 | "capture", 22 | "datachannel" 23 | ], 24 | "license": "MIT", 25 | "main": "index.js", 26 | "scripts": { 27 | "install": "node scripts/install.js", 28 | "test": "node test/all.js" 29 | }, 30 | "dependencies": { 31 | "request": "^2.58.0" 32 | }, 33 | "devDependencies": { 34 | "nan": "^2.1.0", 35 | "node-gyp": "^3.0.3", 36 | "minimist": "^1.1.1", 37 | "simple-peer": "^5.11.5", 38 | "tape": "^4.0.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /test/videoStream.js: -------------------------------------------------------------------------------- 1 | var WebRTC = require('../'); 2 | 3 | WebRTC.setDebug(true); 4 | 5 | function onSuccess(stream) { 6 | var video_list = stream.getVideoTracks(); 7 | 8 | video_list.forEach(function (track) { 9 | console.log('Video Track'); 10 | }); 11 | } 12 | 13 | var constraints = { 14 | audio: false, 15 | video: true, 16 | /* 17 | audio: { 18 | optional: [ 19 | { 20 | googEchoCancellation: true, 21 | googEchoCancellation2: true, 22 | googDAEchoCancellation: true, 23 | googAutoGainControl: true, 24 | googAutoGainControl2: true, 25 | googNoiseSuppression: true, 26 | googNoiseSuppression2: true, 27 | googHighpassFilter: true, 28 | googTypingNoiseDetection: true, 29 | googAudioMirroring: true, 30 | }, 31 | ], 32 | }, 33 | video: { 34 | optional: [ 35 | { 36 | minAspectRatio: 1.333, 37 | maxAspectRatio: 1.778, 38 | maxWidth: 1920, 39 | minWidth: 320, 40 | maxHeight: 1080, 41 | minHeight: 180, 42 | maxFrameRate: 60, 43 | minFrameRate: 30, 44 | }, 45 | ], 46 | }, 47 | optional: [ 48 | { 49 | DtlsSrtpKeyAgreement: true, 50 | }, 51 | ], 52 | mandatory: { 53 | OfferToReceiveAudio: true, 54 | OfferToReceiveVideo: true, 55 | }, 56 | */ 57 | }; 58 | 59 | WebRTC.getUserMedia(constraints, onSuccess); -------------------------------------------------------------------------------- /src/Platform.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef WEBRTC_PLATFORM_H 27 | #define WEBRTC_PLATFORM_H 28 | 29 | #include "Common.h" 30 | 31 | namespace WebRTC { 32 | class Platform { 33 | public: 34 | static void Init(); 35 | static void Dispose(); 36 | static rtc::Thread *GetWorker(); 37 | }; 38 | }; 39 | 40 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [WebRTC](http://en.wikipedia.org/wiki/WebRTC) for NodeJS 2 | 3 | ### Chromium 4 | 5 | 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). 6 | 7 | ### Usage 8 | 9 | For installing or building module from source go to page [Getting Started](https://github.com/vmolsa/webrtc-native/wiki/Getting-started) 10 | 11 | ### API 12 | 13 | ```` 14 | var WebRTC = require('webrtc-native'); 15 | ```` 16 | 17 | #### WebRTC.[RTCPeerConnection](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection) 18 | 19 | #### WebRTC.[RTCIceCandidate](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnectionIceEvent) 20 | 21 | #### WebRTC.[RTCSessionDescription](https://developer.mozilla.org/en-US/docs/Web/API/RTCSessionDescription) 22 | 23 | #### WebRTC.[RTCDataChannel](https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel) 24 | 25 | #### WebRTC.[MediaStream](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream) 26 | 27 | #### WebRTC.[MediaStreamTrack](https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack) 28 | 29 | #### WebRTC.[getUserMedia](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getUserMedia) 30 | 31 | #### WebRTC.[getSources](http://simpl.info/getusermedia/sources/index.html) 32 | 33 | - Returns array of available device inputs 34 | 35 | #### WebRTC.RTCGarbageCollect() 36 | 37 | - Notify V8 Engine to attempt to free memory. 38 | 39 | #### WebRTC.setDebug(boolean) 40 | 41 | - Enable / Disable WebRTC log messages 42 | -------------------------------------------------------------------------------- /src/GetUserMedia.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef WEBRTC_GETUSERMEDIA_H 27 | #define WEBRTC_GETUSERMEDIA_H 28 | 29 | #include "Common.h" 30 | 31 | namespace WebRTC { 32 | class GetUserMedia { 33 | public: 34 | static void Init(v8::Handle exports); 35 | 36 | private: 37 | static void GetMediaStream(const Nan::FunctionCallbackInfo &info); 38 | }; 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /test/getUserMedia.js: -------------------------------------------------------------------------------- 1 | var WebRTC = require('../'); 2 | 3 | //WebRTC.setDebug(true); 4 | 5 | function dumpTrack(track) { 6 | console.log('MediaStreamTrack Enabled:', track.enabled); 7 | console.log('MediaStreamTrack Id:', track.id); 8 | console.log('MediaStreamTrack Kind:', track.kind); 9 | console.log('MediaStreamTrack Label:', track.label); 10 | console.log('MediaStreamTrack Muted:', track.muted); 11 | console.log('MediaStreamTrack ReadyState:', track.readyState); 12 | console.log('MediaStreamTrack Remote:', track.remote); 13 | } 14 | 15 | function onSuccess(stream) { 16 | if (stream && stream.active) { 17 | stream.onaddtrack = function(track) { 18 | console.log('Track Added!'); 19 | }; 20 | 21 | stream.onremovetrack = function (track) { 22 | console.log('Track Removed!'); 23 | }; 24 | 25 | console.log('MediaStream Active:', stream.active); 26 | console.log('MediaStream Ended:', stream.ended); 27 | console.log('MediaStream ID:', stream.id); 28 | 29 | var audio_list = stream.getAudioTracks(); 30 | 31 | audio_list.forEach(function (track) { 32 | console.log('Audio Track'); 33 | dumpTrack(track); 34 | }); 35 | 36 | var video_list = stream.getVideoTracks(); 37 | 38 | video_list.forEach(function (track) { 39 | console.log('Video Track'); 40 | dumpTrack(track); 41 | }); 42 | 43 | setTimeout(function() { 44 | console.log('Closing...'); 45 | }, 5000); 46 | } 47 | } 48 | 49 | function onError(error) { 50 | throw error; 51 | } 52 | 53 | WebRTC.getUserMedia({ 54 | audio: true, 55 | video: true, 56 | }, onSuccess, onError); 57 | -------------------------------------------------------------------------------- /src/addon.gypi: -------------------------------------------------------------------------------- 1 | { 2 | 'target_defaults': { 3 | 'type': 'loadable_module', 4 | 'product_prefix': '', 5 | 'product_extension': 'node', 6 | 'include_dirs': [ 7 | '<(node_root_dir)/include/node', 8 | '<(node_root_dir)/src', 9 | '<(node_root_dir)/deps/uv/include', 10 | '<(node_root_dir)/deps/v8/include' 11 | ], 12 | 'defines': [ 13 | 'BUILDING_NODE_EXTENSION', 14 | 'NODE_GYP_MODULE_NAME=>(_target_name)' 15 | ], 16 | 'conditions': [ 17 | [ 'OS=="mac"', { 18 | 'defines': [ 19 | '_DARWIN_USE_64_BIT_INODE=1' 20 | ], 21 | 'libraries': [ 22 | '-undefined dynamic_lookup' 23 | ], 24 | 'xcode_settings': { 25 | 'DYLIB_INSTALL_NAME_BASE': '@rpath' 26 | }, 27 | }], 28 | [ 'OS=="win"', { 29 | 'libraries': [ 30 | '-lkernel32.lib', 31 | '-luser32.lib', 32 | '-lgdi32.lib', 33 | '-lwinspool.lib', 34 | '-lcomdlg32.lib', 35 | '-ladvapi32.lib', 36 | '-lshell32.lib', 37 | '-lole32.lib', 38 | '-loleaut32.lib', 39 | '-luuid.lib', 40 | '-lodbc32.lib', 41 | '-lDelayImp.lib', 42 | '-l"<(node_root_dir)\\<(ConfigurationName)\\<(node_lib_file)"' 43 | ], 44 | 'msvs_disabled_warnings': [ 45 | 4251 46 | ], 47 | }, { 48 | 'defines': [ 49 | '_LARGEFILE_SOURCE', 50 | '_FILE_OFFSET_BITS=64', 51 | ], 52 | }], 53 | [ 'OS=="freebsd" or OS=="openbsd" or OS=="solaris" or (OS=="linux" and target_arch!="ia32")', { 54 | 'cflags': [ 55 | '-fPIC' 56 | ], 57 | }] 58 | ] 59 | } 60 | } -------------------------------------------------------------------------------- /src/Global.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef WEBRTC_GLOBAL_H 27 | #define WEBRTC_GLOBAL_H 28 | 29 | #include "Common.h" 30 | 31 | namespace WebRTC { 32 | class Global { 33 | public: 34 | static void Init(v8::Handle exports); 35 | static v8::Local Require(v8::Local library); 36 | }; 37 | }; 38 | 39 | #if (NODE_MODULE_VERSION <= NODE_0_10_MODULE_VERSION) 40 | namespace v8 { 41 | class JSON { 42 | public: 43 | static v8::Local Parse(v8::Local str); 44 | }; 45 | }; 46 | #endif 47 | #endif 48 | -------------------------------------------------------------------------------- /src/BackTrace.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef BACKTRACE_H 27 | #define BACKTRACE_H 28 | #ifdef USE_BACKTRACE 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | class BackTrace { 37 | public: 38 | static void Dump(const char *event = "NOEVENT", int skip = 1); 39 | 40 | private: 41 | explicit BackTrace(); 42 | virtual ~BackTrace(); 43 | 44 | void Close(); 45 | 46 | static void OnSegv(int sig); 47 | static void OnBus(int sig); 48 | static void OnAbort(int sig); 49 | static void OnIll(int sig); 50 | 51 | protected: 52 | struct sigaction _segv; 53 | struct sigaction _bus; 54 | struct sigaction _abrt; 55 | struct sigaction _ill; 56 | 57 | static BackTrace landmine; 58 | }; 59 | 60 | #else 61 | 62 | #endif 63 | #endif 64 | -------------------------------------------------------------------------------- /src/GetSources.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef WEBRTC_GETSOURCES_H 27 | #define WEBRTC_GETSOURCES_H 28 | 29 | #include "Common.h" 30 | #include "MediaConstraints.h" 31 | 32 | namespace WebRTC { 33 | class GetSources { 34 | public: 35 | static void Init(v8::Handle exports); 36 | 37 | static rtc::scoped_refptr GetAudioSource(const rtc::scoped_refptr &constraints); 38 | static rtc::scoped_refptr GetAudioSource(const std::string id, const rtc::scoped_refptr &constraints); 39 | 40 | static rtc::scoped_refptr GetVideoSource(const rtc::scoped_refptr &constraints); 41 | static rtc::scoped_refptr GetVideoSource(const std::string id, const rtc::scoped_refptr &constraints); 42 | static v8::Local GetDevices(); 43 | 44 | private: 45 | static void GetVideoSource2(const Nan::FunctionCallbackInfo &info); 46 | static void GetDevices(const Nan::FunctionCallbackInfo &info); 47 | }; 48 | }; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/webrtc.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'includes': [ 3 | '../third_party/webrtc/src/talk/build/common.gypi', 4 | '../third_party/webrtc/src/webrtc/build/common.gypi', 5 | '../build/config.gypi', 6 | '../nodejs.gypi', 7 | 'addon.gypi', 8 | ], 9 | 'targets': [ 10 | { 11 | 'target_name': 'webrtc', 12 | 'sources': [ 13 | 'Platform.cc', 14 | 'Global.cc', 15 | 'BackTrace.cc', 16 | 'EventEmitter.cc', 17 | 'Observers.cc', 18 | 'Module.cc', 19 | 'PeerConnection.cc', 20 | 'DataChannel.cc', 21 | 'GetSources.cc', 22 | 'GetUserMedia.cc', 23 | 'MediaStream.cc', 24 | 'MediaStreamTrack.cc', 25 | 'MediaConstraints.cc', 26 | 'Stats.cc', 27 | ], 28 | 'dependencies': [ 29 | '<(webrtc_root)/webrtc.gyp:webrtc_all', 30 | ], 31 | 'include_dirs': [ 32 | '<(DEPTH)/third_party/jsoncpp/source/include', 33 | '<(DEPTH)/third_party/libsrtp/srtp', 34 | '<(DEPTH)/third_party/libyuv/include', 35 | " (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #include "Global.h" 27 | 28 | using namespace v8; 29 | using namespace WebRTC; 30 | 31 | Nan::Persistent _require; 32 | 33 | #if (NODE_MODULE_VERSION <= NODE_0_10_MODULE_VERSION) 34 | Nan::Persistent _parse; 35 | #endif 36 | 37 | void WebRTC::Global::Init(Handle exports) { 38 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 39 | 40 | Nan::HandleScope scope; 41 | 42 | Local global = Nan::GetCurrentContext()->Global(); 43 | _require.Reset(Local::Cast(global->Get(Nan::New("require").ToLocalChecked()))); 44 | 45 | #if (NODE_MODULE_VERSION <= NODE_0_10_MODULE_VERSION) 46 | Local json = Local::Cast(global->Get(Nan::New("JSON").ToLocalChecked())); 47 | _parse.Reset(Local::Cast(json->Get(Nan::New("parse").ToLocalChecked()))); 48 | #endif 49 | } 50 | 51 | Local WebRTC::Global::Require(Local library) { 52 | Nan::EscapableHandleScope scope; 53 | Local argv[] = { library }; 54 | Local retval = Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(_require), 1, argv); 55 | return scope.Escape(Local::Cast(retval)); 56 | } 57 | 58 | #if (NODE_MODULE_VERSION <= NODE_0_10_MODULE_VERSION) 59 | Local JSON::Parse(Local str) { 60 | Nan::EscapableHandleScope scope; 61 | Local argv[] = { str }; 62 | return scope.Escape(Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(_parse), 1, argv)); 63 | }; 64 | #endif -------------------------------------------------------------------------------- /src/Wrap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef WEBRTC_WRAP_H 27 | #define WEBRTC_WRAP_H 28 | 29 | #include "Common.h" 30 | 31 | namespace WebRTC { 32 | class RTCWrap : public node::ObjectWrap { 33 | public: 34 | inline void Wrap(v8::Local obj, const char *className = "RTCWrap") { 35 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 36 | 37 | _className = className; 38 | node::ObjectWrap::Wrap(obj); 39 | } 40 | 41 | inline v8::Local This() { 42 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 43 | 44 | #if (NODE_MODULE_VERSION < NODE_0_12_MODULE_VERSION) 45 | Nan::EscapableHandleScope scope; 46 | return scope.Escape(Nan::New(node::ObjectWrap::handle_)); 47 | #else 48 | return node::ObjectWrap::handle(); 49 | #endif 50 | } 51 | 52 | template inline T* Unwrap() { 53 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 54 | 55 | return static_cast(this); 56 | } 57 | 58 | template inline static T* Unwrap(v8::Local obj, const char *className = "RTCWrap") { 59 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 60 | 61 | RTCWrap *wrap = node::ObjectWrap::Unwrap(obj); 62 | 63 | if (wrap) { 64 | if (!wrap->_className.compare(className)) { 65 | return wrap->Unwrap(); 66 | } 67 | } 68 | 69 | return 0; 70 | } 71 | 72 | protected: 73 | std::string _className; 74 | }; 75 | }; 76 | 77 | #endif -------------------------------------------------------------------------------- /src/Common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef WEBRTC_COMMON_H 27 | #define WEBRTC_COMMON_H 28 | 29 | #include 30 | 31 | #include "webrtc/video_frame.h" 32 | 33 | #include "webrtc/base/atomicops.h" 34 | #include "webrtc/base/logging.h" 35 | #include "webrtc/base/json.h" 36 | #include "webrtc/base/basictypes.h" 37 | #include "webrtc/base/common.h" 38 | #include "webrtc/base/scoped_ptr.h" 39 | #include "webrtc/base/ssladapter.h" 40 | #include "webrtc/base/sslstreamadapter.h" 41 | #include "webrtc/base/stringutils.h" 42 | #include "webrtc/base/thread.h" 43 | #include "webrtc/base/buffer.h" 44 | #include "webrtc/base/scoped_ref_ptr.h" 45 | #include "webrtc/base/refcount.h" 46 | #include "webrtc/base/stringencode.h" 47 | 48 | #include "webrtc/api/jsep.h" 49 | #include "webrtc/api/jsepsessiondescription.h" 50 | #include "webrtc/api/mediaconstraintsinterface.h" 51 | #include "webrtc/api/mediastreaminterface.h" 52 | #include "webrtc/api/peerconnectionfactory.h" 53 | #include "webrtc/api/peerconnectioninterface.h" 54 | #include "webrtc/api/test/fakeconstraints.h" 55 | #include "webrtc/api/datachannelinterface.h" 56 | 57 | #include "webrtc/api/videosourceinterface.h" 58 | #include "webrtc/media/base/videosourceinterface.h" 59 | #include "webrtc/media/engine/webrtcvideocapturerfactory.h" 60 | #include "webrtc/modules/video_capture/video_capture_factory.h" 61 | 62 | #ifdef WIN32 63 | #ifndef __PRETTY_FUNCTION__ 64 | #define __PRETTY_FUNCTION__ __FUNCTION__ 65 | #endif 66 | #endif 67 | 68 | #include 69 | #include 70 | #include 71 | #include 72 | 73 | #endif -------------------------------------------------------------------------------- /src/Platform.cc: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #include "Platform.h" 28 | 29 | #if defined(WEBRTC_WIN) 30 | #include 31 | #include 32 | #endif 33 | 34 | using namespace WebRTC; 35 | 36 | #ifndef WEBRTC_THREAD_COUNT 37 | #define WEBRTC_THREAD_COUNT 4 38 | #endif 39 | 40 | rtc::Thread signal_thread; 41 | rtc::Thread worker_thread[WEBRTC_THREAD_COUNT]; 42 | uint32_t counter = 0; 43 | 44 | void Platform::Init() { 45 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 46 | 47 | #if defined(WEBRTC_WIN) 48 | rtc::EnsureWinsockInit(); 49 | #endif 50 | 51 | rtc::InitializeSSL(); 52 | 53 | signal_thread.Start(); 54 | 55 | rtc::ThreadManager::Instance()->SetCurrentThread(&signal_thread); 56 | 57 | if (rtc::ThreadManager::Instance()->CurrentThread() != &signal_thread) { 58 | Nan::ThrowError("Internal Thread Error!"); 59 | } 60 | 61 | for (int index = 0; index < WEBRTC_THREAD_COUNT; index++) { 62 | worker_thread[index].Start(); 63 | } 64 | } 65 | 66 | void Platform::Dispose() { 67 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 68 | 69 | signal_thread.SetAllowBlockingCalls(true); 70 | signal_thread.Stop(); 71 | 72 | for (int index = 0; index < WEBRTC_THREAD_COUNT; index++) { 73 | worker_thread[index].SetAllowBlockingCalls(true); 74 | worker_thread[index].Stop(); 75 | } 76 | 77 | if (rtc::ThreadManager::Instance()->CurrentThread() == &signal_thread) { 78 | rtc::ThreadManager::Instance()->SetCurrentThread(NULL); 79 | } 80 | 81 | rtc::CleanupSSL(); 82 | } 83 | 84 | rtc::Thread *Platform::GetWorker() { 85 | return &worker_thread[(counter++) % WEBRTC_THREAD_COUNT]; 86 | } -------------------------------------------------------------------------------- /src/Stats.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef WEBRTC_STATS_H 27 | #define WEBRTC_STATS_H 28 | 29 | #include "Common.h" 30 | #include "Observers.h" 31 | #include "EventEmitter.h" 32 | #include "Wrap.h" 33 | 34 | namespace WebRTC { 35 | class RTCStatsReport : public RTCWrap { 36 | public: 37 | static void Init(); 38 | static v8::Local New(webrtc::StatsReport *report); 39 | 40 | private: 41 | ~RTCStatsReport() final; 42 | 43 | static void New(const Nan::FunctionCallbackInfo &info); 44 | static void Names(const Nan::FunctionCallbackInfo &info); 45 | static void Stat(const Nan::FunctionCallbackInfo &info); 46 | 47 | static void Id(v8::Local property, const Nan::PropertyCallbackInfo &info); 48 | static void Type(v8::Local property, const Nan::PropertyCallbackInfo &info); 49 | static void Timestamp(v8::Local property, const Nan::PropertyCallbackInfo &info); 50 | 51 | protected: 52 | static Nan::Persistent constructor; 53 | webrtc::StatsReport* _report; 54 | }; 55 | 56 | class RTCStatsResponse : public RTCWrap { 57 | public: 58 | static void Init(); 59 | static v8::Local New(const webrtc::StatsReports &reports); 60 | 61 | private: 62 | ~RTCStatsResponse() final; 63 | 64 | static void New(const Nan::FunctionCallbackInfo &info); 65 | static void Result(const Nan::FunctionCallbackInfo &info); 66 | 67 | protected: 68 | static Nan::Persistent constructor; 69 | webrtc::StatsReports _reports; 70 | }; 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /scripts/install.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var os = require('os'); 3 | var spawn = require('child_process').spawn; 4 | var path = require('path'); 5 | var request = require('request'); 6 | 7 | var PLATFORM = os.platform(); 8 | var ROOT = path.resolve(__dirname, '..'); 9 | var ARCH = os.arch(); 10 | var URL = 'http://cide.cc:8080/webrtc/'; 11 | var NODEVER = process.version.split('.'); 12 | var PACKAGE = require(path.resolve(ROOT, 'package.json')); 13 | 14 | NODEVER[2] = 'x'; 15 | NODEVER = NODEVER.join('.'); 16 | 17 | URL += 'webrtc-' + PACKAGE.version + '-' + PLATFORM + '-' + ARCH + '-' + NODEVER + '.node'; 18 | 19 | function build() { 20 | console.log('Building module...'); 21 | 22 | var nodegyp = path.resolve(ROOT, 'node_modules', 'node-gyp', 'bin', 'node-gyp.js'); 23 | 24 | if (!fs.existsSync(nodegyp)) { 25 | nodegyp = path.resolve(ROOT, '..', 'node-gyp', 'bin', 'node-gyp.js'); 26 | 27 | if (!fs.existsSync(nodegyp)) { 28 | throw new Error('Build Failed. Please follow instructions from https://github.com/vmolsa/webrtc-native/wiki/Getting-started#building-from-source'); 29 | } 30 | } 31 | 32 | var res = spawn('node', [ nodegyp, 'rebuild' ], { 33 | cwd: ROOT, 34 | env: process.env, 35 | stdio: 'inherit', 36 | }); 37 | 38 | res.on('error', function(error) { 39 | var res = spawn('iojs', [ nodegyp, 'rebuild' ], { 40 | cwd: ROOT, 41 | env: process.env, 42 | stdio: 'inherit', 43 | }); 44 | }); 45 | } 46 | 47 | function test() { 48 | console.log('Loading module...'); 49 | 50 | try { 51 | var WebRTC = require(path.resolve(ROOT, 'build', 'Release', 'webrtc.node')); 52 | 53 | setTimeout(function() { 54 | console.log('Done! :)'); 55 | }, 200); 56 | } catch (ignored) { 57 | 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.'); 58 | } 59 | } 60 | 61 | if (process.env['BUILD_WEBRTC'] == 'true') { 62 | build(); 63 | } else { 64 | console.log('Downloading module: webrtc-' + PACKAGE.version + '-' + PLATFORM + '-' + ARCH + '-' + NODEVER + '.node'); 65 | 66 | if (!fs.existsSync(path.resolve(ROOT, 'build', 'Release'))) { 67 | if (!fs.existsSync(path.resolve(ROOT, 'build'))) { 68 | fs.mkdirSync(path.resolve(ROOT, 'build')); 69 | } 70 | 71 | fs.mkdirSync(path.resolve(ROOT, 'build', 'Release')); 72 | } 73 | 74 | request.get(URL, function (error, response, body) { 75 | if (!error && response.statusCode == 200) { 76 | setTimeout(test, 200); 77 | } else { 78 | 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.'); 79 | } 80 | }).pipe(fs.createWriteStream(path.resolve(ROOT, 'build', 'Release', 'webrtc.node'))); 81 | } 82 | -------------------------------------------------------------------------------- /test/p2p-browser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/MediaCapturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef WEBRTC_MEDIACAPTURER_H 27 | #define WEBRTC_MEDIACAPTURER_H 28 | 29 | #include "Common.h" 30 | #include "Observers.h" 31 | #include "EventEmitter.h" 32 | #include "Wrap.h" 33 | 34 | namespace WebRTC { 35 | class MediaCapturer : 36 | public RTCWrap, 37 | public EventEmitter, 38 | public rtc::VideoSourceInterface, 39 | public webrtc::AudioTrackSinkInterface 40 | { 41 | public: 42 | static void Init(); 43 | 44 | static v8::Local New(webrtc::AudioSourceInterface *track = 0); 45 | static v8::Local New(webrtc::VideoSourceInterface *track = 0); 46 | 47 | private: 48 | MediaCapturer(); 49 | ~MediaCapturer() final; 50 | 51 | static void New(const Nan::FunctionCallbackInfo &info); 52 | static void Stop(const Nan::FunctionCallbackInfo &info); 53 | 54 | static void GetOnData(v8::Local property, const Nan::PropertyCallbackInfo &info); 55 | static void SetOnData(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 56 | 57 | void OnFrame(const cricket::VideoFrame &frame) final; 58 | void OnData(const void* audio_data, int bits_per_sample, int sample_rate, size_t number_of_channels, size_t number_of_frames) final; 59 | void On(Event *event) final; 60 | 61 | protected: 62 | rtc::scoped_refptr _video; 63 | rtc::scoped_refptr _audio; 64 | rtc::scoped_refptr _source; 65 | rtc::scoped_refptr _observer; 66 | 67 | Nan::Persistent _ondata; 68 | 69 | static Nan::Persistent constructor; 70 | }; 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /test/p2p.js: -------------------------------------------------------------------------------- 1 | var WEBRTC = require('../'); 2 | 3 | function P2P(alice, bob) { 4 | alice.onicecandidate = function(event) { 5 | var candidate = event.candidate || event; 6 | bob.addIceCandidate(candidate); 7 | }; 8 | 9 | bob.onicecandidate = function(event) { 10 | var candidate = event.candidate || event; 11 | alice.addIceCandidate(candidate); 12 | }; 13 | 14 | alice.onnegotiationneeded = function(callback) { 15 | alice.createOffer(function(sdp) { 16 | alice.setLocalDescription(sdp, function() { 17 | bob.setRemoteDescription(sdp, function() { 18 | bob.createAnswer(function(sdp) { 19 | bob.setLocalDescription(sdp, function() { 20 | alice.setRemoteDescription(sdp, function() { 21 | console.log("Alice -> Bob: Connected!"); 22 | 23 | if (callback) { 24 | callback(); 25 | } 26 | }); 27 | }); 28 | }); 29 | }); 30 | }); 31 | }); 32 | }; 33 | 34 | bob.onnegotiationneeded = function(callback) { 35 | bob.createOffer(function(sdp) { 36 | bob.setLocalDescription(sdp, function() { 37 | alice.setRemoteDescription(sdp, function() { 38 | alice.createAnswer(function(sdp) { 39 | alice.setLocalDescription(sdp, function() { 40 | bob.setRemoteDescription(sdp, function() { 41 | console.log("Bob -> Alice: Connected!"); 42 | 43 | if (callback) { 44 | callback(); 45 | } 46 | }); 47 | }); 48 | }); 49 | }); 50 | }); 51 | }); 52 | }; 53 | } 54 | 55 | var config = { 56 | iceServers: [ 57 | { 58 | url: 'stun:stun.l.google.com:19302', 59 | }, 60 | ], 61 | }; 62 | 63 | var constraints = { 64 | audio: { 65 | optional: [ 66 | { 67 | /* 68 | googEchoCancellation: true, 69 | googEchoCancellation2: true, 70 | googDAEchoCancellation: true, 71 | googAutoGainControl: true, 72 | googAutoGainControl2: true, 73 | googNoiseSuppression: true, 74 | googNoiseSuppression2: true, 75 | googHighpassFilter: true, 76 | googTypingNoiseDetection: true, 77 | googAudioMirroring: true, 78 | */ 79 | }, 80 | ], 81 | }, 82 | video: { 83 | optional: [ 84 | { 85 | minAspectRatio: 1.333, 86 | maxAspectRatio: 1.778, 87 | maxWidth: 1920, 88 | minWidth: 320, 89 | maxHeight: 1080, 90 | minHeight: 180, 91 | maxFrameRate: 60, 92 | minFrameRate: 30, 93 | }, 94 | ], 95 | }, 96 | optional: [ 97 | { 98 | DtlsSrtpKeyAgreement: true, 99 | }, 100 | ], 101 | mandatory: { 102 | OfferToReceiveAudio: true, 103 | OfferToReceiveVideo: true, 104 | }, 105 | }; 106 | 107 | var alice = new WEBRTC.RTCPeerConnection(config, constraints); 108 | var bob = new WEBRTC.RTCPeerConnection(config, constraints); 109 | 110 | P2P(alice, bob); 111 | 112 | alice.onnegotiationneeded(function() { 113 | console.log('Done! :)'); 114 | 115 | setTimeout(function() { 116 | console.log('Closing...'); 117 | 118 | alice.close(); 119 | bob.close(); 120 | }, 5000); 121 | }); 122 | -------------------------------------------------------------------------------- /test/p2p_stream.js: -------------------------------------------------------------------------------- 1 | var WEBRTC = require('../'); 2 | 3 | WEBRTC.setDebug(true); 4 | 5 | var config = { 6 | iceServers: [ 7 | { 8 | url: 'stun:stun.l.google.com:19302', 9 | }, 10 | ], 11 | }; 12 | 13 | var constraints = { 14 | audio: { 15 | optional: [ 16 | { 17 | googEchoCancellation: true, 18 | googEchoCancellation2: true, 19 | googDAEchoCancellation: true, 20 | googAutoGainControl: true, 21 | googAutoGainControl2: true, 22 | googNoiseSuppression: true, 23 | googNoiseSuppression2: true, 24 | googHighpassFilter: true, 25 | googTypingNoiseDetection: true, 26 | googAudioMirroring: true, 27 | }, 28 | ], 29 | }, 30 | video: { 31 | optional: [ 32 | { 33 | minAspectRatio: 1.333, 34 | maxAspectRatio: 1.778, 35 | maxWidth: 1920, 36 | minWidth: 320, 37 | maxHeight: 1080, 38 | minHeight: 180, 39 | maxFrameRate: 60, 40 | minFrameRate: 30, 41 | }, 42 | ], 43 | }, 44 | optional: [ 45 | { 46 | DtlsSrtpKeyAgreement: true, 47 | }, 48 | ], 49 | mandatory: { 50 | OfferToReceiveAudio: true, 51 | OfferToReceiveVideo: true, 52 | }, 53 | }; 54 | 55 | var alice = new WEBRTC.RTCPeerConnection(config, constraints); 56 | var bob = new WEBRTC.RTCPeerConnection(config, constraints); 57 | 58 | alice.onicecandidate = function (event) { 59 | var candidate = event.candidate || event; 60 | bob.addIceCandidate(candidate); 61 | }; 62 | 63 | bob.onicecandidate = function (event) { 64 | var candidate = event.candidate || event; 65 | alice.addIceCandidate(candidate); 66 | }; 67 | 68 | alice.onnegotiationneeded = function () { 69 | alice.createOffer(function (sdp) { 70 | alice.setLocalDescription(sdp, function () { 71 | bob.setRemoteDescription(sdp, function () { 72 | bob.createAnswer(function (sdp) { 73 | bob.setLocalDescription(sdp, function () { 74 | alice.setRemoteDescription(sdp, function () { 75 | console.log('Alice -> Bob Connected!'); 76 | }); 77 | }); 78 | }); 79 | }); 80 | }); 81 | }); 82 | }; 83 | 84 | bob.onnegotiationneeded = function () { 85 | bob.createOffer(function (sdp) { 86 | bob.setLocalDescription(sdp, function () { 87 | alice.setRemoteDescription(sdp, function () { 88 | alice.createAnswer(function (sdp) { 89 | alice.setLocalDescription(sdp, function () { 90 | bob.setRemoteDescription(sdp, function () { 91 | console.log('Bob -> Alice Connected!'); 92 | }); 93 | }); 94 | }); 95 | }); 96 | }); 97 | }); 98 | }; 99 | 100 | alice.onaddstream = function(stream) { 101 | console.log('Alice: mediaStream added!'); 102 | }; 103 | 104 | bob.onaddstream = function(stream) { 105 | console.log('Bob: mediaStream added!'); 106 | }; 107 | 108 | alice.onremovestream = function(stream) { 109 | console.log('Alice: mediaStream removed!'); 110 | }; 111 | 112 | bob.onremovestream = function(stream) { 113 | console.log('Bob: mediaStream removed!'); 114 | }; 115 | 116 | WEBRTC.getSources(function (inputs) { 117 | console.log(inputs); 118 | 119 | WEBRTC.getUserMedia(constraints, function(stream) { 120 | if (stream) { 121 | alice.addStream(stream); 122 | 123 | setTimeout(function () { 124 | alice.close(); 125 | bob.close(); 126 | }, 5000); 127 | } 128 | }); 129 | }); 130 | -------------------------------------------------------------------------------- /test/multiconnect.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var tape = require('tape'); 4 | var SimplePeer = require('simple-peer'); 5 | var wrtc = require('..'); 6 | 7 | //wrtc.setDebug(true); 8 | 9 | tape('connect once', function(t) { 10 | t.plan(1); 11 | console.log('###########################\n'); 12 | connect(function(err) { 13 | t.error(err, 'connect callback'); 14 | }); 15 | }); 16 | 17 | tape('connect loop', function(t) { 18 | t.plan(1); 19 | console.log('###########################\n'); 20 | connectLoop(10, function(err) { 21 | t.error(err, 'connect callback'); 22 | }); 23 | }); 24 | 25 | tape('connect concurrent', function(t) { 26 | var n = 10; 27 | t.plan(n); 28 | console.log('###########################\n'); 29 | for (var i = 0; i < n; i += 1) { 30 | connect(callback); 31 | } 32 | 33 | function callback(err) { 34 | t.error(err, 'connect callback'); 35 | } 36 | }); 37 | 38 | tape('connect loop concurrent', function(t) { 39 | var n = 10; 40 | t.plan(n); 41 | console.log('###########################\n'); 42 | for (var i = 0; i < n; i += 1) { 43 | connectLoop(10, callback); 44 | } 45 | 46 | function callback(err) { 47 | t.error(err, 'connect callback'); 48 | } 49 | }); 50 | 51 | var connIdGen = 1; 52 | 53 | function connect(callback) { 54 | var connId = connIdGen; 55 | var connName = 'CONNECTION-' + connId; 56 | connIdGen += 1; 57 | console.log(connName, 'starting'); 58 | 59 | // setup two peers with simple-peer 60 | var peer1 = new SimplePeer({ 61 | wrtc: wrtc 62 | }); 63 | var peer2 = new SimplePeer({ 64 | wrtc: wrtc, 65 | initiator: true 66 | }); 67 | 68 | var timeout = setTimeout(function () { 69 | peer1.destroy(); 70 | peer2.destroy(); 71 | 72 | callback(new Error("Timeout")); 73 | }, 10000); 74 | 75 | // when peer1 has signaling data, give it to peer2, and vice versa 76 | peer1.on('signal', function(data) { 77 | //console.log(connName, 'signal peer1 -> peer2:'); 78 | //console.log(' ', data); 79 | peer2.signal(data); 80 | }); 81 | peer2.on('signal', function(data) { 82 | //console.log(connName, 'signal peer2 -> peer1:'); 83 | //console.log(' ', data); 84 | peer1.signal(data); 85 | }); 86 | 87 | peer1.on('error', function(err) { 88 | console.log(connName, 'peer1 error', err); 89 | callback(err); 90 | }); 91 | 92 | peer2.on('error', function(err) { 93 | console.log(connName, 'peer2 error', err); 94 | callback(err); 95 | }); 96 | 97 | // wait for 'connect' event 98 | peer1.on('connect', function() { 99 | //console.log(connName, 'sending message'); 100 | peer1.send('peers are for kids'); 101 | }); 102 | 103 | peer2.on('data', function() { 104 | //console.log(connName, 'completed'); 105 | 106 | clearTimeout(timeout); 107 | 108 | peer1.destroy(); 109 | peer2.destroy(); 110 | 111 | callback(); 112 | }); 113 | } 114 | 115 | function connectLoop(count, callback) { 116 | if (count <= 0) { 117 | console.log('connect loop completed'); 118 | return callback(); 119 | } else { 120 | console.log('connect loop remain', count); 121 | connect(function(err) { 122 | if (err) { 123 | callback(err); 124 | } else { 125 | connectLoop(count - 1, callback); 126 | } 127 | }); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/MediaConstraints.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | 27 | #ifndef WEBRTC_MEDIACONSTRAINTS_H 28 | #define WEBRTC_MEDIACONSTRAINTS_H 29 | 30 | #include "Common.h" 31 | 32 | namespace WebRTC { 33 | class MediaConstraints : public webrtc::MediaConstraintsInterface, public rtc::RefCountInterface { 34 | friend class rtc::RefCountedObject; 35 | 36 | public: 37 | static rtc::scoped_refptr New(); 38 | static rtc::scoped_refptr New(const v8::Local &constraints); 39 | static rtc::scoped_refptr New(const v8::Local &constraints); 40 | 41 | bool UseAudio() const; 42 | bool UseVideo() const; 43 | 44 | std::string AudioId() const; 45 | std::string VideoId() const; 46 | 47 | bool IsMandatory(const std::string& key); 48 | bool GetMandatory(const std::string& key); 49 | void RemoveMandatory(const std::string& key); 50 | void AddMandatory(const std::string &key, const std::string &value); 51 | void SetMandatory(const std::string &key, const std::string &value); 52 | 53 | template void SetMandatory(const std::string& key, const T& value) { 54 | SetMandatory(key, rtc::ToString(value)); 55 | } 56 | 57 | bool IsOptional(const std::string& key); 58 | bool GetOptional(const std::string& key); 59 | void RemoveOptional(const std::string& key); 60 | void AddOptional(const std::string &key, const std::string &value); 61 | void SetOptional(const std::string &key, const std::string &value); 62 | 63 | template void SetOptional(const std::string& key, const T& value) { 64 | SetOptional(key, rtc::ToString(value)); 65 | } 66 | 67 | const webrtc::MediaConstraintsInterface *ToConstraints() const; 68 | const webrtc::MediaConstraintsInterface::Constraints &GetMandatory() const final; 69 | const webrtc::MediaConstraintsInterface::Constraints &GetOptional() const final; 70 | 71 | private: 72 | explicit MediaConstraints(); 73 | ~MediaConstraints() override; 74 | 75 | void SetOptional(std::string key, v8::Local value); 76 | void SetMandatory(std::string key, v8::Local value); 77 | 78 | protected: 79 | bool _audio; 80 | bool _video; 81 | 82 | std::string _audioId; 83 | std::string _videoId; 84 | 85 | webrtc::MediaConstraintsInterface::Constraints _mandatory; 86 | webrtc::MediaConstraintsInterface::Constraints _optional; 87 | }; 88 | }; 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /examples/node2browser/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 132 | 133 | -------------------------------------------------------------------------------- /src/BackTrace.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifdef USE_BACKTRACE 27 | #include "BackTrace.h" 28 | 29 | BackTrace BackTrace::landmine; 30 | 31 | void BackTrace::Dump(const char *event, int skip) { 32 | void *stack[50] = {0}; 33 | int count = 0, cur = 0; 34 | 35 | count = backtrace(stack, sizeof(stack)); 36 | 37 | if (count) { 38 | for (int index = (count - 1); index > skip && index >= 1; index--) { 39 | char addr[128] = {0}; 40 | Dl_info info; 41 | 42 | snprintf(addr, sizeof(addr), "%p", stack[index]); 43 | 44 | if (dladdr(stack[index], &info) && info.dli_sname) { 45 | char buffer[128] = {0}; 46 | size_t len = sizeof(buffer); 47 | int status = 0; 48 | 49 | (void) abi::__cxa_demangle(info.dli_sname, buffer, &len, &status); 50 | 51 | if (!status) { 52 | printf("%d: %s [%s] %s\n", cur, event, addr, buffer); 53 | } else { 54 | printf("%d: %s [%s] %s\n", cur, event, addr, info.dli_sname); 55 | } 56 | } else { 57 | printf("%d: %s [%s] function()\n", cur, event, addr); 58 | } 59 | 60 | cur++; 61 | } 62 | } 63 | } 64 | 65 | void BackTrace::Close() { 66 | _segv.sa_handler = SIG_DFL; 67 | _bus.sa_handler = SIG_DFL; 68 | _abrt.sa_handler = SIG_DFL; 69 | _ill.sa_handler = SIG_DFL; 70 | 71 | sigaction(SIGSEGV, &_segv, 0); 72 | sigaction(SIGBUS, &_bus, 0); 73 | sigaction(SIGABRT, &_abrt, 0); 74 | sigaction(SIGILL, &_ill, 0); 75 | } 76 | 77 | void BackTrace::OnSegv(int sig) { 78 | BackTrace::Dump("SIGSEGV", 2); 79 | landmine.Close(); 80 | } 81 | 82 | void BackTrace::OnBus(int sig) { 83 | BackTrace::Dump("SIGBUS", 2); 84 | landmine.Close(); 85 | } 86 | 87 | void BackTrace::OnAbort(int sig) { 88 | BackTrace::Dump("SIGABRT", 2); 89 | landmine.Close(); 90 | } 91 | 92 | void BackTrace::OnIll(int sig) { 93 | BackTrace::Dump("SIGILL", 2); 94 | landmine.Close(); 95 | } 96 | 97 | BackTrace::BackTrace() { 98 | sigemptyset(&_segv.sa_mask); 99 | sigemptyset(&_bus.sa_mask); 100 | sigemptyset(&_abrt.sa_mask); 101 | sigemptyset(&_ill.sa_mask); 102 | 103 | _segv.sa_flags = 0; 104 | _segv.sa_handler = BackTrace::OnSegv; 105 | 106 | _bus.sa_flags = 0; 107 | _bus.sa_handler = BackTrace::OnBus; 108 | 109 | _abrt.sa_flags = 0; 110 | _abrt.sa_handler = BackTrace::OnAbort; 111 | 112 | _ill.sa_flags = 0; 113 | _ill.sa_handler = BackTrace::OnIll; 114 | 115 | sigaction(SIGSEGV, &_segv, 0); 116 | sigaction(SIGBUS, &_bus, 0); 117 | sigaction(SIGABRT, &_abrt, 0); 118 | sigaction(SIGILL, &_ill, 0); 119 | } 120 | 121 | BackTrace::~BackTrace() { 122 | BackTrace::Close(); 123 | } 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /examples/node2browser/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var app = express(); 3 | var server = require('http').Server(app); 4 | var io = require('socket.io')(server); 5 | var WebRTC = require('../../'); 6 | 7 | app.use(express.static(__dirname)); 8 | 9 | var io = require('socket.io')(server); 10 | 11 | var config = { 12 | iceServers: [ 13 | { 14 | url: 'stun:stun.l.google.com:19302', 15 | }, 16 | ], 17 | }; 18 | 19 | var constraints = { 20 | audio: { 21 | optional: [ 22 | { 23 | googEchoCancellation: true, 24 | googEchoCancellation2: true, 25 | googDAEchoCancellation: true, 26 | googAutoGainControl: true, 27 | googAutoGainControl2: true, 28 | googNoiseSuppression: true, 29 | googNoiseSuppression2: true, 30 | googHighpassFilter: true, 31 | googTypingNoiseDetection: true, 32 | googAudioMirroring: true, 33 | }, 34 | ], 35 | }, 36 | video: true, 37 | /* 38 | video: { 39 | optional: [ 40 | { 41 | minAspectRatio: 1.333, 42 | maxAspectRatio: 1.778, 43 | maxWidth: 1920, 44 | minWidth: 320, 45 | maxHeight: 1080, 46 | minHeight: 180, 47 | maxFrameRate: 60, 48 | minFrameRate: 30, 49 | }, 50 | ], 51 | }, 52 | */ 53 | optional: [ 54 | { 55 | DtlsSrtpKeyAgreement: true, 56 | }, 57 | ], 58 | mandatory: { 59 | OfferToReceiveAudio: true, 60 | OfferToReceiveVideo: true, 61 | }, 62 | }; 63 | 64 | io.on('connection', function(socket) { 65 | console.log('Peer Connected'); 66 | 67 | var peer = new WebRTC.RTCPeerConnection(config, constraints); 68 | 69 | socket.on('disconnect', function () { 70 | console.log('Peer Disconnected'); 71 | peer.close(); 72 | }); 73 | 74 | socket.on('icecandidate', function(data) { 75 | if (data && data.candidate && data.sdpMid && data.sdpMLineIndex) { 76 | peer.addIceCandidate(new WebRTC.RTCIceCandidate(data)); 77 | } 78 | }); 79 | 80 | socket.on('offer', function(data) { 81 | peer.setRemoteDescription(new WebRTC.RTCSessionDescription(data), function() { 82 | peer.createAnswer(function(sdp) { 83 | peer.setLocalDescription(sdp, function() { 84 | socket.emit('answer', sdp); 85 | }); 86 | }); 87 | }); 88 | }); 89 | 90 | socket.on('answer', function(data) { 91 | peer.setRemoteDescription(new WebRTC.RTCSessionDescription(data)); 92 | }); 93 | 94 | peer.onicecandidate = function(event) { 95 | var candidate = event.candidate || event; 96 | socket.emit('icecandidate', candidate); 97 | }; 98 | 99 | peer.onnegotiationneeded = function() { 100 | peer.createOffer(function(sdp) { 101 | peer.setLocalDescription(sdp, function() { 102 | socket.emit('offer', sdp); 103 | }); 104 | }); 105 | }; 106 | 107 | peer.onaddstream = function(stream) { 108 | console.log('Peer: add mediaStream'); 109 | }; 110 | 111 | peer.onremovestream = function(stream) { 112 | console.log('Peer: remove mediaStream'); 113 | }; 114 | 115 | peer.ondatachannel = function(event) { 116 | var channel = event ? event.channel || event : null; 117 | 118 | channel.onopen = function() { 119 | console.log('Peer Channel opened!'); 120 | }; 121 | 122 | channel.onclose = function() { 123 | console.log('Peer Channel closed!'); 124 | }; 125 | 126 | channel.onmessage = function(event) { 127 | var data = event.data; 128 | 129 | if (data == 'PING') { 130 | console.log('Peer: Sending PONG'); 131 | channel.send('PONG'); 132 | } else { 133 | console.log('Peer Message:', data); 134 | channel.send(data); 135 | } 136 | }; 137 | }; 138 | 139 | peer.ondatachannel(peer.createDataChannel('echo')); 140 | 141 | WebRTC.getUserMedia(constraints, function(stream) { 142 | console.log('Sending Stream to Peer'); 143 | peer.addStream(stream); 144 | }); 145 | }); 146 | 147 | server.listen(8080, function() { 148 | console.log('Open in browser: http://localhost:8080/'); 149 | }); -------------------------------------------------------------------------------- /src/MediaStream.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef WEBRTC_MEDIASTREAM_H 27 | #define WEBRTC_MEDIASTREAM_H 28 | 29 | #include "Common.h" 30 | #include "Observers.h" 31 | #include "EventEmitter.h" 32 | #include "Wrap.h" 33 | 34 | namespace WebRTC { 35 | enum MediaStreamEvent { 36 | kMediaStreamChanged 37 | }; 38 | 39 | class MediaStream : public RTCWrap, public EventEmitter { 40 | public: 41 | static void Init(); 42 | static v8::Local New(rtc::scoped_refptr mediaStream); 43 | 44 | static rtc::scoped_refptr Unwrap(v8::Local value); 45 | static rtc::scoped_refptr Unwrap(v8::Local value); 46 | 47 | private: 48 | MediaStream(); 49 | ~MediaStream() final; 50 | 51 | static void New(const Nan::FunctionCallbackInfo &info); 52 | static void AddTrack(const Nan::FunctionCallbackInfo &info); 53 | static void Clone(const Nan::FunctionCallbackInfo &info); 54 | static void GetTrackById(const Nan::FunctionCallbackInfo &info); 55 | static void GetAudioTracks(const Nan::FunctionCallbackInfo &info); 56 | static void GetVideoTracks(const Nan::FunctionCallbackInfo &info); 57 | static void GetTracks(const Nan::FunctionCallbackInfo &info); 58 | static void RemoveTrack(const Nan::FunctionCallbackInfo &info); 59 | 60 | static void GetActive(v8::Local property, const Nan::PropertyCallbackInfo &info); 61 | static void GetEnded(v8::Local property, const Nan::PropertyCallbackInfo &info); 62 | static void GetId(v8::Local property, const Nan::PropertyCallbackInfo &info); 63 | static void GetOnAddTrack(v8::Local property, const Nan::PropertyCallbackInfo &info); 64 | static void GetOnRemoveTrack(v8::Local property, const Nan::PropertyCallbackInfo &info); 65 | 66 | static void ReadOnly(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 67 | static void SetOnAddTrack(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 68 | static void SetOnRemoveTrack(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 69 | 70 | void CheckState(); 71 | void On(Event *event) final; 72 | 73 | protected: 74 | bool _active; 75 | bool _ended; 76 | 77 | Nan::Persistent _onaddtrack; 78 | Nan::Persistent _onremovetrack; 79 | 80 | rtc::scoped_refptr _observer; 81 | rtc::scoped_refptr _stream; 82 | 83 | webrtc::AudioTrackVector _audio_tracks; 84 | webrtc::VideoTrackVector _video_tracks; 85 | 86 | static Nan::Persistent constructor; 87 | }; 88 | }; 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /test/mediaStream.js: -------------------------------------------------------------------------------- 1 | var WEBRTC = require('../'); 2 | 3 | var config = { 4 | iceServers: [ 5 | { 6 | url: 'stun:stun.l.google.com:19302', 7 | }, 8 | ], 9 | }; 10 | 11 | var constraints = { 12 | audio: { 13 | optional: [ 14 | { 15 | googEchoCancellation: true, 16 | googEchoCancellation2: true, 17 | googDAEchoCancellation: true, 18 | googAutoGainControl: true, 19 | googAutoGainControl2: true, 20 | googNoiseSuppression: true, 21 | googNoiseSuppression2: true, 22 | googHighpassFilter: true, 23 | googTypingNoiseDetection: true, 24 | googAudioMirroring: true, 25 | }, 26 | ], 27 | }, 28 | video: { 29 | optional: [ 30 | { 31 | minAspectRatio: 1.333, 32 | maxAspectRatio: 1.778, 33 | maxWidth: 1920, 34 | minWidth: 320, 35 | maxHeight: 1080, 36 | minHeight: 180, 37 | maxFrameRate: 60, 38 | minFrameRate: 30, 39 | }, 40 | ], 41 | }, 42 | optional: [ 43 | { 44 | DtlsSrtpKeyAgreement: true, 45 | }, 46 | ], 47 | mandatory: { 48 | OfferToReceiveAudio: true, 49 | OfferToReceiveVideo: true, 50 | }, 51 | }; 52 | 53 | function P2P(alice, bob) { 54 | function showState() { 55 | console.log('Alice State:', alice.signalingState); 56 | console.log('Bob State:', bob.signalingState); 57 | } 58 | 59 | alice.onicecandidate = function(event) { 60 | var candidate = event.candidate || event; 61 | bob.addIceCandidate(candidate); 62 | }; 63 | 64 | bob.onicecandidate = function(event) { 65 | var candidate = event.candidate || event; 66 | alice.addIceCandidate(candidate); 67 | }; 68 | 69 | alice.onnegotiationneeded = function() { 70 | showState(); 71 | 72 | alice.createOffer(function(sdp) { 73 | showState(); 74 | 75 | alice.setLocalDescription(sdp, function() { 76 | showState(); 77 | 78 | bob.setRemoteDescription(sdp, function() { 79 | showState(); 80 | 81 | bob.createAnswer(function(sdp) { 82 | showState(); 83 | 84 | bob.setLocalDescription(sdp, function() { 85 | showState(); 86 | 87 | alice.setRemoteDescription(sdp, function() { 88 | showState(); 89 | }); 90 | }); 91 | }); 92 | }); 93 | }); 94 | }); 95 | }; 96 | 97 | bob.onnegotiationneeded = function() { 98 | showState(); 99 | 100 | bob.createOffer(function(sdp) { 101 | showState(); 102 | 103 | bob.setLocalDescription(sdp, function() { 104 | showState(); 105 | 106 | alice.setRemoteDescription(sdp, function() { 107 | showState(); 108 | 109 | alice.createAnswer(function(sdp) { 110 | showState(); 111 | 112 | alice.setLocalDescription(sdp, function() { 113 | showState(); 114 | 115 | bob.setRemoteDescription(sdp, function() { 116 | showState(); 117 | }); 118 | }); 119 | }); 120 | }); 121 | }); 122 | }); 123 | }; 124 | 125 | alice.onaddstream = function(stream) { 126 | if (stream) { 127 | console.log('Alice got mediaStream'); 128 | } 129 | }; 130 | 131 | bob.onaddstream = function(stream) { 132 | if (stream) { 133 | console.log('Bob got mediaStream'); 134 | } 135 | }; 136 | } 137 | 138 | WEBRTC.setDebug(true); 139 | 140 | var alice = new WEBRTC.RTCPeerConnection(config, constraints); 141 | var bob = new WEBRTC.RTCPeerConnection(config, constraints); 142 | 143 | P2P(alice, bob); 144 | 145 | function onSuccess(stream) { 146 | if (stream) { 147 | console.log('Alice: new mediaStream'); 148 | alice.addStream(stream); 149 | 150 | setTimeout(function () { 151 | alice.close(); 152 | bob.close(); 153 | }, 10000); 154 | } 155 | } 156 | 157 | function onError(error) { 158 | throw error; 159 | } 160 | 161 | WEBRTC.getUserMedia(constraints, onSuccess, onError); -------------------------------------------------------------------------------- /src/Observers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef WEBRTC_OBSERVERS_H 27 | #define WEBRTC_OBSERVERS_H 28 | 29 | #include "EventEmitter.h" 30 | 31 | namespace WebRTC { 32 | class OfferObserver : public webrtc::CreateSessionDescriptionObserver, public NotifyEmitter { 33 | public: 34 | OfferObserver(EventEmitter *listener = 0); 35 | 36 | void OnSuccess(webrtc::SessionDescriptionInterface* sdp) final; 37 | void OnFailure(const std::string &error) final; 38 | }; 39 | 40 | class AnswerObserver : public webrtc::CreateSessionDescriptionObserver, public NotifyEmitter { 41 | public: 42 | AnswerObserver(EventEmitter *listener = 0); 43 | 44 | void OnSuccess(webrtc::SessionDescriptionInterface* sdp) final; 45 | void OnFailure(const std::string &error) final; 46 | }; 47 | 48 | class LocalDescriptionObserver : public webrtc::SetSessionDescriptionObserver, public NotifyEmitter { 49 | public: 50 | LocalDescriptionObserver(EventEmitter *listener = 0); 51 | 52 | void OnSuccess() final; 53 | void OnFailure(const std::string &error) final; 54 | }; 55 | 56 | class RemoteDescriptionObserver : public webrtc::SetSessionDescriptionObserver, public NotifyEmitter { 57 | public: 58 | RemoteDescriptionObserver(EventEmitter *listener = 0); 59 | 60 | void OnSuccess() final; 61 | void OnFailure(const std::string &error) final; 62 | }; 63 | 64 | class PeerConnectionObserver : 65 | public webrtc::PeerConnectionObserver, 66 | public rtc::RefCountInterface, 67 | public NotifyEmitter 68 | { 69 | public: 70 | PeerConnectionObserver(EventEmitter *listener = 0); 71 | 72 | void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState state) final; 73 | void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState state) final; 74 | void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState state) final; 75 | void OnStateChange(webrtc::PeerConnectionObserver::StateType state); 76 | void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) final; 77 | void OnDataChannel(webrtc::DataChannelInterface* channel) final; 78 | void OnRenegotiationNeeded() final; 79 | 80 | void OnAddStream(webrtc::MediaStreamInterface* stream) final; 81 | void OnRemoveStream(webrtc::MediaStreamInterface* stream) final; 82 | }; 83 | 84 | class DataChannelObserver : 85 | public webrtc::DataChannelObserver, 86 | public rtc::RefCountInterface, 87 | public NotifyEmitter 88 | { 89 | public: 90 | DataChannelObserver(EventEmitter *listener = 0); 91 | 92 | void OnStateChange() final; 93 | void OnMessage(const webrtc::DataBuffer& buffer) final; 94 | }; 95 | 96 | class MediaStreamObserver : 97 | public webrtc::ObserverInterface, 98 | public rtc::RefCountInterface, 99 | public NotifyEmitter 100 | { 101 | public: 102 | MediaStreamObserver(EventEmitter *listener = 0); 103 | 104 | void OnChanged() final; 105 | }; 106 | 107 | class MediaStreamTrackObserver : 108 | public webrtc::ObserverInterface, 109 | public rtc::RefCountInterface, 110 | public NotifyEmitter 111 | { 112 | public: 113 | MediaStreamTrackObserver(EventEmitter *listener = 0); 114 | 115 | void OnChanged() final; 116 | }; 117 | 118 | class StatsObserver : public webrtc::StatsObserver, public NotifyEmitter { 119 | public: 120 | StatsObserver(EventEmitter *listener = 0); 121 | 122 | void OnComplete(const webrtc::StatsReports& reports) final; 123 | }; 124 | }; 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /src/EventEmitter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef WEBRTC_EVENTEMITTER_H 27 | #define WEBRTC_EVENTEMITTER_H 28 | 29 | #include "Common.h" 30 | 31 | namespace WebRTC { 32 | template class EventWrapper; 33 | 34 | class Event : public rtc::RefCountInterface { 35 | template friend class EventWrapper; 36 | friend class rtc::RefCountedObject; 37 | friend class EventEmitter; 38 | 39 | public: 40 | inline bool HasWrap() const { 41 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 42 | 43 | return _wrap; 44 | } 45 | 46 | template inline T Type() const { 47 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 48 | 49 | return static_cast(_event); 50 | } 51 | 52 | template const T &Unwrap() const { 53 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 54 | 55 | static T nowrap; 56 | 57 | if (_wrap) { 58 | const EventWrapper *ptr = static_cast *>(this); 59 | return ptr->_content; 60 | } 61 | 62 | nowrap = T(); 63 | return nowrap; 64 | } 65 | 66 | private: 67 | explicit Event(int event = 0) : 68 | _event(event), 69 | _wrap(false) 70 | { 71 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 72 | } 73 | 74 | virtual ~Event() { 75 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 76 | } 77 | 78 | protected: 79 | int _event; 80 | bool _wrap; 81 | }; 82 | 83 | template class EventWrapper : public Event { 84 | friend class rtc::RefCountedObject >; 85 | friend class Event; 86 | friend class EventEmitter; 87 | 88 | private: 89 | explicit EventWrapper(int event, const T &content) : 90 | Event(event), 91 | _content(content) 92 | { 93 | _wrap = true; 94 | } 95 | 96 | virtual ~EventWrapper() { } 97 | 98 | protected: 99 | T _content; 100 | }; 101 | 102 | class EventEmitter { 103 | friend class NotifyEmitter; 104 | 105 | public: 106 | explicit EventEmitter(uv_loop_t *loop = 0, bool notify = false); 107 | virtual ~EventEmitter(); 108 | 109 | void AddListener(EventEmitter *listener = 0); 110 | void RemoveListener(EventEmitter *listener = 0); 111 | void RemoveAllListeners(); 112 | 113 | void SetReference(bool alive = true); 114 | 115 | void Emit(int event = 0); 116 | void Emit(rtc::scoped_refptr event); 117 | 118 | template inline void Emit(int event, const T &content) { 119 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 120 | EventEmitter::Emit(new rtc::RefCountedObject >(event, content)); 121 | } 122 | 123 | virtual void On(Event *event) = 0; 124 | 125 | private: 126 | static void onAsync(uv_async_t *handle, int status); 127 | static void onEnded(uv_handle_t *handle); 128 | 129 | void Dispose(); 130 | void DispatchEvents(); 131 | 132 | void AddParent(EventEmitter *listener = 0); 133 | void RemoveParent(EventEmitter *listener = 0); 134 | 135 | protected: 136 | bool _notify; 137 | uv_mutex_t _lock; 138 | uv_mutex_t _list; 139 | uv_async_t* _async; 140 | std::queue > _events; 141 | std::vector _listeners; 142 | std::vector _parents; 143 | }; 144 | 145 | class NotifyEmitter : public EventEmitter { 146 | public: 147 | NotifyEmitter(EventEmitter *listener = 0); 148 | 149 | virtual void On(Event *event); 150 | }; 151 | }; 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /src/Module.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #include "Common.h" 27 | 28 | #include "Global.h" 29 | #include "Platform.h" 30 | #include "Stats.h" 31 | #include "PeerConnection.h" 32 | #include "DataChannel.h" 33 | #include "BackTrace.h" 34 | #include "GetSources.h" 35 | #include "GetUserMedia.h" 36 | #include "MediaStream.h" 37 | #include "MediaStreamTrack.h" 38 | 39 | using namespace v8; 40 | 41 | void SetDebug(const Nan::FunctionCallbackInfo &info) { 42 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 43 | 44 | if (info.Length() && !info[0].IsEmpty()) { 45 | if (info[0]->IsTrue()) { 46 | rtc::LogMessage::LogToDebug(rtc::LS_VERBOSE); 47 | } else { 48 | rtc::LogMessage::LogToDebug(rtc::LS_NONE); 49 | } 50 | } 51 | 52 | info.GetReturnValue().SetUndefined(); 53 | } 54 | 55 | void RTCGarbageCollect(const Nan::FunctionCallbackInfo &info) { 56 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 57 | 58 | Nan::LowMemoryNotification(); 59 | info.GetReturnValue().SetUndefined(); 60 | } 61 | 62 | void RTCIceCandidate(const Nan::FunctionCallbackInfo &info) { 63 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 64 | 65 | if (info.Length() == 1 && info[0]->IsObject() && info.IsConstructCall()) { 66 | Local arg = info[0]->ToObject(); 67 | Local retval = Nan::New(); 68 | 69 | retval->Set(Nan::New("candidate").ToLocalChecked(), arg->Get(Nan::New("candidate").ToLocalChecked())); 70 | retval->Set(Nan::New("sdpMLineIndex").ToLocalChecked(), arg->Get(Nan::New("sdpMLineIndex").ToLocalChecked())); 71 | retval->Set(Nan::New("sdpMid").ToLocalChecked(), arg->Get(Nan::New("sdpMid").ToLocalChecked())); 72 | 73 | return info.GetReturnValue().Set(retval); 74 | } else { 75 | return info.GetReturnValue().Set(info[0]); 76 | } 77 | } 78 | 79 | void RTCSessionDescription(const Nan::FunctionCallbackInfo &info) { 80 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 81 | 82 | if (info.Length() == 1 && info[0]->IsObject() && info.IsConstructCall()) { 83 | Local arg = info[0]->ToObject(); 84 | Local retval = Nan::New(); 85 | 86 | retval->Set(Nan::New("type").ToLocalChecked(), arg->Get(Nan::New("type").ToLocalChecked())); 87 | retval->Set(Nan::New("sdp").ToLocalChecked(), arg->Get(Nan::New("sdp").ToLocalChecked())); 88 | 89 | return info.GetReturnValue().Set(retval); 90 | } else { 91 | return info.GetReturnValue().Set(info[0]); 92 | } 93 | } 94 | 95 | void WebrtcModuleDispose(void *arg) { 96 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 97 | 98 | WebRTC::Platform::Dispose(); 99 | } 100 | 101 | void WebrtcModuleInit(Handle exports) { 102 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 103 | 104 | Nan::HandleScope scope; 105 | 106 | WebRTC::Global::Init(exports); 107 | WebRTC::Platform::Init(); 108 | WebRTC::RTCStatsResponse::Init(); 109 | WebRTC::RTCStatsReport::Init(); 110 | WebRTC::PeerConnection::Init(exports); 111 | WebRTC::DataChannel::Init(); 112 | WebRTC::GetSources::Init(exports); 113 | WebRTC::GetUserMedia::Init(exports); 114 | WebRTC::MediaStream::Init(); 115 | WebRTC::MediaStreamTrack::Init(); 116 | 117 | exports->Set(Nan::New("RTCGarbageCollect").ToLocalChecked(), Nan::New(RTCGarbageCollect)->GetFunction()); 118 | exports->Set(Nan::New("RTCIceCandidate").ToLocalChecked(), Nan::New(RTCIceCandidate)->GetFunction()); 119 | exports->Set(Nan::New("RTCSessionDescription").ToLocalChecked(), Nan::New(RTCSessionDescription)->GetFunction()); 120 | exports->Set(Nan::New("setDebug").ToLocalChecked(), Nan::New(SetDebug)->GetFunction()); 121 | 122 | node::AtExit(WebrtcModuleDispose); 123 | } 124 | 125 | NODE_MODULE(webrtc, WebrtcModuleInit) -------------------------------------------------------------------------------- /src/GetUserMedia.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #include "Platform.h" 27 | #include "GetUserMedia.h" 28 | #include "GetSources.h" 29 | #include "MediaStream.h" 30 | #include "MediaConstraints.h" 31 | 32 | using namespace v8; 33 | using namespace WebRTC; 34 | 35 | void GetUserMedia::Init(Handle exports) { 36 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 37 | 38 | exports->Set(Nan::New("getUserMedia").ToLocalChecked(), Nan::New(GetUserMedia::GetMediaStream)->GetFunction()); 39 | } 40 | 41 | void GetUserMedia::GetMediaStream(const Nan::FunctionCallbackInfo &info) { 42 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 43 | 44 | rtc::scoped_refptr stream; 45 | rtc::scoped_refptr constraints = MediaConstraints::New(info[0]); 46 | const char *error = 0; 47 | bool have_source = false; 48 | 49 | std::string audioId = constraints->AudioId(); 50 | std::string videoId = constraints->VideoId(); 51 | 52 | if (constraints->UseAudio() || constraints->UseVideo()) { 53 | rtc::scoped_refptr factory = webrtc::CreatePeerConnectionFactory(rtc::Thread::Current(), Platform::GetWorker(), 0, 0, 0); 54 | 55 | if (factory.get()) { 56 | stream = factory->CreateLocalMediaStream("stream"); 57 | 58 | if (stream.get()) { 59 | if (constraints->UseAudio()) { 60 | rtc::scoped_refptr audio_track; 61 | 62 | if (audioId.empty()) { 63 | audio_track = GetSources::GetAudioSource(constraints); 64 | } else { 65 | audio_track = GetSources::GetAudioSource(audioId, constraints); 66 | } 67 | 68 | if (audio_track.get()) { 69 | if (!stream->AddTrack(audio_track)) { 70 | error = "Invalid Audio Input"; 71 | } else { 72 | have_source = true; 73 | } 74 | } else { 75 | if (!audioId.empty()) { 76 | error = "Invalid Audio Input"; 77 | } 78 | } 79 | } 80 | 81 | if (constraints->UseVideo()) { 82 | rtc::scoped_refptr video_track; 83 | 84 | if (videoId.empty()) { 85 | video_track = GetSources::GetVideoSource(constraints); 86 | } else { 87 | video_track = GetSources::GetVideoSource(videoId, constraints); 88 | } 89 | 90 | if (video_track.get()) { 91 | if (!stream->AddTrack(video_track)) { 92 | error = "Invalid Video Input"; 93 | } else { 94 | have_source = true; 95 | } 96 | } else { 97 | if (!videoId.empty()) { 98 | error = "Invalid Video Input"; 99 | } 100 | } 101 | } 102 | } else { 103 | error = "Internal Error"; 104 | } 105 | } 106 | } 107 | 108 | if (!have_source) { 109 | error = "No available inputs"; 110 | } 111 | 112 | Handle argv[1]; 113 | 114 | if (!error) { 115 | if (stream.get()) { 116 | argv[0] = MediaStream::New(stream); 117 | } else { 118 | error = "Invalid MediaStream"; 119 | } 120 | } 121 | 122 | if (error) { 123 | if (!info[2].IsEmpty() && info[2]->IsFunction()) { 124 | Local onerror = Local::Cast(info[2]); 125 | argv[0] = Nan::Error(error); 126 | 127 | onerror->Call(info.This(), 1, argv); 128 | } else { 129 | Nan::ThrowError(error); 130 | } 131 | } else { 132 | if (!info[1].IsEmpty() && info[1]->IsFunction()) { 133 | Local onsuccess = Local::Cast(info[1]); 134 | onsuccess->Call(info.This(), 1, argv); 135 | } 136 | } 137 | 138 | info.GetReturnValue().SetUndefined(); 139 | } 140 | -------------------------------------------------------------------------------- /src/DataChannel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef WEBRTC_DATACHANNEL_H 27 | #define WEBRTC_DATACHANNEL_H 28 | 29 | #include "Common.h" 30 | #include "Observers.h" 31 | #include "EventEmitter.h" 32 | #include "Wrap.h" 33 | #include "ArrayBuffer.h" 34 | 35 | namespace WebRTC { 36 | enum DataChannelEvent { 37 | kDataChannelStateChange, 38 | kDataChannelBinary, 39 | kDataChannelData, 40 | }; 41 | 42 | class DataChannel : public RTCWrap, public EventEmitter { 43 | public: 44 | static void Init(); 45 | static v8::Local New(rtc::scoped_refptr dataChannel); 46 | 47 | private: 48 | DataChannel(); 49 | ~DataChannel() final; 50 | 51 | static void New(const Nan::FunctionCallbackInfo &info); 52 | static void Close(const Nan::FunctionCallbackInfo &info); 53 | static void Send(const Nan::FunctionCallbackInfo &info); 54 | 55 | static void GetId(v8::Local property, const Nan::PropertyCallbackInfo &info); 56 | static void GetLabel(v8::Local property, const Nan::PropertyCallbackInfo &info); 57 | static void GetOrdered(v8::Local property, const Nan::PropertyCallbackInfo &info); 58 | static void GetProtocol(v8::Local property, const Nan::PropertyCallbackInfo &info); 59 | static void GetReadyState(v8::Local property, const Nan::PropertyCallbackInfo &info); 60 | static void GetBufferedAmount(v8::Local property, const Nan::PropertyCallbackInfo &info); 61 | static void GetBinaryType(v8::Local property, const Nan::PropertyCallbackInfo &info); 62 | static void GetMaxPacketLifeType(v8::Local property, const Nan::PropertyCallbackInfo &info); 63 | static void GetMaxRetransmits(v8::Local property, const Nan::PropertyCallbackInfo &info); 64 | static void GetNegotiated(v8::Local property, const Nan::PropertyCallbackInfo &info); 65 | static void GetReliable(v8::Local property, const Nan::PropertyCallbackInfo &info); 66 | static void GetOnOpen(v8::Local property, const Nan::PropertyCallbackInfo &info); 67 | static void GetOnMessage(v8::Local property, const Nan::PropertyCallbackInfo &info); 68 | static void GetOnClose(v8::Local property, const Nan::PropertyCallbackInfo &info); 69 | static void GetOnError(v8::Local property, const Nan::PropertyCallbackInfo &info); 70 | 71 | static void ReadOnly(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 72 | static void SetBinaryType(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 73 | static void SetOnOpen(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 74 | static void SetOnMessage(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 75 | static void SetOnClose(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 76 | static void SetOnError(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 77 | 78 | void On(Event *event) final; 79 | 80 | webrtc::DataChannelInterface *GetSocket() const; 81 | 82 | protected: 83 | rtc::scoped_refptr _observer; 84 | rtc::scoped_refptr _socket; 85 | 86 | Nan::Persistent _binaryType; 87 | 88 | Nan::Persistent _onopen; 89 | Nan::Persistent _onmessage; 90 | Nan::Persistent _onclose; 91 | Nan::Persistent _onerror; 92 | 93 | static Nan::Persistent constructor; 94 | }; 95 | }; 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /examples/node2browser_ws/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 177 | 178 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /examples/node2browser_ws/index.js: -------------------------------------------------------------------------------- 1 | var WebRTC = require('../../'); 2 | var WebSocketServer = require('ws').Server; 3 | var express = require('express'); 4 | var app = express(); 5 | var server = require('http').Server(app); 6 | WebRTC.setDebug(false); 7 | app.use(express.static(__dirname)); 8 | 9 | var _sources = []; 10 | var localstream =undefined; 11 | var initialized = false; 12 | 13 | var config = { 14 | iceServers: [ 15 | { 16 | url: 'stun:stun.l.google.com:19302', 17 | }, 18 | ], 19 | }; 20 | 21 | var constraints = { 22 | audio: true, 23 | video: true, 24 | }; 25 | 26 | 27 | 28 | function sourceSelected(audioSource, videoSource) { 29 | 30 | _sources.push(videoSource); 31 | 32 | } 33 | 34 | 35 | WebRTC.getSources(function(sourceInfos) { 36 | 37 | 38 | for (var i = 0; i != sourceInfos.length; ++i) { 39 | var sourceInfo = sourceInfos[i]; 40 | if (sourceInfo.kind === 'audio') { 41 | console.log(sourceInfo.id, sourceInfo.label || 'microphone'); 42 | 43 | audioSource = sourceInfo.id; 44 | } else if (sourceInfo.kind === 'video') { 45 | console.log(sourceInfo.id, sourceInfo.label || 'camera'); 46 | 47 | _sources.push (sourceInfo.id); 48 | } else { 49 | console.log('Some other kind of source: ', sourceInfo); 50 | } 51 | } 52 | 53 | WebRTC.getUserMedia(constraints, getUserMedia_successCallback, getUserMedia_errorCallback); 54 | 55 | }); 56 | 57 | 58 | function getUserMedia_successCallback(stream) { 59 | 60 | localstream = stream; 61 | var video_list = localstream.getVideoTracks(); 62 | 63 | video_list.forEach(function (track) { 64 | console.log('Video Track %s', JSON.stringify(track)); 65 | track.readyState = "alive"; 66 | }); 67 | console.log('Sending Stream to Peer'); 68 | initialized = true; 69 | init(); 70 | } 71 | 72 | function getUserMedia_errorCallback(error) { 73 | console.log ('error %s',error); 74 | } 75 | 76 | function setLocalSDP(p, callback){ 77 | if(p.iceGatheringState != 'complete'){ 78 | setTimeout(function(){ 79 | setLocalSDP(p, callback); 80 | }, 10); 81 | }else{ 82 | callback && callback(); 83 | } 84 | } 85 | 86 | 87 | function init() 88 | { 89 | ws = new WebSocketServer( 90 | { 91 | host: '127.0.0.1', 92 | port: 8181 93 | }); // start websocket server 94 | 95 | ws.on('connection', onConnect_Handler); 96 | 97 | 98 | function onConnect_Handler(connection) 99 | { 100 | 101 | var peer = new WebRTC.RTCPeerConnection(null, {audio: true, video: true}); 102 | peer.addStream(localstream); 103 | peer.onicecandidate = function(event) { 104 | var candidate = event.candidate || event; 105 | connection.send(JSON.stringify({'type':'icecandidate', 'data':candidate})); 106 | }; 107 | peer.createOffer(function(offer){ 108 | peer.setLocalDescription(new WebRTC.RTCSessionDescription(offer), function(){ 109 | setLocalSDP(peer, function(){ 110 | var offerSDP = JSON.stringify(peer.localDescription); 111 | connection.send(offerSDP); 112 | }); 113 | }, function(e){ 114 | console.log (e); 115 | }) 116 | }); 117 | 118 | connection.on('message', function onWsMessage(message, flags) 119 | { 120 | console.log ("INCOMMING %s:", message); 121 | var jmsg = undefined; 122 | try 123 | { 124 | jmsg = JSON.parse(message); 125 | } 126 | catch (e) 127 | { 128 | return ; 129 | } 130 | 131 | if (jmsg.type=='answer') 132 | { 133 | console.log ('answer'); 134 | var clientRemoteSDP = new WebRTC.RTCSessionDescription(jmsg); 135 | peer.setRemoteDescription(clientRemoteSDP, function(){ 136 | console.log('setRemoteDescription OK'); 137 | }, function(err){ 138 | console.log('setRemoteDescription error', err); 139 | }) 140 | } 141 | if (jmsg.hasOwnProperty('candidate')) 142 | { 143 | console.log ('icecandidate: jmsg: %s',JSON.stringify(jmsg)); 144 | peer.addIceCandidate(new WebRTC.RTCIceCandidate(jmsg)); 145 | 146 | } 147 | }); 148 | 149 | 150 | 151 | 152 | peer.onnegotiationneeded = function() { 153 | console.log ('onnegotiationneeded'); 154 | 155 | }; 156 | 157 | peer.onaddstream = function(stream) { 158 | console.log('Peer: add mediaStream'); 159 | }; 160 | 161 | peer.onremovestream = function(stream) { 162 | console.log('Peer: remove mediaStream'); 163 | }; 164 | 165 | peer.ondatachannel = function(event) { 166 | var channel = event ? event.channel || event : null; 167 | 168 | channel.onopen = function() { 169 | console.log('Peer Channel opened!'); 170 | }; 171 | 172 | channel.onclose = function() { 173 | console.log('Peer Channel closed!'); 174 | }; 175 | 176 | channel.onmessage = function(event) { 177 | var data = event.data; 178 | 179 | if (data == 'PING') { 180 | console.log('Peer: Sending PONG'); 181 | channel.send('PONG'); 182 | } else { 183 | console.log('Peer Message:', data); 184 | channel.send(data); 185 | } 186 | }; 187 | }; 188 | 189 | peer.ondatachannel(peer.createDataChannel('echo')); 190 | 191 | 192 | } 193 | 194 | 195 | server.listen(8281, function() { 196 | console.log('Open in browser: http://localhost:8281/index.html'); 197 | }); 198 | } 199 | // */ 200 | 201 | -------------------------------------------------------------------------------- /test/dataChannel.js: -------------------------------------------------------------------------------- 1 | var WebRTC = require('../'); 2 | 3 | //WebRTC.setDebug(true); 4 | 5 | function P2P(alice, bob) { 6 | alice.onicecandidate = function(event) { 7 | var candidate = event.candidate; 8 | 9 | if (candidate) { 10 | bob.addIceCandidate(candidate); 11 | } 12 | }; 13 | 14 | bob.onicecandidate = function(event) { 15 | var candidate = event.candidate; 16 | 17 | if (candidate) { 18 | alice.addIceCandidate(candidate); 19 | } 20 | }; 21 | 22 | alice.onnegotiationneeded = function() { 23 | alice.createOffer(function(sdp) { 24 | alice.setLocalDescription(sdp, function() { 25 | bob.setRemoteDescription(sdp, function() { 26 | bob.createAnswer(function(sdp) { 27 | bob.setLocalDescription(sdp, function() { 28 | alice.setRemoteDescription(sdp, function() { 29 | console.log("Alice -> Bob: Connected!"); 30 | }); 31 | }); 32 | }); 33 | }); 34 | }); 35 | }); 36 | }; 37 | 38 | bob.onnegotiationneeded = function() { 39 | bob.createOffer(function(sdp) { 40 | bob.setLocalDescription(sdp, function() { 41 | alice.setRemoteDescription(sdp, function() { 42 | alice.createAnswer(function(sdp) { 43 | alice.setLocalDescription(sdp, function() { 44 | bob.setRemoteDescription(sdp, function() { 45 | console.log("Bob -> Alice: Connected!"); 46 | }); 47 | }); 48 | }); 49 | }); 50 | }); 51 | }); 52 | }; 53 | 54 | alice.onaddstream = function(stream) { 55 | if (stream) { 56 | console.log('Alice got mediaStream'); 57 | } 58 | }; 59 | 60 | bob.onaddstream = function(stream) { 61 | if (stream) { 62 | console.log('Bob got mediaStream'); 63 | } 64 | }; 65 | 66 | alice.ondatachannel = function(event, callback) { 67 | var channel = event ? event.channel || event : null; 68 | 69 | if (!channel) { 70 | return false; 71 | } 72 | 73 | console.log('Alice: Got DataChannel!'); 74 | 75 | channel.onopen = function() { 76 | console.log('Alice: DataChannel Open!'); 77 | 78 | if (callback) { 79 | callback(channel); 80 | } 81 | }; 82 | 83 | channel.onmessage = function(event) { 84 | var data = event.data; 85 | console.log('Alice:', data); 86 | }; 87 | 88 | channel.onclose = function() { 89 | console.log('Alice: DataChannel Closed!'); 90 | }; 91 | }; 92 | 93 | bob.ondatachannel = function(event, callback) { 94 | var channel = event ? event.channel || event : null; 95 | 96 | if (!channel) { 97 | return false; 98 | } 99 | 100 | console.log('Bob: Got DataChannel!'); 101 | 102 | channel.onopen = function() { 103 | console.log('Bob: DataChannel Open!'); 104 | 105 | if (callback) { 106 | callback(channel); 107 | } 108 | }; 109 | 110 | channel.onmessage = function(event) { 111 | var data = event.data; 112 | console.log('Bob:', data); 113 | channel.send('Hello Alice!'); 114 | }; 115 | 116 | channel.onclose = function() { 117 | console.log('Bob: DataChannel Closed!'); 118 | }; 119 | }; 120 | } 121 | 122 | var config = { 123 | iceServers: [ 124 | { 125 | url: 'stun:stun.l.google.com:19302', 126 | }, 127 | ], 128 | }; 129 | 130 | function sctpTest() { 131 | console.log('Running SCTP DataChannel Test'); 132 | 133 | var sctpDataChannelConfig = { 134 | reliable: true, 135 | ordered: true, 136 | }; 137 | 138 | var sctpDataChannelConstraints = { 139 | audio: false, 140 | video: false, 141 | optional: [ 142 | { 143 | RtpDataChannels: false, 144 | DtlsSrtpKeyAgreement: true, 145 | }, 146 | ], 147 | mandatory: { 148 | OfferToReceiveAudio: false, 149 | OfferToReceiveVideo: false, 150 | }, 151 | }; 152 | 153 | var alice = new WebRTC.RTCPeerConnection(config, sctpDataChannelConstraints); 154 | var bob = new WebRTC.RTCPeerConnection(config, sctpDataChannelConstraints); 155 | 156 | P2P(alice, bob); 157 | 158 | alice.ondatachannel(alice.createDataChannel('TestChannel', sctpDataChannelConfig), function(channel) { 159 | channel.send('Hello Bob!'); 160 | 161 | setTimeout(function () { 162 | channel.close(); 163 | }, 1000); 164 | 165 | setTimeout(function() { 166 | alice.close(); 167 | bob.close(); 168 | }, 5000); 169 | }); 170 | } 171 | 172 | function rtpTest() { 173 | console.log('Running RTP DataChannel Test'); 174 | 175 | var rtpDataChannelConfig = { 176 | reliable: false, 177 | ordered: false, 178 | }; 179 | 180 | var rtpDataChannelConstraints = { 181 | audio: false, 182 | video: false, 183 | optional: [ 184 | { 185 | RtpDataChannels: true, 186 | DtlsSrtpKeyAgreement: false, 187 | }, 188 | ], 189 | mandatory: { 190 | OfferToReceiveAudio: false, 191 | OfferToReceiveVideo: false, 192 | }, 193 | }; 194 | 195 | var alice = new WebRTC.RTCPeerConnection(config, rtpDataChannelConstraints); 196 | var bob = new WebRTC.RTCPeerConnection(config, rtpDataChannelConstraints); 197 | 198 | P2P(alice, bob); 199 | 200 | alice.ondatachannel(alice.createDataChannel('TestChannel', rtpDataChannelConfig), function(channel) { 201 | channel.send('Hello Bob!'); 202 | 203 | setTimeout(function () { 204 | channel.close(); 205 | }, 1000); 206 | 207 | setTimeout(function() { 208 | alice.close(); 209 | bob.close(); 210 | 211 | setTimeout(function() { 212 | sctpTest(); 213 | }, 1000); 214 | }, 5000); 215 | }); 216 | } 217 | 218 | rtpTest(); 219 | -------------------------------------------------------------------------------- /src/MediaStreamTrack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef WEBRTC_MEDIASTREAMTRACK_H 27 | #define WEBRTC_MEDIASTREAMTRACK_H 28 | 29 | #include "Common.h" 30 | #include "Observers.h" 31 | #include "EventEmitter.h" 32 | #include "Wrap.h" 33 | 34 | namespace WebRTC { 35 | enum MediaStreamTrackEvent { 36 | kMediaStreamTrackChanged 37 | }; 38 | 39 | class MediaStreamTrack : public RTCWrap, public EventEmitter { 40 | public: 41 | static void Init(); 42 | 43 | static v8::Local New(rtc::scoped_refptr audioTrack); 44 | static v8::Local New(rtc::scoped_refptr videoTrack); 45 | 46 | static rtc::scoped_refptr Unwrap(v8::Local value); 47 | static rtc::scoped_refptr Unwrap(v8::Local value); 48 | 49 | private: 50 | MediaStreamTrack(); 51 | ~MediaStreamTrack() final; 52 | 53 | static void New(const Nan::FunctionCallbackInfo &info); 54 | static void GetConstraints(const Nan::FunctionCallbackInfo &info); 55 | static void ApplyConstraints(const Nan::FunctionCallbackInfo &info); 56 | static void GetSettings(const Nan::FunctionCallbackInfo &info); 57 | static void GetCapabilities(const Nan::FunctionCallbackInfo &info); 58 | static void Clone(const Nan::FunctionCallbackInfo &info); 59 | static void Stop(const Nan::FunctionCallbackInfo &info); 60 | 61 | static void GetEnabled(v8::Local property, const Nan::PropertyCallbackInfo &info); 62 | static void GetId(v8::Local property, const Nan::PropertyCallbackInfo &info); 63 | static void GetKind(v8::Local property, const Nan::PropertyCallbackInfo &info); 64 | static void GetLabel(v8::Local property, const Nan::PropertyCallbackInfo &info); 65 | static void GetMuted(v8::Local property, const Nan::PropertyCallbackInfo &info); 66 | static void GetReadOnly(v8::Local property, const Nan::PropertyCallbackInfo &info); 67 | static void GetReadyState(v8::Local property, const Nan::PropertyCallbackInfo &info); 68 | static void GetRemote(v8::Local property, const Nan::PropertyCallbackInfo &info); 69 | static void GetOnStarted(v8::Local property, const Nan::PropertyCallbackInfo &info); 70 | static void GetOnMute(v8::Local property, const Nan::PropertyCallbackInfo &info); 71 | static void GetOnUnMute(v8::Local property, const Nan::PropertyCallbackInfo &info); 72 | static void GetOnOverConstrained(v8::Local property, const Nan::PropertyCallbackInfo &info); 73 | static void GetOnEnded(v8::Local property, const Nan::PropertyCallbackInfo &info); 74 | 75 | static void ReadOnly(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 76 | static void SetEnabled(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 77 | static void SetOnStarted(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 78 | static void SetOnMute(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 79 | static void SetOnUnMute(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 80 | static void SetOnOverConstrained(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 81 | static void SetOnEnded(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 82 | 83 | void CheckState(); 84 | void On(Event *event) final; 85 | 86 | protected: 87 | bool isAudioTrack; 88 | bool isVideoTrack; 89 | 90 | rtc::scoped_refptr _track; 91 | rtc::scoped_refptr _source; 92 | rtc::scoped_refptr _observer; 93 | 94 | webrtc::MediaStreamTrackInterface::TrackState _track_state; 95 | webrtc::MediaSourceInterface::SourceState _source_state; 96 | 97 | Nan::Persistent _onstarted; 98 | Nan::Persistent _onmute; 99 | Nan::Persistent _onunmute; 100 | Nan::Persistent _onoverconstrained; 101 | Nan::Persistent _onended; 102 | 103 | static Nan::Persistent constructor; 104 | }; 105 | }; 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /src/MediaCapturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #include "MediaCapturer.h" 27 | 28 | using namespace v8; 29 | using namespace WebRTC; 30 | 31 | Nan::Persistent MediaCapturer::constructor; 32 | 33 | void MediaCapturer::Init() { 34 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 35 | 36 | Nan::HandleScope scope; 37 | 38 | Local tpl = Nan::New(MediaCapturer::New); 39 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 40 | tpl->SetClassName(Nan::New("MediaCapturer").ToLocalChecked()); 41 | 42 | Nan::SetPrototypeMethod(tpl, "stop", MediaCapturer::Stop); 43 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("data").ToLocalChecked(), MediaStreamTrack::GetOnData, MediaStreamTrack::SetOnData); 44 | 45 | constructor.Reset(tpl->GetFunction()); 46 | } 47 | 48 | Local MediaCapturer::New(webrtc::AudioSourceInterface *track) { 49 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 50 | 51 | Nan::EscapableHandleScope scope; 52 | 53 | Local argv[1]; 54 | Local instance = Nan::New(MediaCapturer::constructor); 55 | 56 | if (instance.IsEmpty() || !track) { 57 | return scope.Escape(Nan::Null()); 58 | } 59 | 60 | Local ret = instance->NewInstance(0, argv); 61 | MediaCapturer *self = RTCWrap::Unwrap(ret, "MediaCapturer"); 62 | 63 | self->_audio = track; 64 | self->_source = track; 65 | self->_source->RegisterObserver(self->_observer.get()); 66 | self->_audio->AddSink(self); 67 | 68 | if (self->_audio->state() == webrtc::MediaSourceInterface::kLive) { 69 | self->SetReference(true); 70 | } 71 | 72 | return scope.Escape(ret); 73 | } 74 | 75 | Local MediaCapturer::New(webrtc::VideoSourceInterface *track) { 76 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 77 | 78 | Nan::EscapableHandleScope scope; 79 | 80 | Local argv[1]; 81 | Local instance = Nan::New(MediaCapturer::constructor); 82 | 83 | if (instance.IsEmpty() || !track) { 84 | return scope.Escape(Nan::Null()); 85 | } 86 | 87 | Local ret = instance->NewInstance(0, argv); 88 | MediaCapturer *self = RTCWrap::Unwrap(ret, "MediaCapturer"); 89 | 90 | self->_video = track; 91 | self->_source = track; 92 | self->_source->RegisterObserver(self->_observer.get()); 93 | self->_video->AddOrUpdateSink(self, rtc::VideoSinkWants()); 94 | 95 | if (self->_video->state() == webrtc::MediaSourceInterface::kLive) { 96 | self->SetReference(true); 97 | } 98 | 99 | return scope.Escape(ret); 100 | } 101 | 102 | MediaCapturer::MediaCapturer() { 103 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 104 | 105 | _observer = new rtc::RefCountedObject(this); 106 | } 107 | 108 | MediaCapturer::~MediaCapturer() { 109 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 110 | 111 | if (_video.get()) { 112 | _video->RemoveSink(this); 113 | } 114 | 115 | if (_audio.get()) { 116 | _audio->RemoveSink(this); 117 | } 118 | 119 | if (_source.get()) { 120 | _source->UnregisterObserver(_observer.get()); 121 | } 122 | 123 | _observer->RemoveListener(this); 124 | } 125 | 126 | void MediaCapturer::New(const Nan::FunctionCallbackInfo &info) { 127 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 128 | 129 | Nan::HandleScope scope; 130 | 131 | if (info.IsConstructCall()) { 132 | MediaCapturer* MediaCapturer = new MediaCapturer(); 133 | MediaCapturer->Wrap(info.This(), "MediaCapturer"); 134 | return info.GetReturnValue().Set(info.This()); 135 | } 136 | 137 | Nan::ThrowError("Internal Error"); 138 | info.GetReturnValue().SetUndefined(); 139 | } 140 | 141 | void MediaCapturer::Stop(const Nan::FunctionCallbackInfo &info) { 142 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 143 | 144 | MediaCapturer *self = RTCWrap::Unwrap(info.This(), "MediaCapturer"); 145 | 146 | self->SetReference(false); 147 | 148 | return info.GetReturnValue().SetUndefined(); 149 | } 150 | 151 | void MediaCapturer::GetOnData(Local property, const Nan::PropertyCallbackInfo &info) { 152 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 153 | 154 | MediaCapturer *self = RTCWrap::Unwrap(info.Holder(), "MediaCapturer"); 155 | return info.GetReturnValue().Set(Nan::New(self->_ondata)); 156 | } 157 | 158 | void MediaCapturer::SetOnData(Local property, Local value, const Nan::PropertyCallbackInfo &info) { 159 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 160 | 161 | MediaCapturer *self = RTCWrap::Unwrap(info.Holder(), "MediaCapturer"); 162 | 163 | if (!value.IsEmpty() && value->IsFunction()) { 164 | self->_ondata.Reset(Local::Cast(value)); 165 | } else { 166 | self->_ondata.Reset(); 167 | } 168 | } 169 | 170 | void MediaCapturer::OnFrame(const cricket::VideoFrame &frame) { 171 | printf("Got Video Frame!\n"); 172 | } 173 | 174 | void MediaCapturer::OnData(const void* audio_data, int bits_per_sample, int sample_rate, size_t number_of_channels, size_t number_of_frames) { 175 | printf("Got Audio Frame!\n"); 176 | } 177 | 178 | void MediaCapturer::On(Event *event) { 179 | if (_source.get()) { 180 | if (_source->state() != webrtc::MediaSourceInterface::kLive) { 181 | EventEmitter::SetReference(false); 182 | } 183 | } 184 | } -------------------------------------------------------------------------------- /src/EventEmitter.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #include "EventEmitter.h" 27 | 28 | using namespace WebRTC; 29 | 30 | EventEmitter::EventEmitter(uv_loop_t *loop, bool notify) : _notify(notify) { 31 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 32 | 33 | uv_mutex_init(&_list); 34 | 35 | if (!_notify) { 36 | uv_mutex_init(&_lock); 37 | 38 | _async = new uv_async_t(); 39 | _async->data = this; 40 | 41 | if (!loop) { 42 | loop = uv_default_loop(); 43 | } 44 | 45 | uv_async_init(loop, _async, reinterpret_cast(EventEmitter::onAsync)); 46 | EventEmitter::SetReference(false); 47 | } 48 | } 49 | 50 | EventEmitter::~EventEmitter() { 51 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 52 | 53 | EventEmitter::RemoveAllListeners(); 54 | EventEmitter::Dispose(); 55 | 56 | if (!_notify) { 57 | _async->data = 0; 58 | uv_close(reinterpret_cast(_async), EventEmitter::onEnded); 59 | uv_mutex_destroy(&_lock); 60 | } 61 | 62 | uv_mutex_destroy(&_list); 63 | } 64 | 65 | void EventEmitter::AddListener(EventEmitter *listener) { 66 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 67 | 68 | bool found = false; 69 | std::vector::iterator index; 70 | 71 | if (listener && listener != this) { 72 | uv_mutex_lock(&_list); 73 | 74 | for (index = _listeners.begin(); index < _listeners.end(); index++) { 75 | if ((*index) == listener) { 76 | found = true; 77 | break; 78 | } 79 | } 80 | 81 | if (!found) { 82 | _listeners.push_back(listener); 83 | listener->AddParent(this); 84 | } 85 | 86 | uv_mutex_unlock(&_list); 87 | } 88 | } 89 | 90 | void EventEmitter::RemoveListener(EventEmitter *listener) { 91 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 92 | 93 | std::vector::iterator index; 94 | 95 | if (listener && listener != this) { 96 | uv_mutex_lock(&_list); 97 | 98 | for (index = _listeners.begin(); index < _listeners.end(); index++) { 99 | if ((*index) == listener) { 100 | _listeners.erase(index); 101 | listener->RemoveParent(this); 102 | break; 103 | } 104 | } 105 | 106 | uv_mutex_unlock(&_list); 107 | } 108 | } 109 | 110 | void EventEmitter::RemoveAllListeners() { 111 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 112 | 113 | std::vector::iterator index; 114 | 115 | uv_mutex_lock(&_list); 116 | 117 | for (index = _listeners.begin(); index < _listeners.end(); index++) { 118 | (*index)->RemoveParent(this); 119 | _listeners.erase(index); 120 | } 121 | 122 | uv_mutex_unlock(&_list); 123 | } 124 | 125 | void EventEmitter::Dispose() { 126 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 127 | 128 | if (!_notify) { 129 | while (!_events.empty()) { 130 | rtc::scoped_refptr event = _events.front(); 131 | _events.pop(); 132 | } 133 | } 134 | } 135 | 136 | void EventEmitter::SetReference(bool alive) { 137 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 138 | 139 | if (!_notify) { 140 | uv_mutex_lock(&_lock); 141 | 142 | if (alive) { 143 | uv_ref(reinterpret_cast(_async)); 144 | } else { 145 | uv_unref(reinterpret_cast(_async)); 146 | } 147 | 148 | uv_mutex_unlock(&_lock); 149 | } 150 | } 151 | 152 | void EventEmitter::Emit(int event) { 153 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 154 | 155 | EventEmitter::Emit(new rtc::RefCountedObject(event)); 156 | } 157 | 158 | void EventEmitter::Emit(rtc::scoped_refptr event) { 159 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 160 | 161 | if (event.get()) { 162 | if (!_notify) { 163 | uv_mutex_lock(&_lock); 164 | 165 | _events.push(event); 166 | uv_async_send(_async); 167 | 168 | uv_mutex_unlock(&_lock); 169 | } 170 | 171 | uv_mutex_lock(&_list); 172 | 173 | std::vector::iterator index; 174 | 175 | for (index = _listeners.begin(); index < _listeners.end(); index++) { 176 | (*index)->Emit(event); 177 | } 178 | 179 | uv_mutex_unlock(&_list); 180 | } 181 | } 182 | 183 | void EventEmitter::AddParent(EventEmitter *listener) { 184 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 185 | 186 | uv_mutex_lock(&_list); 187 | _parents.push_back(listener); 188 | uv_mutex_unlock(&_list); 189 | } 190 | 191 | void EventEmitter::RemoveParent(EventEmitter *listener) { 192 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 193 | 194 | std::vector::iterator index; 195 | 196 | uv_mutex_lock(&_list); 197 | 198 | for (index = _listeners.begin(); index < _listeners.end(); index++) { 199 | if ((*index) == listener) { 200 | _listeners.erase(index); 201 | } 202 | } 203 | 204 | uv_mutex_unlock(&_list); 205 | } 206 | 207 | void EventEmitter::onAsync(uv_async_t *handle, int status) { 208 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 209 | 210 | EventEmitter *self = static_cast(handle->data); 211 | 212 | if (self) { 213 | self->DispatchEvents(); 214 | } 215 | } 216 | 217 | void EventEmitter::onEnded(uv_handle_t *handle) { 218 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 219 | 220 | uv_async_t* async = reinterpret_cast(handle); 221 | 222 | if (async) { 223 | delete async; 224 | } 225 | } 226 | 227 | void EventEmitter::DispatchEvents() { 228 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 229 | 230 | uv_mutex_lock(&_lock); 231 | 232 | while (!_events.empty()) { 233 | rtc::scoped_refptr event = _events.front(); 234 | _events.pop(); 235 | 236 | uv_mutex_unlock(&_lock); 237 | 238 | if (event.get()) { 239 | On(event); 240 | } 241 | 242 | uv_mutex_lock(&_lock); 243 | } 244 | 245 | uv_mutex_unlock(&_lock); 246 | } 247 | 248 | NotifyEmitter::NotifyEmitter(EventEmitter *listener) : EventEmitter(0, true) { 249 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 250 | 251 | if (listener) { 252 | NotifyEmitter::AddListener(listener); 253 | } 254 | } 255 | 256 | void NotifyEmitter::On(Event *event) { 257 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 258 | } -------------------------------------------------------------------------------- /src/Observers.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #include "Observers.h" 27 | #include "PeerConnection.h" 28 | #include "DataChannel.h" 29 | #include "MediaStream.h" 30 | #include "MediaStreamTrack.h" 31 | 32 | using namespace WebRTC; 33 | 34 | OfferObserver::OfferObserver(EventEmitter *listener) : 35 | NotifyEmitter(listener) { } 36 | 37 | void OfferObserver::OnSuccess(webrtc::SessionDescriptionInterface* desc) { 38 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 39 | 40 | Json::StyledWriter writer; 41 | Json::Value msg; 42 | std::string sdp; 43 | 44 | if (desc->ToString(&sdp)) { 45 | msg["type"] = desc->type(); 46 | msg["sdp"] = sdp; 47 | 48 | Emit(kPeerConnectionCreateOffer, writer.write(msg)); 49 | } 50 | } 51 | 52 | void OfferObserver::OnFailure(const std::string &error) { 53 | LOG(LS_ERROR) << __PRETTY_FUNCTION__; 54 | 55 | Emit(kPeerConnectionCreateOfferError, error); 56 | } 57 | 58 | AnswerObserver::AnswerObserver(EventEmitter *listener) : 59 | NotifyEmitter(listener) { } 60 | 61 | void AnswerObserver::OnSuccess(webrtc::SessionDescriptionInterface* desc) { 62 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 63 | 64 | Json::StyledWriter writer; 65 | Json::Value msg; 66 | std::string sdp; 67 | 68 | if (desc->ToString(&sdp)) { 69 | msg["type"] = desc->type(); 70 | msg["sdp"] = sdp; 71 | 72 | Emit(kPeerConnectionCreateAnswer, writer.write(msg)); 73 | } 74 | } 75 | 76 | void AnswerObserver::OnFailure(const std::string &error) { 77 | LOG(LS_ERROR) << __PRETTY_FUNCTION__; 78 | 79 | Emit(kPeerConnectionCreateAnswerError, error); 80 | } 81 | 82 | LocalDescriptionObserver::LocalDescriptionObserver(EventEmitter *listener) : 83 | NotifyEmitter(listener) { } 84 | 85 | void LocalDescriptionObserver::OnSuccess() { 86 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 87 | 88 | Emit(kPeerConnectionSetLocalDescription); 89 | } 90 | 91 | void LocalDescriptionObserver::OnFailure(const std::string &error) { 92 | LOG(LS_ERROR) << __PRETTY_FUNCTION__; 93 | 94 | Emit(kPeerConnectionSetLocalDescriptionError, error); 95 | } 96 | 97 | RemoteDescriptionObserver::RemoteDescriptionObserver(EventEmitter *listener) : 98 | NotifyEmitter(listener) { } 99 | 100 | void RemoteDescriptionObserver::OnSuccess() { 101 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 102 | 103 | Emit(kPeerConnectionSetRemoteDescription); 104 | } 105 | 106 | void RemoteDescriptionObserver::OnFailure(const std::string &error) { 107 | LOG(LS_ERROR) << __PRETTY_FUNCTION__; 108 | 109 | Emit(kPeerConnectionSetRemoteDescriptionError, error); 110 | } 111 | 112 | PeerConnectionObserver::PeerConnectionObserver(EventEmitter *listener) : 113 | NotifyEmitter(listener) { } 114 | 115 | void PeerConnectionObserver::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState state) { 116 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 117 | 118 | Emit(kPeerConnectionSignalChange); 119 | 120 | if (state == webrtc::PeerConnectionInterface::kClosed) { 121 | Emit(kPeerConnectionCreateClosed); 122 | } 123 | } 124 | 125 | void PeerConnectionObserver::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState state) { 126 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 127 | 128 | Emit(kPeerConnectionIceChange); 129 | } 130 | 131 | void PeerConnectionObserver::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState state) { 132 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 133 | 134 | Emit(kPeerConnectionIceGathering); 135 | 136 | if (state == webrtc::PeerConnectionInterface::kIceGatheringComplete) { 137 | Emit(kPeerConnectionIceCandidate, std::string()); 138 | } 139 | } 140 | 141 | void PeerConnectionObserver::OnStateChange(webrtc::PeerConnectionObserver::StateType state) { 142 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 143 | } 144 | 145 | void PeerConnectionObserver::OnDataChannel(webrtc::DataChannelInterface *channel) { 146 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 147 | 148 | rtc::scoped_refptr dataChannel = channel; 149 | 150 | if (dataChannel.get()) { 151 | Emit(kPeerConnectionDataChannel, dataChannel); 152 | } 153 | } 154 | 155 | void PeerConnectionObserver::OnAddStream(webrtc::MediaStreamInterface *stream) { 156 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 157 | 158 | rtc::scoped_refptr mediaStream = stream; 159 | 160 | if (mediaStream.get()) { 161 | Emit(kPeerConnectionAddStream, mediaStream); 162 | } 163 | } 164 | 165 | void PeerConnectionObserver::OnRemoveStream(webrtc::MediaStreamInterface *stream) { 166 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 167 | 168 | rtc::scoped_refptr mediaStream = stream; 169 | 170 | if (mediaStream.get()) { 171 | Emit(kPeerConnectionRemoveStream, mediaStream); 172 | } 173 | } 174 | 175 | void PeerConnectionObserver::OnRenegotiationNeeded() { 176 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 177 | 178 | Emit(kPeerConnectionRenegotiation); 179 | } 180 | 181 | void PeerConnectionObserver::OnIceCandidate(const webrtc::IceCandidateInterface* candidate) { 182 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 183 | 184 | Json::StyledWriter writer; 185 | Json::Value msg; 186 | std::string sdp; 187 | 188 | if (candidate->ToString(&sdp)) { 189 | msg["sdpMid"] = candidate->sdp_mid(); 190 | msg["sdpMLineIndex"] = candidate->sdp_mline_index(); 191 | msg["candidate"] = sdp; 192 | 193 | Emit(kPeerConnectionIceCandidate, writer.write(msg)); 194 | } 195 | } 196 | 197 | DataChannelObserver::DataChannelObserver(EventEmitter *listener) : 198 | NotifyEmitter(listener) { } 199 | 200 | void DataChannelObserver::OnStateChange() { 201 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 202 | 203 | Emit(kDataChannelStateChange); 204 | } 205 | 206 | void DataChannelObserver::OnMessage(const webrtc::DataBuffer& buffer) { 207 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 208 | 209 | if (buffer.binary) { 210 | Emit(kDataChannelBinary, buffer.data); 211 | } else { 212 | Emit(kDataChannelData, buffer.data); 213 | } 214 | } 215 | 216 | MediaStreamObserver::MediaStreamObserver(EventEmitter *listener) : 217 | NotifyEmitter(listener) { } 218 | 219 | void MediaStreamObserver::OnChanged() { 220 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 221 | 222 | Emit(kMediaStreamChanged); 223 | } 224 | 225 | MediaStreamTrackObserver::MediaStreamTrackObserver(EventEmitter *listener) : 226 | NotifyEmitter(listener) { } 227 | 228 | void MediaStreamTrackObserver::OnChanged() { 229 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 230 | 231 | Emit(kMediaStreamTrackChanged); 232 | } 233 | 234 | StatsObserver::StatsObserver(EventEmitter *listener) : 235 | NotifyEmitter(listener) { } 236 | 237 | void StatsObserver::OnComplete(const webrtc::StatsReports &reports) { 238 | LOG(LS_INFO) << "StatsObserver::OnComplete()"; 239 | 240 | Emit(kPeerConnectionStats, reports); 241 | } 242 | -------------------------------------------------------------------------------- /src/GetSources.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #include 27 | #include "Platform.h" 28 | #include "MediaStreamTrack.h" 29 | #include "GetSources.h" 30 | using namespace v8; 31 | using namespace WebRTC; 32 | 33 | void GetSources::Init(Handle exports) { 34 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 35 | 36 | exports->Set(Nan::New("getSources").ToLocalChecked(), Nan::New(GetSources::GetDevices)->GetFunction()); 37 | exports->Set(Nan::New("getVideoSource").ToLocalChecked(), Nan::New(GetSources::GetVideoSource2)->GetFunction()); 38 | } 39 | 40 | rtc::scoped_refptr GetSources::GetAudioSource(const rtc::scoped_refptr &constraints) { 41 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 42 | 43 | rtc::scoped_refptr track; 44 | rtc::scoped_refptr factory = webrtc::CreatePeerConnectionFactory(rtc::Thread::Current(), Platform::GetWorker(), 0, 0, 0); 45 | 46 | if (factory.get()) { 47 | track = factory->CreateAudioTrack("audio", factory->CreateAudioSource(constraints->ToConstraints())); 48 | } 49 | 50 | return track; 51 | } 52 | 53 | rtc::scoped_refptr GetSources::GetAudioSource(const std::string id, const rtc::scoped_refptr &constraints) { 54 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 55 | return GetSources::GetAudioSource(constraints); 56 | } 57 | 58 | rtc::scoped_refptr GetSources::GetVideoSource(const rtc::scoped_refptr &constraints) { 59 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 60 | 61 | cricket::VideoCapturer* capturer = nullptr; 62 | rtc::scoped_refptr track; 63 | rtc::scoped_refptr factory = webrtc::CreatePeerConnectionFactory(rtc::Thread::Current(), Platform::GetWorker(), 0, 0, 0); 64 | std::unique_ptr video_info(webrtc::VideoCaptureFactory::CreateDeviceInfo(0)); 65 | cricket::WebRtcVideoDeviceCapturerFactory device_factory; 66 | 67 | if (factory.get()) { 68 | if (video_info) { 69 | int num_devices = video_info->NumberOfDevices(); 70 | 71 | for (int i = 0; i < num_devices; ++i) { 72 | const uint32_t kSize = 256; 73 | char name[kSize] = {0}; 74 | char id[kSize] = {0}; 75 | 76 | if (video_info->GetDeviceName(i, name, kSize, id, kSize) != -1) { 77 | capturer = device_factory.Create(cricket::Device(name, 0)); 78 | 79 | if (capturer) { 80 | 81 | for(int i = 0; name[i]; i++){ 82 | if (name[i]==' ') name[i] = '_'; 83 | name[i] = tolower(name[i]); 84 | } 85 | track = factory->CreateVideoTrack(name, factory->CreateVideoSource(capturer, constraints->ToConstraints())); 86 | return track; 87 | } 88 | } 89 | } 90 | } 91 | } 92 | 93 | return track; 94 | } 95 | 96 | rtc::scoped_refptr GetSources::GetVideoSource(const std::string id_name, const rtc::scoped_refptr &constraints) { 97 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 98 | 99 | cricket::VideoCapturer* capturer = nullptr; 100 | rtc::scoped_refptr track; 101 | rtc::scoped_refptr factory = webrtc::CreatePeerConnectionFactory(rtc::Thread::Current(), Platform::GetWorker(), 0, 0, 0); 102 | std::unique_ptr video_info(webrtc::VideoCaptureFactory::CreateDeviceInfo(0)); 103 | cricket::WebRtcVideoDeviceCapturerFactory device_factory; 104 | 105 | if (factory.get()) { 106 | if (video_info) { 107 | int num_devices = video_info->NumberOfDevices(); 108 | 109 | for (int i = 0; i < num_devices; ++i) { 110 | const uint32_t kSize = 256; 111 | char name[kSize] = {0}; 112 | char id[kSize] = {0}; 113 | 114 | if (video_info->GetDeviceName(i, name, kSize, id, kSize) != -1) { 115 | if (id_name.empty() || id_name.compare(name) == 0) { 116 | capturer = device_factory.Create(cricket::Device(name, 0)); 117 | 118 | if (capturer) { 119 | for(int i = 0; name[i]; i++){ 120 | if (name[i]==' ') name[i] = '_'; 121 | name[i] = tolower(name[i]); 122 | } 123 | track = factory->CreateVideoTrack(name, factory->CreateVideoSource(capturer, constraints->ToConstraints())); 124 | return track; 125 | } 126 | } 127 | } 128 | } 129 | } 130 | } 131 | 132 | return track; 133 | } 134 | 135 | Local GetSources::GetDevices() { 136 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 137 | 138 | Nan::EscapableHandleScope scope; 139 | Local list = Nan::New(); 140 | uint32_t index = 0; 141 | 142 | std::unique_ptr video_info(webrtc::VideoCaptureFactory::CreateDeviceInfo(0)); 143 | 144 | if (video_info) { 145 | int num_devices = video_info->NumberOfDevices(); 146 | 147 | for (int i = 0; i < num_devices; ++i) { 148 | const uint32_t kSize = 256; 149 | char name[kSize] = {0}; 150 | char id[kSize] = {0}; 151 | 152 | if (video_info->GetDeviceName(i, name, kSize, id, kSize) != -1) { 153 | Local device = Nan::New(); 154 | 155 | device->Set(Nan::New("kind").ToLocalChecked(), Nan::New("video").ToLocalChecked()); 156 | device->Set(Nan::New("label").ToLocalChecked(), Nan::New(name).ToLocalChecked()); 157 | device->Set(Nan::New("id").ToLocalChecked(), Nan::New(id).ToLocalChecked()); 158 | 159 | list->Set(index, device); 160 | index++; 161 | } 162 | } 163 | } 164 | 165 | return scope.Escape(list); 166 | } 167 | 168 | 169 | void GetSources::GetVideoSource2(const Nan::FunctionCallbackInfo &info) { 170 | Nan::Utf8String name_id(info[0]->ToString()); 171 | 172 | 173 | rtc::scoped_refptr constraints = MediaConstraints::New(info[1]); 174 | rtc::scoped_refptr track = GetSources::GetVideoSource(*name_id,constraints); 175 | 176 | 177 | info.GetReturnValue().Set(MediaStreamTrack::New(track)); 178 | } 179 | 180 | 181 | void GetSources::GetDevices(const Nan::FunctionCallbackInfo &info) { 182 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 183 | 184 | if (info.Length() == 1 && info[0]->IsFunction()) { 185 | Local callback = Local::Cast(info[0]); 186 | 187 | Local argv[1] = { 188 | GetSources::GetDevices() 189 | }; 190 | 191 | if (!callback.IsEmpty()) { 192 | callback->Call(info.This(), 1, argv); 193 | } 194 | } 195 | 196 | info.GetReturnValue().SetUndefined(); 197 | } 198 | -------------------------------------------------------------------------------- /src/PeerConnection.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef WEBRTC_PEERCONNECTION_H 27 | #define WEBRTC_PEERCONNECTION_H 28 | 29 | #include "Common.h" 30 | #include "Observers.h" 31 | #include "EventEmitter.h" 32 | #include "MediaConstraints.h" 33 | #include "Wrap.h" 34 | 35 | namespace WebRTC { 36 | enum PeerConnectionEvent { 37 | kPeerConnectionCreateClosed = 1, 38 | kPeerConnectionCreateOffer, 39 | kPeerConnectionCreateOfferError, 40 | kPeerConnectionCreateAnswer, 41 | kPeerConnectionCreateAnswerError, 42 | kPeerConnectionSetLocalDescription, 43 | kPeerConnectionSetLocalDescriptionError, 44 | kPeerConnectionSetRemoteDescription, 45 | kPeerConnectionSetRemoteDescriptionError, 46 | kPeerConnectionIceCandidate, 47 | kPeerConnectionSignalChange, 48 | kPeerConnectionIceChange, 49 | kPeerConnectionIceGathering, 50 | kPeerConnectionDataChannel, 51 | kPeerConnectionAddStream, 52 | kPeerConnectionRemoveStream, 53 | kPeerConnectionRenegotiation, 54 | kPeerConnectionStats 55 | }; 56 | 57 | class PeerConnection : public RTCWrap, public EventEmitter { 58 | public: 59 | static void Init(v8::Handle exports); 60 | 61 | private: 62 | PeerConnection(const v8::Local &configuration, 63 | const v8::Local &constraints); 64 | 65 | ~PeerConnection() final; 66 | 67 | static void New(const Nan::FunctionCallbackInfo &info); 68 | static void CreateOffer(const Nan::FunctionCallbackInfo &info); 69 | static void CreateAnswer(const Nan::FunctionCallbackInfo &info); 70 | static void SetLocalDescription(const Nan::FunctionCallbackInfo &info); 71 | static void SetRemoteDescription(const Nan::FunctionCallbackInfo &info); 72 | static void AddIceCandidate(const Nan::FunctionCallbackInfo &info); 73 | static void CreateDataChannel(const Nan::FunctionCallbackInfo &info); 74 | static void AddStream(const Nan::FunctionCallbackInfo &info); 75 | static void RemoveStream(const Nan::FunctionCallbackInfo &info); 76 | static void GetLocalStreams(const Nan::FunctionCallbackInfo &info); 77 | static void GetRemoteStreams(const Nan::FunctionCallbackInfo &info); 78 | static void GetStreamById(const Nan::FunctionCallbackInfo &info); 79 | static void GetStats(const Nan::FunctionCallbackInfo &info); 80 | static void Close(const Nan::FunctionCallbackInfo &info); 81 | 82 | static void GetSignalingState(v8::Local property, const Nan::PropertyCallbackInfo &info); 83 | static void GetIceConnectionState(v8::Local property, const Nan::PropertyCallbackInfo &info); 84 | static void GetIceGatheringState(v8::Local property, const Nan::PropertyCallbackInfo &info); 85 | static void GetOnSignalingStateChange(v8::Local property, const Nan::PropertyCallbackInfo &info); 86 | static void GetOnIceConnectionStateChange(v8::Local property, const Nan::PropertyCallbackInfo &info); 87 | static void GetOnIceCandidate(v8::Local property, const Nan::PropertyCallbackInfo &info); 88 | static void GetOnDataChannel(v8::Local property, const Nan::PropertyCallbackInfo &info); 89 | static void GetOnNegotiationNeeded(v8::Local property, const Nan::PropertyCallbackInfo &info); 90 | static void GetOnAddStream(v8::Local property, const Nan::PropertyCallbackInfo &info); 91 | static void GetOnRemoveStream(v8::Local property, const Nan::PropertyCallbackInfo &info); 92 | static void GetLocalDescription(v8::Local property, const Nan::PropertyCallbackInfo &info); 93 | static void GetRemoteDescription(v8::Local property, const Nan::PropertyCallbackInfo &info); 94 | 95 | static void ReadOnly(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 96 | static void SetOnSignalingStateChange(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 97 | static void SetOnIceConnectionStateChange(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 98 | static void SetOnIceCandidate(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 99 | static void SetOnDataChannel(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 100 | static void SetOnNegotiationNeeded(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 101 | static void SetOnAddStream(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 102 | static void SetOnRemoveStream(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo &info); 103 | 104 | void On(Event *event) final; 105 | 106 | bool IsStable(); 107 | 108 | webrtc::PeerConnectionInterface *GetSocket(); 109 | 110 | protected: 111 | Nan::Persistent _onsignalingstatechange; 112 | Nan::Persistent _oniceconnectionstatechange; 113 | Nan::Persistent _onicecandidate; 114 | Nan::Persistent _ondatachannel; 115 | Nan::Persistent _onnegotiationneeded; 116 | Nan::Persistent _onaddstream; 117 | Nan::Persistent _onremovestream; 118 | 119 | Nan::Persistent _offerCallback; 120 | Nan::Persistent _offerErrorCallback; 121 | 122 | Nan::Persistent _answerCallback; 123 | Nan::Persistent _answerErrorCallback; 124 | 125 | Nan::Persistent _localCallback; 126 | Nan::Persistent _localErrorCallback; 127 | 128 | Nan::Persistent _remoteCallback; 129 | Nan::Persistent _remoteErrorCallback; 130 | 131 | Nan::Persistent _onstats; 132 | 133 | Nan::Persistent _localsdp; 134 | Nan::Persistent _remotesdp; 135 | 136 | static Nan::Persistent constructor; 137 | 138 | rtc::scoped_refptr _stats; 139 | rtc::scoped_refptr _offer; 140 | rtc::scoped_refptr _answer; 141 | rtc::scoped_refptr _local; 142 | rtc::scoped_refptr _remote; 143 | rtc::scoped_refptr _peer; 144 | rtc::scoped_refptr _socket; 145 | rtc::scoped_refptr _factory; 146 | 147 | rtc::scoped_refptr _constraints; 148 | webrtc::PeerConnectionInterface::RTCConfiguration _config; 149 | }; 150 | }; 151 | 152 | #endif -------------------------------------------------------------------------------- /test/bwtest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var wrtc = require('..'); 4 | var tape = require('tape'); 5 | var args = require('minimist')(process.argv.slice(2)); 6 | var SimplePeer = require('simple-peer'); 7 | 8 | 9 | module.exports = bwtest; 10 | bwtest.tape = bwtape; 11 | 12 | 13 | if (require.main === module) { 14 | main(); 15 | } 16 | 17 | 18 | /** 19 | * called when running this script directly from cli 20 | */ 21 | function main() { 22 | if (typeof(args.iceConfig) === 'string') { 23 | // parse json of iceConfig to allow running like this: 24 | // node test/bwtest --iceConfig '{"ordered": false}' 25 | args.iceConfig = JSON.parse(args.iceConfig); 26 | } 27 | console.log('bwtest args:', args); 28 | bwtest(args); 29 | } 30 | 31 | 32 | /** 33 | * setup tape tests for bwtest 34 | */ 35 | function bwtape() { 36 | tape('bwtest default', function(t) { 37 | t.plan(1); 38 | bwtest({ 39 | packetCount: 500, 40 | }, function(err) { 41 | t.error(err, 'bwtest check for error'); 42 | }); 43 | }); 44 | 45 | tape('bwtest no buffering', function(t) { 46 | t.plan(1); 47 | bwtest({ 48 | packetCount: 500, 49 | congestHighThreshold: 0, 50 | congestLowThreshold: 0 51 | }, function(err) { 52 | t.error(err, 'bwtest check for error'); 53 | }); 54 | }); 55 | 56 | tape('bwtest unordered and unreliable', function(t) { 57 | t.plan(1); 58 | bwtest({ 59 | packetCount: 500, 60 | iceConfig: { 61 | ordered: false, 62 | maxRetransmits: 5 63 | } 64 | }, function(err) { 65 | t.error(err, 'bwtest check for error'); 66 | }); 67 | }); 68 | } 69 | 70 | 71 | 72 | /** 73 | * 74 | * BWTEST 75 | * 76 | * run a webrtc bandwidth test with two peers running in this process. 77 | * 78 | * @param options (optional) - see defaults inside for list of options. 79 | * @param callback function(err) called on success/failure. 80 | * 81 | */ 82 | function bwtest(options, callback) { 83 | 84 | // options is optional 85 | if (typeof(options) === 'function') { 86 | callback = options; 87 | options = null; 88 | } 89 | 90 | // defaults 91 | callback = callback || function() {}; 92 | options = options || {}; 93 | options.packetCount = options.packetCount || 5000; 94 | options.packetSize = options.packetSize || 16 * 1024; 95 | options.bufferedDelayMs = options.bufferedDelayMs || 5; 96 | options.congestHighThreshold = options.congestHighThreshold || 1024 * 1024; 97 | options.congestLowThreshold = options.congestLowThreshold || 256 * 1024; 98 | options.iceConfig = options.iceConfig || defaultIceConfig(); 99 | 100 | var n = 0; 101 | var congested = 0; 102 | var stats = { 103 | startTime: 0, 104 | count: 0, 105 | bytes: 0, 106 | congestCount: 0, 107 | congestTime: 0 108 | }; 109 | 110 | // setup two peers with simple-peer 111 | var peer1 = new SimplePeer({ 112 | wrtc: wrtc 113 | }); 114 | var peer2 = new SimplePeer({ 115 | wrtc: wrtc, 116 | initiator: true, 117 | config: options.iceConfig 118 | }); 119 | 120 | // when peer1 has signaling data, give it to peer2, and vice versa 121 | peer1.on('signal', peer2.signal.bind(peer2)); 122 | peer2.on('signal', peer1.signal.bind(peer1)); 123 | 124 | // wait for 'connect' event before using the data channel 125 | peer1.on('error', failure); 126 | peer2.on('error', failure); 127 | peer1.on('connect', start); 128 | peer2.on('data', receive); 129 | 130 | 131 | 132 | // functions // 133 | 134 | /** 135 | * start the test once peers are connected 136 | */ 137 | function start() { 138 | stats.startTime = Date.now(); 139 | send(); 140 | } 141 | 142 | 143 | /** 144 | * send next packet and recurse 145 | */ 146 | function send() { 147 | if (n >= options.packetCount) { 148 | console.log('SEND DONE!', info()); 149 | return; 150 | } 151 | if (n % 100 === 0) { 152 | console.log('SENDING:', info()); 153 | } 154 | if (congestion()) { 155 | setTimeout(send, options.bufferedDelayMs); 156 | return; 157 | } 158 | // TODO allocating new buffer per send as workaround to repeated Externalize() 159 | // after fixing the issues around that we can move back to higher scope. 160 | var buffer = new ArrayBuffer(options.packetSize); 161 | peer1.send(buffer); 162 | n += 1; 163 | if (global.setImmediate) { 164 | global.setImmediate(send); 165 | } else { 166 | setTimeout(send, 0); 167 | } 168 | } 169 | 170 | 171 | /** 172 | * callback for the receiver to update stats and finish the test 173 | */ 174 | function receive(data) { 175 | stats.count += 1; 176 | stats.bytes += data.length; 177 | if (stats.count >= options.packetCount) { 178 | console.log('RECEIVE DONE!', info()); 179 | // closing the channels so the process can exit 180 | peer1.destroy(); 181 | peer2.destroy(); 182 | callback(); 183 | } 184 | } 185 | 186 | 187 | /** 188 | * failure handler 189 | */ 190 | function failure(err) { 191 | 192 | // make sure to call the callback with error, even if anything here will throw 193 | setTimeout(callback.bind(null, err), 0); 194 | 195 | console.error('ERROR!', info(), err.stack || err); 196 | // closing the channels so the process can exit 197 | peer1.destroy(); 198 | peer2.destroy(); 199 | } 200 | 201 | 202 | /** 203 | * handle channel congestion using bufferedAmount 204 | */ 205 | function congestion() { 206 | var bufferedAmount = peer1._channel && peer1._channel.bufferedAmount || 0; 207 | if ((bufferedAmount > options.congestHighThreshold) || 208 | (congested && bufferedAmount > options.congestLowThreshold)) { 209 | if (!congested) { 210 | congested = Date.now(); 211 | } 212 | stats.congestCount += 1; 213 | } else { 214 | if (congested) { 215 | stats.congestTime += Date.now() - congested; 216 | } 217 | congested = 0; 218 | } 219 | return congested; 220 | } 221 | 222 | 223 | 224 | /** 225 | * return information string on the test progress 226 | */ 227 | function info() { 228 | var now = Date.now(); 229 | if (congested) { 230 | stats.congestTime += Date.now() - congested; 231 | congested = now; 232 | } 233 | var took = (now - stats.startTime) / 1000; 234 | var bufferedAmount = peer1._channel && peer1._channel.bufferedAmount; 235 | return 'sent ' + n + ' received ' + stats.count + '. ' + 236 | 'congestion #' + stats.congestCount + ' ' + 237 | (stats.congestTime / 1024).toFixed(3) + ' seconds. ' + 238 | (bufferedAmount ? 'bufferedAmount ' + bufferedAmount + '. ' : '') + 239 | 'took ' + took.toFixed(3) + ' seconds. ' + 240 | 'bandwidth ' + (stats.bytes / took / 1024).toFixed(0) + ' KB/s. '; 241 | } 242 | 243 | 244 | /** 245 | * default ice config is just here for documenting the options - see inside. 246 | */ 247 | function defaultIceConfig() { 248 | return { 249 | /* 250 | * data channels are ordered by default - using unordered channel improves 251 | * performance but will likely require ordering in another app layer 252 | */ 253 | // ordered: false, 254 | 255 | /* 256 | * data channels are reliable by default - using either maxRetransmits 257 | * or maxPacketLifeTime will change to unreliable mode 258 | */ 259 | // maxRetransmits: 5, 260 | // maxPacketLifeTime: 3000, 261 | 262 | /* 263 | * iceServers with stun urls. not needed for this in-process test. 264 | */ 265 | // iceServers: [{url: 'stun:23.21.150.121'}], 266 | }; 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var os = require('os'); 3 | var spawn = require('child_process').spawn; 4 | var path = require('path'); 5 | var request = require('request'); 6 | 7 | var ROOT = path.resolve(__dirname, '..'); 8 | 9 | if (!fs.existsSync(ROOT + path.sep + 'build' + path.sep + 'config.gypi')) { 10 | throw new Error('Run node-gyp rebuild instead of node build.js'); 11 | } 12 | 13 | var PACKAGE = require(path.resolve(ROOT, 'package.json')); 14 | 15 | var CHROMIUM = 'https://chromium.googlesource.com/external/webrtc.git@ca4ec2c3b9331e8f054facf400ebaeb9681831e2'; 16 | var USE_OPENSSL = false; 17 | var USE_GTK = false; 18 | var USE_X11 = false; 19 | 20 | var PLATFORM = os.platform(); 21 | var SYSTEM = os.release(); 22 | var ARCH = process.argv[2].substring(14); 23 | var NODEJS = path.resolve(process.argv[3]); 24 | var NODELIB = process.argv[4].substring(3).split('.')[0]; 25 | var NODEGYP = process.argv[5]; 26 | var URL = 'http://cide.cc:8080/webrtc/'; 27 | var NODEVER = process.version.split('.'); 28 | var NODE_ZERO = (NODEVER[0] === 'v0'); 29 | var CROSSCOMPILE = (ARCH !== process.arch); 30 | 31 | NODEVER[2] = 'x'; 32 | NODEVER = NODEVER.join('.'); 33 | 34 | URL += 'webrtc-' + PACKAGE.version + '-' + PLATFORM + '-' + ARCH + '-' + NODEVER + '.node'; 35 | 36 | if (fs.existsSync(ROOT + path.sep + 'nodejs.gypi')) { 37 | fs.unlinkSync(ROOT + path.sep + 'nodejs.gypi'); 38 | } 39 | 40 | var COMMON = path.resolve(NODEJS, 'include', 'node', 'common.gypi'); 41 | 42 | if (fs.existsSync(COMMON)) { 43 | fs.linkSync(COMMON, ROOT + path.sep + 'nodejs.gypi'); 44 | } else { 45 | fs.linkSync(NODEJS + path.sep + 'common.gypi', ROOT + path.sep + 'nodejs.gypi'); 46 | } 47 | 48 | var CONFIG = 'Release'; 49 | 50 | if (fs.existsSync(ROOT + path.sep + 'build' + path.sep + 'Debug')) { 51 | CONFIG = 'Debug'; 52 | } 53 | 54 | var THIRD_PARTY = path.resolve(ROOT, 'third_party'); 55 | var DEPOT_TOOLS_REPO = 'https://chromium.googlesource.com/chromium/tools/depot_tools.git'; 56 | var DEPOT_TOOLS = path.resolve(THIRD_PARTY, 'depot_tools'); 57 | var WEBRTC = path.resolve(THIRD_PARTY, 'webrtc'); 58 | var WEBRTC_SRC = path.resolve(WEBRTC, 'src'); 59 | var WEBRTC_OUT = path.resolve(WEBRTC_SRC, 'out', CONFIG); 60 | var FETCH = path.resolve(DEPOT_TOOLS, (os.platform() == 'win32') ? 'fetch.bat' : 'fetch'); 61 | var GCLIENT = path.resolve(DEPOT_TOOLS, (os.platform() == 'win32') ? 'gclient.bat' : 'gclient'); 62 | 63 | if (os.platform() == 'win32' && ARCH == 'x64') { 64 | WEBRTC_OUT = path.resolve(WEBRTC_SRC, 'out', CONFIG + '_x64'); 65 | } 66 | 67 | function install() { 68 | fs.linkSync(WEBRTC_OUT + path.sep + 'webrtc.node', path.resolve(ROOT, 'build', CONFIG, 'webrtc.node')); 69 | 70 | if (process.env['CIDE_CREDENTIALS']) { 71 | console.log('Uploading module.'); 72 | 73 | var credentials = { 74 | 'auth': { 75 | 'user': 'cIDE', 76 | 'pass': process.env['CIDE_CREDENTIALS'], 77 | } 78 | }; 79 | 80 | fs.createReadStream(path.resolve(ROOT, 'build', CONFIG, 'webrtc.node')).pipe(request.put(URL, credentials, function(error, response, body) { 81 | if (!error && response.statusCode == 200) { 82 | console.log('Done! :)'); 83 | } else { 84 | console.log('Upload Failed! :('); 85 | } 86 | })); 87 | } else { 88 | setTimeout(function() { 89 | console.log('Done! :)'); 90 | }, 200); 91 | } 92 | } 93 | 94 | function compile() { 95 | var res = spawn('ninja', [ '-C', WEBRTC_OUT ], { 96 | cwd: WEBRTC_SRC, 97 | env: process.env, 98 | stdio: 'inherit', 99 | }); 100 | 101 | res.on('close', function (code) { 102 | if (!code) { 103 | return install(); 104 | } 105 | 106 | process.exit(1); 107 | }); 108 | } 109 | 110 | function build() { 111 | if (fs.existsSync(WEBRTC_SRC)) { 112 | var res = spawn('python', [ WEBRTC_SRC + path.sep + 'webrtc' + path.sep + 'build' + path.sep + 'gyp_webrtc', 'src' + path.sep + 'webrtc.gyp' ], { 113 | cwd: ROOT, 114 | env: process.env, 115 | stdio: 'inherit', 116 | }); 117 | 118 | res.on('close', function (code) { 119 | if (!code) { 120 | return compile(); 121 | } 122 | 123 | process.exit(1); 124 | }); 125 | } 126 | } 127 | 128 | function sync() { 129 | if (!fs.existsSync(THIRD_PARTY + path.sep + 'webrtc_sync')) { 130 | var res = spawn(GCLIENT, ['sync', '--with_branch_heads'], { 131 | cwd: WEBRTC, 132 | env: process.env, 133 | stdio: 'inherit', 134 | }); 135 | 136 | res.on('close', function (code) { 137 | if (!code) { 138 | fs.closeSync(fs.openSync(THIRD_PARTY + path.sep + 'webrtc_sync', 'w')); 139 | return build(); 140 | } 141 | 142 | process.exit(1); 143 | }); 144 | } else { 145 | build(); 146 | } 147 | } 148 | 149 | function configure() { 150 | if (fs.existsSync(WEBRTC_OUT + path.sep + 'webrtc.node')) { 151 | fs.unlinkSync(WEBRTC_OUT + path.sep + 'webrtc.node'); 152 | } 153 | 154 | process.env['GYP_DEFINES'] += ' target_arch=' + ARCH; 155 | process.env['GYP_DEFINES'] += ' host_arch=' + process.arch; 156 | process.env['GYP_DEFINES'] += ' node_root_dir=' + NODEJS.replace(/\\/g, '\\\\'); 157 | process.env['GYP_DEFINES'] += ' node_lib_file=' + NODELIB; 158 | process.env['GYP_DEFINES'] += ' node_gyp_dir=' + NODEGYP.replace(/\\/g, '\\\\'); 159 | process.env['GYP_DEFINES'] += ' build_with_chromium=0'; 160 | process.env['GYP_DEFINES'] += ' use_openssl=' + ((USE_OPENSSL) ? '1' : '0'); 161 | process.env['GYP_DEFINES'] += ' use_gtk='+ ((USE_GTK) ? '1' : '0'); 162 | process.env['GYP_DEFINES'] += ' use_x11=' + ((USE_X11) ? '1' : '0'); 163 | process.env['GYP_DEFINES'] += ' ConfigurationName=' + CONFIG; 164 | process.env['GYP_DEFINES'] += ' include_tests=0'; 165 | 166 | switch (os.platform()) { 167 | case 'darwin': 168 | process.env['GYP_DEFINES'] += ' clang=1'; 169 | 170 | break; 171 | case 'win32': 172 | process.env['DEPOT_TOOLS_WIN_TOOLCHAIN'] = 0; 173 | process.env['GYP_MSVS_VERSION'] = 2013; 174 | 175 | break; 176 | case 'linux': 177 | if (CROSSCOMPILE) { 178 | process.env['GYP_CROSSCOMPILE'] = 1; 179 | process.env['GYP_DEFINES'] += ' clang=0 use_system_expat=0'; 180 | process.env['CXX'] = 'arm-linux-gnueabihf-g++-5'; 181 | 182 | var CPATH = process.env['CPATH']; 183 | 184 | process.env['CPATH'] = '/usr/arm-linux-gnueabihf/include/c++/5/'; 185 | process.env['CPATH'] += '/usr/arm-linux-gnueabihf/include/c++/5/arm-linux-gnueabihf/'; 186 | process.env['CPATH'] += '/usr/arm-linux-gnueabihf/include/c++/5/backward/'; 187 | process.env['CPATH'] += CPATH ? ':' + CPATH : ''; 188 | } else { 189 | if (NODE_ZERO) { 190 | process.env['GYP_DEFINES'] += ' clang=0'; 191 | process.env['CXX'] = 'g++-4.8'; 192 | 193 | var CPATH = process.env['CPATH']; 194 | 195 | process.env['CPATH'] = '/usr/include/c++/4.8/'; 196 | process.env['CPATH'] += '/usr/include/x86_64-linux-gnu/c++/4.8/'; 197 | process.env['CPATH'] += '/usr/include/c++/4.8/backward/'; 198 | process.env['CPATH'] += CPATH ? ':' + CPATH : ''; 199 | } else { 200 | process.env['GYP_DEFINES'] += ' clang=1'; 201 | } 202 | 203 | if (!process.env['JAVA_HOME']) { 204 | if (fs.existsSync('/usr/lib/jvm/java')) { 205 | process.env['JAVA_HOME'] = '/usr/lib/jvm/java'; 206 | } else { 207 | process.env['JAVA_HOME'] = '/usr/lib/jvm/default-java'; 208 | } 209 | } 210 | } 211 | 212 | break; 213 | default: 214 | break; 215 | } 216 | 217 | console.log('target_arch =', ARCH); 218 | console.log('host_arch =', process.arch); 219 | console.log('configuration =', CONFIG); 220 | 221 | sync(); 222 | } 223 | 224 | function config() { 225 | if (!fs.existsSync(WEBRTC) || !fs.existsSync(path.resolve(WEBRTC, '.gclient')) || !fs.existsSync(WEBRTC_SRC)) { 226 | if (!fs.existsSync(WEBRTC)) { 227 | fs.mkdirSync(WEBRTC); 228 | } 229 | 230 | var res = spawn(GCLIENT, ['config', '--name=src', CHROMIUM], { 231 | cwd: WEBRTC, 232 | env: process.env, 233 | stdio: 'inherit', 234 | }); 235 | 236 | res.on('close', function (code) { 237 | if (!code) { 238 | return configure(); 239 | } 240 | 241 | process.exit(1); 242 | }); 243 | } else { 244 | configure(); 245 | } 246 | } 247 | 248 | process.env['GYP_DEFINES'] = process.env['GYP_DEFINES'] ? process.env['GYP_DEFINES'] : ''; 249 | 250 | if (!fs.existsSync(THIRD_PARTY)) { 251 | fs.mkdirSync(THIRD_PARTY); 252 | } 253 | 254 | process.env['PATH'] = process.env['PATH'] + path.delimiter + DEPOT_TOOLS; 255 | 256 | if (!fs.existsSync(DEPOT_TOOLS)) { 257 | var res = spawn('git', ['clone', DEPOT_TOOLS_REPO], { 258 | cwd: THIRD_PARTY, 259 | env: process.env, 260 | stdio: 'inherit', 261 | }); 262 | 263 | res.on('close', function (code) { 264 | if (!code) { 265 | return config(); 266 | } 267 | 268 | process.exit(1); 269 | }); 270 | } else { 271 | config(); 272 | } 273 | -------------------------------------------------------------------------------- /src/Stats.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #include "Stats.h" 27 | 28 | using namespace v8; 29 | using namespace WebRTC; 30 | 31 | Nan::Persistent RTCStatsReport::constructor; 32 | 33 | RTCStatsReport::~RTCStatsReport() { 34 | 35 | } 36 | 37 | void RTCStatsReport::Init() { 38 | Nan::HandleScope scope; 39 | 40 | Local tpl = Nan::New(RTCStatsReport::New); 41 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 42 | tpl->SetClassName(Nan::New("RTCStatsReport").ToLocalChecked()); 43 | 44 | tpl->PrototypeTemplate()->Set(Nan::New("names").ToLocalChecked(), Nan::New(RTCStatsReport::Names)->GetFunction()); 45 | tpl->PrototypeTemplate()->Set(Nan::New("stat").ToLocalChecked(), Nan::New(RTCStatsReport::Stat)->GetFunction()); 46 | 47 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("id").ToLocalChecked(), RTCStatsReport::Id); 48 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("type").ToLocalChecked(), RTCStatsReport::Type); 49 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("timestamp").ToLocalChecked(), RTCStatsReport::Timestamp); 50 | 51 | constructor.Reset(tpl->GetFunction()); 52 | }; 53 | 54 | Local RTCStatsReport::New(webrtc::StatsReport *report) { 55 | Nan::EscapableHandleScope scope; 56 | Local instance = Nan::New(RTCStatsReport::constructor); 57 | 58 | if (instance.IsEmpty()) { 59 | return scope.Escape(Nan::Null()); 60 | } 61 | 62 | Local ret = instance->NewInstance(); 63 | RTCStatsReport *stats = RTCWrap::Unwrap(ret, "RTCStatsReport"); 64 | 65 | if (stats) { 66 | stats->_report = report; 67 | } 68 | 69 | return scope.Escape(ret); 70 | } 71 | 72 | void RTCStatsReport::New(const Nan::FunctionCallbackInfo &info) { 73 | if (info.IsConstructCall()) { 74 | RTCStatsReport* report = new RTCStatsReport(); 75 | report->Wrap(info.This(), "RTCStatsReport"); 76 | return info.GetReturnValue().Set(info.This()); 77 | } 78 | 79 | Nan::ThrowError("Internal Error"); 80 | info.GetReturnValue().SetUndefined(); 81 | } 82 | 83 | void RTCStatsReport::Names(const Nan::FunctionCallbackInfo &info) { 84 | RTCStatsReport *stats = RTCWrap::Unwrap(info.This(), "RTCStatsReport"); 85 | webrtc::StatsReport::Values values = stats->_report->values(); 86 | Local list = Nan::New(); 87 | unsigned int index = 0; 88 | 89 | for (webrtc::StatsReport::Values::iterator it = values.begin(); it != values.end(); it++) { 90 | webrtc::StatsReport::ValuePtr value = values[it->first]; 91 | list->Set(index, Nan::New(value->display_name()).ToLocalChecked()); 92 | index++; 93 | } 94 | 95 | return info.GetReturnValue().Set(list); 96 | } 97 | 98 | void RTCStatsReport::Stat(const Nan::FunctionCallbackInfo &info) { 99 | RTCStatsReport *stats = RTCWrap::Unwrap(info.This(), "RTCStatsReport"); 100 | webrtc::StatsReport::Values values = stats->_report->values(); 101 | 102 | if (info.Length() >= 1 && info[0]->IsString()) { 103 | String::Utf8Value entry_value(info[0]->ToString()); 104 | std::string entry(*entry_value); 105 | 106 | for (webrtc::StatsReport::Values::iterator it = values.begin(); it != values.end(); it++) { 107 | webrtc::StatsReport::ValuePtr value = values[it->first]; 108 | 109 | if (!entry.compare(value->display_name())) { 110 | switch (value->type()) { 111 | case webrtc::StatsReport::Value::kInt: 112 | return info.GetReturnValue().Set(Nan::New(value->int_val())); 113 | 114 | break; 115 | case webrtc::StatsReport::Value::kInt64: 116 | return info.GetReturnValue().Set(Nan::New(static_cast(value->int64_val()))); 117 | 118 | break; 119 | case webrtc::StatsReport::Value::kFloat: 120 | return info.GetReturnValue().Set(Nan::New(value->float_val())); 121 | 122 | break; 123 | case webrtc::StatsReport::Value::kString: 124 | return info.GetReturnValue().Set(Nan::New(value->string_val().c_str()).ToLocalChecked()); 125 | 126 | break; 127 | case webrtc::StatsReport::Value::kStaticString: 128 | return info.GetReturnValue().Set(Nan::New(value->static_string_val()).ToLocalChecked()); 129 | 130 | break; 131 | case webrtc::StatsReport::Value::kBool: 132 | return info.GetReturnValue().Set(Nan::New(value->bool_val())); 133 | 134 | break; 135 | case webrtc::StatsReport::Value::kId: 136 | return info.GetReturnValue().Set(Nan::New(value->ToString().c_str()).ToLocalChecked()); 137 | 138 | break; 139 | } 140 | } 141 | } 142 | } 143 | 144 | info.GetReturnValue().SetUndefined(); 145 | } 146 | 147 | void RTCStatsReport::Id(Local property, const Nan::PropertyCallbackInfo &info) { 148 | RTCStatsReport *stats = RTCWrap::Unwrap(info.This(), "RTCStatsReport"); 149 | std::string id(stats->_report->id()->ToString()); 150 | return info.GetReturnValue().Set(Nan::New(id.c_str()).ToLocalChecked()); 151 | } 152 | 153 | void RTCStatsReport::Type(Local property, const Nan::PropertyCallbackInfo &info) { 154 | RTCStatsReport *stats = RTCWrap::Unwrap(info.This(), "RTCStatsReport"); 155 | return info.GetReturnValue().Set(Nan::New(stats->_report->TypeToString()).ToLocalChecked()); 156 | } 157 | 158 | void RTCStatsReport::Timestamp(Local property, const Nan::PropertyCallbackInfo &info) { 159 | RTCStatsReport *stats = RTCWrap::Unwrap(info.This(), "RTCStatsReport"); 160 | return info.GetReturnValue().Set(Nan::New(stats->_report->timestamp())); 161 | } 162 | 163 | Nan::Persistent RTCStatsResponse::constructor; 164 | 165 | RTCStatsResponse::~RTCStatsResponse() { 166 | 167 | } 168 | 169 | void RTCStatsResponse::Init() { 170 | Nan::HandleScope scope; 171 | 172 | Local tpl = Nan::New(RTCStatsResponse::New); 173 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 174 | tpl->SetClassName(Nan::New("RTCStatsResponse").ToLocalChecked()); 175 | 176 | tpl->PrototypeTemplate()->Set(Nan::New("result").ToLocalChecked(), Nan::New(RTCStatsResponse::Result)->GetFunction()); 177 | 178 | constructor.Reset(tpl->GetFunction()); 179 | } 180 | 181 | void RTCStatsResponse::New(const Nan::FunctionCallbackInfo &info) { 182 | if (info.IsConstructCall()) { 183 | RTCStatsResponse *response = new RTCStatsResponse(); 184 | response->Wrap(info.This(), "RTCStatsResponse"); 185 | return info.GetReturnValue().Set(info.This()); 186 | } 187 | 188 | Nan::ThrowError("Internal Error"); 189 | info.GetReturnValue().SetUndefined(); 190 | } 191 | 192 | Local RTCStatsResponse::New(const webrtc::StatsReports &reports) { 193 | Nan::EscapableHandleScope scope; 194 | Local instance = Nan::New(RTCStatsResponse::constructor); 195 | 196 | if (instance.IsEmpty()) { 197 | return scope.Escape(Nan::Null()); 198 | } 199 | 200 | Local ret = instance->NewInstance(); 201 | RTCStatsResponse *response = RTCWrap::Unwrap(ret, "RTCStatsResponse"); 202 | 203 | response->_reports = reports; 204 | 205 | return scope.Escape(ret); 206 | } 207 | 208 | void RTCStatsResponse::Result(const Nan::FunctionCallbackInfo &info) { 209 | RTCStatsResponse *response = RTCWrap::Unwrap(info.This(), "RTCStatsResponse"); 210 | Local list = Nan::New(response->_reports.size()); 211 | 212 | for(unsigned int index = 0; index < response->_reports.size(); index++) { 213 | list->Set(index, RTCStatsReport::New(const_cast(response->_reports.at(index)))); 214 | } 215 | 216 | return info.GetReturnValue().Set(list); 217 | } 218 | -------------------------------------------------------------------------------- /src/ArrayBuffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef NODE_ARRAYBUFFER_H 27 | #define NODE_ARRAYBUFFER_H 28 | 29 | #ifdef WIN32 30 | #pragma warning( disable : 4267 ) 31 | #endif 32 | 33 | #include 34 | #include 35 | 36 | namespace node { 37 | class ArrayBuffer { 38 | public: 39 | inline static ArrayBuffer* New(const char *str = 0) { 40 | #if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION) 41 | return ArrayBuffer::New(v8::Isolate::GetCurrent(), std::string(str)); 42 | #else 43 | return ArrayBuffer::New(std::string(str)); 44 | #endif 45 | } 46 | 47 | inline static ArrayBuffer* New(const std::string &data) { 48 | #if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION) 49 | return ArrayBuffer::New(v8::Isolate::GetCurrent(), data.data(), data.size()); 50 | #else 51 | return ArrayBuffer::New(data.data(), data.size()); 52 | #endif 53 | } 54 | 55 | #if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION) 56 | template inline static ArrayBuffer* New(T *str, size_t length) { 57 | return ArrayBuffer::New(v8::Isolate::GetCurrent(), reinterpret_cast(str), length); 58 | } 59 | 60 | inline static ArrayBuffer* New(const char *str, size_t length) { 61 | return ArrayBuffer::New(v8::Isolate::GetCurrent(), str, length); 62 | } 63 | 64 | inline static ArrayBuffer* New(const v8::Local &arrayBuffer) { 65 | return ArrayBuffer::New(v8::Isolate::GetCurrent(), arrayBuffer); 66 | } 67 | 68 | inline static ArrayBuffer* New(const v8::Local &arg) { 69 | return ArrayBuffer::New(v8::Isolate::GetCurrent(), arg); 70 | } 71 | 72 | inline static ArrayBuffer* New(v8::Isolate *isolate, const std::string &data) { 73 | return ArrayBuffer::New(isolate, data.data(), data.size()); 74 | } 75 | 76 | inline static ArrayBuffer* New(v8::Isolate *isolate, const char *str = 0) { 77 | return ArrayBuffer::New(isolate, std::string(str)); 78 | } 79 | 80 | inline static ArrayBuffer* New(v8::Isolate *isolate, const char *str, size_t length) { 81 | if (!isolate) { 82 | isolate = v8::Isolate::GetCurrent(); 83 | } 84 | 85 | ArrayBuffer *buffer = new ArrayBuffer(); 86 | v8::Local arrayBuffer; 87 | 88 | buffer->_data = 0; 89 | buffer->_len = length; 90 | 91 | if (length) { 92 | buffer->_data = new char[length + 1]; 93 | buffer->_data[length] = '\0'; 94 | 95 | for (size_t index = 0; index < length; index++) { 96 | buffer->_data[index] = str[index]; 97 | } 98 | 99 | arrayBuffer = v8::ArrayBuffer::New(isolate, buffer->_data, length); 100 | } 101 | else { 102 | arrayBuffer = v8::ArrayBuffer::New(isolate, length); 103 | } 104 | 105 | buffer->_arrayBuffer.Reset(isolate, arrayBuffer); 106 | buffer->_arrayBuffer.SetWeak(buffer, ArrayBuffer::onDispose); 107 | buffer->_arrayBuffer.MarkIndependent(); 108 | 109 | arrayBuffer->SetHiddenValue(v8::String::NewFromUtf8(isolate, "node::ArrayBuffer"), v8::External::New(isolate, buffer)); 110 | return buffer; 111 | } 112 | 113 | inline static ArrayBuffer* New(v8::Isolate *isolate, const v8::Local &arrayBuffer) { 114 | if (!isolate) { 115 | isolate = v8::Isolate::GetCurrent(); 116 | } 117 | 118 | if (arrayBuffer.IsEmpty()) { 119 | return ArrayBuffer::New(isolate); 120 | } 121 | 122 | if (arrayBuffer->IsExternal()) { 123 | v8::Local ptr = arrayBuffer->GetHiddenValue(v8::String::NewFromUtf8(isolate, "node::ArrayBuffer")); 124 | 125 | if (ptr.IsEmpty()) { 126 | v8::Local uintArray = v8::Uint8Array::New(arrayBuffer, 0, arrayBuffer->ByteLength()); 127 | return ArrayBuffer::New(isolate, uintArray); 128 | } else { 129 | v8::Local ext = v8::Local::Cast(ptr); 130 | return static_cast(ext->Value()); 131 | } 132 | } else { 133 | ArrayBuffer *buffer = new ArrayBuffer(); 134 | v8::ArrayBuffer::Contents content = arrayBuffer->Externalize(); 135 | 136 | buffer->_data = static_cast(content.Data()); 137 | buffer->_len = content.ByteLength(); 138 | buffer->_arrayBuffer.Reset(isolate, arrayBuffer); 139 | buffer->_arrayBuffer.SetWeak(buffer, ArrayBuffer::onDispose); 140 | buffer->_arrayBuffer.MarkIndependent(); 141 | 142 | arrayBuffer->SetHiddenValue(v8::String::NewFromUtf8(isolate, "node::ArrayBuffer"), v8::External::New(isolate, buffer)); 143 | 144 | return buffer; 145 | } 146 | 147 | return 0; 148 | } 149 | 150 | inline static ArrayBuffer* New(v8::Isolate *isolate, const v8::Local &arg) { 151 | if (!arg.IsEmpty()) { 152 | if (arg->IsArrayBuffer() || arg->IsTypedArray()) { 153 | v8::Local arrayBuffer; 154 | 155 | if (arg->IsArrayBuffer()) { 156 | arrayBuffer = v8::Local::Cast(arg); 157 | } 158 | else { 159 | v8::Local view = v8::Local::Cast(arg); 160 | arrayBuffer = view->Buffer(); 161 | } 162 | 163 | return ArrayBuffer::New(isolate, arrayBuffer); 164 | } 165 | 166 | if (arg->IsString()) { 167 | v8::String::Utf8Value str(arg->ToString()); 168 | return ArrayBuffer::New(isolate, *str, str.length()); 169 | } 170 | } 171 | 172 | return ArrayBuffer::New(isolate); 173 | } 174 | 175 | inline v8::Local ToArrayBuffer(v8::Isolate *isolate = 0) const { 176 | if (!isolate) { 177 | isolate = v8::Isolate::GetCurrent(); 178 | } 179 | 180 | v8::EscapableHandleScope scope(isolate); 181 | return scope.Escape(v8::Local::New(isolate, _arrayBuffer)); 182 | } 183 | 184 | inline v8::Local ToString(v8::Isolate *isolate = 0) const { 185 | if (!isolate) { 186 | isolate = v8::Isolate::GetCurrent(); 187 | } 188 | 189 | v8::EscapableHandleScope scope(isolate); 190 | v8::Local retval = v8::String::NewFromUtf8(isolate, ArrayBuffer::ToUtf8(), v8::String::kNormalString, ArrayBuffer::Length()); 191 | return scope.Escape(retval); 192 | } 193 | 194 | #else 195 | template inline static ArrayBuffer* New(T *str, size_t length) { 196 | const char *ptr = reinterpret_cast(str); 197 | return ArrayBuffer::New(ptr, length); 198 | } 199 | 200 | inline static ArrayBuffer* New(const char *str, size_t length) { 201 | ArrayBuffer *buffer = new ArrayBuffer(); 202 | 203 | v8::Local global = v8::Context::GetCurrent()->Global(); 204 | v8::Local instance = global->Get(v8::String::New("ArrayBuffer")); 205 | v8::Local constructor = v8::Local::Cast(instance); 206 | v8::Local arrayBuffer = constructor->NewInstance(); 207 | 208 | buffer->_data = 0; 209 | buffer->_len = length; 210 | 211 | if (length) { 212 | buffer->_data = new char[length + 1]; 213 | buffer->_data[length] = '\0'; 214 | 215 | for (size_t index = 0; index < length; index++) { 216 | buffer->_data[index] = str[index]; 217 | } 218 | 219 | arrayBuffer->SetIndexedPropertiesToExternalArrayData(buffer->_data, v8::kExternalByteArray, buffer->_len); 220 | } 221 | 222 | buffer->_arrayBuffer = v8::Persistent::New(arrayBuffer); 223 | buffer->_arrayBuffer.MakeWeak(buffer, ArrayBuffer::onDispose); 224 | buffer->_arrayBuffer.MarkIndependent(); 225 | 226 | arrayBuffer->SetHiddenValue(v8::String::New("node::ArrayBuffer"), v8::External::New(buffer)); 227 | return buffer; 228 | } 229 | 230 | inline static ArrayBuffer* New(const v8::Local &arrayBuffer) { 231 | if (!arrayBuffer.IsEmpty()) { 232 | v8::Local ptr = arrayBuffer->GetHiddenValue(v8::String::New("node::ArrayBuffer")); 233 | 234 | if (!ptr.IsEmpty()) { 235 | v8::Local ext = v8::Local::Cast(ptr); 236 | return static_cast(ext->Value()); 237 | } else { 238 | if (arrayBuffer->HasIndexedPropertiesInExternalArrayData()) { 239 | int length = arrayBuffer->GetIndexedPropertiesExternalArrayDataLength(); 240 | 241 | if (length > 0) { 242 | char *data = static_cast(arrayBuffer->GetIndexedPropertiesExternalArrayData()); 243 | return ArrayBuffer::New(data, static_cast(length)); 244 | } 245 | } 246 | } 247 | } 248 | 249 | return ArrayBuffer::New(); 250 | } 251 | 252 | inline static ArrayBuffer* New(const v8::Local &arg) { 253 | if (!arg.IsEmpty()) { 254 | if (arg->IsObject()) { 255 | v8::Local arrayBuffer = v8::Local::Cast(arg); 256 | return ArrayBuffer::New(arrayBuffer); 257 | } 258 | 259 | if (arg->IsString()) { 260 | v8::String::Utf8Value str(arg->ToString()); 261 | return ArrayBuffer::New(*str, str.length()); 262 | } 263 | } 264 | 265 | return ArrayBuffer::New(); 266 | } 267 | 268 | inline v8::Local ToArrayBuffer() const { 269 | v8::HandleScope scope; 270 | v8::Local arrayBuffer = v8::Local::New(_arrayBuffer); 271 | return scope.Close(arrayBuffer); 272 | } 273 | 274 | inline v8::Local ToString() const { 275 | v8::HandleScope scope; 276 | v8::Local str = v8::String::New(ArrayBuffer::ToUtf8(), ArrayBuffer::Length()); 277 | return scope.Close(str); 278 | } 279 | 280 | #endif 281 | inline std::string ToCString() const { 282 | return std::string(ArrayBuffer::ToUtf8(), ArrayBuffer::Length()); 283 | } 284 | 285 | template inline T* To() { 286 | return reinterpret_cast(_data); 287 | } 288 | 289 | template inline const T* To() const { 290 | return reinterpret_cast(_data); 291 | } 292 | 293 | inline char *ToUtf8() { 294 | return _data; 295 | } 296 | 297 | inline const char *ToUtf8() const { 298 | return _data; 299 | } 300 | 301 | inline void *Data() const { 302 | return _data; 303 | } 304 | 305 | inline size_t Length() const { 306 | return _len; 307 | } 308 | 309 | inline size_t ByteLength() const { 310 | return _len; 311 | } 312 | 313 | #if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION) 314 | static inline void onDispose(const v8::WeakCallbackData &info) { 315 | v8::Isolate *isolate = info.GetIsolate(); 316 | v8::HandleScope scope(isolate); 317 | 318 | ArrayBuffer *wrap = info.GetParameter(); 319 | 320 | if (wrap) { 321 | v8::Local arrayBuffer = v8::Local::New(isolate, wrap->_arrayBuffer); 322 | wrap->_arrayBuffer.Reset(); 323 | 324 | if (!arrayBuffer.IsEmpty()) { 325 | arrayBuffer->DeleteHiddenValue(v8::String::NewFromUtf8(isolate, "node::ArrayBuffer")); 326 | } 327 | 328 | delete wrap; 329 | } 330 | } 331 | #else 332 | static inline void onDispose(v8::Persistent value, void *data) { 333 | v8::HandleScope scope; 334 | ArrayBuffer *wrap = static_cast(data); 335 | 336 | if (wrap) { 337 | v8::Local arrayBuffer = v8::Local::New(wrap->_arrayBuffer); 338 | 339 | if (!arrayBuffer.IsEmpty()) { 340 | arrayBuffer->DeleteHiddenValue(v8::String::New("node::ArrayBuffer")); 341 | } 342 | 343 | delete wrap; 344 | } 345 | } 346 | #endif 347 | 348 | private: 349 | virtual ~ArrayBuffer() { 350 | #if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION) 351 | if (_len) { 352 | delete [] _data; 353 | } 354 | #else 355 | _arrayBuffer.ClearWeak(); 356 | _arrayBuffer.Dispose(); 357 | _arrayBuffer.Clear(); 358 | #endif 359 | } 360 | 361 | protected: 362 | char* _data; 363 | size_t _len; 364 | 365 | #if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION) 366 | v8::Persistent _arrayBuffer; 367 | #else 368 | v8::Persistent _arrayBuffer; 369 | #endif 370 | 371 | }; 372 | }; 373 | 374 | #endif 375 | -------------------------------------------------------------------------------- /src/DataChannel.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 vmolsa (http://github.com/vmolsa) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #include "DataChannel.h" 27 | 28 | using namespace v8; 29 | using namespace WebRTC; 30 | 31 | Nan::Persistent DataChannel::constructor; 32 | 33 | void DataChannel::Init() { 34 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 35 | 36 | Nan::HandleScope scope; 37 | 38 | Local tpl = Nan::New(DataChannel::New); 39 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 40 | tpl->SetClassName(Nan::New("RTCDataChannel").ToLocalChecked()); 41 | 42 | Nan::SetPrototypeMethod(tpl, "close", DataChannel::Close); 43 | Nan::SetPrototypeMethod(tpl, "send", DataChannel::Send); 44 | 45 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("id").ToLocalChecked(), DataChannel::GetId); 46 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("label").ToLocalChecked(), DataChannel::GetLabel); 47 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("ordered").ToLocalChecked(), DataChannel::GetOrdered); 48 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("protocol").ToLocalChecked(), DataChannel::GetProtocol); 49 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("readyState").ToLocalChecked(), DataChannel::GetReadyState); 50 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("bufferedAmount").ToLocalChecked(), DataChannel::GetBufferedAmount); 51 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("binaryType").ToLocalChecked(), DataChannel::GetBinaryType, DataChannel::SetBinaryType); 52 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("maxPacketLifeType").ToLocalChecked(), DataChannel::GetMaxPacketLifeType); 53 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("maxRetransmits").ToLocalChecked(), DataChannel::GetMaxRetransmits); 54 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("negotiated").ToLocalChecked(), DataChannel::GetNegotiated); 55 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("reliable").ToLocalChecked(), DataChannel::GetReliable); 56 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("onopen").ToLocalChecked(), DataChannel::GetOnOpen, DataChannel::SetOnOpen); 57 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("onmessage").ToLocalChecked(), DataChannel::GetOnMessage, DataChannel::SetOnMessage); 58 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("onclose").ToLocalChecked(), DataChannel::GetOnClose, DataChannel::SetOnClose); 59 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("onerror").ToLocalChecked(), DataChannel::GetOnError, DataChannel::SetOnError); 60 | 61 | constructor.Reset(tpl->GetFunction()); 62 | } 63 | 64 | DataChannel::DataChannel() { 65 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 66 | 67 | _observer = new rtc::RefCountedObject(this); 68 | } 69 | 70 | DataChannel::~DataChannel() { 71 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 72 | 73 | if (_socket.get()) { 74 | _socket->UnregisterObserver(); 75 | _observer->RemoveListener(this); 76 | 77 | webrtc::DataChannelInterface::DataState state(_socket->state()); 78 | 79 | if (state != webrtc::DataChannelInterface::kClosing || 80 | state != webrtc::DataChannelInterface::kClosed) 81 | { 82 | _socket->Close(); 83 | } 84 | } 85 | } 86 | 87 | void DataChannel::New(const Nan::FunctionCallbackInfo &info) { 88 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 89 | 90 | if (info.IsConstructCall()) { 91 | DataChannel* dataChannel = new DataChannel(); 92 | dataChannel->Wrap(info.This(), "DataChannel"); 93 | return info.GetReturnValue().Set(info.This()); 94 | } 95 | 96 | Nan::ThrowError("Internal Error"); 97 | info.GetReturnValue().SetUndefined(); 98 | } 99 | 100 | Local DataChannel::New(rtc::scoped_refptr dataChannel) { 101 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 102 | 103 | Nan::EscapableHandleScope scope; 104 | Local instance = Nan::New(DataChannel::constructor); 105 | 106 | if (instance.IsEmpty() || !dataChannel.get()) { 107 | return scope.Escape(Nan::Null()); 108 | } 109 | 110 | Local ret = instance->NewInstance(); 111 | DataChannel *self = RTCWrap::Unwrap(ret, "DataChannel"); 112 | 113 | self->SetReference(true); 114 | self->_socket = dataChannel; 115 | self->_socket->RegisterObserver(self->_observer.get()); 116 | self->Emit(kDataChannelStateChange); 117 | 118 | self->_binaryType.Reset(Nan::New("arraybuffer").ToLocalChecked()); 119 | 120 | return scope.Escape(ret); 121 | } 122 | 123 | webrtc::DataChannelInterface *DataChannel::GetSocket() const { 124 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 125 | 126 | return _socket.get(); 127 | } 128 | 129 | void DataChannel::Close(const Nan::FunctionCallbackInfo &info) { 130 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 131 | 132 | DataChannel *self = RTCWrap::Unwrap(info.This(), "DataChannel"); 133 | webrtc::DataChannelInterface *socket = self->GetSocket(); 134 | 135 | if (socket) { 136 | webrtc::DataChannelInterface::DataState state(socket->state()); 137 | 138 | if (state != webrtc::DataChannelInterface::kClosing || 139 | state != webrtc::DataChannelInterface::kClosed) 140 | { 141 | socket->Close(); 142 | } 143 | } 144 | 145 | info.GetReturnValue().SetUndefined(); 146 | } 147 | 148 | void DataChannel::Send(const Nan::FunctionCallbackInfo &info) { 149 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 150 | 151 | DataChannel *self = RTCWrap::Unwrap(info.This(), "DataChannel"); 152 | webrtc::DataChannelInterface *socket = self->GetSocket(); 153 | bool retval = false; 154 | 155 | if (socket) { 156 | if(info[0]->IsString()) { 157 | std::string data(*Nan::Utf8String(info[0])); 158 | webrtc::DataBuffer buffer(data); 159 | retval = socket->Send(buffer); 160 | } else { 161 | node::ArrayBuffer *container = node::ArrayBuffer::New(info[0]); 162 | rtc::Buffer data(reinterpret_cast(container->Data()), container->Length()); 163 | //rtc::CopyOnWriteBuffer data(reinterpret_cast(container->Data()), container->Length()); 164 | webrtc::DataBuffer buffer(data, true); 165 | retval = socket->Send(buffer); 166 | } 167 | } 168 | 169 | return info.GetReturnValue().Set(Nan::New(retval)); 170 | } 171 | 172 | void DataChannel::GetId(Local property, const Nan::PropertyCallbackInfo &info) { 173 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 174 | 175 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 176 | webrtc::DataChannelInterface *socket = self->GetSocket(); 177 | 178 | if (socket) { 179 | return info.GetReturnValue().Set(Nan::New(socket->id())); 180 | } 181 | 182 | info.GetReturnValue().SetUndefined(); 183 | } 184 | 185 | void DataChannel::GetLabel(Local property, const Nan::PropertyCallbackInfo &info) { 186 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 187 | 188 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 189 | webrtc::DataChannelInterface *socket = self->GetSocket(); 190 | 191 | if (socket) { 192 | return info.GetReturnValue().Set(Nan::New(socket->label().c_str()).ToLocalChecked()); 193 | } 194 | 195 | info.GetReturnValue().SetUndefined(); 196 | } 197 | 198 | void DataChannel::GetOrdered(Local property, const Nan::PropertyCallbackInfo &info) { 199 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 200 | 201 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 202 | webrtc::DataChannelInterface *socket = self->GetSocket(); 203 | 204 | if (socket) { 205 | return info.GetReturnValue().Set(Nan::New(socket->ordered())); 206 | } 207 | 208 | info.GetReturnValue().SetUndefined(); 209 | } 210 | 211 | void DataChannel::GetProtocol(Local property, const Nan::PropertyCallbackInfo &info) { 212 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 213 | 214 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 215 | webrtc::DataChannelInterface *socket = self->GetSocket(); 216 | 217 | if (socket) { 218 | return info.GetReturnValue().Set(Nan::New(socket->protocol().c_str()).ToLocalChecked()); 219 | } 220 | 221 | info.GetReturnValue().SetUndefined(); 222 | } 223 | 224 | void DataChannel::GetReadyState(Local property, const Nan::PropertyCallbackInfo &info) { 225 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 226 | 227 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 228 | webrtc::DataChannelInterface *socket = self->GetSocket(); 229 | 230 | if (socket) { 231 | webrtc::DataChannelInterface::DataState state(socket->state()); 232 | 233 | switch (state) { 234 | case webrtc::DataChannelInterface::kConnecting: 235 | return info.GetReturnValue().Set(Nan::New("connecting").ToLocalChecked()); 236 | break; 237 | case webrtc::DataChannelInterface::kOpen: 238 | return info.GetReturnValue().Set(Nan::New("open").ToLocalChecked()); 239 | break; 240 | case webrtc::DataChannelInterface::kClosing: 241 | return info.GetReturnValue().Set(Nan::New("closing").ToLocalChecked()); 242 | break; 243 | case webrtc::DataChannelInterface::kClosed: 244 | return info.GetReturnValue().Set(Nan::New("closed").ToLocalChecked()); 245 | break; 246 | } 247 | } 248 | 249 | info.GetReturnValue().SetUndefined(); 250 | } 251 | 252 | void DataChannel::GetBufferedAmount(Local property, const Nan::PropertyCallbackInfo &info) { 253 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 254 | 255 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 256 | webrtc::DataChannelInterface *socket = self->GetSocket(); 257 | 258 | if (socket) { 259 | return info.GetReturnValue().Set(Nan::New(static_cast(socket->buffered_amount()))); 260 | } 261 | 262 | info.GetReturnValue().SetUndefined(); 263 | } 264 | 265 | void DataChannel::GetBinaryType(Local property, const Nan::PropertyCallbackInfo &info) { 266 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 267 | 268 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 269 | return info.GetReturnValue().Set(Nan::New(self->_binaryType)); 270 | } 271 | 272 | void DataChannel::GetMaxPacketLifeType(Local property, const Nan::PropertyCallbackInfo &info) { 273 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 274 | 275 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 276 | webrtc::DataChannelInterface *socket = self->GetSocket(); 277 | 278 | if (socket) { 279 | return info.GetReturnValue().Set(Nan::New(static_cast(socket->maxRetransmitTime()))); 280 | } 281 | 282 | info.GetReturnValue().SetUndefined(); 283 | } 284 | 285 | void DataChannel::GetMaxRetransmits(Local property, const Nan::PropertyCallbackInfo &info) { 286 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 287 | 288 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 289 | webrtc::DataChannelInterface *socket = self->GetSocket(); 290 | 291 | if (socket) { 292 | return info.GetReturnValue().Set(Nan::New(static_cast(socket->maxRetransmits()))); 293 | } 294 | 295 | info.GetReturnValue().SetUndefined(); 296 | } 297 | 298 | void DataChannel::GetNegotiated(Local property, const Nan::PropertyCallbackInfo &info) { 299 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 300 | 301 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 302 | webrtc::DataChannelInterface *socket = self->GetSocket(); 303 | 304 | if (socket) { 305 | return info.GetReturnValue().Set(Nan::New(socket->negotiated())); 306 | } 307 | 308 | return info.GetReturnValue().Set(Nan::False()); 309 | } 310 | 311 | void DataChannel::GetReliable(Local property, const Nan::PropertyCallbackInfo &info) { 312 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 313 | 314 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 315 | webrtc::DataChannelInterface *socket = self->GetSocket(); 316 | 317 | if (socket) { 318 | return info.GetReturnValue().Set(Nan::New(socket->reliable())); 319 | } 320 | 321 | return info.GetReturnValue().Set(Nan::False()); 322 | } 323 | 324 | void DataChannel::GetOnOpen(Local property, const Nan::PropertyCallbackInfo &info) { 325 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 326 | 327 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 328 | return info.GetReturnValue().Set(Nan::New(self->_onopen)); 329 | } 330 | 331 | void DataChannel::GetOnMessage(Local property, const Nan::PropertyCallbackInfo &info) { 332 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 333 | 334 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 335 | return info.GetReturnValue().Set(Nan::New(self->_onmessage)); 336 | } 337 | 338 | void DataChannel::GetOnClose(Local property, const Nan::PropertyCallbackInfo &info) { 339 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 340 | 341 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 342 | return info.GetReturnValue().Set(Nan::New(self->_onclose)); 343 | } 344 | 345 | void DataChannel::GetOnError(Local property, const Nan::PropertyCallbackInfo &info) { 346 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 347 | 348 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 349 | return info.GetReturnValue().Set(Nan::New(self->_onerror)); 350 | } 351 | 352 | void DataChannel::ReadOnly(Local property, Local value, const Nan::PropertyCallbackInfo &info) { 353 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 354 | } 355 | 356 | void DataChannel::SetBinaryType(Local property, Local value, const Nan::PropertyCallbackInfo &info) { 357 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 358 | 359 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 360 | 361 | if (!value.IsEmpty() && value->IsString()) { 362 | self->_binaryType.Reset(value->ToString()); 363 | } else { 364 | self->_binaryType.Reset(Nan::New("arraybuffer").ToLocalChecked()); 365 | } 366 | } 367 | 368 | void DataChannel::SetOnOpen(Local property, Local value, const Nan::PropertyCallbackInfo &info) { 369 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 370 | 371 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 372 | 373 | if (!value.IsEmpty() && value->IsFunction()) { 374 | self->_onopen.Reset(Local::Cast(value)); 375 | } else { 376 | self->_onopen.Reset(); 377 | } 378 | } 379 | 380 | void DataChannel::SetOnMessage(Local property, Local value, const Nan::PropertyCallbackInfo &info) { 381 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 382 | 383 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 384 | 385 | if (!value.IsEmpty() && value->IsFunction()) { 386 | self->_onmessage.Reset(Local::Cast(value)); 387 | } else { 388 | self->_onmessage.Reset(); 389 | } 390 | } 391 | 392 | void DataChannel::SetOnClose(Local property, Local value, const Nan::PropertyCallbackInfo &info) { 393 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 394 | 395 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 396 | 397 | if (!value.IsEmpty() && value->IsFunction()) { 398 | self->_onclose.Reset(Local::Cast(value)); 399 | } else { 400 | self->_onclose.Reset(); 401 | } 402 | } 403 | 404 | void DataChannel::SetOnError(Local property, Local value, const Nan::PropertyCallbackInfo &info) { 405 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 406 | 407 | DataChannel *self = RTCWrap::Unwrap(info.Holder(), "DataChannel"); 408 | 409 | if (!value.IsEmpty() && value->IsFunction()) { 410 | self->_onerror.Reset(Local::Cast(value)); 411 | } else { 412 | self->_onclose.Reset(); 413 | } 414 | } 415 | 416 | void DataChannel::On(Event *event) { 417 | LOG(LS_INFO) << __PRETTY_FUNCTION__; 418 | 419 | Nan::HandleScope scope; 420 | DataChannelEvent type = event->Type(); 421 | node::ArrayBuffer *arrayBuffer = 0; 422 | Local callback; 423 | Local argv[1]; 424 | bool isError = false; 425 | int argc = 0; 426 | 427 | if (type == kDataChannelStateChange) { 428 | webrtc::DataChannelInterface *socket = DataChannel::GetSocket(); 429 | 430 | if (socket) { 431 | switch (socket->state()) { 432 | case webrtc::DataChannelInterface::kConnecting: 433 | 434 | break; 435 | case webrtc::DataChannelInterface::kOpen: 436 | callback = Nan::New(_onopen); 437 | 438 | break; 439 | case webrtc::DataChannelInterface::kClosing: 440 | 441 | break; 442 | case webrtc::DataChannelInterface::kClosed: 443 | EventEmitter::SetReference(false); 444 | 445 | callback = Nan::New(_onclose); 446 | _onclose.Reset(); 447 | 448 | break; 449 | } 450 | } 451 | } else { 452 | callback = Nan::New(_onmessage); 453 | rtc::Buffer buffer = event->Unwrap(); 454 | Local container = Nan::New(); 455 | argv[0] = container; 456 | argc = 1; 457 | 458 | if (type == kDataChannelData) { 459 | container->Set(Nan::New("data").ToLocalChecked(), Nan::New(reinterpret_cast(buffer.data()), buffer.size()).ToLocalChecked()); 460 | } else { 461 | arrayBuffer = node::ArrayBuffer::New(buffer.data(), buffer.size()); 462 | container->Set(Nan::New("data").ToLocalChecked(), arrayBuffer->ToArrayBuffer()); 463 | } 464 | } 465 | 466 | if (!callback.IsEmpty() && callback->IsFunction()) { 467 | callback->Call(RTCWrap::This(), argc, argv); 468 | } else if (isError) { 469 | Nan::ThrowError(argv[0]); 470 | } 471 | } 472 | --------------------------------------------------------------------------------