stream volume and listener count

main
jerl 2024-06-23 21:55:28 -07:00
parent 3b288c9719
commit 4769e418e8
5 changed files with 93 additions and 27 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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;
}}>`);
}}>
<p id='listeners'>${window.currentThread.listeners ?
window.currentThread.listeners + ' listeners' : ''}
</p>`);
if (window.currentThread.streamname)
document.getElementById('streamname').value = window.currentThread.streamname;
}
@ -104,18 +106,21 @@ function loadStreams() {
function addStream(stream) {
let p = html.node`
<p>
<button id='play' onclick=${e => {
<button id='play' onclick=${function(event) {
if (stream.playing) {
audioctx.suspend();
stream.audioctx.suspend();
delete instance.streaming[stream.id];
stream.playing = false;
e.target.innerText = '▶';
this.innerText = '▶';
}
else {
audioctx = new AudioContext();
stream.audioctx = new AudioContext();
stream.gain = stream.audioctx.createGain();
stream.gain.connect(stream.audioctx.destination);
stream.gain.gain.value = p.children['volume'].value / 100;
instance.streaming[stream.id] = stream;
stream.playing = true;
e.target.innerText = '⏹';
this.innerText = '⏹';
}
instance.emit('play_stream', {
id: stream.id,
@ -126,11 +131,15 @@ function loadStreams() {
console.log('play stream failed: ', msg.message);
});
}}>${instance.streaming[stream.id] ? '⏹' : '▶'}</button>
<input id='volume' type='range' oninput=${function(event) {
if (stream.gain)
stream.gain.gain.value = this.value / 100;
}}>
<span id='name'>${stream.name ? ` - ${stream.name}` : ''}</span>
</p>`;
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)

View File

@ -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();
}
});

View File

@ -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
});