Have you read the FAQ and checked for duplicate open issues?
Yes, this is related to https://github.com/google/shaka-player/issues/1093 but this has been locked as too old.
What version of Shaka Player are you using?
Tried with both 2.5.12 and 3.0.1
Can you reproduce the issue with our latest release version?
Yes
Can you reproduce the issue with the latest code from master?
Not tested
Are you using the demo app or your own custom app?
Custom App
If custom app, can you reproduce the issue using our demo app?
Not tested
What browser and OS are you using?
Chrome 84.0.4147.89, MacOS 10.15.6
For embedded devices (smart TVs, etc.), what model and firmware version are you using?
-
What are the manifest and license server URIs?
Shouldn't be needed a specific manifest, but it must be a DASH with DRM.
What did you do?
What did you expect to happen?
What actually happened?
So, here's what we were trying to do.
To get the correct license for a DRM content, we need three parameters. We obtain two of them through the HTTP Request that returns us also the main manifest URL. The third one is the token for authenticating on the service that serves us everything about the media (parameters data included).
Theoretically, we might incur into an expired token. For this reason we want to throw error and unload the content.
Here's our code:
return this.player.load(src, startTime, mimeType)
.then(() => {
console.log('READY - The video has now been loaded!');
this.changePlaybackState('READY');
})
.catch(this.handleShakaError_);
handleShakaError_(err: shaka.util.Error) {
// ... other code
console.log('onShakaError');
console.error(err);
this.unload_()
.then(() => {
console.log('THEN, WHAT?');
this.props.delegate?.onError(new ShakaError(err));
})
.catch((err) => console.log('error in unloading', err));
}
unload_() {
// more code ...
return this.player.unload(false)
.then(() => {
console.log('Unload shaka: finished');
this.changePlaybackState('IDLE');
})
.catch((err) => {
console.error('Error in unload', err);
return err;
});
}
We are receiving in handleShakaError_ this error if we pass in the license URL an expired or invalid token: Shaka Error DRM.LICENSE_REQUEST_FAILED. So we expect then that both Unload shaka: finished or Error in unload AND THEN, WHAT? to be printed in the console, but it never happen.
Instead we see only, in debug mode, Shaka's logs:
Starting unload...
Closing session 027B2E46533F4895A5055741BFF24CAE
So we started digging down to the root of the problem and we found this:
What happens is that the flow into Shaka halts when this.drmEngine_.destroy(); is executed. In particular, it gets halted on await this.closeOpenSessions_();.
We found that this issue seems linked to issue #1093. It was "solved" by saying that it was a problem with Chrome on MacOS, which wasn't solving the session.close() for any reason when working with DRM content.
A workaround has been introduced in - I don't know which version it was available on Dec 2017 - this commit: https://github.com/google/shaka-player/commit/734797b8c0a2c68876683c8f544dc1625bd49584: a Promise.race with a timeout.
Over time, this workaround has been moved to shaka.media.DrmEngine.closeSession_, but at a certain point, on 1 November 2019, this method has been removed and the fix with it - check here: https://github.com/google/shaka-player/commit/6e252e7b81c49850653a87ba3482bb4cf68961d4#diff-052c6be0b439274b171a21b6729378b1L248
According to the commit message, the Chrome issue seems to be solved, but actually I don't think it so. Also the topic of Chromebug (https://crbug.com/690583) that was linked in the original issue on GH, is not available anymore (I get "Permission Denied").
Thank you.
I can reproduce this in the newest master, with just a few minor code changes to the demo.
It looks like there might have been a regression in Chrome at some point. I'll re-add that workaround for now, and contact the Chrome team.
Looking into this more, it might be a new bug rather than, strictly speaking, a regression.
The old bug that was filed, was for the case where you removed the session, didn't handle the license-release message, and then tried to close the session.
This bug, on the other hand, looks to happen when you make a session, make a request, but try to remove or close the session before the request finishes.
I spend a while looking at the EME spec, and I can't figure out if you are supposed to be able to cancel requests that way, by the spec. However, trying something similar with ClearKey in Chrome, it works there, which I feel points to this being a bug.
Thank you very much @theodab. Actually we perform the request but I fails with HTTP code 422 for the service specifications (token is invalid). So, I think, the session should clear correctly, isn't it?
Well, if it results in us not receiving a response for something, then we will end up with a hanging session request, and we will be unable to close the session.
Unless I'm misunderstanding you, and there are two different obscure timing bugs involved. That's totally possible too, I guess.
Anyway, I filed the issue here: http://crbug.com/1108158
Is it normal I keep getting permission denied, even if logged in, while looking at the link you gave me? A colleague of mine which is working with me has the same issue.
Anyway, yes, as you say it seems to be a matter of the MediaKeySession that cannot be closed, that breaks everything.
Can you suggest us a workaround?
Currently, on DRM Error, we are running this.player.destroy(), without waiting its result, and to recreate from scratch also the HTMLVideoElement along with a new Shaka instance (so, we are making old shaka instance orphan).
We are destroying also the HTMLVideoElement because, to test, we tried to execute with a setTimeout the Shaka instance creation:
handleShakaError_(err: shaka.util.Error) {
// ... other code ...
if (err.severity === shaka.util.Error.Severity.CRITICAL) {
this.unload_(true).then(() => {
this.player.destroy();
setTimeout(() => {
this.initPlayer_();
this.props.delegate?.onError(new ShakaError(err));
}, 3000);
}
// ... other code ...
}
initPlayer_() {
this.player = new shaka.Player(this.videoNode);
// ... other init code ...
}
If we do that, we get the following error wrapped within a Shaka Error:
Failed to execute 'setMediaKeys' on 'HTMLMediaElement': The existing ContentDecryptionModule object cannot be removed at this time.
If we remove the setTimeout, the player remains just stuck.
Is it normal I keep getting permission denied, even if logged in, while looking at the link you gave me? A colleague of mine which is working with me has the same issue.
I'm not sure of the exact policy, but it seems that chrome bugs on certain components (like the Widevine CDM) default to being restricted to Google employees. I've requested that the new bug filed by @theodab be opened to the public, though I can't guarantee that it will happen. It's up to the Chrome team to decide if the issue's contents are sensitive.
I currently have the previous workaround (and a regression test) in code review.
In the meantime, I don't know how much you can do. Destroying the media element mid-unload is bound to cause weird effects. If I had to guess, I'd say that it's unblocking the close session process... and then get to the next step of unloading, where we try to unset the media keys on the (now-destroyed) video element.
Most helpful comment
I currently have the previous workaround (and a regression test) in code review.
In the meantime, I don't know how much you can do. Destroying the media element mid-unload is bound to cause weird effects. If I had to guess, I'd say that it's unblocking the close session process... and then get to the next step of unloading, where we try to unset the media keys on the (now-destroyed) video element.