From 02f72e2372d2442301ca68b116b229d9dc12a610 Mon Sep 17 00:00:00 2001 From: ComputerTech Date: Tue, 20 Jan 2026 18:14:50 +0000 Subject: [PATCH] Fix buffering issue and app bugs: improve stream delivery, fixed reset UI desync, and EQ naming --- script.js | 12 +++++++++++- server.py | 21 +++++++++++++++++---- techdj_qt.py | 27 +++++++++++++++++---------- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/script.js b/script.js index 9d90f25..d66e193 100644 --- a/script.js +++ b/script.js @@ -2242,7 +2242,17 @@ function initListenerMode() { socket.on('broadcast_started', () => { const nowPlayingEl = document.getElementById('listener-now-playing'); if (nowPlayingEl) nowPlayingEl.textContent = '🎵 Stream is live!'; - // Reset MediaSource for fresh stream if needed + + // Force a reload of the audio element to capture the fresh stream + if (window.listenerAudio) { + console.log('🔄 Broadcast started: Refreshing audio stream...'); + const wasPlaying = !window.listenerAudio.paused; + window.listenerAudio.src = getMp3FallbackUrl(); + window.listenerAudio.load(); + if (wasPlaying || window.listenerAudioEnabled) { + window.listenerAudio.play().catch(e => console.warn('Auto-play after refresh blocked:', e)); + } + } }); socket.on('stream_status', (data) => { diff --git a/server.py b/server.py index c781de2..e3f9a17 100644 --- a/server.py +++ b/server.py @@ -55,7 +55,7 @@ _transcode_threads_started = False _transcoder_bytes_out = 0 _transcoder_last_error = None _last_audio_chunk_ts = 0.0 -_mp3_preroll = collections.deque(maxlen=60) # Pre-roll (~2.5s at 192k) +_mp3_preroll = collections.deque(maxlen=256) # Pre-roll (~10s at 192k with 1KB chunks) def _start_transcoder_if_needed(is_mp3_input=False): @@ -141,7 +141,8 @@ def _start_transcoder_if_needed(is_mp3_input=False): break continue except Exception as e: - print(f"⚠️ Transcoder writer error: {e}") + if _ffmpeg_proc is not None: + print(f"⚠️ Transcoder writer error: {e}") _transcoder_last_error = f'stdin write failed: {e}' break _transcode_threads_started = False @@ -153,8 +154,9 @@ def _start_transcoder_if_needed(is_mp3_input=False): proc = _ffmpeg_proc while proc and proc.poll() is None: try: - # Use a larger read for efficiency - data = proc.stdout.read(4096) + # Smaller read for smoother delivery (1KB) + # This prevents buffering delays at lower bitrates + data = proc.stdout.read(1024) if not data: break _transcoder_bytes_out += len(data) @@ -199,6 +201,17 @@ def _stop_transcoder(): if proc is None: return + + # Signal all listening clients to finish their stream + with _mp3_lock: + clients = list(_mp3_clients) + for q in clients: + try: + q.put_nowait(None) + except: + pass + _mp3_clients.clear() + try: proc.terminate() except Exception: diff --git a/techdj_qt.py b/techdj_qt.py index 09ad5f3..be2b5eb 100644 --- a/techdj_qt.py +++ b/techdj_qt.py @@ -57,6 +57,7 @@ class AudioEngine: 'loop_active': False, 'repeat': False, 'queue': [], + 'needs_next_track': False, }, 'B': { 'audio_data': None, @@ -75,6 +76,7 @@ class AudioEngine: 'loop_active': False, 'repeat': False, 'queue': [], + 'needs_next_track': False, } } @@ -410,8 +412,8 @@ class BroadcastThread(QThread): # Thread to read encoded chunks from stdout def read_output(): - # Smaller buffer for more frequent updates (4KB = ~0.15s @ 192k) - buffer_size = 4096 + # Smaller buffer for more frequent updates (2KB = ~0.08s @ 192k) + buffer_size = 2048 while self.running: try: data = self.process.stdout.read(buffer_size) @@ -806,8 +808,9 @@ class DeckWidget(QWidget): eq_widget = QWidget() eq_layout = QHBoxLayout(eq_widget) eq_layout.setSpacing(8) + self.eq_sliders = {} - for band in ['HI', 'MID', 'LO']: + for band in ['HIGH', 'MID', 'LOW']: band_widget = QWidget() band_layout = QVBoxLayout(band_widget) band_layout.setSpacing(2) @@ -819,6 +822,7 @@ class DeckWidget(QWidget): slider.setFixedHeight(80) slider.setStyleSheet(self.get_slider_style()) slider.valueChanged.connect(lambda v, b=band.lower(): self.on_eq_change(b, v)) + self.eq_sliders[band.lower()] = slider label = QLabel(band) label.setStyleSheet("color: #888; font-size: 9px;") @@ -1001,20 +1005,23 @@ class DeckWidget(QWidget): def reset_deck(self): """Reset all deck controls to default values""" + # Setting values on sliders will trigger the valueChanged signal + # which will in turn update the audio engine. + # Reset volume to 80% self.volume_slider.setValue(80) # Reset speed to 100% self.speed_slider.setValue(100) - # Reset EQ to 0 (just update the engine, sliders will update via signals) - self.audio_engine.set_eq(self.deck_id, 'high', 0) - self.audio_engine.set_eq(self.deck_id, 'mid', 0) - self.audio_engine.set_eq(self.deck_id, 'low', 0) + # Reset EQ sliders to 0 + if hasattr(self, 'eq_sliders'): + for band, slider in self.eq_sliders.items(): + slider.setValue(0) - # Reset filters - self.audio_engine.set_filter(self.deck_id, 'lowpass', 100) - self.audio_engine.set_filter(self.deck_id, 'highpass', 0) + # Reset filter sliders + self.lp_slider.setValue(100) + self.hp_slider.setValue(0) print(f"🔄 Deck {self.deck_id} reset to defaults")