fix: create room IO media streams off the event loop and demote retryable STT errors - #7502
Open
muntazir868 wants to merge 2 commits into
Open
muntazir868 wants to merge 2 commits into
muntazir868 wants to merge 2 commits into
Conversation
AudioStream/VideoStream.from_track performs a synchronous FFI request (initializing noise cancellation can block for >100ms) and was called directly from the track_subscribed handler, tripping the loop monitor. Create the stream in a task via asyncio.to_thread, pass the running loop explicitly so frames still dispatch onto it, and guard against track events that supersede an in-flight creation with a generation counter plus a lock around processor ownership.
A gateway reject before input end (e.g. a provider refusing the session during init, code 2006) is retried by SpeechStream, which already logs a WARNING, and the session recreates the stream when retries are exhausted. Logging the same failure as ERROR in recv_task blamed the application for a handled gateway retry; demote retryable errors to debug and keep ERROR for terminal ones.
Contributor
There was a problem hiding this comment.
Devin Review found 1 potential issue.
1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #7441
Summary
1. Room IO: create media streams off the event loop
AudioStream.from_track/VideoStream.from_trackrun a synchronous FFI request, and_on_track_availablecalled it directly from thetrack_subscribedhandler — initializing noise cancellation (e.g.BVC()) blocked the loop for 106–119ms and tripped the loop monitor._create_streamis now async; the audio/video implementations runfrom_trackviaasyncio.to_threadand passloop=explicitly so the stream still dispatches frames onto the job loop._create_and_forward_stream) serialized by a lock, with a generation counter: a track event that supersedes an in-flight creation discards the pending stream instead of installing it, and_close_streamdefers processor cleanup to that task while it settles.aclosewaits for in-flight creations before tearing down._track/_publication, preserving the previous synchronous failure's retry semantics.2. Inference STT: retryable
recv_taskerrors log at debugA gateway reject before input end (e.g.
code=2006, "Streaming ASR unavailable" during init) isretryable=Trueand already handled bySpeechStream's retry loop (WARNING) and the session's stream recreation.recv_tasklogged the same failure as ERROR twice (inline +log_exceptions), blaming the application for a handled gateway retry.debug; terminal errors still log aterror.log_exceptionswrapper onrecv_taskis replaced with level-aware handling.Testing
make check(ruff format + lint, mypy strict) — cleanuv run pytest --unit --audio_eot— 4015 passed, 0 failedtest_audio_stream_created_off_event_loop_and_bound_to_it— creation runs on a worker thread,loop=is the running loop, and the loop keeps ticking whilefrom_trackblocks for 150mstest_stream_create_discarded_when_superseded— generation guard discards an overtaken creationtest_retryable_error_logs_at_debug_not_error/test_non_retryable_error_still_logs_at_error— log-level behaviortests/test_room_io.pyrunsto_threadinline under virtual time (the autojump clock races real executor threads); the off-loop tests opt out with thereal_timemarker.