stream volume and listener count
							parent
							
								
									3b288c9719
								
							
						
					
					
						commit
						4769e418e8
					
				
							
								
								
									
										3
									
								
								DOCS.md
								
								
								
								
							
							
						
						
									
										3
									
								
								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 | ||||
|  |  | |||
|  | @ -46,25 +46,61 @@ | |||
| 				background: #303030; | ||||
| 			} | ||||
| 			button, | ||||
| 			input, | ||||
| 			input:not([type]), input[type='text'], | ||||
| 			.tab { | ||||
| 				padding: 4px 7px; | ||||
| 			} | ||||
| 			input { | ||||
| 				background: #1b1b1b; | ||||
| 				outline: none; | ||||
| 				&::placeholder { | ||||
| 					color: #aaa; | ||||
| 				} | ||||
| 				&:not([type]), &[type='text'] { | ||||
| 					border: 1px solid #444; | ||||
| 					&:focus { | ||||
| 						padding-bottom: 2px; | ||||
| 						border-bottom: 3px solid #777; | ||||
| 					} | ||||
| 				&::placeholder { | ||||
| 					color: #aaa; | ||||
| 				} | ||||
| 				&[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) { | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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(); | ||||
| 		} | ||||
| 	}); | ||||
|  |  | |||
|  | @ -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 | ||||
| 	}); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue