2014-03-27 26 views
9

今天我必須再次提出這個問題。點對點重做會議,WebRTC

我正在處理一個代碼連接到一對一的代碼,允許一個羣組對話。沒有拐彎抹角,我有這樣的代碼:當兩個用戶之間的對話添加其他成員時運轉良好,然後

CallToUsers = function(connection) { 
    var connection = connection; 
    var isChannelReady; 
    var isInitiator = false; 
    var isStarted = false; 
    var servers = null; 
    var localStream = connection.getStream(); 
    var localStreams = []; 
    var localConnection; 
    var turnReady; 
    var remoteStreams = []; 
    var remoteStream; 
    var pcConfig = { 
     'iceServers': [{ 
      'url': 'stun:stun.l.google.com:19302' 
      }] 
     }; 
    var pcConstraints = { 
     'optional': [{ 
      'DtlsSrtpKeyAgreement': true 
      }] 
     }; 
    var sdpConstraints = { 
     'mandatory': { 
      'OfferToReceiveAudio': true, 
      'OfferToReceiveVideo': true 
     } 
    }; 
    var room; 
    var socket = io.connect(); 
    var divElement = document.createElement('div'); 
    divElement.setAttribute('id', 'remotesVideo'); 
    document.body.appendChild(divElement); 

    var createRoom = function(room) { 
     room = room; 
     if(room !== '') { 
      console.log('Create or join to room', room); 
      socket.emit('create or join', room); 
     } 

     socket.on('created', function(room) { 
      console.log('Created room ' + room); 
      isInitiator = true; 
     }); 

     /*socket.on('full', function(room) { 
      console.log('Room' + room + ' is full'); 
     });*/ 

     socket.on('join', function(room) { 
      console.log('Another peer made request to join ' + room); 
      isChannelReady = true; 
     }); 

     socket.on('joined', function(room) { 
      console.log('User joined to room ' + room); 
      isChannelReady = true; 
     }); 

     socket.on('log', function(array) { 
      console.log.apply(console, array); 
     }); 
    }; 

    var sendMessage = function(message) { 
     console.log('Client sending a message: ', message); 
     socket.emit('message', message); 
    }; 

    window.onbeforeunload = function(e){ 
     sendMessage('bye'); 
    }; 

    var startCall = function() { 
     sendMessage('got user media'); 

     if(isInitiator) { 
      maybeStart(); 
     } 

     socket.on('message', function(message) { 
      console.log('Client received a message: ' + message); 
      if(message === 'got user media') { 
       maybeStart(); 
      } else if(message.type === 'offer') { 
       if(!isInitiator && !isStarted) { 
        maybeStart(); 
       } 

       for(var i = 0; i < localStreams.length; i++) { 
        localStreams[i].setRemoteDescription(new RTCSessionDescription(message)); 
       } 

       doAnswer(); 
      } else if(message.type === 'answer' && isStarted) { 
       for(var i = 0; i < localStreams.length; i++) { 
        localStreams[i].setRemoteDescription(new RTCSessionDescription(message)); 
       } 
      } else if(message.type === 'candidate' && isStarted) { 
       var candidate = new RTCIceCandidate({ 
        sdpMLineIndex: message.label, 
        candidate: message.candidate 
       }); 

       for(var i = 0; i < localStreams.length; i++) { 
        localStreams[i].addIceCandidate(candidate); 
       } 
      } else if(message === 'bye' && isStarted) { 
       handleRemoteEndCall(); 
      } 
     }); 

     //if(location.hostname != 'localhost') { 
      //requestTurn('https://computeengineondemand.appspot.com/turn?username=41784574&key=4080218913'); 
     //} 
    }; 

    var maybeStart = function() { 
     if(!isStarted && typeof localStream != 'undefined' && isChannelReady) { 
      createPeerConnection(); 
      for(var i = 0; i < localStreams.length; i++) { 
       localStreams[i].addStream(localStream); 
      } 
      isStarted = true; 

      if(isInitiator) { 
       doCall(); 
      } 
     } 
    }; 

    var createPeerConnection = function() { 
     try { 
       localConnection = new RTCPeerConnection(pcConfig, pcConstraints); 
       localConnection.onicecandidate = handleIceCandidate; 
       localConnection.onaddstream = handleRemoteStreamAdded; 
       localConnection.onremovestream = handleRemoteStreamRemoved; 
       localStreams.push(localConnection); 
      console.log('Created RTCPeerConnection'); 
     } catch(e) { 
      console.log('exception ' + e.message); 
      return; 
     } 
    }; 

    var handleIceCandidate = function(event) { 
     if(event.candidate) { 
      sendMessage({ 
       type: 'candidate', 
       label: event.candidate.sdpMLineIndex, 
       id: event.candidate.sdpMid, 
       candidate: event.candidate.candidate 
      }); 
     } else { 
      console.log('End of candidates'); 
     } 
    }; 

    var handleRemoteStreamAdded = function(event) { 
     console.log('Remote stream added'); 
     var newVideo = document.createElement('video'); 
     newVideo.setAttribute('id', Math.floor((Math.random() * 1000) + 1)); 
     newVideo.muted = false; 
     divElement.appendChild(newVideo); 
     attachMediaStream(newVideo, event.stream); 
     remoteStream = event.stream; 
     remoteStreams.push(remoteStream); 
    }; 

    var handleRemoteStreamRemoved = function(event) { 
     console.log('Delete'); 
    }; 

    var handleCreateOfferError = function(event) { 
     console.log('createOffer() error: ' + e); 
    } 

    var setLocalAndSendMessage = function(sessionDescription) { 
     sessionDescription.sdp = preferOpus(sessionDescription.sdp); 
     for(var i = 0; i < localStreams.length; i++) { 
      localStreams[i].setLocalDescription(sessionDescription); 
     } 
     sendMessage(sessionDescription); 
    }; 

    var doCall = function() { 
     console.log('Start call'); 
     for(var i = 0; i < localStreams.length; i++) { 
      localStreams[i].createOffer(setLocalAndSendMessage, handleCreateOfferError); 
     } 
    }; 

    var doAnswer = function() { 
     console.log('Sending answer'); 
     for(var i = 0; i < localStreams.length; i++) { 
      localStreams[i].createAnswer(setLocalAndSendMessage, null, sdpConstraints); 
     } 
    }; 

    var endCall = function() { 
     console.log('Hanging up'); 
     isStarted = false; 
     for(var i = 0; i < localStreams.length; i++) { 
      localStreams[i].close(); 
      localStreams[i] = null; 
     } 
     sendMessage('bye'); 
    }; 

    var handleRemoteEndCall = function() { 
    }; 

    var requestTurn = function(turnUrl) { 
     var turnExists = false; 

     for(var i in pcConfig.iceServers) { 
      if(pcConfig.iceServers[i].url.substr(0, 5) === 'turn:') { 
       turnExists = true; 
       turnReady = true; 
       break; 
      } 
     } 

     if(!turnExists) { 
      console.log('Getting TURN server from ', turnUrl); 

      var xhr = new XMLHttpRequest(); 
      xhr.onreadystatechange = function() { 
       if(xhr.readyState === 4 && xhr.status === 200) { 
        var turnServer = JSON.parse(xhr.responseText); 
        console.log('Got TURN server: ', turnServer); 
        pc_config.iceServers.push({ 
         'url': 'turn:' + turnServer.username + '@' + turnServer.turn, 
         'credential': turnServer.password 
        }); 
        turnReady = true; 
       } 
      }; 

      xhr.open('GET', turnUrl, true); 
      xhr.send(); 
     } 
    }; 

    var preferOpus = function(sdp) { 
     var sdpLines = sdp.split('\r\n'); 
     var mLineIndex; 

     for(var i = 0; i < sdpLines.length; i++) { 
      if(sdpLines[i].search('m=audio') !== -1) { 
       mLineIndex = i; 
       break; 
      } 
     } 

     if(mLineIndex === null) { 
      return sdp; 
     } 

     for(i = 0; i < sdpLines.length; i++) { 
      if(sdpLines[i].search('opus/48000') !== -1) { 
       var opusPayload = extractSdp(sdpLines[i], /:(\d+) opus\/48000/i); 

       if(opusPayload) { 
        sdpLines[mLineIndex] = setDefaultCodec(sdpLines[mLineIndex], opusPayload); 
       } 

       break; 
      } 
     } 

     sdpLines = removeCN(sdpLines, mLineIndex); 

     sdp = sdpLines.join('\r\n'); 

     return sdp; 
    }; 

    var extractSdp = function(sdpLine, pattern) { 
     var result = sdpLine.match(pattern); 

     return result && result.length === 2 ? result[1] : null; 
    }; 

    var setDefaultCodec = function(mLine, payload) { 
     var elements = mLine.split(' '); 
     var newLine = []; 
     var index = 0; 

     for(var i = 0; i < elements.length; i++) { 
      if(index === 3) { 
       newLine[index++] = payload; 
      } 
      if(elements[i] !== payload) { 
       newLine[index++] = elements[i]; 
      } 
     } 

     return newLine.join(' '); 
    }; 

    var removeCN = function(sdpLines, mLineIndex) { 
     var mLineElements = sdpLines[mLineIndex].split(' '); 

     for(var i = sdpLines.length - 1; i >= 0; i--) { 
      var payload = extractSdp(sdpLines[i], /a=rtpmap:(\d+) CN\/\d+/i); 

      if(payload) { 
       var cnPos = mLineElements.indexOf(payload); 

       if(cnPos !== -1) { 
        mLineElements.splice(cnPos, 1); 
       } 

       sdpLines.splice(i, 1); 
      } 
     } 

     sdpLines[mLineIndex] = mLineElements.join(' '); 

     return sdpLines; 
    }; 

    return { 
     startCall: startCall, 
     endCall: endCall, 
     createRoom: createRoom 
    }; 
}; 

,它不再連接到另外兩個同行,雖然明確了日誌我看到重視同一個房間。

在控制檯中,沒有錯誤。

有人願意幫忙嗎?

@edit

如果需要的話,我將服務器代碼太:

var static = require('node-static'); 
var http = require('http'); 
var file = new(static.Server)(); 
var app = http.createServer(function (req, res) { 
    file.serve(req, res); 
}).listen(2017); 


var io = require('socket.io').listen(app); 
io.sockets.on('connection', function (socket){ 

    function log(){ 
     var array = [">>> "]; 
     for (var i = 0; i < arguments.length; i++) { 
     array.push(arguments[i]); 
     } 
     socket.emit('log', array); 
    } 

    socket.on('message', function (message) { 
     log('Got message: ', message); 
     socket.broadcast.emit('message', message); // should be room only 
    }); 

    socket.on('create or join', function (room) { 
     var numClients = io.sockets.clients(room).length; 

     log('Room ' + room + ' has ' + numClients + ' client(s)'); 
     log('Request to create or join room', room); 

     if (numClients == 0){ 
      socket.join(room); 
      socket.emit('created', room); 
     } else { 
      io.sockets.in(room).emit('join', room); 
      socket.join(room); 
      socket.emit('joined', room); 
     } 
     socket.emit('emit(): client ' + socket.id + ' joined room ' + room); 
     socket.broadcast.emit('broadcast(): client ' + socket.id + ' joined room ' + room); 

    }); 

}); 
+3

但你在哪裏創建第二個對等連接?我在maybeStart中看到的是,如果(!isStarted && typeof localStream!='undefined'&& isChannelReady),則不會創建另一個對等連接。當第三個人來時,我不認爲這是真的。 –

回答

1

終於解決了這個問題。撰寫所有同行所連接的會議的一般規則是:每個新來話都扮演應答者的角色,並在與發送給他提議的所有優惠建立連接之後,開始擔任發件人(除了第一個同伴,這始終是報價)。 @Mert Koksal,謝謝你的興趣。