import { render, html } from '/uhtml.js'; let mediaStream; async function stream(thread) { if (thread.handle) { clearInterval(thread.handle); delete thread.handle; if (thread.recorder.state === 'recording') thread.recorder.stop(); thread.instance.emit('stream', { id: thread.streamid, thread: thread.id, stop: true }); document.getElementById('streaming').innerText = 'start streaming'; document.getElementById('listeners').innerText = ''; return; } if (!mediaStream) mediaStream = await navigator.mediaDevices.getUserMedia({ audio: { autoGainControl: false, echoCancellation: false, noiseSuppression: false, sampleRate: 48000, sampleSize: 16 } }); if (!mediaStream) { console.log("couldn't get media stream"); return; } thread.instance.emit('stream', { thread: thread.id, name: document.getElementById('streamname').value }, async msg => { if (!msg.success) { console.log('stream failed:', msg.message); return; } thread.streamid = msg.id; document.getElementById('streaming').innerText = 'stop streaming'; thread.recorder = new MediaRecorder(mediaStream, { mimeType: 'audio/webm;codecs=opus' }); thread.recorder.start(); thread.recorder.ondataavailable = async event => { if (!event.data.size || !thread.handle) return; thread.instance.emit('streamdata', { id: thread.streamid, audio: await event.data.arrayBuffer() }, msg => { if (msg.success) return; console.log('streamdata failed:', msg.message); if (msg.message === 'stream not found' && thread.handle) stream(thread); }); }; // first 200ms chunk will be used as stream header thread.handle = setTimeout(() => { thread.recorder.requestData(); thread.handle = setInterval(() => { if (!thread.handle) return; thread.recorder.requestData(); }, 500); }, 200); }); } function loadStreams() { let instance = window.currentInstance; let div = document.getElementById('stream'); div.innerHTML = ''; if (window.currentThread?.permissions.post) { render(div, html.node` stream name:
${currentThread.listeners ? currentThread.listeners + ' listeners' : ''}
`); if (currentThread.streamname) document.getElementById('streamname').value = currentThread.streamname; } div.insertAdjacentHTML('beforeend', `streams:
`); 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[2]); p.id = 'stream' + stream.id; document.getElementById('streams').append(p); } if (!instance.streaming) { instance.streaming = {}; instance.socket.on('stream', async msg => { let streams = document.querySelector( `#instance${instance.id} > #threads > #threadlist > #thread${msg.thread}`) .thread.streams; let i = streams.findIndex(s => s.id === msg.id); let p = document.getElementById('stream' + msg.id); if (msg.stopped) { if (i !== -1) { streams.splice(i, 1); if (msg.thread === window.currentThread?.id) p.remove(); } } else if (i === -1) { streams.push(msg); if (msg.thread === window.currentThread?.id) addStream(msg); } else { streams[i].name = msg.name; if (msg.thread === window.currentThread?.id) p.children['name'].innerText = msg.name ? ' - ' + msg.name : ''; } }); 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) for (let stream of window.currentThread.streams) addStream(stream); } export default loadStreams;