androidx / androidx/media

RemoteCastPlayer silently ignores MediaChannelResult status for setPlayWhenReady, setPlaybackParameters, setRepeatMode and setVolume

Open
#3,373 1 comment 0 reactions 2 assignees View on GitHub

@tanay187 is already working on this.

Since Aug 14, 2026.

Dominant language
Java
Stars
3k
Forks
955
Avg merge
12d 14h
Merged PRs (30d)
2

Description

Version

Media3 1.11.0

More version details

androidx.media3:media3-cast:1.11.0 with play-services-cast-framework:22.3.1. Findings below come from reading the shipped bytecode of media3-cast-1.11.0.aar with javap -c -p.

Devices that reproduce the issue

Not device-specific. The symptom needs a receiver that rejects a request; mine was a Chromecast Audio on the Default Media Receiver (CC1AD845) with a second sender attached to the same session, which made the receiver answer Invalid Request.

Devices that do not reproduce the issue

n/a

Reproducible in the demo app?

Not tested

Reproduction steps
  1. Cast to a receiver that will reject a request. The reliable way is to join a Default Media Receiver session that another sender is also mutating, so the receiver's sequence numbers stop matching.
  2. Call setPlaybackParameters (or setPlayWhenReady, setRepeatMode, setVolume) on the CastPlayer.
  3. Watch logcat and watch the app.

The Cast SDK reports the rejection:

W/MediaControlChannel: received unexpected error: Invalid Request.
W/MediaControlChannel: Possibility of local queue out of sync with receiver queue.
                       Refetching sequence number. Current Local Sequence Number = 6

Media3 does not, and the app has no callback through which it could learn.

Expected result

An app can tell that a request it issued was rejected by the receiver, so it can retry, reconcile, or tell the user. Media3 already does this for two other request families, which is why the gap reads as an oversight rather than a deliberate contract:

  • RemoteCastPlayer$SeekResultCallback reads Status.getStatusCode() and logs Seek failed. Error code.
  • RemoteCastPlayer$StatusListener logs Session start failed and Session resume failed.
Actual result

The ResultCallback<MediaChannelResult> instances used for the state setters never look at the result. RemoteCastPlayer$1.onResult is representative — it null-checks the client, clears the pending-result bookkeeping and flushes listener events, and that is all:

public void onResult(RemoteMediaClient$MediaChannelResult);
   0: getfield      this$0
   4: invokestatic  RemoteCastPlayer.access$1100   // remoteMediaClient
   7: ifnull        28
  10: ...
  15: invokestatic  RemoteCastPlayer.access$1200   // clear pending callback
  22: invokestatic  RemoteCastPlayer.access$1300   // listeners
  25: invokevirtual ListenerSet.flushEvents
  28: return

RemoteCastPlayer$2 through $5 have the same shape. None of the five references Status, getStatusCode, or isSuccess; by contrast SeekResultCallback does.

Tracing where those five are constructed, they cover:

Callback site Public API
RemoteCastPlayer$1$5 setPlayWhenReady(boolean), setPlaybackParameters(PlaybackParameters), setRepeatMode(int), setVolume(float), plus updateTracksAndNotifyIfChanged

So a rejected play/pause, playback-speed, repeat-mode or volume change is indistinguishable from a successful one. The player's masked state reverts on the next receiver status, but nothing tells the app why, and nothing is logged.

The practical consequence for me: playback speed set locally did not take effect on the receiver, and there was no way to find out from the library whether the setPlaybackParameters request had been rejected or never mattered. I ended up re-applying the speed after STATE_READY as a workaround, without being able to confirm which of the two it was.

I have not traced the queue-mutation path (queueInsertItems, queueReorderItems, queueRemoveItems, load) to the same level of certainty, so I am not claiming anything about it here — though those also attach a ResultCallback through StateHolder and were what first sent me looking.

Logging a failure the way SeekResultCallback already does would be enough to make this diagnosable. Surfacing it to the app would be better.

Media

Not content-dependent.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.