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

'trackschanged' event not fired after a license request is denied for an HD track #4874

Closed
loicraux opened this issue Jan 9, 2023 · 6 comments · Fixed by #5962
Closed

'trackschanged' event not fired after a license request is denied for an HD track #4874

loicraux opened this issue Jan 9, 2023 · 6 comments · Fixed by #5962
Labels
priority: P2 Smaller impact or easy workaround status: archived Archived and locked; will not be updated type: bug Something isn't working correctly
Milestone

Comments

@loicraux
Copy link
Contributor

loicraux commented Jan 9, 2023

Have you read the FAQ and checked for duplicate open issues?
Yes

What version of Shaka Player are you using?
4.3.1

Can you reproduce the issue with our latest release version?
Yes

Can you reproduce the issue with the latest code from main?
Yes

Are you using the demo app or your own custom app?
Both

If custom app, can you reproduce the issue using our demo app?
Yes

What browser and OS are you using?
Chrome or Firefox on Linux Ubuntu

For embedded devices (smart TVs, etc.), what model and firmware version are you using?
N/A

What are the manifest and license server URIs?

https://shaka-player-demo.appspot.com/demo/#audiolang=fr;textlang=fr;uilang=fr;asset=https://dpk3dq0d69joz.cloudfront.net/origin/HLS_140672_0-VO-cenc.ism/stream.mpd;license=https://widevine-dash.ezdrm.com/proxy?pX=BA5EDC&contentId=HLS_140672_0-VO&[email protected];panel=CUSTOM%20CONTENT;build=uncompiled

What configuration are you using? What is the output of player.getConfiguration()?

Result of running the following code in the demo app :

