import asyncio import requests from livekit import rtc import wave import numpy as np from livekit.rtc import AudioSource, AudioFrame, LocalAudioTrack TOKEN_URL = "http://localhost:8000/getToken" WS_URL = "wss://esp32-vt80c4y6.livekit.cloud" # 你的 LiveKit Server 地址 ROOM_NAME = "test-room20" import uuid IDENTITY = f"uv-{uuid.uuid4().hex[:6]}" # IDENTITY = "test-user0" def get_token(): resp = requests.get( TOKEN_URL, params={ "room": ROOM_NAME, "identity": IDENTITY, "agent_name": "my-agent", # 关键!!! }, ) data = resp.json() return data["token"] async def main(): token = get_token() room = rtc.Room() @room.on("participant_connected") def on_participant_connected(participant): print(f"✅ 有人加入房间: {participant.identity}") @room.on("participant_disconnected") def on_participant_disconnected(participant): print(f"❌ 有人离开房间: {participant.identity}") print("🔌 正在连接房间...") await room.connect(WS_URL, token) print("✅ 已连接房间:", ROOM_NAME) print("当前房间成员:") for p in room.remote_participants.values(): print(" -", p.identity) @room.on("data_received") def on_data_received(data, participant, kind, topic): try: msg = data.decode() print(f"📩 来自 {participant.identity}: {msg}") except: print("📩 收到二进制数据") @room.on("track_subscribed") def on_track_subscribed(track, publication, participant): print(f"🎧 订阅轨道: {participant.identity}") if track.kind == rtc.TrackKind.KIND_AUDIO: print("👉 TTS 音频来了") # 等一下确保连接稳定 await asyncio.sleep(1) await room.local_participant.publish_data( b"hello", reliable=True, topic="chat" ) # 上传 wav await publish_wav(room, "2food.wav") await room.disconnect() async def publish_wav(room, wav_path): print("🎵 开始上传本地 wav:", wav_path) wf = wave.open(wav_path, "rb") sample_rate = wf.getframerate() num_channels = wf.getnchannels() sample_width = wf.getsampwidth() print(f"📊 WAV信息: {sample_rate}Hz, {num_channels}ch, {sample_width*8}bit") # 创建音频源 source = AudioSource(sample_rate, num_channels) # 创建本地音轨 track = LocalAudioTrack.create_audio_track("mic", source) # 发布轨道 await room.local_participant.publish_track(track) print("📡 已发布音轨") frame_duration = 0.02 # 20ms samples_per_frame = int(sample_rate * frame_duration) while True: data = wf.readframes(samples_per_frame) if not data: break # 用于计算长度 audio = np.frombuffer(data, dtype=np.int16) if len(audio) == 0: continue samples_per_channel = len(audio) // num_channels frame = AudioFrame( data=data, # ✅ 关键:用 bytes sample_rate=sample_rate, num_channels=num_channels, samples_per_channel=samples_per_channel, ) await source.capture_frame(frame) await asyncio.sleep(frame_duration) print("✅ wav 推流结束") if __name__ == "__main__": asyncio.run(main())