Skip to content

fix(cast): wait for media session before issuing play()#485

Open
brycesub wants to merge 1 commit into
muammar:masterfrom
brycesub:fix/cast-wait-for-media-session
Open

fix(cast): wait for media session before issuing play()#485
brycesub wants to merge 1 commit into
muammar:masterfrom
brycesub:fix/cast-wait-for-media-session

Conversation

@brycesub

Copy link
Copy Markdown

Problem

Casting intermittently crashes at startup with:

pychromecast.error.RequestFailed: Failed to execute play.

play_media(autoplay=True) only starts playback once the device has fetched the stream and established a media session. That handshake is asynchronous, but play_cast() slept a fixed 5 seconds and then unconditionally called media_controller.play(). When the session wasn't active yet, play() raised RequestFailed and the unhandled exception killed the whole cast.

This is a pre-existing race — the sleep(5) + play() block dates back to 2024-02. It rarely triggered because most paths establish a session within 5 seconds, but a slow cold start (portal grant + encoder init + buffering) reliably exceeds it.

Fix

Replace the blind sleep with media_controller.block_until_active(timeout=30), which returns as soon as the session is ready. Then only call play() when a session is actually active (and skip it entirely if autoplay is already playing), printing an actionable warning instead of crashing if no session forms in time.

The fix is generic and benefits every cast path.

Tests

Adds tests/test_cast_play.py covering the three handshake outcomes:

  • no session → must not crash, must not issue play()
  • active session → must play()
  • already playing → must not re-issue play()
$ python -m pytest tests/test_cast_play.py -q
...                                          [100%]
3 passed

🤖 Generated with Claude Code

play_media(autoplay=True) starts playback only once the device fetches the
stream and establishes a media session. That handshake is asynchronous, but
play_cast() slept a fixed 5 seconds and then unconditionally called
media_controller.play(). When the session was not active yet, play() raised
pychromecast RequestFailed ("Failed to execute play.") and the unhandled
exception killed the whole cast.

This is a pre-existing race (the sleep+play block dates to 2024-02 and lives
on master untouched by the Wayland branch). It surfaces reliably with the new
Wayland --screencast path, whose cold start (portal grant + GStreamer/x264
init + buffering) routinely exceeds 5 seconds; faster paths usually beat the
sleep and so rarely tripped it.

Replace the blind sleep with media_controller.block_until_active(timeout=30),
which returns as soon as the session is ready. Then only play() when a session
is actually active (and skip it if autoplay is already playing), printing an
actionable warning instead of crashing if no session forms in time. The fix is
generic and helps every cast path, not just Wayland.

Add tests/test_cast_play.py covering the three handshake outcomes: no session
(must not crash), active session (must play), already playing (must not
re-issue play).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant