File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -153,13 +153,26 @@ def callback(
153153 buffer_pos = 0
154154
155155 producer_task = asyncio .create_task (buffer_producer ())
156-
157- with sd .OutputStream (
158- samplerate = SAMPLE_RATE ,
159- channels = self .channels ,
160- dtype = self .dtype ,
161- callback = callback ,
162- ):
163- await event .wait ()
164-
165- await producer_task
156+ playback_task = asyncio .create_task (event .wait ())
157+
158+ try :
159+ with sd .OutputStream (
160+ samplerate = SAMPLE_RATE ,
161+ channels = self .channels ,
162+ dtype = self .dtype ,
163+ callback = callback ,
164+ ):
165+ done , _ = await asyncio .wait (
166+ (producer_task , playback_task ),
167+ return_when = asyncio .FIRST_COMPLETED ,
168+ )
169+ if producer_task in done :
170+ producer_task .result ()
171+ await playback_task
172+
173+ await producer_task
174+ finally :
175+ for task in (producer_task , playback_task ):
176+ if not task .done ():
177+ task .cancel ()
178+ await asyncio .gather (producer_task , playback_task , return_exceptions = True )
Original file line number Diff line number Diff line change 1+ from __future__ import annotations
2+
3+ import asyncio
4+ from typing import Any
5+ from collections .abc import AsyncGenerator
6+
7+ import pytest
8+
9+ from openai .helpers import local_audio_player
10+
11+
12+ class SilentOutputStream :
13+ def __init__ (self , ** kwargs : Any ) -> None :
14+ pass
15+
16+ def __enter__ (self ) -> SilentOutputStream :
17+ return self
18+
19+ def __exit__ (self , * args : Any ) -> None :
20+ pass
21+
22+
23+ async def test_play_stream_propagates_producer_failure (monkeypatch : pytest .MonkeyPatch ) -> None :
24+ async def broken_stream () -> AsyncGenerator [None , None ]:
25+ if asyncio .current_task () is None :
26+ yield None
27+ raise RuntimeError ("synthetic producer failure" )
28+
29+ monkeypatch .setattr (local_audio_player .sd , "OutputStream" , SilentOutputStream )
30+
31+ with pytest .raises (RuntimeError , match = "synthetic producer failure" ):
32+ await asyncio .wait_for (
33+ local_audio_player .LocalAudioPlayer ().play_stream (broken_stream ()),
34+ timeout = 1 ,
35+ )
You can’t perform that action at this time.
0 commit comments