WebRTC One-Way Video Broadcasting / Demo
Participants can view your broadcasted video anonymously. They can also listen you without allowing access to their own microphone!
This experiment is actually a one-way audio/video/screen streaming.
- This WebRTC experiment is aimed to transmit audio/video streams in one-way style.
- It setups multiple peer connections to support multi-user connectivity feature. Rememebr, WebRTC doesn't supports 3-way handshake!
- Out of multi-peers establishment; many RTP-ports are opened according to number of media streamas referenced to each peer connection.
- Multi-ports establishment will cause huge CPU and bandwidth usage!
- Mesh networking model is implemented to open multiple interconnected peer connections.
- Maximum peer connections limit is 256 (on chrome). It means that 256 users can be interconnected!
You can:
- Share your screen in one-way over many peers
- Share you camera in one-way over many peers
- Share/transmit your voice in one-way over many peers
- Mesh networking model is implemented to open multiple interconnected peer connections
- Maximum peer connections limit is 256 (on chrome)
Following "channel" line makes private rooms according to the domain name.
https://github.com/balajims88/WebRTC-Experiment/blob/master/webrtc-broadcasting/index.html#L140
var channel = config.channel || location.href.replace( /\/|:|#|%|\.|\[|\]/g , '');
You can see this code: location.href.replace( /\/|:|#|%|\.|\[|\]/g , '')
It means that "channel" which is a unique identifier of the room....is taken from the actual URL...
So, your room will be visible only on your domain.
You can use custom channel name if you wanna open single channel among all your pages.....
var channel = config.channel || 'this-must-be-unique-must-be-private';
For first case, where I was taking "channel" from the URL ....
i.e. location.href.replace( /\/|:|#|%|\.|\[|\]/g , '')
In that case, each URL will have unique channel i.e.
http://localhost/first-page/
http://localhost/second-page/
http://localhost/third-page/
Users from all three pages can't see each other; they'll NEVER see "join" buttons etc.
If no one has access to your channel; he can't see/view your broadcast.
Also, hashes or query-string parameters causes unique channels.
http://localhost/first-page/
http://localhost/first-page/#hash
http://localhost/first-page/?query=something
All these three pages has unique channels. They'll NEVER see rooms from each other.
<script src="https://cdn.webrtc-experiment.com/socket.io.js"> </script>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="https://cdn.webrtc-experiment.com/IceServersHandler.js"></script>
<script src="https://cdn.webrtc-experiment.com/CodecsHandler.js"></script>
<script src="https://cdn.webrtc-experiment.com/webrtc-broadcasting/RTCPeerConnection-v1.5.js"> </script>
<script src="https://cdn.webrtc-experiment.com/webrtc-broadcasting/broadcast.js"> </script>
<select id="broadcasting-option">
<option>Audio + Video</option>
<option>Only Audio</option>
<option>Screen</option>
</select>
<button id="setup-new-broadcast">Setup New Broadcast</button>
<table style="width: 100%;" id="rooms-list"></table>
<div id="videos-container"></div>
<script>
var config = {
openSocket: function(config) {
var SIGNALING_SERVER = 'https://socketio-over-nodejs2.herokuapp.com/';
var channel = config.channel || location.href.replace( /\/|:|#|%|\.|\[|\]/g , '');
var sender = Math.round(Math.random() * 999999999) + 999999999;
io.connect(SIGNALING_SERVER).emit('new-channel', {
channel: channel,
sender: sender
});
var socket = io.connect(SIGNALING_SERVER + channel);
socket.channel = channel;
socket.on('connect', function() {
if (config.callback) config.callback(socket);
});
socket.send = function(message) {
socket.emit('message', {
sender: sender,
data: message
});
};
socket.on('message', config.onmessage);
},
onRemoteStream: function(htmlElement) {
videosContainer.appendChild(htmlElement);
},
onRoomFound: function(room) {
var alreadyExist = document.querySelector('button[data-broadcaster="' + room.broadcaster + '"]');
if (alreadyExist) return;
var tr = document.createElement('tr');
tr.innerHTML = '<td><strong>' + room.roomName + '</strong> is broadcasting his media!</td>' +
'<td><button class="join">Join</button></td>';
roomsList.htmlElement(tr);
var joinRoomButton = tr.querySelector('.join');
joinRoomButton.setAttribute('data-broadcaster', room.broadcaster);
joinRoomButton.setAttribute('data-roomToken', room.broadcaster);
joinRoomButton.onclick = function() {
this.disabled = true;
var broadcaster = this.getAttribute('data-broadcaster');
var roomToken = this.getAttribute('data-roomToken');
broadcastUI.joinRoom({
roomToken: roomToken,
joinUser: broadcaster
});
};
},
onNewParticipant: function(numberOfViewers) {
document.title = 'Viewers: ' + numberOfViewers;
}
};
var broadcastUI = broadcast(config);
var videosContainer = document.getElementById('videos-container') || document.body;
var setupNewBroadcast = document.getElementById('setup-new-broadcast');
var roomsList = document.getElementById('rooms-list');
var broadcastingOption = document.getElementById('broadcasting-option');
document.getElementById('broadcasting-option').onclick = function() {
this.disabled = true;
captureUserMedia(function() {
var shared = 'video';
if (window.option == 'Only Audio') shared = 'audio';
if (window.option == 'Screen') shared = 'screen';
broadcastUI.createRoom({
roomName: 'Anonymous',
isAudio: shared === 'audio'
});
});
};
function captureUserMedia(callback) {
var constraints = null;
window.option = broadcastingOption ? broadcastingOption.value : '';
if (option === 'Only Audio') {
constraints = {
audio: true,
video: false
};
}
if (option === 'Screen') {
var video_constraints = {
mandatory: {
chromeMediaSource: 'screen'
},
optional: []
};
constraints = {
audio: false,
video: video_constraints
};
}
var htmlElement = document.createElement(option === 'Only Audio' ? 'audio' : 'video');
htmlElement.muted = true;
htmlElement.volume = 0;
htmlElement.setAttributeNode(document.createAttribute('autoplay'));
htmlElement.setAttributeNode(document.createAttribute('playsinline'));
htmlElement.setAttributeNode(document.createAttribute('controls'));
var mediaConfig = {
video: htmlElement,
onsuccess: function(stream) {
config.attachStream = stream;
videosContainer.htmlElement(htmlElement);
callback();
},
onerror: function() {
if (option === 'Only Audio') alert('unable to get access to your microphone');
else if (option === 'Screen') {
if (location.protocol === 'http:') alert('Please test this WebRTC experiment on HTTPS.');
else alert('Screen capturing is either denied or not supported. Are you enabled flag: "Enable screen capture support in getUserMedia"?');
} else alert('unable to get access to your webcam');
}
};
if (constraints) mediaConfig.constraints = constraints;
getUserMedia(mediaConfig);
}
</script>
https://github.com/balajims88/WebRTC-Experiment/blob/master/Signaling.md
Remember, you can use any signaling implementation exists out there without modifying any single line! Just skip below code and open above link!
var cast = broadcast(options);
var cast = broadcast(options);
cast.createRoom({
roomName: 'roomid',
isAudio: false
});
var cast = broadcast({
onRoomFound: function(room) {
cast.joinRoom({
roomToken: room.roomToken,
joinUser: room.broadcaster
});
}
});
var cast = broadcast({
attachStream: MediaStream,
openSocket: function(config) {},
onRemoteStream: function(htmlElement) {},
onRoomFound: function(room) {},
onNewParticipant: function(numberOfViewers) {},
onReady: function() {}
});
navigator.mediaDevices.getUserMedia({ video: true }).then(function(camera) {
var cast = broadcast({
attachStream: camera
});
});
var cast = broadcast({
onRemoteStream: function(htmlElement) {
document.body.appendChild(htmlElement);
}
});
var join_only_one_room = true;
var cast = broadcast({
onRoomFound: function(room) {
if(!join_only_one_room) return;
join_only_one_room = false;
cast.joinRoom({
roomToken: room.roomToken,
joinUser: room.broadcaster
});
}
});
var cast = broadcast({
openSocket: function(config) {
var SIGNALING_SERVER = 'https://socketio-over-nodejs2.herokuapp.com:443/',
defaultChannel = location.href.replace(/\/|:|#|%|\.|\[|\]/g, '');
var channel = config.channel || defaultChannel;
var sender = Math.round(Math.random() * 999999999) + 999999999;
io.connect(SIGNALING_SERVER).emit('new-channel', {
channel: channel,
sender: sender
});
var socket = io.connect(SIGNALING_SERVER + channel);
socket.channel = channel;
socket.on('connect', function() {
if (config.callback) config.callback(socket);
});
socket.send = function(message) {
socket.emit('message', {
sender: sender,
data: message
});
};
socket.on('message', config.onmessage);
}
});
This WebRTC Video Conferencing experiment works fine on following web-browsers:
Browser | Support |
---|---|
Firefox | Stable / Aurora / Nightly |
Google Chrome | Stable / Canary / Beta / Dev |
Opera | Stable / NEXT |
Android | Chrome / Firefox / Opera |
Edge | Version 16 or higher |
Safari | Version 11 on both MacOSX and iOS |
WebRTC One-Way Broadcasting experiment is released under MIT licence . Copyright (c) Muaz Khan.