# -*- coding: utf-8 -*-

import asyncio
import sounddevice as sd
import subprocess
import threading
import queue
import sys
print("Python executable:", sys.executable)
import websockets
print("websockets version:", websockets.__version__)
print("websockets module file:", websockets.__file__)


# --- 設定 ---
SERVER_URL = 'wss://www.winway.tw:8765'
SAMPLE_RATE = 48000  # 播放的取樣率，必須與 ffmpeg 輸出一致
CHANNELS = 1         # 聲道數 (單聲道)
DTYPE = 'int16'      # 音訊資料型別，必須與 ffmpeg 輸出一致

# --- FFmpeg 指令 ---
# -f webm: 明確指定輸入格式為 WebM (瀏覽器 MediaRecorder 常見格式)，避免 ffmpeg 猜測失敗
# -i pipe:0: 從標準輸入讀取資料
# -f s16le: 輸出格式為 signed 16-bit little-endian PCM
# -ar {SAMPLE_RATE}: 設定音訊取樣率
# -ac {CHANNELS}: 設定聲道數
# -: 將結果輸出到標準輸出
ffmpeg_command = [
    'ffmpeg',
    '-f', 'webm',
    '-c:a', 'libopus',
    '-i', 'pipe:0',
    '-f', 's16le',
    '-ar', str(SAMPLE_RATE),
    '-ac', str(CHANNELS),
    '-'
]

# 用於在執行緒之間傳遞解碼後音訊的佇列
audio_queue = queue.Queue()

def play_audio_from_queue():
    """
    此函式在獨立的執行緒中執行。
    它從佇列中讀取解碼後的音訊並透過 sounddevice 播放。
    """
    with sd.RawOutputStream(samplerate=SAMPLE_RATE, channels=CHANNELS, dtype=DTYPE) as stream:
        print("✅ 音訊輸出裝置已就緒，等待音訊資料...")
        while True:
            data = audio_queue.get()
            if data is None:  # 收到 None 時，表示串流結束
                break
            stream.write(data)
            # print(f"🎧 正在播放 {len(data)} bytes 的音訊...") # 取消註解此行可看見詳細播放日誌
        print("⏹️ 音訊輸出串流結束。")


# --- 純 WebSocket 播放主程式 ---
async def main():
    try:
        print("▶️  正在啟動 ffmpeg 解碼程序...")
        ffmpeg_process = subprocess.Popen(
            ffmpeg_command,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE
        )
        print("✅ ffmpeg 程序已啟動。")
    except FileNotFoundError:
        print("\n" + "="*60)
        print("❌ 錯誤: 找不到 'ffmpeg' 指令。")
        print("   請先在您的作業系統中安裝 ffmpeg，並確保其路徑已加入環境變數。")
        print("   - Windows: https://ffmpeg.org/download.html")
        print("   - macOS (Homebrew): brew install ffmpeg")
        print("   - Linux (apt): sudo apt-get install ffmpeg")
        print("="*60 + "\n")
        return

    player_thread = threading.Thread(target=play_audio_from_queue)
    player_thread.daemon = True
    player_thread.start()

    def read_ffmpeg_output():
        while True:
            decoded_data = ffmpeg_process.stdout.read(2048)
            if not decoded_data:
                break
            audio_queue.put(decoded_data)
        stderr_output = ffmpeg_process.stderr.read()
        if stderr_output:
            print(f"\n--- FFmpeg 錯誤訊息 ---\n{stderr_output.decode(sys.stderr.encoding, errors='ignore')}")
        print("⏹️ FFmpeg 輸出讀取結束。")

    ffmpeg_reader_thread = threading.Thread(target=read_ffmpeg_output)
    ffmpeg_reader_thread.daemon = True
    ffmpeg_reader_thread.start()

    received_header = False
    header_buffer = b''
    def is_webm_header_complete(buf):
        return buf.startswith(b'\x1A\x45\xDF\xA3') and b'webm' in buf and len(buf) > 4096

    print(f"🔗 正在連接到 {SERVER_URL} (WebSocket)...")
    try:
        # websockets.connect extra_headers 需為 list of tuples for older versions
        extra_headers = [('Origin', 'https://www.winway.tw')]
        async with websockets.connect(
            SERVER_URL,
            extra_headers=extra_headers
        ) as websocket:
            print("✅ 已連接 WebSocket 伺服器，等待音訊資料...")
            while True:
                message = await websocket.recv()
                if isinstance(message, str):
                    # 跳過文字訊息
                    continue
                data = message
                print(f"📡 收到 {len(data)} bytes 的音訊資料。")
                if not received_header:
                    header_buffer += data
                    print(f"⏳ 累積 header 中，目前 {len(header_buffer)} bytes... 前 32 bytes: {header_buffer[:32].hex(' ')}")
                    if is_webm_header_complete(header_buffer):
                        print(f"📝 已寫入 WebM header ({len(header_buffer)} bytes) 給 ffmpeg。header 前 32 bytes: {header_buffer[:32].hex(' ')}")
                        ffmpeg_process.stdin.write(header_buffer)
                        received_header = True
                        print(f"📝 已寫入 WebM header ({len(header_buffer)} bytes) 給 ffmpeg。header 前 32 bytes: {header_buffer[:32].hex(' ')}")
                else:
                    ffmpeg_process.stdin.write(data)
    except websockets.ConnectionClosed:
        print("🔌 WebSocket 連線已關閉。")
    except KeyboardInterrupt:
        print("\n� 使用者中斷程式。")
    except Exception as e:
        print(f"❌ 連線或資料處理時發生錯誤: {e}")
    finally:
        print("🧹 正在清理資源...")
        if 'ffmpeg_process' in locals() and ffmpeg_process.poll() is None:
            ffmpeg_process.stdin.close()
            ffmpeg_process.wait()
        audio_queue.put(None)
        player_thread.join()
        print("👋 程式結束。")

if __name__ == '__main__':
    asyncio.run(main())


