[
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\nbuild\n\n# Dependency directory\n# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git\nnode_modules\n\nthird_party\n\nconfig.gypi\nnodejs.gypi\n"
  },
  {
    "path": ".npmignore",
    "content": "# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\nbuild\n\n# Dependency directory\n# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git\nnode_modules\n\nsrc\nthird_party\n\nconfig.gypi\nnodejs.gypi\n\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa) \n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "[WebRTC](http://en.wikipedia.org/wiki/WebRTC) for NodeJS\n\n### Chromium\n\nwebrtc-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).\n\n### Usage\n\nFor installing or building module from source go to page [Getting Started](https://github.com/vmolsa/webrtc-native/wiki/Getting-started)\n\n### API\n\n````\nvar WebRTC = require('webrtc-native');\n````\n\n#### WebRTC.[RTCPeerConnection](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection)\n\n#### WebRTC.[RTCIceCandidate](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnectionIceEvent)\n\n#### WebRTC.[RTCSessionDescription](https://developer.mozilla.org/en-US/docs/Web/API/RTCSessionDescription)\n\n#### WebRTC.[RTCDataChannel](https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel)\n\n#### WebRTC.[MediaStream](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream)\n\n#### WebRTC.[MediaStreamTrack](https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack)\n\n#### WebRTC.[getUserMedia](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getUserMedia)\n\n#### WebRTC.[getSources](http://simpl.info/getusermedia/sources/index.html)\n\n- Returns array of available device inputs\n\n#### WebRTC.RTCGarbageCollect()\n\n- Notify V8 Engine to attempt to free memory.\n\n#### WebRTC.setDebug(boolean)\n\n- Enable / Disable WebRTC log messages\n"
  },
  {
    "path": "binding.gyp",
    "content": "{\n  'targets': [\n    {\n      'target_name': 'action_before_build',\n      'dependencies': [],\n      'hard_dependency': 1,\n      'type': 'none',\n      'actions': [\n        {\n          'action_name': 'run_build_script',\n          'inputs': [],\n          'outputs': [''],\n          'action': [\n            'node', 'scripts/build.js', '-Dtarget-arch=<(target_arch)', '<(node_root_dir)', '<(node_lib_file)', '<(node_gyp_dir)'\n          ],\n        }\n      ]\n    },\n  ],\n}\n"
  },
  {
    "path": "examples/node2browser/index.html",
    "content": "<html>\n<head>\n  <script src=\"https://cdn.socket.io/socket.io-1.2.0.js\"></script>\n</head>\n<body>\n  <video></video>\n<script>\n  var config = {\n    iceServers: [\n      {\n        url: 'stun:stun.l.google.com:19302',\n      },\n    ],\n  };\n  \n  var constraints = {\n    optional: [\n      {\n        DtlsSrtpKeyAgreement: true,\n      },\n    ],\n    mandatory: {\n      OfferToReceiveAudio: true,\n      OfferToReceiveVideo: true,\n    },\n  };\n   \n  var socket = io.connect();\n  var peer = new window.webkitRTCPeerConnection(config, constraints);\n  \n  socket.on('disconnect', function() {\n    peer.close();\n  });\n  \n  socket.on('icecandidate', function(data) {\n    if (data && data.candidate && data.sdpMid && data.sdpMLineIndex) {\n      peer.addIceCandidate(new RTCIceCandidate(data));\n    }\n  });\n  \n  socket.on('offer', function(data) {\n    peer.setRemoteDescription(new RTCSessionDescription(data), function() {\n      peer.createAnswer(function(sdp) {\n        peer.setLocalDescription(sdp, function() {\n          socket.emit('answer', sdp);\n        });\n      });\n    });\n  });\n  \n  socket.on('answer', function (data) {\n    peer.setRemoteDescription(new RTCSessionDescription(data));\n  });\n    \n  peer.onicecandidate = function(event) {\n    var candidate = event.candidate || event;\n    socket.emit('icecandidate', candidate);\n  };\n\n  peer.onnegotiationneeded = function() {\n    peer.createOffer(function(sdp) {\n      peer.setLocalDescription(sdp, function() {\n        socket.emit('offer', sdp);\n      });\n    });\n  };\n  \n  peer.onaddstream = function(event) {\n    if (event.stream && event.stream.active) {\n      console.log('Peer Add mediaStream:', event.stream);\n    \n      var video = document.querySelector('video');\n      video.src = window.URL.createObjectURL(event.stream);\n      \n      video.onloadedmetadata = function(event) {\n        video.play();\n      };\n          \n      event.stream.onaddtrack = function(track) {\n        console.log('Track Added!');\n      };\n\n      event.stream.onremovetrack = function (track) {\n        console.log('Track Removed!');\n      };\n\n      var audio_list = event.stream.getAudioTracks();\n      \n      audio_list.forEach(function (track) {\n        console.log(track);\n      });\n\n      var video_list = event.stream.getVideoTracks();\n      \n      video_list.forEach(function (track) {\n        console.log(track);\n      });\n    }    \n  };\n  \n  peer.onremovestream = function(event) {\n    console.log('Peer Remove mediaStream:', event.stream);\n  };\n\n  peer.ondatachannel = function(event) {\n    var channel = event ? event.channel || event : null;\n    var pingpong = null;\n\n    channel.onopen = function() {\n      console.log('Peer Channel opened!');\n      \n      pingpong = setInterval(function() {\n        console.log('Peer: Sending PING');\n        channel.send('PING');\n      }, 5000);\n    };\n    \n    channel.onclose = function() {\n      console.log('Peer Channel closed!');\n      \n      if (pingpong) {\n        clearInterval(pingpong);\n      }\n    };\n    \n    channel.onmessage = function(event) {\n      var data = event.data;\n      console.log('Peer Message:', data);\n    };\n  };\n</script>\n</body>\n</html>"
  },
  {
    "path": "examples/node2browser/index.js",
    "content": "var express = require('express');\nvar app = express();\nvar server = require('http').Server(app);\nvar io = require('socket.io')(server);\nvar WebRTC = require('../../');\n\napp.use(express.static(__dirname));\n\nvar io = require('socket.io')(server);\n\nvar config = {\n  iceServers: [\n    {\n      url: 'stun:stun.l.google.com:19302',\n    },\n  ],\n};\n\nvar constraints = {\n  audio: {\n    optional: [\n      {\n        googEchoCancellation: true,\n        googEchoCancellation2: true,\n        googDAEchoCancellation: true,\n        googAutoGainControl: true,\n        googAutoGainControl2: true,\n        googNoiseSuppression: true,\n        googNoiseSuppression2: true,\n        googHighpassFilter: true,\n        googTypingNoiseDetection: true,\n        googAudioMirroring: true,\n      },\n    ],\n  },\n  video: true,\n/*\n  video: {\n    optional: [\n      {\n        minAspectRatio: 1.333,\n        maxAspectRatio: 1.778,\n        maxWidth: 1920,\n        minWidth: 320,\n        maxHeight: 1080,\n        minHeight: 180,\n        maxFrameRate: 60,\n        minFrameRate: 30,\n      },\n    ],\n  },\n*/\n  optional: [\n    {\n      DtlsSrtpKeyAgreement: true,\n    },\n  ],\n  mandatory: {\n    OfferToReceiveAudio: true,\n    OfferToReceiveVideo: true,\n  },\n};\n\nio.on('connection', function(socket) {\n  console.log('Peer Connected');\n  \n  var peer = new WebRTC.RTCPeerConnection(config, constraints);\n  \n  socket.on('disconnect', function () {\n    console.log('Peer Disconnected');\n    peer.close();\n  });\n  \n  socket.on('icecandidate', function(data) {\n    if (data && data.candidate && data.sdpMid && data.sdpMLineIndex) {\n      peer.addIceCandidate(new WebRTC.RTCIceCandidate(data));\n    }\n  });\n  \n  socket.on('offer', function(data) {\n    peer.setRemoteDescription(new WebRTC.RTCSessionDescription(data), function() {\n      peer.createAnswer(function(sdp) {\n        peer.setLocalDescription(sdp, function() {\n          socket.emit('answer', sdp);\n        });\n      });\n    });\n  });\n  \n  socket.on('answer', function(data) {\n    peer.setRemoteDescription(new WebRTC.RTCSessionDescription(data));\n  });\n    \n  peer.onicecandidate = function(event) {\n    var candidate = event.candidate || event;\n    socket.emit('icecandidate', candidate);\n  };\n\n  peer.onnegotiationneeded = function() {\n    peer.createOffer(function(sdp) {\n      peer.setLocalDescription(sdp, function() {\n        socket.emit('offer', sdp);\n      });\n    });\n  };\n  \n  peer.onaddstream = function(stream) {\n    console.log('Peer: add mediaStream');\n  };\n  \n  peer.onremovestream = function(stream) {\n    console.log('Peer: remove mediaStream');\n  };\n\n  peer.ondatachannel = function(event) {\n    var channel = event ? event.channel || event : null;\n\n    channel.onopen = function() {\n      console.log('Peer Channel opened!');\n    };\n    \n    channel.onclose = function() {\n      console.log('Peer Channel closed!');\n    };    \n\n    channel.onmessage = function(event) {\n      var data = event.data;\n      \n      if (data == 'PING') {\n        console.log('Peer: Sending PONG');\n        channel.send('PONG');\n      } else {\n        console.log('Peer Message:', data);\n        channel.send(data);\n      }\n    };\n  };\n  \n  peer.ondatachannel(peer.createDataChannel('echo'));\n  \n  WebRTC.getUserMedia(constraints, function(stream) {\n    console.log('Sending Stream to Peer');\n    peer.addStream(stream);\n  });\n});\n\nserver.listen(8080, function() {\n  console.log('Open in browser: http://localhost:8080/');\n});"
  },
  {
    "path": "examples/node2browser/package.json",
    "content": "{\n  \"dependencies\": {\n    \"express\": \"^4.13.0\",\n    \"socket.io\": \"^1.3.5\"\n  }\n}\n"
  },
  {
    "path": "examples/node2browser_ws/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n </head>\n\n<script language=\"javascript\">\n\n\nwindow.onload  = function(e){ \n\n  var config = {\n    iceServers: [\n      {\n        url: 'stun:stun.l.google.com:19302',\n      },\n    ],\n  };\n  \n  var constraints = {\n     optional: [\n      {\n        DtlsSrtpKeyAgreement: true,\n      },\n    ],\n    mandatory: {\n      OfferToReceiveAudio: true,\n      OfferToReceiveVideo: true,\n    },\n  };\n  navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia;\n  window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;\n  window.RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate || window.webkitRTCIceCandidate;\n  window.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription;\n  \n      \n\n\n\n  var peer = new RTCPeerConnection (config, constraints);\n\n  var connection = new WebSocket('ws://127.0.0.1:8181');\n\n  function peer_onConnect(connection)\n  {\n    peer.onicecandidate = function(event) {\n    var data = event.candidate || event;\n      if (event.candidate && peer.signalingState !== 'closed') {\n      connection.send(JSON.stringify(data));\n      }\n    };\n    \n    peer.onnegotiationneeded = function() {\n      console.log (\"onnegotiationneeded\");\n\n    };\n    \n    peer.onaddstream = function(event) {\n      if (event.stream && event.stream.active) {\n        console.log('Peer Add mediaStream:', event.stream);\n      \n        var video = document.querySelector('video');\n        video.src = window.URL.createObjectURL(event.stream);\n        video.setAttribute( 'autoplay', 'autoplay' );\n        \n\n        video.onloadedmetadata = function(event) {\n          video.play();\n        };\n            \n        event.stream.onaddtrack = function(track) {\n          console.log('Track Added!');\n        };\n        event.stream.onremovetrack = function (track) {\n          console.log('Track Removed!');\n        };\n        var audio_list = event.stream.getAudioTracks();\n        \n        audio_list.forEach(function (track) {\n          console.log(track);\n        });\n        var video_list = event.stream.getVideoTracks();\n        \n        video_list.forEach(function (track) {\n          console.log(track);\n        });\n      }    \n    };\n    \n    peer.onremovestream = function(event) {\n      console.log('Peer Remove mediaStream:', event.stream);\n    };\n    peer.ondatachannel = function(event) {\n      var channel = event ? event.channel || event : null;\n      var pingpong = null;\n      channel.onopen = function() {\n        console.log('Peer Channel opened!');\n        \n        pingpong = setInterval(function() {\n          console.log('Peer: Sending PING');\n          channel.send('PING');\n        }, 5000);\n      };\n      \n      channel.onclose = function() {\n        console.log('Peer Channel closed!');\n        \n        if (pingpong) {\n          clearInterval(pingpong);\n        }\n      };\n      \n      channel.onmessage = function(event) {\n        var data = event.data;\n        console.log('Peer Message:', data);\n      };\n    };\n  }\n  \n  // When the connection is open, send some data to the server\n  connection.onopen = function () {\n    connection.send('Ping'); // Send the message 'Ping' to the server\n    peer_onConnect(connection);\n  };\n\n  // Log errors\n  connection.onerror = function (error) {\n    console.log('WebSocket Error ' + error);\n  };\n\n  // Log messages from the server\n  connection.onmessage = function (e) {\n    console.log('Server: ' + e.data);\n\n    var jmsg = JSON.parse(e.data);\n    if (jmsg.hasOwnProperty('type') == false)\n    {\n      return ;\n    }\n    \n    if (jmsg.type == 'offer')\n    {\n      \n       peer.setRemoteDescription(new RTCSessionDescription(jmsg), function() {\n       peer.createAnswer(function(answer) {\n        peer.setLocalDescription(answer, function(s) {\n          \n           connection.send(JSON.stringify(answer));\n           console.log('Send Answer: %s',JSON.stringify(answer));\n        });\n      }, function (err)\n    {\n      console.log (err);\n    })\n    });\n    \n    }\n    if (jmsg.type == 'answer')\n    {\n      peer.setRemoteDescription(new RTCSessionDescription(data));\n    }\n\n    if (jmsg.type == 'icecandidate')\n    {\n      if (jmsg.data && jmsg.candidate ) {\n      peer.addIceCandidate(new RTCIceCandidate(jmsg.data));\n      }\n    }\n  };\n\n\n\n};\n\n\n\n</script>\n\n<body>\n  <video autoplay controls></video>\n</body>\n</html>"
  },
  {
    "path": "examples/node2browser_ws/index.js",
    "content": "var WebRTC = require('../../');\nvar WebSocketServer = require('ws').Server;\nvar express = require('express');\nvar app = express();\nvar server = require('http').Server(app);\nWebRTC.setDebug(false);\napp.use(express.static(__dirname));\n\nvar _sources = [];\nvar localstream  =undefined;\nvar initialized = false;\n\nvar config = {\n  iceServers: [\n    {\n      url: 'stun:stun.l.google.com:19302',\n    },\n  ],\n};\n\nvar constraints = {\n  audio: true,\n  video: true,\n};\n\n\n\nfunction sourceSelected(audioSource, videoSource) {\n  \n  _sources.push(videoSource);\n\n}\n\n\nWebRTC.getSources(function(sourceInfos) {\n  \n\n  for (var i = 0; i != sourceInfos.length; ++i) {\n    var sourceInfo = sourceInfos[i];\n    if (sourceInfo.kind === 'audio') {\n      console.log(sourceInfo.id, sourceInfo.label || 'microphone');\n\n      audioSource = sourceInfo.id;\n    } else if (sourceInfo.kind === 'video') {\n      console.log(sourceInfo.id, sourceInfo.label || 'camera');\n\n      _sources.push (sourceInfo.id);\n    } else {\n      console.log('Some other kind of source: ', sourceInfo);\n    }\n  }\n\n  WebRTC.getUserMedia(constraints, getUserMedia_successCallback, getUserMedia_errorCallback);\n\n});\n\n\nfunction getUserMedia_successCallback(stream) {\n\n      localstream = stream;\n      var video_list = localstream.getVideoTracks();\n      \n    video_list.forEach(function (track) {\n      console.log('Video Track %s', JSON.stringify(track));\n      track.readyState = \"alive\";\n    });\n    console.log('Sending Stream to Peer');\n    initialized = true;\n    init();\n    }\n\n  function getUserMedia_errorCallback(error) {\n    console.log ('error %s',error);\n  }\n\nfunction setLocalSDP(p, callback){\n    if(p.iceGatheringState != 'complete'){\n        setTimeout(function(){\n            setLocalSDP(p, callback);\n        }, 10);\n    }else{\n        callback && callback();\n    }\n}\n\n\nfunction init()\n{\n  ws = new WebSocketServer(\n  {\n          host: '127.0.0.1',\n          port: 8181\n  }); // start websocket server\n\n  ws.on('connection', onConnect_Handler);\n\n    \n  function onConnect_Handler(connection)\n  {\n\n    var peer = new WebRTC.RTCPeerConnection(null, {audio: true, video: true});\n    peer.addStream(localstream);\n    peer.onicecandidate = function(event) {\n      var candidate = event.candidate || event;\n      connection.send(JSON.stringify({'type':'icecandidate', 'data':candidate}));\n    };\n    peer.createOffer(function(offer){\n          peer.setLocalDescription(new WebRTC.RTCSessionDescription(offer), function(){\n            setLocalSDP(peer, function(){\n              var offerSDP = JSON.stringify(peer.localDescription);\n              connection.send(offerSDP);\n            });\n          }, function(e){\n              console.log (e);\n          })\n        });\n\n    connection.on('message', function onWsMessage(message, flags)\n    {\n      console.log (\"INCOMMING %s:\", message);\n      var jmsg = undefined;\n      try\n      {\n        jmsg = JSON.parse(message);\n      }\n      catch (e)\n      {\n        return ;\n      }\n      \n      if (jmsg.type=='answer')\n      {\n        console.log ('answer');\n         var clientRemoteSDP = new WebRTC.RTCSessionDescription(jmsg);\n        peer.setRemoteDescription(clientRemoteSDP, function(){\n          console.log('setRemoteDescription OK');\n        }, function(err){\n          console.log('setRemoteDescription error', err);\n        })\n      }\n      if (jmsg.hasOwnProperty('candidate'))\n      {\n         console.log ('icecandidate: jmsg: %s',JSON.stringify(jmsg));\n        peer.addIceCandidate(new WebRTC.RTCIceCandidate(jmsg));\n      \n      }\n    });\n\n\n    \n\n    peer.onnegotiationneeded = function() {\n      console.log ('onnegotiationneeded');\n      \n    };\n    \n    peer.onaddstream = function(stream) {\n      console.log('Peer: add mediaStream');\n    };\n    \n    peer.onremovestream = function(stream) {\n      console.log('Peer: remove mediaStream');\n    };\n\n    peer.ondatachannel = function(event) {\n      var channel = event ? event.channel || event : null;\n\n      channel.onopen = function() {\n        console.log('Peer Channel opened!');\n      };\n      \n      channel.onclose = function() {\n        console.log('Peer Channel closed!');\n      };    \n\n      channel.onmessage = function(event) {\n        var data = event.data;\n        \n        if (data == 'PING') {\n          console.log('Peer: Sending PONG');\n          channel.send('PONG');\n        } else {\n          console.log('Peer Message:', data);\n          channel.send(data);\n        }\n      };\n    };\n    \n    peer.ondatachannel(peer.createDataChannel('echo'));\n    \n  \n  }\n\n \n  server.listen(8281,  function() {\n    console.log('Open in browser: http://localhost:8281/index.html');\n  });\n}\n// */\n\n"
  },
  {
    "path": "examples/node2browser_ws/package.json",
    "content": "{\n  \"dependencies\": {\n    \"express\": \"^4.13.0\",\n    \"ws\": \"^1.1.0\"\n  }\n}"
  },
  {
    "path": "index.js",
    "content": "\nmodule.exports = require('./build/Release/webrtc.node');\n"
  },
  {
    "path": "node_versions.json",
    "content": "[\n  \"iojs-v2.3.2\",\n  \"iojs-v3.3.1\",\n  \"v0.10.38\",\n  \"v0.12.5\",\n  \"v4.2.1\",\n  \"v4.3.2\",\n  \"v4.4.0\",\n  \"v5.0.0\",\n  \"v5.1.1\",\n  \"v5.2.0\",\n  \"v5.3.0\",\n  \"v5.4.1\",\n  \"v5.5.0\",\n  \"v5.6.0\",\n  \"v5.7.1\",\n  \"v5.8.0\",\n  \"v5.9.1\"\n]"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"webrtc-native\",\n  \"version\": \"1.4.0\",\n  \"description\": \"WebRTC for NodeJS\",\n  \"homepage\": \"https://github.com/vmolsa/webrtc-native\",\n  \"author\": \"https://github.com/vmolsa\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/vmolsa/webrtc-native.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/vmolsa/webrtc-native/issues\"\n  },\n  \"keywords\": [\n    \"webrtc\",\n    \"p2p\",\n    \"streaming\",\n    \"dtls\",\n    \"srtp\",\n    \"rtp\",\n    \"capture\",\n    \"datachannel\"\n  ],\n  \"license\": \"MIT\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"install\": \"node scripts/install.js\",\n    \"test\": \"node test/all.js\"\n  },\n  \"dependencies\": {\n    \"request\": \"^2.58.0\"\n  },\n  \"devDependencies\": {\n    \"nan\": \"^2.1.0\",\n    \"node-gyp\": \"^3.0.3\",\n    \"minimist\": \"^1.1.1\",\n    \"simple-peer\": \"^5.11.5\",\n    \"tape\": \"^4.0.0\"\n  }\n}\n"
  },
  {
    "path": "scripts/build.js",
    "content": "var fs = require('fs');\nvar os = require('os');\nvar spawn = require('child_process').spawn;\nvar path = require('path');\nvar request = require('request');\n\nvar ROOT = path.resolve(__dirname, '..');\n\nif (!fs.existsSync(ROOT + path.sep + 'build' + path.sep + 'config.gypi')) {\n  throw new Error('Run node-gyp rebuild instead of node build.js');\n}\n\nvar PACKAGE = require(path.resolve(ROOT, 'package.json'));\n\nvar CHROMIUM = 'https://chromium.googlesource.com/external/webrtc.git@ca4ec2c3b9331e8f054facf400ebaeb9681831e2';\nvar USE_OPENSSL = false;\nvar USE_GTK = false;\nvar USE_X11 = false;\n\nvar PLATFORM = os.platform();\nvar SYSTEM = os.release();\nvar ARCH = process.argv[2].substring(14);\nvar NODEJS = path.resolve(process.argv[3]);\nvar NODELIB = process.argv[4].substring(3).split('.')[0];\nvar NODEGYP = process.argv[5];\nvar URL = 'http://cide.cc:8080/webrtc/';\nvar NODEVER = process.version.split('.');\nvar NODE_ZERO = (NODEVER[0] === 'v0');\nvar CROSSCOMPILE = (ARCH !== process.arch);\n\nNODEVER[2] = 'x';\nNODEVER = NODEVER.join('.');\n  \nURL += 'webrtc-' + PACKAGE.version + '-' + PLATFORM + '-' + ARCH + '-' + NODEVER + '.node';\n  \nif (fs.existsSync(ROOT + path.sep + 'nodejs.gypi')) {\n  fs.unlinkSync(ROOT + path.sep + 'nodejs.gypi');\n}\n\nvar COMMON = path.resolve(NODEJS, 'include', 'node', 'common.gypi');\n\nif (fs.existsSync(COMMON)) {\n  fs.linkSync(COMMON, ROOT + path.sep + 'nodejs.gypi');\n} else {\n  fs.linkSync(NODEJS + path.sep + 'common.gypi', ROOT + path.sep + 'nodejs.gypi');\n}\n\nvar CONFIG = 'Release';\n\nif (fs.existsSync(ROOT + path.sep + 'build' + path.sep + 'Debug')) {\n  CONFIG = 'Debug';\n}\n\nvar THIRD_PARTY = path.resolve(ROOT, 'third_party');\nvar DEPOT_TOOLS_REPO = 'https://chromium.googlesource.com/chromium/tools/depot_tools.git';\nvar DEPOT_TOOLS = path.resolve(THIRD_PARTY, 'depot_tools');\nvar WEBRTC = path.resolve(THIRD_PARTY, 'webrtc');\nvar WEBRTC_SRC = path.resolve(WEBRTC, 'src');\nvar WEBRTC_OUT = path.resolve(WEBRTC_SRC, 'out', CONFIG);\nvar FETCH = path.resolve(DEPOT_TOOLS, (os.platform() == 'win32') ? 'fetch.bat' : 'fetch');\nvar GCLIENT = path.resolve(DEPOT_TOOLS, (os.platform() == 'win32') ? 'gclient.bat' : 'gclient');\n\nif (os.platform() == 'win32' && ARCH == 'x64') {\n  WEBRTC_OUT = path.resolve(WEBRTC_SRC, 'out', CONFIG + '_x64');\n}\n\nfunction install() {\n  fs.linkSync(WEBRTC_OUT + path.sep + 'webrtc.node', path.resolve(ROOT, 'build', CONFIG, 'webrtc.node'));\n  \n  if (process.env['CIDE_CREDENTIALS']) {\n    console.log('Uploading module.');\n    \n    var credentials = {\n      'auth': {\n        'user': 'cIDE',\n        'pass': process.env['CIDE_CREDENTIALS'],\n      }\n    };\n    \n    fs.createReadStream(path.resolve(ROOT, 'build', CONFIG, 'webrtc.node')).pipe(request.put(URL, credentials, function(error, response, body) {\n      if (!error && response.statusCode == 200) {\n        console.log('Done! :)');\n      } else {\n        console.log('Upload Failed! :(');\n      }\n    }));\n  } else {\n    setTimeout(function() {\n      console.log('Done! :)');\n    }, 200);\n  }\n}\n\nfunction compile() {\n  var res = spawn('ninja', [ '-C', WEBRTC_OUT ], {\n    cwd: WEBRTC_SRC,\n    env: process.env,\n    stdio: 'inherit',\n  });\n\n  res.on('close', function (code) {\n    if (!code) {\n      return install();\n    }\n\n    process.exit(1);\n  });\n}\n\nfunction build() { \n  if (fs.existsSync(WEBRTC_SRC)) {\n    var res = spawn('python', [ WEBRTC_SRC + path.sep + 'webrtc' + path.sep + 'build' + path.sep + 'gyp_webrtc', 'src' + path.sep + 'webrtc.gyp' ], {\n      cwd: ROOT,\n      env: process.env,\n      stdio: 'inherit',\n    });\n  \n    res.on('close', function (code) {\n      if (!code) {\n        return compile();\n      }\n  \n      process.exit(1);\n    });\n  }\n}\n\nfunction sync() {\n  if (!fs.existsSync(THIRD_PARTY + path.sep + 'webrtc_sync')) {\n    var res = spawn(GCLIENT, ['sync', '--with_branch_heads'], {\n      cwd: WEBRTC,\n      env: process.env,\n      stdio: 'inherit',\n    });\n\n    res.on('close', function (code) {\n      if (!code) {\n        fs.closeSync(fs.openSync(THIRD_PARTY + path.sep + 'webrtc_sync', 'w'));\n        return build();\n      }\n\n      process.exit(1);\n    });\n  } else {\n    build();\n  }\n}\n\nfunction configure() {\n  if (fs.existsSync(WEBRTC_OUT + path.sep + 'webrtc.node')) {\n    fs.unlinkSync(WEBRTC_OUT + path.sep + 'webrtc.node');\n  }\n  \n  process.env['GYP_DEFINES'] += ' target_arch=' + ARCH;\n  process.env['GYP_DEFINES'] += ' host_arch=' + process.arch;\n  process.env['GYP_DEFINES'] += ' node_root_dir=' + NODEJS.replace(/\\\\/g, '\\\\\\\\');\n  process.env['GYP_DEFINES'] += ' node_lib_file=' + NODELIB;\n  process.env['GYP_DEFINES'] += ' node_gyp_dir=' + NODEGYP.replace(/\\\\/g, '\\\\\\\\');\n  process.env['GYP_DEFINES'] += ' build_with_chromium=0';\n  process.env['GYP_DEFINES'] += ' use_openssl=' + ((USE_OPENSSL) ? '1' : '0');\n  process.env['GYP_DEFINES'] += ' use_gtk='+ ((USE_GTK) ? '1' : '0');\n  process.env['GYP_DEFINES'] += ' use_x11=' + ((USE_X11) ? '1' : '0');\n  process.env['GYP_DEFINES'] += ' ConfigurationName=' + CONFIG;  \n  process.env['GYP_DEFINES'] += ' include_tests=0';\n  \n  switch (os.platform()) {\n    case 'darwin':\n      process.env['GYP_DEFINES'] += ' clang=1';\n\n      break;\n    case 'win32':\n      process.env['DEPOT_TOOLS_WIN_TOOLCHAIN'] = 0;\n      process.env['GYP_MSVS_VERSION'] = 2013;\n      \n      break;\n    case 'linux':\n      if (CROSSCOMPILE) {\n        process.env['GYP_CROSSCOMPILE'] = 1;\n        process.env['GYP_DEFINES'] += ' clang=0 use_system_expat=0';\n        process.env['CXX'] = 'arm-linux-gnueabihf-g++-5';\n        \n        var CPATH = process.env['CPATH'];\n        \n        process.env['CPATH'] = '/usr/arm-linux-gnueabihf/include/c++/5/';\n        process.env['CPATH'] += '/usr/arm-linux-gnueabihf/include/c++/5/arm-linux-gnueabihf/';\n        process.env['CPATH'] += '/usr/arm-linux-gnueabihf/include/c++/5/backward/';\n        process.env['CPATH'] += CPATH ? ':' + CPATH : '';\n      } else {\n        if (NODE_ZERO) {\n          process.env['GYP_DEFINES'] += ' clang=0';\n          process.env['CXX'] = 'g++-4.8';\n          \n          var CPATH = process.env['CPATH'];\n          \n          process.env['CPATH'] = '/usr/include/c++/4.8/';\n          process.env['CPATH'] += '/usr/include/x86_64-linux-gnu/c++/4.8/';\n          process.env['CPATH'] += '/usr/include/c++/4.8/backward/';\n          process.env['CPATH'] += CPATH ? ':' + CPATH : '';\n        } else {\n          process.env['GYP_DEFINES'] += ' clang=1';\n        }\n\n        if (!process.env['JAVA_HOME']) {\n          if (fs.existsSync('/usr/lib/jvm/java')) {\n            process.env['JAVA_HOME'] = '/usr/lib/jvm/java';\n          } else {\n            process.env['JAVA_HOME'] = '/usr/lib/jvm/default-java';\n          }\n        }\n      }\n\n      break;\n    default:\n      break;\n  }\n\n  console.log('target_arch =', ARCH);\n  console.log('host_arch =', process.arch);\n  console.log('configuration =', CONFIG);\n\n  sync();\n}\n\nfunction config() {\n  if (!fs.existsSync(WEBRTC) || !fs.existsSync(path.resolve(WEBRTC, '.gclient')) || !fs.existsSync(WEBRTC_SRC)) {\n    if (!fs.existsSync(WEBRTC)) {\n      fs.mkdirSync(WEBRTC);\n    }\n    \n    var res = spawn(GCLIENT, ['config', '--name=src', CHROMIUM], {\n      cwd: WEBRTC,\n      env: process.env,\n      stdio: 'inherit',\n    });\n\n    res.on('close', function (code) {\n      if (!code) {\n        return configure();\n      }\n\n      process.exit(1);\n    });\n  } else {\n    configure();\n  }\n}\n\nprocess.env['GYP_DEFINES'] = process.env['GYP_DEFINES'] ? process.env['GYP_DEFINES'] : '';\n\nif (!fs.existsSync(THIRD_PARTY)) {\n  fs.mkdirSync(THIRD_PARTY);\n}\n\nprocess.env['PATH'] = process.env['PATH'] + path.delimiter + DEPOT_TOOLS;\n\nif (!fs.existsSync(DEPOT_TOOLS)) {\n  var res = spawn('git', ['clone', DEPOT_TOOLS_REPO], {\n    cwd: THIRD_PARTY,\n    env: process.env,\n    stdio: 'inherit',\n  });\n\n  res.on('close', function (code) {\n    if (!code) {\n      return config();\n    }\n\n    process.exit(1);\n  });\n} else {\n  config();\n}\n"
  },
  {
    "path": "scripts/install.js",
    "content": "var fs = require('fs');\nvar os = require('os');\nvar spawn = require('child_process').spawn;\nvar path = require('path');\nvar request = require('request');\n\nvar PLATFORM = os.platform();\nvar ROOT = path.resolve(__dirname, '..');\nvar ARCH = os.arch();\nvar URL = 'http://cide.cc:8080/webrtc/';\nvar NODEVER = process.version.split('.');\nvar PACKAGE = require(path.resolve(ROOT, 'package.json'));\n\nNODEVER[2] = 'x';\nNODEVER = NODEVER.join('.');\n\nURL += 'webrtc-' + PACKAGE.version + '-' + PLATFORM + '-' + ARCH + '-' + NODEVER + '.node';\n\nfunction build() {\n  console.log('Building module...');\n  \n  var nodegyp = path.resolve(ROOT, 'node_modules', 'node-gyp', 'bin', 'node-gyp.js');\n  \n  if (!fs.existsSync(nodegyp)) {\n    nodegyp = path.resolve(ROOT, '..', 'node-gyp', 'bin', 'node-gyp.js');\n    \n    if (!fs.existsSync(nodegyp)) {      \n      throw new Error('Build Failed. Please follow instructions from https://github.com/vmolsa/webrtc-native/wiki/Getting-started#building-from-source');\n    }\n  }\n  \n  var res = spawn('node', [ nodegyp, 'rebuild' ], {\n    cwd: ROOT,\n    env: process.env,\n    stdio: 'inherit',\n  });\n  \n  res.on('error', function(error) {\n    var res = spawn('iojs', [ nodegyp, 'rebuild' ], {\n      cwd: ROOT,\n      env: process.env,\n      stdio: 'inherit',\n    });\n  });\n}\n\nfunction test() {\n  console.log('Loading module...');\n  \n  try {\n    var WebRTC = require(path.resolve(ROOT, 'build', 'Release', 'webrtc.node'));\n    \n    setTimeout(function() {\n      console.log('Done! :)');\n    }, 200);\n  } catch (ignored) {\n    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.');\n  }\n}\n\nif (process.env['BUILD_WEBRTC'] == 'true') {\n  build();\n} else {\n  console.log('Downloading module: webrtc-' + PACKAGE.version + '-' + PLATFORM + '-' + ARCH + '-' + NODEVER + '.node');\n\n  if (!fs.existsSync(path.resolve(ROOT, 'build', 'Release'))) {\n    if (!fs.existsSync(path.resolve(ROOT, 'build'))) {\n      fs.mkdirSync(path.resolve(ROOT, 'build'));\n    }\n    \n    fs.mkdirSync(path.resolve(ROOT, 'build', 'Release'));\n  }\n\n  request.get(URL, function (error, response, body) {\n    if (!error && response.statusCode == 200) {\n      setTimeout(test, 200);\n    } else {\n      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.');\n    }\n  }).pipe(fs.createWriteStream(path.resolve(ROOT, 'build', 'Release', 'webrtc.node')));\n}\n"
  },
  {
    "path": "scripts/multibuild.cmd",
    "content": "nvmw install %1 & nvmw use %1 && npm install"
  },
  {
    "path": "scripts/multibuild.sh",
    "content": "#!/bin/sh\n\n. ~/.nvm/nvm.sh\n\nnvm install $1\nnvm use $1\nnpm install\n"
  },
  {
    "path": "scripts/nvm.sh",
    "content": "#!/bin/sh\n\n. ~/.nvm/nvm.sh\n\nnvm $1 $2\n"
  },
  {
    "path": "scripts/upload.js",
    "content": "var os = require('os');\nvar spawn = require('child_process').spawn;\nvar versions = require('../node_versions.json');\n\nvar ROOT = process.cwd();\nvar MULTIBUILD = (os.platform() == 'win32') ? 'scripts\\\\multibuild.cmd' : 'scripts/multibuild.sh';\n\nprocess.env['BUILD_WEBRTC'] = 'true';\n\nfunction build(version, callback) {\n  var res = spawn(MULTIBUILD, [ version ], {\n    cwd: ROOT,\n    env: process.env,\n    stdio: 'inherit',\n  });\n\n  res.on('close', function (code) {\n    callback(code == 0);\n  });\n}\n\nfunction buildNext(index) {\n  if (index < versions.length) {\n    build(versions[index], function(result) {\n      if (result) {\n        buildNext(index + 1);\n      }\n    });\n  }\n}\n\nbuildNext(0);\n"
  },
  {
    "path": "src/ArrayBuffer.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef NODE_ARRAYBUFFER_H\n#define NODE_ARRAYBUFFER_H\n\n#ifdef WIN32\n#pragma warning( disable : 4267 )\n#endif\n\n#include <nan.h>\n#include <string>\n\nnamespace node {\n  class ArrayBuffer {\n  public:\n    inline static ArrayBuffer* New(const char *str = 0) {\n#if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION)\n      return ArrayBuffer::New(v8::Isolate::GetCurrent(), std::string(str));\n#else \n      return ArrayBuffer::New(std::string(str));\n#endif\n    }\n\n    inline static ArrayBuffer* New(const std::string &data) {\n#if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION)\n      return ArrayBuffer::New(v8::Isolate::GetCurrent(), data.data(), data.size());\n#else\n      return ArrayBuffer::New(data.data(), data.size());\n#endif\n    }\n\n#if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION)\n    template <class T = char> inline static ArrayBuffer* New(T *str, size_t length) {\n      return ArrayBuffer::New(v8::Isolate::GetCurrent(), reinterpret_cast<char*>(str), length);\n    }\n\n    inline static ArrayBuffer* New(const char *str, size_t length) {\n      return ArrayBuffer::New(v8::Isolate::GetCurrent(), str, length);\n    }\n    \n    inline static ArrayBuffer* New(const v8::Local<v8::ArrayBuffer> &arrayBuffer) {\n      return ArrayBuffer::New(v8::Isolate::GetCurrent(), arrayBuffer);\n    }\n\n    inline static ArrayBuffer* New(const v8::Local<v8::Value> &arg) {\n      return ArrayBuffer::New(v8::Isolate::GetCurrent(), arg);\n    }\n\n    inline static ArrayBuffer* New(v8::Isolate *isolate, const std::string &data) {\n      return ArrayBuffer::New(isolate, data.data(), data.size());\n    }\n\n    inline static ArrayBuffer* New(v8::Isolate *isolate, const char *str = 0) {\n      return ArrayBuffer::New(isolate, std::string(str));\n    }\n\n    inline static ArrayBuffer* New(v8::Isolate *isolate, const char *str, size_t length) {\n      if (!isolate) {\n        isolate = v8::Isolate::GetCurrent();\n      }\n\n      ArrayBuffer *buffer = new ArrayBuffer();\n      v8::Local<v8::ArrayBuffer> arrayBuffer;\n\n      buffer->_data = 0;\n      buffer->_len = length;\n\n      if (length) {\n        buffer->_data = new char[length + 1];\n        buffer->_data[length] = '\\0';\n\n        for (size_t index = 0; index < length; index++) {\n          buffer->_data[index] = str[index];\n        }\n\n        arrayBuffer = v8::ArrayBuffer::New(isolate, buffer->_data, length);\n      }\n      else {\n        arrayBuffer = v8::ArrayBuffer::New(isolate, length);\n      }\n\n      buffer->_arrayBuffer.Reset(isolate, arrayBuffer);\n      buffer->_arrayBuffer.SetWeak(buffer, ArrayBuffer::onDispose);\n      buffer->_arrayBuffer.MarkIndependent();\n\n      arrayBuffer->SetHiddenValue(v8::String::NewFromUtf8(isolate, \"node::ArrayBuffer\"), v8::External::New(isolate, buffer));\n      return buffer;\n    }\n\n    inline static ArrayBuffer* New(v8::Isolate *isolate, const v8::Local<v8::ArrayBuffer> &arrayBuffer) {\n      if (!isolate) {\n        isolate = v8::Isolate::GetCurrent();\n      }\n\n      if (arrayBuffer.IsEmpty()) {\n        return ArrayBuffer::New(isolate);\n      }\n\n      if (arrayBuffer->IsExternal()) {\n        v8::Local<v8::Value> ptr = arrayBuffer->GetHiddenValue(v8::String::NewFromUtf8(isolate, \"node::ArrayBuffer\"));\n\n        if (ptr.IsEmpty()) {\n          v8::Local<v8::Value> uintArray = v8::Uint8Array::New(arrayBuffer, 0, arrayBuffer->ByteLength());\n          return ArrayBuffer::New(isolate, uintArray);\n        } else {\n          v8::Local<v8::External> ext = v8::Local<v8::External>::Cast(ptr);\n          return static_cast<ArrayBuffer*>(ext->Value());\n        }\n      } else {\n        ArrayBuffer *buffer = new ArrayBuffer();\n        v8::ArrayBuffer::Contents content = arrayBuffer->Externalize();\n\n        buffer->_data = static_cast<char*>(content.Data());\n        buffer->_len = content.ByteLength();\n        buffer->_arrayBuffer.Reset(isolate, arrayBuffer);\n        buffer->_arrayBuffer.SetWeak(buffer, ArrayBuffer::onDispose);\n        buffer->_arrayBuffer.MarkIndependent();\n\n        arrayBuffer->SetHiddenValue(v8::String::NewFromUtf8(isolate, \"node::ArrayBuffer\"), v8::External::New(isolate, buffer));\n\n        return buffer;\n      }\n\n      return 0;\n    }\n\n    inline static ArrayBuffer* New(v8::Isolate *isolate, const v8::Local<v8::Value> &arg) {\n      if (!arg.IsEmpty()) {\n        if (arg->IsArrayBuffer() || arg->IsTypedArray()) {\n          v8::Local<v8::ArrayBuffer> arrayBuffer;\n\n          if (arg->IsArrayBuffer()) {\n            arrayBuffer = v8::Local<v8::ArrayBuffer>::Cast(arg);\n          }\n          else {\n            v8::Local<v8::ArrayBufferView> view = v8::Local<v8::ArrayBufferView>::Cast(arg);\n            arrayBuffer = view->Buffer();\n          }\n\n          return ArrayBuffer::New(isolate, arrayBuffer);\n        }\n\n        if (arg->IsString()) {\n          v8::String::Utf8Value str(arg->ToString());\n          return ArrayBuffer::New(isolate, *str, str.length());\n        }\n      }\n\n      return ArrayBuffer::New(isolate);\n    }\n\n    inline v8::Local<v8::ArrayBuffer> ToArrayBuffer(v8::Isolate *isolate = 0) const {\n      if (!isolate) {\n        isolate = v8::Isolate::GetCurrent();\n      }\n\n      v8::EscapableHandleScope scope(isolate);\n      return scope.Escape(v8::Local<v8::ArrayBuffer>::New(isolate, _arrayBuffer));\n    }\n\n    inline v8::Local<v8::String> ToString(v8::Isolate *isolate = 0) const {\n      if (!isolate) {\n        isolate = v8::Isolate::GetCurrent();\n      }\n\n      v8::EscapableHandleScope scope(isolate);\n      v8::Local<v8::String> retval = v8::String::NewFromUtf8(isolate, ArrayBuffer::ToUtf8(), v8::String::kNormalString, ArrayBuffer::Length());\n      return scope.Escape(retval);\n    }\n\n#else\n    template <class T = char> inline static ArrayBuffer* New(T *str, size_t length) {\n      const char *ptr = reinterpret_cast<char*>(str);\n      return ArrayBuffer::New(ptr, length);\n    }\n\n    inline static ArrayBuffer* New(const char *str, size_t length) {\n      ArrayBuffer *buffer = new ArrayBuffer();\n\n      v8::Local<v8::Object> global = v8::Context::GetCurrent()->Global();\n      v8::Local<v8::Value> instance = global->Get(v8::String::New(\"ArrayBuffer\"));\n      v8::Local<v8::Function> constructor = v8::Local<v8::Function>::Cast(instance);\n      v8::Local<v8::Object> arrayBuffer = constructor->NewInstance();\n\n      buffer->_data = 0;\n      buffer->_len = length;\n\n      if (length) {\n        buffer->_data = new char[length + 1];\n        buffer->_data[length] = '\\0';\n\n        for (size_t index = 0; index < length; index++) {\n          buffer->_data[index] = str[index];\n        }\n\n        arrayBuffer->SetIndexedPropertiesToExternalArrayData(buffer->_data, v8::kExternalByteArray, buffer->_len);\n      }\n\n      buffer->_arrayBuffer = v8::Persistent<v8::Object>::New(arrayBuffer);\n      buffer->_arrayBuffer.MakeWeak(buffer, ArrayBuffer::onDispose);\n      buffer->_arrayBuffer.MarkIndependent();\n\n      arrayBuffer->SetHiddenValue(v8::String::New(\"node::ArrayBuffer\"), v8::External::New(buffer));\n      return buffer;\n    }\n\n    inline static ArrayBuffer* New(const v8::Local<v8::Object> &arrayBuffer) {\n      if (!arrayBuffer.IsEmpty()) {\n        v8::Local<v8::Value> ptr = arrayBuffer->GetHiddenValue(v8::String::New(\"node::ArrayBuffer\"));\n\n        if (!ptr.IsEmpty()) {\n          v8::Local<v8::External> ext = v8::Local<v8::External>::Cast(ptr);\n          return static_cast<ArrayBuffer*>(ext->Value());\n        } else {\n          if (arrayBuffer->HasIndexedPropertiesInExternalArrayData()) {\n            int length = arrayBuffer->GetIndexedPropertiesExternalArrayDataLength();\n\n            if (length > 0) {\n              char *data = static_cast<char*>(arrayBuffer->GetIndexedPropertiesExternalArrayData());\n              return ArrayBuffer::New(data, static_cast<size_t>(length));\n            }\n          }\n        }\n      }\n\n      return ArrayBuffer::New();\n    }\n\n    inline static ArrayBuffer* New(const v8::Local<v8::Value> &arg) {\n      if (!arg.IsEmpty()) {\n        if (arg->IsObject()) {\n          v8::Local<v8::Object> arrayBuffer = v8::Local<v8::Object>::Cast(arg);\n          return ArrayBuffer::New(arrayBuffer);\n        }\n\n        if (arg->IsString()) {\n          v8::String::Utf8Value str(arg->ToString());\n          return ArrayBuffer::New(*str, str.length());\n        }\n      }\n\n      return ArrayBuffer::New();\n    }\n\n    inline v8::Local<v8::Object> ToArrayBuffer() const {\n      v8::HandleScope scope;\n      v8::Local<v8::Object> arrayBuffer = v8::Local<v8::Object>::New(_arrayBuffer);\n      return scope.Close(arrayBuffer);\n    }\n\n    inline v8::Local<v8::String> ToString() const {\n      v8::HandleScope scope;\n      v8::Local<v8::String> str = v8::String::New(ArrayBuffer::ToUtf8(), ArrayBuffer::Length());\n      return scope.Close(str);\n    }\n\n#endif\n    inline std::string ToCString() const {\n      return std::string(ArrayBuffer::ToUtf8(), ArrayBuffer::Length());\n    }\n\n    template <class T = char> inline T* To() {\n      return reinterpret_cast<T*>(_data);\n    }\n    \n    template <class T = char> inline const T* To() const {\n      return reinterpret_cast<const T*>(_data);\n    }\n\n    inline char *ToUtf8() {\n      return _data;\n    }\n    \n    inline const char *ToUtf8() const {\n      return _data;\n    }\n\n    inline void *Data() const {\n      return _data;\n    }\n\n    inline size_t Length() const {\n      return _len;\n    }\n\n    inline size_t ByteLength() const {\n      return _len;\n    }\n\n#if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION)\n    static inline void onDispose(const v8::WeakCallbackData<v8::ArrayBuffer, ArrayBuffer> &info) {\n      v8::Isolate *isolate = info.GetIsolate();\n      v8::HandleScope scope(isolate);\n\n      ArrayBuffer *wrap = info.GetParameter();\n\n      if (wrap) {\n        v8::Local<v8::ArrayBuffer> arrayBuffer = v8::Local<v8::ArrayBuffer>::New(isolate, wrap->_arrayBuffer);\n        wrap->_arrayBuffer.Reset();\n\n        if (!arrayBuffer.IsEmpty()) {\n          arrayBuffer->DeleteHiddenValue(v8::String::NewFromUtf8(isolate, \"node::ArrayBuffer\"));\n        }\n\n        delete wrap;\n      }\n    }\n#else\n    static inline void onDispose(v8::Persistent<v8::Value> value, void *data) {\n      v8::HandleScope scope;\n      ArrayBuffer *wrap = static_cast<ArrayBuffer*>(data);\n\n      if (wrap) {\n        v8::Local<v8::Object> arrayBuffer = v8::Local<v8::Object>::New(wrap->_arrayBuffer);\n\n        if (!arrayBuffer.IsEmpty()) {\n          arrayBuffer->DeleteHiddenValue(v8::String::New(\"node::ArrayBuffer\"));\n        }\n\n        delete wrap;\n      }\n    }\n#endif\n\n  private:\n    virtual ~ArrayBuffer() {\n#if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION)\n      if (_len) {\n        delete [] _data;\n      }\n#else\n      _arrayBuffer.ClearWeak();\n      _arrayBuffer.Dispose();\n      _arrayBuffer.Clear();\n#endif\n    }\n\n  protected:\n    char* _data;\n    size_t _len;\n\n#if (NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION)\n    v8::Persistent<v8::ArrayBuffer> _arrayBuffer;\n#else\n    v8::Persistent<v8::Object> _arrayBuffer;\n#endif\n\n  };\n};\n\n#endif\n"
  },
  {
    "path": "src/BackTrace.cc",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifdef USE_BACKTRACE\n#include \"BackTrace.h\"\n\nBackTrace BackTrace::landmine;\n\nvoid BackTrace::Dump(const char *event, int skip) {\n  void *stack[50] = {0};\n  int count = 0, cur = 0;\n  \n  count = backtrace(stack, sizeof(stack));\n  \n  if (count) {\n    for (int index = (count - 1); index > skip && index >= 1; index--) {\n      char addr[128] = {0};\n      Dl_info info;\n     \n      snprintf(addr, sizeof(addr), \"%p\", stack[index]);\n     \n      if (dladdr(stack[index], &info) && info.dli_sname) {\n        char buffer[128] = {0};\n        size_t len = sizeof(buffer);\n        int status = 0;\n\n        (void) abi::__cxa_demangle(info.dli_sname, buffer, &len, &status);\n        \n        if (!status) {\n          printf(\"%d: %s [%s] %s\\n\", cur, event, addr, buffer);\n        } else {\n          printf(\"%d: %s [%s] %s\\n\", cur, event, addr, info.dli_sname);\n        }\n      } else {\n        printf(\"%d: %s [%s] function()\\n\", cur, event, addr);\n      }\n      \n      cur++;\n    }\n  }\n}\n\nvoid BackTrace::Close() {\n  _segv.sa_handler = SIG_DFL;\n  _bus.sa_handler = SIG_DFL;\n  _abrt.sa_handler = SIG_DFL;\n  _ill.sa_handler = SIG_DFL;\n  \n  sigaction(SIGSEGV, &_segv, 0);\n  sigaction(SIGBUS, &_bus, 0);\n  sigaction(SIGABRT, &_abrt, 0);\n  sigaction(SIGILL, &_ill, 0);\n}\n\nvoid BackTrace::OnSegv(int sig) {\n  BackTrace::Dump(\"SIGSEGV\", 2);\n  landmine.Close();\n}\n\nvoid BackTrace::OnBus(int sig) {\n  BackTrace::Dump(\"SIGBUS\", 2);\n  landmine.Close();\n}\n\nvoid BackTrace::OnAbort(int sig) {\n  BackTrace::Dump(\"SIGABRT\", 2);\n  landmine.Close();\n}\n\nvoid BackTrace::OnIll(int sig) {\n  BackTrace::Dump(\"SIGILL\", 2);\n  landmine.Close();\n}\n\nBackTrace::BackTrace() {\n  sigemptyset(&_segv.sa_mask);\n  sigemptyset(&_bus.sa_mask);\n  sigemptyset(&_abrt.sa_mask);\n  sigemptyset(&_ill.sa_mask);\n\n  _segv.sa_flags = 0;\n  _segv.sa_handler = BackTrace::OnSegv;\n\n  _bus.sa_flags = 0;\n  _bus.sa_handler = BackTrace::OnBus;\n\n  _abrt.sa_flags = 0;\n  _abrt.sa_handler = BackTrace::OnAbort; \n  \n  _ill.sa_flags = 0;\n  _ill.sa_handler = BackTrace::OnIll; \n\n  sigaction(SIGSEGV, &_segv, 0);\n  sigaction(SIGBUS, &_bus, 0);\n  sigaction(SIGABRT, &_abrt, 0);\n  sigaction(SIGILL, &_ill, 0);\n}\n\nBackTrace::~BackTrace() {\n  BackTrace::Close();\n}\n\n#endif\n"
  },
  {
    "path": "src/BackTrace.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef BACKTRACE_H\n#define BACKTRACE_H\n#ifdef USE_BACKTRACE\n\n#include <stdio.h>\n#include <signal.h>\n#include <execinfo.h>\n#include <dlfcn.h>\n#include <cxxabi.h>\n\nclass BackTrace {\n public:\n  static void Dump(const char *event = \"NOEVENT\", int skip = 1);\n  \n private:\n  explicit BackTrace();\n  virtual ~BackTrace();\n  \n  void Close();\n  \n  static void OnSegv(int sig);\n  static void OnBus(int sig);\n  static void OnAbort(int sig);\n  static void OnIll(int sig);\n\n protected:\n  struct sigaction _segv;\n  struct sigaction _bus;\n  struct sigaction _abrt;\n  struct sigaction _ill;\n  \n  static BackTrace landmine;\n};\n\n#else\n\n#endif\n#endif\n"
  },
  {
    "path": "src/Common.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef WEBRTC_COMMON_H\n#define WEBRTC_COMMON_H\n\n#include <nan.h>\n\n#include \"webrtc/video_frame.h\"\n\n#include \"webrtc/base/atomicops.h\"\n#include \"webrtc/base/logging.h\"\n#include \"webrtc/base/json.h\"\n#include \"webrtc/base/basictypes.h\"\n#include \"webrtc/base/common.h\"\n#include \"webrtc/base/scoped_ptr.h\"\n#include \"webrtc/base/ssladapter.h\"\n#include \"webrtc/base/sslstreamadapter.h\"\n#include \"webrtc/base/stringutils.h\"\n#include \"webrtc/base/thread.h\"\n#include \"webrtc/base/buffer.h\"\n#include \"webrtc/base/scoped_ref_ptr.h\"\n#include \"webrtc/base/refcount.h\"\n#include \"webrtc/base/stringencode.h\"\n\n#include \"webrtc/api/jsep.h\"\n#include \"webrtc/api/jsepsessiondescription.h\"\n#include \"webrtc/api/mediaconstraintsinterface.h\"\n#include \"webrtc/api/mediastreaminterface.h\"\n#include \"webrtc/api/peerconnectionfactory.h\"\n#include \"webrtc/api/peerconnectioninterface.h\"\n#include \"webrtc/api/test/fakeconstraints.h\"\n#include \"webrtc/api/datachannelinterface.h\"\n\n#include \"webrtc/api/videosourceinterface.h\"\n#include \"webrtc/media/base/videosourceinterface.h\"\n#include \"webrtc/media/engine/webrtcvideocapturerfactory.h\"\n#include \"webrtc/modules/video_capture/video_capture_factory.h\"\n\n#ifdef WIN32\n#ifndef __PRETTY_FUNCTION__\n#define __PRETTY_FUNCTION__ __FUNCTION__\n#endif\n#endif\n\n#include <queue>\n#include <string>\n#include <uv.h>\n#include <node_object_wrap.h>\n\n#endif"
  },
  {
    "path": "src/DataChannel.cc",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#include \"DataChannel.h\"\n\nusing namespace v8;\nusing namespace WebRTC;\n\nNan::Persistent<Function> DataChannel::constructor;\n\nvoid DataChannel::Init() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::HandleScope scope;\n  \n  Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(DataChannel::New);\n  tpl->InstanceTemplate()->SetInternalFieldCount(1);\n  tpl->SetClassName(Nan::New(\"RTCDataChannel\").ToLocalChecked());\n  \n  Nan::SetPrototypeMethod(tpl, \"close\", DataChannel::Close);\n  Nan::SetPrototypeMethod(tpl, \"send\", DataChannel::Send);\n  \n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"id\").ToLocalChecked(), DataChannel::GetId);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"label\").ToLocalChecked(), DataChannel::GetLabel);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"ordered\").ToLocalChecked(), DataChannel::GetOrdered);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"protocol\").ToLocalChecked(), DataChannel::GetProtocol);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"readyState\").ToLocalChecked(), DataChannel::GetReadyState);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"bufferedAmount\").ToLocalChecked(), DataChannel::GetBufferedAmount);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"binaryType\").ToLocalChecked(), DataChannel::GetBinaryType, DataChannel::SetBinaryType);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"maxPacketLifeType\").ToLocalChecked(), DataChannel::GetMaxPacketLifeType);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"maxRetransmits\").ToLocalChecked(), DataChannel::GetMaxRetransmits);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"negotiated\").ToLocalChecked(), DataChannel::GetNegotiated);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"reliable\").ToLocalChecked(), DataChannel::GetReliable);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onopen\").ToLocalChecked(), DataChannel::GetOnOpen, DataChannel::SetOnOpen);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onmessage\").ToLocalChecked(), DataChannel::GetOnMessage, DataChannel::SetOnMessage);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onclose\").ToLocalChecked(), DataChannel::GetOnClose, DataChannel::SetOnClose);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onerror\").ToLocalChecked(), DataChannel::GetOnError, DataChannel::SetOnError);\n  \n  constructor.Reset<Function>(tpl->GetFunction());\n}\n\nDataChannel::DataChannel() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  _observer = new rtc::RefCountedObject<DataChannelObserver>(this);\n}\n\nDataChannel::~DataChannel() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (_socket.get()) {  \n    _socket->UnregisterObserver();\n    _observer->RemoveListener(this);\n    \n    webrtc::DataChannelInterface::DataState state(_socket->state());\n    \n    if (state != webrtc::DataChannelInterface::kClosing ||\n        state != webrtc::DataChannelInterface::kClosed)\n    {\n      _socket->Close();\n    }\n  }\n}\n\nvoid DataChannel::New(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  if (info.IsConstructCall()) {\n    DataChannel* dataChannel = new DataChannel();\n    dataChannel->Wrap(info.This(), \"DataChannel\");\n    return info.GetReturnValue().Set(info.This());\n  }\n\n  Nan::ThrowError(\"Internal Error\");\n  info.GetReturnValue().SetUndefined();\n}\n\nLocal<Value> DataChannel::New(rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::EscapableHandleScope scope;\n  Local<Function> instance = Nan::New(DataChannel::constructor);\n  \n  if (instance.IsEmpty() || !dataChannel.get()) {\n    return scope.Escape(Nan::Null());\n  }\n  \n  Local<Object> ret = instance->NewInstance();\n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(ret, \"DataChannel\");\n\n  self->SetReference(true);\n  self->_socket = dataChannel;\n  self->_socket->RegisterObserver(self->_observer.get());\n  self->Emit(kDataChannelStateChange);\n\n  self->_binaryType.Reset(Nan::New(\"arraybuffer\").ToLocalChecked());\n\n  return scope.Escape(ret);\n}\n\nwebrtc::DataChannelInterface *DataChannel::GetSocket() const {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  return _socket.get();\n}\n\nvoid DataChannel::Close(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.This(), \"DataChannel\");\n  webrtc::DataChannelInterface *socket = self->GetSocket();\n  \n  if (socket) {\n    webrtc::DataChannelInterface::DataState state(socket->state());\n    \n    if (state != webrtc::DataChannelInterface::kClosing ||\n        state != webrtc::DataChannelInterface::kClosed)\n    {\n      socket->Close();\n    }\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid DataChannel::Send(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.This(), \"DataChannel\");\n  webrtc::DataChannelInterface *socket = self->GetSocket();\n  bool retval = false;\n\n  if (socket) {\n    if(info[0]->IsString()) {\n      std::string data(*Nan::Utf8String(info[0]));\n      webrtc::DataBuffer buffer(data);\n      retval = socket->Send(buffer);\n    } else {\n      node::ArrayBuffer *container = node::ArrayBuffer::New(info[0]);\n      rtc::Buffer data(reinterpret_cast<uint8_t*>(container->Data()), container->Length());\n      //rtc::CopyOnWriteBuffer data(reinterpret_cast<uint8_t*>(container->Data()), container->Length());\n      webrtc::DataBuffer buffer(data, true);\n      retval = socket->Send(buffer);\n    }\n  }\n  \n  return info.GetReturnValue().Set(Nan::New(retval));\n}\n\nvoid DataChannel::GetId(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n  webrtc::DataChannelInterface *socket = self->GetSocket();\n  \n  if (socket) {\n    return info.GetReturnValue().Set(Nan::New(socket->id()));\n  }\n\n  info.GetReturnValue().SetUndefined();\n}\n\nvoid DataChannel::GetLabel(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n  webrtc::DataChannelInterface *socket = self->GetSocket();\n  \n  if (socket) {\n    return info.GetReturnValue().Set(Nan::New(socket->label().c_str()).ToLocalChecked());\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid DataChannel::GetOrdered(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n  webrtc::DataChannelInterface *socket = self->GetSocket();\n  \n  if (socket) {\n    return info.GetReturnValue().Set(Nan::New(socket->ordered()));\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid DataChannel::GetProtocol(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n  webrtc::DataChannelInterface *socket = self->GetSocket();\n  \n  if (socket) {\n    return info.GetReturnValue().Set(Nan::New(socket->protocol().c_str()).ToLocalChecked());\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid DataChannel::GetReadyState(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n  webrtc::DataChannelInterface *socket = self->GetSocket();\n  \n  if (socket) {\n    webrtc::DataChannelInterface::DataState state(socket->state());\n  \n    switch (state) {\n      case webrtc::DataChannelInterface::kConnecting:\n        return info.GetReturnValue().Set(Nan::New(\"connecting\").ToLocalChecked());\n        break;\n      case webrtc::DataChannelInterface::kOpen:\n        return info.GetReturnValue().Set(Nan::New(\"open\").ToLocalChecked());\n        break;\n      case webrtc::DataChannelInterface::kClosing:\n        return info.GetReturnValue().Set(Nan::New(\"closing\").ToLocalChecked());\n        break;\n      case webrtc::DataChannelInterface::kClosed:\n        return info.GetReturnValue().Set(Nan::New(\"closed\").ToLocalChecked());\n        break;\n    }\n  }\n\n  info.GetReturnValue().SetUndefined();\n}\n\nvoid DataChannel::GetBufferedAmount(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n  webrtc::DataChannelInterface *socket = self->GetSocket();\n  \n  if (socket) {\n    return info.GetReturnValue().Set(Nan::New(static_cast<uint32_t>(socket->buffered_amount())));\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid DataChannel::GetBinaryType(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n  return info.GetReturnValue().Set(Nan::New(self->_binaryType));\n}\n\nvoid DataChannel::GetMaxPacketLifeType(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n  webrtc::DataChannelInterface *socket = self->GetSocket();\n  \n  if (socket) {\n    return info.GetReturnValue().Set(Nan::New(static_cast<uint32_t>(socket->maxRetransmitTime())));\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid DataChannel::GetMaxRetransmits(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n  webrtc::DataChannelInterface *socket = self->GetSocket();\n  \n  if (socket) {\n    return info.GetReturnValue().Set(Nan::New(static_cast<uint32_t>(socket->maxRetransmits())));\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid DataChannel::GetNegotiated(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n  webrtc::DataChannelInterface *socket = self->GetSocket();\n  \n  if (socket) {\n    return info.GetReturnValue().Set(Nan::New(socket->negotiated()));\n  }\n  \n  return info.GetReturnValue().Set(Nan::False());\n}\n\nvoid DataChannel::GetReliable(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n  webrtc::DataChannelInterface *socket = self->GetSocket();\n  \n  if (socket) {\n    return info.GetReturnValue().Set(Nan::New(socket->reliable()));\n  }\n  \n  return info.GetReturnValue().Set(Nan::False());\n}\n\nvoid DataChannel::GetOnOpen(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onopen));\n}\n\nvoid DataChannel::GetOnMessage(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onmessage));\n}\n\nvoid DataChannel::GetOnClose(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onclose));\n}\n\nvoid DataChannel::GetOnError(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onerror));\n}  \n\nvoid DataChannel::ReadOnly(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n}\n\nvoid DataChannel::SetBinaryType(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n\n  if (!value.IsEmpty() && value->IsString()) {\n    self->_binaryType.Reset(value->ToString());\n  } else {\n    self->_binaryType.Reset(Nan::New(\"arraybuffer\").ToLocalChecked());\n  }\n}\n\nvoid DataChannel::SetOnOpen(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onopen.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onopen.Reset();\n  }\n}\n\nvoid DataChannel::SetOnMessage(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onmessage.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onmessage.Reset();\n  }\n}\n\nvoid DataChannel::SetOnClose(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onclose.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onclose.Reset();\n  }\n}\n\nvoid DataChannel::SetOnError(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  DataChannel *self = RTCWrap::Unwrap<DataChannel>(info.Holder(), \"DataChannel\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onerror.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onclose.Reset();\n  }\n}\n\nvoid DataChannel::On(Event *event) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::HandleScope scope;\n  DataChannelEvent type = event->Type<DataChannelEvent>();\n  node::ArrayBuffer *arrayBuffer = 0;\n  Local<Function> callback;\n  Local<Value> argv[1];\n  bool isError = false;\n  int argc = 0;\n  \n  if (type == kDataChannelStateChange) {\n    webrtc::DataChannelInterface *socket = DataChannel::GetSocket();\n    \n    if (socket) {\n      switch (socket->state()) {\n        case webrtc::DataChannelInterface::kConnecting:\n\n          break;\n        case webrtc::DataChannelInterface::kOpen:\n          callback = Nan::New<Function>(_onopen);\n\n          break;\n        case webrtc::DataChannelInterface::kClosing:\n\n          break;\n        case webrtc::DataChannelInterface::kClosed:\n          EventEmitter::SetReference(false);\n          \n          callback = Nan::New<Function>(_onclose);\n          _onclose.Reset();\n\n          break;\n      }\n    }\n  } else {\n    callback = Nan::New<Function>(_onmessage);\n    rtc::Buffer buffer = event->Unwrap<rtc::Buffer>();\n    Local<Object> container = Nan::New<Object>();\n    argv[0] = container;\n    argc = 1;\n\n    if (type == kDataChannelData) {\n      container->Set(Nan::New(\"data\").ToLocalChecked(), Nan::New(reinterpret_cast<char *>(buffer.data()), buffer.size()).ToLocalChecked());\n    } else {\n      arrayBuffer = node::ArrayBuffer::New(buffer.data(), buffer.size());                                \n      container->Set(Nan::New(\"data\").ToLocalChecked(), arrayBuffer->ToArrayBuffer());\n    }\n  }\n  \n  if (!callback.IsEmpty() && callback->IsFunction()) {\n    callback->Call(RTCWrap::This(), argc, argv);\n  } else if (isError) {\n    Nan::ThrowError(argv[0]);\n  }\n}\n"
  },
  {
    "path": "src/DataChannel.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef WEBRTC_DATACHANNEL_H\n#define WEBRTC_DATACHANNEL_H\n\n#include \"Common.h\"\n#include \"Observers.h\"\n#include \"EventEmitter.h\"\n#include \"Wrap.h\"\n#include \"ArrayBuffer.h\"\n\nnamespace WebRTC {\n  enum DataChannelEvent {\n    kDataChannelStateChange,\n    kDataChannelBinary,\n    kDataChannelData,\n  };  \n  \n  class DataChannel : public RTCWrap, public EventEmitter {    \n   public:    \n    static void Init();\n    static v8::Local<v8::Value> New(rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel);\n    \n   private:\n    DataChannel();\n    ~DataChannel() final;\n    \n    static void New(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void Close(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void Send(const Nan::FunctionCallbackInfo<v8::Value> &info);\n\n    static void GetId(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetLabel(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOrdered(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetProtocol(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetReadyState(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetBufferedAmount(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetBinaryType(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetMaxPacketLifeType(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetMaxRetransmits(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetNegotiated(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetReliable(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnOpen(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnMessage(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnClose(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnError(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n\n    static void ReadOnly(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetBinaryType(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnOpen(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnMessage(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnClose(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnError(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n\n    void On(Event *event) final;\n    \n    webrtc::DataChannelInterface *GetSocket() const;\n    \n   protected:\n    rtc::scoped_refptr<DataChannelObserver> _observer;\n    rtc::scoped_refptr<webrtc::DataChannelInterface> _socket;\n    \n    Nan::Persistent<v8::String> _binaryType;\n    \n    Nan::Persistent<v8::Function> _onopen;\n    Nan::Persistent<v8::Function> _onmessage;\n    Nan::Persistent<v8::Function> _onclose;\n    Nan::Persistent<v8::Function> _onerror;\n    \n    static Nan::Persistent<v8::Function> constructor;\n  };\n};\n\n#endif\n    "
  },
  {
    "path": "src/EventEmitter.cc",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#include \"EventEmitter.h\"\n\nusing namespace WebRTC;\n\nEventEmitter::EventEmitter(uv_loop_t *loop, bool notify) : _notify(notify) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  uv_mutex_init(&_list);\n  \n  if (!_notify) {\n    uv_mutex_init(&_lock);\n    \n    _async = new uv_async_t();\n    _async->data = this;\n    \n    if (!loop) {\n      loop = uv_default_loop();\n    }\n    \n    uv_async_init(loop, _async, reinterpret_cast<uv_async_cb>(EventEmitter::onAsync));\n    EventEmitter::SetReference(false);\n  }\n}\n\nEventEmitter::~EventEmitter() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  EventEmitter::RemoveAllListeners();\n  EventEmitter::Dispose();\n\n  if (!_notify) {\n    _async->data = 0;\n    uv_close(reinterpret_cast<uv_handle_t*>(_async), EventEmitter::onEnded);\n    uv_mutex_destroy(&_lock);\n  }\n  \n  uv_mutex_destroy(&_list);\n}\n\nvoid EventEmitter::AddListener(EventEmitter *listener) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  bool found = false;\n  std::vector<EventEmitter*>::iterator index;\n \n  if (listener && listener != this) {\n    uv_mutex_lock(&_list);\n  \n    for (index = _listeners.begin(); index < _listeners.end(); index++) {\n      if ((*index) == listener) {\n        found = true;\n        break;\n      }\n    }\n    \n    if (!found) {\n      _listeners.push_back(listener);\n      listener->AddParent(this);\n    }\n    \n    uv_mutex_unlock(&_list);\n  }\n}\n\nvoid EventEmitter::RemoveListener(EventEmitter *listener) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  std::vector<EventEmitter*>::iterator index;\n    \n  if (listener && listener != this) {\n    uv_mutex_lock(&_list);\n    \n    for (index = _listeners.begin(); index < _listeners.end(); index++) {\n      if ((*index) == listener) {\n        _listeners.erase(index);\n        listener->RemoveParent(this);\n        break;\n      }\n    }\n    \n    uv_mutex_unlock(&_list);\n  }\n}\n\nvoid EventEmitter::RemoveAllListeners() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  std::vector<EventEmitter*>::iterator index;\n  \n  uv_mutex_lock(&_list);\n  \n  for (index = _listeners.begin(); index < _listeners.end(); index++) {\n    (*index)->RemoveParent(this);\n    _listeners.erase(index);\n  }\n  \n  uv_mutex_unlock(&_list);\n}\n\nvoid EventEmitter::Dispose() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  if (!_notify) {\n    while (!_events.empty()) {\n      rtc::scoped_refptr<Event> event = _events.front();\n      _events.pop();\n    }\n  }\n}\n\nvoid EventEmitter::SetReference(bool alive) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (!_notify) {\n    uv_mutex_lock(&_lock);\n    \n    if (alive) {\n      uv_ref(reinterpret_cast<uv_handle_t*>(_async));\n    } else {\n      uv_unref(reinterpret_cast<uv_handle_t*>(_async));\n    }\n    \n    uv_mutex_unlock(&_lock);\n  }\n}\n\nvoid EventEmitter::Emit(int event) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  EventEmitter::Emit(new rtc::RefCountedObject<Event>(event));\n}\n\nvoid EventEmitter::Emit(rtc::scoped_refptr<Event> event) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (event.get()) {\n    if (!_notify) {\n      uv_mutex_lock(&_lock);\n      \n      _events.push(event);  \n      uv_async_send(_async);\n  \n      uv_mutex_unlock(&_lock);\n    }\n    \n    uv_mutex_lock(&_list);\n    \n    std::vector<EventEmitter*>::iterator index;\n    \n    for (index = _listeners.begin(); index < _listeners.end(); index++) {\n      (*index)->Emit(event);\n    }\n    \n    uv_mutex_unlock(&_list);\n  }\n}\n\nvoid EventEmitter::AddParent(EventEmitter *listener) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  uv_mutex_lock(&_list);\n  _parents.push_back(listener);\n  uv_mutex_unlock(&_list);\n}\n\nvoid EventEmitter::RemoveParent(EventEmitter *listener) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  std::vector<EventEmitter*>::iterator index;\n  \n  uv_mutex_lock(&_list);\n  \n  for (index = _listeners.begin(); index < _listeners.end(); index++) {\n    if ((*index) == listener) {\n      _listeners.erase(index);\n    }\n  }\n  \n  uv_mutex_unlock(&_list);\n}\n\nvoid EventEmitter::onAsync(uv_async_t *handle, int status) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  EventEmitter *self = static_cast<EventEmitter*>(handle->data);\n    \n  if (self) {\n    self->DispatchEvents();\n  }\n}\n \nvoid EventEmitter::onEnded(uv_handle_t *handle) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  uv_async_t* async = reinterpret_cast<uv_async_t*>(handle);\n   \n  if (async) {\n    delete async;\n  }\n}\n \nvoid EventEmitter::DispatchEvents() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  uv_mutex_lock(&_lock);\n\n  while (!_events.empty()) {\n    rtc::scoped_refptr<Event> event = _events.front();\n    _events.pop();\n    \n    uv_mutex_unlock(&_lock);\n\n    if (event.get()) {\n      On(event);\n    }\n    \n    uv_mutex_lock(&_lock);\n  }\n  \n  uv_mutex_unlock(&_lock);\n}\n\nNotifyEmitter::NotifyEmitter(EventEmitter *listener) : EventEmitter(0, true) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (listener) {\n    NotifyEmitter::AddListener(listener);\n  }\n}\n\nvoid NotifyEmitter::On(Event *event) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n}"
  },
  {
    "path": "src/EventEmitter.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef WEBRTC_EVENTEMITTER_H\n#define WEBRTC_EVENTEMITTER_H\n\n#include \"Common.h\"\n\nnamespace WebRTC { \n  template<class T> class EventWrapper;\n  \n  class Event : public rtc::RefCountInterface {\n    template<class T> friend class EventWrapper;\n    friend class rtc::RefCountedObject<Event>;\n    friend class EventEmitter;\n    \n   public:\n    inline bool HasWrap() const {\n      LOG(LS_INFO) << __PRETTY_FUNCTION__;\n      \n      return _wrap;\n    }\n    \n    template <class T> inline T Type() const {\n      LOG(LS_INFO) << __PRETTY_FUNCTION__;\n      \n      return static_cast<T>(_event);\n    }\n    \n    template<class T> const T &Unwrap() const {\n      LOG(LS_INFO) << __PRETTY_FUNCTION__;\n      \n      static T nowrap;\n      \n      if (_wrap) {\n        const EventWrapper<T> *ptr = static_cast<const EventWrapper<T> *>(this);\n        return ptr->_content;\n      }\n      \n      nowrap = T();\n      return nowrap;\n    }\n   \n   private: \n    explicit Event(int event = 0) :\n      _event(event),\n      _wrap(false)\n    {\n      LOG(LS_INFO) << __PRETTY_FUNCTION__;\n    }\n    \n    virtual ~Event() {\n      LOG(LS_INFO) << __PRETTY_FUNCTION__;\n    }\n    \n   protected:\n    int _event;\n    bool _wrap;\n  };\n  \n  template<class T> class EventWrapper : public Event {\n    friend class rtc::RefCountedObject<EventWrapper<T> >;\n    friend class Event;\n    friend class EventEmitter;\n\n   private:\n    explicit EventWrapper(int event, const T &content) :\n      Event(event),\n      _content(content)\n    {\n      _wrap = true;\n    }\n\n    virtual ~EventWrapper() { }\n\n   protected:\n    T _content;\n  };\n  \n  class EventEmitter {\n    friend class NotifyEmitter;\n     \n   public:\n    explicit EventEmitter(uv_loop_t *loop = 0, bool notify = false);\n    virtual ~EventEmitter();\n    \n    void AddListener(EventEmitter *listener = 0);\n    void RemoveListener(EventEmitter *listener = 0);\n    void RemoveAllListeners();\n\n    void SetReference(bool alive = true);\n    \n    void Emit(int event = 0);\n    void Emit(rtc::scoped_refptr<Event> event);\n\n    template <class T> inline void Emit(int event, const T &content) {\n      LOG(LS_INFO) << __PRETTY_FUNCTION__;\n      EventEmitter::Emit(new rtc::RefCountedObject<EventWrapper<T> >(event, content));\n    }\n    \n    virtual void On(Event *event) = 0;\n    \n   private:\n    static void onAsync(uv_async_t *handle, int status);\n    static void onEnded(uv_handle_t *handle);\n    \n    void Dispose();\n    void DispatchEvents();\n    \n    void AddParent(EventEmitter *listener = 0);\n    void RemoveParent(EventEmitter *listener = 0);\n    \n   protected:\n    bool _notify;\n    uv_mutex_t _lock;\n    uv_mutex_t _list;\n    uv_async_t* _async;\n    std::queue<rtc::scoped_refptr<Event> > _events;\n    std::vector<EventEmitter*> _listeners;\n    std::vector<EventEmitter*> _parents;\n  };\n  \n  class NotifyEmitter : public EventEmitter {\n   public:\n    NotifyEmitter(EventEmitter *listener = 0);\n    \n    virtual void On(Event *event);\n  };\n};\n\n#endif\n"
  },
  {
    "path": "src/GetSources.cc",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#include <ctype.h>\n#include \"Platform.h\"\n#include \"MediaStreamTrack.h\"\n#include \"GetSources.h\"\nusing namespace v8;\nusing namespace WebRTC;\n\nvoid GetSources::Init(Handle<Object> exports) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  exports->Set(Nan::New(\"getSources\").ToLocalChecked(), Nan::New<FunctionTemplate>(GetSources::GetDevices)->GetFunction());\n  exports->Set(Nan::New(\"getVideoSource\").ToLocalChecked(), Nan::New<FunctionTemplate>(GetSources::GetVideoSource2)->GetFunction());\n}\n\nrtc::scoped_refptr<webrtc::AudioTrackInterface> GetSources::GetAudioSource(const rtc::scoped_refptr<MediaConstraints> &constraints) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  rtc::scoped_refptr<webrtc::AudioTrackInterface> track;  \n  rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory = webrtc::CreatePeerConnectionFactory(rtc::Thread::Current(), Platform::GetWorker(), 0, 0, 0);\n  \n  if (factory.get()) {\n    track = factory->CreateAudioTrack(\"audio\", factory->CreateAudioSource(constraints->ToConstraints()));\n  }\n\n  return track;\n}\n\nrtc::scoped_refptr<webrtc::AudioTrackInterface> GetSources::GetAudioSource(const std::string id, const rtc::scoped_refptr<MediaConstraints> &constraints) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  return GetSources::GetAudioSource(constraints);\n}\n\nrtc::scoped_refptr<webrtc::VideoTrackInterface> GetSources::GetVideoSource(const rtc::scoped_refptr<MediaConstraints> &constraints) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  cricket::VideoCapturer* capturer = nullptr;\n  rtc::scoped_refptr<webrtc::VideoTrackInterface> track;\n  rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory = webrtc::CreatePeerConnectionFactory(rtc::Thread::Current(), Platform::GetWorker(), 0, 0, 0);\n  std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> video_info(webrtc::VideoCaptureFactory::CreateDeviceInfo(0));\n  cricket::WebRtcVideoDeviceCapturerFactory device_factory;\n\n  if (factory.get()) {\n    if (video_info) {\n      int num_devices = video_info->NumberOfDevices();\n      \n      for (int i = 0; i < num_devices; ++i) {\n        const uint32_t kSize = 256;\n        char name[kSize] = {0};\n        char id[kSize] = {0};\n        \n        if (video_info->GetDeviceName(i, name, kSize, id, kSize) != -1) {\n          capturer = device_factory.Create(cricket::Device(name, 0));\n          \n          if (capturer) {\n            \n            for(int i = 0; name[i]; i++){\n              if (name[i]==' ') name[i] = '_';\n              name[i] = tolower(name[i]);\n            }\n            track = factory->CreateVideoTrack(name, factory->CreateVideoSource(capturer, constraints->ToConstraints()));\n            return track;\n          }\n        }\n      }\n    }\n  }\n  \n  return track;\n}\n\nrtc::scoped_refptr<webrtc::VideoTrackInterface> GetSources::GetVideoSource(const std::string id_name, const rtc::scoped_refptr<MediaConstraints> &constraints) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  cricket::VideoCapturer* capturer = nullptr;\n  rtc::scoped_refptr<webrtc::VideoTrackInterface> track;\n  rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory = webrtc::CreatePeerConnectionFactory(rtc::Thread::Current(), Platform::GetWorker(), 0, 0, 0);\n  std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> video_info(webrtc::VideoCaptureFactory::CreateDeviceInfo(0));\n  cricket::WebRtcVideoDeviceCapturerFactory device_factory;\n\n  if (factory.get()) {\n    if (video_info) {\n      int num_devices = video_info->NumberOfDevices();\n      \n      for (int i = 0; i < num_devices; ++i) {\n        const uint32_t kSize = 256;\n        char name[kSize] = {0};\n        char id[kSize] = {0};\n        \n        if (video_info->GetDeviceName(i, name, kSize, id, kSize) != -1) {\n          if (id_name.empty() || id_name.compare(name) == 0) {\n            capturer = device_factory.Create(cricket::Device(name, 0));\n            \n            if (capturer) {\n              for(int i = 0; name[i]; i++){\n                if (name[i]==' ') name[i] = '_';\n                name[i] = tolower(name[i]);\n              }\n              track = factory->CreateVideoTrack(name, factory->CreateVideoSource(capturer, constraints->ToConstraints()));\n              return track;\n            }\n          }\n        }\n      }\n    }\n  }\n\n  return track;\n}\n\nLocal<Value> GetSources::GetDevices() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::EscapableHandleScope scope;\n  Local<Array> list = Nan::New<Array>();\n  uint32_t index = 0;\n\n  std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> video_info(webrtc::VideoCaptureFactory::CreateDeviceInfo(0));\n\n  if (video_info) {\n    int num_devices = video_info->NumberOfDevices();\n    \n    for (int i = 0; i < num_devices; ++i) {\n      const uint32_t kSize = 256;\n      char name[kSize] = {0};\n      char id[kSize] = {0};\n      \n      if (video_info->GetDeviceName(i, name, kSize, id, kSize) != -1) {\n        Local<Object> device = Nan::New<Object>();\n\n        device->Set(Nan::New(\"kind\").ToLocalChecked(), Nan::New(\"video\").ToLocalChecked());\n        device->Set(Nan::New(\"label\").ToLocalChecked(), Nan::New(name).ToLocalChecked());\n        device->Set(Nan::New(\"id\").ToLocalChecked(), Nan::New(id).ToLocalChecked());\n\n        list->Set(index, device);\n        index++;\n      }\n    }\n  }\n\n  return scope.Escape(list);\n}\n\n\nvoid GetSources::GetVideoSource2(const Nan::FunctionCallbackInfo<Value> &info) {\n  Nan::Utf8String  name_id(info[0]->ToString());\n  \n  \n  rtc::scoped_refptr<MediaConstraints> constraints = MediaConstraints::New(info[1]);\n  rtc::scoped_refptr<webrtc::VideoTrackInterface> track = GetSources::GetVideoSource(*name_id,constraints);\n  \n  \n  info.GetReturnValue().Set(MediaStreamTrack::New(track));\n}\n\n\nvoid GetSources::GetDevices(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (info.Length() == 1 && info[0]->IsFunction()) {\n    Local<Function> callback = Local<Function>::Cast(info[0]);\n\n    Local<Value> argv[1] = { \n      GetSources::GetDevices()\n    };\n\n    if (!callback.IsEmpty()) {\n      callback->Call(info.This(), 1, argv);\n    }\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n"
  },
  {
    "path": "src/GetSources.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef WEBRTC_GETSOURCES_H\n#define WEBRTC_GETSOURCES_H\n\n#include \"Common.h\"\n#include \"MediaConstraints.h\"\n\nnamespace WebRTC {\n  class GetSources {\n   public:\n    static void Init(v8::Handle<v8::Object> exports);\n\n    static rtc::scoped_refptr<webrtc::AudioTrackInterface> GetAudioSource(const rtc::scoped_refptr<MediaConstraints> &constraints);\n    static rtc::scoped_refptr<webrtc::AudioTrackInterface> GetAudioSource(const std::string id, const rtc::scoped_refptr<MediaConstraints> &constraints);\n\n    static rtc::scoped_refptr<webrtc::VideoTrackInterface> GetVideoSource(const rtc::scoped_refptr<MediaConstraints> &constraints);\n    static rtc::scoped_refptr<webrtc::VideoTrackInterface> GetVideoSource(const std::string id, const rtc::scoped_refptr<MediaConstraints> &constraints);\n    static v8::Local<v8::Value> GetDevices();\n\n   private:\n    static void GetVideoSource2(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void GetDevices(const Nan::FunctionCallbackInfo<v8::Value> &info);\n  };\n}; \n\n#endif\n"
  },
  {
    "path": "src/GetUserMedia.cc",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#include \"Platform.h\"\n#include \"GetUserMedia.h\"\n#include \"GetSources.h\"\n#include \"MediaStream.h\"\n#include \"MediaConstraints.h\"\n\nusing namespace v8;\nusing namespace WebRTC;\n\nvoid GetUserMedia::Init(Handle<Object> exports) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  exports->Set(Nan::New(\"getUserMedia\").ToLocalChecked(), Nan::New<FunctionTemplate>(GetUserMedia::GetMediaStream)->GetFunction());\n}\n\nvoid GetUserMedia::GetMediaStream(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  rtc::scoped_refptr<webrtc::MediaStreamInterface> stream;\n  rtc::scoped_refptr<MediaConstraints> constraints = MediaConstraints::New(info[0]);\n  const char *error = 0;\n  bool have_source = false;\n\n  std::string audioId = constraints->AudioId();\n  std::string videoId = constraints->VideoId();\n\n  if (constraints->UseAudio() || constraints->UseVideo()) {\n    rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory = webrtc::CreatePeerConnectionFactory(rtc::Thread::Current(), Platform::GetWorker(), 0, 0, 0);\n    \n    if (factory.get()) {\n      stream = factory->CreateLocalMediaStream(\"stream\");\n\n      if (stream.get()) {\n        if (constraints->UseAudio()) {\n          rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track;\n\n          if (audioId.empty()) {\n            audio_track = GetSources::GetAudioSource(constraints);\n          } else {\n            audio_track = GetSources::GetAudioSource(audioId, constraints);\n          }\n\n          if (audio_track.get()) {\n            if (!stream->AddTrack(audio_track)) {\n              error = \"Invalid Audio Input\";\n            } else {\n              have_source = true;\n            }\n          } else {\n            if (!audioId.empty()) {\n              error = \"Invalid Audio Input\";\n            }\n          }\n        } \n        \n        if (constraints->UseVideo()) {\n          rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track;\n\n          if (videoId.empty()) {\n            video_track = GetSources::GetVideoSource(constraints);\n          } else {\n            video_track = GetSources::GetVideoSource(videoId, constraints);\n          }\n\n          if (video_track.get()) {\n            if (!stream->AddTrack(video_track)) {\n              error = \"Invalid Video Input\";\n            } else {\n              have_source = true;\n            }\n          } else {\n            if (!videoId.empty()) {\n              error = \"Invalid Video Input\";\n            }\n          }\n        }\n      } else {\n        error = \"Internal Error\";\n      }\n    }\n  }\n  \n  if (!have_source) {\n    error = \"No available inputs\";\n  }\n\n  Handle<Value> argv[1];\n\n  if (!error) {   \n    if (stream.get()) {\n      argv[0] = MediaStream::New(stream);\n    } else {\n      error = \"Invalid MediaStream\";\n    }\n  }\n\n  if (error) {\n    if (!info[2].IsEmpty() && info[2]->IsFunction()) {\n      Local<Function> onerror = Local<Function>::Cast(info[2]);\n      argv[0] = Nan::Error(error);\n\n      onerror->Call(info.This(), 1, argv);\n    } else {\n      Nan::ThrowError(error);\n    }\n  } else {\n    if (!info[1].IsEmpty() && info[1]->IsFunction()) {\n      Local<Function> onsuccess = Local<Function>::Cast(info[1]);\n      onsuccess->Call(info.This(), 1, argv);\n    }\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n"
  },
  {
    "path": "src/GetUserMedia.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef WEBRTC_GETUSERMEDIA_H\n#define WEBRTC_GETUSERMEDIA_H\n\n#include \"Common.h\"\n\nnamespace WebRTC {\n  class GetUserMedia {\n   public:\n    static void Init(v8::Handle<v8::Object> exports);\n\n   private:\n    static void GetMediaStream(const Nan::FunctionCallbackInfo<v8::Value> &info);\n  };\n};\n\n#endif\n"
  },
  {
    "path": "src/Global.cc",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#include \"Global.h\"\n\nusing namespace v8;\nusing namespace WebRTC;\n\nNan::Persistent<Function> _require;\n\n#if (NODE_MODULE_VERSION <= NODE_0_10_MODULE_VERSION)\nNan::Persistent<Function> _parse;\n#endif\n\nvoid WebRTC::Global::Init(Handle<Object> exports) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::HandleScope scope;\n  \n  Local<Object> global = Nan::GetCurrentContext()->Global();\n  _require.Reset(Local<Function>::Cast(global->Get(Nan::New(\"require\").ToLocalChecked())));\n  \n#if (NODE_MODULE_VERSION <= NODE_0_10_MODULE_VERSION)\n  Local<Object> json = Local<Object>::Cast(global->Get(Nan::New(\"JSON\").ToLocalChecked()));\n  _parse.Reset(Local<Function>::Cast(json->Get(Nan::New(\"parse\").ToLocalChecked())));   \n#endif\n}\n\nLocal<Function> WebRTC::Global::Require(Local<String> library) {\n  Nan::EscapableHandleScope scope;\n  Local<Value> argv[] = { library };\n  Local<Value> retval = Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(_require), 1, argv);\n  return scope.Escape(Local<Function>::Cast(retval));\n}\n\n#if (NODE_MODULE_VERSION <= NODE_0_10_MODULE_VERSION)\nLocal<Value> JSON::Parse(Local<Value> str) {\n  Nan::EscapableHandleScope scope;\n  Local<Value> argv[] = { str };\n  return scope.Escape(Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(_parse), 1, argv));\n};\n#endif"
  },
  {
    "path": "src/Global.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef WEBRTC_GLOBAL_H\n#define WEBRTC_GLOBAL_H\n\n#include \"Common.h\"\n\nnamespace WebRTC {\n  class Global {\n\tpublic:\n\t  static void Init(v8::Handle<v8::Object> exports);\n\t  static v8::Local<v8::Function> Require(v8::Local<v8::String> library);\n  };\n};\n\n#if (NODE_MODULE_VERSION <= NODE_0_10_MODULE_VERSION)\nnamespace v8 {\n  class JSON {\n   public:\n    static v8::Local<v8::Value> Parse(v8::Local<v8::Value> str);\n  };\n};\n#endif\n#endif\n"
  },
  {
    "path": "src/MediaCapturer.cc",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#include \"MediaCapturer.h\"\n\nusing namespace v8;\nusing namespace WebRTC;\n\nNan::Persistent<Function> MediaCapturer::constructor;\n\nvoid MediaCapturer::Init() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::HandleScope scope;\n\n  Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(MediaCapturer::New);\n  tpl->InstanceTemplate()->SetInternalFieldCount(1);\n  tpl->SetClassName(Nan::New(\"MediaCapturer\").ToLocalChecked());\n\n  Nan::SetPrototypeMethod(tpl, \"stop\", MediaCapturer::Stop);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"data\").ToLocalChecked(), MediaStreamTrack::GetOnData, MediaStreamTrack::SetOnData);\n\n  constructor.Reset<Function>(tpl->GetFunction());\n}\n\nLocal<Value> MediaCapturer::New(webrtc::AudioSourceInterface *track) {\nLOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::EscapableHandleScope scope;\n\n  Local<Value> argv[1];\n  Local<Function> instance = Nan::New(MediaCapturer::constructor);\n  \n  if (instance.IsEmpty() || !track) {\n    return scope.Escape(Nan::Null());\n  }\n  \n  Local<Object> ret = instance->NewInstance(0, argv);\n  MediaCapturer *self = RTCWrap::Unwrap<MediaCapturer>(ret, \"MediaCapturer\");\n  \n  self->_audio = track;\n  self->_source = track;\n  self->_source->RegisterObserver(self->_observer.get());\n  self->_audio->AddSink(self);\n  \n  if (self->_audio->state() == webrtc::MediaSourceInterface::kLive) {\n    self->SetReference(true);\n  }\n  \n  return scope.Escape(ret);\n}\n\nLocal<Value> MediaCapturer::New(webrtc::VideoSourceInterface *track) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::EscapableHandleScope scope;\n\n  Local<Value> argv[1];\n  Local<Function> instance = Nan::New(MediaCapturer::constructor);\n  \n  if (instance.IsEmpty() || !track) {\n    return scope.Escape(Nan::Null());\n  }\n  \n  Local<Object> ret = instance->NewInstance(0, argv);\n  MediaCapturer *self = RTCWrap::Unwrap<MediaCapturer>(ret, \"MediaCapturer\");\n  \n  self->_video = track;\n  self->_source = track;\n  self->_source->RegisterObserver(self->_observer.get());\n  self->_video->AddOrUpdateSink(self, rtc::VideoSinkWants());\n  \n  if (self->_video->state() == webrtc::MediaSourceInterface::kLive) {\n    self->SetReference(true);\n  }\n  \n  return scope.Escape(ret);\n}\n\nMediaCapturer::MediaCapturer() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  _observer = new rtc::RefCountedObject<MediaStreamTrackObserver>(this);\n}\n\nMediaCapturer::~MediaCapturer() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (_video.get()) {\n    _video->RemoveSink(this);\n  }\n  \n  if (_audio.get()) {\n    _audio->RemoveSink(this);\n  }\n  \n  if (_source.get()) {\n    _source->UnregisterObserver(_observer.get());\n  }\n  \n  _observer->RemoveListener(this);\n}\n\nvoid MediaCapturer::New(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::HandleScope scope;\n  \n  if (info.IsConstructCall()) {\n    MediaCapturer* MediaCapturer = new MediaCapturer();\n    MediaCapturer->Wrap(info.This(), \"MediaCapturer\");\n    return info.GetReturnValue().Set(info.This());\n  }\n\n  Nan::ThrowError(\"Internal Error\");\n  info.GetReturnValue().SetUndefined();\n}\n\nvoid MediaCapturer::Stop(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaCapturer *self = RTCWrap::Unwrap<MediaCapturer>(info.This(), \"MediaCapturer\");\n\n  self->SetReference(false);\n\n  return info.GetReturnValue().SetUndefined();\n}\n\nvoid MediaCapturer::GetOnData(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  MediaCapturer *self = RTCWrap::Unwrap<MediaCapturer>(info.Holder(), \"MediaCapturer\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_ondata));\n}\n\nvoid MediaCapturer::SetOnData(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaCapturer *self = RTCWrap::Unwrap<MediaCapturer>(info.Holder(), \"MediaCapturer\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_ondata.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_ondata.Reset();\n  }\n}\n\nvoid MediaCapturer::OnFrame(const cricket::VideoFrame &frame) {\n  printf(\"Got Video Frame!\\n\");\n}\n\nvoid MediaCapturer::OnData(const void* audio_data, int bits_per_sample, int sample_rate, size_t number_of_channels, size_t number_of_frames) {\n  printf(\"Got Audio Frame!\\n\");\n}\n\nvoid MediaCapturer::On(Event *event) {\n  if (_source.get()) {\n    if (_source->state() != webrtc::MediaSourceInterface::kLive) {\n      EventEmitter::SetReference(false);\n    }\n  }\n}"
  },
  {
    "path": "src/MediaCapturer.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef WEBRTC_MEDIACAPTURER_H\n#define WEBRTC_MEDIACAPTURER_H\n\n#include \"Common.h\"\n#include \"Observers.h\" \n#include \"EventEmitter.h\"\n#include \"Wrap.h\"\n\nnamespace WebRTC {  \n  class MediaCapturer : \n    public RTCWrap, \n    public EventEmitter, \n    public rtc::VideoSourceInterface<cricket::VideoFrame>, \n    public webrtc::AudioTrackSinkInterface \n  {\n   public:\n    static void Init();\n      \n    static v8::Local<v8::Value> New(webrtc::AudioSourceInterface *track = 0);\n    static v8::Local<v8::Value> New(webrtc::VideoSourceInterface *track = 0);\n\n   private:\n    MediaCapturer();\n    ~MediaCapturer() final;\n    \n    static void New(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void Stop(const Nan::FunctionCallbackInfo<v8::Value> &info);\n\n    static void GetOnData(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void SetOnData(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    \n    void OnFrame(const cricket::VideoFrame &frame) final;\n    void OnData(const void* audio_data, int bits_per_sample, int sample_rate, size_t number_of_channels, size_t number_of_frames) final;\n    void On(Event *event) final;\n\n   protected:\n     rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> _video;\n     rtc::scoped_refptr<webrtc::AudioSourceInterface> _audio;\n     rtc::scoped_refptr<webrtc::MediaSourceInterface> _source;\n     rtc::scoped_refptr<MediaStreamTrackObserver> _observer;\n     \n     Nan::Persistent<v8::Function> _ondata;\n     \n     static Nan::Persistent<v8::Function> constructor;\n  };\n};\n\n#endif\n"
  },
  {
    "path": "src/MediaConstraints.cc",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#include \"MediaConstraints.h\"\n\nusing namespace v8;\nusing namespace WebRTC;\n\nMediaConstraints::MediaConstraints() :\n  _audio(false),\n  _video(false)\n{\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n}\n\nMediaConstraints::~MediaConstraints() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n}\n\nrtc::scoped_refptr<MediaConstraints> MediaConstraints::New() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  return new rtc::RefCountedObject<MediaConstraints>();\n}\n\nrtc::scoped_refptr<MediaConstraints> MediaConstraints::New(const Local<Object> &constraints) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::HandleScope scope;\n  \n  rtc::scoped_refptr<MediaConstraints> self = MediaConstraints::New();\n\n  if (constraints.IsEmpty()) {\n    return self;\n  }\n\n  Local<Value> optional_value = constraints->Get(Nan::New(\"optional\").ToLocalChecked());\n\n  if (!optional_value.IsEmpty() && optional_value->IsArray()) {\n    Local<Array> options = Local<Array>::Cast(optional_value);\n\n    for (unsigned int index = 0; index < options->Length(); index++) {\n      Local<Value> option_value = options->Get(index);\n\n      if (!option_value.IsEmpty() && option_value->IsObject()) {\n        Local<Object> option = Local<Object>::Cast(option_value);\n        Local<Value> DtlsSrtpKeyAgreement = option->Get(Nan::New(\"DtlsSrtpKeyAgreement\").ToLocalChecked());\n        Local<Value> RtpDataChannels = option->Get(Nan::New(\"RtpDataChannels\").ToLocalChecked());\n        Local<Value> googDscp = option->Get(Nan::New(\"googDscp\").ToLocalChecked());\n        Local<Value> googIPv6 = option->Get(Nan::New(\"googIPv6\").ToLocalChecked());\n        Local<Value> googSuspendBelowMinBitrate = option->Get(Nan::New(\"googSuspendBelowMinBitrate\").ToLocalChecked());\n        Local<Value> googCombinedAudioVideoBwe = option->Get(Nan::New(\"googCombinedAudioVideoBwe\").ToLocalChecked());\n        Local<Value> googScreencastMinBitrate = option->Get(Nan::New(\"googScreencastMinBitrate\").ToLocalChecked());\n        Local<Value> googCpuOveruseDetection = option->Get(Nan::New(\"googCpuOveruseDetection\").ToLocalChecked());\n        Local<Value> googPayloadPadding = option->Get(Nan::New(\"googPayloadPadding\").ToLocalChecked());\n\n        self->SetOptional(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, DtlsSrtpKeyAgreement);\n        self->SetOptional(webrtc::MediaConstraintsInterface::kEnableRtpDataChannels, RtpDataChannels);\n        self->SetOptional(webrtc::MediaConstraintsInterface::kEnableDscp, googDscp);\n        self->SetOptional(webrtc::MediaConstraintsInterface::kEnableIPv6, googIPv6);\n        self->SetOptional(webrtc::MediaConstraintsInterface::kEnableVideoSuspendBelowMinBitrate, googSuspendBelowMinBitrate);\n        self->SetOptional(webrtc::MediaConstraintsInterface::kCombinedAudioVideoBwe, googCombinedAudioVideoBwe);\n        self->SetOptional(webrtc::MediaConstraintsInterface::kScreencastMinBitrate, googScreencastMinBitrate);\n        self->SetOptional(webrtc::MediaConstraintsInterface::kCpuOveruseDetection, googCpuOveruseDetection);\n        self->SetOptional(webrtc::MediaConstraintsInterface::kPayloadPadding, googPayloadPadding);\n      }\n    }\n  }\n\n  Local<Value> mandatory_value = constraints->Get(Nan::New(\"mandatory\").ToLocalChecked());\n\n  if (!mandatory_value.IsEmpty() && mandatory_value->IsObject()) {\n    Local<Object> mandatory = Local<Object>::Cast(mandatory_value);\n    Local<Value> OfferToReceiveAudio = mandatory->Get(Nan::New(\"OfferToReceiveAudio\").ToLocalChecked());\n    Local<Value> OfferToReceiveVideo = mandatory->Get(Nan::New(\"OfferToReceiveVideo\").ToLocalChecked());\n    Local<Value> VoiceActivityDetection = mandatory->Get(Nan::New(\"VoiceActivityDetection\").ToLocalChecked());\n    Local<Value> IceRestart = mandatory->Get(Nan::New(\"IceRestart\").ToLocalChecked());\n    Local<Value> googUseRtpMUX = mandatory->Get(Nan::New(\"googUseRtpMUX\").ToLocalChecked());\n\n    self->SetMandatory(webrtc::MediaConstraintsInterface::kOfferToReceiveAudio, OfferToReceiveAudio);\n    self->SetMandatory(webrtc::MediaConstraintsInterface::kOfferToReceiveVideo, OfferToReceiveVideo);\n    self->SetMandatory(webrtc::MediaConstraintsInterface::kVoiceActivityDetection, VoiceActivityDetection);\n    self->SetMandatory(webrtc::MediaConstraintsInterface::kIceRestart, IceRestart);\n    self->SetMandatory(webrtc::MediaConstraintsInterface::kUseRtpMux, googUseRtpMUX);\n  }\n\n  Local<Value> audio_value = constraints->Get(Nan::New(\"audio\").ToLocalChecked());\n\n  if (!audio_value.IsEmpty()) {\n    if (audio_value->IsTrue() || audio_value->IsFalse()) {\n      self->_audio = true;\n    } else if (audio_value->IsObject()) {\n      Local<Object> audio = Local<Object>::Cast(audio_value);\n      optional_value = audio->Get(Nan::New(\"optional\").ToLocalChecked());\n\n      if (!optional_value.IsEmpty() && optional_value->IsArray()) {\n        Local<Array> options = Local<Array>::Cast(optional_value);\n\n        for (unsigned int index = 0; index < options->Length(); index++) {\n          Local<Value> option_value = options->Get(index);\n\n          if (!option_value.IsEmpty() && option_value->IsObject()) {\n            Local<Object> option = Local<Object>::Cast(option_value);\n            Local<Value> EchoCancellation = option->Get(Nan::New(\"echoCancellation\").ToLocalChecked());\n            Local<Value> googEchoCancellation = option->Get(Nan::New(\"googEchoCancellation\").ToLocalChecked());\n            Local<Value> googEchoCancellation2 = option->Get(Nan::New(\"googEchoCancellation2\").ToLocalChecked());\n            Local<Value> googDAEchoCancellation = option->Get(Nan::New(\"googDAEchoCancellation\").ToLocalChecked());\n            Local<Value> googAutoGainControl = option->Get(Nan::New(\"googAutoGainControl\").ToLocalChecked());\n            Local<Value> googAutoGainControl2 = option->Get(Nan::New(\"googAutoGainControl2\").ToLocalChecked());\n            Local<Value> googNoiseSuppression = option->Get(Nan::New(\"googNoiseSuppression\").ToLocalChecked());\n            Local<Value> googNoiseSuppression2 = option->Get(Nan::New(\"googNoiseSuppression2\").ToLocalChecked());\n            Local<Value> googHighpassFilter = option->Get(Nan::New(\"googHighpassFilter\").ToLocalChecked());\n            Local<Value> googTypingNoiseDetection = option->Get(Nan::New(\"googTypingNoiseDetection\").ToLocalChecked());\n            Local<Value> googAudioMirroring = option->Get(Nan::New(\"googAudioMirroring\").ToLocalChecked());\n            Local<Value> noiseReduction = option->Get(Nan::New(\"googNoiseReduction\").ToLocalChecked());\n            Local<Value> sourceId = option->Get(Nan::New(\"sourceId\").ToLocalChecked());\n\n            self->SetOptional(webrtc::MediaConstraintsInterface::kEchoCancellation, EchoCancellation);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kGoogEchoCancellation, googEchoCancellation);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kExtendedFilterEchoCancellation, googEchoCancellation2);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kDAEchoCancellation, googDAEchoCancellation);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kAutoGainControl, googAutoGainControl);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kExperimentalAutoGainControl, googAutoGainControl2);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kNoiseSuppression, googNoiseSuppression);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kExperimentalNoiseSuppression, googNoiseSuppression2);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kHighpassFilter, googHighpassFilter);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kTypingNoiseDetection, googTypingNoiseDetection);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kAudioMirroring, googAudioMirroring);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kNoiseReduction, noiseReduction);\n\n            if (!sourceId.IsEmpty() && sourceId->IsString()) {\n              String::Utf8Value sourceId_str(sourceId->ToString());\n              self->_audioId = *sourceId_str;\n            }\n          }\n        }\n      }\n\n      self->_audio = true;\n    }\n  }\n\n  Local<Value> video_value = constraints->Get(Nan::New(\"video\").ToLocalChecked());\n\n  if (!video_value.IsEmpty()) {\n    if (video_value->IsTrue() || video_value->IsFalse()) {\n      self->_video = true;\n    } else if (video_value->IsObject()) {\n      Local<Object> video = Local<Object>::Cast(audio_value);\n      optional_value = video->Get(Nan::New(\"optional\").ToLocalChecked());\n\n      if (!optional_value.IsEmpty() && optional_value->IsArray()) {\n        Local<Array> options = Local<Array>::Cast(optional_value);\n\n        for (unsigned int index = 0; index < options->Length(); index++) {\n          Local<Value> option_value = options->Get(index);\n\n          if (!option_value.IsEmpty() && option_value->IsObject()) {\n            Local<Object> option = Local<Object>::Cast(option_value);\n\n            Local<Value> minAspectRatio = option->Get(Nan::New(\"minAspectRatio\").ToLocalChecked());\n            Local<Value> maxAspectRatio = option->Get(Nan::New(\"maxAspectRatio\").ToLocalChecked());\n            Local<Value> maxWidth = option->Get(Nan::New(\"maxWidth\").ToLocalChecked());\n            Local<Value> minWidth = option->Get(Nan::New(\"minWidth\").ToLocalChecked());\n            Local<Value> maxHeight = option->Get(Nan::New(\"maxHeight\").ToLocalChecked());\n            Local<Value> minHeight = option->Get(Nan::New(\"minHeight\").ToLocalChecked());\n            Local<Value> maxFrameRate = option->Get(Nan::New(\"maxFrameRate\").ToLocalChecked());\n            Local<Value> minFrameRate = option->Get(Nan::New(\"minFrameRate\").ToLocalChecked());\n            Local<Value> sourceId = option->Get(Nan::New(\"sourceId\").ToLocalChecked());\n\n            self->SetOptional(webrtc::MediaConstraintsInterface::kMinAspectRatio, minAspectRatio);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kMaxAspectRatio, maxAspectRatio);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kMaxWidth, maxWidth);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kMinWidth, minWidth);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kMaxHeight, maxHeight);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kMinHeight, minHeight);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kMaxFrameRate, maxFrameRate);\n            self->SetOptional(webrtc::MediaConstraintsInterface::kMinFrameRate, minFrameRate);\n            \n            if (!sourceId.IsEmpty() && sourceId->IsString()) {\n              String::Utf8Value sourceId_str(sourceId->ToString());\n              self->_videoId = *sourceId_str;\n            }\n          }\n        }\n      }\n\n      self->_video = true;\n    }\n  }\n\n\n  return self;\n}\n\nrtc::scoped_refptr<MediaConstraints> MediaConstraints::New(const Local<Value> &constraints) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::HandleScope scope;\n  \n  if (!constraints.IsEmpty() && constraints->IsObject()) {\n    Local<Object> obj = Local<Object>::Cast(constraints);\n    return MediaConstraints::New(obj);\n  }\n\n  return MediaConstraints::New();\n}\n\n\nvoid MediaConstraints::SetOptional(std::string key, Local<Value> value) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (!value.IsEmpty() && !value->IsNull() && !value->IsUndefined()) {\n    if (value->IsTrue() || value->IsFalse()) {\n      MediaConstraints::SetOptional(key, value->IsTrue() ?\n                                    std::string(webrtc::MediaConstraintsInterface::kValueTrue) :\n                                    std::string(webrtc::MediaConstraintsInterface::kValueFalse));\n    } else if (value->IsNumber()) {\n      MediaConstraints::SetOptional(key, value->NumberValue());\n    } else if (value->IsInt32()) {\n      MediaConstraints::SetOptional(key, value->Int32Value());\n    } else if (value->IsUint32()) {\n      MediaConstraints::SetOptional(key, value->Uint32Value());\n    } else {\n      Nan::ThrowError(\"Unknown MediaConstraints Type\");\n    }\n  }\n}\n\nvoid MediaConstraints::SetMandatory(std::string key, Local<Value> value) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (!value.IsEmpty() && !value->IsNull() && !value->IsUndefined()) {\n    if (value->IsTrue() || value->IsFalse()) {\n      MediaConstraints::SetMandatory(key, value->IsTrue() ?\n                                     std::string(webrtc::MediaConstraintsInterface::kValueTrue) :\n                                     std::string(webrtc::MediaConstraintsInterface::kValueFalse));\n    } else if (value->IsNumber()) {\n      MediaConstraints::SetMandatory(key, value->NumberValue());\n    } else if (value->IsInt32()) {\n      MediaConstraints::SetMandatory(key, value->Int32Value());\n    } else if (value->IsUint32()) {\n      MediaConstraints::SetMandatory(key, value->Uint32Value());\n    } else {\n      Nan::ThrowError(\"Unknown MediaConstraints Type\");\n    }\n  }\n}\n\nbool MediaConstraints::IsMandatory(const std::string& key) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  std::string value;\n\n  if (_mandatory.FindFirst(key, &value)) {\n    return true;\n  }\n\n  return false;\n}\n\nbool MediaConstraints::GetMandatory(const std::string& key) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  std::string value;\n\n  if (_mandatory.FindFirst(key, &value)) {\n    if (!value.compare(\"true\")) {\n      return true;\n    }\n  }\n\n  return false;\n}\n\nvoid MediaConstraints::RemoveMandatory(const std::string& key) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  std::string value;\n\n  if (_mandatory.FindFirst(key, &value)) {\n    for (webrtc::MediaConstraintsInterface::Constraints::iterator iter = _mandatory.begin(); iter != _mandatory.end(); ++iter) {\n      if (iter->key == key) {\n        _mandatory.erase(iter);\n        break;\n      }\n    }\n  }\n}\n\nvoid MediaConstraints::AddMandatory(const std::string &key, const std::string &value) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  _mandatory.push_back(webrtc::MediaConstraintsInterface::Constraint(key, value));\n}\n\nvoid MediaConstraints::SetMandatory(const std::string &key, const std::string &value) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaConstraints::RemoveMandatory(key);\n  MediaConstraints::AddMandatory(key, value);\n}\n\nbool MediaConstraints::IsOptional(const std::string& key) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  std::string value;\n\n  if (_mandatory.FindFirst(key, &value)) {\n    return true;\n  }\n\n  return false;\n}\n\nbool MediaConstraints::GetOptional(const std::string& key) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  std::string value;\n\n  if (_optional.FindFirst(key, &value)) {\n    if (!value.compare(\"true\")) {\n      return true;\n    }\n  }\n\n  return false;\n}\n\nvoid MediaConstraints::RemoveOptional(const std::string& key) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  std::string value;\n\n  if (_optional.FindFirst(key, &value)) {\n    for (webrtc::MediaConstraintsInterface::Constraints::iterator iter = _optional.begin(); iter != _optional.end(); ++iter) {\n      if (iter->key == key) {\n        _optional.erase(iter);\n        break;\n      }\n    }\n  }\n}\n\nvoid MediaConstraints::AddOptional(const std::string &key, const std::string &value) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  _optional.push_back(webrtc::MediaConstraintsInterface::Constraint(key, value));\n}\n\nvoid MediaConstraints::SetOptional(const std::string &key, const std::string &value) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaConstraints::RemoveOptional(key);\n  MediaConstraints::AddOptional(key, value);\n}\n\nbool MediaConstraints::UseAudio() const {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  return _audio;\n}\n\nbool MediaConstraints::UseVideo() const {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  return _video;\n}\n\nstd::string MediaConstraints::AudioId() const {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  return _audioId;\n}\n\nstd::string MediaConstraints::VideoId() const {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  return _videoId;\n}\n\nconst webrtc::MediaConstraintsInterface *MediaConstraints::ToConstraints() const {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  return this;\n}\n\nconst webrtc::MediaConstraintsInterface::Constraints &MediaConstraints::GetMandatory() const {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  return _mandatory;\n}\n\nconst webrtc::MediaConstraintsInterface::Constraints &MediaConstraints::GetOptional() const {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  return _optional;\n}\n"
  },
  {
    "path": "src/MediaConstraints.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n\n#ifndef WEBRTC_MEDIACONSTRAINTS_H\n#define WEBRTC_MEDIACONSTRAINTS_H\n\n#include \"Common.h\"\n\nnamespace WebRTC {\n  class MediaConstraints : public webrtc::MediaConstraintsInterface, public rtc::RefCountInterface {\n    friend class rtc::RefCountedObject<MediaConstraints>;\n\n   public:\n    static rtc::scoped_refptr<MediaConstraints> New();\n    static rtc::scoped_refptr<MediaConstraints> New(const v8::Local<v8::Object> &constraints);\n    static rtc::scoped_refptr<MediaConstraints> New(const v8::Local<v8::Value> &constraints);\n\n    bool UseAudio() const;\n    bool UseVideo() const;\n\n    std::string AudioId() const;\n    std::string VideoId() const;\n\n    bool IsMandatory(const std::string& key);\n    bool GetMandatory(const std::string& key);\n    void RemoveMandatory(const std::string& key);\n    void AddMandatory(const std::string &key, const std::string &value);\n    void SetMandatory(const std::string &key, const std::string &value);\n\n    template <class T> void SetMandatory(const std::string& key, const T& value) {\n      SetMandatory(key, rtc::ToString<T>(value));\n    }\n\n    bool IsOptional(const std::string& key);\n    bool GetOptional(const std::string& key);\n    void RemoveOptional(const std::string& key);\n    void AddOptional(const std::string &key, const std::string &value);\n    void SetOptional(const std::string &key, const std::string &value);\n\n    template <class T> void SetOptional(const std::string& key, const T& value) {\n      SetOptional(key, rtc::ToString<T>(value));\n    }\n\n    const webrtc::MediaConstraintsInterface *ToConstraints() const;\n    const webrtc::MediaConstraintsInterface::Constraints &GetMandatory() const final;\n    const webrtc::MediaConstraintsInterface::Constraints &GetOptional() const final;\n\n   private:\n    explicit MediaConstraints();\n    ~MediaConstraints() override;\n\n    void SetOptional(std::string key, v8::Local<v8::Value> value);\n    void SetMandatory(std::string key, v8::Local<v8::Value> value);\n\n   protected:\n    bool _audio;\n    bool _video;\n\n    std::string _audioId;\n    std::string _videoId;\n\n    webrtc::MediaConstraintsInterface::Constraints _mandatory;\n    webrtc::MediaConstraintsInterface::Constraints _optional;\n  };\n};\n\n#endif\n"
  },
  {
    "path": "src/MediaStream.cc",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#include \"MediaStream.h\"\n#include \"MediaStreamTrack.h\"\n\nusing namespace v8;\nusing namespace WebRTC;\n\nNan::Persistent<Function> MediaStream::constructor;\n\nvoid MediaStream::Init() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::HandleScope scope;\n\n  Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(MediaStream::New);\n  tpl->InstanceTemplate()->SetInternalFieldCount(1);\n  tpl->SetClassName(Nan::New(\"MediaStream\").ToLocalChecked());\n\n  Nan::SetPrototypeMethod(tpl, \"addTrack\", MediaStream::AddTrack);\n  Nan::SetPrototypeMethod(tpl, \"removeTrack\", MediaStream::RemoveTrack);\n  Nan::SetPrototypeMethod(tpl, \"clone\", MediaStream::Clone);\n  Nan::SetPrototypeMethod(tpl, \"getAudioTracks\", MediaStream::GetAudioTracks);\n  Nan::SetPrototypeMethod(tpl, \"getTrackById\", MediaStream::GetTrackById);\n  Nan::SetPrototypeMethod(tpl, \"getVideoTracks\", MediaStream::GetVideoTracks);\n  Nan::SetPrototypeMethod(tpl, \"getTracks\", MediaStream::GetTracks);\n\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"active\").ToLocalChecked(), MediaStream::GetActive);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"ended\").ToLocalChecked(), MediaStream::GetEnded);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"id\").ToLocalChecked(), MediaStream::GetId);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onaddtrack\").ToLocalChecked(), MediaStream::GetOnAddTrack, MediaStream::SetOnAddTrack);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onremovetrack\").ToLocalChecked(), MediaStream::GetOnRemoveTrack, MediaStream::SetOnRemoveTrack);\n\n  constructor.Reset(tpl->GetFunction());\n}\n\nLocal<Value> MediaStream::New(rtc::scoped_refptr<webrtc::MediaStreamInterface> mediaStream) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::EscapableHandleScope scope;\n\n  Local<Value> empty;\n  Local<Function> instance = Nan::New(MediaStream::constructor);\n\n  if (instance.IsEmpty() || !mediaStream.get()) {\n    return scope.Escape(Nan::Null());\n  }\n\n  Local<Object> ret = instance->NewInstance();\n  MediaStream *self = RTCWrap::Unwrap<MediaStream>(ret, \"MediaStream\");\n  \n  if (self) {   \n    self->_stream = mediaStream;\n    self->_audio_tracks = self->_stream->GetAudioTracks();\n    self->_video_tracks = self->_stream->GetVideoTracks();\n    self->_stream->RegisterObserver(self->_observer.get());\n    self->CheckState();\n    \n    return scope.Escape(ret);\n  }\n\n  return scope.Escape(Nan::Null());\n}\n\nMediaStream::MediaStream() :\n  _active(false),\n  _ended(true)\n{\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  _observer = new rtc::RefCountedObject<MediaStreamObserver>(this);\n}\n\nMediaStream::~MediaStream() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (_stream.get()) {\n    _stream->UnregisterObserver(_observer.get());\n  }\n  \n  _observer->RemoveListener(this);\n}\n\nvoid MediaStream::New(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  Nan::HandleScope scope;\n\n  if (info.IsConstructCall()) {\n    MediaStream* mediaStream = new MediaStream();\n    mediaStream->Wrap(info.This(), \"MediaStream\");\n    return info.GetReturnValue().Set(info.This());\n  }\n  \n  Nan::ThrowError(\"Internal Error\");\n  info.GetReturnValue().SetUndefined();\n}\n\nrtc::scoped_refptr<webrtc::MediaStreamInterface> MediaStream::Unwrap(Local<Object> value) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (!value.IsEmpty()) {\n    MediaStream *self = RTCWrap::Unwrap<MediaStream>(value, \"MediaStream\");\n\n    if (self) {\n      return self->_stream;\n    }\n  }\n\n  return 0;\n}\n\nrtc::scoped_refptr<webrtc::MediaStreamInterface> MediaStream::Unwrap(Local<Value> value) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (!value.IsEmpty() && value->IsObject()) {\n    Local<Object> stream = Local<Object>::Cast(value);\n    return MediaStream::Unwrap(stream);\n  }\n\n  return 0;\n}\n\nvoid MediaStream::AddTrack(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = MediaStream::Unwrap(info.This());\n  bool retval = false;\n\n  if (stream.get()) {\n    if (info.Length() >= 1 && info[0]->IsObject()) {\n      rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track = MediaStreamTrack::Unwrap(info[0]);\n\n      if (track.get()) {\n        std::string kind = track->kind();\n\n        if (kind.compare(\"audio\") == 0) {\n          rtc::scoped_refptr<webrtc::AudioTrackInterface> audio(static_cast<webrtc::AudioTrackInterface*>(track.get()));\n          retval = stream->AddTrack(audio);\n        } else {\n          rtc::scoped_refptr<webrtc::VideoTrackInterface> video(static_cast<webrtc::VideoTrackInterface*>(track.get()));\n          retval = stream->AddTrack(video);\n        }\n      }\n    }\n  } else {\n    Nan::ThrowError(\"Internal Error\");\n  }\n\n  return info.GetReturnValue().Set(Nan::New(retval));\n}\n\nvoid MediaStream::RemoveTrack(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = MediaStream::Unwrap(info.This());\n  bool retval = false;\n\n  if (stream.get()) {\n    if (info.Length() >= 1 && info[0]->IsObject()) {\n      rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track = MediaStreamTrack::Unwrap(info[0]);\n\n      if (track.get()) {\n        std::string kind = track->kind();\n\n        if (kind.compare(\"audio\") == 0) {\n          rtc::scoped_refptr<webrtc::AudioTrackInterface> audio(static_cast<webrtc::AudioTrackInterface*>(track.get()));\n          retval = stream->RemoveTrack(audio);\n        } else {\n          rtc::scoped_refptr<webrtc::VideoTrackInterface> video(static_cast<webrtc::VideoTrackInterface*>(track.get()));\n          retval = stream->RemoveTrack(video);\n        }\n      }\n    }\n  } else {\n    Nan::ThrowError(\"Internal Error\");\n  }\n\n  return info.GetReturnValue().Set(Nan::New(retval));\n}\n\nvoid MediaStream::Clone(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  rtc::scoped_refptr<webrtc::MediaStreamInterface> self = MediaStream::Unwrap(info.This());\n  rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory = webrtc::CreatePeerConnectionFactory();\n  rtc::scoped_refptr<webrtc::MediaStreamInterface> stream;\n\n  if (self.get() && factory.get()) {\n    stream = factory->CreateLocalMediaStream(\"stream\");\n\n    if (stream.get()) {\n      webrtc::AudioTrackVector audio_list = self->GetAudioTracks();\n      std::vector<rtc::scoped_refptr<webrtc::AudioTrackInterface> >::iterator audio_it;\n\n      for (audio_it = audio_list.begin(); audio_it != audio_list.end(); audio_it++) {\n        rtc::scoped_refptr<webrtc::AudioTrackInterface> track(*audio_it);\n\n        if (track.get()) {\n          stream->AddTrack(track.get());\n        }\n      }\n\n      webrtc::VideoTrackVector video_list = self->GetVideoTracks();\n      std::vector<rtc::scoped_refptr<webrtc::VideoTrackInterface> >::iterator video_it;\n\n      for (video_it = video_list.begin(); video_it != video_list.end(); video_it++) {\n        rtc::scoped_refptr<webrtc::VideoTrackInterface> track(*video_it);\n\n        if (track.get()) {\n          stream->AddTrack(track.get());\n        }\n      }\n\n      return info.GetReturnValue().Set(MediaStream::New(stream));\n    }\n  }\n  \n  Nan::ThrowError(\"Internal Error\");\n  info.GetReturnValue().SetUndefined();\n}\n\nvoid MediaStream::GetTrackById(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = MediaStream::Unwrap(info.This());\n\n  if (stream.get()) {\n    if (info.Length() >= 1 && info[0]->IsString()) {\n      v8::String::Utf8Value idValue(info[0]->ToString());\n      std::string id(*idValue);\n\n      rtc::scoped_refptr<webrtc::AudioTrackInterface> audio = stream->FindAudioTrack(id);\n\n      if (audio.get()) {\n        return info.GetReturnValue().Set(MediaStreamTrack::New(audio.get()));\n      }\n\n      rtc::scoped_refptr<webrtc::VideoTrackInterface> video = stream->FindVideoTrack(id);\n\n      if (video.get()) {\n        return info.GetReturnValue().Set(MediaStreamTrack::New(video.get()));\n      }\n    }\n\n    return info.GetReturnValue().Set(Nan::Null());\n  } else {\n    Nan::ThrowError(\"Internal Error\");\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid MediaStream::GetAudioTracks(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  rtc::scoped_refptr<webrtc::MediaStreamInterface> self = MediaStream::Unwrap(info.This());\n\n  if (self.get()) {\n    webrtc::AudioTrackVector audio_list = self->GetAudioTracks();\n    std::vector<rtc::scoped_refptr<webrtc::AudioTrackInterface> >::iterator audio_it;\n    Local<Array> list = Nan::New<Array>();\n    uint32_t index = 0;\n\n    for (audio_it = audio_list.begin(); audio_it != audio_list.end(); audio_it++) {\n      rtc::scoped_refptr<webrtc::AudioTrackInterface> track(*audio_it);\n\n      if (track.get()) {\n        list->Set(index, MediaStreamTrack::New(track.get()));\n        index++;\n      }\n    }\n\n    return info.GetReturnValue().Set(list);\n  } else {\n    Nan::ThrowError(\"Internal Error\");\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid MediaStream::GetVideoTracks(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  rtc::scoped_refptr<webrtc::MediaStreamInterface> self = MediaStream::Unwrap(info.This());\n\n  if (self.get()) {\n    webrtc::VideoTrackVector video_list = self->GetVideoTracks();\n    std::vector<rtc::scoped_refptr<webrtc::VideoTrackInterface> >::iterator video_it;\n    Local<Array> list = Nan::New<Array>();\n    uint32_t index = 0;\n\n    for (video_it = video_list.begin(); video_it != video_list.end(); video_it++) {\n      rtc::scoped_refptr<webrtc::VideoTrackInterface> track(*video_it);\n\n      if (track.get()) {\n        list->Set(index, MediaStreamTrack::New(track.get()));\n        index++;\n      }\n    }\n\n    return info.GetReturnValue().Set(list);\n  } else {\n    Nan::ThrowError(\"Internal Error\");\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid MediaStream::GetTracks(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  rtc::scoped_refptr<webrtc::MediaStreamInterface> self = MediaStream::Unwrap(info.This());\n\n  if (self.get()) {\n    webrtc::AudioTrackVector audio_list = self->GetAudioTracks();\n    webrtc::VideoTrackVector video_list = self->GetVideoTracks();\n    \n    std::vector<rtc::scoped_refptr<webrtc::AudioTrackInterface> >::iterator audio_it;\n    std::vector<rtc::scoped_refptr<webrtc::VideoTrackInterface> >::iterator video_it;\n    \n    Local<Array> list = Nan::New<Array>();\n    uint32_t index = 0;\n\n    for (audio_it = audio_list.begin(); audio_it != audio_list.end(); audio_it++) {\n      rtc::scoped_refptr<webrtc::AudioTrackInterface> track(*audio_it);\n\n      if (track.get()) {\n        list->Set(index, MediaStreamTrack::New(track.get()));\n        index++;\n      }\n    }\n \n    for (video_it = video_list.begin(); video_it != video_list.end(); video_it++) {\n      rtc::scoped_refptr<webrtc::VideoTrackInterface> track(*video_it);\n\n      if (track.get()) {\n        list->Set(index, MediaStreamTrack::New(track.get()));\n        index++;\n      }\n    }\n\n    return info.GetReturnValue().Set(list);\n  } else {\n    Nan::ThrowError(\"Internal Error\");\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid MediaStream::GetActive(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  MediaStream *self = RTCWrap::Unwrap<MediaStream>(info.Holder(), \"MediaStream\");\n  return info.GetReturnValue().Set(Nan::New(self->_active));\n}\n\nvoid MediaStream::GetEnded(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  MediaStream *self = RTCWrap::Unwrap<MediaStream>(info.Holder(), \"MediaStream\");\n  return info.GetReturnValue().Set(Nan::New(self->_ended));\n}\n\nvoid MediaStream::GetId(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = MediaStream::Unwrap(info.Holder());\n  \n  if (stream.get()) {\n    return info.GetReturnValue().Set(Nan::New(stream->label().c_str()).ToLocalChecked());\n  } else {\n    Nan::ThrowError(\"Internal Error\");\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid MediaStream::GetOnAddTrack(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStream *self = RTCWrap::Unwrap<MediaStream>(info.Holder(), \"MediaStream\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onaddtrack));\n}\n\nvoid MediaStream::GetOnRemoveTrack(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStream *self = RTCWrap::Unwrap<MediaStream>(info.Holder(), \"MediaStream\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onremovetrack));\n}\n\nvoid MediaStream::ReadOnly(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n}\n\nvoid MediaStream::SetOnAddTrack(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStream *self = RTCWrap::Unwrap<MediaStream>(info.Holder(), \"MediaStream\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onaddtrack.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onaddtrack.Reset();\n  }\n}\n\nvoid MediaStream::SetOnRemoveTrack(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStream *self = RTCWrap::Unwrap<MediaStream>(info.Holder(), \"MediaStream\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onremovetrack.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onremovetrack.Reset();\n  }\n}\n\nvoid MediaStream::CheckState() {\n  _active = false;\n  _ended = true;\n  \n  webrtc::AudioTrackVector new_audio_tracks = _stream->GetAudioTracks();\n  webrtc::VideoTrackVector new_video_tracks = _stream->GetVideoTracks();\n\n  for (const auto& cached_track : _audio_tracks) {\n    auto it = std::find_if(\n        new_audio_tracks.begin(), new_audio_tracks.end(),\n        [cached_track](const webrtc::AudioTrackVector::value_type& new_track) {\n          return new_track->id().compare(cached_track->id()) == 0;\n        });\n    if (it == new_audio_tracks.end()) {\n      Local<Function> callback = Nan::New<Function>(_onremovetrack);\n      Local<Value> argv[] = {\n        MediaStreamTrack::New(cached_track.get())\n      };\n\n      if (!callback.IsEmpty() && callback->IsFunction()) {\n        callback->Call(RTCWrap::This(), 1, argv);\n      }\n    }\n  }\n  \n  for (const auto& new_track : new_audio_tracks) {\n    if (new_track->state() == webrtc::MediaStreamTrackInterface::kLive) {\n      _active = true;\n      _ended = false;\n    }\n    \n    auto it = std::find_if(\n        _audio_tracks.begin(), _audio_tracks.end(),\n        [new_track](const webrtc::AudioTrackVector::value_type& cached_track) {\n          return new_track->id().compare(cached_track->id()) == 0;\n        });\n    if (it == _audio_tracks.end()) {\n      Local<Function> callback = Nan::New<Function>(_onaddtrack);\n      Local<Value> argv[] = {\n        MediaStreamTrack::New(new_track.get())\n      };\n\n      if (!callback.IsEmpty() && callback->IsFunction()) {\n        callback->Call(RTCWrap::This(), 1, argv);\n      }\n    }\n  }\n  \n  for (const auto& cached_track : _video_tracks) {\n    auto it = std::find_if(\n        new_video_tracks.begin(), new_video_tracks.end(),\n        [cached_track](const webrtc::VideoTrackVector::value_type& new_track) {\n          return new_track->id().compare(cached_track->id()) == 0;\n        });\n    if (it == new_video_tracks.end()) {\n      Local<Function> callback = Nan::New<Function>(_onremovetrack);\n      Local<Value> argv[] = {\n        MediaStreamTrack::New(cached_track.get())\n      };\n\n      if (!callback.IsEmpty() && callback->IsFunction()) {\n        callback->Call(RTCWrap::This(), 1, argv);\n      }\n    }\n  }\n  \n  for (const auto& new_track : new_video_tracks) {\n    if (new_track->state() == webrtc::MediaStreamTrackInterface::kLive) {\n      _active = true;\n      _ended = false;\n    }\n    \n    auto it = std::find_if(\n        _video_tracks.begin(), _video_tracks.end(),\n        [new_track](const webrtc::VideoTrackVector::value_type& cached_track) {\n          return new_track->id().compare(cached_track->id()) == 0;\n        });\n    if (it == _video_tracks.end()) {\n      Local<Function> callback = Nan::New<Function>(_onaddtrack);\n      Local<Value> argv[] = {\n        MediaStreamTrack::New(new_track.get())\n      };\n\n      if (!callback.IsEmpty() && callback->IsFunction()) {\n        callback->Call(RTCWrap::This(), 1, argv);\n      }\n    }\n  }\n  \n  _audio_tracks = new_audio_tracks;\n  _video_tracks = new_video_tracks;\n}\n\nvoid MediaStream::On(Event *event) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::HandleScope scope;\n  MediaStreamEvent type = event->Type<MediaStreamEvent>();\n\n  if (type != kMediaStreamChanged) {\n    Nan::ThrowError(\"Internal Error\");\n    return;\n  }\n  \n  MediaStream::CheckState();\n}\n"
  },
  {
    "path": "src/MediaStream.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef WEBRTC_MEDIASTREAM_H\n#define WEBRTC_MEDIASTREAM_H\n\n#include \"Common.h\"\n#include \"Observers.h\" \n#include \"EventEmitter.h\"\n#include \"Wrap.h\"\n\nnamespace WebRTC {\n  enum MediaStreamEvent {\n    kMediaStreamChanged\n  };\n  \n  class MediaStream : public RTCWrap, public EventEmitter {\n   public:\n    static void Init();    \n    static v8::Local<v8::Value> New(rtc::scoped_refptr<webrtc::MediaStreamInterface> mediaStream);\n\n    static rtc::scoped_refptr<webrtc::MediaStreamInterface> Unwrap(v8::Local<v8::Object> value);\n    static rtc::scoped_refptr<webrtc::MediaStreamInterface> Unwrap(v8::Local<v8::Value> value);\n\n   private:\n    MediaStream();\n    ~MediaStream() final;\n    \n    static void New(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void AddTrack(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void Clone(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void GetTrackById(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void GetAudioTracks(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void GetVideoTracks(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void GetTracks(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void RemoveTrack(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    \n    static void GetActive(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetEnded(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetId(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnAddTrack(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnRemoveTrack(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n\n    static void ReadOnly(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnAddTrack(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnRemoveTrack(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n\n    void CheckState();\n    void On(Event *event) final;\n\n   protected:\n    bool _active;\n    bool _ended;\n    \n    Nan::Persistent<v8::Function> _onaddtrack;\n    Nan::Persistent<v8::Function> _onremovetrack;\n\n    rtc::scoped_refptr<MediaStreamObserver> _observer;\n    rtc::scoped_refptr<webrtc::MediaStreamInterface> _stream;\n\n    webrtc::AudioTrackVector _audio_tracks;\n    webrtc::VideoTrackVector _video_tracks;\n\n    static Nan::Persistent<v8::Function> constructor;\n  };\n};\n\n#endif\n"
  },
  {
    "path": "src/MediaStreamTrack.cc",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#include \"MediaStreamTrack.h\"\n\nusing namespace v8;\nusing namespace WebRTC;\n\nNan::Persistent<Function> MediaStreamTrack::constructor;\n\nvoid MediaStreamTrack::Init() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::HandleScope scope;\n\n  Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(MediaStreamTrack::New);\n  tpl->InstanceTemplate()->SetInternalFieldCount(1);\n  tpl->SetClassName(Nan::New(\"MediaStreamTrack\").ToLocalChecked());\n\n  Nan::SetPrototypeMethod(tpl, \"getConstraints\", MediaStreamTrack::GetConstraints);\n  Nan::SetPrototypeMethod(tpl, \"applyConstraints\", MediaStreamTrack::ApplyConstraints);\n  Nan::SetPrototypeMethod(tpl, \"setSettings\", MediaStreamTrack::GetSettings);\n  Nan::SetPrototypeMethod(tpl, \"getCapabilities\", MediaStreamTrack::GetCapabilities);\n  Nan::SetPrototypeMethod(tpl, \"clone\", MediaStreamTrack::Clone);\n  Nan::SetPrototypeMethod(tpl, \"stop\", MediaStreamTrack::Stop);\n\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"enabled\").ToLocalChecked(), MediaStreamTrack::GetEnabled, MediaStreamTrack::SetEnabled);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"id\").ToLocalChecked(), MediaStreamTrack::GetId);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"kind\").ToLocalChecked(), MediaStreamTrack::GetKind);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"label\").ToLocalChecked(), MediaStreamTrack::GetLabel);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"muted\").ToLocalChecked(), MediaStreamTrack::GetMuted);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"readonly\").ToLocalChecked(), MediaStreamTrack::GetReadOnly);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"readyState\").ToLocalChecked(), MediaStreamTrack::GetReadyState);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"remote\").ToLocalChecked(), MediaStreamTrack::GetRemote);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onstarted\").ToLocalChecked(), MediaStreamTrack::GetOnStarted, MediaStreamTrack::SetOnStarted);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onmute\").ToLocalChecked(), MediaStreamTrack::GetOnMute, MediaStreamTrack::SetOnMute);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onunmute\").ToLocalChecked(), MediaStreamTrack::GetOnUnMute, MediaStreamTrack::SetOnUnMute);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onoverconstrained\").ToLocalChecked(), MediaStreamTrack::GetOnOverConstrained, MediaStreamTrack::SetOnOverConstrained);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onended\").ToLocalChecked(), MediaStreamTrack::GetOnEnded, MediaStreamTrack::SetOnEnded);\n\n  constructor.Reset<Function>(tpl->GetFunction());\n}\n\nLocal<Value> MediaStreamTrack::New(rtc::scoped_refptr<webrtc::AudioTrackInterface> audioTrack) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::EscapableHandleScope scope;\n\n  Local<Value> argv[1];\n  Local<Function> instance = Nan::New(MediaStreamTrack::constructor);\n\n  if (instance.IsEmpty() || !audioTrack.get()) {\n    return scope.Escape(Nan::Null());\n  }\n\n  Local<Object> ret = instance->NewInstance(0, argv);\n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(ret, \"MediaStreamTrack\");\n\n  self->isAudioTrack = true;\n  self->_track = audioTrack;\n  self->_source = audioTrack->GetSource();\n  self->_track_state = self->_track->state();\n  self->_source_state = self->_source->state();\n  self->_track->RegisterObserver(self->_observer.get());\n  self->_source->RegisterObserver(self->_observer.get());\n  self->CheckState();\n\n  return scope.Escape(ret);\n}\n\nLocal<Value> MediaStreamTrack::New(rtc::scoped_refptr<webrtc::VideoTrackInterface> videoTrack) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::EscapableHandleScope scope;\n\n  Local<Value> argv[1];\n  Local<Function> instance = Nan::New(MediaStreamTrack::constructor);\n\n  if (instance.IsEmpty() || !videoTrack.get()) {\n    return scope.Escape(Nan::Null());\n  }\n\n  Local<Object> ret = instance->NewInstance(0, argv);\n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(ret, \"MediaStreamTrack\");\n\n  self->isVideoTrack = true;\n  self->_track = videoTrack;\n  self->_source = videoTrack->GetSource();\n  self->_track_state = self->_track->state();\n  self->_source_state = self->_source->state();\n  self->_track->RegisterObserver(self->_observer.get());\n  self->_source->RegisterObserver(self->_observer.get());\n  self->CheckState();\n\n  return scope.Escape(ret);\n}\n\nMediaStreamTrack::MediaStreamTrack() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  _observer = new rtc::RefCountedObject<MediaStreamTrackObserver>(this);\n}\n\nMediaStreamTrack::~MediaStreamTrack() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (_track.get()) {\n    _track->UnregisterObserver(_observer.get());\n  }\n  \n  if (_source.get()) {\n    _source->UnregisterObserver(_observer.get());\n  }\n  \n  _observer->RemoveListener(this);\n}\n\nvoid MediaStreamTrack::New(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::HandleScope scope;\n  \n  if (info.IsConstructCall()) {\n    MediaStreamTrack* mediaStreamTrack = new MediaStreamTrack();\n    mediaStreamTrack->Wrap(info.This(), \"MediaStreamTrack\");\n    return info.GetReturnValue().Set(info.This());\n  }\n\n  Nan::ThrowError(\"Internal Error\");\n  info.GetReturnValue().SetUndefined();\n}\n\nrtc::scoped_refptr<webrtc::MediaStreamTrackInterface> MediaStreamTrack::Unwrap(Local<Object> value) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (!value.IsEmpty()) {\n    MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(value, \"MediaStreamTrack\");\n\n    if (self) {\n      return self->_track;\n    }\n  }\n\n  return 0;\n}\n\nrtc::scoped_refptr<webrtc::MediaStreamTrackInterface> MediaStreamTrack::Unwrap(Local<Value> value) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (!value.IsEmpty() && value->IsObject()) {\n    Local<Object> track = Local<Object>::Cast(value);\n    return MediaStreamTrack::Unwrap(track);\n  }\n\n  return 0;\n}\n\nvoid MediaStreamTrack::GetConstraints(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  //MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.This(), \"MediaStreamTrack\");\n\n  info.GetReturnValue().SetUndefined();\n}\n\nvoid MediaStreamTrack::ApplyConstraints(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  //MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.This(), \"MediaStreamTrack\");\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid MediaStreamTrack::GetSettings(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  //MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.This(), \"MediaStreamTrack\");\n\n  info.GetReturnValue().SetUndefined();\n}\n\nvoid MediaStreamTrack::GetCapabilities(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  //MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.This(), \"MediaStreamTrack\");\n\n  info.GetReturnValue().SetUndefined();\n}\n\nvoid MediaStreamTrack::Clone(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n \n  //MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.This(), \"MediaStreamTrack\");\n\n  info.GetReturnValue().SetUndefined();\n}\n\nvoid MediaStreamTrack::Stop(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.This(), \"MediaStreamTrack\");\n  info.GetReturnValue().Set(Nan::New(self->_track->set_state(webrtc::MediaStreamTrackInterface::kEnded)));\n}\n\nvoid MediaStreamTrack::GetEnabled(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.This(), \"MediaStreamTrack\");\n  info.GetReturnValue().Set(Nan::New(self->_track->enabled()));\n}\n\nvoid MediaStreamTrack::GetId(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n  info.GetReturnValue().Set(Nan::New(self->_track->id().c_str()).ToLocalChecked());\n}\n\nvoid MediaStreamTrack::GetKind(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n  info.GetReturnValue().Set(Nan::New(self->_track->kind().c_str()).ToLocalChecked());\n}\n\nvoid MediaStreamTrack::GetLabel(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  info.GetReturnValue().Set(Nan::New(\"\").ToLocalChecked());\n}\n\nvoid MediaStreamTrack::GetMuted(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n  info.GetReturnValue().Set(Nan::New((self->_source->state() == webrtc::MediaSourceInterface::kMuted) ? true : false));\n}\n\nvoid MediaStreamTrack::GetReadOnly(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  return info.GetReturnValue().Set(Nan::New(true));\n}\n\nvoid MediaStreamTrack::GetReadyState(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n\n  if (self->_track->state() == webrtc::MediaStreamTrackInterface::kLive) {\n    return info.GetReturnValue().Set(Nan::New(\"live\").ToLocalChecked());\n  }\n  \n  info.GetReturnValue().Set(Nan::New(\"ended\").ToLocalChecked());\n}\n\nvoid MediaStreamTrack::GetRemote(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n  info.GetReturnValue().Set(Nan::New(self->_source->remote()));\n}\n\nvoid MediaStreamTrack::GetOnStarted(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onstarted));\n}\n\nvoid MediaStreamTrack::GetOnMute(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onmute));\n}\n\nvoid MediaStreamTrack::GetOnUnMute(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onunmute));\n}\n\nvoid MediaStreamTrack::GetOnOverConstrained(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onoverconstrained));\n}\n\nvoid MediaStreamTrack::GetOnEnded(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onended));\n}\n\n\nvoid MediaStreamTrack::ReadOnly(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  //MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n\n  // TODO(): Implement This\n}\n\nvoid MediaStreamTrack::SetEnabled(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n  \n  if (!value.IsEmpty() && value->IsBoolean()) {\n    self->_track->set_enabled(value->IsTrue() ? true : false);\n  }\n}\n\nvoid MediaStreamTrack::SetOnStarted(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onstarted.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onstarted.Reset();\n  }\n}\n\nvoid MediaStreamTrack::SetOnMute(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onmute.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onmute.Reset();\n  }\n}\n\nvoid MediaStreamTrack::SetOnUnMute(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onunmute.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onunmute.Reset();\n  }\n}\n\nvoid MediaStreamTrack::SetOnOverConstrained(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onoverconstrained.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onoverconstrained.Reset();\n  }\n}\n\nvoid MediaStreamTrack::SetOnEnded(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  MediaStreamTrack *self = RTCWrap::Unwrap<MediaStreamTrack>(info.Holder(), \"MediaStreamTrack\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onended.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onended.Reset();\n  }\n}\n\nvoid MediaStreamTrack::CheckState() {\n  webrtc::MediaStreamTrackInterface::TrackState new_state = _track->state();\n  webrtc::MediaSourceInterface::SourceState new_source = _source->state();\n  \n  if (_track_state != new_state) {\n    if (new_state == webrtc::MediaStreamTrackInterface::kEnded || new_state == webrtc::MediaStreamTrackInterface::kFailed) {\n      Local<Function> callback = Nan::New<Function>(_onended);\n      Local<Value> argv[1];\n\n      if (!callback.IsEmpty() && callback->IsFunction()) {\n        callback->Call(RTCWrap::This(), 0, argv);\n      }\n    } else if (_track_state == webrtc::MediaStreamTrackInterface::kInitializing && new_state == webrtc::MediaStreamTrackInterface::kLive) {\n      Local<Function> callback = Nan::New<Function>(_onstarted);\n      Local<Value> argv[1];\n\n      if (!callback.IsEmpty() && callback->IsFunction()) {\n        callback->Call(RTCWrap::This(), 0, argv);\n      }\n    }\n  }\n\n  if (_source_state != new_source) {\n    if (new_source == webrtc::MediaSourceInterface::kMuted) {\n      Local<Function> callback = Nan::New<Function>(_onmute);\n      Local<Value> argv[1];\n\n      if (!callback.IsEmpty() && callback->IsFunction()) {\n        callback->Call(RTCWrap::This(), 0, argv);\n      }\n    } else {\n      Local<Function> callback = Nan::New<Function>(_onunmute);\n      Local<Value> argv[1];\n\n      if (!callback.IsEmpty() && callback->IsFunction()) {\n        callback->Call(RTCWrap::This(), 0, argv);\n      }\n    }\n  }\n \n  _source_state = new_source;  \n  _track_state = new_state;\n}\n\nvoid MediaStreamTrack::On(Event *event) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::HandleScope scope;\n  MediaStreamTrackEvent type = event->Type<MediaStreamTrackEvent>();\n\n  if (type != kMediaStreamTrackChanged) {\n    return;\n  }\n  \n  MediaStreamTrack::CheckState();\n}\n"
  },
  {
    "path": "src/MediaStreamTrack.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef WEBRTC_MEDIASTREAMTRACK_H\n#define WEBRTC_MEDIASTREAMTRACK_H\n\n#include \"Common.h\"\n#include \"Observers.h\" \n#include \"EventEmitter.h\"\n#include \"Wrap.h\"\n\nnamespace WebRTC {\n  enum MediaStreamTrackEvent {\n    kMediaStreamTrackChanged\n  };  \n  \n  class MediaStreamTrack : public RTCWrap, public EventEmitter {\n   public:\n    static void Init();\n    \n    static v8::Local<v8::Value> New(rtc::scoped_refptr<webrtc::AudioTrackInterface> audioTrack);\n    static v8::Local<v8::Value> New(rtc::scoped_refptr<webrtc::VideoTrackInterface> videoTrack);\n\n    static rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> Unwrap(v8::Local<v8::Object> value);\n    static rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> Unwrap(v8::Local<v8::Value> value);\n\n   private:\n    MediaStreamTrack();\n    ~MediaStreamTrack() final;\n\n    static void New(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void GetConstraints(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void ApplyConstraints(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void GetSettings(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void GetCapabilities(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void Clone(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void Stop(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    \n    static void GetEnabled(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetId(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetKind(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetLabel(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetMuted(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetReadOnly(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetReadyState(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetRemote(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnStarted(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnMute(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnUnMute(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnOverConstrained(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnEnded(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n\n    static void ReadOnly(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetEnabled(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnStarted(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnMute(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnUnMute(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnOverConstrained(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnEnded(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    \n    void CheckState();\n    void On(Event *event) final;\n\n   protected:\n    bool isAudioTrack;\n    bool isVideoTrack;\n    \n    rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> _track;\n    rtc::scoped_refptr<webrtc::MediaSourceInterface> _source;\n    rtc::scoped_refptr<MediaStreamTrackObserver> _observer;\n \n    webrtc::MediaStreamTrackInterface::TrackState _track_state;\n    webrtc::MediaSourceInterface::SourceState _source_state;\n\n    Nan::Persistent<v8::Function> _onstarted;\n    Nan::Persistent<v8::Function> _onmute;\n    Nan::Persistent<v8::Function> _onunmute;\n    Nan::Persistent<v8::Function> _onoverconstrained;\n    Nan::Persistent<v8::Function> _onended;\n\n    static Nan::Persistent<v8::Function> constructor;\n  };\n};\n\n#endif\n"
  },
  {
    "path": "src/Module.cc",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#include \"Common.h\"\n\n#include \"Global.h\"\n#include \"Platform.h\"\n#include \"Stats.h\"\n#include \"PeerConnection.h\"\n#include \"DataChannel.h\"\n#include \"BackTrace.h\"\n#include \"GetSources.h\"\n#include \"GetUserMedia.h\"\n#include \"MediaStream.h\"\n#include \"MediaStreamTrack.h\"\n\nusing namespace v8;\n\nvoid SetDebug(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (info.Length() && !info[0].IsEmpty()) {\n    if (info[0]->IsTrue()) {\n      rtc::LogMessage::LogToDebug(rtc::LS_VERBOSE);\n    } else {\n      rtc::LogMessage::LogToDebug(rtc::LS_NONE);\n    }\n  }\n\n  info.GetReturnValue().SetUndefined();\n}\n\nvoid RTCGarbageCollect(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::LowMemoryNotification();\n  info.GetReturnValue().SetUndefined();\n}\n\nvoid RTCIceCandidate(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (info.Length() == 1 && info[0]->IsObject() && info.IsConstructCall()) {\n    Local<Object> arg = info[0]->ToObject();\n    Local<Object> retval = Nan::New<Object>();\n    \n    retval->Set(Nan::New(\"candidate\").ToLocalChecked(), arg->Get(Nan::New(\"candidate\").ToLocalChecked()));               \n    retval->Set(Nan::New(\"sdpMLineIndex\").ToLocalChecked(), arg->Get(Nan::New(\"sdpMLineIndex\").ToLocalChecked()));\n    retval->Set(Nan::New(\"sdpMid\").ToLocalChecked(), arg->Get(Nan::New(\"sdpMid\").ToLocalChecked()));\n    \n    return info.GetReturnValue().Set(retval);\n  } else {\n    return info.GetReturnValue().Set(info[0]);\n  }\n}\n\nvoid RTCSessionDescription(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (info.Length() == 1 && info[0]->IsObject() && info.IsConstructCall()) {\n    Local<Object> arg = info[0]->ToObject();\n    Local<Object> retval = Nan::New<Object>();\n    \n    retval->Set(Nan::New(\"type\").ToLocalChecked(), arg->Get(Nan::New(\"type\").ToLocalChecked()));\n    retval->Set(Nan::New(\"sdp\").ToLocalChecked(), arg->Get(Nan::New(\"sdp\").ToLocalChecked()));\n\n    return info.GetReturnValue().Set(retval);\n  } else {\n    return info.GetReturnValue().Set(info[0]);\n  }\n}\n\nvoid WebrtcModuleDispose(void *arg) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  WebRTC::Platform::Dispose();\n}\n\nvoid WebrtcModuleInit(Handle<Object> exports) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::HandleScope scope;\n\n  WebRTC::Global::Init(exports);\n  WebRTC::Platform::Init();\n  WebRTC::RTCStatsResponse::Init();\n  WebRTC::RTCStatsReport::Init();\n  WebRTC::PeerConnection::Init(exports);\n  WebRTC::DataChannel::Init();\n  WebRTC::GetSources::Init(exports);\n  WebRTC::GetUserMedia::Init(exports);\n  WebRTC::MediaStream::Init();\n  WebRTC::MediaStreamTrack::Init();\n  \n  exports->Set(Nan::New(\"RTCGarbageCollect\").ToLocalChecked(), Nan::New<FunctionTemplate>(RTCGarbageCollect)->GetFunction()); \n  exports->Set(Nan::New(\"RTCIceCandidate\").ToLocalChecked(), Nan::New<FunctionTemplate>(RTCIceCandidate)->GetFunction());\n  exports->Set(Nan::New(\"RTCSessionDescription\").ToLocalChecked(), Nan::New<FunctionTemplate>(RTCSessionDescription)->GetFunction());\n  exports->Set(Nan::New(\"setDebug\").ToLocalChecked(), Nan::New<FunctionTemplate>(SetDebug)->GetFunction());\n\n  node::AtExit(WebrtcModuleDispose);\n}\n\nNODE_MODULE(webrtc, WebrtcModuleInit)"
  },
  {
    "path": "src/Observers.cc",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#include \"Observers.h\"\n#include \"PeerConnection.h\"\n#include \"DataChannel.h\"\n#include \"MediaStream.h\"\n#include \"MediaStreamTrack.h\"\n\nusing namespace WebRTC;\n\nOfferObserver::OfferObserver(EventEmitter *listener) : \n  NotifyEmitter(listener) { }\n\nvoid OfferObserver::OnSuccess(webrtc::SessionDescriptionInterface* desc) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Json::StyledWriter writer;\n  Json::Value msg;\n  std::string sdp;\n  \n  if (desc->ToString(&sdp)) {\n    msg[\"type\"] = desc->type();\n    msg[\"sdp\"] = sdp;\n\n    Emit(kPeerConnectionCreateOffer, writer.write(msg));\n  }\n}\n\nvoid OfferObserver::OnFailure(const std::string &error) {\n  LOG(LS_ERROR) << __PRETTY_FUNCTION__;\n  \n  Emit(kPeerConnectionCreateOfferError, error);\n}\n\nAnswerObserver::AnswerObserver(EventEmitter *listener) : \n  NotifyEmitter(listener) { }\n  \nvoid AnswerObserver::OnSuccess(webrtc::SessionDescriptionInterface* desc) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Json::StyledWriter writer;\n  Json::Value msg;\n  std::string sdp;\n  \n  if (desc->ToString(&sdp)) { \n    msg[\"type\"] = desc->type();\n    msg[\"sdp\"] = sdp;\n    \n    Emit(kPeerConnectionCreateAnswer, writer.write(msg));\n  }\n}\n\nvoid AnswerObserver::OnFailure(const std::string &error) {\n  LOG(LS_ERROR) << __PRETTY_FUNCTION__;\n  \n  Emit(kPeerConnectionCreateAnswerError, error);\n}\n\nLocalDescriptionObserver::LocalDescriptionObserver(EventEmitter *listener) : \n  NotifyEmitter(listener) { }\n\nvoid LocalDescriptionObserver::OnSuccess() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Emit(kPeerConnectionSetLocalDescription);\n}\n\nvoid LocalDescriptionObserver::OnFailure(const std::string &error) {\n  LOG(LS_ERROR) << __PRETTY_FUNCTION__;\n  \n  Emit(kPeerConnectionSetLocalDescriptionError, error);\n}\n\nRemoteDescriptionObserver::RemoteDescriptionObserver(EventEmitter *listener) : \n  NotifyEmitter(listener) { }\n\nvoid RemoteDescriptionObserver::OnSuccess() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Emit(kPeerConnectionSetRemoteDescription);\n}\n\nvoid RemoteDescriptionObserver::OnFailure(const std::string &error) {\n  LOG(LS_ERROR) << __PRETTY_FUNCTION__;\n  \n  Emit(kPeerConnectionSetRemoteDescriptionError, error);\n}\n\nPeerConnectionObserver::PeerConnectionObserver(EventEmitter *listener) : \n  NotifyEmitter(listener) { }\n\nvoid PeerConnectionObserver::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState state) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Emit(kPeerConnectionSignalChange);\n  \n  if (state == webrtc::PeerConnectionInterface::kClosed) {\n    Emit(kPeerConnectionCreateClosed);\n  }\n}\n\nvoid PeerConnectionObserver::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState state) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Emit(kPeerConnectionIceChange);\n}\n\nvoid PeerConnectionObserver::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState state) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Emit(kPeerConnectionIceGathering);\n  \n  if (state == webrtc::PeerConnectionInterface::kIceGatheringComplete) {\n    Emit(kPeerConnectionIceCandidate, std::string());\n  }\n}\n\nvoid PeerConnectionObserver::OnStateChange(webrtc::PeerConnectionObserver::StateType state) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n}\n\nvoid PeerConnectionObserver::OnDataChannel(webrtc::DataChannelInterface *channel) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel = channel;\n  \n  if (dataChannel.get()) {\n    Emit(kPeerConnectionDataChannel, dataChannel);\n  }\n}\n\nvoid PeerConnectionObserver::OnAddStream(webrtc::MediaStreamInterface *stream) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  rtc::scoped_refptr<webrtc::MediaStreamInterface> mediaStream = stream;\n\n  if (mediaStream.get()) {\n    Emit(kPeerConnectionAddStream, mediaStream);\n  }\n}\n\nvoid PeerConnectionObserver::OnRemoveStream(webrtc::MediaStreamInterface *stream) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  rtc::scoped_refptr<webrtc::MediaStreamInterface> mediaStream = stream;\n\n  if (mediaStream.get()) {\n    Emit(kPeerConnectionRemoveStream, mediaStream);\n  }\n}\n\nvoid PeerConnectionObserver::OnRenegotiationNeeded() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Emit(kPeerConnectionRenegotiation);\n}\n\nvoid PeerConnectionObserver::OnIceCandidate(const webrtc::IceCandidateInterface* candidate) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Json::StyledWriter writer;\n  Json::Value msg;\n  std::string sdp;\n  \n  if (candidate->ToString(&sdp)) {\n    msg[\"sdpMid\"] = candidate->sdp_mid();\n    msg[\"sdpMLineIndex\"] = candidate->sdp_mline_index();\n    msg[\"candidate\"] = sdp;\n    \n    Emit(kPeerConnectionIceCandidate, writer.write(msg));\n  }\n}\n\nDataChannelObserver::DataChannelObserver(EventEmitter *listener) : \n  NotifyEmitter(listener) { }\n\nvoid DataChannelObserver::OnStateChange() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  Emit(kDataChannelStateChange);\n}\n\nvoid DataChannelObserver::OnMessage(const webrtc::DataBuffer& buffer) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (buffer.binary) {\n    Emit(kDataChannelBinary, buffer.data);\n  } else {\n    Emit(kDataChannelData, buffer.data);\n  }\n}\n\nMediaStreamObserver::MediaStreamObserver(EventEmitter *listener) :\n  NotifyEmitter(listener) { }\n\nvoid MediaStreamObserver::OnChanged() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Emit(kMediaStreamChanged);\n}\n\nMediaStreamTrackObserver::MediaStreamTrackObserver(EventEmitter *listener) :\n  NotifyEmitter(listener) { }\n\nvoid MediaStreamTrackObserver::OnChanged() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Emit(kMediaStreamTrackChanged);\n}\n\nStatsObserver::StatsObserver(EventEmitter *listener) :\n  NotifyEmitter(listener) { }\n\nvoid StatsObserver::OnComplete(const webrtc::StatsReports &reports) {\n  LOG(LS_INFO) << \"StatsObserver::OnComplete()\";\n  \n  Emit(kPeerConnectionStats, reports);\n}\n"
  },
  {
    "path": "src/Observers.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef WEBRTC_OBSERVERS_H\n#define WEBRTC_OBSERVERS_H\n\n#include \"EventEmitter.h\"\n\nnamespace WebRTC {  \n  class OfferObserver : public webrtc::CreateSessionDescriptionObserver, public NotifyEmitter {\n   public:\n    OfferObserver(EventEmitter *listener = 0);\n    \n    void OnSuccess(webrtc::SessionDescriptionInterface* sdp) final;\n    void OnFailure(const std::string &error) final;\n  };\n  \n  class AnswerObserver : public webrtc::CreateSessionDescriptionObserver, public NotifyEmitter {    \n   public:\n    AnswerObserver(EventEmitter *listener = 0);\n    \n    void OnSuccess(webrtc::SessionDescriptionInterface* sdp) final;\n    void OnFailure(const std::string &error) final;\n  };\n\n  class LocalDescriptionObserver : public webrtc::SetSessionDescriptionObserver, public NotifyEmitter {\n   public:\n    LocalDescriptionObserver(EventEmitter *listener = 0);\n\n    void OnSuccess() final;\n    void OnFailure(const std::string &error) final;\n  };\n    \n  class RemoteDescriptionObserver : public webrtc::SetSessionDescriptionObserver, public NotifyEmitter {    \n   public:\n    RemoteDescriptionObserver(EventEmitter *listener = 0);\n    \n    void OnSuccess() final;\n    void OnFailure(const std::string &error) final;\n  };\n  \n  class PeerConnectionObserver : \n    public webrtc::PeerConnectionObserver, \n    public rtc::RefCountInterface,\n    public NotifyEmitter\n  {\n   public:\n    PeerConnectionObserver(EventEmitter *listener = 0);\n    \n    void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState state) final;\n    void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState state) final;\n    void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState state) final;\n    void OnStateChange(webrtc::PeerConnectionObserver::StateType state);\n    void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) final;\n    void OnDataChannel(webrtc::DataChannelInterface* channel) final;\n    void OnRenegotiationNeeded() final;\n\n    void OnAddStream(webrtc::MediaStreamInterface* stream) final;\n    void OnRemoveStream(webrtc::MediaStreamInterface* stream) final;\n  };\n  \n  class DataChannelObserver : \n    public webrtc::DataChannelObserver, \n    public rtc::RefCountInterface,\n    public NotifyEmitter \n  {\n   public:\n    DataChannelObserver(EventEmitter *listener = 0);\n\n    void OnStateChange() final;\n    void OnMessage(const webrtc::DataBuffer& buffer) final;\n  };\n\n  class MediaStreamObserver :\n    public webrtc::ObserverInterface,\n    public rtc::RefCountInterface,\n    public NotifyEmitter \n  {\n   public:\n     MediaStreamObserver(EventEmitter *listener = 0);\n     \n     void OnChanged() final;\n  };\n\n  class MediaStreamTrackObserver :\n    public webrtc::ObserverInterface,\n    public rtc::RefCountInterface,\n    public NotifyEmitter\n  {\n   public:\n    MediaStreamTrackObserver(EventEmitter *listener = 0);\n    \n    void OnChanged() final;\n  };\n\n  class StatsObserver : public webrtc::StatsObserver, public NotifyEmitter {\n   public:\n    StatsObserver(EventEmitter *listener = 0);\n\n    void OnComplete(const webrtc::StatsReports& reports) final;\n  };\n};\n\n#endif\n"
  },
  {
    "path": "src/PeerConnection.cc",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#include <nan.h>\n#include \"Global.h\"\n#include \"Platform.h\"\n#include \"PeerConnection.h\"\n#include \"DataChannel.h\"\n#include \"MediaStream.h\"\n#include \"Stats.h\"\n\nusing namespace v8;\nusing namespace WebRTC;\n\nvoid PeerConnection::Init(Handle<Object> exports) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::HandleScope scope;\n  \n  Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(PeerConnection::New);\n  tpl->InstanceTemplate()->SetInternalFieldCount(1);\n  tpl->SetClassName(Nan::New(\"RTCPeerConnection\").ToLocalChecked());\n\n  Nan::SetPrototypeMethod(tpl, \"createOffer\", PeerConnection::CreateOffer);\n  Nan::SetPrototypeMethod(tpl, \"createAnswer\", PeerConnection::CreateAnswer);\n  Nan::SetPrototypeMethod(tpl, \"setLocalDescription\", PeerConnection::SetLocalDescription);\n  Nan::SetPrototypeMethod(tpl, \"setRemoteDescription\", PeerConnection::SetRemoteDescription);\n  Nan::SetPrototypeMethod(tpl, \"addIceCandidate\", PeerConnection::AddIceCandidate);\n  Nan::SetPrototypeMethod(tpl, \"createDataChannel\", PeerConnection::CreateDataChannel);\n  Nan::SetPrototypeMethod(tpl, \"addStream\", PeerConnection::AddStream);\n  Nan::SetPrototypeMethod(tpl, \"removeStream\", PeerConnection::RemoveStream);\n  Nan::SetPrototypeMethod(tpl, \"getLocalStreams\", PeerConnection::GetLocalStreams);\n  Nan::SetPrototypeMethod(tpl, \"getRemoteStreams\", PeerConnection::GetRemoteStreams);\n  Nan::SetPrototypeMethod(tpl, \"getStreamById\", PeerConnection::GetStreamById);\n  Nan::SetPrototypeMethod(tpl, \"getStats\", PeerConnection::GetStats);\n  Nan::SetPrototypeMethod(tpl, \"close\", PeerConnection::Close);\n\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"signalingState\").ToLocalChecked(), PeerConnection::GetSignalingState);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"iceConnectionState\").ToLocalChecked(), PeerConnection::GetIceConnectionState);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"iceGatheringState\").ToLocalChecked(), PeerConnection::GetIceGatheringState);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"localDescription\").ToLocalChecked(), PeerConnection::GetLocalDescription);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"remoteDescription\").ToLocalChecked(), PeerConnection::GetRemoteDescription);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onsignalingstatechange\").ToLocalChecked(), PeerConnection::GetOnSignalingStateChange, PeerConnection::SetOnSignalingStateChange);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"oniceconnectionstatechange\").ToLocalChecked(), PeerConnection::GetOnIceConnectionStateChange, PeerConnection::SetOnIceConnectionStateChange);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onicecandidate\").ToLocalChecked(), PeerConnection::GetOnIceCandidate, PeerConnection::SetOnIceCandidate);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"ondatachannel\").ToLocalChecked(), PeerConnection::GetOnDataChannel, PeerConnection::SetOnDataChannel);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onnegotiationneeded\").ToLocalChecked(), PeerConnection::GetOnNegotiationNeeded, PeerConnection::SetOnNegotiationNeeded);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onaddstream\").ToLocalChecked(), PeerConnection::GetOnAddStream, PeerConnection::SetOnAddStream);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"onremovestream\").ToLocalChecked(), PeerConnection::GetOnRemoveStream, PeerConnection::SetOnRemoveStream);\n\n  constructor.Reset<Function>(tpl->GetFunction());\n  exports->Set(Nan::New(\"RTCPeerConnection\").ToLocalChecked(), tpl->GetFunction());\n}\n\nNan::Persistent<Function> PeerConnection::constructor;\n\nPeerConnection::PeerConnection(const Local<Object> &configuration,\n                               const Local<Object> &constraints)\n{ \n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n    \n  if (!configuration.IsEmpty()) {\n    Local<Value> iceservers_value = configuration->Get(Nan::New(\"iceServers\").ToLocalChecked());\n    \n    if (!iceservers_value.IsEmpty() && iceservers_value->IsArray()) {\n      Local<Array> list = Local<Array>::Cast(iceservers_value);\n\n      for (unsigned int index = 0; index < list->Length(); index++) {\n        Local<Value> server_value = list->Get(index);\n\n        if (!server_value.IsEmpty() && server_value->IsObject()) {\n          Local<Object> server = Local<Object>::Cast(server_value);\n          Local<Value> url_value = server->Get(Nan::New(\"url\").ToLocalChecked());\n          Local<Value> username_value = server->Get(Nan::New(\"username\").ToLocalChecked());\n          Local<Value> credential_value = server->Get(Nan::New(\"credential\").ToLocalChecked());\n\n          if (!url_value.IsEmpty() && url_value->IsString()) {\n            v8::String::Utf8Value url(url_value->ToString());\n            webrtc::PeerConnectionInterface::IceServer entry;\n\n            entry.uri = *url;\n\n            if (!username_value.IsEmpty() && username_value->IsString()) {\n              String::Utf8Value username(username_value->ToString());\n              entry.username = *username;\n            }\n\n            if (!credential_value.IsEmpty() && credential_value->IsString()) {\n              String::Utf8Value credential(credential_value->ToString());\n              entry.password = *credential;\n            }\n\n            _config.servers.push_back(entry);\n          }\n        }        \n      }\n    }\n  }\n\n  _constraints = MediaConstraints::New(constraints);\n\n  if (!_constraints->GetOptional(\"RtpDataChannels\")) {\n    if (!_constraints->IsOptional(\"DtlsSrtpKeyAgreement\")) {\n      _constraints->SetOptional(\"DtlsSrtpKeyAgreement\", \"true\");\n    }\n  }\n\n  _stats = new rtc::RefCountedObject<StatsObserver>(this);\n  _offer = new rtc::RefCountedObject<OfferObserver>(this);\n  _answer = new rtc::RefCountedObject<AnswerObserver>(this);\n  _local = new rtc::RefCountedObject<LocalDescriptionObserver>(this);\n  _remote = new rtc::RefCountedObject<RemoteDescriptionObserver>(this);\n  _peer = new rtc::RefCountedObject<PeerConnectionObserver>(this);\n  _factory = webrtc::CreatePeerConnectionFactory(rtc::Thread::Current(), Platform::GetWorker(), 0, 0, 0);\n}\n\nPeerConnection::~PeerConnection() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (_socket.get()) {\n    webrtc::PeerConnectionInterface::SignalingState state(_socket->signaling_state());\n\n    if (state != webrtc::PeerConnectionInterface::kClosed) {\n      _socket->Close();\n    }\n  }\n  \n  _stats->RemoveListener(this);\n  _offer->RemoveListener(this);\n  _answer->RemoveListener(this);\n  _local->RemoveListener(this);\n  _remote->RemoveListener(this);\n  _peer->RemoveListener(this);\n}\n\nwebrtc::PeerConnectionInterface *PeerConnection::GetSocket() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  if (!_socket.get()) {\n    if (_factory.get()) {\n      EventEmitter::SetReference(true);\n      _socket = _factory->CreatePeerConnection(_config, _constraints->ToConstraints(), NULL, NULL, _peer.get());\n      \n      if (!_socket.get()) {\n        Nan::ThrowError(\"Internal Socket Error\");\n      }\n    } else {\n      Nan::ThrowError(\"Internal Factory Error\");\n    }\n  }\n   \n  return _socket.get();\n}\n\nvoid PeerConnection::New(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Local<Object> configuration;\n  Local<Object> constraints;\n  \n  if (info.Length() >= 1 && info[0]->IsObject()) {\n    configuration = Local<Object>::Cast(info[0]);\n    \n    if (info.Length() >= 2 && info[1]->IsObject()) {\n      constraints = Local<Object>::Cast(info[1]);\n    }\n  }\n\n  if (info.IsConstructCall()) {\n    PeerConnection* peer = new PeerConnection(configuration, constraints);\n    peer->Wrap(info.This(), \"PeerConnection\");\n    return info.GetReturnValue().Set(info.This());\n  } else {\n    const int argc = 2;\n    Local<Value> argv[argc] = {\n      configuration,\n      constraints\n    };\n    \n    Local<Function> instance = Nan::New(PeerConnection::constructor);\n    return info.GetReturnValue().Set(instance->NewInstance(argc, argv));\n  }\n}\n\nvoid PeerConnection::CreateOffer(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.This(), \"PeerConnection\");\n  webrtc::PeerConnectionInterface *socket = self->GetSocket();\n  \n  if (!info[0].IsEmpty() && info[0]->IsFunction()) {\n    self->_offerCallback.Reset<Function>(Local<Function>::Cast(info[0]));\n  } else {\n    self->_offerCallback.Reset();\n  }\n  \n  if (!info[1].IsEmpty() && info[1]->IsFunction()) {\n    self->_offerErrorCallback.Reset<Function>(Local<Function>::Cast(info[1]));\n  } else {\n    self->_offerErrorCallback.Reset();\n  }\n  \n  if (socket) {\n    socket->CreateOffer(self->_offer.get(), self->_constraints->ToConstraints());\n  } else {\n    Nan::ThrowError(\"Internal Error\");\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::CreateAnswer(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.This(), \"PeerConnection\");\n  webrtc::PeerConnectionInterface *socket = self->GetSocket();\n  \n  if (!info[0].IsEmpty() && info[0]->IsFunction()) {\n    self->_answerCallback.Reset<Function>(Local<Function>::Cast(info[0]));\n  } else {\n    self->_answerCallback.Reset();\n  }\n  \n  if (!info[1].IsEmpty() && info[1]->IsFunction()) {\n    self->_answerErrorCallback.Reset<Function>(Local<Function>::Cast(info[1]));\n  } else {\n    self->_answerErrorCallback.Reset();\n  }\n  \n  if (socket) {\n    socket->CreateAnswer(self->_answer.get(), self->_constraints->ToConstraints());\n  } else {\n    Nan::ThrowError(\"Internal Error\");\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::SetLocalDescription(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.This(), \"PeerConnection\");\n  webrtc::PeerConnectionInterface *socket = self->GetSocket();\n  const char *error = \"Invalid SessionDescription\";\n\n  if (!info[0].IsEmpty() && info[0]->IsObject()) {\n    Local<Object> desc_obj = Local<Object>::Cast(info[0]);\n    Local<Value> type_value = desc_obj->Get(Nan::New(\"type\").ToLocalChecked());\n    Local<Value> sdp_value = desc_obj->Get(Nan::New(\"sdp\").ToLocalChecked());\n    \n    if (!type_value.IsEmpty() && type_value->IsString()) {\n      if (!sdp_value.IsEmpty() && sdp_value->IsString()) {\n        if (!info[1].IsEmpty() && info[1]->IsFunction()) {\n          self->_localCallback.Reset<Function>(Local<Function>::Cast(info[1]));\n        } else {\n          self->_localCallback.Reset();\n        }\n\n        if (!info[2].IsEmpty() && info[2]->IsFunction()) {\n          self->_localErrorCallback.Reset<Function>(Local<Function>::Cast(info[2]));\n        } else {\n          self->_localErrorCallback.Reset();\n        }\n    \n        String::Utf8Value type(type_value->ToString());\n        String::Utf8Value sdp(sdp_value->ToString());\n\n        webrtc::SessionDescriptionInterface *desc(webrtc::CreateSessionDescription(*type, *sdp, 0));\n        \n        if (desc) {\n          if (socket) {\n            self->_localsdp.Reset<Object>(desc_obj);\n            socket->SetLocalDescription(self->_local.get(), desc);\n            error = 0;\n          } else {\n            error = \"Internal Error\";\n          }\n        }\n      }\n    }\n  }\n  \n  if (error) {\n    if (!info[2].IsEmpty() && info[2]->IsFunction()) {\n      Local<Value> argv[1] = {\n        Nan::Error(error)\n      };\n\n      Local<Function> onerror = Local<Function>::Cast(info[2]);\n      onerror->Call(info.This(), 1, argv);\n    } else {\n      Nan::ThrowError(error);\n    }\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::SetRemoteDescription(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.This(), \"PeerConnection\");\n  webrtc::PeerConnectionInterface *socket = self->GetSocket();\n  const char *error = \"Invalid SessionDescription\";\n  \n  if (!info[0].IsEmpty() && info[0]->IsObject()) {\n    Local<Object> desc_obj = Local<Object>::Cast(info[0]);\n    Local<Value> type_value = desc_obj->Get(Nan::New(\"type\").ToLocalChecked());\n    Local<Value> sdp_value = desc_obj->Get(Nan::New(\"sdp\").ToLocalChecked());\n    \n    if (!type_value.IsEmpty() && type_value->IsString()) {\n      if (!sdp_value.IsEmpty() && sdp_value->IsString()) {\n        if (!info[1].IsEmpty() && info[1]->IsFunction()) {\n          self->_remoteCallback.Reset<Function>(Local<Function>::Cast(info[1]));\n        } else {\n          self->_remoteCallback.Reset();\n        }\n\n        if (!info[2].IsEmpty() && info[2]->IsFunction()) {\n          self->_remoteErrorCallback.Reset<Function>(Local<Function>::Cast(info[2]));\n        } else {\n          self->_remoteErrorCallback.Reset();\n        }\n    \n        String::Utf8Value type(type_value->ToString());\n        String::Utf8Value sdp(sdp_value->ToString());\n\n        webrtc::SessionDescriptionInterface *desc(webrtc::CreateSessionDescription(*type, *sdp, 0));\n        \n        if (desc) {\n          if (socket) {\n            self->_remotesdp.Reset<Object>(desc_obj);\n            socket->SetRemoteDescription(self->_remote.get(), desc);\n            error = 0;\n          } else {\n            error = \"Internal Error\";\n          }\n        }\n      }\n    }\n  }\n\n  if (error) {\n    if (!info[2].IsEmpty() && info[2]->IsFunction()) {\n      Local<Value> argv[1] = {\n        Nan::Error(error)\n      };\n\n      Local<Function> onerror = Local<Function>::Cast(info[2]);\n      onerror->Call(info.This(), 1, argv);\n    } else {\n      Nan::ThrowError(error);\n    }\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::AddIceCandidate(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.This(), \"PeerConnection\");\n  webrtc::PeerConnectionInterface *socket = self->GetSocket();\n  \n  const char *error = 0;\n  Local<Value> argv[1];\n\n  if (!info[0].IsEmpty() && info[0]->IsObject()) {\n    Local<Object> desc = Local<Object>::Cast(info[0]);\n    Local<Value> sdpMid_value = desc->Get(Nan::New(\"sdpMid\").ToLocalChecked());\n    Local<Value> sdpMLineIndex_value = desc->Get(Nan::New(\"sdpMLineIndex\").ToLocalChecked());\n    Local<Value> sdp_value = desc->Get(Nan::New(\"candidate\").ToLocalChecked());\n    \n    if (!sdpMid_value.IsEmpty() && sdpMid_value->IsString()) {\n      if (!sdpMLineIndex_value.IsEmpty() && sdpMLineIndex_value->IsInt32()) {\n        if (!sdp_value.IsEmpty() && sdp_value->IsString()) {\n          Local<Int32> sdpMLineIndex(sdpMLineIndex_value->ToInt32());\n          String::Utf8Value sdpMid(sdpMid_value->ToString());\n          String::Utf8Value sdp(sdp_value->ToString());\n          \n          rtc::scoped_ptr<webrtc::IceCandidateInterface> candidate(webrtc::CreateIceCandidate(*sdpMid, sdpMLineIndex->Value(), *sdp, 0));\n  \n          if (candidate.get()) {\n            if (socket) {\n              if (socket->AddIceCandidate(candidate.get())) {\n                if (!info[1].IsEmpty() && info[1]->IsFunction()) {\n                  Local<Function> success = Local<Function>::Cast(info[1]);\n                  success->Call(info.This(), 0, argv);\n                }\n              } else {            \n                error = \"Failed to add ICECandidate\";\n              }\n            } else {\n              error = \"Internal Error\";\n            }\n          } else {\n            error = \"Invalid ICECandidate\";\n          }\n        } else {\n          error = \"Invalid candidate\";\n        }\n      } else {\n        error = \"Invalid sdpMLineIndex\";\n      }\n    } else {\n      error = \"Invalid sdpMid\";\n    }\n  }\n  \n  if (error) {\n    if (!info[2].IsEmpty() && info[2]->IsFunction()) {\n      argv[0] = Nan::Error(error);\n      \n      Local<Function> onerror = Local<Function>::Cast(info[2]);\n      onerror->Call(info.This(), 1, argv);\n    } else {\n      Nan::ThrowError(error);\n    }\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::CreateDataChannel(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.This(), \"PeerConnection\");\n  webrtc::PeerConnectionInterface *socket = self->GetSocket();\n\n  std::string label;\n  webrtc::DataChannelInit config;\n  \n  if (!info[0].IsEmpty() && info[0]->IsString()) {\n    String::Utf8Value label_utf8(info[0]->ToString());\n    label = *label_utf8;\n  }\n  \n  if (!info[1].IsEmpty() && info[1]->IsObject()) {\n    Local<Object> config_obj = Local<Object>::Cast(info[0]);\n    \n    Local<Value> reliable_value = config_obj->Get(Nan::New(\"reliable\").ToLocalChecked());\n    Local<Value> ordered_value = config_obj->Get(Nan::New(\"ordered\").ToLocalChecked());\n    Local<Value> maxRetransmitTime_value = config_obj->Get(Nan::New(\"maxRetransmitTime\").ToLocalChecked());\n    Local<Value> maxRetransmits_value = config_obj->Get(Nan::New(\"maxRetransmits\").ToLocalChecked());\n    Local<Value> protocol_value = config_obj->Get(Nan::New(\"protocol\").ToLocalChecked());\n    Local<Value> id_value = config_obj->Get(Nan::New(\"id\").ToLocalChecked());\n\n    if (!reliable_value.IsEmpty()) {\n      if (reliable_value->IsTrue()) {\n        config.reliable = true;\n      } else {\n        config.reliable = false;\n      }\n    }\n    \n    if (!ordered_value.IsEmpty()) {\n      if (ordered_value->IsTrue()) {\n        config.ordered = true;\n      } else {\n        config.ordered = false;\n      }\n    }\n    \n    if (!maxRetransmitTime_value.IsEmpty() && maxRetransmitTime_value->IsInt32()) {\n      Local<Int32> maxRetransmitTime(maxRetransmitTime_value->ToInt32());\n      config.maxRetransmitTime = maxRetransmitTime->Value();\n    }\n    \n    if (!maxRetransmits_value.IsEmpty() && maxRetransmits_value->IsInt32()) {\n      Local<Int32> maxRetransmits(maxRetransmits_value->ToInt32());\n      config.maxRetransmits = maxRetransmits->Value();\n    }\n    \n    if (!protocol_value.IsEmpty() && protocol_value->IsString()) {\n      String::Utf8Value protocol(protocol_value->ToString());\n      config.protocol = *protocol;\n    }\n    \n    if (!id_value.IsEmpty() && id_value->IsInt32()) {\n      Local<Int32> id(id_value->ToInt32());\n      config.id = id->Value();\n    }\n  }\n  \n  if (socket) {\n    rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel = socket->CreateDataChannel(label, &config);\n    \n    if (dataChannel.get()) {\n      return info.GetReturnValue().Set(DataChannel::New(dataChannel));\n    }\n  }\n  \n  Nan::ThrowError(\"Internal Error\");\n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::AddStream(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.This(), \"PeerConnection\");\n  rtc::scoped_refptr<webrtc::MediaStreamInterface> mediaStream = MediaStream::Unwrap(info[0]);\n\n  if (mediaStream.get()) {\n    webrtc::PeerConnectionInterface *socket = self->GetSocket();\n\n    if (socket) {\n      if (!socket->AddStream(mediaStream)) {\n        Nan::ThrowError(\"AddStream Failed\");\n      }\n    } else {\n      Nan::ThrowError(\"Internal Error\");\n    }\n  } else {\n    Nan::ThrowError(\"Invalid MediaStream Object\");\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::RemoveStream(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.This(), \"PeerConnection\");\n  rtc::scoped_refptr<webrtc::MediaStreamInterface> mediaStream = MediaStream::Unwrap(info[0]);\n\n  if (mediaStream.get()) {\n    webrtc::PeerConnectionInterface *socket = self->GetSocket();\n\n    if (socket) {\n      socket->RemoveStream(mediaStream);\n    } else {\n      Nan::ThrowError(\"Internal Error\");\n    }\n  } else {\n    Nan::ThrowError(\"Invalid MediaStream Object\");\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::GetLocalStreams(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.This(), \"PeerConnection\");\n  webrtc::PeerConnectionInterface *socket = self->GetSocket();\n\n  if (socket) {\n    rtc::scoped_refptr<webrtc::StreamCollectionInterface> local = socket->local_streams();\n\n    if (local.get()) {\n      Local<Array> list = Nan::New<Array>();\n      uint32_t index = 0;\n      size_t count;\n\n      for (count = 0; count < local->count(); count++) {\n        list->Set(index, MediaStream::New(local->at(count)));\n      }\n\n      return info.GetReturnValue().Set(list);\n    }\n  }\n    \n  Nan::ThrowError(\"Internal Error\");\n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::GetRemoteStreams(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.This(), \"PeerConnection\");\n  webrtc::PeerConnectionInterface *socket = self->GetSocket();\n\n  if (socket) {\n    rtc::scoped_refptr<webrtc::StreamCollectionInterface> remote = socket->remote_streams();\n\n    if (remote.get()) {\n      Local<Array> list = Nan::New<Array>();\n      uint32_t index = 0;\n      size_t count;\n\n      for (count = 0; count < remote->count(); count++) {\n        list->Set(index, MediaStream::New(remote->at(count)));\n      }\n\n      return info.GetReturnValue().Set(list);\n    }\n  }\n\n  Nan::ThrowError(\"Internal Error\");\n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::GetStreamById(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.This(), \"PeerConnection\");\n  webrtc::PeerConnectionInterface *socket = self->GetSocket();\n\n  if (socket) {\n    if (info.Length() >= 1 && info[0]->IsString()) {\n      v8::String::Utf8Value idValue(info[0]->ToString());\n      std::string id(*idValue);\n\n      rtc::scoped_refptr<webrtc::StreamCollectionInterface> local = socket->local_streams();\n      rtc::scoped_refptr<webrtc::StreamCollectionInterface> remote = socket->remote_streams();\n      rtc::scoped_refptr<webrtc::MediaStreamInterface> stream;\n\n      if (local.get()) {\n        stream = local->find(id);\n      }\n\n      if (remote.get() && !stream.get()) {\n        stream = remote->find(id);\n      }\n\n      if (stream.get()) {\n        return info.GetReturnValue().Set(MediaStream::New(stream));\n      } else {\n        return info.GetReturnValue().Set(Nan::Null());\n      }\n    } else {\n      Nan::ThrowError(\"Invalid Argument\");\n    }\n  }\n\n  Nan::ThrowError(\"Internal Error\");\n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::GetStats(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.This(), \"PeerConnection\");\n  webrtc::PeerConnectionInterface *socket = self->GetSocket();\n\n  if (!info[0].IsEmpty() && info[0]->IsFunction()) {\n    self->_onstats.Reset<Function>(Local<Function>::Cast(info[0]));\n\n    if (socket) {\n      if (!socket->GetStats(self->_stats.get(), 0, webrtc::PeerConnectionInterface::kStatsOutputLevelStandard)) {\n        Local<Function> callback = Nan::New<Function>(self->_onstats);\n        Local<Value> argv[1] = { Nan::Null() };\n\n        callback->Call(info.This(), 1, argv);\n        self->_onstats.Reset();\n      }\n    } else {\n      Nan::ThrowError(\"Internal Error\");\n    }\n  } else {\n    Nan::ThrowError(\"Missing Callback\");\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::Close(const Nan::FunctionCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.This(), \"PeerConnection\"); \n  webrtc::PeerConnectionInterface *socket = self->GetSocket();\n  \n  if (socket) {\n    socket->Close();\n  } else {\n    Nan::ThrowError(\"Internal Error\");\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::GetSignalingState(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n  webrtc::PeerConnectionInterface *socket = self->GetSocket();\n\n  if (socket) {\n    webrtc::PeerConnectionInterface::SignalingState state(socket->signaling_state());\n    \n    switch (state) {\n      case webrtc::PeerConnectionInterface::kStable:\n        return info.GetReturnValue().Set(Nan::New(\"stable\").ToLocalChecked());\n        break;\n      case webrtc::PeerConnectionInterface::kHaveLocalOffer:\n        return info.GetReturnValue().Set(Nan::New(\"have-local-offer\").ToLocalChecked());\n        break;\n      case webrtc::PeerConnectionInterface::kHaveLocalPrAnswer:\n        return info.GetReturnValue().Set(Nan::New(\"have-local-pranswer\").ToLocalChecked());\n        break;\n      case webrtc::PeerConnectionInterface::kHaveRemoteOffer:\n        return info.GetReturnValue().Set(Nan::New(\"have-remote-offer\").ToLocalChecked());\n        break;\n      case webrtc::PeerConnectionInterface::kHaveRemotePrAnswer:\n        return info.GetReturnValue().Set(Nan::New(\"have-remote-pranswer\").ToLocalChecked());\n        break;\n      default: \n        return info.GetReturnValue().Set(Nan::New(\"closed\").ToLocalChecked());\n        break;\n    }\n  } else {\n    Nan::ThrowError(\"Internal Error\");\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::GetIceConnectionState(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n  webrtc::PeerConnectionInterface *socket = self->GetSocket();\n\n  if (socket) {\n    webrtc::PeerConnectionInterface::IceConnectionState state(socket->ice_connection_state());\n\n    switch (state) {\n      case webrtc::PeerConnectionInterface::kIceConnectionNew:\n        return info.GetReturnValue().Set(Nan::New(\"new\").ToLocalChecked());\n        break;\n      case webrtc::PeerConnectionInterface::kIceConnectionChecking:\n        return info.GetReturnValue().Set(Nan::New(\"checking\").ToLocalChecked());\n        break;\n      case webrtc::PeerConnectionInterface::kIceConnectionConnected:\n        return info.GetReturnValue().Set(Nan::New(\"connected\").ToLocalChecked());\n        break;\n      case webrtc::PeerConnectionInterface::kIceConnectionCompleted:\n        return info.GetReturnValue().Set(Nan::New(\"completed\").ToLocalChecked());\n        break;\n      case webrtc::PeerConnectionInterface::kIceConnectionFailed:\n        return info.GetReturnValue().Set(Nan::New(\"failed\").ToLocalChecked());\n        break;\n      case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:\n        return info.GetReturnValue().Set(Nan::New(\"disconnected\").ToLocalChecked());\n        break;\n      default:\n        return info.GetReturnValue().Set(Nan::New(\"closed\").ToLocalChecked());\n        break;\n    }\n  } else {\n    Nan::ThrowError(\"Internal Error\");\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::GetIceGatheringState(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n  webrtc::PeerConnectionInterface *socket = self->GetSocket();\n\n  if (socket) {\n    webrtc::PeerConnectionInterface::IceGatheringState state(socket->ice_gathering_state());\n\n    switch (state) {\n      case webrtc::PeerConnectionInterface::kIceGatheringNew:\n        return info.GetReturnValue().Set(Nan::New(\"new\").ToLocalChecked());\n        break;\n      case webrtc::PeerConnectionInterface::kIceGatheringGathering:\n        return info.GetReturnValue().Set(Nan::New(\"gathering\").ToLocalChecked());\n        break;\n      default:\n        return info.GetReturnValue().Set(Nan::New(\"complete\").ToLocalChecked());\n        break;\n    }   \n  } else {\n    Nan::ThrowError(\"Internal Error\");\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid PeerConnection::GetOnSignalingStateChange(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onsignalingstatechange));\n}\n\nvoid PeerConnection::GetOnIceConnectionStateChange(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_oniceconnectionstatechange));\n}\n\nvoid PeerConnection::GetOnIceCandidate(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onicecandidate));\n}\n\nvoid PeerConnection::GetLocalDescription(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n  return info.GetReturnValue().Set(Nan::New<Object>(self->_localsdp));\n}\n\nvoid PeerConnection::GetRemoteDescription(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n  return info.GetReturnValue().Set(Nan::New<Object>(self->_remotesdp));\n}\n\nvoid PeerConnection::GetOnDataChannel(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_ondatachannel));\n}\n\nvoid PeerConnection::GetOnNegotiationNeeded(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onnegotiationneeded));\n}\n\nvoid PeerConnection::GetOnAddStream(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n\n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onaddstream));\n}\n\nvoid PeerConnection::GetOnRemoveStream(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n  return info.GetReturnValue().Set(Nan::New<Function>(self->_onremovestream));\n}\n\nvoid PeerConnection::ReadOnly(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n}\n\nvoid PeerConnection::SetOnSignalingStateChange(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onsignalingstatechange.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onsignalingstatechange.Reset();\n  }\n}\n\nvoid PeerConnection::SetOnIceConnectionStateChange(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_oniceconnectionstatechange.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_oniceconnectionstatechange.Reset();\n  }\n}\n\nvoid PeerConnection::SetOnIceCandidate(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onicecandidate.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onicecandidate.Reset();\n  }\n}\n\nvoid PeerConnection::SetOnDataChannel(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_ondatachannel.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_ondatachannel.Reset();\n  }\n}\n\nvoid PeerConnection::SetOnNegotiationNeeded(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onnegotiationneeded.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onnegotiationneeded.Reset();\n  }\n}\n\nvoid PeerConnection::SetOnAddStream(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onaddstream.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onaddstream.Reset();\n  }\n}\n\nvoid PeerConnection::SetOnRemoveStream(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<void> &info) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  PeerConnection *self = RTCWrap::Unwrap<PeerConnection>(info.Holder(), \"PeerConnection\");\n\n  if (!value.IsEmpty() && value->IsFunction()) {\n    self->_onremovestream.Reset<Function>(Local<Function>::Cast(value));\n  } else {\n    self->_onremovestream.Reset();\n  }\n}\n\nvoid PeerConnection::On(Event *event) {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  Nan::HandleScope scope;\n  PeerConnectionEvent type = event->Type<PeerConnectionEvent>();\n  Local<Function> callback;\n  Local<Object> container;\n  Local<Value> argv[1];\n  bool isError = false;\n  std::string data;\n  int argc = 0;\n  \n  switch (type) {\n    case kPeerConnectionCreateClosed:\n      EventEmitter::SetReference(false);\n      \n      break;\n    case kPeerConnectionCreateOffer:\n      callback = Nan::New<Function>(_offerCallback);\n      \n      _offerCallback.Reset();\n      _offerErrorCallback.Reset();\n\n      data = event->Unwrap<std::string>();\n      argv[0] = JSON::Parse(Nan::New(data.c_str()).ToLocalChecked());\n      argc = 1;\n      \n      break;\n    case kPeerConnectionCreateOfferError:\n      callback = Nan::New<Function>(_offerErrorCallback);\n      \n      _offerCallback.Reset();\n      _offerErrorCallback.Reset();\n      \n      isError = true;\n      data = event->Unwrap<std::string>();\n      argv[0] = Nan::Error(data.c_str());\n      argc = 1;\n      \n      break;\n    case kPeerConnectionCreateAnswer:\n      callback = Nan::New<Function>(_answerCallback);\n      \n      _answerCallback.Reset();\n      _answerErrorCallback.Reset();\n      \n      data = event->Unwrap<std::string>();\n      argv[0] = JSON::Parse(Nan::New(data.c_str()).ToLocalChecked());\n      argc = 1;\n      \n      break;\n    case kPeerConnectionCreateAnswerError:\n      callback = Nan::New<Function>(_answerErrorCallback);\n      \n      _answerCallback.Reset();\n      _answerErrorCallback.Reset();\n      \n      isError = true;\n      data = event->Unwrap<std::string>();\n      argv[0] = Nan::Error(data.c_str());\n      argc = 1;\n      \n      break;\n    case kPeerConnectionSetLocalDescription:\n      callback = Nan::New<Function>(_localCallback);\n      \n      _localCallback.Reset();\n      _localErrorCallback.Reset();\n      \n      break;\n    case kPeerConnectionSetLocalDescriptionError:\n      callback = Nan::New<Function>(_localErrorCallback);\n      \n      _localCallback.Reset();\n      _localErrorCallback.Reset();\n      _localsdp.Reset();\n      \n      isError = true;\n      data = event->Unwrap<std::string>();\n      argv[0] = Nan::Error(data.c_str());\n      argc = 1;\n      \n      break;\n    case kPeerConnectionSetRemoteDescription:\n      callback = Nan::New<Function>(_remoteCallback);\n      \n      _remoteCallback.Reset();\n      _remoteErrorCallback.Reset();\n      \n      break;\n    case kPeerConnectionSetRemoteDescriptionError:\n      callback = Nan::New<Function>(_remoteErrorCallback);\n      \n      _remoteCallback.Reset();\n      _remoteErrorCallback.Reset();\n      _remotesdp.Reset();\n      \n      isError = true;\n      data = event->Unwrap<std::string>();\n      argv[0] = Nan::Error(data.c_str());\n      argc = 1;\n      \n      break;\n    case kPeerConnectionIceCandidate:\n      callback = Nan::New<Function>(_onicecandidate);\n      container = Nan::New<Object>();\n      \n      data = event->Unwrap<std::string>();\n      \n      if (data.empty()) {\n        container->Set(Nan::New(\"candidate\").ToLocalChecked(), Nan::Null());\n      } else {\n        container->Set(Nan::New(\"candidate\").ToLocalChecked(), JSON::Parse(Nan::New(data.c_str()).ToLocalChecked()));\n      }\n      \n      argv[0] = container;\n      argc = 1;\n      \n      break;\n    case kPeerConnectionSignalChange:\n      callback = Nan::New<Function>(_onsignalingstatechange);\n      \n      break;\n    case kPeerConnectionIceChange:\n      callback = Nan::New<Function>(_oniceconnectionstatechange);\n      \n      break;\n    case kPeerConnectionIceGathering:\n      \n      break;\n    case kPeerConnectionDataChannel:\n      callback = Nan::New<Function>(_ondatachannel);\n      \n      container = Nan::New<Object>();\n      container->Set(Nan::New(\"channel\").ToLocalChecked(), DataChannel::New(event->Unwrap<rtc::scoped_refptr<webrtc::DataChannelInterface> >()));\n\n      argv[0] = container;\n      argc = 1;\n      \n      break;\n    case kPeerConnectionAddStream:\n      callback = Nan::New<Function>(_onaddstream);\n\n      container = Nan::New<Object>();\n      container->Set(Nan::New(\"stream\").ToLocalChecked(), MediaStream::New(event->Unwrap<rtc::scoped_refptr<webrtc::MediaStreamInterface> >()));\n      \n      argv[0] = container;\n      argc = 1;\n\n      break;\n    case kPeerConnectionRemoveStream:\n      callback = Nan::New<Function>(_onremovestream);\n      \n      container = Nan::New<Object>();\n      container->Set(Nan::New(\"stream\").ToLocalChecked(), MediaStream::New(event->Unwrap<rtc::scoped_refptr<webrtc::MediaStreamInterface> >()));\n      \n      argv[0] = container;\n      argc = 1;\n\n      break;\n    case kPeerConnectionRenegotiation:\n      callback = Nan::New<Function>(_onnegotiationneeded);\n      \n      break;\n    case kPeerConnectionStats:\n      callback = Nan::New<Function>(_onstats);\n\n      argv[0] = RTCStatsResponse::New(event->Unwrap<webrtc::StatsReports>());\n      argc = 1;\n\n      break;\n  }\n  \n  if (!callback.IsEmpty() && callback->IsFunction()) {\n    callback->Call(RTCWrap::This(), argc, argv);\n  } else if (isError) {\n    Nan::ThrowError(argv[0]);\n  }\n}\n\nbool PeerConnection::IsStable() {\n  webrtc::PeerConnectionInterface *socket = PeerConnection::GetSocket();\n\n  if (socket) {\n    webrtc::PeerConnectionInterface::SignalingState state(socket->signaling_state());\n    \n    if (state == webrtc::PeerConnectionInterface::kStable) {\n      return true;\n    }\n  }\n  \n  return false;\n}\n\n"
  },
  {
    "path": "src/PeerConnection.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef WEBRTC_PEERCONNECTION_H\n#define WEBRTC_PEERCONNECTION_H\n\n#include \"Common.h\"\n#include \"Observers.h\" \n#include \"EventEmitter.h\"\n#include \"MediaConstraints.h\"\n#include \"Wrap.h\"\n\nnamespace WebRTC {\n  enum PeerConnectionEvent {\n    kPeerConnectionCreateClosed = 1,\n    kPeerConnectionCreateOffer,\n    kPeerConnectionCreateOfferError,\n    kPeerConnectionCreateAnswer,\n    kPeerConnectionCreateAnswerError,\n    kPeerConnectionSetLocalDescription,\n    kPeerConnectionSetLocalDescriptionError,\n    kPeerConnectionSetRemoteDescription,\n    kPeerConnectionSetRemoteDescriptionError,\n    kPeerConnectionIceCandidate,\n    kPeerConnectionSignalChange,\n    kPeerConnectionIceChange,\n    kPeerConnectionIceGathering,\n    kPeerConnectionDataChannel,\n    kPeerConnectionAddStream,\n    kPeerConnectionRemoveStream,\n    kPeerConnectionRenegotiation,\n    kPeerConnectionStats\n  };  \n  \n  class PeerConnection : public RTCWrap, public EventEmitter {\n   public:\n    static void Init(v8::Handle<v8::Object> exports);\n    \n   private:\n    PeerConnection(const v8::Local<v8::Object> &configuration,\n                   const v8::Local<v8::Object> &constraints);\n                      \n    ~PeerConnection() final;\n   \n    static void New(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void CreateOffer(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void CreateAnswer(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void SetLocalDescription(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void SetRemoteDescription(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void AddIceCandidate(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void CreateDataChannel(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void AddStream(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void RemoveStream(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void GetLocalStreams(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void GetRemoteStreams(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void GetStreamById(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void GetStats(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void Close(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    \n    static void GetSignalingState(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetIceConnectionState(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetIceGatheringState(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnSignalingStateChange(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnIceConnectionStateChange(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnIceCandidate(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnDataChannel(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnNegotiationNeeded(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnAddStream(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetOnRemoveStream(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetLocalDescription(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void GetRemoteDescription(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    \n    static void ReadOnly(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnSignalingStateChange(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnIceConnectionStateChange(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnIceCandidate(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnDataChannel(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnNegotiationNeeded(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnAddStream(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n    static void SetOnRemoveStream(v8::Local<v8::String> property, v8::Local<v8::Value> value, const Nan::PropertyCallbackInfo<void> &info);\n\n    void On(Event *event) final;\n    \n    bool IsStable();\n    \n    webrtc::PeerConnectionInterface *GetSocket();\n    \n   protected:\n    Nan::Persistent<v8::Function> _onsignalingstatechange;\n    Nan::Persistent<v8::Function> _oniceconnectionstatechange;\n    Nan::Persistent<v8::Function> _onicecandidate;\n    Nan::Persistent<v8::Function> _ondatachannel;\n    Nan::Persistent<v8::Function> _onnegotiationneeded;\n    Nan::Persistent<v8::Function> _onaddstream;\n    Nan::Persistent<v8::Function> _onremovestream;\n    \n    Nan::Persistent<v8::Function> _offerCallback;\n    Nan::Persistent<v8::Function> _offerErrorCallback;\n    \n    Nan::Persistent<v8::Function> _answerCallback;\n    Nan::Persistent<v8::Function> _answerErrorCallback;\n    \n    Nan::Persistent<v8::Function> _localCallback;\n    Nan::Persistent<v8::Function> _localErrorCallback;\n    \n    Nan::Persistent<v8::Function> _remoteCallback;\n    Nan::Persistent<v8::Function> _remoteErrorCallback;\n\n    Nan::Persistent<v8::Function> _onstats;\n    \n    Nan::Persistent<v8::Object> _localsdp;\n    Nan::Persistent<v8::Object> _remotesdp;\n    \n    static Nan::Persistent<v8::Function> constructor;\n    \n    rtc::scoped_refptr<StatsObserver> _stats;\n    rtc::scoped_refptr<OfferObserver> _offer;\n    rtc::scoped_refptr<AnswerObserver> _answer;\n    rtc::scoped_refptr<LocalDescriptionObserver> _local;\n    rtc::scoped_refptr<RemoteDescriptionObserver> _remote;\n    rtc::scoped_refptr<PeerConnectionObserver> _peer;\n    rtc::scoped_refptr<webrtc::PeerConnectionInterface> _socket;\n    rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> _factory;\n    \n    rtc::scoped_refptr<MediaConstraints> _constraints;\n    webrtc::PeerConnectionInterface::RTCConfiguration _config;\n  };\n};\n\n#endif"
  },
  {
    "path": "src/Platform.cc",
    "content": "\n/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#include \"Platform.h\"\n\n#if defined(WEBRTC_WIN)\n#include <webrtc/base/win32socketinit.h>\n#include <webrtc/base/win32socketserver.h>\n#endif\n\nusing namespace WebRTC;\n\n#ifndef WEBRTC_THREAD_COUNT\n#define WEBRTC_THREAD_COUNT 4\n#endif\n\nrtc::Thread signal_thread;\nrtc::Thread worker_thread[WEBRTC_THREAD_COUNT];\nuint32_t counter = 0;\n\nvoid Platform::Init() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n#if defined(WEBRTC_WIN)\n  rtc::EnsureWinsockInit();\n#endif\n  \n  rtc::InitializeSSL();\n   \n  signal_thread.Start();\n  \n  rtc::ThreadManager::Instance()->SetCurrentThread(&signal_thread);\n  \n  if (rtc::ThreadManager::Instance()->CurrentThread() != &signal_thread) {\n    Nan::ThrowError(\"Internal Thread Error!\");\n  }\n  \n  for (int index = 0; index < WEBRTC_THREAD_COUNT; index++) {\n    worker_thread[index].Start();\n  }\n}\n\nvoid Platform::Dispose() {\n  LOG(LS_INFO) << __PRETTY_FUNCTION__;\n  \n  signal_thread.SetAllowBlockingCalls(true);\n  signal_thread.Stop();\n  \n  for (int index = 0; index < WEBRTC_THREAD_COUNT; index++) {\n    worker_thread[index].SetAllowBlockingCalls(true);\n    worker_thread[index].Stop();\n  }\n\n  if (rtc::ThreadManager::Instance()->CurrentThread() == &signal_thread) {\n    rtc::ThreadManager::Instance()->SetCurrentThread(NULL);\n  }\n  \n  rtc::CleanupSSL();\n}\n\nrtc::Thread *Platform::GetWorker() {\n  return &worker_thread[(counter++) % WEBRTC_THREAD_COUNT];\n}"
  },
  {
    "path": "src/Platform.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef WEBRTC_PLATFORM_H\n#define WEBRTC_PLATFORM_H\n\n#include \"Common.h\"\n\nnamespace WebRTC {\n  class Platform {\n\t  public:\n\t    static void Init();\n\t    static void Dispose();\n      static rtc::Thread *GetWorker();\n  };\n};\n\n#endif"
  },
  {
    "path": "src/Stats.cc",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#include \"Stats.h\"\n\nusing namespace v8;\nusing namespace WebRTC;\n\nNan::Persistent<Function> RTCStatsReport::constructor;\n\nRTCStatsReport::~RTCStatsReport() {\n  \n}\n\nvoid RTCStatsReport::Init() {\n  Nan::HandleScope scope;\n  \n  Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(RTCStatsReport::New);\n  tpl->InstanceTemplate()->SetInternalFieldCount(1);\n  tpl->SetClassName(Nan::New(\"RTCStatsReport\").ToLocalChecked());\n\n  tpl->PrototypeTemplate()->Set(Nan::New(\"names\").ToLocalChecked(), Nan::New<FunctionTemplate>(RTCStatsReport::Names)->GetFunction());\n  tpl->PrototypeTemplate()->Set(Nan::New(\"stat\").ToLocalChecked(), Nan::New<FunctionTemplate>(RTCStatsReport::Stat)->GetFunction());\n  \n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"id\").ToLocalChecked(), RTCStatsReport::Id);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"type\").ToLocalChecked(), RTCStatsReport::Type);\n  Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New(\"timestamp\").ToLocalChecked(), RTCStatsReport::Timestamp);\n    \n  constructor.Reset(tpl->GetFunction());\n};\n\nLocal<Value> RTCStatsReport::New(webrtc::StatsReport *report) {  \n  Nan::EscapableHandleScope scope;\n  Local<Function> instance = Nan::New(RTCStatsReport::constructor);\n\n  if (instance.IsEmpty()) {\n    return scope.Escape(Nan::Null());\n  }\n\n  Local<Object> ret = instance->NewInstance();\n  RTCStatsReport *stats = RTCWrap::Unwrap<RTCStatsReport>(ret, \"RTCStatsReport\");\n\n  if (stats) {\n    stats->_report = report;\n  }\n\n  return scope.Escape(ret);\n}\n\nvoid RTCStatsReport::New(const Nan::FunctionCallbackInfo<Value> &info) {\n  if (info.IsConstructCall()) {\n    RTCStatsReport* report = new RTCStatsReport();\n    report->Wrap(info.This(), \"RTCStatsReport\");\n    return info.GetReturnValue().Set(info.This());\n  }\n\n  Nan::ThrowError(\"Internal Error\");\n  info.GetReturnValue().SetUndefined();\n}\n\nvoid RTCStatsReport::Names(const Nan::FunctionCallbackInfo<Value> &info) { \n  RTCStatsReport *stats = RTCWrap::Unwrap<RTCStatsReport>(info.This(), \"RTCStatsReport\");\n  webrtc::StatsReport::Values values = stats->_report->values();\n  Local<Array> list = Nan::New<Array>();\n  unsigned int index = 0;\n  \n  for (webrtc::StatsReport::Values::iterator it = values.begin(); it != values.end(); it++) {\n    webrtc::StatsReport::ValuePtr value = values[it->first];\n    list->Set(index, Nan::New(value->display_name()).ToLocalChecked());\n    index++;\n  }\n  \n  return info.GetReturnValue().Set(list);\n}\n\nvoid RTCStatsReport::Stat(const Nan::FunctionCallbackInfo<Value> &info) {\n  RTCStatsReport *stats = RTCWrap::Unwrap<RTCStatsReport>(info.This(), \"RTCStatsReport\");\n  webrtc::StatsReport::Values values = stats->_report->values();\n\n  if (info.Length() >= 1 && info[0]->IsString()) {\n    String::Utf8Value entry_value(info[0]->ToString());\n    std::string entry(*entry_value);\n    \n    for (webrtc::StatsReport::Values::iterator it = values.begin(); it != values.end(); it++) {\n      webrtc::StatsReport::ValuePtr value = values[it->first];\n\n      if (!entry.compare(value->display_name())) {\n        switch (value->type()) {\n          case webrtc::StatsReport::Value::kInt:\n            return info.GetReturnValue().Set(Nan::New(value->int_val()));\n            \n            break;\n          case webrtc::StatsReport::Value::kInt64:\n            return info.GetReturnValue().Set(Nan::New(static_cast<int32_t>(value->int64_val())));\n            \n            break;\n          case webrtc::StatsReport::Value::kFloat:\n            return info.GetReturnValue().Set(Nan::New(value->float_val()));\n          \n            break;\n          case webrtc::StatsReport::Value::kString:\n            return info.GetReturnValue().Set(Nan::New(value->string_val().c_str()).ToLocalChecked());\n            \n            break;\n          case webrtc::StatsReport::Value::kStaticString:\n            return info.GetReturnValue().Set(Nan::New(value->static_string_val()).ToLocalChecked());\n            \n            break;\n          case webrtc::StatsReport::Value::kBool:\n            return info.GetReturnValue().Set(Nan::New(value->bool_val()));\n            \n            break;\n          case webrtc::StatsReport::Value::kId:\n            return info.GetReturnValue().Set(Nan::New(value->ToString().c_str()).ToLocalChecked());\n          \n            break;\n        }\n      }\n    }\n  }\n  \n  info.GetReturnValue().SetUndefined();\n}\n\nvoid RTCStatsReport::Id(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  RTCStatsReport *stats = RTCWrap::Unwrap<RTCStatsReport>(info.This(), \"RTCStatsReport\");\n  std::string id(stats->_report->id()->ToString());\n  return info.GetReturnValue().Set(Nan::New(id.c_str()).ToLocalChecked()); \n}\n\nvoid RTCStatsReport::Type(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  RTCStatsReport *stats = RTCWrap::Unwrap<RTCStatsReport>(info.This(), \"RTCStatsReport\");\n  return info.GetReturnValue().Set(Nan::New(stats->_report->TypeToString()).ToLocalChecked());\n}\n\nvoid RTCStatsReport::Timestamp(Local<String> property, const Nan::PropertyCallbackInfo<Value> &info) {\n  RTCStatsReport *stats = RTCWrap::Unwrap<RTCStatsReport>(info.This(), \"RTCStatsReport\");\n  return info.GetReturnValue().Set(Nan::New(stats->_report->timestamp()));\n}\n\nNan::Persistent<Function> RTCStatsResponse::constructor;\n\nRTCStatsResponse::~RTCStatsResponse() {\n  \n}\n\nvoid RTCStatsResponse::Init() {\n  Nan::HandleScope scope;\n\n  Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(RTCStatsResponse::New);\n  tpl->InstanceTemplate()->SetInternalFieldCount(1);\n  tpl->SetClassName(Nan::New(\"RTCStatsResponse\").ToLocalChecked());\n\n  tpl->PrototypeTemplate()->Set(Nan::New(\"result\").ToLocalChecked(), Nan::New<FunctionTemplate>(RTCStatsResponse::Result)->GetFunction());\n                                \n  constructor.Reset(tpl->GetFunction());\n}\n\nvoid RTCStatsResponse::New(const Nan::FunctionCallbackInfo<Value> &info) {\n  if (info.IsConstructCall()) {\n    RTCStatsResponse *response = new RTCStatsResponse();\n    response->Wrap(info.This(), \"RTCStatsResponse\");\n    return info.GetReturnValue().Set(info.This());\n  }\n\n  Nan::ThrowError(\"Internal Error\");\n  info.GetReturnValue().SetUndefined();\n}\n\nLocal<Value> RTCStatsResponse::New(const webrtc::StatsReports &reports) {  \n  Nan::EscapableHandleScope scope;\n  Local<Function> instance = Nan::New(RTCStatsResponse::constructor);\n\n  if (instance.IsEmpty()) {\n    return scope.Escape(Nan::Null());\n  }\n\n  Local<Object> ret = instance->NewInstance();\n  RTCStatsResponse *response = RTCWrap::Unwrap<RTCStatsResponse>(ret, \"RTCStatsResponse\");\n\n  response->_reports = reports;\n\n  return scope.Escape(ret);\n}\n\nvoid RTCStatsResponse::Result(const Nan::FunctionCallbackInfo<Value> &info) {\n  RTCStatsResponse *response = RTCWrap::Unwrap<RTCStatsResponse>(info.This(), \"RTCStatsResponse\");\n  Local<Array> list = Nan::New<Array>(response->_reports.size());\n \n  for(unsigned int index = 0; index < response->_reports.size(); index++) {\n    list->Set(index, RTCStatsReport::New(const_cast<webrtc::StatsReport*>(response->_reports.at(index))));\n  }\n\n  return info.GetReturnValue().Set(list);\n}\n"
  },
  {
    "path": "src/Stats.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef WEBRTC_STATS_H\n#define WEBRTC_STATS_H\n\n#include \"Common.h\"\n#include \"Observers.h\" \n#include \"EventEmitter.h\"\n#include \"Wrap.h\"\n\nnamespace WebRTC {\n  class RTCStatsReport : public RTCWrap {\n   public:\n    static void Init();\n    static v8::Local<v8::Value> New(webrtc::StatsReport *report);\n    \n   private:\n    ~RTCStatsReport() final;\n    \n    static void New(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void Names(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void Stat(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    \n    static void Id(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void Type(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    static void Timestamp(v8::Local<v8::String> property, const Nan::PropertyCallbackInfo<v8::Value> &info);\n    \n   protected:\n    static Nan::Persistent<v8::Function> constructor;\n    webrtc::StatsReport* _report;\n  };\n  \n  class RTCStatsResponse : public RTCWrap {\n   public:\n    static void Init();\n    static v8::Local<v8::Value> New(const webrtc::StatsReports &reports);\n    \n   private:\n    ~RTCStatsResponse() final;\n   \n    static void New(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    static void Result(const Nan::FunctionCallbackInfo<v8::Value> &info);\n    \n   protected:\n    static Nan::Persistent<v8::Function> constructor;\n    webrtc::StatsReports _reports;\n  };\n};\n\n#endif\n"
  },
  {
    "path": "src/Wrap.h",
    "content": "/*\n* The MIT License (MIT)\n*\n* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n* THE SOFTWARE.\n*\n*/\n\n#ifndef WEBRTC_WRAP_H\n#define WEBRTC_WRAP_H\n\n#include \"Common.h\"\n\nnamespace WebRTC {\n  class RTCWrap : public node::ObjectWrap {\n    public:\n      inline void Wrap(v8::Local<v8::Object> obj, const char *className = \"RTCWrap\") {\n        LOG(LS_INFO) << __PRETTY_FUNCTION__;\n        \n        _className = className;\n        node::ObjectWrap::Wrap(obj);\n      }\n      \n      inline v8::Local<v8::Object> This() {\n        LOG(LS_INFO) << __PRETTY_FUNCTION__;\n        \n#if (NODE_MODULE_VERSION < NODE_0_12_MODULE_VERSION)\n        Nan::EscapableHandleScope scope;\n        return scope.Escape(Nan::New<v8::Object>(node::ObjectWrap::handle_));\n#else\n        return node::ObjectWrap::handle();\n#endif\n      }\n      \n      template<class T> inline T* Unwrap() {\n        LOG(LS_INFO) << __PRETTY_FUNCTION__;\n        \n        return static_cast<T*>(this);\n      }\n      \n      template<class T> inline static T* Unwrap(v8::Local<v8::Object> obj, const char *className = \"RTCWrap\") {\n        LOG(LS_INFO) << __PRETTY_FUNCTION__;\n        \n        RTCWrap *wrap = node::ObjectWrap::Unwrap<RTCWrap>(obj);\n\n        if (wrap) {\n          if (!wrap->_className.compare(className)) {\n            return wrap->Unwrap<T>();\n          }\n        }\n        \n        return 0;\n      }\n    \n    protected:\n      std::string _className;   \n  };\n};\n\n#endif"
  },
  {
    "path": "src/addon.gypi",
    "content": "{\n  'target_defaults': {\n    'type': 'loadable_module',\n    'product_prefix': '',\n    'product_extension': 'node',\n    'include_dirs': [\n      '<(node_root_dir)/include/node',\n      '<(node_root_dir)/src',\n      '<(node_root_dir)/deps/uv/include',\n      '<(node_root_dir)/deps/v8/include'\n    ],\n    'defines': [\n      'BUILDING_NODE_EXTENSION',\n      'NODE_GYP_MODULE_NAME=>(_target_name)'\n    ],\n    'conditions': [\n      [ 'OS==\"mac\"', {\n        'defines': [ \n          '_DARWIN_USE_64_BIT_INODE=1' \n        ],\n        'libraries': [\n          '-undefined dynamic_lookup'\n        ],\n        'xcode_settings': {\n          'DYLIB_INSTALL_NAME_BASE': '@rpath'\n        },\n      }],\n      [ 'OS==\"win\"', {\n        'libraries': [\n          '-lkernel32.lib',\n          '-luser32.lib',\n          '-lgdi32.lib',\n          '-lwinspool.lib',\n          '-lcomdlg32.lib',\n          '-ladvapi32.lib',\n          '-lshell32.lib',\n          '-lole32.lib',\n          '-loleaut32.lib',\n          '-luuid.lib',\n          '-lodbc32.lib',\n          '-lDelayImp.lib',\n          '-l\"<(node_root_dir)\\\\<(ConfigurationName)\\\\<(node_lib_file)\"'\n        ],\n        'msvs_disabled_warnings': [ \n          4251 \n        ],\n      }, {\n        'defines': [\n          '_LARGEFILE_SOURCE',\n          '_FILE_OFFSET_BITS=64',\n        ],\n      }],\n      [ 'OS==\"freebsd\" or OS==\"openbsd\" or OS==\"solaris\" or (OS==\"linux\" and target_arch!=\"ia32\")', {\n        'cflags': [ \n          '-fPIC'\n        ],\n      }]\n    ]\n  }\n}"
  },
  {
    "path": "src/webrtc.gyp",
    "content": "{\n  'includes': [\n    '../third_party/webrtc/src/talk/build/common.gypi',\n    '../third_party/webrtc/src/webrtc/build/common.gypi',\n    '../build/config.gypi',\n    '../nodejs.gypi',\n    'addon.gypi',\n  ],\n  'targets': [\n    {\n      'target_name': 'webrtc',\n      'sources': [\n        'Platform.cc',\n        'Global.cc',\n        'BackTrace.cc',\n        'EventEmitter.cc',\n        'Observers.cc',\n        'Module.cc',\n        'PeerConnection.cc',\n        'DataChannel.cc',\n        'GetSources.cc',\n        'GetUserMedia.cc',\n        'MediaStream.cc',\n        'MediaStreamTrack.cc',\n        'MediaConstraints.cc',\n        'Stats.cc',\n      ],\n      'dependencies': [\n        '<(webrtc_root)/webrtc.gyp:webrtc_all',\n      ],\n      'include_dirs': [\n        '<(DEPTH)/third_party/jsoncpp/source/include',\n        '<(DEPTH)/third_party/libsrtp/srtp',\n        '<(DEPTH)/third_party/libyuv/include',\n        \"<!(node -e \\\"require('nan')\\\")\",\n      ],\n      'conditions': [\n        ['OS==\"linux\"', {\n          'cflags': [\n            '-Wno-deprecated-declarations',\n            '-Wno-unused-variable',\n            '-Wno-unknown-pragmas',\n            '-Wno-unused-result',\n          ],\n          'cflags_cc': [\n            '-Wno-non-virtual-dtor',\n            '-Wno-delete-non-virtual-dtor',\n            '-Wno-overloaded-virtual',\n          ],\n          'ldflags': [\n            '-Wl,--unresolved-symbols=ignore-in-object-files',\n          ],\n          'defines': [\n            'USE_BACKTRACE',\n          ],\n        }],\n        ['OS==\"win\"', {\n          'msvs_disabled_warnings': [\n            4267,\n            4005,\n            4201,\n            4506,\n          ],\n        }],\n        ['OS==\"mac\"', {\n          'xcode_settings': {\n            'OTHER_CFLAGS': [\n              '-Wno-nonnull',\n              '-Wno-deprecated-declarations',\n              '-Wno-newline-eof',\n              '-Wno-unknown-pragmas',\n              '-Wno-unused-result',\n            ],\n          },\n          'defines': [\n            'USE_BACKTRACE',\n          ],\n        }],\n      ],\n    },\n    {\n      'target_name': 'All',\n      'type': 'none',\n      'dependencies': [\n        'webrtc',\n      ],\n    },\n  ],\n}\n"
  },
  {
    "path": "test/all.js",
    "content": "require('./multiconnect');\nrequire('./bwtest').tape();\n"
  },
  {
    "path": "test/bwtest.js",
    "content": "'use strict';\n\nvar wrtc = require('..');\nvar tape = require('tape');\nvar args = require('minimist')(process.argv.slice(2));\nvar SimplePeer = require('simple-peer');\n\n\nmodule.exports = bwtest;\nbwtest.tape = bwtape;\n\n\nif (require.main === module) {\n    main();\n}\n\n\n/**\n * called when running this script directly from cli\n */\nfunction main() {\n    if (typeof(args.iceConfig) === 'string') {\n        // parse json of iceConfig to allow running like this:\n        // node test/bwtest --iceConfig '{\"ordered\": false}'\n        args.iceConfig = JSON.parse(args.iceConfig);\n    }\n    console.log('bwtest args:', args);\n    bwtest(args);\n}\n\n\n/**\n * setup tape tests for bwtest\n */\nfunction bwtape() {\n    tape('bwtest default', function(t) {\n        t.plan(1);\n        bwtest({\n            packetCount: 500,\n        }, function(err) {\n            t.error(err, 'bwtest check for error');\n        });\n    });\n\n    tape('bwtest no buffering', function(t) {\n        t.plan(1);\n        bwtest({\n            packetCount: 500,\n            congestHighThreshold: 0,\n            congestLowThreshold: 0\n        }, function(err) {\n            t.error(err, 'bwtest check for error');\n        });\n    });\n\n    tape('bwtest unordered and unreliable', function(t) {\n        t.plan(1);\n        bwtest({\n            packetCount: 500,\n            iceConfig: {\n                ordered: false,\n                maxRetransmits: 5\n            }\n        }, function(err) {\n            t.error(err, 'bwtest check for error');\n        });\n    });\n}\n\n\n\n/**\n *\n * BWTEST\n *\n * run a webrtc bandwidth test with two peers running in this process.\n *\n * @param options (optional) - see defaults inside for list of options.\n * @param callback function(err) called on success/failure.\n *\n */\nfunction bwtest(options, callback) {\n\n    // options is optional\n    if (typeof(options) === 'function') {\n        callback = options;\n        options = null;\n    }\n\n    // defaults\n    callback = callback || function() {};\n    options = options || {};\n    options.packetCount = options.packetCount || 5000;\n    options.packetSize = options.packetSize || 16 * 1024;\n    options.bufferedDelayMs = options.bufferedDelayMs || 5;\n    options.congestHighThreshold = options.congestHighThreshold || 1024 * 1024;\n    options.congestLowThreshold = options.congestLowThreshold || 256 * 1024;\n    options.iceConfig = options.iceConfig || defaultIceConfig();\n\n    var n = 0;\n    var congested = 0;\n    var stats = {\n        startTime: 0,\n        count: 0,\n        bytes: 0,\n        congestCount: 0,\n        congestTime: 0\n    };\n\n    // setup two peers with simple-peer\n    var peer1 = new SimplePeer({\n        wrtc: wrtc\n    });\n    var peer2 = new SimplePeer({\n        wrtc: wrtc,\n        initiator: true,\n        config: options.iceConfig\n    });\n\n    // when peer1 has signaling data, give it to peer2, and vice versa\n    peer1.on('signal', peer2.signal.bind(peer2));\n    peer2.on('signal', peer1.signal.bind(peer1));\n\n    // wait for 'connect' event before using the data channel\n    peer1.on('error', failure);\n    peer2.on('error', failure);\n    peer1.on('connect', start);\n    peer2.on('data', receive);\n\n\n\n    // functions //\n\n    /**\n     * start the test once peers are connected\n     */\n    function start() {\n        stats.startTime = Date.now();\n        send();\n    }\n\n\n    /**\n     * send next packet and recurse\n     */\n    function send() {\n        if (n >= options.packetCount) {\n            console.log('SEND DONE!', info());\n            return;\n        }\n        if (n % 100 === 0) {\n            console.log('SENDING:', info());\n        }\n        if (congestion()) {\n            setTimeout(send, options.bufferedDelayMs);\n            return;\n        }\n        // TODO allocating new buffer per send as workaround to repeated Externalize()\n        // after fixing the issues around that we can move back to higher scope.\n        var buffer = new ArrayBuffer(options.packetSize);\n        peer1.send(buffer);\n        n += 1;\n        if (global.setImmediate) {\n            global.setImmediate(send);\n        } else {\n            setTimeout(send, 0);\n        }\n    }\n\n\n    /**\n     * callback for the receiver to update stats and finish the test\n     */\n    function receive(data) {\n        stats.count += 1;\n        stats.bytes += data.length;\n        if (stats.count >= options.packetCount) {\n            console.log('RECEIVE DONE!', info());\n            // closing the channels so the process can exit\n            peer1.destroy();\n            peer2.destroy();\n            callback();\n        }\n    }\n\n\n    /**\n     * failure handler\n     */\n    function failure(err) {\n\n        // make sure to call the callback with error, even if anything here will throw\n        setTimeout(callback.bind(null, err), 0);\n\n        console.error('ERROR!', info(), err.stack || err);\n        // closing the channels so the process can exit\n        peer1.destroy();\n        peer2.destroy();\n    }\n\n\n    /**\n     * handle channel congestion using bufferedAmount\n     */\n    function congestion() {\n        var bufferedAmount = peer1._channel && peer1._channel.bufferedAmount || 0;\n        if ((bufferedAmount > options.congestHighThreshold) ||\n            (congested && bufferedAmount > options.congestLowThreshold)) {\n            if (!congested) {\n                congested = Date.now();\n            }\n            stats.congestCount += 1;\n        } else {\n            if (congested) {\n                stats.congestTime += Date.now() - congested;\n            }\n            congested = 0;\n        }\n        return congested;\n    }\n\n\n\n    /**\n     * return information string on the test progress\n     */\n    function info() {\n        var now = Date.now();\n        if (congested) {\n            stats.congestTime += Date.now() - congested;\n            congested = now;\n        }\n        var took = (now - stats.startTime) / 1000;\n        var bufferedAmount = peer1._channel && peer1._channel.bufferedAmount;\n        return 'sent ' + n + ' received ' + stats.count + '. ' +\n            'congestion #' + stats.congestCount + ' ' +\n            (stats.congestTime / 1024).toFixed(3) + ' seconds. ' +\n            (bufferedAmount ? 'bufferedAmount ' + bufferedAmount + '. ' : '') +\n            'took ' + took.toFixed(3) + ' seconds. ' +\n            'bandwidth ' + (stats.bytes / took / 1024).toFixed(0) + ' KB/s. ';\n    }\n\n\n    /**\n     * default ice config is just here for documenting the options - see inside.\n     */\n    function defaultIceConfig() {\n        return {\n            /*\n             * data channels are ordered by default - using unordered channel improves\n             * performance but will likely require ordering in another app layer\n             */\n            // ordered: false,\n\n            /*\n             * data channels are reliable by default - using either maxRetransmits\n             * or maxPacketLifeTime will change to unreliable mode\n             */\n            // maxRetransmits: 5,\n            // maxPacketLifeTime: 3000,\n\n            /*\n             * iceServers with stun urls. not needed for this in-process test.\n             */\n            // iceServers: [{url: 'stun:23.21.150.121'}],\n        };\n    }\n}\n"
  },
  {
    "path": "test/core.js",
    "content": "var WebRTC = require('../');\n\nconsole.log('WebRTC Module Loaded!');\n\n//WebRTC.setDebug(true);"
  },
  {
    "path": "test/dataChannel.js",
    "content": "var WebRTC = require('../');\n\n//WebRTC.setDebug(true);\n\nfunction P2P(alice, bob) {\n  alice.onicecandidate = function(event) {\n    var candidate = event.candidate;\n    \n    if (candidate) {\n      bob.addIceCandidate(candidate);\n    }\n  };\n\n  bob.onicecandidate = function(event) {\n    var candidate = event.candidate;\n    \n    if (candidate) {\n      alice.addIceCandidate(candidate);\n    }\n  };\n\n  alice.onnegotiationneeded = function() {      \n    alice.createOffer(function(sdp) {        \n      alice.setLocalDescription(sdp, function() {\n        bob.setRemoteDescription(sdp, function() { \n          bob.createAnswer(function(sdp) {\n            bob.setLocalDescription(sdp, function() {\n              alice.setRemoteDescription(sdp, function() {\n                console.log(\"Alice -> Bob: Connected!\");\n              });\n            });\n          });\n        });  \n      });\n    });\n  };\n\n  bob.onnegotiationneeded = function() {\n    bob.createOffer(function(sdp) {\n      bob.setLocalDescription(sdp, function() {          \n        alice.setRemoteDescription(sdp, function() {            \n          alice.createAnswer(function(sdp) {              \n            alice.setLocalDescription(sdp, function() {                \n              bob.setRemoteDescription(sdp, function() {\n                console.log(\"Bob -> Alice: Connected!\");\n              });\n            });\n          });\n        });  \n      });\n    });\n  };\n\n  alice.onaddstream = function(stream) {\n    if (stream) {\n      console.log('Alice got mediaStream');\n    }\n  };\n\n  bob.onaddstream = function(stream) {\n    if (stream) {\n      console.log('Bob got mediaStream');\n    }\n  };\n  \n  alice.ondatachannel = function(event, callback) {\n    var channel = event ? event.channel || event : null;\n\n    if (!channel) {\n      return false;\n    }\n    \n    console.log('Alice: Got DataChannel!');\n\n    channel.onopen = function() {\n      console.log('Alice: DataChannel Open!');\n\n      if (callback) {\n        callback(channel);\n      }\n    };\n\n    channel.onmessage = function(event) {\n      var data = event.data;\n      console.log('Alice:', data);\n    };\n\n    channel.onclose = function() {\n      console.log('Alice: DataChannel Closed!');\n    };\n  };\n  \n  bob.ondatachannel = function(event, callback) {\n    var channel = event ? event.channel || event : null;\n\n    if (!channel) {\n      return false;\n    }\n    \n    console.log('Bob: Got DataChannel!');\n    \n    channel.onopen = function() {\n      console.log('Bob: DataChannel Open!');\n\n      if (callback) {\n        callback(channel);\n      }\n    };\n\n    channel.onmessage = function(event) {\n      var data = event.data;\n      console.log('Bob:', data);\n      channel.send('Hello Alice!');\n    };\n\n    channel.onclose = function() {\n      console.log('Bob: DataChannel Closed!');\n    };\n  };  \n}\n\nvar config = {\n  iceServers: [\n    {\n      url: 'stun:stun.l.google.com:19302',\n    },\n  ],\n};\n\nfunction sctpTest() {\n  console.log('Running SCTP DataChannel Test');\n  \n  var sctpDataChannelConfig = {\n    reliable: true,\n    ordered: true,\n  };\n\n  var sctpDataChannelConstraints = {\n    audio: false,\n    video: false,\n    optional: [\n      {\n        RtpDataChannels: false,\n        DtlsSrtpKeyAgreement: true,\n      },\n    ],\n    mandatory: {\n      OfferToReceiveAudio: false,\n      OfferToReceiveVideo: false,\n    },\n  };\n\n  var alice = new WebRTC.RTCPeerConnection(config, sctpDataChannelConstraints);\n  var bob = new WebRTC.RTCPeerConnection(config, sctpDataChannelConstraints);\n\n  P2P(alice, bob);\n\n  alice.ondatachannel(alice.createDataChannel('TestChannel', sctpDataChannelConfig), function(channel) {  \n    channel.send('Hello Bob!');\n\n    setTimeout(function () {\n      channel.close();\n    }, 1000);\n\n    setTimeout(function() {\n      alice.close();\n      bob.close();\n    }, 5000);\n  });\n}\n\nfunction rtpTest() {\n  console.log('Running RTP DataChannel Test');\n  \n  var rtpDataChannelConfig = {\n    reliable: false,\n    ordered: false,\n  };\n\n  var rtpDataChannelConstraints = {\n    audio: false,\n    video: false,\n    optional: [\n      {\n        RtpDataChannels: true,\n        DtlsSrtpKeyAgreement: false,\n      },\n    ],\n    mandatory: {\n      OfferToReceiveAudio: false,\n      OfferToReceiveVideo: false,\n    },\n  };\n\n  var alice = new WebRTC.RTCPeerConnection(config, rtpDataChannelConstraints);\n  var bob = new WebRTC.RTCPeerConnection(config, rtpDataChannelConstraints);\n\n  P2P(alice, bob);\n\n  alice.ondatachannel(alice.createDataChannel('TestChannel', rtpDataChannelConfig), function(channel) {  \n    channel.send('Hello Bob!');\n\n    setTimeout(function () {\n      channel.close();\n    }, 1000);\n\n    setTimeout(function() {\n      alice.close();\n      bob.close();\n      \n      setTimeout(function() {\n        sctpTest();\n      }, 1000);\n    }, 5000);\n  });\n}\n\nrtpTest();\n"
  },
  {
    "path": "test/getSources.js",
    "content": "var WebRTC = require('../');\n\nWebRTC.getSources(function(sources) {\n  console.log(sources);\n});\n"
  },
  {
    "path": "test/getUserMedia.js",
    "content": "var WebRTC = require('../');\n\n//WebRTC.setDebug(true);\n\nfunction dumpTrack(track) {\n  console.log('MediaStreamTrack Enabled:', track.enabled);\n  console.log('MediaStreamTrack Id:', track.id);\n  console.log('MediaStreamTrack Kind:', track.kind);\n  console.log('MediaStreamTrack Label:', track.label);\n  console.log('MediaStreamTrack Muted:', track.muted);\n  console.log('MediaStreamTrack ReadyState:', track.readyState);\n  console.log('MediaStreamTrack Remote:', track.remote);\n}\n\nfunction onSuccess(stream) {\n  if (stream && stream.active) {\n    stream.onaddtrack = function(track) {\n      console.log('Track Added!');\n    };\n\n    stream.onremovetrack = function (track) {\n      console.log('Track Removed!');\n    };\n\n    console.log('MediaStream Active:', stream.active);\n    console.log('MediaStream Ended:', stream.ended);\n    console.log('MediaStream ID:', stream.id);\n\n    var audio_list = stream.getAudioTracks();\n    \n    audio_list.forEach(function (track) {\n      console.log('Audio Track');\n      dumpTrack(track);\n    });\n\n    var video_list = stream.getVideoTracks();\n    \n    video_list.forEach(function (track) {\n      console.log('Video Track');\n      dumpTrack(track);\n    });\n    \n    setTimeout(function() {\n      console.log('Closing...');\n    }, 5000);\n  }\n}\n\nfunction onError(error) {\n  throw error;\n}\n\nWebRTC.getUserMedia({\n  audio: true,\n  video: true,\n}, onSuccess, onError);\n"
  },
  {
    "path": "test/mediaStream.js",
    "content": "var WEBRTC = require('../');\n\nvar config = {\n  iceServers: [\n    {\n      url: 'stun:stun.l.google.com:19302',\n    },\n  ],\n};\n\nvar constraints = {\n  audio: {\n    optional: [\n      {\n        googEchoCancellation: true,\n        googEchoCancellation2: true,\n        googDAEchoCancellation: true,\n        googAutoGainControl: true,\n        googAutoGainControl2: true,\n        googNoiseSuppression: true,\n        googNoiseSuppression2: true,\n        googHighpassFilter: true,\n        googTypingNoiseDetection: true,\n        googAudioMirroring: true,\n      },\n    ],\n  },\n  video: {\n    optional: [\n      {\n        minAspectRatio: 1.333,\n        maxAspectRatio: 1.778,\n        maxWidth: 1920,\n        minWidth: 320,\n        maxHeight: 1080,\n        minHeight: 180,\n        maxFrameRate: 60,\n        minFrameRate: 30,\n      },\n    ],\n  },\n  optional: [\n    {\n      DtlsSrtpKeyAgreement: true,\n    },\n  ],\n  mandatory: {\n    OfferToReceiveAudio: true,\n    OfferToReceiveVideo: true,\n  },\n};\n\nfunction P2P(alice, bob) {\n  function showState() {\n    console.log('Alice State:', alice.signalingState);\n    console.log('Bob State:', bob.signalingState);\n  }\n  \n  alice.onicecandidate = function(event) {\n    var candidate = event.candidate || event;\n    bob.addIceCandidate(candidate);\n  };\n\n  bob.onicecandidate = function(event) {\n    var candidate = event.candidate || event;\n    alice.addIceCandidate(candidate);\n  };\n\n  alice.onnegotiationneeded = function() {\n    showState();\n      \n    alice.createOffer(function(sdp) {\n      showState();\n        \n      alice.setLocalDescription(sdp, function() {\n        showState();\n          \n        bob.setRemoteDescription(sdp, function() { \n          showState();\n            \n          bob.createAnswer(function(sdp) {\n            showState();\n              \n            bob.setLocalDescription(sdp, function() {\n              showState();\n                \n              alice.setRemoteDescription(sdp, function() {\n                showState();\n              });\n            });\n          });\n        });  \n      });\n    });\n  };\n\n  bob.onnegotiationneeded = function() {\n    showState();\n      \n    bob.createOffer(function(sdp) {\n      showState();\n        \n      bob.setLocalDescription(sdp, function() {\n        showState();\n          \n        alice.setRemoteDescription(sdp, function() {\n          showState();\n            \n          alice.createAnswer(function(sdp) {\n            showState();\n              \n            alice.setLocalDescription(sdp, function() {\n              showState();\n                \n              bob.setRemoteDescription(sdp, function() {\n                showState();\n              });\n            });\n          });\n        });  \n      });\n    });\n  };\n\n  alice.onaddstream = function(stream) {\n    if (stream) {\n      console.log('Alice got mediaStream');\n    }\n  };\n\n  bob.onaddstream = function(stream) {\n    if (stream) {\n      console.log('Bob got mediaStream');\n    }\n  };\n}\n\nWEBRTC.setDebug(true);\n\nvar alice = new WEBRTC.RTCPeerConnection(config, constraints);\nvar bob = new WEBRTC.RTCPeerConnection(config, constraints);\n\nP2P(alice, bob);\n\nfunction onSuccess(stream) {\n  if (stream) {\n    console.log('Alice: new mediaStream');\n    alice.addStream(stream);\n\n    setTimeout(function () {\n      alice.close();\n      bob.close();\n    }, 10000);\n  }\n}\n\nfunction onError(error) {\n  throw error;\n}\n\nWEBRTC.getUserMedia(constraints, onSuccess, onError);"
  },
  {
    "path": "test/multiconnect.js",
    "content": "'use strict';\n\nvar tape = require('tape');\nvar SimplePeer = require('simple-peer');\nvar wrtc = require('..');\n\n//wrtc.setDebug(true);\n\ntape('connect once', function(t) {\n    t.plan(1);\n    console.log('###########################\\n');\n    connect(function(err) {\n        t.error(err, 'connect callback');\n    });\n});\n\ntape('connect loop', function(t) {\n    t.plan(1);\n    console.log('###########################\\n');\n    connectLoop(10, function(err) {\n        t.error(err, 'connect callback');\n    });\n});\n\ntape('connect concurrent', function(t) {\n    var n = 10;\n    t.plan(n);\n    console.log('###########################\\n');\n    for (var i = 0; i < n; i += 1) {\n        connect(callback);\n    }\n\n    function callback(err) {\n        t.error(err, 'connect callback');\n    }\n});\n\ntape('connect loop concurrent', function(t) {\n    var n = 10;\n    t.plan(n);\n    console.log('###########################\\n');\n    for (var i = 0; i < n; i += 1) {\n        connectLoop(10, callback);\n    }\n\n    function callback(err) {\n        t.error(err, 'connect callback');\n    }\n});\n\nvar connIdGen = 1;\n\nfunction connect(callback) {\n    var connId = connIdGen;\n    var connName = 'CONNECTION-' + connId;\n    connIdGen += 1;\n    console.log(connName, 'starting');\n\n    // setup two peers with simple-peer\n    var peer1 = new SimplePeer({\n        wrtc: wrtc\n    });\n    var peer2 = new SimplePeer({\n        wrtc: wrtc,\n        initiator: true\n    });\n\n    var timeout = setTimeout(function () {\n      peer1.destroy();\n      peer2.destroy();\n\n      callback(new Error(\"Timeout\"));\n    }, 10000);\n\n    // when peer1 has signaling data, give it to peer2, and vice versa\n    peer1.on('signal', function(data) {\n        //console.log(connName, 'signal peer1 -> peer2:');\n        //console.log(' ', data);\n        peer2.signal(data);\n    });\n    peer2.on('signal', function(data) {\n        //console.log(connName, 'signal peer2 -> peer1:');\n        //console.log(' ', data);\n        peer1.signal(data);\n    });\n\n    peer1.on('error', function(err) {\n        console.log(connName, 'peer1 error', err);\n        callback(err);\n    });\n    \n    peer2.on('error', function(err) {\n        console.log(connName, 'peer2 error', err);\n        callback(err);\n    });\n\n    // wait for 'connect' event\n    peer1.on('connect', function() {\n        //console.log(connName, 'sending message');\n        peer1.send('peers are for kids');\n    });\n\n    peer2.on('data', function() {\n        //console.log(connName, 'completed');\n\n        clearTimeout(timeout);\n\n        peer1.destroy();\n        peer2.destroy();\n        \n        callback();\n    });\n}\n\nfunction connectLoop(count, callback) {\n    if (count <= 0) {\n        console.log('connect loop completed');\n        return callback();\n    } else {\n        console.log('connect loop remain', count);\n        connect(function(err) {\n            if (err) {\n                callback(err);\n            } else {\n                connectLoop(count - 1, callback);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "test/p2p-browser.html",
    "content": "<html>\n<body>\n<script>\nfunction P2P(alice, bob) {\n  alice.onicecandidate = function(event) {\n    var candidate = event.candidate || event;\n    bob.addIceCandidate(candidate);\n  };\n\n  bob.onicecandidate = function(event) {\n    var candidate = event.candidate || event;\n    alice.addIceCandidate(candidate);\n  };\n\n  alice.onnegotiationneeded = function(callback) {      \n    alice.createOffer(function(sdp) {        \n      alice.setLocalDescription(sdp, function() {\n        bob.setRemoteDescription(sdp, function() { \n          bob.createAnswer(function(sdp) {\n            bob.setLocalDescription(sdp, function() {\n              alice.setRemoteDescription(sdp, function() {\n                console.log(\"Alice -> Bob: Connected!\");\n                \n                if (callback) {\n                  callback();\n                }\n              });\n            });\n          });\n        });  \n      });\n    });\n  };\n\n  bob.onnegotiationneeded = function(callback) {\n    bob.createOffer(function(sdp) {\n      bob.setLocalDescription(sdp, function() {          \n        alice.setRemoteDescription(sdp, function() {            \n          alice.createAnswer(function(sdp) {              \n            alice.setLocalDescription(sdp, function() {                \n              bob.setRemoteDescription(sdp, function() {\n                console.log(\"Bob -> Alice: Connected!\");\n                \n                if (callback) {\n                  callback();\n                }\n              });\n            });\n          });\n        });  \n      });\n    });\n  };\n}\n\nvar config = {\n  iceServers: [\n    {\n      url: 'stun:stun.l.google.com:19302',\n    },\n  ],\n};\n\nvar constraints = {\n  optional: [\n    {\n      DtlsSrtpKeyAgreement: true,\n    },\n  ],\n  mandatory: {\n    OfferToReceiveAudio: true,\n    OfferToReceiveVideo: true,\n  },\n};\n\nconsole.log(window);\n\nvar alice = new window.webkitRTCPeerConnection(config, constraints);\nvar bob = new window.webkitRTCPeerConnection(config, constraints);\n\nP2P(alice, bob);\n\nalice.onnegotiationneeded(function() {\n  alice.getStats(function(stats) {\n    console.log(stats);\n    \n    stats.result().forEach(function(report) {\n      report.names().forEach(function(name) {\n        console.log(name);\n      });\n      \n      console.log(report);\n    });\n  });\n  \n  setTimeout(function() {\n    alice.close();\n    bob.close();\n  }, 5000);\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/p2p.js",
    "content": "var WEBRTC = require('../');\n\nfunction P2P(alice, bob) {\n  alice.onicecandidate = function(event) {\n    var candidate = event.candidate || event;\n    bob.addIceCandidate(candidate);\n  };\n\n  bob.onicecandidate = function(event) {\n    var candidate = event.candidate || event;\n    alice.addIceCandidate(candidate);\n  };\n\n  alice.onnegotiationneeded = function(callback) {      \n    alice.createOffer(function(sdp) {        \n      alice.setLocalDescription(sdp, function() {\n        bob.setRemoteDescription(sdp, function() { \n          bob.createAnswer(function(sdp) {\n            bob.setLocalDescription(sdp, function() {\n              alice.setRemoteDescription(sdp, function() {\n                console.log(\"Alice -> Bob: Connected!\");\n                \n                if (callback) {\n                  callback();\n                }\n              });\n            });\n          });\n        });  \n      });\n    });\n  };\n\n  bob.onnegotiationneeded = function(callback) {\n    bob.createOffer(function(sdp) {\n      bob.setLocalDescription(sdp, function() {          \n        alice.setRemoteDescription(sdp, function() {            \n          alice.createAnswer(function(sdp) {              \n            alice.setLocalDescription(sdp, function() {                \n              bob.setRemoteDescription(sdp, function() {\n                console.log(\"Bob -> Alice: Connected!\");\n                \n                if (callback) {\n                  callback();\n                }\n              });\n            });\n          });\n        });  \n      });\n    });\n  };\n}\n\nvar config = {\n  iceServers: [\n    {\n      url: 'stun:stun.l.google.com:19302',\n    },\n  ],\n};\n\nvar constraints = {\n  audio: {\n    optional: [\n      {\n/*\n        googEchoCancellation: true,\n        googEchoCancellation2: true,\n        googDAEchoCancellation: true,\n        googAutoGainControl: true,\n        googAutoGainControl2: true,\n        googNoiseSuppression: true,\n        googNoiseSuppression2: true,\n        googHighpassFilter: true,\n        googTypingNoiseDetection: true,\n        googAudioMirroring: true,\n*/\n      },\n    ],\n  },\n  video: {\n    optional: [\n      {\n        minAspectRatio: 1.333,\n        maxAspectRatio: 1.778,\n        maxWidth: 1920,\n        minWidth: 320,\n        maxHeight: 1080,\n        minHeight: 180,\n        maxFrameRate: 60,\n        minFrameRate: 30,\n      },\n    ],\n  },\n  optional: [\n    {\n      DtlsSrtpKeyAgreement: true,\n    },\n  ],\n  mandatory: {\n    OfferToReceiveAudio: true,\n    OfferToReceiveVideo: true,\n  },\n};\n\nvar alice = new WEBRTC.RTCPeerConnection(config, constraints);\nvar bob = new WEBRTC.RTCPeerConnection(config, constraints);\n\nP2P(alice, bob);\n\nalice.onnegotiationneeded(function() {\n  console.log('Done! :)');\n  \n  setTimeout(function() {\n    console.log('Closing...');\n    \n    alice.close();\n    bob.close();\n  }, 5000);\n});\n"
  },
  {
    "path": "test/p2p_stream.js",
    "content": "var WEBRTC = require('../');\n\nWEBRTC.setDebug(true);\n\nvar config = {\n  iceServers: [\n    {\n      url: 'stun:stun.l.google.com:19302',\n    },\n  ],\n};\n\nvar constraints = {\n  audio: {\n    optional: [\n      {\n        googEchoCancellation: true,\n        googEchoCancellation2: true,\n        googDAEchoCancellation: true,\n        googAutoGainControl: true,\n        googAutoGainControl2: true,\n        googNoiseSuppression: true,\n        googNoiseSuppression2: true,\n        googHighpassFilter: true,\n        googTypingNoiseDetection: true,\n        googAudioMirroring: true,\n      },\n    ],\n  },\n  video: {\n    optional: [\n      {\n        minAspectRatio: 1.333,\n        maxAspectRatio: 1.778,\n        maxWidth: 1920,\n        minWidth: 320,\n        maxHeight: 1080,\n        minHeight: 180,\n        maxFrameRate: 60,\n        minFrameRate: 30,\n      },\n    ],\n  },\n  optional: [\n    {\n      DtlsSrtpKeyAgreement: true,\n    },\n  ],\n  mandatory: {\n    OfferToReceiveAudio: true,\n    OfferToReceiveVideo: true,\n  },\n};\n\nvar alice = new WEBRTC.RTCPeerConnection(config, constraints);\nvar bob = new WEBRTC.RTCPeerConnection(config, constraints);\n\nalice.onicecandidate = function (event) {\n  var candidate = event.candidate || event;\n  bob.addIceCandidate(candidate);\n};\n\nbob.onicecandidate = function (event) {\n  var candidate = event.candidate || event;\n  alice.addIceCandidate(candidate);\n};\n\nalice.onnegotiationneeded = function () {\n  alice.createOffer(function (sdp) {\n    alice.setLocalDescription(sdp, function () {\n      bob.setRemoteDescription(sdp, function () {\n        bob.createAnswer(function (sdp) {\n          bob.setLocalDescription(sdp, function () {\n            alice.setRemoteDescription(sdp, function () {\n              console.log('Alice -> Bob Connected!');\n            });\n          });\n        });\n      });\n    });\n  });\n};\n\nbob.onnegotiationneeded = function () {\n  bob.createOffer(function (sdp) {\n    bob.setLocalDescription(sdp, function () {\n      alice.setRemoteDescription(sdp, function () {\n        alice.createAnswer(function (sdp) {\n          alice.setLocalDescription(sdp, function () {\n            bob.setRemoteDescription(sdp, function () {\n              console.log('Bob -> Alice Connected!');\n            });\n          });\n        });\n      });\n    });\n  });\n};\n\nalice.onaddstream = function(stream) {\n  console.log('Alice: mediaStream added!');\n};\n\nbob.onaddstream = function(stream) {\n  console.log('Bob: mediaStream added!');\n};\n\nalice.onremovestream = function(stream) {\n  console.log('Alice: mediaStream removed!');\n};\n\nbob.onremovestream = function(stream) {\n  console.log('Bob: mediaStream removed!');\n};\n\nWEBRTC.getSources(function (inputs) {\n  console.log(inputs);\n\n  WEBRTC.getUserMedia(constraints, function(stream) {\n    if (stream) {\n      alice.addStream(stream);\n\n      setTimeout(function () {\n        alice.close();\n        bob.close();\n      }, 5000);\n    }\n  });\n});\n"
  },
  {
    "path": "test/test.js",
    "content": "var WebRTC = require('../');\n\n//WebRTC.setDebug(true);\n\nvar renderer = new WebRTC.MediaSource('window');\nvar capturer = new WebRTC.MediaSource('webcam');\n\ncapturer.connect(renderer);\n\nsetTimeout(function() {\n  console.log('Closing...');\n  \n  capturer.end();\n}, 10000);"
  },
  {
    "path": "test/videoStream.js",
    "content": "var WebRTC = require('../');\n\nWebRTC.setDebug(true);\n\nfunction onSuccess(stream) {\n  var video_list = stream.getVideoTracks();\n    \n  video_list.forEach(function (track) {\n    console.log('Video Track');\n  });\n}\n\nvar constraints = {\n  audio: false,\n  video: true,\n/*\n  audio: {\n    optional: [\n      {\n        googEchoCancellation: true,\n        googEchoCancellation2: true,\n        googDAEchoCancellation: true,\n        googAutoGainControl: true,\n        googAutoGainControl2: true,\n        googNoiseSuppression: true,\n        googNoiseSuppression2: true,\n        googHighpassFilter: true,\n        googTypingNoiseDetection: true,\n        googAudioMirroring: true,\n      },\n    ],\n  },\n  video: {\n    optional: [\n      {\n        minAspectRatio: 1.333,\n        maxAspectRatio: 1.778,\n        maxWidth: 1920,\n        minWidth: 320,\n        maxHeight: 1080,\n        minHeight: 180,\n        maxFrameRate: 60,\n        minFrameRate: 30,\n      },\n    ],\n  },\n  optional: [\n    {\n      DtlsSrtpKeyAgreement: true,\n    },\n  ],\n  mandatory: {\n    OfferToReceiveAudio: true,\n    OfferToReceiveVideo: true,\n  },\n*/\n};\n\nWebRTC.getUserMedia(constraints, onSuccess);"
  }
]