请告诉我你是否觉得它有用&可以理解的。谢谢!
我试图让Streams通过WebRTC和Websocket(nodejs-server)工作。据我所知,通过SDP的握手工作,并建立了Peerconnection。 问题是 - 远程视频没有播放。 src-Attribute获取了Blob并设置了自动播放,但它只是不会播放。 也许我对ICE候选人做错了(他们用于媒体流,对吧?)。 有没有办法检查PeerConnection是否设置正确?
编辑:也许我应该解释一下代码是如何工作的
在网站加载时建立与websocket-server的连接,创建使用googles STUN-server的PeerConnection,并收集视频和音频流。添加到PeerConnection
当一个用户点击“创建商品”时 - 按钮会将包含其会话描述(SDP)的消息发送到服务器(客户端功能sendOffer()),该服务器将其广播给其他用户
其他用户收到消息并保存他收到的SDP
如果用户点击“接受报价”,SDP将被添加到RemoteDescription(func createAnswer()),然后该报告会向产品用户发送应答消息(包含应答用户的SDP)
在产品用户方面执行func offerAccepted(),将其他用户的SDP添加到他的RemoteDesription中。
我不确定在什么时候确切地调用了icecandidate处理程序,但我认为它们应该可以正常工作,因为我同时获得两个日志。
这是我的代码(这只是用于测试,所以即使有一个叫做广播的功能,也意味着一次只有2个用户可以在同一个网站上):
index.html的标记:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
#acceptOffer {
display: none;
}
</style>
</head>
<body>
<h2>Chat</h2>
<div>
<textarea class="output" name="" id="" cols="30" rows="10"></textarea>
</div>
<button id="createOffer">create Offer</button>
<button id="acceptOffer">accept Offer</button>
<h2>My Stream</h2>
<video id="myStream" autoplay src=""></video>
<h2>Remote Stream</h2>
<video id="remoteStream" autoplay src=""></video>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="websocketClient.js"></script>
</body>
</html>
以下是服务器代码:
"use strict";
var webSocketsServerPort = 61122;
var webSocketServer = require('websocket').server,
http = require('http'),
clients = [];
var server = http.createServer(function(request, response) {
// Not important for us. We're writing WebSocket server, not HTTP server
});
server.listen(webSocketsServerPort, function() {
console.log((new Date()) + " Server is listening on port " + webSocketsServerPort);
});
var wsServer = new webSocketServer({
httpServer: server
});
wsServer.on('request', function(request) {
console.log((new Date()) + ' Connection from origin ' + request.origin + '.');
var connection = request.accept(null, request.origin),
index = clients.push(connection) - 1,
userName=false;
console.log((new Date()) + ' Connection accepted from '+connection.remoteAddress);
// user sent some message
connection.on('message', function(message) {
var json = JSON.parse(message.utf8Data);
console.log(json.type);
switch (json.type) {
case 'broadcast':
broadcast(json);
break;
case 'emit':
emit({type:'offer', data:json.data.data});
break;
case 'client':
respondToClient(json, clients[index]);
break;
default:
respondToClient({type:'error', data:'Sorry, i dont understand that.'}, clients[index]);
break;
}
});
connection.on('close', function(connection) {
clients.splice(index,1);
console.log((new Date()) + " Peer " + connection.remoteAddress + " disconnected.");
broadcast({type:'text', data: userName+' has left the channel.'});
});
var respondToClient = function(data, client){
client.sendUTF(JSON.stringify( data ));
};
var broadcast = function(data){
for(var i = 0; i < clients.length; i++ ) {
if(i != index ) {
clients[i].sendUTF(JSON.stringify( data ));
}
}
};
var emit = function(){
// TBD
};
});
这里是客户代码:
$(function () {
"use strict";
/**
* Websocket Stuff
**/
window.WebSocket = window.WebSocket || window.MozWebSocket;
// open connection
var connection = new WebSocket('ws://url-to-node-server:61122'),
myName = false,
mySDP = false,
otherSDP = false;
connection.onopen = function () {
console.log("connection to WebSocketServer successfull");
};
connection.onerror = function (error) {
console.log("WebSocket connection error");
};
connection.onmessage = function (message) {
try {
var json = JSON.parse(message.data),
output = document.getElementsByClassName('output')[0];
switch(json.callback) {
case 'offer':
otherSDP = json.data;
document.getElementById('acceptOffer').style.display = 'block';
break;
case 'setIceCandidate':
console.log('ICE CANDITATE ADDED');
peerConnection.addIceCandidate(json.data);
break;
case 'text':
var text = output.value;
output.value = json.data+'\n'+output.value;
break;
case 'answer':
otherSDP = json.data;
offerAccepted();
break;
}
} catch (e) {
console.log('This doesn\'t look like a valid JSON or something else went wrong.');
return;
}
};
/**
* P2P Stuff
**/
navigator.getMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
// create Connection
var peerConnection = new webkitRTCPeerConnection(
{ "iceServers": [{ "url": "stun:stun.l.google.com:19302" }] }
);
var remoteVideo = document.getElementById('remoteStream'),
myVideo = document.getElementById('myStream'),
// get local video-Stream and add to Peerconnection
stream = navigator.webkitGetUserMedia({ audio: false, video: true }, function (stream) {
myVideo.src = webkitURL.createObjectURL(stream);
console.log(stream);
peerConnection.addStream(stream);
});
// executes if other side adds stream
peerConnection.onaddstream = function(e){
console.log("stream added");
if (!e)
{
return;
}
remoteVideo.setAttribute("src",URL.createObjectURL(e.stream));
console.log(e.stream);
};
// executes if my icecandidate is received, then send it to other side
peerConnection.onicecandidate = function(candidate){
console.log('ICE CANDITATE RECEIVED');
var json = JSON.stringify( { type: 'broadcast', callback:'setIceCandidate', data:candidate});
connection.send(json);
};
// send offer via Websocket
var sendOffer = function(){
peerConnection.createOffer(function (sessionDescription) {
peerConnection.setLocalDescription(sessionDescription);
// POST-Offer-SDP-For-Other-Peer(sessionDescription.sdp, sessionDescription.type);
var json = JSON.stringify( { type: 'broadcast', callback:'offer',data:{sdp:sessionDescription.sdp,type:'offer'}});
connection.send(json);
}, null, { 'mandatory': { 'OfferToReceiveAudio': true, 'OfferToReceiveVideo': true } });
};
// executes if offer is received and has been accepted
var createAnswer = function(){
peerConnection.setRemoteDescription(new RTCSessionDescription(otherSDP));
peerConnection.createAnswer(function (sessionDescription) {
peerConnection.setLocalDescription(sessionDescription);
// POST-answer-SDP-back-to-Offerer(sessionDescription.sdp, sessionDescription.type);
var json = JSON.stringify( { type: 'broadcast', callback:'answer',data:{sdp:sessionDescription.sdp,type:'answer'}});
connection.send(json);
}, null, { 'mandatory': { 'OfferToReceiveAudio': true, 'OfferToReceiveVideo': true } });
};
// executes if other side accepted my offer
var offerAccepted = function(){
peerConnection.setRemoteDescription(new RTCSessionDescription(otherSDP));
console.log('it should work now');
};
$('#acceptOffer').on('click',function(){
createAnswer();
});
$('#createOffer').on('click',function(){
sendOffer();
});
});
我还读到在发送任何优惠之前必须收集本地媒体流。这是否意味着我必须在创建PeerConnection时添加它? 即像这样的东西:
// create Connection
var peerConnection = new webkitRTCPeerConnection(
{
"iceServers": [{ "url": "stun:stun.l.google.com:19302" }],
"mediaStream": stream // attach media stream here?
}
);
提前致谢,我感谢任何帮助!
EDIT2: 我现在更进一步了。似乎添加远程ice-candidate(客户端代码中的switch-case setIceCandidate)因为“指定了无效或非法字符串”而无法正常工作。 json.data.candidate-object如下所示:
candidate: "a=candidate:1663431597 2 udp 1845501695 141.84.69.86 57538 typ srflx raddr 10.150.16.92 rport 57538 generation 0
↵"
sdpMLineIndex: 1
sdpMid: "video"
我尝试创建像这样的新候选人
var remoteCandidate = new RTCIceCandidate(json.data.candidate);
peerConnection.addIceCandidate(remoteCandidate);
但我仍然有语法错误
答案 0 :(得分:21)
我最近遇到了基本相同的问题,我在这里得到的最好的建议是创建我的程序版本,我在其中手动复制并粘贴来自一个“同行”的SDP和ICE信息(即浏览器选项卡)到另一个,反之亦然。
通过这样做,我意识到了几件事:
您必须在 之前调用对等连接对象 的addStream方法,以尝试创建任何要约/答案。
在调用createOffer或createAnswer方法时,会立即生成该客户端的ICE候选项。但是,一旦您将ICE信息发送给另一个对等方,您就无法在设置远程描述之后(通过使用收到的要约/回答)实际设置ICE信息。
确保您正确编码要在线路上发送的所有信息。在JS中,这意味着您应该对要在线上发送的所有数据使用encodeURIComponent函数。我有一个问题,其中SDP和ICE信息有时会被正确设置,有时不会。这与我不对数据进行URI编码这一事实有关,这导致数据中的任何加号变成了空格,这搞砸了所有内容。
无论如何,就像我说的,我建议您创建一个程序版本,其中有一堆文本区域用于将所有数据吐出到屏幕上,然后有其他文本区域可以将复制的数据粘贴到为另一个同伴设置它 这样做真的澄清了整个WebRTC流程,老实说,在我见过的任何文档/教程中都没有很好的解释。
祝你好运,如果我能帮助我,请告诉我。
答案 1 :(得分:0)
function sharescreen(){
getScreenStream(function(screenStream) {
localpearconnection.removeTrack(localStream);
localpearconnection.addStream(screenStream);
localpearconnection.createOffer().then(description => createdLocalDescription(description)).catch(errorHandler);
document.getElementById('localVideo').srcObject = screenStream;});}
function getScreenStream(callback) {
if (navigator.getDisplayMedia) {
navigator.getDisplayMedia({
video: true
}).then(screenStream => {
callback(screenStream);
});
} else if (navigator.mediaDevices.getDisplayMedia) {
navigator.mediaDevices.getDisplayMedia({
video: true
}).then(screenStream => {
callback(screenStream);
});
} else {
getScreenId(function(error, sourceId, screen_constraints) {
navigator.mediaDevices.getUserMedia(screen_constraints).then(function(screenStream) {
callback(screenStream);
});
});
}}
上面的代码对我有用。