From 079009a13ee3670d17136499eb92e69fea9f8487 Mon Sep 17 00:00:00 2001 From: Peter Harpending Date: Tue, 24 Feb 2026 10:40:43 -0800 Subject: [PATCH] [wip] now display user's camera next tricky thing is connecting users --- priv/static/js/dist/webrtc.d.ts | 20 ++--- priv/static/js/dist/webrtc.js | 85 ++++++-------------- priv/static/js/dist/webrtc.js.map | 2 +- priv/static/js/ts/webrtc.ts | 129 +++++++----------------------- priv/static/webrtc.html | 13 +-- scratch/webrtc01.ts | 127 +++++++++++++++++++++++++++++ 6 files changed, 192 insertions(+), 184 deletions(-) create mode 100644 scratch/webrtc01.ts diff --git a/priv/static/js/dist/webrtc.d.ts b/priv/static/js/dist/webrtc.d.ts index 317e6cc..a30338b 100644 --- a/priv/static/js/dist/webrtc.d.ts +++ b/priv/static/js/dist/webrtc.d.ts @@ -9,14 +9,14 @@ * * @module */ -type state = { - whoami: string; - roster: Array; -}; -declare let st: state; declare function main(): Promise; -type ws_msg = ["whoami", string] | ["roster", Array]; -declare function handle_ws_msg(message: ws_msg): void; -declare function ws_send_json(ws: WebSocket, x: any): void; -declare function render_state(): void; -declare function nickkk(nick: string): HTMLElement; +/** + * Try to get the user's camera + * + * tries to get screenshare if user camera not available for whatever reason + * + * chimps out if + * - not on https + * - user says no + */ +declare function getUserCamera(): Promise; diff --git a/priv/static/js/dist/webrtc.js b/priv/static/js/dist/webrtc.js index a5eb94c..246c066 100644 --- a/priv/static/js/dist/webrtc.js +++ b/priv/static/js/dist/webrtc.js @@ -10,71 +10,32 @@ * * @module */ -let st = { whoami: "", - roster: [] }; main(); async function main() { - // start websocket immediately - let ws; - let init = document.getElementById('init'); - let init_join = document.getElementById('init-join'); - // handle button click - init_join.addEventListener('click', function () { - init.hidden = true; - document.getElementById('run').hidden = false; - ws = new WebSocket('/ws/webrtc'); - ws.onopen = function (e) { console.log('ws open'); }; - ws.onclose = function (e) { console.warn('ws closed'); }; - ws.onerror = function (e) { console.error('ws error:', e); }; - ws.onmessage = - function (e) { - // console.log('ws message:', e.data); - let message = JSON.parse(e.data); - handle_ws_msg(message); - }; - }); + console.log('peepy'); + let video = await getUserCamera(); + console.log('poopy'); + console.log('poopu'); + let moi = document.getElementById('me'); + moi.srcObject = video; + console.log('poopa'); } -function handle_ws_msg(message) { - console.log('message from server:', message); - switch (message[0]) { - case "whoami": - st.whoami = message[1]; - break; - case "roster": - st.roster = message[1]; - break; - default: - console.warn("unknown message", message); +/** + * Try to get the user's camera + * + * tries to get screenshare if user camera not available for whatever reason + * + * chimps out if + * - not on https + * - user says no + */ +async function getUserCamera() { + if (!(navigator.mediaDevices)) { + console.error('navigator.mediaDevices is null; user not on https or something'); } - render_state(); -} -function ws_send_json(ws, x) { - let s = JSON.stringify(x, undefined, 4); - console.log('sending:\n', s); - ws.send(s); -} -function render_state() { - console.log('st', st); - // whoami - document.getElementById('whoami').innerText = st.whoami; - // - let roster_ul = document.getElementById('roster-ul'); - let newChildren = []; - for (let nick of st.roster) { - if (!(nick === st.whoami)) { - let li = nickkk(nick); - newChildren.push(li); - } - } - roster_ul.replaceChildren(...newChildren); -} -function nickkk(nick) { - let li = document.createElement('li'); - li.innerText += nick; - li.innerText += ' '; - let call_a = document.createElement('button'); - call_a.innerText = 'call'; - li.appendChild(call_a); - return li; + let availableDevices = await navigator.mediaDevices.enumerateDevices(); + console.log(availableDevices); + return await navigator.mediaDevices.getUserMedia({ video: true, audio: false }); + // return await navigator.mediaDevices.getDisplayMedia(); } //# sourceMappingURL=webrtc.js.map \ No newline at end of file diff --git a/priv/static/js/dist/webrtc.js.map b/priv/static/js/dist/webrtc.js.map index 824ced9..df0e914 100644 --- a/priv/static/js/dist/webrtc.js.map +++ b/priv/static/js/dist/webrtc.js.map @@ -1 +1 @@ -{"version":3,"file":"webrtc.js","sourceRoot":"","sources":["../ts/webrtc.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"webrtc.js","sourceRoot":"","sources":["../ts/webrtc.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;AAEH,IAAI,EAAE,CAAC;AAEP,KAAK,UACL,IAAI;IAIA,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrB,IAAI,KAAK,GAAsB,MAAM,aAAa,EAAE,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrB,IAAI,GAAG,GAAG,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAqB,CAAC;IAC5D,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC;IACtB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC;AAGD;;;;;;;;GAQG;AACH,KAAK,UACL,aAAa;IAIT,IAAI,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE;QAC3B,OAAO,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC;KACnF;IAED,IAAI,gBAAgB,GAChB,MAAM,SAAS,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAE9B,OAAO,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,EAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAC,CAAC,CAAC;IAC9E,yDAAyD;AAC7D,CAAC"} \ No newline at end of file diff --git a/priv/static/js/ts/webrtc.ts b/priv/static/js/ts/webrtc.ts index 3c5bf59..3ae2818 100644 --- a/priv/static/js/ts/webrtc.ts +++ b/priv/static/js/ts/webrtc.ts @@ -10,14 +10,6 @@ * @module */ -type state = - {whoami: string, - roster: Array}; - -let st: state = - {whoami: "", - roster: []}; - main(); async function @@ -25,103 +17,38 @@ main () : Promise { - // start websocket immediately - let ws: WebSocket; - let init = document.getElementById('init') as HTMLDivElement; - let init_join = document.getElementById('init-join') as HTMLButtonElement; - - // handle button click - init_join.addEventListener('click', - function() { - init.hidden = true; - document.getElementById('run')!.hidden = false; - ws = new WebSocket('/ws/webrtc'); - ws.onopen = function(e) { console.log('ws open'); }; - ws.onclose = function(e) { console.warn('ws closed'); }; - ws.onerror = function(e) { console.error('ws error:', e); }; - ws.onmessage = - function(e) { - // console.log('ws message:', e.data); - let message = JSON.parse(e.data) as ws_msg; - handle_ws_msg(message); - }; - } - ); -} - -type ws_msg = ["whoami", string] - | ["roster", Array]; - -function -handle_ws_msg - (message: ws_msg) - : void -{ - console.log('message from server:', message); - switch(message[0]) { - case "whoami": - st.whoami = message[1]; - break; - case "roster": - st.roster = (message[1] as Array); - break; - default: - console.warn("unknown message", message); - } - - render_state(); + console.log('peepy'); + let video : MediaStream = await getUserCamera(); + console.log('poopy'); + console.log('poopu'); + let moi = document.getElementById('me') as HTMLVideoElement; + moi.srcObject = video; + console.log('poopa'); } - -function -ws_send_json - (ws : WebSocket, - x : any) - : void -{ - let s: string = JSON.stringify(x, undefined, 4); - console.log('sending:\n', s); - - ws.send(s); -} - - - -function -render_state +/** + * Try to get the user's camera + * + * tries to get screenshare if user camera not available for whatever reason + * + * chimps out if + * - not on https + * - user says no + */ +async function +getUserCamera () - : void + : Promise { - console.log('st', st); - // whoami - document.getElementById('whoami')!.innerText = st.whoami; - // - let roster_ul = document.getElementById('roster-ul') as HTMLUListElement; - let newChildren : Array = []; - for (let nick of st.roster) { - if (!(nick === st.whoami)) { - let li = nickkk(nick); - newChildren.push(li); - } + if (!(navigator.mediaDevices)) { + console.error('navigator.mediaDevices is null; user not on https or something'); } - roster_ul.replaceChildren(...newChildren); -} - -function -nickkk - (nick: string) - : HTMLElement -{ - let li = document.createElement('li'); - - li.innerText += nick; - li.innerText += ' '; - - let call_a = document.createElement('button'); - call_a.innerText = 'call'; - - li.appendChild(call_a); - - return li; + + let availableDevices: Array = + await navigator.mediaDevices.enumerateDevices(); + console.log(availableDevices); + + return await navigator.mediaDevices.getUserMedia({video: true, audio: false}); + // return await navigator.mediaDevices.getDisplayMedia(); } diff --git a/priv/static/webrtc.html b/priv/static/webrtc.html index 1a2a049..4d4493d 100644 --- a/priv/static/webrtc.html +++ b/priv/static/webrtc.html @@ -15,17 +15,10 @@

FEWD: webrtc demo

-
- -
+
+ - -
diff --git a/scratch/webrtc01.ts b/scratch/webrtc01.ts new file mode 100644 index 0000000..3c5bf59 --- /dev/null +++ b/scratch/webrtc01.ts @@ -0,0 +1,127 @@ +/** + * webrtc page script + * + * Author: Peter Harpending + * Date: 2026-02-04 + * Copyright: Copyright (c) 2026 QPQ AG + * + * Reference: https://git.qpq.swiss/QPQ-AG/research-megadoc/src/commit/c7c4592d4b21ad120145ef63334471a1a7ec1e60/paste/2026-02/grok-webrtc.html + * + * @module + */ + +type state = + {whoami: string, + roster: Array}; + +let st: state = + {whoami: "", + roster: []}; + +main(); + +async function +main + () + : Promise +{ + // start websocket immediately + let ws: WebSocket; + let init = document.getElementById('init') as HTMLDivElement; + let init_join = document.getElementById('init-join') as HTMLButtonElement; + + // handle button click + init_join.addEventListener('click', + function() { + init.hidden = true; + document.getElementById('run')!.hidden = false; + ws = new WebSocket('/ws/webrtc'); + ws.onopen = function(e) { console.log('ws open'); }; + ws.onclose = function(e) { console.warn('ws closed'); }; + ws.onerror = function(e) { console.error('ws error:', e); }; + ws.onmessage = + function(e) { + // console.log('ws message:', e.data); + let message = JSON.parse(e.data) as ws_msg; + handle_ws_msg(message); + }; + } + ); +} + +type ws_msg = ["whoami", string] + | ["roster", Array]; + +function +handle_ws_msg + (message: ws_msg) + : void +{ + console.log('message from server:', message); + switch(message[0]) { + case "whoami": + st.whoami = message[1]; + break; + case "roster": + st.roster = (message[1] as Array); + break; + default: + console.warn("unknown message", message); + } + + render_state(); +} + + + +function +ws_send_json + (ws : WebSocket, + x : any) + : void +{ + let s: string = JSON.stringify(x, undefined, 4); + console.log('sending:\n', s); + + ws.send(s); +} + + + +function +render_state + () + : void +{ + console.log('st', st); + // whoami + document.getElementById('whoami')!.innerText = st.whoami; + // + let roster_ul = document.getElementById('roster-ul') as HTMLUListElement; + let newChildren : Array = []; + for (let nick of st.roster) { + if (!(nick === st.whoami)) { + let li = nickkk(nick); + newChildren.push(li); + } + } + roster_ul.replaceChildren(...newChildren); +} + +function +nickkk + (nick: string) + : HTMLElement +{ + let li = document.createElement('li'); + + li.innerText += nick; + li.innerText += ' '; + + let call_a = document.createElement('button'); + call_a.innerText = 'call'; + + li.appendChild(call_a); + + return li; +}