Skip to content

Commit

Permalink
test: Disable power-saving features on both Chrome and Edge (shaka-pr…
Browse files Browse the repository at this point in the history
…oject#5508)

Power-saving features on Chrome and Edge were subtly interfering with
playback tests. Timers could be throttled, and both video-only media and
media in occluded windows could be paused by the browser.

This was discovered only after awaiting play() Promises in all tests.
These Promises were being rejected with useful error messages that led
to these discoveries.

Awaiting play() requires us to disable stall detection during playback
tests. This is because on some platforms, stalls get resolved by calling
pause() and then play(), which would cause the original awaited play()
Promise to be rejected.

Finally, some Player tests created additional Player instances that were
unnecessary. Removing those allowed me to centralize most of the
configuration to disable stall detection.
  • Loading branch information
joeyparrish committed Aug 19, 2023
1 parent bba4d9f commit ffafacf
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 90 deletions.
40 changes: 37 additions & 3 deletions build/shaka-lab.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,33 @@ vars:
# Normally, Chrome disallows autoplaying videos in many cases. Enable
# it for testing.
- "--autoplay-policy=no-user-gesture-required"
# Disable browser features that try to save power by suspending media,
# throttling timers, etc.
- "--disable-background-media-suspend"
- "--disable-background-timer-throttling"
- "--disable-backgrounding-occluded-windows"

# Instruct chromedriver not to disable component updater. The component
# updater must run in order for the Widevine CDM to be available when
# using a new user-data-dir.
excludeSwitches:
- "disable-component-update"

# Instruct chromedriver not to disable component updater. The
# component updater must run in order for the Widevine CDM to be
# available when using a new user-data-dir.
basic_edge_config: &basic_edge_config
ms:edgeOptions:
args:
# Normally, Edge disallows autoplaying videos in many cases. Enable it
# for testing.
- "--autoplay-policy=no-user-gesture-required"
# Disable browser features that try to save power by suspending media,
# throttling timers, etc.
- "--disable-background-media-suspend"
- "--disable-background-timer-throttling"
- "--disable-backgrounding-occluded-windows"

# Instruct edgedriver not to disable component updater. The component
# updater must run in order for the Widevine CDM to be available when
# using a new user-data-dir.
excludeSwitches:
- "disable-component-update"

Expand Down Expand Up @@ -73,6 +96,11 @@ vars:
# Allow remote attestation even though the device may be in dev mode. This
# is critical for testing involving L1 content licenses.
- "--allow-ra-in-dev-mode"
# Disable browser features that try to save power by suspending media,
# throttling timers, etc.
- "--disable-background-media-suspend"
- "--disable-background-timer-throttling"
- "--disable-backgrounding-occluded-windows"

safari_tp_config: &safari_tp_config
safari.options:
Expand All @@ -96,6 +124,8 @@ FirefoxMac:
EdgeMac:
browser: msedge
os: Mac
extra_configs:
- *basic_edge_config

Safari:
browser: safari
Expand Down Expand Up @@ -127,6 +157,8 @@ FirefoxWindows:
Edge:
browser: msedge
os: Windows
extra_configs:
- *basic_edge_config


### Linux ###
Expand All @@ -146,6 +178,8 @@ FirefoxLinux:
EdgeLinux:
browser: msedge
os: Linux
extra_configs:
- *basic_edge_config


### Misc ###
Expand Down
4 changes: 2 additions & 2 deletions test/media/drm_engine_integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ describe('DrmEngine', () => {
/* hasClosedCaptions= */ false);

expect(video.buffered.end(0)).toBeGreaterThan(0);
video.play();
await video.play();

const waiter = new shaka.test.Waiter(eventManager).timeoutAfter(15);
waiter.setMediaSourceEngine(mediaSourceEngine);
Expand Down Expand Up @@ -330,7 +330,7 @@ describe('DrmEngine', () => {
/* hasClosedCaptions= */ false);

expect(video.buffered.end(0)).toBeGreaterThan(0);
video.play();
await video.play();

const waiter = new shaka.test.Waiter(eventManager).timeoutAfter(15);
waiter.setMediaSourceEngine(mediaSourceEngine);
Expand Down
25 changes: 14 additions & 11 deletions test/media/streaming_engine_integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ describe('StreamingEngine', () => {
beforeEach(() => {
config = shaka.util.PlayerConfiguration.createDefault().streaming;

// Disable stall detection, which can interfere with playback tests.
config.stallEnabled = false;

onError = jasmine.createSpy('onError');
onError.and.callFake(fail);
onEvent = jasmine.createSpy('onEvent');
Expand Down Expand Up @@ -279,7 +282,7 @@ describe('StreamingEngine', () => {
// Let's go!
streamingEngine.switchVariant(variant);
await streamingEngine.start();
video.play();
await video.play();
// The overall test timeout is 120 seconds, and the content is 40
// seconds. It should be possible to complete this test in 100 seconds,
// and if not, we want the error thrown to be within the overall test's
Expand All @@ -299,7 +302,7 @@ describe('StreamingEngine', () => {
// Let's go!
streamingEngine.switchVariant(variant);
await streamingEngine.start();
video.play();
await video.play();

// Wait for playback to begin before increasing the playback rate. This
// improves test reliability on slow platforms like Chromecast.
Expand All @@ -313,7 +316,7 @@ describe('StreamingEngine', () => {
// Let's go!
streamingEngine.switchVariant(variant);
await streamingEngine.start();
video.play();
await video.play();

// After 35 seconds seek back 10 seconds into the first Period.
await waiter.timeoutAfter(80).waitUntilPlayheadReaches(video, 35);
Expand All @@ -325,7 +328,7 @@ describe('StreamingEngine', () => {
// Let's go!
streamingEngine.switchVariant(variant);
await streamingEngine.start();
video.play();
await video.play();
await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 20);
video.currentTime = 40;
await waiter.timeoutAfter(60).waitForEnd(video);
Expand Down Expand Up @@ -353,7 +356,7 @@ describe('StreamingEngine', () => {
streamingEngine.switchVariant(variant);
await streamingEngine.start();

video.play();
await video.play();
await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 305);

const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT;
Expand All @@ -376,7 +379,7 @@ describe('StreamingEngine', () => {
// Seek outside the availability window right away. The playhead
// should adjust the video's current time.
video.currentTime = segmentAvailability.end + 120;
video.play();
await video.play();

// Wait until the repositioning is complete so we don't
// immediately hit this case.
Expand All @@ -401,7 +404,7 @@ describe('StreamingEngine', () => {
video.currentTime = segmentAvailability.start - 120;
expect(video.currentTime).toBeGreaterThan(0);

video.play();
await video.play();
await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 305);

// We are playing close to the beginning of the availability window.
Expand Down Expand Up @@ -429,7 +432,7 @@ describe('StreamingEngine', () => {
// Let's go!
streamingEngine.switchVariant(variant);
await streamingEngine.start();
video.play();
await video.play();

await waiter.timeoutAfter(5).waitUntilPlayheadReaches(video, 0.01);
expect(video.buffered.length).toBeGreaterThan(0);
Expand All @@ -444,7 +447,7 @@ describe('StreamingEngine', () => {
// Let's go!
streamingEngine.switchVariant(variant);
await streamingEngine.start();
video.play();
await video.play();

await waiter.timeoutAfter(5).waitUntilPlayheadReaches(video, 0.01);
expect(video.buffered.length).toBeGreaterThan(0);
Expand All @@ -463,7 +466,7 @@ describe('StreamingEngine', () => {
await waiter.timeoutAfter(5).waitForEvent(video, 'loadeddata');

video.currentTime = 8;
video.play();
await video.play();

await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 23);
// Should be close enough to still have the gap buffered.
Expand All @@ -480,7 +483,7 @@ describe('StreamingEngine', () => {
await waiter.timeoutAfter(5).waitForEvent(video, 'loadeddata');

video.currentTime = 8;
video.play();
await video.play();

await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 23);
// Should be close enough to still have the gap buffered.
Expand Down
39 changes: 16 additions & 23 deletions test/mss/mss_player_integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ describe('MSS Player', () => {
beforeEach(() => {
player = new compiledShaka.Player(video);

// Make sure we are playing the lowest res available to avoid test flake
// based on network issues. Note that disabling ABR and setting a low
// abr.defaultBandwidthEstimate would not be sufficient, because it
// would only affect the choice of track on the first period. When we
// cross a period boundary, the default bandwidth estimate will no
// longer be in effect, and AbrManager may choose higher res tracks for
// the new period. Using abr.restrictions.maxHeight will let us force
// AbrManager to the lowest resolution, which is its fallback when these
// soft restrictions cannot be met.
player.configure('abr.restrictions.maxHeight', 1);

// Disable stall detection, which can interfere with playback tests.
player.configure('streaming.stallEnabled', false);

// Grab event manager from the uncompiled library:
eventManager = new shaka.util.EventManager();
waiter = new shaka.test.Waiter(eventManager);
Expand All @@ -61,20 +75,9 @@ describe('MSS Player', () => {
});

it('MSS VoD', async () => {
// Make sure we are playing the lowest res available to avoid test flake
// based on network issues. Note that disabling ABR and setting a low
// abr.defaultBandwidthEstimate would not be sufficient, because it
// would only affect the choice of track on the first period. When we
// cross a period boundary, the default bandwidth estimate will no
// longer be in effect, and AbrManager may choose higher res tracks for
// the new period. Using abr.restrictions.maxHeight will let us force
// AbrManager to the lowest resolution, which is its fallback when these
// soft restrictions cannot be met.
player.configure('abr.restrictions.maxHeight', 1);

await player.load(url, /* startTime= */ null,
/* mimeType= */ 'application/vnd.ms-sstr+xml');
video.play();
await video.play();
expect(player.isLive()).toBe(false);

// Wait for the video to start playback. If it takes longer than 10
Expand All @@ -93,16 +96,6 @@ describe('MSS Player', () => {
if (!support['com.microsoft.playready']) {
return;
}
// Make sure we are playing the lowest res available to avoid test flake
// based on network issues. Note that disabling ABR and setting a low
// abr.defaultBandwidthEstimate would not be sufficient, because it
// would only affect the choice of track on the first period. When we
// cross a period boundary, the default bandwidth estimate will no
// longer be in effect, and AbrManager may choose higher res tracks for
// the new period. Using abr.restrictions.maxHeight will let us force
// AbrManager to the lowest resolution, which is its fallback when these
// soft restrictions cannot be met.
player.configure('abr.restrictions.maxHeight', 1);

player.configure({
drm: {
Expand All @@ -114,7 +107,7 @@ describe('MSS Player', () => {

await player.load(playreadyUrl, /* startTime= */ null,
/* mimeType= */ 'application/vnd.ms-sstr+xml');
video.play();
await video.play();
expect(player.isLive()).toBe(false);

// Wait for the video to start playback. If it takes longer than 10
Expand Down
9 changes: 6 additions & 3 deletions test/offline/offline_integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ filterDescribe('Offline', supportsStorage, () => {
player = new shaka.Player(video);
player.addEventListener('error', fail);

// Disable stall detection, which can interfere with playback tests.
player.configure('streaming.stallEnabled', false);

eventManager = new shaka.util.EventManager();
waiter = new shaka.test.Waiter(eventManager);
waiter.setPlayer(player);
Expand Down Expand Up @@ -67,7 +70,7 @@ filterDescribe('Offline', supportsStorage, () => {

await player.load(contentUri);

video.play();
await video.play();
await playTo(/* end= */ 3, /* timeout= */ 20);
await player.unload();
await storage.remove(contentUri);
Expand Down Expand Up @@ -103,7 +106,7 @@ filterDescribe('Offline', supportsStorage, () => {

await player.load(contentUri);

video.play();
await video.play();
await playTo(/* end= */ 3, /* timeout= */ 20);
await player.unload();
await storage.remove(contentUri);
Expand Down Expand Up @@ -146,7 +149,7 @@ filterDescribe('Offline', supportsStorage, () => {

await player.load(contentUri);

video.play();
await video.play();
await playTo(/* end= */ 3, /* timeout= */ 20);
await player.unload();
await storage.remove(contentUri);
Expand Down
35 changes: 19 additions & 16 deletions test/player_external.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,24 @@ describe('Player', () => {
beforeEach(() => {
player = new compiledShaka.Player(video);

// Make sure we are playing the lowest res available to avoid test flake
// based on network issues. Note that disabling ABR and setting a low
// abr.defaultBandwidthEstimate would not be sufficient, because it
// would only affect the choice of track on the first period. When we
// cross a period boundary, the default bandwidth estimate will no
// longer be in effect, and AbrManager may choose higher res tracks for
// the new period. Using abr.restrictions.maxHeight will let us force
// AbrManager to the lowest resolution, which is its fallback when these
// soft restrictions cannot be met.
player.configure('abr.restrictions.maxHeight', 1);

// Make sure that live streams are synced against a good clock.
player.configure('manifest.dash.clockSyncUri',
'https://shaka-player-demo.appspot.com/time.txt');

// Disable stall detection, which can interfere with playback tests.
player.configure('streaming.stallEnabled', false);

// Grab event manager from the uncompiled library:
eventManager = new shaka.util.EventManager();
waiter = new shaka.test.Waiter(eventManager);
Expand Down Expand Up @@ -92,21 +110,6 @@ describe('Player', () => {
}
}

// Make sure we are playing the lowest res available to avoid test flake
// based on network issues. Note that disabling ABR and setting a low
// abr.defaultBandwidthEstimate would not be sufficient, because it
// would only affect the choice of track on the first period. When we
// cross a period boundary, the default bandwidth estimate will no
// longer be in effect, and AbrManager may choose higher res tracks for
// the new period. Using abr.restrictions.maxHeight will let us force
// AbrManager to the lowest resolution, which is its fallback when these
// soft restrictions cannot be met.
player.configure('abr.restrictions.maxHeight', 1);

// Make sure that live streams are synced against a good clock.
player.configure('manifest.dash.clockSyncUri',
'https://shaka-player-demo.appspot.com/time.txt');

// Add asset-specific configuration.
player.configure(asset.getConfiguration());

Expand All @@ -125,7 +128,7 @@ describe('Player', () => {
const isLive = asset.features.includes(Feature.LIVE);
expect(player.isLive()).toBe(isLive);
}
video.play();
await video.play();

// Wait for the video to start playback. If it takes longer than 20
// seconds, fail the test.
Expand Down

0 comments on commit ffafacf

Please sign in to comment.