const video = document.getElementById('video');
const ui = video['ui'];
copy(JSON.stringify(ui.player_.getConfiguration(), null, 2))
{
  "drm": {
    "retryParameters": {
      "maxAttempts": 2,
      "baseDelay": 1000,
      "backoffFactor": 2,
      "fuzzFactor": 0.5,
      "timeout": 30000,
      "stallTimeout": 5000,
      "connectionTimeout": 10000
    },
    "servers": {
      "com.widevine.alpha": "https://widevine-dash.ezdrm.com/proxy?pX=BA5EDC&contentId=HLS_140672_0-VO&[email protected]",
      "com.microsoft.playready": "https://widevine-dash.ezdrm.com/proxy?pX=BA5EDC&contentId=HLS_140672_0-VO&[email protected]",
      "com.apple.fps": "https://widevine-dash.ezdrm.com/proxy?pX=BA5EDC&contentId=HLS_140672_0-VO&[email protected]",
      "com.adobe.primetime": "https://widevine-dash.ezdrm.com/proxy?pX=BA5EDC&contentId=HLS_140672_0-VO&[email protected]",
      "org.w3.clearkey": "https://widevine-dash.ezdrm.com/proxy?pX=BA5EDC&contentId=HLS_140672_0-VO&[email protected]"
    },
    "clearKeys": {},
    "advanced": {
      "com.widevine.alpha": {
        "distinctiveIdentifierRequired": false,
        "persistentStateRequired": false,
        "videoRobustness": "",
        "audioRobustness": "",
        "sessionType": "",
        "serverCertificate": {},
        "serverCertificateUri": "",
        "individualizationServer": ""
      },
      "com.microsoft.playready": {
        "distinctiveIdentifierRequired": false,
        "persistentStateRequired": false,
        "videoRobustness": "",
        "audioRobustness": "",
        "sessionType": "",
        "serverCertificate": {},
        "serverCertificateUri": "",
        "individualizationServer": ""
      },
      "com.apple.fps": {
        "distinctiveIdentifierRequired": false,
        "persistentStateRequired": false,
        "videoRobustness": "",
        "audioRobustness": "",
        "sessionType": "",
        "serverCertificate": {},
        "serverCertificateUri": "",
        "individualizationServer": ""
      },
      "com.adobe.primetime": {
        "distinctiveIdentifierRequired": false,
        "persistentStateRequired": false,
        "videoRobustness": "",
        "audioRobustness": "",
        "sessionType": "",
        "serverCertificate": {},
        "serverCertificateUri": "",
        "individualizationServer": ""
      },
      "org.w3.clearkey": {
        "distinctiveIdentifierRequired": false,
        "persistentStateRequired": false,
        "videoRobustness": "",
        "audioRobustness": "",
        "sessionType": "",
        "serverCertificate": {},
        "serverCertificateUri": "",
        "individualizationServer": ""
      }
    },
    "delayLicenseRequestUntilPlayed": false,
    "logLicenseExchange": false,
    "updateExpirationTime": 1,
    "preferredKeySystems": [],
    "keySystemsMapping": {},
    "parseInbandPsshEnabled": false
  },
  "manifest": {
    "retryParameters": {
      "maxAttempts": 2,
      "baseDelay": 1000,
      "backoffFactor": 2,
      "fuzzFactor": 0.5,
      "timeout": 30000,
      "stallTimeout": 5000,
      "connectionTimeout": 10000
    },
    "availabilityWindowOverride": null,
    "disableAudio": false,
    "disableVideo": false,
    "disableText": false,
    "disableThumbnails": false,
    "defaultPresentationDelay": 0,
    "segmentRelativeVttTiming": false,
    "dash": {
      "clockSyncUri": "https://shaka-player-demo.appspot.com/time.txt",
      "ignoreDrmInfo": false,
      "disableXlinkProcessing": false,
      "xlinkFailGracefully": false,
      "ignoreMinBufferTime": false,
      "autoCorrectDrift": true,
      "initialSegmentLimit": 1000,
      "ignoreSuggestedPresentationDelay": false,
      "ignoreEmptyAdaptationSet": false,
      "ignoreMaxSegmentDuration": false,
      "keySystemsByURI": {
        "urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b": "org.w3.clearkey",
        "urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e": "org.w3.clearkey",
        "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed": "com.widevine.alpha",
        "urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95": "com.microsoft.playready",
        "urn:uuid:79f0049a-4098-8642-ab92-e65be0885f95": "com.microsoft.playready",
        "urn:uuid:f239e769-efa3-4850-9c16-a903c6932efb": "com.adobe.primetime"
      },
      "sequenceMode": false
    },
    "hls": {
      "ignoreTextStreamFailures": false,
      "ignoreImageStreamFailures": false,
      "defaultAudioCodec": "mp4a.40.2",
      "defaultVideoCodec": "avc1.42E01E",
      "ignoreManifestProgramDateTime": false,
      "mediaPlaylistFullMimeType": "video/mp2t; codecs=\"avc1.42E01E, mp4a.40.2\"",
      "useSafariBehaviorForLive": true,
      "liveSegmentsDelay": 3
    }
  },
  "streaming": {
    "retryParameters": {
      "maxAttempts": 2,
      "baseDelay": 1000,
      "backoffFactor": 2,
      "fuzzFactor": 0.5,
      "timeout": 30000,
      "stallTimeout": 5000,
      "connectionTimeout": 10000
    },
    "rebufferingGoal": 2,
    "bufferingGoal": 10,
    "bufferBehind": 30,
    "ignoreTextStreamFailures": false,
    "alwaysStreamText": false,
    "startAtSegmentBoundary": false,
    "gapDetectionThreshold": 0.5,
    "durationBackoff": 1,
    "forceTransmux": false,
    "safeSeekOffset": 5,
    "stallEnabled": true,
    "stallThreshold": 1,
    "stallSkip": 0.1,
    "useNativeHlsOnSafari": true,
    "inaccurateManifestTolerance": 2,
    "lowLatencyMode": false,
    "autoLowLatencyMode": false,
    "forceHTTPS": false,
    "preferNativeHls": false,
    "updateIntervalSeconds": 1,
    "dispatchAllEmsgBoxes": false,
    "observeQualityChanges": false,
    "maxDisabledTime": 30,
    "parsePrftBox": false
  },
  "mediaSource": {
    "sourceBufferExtraFeatures": ""
  },
  "offline": {
    "usePersistentLicense": true,
    "numberOfParallelDownloads": 5
  },
  "abr": {
    "enabled": true,
    "useNetworkInformation": true,
    "defaultBandwidthEstimate": 1000000,
    "switchInterval": 8,
    "bandwidthUpgradeTarget": 0.85,
    "bandwidthDowngradeTarget": 0.95,
    "restrictions": {
      "minWidth": 0,
      "maxWidth": null,
      "minHeight": 0,
      "maxHeight": null,
      "minPixels": 0,
      "maxPixels": null,
      "minFrameRate": 0,
      "maxFrameRate": null,
      "minBandwidth": 0,
      "maxBandwidth": null
    },
    "advanced": {
      "minTotalBytes": 128000,
      "minBytes": 16000,
      "fastHalfLife": 2,
      "slowHalfLife": 5
    },
    "restrictToElementSize": false,
    "restrictToScreenSize": false,
    "ignoreDevicePixelRatio": false
  },
  "autoShowText": 3,
  "preferredAudioLanguage": "fr",
  "preferredTextLanguage": "fr",
  "preferredVariantRole": "",
  "preferredTextRole": "",
  "preferredAudioChannelCount": 2,
  "preferredVideoCodecs": [],
  "preferredAudioCodecs": [],
  "preferForcedSubs": false,
  "preferredDecodingAttributes": [],
  "restrictions": {
    "minWidth": 0,
    "maxWidth": null,
    "minHeight": 0,
    "maxHeight": null,
    "minPixels": 0,
    "maxPixels": null,
    "minFrameRate": 0,
    "maxFrameRate": null,
    "minBandwidth": 0,
    "maxBandwidth": null
  },
  "playRangeStart": 0,
  "playRangeEnd": null,
  "cmcd": {
    "enabled": false,
    "sessionId": "",
    "contentId": "",
    "useHeaders": false
  },
  "lcevc": {
    "enabled": false,
    "dynamicPerformanceScaling": true,
    "logLevel": 0,
    "drawLogo": false
  }
}

