是否未检测到转弯服务器?

时间:2016-09-27 13:10:14

标签: javascript html5 webrtc sdp

我已经设置了自己的转向服务器以防止发生跨域错误。当客户端需要使用TURN服务器而不是STUN时,没有视频源。然而,消息正在通过。我的main.js(从WebRTC Development起飞)

'use strict';

var isChannelReady = false;
var isInitiator = false;
var isStarted = false;
var localStream;
var pc;
var remoteStream;
var turnReady;

var pcConfig = {
  'iceServers': [{
    'url': 'brett@66.172.10.133',
    'credential': 'thorn'
  }]
};

// Set up audio and video regardless of what devices are present.
var sdpConstraints = {
  'mandatory': {
    'OfferToReceiveAudio': true,
    'OfferToReceiveVideo': true
  }
};

/////////////////////////////////////////////

var room = 'foo2';
// Could prompt for room name:
// room = prompt('Enter room name:');

var socket = io.connect();

if (room !== '') {
  socket.emit('create or join', room);
  console.log('Attempted to create or  join room', 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 a request to join room ' + room);
  console.log('This peer is the initiator of room ' + room + '!');
  isChannelReady = true;
});

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

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

////////////////////////////////////////////////

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

// This client receives a message
socket.on('message', function(message) {
  console.log('Client received message:', message);
  if (message === 'got user media') {
    maybeStart();
  } else if (message.type === 'offer') {
    if (!isInitiator && !isStarted) {
      maybeStart();
    }
    pc.setRemoteDescription(new RTCSessionDescription(message));
    doAnswer();
  } else if (message.type === 'answer' && isStarted) {
    pc.setRemoteDescription(new RTCSessionDescription(message));
  } else if (message.type === 'candidate' && isStarted) {
    var candidate = new RTCIceCandidate({
      sdpMLineIndex: message.label,
      candidate: message.candidate
    });
    pc.addIceCandidate(candidate);
  } else if (message === 'bye' && isStarted) {
    handleRemoteHangup();
  }
});

////////////////////////////////////////////////////

var localVideo = document.querySelector('#localVideo');
var remoteVideo = document.querySelector('#remoteVideo');

navigator.mediaDevices.getUserMedia({
  audio: false,
  video: true
})
.then(gotStream)
.catch(function(e) {
  alert('getUserMedia() error: ' + e.name);
});

function gotStream(stream) {
  console.log('Adding local stream.');
  localVideo.src = window.URL.createObjectURL(stream);
  localStream = stream;
  sendMessage('got user media');
  if (isInitiator) {
    maybeStart();
  }
}

var constraints = {
  video: true
};

console.log('Getting user media with constraints', constraints);

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

function maybeStart() {
  console.log('>>>>>>> maybeStart() ', isStarted, localStream, isChannelReady);
  if (!isStarted && typeof localStream !== 'undefined' && isChannelReady) {
    console.log('>>>>>> creating peer connection');
    createPeerConnection();
    pc.addStream(localStream);
    isStarted = true;
    console.log('isInitiator', isInitiator);
    if (isInitiator) {
      doCall();
    }
  }
}

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

/////////////////////////////////////////////////////////

function createPeerConnection() {
  try {
    pc = new RTCPeerConnection(null);
    pc.onicecandidate = handleIceCandidate;
    pc.onaddstream = handleRemoteStreamAdded;
    pc.onremovestream = handleRemoteStreamRemoved;
    console.log('Created RTCPeerConnnection');
  } catch (e) {
    console.log('Failed to create PeerConnection, exception: ' + e.message);
    alert('Cannot create RTCPeerConnection object.');
    return;
  }
}

function handleIceCandidate(event) {
  console.log('icecandidate event: ', 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.');
  }
}

function handleRemoteStreamAdded(event) {
  console.log('Remote stream added.');
  remoteVideo.src = window.URL.createObjectURL(event.stream);
  remoteStream = event.stream;
}

function handleCreateOfferError(event) {
  console.log('createOffer() error: ', event);
}

function doCall() {
  console.log('Sending offer to peer');
  pc.createOffer(setLocalAndSendMessage, handleCreateOfferError);
}

function doAnswer() {
  console.log('Sending answer to peer.');
  pc.createAnswer().then(
    setLocalAndSendMessage,
    onCreateSessionDescriptionError
  );
}

function setLocalAndSendMessage(sessionDescription) {
  // Set Opus as the preferred codec in SDP if Opus is present.
  //  sessionDescription.sdp = preferOpus(sessionDescription.sdp);
  pc.setLocalDescription(sessionDescription);
  console.log('setLocalAndSendMessage sending message', sessionDescription);
  sendMessage(sessionDescription);
}

function onCreateSessionDescriptionError(error) {
  trace('Failed to create session description: ' + error.toString());
}

function requestTurn(turnURL) {
        pcConfig.iceServers.push({
          'url': 'turn:brett@66.172.10.133',
          'credential': 'thorn'
        });
        turnReady = true;

}

function handleRemoteStreamAdded(event) {
  console.log('Remote stream added.');
  remoteVideo.src = window.URL.createObjectURL(event.stream);
  remoteStream = event.stream;
}

function handleRemoteStreamRemoved(event) {
  console.log('Remote stream removed. Event: ', event);
}

function hangup() {
  console.log('Hanging up.');
  stop();
  sendMessage('bye');
}

function handleRemoteHangup() {
  console.log('Session terminated.');
  stop();
  isInitiator = false;
}

function stop() {
  isStarted = false;
  // isAudioMuted = false;
  // isVideoMuted = false;
  pc.close();
  pc = null;
}

///////////////////////////////////////////

// Set Opus as the default audio codec if it's present.
function preferOpus(sdp) {
  var sdpLines = sdp.split('\r\n');
  var mLineIndex;
  // Search for m line.
  for (var i = 0; i < sdpLines.length; i++) {
    if (sdpLines[i].search('m=audio') !== -1) {
      mLineIndex = i;
      break;
    }
  }
  if (mLineIndex === null) {
    return sdp;
  }

  // If Opus is available, set it as the default in m line.
  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;
    }
  }

  // Remove CN in m line and sdp.
  sdpLines = removeCN(sdpLines, mLineIndex);

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

function extractSdp(sdpLine, pattern) {
  var result = sdpLine.match(pattern);
  return result && result.length === 2 ? result[1] : null;
}

// Set the selected codec to the first in m line.
function setDefaultCodec(mLine, payload) {
  var elements = mLine.split(' ');
  var newLine = [];
  var index = 0;
  for (var i = 0; i < elements.length; i++) {
    if (index === 3) { // Format of media starts from the fourth.
      newLine[index++] = payload; // Put target payload to the first.
    }
    if (elements[i] !== payload) {
      newLine[index++] = elements[i];
    }
  }
  return newLine.join(' ');
}

// Strip CN from sdp before CN constraints is ready.
function removeCN(sdpLines, mLineIndex) {
  var mLineElements = sdpLines[mLineIndex].split(' ');
  // Scan from end for the convenience of removing an item.
  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) {
        // Remove CN payload from m line.
        mLineElements.splice(cnPos, 1);
      }
      // Remove CN line in sdp
      sdpLines.splice(i, 1);
    }
  }

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

出于某种原因,除了在同一网络上之外没有视频输入(因此我怀疑没有联系转弯服务器)。另外,下面是我正在使用的html:

<!DOCTYPE html>
<html>

<head>

  <title>Realtime communication with WebRTC</title>

  <link rel="stylesheet" href="/css/main.css" />

</head>

<body>

  <h1>Realtime communication with WebRTC</h1>

  <div id="videos">
    <video id="localVideo" autoplay muted></video>
    <video id="remoteVideo" autoplay></video>
  </div>

  <script src="/socket.io/socket.io.js"></script>
  <script src="js/lib/adapter.js"></script>
  <script src="js/main.js"></script>

</body>

</html>

任何帮助将不胜感激。

编辑:我已将用户名和密码设置为:

# Typically, the realm field must match the value of AuthenticationRealm
# defined in reTurnServer.config
#
# The state field (not case sensitive) can be one of:
#
#   authorized   (user authorized)
#   refused      (user denied access)
#   restricted   (for when bandwidth limiting is implemented)
#
# This file format is interchangeable with TurnServer.org's user database
#
# Comments can be inserted by starting a line with #
#
test:foobar:example.org:REFUSED
brett:thorn:66.172.10.133:AUTHORISED

我不明白为什么会有授权问题。

编辑:由于拼写错误的单词而修复了授权问题。但是,我在浏览器中收到以下内容但仍然没有视频Feed:

GET http://66.172.10.133:8080/socket.io/?EIO=3&transp...lling&t=1475036226795-4&sid=rlFY-bqt9vnv6S5FAAAA

200 OK
        250ms   
