diff --git a/DOCS.md b/DOCS.md index 353c7c8..6d4eaaa 100644 --- a/DOCS.md +++ b/DOCS.md @@ -1,3 +1,6 @@ +# NOTICE: this document is outdated +# todo: update this document + # vybe websocket protocol - sent by client socket.io actions + expected msg format and other info diff --git a/client/index.html b/client/index.html index f689102..73d9c69 100644 --- a/client/index.html +++ b/client/index.html @@ -46,25 +46,61 @@ background: #303030; } button, - input, + input:not([type]), input[type='text'], .tab { padding: 4px 7px; } input { background: #1b1b1b; outline: none; - border: 1px solid #444; - &:focus { - padding-bottom: 2px; - border-bottom: 3px solid #777; - } &::placeholder { color: #aaa; } + &:not([type]), &[type='text'] { + border: 1px solid #444; + &:focus { + padding-bottom: 2px; + border-bottom: 3px solid #777; + } + } &[type='radio'], &[type='checkbox'] { position: relative; top: 2px; } + &[type='range'] { + width: 100px; + -webkit-appearance: none; + appearance: none; + background-color: #4f4f4f; + border-radius: 1rem; + height: 0.5rem; + &:focus { + outline: none; + } + &::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + background-color: #555; + border-radius: 1rem; + border: 2px solid #909090; + height: 17px; + width: 17px; + } + &:focus::-webkit-slider-thumb { + border: 2px solid #e0e0e0; + } + &::-moz-range-thumb { + appearance: none; + background-color: #555; + border-radius: 1rem; + border: 2px solid #909090; + height: 13px; + width: 13px; + } + &:focus::-moz-range-thumb { + border: 2px solid #e0e0e0; + } + } } #register { margin-inline: 14px; @@ -91,7 +127,7 @@ display: block; } h3 { - margin: 0; + margin: 2px; } h4 { margin: 6px 0; @@ -142,11 +178,14 @@ } #home { margin: 0; - max-width: 250px; + max-width: 256px; display: flex; flex-direction: column; justify-content: space-between; } + #instances { + margin-inline: 2px; + } #instancelist { overflow-y: auto; > :not(div) { diff --git a/client/stream.js b/client/stream.js index fb73c0d..35cb3a9 100644 --- a/client/stream.js +++ b/client/stream.js @@ -15,6 +15,7 @@ async function stream() { stop: true }); document.getElementById('streaming').innerText = 'start streaming'; + document.getElementById('listeners').innerText = ''; return; } if (!mediaStream) @@ -71,8 +72,6 @@ async function stream() { }); } -let audioctx; - function loadStreams() { let instance = window.currentInstance; @@ -93,7 +92,10 @@ function loadStreams() { name: this.value }); window.currentThread.streamname = this.value; - }}>`); + }}> +

${window.currentThread.listeners ? + window.currentThread.listeners + ' listeners' : ''} +

`); if (window.currentThread.streamname) document.getElementById('streamname').value = window.currentThread.streamname; } @@ -104,18 +106,21 @@ function loadStreams() { function addStream(stream) { let p = html.node`

- + ${stream.name ? ` - ${stream.name}` : ''}

`; p.insertBefore(window.makeUser(stream.user, stream.user.id.split?.('@')[1] || window.currentInstance.url), - p.children[1]); + p.children[2]); p.id = 'stream' + stream.id; document.getElementById('streams').append(p); } @@ -164,13 +173,23 @@ function loadStreams() { }); instance.socket.on('streamdata', async msg => { - if (!instance.streaming[msg.id]) + let stream = instance.streaming[msg.id]; + if (!stream) return; - let source = audioctx.createBufferSource(); - source.buffer = await audioctx.decodeAudioData(msg.audio); - source.connect(audioctx.destination); + let source = stream.audioctx.createBufferSource(); + source.buffer = await stream.audioctx.decodeAudioData(msg.audio); + source.connect(stream.gain); source.start(/*audioStartTime*/); }); + + instance.socket.on('listeners', msg => { + document.querySelector( + `#instance${instance.id} > #threads > #threadlist > #thread${msg.thread}`) + .thread.listeners = msg.count; + if (msg.thread === window.currentThread?.id) + document.getElementById('listeners').innerText = + msg.count ? msg.count + ' listeners' : ''; + }); } if (window.currentThread) diff --git a/server.js b/server.js index bc7fb0f..f44ad73 100644 --- a/server.js +++ b/server.js @@ -110,7 +110,7 @@ io.on('connection', (socket) => { for (let id in vybe.streams) { const stream = vybe.streams[id]; delete stream.listeners[socket.id]; - if (stream.socket === socket.id) + if (stream.socket === socket) stream.stop(); } }); diff --git a/src/events/stream.js b/src/events/stream.js index fffcc8b..f4b4c3a 100644 --- a/src/events/stream.js +++ b/src/events/stream.js @@ -35,7 +35,7 @@ async function stream(msg, respond, socket) { } } } - if (msg.id) { + if (typeof msg.id === 'number') { stream = vybe.streams[msg.id]; if (!stream) return respond({ @@ -79,7 +79,7 @@ async function stream(msg, respond, socket) { stream, userid: msg.auth_user.id, listeners: {}, - socket: socket.id, + socket, stop: async () => { stream.stopped = true; thread.streams.splice(thread.streams.findIndex(s => s.id === stream.id), 1); @@ -127,15 +127,20 @@ async function play_stream(msg, respond, socket) { message: "user doesn't have permission" }); } - if (!vybe.streams[msg.id]) + let stream = vybe.streams[msg.id]; + if (!stream) return respond({ success: false, message: 'stream not found' }); if (msg.playing) - vybe.streams[msg.id].listeners[socket.id] = socket; + stream.listeners[socket.id] = socket; else - delete vybe.streams[msg.id].listeners[socket.id]; + delete stream.listeners[socket.id]; + stream.socket.emit('listeners', { + thread: stream.stream.thread, + count: Object.keys(stream.listeners).length + }); respond({ success: true });