Async coroutine: Read encoded Opus data from the queue and send at fixed time intervals
()
| 939 | log("info", "Encode thread stopped") |
| 940 | |
| 941 | async def send_audio_loop(): |
| 942 | """Async coroutine: Read encoded Opus data from the queue and send at fixed time intervals""" |
| 943 | nonlocal reset_send_state, audio_send_started |
| 944 | frame_interval = 0.010 |
| 945 | next_send_time = None |
| 946 | frames_sent = 0 |
| 947 | |
| 948 | while not close: |
| 949 | try: |
| 950 | if reset_send_state['flag']: |
| 951 | next_send_time = None |
| 952 | frames_sent = 0 |
| 953 | reset_send_state['flag'] = False |
| 954 | log("info", "Reset send state for new turn") |
| 955 | |
| 956 | try: |
| 957 | opus_bytes = opus_bytes_queue.get_nowait() |
| 958 | except queue.Empty: |
| 959 | await asyncio.sleep(0.005) |
| 960 | continue |
| 961 | |
| 962 | current_time = time.time() |
| 963 | |
| 964 | if next_send_time is None: |
| 965 | next_send_time = current_time |
| 966 | |
| 967 | wait_time = next_send_time - current_time |
| 968 | |
| 969 | if wait_time > 0: |
| 970 | await asyncio.sleep(wait_time) |
| 971 | |
| 972 | await ws.send_bytes(b"\x01" + opus_bytes) |
| 973 | frames_sent += 1 |
| 974 | |
| 975 | # When the first frame is sent, notify the text sending thread to start |
| 976 | if frames_sent == 1: |
| 977 | audio_send_started['flag'] = True |
| 978 | log("info", "Audio sending started, text buffer can start sending") |
| 979 | |
| 980 | next_send_time += frame_interval |
| 981 | |
| 982 | lag = time.time() - next_send_time |
| 983 | if lag > 0.5: |
| 984 | log("warning", f"Send lag detected: {lag*1000:.0f}ms, resetting time base") |
| 985 | next_send_time = time.time() + frame_interval |
| 986 | |
| 987 | timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3] |
| 988 | log("info", f"[{timestamp}] Sent frame #{frames_sent} (queue: {opus_bytes_queue.qsize()}, lag: {lag*1000:.1f}ms)") |
| 989 | |
| 990 | except Exception as e: |
| 991 | log("error", f"Send coroutine error: {e}") |
| 992 | import traceback |
| 993 | traceback.print_exc() |
| 994 | |
| 995 | log("info", f"Send coroutine stopped, total frames sent: {frames_sent}") |
| 996 | |
| 997 | async def send_text_loop(): |
| 998 | """Asynchronous coroutine: Read text from the text buffer queue and send it at 200ms intervals after audio transmission begins.""" |