rtc

minimal webrtc client
git clone https://git.ce9e.org/rtc.git

commit
495db04cefe8c45ae7ebfa408d0b879b9bb41494
parent
c244fd563ad9f85ef7c48dafbe296f5b112c2227
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2020-04-03 19:35
split chat and controls into separate modules

Diffstat

A www/chat.js 24 ++++++++++++++++++++++++
A www/controls.js 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M www/rtc.js 125 +++++--------------------------------------------------------

3 files changed, 123 insertions, 115 deletions


diff --git a/www/chat.js b/www/chat.js

@@ -0,0 +1,24 @@
   -1     1 import * as signal from './signal.js';
   -1     2 
   -1     3 var history = document.querySelector('.chat-history');
   -1     4 var form = document.querySelector('.chat-form');
   -1     5 
   -1     6 export var init = function(room, queue) {
   -1     7 	form.addEventListener('submit', function(event) {
   -1     8 		var input = event.target.msg;
   -1     9 		event.preventDefault();
   -1    10 		if (!input.value) {
   -1    11 			return;
   -1    12 		}
   -1    13 		signal.post(room, {sender: queue, type: 'chat', text: input.value}).then(function() {
   -1    14 			input.value = '';
   -1    15 		});
   -1    16 	});
   -1    17 };
   -1    18 
   -1    19 export var addMsg = function(sender, msg) {
   -1    20 	var li = document.createElement('li');
   -1    21 	li.textContent = msg;
   -1    22 	history.append(li);
   -1    23 	history.scrollTop = history.scrollHeight;
   -1    24 };

diff --git a/www/controls.js b/www/controls.js

@@ -0,0 +1,89 @@
   -1     1 export var init = function(localVideo, cons) {
   -1     2 	var controls = document.querySelector('.rtc-controls');
   -1     3 
   -1     4 	var updateConnections = function() {
   -1     5 		var sender;
   -1     6 		var tracks = localVideo.srcObject.getTracks();
   -1     7 
   -1     8 		for (sender in cons) {
   -1     9 			var con = cons[sender].con;
   -1    10 
   -1    11 			con.getSenders().forEach(s => {
   -1    12 				con.removeTrack(s);
   -1    13 			});
   -1    14 
   -1    15 			tracks.forEach(track => {
   -1    16 				con.addTrack(track, localVideo.srcObject);
   -1    17 			});
   -1    18 		}
   -1    19 	};
   -1    20 
   -1    21 	var updateStreams = async function(event) {
   -1    22 		var tracks = localVideo.srcObject.getTracks();
   -1    23 		var kind = event.target.name === 'audio' ? 'audio' : 'video';
   -1    24 
   -1    25 		if (!event.target.checked) {
   -1    26 			tracks.forEach(track => {
   -1    27 				if (track.kind === kind) {
   -1    28 					track.enabled = false;
   -1    29 				}
   -1    30 			});
   -1    31 		} else if (
   -1    32 			tracks.filter(t => t.kind === kind).length &&
   -1    33 			!(controls.video.checked && controls.screen.checked)
   -1    34 		) {
   -1    35 			tracks.forEach(track => {
   -1    36 				if (track.kind === kind) {
   -1    37 					track.enabled = true;
   -1    38 				}
   -1    39 			});
   -1    40 		} else {
   -1    41 			var newStream = new MediaStream();
   -1    42 			var stream;
   -1    43 			try {
   -1    44 				if (event.target.name === 'screen') {
   -1    45 					stream = await navigator.mediaDevices.getDisplayMedia();
   -1    46 				} else {
   -1    47 					stream = await navigator.mediaDevices.getUserMedia({[kind]: true});
   -1    48 				}
   -1    49 			} catch (err) {
   -1    50 				event.target.checked = false;
   -1    51 				return;
   -1    52 			}
   -1    53 
   -1    54 			if (event.target.name === 'video') {
   -1    55 				controls.screen.checked = false;
   -1    56 				localVideo.classList.add('mirrored');
   -1    57 			} else if (event.target.name === 'screen') {
   -1    58 				controls.video.checked = false;
   -1    59 				localVideo.classList.remove('mirrored');
   -1    60 			}
   -1    61 
   -1    62 			tracks.forEach(track => {
   -1    63 				if (track.kind === kind) {
   -1    64 					track.stop();
   -1    65 				} else {
   -1    66 					newStream.addTrack(track);
   -1    67 				}
   -1    68 			});
   -1    69 			stream.getTracks().forEach(track => {
   -1    70 				newStream.addTrack(track);
   -1    71 			});
   -1    72 
   -1    73 			localVideo.srcObject = newStream;
   -1    74 			updateConnections();
   -1    75 		}
   -1    76 	};
   -1    77 
   -1    78 	controls.addEventListener('change', updateStreams);
   -1    79 
   -1    80 	navigator.mediaDevices.enumerateDevices().then(devices => {
   -1    81 		devices.forEach(device => {
   -1    82 			if (device.kind === 'audioinput') {
   -1    83 				controls.audio.disabled = false;
   -1    84 			} else if (device.kind === 'videoinput') {
   -1    85 				controls.video.disabled = false;
   -1    86 			}
   -1    87 		});
   -1    88 	});
   -1    89 };

diff --git a/www/rtc.js b/www/rtc.js

@@ -1,6 +1,8 @@
    1     1 /* eslint no-console: "off" */
    2     2 
    3     3 import * as signal from './signal.js';
   -1     4 import * as chat from './chat.js';
   -1     5 import * as controls from './controls.js';
    4     6 
    5     7 // https://webrtc.github.io/samples/
    6     8 // https://www.html5rocks.com/en/tutorials/webrtc/basics/
