Remote-Videostreams funktioniert nicht mit WebRTC
EDIT: ich schrieb eine detaillierte Anleitung, die erklärt, wie man ein einfaches Videochat-Anwendung einschließlich eines signaling-server:
Tutorial: Erstellen Sie Ihre eigenen Videochat-Anwendung mit HTML und JavaScript
Bitte sagen Sie mir, wenn Sie finden es hilfreich, die & verständlich. Danke!
ich versuche Streams zu arbeiten, über WebRTC und Websocket (nodejs-server). Soweit ich sehen kann der handshake über SDP-Werke und die Peerconnection etabliert ist.
Das problem ist, die Remote-Video nicht wiedergegeben wird. Das src-Attribut wird der Blob und die automatische Wiedergabe ist gesetzt, aber es will einfach nicht spielen.
Vielleicht bin ich etwas falsch mit dem ICE-Kandidaten (Sie sind für media-streaming, richtig?).
Gibt es eine Möglichkeit zu überprüfen, ob die PeerConnection richtig eingerichtet ist?
EDIT: Vielleicht sollte ich erklären, wie der code funktioniert
-
Beim laden der website eine Verbindung zum websocket-server hergestellt ist, eine PeerConnection mit googles STUN-server erstellt und die Video-und Audio-Streams werden gesammelt & Hinzugefügt, um die PeerConnection
-
Wenn ein Benutzer klickt auf "Angebot erstellen"-button eine Nachricht mit seiner Session-Beschreibung (SDP) wird an den server senden (client func sendOffer()), was sendet es an den anderen Benutzer
-
Der andere Benutzer erhält die Nachricht und speichert die SDP erhielt er
-
Wenn der Benutzer klickt auf "Angebot akzeptieren", das SDP Hinzugefügt RemoteDescription (func createAnswer ()), die sendet dann eine Antwort-Nachricht (mit der SDP von der Beantwortung-Benutzer), um das Angebot-Nutzer
-
Beim Angebot-user-Seite das func offerAccepted() ausgeführt wird, fügt die SDP von den anderen user seinen RemoteDesription.
Ich bin nicht sicher, an welchem Punkt genau die icecandidate-Handler aufgerufen werden, aber ich denke, Sie sollten arbeiten, weil ich beide Protokolle auf beiden Seiten.
Hier mein Code (dies ist nur für Testzwecke, also selbst wenn es eine Funktion namens broadcast bedeutet es, dass nur 2 user können auf der gleichen website zu einem Zeitpunkt):
Markup 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>
Hier ist der Server-Code:
"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
};
});
Und hier den Client-Code:
$(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();
});
});
Ich auch gelesen, dass der local-media-stream aufgefangen werden muss, bevor Sie ein Angebot senden. Bedeutet das, ich muss hinzufügen, dass es, wenn die PeerConnection erstellt?
I. e. so etwas wie dieses:
//create Connection
var peerConnection = new webkitRTCPeerConnection(
{
"iceServers": [{ "url": "stun:stun.l.google.com:19302" }],
"mediaStream": stream //attach media stream here?
}
);
Vielen Dank im Voraus, ich freue mich über jede Hilfe!!!
EDIT2:
ich bin ein Stück weiter jetzt. es scheint, dass das hinzufügen der remote-Eis-Kandidaten (switch-case-setIceCandidate, die im client-code) nicht funktioniert, weil der "Eine ungültige oder illegale string angegeben wurde. ". das json-Format.Daten.Kandidaten-Objekt sieht wie folgt aus:
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"
habe ich versucht die Schaffung einer neuen Kandidaten wie diese
var remoteCandidate = new RTCIceCandidate(json.data.candidate);
peerConnection.addIceCandidate(remoteCandidate);
aber ich habe immer noch ein syntax-Fehler
- Vielleicht hilft das: stackoverflow.com/questions/17346616/...
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich hatte Schwierigkeiten, mit im wesentlichen der gleichen Sache vor kurzem, und der beste Rat, den ich von jemandem bekommen hat, hier wurde auf eine version von meinem Programm, in dem ich manuell kopiert und eingefügt, der SDP und ICE info von einem "peer" (d.h., browser-tab) zum anderen und Umgekehrt.
Dadurch, erkannte ich einige Dinge:
Müssen Sie rufen Sie die addStream Methode des peer-connection-Objekt vor Sie versuchen, erstellen Angebote/Antworten.
Beim Aufruf der createOffer oder createAnswer Methode, das EIS Kandidaten für diesen client sind sofort generiert. Allerdings, wenn Sie geschickt haben, dem EIS info an die anderen peer, können Sie tatsächlich setzen Sie die EIS-info erst nach einer remote-Beschreibung festgelegt ist (durch die Verwendung der erhaltenen Angebot/Antwort).
Stellen Sie sicher, dass Sie ordnungsgemäß Codierung alle Infos zu gesendet, der auf dem Draht. In JS, das bedeutet, dass Sie verwenden sollten, die alsterrunde Funktion auf alle Daten, die versendet werden soll, auf dem Draht. Ich hatte ein Problem in der SDP und EIS info würde mal korrekt eingestellt werden und manchmal nicht. Es hatte mit der Tatsache zu tun, dass ich nicht URI-encoding der Daten, die dazu geführt, dass ein plus-Zeichen in die Daten, die sich in Räumen, die versaut alles.
Sowieso, wie ich schon sagte, ich empfehlen, eine version des Programms, in dem Sie eine Reihe von text-Bereiche für die spuckt alle Daten auf den Bildschirm, und dann haben andere Textbereiche, können Sie die kopierten Daten in die für die Einstellung für den anderen peer.
Tut das wirklich geklärt ist das ganze WebRTC Prozess, ehrlich gesagt, nicht gut erklärt in der alle Dokumente/Anleitungen, die ich bisher gesehen habe.
Glück, und lassen Sie mich wissen, wenn ich helfen kann mehr.