WebRTC:ICE、STUN 和 TURN,但我不能只使用我的 SignalR.NET 连接吗?
Posted
技术标签:
【中文标题】WebRTC:ICE、STUN 和 TURN,但我不能只使用我的 SignalR.NET 连接吗?【英文标题】:WebRTC: ICE, STUN and TURN, but can't I just use my SignalR.NET connection? 【发布时间】:2018-04-20 00:53:10 【问题描述】:我目前正在开发一个会议视频网络应用程序。我决定走WebRTC路线,但我仍然不清楚如何正确使用它。
我的应用程序是在 ASP.NET MVC 中制作的,我还添加了 SignalR 用于聊天/通知功能。我需要在用户之间建立实时连接并记录扬声器的流。扬声器的录音现在可以正常工作了。
我创建了一个页面,启动媒体记录器来捕获用户的网络摄像头,然后我附加到 ondataavailable 事件以捕获网络摄像头数据:
mediaRecorder.ondataavailable = function (e)
console.log('Data received: ', e);
// Increase index
streamindex++;
// Save client dates
var stopdate = new Date();
var startdate = olddate;
olddate = stopdate;
// Format dates
var startdatestr =
startdate.getFullYear() + "-" +
startdate.getMonth() + "-" +
startdate.getDate() + " " +
startdate.getHours() + ':' +
startdate.getMinutes() + ':' +
startdate.getSeconds() + '.' +
startdate.getMilliseconds();
var stopdatestr =
stopdate.getFullYear() + "-" +
stopdate.getMonth() + "-" +
stopdate.getDate() + " " +
stopdate.getHours() + ':' +
stopdate.getMinutes() + ':' +
stopdate.getSeconds() + '.' +
stopdate.getMilliseconds();
// Send data to server
$.ajax(
url: '/Upload?StreamId=' + streamid + '&Index=' + streamindex + '&StartDate=' + startdatestr + '&StopDate=' + stopdatestr,
type: 'POST',
contentType: 'application/octet-stream',
data: e.data,
processData: false
);
;
我在服务器上保存数据,这似乎工作得很好。
现在我想在客户端之间建立点对点连接,我在网上查看了如何做到这一点,但我发现我必须使用 STUN 和 TURN 服务器来创建连接。因为我使用 .NET,所以我不太喜欢必须部署 nodejs 服务器的想法。我在网上找到了这段代码:
function call()
callButton.disabled = true;
hangupButton.disabled = false;
trace("Starting call");
if (localStream.getVideoTracks().length > 0)
trace('Using video device: ' + localStream.getVideoTracks()[0].label);
if (localStream.getAudioTracks().length > 0)
trace('Using audio device: ' + localStream.getAudioTracks()[0].label);
var servers = null;
localPeerConnection = new RTCPeerConnection(servers);
trace("Created local peer connection object localPeerConnection");
localPeerConnection.onicecandidate = gotLocalIceCandidate;
remotePeerConnection = new RTCPeerConnection(servers);
trace("Created remote peer connection object remotePeerConnection");
remotePeerConnection.onicecandidate = gotRemoteIceCandidate;
remotePeerConnection.onaddstream = gotRemoteStream;
localPeerConnection.addStream(localStream);
trace("Added localStream to localPeerConnection");
localPeerConnection.createOffer(gotLocalDescription, handleError);
function gotLocalDescription(description)
localPeerConnection.setLocalDescription(description);
trace("Offer from localPeerConnection: \n" + description.sdp);
remotePeerConnection.setRemoteDescription(description);
remotePeerConnection.createAnswer(gotRemoteDescription, handleError);
function gotRemoteDescription(description)
remotePeerConnection.setLocalDescription(description);
trace("Answer from remotePeerConnection: \n" + description.sdp);
localPeerConnection.setRemoteDescription(description);
function hangup()
trace("Ending call");
localPeerConnection.close();
remotePeerConnection.close();
localPeerConnection = null;
remotePeerConnection = null;
hangupButton.disabled = true;
callButton.disabled = false;
function gotRemoteStream(event)
remoteVideo.src = URL.createObjectURL(event.stream);
trace("Received remote stream");
function gotLocalIceCandidate(event)
if (event.candidate)
remotePeerConnection.addIceCandidate(new RTCIceCandidate(event.candidate));
trace("Local ICE candidate: \n" + event.candidate.candidate);
function gotRemoteIceCandidate(event)
if (event.candidate)
localPeerConnection.addIceCandidate(new RTCIceCandidate(event.candidate));
trace("Remote ICE candidate: \n " + event.candidate.candidate);
本示例使用本地 RTCPeerConnection 发送视频/音频数据。如果我想在线使用这个示例,我应该将 STUN / TURN 服务器添加到“servers”变量中。但是由于我没有 STUN / TURN 服务器,有什么方法可以使用 SignalR 建立 WebRTC 连接?
(SignalR 让我可以非常轻松地在客户端之间发送消息/数据)
【问题讨论】:
【参考方案1】:好的,原来我必须使用 Turn/Stun 服务器,因为它尝试在客户端之间建立点对点连接,并且支持所有 WebRTC 功能。
另一方面,WebRTC 确实需要您拥有自己的信令服务来建立客户端之间的连接。这就是 SignalR 的用武之地,在设置 RTCPeerConnection 时,您需要设置一些事件处理程序,例如您需要向其他客户端发送信号的“oniceccandidate”和“onaddstream”。
我在网上找到了这个例子:https://www.skylinetechnologies.com/Blog/Skyline-Blog/February-2013/Peer-to-Peer-Media-Streaming-with-WebRTC-and-Signa
(function ()
var _myConnection,
_myMediaStream;
function _createConnection(onStreamAddedCallback)
// Create a new PeerConnection
var connection = new webkitRTCPeerConnection(null);
// ICE Candidate Callback
connection.onicecandidate = function (event)
if (event.candidate)
hub.server.send(JSON.stringify( "candidate": event.candidate ));
;
// Negotiation needed callback
connection.onnegotiationneeded = function ()
connection.createOffer(function (desc)
connection.setLocalDescription(desc, function ()
hub.server.send(JSON.stringify( "sdp": connection.localDescription ));
);
);
;
// Stream handler
connection.onaddstream = onStreamAddedCallback;
return connection;
// Set Up SignalR Signaler
var hub = $.connection.webRtcHub;
$.support.cors = true;
$.connection.hub.url = '/signalr/hubs';
$.connection.hub.start( xdomain: true , function ()
console.log('connected to hub.');
init();
);
hub.client.newMessage = function (data)
var message = JSON.parse(data),
connection = _myConnection || _createConnection(onAddStream);
if (message.sdp)
connection.setRemoteDescription(new RTCSessionDescription(message.sdp), function ()
if (connection.remoteDescription.type == "offer")
console.log('received offer, sending response...');
connection.createAnswer(function (desc)
connection.setLocalDescription(desc, function ()
hub.server.send(JSON.stringify( "sdp": connection.localDescription ));
);
);
);
else if (message.candidate)
console.log('adding ice candidate...');
connection.addIceCandidate(new RTCIceCandidate(message.candidate));
_myConnection = connection;
;
function onAddStream(event)
console.log('Adding stream id: ' + event.stream.id);
var newVideoElement = document.createElement('video');
newVideoElement.className = 'video';
newVideoElement.src = window.webkitURL.createObjectURL(event.stream);
newVideoElement.autoplay = 'autoplay';
document.querySelector('body').appendChild(newVideoElement);
function init()
navigator.webkitGetUserMedia(
// Request Permissions
video: true,
audio: true
,
function (stream) // succcess callback
var videoElement = document.querySelector('.video.mine');
_myMediaStream = stream;
videoElement.src = window.webkitURL.createObjectURL(_myMediaStream);
console.log('my stream id: ' + stream.id);
$('#startBtn').removeAttr('disabled');
,
function (error) // error callback
alert(JSON.stringify(error));
);
$('#startBtn').click(function ()
_myConnection = _createConnection(onAddStream);
_myConnection.addStream(_myMediaStream);
// done being able to work
$('#startBtn').attr('disabled', 'disabled');
);
)();
我用这段代码编写了我自己的客户端和服务器库(我想要一个一对多的视频会议系统)。您可以使用从 navigator.webkitGetUserMedia 获得的流来连接多个 RTCPeerConnections。知道了这部分之后,一切就都到位了。
【讨论】:
您好,您的工作解决方案与非工作解决方案有什么不同?你能在不使用 STUN 或 TURN 服务器的情况下让它工作吗?我能看到的唯一区别是您的解决方案使用“webkitRTCPeerConnection” 老问题,不,除非您的一位参与者直接连接到互联网(使用路由器),否则没有眩晕/转弯是不可能让它工作的。 @ikwillem 你能否分享一个工作样本,我需要了解所有活动部件。谢谢 嘿@ikwillem,你找到这个问题的解决方案了吗? 这是一个老问题,今天“onAddStream”和“AddStream”已经被贬低了。所以代码很可能不再起作用。有多个较新的示例可用:webrtc.github.io/samples 这也很有帮助developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/…以上是关于WebRTC:ICE、STUN 和 TURN,但我不能只使用我的 SignalR.NET 连接吗?的主要内容,如果未能解决你的问题,请参考以下文章