diff --git a/server.py b/server.py index cc68825..5536041 100644 --- a/server.py +++ b/server.py @@ -29,6 +29,9 @@ _ffmpeg_in_q = queue.Queue(maxsize=200) _mp3_clients = set() # set[queue.Queue] _mp3_lock = threading.Lock() _transcode_threads_started = False +_transcoder_bytes_out = 0 +_transcoder_last_error = None +_last_audio_chunk_ts = 0.0 def _start_transcoder_if_needed(): @@ -62,7 +65,10 @@ def _start_transcoder_if_needed(): print('⚠️ ffmpeg not found; /stream.mp3 fallback disabled') return + print('🎛️ ffmpeg transcoder started for /stream.mp3') + def _writer(): + global _transcoder_last_error while True: chunk = _ffmpeg_in_q.get() if chunk is None: @@ -74,9 +80,11 @@ def _start_transcoder_if_needed(): proc.stdin.write(chunk) except Exception: # If ffmpeg dies or pipe breaks, just stop writing. + _transcoder_last_error = 'stdin write failed' break def _reader(): + global _transcoder_bytes_out, _transcoder_last_error proc = _ffmpeg_proc if proc is None or proc.stdout is None: return @@ -84,9 +92,11 @@ def _start_transcoder_if_needed(): try: data = proc.stdout.read(4096) except Exception: + _transcoder_last_error = 'stdout read failed' break if not data: break + _transcoder_bytes_out += len(data) with _mp3_lock: clients = list(_mp3_clients) for q in clients: @@ -120,8 +130,10 @@ def _stop_transcoder(): def _feed_transcoder(data: bytes): + global _last_audio_chunk_ts if _ffmpeg_proc is None or _ffmpeg_proc.poll() is not None: return + _last_audio_chunk_ts = eventlet.greenthread.time.time() try: _ffmpeg_in_q.put_nowait(data) except Exception: @@ -280,6 +292,21 @@ def setup_shared_routes(app): }, ) + @app.route('/stream_debug') + def stream_debug(): + proc = _ffmpeg_proc + running = proc is not None and proc.poll() is None + return jsonify({ + 'broadcast_active': broadcast_state.get('active', False), + 'broadcast_mimeType': broadcast_state.get('mimeType'), + 'ffmpeg_running': running, + 'ffmpeg_found': (proc is not None), + 'mp3_clients': len(_mp3_clients), + 'transcoder_bytes_out': _transcoder_bytes_out, + 'transcoder_last_error': _transcoder_last_error, + 'last_audio_chunk_ts': _last_audio_chunk_ts, + }) + # === DJ SERVER (Port 5000) === dj_app = Flask(__name__, static_folder='.', static_url_path='') dj_app.config['SECRET_KEY'] = 'dj_panel_secret' @@ -344,6 +371,10 @@ def dj_audio(data): # Relay audio chunk to all listeners immediately if broadcast_state['active']: listener_socketio.emit('audio_data', data, namespace='/') + # Ensure MP3 fallback transcoder is running (if ffmpeg is installed) + if _ffmpeg_proc is None or _ffmpeg_proc.poll() is not None: + _start_transcoder_if_needed() + if isinstance(data, (bytes, bytearray)): _feed_transcoder(bytes(data))