Skip to content

[jsonrpc] The playerid is derived from the playlist, not the player, so a playing video can be unreachable from every Player method #128

Description

@malard

The playerid is derived from the playlist, not the player

Split out of xbmc#29077 — the official iOS remote cannot change the audio stream during Blu-ray playback. The app is not at fault: it uses the playerid Player.GetActivePlayers handed it.

The bug

Player.GetActivePlayers reports a video player under playerid 0:

{"id": 105, "jsonrpc": "2.0", "result": [{"playerid": 0, "playertype": "internal", "type": "video"}]}

and every video-only method then refuses both that id and the real one:

Player.SetAudioStream  {"stream": 2, "playerid": 0}         -> -32100 Failed to execute method
Player.SetAudioStream  {"stream": 2, "playerid": 1}         -> -32100 Failed to execute method
Player.GetProperties   ["audiostreams"] "playerid": 1       -> -32100 Failed to execute method
Player.GetProperties   ["audiostreams"] "playerid": 0       -> 200, the full stream list

(reporter's transcript over the web server, Kodi 21.2, xbmc#29077)

A client that follows the documented flow — call GetActivePlayers, then address the playerid it returns — cannot reach the player at all. The read path answers anyway, so nothing about the state is visible until a write silently fails.

The chain

  1. The playing item does not classify as video. VIDEO::IsVideo() (xbmc/video/VideoFileItemClassify.cpp:91) has no bluray:// case, and the URIUtils::IsDVD() it calls (xbmc/utils/URIUtils.cpp:1128) matches only the literal dvd://1 off Windows. A bluray://<encoded>/ or dvd://<encoded>/ path returns false.

  2. So the playlist player files it under music. CPlayListPlayer's TMSG_MEDIA_PLAY handler (xbmc/PlayListPlayer.cpp:1008) starts at Id::TYPE_MUSIC and upgrades to TYPE_VIDEO only if some item passes IsVideo(). The current playlist becomes TYPE_MUSIC (0), while CApplication::PlayFile goes on to play the disc as video.

  3. JSON-RPC takes the playerid from the playlist. CPlayerOperations::GetPlaylist() (xbmc/interfaces/json-rpc/PlayerOperations.cpp:1598) returns the current playlist and consults the player only when there is none, so GetActivePlayers (:142) stamps playerid = 0 onto the video entry.

  4. GetPlayer() round-trips through the same function (:1568): 0 resolves to Audio, and 1 resolves to None because GetPlaylist(Video) returns 0 and no longer matches the id asked for. SetAudioStream (:1359) handles only Video. Both ids fail, for two different reasons.

  5. The read path papers over it. GetPropertyValue for currentaudiostream and audiostreams (:2052, :2093) handles case Video: case Audio: together against the same CApplicationPlayer, so playerid 0 returns the real stream list. That is why the remote's menu populates, and follows changes made from the OSD, while its own writes do nothing.

Reachable from our own surface

Player.Open posts the same message through the same classification (PlayerOperations.cpp:1132, via PlayFileItemList), so this reproduces over JSON-RPC alone with a disc path — no Python add-on involved. It is not disc-specific either: any item that plays as video but fails IsVideo() puts the whole Player namespace into this state.

Fix

Two defects, and one upstream of them:

  • The playerid should come from the player. GetActivePlayers answers what is playing; deriving that answer from the playlist lets it name a player that is not the one playing. This is the fix.
  • Read and write disagree about which playerids are valid. Whatever resolution rule lands, GetProperties and SetAudioStream / SetSubtitle must apply the same one: a playerid that returns audiostreams has to accept SetAudioStream.
  • IsVideo() does not know bluray:// and barely knows dvd://. Upstream of both, worth fixing on its own, but it does not make the API correct — the reachability gap survives for the next item that misclassifies.

Status

Diagnosed by reading jsonrpc-14; the wire evidence above is the reporter's, not reproduced here yet. Failing tests first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions