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

Chromecast bug - Trouble w/ license requests on certain hardware #576

Closed
wipawan-zz opened this issue Nov 7, 2016 · 14 comments
Closed

Chromecast bug - Trouble w/ license requests on certain hardware #576

wipawan-zz opened this issue Nov 7, 2016 · 14 comments
Assignees
Labels
status: archived Archived and locked; will not be updated status: unable to reproduce Issue could not be reproduced by the team type: bug Something isn't working correctly type: external An issue with an external dependency; not our issue; sometimes kept open for tracking

Comments

@wipawan-zz
Copy link

wipawan-zz commented Nov 7, 2016

  • What version of Shaka Player are you using?
    Shaka-player version 2.0.1

    • Can you reproduce the issue with our latest release version?
      Yes
    • Can you reproduce the issue with the latest code from master?
      Yes
  • Are you using the demo app or your own custom app?
    I'm using my own custom app.

    • If custom app, can you reproduce the issue using our demo app?
      No. The issue seems to be related to the license request. My custom application attaches Widevine Challenge parameter to the license request using registerRequestFilter() method (license wrapping). All the assets in the demo application seem to make a simple license request.
  • What did you do?
    The following are the steps/observations to reproduce the issue

  1. Hit cast button from sender application
  2. Select video content to play on chromecast
  3. After the video is loaded, it continues to play on chromecast
  4. Stop casting
  5. Start casting again
  6. Select the same video and play
  7. The receiver application is stalled

The key observation is that this issue only occurs on Chromecast 1 (released in 2013). The receiver application works perfectly with Chromecast 2 (released in 2015). Also, I did not experience the same issue with Cast API Media Player. The issue happens after the latest 1.21.74816 firmware update.

I'd like to ask if the issue could be solved by changing network and buffering configuration. Please find attached logs for three casting attempts.
chromecast_2 - casting on Chromecast generation 2
chromecast_1_1st - first casting on Chromecast generation 1
chromecast_1_2nd - second casting on Chromecast generation 1
logs.zip

Edit: I've captured timeline recordings for both devices. Chromecast 1 fails after the second LOAD event from sender. Chromecast 2 is able to support multiple LOAD events.
Chromecast 1
chromecast_1

Chromecast 2
chromecast_2

@wipawan-zz
Copy link
Author

Hello, is there any comment on this issue? Your feedback will be much appreciated. Thank you!

@joeyparrish
Copy link
Member

I'm sorry, we haven't had a chance to triage this issue yet. Thank you for the report, and we will look at this as soon as our team can find the time.

@joeyparrish joeyparrish self-assigned this Nov 15, 2016
@joeyparrish joeyparrish added the status: unable to reproduce Issue could not be reproduced by the team label Nov 15, 2016
@joeyparrish
Copy link
Member

I'm unable to reproduce using our demo app, our content, and a v1 Chromecast from 2013.

Here is what I did:

  1. Load the demo app.
  2. Click the cast button in the video controls in the sender.
  3. Select the first-generation Chromecast from the list of receiver devices.
  4. Select "Sintel 4k (multicodec, widevine)" from the asset list.
  5. Click the "Load" button.
  6. Let the video play for 15 seconds on the Chromecast.
  7. Click the cast button in the video controls.
  8. Click "stop" in the cast dialog to terminate the receiver app.
  9. Let the video play for 15 more seconds in the browser.
  10. Click the cast button again.
  11. Select the first-generation Chromecast from the list of receiver devices.
  12. Let the video continue playing on the Chromecast.

The video never stalled.

@joeyparrish
Copy link
Member

I believe this is a problem with your custom app, and I believe the Chromecast device versions are a red herring.

Since you are registering request filters, I believe the problem may be with how you do that on the sender vs receiver. Without seeing your application's code, I have to guess. But my guess is that you are not setting up the filters on the receiver, only on the sender.

