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
-
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.
-
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.
-
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.
-
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.
-
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.
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.GetActivePlayershanded it.The bug
Player.GetActivePlayersreports a video player under playerid0:{"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:
(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
The playing item does not classify as video.
VIDEO::IsVideo()(xbmc/video/VideoFileItemClassify.cpp:91) has nobluray://case, and theURIUtils::IsDVD()it calls (xbmc/utils/URIUtils.cpp:1128) matches only the literaldvd://1off Windows. Abluray://<encoded>/ordvd://<encoded>/path returns false.So the playlist player files it under music.
CPlayListPlayer'sTMSG_MEDIA_PLAYhandler (xbmc/PlayListPlayer.cpp:1008) starts atId::TYPE_MUSICand upgrades toTYPE_VIDEOonly if some item passesIsVideo(). The current playlist becomesTYPE_MUSIC(0), whileCApplication::PlayFilegoes on to play the disc as video.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, soGetActivePlayers(:142) stampsplayerid = 0onto the video entry.GetPlayer()round-trips through the same function (:1568):0resolves toAudio, and1resolves toNonebecauseGetPlaylist(Video)returns 0 and no longer matches the id asked for.SetAudioStream(:1359) handles onlyVideo. Both ids fail, for two different reasons.The read path papers over it.
GetPropertyValueforcurrentaudiostreamandaudiostreams(:2052,:2093) handlescase Video: case Audio:together against the sameCApplicationPlayer, 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.Openposts the same message through the same classification (PlayerOperations.cpp:1132, viaPlayFileItemList), 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 failsIsVideo()puts the wholePlayernamespace into this state.Fix
Two defects, and one upstream of them:
GetActivePlayersanswers what is playing; deriving that answer from the playlist lets it name a player that is not the one playing. This is the fix.GetPropertiesandSetAudioStream/SetSubtitlemust apply the same one: a playerid that returnsaudiostreamshas to acceptSetAudioStream.IsVideo()does not knowbluray://and barely knowsdvd://. 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.