Continuously processes audio chunks received from an asyncio Queue. Retrieves audio data, processes it using `process_audio_chunk`, and feeds the result to the transcriber unless interrupted or the transcription task has failed. Stops when `None` is received from th
(self, audio_queue: asyncio.Queue)
| 151 | |
| 152 | |
| 153 | async def process_chunk_queue(self, audio_queue: asyncio.Queue) -> None: |
| 154 | """ |
| 155 | Continuously processes audio chunks received from an asyncio Queue. |
| 156 | |
| 157 | Retrieves audio data, processes it using `process_audio_chunk`, and |
| 158 | feeds the result to the transcriber unless interrupted or the transcription |
| 159 | task has failed. Stops when `None` is received from the queue or upon error. |
| 160 | |
| 161 | Args: |
| 162 | audio_queue: An asyncio queue expected to yield dictionaries containing |
| 163 | 'pcm' (raw audio bytes) or None to terminate. |
| 164 | """ |
| 165 | logger.info("👂▶️ Starting audio chunk processing loop.") |
| 166 | while True: |
| 167 | try: |
| 168 | # Check if the transcription task has permanently failed *before* getting item |
| 169 | if self._transcription_failed: |
| 170 | logger.error("👂🛑 Transcription task failed previously. Stopping audio processing.") |
| 171 | break # Stop processing if transcription backend is down |
| 172 | |
| 173 | # Check if the task finished unexpectedly (e.g., cancelled but not failed) |
| 174 | # Needs to check self.transcription_task existence as it might be None during shutdown |
| 175 | if self.transcription_task and self.transcription_task.done() and not self._transcription_failed: |
| 176 | # Attempt to check exception status if task is done |
| 177 | task_exception = self.transcription_task.exception() |
| 178 | if task_exception and not isinstance(task_exception, asyncio.CancelledError): |
| 179 | # If there was an exception other than CancelledError, treat it as failed. |
| 180 | logger.error(f"👂🛑 Transcription task finished with unexpected error: {task_exception}. Stopping audio processing.", exc_info=task_exception) |
| 181 | self._transcription_failed = True # Mark as failed |
| 182 | break |
| 183 | else: |
| 184 | # Finished cleanly or was cancelled |
| 185 | logger.warning("👂⏹️ Transcription task is no longer running (completed or cancelled). Stopping audio processing.") |
| 186 | break # Stop processing |
| 187 | |
| 188 | audio_data = await audio_queue.get() |
| 189 | if audio_data is None: |
| 190 | logger.info("👂🔌 Received termination signal for audio processing.") |
| 191 | break # Termination signal |
| 192 | |
| 193 | pcm_data = audio_data.pop("pcm") |
| 194 | |
| 195 | # Process audio chunk (resampling happens consistently via float32) |
| 196 | processed = self.process_audio_chunk(pcm_data) |
| 197 | if processed.size == 0: |
| 198 | continue # Skip empty chunks |
| 199 | |
| 200 | # Feed audio only if not interrupted and transcriber should be running |
| 201 | if not self.interrupted: |
| 202 | # Check failure flag again, as it might have been set between queue.get and here |
| 203 | if not self._transcription_failed: |
| 204 | # Feed audio to the underlying processor |
| 205 | self.transcriber.feed_audio(processed.tobytes(), audio_data) |
| 206 | # No 'else' needed here because the checks at the start of the loop handle termination |
| 207 | |
| 208 | except asyncio.CancelledError: |
| 209 | logger.info("👂🚫 Audio processing task cancelled.") |
| 210 | break |
no test coverage detected