Skip to content

Commit

Permalink
fix: output-restricted event handling for unplayable streams (#1305)
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-barstow authored and misteroneill committed Aug 19, 2022
1 parent 57c0e72 commit 1c62a98
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 29 deletions.
43 changes: 34 additions & 9 deletions src/videojs-http-streaming.js
Original file line number Diff line number Diff line change
Expand Up @@ -1017,15 +1017,40 @@ class VhsHandler extends Component {
});

this.player_.tech_.on('keystatuschange', (e) => {
if (e.status === 'output-restricted') {
this.playlistController_.excludePlaylist({
playlistToExclude: this.playlistController_.media(),
error: {
message: `DRM keystatus changed to ${e.status}. Playlist will fail to play. ` +
'Check for HDCP content.'
},
playlistExclusionDuration: Infinity
});
if (e.status !== 'output-restricted') {
return;
}

const mainPlaylist = this.playlistController_.main();

if (!mainPlaylist || !mainPlaylist.playlists) {
return;
}

const excludedHDPlaylists = [];

// Assume all HD streams are unplayable and exclude them from ABR selection
mainPlaylist.playlists.forEach(playlist => {
if (playlist && playlist.attributes && playlist.attributes.RESOLUTION &&
playlist.attributes.RESOLUTION.height >= 720) {
if (!playlist.excludeUntil || playlist.excludeUntil < Infinity) {

playlist.excludeUntil = Infinity;
excludedHDPlaylists.push(playlist);
}
}
});

if (excludedHDPlaylists.length) {
videojs.log.warn(
'DRM keystatus changed to "output-restricted." Removing the following HD playlists ' +
'that will most likely fail to play and clearing the buffer. ' +
'This may be due to HDCP restrictions on the stream and the capabilities of the current device.',
...excludedHDPlaylists
);

// Clear the buffer before switching playlists, since it may already contain unplayable segments
this.playlistController_.fastQualityChange_();
}
});

Expand Down
74 changes: 54 additions & 20 deletions test/videojs-http-streaming.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4278,11 +4278,20 @@ QUnit.test('configures eme for HLS on source buffer creation', function(assert)
});

QUnit.test('eme handles keystatuschange where status is output-restricted', function(assert) {
const originalWarn = videojs.log.warn;
let warning = '';
let qualitySwitches = 0;

videojs.log.warn = (...text) => {
warning += [...text].join('');
};

this.player.eme = {
options: {
previousSetting: 1
}
};

this.player.src({
src: 'manifest/main.m3u8',
type: 'application/x-mpegURL',
Expand All @@ -4295,39 +4304,64 @@ QUnit.test('eme handles keystatuschange where status is output-restricted', func

this.clock.tick(1);

const media = {
attributes: {
CODECS: 'avc1.420015, mp4a.40.2c'
const playlists = [
{
attributes: {
RESOLUTION: {
width: 1280,
height: 720
}
}
},
contentProtection: {
keySystem1: {
pssh: 'test'
{
attributes: {
RESOLUTION: {
width: 1920,
height: 1080
}
}
},
{
attributes: {
RESOLUTION: {
width: 848,
height: 480
}
}
}
};
];

this.player.tech_.vhs.playlists = {
main: { playlists: [media] },
media: () => media
main: { playlists },
media: () => playlists[0]
};

const excludes = [];
this.player.tech_.vhs.playlistController_.main = () => {
return {
playlists
};
};

this.player.tech_.vhs.playlistController_.excludePlaylist = (exclude) => {
excludes.push(exclude);
this.player.tech_.vhs.playlistController_.fastQualityChange_ = () => {
qualitySwitches++;
};

this.player.tech_.vhs.playlistController_.sourceUpdater_.trigger('createdsourcebuffers');
this.player.tech_.trigger({type: 'keystatuschange', status: 'output-restricted'});

assert.deepEqual(excludes, [{
playlistExclusionDuration: Infinity,
error: {
message: 'DRM keystatus changed to output-restricted. Playlist will fail to play. ' +
'Check for HDCP content.'
},
playlistToExclude: undefined
}], 'excluded playlist');
assert.equal(playlists[0].excludeUntil, Infinity, 'first HD playlist excluded');
assert.equal(playlists[1].excludeUntil, Infinity, 'second HD playlist excluded');
assert.equal(playlists[2].excludeUntil, undefined, 'non-HD playlist not excluded');
assert.equal(qualitySwitches, 1, 'fastQualityChange_ called once');
assert.equal(
warning,
'DRM keystatus changed to "output-restricted." Removing the following HD playlists ' +
'that will most likely fail to play and clearing the buffer. ' +
'This may be due to HDCP restrictions on the stream and the capabilities of the current device.' +
[playlists[0], playlists[1]].join('')
);

videojs.log.warn = originalWarn;
});

QUnit.test('eme handles keystatuschange where status is usable', function(assert) {
Expand Down

0 comments on commit 1c62a98

Please sign in to comment.