title: RTCPeerConnection.onicecandidate not fire
body: <p>I am create an app that will share the camera video to multiple peer connection using WebRTC. The server simply provide a room for users, all users in the room  will see the camera video. The only not working was the onicecandidate did not fire, therefore no peer connection can be made.</p>
  
  <p>I create new peer connection for each new users. All seems fine (broadcaster and viewers can exchange messages:
  1) When a viewer joined into the room, the Broadcaster creates new peer connection, create offer, set local description, and send it to the new viewer.
  2) New viewer will set the remote description, create answer, set local description and send the answer back to the broadcaster.
  3)Broadcaster can receive answer, set remote description, but I could not create ice candidate.</p>
  
  <p>Any insight why the RTCPeerConnection.onicecandidate do not fire??</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>"use strict";
  
  // config
  
  
  //Acess camera from the http://localhost:2013 is allowed because it is considered a safe environment
  //Acess camera from the http://192.168.10.7:2013 is considered a non secure environment (therefore require https)
  //var serverIP = "http://192.168.10.7:2013";
  //var serverIP = "https://172.21.2.197:2013";
  //var serverIP = "https://172.20.10.12:2013";
  var serverIP = "https://localhost:2013";
  
  // RTCPeerConnection Options
  var server = {
      // Uses Google's STUN server
      iceServers: [{
          "url": "stun:stun.xten.com"
      }, 
      {
      // Use my TURN server on DigitalOcean
          'url': 'turn:numb.viagenie.ca',
          'credential': 'sunghiep',
          'username': 'nghiepnds@yahoo.com'
      }]
  };
  
  //DOM Objects
  var btnSend = document.getElementById('btn-send');
  var btnVideoStop = document.getElementById('btn-video-stop');
  var btnVideoStart = document.getElementById('btn-video-start');
  var btnVideoJoin = document.getElementById('btn-video-join');
  var localVideo = document.getElementById('local-video');
  var remoteVideo = document.getElementById('remote-video');
  var inputRoomName = document.getElementById('room-name');
  
  //WebRTC Objects
  var signallingServer;
  var localStream;
  var viewPeerConnection;
  
  var sdpConstraints = {
      optional: [],
      mandatory: {
          OfferToReceiveVideo: true
      }
  };
  
  // declare RTCPeerConnection
  window.RTCPeerConnection =  window.RTCPeerConnection || window.mozRTCPeerConnection ||
                              window.webkitRTCPeerConnection || window.msRTCPeerConnection;
  // declare RTCSessionDescription (SDP)
  window.RTCSessionDescription =  window.RTCSessionDescription || window.mozRTCSessionDescription ||
                                  window.webkitRTCSessionDescription || window.msRTCSessionDescription;
  
  // declare the getUserMedia
  navigator.getUserMedia =    navigator.getUserMedia || navigator.mozGetUserMedia ||
                              navigator.webkitGetUserMedia || navigator.msGetUserMedia;
  
  //in other example I use: navigator.mediaDevices.getUserMedia. WHY is different here???? It is because I use adapter.js
  
  window.SignallingServer = window.SignallingServer;
  
  var peers = [];
  
  // start the video a Room
  btnVideoStart.onclick = function(e) {
      e.preventDefault();
  
      //Create room
     createRoom()
  };
  
  btnVideoJoin.onclick = function(e) {
      e.preventDefault();
      // View video
      trace("Click on Join");
      joinRoom()
  };
  
  btnVideoStop.onclick = function(e) {
      e.preventDefault();
      // stop video stream
      if (localStream != null) {
          localStream.getVideoTracks().forEach(function (track) {
              track.stop();
          });
      }
  
      // kill all connections
      if (localPeerConnection != null) {
          localPeerConnection.removeStream(localStream);
          localPeerConnection.close();
          signallingServer.close();
          localVideo.src = "";
          remoteVideo.src = "";
      }
  
      btnVideoStart.disabled = false;
      btnVideoJoin.disabled = false;
      btnVideoStop.disabled = true;
  };
  
  
  function createRoom(){
      //get room's name
      var room = inputRoomName.value;
  
      if (room == undefined || room.length &lt;= 0) {
          alert('Please enter room name');
          return;
      }
  
      // create local data channel, send it to remote
      navigator.getUserMedia({
          video: true,
          audio: true
      }, function(stream) {
          // get and save local stream
          trace('Got stream, saving it now and starting RTC conn');
          //show video on video object
          localStream = stream;
          localVideo.src = window.URL.createObjectURL(stream);
      }, errorHandler);
  
      btnVideoStart.disabled = true;
      btnVideoJoin.disabled = true;
      btnVideoStop.disabled = false;
  
      // create signalling server
      signallingServer = new SignallingServer(room, serverIP);
  
      //create room
      signallingServer.create();
  
  
      // a remote peer has joined room, initiate sdp exchange
      signallingServer.onGuestJoined = function(room, socketId) {
          trace('Guest(' + socketId +') joined room ['+ room +']! ');
          var guestId = socketId;
          var roomName =  room;
  
          // Create new peer connection for new joiner
          //trace("create new RTCPeerConnection");
          //var pc = new RTCPeerConnection(server);
          //peers.set(guestId, pc);
          peers[socketId] = new RTCPeerConnection(server);
          trace(peers);
  
          // send ice to the new joiner
          trace('Collecting ices ...');
          peers[socketId].onicecandidate  = function(evt) {
              trace('ice ready ...');
              if (evt.candidate){
                  signallingServer.sendICECandidate(room, socketId, evt.candidate);
              }
  
          };
  
  
           //create local data channel, share remote
          navigator.getUserMedia({
              video: true,
              audio: true
          }, function(stream) {
              // get and save local stream
              trace('Got stream, saving it now and starting RTC conn');
              // Add stream to peer connection
              localStream = stream;
              peers[socketId].addStream(localStream);
          }, errorHandler);
  
  
          // Create offer,
          peers[socketId].createOffer(function(sessionDescription) {
              trace('Created offer');
              // Set local description
              peers[socketId].setLocalDescription(sessionDescription, function(){
                  // Send local sdp to remote
                  trace('Set local sdp success');
  
                  signallingServer.sendOffer(guestId, roomName, sessionDescription);
                  trace('Sending sdp offer');
  
                  trace(peers);
  
              }, function(){
                  trace('Set local sdp failed');
              });
  
          }, function(){
              trace('Create offer failed');
          });
  
      };
  
  
  
  
      //Receive the answer
      signallingServer.onReceiveAnswer = function(sender, sdp) {
          trace('Receive remote sdp with answer');
          // Step 7 - Set the remote SDP
          peers[sender].setRemoteDescription(new RTCSessionDescription(sdp), function () {
              trace('Set Remote Description success');
          }, function () {
              trace('Set Remote Description fail');
          });
  
          trace(peers);
      };
  
      // when room is full, alert user
      signallingServer.onRoomFull = function(room) {
          window.alert('Room "' + room +
              '"" is full! Please join or create another room');
      };
  
  
  }
  
  function joinRoom(){
      //get room's name
      var room = inputRoomName.value;
  
      if (room == undefined || room.length &lt;= 0) {
          alert('Please enter room name');
          return;
      }
  
      btnVideoStart.disabled = true;
      btnVideoJoin.disabled = true;
      btnVideoStop.disabled = false;
  
      // Step 1 - Create peer connection
      viewPeerConnection = new RTCPeerConnection(server);
  
      // create signalling server
      signallingServer = new SignallingServer(room, serverIP);
  
      //join room
      signallingServer.join();
  
      // got sdp offer
      signallingServer.onReceiveOffer = function(offerCreatorId, roomName, sdp) {
          // Step 7 - Set remote SDP
          viewPeerConnection.setRemoteDescription(new RTCSessionDescription(sdp), function() {
              trace('Set Remote Description');
              trace(sdp);
              // Step 8 - Create an answer
              var answerPromise = viewPeerConnection.createAnswer();
              answerPromise.then(function(answer){
                  // Step 9 - Set local description from the incoming SDP
                  trace('Set Local Description');
                  trace(answer);
                  viewPeerConnection.setLocalDescription(answer)});
  
              answerPromise.then(function(answer){
                  trace('Send Answer Description');
                  trace(answer);
                  // Step 10 - Send local sdp(answer) to remote
                  signallingServer.sendAnswer(offerCreatorId, roomName, answer);
              }).catch(handleGetUserMediaError);
          });
  
      };
  
      // ICE Candidate is created when cannot establish the peer connection due to NAT/FIREWALL
      // when received ICE candidate info
      signallingServer.onReceiveICECandidate = function(candidate) {
          trace('Add ice candidate');
          viewPeerConnection.addIceCandidate(new RTCIceCandidate(candidate));
      };
  
      viewPeerConnection.onaddstream = function(data) {
          trace("stream ready");
          remoteVideo.src = window.URL.createObjectURL(data.stream);
      };
  }
  
  function errorHandler(error) {
      console.error('Something went wrong!');
      console.error(error);
  }
  
  function trace(text) {
      console.info(text);
  }
  
  function handleGetUserMediaError(){
      trace("getUserMedia Error")
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;!DOCTYPE html&gt;
  &lt;html lang="en"&gt;
  &lt;!--[if lt IE 7]&gt;
  &lt;html class="no-js lt-ie9 lt-ie8 lt-ie7" lang=""&gt;
  &lt;![endif]--&gt;
  &lt;!--[if IE 7]&gt;
  &lt;html class="no-js lt-ie9 lt-ie8" lang=""&gt;
  &lt;![endif]--&gt;
  &lt;!--[if IE 8]&gt;
  &lt;html class="no-js lt-ie9" lang=""&gt;
  &lt;![endif]--&gt;
  &lt;!--[if gt IE 8]&gt;
  &lt;!--&gt;
  &lt;html class="no-js" lang=""&gt;
  &lt;!--&lt;![endif]--&gt;
  &lt;head&gt;
      &lt;meta charset="utf-8"&gt;
      &lt;meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"&gt;
      &lt;title&gt;&lt;/title&gt;
      &lt;meta name="description" content=""&gt;
      &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
  
      &lt;link rel="stylesheet" href="css/bootstrap.min.css"&gt;
      &lt;style&gt;
          body {
              padding-top: 50px;
              padding-bottom: 20px;
          }
      &lt;/style&gt;
      &lt;link rel="stylesheet" href="css/bootstrap-theme.min.css"&gt;
      &lt;link rel="stylesheet" href="css/main.css"&gt;
  
      &lt;script src="js/vendor/modernizr-2.8.3-respond-1.4.2.min.js"&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
  &lt;!--[if lt IE 8]&gt;
  &lt;p class="browserupgrade"&gt;
      You are using an &lt;strong&gt;outdated&lt;/strong&gt;
      browser. Please
      &lt;a href="http://browsehappy.com/"&gt;upgrade your browser&lt;/a&gt;
      to improve your experience.
  &lt;/p&gt;
  &lt;![endif]--&gt;
  &lt;nav class="navbar navbar-default navbar-fixed-top" role="navigation"&gt;
      &lt;div class="container"&gt;
          &lt;div class="navbar-header"&gt;
              &lt;button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
                      aria-expanded="false"&gt;
                  &lt;span class="sr-only"&gt;Toggle navigation&lt;/span&gt;
                  &lt;span class="icon-bar"&gt;&lt;/span&gt;
                  &lt;span class="icon-bar"&gt;&lt;/span&gt;
                  &lt;span class="icon-bar"&gt;&lt;/span&gt;
              &lt;/button&gt;
              &lt;a class="navbar-brand" href="#"&gt;WebRTC Video Chat&lt;/a&gt;
          &lt;/div&gt;
          &lt;div id="navbar" class="navbar-collapse collapse"&gt;
              &lt;!-- chatroom name form --&gt;
              &lt;form class="navbar-form navbar-right form-inline"&gt;
                  &lt;div class="form-group"&gt;
                      &lt;input class="form-control" type="text" id="room-name" placeholder="Room name"/&gt;
                  &lt;/div&gt;
                  &lt;button class="btn btn-primary" id="btn-video-start"&gt;Create Live Broadcast&lt;/button&gt;
                  &lt;button class="btn btn-default" id="btn-video-join"&gt;Join&lt;/button&gt;
                  &lt;button class="btn btn-default" disabled id="btn-video-stop"&gt;Stop&lt;/button&gt;
              &lt;/form&gt;
          &lt;/div&gt;
  
          &lt;!--/.navbar-collapse --&gt; &lt;/div&gt;
  
  &lt;/nav&gt;
  
  &lt;div class="container main"&gt;
      &lt;div class="row videos"&gt;
          &lt;div class="remote-video"&gt;
              &lt;video width="280" height="250" autoplay="true" id="remote-video"&gt;&lt;/video&gt;
          &lt;/div&gt;
          &lt;div class="local-video"&gt;
              &lt;video width="560" height="500" autoplay="true" id="local-video" muted&gt;&lt;/video&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  &lt;/div&gt;
  &lt;!-- /container --&gt;
  &lt;script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"&gt;&lt;/script&gt;
  &lt;script&gt;window.jQuery || document.write('&lt;script src="js/vendor/jquery-1.11.2.min.js"&gt;&lt;\/script&gt;')&lt;/script&gt;
  
  &lt;script src="js/vendor/bootstrap.min.js"&gt;&lt;/script&gt;
  &lt;script src="js/vendor/socket.io.js"&gt;&lt;/script&gt;
  
  &lt;script src="js/main.js"&gt;&lt;/script&gt;
  &lt;!--&lt;script src="js/adapter.js"&gt;&lt;/script&gt;--&gt;
  &lt;script src="js/signalling.js"&gt;&lt;/script&gt;
  
  &lt;!--&lt;script src="//localhost:9010/livereload.js"&gt;&lt;/script&gt;--&gt;
  
  &lt;!-- Google Analytics: change UA-XXXXX-X to be your site's ID. --&gt;
  &lt;script&gt;
      (function (b, o, i, l, e, r) {
          b.GoogleAnalyticsObject = l;
          b[l] || (b[l] =
                  function () {
                      (b[l].q = b[l].q || []).push(arguments)
                  });
          b[l].l = +new Date;
          e = o.createElement(i);
          r = o.getElementsByTagName(i)[0];
          e.src = '//www.google-analytics.com/analytics.js';
          r.parentNode.insertBefore(e, r)
      }(window, document, 'script', 'ga'));
      ga('create', 'UA-XXXXX-X', 'auto');
      ga('send', 'pageview');
  &lt;/script&gt;
  &lt;/body&gt;
  &lt;/html&gt;</code></pre>
  </div>
  </div>
  </p>