Media Player — media_player
Anything that originates content: a streamer, a disc player, a cable box, a music service.
It is a source in the signal graph — a room's watch or listen names one of these.
Capabilities
Declared in the driver manifest under [[proxy]] capabilities. Anything not declared takes the default below.
| Capability | Type | Default | Meaning |
|---|---|---|---|
has_app_launcher | bool | false | The player's top-level application launcher can be opened |
has_apps | bool | false | Installed applications can be listed and launched |
has_browse | bool | false | Content can be listed and selected by id |
has_crossfade | bool | false | Blends the end of one track into the next |
has_deep_link | bool | false | launch_app can open a particular title, not just the app. |
Separate from has_apps because the two come apart in both directions and the difference is
invisible from outside: a Roku set to Limited control still launches channels and a tvOS app
that dropped its deep links still opens. Without this, content_id is a parameter every
app-capable driver accepts and some silently ignore — so "play Severance" reports success and
leaves somebody on a home screen.
Whoever is resolving a title reads this to decide whether to bother looking one up, and to
tell a person the truth when the answer is no.
|
| has_discrete_volume | bool | false | |
| has_dpad | bool | false | Cursor navigation for an on-screen UI |
| has_hold | bool | false | A key can be held down and later released, rather than only tapped. See hold.
Separate from the commands it holds because the two really do come apart: an IR emitter can
ramp anything it has a code for, and a box reached over HTTP one request at a time can ramp
nothing at all however many keys it has.
|
| has_metadata | bool | false | Reports title/artist/art |
| has_mute | bool | false | |
| has_number_keys | bool | false | |
| has_playlists | bool | false | |
| has_queue | bool | false | Content can be queued rather than only played now |
| has_scan | bool | false | Fast forward / rewind |
| has_search | bool | false | |
| has_seek | bool | false | |
| has_shuffle_repeat | bool | false | |
| has_skip | bool | false | |
| has_transport | bool | true | Play/pause/stop |
| has_up_down_volume | bool | false | |
| is_audio_source | bool | true | |
| is_video_source | bool | false | |
| volume_max | u32 | 100 | |
Commands
browse
Only present when
has_browseis declared true.
List what is under node. Results do not come back from this call — a command cannot return —
they arrive as browse_results carrying the same token.
| Parameter | Type | Notes |
|---|---|---|
limit | u32 (optional) | |
node | string (optional) | A container id from an earlier result. Absent means the root. |
offset | u32 (optional) | |
token | string (optional) | Echoed back on the matching browse_results |
dpad
Only present when
has_dpadis declared true.
| Parameter | Type | Notes |
|---|---|---|
key | one of up · down · left · right · select · back · menu · home · info |
hold
Only present when
has_holdis declared true.
Begin holding a key down, and keep holding it until release.
The difference between a step and a ramp. Sending volume_up forty times is not the same
thing as holding it: an IR emitter has to keep the carrier up rather than re-send a frame, and
a box on the network wants a press with no release rather than forty presses. Both are the
same intent — somebody has their finger on a button — and this is where that intent goes.
Pairs with keypad's held and released, which exist to bracket exactly this.
what names the command being held rather than there being a hold_volume_up, a
hold_scan_forward and six more — and each key is gated by the capability that provides it, so
a box is only ever offered the keys it has. An Apple TV over IR has arrows and no volume; the
same television over its network link has both; neither has a scan key. All three are the same
contract and none of them advertises a key it would only refuse.
| Parameter | Type | Notes |
|---|---|---|
what | one of volume_up (needs has_up_down_volume) · volume_down (needs has_up_down_volume) · scan_forward (needs has_scan) · scan_reverse (needs has_scan) · up (needs has_dpad) · down (needs has_dpad) · left (needs has_dpad) · right (needs has_dpad) |
launch_app
Only present when
has_appsis declared true.
Open an installed application. The valid names are whatever apps reports for this device.
| Parameter | Type | Notes |
|---|---|---|
app | string | |
content_id | string (optional) | Deep link to a specific title. Ignored by a device that does not declare has_deep_link. |
Opaque, and per service rather than per device — which is what makes it portable. A Disney+
video id is the same id whether it is being opened on a Roku or an Apple TV; what differs is
only how each box spells the request, and spelling it is the driver's job. So the portable
reference to a piece of content is the app name, this id, and content_kind — never a URL,
which is already one vendor's dialect.
|
| content_kind | one of movie · series · season · episode · live · short (optional) | What content_id refers to. Absent means the driver should do whatever it does by default.
Needed because some devices will not deep link without being told: Roku's ECP takes a
mediaType alongside the content id and opens the wrong thing — or nothing — when it is
wrong, and a driver with no way to be told has to guess movie and be wrong for every series.
|
| launch_id | string (optional) | The string this platform uses for app, from the shared app catalog — a Roku channel number, an
Android package, a bundle id, whatever that platform's launch call takes.
Filled in by core, never by a caller: a driver whose manifest declares [driver] app_platform
gets this alongside app, looked up under whichever spelling was asked for. That is what keeps a
table of channel numbers and bundle ids out of every driver, and lets a correction reach houses
without rebuilding one — see https://github.com/junohouse/apps.
Absent means the catalog had no id for this platform, which is ordinary. A device's own list still wins: a box that reported what it has installed knows the truth about itself, where the catalog knows only what a box of this kind can usually run. Use this when the device said nothing — a set whose local API cannot list its apps at all, or an app it did not mention. |
mute_toggle
Only present when
has_muteis declared true.
No parameters.
open_app_launcher
Only present when
has_app_launcheris declared true.
Open the player's top-level application launcher.
This is separate from dpad { key = "home" }: some televisions expose their app launcher as
a dedicated input or command, while others reach it with a Home key. The driver owns that
difference. Core uses this command when the media player is selected as a room source.
No parameters.
pause
No parameters.
play
No parameters.
play_item
Only present when
has_browseis declared true.
Play a content id previously returned by browse or search
| Parameter | Type | Notes |
|---|---|---|
id | string | |
queue_action | one of now · next · append · replace (optional) | What to do with the queue. Absent means now, which is the only thing a player without |
has_queue can do — and why this is optional rather than gated: requires lives on a command, | ||
| not a parameter, so a queueless player ignores it rather than being unable to receive it. | ||
shuffle | bool (optional) | Set shuffle as part of loading, rather than as a second command that races the first. "Shuffle |
| my Discover Weekly" is one intent and every service treats it as one call. | ||
release
Only present when
has_holdis declared true.
Stop holding whatever hold started. Takes no argument: one thing is held at a time, because
one finger is on one button, and a release that had to name its key would be a way to get them
out of step.
A driver is expected to release on its own if the connection drops mid-hold. A stuck ramp is worse than a lost one — it runs the volume to the top of its range with nobody touching it.
No parameters.
scan_forward
Only present when
has_scanis declared true.
No parameters.
scan_reverse
Only present when
has_scanis declared true.
No parameters.
search
Only present when
has_searchis declared true.
| Parameter | Type | Notes |
|---|---|---|
query | string | |
token | string (optional) | Echoed back on the matching search_results |
seek
Only present when
has_seekis declared true.
| Parameter | Type | Notes |
|---|---|---|
position_ms | u32 |
set_crossfade
Only present when
has_crossfadeis declared true.
| Parameter | Type | Notes |
|---|---|---|
crossfade | bool |
set_mute
Only present when
has_muteis declared true.
| Parameter | Type | Notes |
|---|---|---|
mute | bool |
set_repeat
Only present when
has_shuffle_repeatis declared true.
| Parameter | Type | Notes |
|---|---|---|
mode | one of off · one · all |
set_shuffle
Only present when
has_shuffle_repeatis declared true.
| Parameter | Type | Notes |
|---|---|---|
shuffle | bool |
set_volume
Only present when
has_discrete_volumeis declared true.
| Parameter | Type | Notes |
|---|---|---|
level | u32 0–100 |
skip_back
Only present when
has_skipis declared true.
No parameters.
skip_forward
Only present when
has_skipis declared true.
No parameters.
stop
No parameters.
volume_down
Only present when
has_up_down_volumeis declared true.
No parameters.
volume_up
Only present when
has_up_down_volumeis declared true.
No parameters.
Notifications
app_changed
Only present when
has_appsis declared true.
| Parameter | Type | Notes |
|---|---|---|
app | string |
apps_changed
Only present when
has_appsis declared true.
The installed application list, read from the device.
| Parameter | Type | Notes |
|---|---|---|
app_icons | string[] (optional) | One artwork URL per entry in apps, same order, empty string where the device has none. A |
| control surface draws the channel the way its owner recognizes it — by its logo, not its name. |
These are addresses on the device, and they stay there: a client asks the controller for
/artwork?binding=..&i=.. and the controller fetches the picture. That is what makes this
work from a phone that is not on the television's network, and it means a driver only has to
say where its artwork lives, not serve it.
|
| apps | string[] | |
browse_results
Only present when
has_browseis declared true.
One page of what browse was asked for, carrying that call's token.
items is json rather than a described structure because its shape belongs to a music
service and not to us: a Sonos search hit, a Spotify album and a DLNA folder agree on almost
nothing except that each has a name and can be selected. Every consumer draws them as a list
and sends the id back, which is the whole contract. Each entry:
{ "id": "...", "name": "...", "subtitle": "...", "art": "...",
"playable": true, "container": false }
container marks something to browse into — an album, a folder, a service. playable and
container are independent: an album is both.
token is whatever the browse carried, echoed. A driver that was given none sends none, and
core treats the result as the latest for that binding — which is what one person at one screen
actually does.
| Parameter | Type | Notes |
|---|---|---|
items | json | |
offset | u32 (optional) | |
token | string (optional) | |
total | u32 (optional) | Across all pages, when the source knows it |
metadata_changed
Only present when
has_metadatais declared true.
| Parameter | Type | Notes |
|---|---|---|
album | string (optional) | |
art_url | string (optional) | |
artist | string (optional) | |
duration_ms | u32 (optional) | |
title | string (optional) |
mute_changed
Only present when
has_muteis declared true.
| Parameter | Type | Notes |
|---|---|---|
mute | bool |
online_changed
| Parameter | Type | Notes |
|---|---|---|
online | bool |
position_changed
Only present when
has_seekis declared true.
| Parameter | Type | Notes |
|---|---|---|
position_ms | u32 |
search_results
Only present when
has_searchis declared true.
As browse_results, for a search.
| Parameter | Type | Notes |
|---|---|---|
items | json | |
token | string (optional) | |
total | u32 (optional) |
transport_changed
| Parameter | Type | Notes |
|---|---|---|
state | one of playing · paused · stopped · buffering |
volume_changed
Only present when
has_discrete_volumeis declared true.
| Parameter | Type | Notes |
|---|---|---|
level | u32 |
State
Last-known values core keeps for a binding of this proxy.
| Key | Type | Meaning |
|---|---|---|
app | string | Application currently in the foreground |
app_icons | string[] | Artwork for apps, one per entry, same order |
apps | string[] | Installed applications, as read from the device |
artist | string | |
mute | bool | |
online | bool | |
title | string | |
transport | string | |
volume | u32 |