core
core copied to clipboard
Roku Media player does not stream to "Play On Roku"
The problem
When trying to stream content to Roku through the media player on HA, the Play on Roku app starts but exits immediately. In a packet capture, I see the correct HTTP request being sent to the Play on Roku app, however this request dies on the Roku side. This issue does not appear to be limited to the Home Assistant integration, as I have tried sending the POST directly from my local computer with the same result. I have tried connecting to Roku on port 8080 and 8085 but couldn't get any debugs logs or traces, which I believe is mostly due to my lack of knowledge about the Roku platform.
Also tried the chrome extension RokuKast which has the same problem even for videos from the internet, and reading the comment on the RokuKast repo it looks like the endpoint might have changed: https://github.com/dgreuel/RokuKast/issues/38
Everything works OK when I use the custom component and the side-loaded app as outlined here, but it's missing some key features that I would like to use: https://github.com/lvcabral/ha-roku-media-player
I realise this might not be a true HA issue but I'm posting it here as this appears to be the most active community related to the topic. Would appreciate any help with this. Thank you!
What version of Home Assistant Core has the issue?
2022.11.4
What was the last working version of Home Assistant Core?
No response
What type of installation are you running?
Home Assistant Container
Integration causing the issue
roku
Link to integration documentation on our website
https://www.home-assistant.io/integrations/roku/
Diagnostics information
config_entry-roku-fe39abfab7f8393cc8cbd8d7209d4768.json.txt
Example YAML snippet
No response
Anything in the logs that might be useful for us?
No response
Additional information
Roku Software Version: 11.5.0 build 4235-88
This is the current format of the POST request in the packet capture and looks correct to me: http://10.76.103.17:8060/input/15985?t=v&u=https%3A%2F%2Fhomeassistant.local.s1ngh.ca%2Fmedia%2Flocal%2FBigBuckBunny.mp4%3FauthSig%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI5NWFkZmYzMjM3YWM0YjllODY5ZTJiNDc4NzIxMWZiOCIsInBhdGgiOiIvbWVkaWEvbG9jYWwvQmlnQnVja0J1bm55Lm1wNCIsInBhcmFtcyI6e30sImlhdCI6MTY3MDgzMzA2MiwiZXhwIjoxNjcwOTE5NDYyfQ.s2dDURHQMm3kTwbKCJaTPlnCbrS4IOeBsUm7sva31xg&videoName=media-source%3A%2F%2Fmedia_source%2Flocal%2FBigBuckBunny.mp4&videoFormat=mp4
Hey there @ctalkington, mind taking a look at this issue as it has been labeled with an integration (roku) you are listed as a code owner for? Thanks!
Code owner commands
Code owners of roku can trigger bot actions by commenting:
@home-assistant closeCloses the issue.@home-assistant rename Awesome new titleChange the title of the issue.@home-assistant reopenReopen the issue.@home-assistant unassign rokuRemoves the current integration label and assignees on the issue, add the integration domain after the command.
(message by CodeOwnersMention)
roku documentation roku source (message by IssueLinks)
Found this issue because the "Play on Roku" app described in the documentation isn't even listed in the app store anymore. Looks like Roku delisted apps that were using an older version of their SDK. There are a ton of other media player and cast apps, including "PlayOn Cloud Cast", but not sure if any are compatible with the current HA integration.
Having the exact same problem. When starting to play the same URL through the Roku app on Android, the media player in HA recognizes that stream and allows me further control like pause, resume, volume control, etc. But starting a stream from the media player in HA shows the described issue.
It appears that Roku disabled Play On Roku. Read about if from a Roku employee here
thanks for the information. I will have to see if we can pivot to using an already established channel for such.
In that linked thread two comments above there is a comment about Tubio which is a combination of a Roku app and an Android app. I tried that, it works really nice and lets me stream any video or audio to the Roku device. Of course, I don't want to promote that solution, I'd rather hope to get something similar in HA/MA. That would be the ultimate solution to me.
As mentioned in https://community.roku.com/t5/Solving-playback-issues/OS-11-5-Roku-11-5-broke-Play-on-Roku-video-playback/m-p/827826/highlight/true#M44919, Roku decided to lock down access to the Play on Roku channel / ECP endpoint as of version 11.5 (released Fall 2022).
This was used by the HA integration to play Audio, Video, & URL sources (see https://github.com/home-assistant/core/blob/dev/homeassistant/components/roku/media_player.py#L454), specifically through the python-rokuecp wrapper library (see https://github.com/ctalkington/python-rokuecp/blob/0adea4c21a90a8deded3c12264b13460faeb412e/src/rokuecp/rokuecp.py#L266-L285).
Some comments on the Roku forum thread mention that casting on various apps (Web Video Caster, Tubio) works when using the newer "Roku Channel protocol", but as far as I can tell there's nothing about the "The Roku Channel" Roku channel, as included on Roku devices, that handles casting and that terminology instead must refer to the relevant third party app's dedicated Roku channels (Web Video Caster & Tubio).
From looking at the Roku Developer docs on the available ECP commands I'm not seeing any commands that would allow for casting media to Roku devices, which as far as I can tell leaves the HA integration with the following options:
- Attempt to utilize an existing channel, potentially via deep linking to play content sent from HA
- Create and publish a "Home Assistant" Roku channel and require device owners to install said channel on their devices to handle any requests sent from HA
- Potentially reverse engineer existing apps / channels (although that seems to not have had much success so far).
- Potentially use / abuse the DIAL protocol support present in Roku to accomplish the same desired end results, see Roku's example for their specific DIAL documentation & http://www.dial-multiscreen.org/dial-protocol-specification for more general information about the DIAL protocol.
@ctalkington do you have any thoughts on the above or ideas for alternative integrations that I could utilize that would allow me to accomplish the same desired end result of sending media content from HA to my Roku TV?
so the issue with HA or community registered app is the process to get such approved by Roku. They are unlikely to allow something that's only purpose is to bypass a security change they made so the app would need to provide some other functionality and implement deep linking of media as a feature.
I had started a discussion about such a community venture of getting https://github.com/lvcabral/ha-roku-cast-app as an official app but it would take a large effort so sideloading and supporting custom app id for deep linking in HA integration would likely be easier to achieve. but this was during the holidays and my personal availability has been low since. I'll try to get to the rokuecp and HA updates in the next few weeks.
DIAL would just launch the roku app with params, doesn't do anything ECP can't in that regard. It's a semi-abandoned protocol with Google cast specs these days.
I really have liked rokus and own one in every room and even do this HA development but they are pivoting their model and are less friendly to integrate with compared to a few years back. I really wonder how long ECP will last before it's security concern
I'm completely new to HA and today I personally wasted many hours trying to pass a video stream to my Roku from HA before I stumbled across the posting in the Roku forums about the "Play On Roku" being depreciated.
What needs to happen to fix the HA documentation to note the broken features that occurred back in November of 2022?
Is sideloading Roku Home Assistant Cast App https://github.com/lvcabral/ha-roku-cast-app a viable workaround? At first glance it appears to depend on the now broken method for passing media to roku.
Do we have a solution to casting on Roku's yet? Apparently there is a way via. casting through the Roku Channel app. I wonder if we can integrate that into HA?
@LegendaryFire
Some comments on the Roku forum thread mention that casting on various apps (Web Video Caster, Tubio) works when using the newer "Roku Channel protocol", but as far as I can tell there's nothing about the "The Roku Channel" Roku channel, as included on Roku devices, that handles casting and that terminology instead must refer to the relevant third party app's dedicated Roku channels (Web Video Caster & Tubio).
Do you have more specific information than that?
@LukeTowers I haven't had a chance to look into it further, but am hoping to over the weekend here.
P.S. I just realized we're in the same province. 😂
@LegendaryFire nice man, shoot me an email if you're ever in Regina and we can go grab a coffee or lunch or something 😄
I just spent a few hours trying to stream my camera to Roku with this integration. I thought I was doing something wrong until I read these notes about Roku locking down this feature. Is there a workarounf for this? If not, can you remove that feature from the integration or place a note in the in the integration to let users know that streaming may not work? Thanks
Any workaround? I would love for this to work.
I still need to review how Roku blocked this functionality and see if I can workaround their changes. I really want to avoid having to maintain a Channel or rely on some 3rd party Channel which I haven't found documentation openly available for.
@ctalkington
I did a capture of the android app talking to my Roku Ultra.
It uses a protocol it says ecp-2. It seems similar to regular ecp but over web sockets.
However, upon connecting the roku device sends a challenge with a nonce, and the app responds with a sha1 of the concatenation of the nonce and a hard coded uuid.
The hard coded uuid is F3A278B8-1C6F-44A9-9D89-F1979CA4C6F1.
Example exchange:
GET http://192.168.1.176:8060/ecp-session HTTP/1.1
Sec-WebSocket-Origin: Android
Sec-WebSocket-Protocol: ecp-2
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: jU9KP0hjtBw7zbNQUH+SFw==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: permessage-deflate
Host: 192.168.1.176:8060
Accept-Encoding: gzip
User-Agent: okhttp/4.9.0-roku1
2023-11-11 18:45:13.491
{
"notify": "authenticate",
"param-challenge": "x4F6nRyCvRjhe1a+L2QZBw==",
"timestamp": "233317.714"
}
2023-11-11 18:45:13.537
{
"param-response": "XzpAJnctaMSVBr1DjvWWLUU2Vaw=",
"request": "authenticate",
"request-id": "0"
}
2023-11-11 18:45:13.561
{
"response": "authenticate",
"response-id": "0",
"status": "200",
"status-msg": "OK"
}
Turning on my tv via roku:
{"request":"key-press","request-id":"6","param-key":"Power"}
{"response":"key-press","response-id":"6","status":"200","status-msg":"OK"}
Streaming a video from my phone:
{"request":"input","request-id":"8","param-params":"{\"a\":\"sta\",\"t\":\"v\",\"u\":\"http:\\\/\\\/192.168.1.160:5150\\\/VIDEO%2Fm_0.m3u8\",\"framerate\":\"30\",\"h\":\"192.168.1.160:5150\",\"videoname\":\"20231104_111237\",\"k\":\"http:\\\/\\\/192.168.1.160:5150\\\/%2FVIDEO_THUMB%2F17870\",\"videoformat\":\"hls\",\"videoresolution\":\"1080\"}","param-channel-id":"15985"}
Proof of concept nodejs code: (Sorry, it would have taken me longer to write it in Python. It should be simple enough to convert to Python for someone who uses it every day.)
index.mjs:
import WebSocket from 'ws';
import crypto from 'crypto';
const key = 'F3A278B8-1C6F-44A9-9D89-F1979CA4C6F1';
const host = process.argv[2];
console.log('connecting to ', host);
const ws = new WebSocket(`ws://${host}:8060/ecp-session`, 'ecp-2');
ws.on('error', console.error);
ws.on('open', function open() {
console.log('opened!');
});
ws.on('close', function () {
console.log('closed!');
});
const dummy_video = {"a":"sta","t":"v","u":"http://192.168.1.160:5150/VIDEO%2Fm_0.m3u8","framerate":"30","h":"192.168.1.160:5150","videoname":"20231104_111237","k":"http://192.168.1.160:5150/%2FVIDEO_THUMB%2F17870","videoformat":"hls","videoresolution":"1080"};
let request_counter = 0;
ws.on('message', function message(data) {
console.log('received: %s', data);
const msg = JSON.parse(data);
if (msg.notify === 'authenticate') {
const hasher = crypto.createHash('sha1');
hasher.update(msg['param-challenge'] + key);
const response = {
"param-response": hasher.digest('base64'),
"request": "authenticate",
'request-id': (request_counter++).toString()
};
console.log(JSON.stringify(response));
ws.send(JSON.stringify(response));
}
if (msg.response === 'authenticate') {
if (msg.status !== '200') throw new Error('failed to authenticate!');
ws.send(JSON.stringify({
"request": "input",
"request-id": (request_counter++).toString(),
"param-params": JSON.stringify(dummy_video),
"param-channel-id":"15985"
}));
}
});
The package.json:
{
"name": "roku-play-stream",
"version": "1.0.0",
"main": "index.mjs",
"license": "MIT",
"dependencies": {
"ws": "^8.14.2"
}
}
Usage: yarn install node ./index.mjs 192.168.1.100 assuming your Roku is on that one dot one hundred address.
Hope this helps!
BTW, I was surprised I couldn't find any references to ecp-2 on google. Am I the first person to packet capture this? Surely not.
Even stranger, searching for the hard coded uuid, I do find exactly one hit. Looks like someone else implementing the same algorithm, but for Arduino?
@attain-squiggly-zeppelin nice I'll see about adapting the node code over the upcoming holiday breaks
@ctalkington any update on this? I don't have time right now, but maybe in a couple of weeks I can give it a try, if you won't be able to get to it any time soon. (And if you'll at least have time to review PRs.)
would love to get this working too. I want to stream my reolink doorbell to my TV when someone rings it. @attain-squiggly-zeppelin , i tried your code and sent a mp4 link from my go2rtc server, it started and launched the roku media player, but exit immediately. any suggestions ?
@attain-squiggly-zeppelin Please const key = 'F3A278B8-1C6F-44A9-9D89-F1979CA4C6F1'; How to get the key?
@attain-squiggly-zeppelin I just decompiled roku's official android code and found that the uuid is indeed generated through the following hexadecimal array "39", "35", "45", "36", "31", "30", "44", "30", "2D", "37", "43", "32", "39", "2D", "34", "34", "45", "46", "2D", "46", "42", "30", "46", "2D", "39", "37", "46", "31", "46", "43", "45", "34", "43", "32", "39", "37" The final result is F3A278B8-1C6F-44A9-9D89-F1979CA4C6F1
So bad news about this. It looks like Play On Roku has been completely removed. There is no "Share Media" tab in the Roku app anymore... I did convert the NodeJS code to Python and authenticated successfully, but Play On Roku just closed instantly.
There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates. Please make sure to update to the latest Home Assistant version and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.
Issue still exists Mr. Bot, question is if @ctalkington has the bandwidth to take a look 😂 if not then it can probably be closed until someone with bandwidth and interest can get to it.
Is there any update? They might keep changing the uuid in the future. I believe sideloaded app would be a better solution. https://github.com/lvcabral/ha-roku-cast-app
Hi @ctalkington , I have created a Roku Channel that acts as a drop-in replacement for "Play On Roku" It uses the same deeplink protocol as well as expands on the original functionality of "Play On Roku" and supports additional formats like FLAC, AAC. MKV and more. I call it Media Assistant Its fully open source and I have document the API. I was also able to get it published to the Roku Channel Store in all regions so it would not need to be side-loaded. I have also tested it with the Roku Home Assistant integration and it can be dropped in right in place of "Play on Roku's" Channel Id though in order to get the additional media formats to work they would have to be added into your python-rokuecp project. Would it be possible to get it added to the Home assistant integration since it seems that "Play On Roku" is no long useable. I'm also willing to make any changes to the app in order to make it work better with Home Assistant. I have attached links below to the Media Assistant Github page as well as its Roku Channel Store listing.
https://github.com/MedievalApple/Media-Assistant https://channelstore.roku.com/details/625f8ef7740dff93df7d85fc510303b4/media-assistant
That's amazing @MedievalApple! Really looking forward to seeing the integration updated to support that channel instead!