When you use player.getNetworkingEngine() on the sender side, you should see a log warning you "NOTE: getNetworkingEngine() is always local!". (If you don't see this, you should be doing your integration work with an uncompiled version of Shaka Player to get logs. You can switch back to the compiled version for production deployment.)

In order to set up filters on the receiver, you must use the appDataCallback parameter of shaka.cast.CastReceiver. In that callback, your receiver app can set up any necessary filters using the "app data" sent by the sender app. The sender uses castProxy.setAppData() before casting to communicate this information to the receiver.

Does this help?

@joeyparrish joeyparrish changed the title Unable to load subsequent Widevine videos on Chromecast 1 Trouble w/ Chromecast and license request filters Nov 15, 2016
@wipawan-zz
Copy link
Author

Thanks @joeyparrish for your response.

The Chromecast device versions are my observation since it seems consistent that the issue only occurs on Chromecast 1. We've tried on a couple of units and all produced the same result.

The shaka-player resides on the receiver code. I'm just getting event messages from the sender and registering request filters is done on the receiver application. I can send you my application code through your email if you wish to see it.

I've tried switching back to cast sdk media player library and it seems to be able to cast the next videos.

@joeyparrish
Copy link
Member

We tried to make casting as easy as possible, but we may have fallen short of that goal for setups like yours.

If you send me your application code, I'll do what I can to help you debug it. I can't reproduce on the demo app, so I think seeing the application code is the only option. Thanks!

@wipawan-zz
Copy link
Author

@joeyparrish Sure! Would you be able to provide your email address?

@joeyparrish
Copy link
Member

It's in the AUTHORS file in the Shaka Player sources.

@joeyparrish
Copy link
Member

Sorry, not AUTHORS, I meant CONTRIBUTORS.

@wipawan-zz
Copy link
Author

@joeyparrish Alright, thanks. I've just sent it to you :)

@joeyparrish
Copy link
Member

Sorry for the delay. Your app code got lost in my spam filter.

I've taken a look at your code and now I understand your setup. Shaka is only being used on the receiver side, and you aren't using any of our cast APIs on either end.

I spotted one unrelated bug in your code:

    player.getConfiguration().abr.enabled = true;

The config returned from that is a copy, so modifying it has no effect. Instead, do this:

    player.configure({abr: {enabled: true}});

This pattern appears twice in your code.

It's hard to say if your request filter is correct since I only have the client code, but this looks suspicious to me:

    player.getNetworkingEngine().registerRequestFilter((type, request) => {
      if (type == shaka.net.NetworkingEngine.RequestType.LICENSE) {
        let rawLicenseRequest = new Uint8Array(request.body);
        let rawLicenseRequestBase64 = encodeURIComponent(
            arrayTob64String(rawLicenseRequest));
        request.uris[0] += rawLicenseRequestBase64;
      }
    });

Although you modify the URI to attach a base64-encoded version of the request body, you leave that body in place. So the same raw license request is being sent to your server in two forms. To remove it from the body, try this after you modify the URI:

        request.body = new Uint8Array();

Other than that, I don't see anything obviously wrong with your app code. I still can't reproduce anything like this with our demo app even on v1 Chromecast hardware.

You've filed this bug against Chromecast, and they have merged it into this bug. The latter does not involve Shaka at all, so I believe this is a Chromecast issue that is outside of Shaka Player. Because of that, I'm going to mark this as an external bug. I'll leave it open for now while we track progress on the Chromecast side.

@joeyparrish joeyparrish added type: bug Something isn't working correctly type: external An issue with an external dependency; not our issue; sometimes kept open for tracking labels Nov 22, 2016
@joeyparrish joeyparrish changed the title Trouble w/ Chromecast and license request filters Chromecast bug - Trouble w/ license requests on certain hardware Nov 22, 2016
@lgan1989
Copy link

lgan1989 commented Nov 25, 2016

hi @joeyparrish ,

I have noted a pattern in the cases when we are able to reproduce the bug, that is during the loading period of first video, it's always creating an extra temporary sessions (right after the initial one), it results in sending out extra license request.

When I look at the code in drm_engine.js, the following code seems to be used for avoid duplicated session:

    if (Uint8ArrayUtils.equal(initData, this.activeSessions_[i].initData)) {
      shaka.log.debug('Ignoring duplicate init data.');
      return;
    }

however, when I added a break point and inspect the data, I found that initData and this.activeSessions_[i].initData are most likely the same, but with a small portion of different value, so the Equal function here will consider they are different and it will allow it to create another session.

I'm actually not sure if this is expected or not, but this seems to be the one that brings the hanging/buffering issue on Chromecast V1 (in V2, although it also creating two sessions at the beginning, no hang/buffering issue is seen), since After I update the code to use another function to check their equality, something like:

shaka.util.Uint8ArrayUtils.mostLikelyeEqual = function(arr1, arr2) {
  if (!arr1 && !arr2) return true;
  if (!arr1 || !arr2) return false;
  if (arr1.length != arr2.length) return false;
  let c = 0;
  let threshold = 30;
  for (var i = 0; i < arr1.length; ++i) {
    if (arr1[i] != arr2[i]) c ++;
  }
  return c <= threshold;
};

The issue on chromecast v1 is gone.

It now seems to be some hardware/firmware related issue, would like to hear some thoughts from you.

@joeyparrish
Copy link
Member

That's very strange.

See #580 for a discussion of how this filtering works and why. In short, if the init datas differ even a little bit, we can't be certain that one session will receive all the keys we need. We could create one session, get a license, then wait and see which keys we got, but that would lead to increased latency, so we don't take that approach.

We accept that some number of duplicate sessions will be created because:

  1. we don't have perfect information from the manifest to know how many licenses we need, and
  2. CDMs generally handle duplicate sessions gracefully.

Unless something else is going on that we can't see, it would seem that the CDM on the v1 Chromecast is not gracefully handling duplicate sessions in some way. This would still be an external bug, though, that needs to be reported to the Chromecast team.

Please update the Chromecast bug with this new information so that the Chromecast team can start looking in the right direction.

@joeyparrish
Copy link
Member

@wipawan, it seems that much discussion has taken place on the Chromecast bug tracker, with some bugs merged into others. Since I am having trouble tracking those conversations, I will have a hard time keeping this bug open to track those. I will close this now, but please let us know if we can do anything else to assist you while you work with the Chromecast team. Thanks!

@shaka-project shaka-project locked and limited conversation to collaborators Mar 22, 2018
@shaka-bot shaka-bot added the status: archived Archived and locked; will not be updated label Apr 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
status: archived Archived and locked; will not be updated status: unable to reproduce Issue could not be reproduced by the team type: bug Something isn't working correctly type: external An issue with an external dependency; not our issue; sometimes kept open for tracking
Projects
None yet
Development

No branches or pull requests

4 participants