Can I send a MediaStream from a PeerConnection to another? - webrtc

I'm using Chrome 23.0.1246.0 canary, the latest version.
I want to send a MediaStream that reveived from a client via PeerConnection to another client via PeerConnection.
I mean, the ClientA send its local media stream to me via the PeerConnection between us, and then, I send this media stream to ClientB via the PeerConnection between ClientB and me.
This is my code, but it doesn't work, when I click the AddVideo button for the second time, the "gotRemoteStream" function doesn't be invoked. I don't konw the reason.
Anybody can help me?
<!DOCTYPE html>
<html>
<head>
<title>Video Link</title>
<style type="text/css">
video { width: 200px;}
</style>
</head>
<body>
<input id="btnAddVideo" type="button" value="Add Video" onclick="AddVideo();" />
<div id="videos"></div>
<script type="text/ecmascript">
var pcs = new Array();
var pcr = new Array();
var mediaStream = new Array();
var msIndex = 0;
navigator.webkitGetUserMedia({ audio: true, video: true }, gotStream, function () { alert('get MediaStream Error'); });
function gotStream(stream) {
mediaStream[0] = stream;
}
var pc1;
var pc2;
function AddVideo() {
if (mediaStream[msIndex] == null) return;
pc1 = new webkitPeerConnection00(null, iceCallback1);
pc1.addStream(mediaStream[msIndex]);
var offer = pc1.createOffer(null);
pc1.setLocalDescription(256, offer);
pc2 = new webkitPeerConnection00(null, iceCallback2);
pc2.onaddstream = gotRemoteStream;
pc2.setRemoteDescription(256, new SessionDescription(offer.toSdp()));
var answer = pc2.createAnswer(offer.toSdp(), { has_audio: true, has_video: true });
pc2.setLocalDescription(768, answer);
pc1.setRemoteDescription(768, new SessionDescription(answer.toSdp()));
pc2.startIce();
pc1.startIce();
pcs.push(pc1);
pcr.push(pc2);
}
function iceCallback1(candidate, bMore) {
pc2.processIceMessage(new IceCandidate(candidate.label, candidate.toSdp()));
}
function iceCallback2(candidate, bMore) {
pc1.processIceMessage(new IceCandidate(candidate.label, candidate.toSdp()));
}
function gotRemoteStream(e) {
var v = document.createElement('video');
v.autoplay = 'autoplay';
v.src = webkitURL.createObjectURL(e.stream);
document.getElementById('videos').appendChild(v);
mediaStream.push(e.stream);
msIndex++;
}
</script>
</body>
</html>

Yes, you can. With the function addStream of a PeerConnection you can add any MediaStream you want. Indeed you have to exchange the SDPs (local and remote description) between the clients once again after adding the stream to the PeerConnection.
Your code is not up-to-date, because since you posted your question there have been a lot of improvment to the api. If you update it with the help of the current standard, I can help you. :)

Related

MSE WebM video with no audio

