Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Roku Media player does not stream to "Play On Roku" #83819

Closed
pushpinderbal opened this issue Dec 12, 2022 · 38 comments · Fixed by #128133
Closed

Roku Media player does not stream to "Play On Roku" #83819

pushpinderbal opened this issue Dec 12, 2022 · 38 comments · Fixed by #128133
Assignees

Comments

@pushpinderbal
Copy link

pushpinderbal commented Dec 12, 2022

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: dgreuel/RokuKast#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

@home-assistant
Copy link

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 close Closes the issue.
  • @home-assistant rename Awesome new title Change the title of the issue.
  • @home-assistant reopen Reopen the issue.
  • @home-assistant unassign roku Removes 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)

@theTaikun
Copy link

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.

@jurgenhaas
Copy link
Contributor

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.

@terranjp
Copy link

It appears that Roku disabled Play On Roku. Read about if from a Roku employee here

@ctalkington
Copy link
Contributor

thanks for the information. I will have to see if we can pivot to using an already established channel for such.

@jurgenhaas
Copy link
Contributor

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.

@LukeTowers
Copy link

LukeTowers commented Mar 16, 2023

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:

  1. Attempt to utilize an existing channel, potentially via deep linking to play content sent from HA
  2. 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
  3. Potentially reverse engineer existing apps / channels (although that seems to not have had much success so far).
  4. 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?

@ctalkington
Copy link
Contributor

ctalkington commented Mar 17, 2023

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.

@ctalkington
Copy link
Contributor

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

@SmartLikeTruck
Copy link

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.

@LegendaryFire
Copy link

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?

@LukeTowers
Copy link

@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?

@LegendaryFire
Copy link

@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. 😂

@LukeTowers
Copy link

@LegendaryFire nice man, shoot me an email if you're ever in Regina and we can go grab a coffee or lunch or something 😄

@SDeGonge
Copy link

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

@12nick12
Copy link

Any workaround? I would love for this to work.

@ctalkington
Copy link
Contributor

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.

@attain-squiggly-zeppelin

@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!

@attain-squiggly-zeppelin

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?

@ctalkington
Copy link
Contributor

@attain-squiggly-zeppelin nice I'll see about adapting the node code over the upcoming holiday breaks

@attain-squiggly-zeppelin

@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.)

@carefulcomputer
Copy link

carefulcomputer commented Feb 11, 2024

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 ?

@sougoukk
Copy link

sougoukk commented Apr 3, 2024

@attain-squiggly-zeppelin
Please const key = 'F3A278B8-1C6F-44A9-9D89-F1979CA4C6F1';
How to get the key?

@sougoukk
Copy link

sougoukk commented Apr 3, 2024

@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

@justaCasualCoder
Copy link

justaCasualCoder commented Apr 9, 2024

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.

@issue-triage-workflows
Copy link

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.

@LukeTowers
Copy link

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.

@zek
Copy link

zek commented Sep 18, 2024

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

@MedievalApple
Copy link

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

@LukeTowers
Copy link

That's amazing @MedievalApple! Really looking forward to seeing the integration updated to support that channel instead!

@LukeTowers
Copy link

@MedievalApple are you able to submit a PR to switch to using your channel instead so that it's easier for @ctalkington to review and merge it?

@LegendaryFire
Copy link

@MedievalApple Would definitely like to contribute to your project once I get some more free time.

@ctalkington
Copy link
Contributor

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

I will review this and try to figure out the framework for this in the python library now that an option is published

@MedievalApple
Copy link

Thank You, If you have any questions about the app feel free to reach out

@ctalkington
Copy link
Contributor

ctalkington commented Oct 12, 2024

Thank You, If you have any questions about the app feel free to reach out

I'm using the launch with roku store id with deeplink and getting inconsistent behavior on my Roku TV. I'm wondering if it was the media url I used or something with my dev instance. Doing some debugging this weekend.

It seems the app doesn't launch at all and the one time it did, it was the landing page with no media playback

@MedievalApple
Copy link

MedievalApple commented Oct 12, 2024

That sounds like a issue with the formatting of the URL parameters in the deeplink if the Roku receives a URL with incorrectly formatted parameters to the /launch/[Channel Id] endpoint it will refuse to launch the app and if it does launch the app but you get the landing page that says Launch media using a deeplink that usually means the formatting is correct but either the parameters are missing from the deeplink request or the contentid/u parameter is missing or has an invalid url. Would it be possible for you to send a example of the request you were trying to sent to it?

Ive also noticed that the examples in my documentation aren't currently working because the media source they use is from archive.org which is currently down

Here's a python example that should be the minimum request required to launch media on the app if you want to try this to test Media Assistant I confirmed this example works with the store version of the app on my Roku Stick.

import requests

rokuIP = 'InsertRokuIP'
channelID = '782875'

urlParams = {'u': 'https://incompetech.com/music/royalty-free/mp3-royaltyfree/Local%20Forecast%20-%20Elevator.mp3', 't': 'a'}
r = requests.post(f'http://{rokuIP}:8060/launch/{channelID}', params=urlParams, data ={})

@MedievalApple
Copy link

I also tested the pull request: fix playing media via roku #128133 with Media Assistant by trying to play one of the Home Assistant radio browser streams and it seems to play fine.

@ctalkington
Copy link
Contributor

I also tested the pull request: fix playing media via roku #128133 with Media Assistant by trying to play one of the Home Assistant radio browser streams and it seems to play fine.

I think the issue was we didn't always send the t=v which I recently fixed and got it to send several successful. I haven't worked with BrightScript but I don't think your default for t applies because it only sets the deeplink if both u AND t are valid inputs so you can't just send u alone

https://github.com/MedievalApple/Media-Assistant/blob/eeea22e2d0ecb174ad72d21b80b05eec7bfe508f/source/main.brs#L32

@github-actions github-actions bot locked and limited conversation to collaborators Nov 12, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.