@@ -115,115 +117,9 @@ signal.listen(queue + ':' + queuePassword, function(msg) {
  115   117 	}
  116   118 });
  117   119 
  118    -1 signal.post(room, {sender: queue, type: 'announce'});
  119    -1 
  120    -1 window.addEventListener('beforeunload', function() {
  121    -1 	signal.beacon(room, {sender: queue, type: 'leave'});
  122    -1 });
  123    -1 
  124    -1 var updateConnections = function() {
  125    -1 	var sender;
  126    -1 	var tracks = localVideo.srcObject.getTracks();
  127    -1 
  128    -1 	for (sender in cons) {
  129    -1 		var con = cons[sender].con;
  130    -1 
  131    -1 		con.getSenders().forEach(s => {
  132    -1 			con.removeTrack(s);
  133    -1 		});
  134    -1 
  135    -1 		tracks.forEach(track => {
  136    -1 			con.addTrack(track, localVideo.srcObject);
  137    -1 		});
  138    -1 	}
  139    -1 };
  140    -1 
  141    -1 var controls = document.querySelector('.rtc-controls');
  142    -1 
  143    -1 var updateStreams = async function(event) {
  144    -1 	var tracks = localVideo.srcObject.getTracks();
  145    -1 	var kind = event.target.name === 'audio' ? 'audio' : 'video';
  146    -1 
  147    -1 	if (!event.target.checked) {
  148    -1 		tracks.forEach(track => {
  149    -1 			if (track.kind === kind) {
  150    -1 				track.enabled = false;
  151    -1 			}
  152    -1 		});
  153    -1 	} else if (
  154    -1 		tracks.filter(t => t.kind === kind).length &&
  155    -1 		!(controls.video.checked && controls.screen.checked)
  156    -1 	) {
  157    -1 		tracks.forEach(track => {
  158    -1 			if (track.kind === kind) {
  159    -1 				track.enabled = true;
  160    -1 			}
  161    -1 		});
  162    -1 	} else {
  163    -1 		var newStream = new MediaStream();
  164    -1 		var stream;
  165    -1 		try {
  166    -1 			if (event.target.name === 'screen') {
  167    -1 				stream = await navigator.mediaDevices.getDisplayMedia();
  168    -1 			} else {
  169    -1 				stream = await navigator.mediaDevices.getUserMedia({[kind]: true});
  170    -1 			}
  171    -1 		} catch (err) {
  172    -1 			event.target.checked = false;
  173    -1 			return;
  174    -1 		}
  175    -1 
  176    -1 		if (event.target.name === 'video') {
  177    -1 			controls.screen.checked = false;
  178    -1 			localVideo.classList.add('mirrored');
  179    -1 		} else if (event.target.name === 'screen') {
  180    -1 			controls.video.checked = false;
  181    -1 			localVideo.classList.remove('mirrored');
  182    -1 		}
  183    -1 
  184    -1 		tracks.forEach(track => {
  185    -1 			if (track.kind === kind) {
  186    -1 				track.stop();
  187    -1 			} else {
  188    -1 				newStream.addTrack(track);
  189    -1 			}
  190    -1 		});
  191    -1 		stream.getTracks().forEach(track => {
  192    -1 			newStream.addTrack(track);
  193    -1 		});
  194    -1 
  195    -1 		localVideo.srcObject = newStream;
  196    -1 		updateConnections();
  197    -1 	}
  198    -1 };
  199    -1 
  200    -1 document.querySelector('.rtc-controls').addEventListener('change', updateStreams);
  201    -1 
  202    -1 
  203    -1 var history = document.querySelector('.chat-history');
  204    -1 var form = document.querySelector('.chat-form');
  205    -1 
  206    -1 form.addEventListener('submit', function(event) {
  207    -1 	var input = event.target.msg;
  208    -1 	event.preventDefault();
  209    -1 	if (!input.value) {
  210    -1 		return;
  211    -1 	}
  212    -1 	signal.post(room, {sender: queue, type: 'chat', text: input.value}).then(function() {
  213    -1 		input.value = '';
  214    -1 	});
  215    -1 });
  216    -1 
  217    -1 var addChatMsg = function(sender, msg) {
  218    -1 	var li = document.createElement('li');
  219    -1 	li.textContent = msg;
  220    -1 	history.append(li);
  221    -1 	history.scrollTop = history.scrollHeight;
  222    -1 };
  223    -1 
  224   120 signal.listen(room, function(msg) {
  225   121 	if (msg.type === 'chat') {
  226    -1 		addChatMsg(msg.sender, msg.text);
   -1   122 		chat.addMsg(msg.sender, msg.text);
  227   123 	} else if (msg.type === 'announce') {
  228   124 		makeOffer(msg.sender);
  229   125 	} else if (msg.type === 'leave') {
@@ -233,12 +129,11 @@ signal.listen(room, function(msg) {
  233   129 	}
  234   130 });
  235   131 
  236    -1 navigator.mediaDevices.enumerateDevices().then(devices => {
  237    -1 	devices.forEach(device => {
  238    -1 		if (device.kind === 'audioinput') {
  239    -1 			document.querySelector('.rtc-controls [name="audio"]').disabled = false;
  240    -1 		} else if (device.kind === 'videoinput') {
  241    -1 			document.querySelector('.rtc-controls [name="video"]').disabled = false;
  242    -1 		}
  243    -1 	});
   -1   132 window.addEventListener('beforeunload', function() {
   -1   133 	signal.beacon(room, {sender: queue, type: 'leave'});
  244   134 });
   -1   135 
   -1   136 chat.init(room, queue);
   -1   137 controls.init(localVideo, cons);
   -1   138 
   -1   139 signal.post(room, {sender: queue, type: 'announce'});