I can't receive any data from the remote stream and the div with the id of the remote streams that I've created with Javascript doesn't show I don't understand why ! The Javascript code doesn't work on the browser it's a little bit strange it's my first time coming across with this kind of problem please help me solve it.
This is the code :
// Local stream
// rtc object
var rtc = {
client: null,
joined: false,
published: false,
localStream: null,
remoteStreams: [],
params: {}
};
// Options for joining a channel
var option = {
mode: "rtc",
codec: "h264",
appID: "22a27d03d0edf54749a03597d72ad82aaa78",
channel: "qiossa",
uid: null,
token: "006a27d03d0edf54749a03597d72ad82aaaIADHJF46Q3g4Jn+mjfRgh5Le76OO2BpUfEuvw1Qv+35XKFwgy+4AAAAAEACfOV6k44bGXgEAAQCIh8Ze"
};
// Create a client
rtc.client = AgoraRTC.createClient({mode: option.mode, codec: option.codec});
// Initialize the client
rtc.client.init(option.appID, function () {
console.log("init success");
}, (err) => {
console.error(err);
});
// Join a channel
rtc.client.join(option.token, option.channel, option.uid, function (uid) {
console.log("join channel: " + option.channel + " success, uid: " + uid);
rtc.params.uid = uid;
}, function(err) {
console.error("client join failed", err);
});
// Create a local stream
rtc.localStream = AgoraRTC.createStream({
streamID: rtc.params.uid,
audio: true,
video: true,
screen: false,
});
// Initialize the local stream
rtc.localStream.init(function () {
console.log("init local stream success");
// play stream with html element id "local_stream"
rtc.localStream.play("local_stream");
}, function (err) {
console.error("init local stream failed ", err);
});
// Publish the local stream
rtc.client.publish(rtc.localStream, function (err) {
console.log("publish failed");
console.error(err);
});
//*************************************************************************************************************//
// Remote stream
rtc.client.on("stream-added", function (evt) {
var remoteStream = evt.stream;
var id = remoteStream.getId();
if (id !== rtc.params.uid) {
rtc.client.subscribe(remoteStream, function (err) {
console.log("stream subscribe failed", err);
});
}
console.log("stream-added remote-uid: ", id);
});
rtc.client.on("stream-subscribed", function (evt) {
var remoteStream = evt.stream;
var id = remoteStream.getId();
// Add a view for the remote stream.
let streamDiv=document.createElement("div"); // Create a new div for every stream
streamDiv.id= id; // Assigning id to div
streamDiv.style.transform="rotateY(180deg)"; // Takes care of lateral inversion (mirror image)
remoteContainer.appendChild(streamDiv);
// Play the remote stream.
remoteStream.play("remote_video_" + id);
console.log("stream-subscribed remote-uid: ", id);
});
Photo of the problem
The local stream needs to be created, initialised, played and published within the join function.
This is the corrected code for the rtc.client.join() function:
rtc.client.join(option.token, option.channel, option.uid, (uid)=>{
console.log("join channel: " + option.channel + " success, uid: " + uid);
rtc.params.uid = uid;
// Create a local stream
rtc.localStream = AgoraRTC.createStream({
streamID: rtc.params.uid,
audio: true,
video: true,
screen: false,
});
// Initialize the local stream
rtc.localStream.init(function () {
console.log("init local stream success");
// play stream with html element id "local_stream"
rtc.localStream.play("local_stream");
}, function (err) {
console.error("init local stream failed ", err);
});
// Publish the local stream
rtc.client.publish(rtc.localStream, function (err) {
console.log("publish failed");
console.error(err);
});
}, function(err) {
console.error("client join failed", err);
});
Get back to us for any further queries.
console problems
// Local stream
// rtc object
var rtc = {
client: null,
joined: false,
published: false,
localStream: null,
remoteStreams: [],
params: {}
};
// Options for joining a channel
var option = {
mode: "rtc",
codec: "h264",
appID: "",
channel: "qiossa",
uid: null,
token: "006a27d03d0edf54749a03597d72ad82aaaIADkVIvop7lo0OEkm/7Tuz/Tp4M+TXhFd9DkLAAwu9fNllwgy+4AAAAAEAD4aAmV2FzKXgEAAQBjT8pe"
};
// Create a client
rtc.client = AgoraRTC.createClient({mode: option.mode, codec: option.codec});
// Initialize the client
rtc.client.init(option.appID, function () {
console.log("init success");
}, (err) => {
console.error(err);
});
// Join a channel
rtc.client.join(option.token, option.channel, option.uid, function (uid) {
console.log("join channel: " + option.channel + " success, uid: " + uid);
rtc.params.uid = uid;
// Create a local stream
rtc.localStream = AgoraRTC.createStream({
streamID: rtc.params.uid,
audio: true,
video: true,
screen: false,
});
// Initialize the local stream
rtc.localStream.init(function () {
console.log("init local stream success");
// play stream with html element id "local_stream"
rtc.localStream.play("local_stream");
}, function (err) {
console.error("init local stream failed ", err);
});
// Publish the local stream
rtc.client.publish(rtc.localStream, function (err) {
console.log("publish failed");
console.error(err);
});
}, function(err) {
console.error("client join failed", err);
});
//*************************************************************************************************************//
// Remote stream
rtc.client.on("stream-added", function (evt) {
var remoteStream = evt.stream;
var id = remoteStream.getId();
if (id !== rtc.params.uid) {
rtc.client.subscribe(remoteStream, function (err) {
console.log("stream subscribe failed", err);
});
}
console.log("stream-added remote-uid: ", id);
});
rtc.client.on("stream-subscribed", function (evt) {
var remoteStream = evt.stream;
var id = remoteStream.getId();
// Add a view for the remote stream.
addView(id);
// Play the remote stream.
remoteStream.play("remote_video_" + id);
console.log("stream-subscribed remote-uid: ", id);
});
rtc.client.on("stream-removed", function (evt) {
var remoteStream = evt.stream;
var id = remoteStream.getId();
// Stop playing the remote stream.
remoteStream.stop("remote_video_" + id);
// Remove the view of the remote stream.
removeView(id);
console.log("stream-removed remote-uid: ", id);
});
// Leave the channel
rtc.client.leave(function () {
// Stop playing the local stream
rtc.localStream.stop();
// Close the local stream
rtc.localStream.close();
// Stop playing the remote streams and remove the views
while (rtc.remoteStreams.length > 0) {
var stream = rtc.remoteStreams.shift();
var id = stream.getId();
stream.stop();
removeView(id);
}
console.log("client leaves channel success");
}, function (err) {
console.log("channel leave failed");
console.error(err);
});
function addView (id, show) {
if (!$("#" + id)[0]) {
$("<div/>", {
id: "remote_video_panel_" + id,
class: "video-view",
}).appendTo("#video")
$("<div/>", {
id: "remote_video_" + id,
class: "video-placeholder",
}).appendTo("#remote_video_panel_" + id)
$("<div/>", {
id: "remote_video_info_" + id,
class: "video-profile " + (show ? "" : "hide"),
}).appendTo("#remote_video_panel_" + id)
$("<div/>", {
id: "video_autoplay_"+ id,
class: "autoplay-fallback hide",
}).appendTo("#remote_video_panel_" + id)
}
}
function removeView (id) {
if ($("#remote_video_panel_" + id)[0]) {
$("#remote_video_panel_"+id).remove()
}
}
Related
I am trying to transfer a video streaming from one browser to another with WebRTC and socket.io. It works just fine in the same network. No image is getting through across different ones.
I use socket-io as a signal server. I register two browsers in a "room" and then start sending signals.
The code which is executed in the browser from which the streaming is sent:
function joinRoom(room) {
if (room === '') {
alert('Please type a room ID')
} else {
data = { room: room};
socket.emit('join', data);
}
}
// SOCKET EVENT CALLBACKS =====================================================
socket.on('room_created', async () => {
console.log('Socket event callback: room_created')
await setLocalStream(mediaConstraints)
socket.emit('startc', {room: roomId, clientip: clientip})
isRoomCreator = true
})
socket.on('full_room', () => {
console.log('Socket event callback: full_room')
alert('The room is full, please try another one')
})
socket.on('startc', async () => {
console.log('Socket event callback: start_call')
if (isRoomCreator) {
rtcPeerConnection = new RTCPeerConnection(iceServers)
addLocalTracks(rtcPeerConnection)
rtcPeerConnection.ontrack = setRemoteStream
rtcPeerConnection.onicecandidate = sendIceCandidate
await createOffer(rtcPeerConnection)
}
})
socket.on('offer', async (event) => {
console.log('Socket event callback: offer')
if (!isRoomCreator) {
rtcPeerConnection = new RTCPeerConnection(iceServers)
addLocalTracks(rtcPeerConnection)
rtcPeerConnection.ontrack = setRemoteStream
rtcPeerConnection.onicecandidate = sendIceCandidate
rtcPeerConnection.setRemoteDescription(new RTCSessionDescription(event))
await createAnswer(rtcPeerConnection)
}
})
socket.on('answer', (event) => {
console.log('answer');
console.log('Socket event callback: webrtc_answer')
rtcPeerConnection.setRemoteDescription(new RTCSessionDescription(event))
})
socket.on('webrtc_ice_candidate', (event) => {
console.log('Socket event callback: webrtc_ice_candidate')
// ICE candidate configuration.
var candidate = new RTCIceCandidate({
sdpMLineIndex: event.label,
candidate: event.candidate,
})
rtcPeerConnection.addIceCandidate(candidate)
})
The code that accepts the streamed media (vuejs):
socket.on("offer", (data) => {
this.$emit("closeWaitingToConnect");
this.createAnswer(data);
});
joinMeToRoom() {
console.log("joinToRoom: ", this.room);
this.$socket.emit("join", this.room);
}, //joinMeToRoom ()
createAnswer: function(event) {
var roomId = this.room.room;
let sessionDescription
this.peer.ontrack = this.setRemoteStream
this.peer.onicecandidate = this.sendIceCandidate
this.peer.setRemoteDescription(new RTCSessionDescription(event))
try {
sessionDescription = this.peer.createAnswer().then((answer) => {
var anwer =
console.log('sessionDescription');
console.log(answer);
this.$socket.emit('answer', {
type: 'webrtc_answer',
sdp: answer,
sessionDescription: JSON.stringify(answer),
roomId,
})
return this.peer.setLocalDescription(answer)
});
} catch (error) {
console.error('cae: '+error)
}
},
getScreenPosition() {
const right = this.$refs.screen.getBoundingClientRect().right;
const bottom = this.$refs.screen.getBoundingClientRect().bottom;
return { bottom: bottom, right: right };
},
setRemoteStream(event) {
console.log('event setRemoteStream');
console.log(event);
var stream_screen = document.querySelector("video");
stream_screen.srcObject = event.streams[0];
stream_screen.play();
var remoteStream = event.stream
},
I have setup my own TURN server and tried paid versions. Still can't get the stream across different networks.
What am I missing?
we are using peer js webrtc for video call. Everything is working fine just the problem is i am not able to switch camera during call. I have done some work where i can switch camera in local during call but its doesnt effect on remote area.
here is my code
$('select').on('change', function (e) {
navigator.mediaDevices.enumerateDevices().then(function (devices) {
var valueSelected = $("#myselect option:selected").val();
alert(valueSelected);
//var myselect = 0;
if (valueSelected == "0") {
var cameras = [];
devices.forEach(function (device) {
'videoinput' === device.kind && cameras.push(device.deviceId);
});
var constraints = { video: { deviceId: { exact: cameras[0] } } };
navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
window.localStream = stream;
myapp.setMyVideo(window.localStream)
//if (callback)
// callback();
}, function (err) {
console.log("The following error occurred: " + err.name);
alert('Unable to call ' + err.name)
});
}
else {
var cameras = [];
devices.forEach(function (device) {
'videoinput' === device.kind && cameras.push(device.deviceId);
});
var constraints = { video: { deviceId: { exact: cameras[1] } } };
navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
window.localStream = stream;
myapp.setMyVideo(window.localStream)
//if (callback)
// callback();
}, function (err) {
console.log("The following error occurred: " + err.name);
alert('Unable to call ' + err.name)
});
}
//var myselect = $("#myselect option:selected").val();
});
});
The recommended way to change stream when a peer-to-peer connection is established is to use replaceTrack function that does not require ICE renegotiation:
RTCRtpSender.replaceTrack
The documentation says:
Among the use cases for replaceTrack() is the common need to switch between the rear- and front-facing cameras on a phone. With replaceTrack(), you can simply have a track object for each camera and switch between the two as needed. See the example...
chrome version: 62.0.3202.94;
firefox version: 57.0.1;
I write a simple demo use webrtc and socket.io.
It works with pages. For example, I open one page to connect socket, and waiting for PeerConnection info from the main page(which get the local media). When I open the main, I create ice and sdp and then exchange them by socket.io to create connection.
Here is the code.
// The server side:
const express = require('express')
const app = express()
const path = require('path')
app.use(express.static(path.join(__dirname, 'public')))
app.get('/phone', function(req, res) {
res.sendfile(__dirname + '/phone.html')
})
app.get('/', function(req, res) {
res.sendfile(__dirname + '/index.html')
})
const server = require('http').createServer(app)
const io = require('socket.io')(server)
let clients = []
io.on('connection', function(socket) {
clients.push(socket)
const referer = socket.handshake.headers.referer
// socket connect from '/phone'
if (referer.match('/phone')) {
// send the ice from phone to others
socket.on('phone_ice_candidate', function(res) {
socket.broadcast.emit('pc_add_ice', {
ice: res.ice
})
})
// send the sdp from phone to others
socket.on('send_phone_sdp', function(data) {
socket.broadcast.emit('set_pc_remote_sdp', {
desc: data.desc
})
})
}
// phone add ice from web
socket.on('remote_ice_candidate', function(ice) {
socket.to(getId(clients, '/phone')).emit('send_ice_to_pc', {
ice: ice
})
})
// phone add sdp from web
socket.on('send_pc_sdp', function(data) {
// send to phone
socket.to(getId(clients, '/phone')).emit('set_phone_remote_sdp', {
desc: data
})
})
// socket disconnect and remove it from clients
socket.on('disconnect', () => {
let id = socket.id
clients.forEach((client, index) => {
if (client.id === id) {
clients.splice(index, 1)
}
})
})
})
// get the socket id to emit
function getId(sockets, exp) {
let id
sockets.forEach(socket => {
if (socket.handshake.headers.referer.match(exp)) {
id = socket.id
}
})
return id
}
server.listen(3000, function() {
console.log('port listening at 3000')
})
// --------------------------------------------- //
// web.js
var socket = io();
var server = {
// "iceServers": [{
// "url": "stun:stun.l.google.com:19302"
// }]
},
pc = new RTCPeerConnection(null),
v = document.querySelector('#video2')
// web onicecandidate
pc.onicecandidate = function(event) {
if (event.candidate) {
socket.emit('remote_ice_candidate', {
ice: event.candidate
})
}
}
// web addIceCandidate
socket.on('pc_add_ice', function(event) {
pc.addIceCandidate(new RTCIceCandidate(event.ice))
})
// didn't trigger
pc.ontrack = function(e) {
// v.srcObject = e.streams[0];
console.log(e, 'pc.ontrack')
}
// web setRemoteDescription and createAnswer
socket.on('set_pc_remote_sdp', function(e) {
pc.setRemoteDescription(e.desc).then(
function() {
console.log('remote setRemoteDescription success')
pc.createAnswer().then(function(desc) {
pc.setLocalDescription(desc).then(
function() {
socket.emit('send_pc_sdp', {
desc: desc
})
},
function(err) {
console.log(err)
}
);
})
},
function() {
console.log('pc setLocalDescription error')
}
)
})
// web iceConnectionState
pc.oniceconnectionstatechange = function() {
console.log('web oniceconnectionstatechange', pc.iceConnectionState)
// log checking -> connected
};
//---------------------------------------------//
// phone.js
var socket = io();
var server = {
// "iceServers": [{
// "url": "stun:stun.l.google.com:19302"
// }]
},
pc = new RTCPeerConnection(null),
v = document.querySelector('#video1')
// phone onicecandidate
pc.onicecandidate = function(event) {
if (event.candidate) {
socket.emit('phone_ice_candidate', {
ice: event.candidate
})
}
}
// phone addIceCandidate
socket.on('send_ice_to_pc', function(event) {
pc.addIceCandidate(new RTCIceCandidate(event.ice.ice))
})
// getUserMedia
navigator.mediaDevices.getUserMedia({
video: {
width: 400,
height: 300
},
audio: false
})
.then(function(stream) {
v.src = window.URL.createObjectURL(stream);
pc.addStream(stream);
})
.then(function() {
// create offer
pc.createOffer({
offerToReceiveVideo: 1
}).then(function(e) {
// pc setLocalDescription
pc.setLocalDescription(e).then(
function() {
socket.emit('send_phone_sdp', {
desc: e
})
},
function() {
console.log('pc setLocalDescription error')
}
)
});
})
.catch(function(err) {
console.log(err.name + ": " + err.message);
})
// phone setRemoteDescription
socket.on('set_phone_remote_sdp', function(e) {
pc.setRemoteDescription(e.desc.desc).then(
function() {
console.log('pc setRemoteDescription success')
},
function(err) {
console.log(err)
})
})
// phone iceConnectionState
pc.oniceconnectionstatechange = function() {
console.log('phone oniceconnectionstatechange', pc.iceConnectionState)
// log checking -> connected -> completed
};
When i use firefox to open it, there is an error ICE failed, add a STUN server and see about:webrtc for more details in console.
In chrome the 'phone iceConnectionState' changed checking -> connected -> completed, the 'web iceConnectionState' changed checking -> connected.
have you set autoplay in your html? I have the same issue, and it turns out I should have set autoplay in my html tag. Namely:
<video autoplay></video>
Hope this helps!
getUserMedia is an async function. You are calling createOffer before you call pc.addStream which means there is nothing to negotiate.
Make the promise callback return your pc.createOffer() after pc.addStream(stream);
PTAL at https://www.html5rocks.com/en/tutorials/webrtc/basics/#toc-signaling and compare your code to the example and see if you can figure it out.
I am trying to make a video calling web application using webRTC. I am using angularjs and express.io
I am getting this error:
DOMException: Failed to set remote offer sdp: Called in wrong state: STATE_SENTOFFER
Some of my code is:
// in controller (socket is already defined in controller)
var videolocal = document.getElementById('videolocal');
var videoremote = document.getElementById('videoremote');
var streamlocal = null;
var pc = null;
window.URL = window.URL || window.webkitURL;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
var configuration = {'iceServers': [
// {'url': 'stun:stun.services.mozilla.com'},
{'url': 'stun:stun.l.google.com:19302'}
]};
// run start(true) to initiate a call
$scope.start = function() {
console.log('start');
// get the local stream, show it in the local video element and send it
navigator.getUserMedia({ "audio": true, "video": true }, function (stream) {
videolocal.src = URL.createObjectURL(stream);
pc = new RTCPeerConnection(configuration);
pc.addStream(stream);
// once remote stream arrives, show it in the remote video element
pc.onaddstream = function (evt) {
console.log('onaddstream');
videoremote.src = URL.createObjectURL(evt.stream);
};
// send any ice candidates to the other peer
pc.onicecandidate = function (evt) {
console.log('onicecandidate');
if(evt.candidate){
socket.emit('video_call',{user:2, type: 'candidate', candidate: evt.candidate});
}
};
// create an offer
pc.createOffer(function (offer) {
socket.emit('video_call', {user:2, type: "offer", offer: offer});
pc.setLocalDescription(offer);
}, function (error) {
alert("Error when creating an offer");
});
}, function () {alert('error in start')});
}
$scope.start();
socket.on('video_call', function (data) {
console.log(data);
//when somebody sends us an offer
function handleOffer(offer) {
// this line is giving error
pc.setRemoteDescription(new RTCSessionDescription(offer), function(){alert('success')}, function(e){ console.log(e); alert(e)});
//create an answer to an offer
pc.createAnswer(function (answer) {
pc.setLocalDescription(answer);
socket.emit('video_call', {user:2, type: "answer", answer: answer});
}, function (error) {
console.log(error);
alert("Error when creating an answer");
});
};
//when we got an answer from a remote user
function handleAnswer(answer) {
pc.setRemoteDescription(new RTCSessionDescription(answer));
};
//when we got an ice candidate from a remote user
function handleCandidate(candidate) {
pc.addIceCandidate(new RTCIceCandidate(candidate));
};
switch(data['type']) {
case "offer":
handleOffer(data["offer"]);
break;
case "answer":
handleAnswer(data['answer']);
break;
//when a remote peer sends an ice candidate to us
case "candidate":
handleCandidate(data['candidate']);
break;
default:
break;
}
});
On server:
// this function is called on video_call event
video_call: function (data) {
var id = data.user;
// if user is active
// users is dict of users (user_id as key)
if(Object.keys(users).indexOf(id.toString()) > -1){
// for each device of the user
users[id].forEach(function(user_socket){
console.log(data);
user_socket.emit('video_call', data);
});
}
}
Please can anyone tell what is wrong with this code. The local stream is capturing properly. I am using chromium browser.
Data on server:
I think the problem is that in your handleOffer() function you need to create another PeerConnection and call setRemoteDescription() on that pc.
var remote_pc = new RTCPeerConnection(configuration)
remote_pc.setRemoteDescription(new RTCSessionDescription(offer), ...) {
remote_pc.createAnswer()
}
This is what I have in my code.
EDIT: In the official link you can go to chapter 11.7 and check the steps after 15 (when the offer is sent and the other peer receives it).
I'm trying to connect to a browser for video chat using WebRTC and websockets.
I'm able to createoffer, get the ice candidates but the function (where I expect a remote stream response) serverconnection.onmessage is never called.
in my index.html
function pageReady() {
localVideo = document.getElementById("localVideo");
remoteVideo = document.getElementById("remoteVideo");
serverConnection = new WebSocket('ws://localhost:3434');
serverConnection.onmessage = gotMessageFromServer;
var constraints = {
video: true,
audio: true,
};
if (navigator.getUserMedia) {
navigator.getUserMedia(constraints, getUserMediaSuccess, getUserMediaError);
} else {
alert('Your browser does not support getUserMedia API');
}
}
function start(isCaller) {
peerConnection = new RTCPeerConnection(peerConnectionConfig, optional);
console.log('the peer connection is', peerConnection);
peerConnection.onicecandidate = gotIceCandidate;
peerConnection.onaddstream = gotRemoteStream;
peerConnection.addStream(localStream);
if (isCaller)
peerConnection.createOffer(gotDescription, createOfferError);
}
function gotMessageFromServer(message) {
console.log('message is', json);
if (!peerConnection) start(false);
var signal = JSON.parse(message.data);
if (signal.sdp) {
console.log('message is signal.sdp', signal.sdp);
peerConnection.setRemoteDescription(new RTCSessionDescription(signal.sdp), function () {
peerConnection.createAnswer(gotDescription, createAnswerError);
});
} else if (signal.ice) {
console.log('message is signal.ice', signal.ice);
peerConnection.addIceCandidate(new RTCIceCandidate(signal.ice));
}
}
server.js
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({ noServer: true });
var http = require('http'),
fs = require('fs');
fs.readFile('../index.html', function (err, html) {
if (err) {
throw err;
}
var server = http.createServer(function (request, response) {
response.writeHeader(200, { "Content-Type": "text/html" });
response.write(html);
response.end();
})
server.listen(3434);
server.on('upgrade', function (req, socket, head) {
wss.handleUpgrade(req, socket, head, function (client) {
});
});
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});
ws.send(message);
});
});