Encoding thread: Take complete frames from audio_buffer, encode them into Opus, and place them into opus_bytes_queue
()
| 847 | log("info", "TTS receiver thread stopped") |
| 848 | |
| 849 | def encode_thread_func(): |
| 850 | """Encoding thread: Take complete frames from audio_buffer, encode them into Opus, and place them into opus_bytes_queue""" |
| 851 | nonlocal reset_first_frame, tts_generation_complete, frame_generation_complete |
| 852 | |
| 853 | local_opus_writer = sphn.OpusStreamWriter(self.sample_rate) |
| 854 | frame_size = int(self.sample_rate * 0.04) # 80ms = 1920 samples @ 24kHz |
| 855 | local_buffer = np.array([], dtype=np.float32) |
| 856 | is_first_frame = True |
| 857 | first_frame_start_time = None |
| 858 | |
| 859 | log("info", "Encode thread started") |
| 860 | |
| 861 | while not close: |
| 862 | try: |
| 863 | if reset_first_frame['flag']: |
| 864 | is_first_frame = True |
| 865 | first_frame_start_time = None |
| 866 | reset_first_frame['flag'] = False |
| 867 | local_buffer = np.array([], dtype=np.float32) |
| 868 | log("info", "Reset first frame flag for new conversation turn") |
| 869 | |
| 870 | with audio_buffer_lock: |
| 871 | if len(audio_buffer_list) > 0: |
| 872 | chunk = audio_buffer_list.pop(0) |
| 873 | else: |
| 874 | chunk = None |
| 875 | |
| 876 | if chunk is None: |
| 877 | if frame_generation_complete['flag'] and len(local_buffer) > 0: |
| 878 | log("info", f"TTS completed, flushing remaining {len(local_buffer)} samples") |
| 879 | |
| 880 | if is_first_frame: |
| 881 | is_first_frame = False |
| 882 | log("info", "Skipping first frame delay due to TTS completion") |
| 883 | |
| 884 | while len(local_buffer) >= frame_size: |
| 885 | frame = local_buffer[:frame_size] |
| 886 | local_buffer = local_buffer[frame_size:] |
| 887 | |
| 888 | opus_bytes = local_opus_writer.append_pcm(frame) |
| 889 | if opus_bytes is not None and len(opus_bytes) > 0: |
| 890 | opus_bytes_queue.put(opus_bytes) |
| 891 | |
| 892 | # Process the last incomplete frame (pad with zeros) |
| 893 | if len(local_buffer) > 0: |
| 894 | padding = np.zeros(frame_size - len(local_buffer), dtype=np.float32) |
| 895 | frame = np.concatenate([local_buffer, padding]) |
| 896 | local_buffer = np.array([], dtype=np.float32) |
| 897 | |
| 898 | opus_bytes = local_opus_writer.append_pcm(frame) |
| 899 | if opus_bytes is not None and len(opus_bytes) > 0: |
| 900 | opus_bytes_queue.put(opus_bytes) |
| 901 | log("info", "Encoded final partial frame") |
| 902 | |
| 903 | log("info", "All audio flushed to queue") |
| 904 | |
| 905 | time.sleep(0.01) |
| 906 | continue |