From 2f65b97b79c9b9dfde1b95afadf7c790827054c7 Mon Sep 17 00:00:00 2001 From: Michelle Zhuo Date: Wed, 31 Mar 2021 12:24:42 -0700 Subject: [PATCH] feat(MediaCap): Use MediaCapabilities for offline storage Issue #1391 Change-Id: Ifdf4477d3798ddacf77036f7d85d9cb29438becc --- build/types/core | 1 - lib/offline/storage.js | 19 ++++---- lib/util/manifest_filter.js | 70 ----------------------------- lib/util/stream_utils.js | 40 ++++++++++++----- test/offline/storage_integration.js | 27 +++++++---- 5 files changed, 57 insertions(+), 100 deletions(-) delete mode 100644 lib/util/manifest_filter.js diff --git a/build/types/core b/build/types/core index b093118943..5f19623958 100644 --- a/build/types/core +++ b/build/types/core @@ -75,7 +75,6 @@ +../../lib/util/iterables.js +../../lib/util/language_utils.js +../../lib/util/lazy.js -+../../lib/util/manifest_filter.js +../../lib/util/manifest_parser_utils.js +../../lib/util/map_utils.js +../../lib/util/media_ready_state_utils.js diff --git a/lib/offline/storage.js b/lib/offline/storage.js index 884733c6dd..bb1c804ab6 100644 --- a/lib/offline/storage.js +++ b/lib/offline/storage.js @@ -27,7 +27,6 @@ goog.require('shaka.util.Error'); goog.require('shaka.util.Functional'); goog.require('shaka.util.IDestroyable'); goog.require('shaka.util.Iterables'); -goog.require('shaka.util.ManifestFilter'); goog.require('shaka.util.MimeUtils'); goog.require('shaka.util.Networking'); goog.require('shaka.util.Platform'); @@ -483,25 +482,27 @@ shaka.offline.Storage = class { // Filter the manifest based on the restrictions given in the player // configuration. const maxHwRes = {width: Infinity, height: Infinity}; - shaka.util.ManifestFilter.filterByRestrictions( - manifest, config.restrictions, maxHwRes); + StreamUtils.filterByRestrictions(manifest, config.restrictions, maxHwRes); // Filter the manifest based on what we know media source will be able to // play later (no point storing something we can't play). - // TODO: add an argument of usePersistentLicense, and use the value of - // config.offline.usePersistentLicense. - shaka.util.ManifestFilter.filterByMediaSourceSupport(manifest); + if (config.useMediaCapabilities) { + StreamUtils.filterManifestByMediaCapabilities( + manifest, config.offline.usePersistentLicense); + } else { + StreamUtils.filterManifestByMediaSource(manifest); + } // Filter the manifest based on what we know our drm system will support // playing later. - shaka.util.ManifestFilter.filterByDrmSupport(manifest, drmEngine); + StreamUtils.filterManifestByDrm(manifest, drmEngine); // Gather all tracks. const allTracks = []; // Choose the codec that has the lowest average bandwidth. const preferredAudioChannelCount = config.preferredAudioChannelCount; - shaka.util.StreamUtils.chooseCodecsAndFilterManifest( + StreamUtils.chooseCodecsAndFilterManifest( manifest, preferredAudioChannelCount); for (const variant of manifest.variants) { @@ -998,7 +999,7 @@ shaka.offline.Storage = class { drmEngine.configure(config.drm); await drmEngine.initForStorage( manifest.variants, config.offline.usePersistentLicense, - /* useMediaCapabilities= */ config.useMediaCapabilities); + config.useMediaCapabilities); await drmEngine.setServerCertificate(); await drmEngine.createOrLoad(); diff --git a/lib/util/manifest_filter.js b/lib/util/manifest_filter.js deleted file mode 100644 index 255c6a6e3c..0000000000 --- a/lib/util/manifest_filter.js +++ /dev/null @@ -1,70 +0,0 @@ -/*! @license - * Shaka Player - * Copyright 2016 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -goog.provide('shaka.util.ManifestFilter'); - -goog.require('shaka.media.MediaSourceEngine'); -goog.require('shaka.util.StreamUtils'); -goog.requireType('shaka.media.DrmEngine'); - - -/** - * This utility class contains all the functions used to filter manifests - * before playback and before storage. - */ -shaka.util.ManifestFilter = class { - /** - * Filter the variants in |manifest| to only include the variants that meet - * the given restrictions. - * - * @param {shaka.extern.Manifest} manifest - * @param {shaka.extern.Restrictions} restrictions - * @param {{width: number, height:number}} maxHwResolution - */ - static filterByRestrictions(manifest, restrictions, maxHwResolution) { - manifest.variants = manifest.variants.filter((variant) => { - return shaka.util.StreamUtils.meetsRestrictions( - variant, restrictions, maxHwResolution); - }); - } - - - /** - * Filter the variants in the |manifest| to only include those that are - * supported by media source. - * - * @param {shaka.extern.Manifest} manifest - */ - static filterByMediaSourceSupport(manifest) { - const MediaSourceEngine = shaka.media.MediaSourceEngine; - - manifest.variants = manifest.variants.filter((variant) => { - let supported = true; - if (variant.audio) { - supported = - supported && MediaSourceEngine.isStreamSupported(variant.audio); - } - if (variant.video) { - supported = - supported && MediaSourceEngine.isStreamSupported(variant.video); - } - return supported; - }); - } - - /** - * Filter the variants in |manifest| to only include those that are supported - * by |drm|. - * - * @param {shaka.extern.Manifest} manifest - * @param {!shaka.media.DrmEngine} drmEngine - */ - static filterByDrmSupport(manifest, drmEngine) { - manifest.variants = manifest.variants.filter((variant) => { - return drmEngine.supportsVariant(variant); - }); - } -}; diff --git a/lib/util/stream_utils.js b/lib/util/stream_utils.js index ab16100833..5a71739fcf 100644 --- a/lib/util/stream_utils.js +++ b/lib/util/stream_utils.js @@ -179,6 +179,21 @@ shaka.util.StreamUtils = class { return baseVideoCodec + '-' + baseAudioCodec; } + /** + * Filter the variants in |manifest| to only include the variants that meet + * the given restrictions. + * + * @param {shaka.extern.Manifest} manifest + * @param {shaka.extern.Restrictions} restrictions + * @param {{width: number, height:number}} maxHwResolution + */ + static filterByRestrictions(manifest, restrictions, maxHwResolution) { + manifest.variants = manifest.variants.filter((variant) => { + return shaka.util.StreamUtils.meetsRestrictions( + variant, restrictions, maxHwResolution); + }); + } + /** * @param {shaka.extern.Variant} variant * @param {shaka.extern.Restrictions} restrictions @@ -278,10 +293,11 @@ shaka.util.StreamUtils = class { // needed. // TODO: remove the first parameter 'drmEngine' and the function // 'filterManifestByDrm_'. - shaka.util.StreamUtils.filterManifestByDrm_(drmEngine, manifest); + shaka.util.StreamUtils.filterManifestByDrm(manifest, drmEngine); if (useMediaCapabilities) { - await shaka.util.StreamUtils.filterManifestByMediaCapabilities_(manifest); + await shaka.util.StreamUtils.filterManifestByMediaCapabilities(manifest, + manifest.offlineSessionIds.length > 0); } else { shaka.util.StreamUtils.filterManifestByMediaSource(manifest); } @@ -293,13 +309,12 @@ shaka.util.StreamUtils = class { /** - * Alters the given Manifest to filter out any streams unsupported by the DRM. - * - * @param {shaka.media.DrmEngine} drmEngine + * Filter the variants in |manifest| to only include those that are supported + * by |drm|. * @param {shaka.extern.Manifest} manifest - * @private + * @param {shaka.media.DrmEngine} drmEngine */ - static filterManifestByDrm_(drmEngine, manifest) { + static filterManifestByDrm(manifest, drmEngine) { manifest.variants = manifest.variants.filter((variant) => { if (drmEngine && drmEngine.initialized()) { if (!drmEngine.supportsVariant(variant)) { @@ -308,6 +323,7 @@ shaka.util.StreamUtils = class { return false; } } + shaka.log.debug('DrmEngine is not initialized yet.'); return true; }); } @@ -318,13 +334,13 @@ shaka.util.StreamUtils = class { * platform via MediaCapabilities.decodingInfo() API. * * @param {shaka.extern.Manifest} manifest - * @private + * @param {boolean} usePersistentLicenses */ - static async filterManifestByMediaCapabilities_(manifest) { + static async filterManifestByMediaCapabilities( + manifest, usePersistentLicenses) { goog.asserts.assert(navigator.mediaCapabilities, 'MediaCapabilities should be valid.'); - const usePersistentLicenses = manifest.offlineSessionIds.length > 0; await shaka.util.StreamUtils.getDecodingInfosForVariants( manifest.variants, usePersistentLicenses); manifest.variants = manifest.variants.filter((variant) => { @@ -342,8 +358,8 @@ shaka.util.StreamUtils = class { /** - * Alters the given variants to filter out any streams unsupported by the - * MediaSource. + * Filter the variants in the |manifest| to only include those that are + * supported by media source. * TODO: remove once MediaCap implementations are done. * @param {shaka.extern.Manifest} manifest */ diff --git a/test/offline/storage_integration.js b/test/offline/storage_integration.js index 9b6a5a32df..cabde9d3d5 100644 --- a/test/offline/storage_integration.js +++ b/test/offline/storage_integration.js @@ -147,7 +147,15 @@ filterDescribe('Storage', storageSupport, () => { } }); - filterDescribe('persistent license', drmStorageSupport, () => { + for (const useMediaCapabilities of [true, false]) { + const isEnabled = useMediaCapabilities ? 'enabled' : 'disabled'; + filterDescribe('persistent license with MediaCapabilities ' + isEnabled, + drmStorageSupport, () => { + testPersistentLicense(useMediaCapabilities); + }); + } + + function testPersistentLicense(useMediaCapabilities) { /** @type {!shaka.Player} */ let player; /** @type {!shaka.offline.Storage} */ @@ -158,6 +166,7 @@ filterDescribe('Storage', storageSupport, () => { // networking engine. This allows us to use Player.configure in these // tests. player = new shaka.Player(); + player.configure({'useMediaCapabilities': useMediaCapabilities}); storage = new shaka.offline.Storage(player); }); @@ -192,7 +201,7 @@ filterDescribe('Storage', storageSupport, () => { expect(manifest.offlineSessionIds.length).toBeTruthy(); // PART 2 - Check that the licences are stored. - await withDrm(player, manifest, (drm) => { + await withDrm(player, manifest, useMediaCapabilities, (drm) => { return Promise.all(manifest.offlineSessionIds.map(async (session) => { const foundSession = await loadOfflineSession(drm, session); expect(foundSession).toBeTruthy(); @@ -204,7 +213,7 @@ filterDescribe('Storage', storageSupport, () => { await storage.remove(uri.toString()); // PART 4 - Check that the licenses were removed. - const p = withDrm(player, manifest, (drm) => { + const p = withDrm(player, manifest, useMediaCapabilities, (drm) => { return Promise.all(manifest.offlineSessionIds.map(async (session) => { const notFoundSession = await loadOfflineSession(drm, session); expect(notFoundSession).toBeFalsy(); @@ -248,7 +257,7 @@ filterDescribe('Storage', storageSupport, () => { const storedContents = await storage.list(); expect(storedContents).toEqual([]); - await withDrm(player, manifest, (drm) => { + await withDrm(player, manifest, useMediaCapabilities, (drm) => { return Promise.all(manifest.offlineSessionIds.map(async (session) => { const foundSession = await loadOfflineSession(drm, session); expect(foundSession).toBeTruthy(); @@ -261,7 +270,7 @@ filterDescribe('Storage', storageSupport, () => { expect(didRemoveAll).toBe(true); // PART 6 - Check that the licenses were removed. - const p = withDrm(player, manifest, (drm) => { + const p = withDrm(player, manifest, useMediaCapabilities, (drm) => { return Promise.all(manifest.offlineSessionIds.map(async (session) => { const notFoundSession = await loadOfflineSession(drm, session); expect(notFoundSession).toBeFalsy(); @@ -273,7 +282,7 @@ filterDescribe('Storage', storageSupport, () => { shaka.util.Error.Code.OFFLINE_SESSION_REMOVED)); await expectAsync(p).toBeRejectedWith(expected); }); - }); + } describe('default track selection callback', () => { const PlayerConfiguration = shaka.util.PlayerConfiguration; @@ -1672,10 +1681,11 @@ filterDescribe('Storage', storageSupport, () => { /** * @param {!shaka.Player} player * @param {shaka.extern.Manifest} manifest + * @param {boolean} useMediaCapabilities * @param {function(!shaka.media.DrmEngine):Promise} action * @return {!Promise} */ - async function withDrm(player, manifest, action) { + async function withDrm(player, manifest, useMediaCapabilities, action) { const net = player.getNetworkingEngine(); goog.asserts.assert(net, 'Player should have a net engine right now'); @@ -1693,7 +1703,8 @@ filterDescribe('Storage', storageSupport, () => { try { drm.configure(player.getConfiguration().drm); const variants = manifest.variants; - await drm.initForStorage(variants, /* usePersistentLicenses= */ true); + await drm.initForStorage(variants, /* usePersistentLicenses= */ true, + useMediaCapabilities); await action(drm); } finally { await drm.destroy();