Sfoglia il codice sorgente

Optimized audio streaming pcm over websocket

TC 1 giorno fa
parent
commit
8ec10c5b09
2 ha cambiato i file con 33 aggiunte e 27 eliminazioni
  1. 4 1
      remdeskd/mod/usbcapture/audio_device.go
  2. 29 26
      remdeskd/www/index.html

+ 4 - 1
remdeskd/mod/usbcapture/audio_device.go

@@ -136,7 +136,7 @@ func (i Instance) AudioStreamingHandler(w http.ResponseWriter, r *http.Request)
 	i.audiostopchan = make(chan bool, 1)
 	log.Println("Starting audio pipe with arecord...")
 
-	// Start arecord with 24kHz, 16-bit, stereo
+	// Start arecord with 48kHz, 16-bit, stereo
 	cmd := exec.Command("arecord",
 		"-f", "S16_LE", // Format: 16-bit little-endian
 		"-r", fmt.Sprint(i.Config.AudioConfig.SampleRate),
@@ -186,6 +186,9 @@ func (i Instance) AudioStreamingHandler(w http.ResponseWriter, r *http.Request)
 			n, err := reader.Read(buf)
 			if err != nil {
 				log.Println("Read error:", err)
+				if i.audiostopchan != nil {
+					i.audiostopchan <- true // Signal to stop the audio pipe
+				}
 				goto DONE
 			}
 

+ 29 - 26
remdeskd/www/index.html

@@ -301,7 +301,8 @@
                 }
             };
 
-            const MAX_AUDIO_QUEUE = 2;
+            const MAX_AUDIO_QUEUE = 8;
+            let scheduledTime = 0;
             audioSocket.onmessage = function(event) {
                 if (!audioContext) return;
                 let pcm = new Int16Array(event.data);
@@ -311,7 +312,7 @@
                 }
                 if (pcm.length % 2 !== 0) {
                     console.warn("Received PCM data with odd length, dropping last sample");
-                    pcm = pcm.slice(0, -1); // Drop last sample if odd length
+                    pcm = pcm.slice(0, -1);
                 }
                 // Convert Int16 PCM to Float32 [-1, 1]
                 let floatBuf = new Float32Array(pcm.length);
@@ -320,14 +321,10 @@
                 }
                 // Limit queue size to prevent memory overflow
                 if (audioQueue.length >= MAX_AUDIO_QUEUE) {
-                    audioQueue.shift(); // Remove oldest audio buffer if queue is full
+                    audioQueue.shift();
                 }
                 audioQueue.push(floatBuf);
-                if (!audioPlaying) {
-                    audioPlaying = true;
-                    playAudioQueue();
-                }
-                
+                scheduleAudioPlayback();
             };
 
             audioSocket.onclose = function() {
@@ -335,32 +332,38 @@
                 audioSocket = null;
                 audioPlaying = false;
                 audioQueue = [];
+                scheduledTime = 0;
             };
 
             audioSocket.onerror = function(e) {
                 console.error("Audio WebSocket error", e);
             };
-        }
 
-        function playAudioQueue() {
-            if (!audioContext || audioQueue.length === 0) {
-                audioPlaying = false;
-                return;
-            }
-            let floatBuf = audioQueue.shift();
-            let frameCount = floatBuf.length / 2;
-            let buffer = audioContext.createBuffer(2, frameCount, 48000);
-            for (let ch = 0; ch < 2; ch++) {
-                let channelData = buffer.getChannelData(ch);
-                for (let i = 0; i < frameCount; i++) {
-                    channelData[i] = floatBuf[i * 2 + ch];
+            function scheduleAudioPlayback() {
+                if (!audioContext || audioQueue.length === 0) return;
+
+                // Use audioContext.currentTime to schedule buffers back-to-back
+                if (scheduledTime < audioContext.currentTime) {
+                    scheduledTime = audioContext.currentTime;
+                }
+
+                while (audioQueue.length > 0) {
+                    let floatBuf = audioQueue.shift();
+                    let frameCount = floatBuf.length / 2;
+                    let buffer = audioContext.createBuffer(2, frameCount, 48000);
+                    for (let ch = 0; ch < 2; ch++) {
+                        let channelData = buffer.getChannelData(ch);
+                        for (let i = 0; i < frameCount; i++) {
+                            channelData[i] = floatBuf[i * 2 + ch];
+                        }
+                    }
+                    let source = audioContext.createBufferSource();
+                    source.buffer = buffer;
+                    source.connect(audioContext.destination);
+                    source.start(scheduledTime);
+                    scheduledTime += buffer.duration;
                 }
             }
-            let source = audioContext.createBufferSource();
-            source.buffer = buffer;
-            source.connect(audioContext.destination);
-            source.onended = playAudioQueue;
-            source.start();
         }
 
         function stopAudioWebSocket() {