socket.io.js (line 2739)
Adding local stream.
main.js (line 109)
Client sending message: got user media
main.js (line 66)
>>>>>>> maybeStart() false LocalMediaStream { id="{0daeeab5-8929-40c8-b7ea-cf65028a5363}",  currentTime=0,  stop=stop(),  more...} false
main.js (line 131)
Message from server: Client said: got user media
main.js (line 60)
Another peer made a request to join room foo2
main.js (line 49)
This peer is the initiator of room foo2!
main.js (line 50)
Client received message: got user media
main.js (line 72)
>>>>>>> maybeStart() false LocalMediaStream { id="{0daeeab5-8929-40c8-b7ea-cf65028a5363}",  currentTime=9.666666666666666,  stop=stop(),  more...} true
main.js (line 131)
>>>>>> creating peer connection
main.js (line 133)
Created RTCPeerConnnection
main.js (line 156)
isInitiator true
main.js (line 137)
Sending offer to peer
main.js (line 189)
setLocalAndSendMessage sending message RTCSessionDescription { type="offer",  sdp="v=0\r\no=mozilla...THIS_IS...e7-a980-692a3ea8198a}\r\n",  toJSON=toJSON()}
main.js (line 205)
Client sending message: RTCSessionDescription { type="offer",  sdp="v=0\r\no=mozilla...THIS_IS...e7-a980-692a3ea8198a}\r\n",  toJSON=toJSON()}
main.js (line 66)
icecandidate event: icecandidate 
main.js (line 165)
Client sending message: Object { type="candidate",  label=0,  id="sdparta_0",  more...}
main.js (line 66)
icecandidate event: icecandidate 
main.js (line 165)
Client sending message: Object { type="candidate",  label=0,  id="sdparta_0",  more...}
main.js (line 66)
icecandidate event: icecandidate 
main.js (line 165)
Client sending message: Object { type="candidate",  label=0,  id="sdparta_0",  more...}
main.js (line 66)
icecandidate event: icecandidate 
main.js (line 165)
Client sending message: Object { type="candidate",  label=0,  id="sdparta_0",  more...}
main.js (line 66)
icecandidate event: icecandidate 
main.js (line 165)
End of candidates.
main.js (line 174)
Message from server: Client said: Object { type="offer",  sdp="v=0\r\no=mozilla...THIS_IS...e7-a980-692a3ea8198a}\r\n"}
main.js (line 60)
Message from server: Client said: Object { type="candidate",  label=0,  id="sdparta_0",  more...}
main.js (line 60)
Message from server: Client said: Object { type="candidate",  label=0,  id="sdparta_0",  more...}
main.js (line 60)
Message from server: Client said: Object { type="candidate",  label=0,  id="sdparta_0",  more...}
main.js (line 60)
Message from server: Client said: Object { type="candidate",  label=0,  id="sdparta_0",  more...}
main.js (line 60)
Client received message: Object { type="answer",  sdp="v=0\r\no=- 679697878549041...69f-968e-efbdb26e287c\r\n"}
main.js (line 72)
Remote stream added.
main.js (line 223)
Client received message: Object { type="candidate",  label=0,  id="sdparta_0",  more...}
main.js (line 72)
Client received message: Object { type="candidate",  label=0,  id="sdparta_0",  more...}
main.js (line 72)
ICE failed, see about:webrtc for more details

另外,我在连接日志(about:webrtc)中得到了这个:

(registry/INFO) insert 'ice' (registry) succeeded: ice

(registry/INFO) insert 'ice.pref' (registry) succeeded: ice.pref

(registry/INFO) insert 'ice.pref.type' (registry) succeeded: ice.pref.type

(registry/INFO) insert 'ice.pref.type.srv_rflx' (UCHAR) succeeded: 0x64

(registry/INFO) insert 'ice.pref.type.peer_rflx' (UCHAR) succeeded: 0x6e

(registry/INFO) insert 'ice.pref.type.host' (UCHAR) succeeded: 0x7e

(registry/INFO) insert 'ice.pref.type.relayed' (UCHAR) succeeded: 0x05

(registry/INFO) insert 'ice.pref.type.srv_rflx_tcp' (UCHAR) succeeded: 0x63

(registry/INFO) insert 'ice.pref.type.peer_rflx_tcp' (UCHAR) succeeded: 0x6d

(registry/INFO) insert 'ice.pref.type.host_tcp' (UCHAR) succeeded: 0x7d

(registry/INFO) insert 'ice.pref.type.relayed_tcp' (UCHAR) succeeded: 0x00

(registry/INFO) insert 'stun' (registry) succeeded: stun

(registry/INFO) insert 'stun.client' (registry) succeeded: stun.client