I've written a MSE video player and it's loading WebMs. These are loading well, however I have a problem with video files with no audio tracks.
I've tried changing the codec depending on if there is audio
mediaSource.addSourceBuffer(`video/webm; ${videoHasAudio(asset) ? 'codecs="vp9,vorbis"' : 'codecs="vp9"'}`)`
And I thought this was working but now isn't. How do I run silent WebMs in MSE?
I have added sample MSE project here:
https://github.com/thowfeeq178/MediaSourceExtention
checkout the example in the github
overview:
we need to add one for video and one for audio like below:
// BBB : https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd
var baseUrl = "https://dash.akamaized.net/akamai/bbb_30fps/";
var initUrl = baseUrl + "bbb_30fps_480x270_600k/bbb_30fps_480x270_600k_0.m4v";
var initAudioUrl = baseUrl + "bbb_a64k/bbb_a64k_0.m4a";
var templateUrl =
baseUrl + "bbb_30fps_480x270_600k/bbb_30fps_480x270_600k_$Number$.m4v";
var templateUrlForAudio = baseUrl + "bbb_a64k/bbb_a64k_$Number$.m4a";
var sourceBuffer;
var audioSourceBuffer;
var index = 0;
var audioIndex = 0;
var numberOfChunks = 159;
var video = document.querySelector("video");
var ms = new MediaSource();
function onPageLoad() {
console.log("page loaded ..");
if (!window.MediaSource) {
console.error("No Media Source API available");
return;
}
// making source controlled by JS using MS
video.src = window.URL.createObjectURL(ms);
ms.addEventListener("sourceopen", onMediaSourceOpen);
}
function onMediaSourceOpen() {
// create source buffer
sourceBuffer = ms.addSourceBuffer('video/mp4; codecs="avc1.4d401f"');
audioSourceBuffer = ms.addSourceBuffer('audio/mp4; codecs="mp4a.40.5"');
// when ever one segment is loaded go for next
sourceBuffer.addEventListener("updateend", nextSegment);
audioSourceBuffer.addEventListener("updateend", nextAudioSegment);
// fire init segemnts
GET(initUrl, appendToBuffer);
GET(initAudioUrl, appendToAudioBuffer);
// play
video.play();
}
// get next segment based on index and append, once everything loaded unlisten to the event
function nextSegment() {
var url = templateUrl.replace("$Number$", index);
GET(url, appendToBuffer);
index++;
if (index > numberOfChunks) {
sourceBuffer.removeEventListener("updateend", nextSegment);
}
}
// get next audio segment based on index and append, once everything loaded unlisten to the event
function nextAudioSegment() {
var audioUrl = templateUrlForAudio.replace("$Number$", audioIndex);
GET(audioUrl, appendToAudioBuffer);
audioIndex++;
if (index > numberOfChunks) {
audioSourceBuffer.removeEventListener("updateend", nextAudioSegment);
}
}
// add to existing source
function appendToBuffer(videoChunk) {
if (videoChunk) {
sourceBuffer.appendBuffer(new Uint8Array(videoChunk));
}
}
function appendToAudioBuffer(audioChunk) {
if (audioChunk) {
audioSourceBuffer.appendBuffer(new Uint8Array(audioChunk));
}
}
// just network thing
function GET(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "arraybuffer";
xhr.onload = function(e) {
if (xhr.status != 200) {
console.warn("Unexpected status code " + xhr.status + " for " + url);
return false;
}
callback(xhr.response);
};
xhr.send();
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>MSE Demo</title>
</head>
<body onload="onPageLoad()">
<h1>MSE Demo</h1>
<div>
<video muted controls width="80%"></video>
</div>
</body>
</html>

Advantages of blob over video url

I have trawled the internet looking at why blob videos are used but I am not tech savy enough to really understand it. Can someone explain simply why a blob URL for my video is better (if it is) than loading the src as /video/intro.mp4.
Here is the code that I have used. Which one is better for my use case?
<video rel='preload' as='video' id='bgvid'>
<source type='video/mp4' src='/video/intro.mp4' />
</video>
or
var req = new XMLHttpRequest();
req.open('GET', videoURL, true);
req.responseType = 'blob';
req.onload = function() {
if (this.status === 200) {
var videoBlob = this.response;
var vid = URL.createObjectURL(videoBlob); // IE10+
var video = document.getElementById('bgvid');
video.autoplay = true;
video.src = vid;
}
}
req.onerror = function() {
// Error
}
Thanks
I would say the regular html way because it does not take extra time to process because the html is built right into the webpage

Speech Synthesis API offline languages

Is it possible to use the speech synthesis API offline? If so, can I use multiple languages or just the default language?
I have tried this code and it works online, but it does not work offline. How can I make it work online?
<html>
<head>
<title>Index</title>
</head>
<p id = "1"></p>
<script src="../js/jquery-3.2.1.js"></script>
<script type="text/javascript">
$(document).ready(function() {
document.addEventListener("keydown", function (e) {
var audio = document.getElementById("myAudio");
if (e.keyCode ===49 || e.keyCode ===97) { //1 is pressed
mySpeech();
}
});
})
function mySpeech(){
var msg = new SpeechSynthesisUtterance();
var voices = window.speechSynthesis.getVoices();
msg.voiceURI = 'native';
msg.lang = 'it-IT'
//msg.voice = voices[$('#voices').val()];
msg.rate = 1; // 0 to 1
msg.pitch = 1; // 0 to 2
msg.text = "hello world";
speechSynthesis.speak(msg);
}
</script>
</body>
The only languages that will work offline are the browser's local voices.

rtcmulticonnection safari apple mac

I have my own rtcmulticonnection server up and running
I found this plugin https://github.com/muaz-khan/PluginRTC
But it doesn't seems to work
I get WebRTC 1.0 (RTCPeerConnection) API are NOT available in this
browser.
here my code (working in chrome and firefox but not in safari)
<div id="videos-container"></div>
<script src="js/rmc3.min.js').'"></script>
<script src="js/socket.io.js').'"></script>
<script src="js/Plugin.EveryWhere.js').'"></script>
<script>
var connection = new RTCMultiConnection();
connection.socketURL = "https://__MyDomain.com:9000/";
var roomid = "main_room";
connection.session = {
audio: true,
video: true
};
connection.sdpConstraints.mandatory = {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true
};
var videosContainer = document.getElementById("videos-container");
connection.onstream = function(event) {
videosContainer.appendChild(event.mediaElement);
setTimeout(function() { event.mediaElement.play(); }, 5000);
};
connection.openOrJoin(roomid);
// *** Plugin.EveryWhere.js [BEGIN]
var Plugin = {};
window.onPluginRTCInitialized = function(pluginRTCObject) {
Plugin = pluginRTCObject;
MediaStreamTrack = Plugin.MediaStreamTrack;
RTCPeerConnection = Plugin.RTCPeerConnection;
RTCIceCandidate = Plugin.RTCIceCandidate;
RTCSessionDescription = Plugin.RTCSessionDescription;
};
if (!!window.PluginRTC) window.onPluginRTCInitialized(window.PluginRTC);
connection.onaddstream = function(event) {
if (isPluginRTC) {
var mediaElement = document.createElement("videos-container");
var body = (document.body || document.documentElement);
body.insertBefore(mediaElement, body.firstChild);
setTimeout(function() {
Plugin.attachMediaStream(mediaElement, event.stream);
// here you can append "mediaElement" to specific container
// specificContainer.appendChild(mediaElement);
}, 3000);
} else {
// do chrome/Firefox relevant stuff with "event.stream"
}
};
// *** Plugin.EveryWhere.js [END]
</script>
Is someone was able to make the plugin work ?
If yes how or what step did I missed ?
Thanks
RTCMultiConnection-v3.2.95 now supports IE/Safari:
https://github.com/muaz-khan/RTCMultiConnection/releases/tag/3.2.95
To support Safari/IE, please modify Gruntfile.js#L30 to enable dev/Plugin.EveryWhere.js.
Then don't forget calling grunt to recompile the codes.
Now set connection.trickleIce=false in your HTML file. And now video-conferencing/chat/etc. will work both among chrome/firefox/safari/IE.
Please install PluginRTC.dmg or PluginRTC.exe.
Additional notes:
You've to initiate calls from Safari/IE, because currently Safari/IE can not create answers. i.e. IE/Safari MUST call connection.open instead of calling connection.join.
Set this in your HTML: connection.processSdp = function(sdp) {return sdp;}; to prevent SDP conflicts/errors.

Simple WebRTC Example! But why it didn't work & what did I do wrong?

I found this link on the internet which demonstrates how WebRTC works https://shanetully.com/2014/09/a-dead-simple-webrtc-example/
Its source code is here https://github.com/shanet/WebRTC-Example
Now, I am trying to follow the example and here what I did:
1- I created a folder name voicechat
2- I created 2 folders inside voicechat. That is voicechat\client & voicechat\server
3- I put the index.html & webrtc.js into voicechat\client
4- I put server.js into voicechat\server
5- I put the folder voicechat into my Tomcat webapps folder. So The path will be like this C:\apache-tomcat-7.0.53\webapps\ROOT\voicechat
6- I started my Tomcat.
7- I opened http://xxx.xxx.xxx.xxx/voicechat/client/index.html in my PC & the webpage showed webcam (webcam 1) of my PC. No problem.
8- I opened http://xxx.xxx.xxx.xxx/voicechat/client/index.html in another PC & the webpage also showed webcam (webcam 2) of other PC. But I could not see webcam 1 of my PC. And when I talked in my PC, the person sitting in other PC could not hear what I am talking and via versa.
So, why it didn't work What did I do wrong?
Here is the code of 3 files:
index.html
<html>
<head>
<script src="webrtc.js"></script>
</head>
<body>
<video id="localVideo" autoplay muted style="width:40%;"></video>
<video id="remoteVideo" autoplay style="width:40%;"></video>
<br />
<input type="button" id="start" onclick="start(true)" value="Start Video"></input>
<script type="text/javascript">
pageReady();
</script>
</body>
</html>
webrtc.js
var localVideo;
var remoteVideo;
var peerConnection;
var peerConnectionConfig = {'iceServers': [{'url': 'stun:stun.services.mozilla.com'}, {'url': 'stun:stun.l.google.com:19302'}]};
navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
window.RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate || window.webkitRTCIceCandidate;
window.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription;
function pageReady() {
localVideo = document.getElementById('localVideo');
remoteVideo = document.getElementById('remoteVideo');
serverConnection = new WebSocket('ws://127.0.0.1:3434');
serverConnection.onmessage = gotMessageFromServer;
var constraints = {
video: true,
audio: true,
};
if(navigator.getUserMedia) {
navigator.getUserMedia(constraints, getUserMediaSuccess, errorHandler);
} else {
alert('Your browser does not support getUserMedia API');
}
}
function getUserMediaSuccess(stream) {
localStream = stream;
localVideo.src = window.URL.createObjectURL(stream);
}
function start(isCaller) {
peerConnection = new RTCPeerConnection(peerConnectionConfig);
peerConnection.onicecandidate = gotIceCandidate;
peerConnection.onaddstream = gotRemoteStream;
peerConnection.addStream(localStream);
if(isCaller) {
peerConnection.createOffer(gotDescription, errorHandler);
}
}
function gotMessageFromServer(message) {
if(!peerConnection) start(false);
var signal = JSON.parse(message.data);
if(signal.sdp) {
peerConnection.setRemoteDescription(new RTCSessionDescription(signal.sdp), function() {
peerConnection.createAnswer(gotDescription, errorHandler);
}, errorHandler);
} else if(signal.ice) {
peerConnection.addIceCandidate(new RTCIceCandidate(signal.ice));
}
}
function gotIceCandidate(event) {
if(event.candidate != null) {
serverConnection.send(JSON.stringify({'ice': event.candidate}));
}
}
function gotDescription(description) {
console.log('got description');
peerConnection.setLocalDescription(description, function () {
serverConnection.send(JSON.stringify({'sdp': description}));
}, function() {console.log('set description error')});
}
function gotRemoteStream(event) {
console.log('got remote stream');
remoteVideo.src = window.URL.createObjectURL(event.stream);
}
function errorHandler(error) {
console.log(error);
}
server.js
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({port: 3434});
wss.broadcast = function(data) {
for(var i in this.clients) {
this.clients[i].send(data);
}
};
wss.on('connection', function(ws) {
ws.on('message', function(message) {
console.log('received: %s', message);
wss.broadcast(message);
});
});
server.js is intended to be run as a node server for websocket signaling. Run it with node server.js. You shouldn't need Tomcat at all.
From the project readme:
The signaling server uses Node.js and ws and can be started as such:
$ npm install ws
$ node server/server.js
With the client running, open client/index.html in a recent version of either Firefox or Chrome.
You can open index.html with just a file URL.
I changed HTTPS_PORT = 8443 to HTTP_PORT = 8443. Do same with all the https; change it to http. Next, have only const serverConfig = { }; as the serverConfig and delete serverConfig in const httpServer = http.createServer(handleRequest); After these changes, u can now run your server with npm start.
This is the ultimate simple code can do the job. No need to install Node.js. Why need to install Node.js?
AND put that code into index.html file and start your webhost, then you done!
<!DOCTYPE html>
<html>
<head>
<script src="//simplewebrtc.com/latest.js"></script>
</head>
<body>
<div id="localVideo" muted></div>
<div id="remoteVideo"></div>
<script>
var webrtc = new SimpleWebRTC({
localVideoEl: 'localVideo',
remoteVideosEl: 'remoteVideo',
autoRequestMedia: true
});
webrtc.on('readyToCall', function () {
webrtc.joinRoom('My room name');
});
</script>
</body>
</html>