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

feat: set up required key sessions on waitingforkey event #1232

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 43 additions & 16 deletions src/videojs-http-streaming.js
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,41 @@ class VhsHandler extends Component {
this.tech_.src(this.mediaSourceUrl_);
}

createKeySessions_() {
const audioPlaylistLoader =
this.masterPlaylistController_.mediaTypes_.AUDIO.activePlaylistLoader;

this.logger_('waiting for EME key session creation');
waitForKeySessionCreation({
player: this.player_,
sourceKeySystems: this.source_.keySystems,
audioMedia: audioPlaylistLoader && audioPlaylistLoader.media(),
mainPlaylists: this.playlists.master.playlists
}).then(() => {
this.logger_('created EME key session');
this.masterPlaylistController_.sourceUpdater_.initializedEme();
}).catch((err) => {
this.logger_('error while creating EME key session', err);
this.player_.error({
message: 'Failed to initialize media keys for EME',
code: 3
});
});
}

handleWaitingForKey_() {
// If waitingforkey is fired, it's possible that the data that's necessary to retrieve
// the key is in the manifest. While this should've happened on initial source load, it
// may happen again in live streams where the keys change, and the manifest info
// reflects the update.
//
// Because videojs-contrib-eme compares the PSSH data we send to that of PSSH data it's
// already requested keys for, we don't have to worry about this generating extraneous
// requests.
this.logger_('waitingforkey fired, attempting to create any new key sessions');
this.createKeySessions_();
}

/**
* If necessary and EME is available, sets up EME options and waits for key session
* creation.
Expand Down Expand Up @@ -1033,6 +1068,9 @@ class VhsHandler extends Component {
}
});

this.handleWaitingForKey_ = this.handleWaitingForKey_.bind(this);
this.player_.tech_.on('waitingforkey', this.handleWaitingForKey_);

// In IE11 this is too early to initialize media keys, and IE11 does not support
// promises.
if (videojs.browser.IE_VERSION === 11 || !didSetupEmeOptions) {
Expand All @@ -1041,22 +1079,7 @@ class VhsHandler extends Component {
return;
}

this.logger_('waiting for EME key session creation');
waitForKeySessionCreation({
player: this.player_,
sourceKeySystems: this.source_.keySystems,
audioMedia: audioPlaylistLoader && audioPlaylistLoader.media(),
mainPlaylists: this.playlists.master.playlists
}).then(() => {
this.logger_('created EME key session');
this.masterPlaylistController_.sourceUpdater_.initializedEme();
}).catch((err) => {
this.logger_('error while creating EME key session', err);
this.player_.error({
message: 'Failed to initialize media keys for EME',
code: 3
});
});
this.createKeySessions_();
}

/**
Expand Down Expand Up @@ -1171,6 +1194,10 @@ class VhsHandler extends Component {
this.mediaSourceUrl_ = null;
}

if (this.tech_) {
this.tech_.off('waitingforkey', this.handleWaitingForKey_);
}

super.dispose();
}

Expand Down
39 changes: 39 additions & 0 deletions test/videojs-http-streaming.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4713,6 +4713,45 @@ QUnit.test('eme handles keystatuschange where status is usable', function(assert
assert.deepEqual(excludes, [], 'did not exclude anything');
});

QUnit.test('eme waitingforkey event triggers another setup', function(assert) {
this.player.eme = { options: { setting: 1 } };
this.player.src({
src: 'manifest/master.m3u8',
type: 'application/x-mpegURL',
keySystems: { keySystem1: { url: 'url1' } }
});

this.clock.tick(1);

const media = {
attributes: { CODECS: 'avc1.420015, mp4a.40.2c' },
contentProtection: { keySystem1: { pssh: 'test' } }
};

const vhs = this.player.tech_.vhs;

vhs.playlists = {
master: { playlists: [media] },
media: () => media
};

const origCreateKeySessions = vhs.createKeySessions_.bind(vhs);
let createKeySessionCalls = 0;

vhs.createKeySessions_ = () => {
createKeySessionCalls++;
origCreateKeySessions();
};

vhs.masterPlaylistController_.sourceUpdater_.trigger('createdsourcebuffers');

assert.equal(createKeySessionCalls, 1, 'called createKeySessions_ once');

this.player.tech_.trigger({type: 'waitingforkey', status: 'usable'});

assert.equal(createKeySessionCalls, 2, 'called createKeySessions_ again');
});

QUnit.test('integration: configures eme for DASH on source buffer creation', function(assert) {
assert.timeout(3000);
const done = assert.async();
Expand Down