(registry/INFO) insert 'stun.client.maximum_transmits' (UINT4) succeeded: 7

(registry/INFO) insert 'ice.trickle_grace_period' (UINT4) succeeded: 5000

(registry/INFO) insert 'ice.tcp' (registry) succeeded: ice.tcp

(registry/INFO) insert 'ice.tcp.so_sock_count' (INT4) succeeded: 0

(registry/INFO) insert 'ice.tcp.listen_backlog' (INT4) succeeded: 10

(registry/INFO) insert 'ice.tcp.disable' (char) succeeded: \001

(ice/NOTICE) ICE(PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/)): peer (PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/):default) no streams with non-empty check lists

(ice/NOTICE) ICE(PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/)): peer (PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/):default) no streams with pre-answer requests

(ice/NOTICE) ICE(PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/)): peer (PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/):default) no checks to start

(ice/INFO) ICE-PEER(PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/):default)/CAND-PAIR(twON): setting pair to state FROZEN: twON|IP4:192.168.8.100:53095/UDP|IP4:10.76.93.143:51210/UDP(host(IP4:192.168.8.100:53095/UDP)|candidate:3063157045 1 udp 2122260223 10.76.93.143 51210 typ host generation 0)

(ice/INFO) ICE(PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/))/CAND-PAIR(twON): Pairing candidate IP4:192.168.8.100:53095/UDP (7e7f00ff):IP4:10.76.93.143:51210/UDP (7e7f1eff) priority=9115005270282354174 (7e7f00fffcfe3dfe)

(ice/INFO) ICE-PEER(PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/):default)/ICE-STREAM(0-1475043603256000 (id=48 url=http://66.172.10.133:8080/) aLevel=0): Starting check timer for stream.

(ice/INFO) ICE-PEER(PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/):default)/CAND-PAIR(twON): setting pair to state WAITING: twON|IP4:192.168.8.100:53095/UDP|IP4:10.76.93.143:51210/UDP(host(IP4:192.168.8.100:53095/UDP)|candidate:3063157045 1 udp 2122260223 10.76.93.143 51210 typ host generation 0)

(ice/INFO) ICE-PEER(PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/):default)/CAND-PAIR(twON): setting pair to state IN_PROGRESS: twON|IP4:192.168.8.100:53095/UDP|IP4:10.76.93.143:51210/UDP(host(IP4:192.168.8.100:53095/UDP)|candidate:3063157045 1 udp 2122260223 10.76.93.143 51210 typ host generation 0)

(ice/NOTICE) ICE(PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/)): peer (PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/):default) is now checking

(ice/WARNING) ICE(PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/)): Error parsing attribute: candidate:4162317765 1 tcp 1518280447 10.76.93.143 0 typ host tcptype active generation 0

(ice/WARNING) ICE-PEER(PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/):default): no pairs for 0-1475043603256000 (id=48 url=http://66.172.10.133:8080/) aLevel=0

(ice/INFO) ICE(PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/)): peer (PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/):default) Trickle grace period is over; marking every component with only failed pairs as failed.

(stun/INFO) STUN-CLIENT(twON|IP4:192.168.8.100:53095/UDP|IP4:10.76.93.143:51210/UDP(host(IP4:192.168.8.100:53095/UDP)|candidate:3063157045 1 udp 2122260223 10.76.93.143 51210 typ host generation 0)): Timed out

(ice/INFO) ICE-PEER(PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/):default)/CAND-PAIR(twON): setting pair to state FAILED: twON|IP4:192.168.8.100:53095/UDP|IP4:10.76.93.143:51210/UDP(host(IP4:192.168.8.100:53095/UDP)|candidate:3063157045 1 udp 2122260223 10.76.93.143 51210 typ host generation 0)

(ice/INFO) ICE-PEER(PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/):default)/STREAM(0-1475043603256000 (id=48 url=http://66.172.10.133:8080/) aLevel=0)/COMP(1): All pairs are failed, and grace period has elapsed. Marking component as failed.

(ice/INFO) ICE-PEER(PC:1475043603256000 (id=48 url=http://66.172.10.133:8080/):default): all checks completed success=0 fail=1

+++++++ END ++++++++

1 个答案:

答案 0 :(得分:1)

使用https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/检查您的TURN服务器 如果您获得候选中继,您的TURN服务器可以正常工作。我只能看到类型为srflx的候选人,这通常表明您的转弯服务器可以访问,但身份验证失败。

此外,在网址字段中使用用户名和网址代替旧用户@ host语法。