What did you do?

Hello !

I am currently experiencing problems with shaka-player version 4.3.1.

Our DRM provider is EZDRM and one of our programs is streamed using MPEG-DASH with the following tracks and keys:

MPD manifest -----> Key #1 ------> Audio #1
               |             +---> Audio #2
               |             +---> Audio #3
               |
               +--> Key #2 ------> Variant track 240p
               |             +---> Variant track 360p
               |             +---> Variant track 480p
               |
               +--> Key #3 ------> Variant track 720p (HD)

Shaka player is configured to use ABR, loads the manifest and makes 3 license requests for the 3 keys. The first 2 requests are granted but the third one is denied. This is normal, since this is what we want: to deny the playback of the 720p stream in the browser.

EZDRM (ou DRM provider) returns an empty response (0 bytes) for the 3rd license request (I don't know if this is normal, but we always got an empty response in this case from EZDRM, it reminds me of this ticket comment), which triggers an error 6008 (Failed to execute 'update' on 'MediaKeySession': The response parameter is empty) on the client side (shaka player). I don't know if it's normal to get this 6008 error, but we always got it in this case.

The problem is that you can't play the movie (or play it only for a few seconds, until ABR figures out that the network is good and it can switch to 720p).

What did you expect to happen?

The movie should be playable with ABR, and 720p track not available.

What actually happened?

While debugging further, I found out that :

  • currently as soon as the ABR asks for the 720p video track, the playback actually fails.
  • previously we received 2 "trackschanged" events, the first one listing 12 variant tracks (4 videos * 3 audios), then a second "trackschanged" event listing only 9 variant tracks (3 videos * 3 audios), the 720p video track being "removed". But on the latest versions of shaka player, only the first event is issued, as if the 720p track was not "removed"?

By analyzing our code with git bisect, I found that it was the update of shaka player from version 2.3.0 to version 3.2.9 that introduced the problem on our side, then by dichotomizing the versions of shaka player between 2.3.0 and 3.2.9, I found that it was version 2.4.4 that introduced the problem.

I'm having trouble seeing in the contents of 2.4.4 what could cause this...

So my questions are:

  • Is it normal that the 720p track is not automatically removed after a 6008 error when requesting a license?
  • What could cause this change of behavior in the release v2.4.4?
  • Is an empty response (0 bytes) on the 3rd license request acceptable from the client (shaka player) point of view?
  • and eventually, more generally, is it normal to have a 6008 error or should it never happen?

Thanks in advance for your answers and help! (and for the great work with shaka player ;)

@loicraux loicraux added the type: bug Something isn't working correctly label Jan 9, 2023
@github-actions github-actions bot added this to the v4.4 milestone Jan 9, 2023
@loicraux
Copy link
Contributor Author

I've dug a bit deeper and found out that the commit that introduces the change of behavior (only one 'trackschanged' event fired instead of two) is this one : c046081

@loicraux
Copy link
Contributor Author

Also I've asked EZDRM support whether or not this blank response was OK from their side, and here is their answer :

Hello
That is not an issue
That is a normal response.
If you do not allow a license a blank 200 is sent to end the request

Is there anything I could do in a responseFilter so that the session.update() will succeed (with denial of the license) ?

@martinstark
Copy link
Contributor

Is there anything I could do in a responseFilter so that the session.update() will succeed (with denial of the license) ?

There might be better solutions, but in the meantime:

  1. There are properties on the variant tracks called allowedByApplication and allowedByKeySystem that could maybe be used to disable a track for the duration of the playback session. The empty DRM response should presumably set the allowedByKeySystem property to false, maybe that is what has stopped working. You could try introducing a response filter that triggers on DRM requests, check if the response is empty, and disable the track manually.
  2. You could try creating a response filter that checks if the DRM response is empty and sets a bitrate restriction in shaka to prevent jumping to the 720p variant.

@loicraux
Copy link
Contributor Author

loicraux commented Jan 16, 2023

Is there anything I could do in a responseFilter so that the session.update() will succeed (with denial of the license) ?

There might be better solutions, but in the meantime:

  1. There are properties on the variant tracks called allowedByApplication and allowedByKeySystem that could maybe be used to disable a track for the duration of the playback session. The empty DRM response should presumably set the allowedByKeySystem property to false, maybe that is what has stopped working. You could try introducing a response filter that triggers on DRM requests, check if the response is empty, and disable the track manually.

Since :

  • allowedByApplication and allowedByKeySystem are both internals of Shaka Player on variants of the list this.manifest_.variants
  • and when my response filter is called, I don't know how I could find the related variant in this.manifest_.variants...

... I am not sure I can use this solution :(

  1. You could try creating a response filter that checks if the DRM response is empty and sets a bitrate restriction in shaka to prevent jumping to the 720p variant.

I am not sure I can determine which variant is being refused in the response filter ?

Thanks for the suggestions though!

@martinstark
Copy link
Contributor

martinstark commented Jan 16, 2023

My bad, I assumed the documentation I looked at was for the variants returned by getVariantTracks. I did a quick test and I can indeed not access those values.

I am not sure I can determine which variant is being refused in the response filter ?

True. I can't think of a way to do that, so that workaround would only work if you knew in advance that it would always be the highest bitrate.

@loicraux
Copy link
Contributor Author

loicraux commented Jan 18, 2023

Can the shaka player development team give me their opinion about this problem?

I think this piece of code should still be executed when session.update() throws an exception (which is our case with EZDRM returning an empty response)... I don't really see the difference between not receiving a key status update after 5 seconds (SESSION_LOAD_TIMEOUT_) and our case where session.update() fails... :

    if (metadata) {
      if (metadata.updatePromise) {
        metadata.updatePromise.resolve();
      }
      // In case there are no key statuses, consider this session loaded
      // after a reasonable timeout.  It should definitely not take 5
      // seconds to process a license.
      const timer = new shaka.util.Timer(() => {
        metadata.loaded = true;
        if (this.areAllSessionsLoaded_()) {
          this.allSessionsLoaded_.resolve();
        }
      });

      timer.tickAfter(
          /* seconds= */ shaka.media.DrmEngine.SESSION_LOAD_TIMEOUT_);
    }

Just like ignoreTextStreamFailures allows to ignore any errors in a malformed text stream, filter out those streams and allow normal playback of the video, I would expect shaka-player to also ignore a "malformed" license server response and issue a 'trackschanged' event and allow the video to play, at least with a configuration setting... What do you think about that ?

By the way, has anyone else using EZDRM experienced this same problem? If so, I'd be interested to know how they solved or worked around it!

@avelad avelad modified the milestones: v4.4, v4.5 Aug 31, 2023
@avelad avelad modified the milestones: v4.5, v4.6 Oct 5, 2023
@avelad avelad modified the milestones: v4.6, v5.0 Nov 16, 2023
@avelad avelad added the priority: P2 Smaller impact or easy workaround label Nov 30, 2023
avelad added a commit that referenced this issue Dec 1, 2023
avelad added a commit that referenced this issue Dec 4, 2023
@shaka-bot shaka-bot added the status: archived Archived and locked; will not be updated label Jan 30, 2024
@shaka-project shaka-project locked as resolved and limited conversation to collaborators Jan 30, 2024
joeyparrish pushed a commit that referenced this issue Feb 17, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
priority: P2 Smaller impact or easy workaround status: archived Archived and locked; will not be updated type: bug Something isn't working correctly
Projects
None yet
4 participants