media/cast_receiver_app/test/player_test.js
aquilescanta 0ddd3c2bd0 Implement DecryptableSampleQueueReader.isReady
PiperOrigin-RevId: 254746146
2019-07-02 17:43:00 +01:00

471 lines
17 KiB
JavaScript

/**
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @fileoverview Unit tests for playback methods.
*/
goog.module('exoplayer.cast.test');
goog.setTestOnly();
const ConfigurationFactory = goog.require('exoplayer.cast.ConfigurationFactory');
const Player = goog.require('exoplayer.cast.Player');
const mocks = goog.require('exoplayer.cast.test.mocks');
const testSuite = goog.require('goog.testing.testSuite');
const util = goog.require('exoplayer.cast.test.util');
let player;
let shakaFake;
testSuite({
setUp() {
mocks.setUp();
shakaFake = mocks.createShakaFake();
player = new Player(shakaFake, new ConfigurationFactory());
},
/** Tests the player initialisation */
testPlayerInitialisation() {
mocks.state().isSilent = true;
const states = [];
let stateCounter = 0;
let currentState;
player.addPlayerListener((playerState) => {
states.push(playerState);
});
// Dump the initial state manually.
player.invalidate();
stateCounter++;
assertEquals(stateCounter, states.length);
currentState = states[stateCounter - 1];
assertEquals(0, currentState.mediaQueue.length);
assertEquals(0, currentState.windowIndex);
assertNull(currentState.playbackPosition);
// Seek with uuid to prepare with later
const uuid = 'uuid1';
player.seekToUuid(uuid, 30 * 1000);
stateCounter++;
assertEquals(stateCounter, states.length);
currentState = states[stateCounter - 1];
assertEquals(30 * 1000, player.getCurrentPositionMs());
assertEquals(0, player.getCurrentWindowIndex());
assertEquals(-1, player.windowIndex_);
assertEquals(1, currentState.playbackPosition.periodId);
assertEquals(uuid, currentState.playbackPosition.uuid);
assertEquals(uuid, player.uuidToPrepare_);
// Add a DASH media item.
player.addQueueItems(0, util.queue.slice(0, 2));
stateCounter++;
assertEquals(stateCounter, states.length);
currentState = states[stateCounter - 1];
assertEquals('IDLE', currentState.playbackState);
assertNotNull(currentState.playbackPosition);
util.assertUuidIndexMap(player.queueUuidIndexMap_, currentState.mediaQueue);
// Prepare.
player.prepare();
stateCounter++;
assertEquals(stateCounter, states.length);
currentState = states[stateCounter - 1];
assertEquals(2, currentState.mediaQueue.length);
assertEquals('BUFFERING', currentState.playbackState);
assertEquals(
Player.DUMMY_MEDIA_ITEM_INFO, currentState.mediaItemsInfo[uuid]);
assertNull(player.uuidToPrepare_);
// The video element starts waiting.
mocks.state().isSilent = false;
mocks.notifyListeners('waiting');
// Nothing happens, masked buffering state after preparing.
assertEquals(stateCounter, states.length);
// The manifest arrives.
mocks.notifyListeners('streaming');
stateCounter++;
assertEquals(stateCounter, states.length);
currentState = states[stateCounter - 1];
assertEquals(2, currentState.mediaQueue.length);
assertEquals('BUFFERING', currentState.playbackState);
assertEquals(uuid, currentState.playbackPosition.uuid);
assertEquals(0, currentState.playbackPosition.periodId);
assertEquals(30 * 1000, currentState.playbackPosition.positionMs);
// The dummy media item info has been replaced by the real one.
assertEquals(20000000, currentState.mediaItemsInfo[uuid].windowDurationUs);
assertEquals(0, currentState.mediaItemsInfo[uuid].defaultStartPositionUs);
assertEquals(0, currentState.mediaItemsInfo[uuid].positionInFirstPeriodUs);
assertTrue(currentState.mediaItemsInfo[uuid].isSeekable);
assertFalse(currentState.mediaItemsInfo[uuid].isDynamic);
// Tracks have initially changed.
mocks.notifyListeners('trackschanged');
// Nothing happens because the media item info remains the same.
assertEquals(stateCounter, states.length);
// The video element reports the first frame rendered.
mocks.notifyListeners('loadeddata');
stateCounter++;
assertEquals(stateCounter, states.length);
currentState = states[stateCounter - 1];
assertEquals(2, currentState.mediaQueue.length);
assertEquals('READY', currentState.playbackState);
assertEquals(uuid, currentState.playbackPosition.uuid);
assertEquals(0, currentState.playbackPosition.periodId);
assertEquals(30 * 1000, currentState.playbackPosition.positionMs);
// Playback starts.
mocks.notifyListeners('playing');
// Nothing happens; we are ready already.
assertEquals(stateCounter, states.length);
// Add another queue item.
player.addQueueItems(1, util.queue.slice(3, 4));
stateCounter++;
assertEquals(stateCounter, states.length);
mocks.state().isSilent = true;
// Seek to the next queue item.
player.seekToWindow(1, 0);
stateCounter++;
assertEquals(stateCounter, states.length);
currentState = states[stateCounter - 1];
const uuid1 = currentState.mediaQueue[1].uuid;
assertEquals(
Player.DUMMY_MEDIA_ITEM_INFO, currentState.mediaItemsInfo[uuid1]);
util.assertUuidIndexMap(player.queueUuidIndexMap_, currentState.mediaQueue);
// The video element starts waiting.
mocks.state().isSilent = false;
mocks.notifyListeners('waiting');
// Nothing happens, masked buffering state after preparing.
assertEquals(stateCounter, states.length);
// The manifest arrives.
mocks.notifyListeners('streaming');
stateCounter++;
assertEquals(stateCounter, states.length);
currentState = states[stateCounter - 1];
// The dummy media item info has been replaced by the real one.
assertEquals(20000000, currentState.mediaItemsInfo[uuid].windowDurationUs);
assertEquals(0, currentState.mediaItemsInfo[uuid].defaultStartPositionUs);
assertEquals(0, currentState.mediaItemsInfo[uuid].positionInFirstPeriodUs);
assertTrue(currentState.mediaItemsInfo[uuid].isSeekable);
assertFalse(currentState.mediaItemsInfo[uuid].isDynamic);
},
/** Tests next and previous window when not yet prepared. */
testNextPreviousWindow_notPrepared() {
assertEquals(-1, player.getNextWindowIndex());
assertEquals(-1, player.getPreviousWindowIndex());
player.addQueueItems(0, util.queue.slice(0, 2));
assertEquals(-1, player.getNextWindowIndex());
assertEquals(-1, player.getPreviousWindowIndex());
},
/** Tests setting play when ready. */
testPlayWhenReady() {
player.addQueueItems(0, util.queue.slice(0, 3));
let playWhenReady = false;
player.addPlayerListener((state) => {
playWhenReady = state.playWhenReady;
});
assertEquals(false, player.getPlayWhenReady());
assertEquals(false, playWhenReady);
player.setPlayWhenReady(true);
assertEquals(true, player.getPlayWhenReady());
assertEquals(true, playWhenReady);
player.setPlayWhenReady(false);
assertEquals(false, player.getPlayWhenReady());
assertEquals(false, playWhenReady);
},
/** Tests seeking to another position in the actual window. */
async testSeek_inWindow() {
player.addQueueItems(0, util.queue.slice(0, 3));
await player.seekToWindow(0, 1000);
assertEquals(1, shakaFake.getMediaElement().currentTime);
assertEquals(1000, player.getCurrentPositionMs());
assertEquals(0, player.getCurrentWindowIndex());
},
/** Tests seeking to another window. */
async testSeek_nextWindow() {
player.addQueueItems(0, util.queue.slice(0, 3));
await player.prepare();
assertEquals(util.queue[0].media.uri, shakaFake.getMediaElement().src);
assertEquals(-1, player.getPreviousWindowIndex());
assertEquals(1, player.getNextWindowIndex());
player.seekToWindow(1, 2000);
assertEquals(0, player.getPreviousWindowIndex());
assertEquals(2, player.getNextWindowIndex());
assertEquals(2000, player.getCurrentPositionMs());
assertEquals(1, player.getCurrentWindowIndex());
assertEquals(util.queue[1].media.uri, mocks.state().loadedUri);
},
/** Tests the repeat mode 'none' */
testRepeatMode_none() {
player.addQueueItems(0, util.queue.slice(0, 3));
player.prepare();
assertEquals(Player.RepeatMode.OFF, player.getRepeatMode());
assertEquals(-1, player.getPreviousWindowIndex());
assertEquals(1, player.getNextWindowIndex());
player.seekToWindow(2, 0);
assertEquals(1, player.getPreviousWindowIndex());
assertEquals(-1, player.getNextWindowIndex());
},
/** Tests the repeat mode 'all'. */
testRepeatMode_all() {
let repeatMode;
player.addQueueItems(0, util.queue.slice(0, 3));
player.prepare();
player.addPlayerListener((state) => {
repeatMode = state.repeatMode;
});
player.setRepeatMode(Player.RepeatMode.ALL);
assertEquals(Player.RepeatMode.ALL, repeatMode);
player.seekToWindow(0,0);
assertEquals(2, player.getPreviousWindowIndex());
assertEquals(1, player.getNextWindowIndex());
player.seekToWindow(2, 0);
assertEquals(1, player.getPreviousWindowIndex());
assertEquals(0, player.getNextWindowIndex());
},
/**
* Tests navigation within the queue when repeat mode and shuffle mode is on.
*/
testRepeatMode_all_inShuffleMode() {
const initialOrder = [2, 1, 0];
let shuffleOrder;
let windowIndex;
player.addQueueItems(0, util.queue.slice(0, 3), initialOrder);
player.prepare();
player.addPlayerListener((state) => {
shuffleOrder = state.shuffleOrder;
windowIndex = state.windowIndex;
});
player.setRepeatMode(Player.RepeatMode.ALL);
player.setShuffleModeEnabled(true);
assertEquals(windowIndex, player.shuffleOrder_[player.shuffleIndex_]);
assertArrayEquals(initialOrder, shuffleOrder);
player.seekToWindow(shuffleOrder[2], 0);
assertEquals(shuffleOrder[2], windowIndex);
assertEquals(shuffleOrder[0], player.getNextWindowIndex());
assertEquals(shuffleOrder[1], player.getPreviousWindowIndex());
player.seekToWindow(shuffleOrder[0], 0);
assertEquals(shuffleOrder[0], windowIndex);
},
/** Tests the repeat mode 'one' */
testRepeatMode_one() {
let repeatMode;
player.addQueueItems(0, util.queue.slice(0, 3));
player.prepare();
player.addPlayerListener((state) => {
repeatMode = state.repeatMode;
});
player.setRepeatMode(Player.RepeatMode.ONE);
assertEquals(Player.RepeatMode.ONE, repeatMode);
assertEquals(0, player.getPreviousWindowIndex());
assertEquals(0, player.getNextWindowIndex());
player.seekToWindow(1, 0);
assertEquals(1, player.getPreviousWindowIndex());
assertEquals(1, player.getNextWindowIndex());
player.setShuffleModeEnabled(true);
assertEquals(1, player.getPreviousWindowIndex());
assertEquals(1, player.getNextWindowIndex());
},
/** Tests building a media item info from the manifest. */
testBuildMediaItemInfo_fromManifest() {
let mediaItemInfos = null;
player.addQueueItems(0, util.queue.slice(0, 3));
player.addPlayerListener((state) => {
mediaItemInfos = state.mediaItemsInfo;
});
player.seekToWindow(1, 0);
player.prepare();
assertUndefined(mediaItemInfos['uuid0']);
const mediaItemInfo = mediaItemInfos['uuid1'];
assertNotUndefined(mediaItemInfo);
assertFalse(mediaItemInfo.isDynamic);
assertTrue(mediaItemInfo.isSeekable);
assertEquals(0, mediaItemInfo.defaultStartPositionUs);
assertEquals(20 * 1000 * 1000, mediaItemInfo.windowDurationUs);
assertEquals(1, mediaItemInfo.periods.length);
assertEquals(20 * 1000 * 1000, mediaItemInfo.periods[0].durationUs);
},
/** Tests building a media item info with multiple periods. */
testBuildMediaItemInfo_fromManifest_multiPeriod() {
let mediaItemInfos = null;
player.addQueueItems(0, util.queue.slice(0, 3));
player.addPlayerListener((state) => {
mediaItemInfos = state.mediaItemsInfo;
});
// Setting manifest properties to emulate a multiperiod stream manifest.
mocks.state().getManifest().periods.push({startTime: 20});
mocks.state().manifestState.windowDuration = 50;
player.seekToWindow(1, 0);
player.prepare();
const mediaItemInfo = mediaItemInfos['uuid1'];
assertNotUndefined(mediaItemInfo);
assertFalse(mediaItemInfo.isDynamic);
assertTrue(mediaItemInfo.isSeekable);
assertEquals(0, mediaItemInfo.defaultStartPositionUs);
assertEquals(50 * 1000 * 1000, mediaItemInfo.windowDurationUs);
assertEquals(2, mediaItemInfo.periods.length);
assertEquals(20 * 1000 * 1000, mediaItemInfo.periods[0].durationUs);
assertEquals(30 * 1000 * 1000, mediaItemInfo.periods[1].durationUs);
},
/** Tests building a media item info from a live manifest. */
testBuildMediaItemInfo_fromManifest_live() {
let mediaItemInfos = null;
player.addQueueItems(0, util.queue.slice(0, 3));
player.addPlayerListener((state) => {
mediaItemInfos = state.mediaItemsInfo;
});
// Setting manifest properties to emulate a live stream manifest.
mocks.state().manifestState.isLive = true;
mocks.state().manifestState.windowDuration = 30;
mocks.state().manifestState.delay = 10;
mocks.state().getManifest().periods.push({startTime: 20});
player.seekToWindow(1, 0);
player.prepare();
const mediaItemInfo = mediaItemInfos['uuid1'];
assertNotUndefined(mediaItemInfo);
assertTrue(mediaItemInfo.isDynamic);
assertTrue(mediaItemInfo.isSeekable);
assertEquals(20 * 1000 * 1000, mediaItemInfo.defaultStartPositionUs);
assertEquals(20 * 1000 * 1000, mediaItemInfo.windowDurationUs);
assertEquals(2, mediaItemInfo.periods.length);
assertEquals(20 * 1000 * 1000, mediaItemInfo.periods[0].durationUs);
assertEquals(Infinity, mediaItemInfo.periods[1].durationUs);
},
/** Tests whether the shaka request filter is set for life streams. */
testRequestFilterIsSetAndRemovedForLive() {
player.addQueueItems(0, util.queue.slice(0, 3));
// Set manifest properties to emulate a live stream manifest.
mocks.state().manifestState.isLive = true;
mocks.state().manifestState.windowDuration = 30;
mocks.state().manifestState.delay = 10;
mocks.state().getManifest().periods.push({startTime: 20});
assertNull(mocks.state().responseFilter);
assertFalse(player.isManifestFilterRegistered_);
player.seekToWindow(1, 0);
player.prepare();
assertNotNull(mocks.state().responseFilter);
assertTrue(player.isManifestFilterRegistered_);
// Set manifest properties to emulate a non-live stream */
mocks.state().manifestState.isLive = false;
mocks.state().manifestState.windowDuration = 20;
mocks.state().manifestState.delay = 0;
mocks.state().getManifest().periods.push({startTime: 20});
player.seekToWindow(0, 0);
assertNull(mocks.state().responseFilter);
assertFalse(player.isManifestFilterRegistered_);
},
/** Tests whether the media info is removed when queue item is removed. */
testRemoveMediaItemInfo() {
let mediaItemInfos = null;
player.addQueueItems(0, util.queue.slice(0, 3));
player.addPlayerListener((state) => {
mediaItemInfos = state.mediaItemsInfo;
});
player.seekToWindow(1, 0);
player.prepare();
assertNotUndefined(mediaItemInfos['uuid1']);
player.removeQueueItems(['uuid1']);
assertUndefined(mediaItemInfos['uuid1']);
},
/** Tests shuffling. */
testSetShuffeModeEnabled() {
let shuffleModeEnabled = false;
player.addQueueItems(0, util.queue.slice(0, 3));
player.addPlayerListener((state) => {
shuffleModeEnabled = state.shuffleModeEnabled;
});
player.setShuffleModeEnabled(true);
assertTrue(shuffleModeEnabled);
player.setShuffleModeEnabled(false);
assertFalse(shuffleModeEnabled);
},
/** Tests setting a new playback order. */
async testSetShuffleOrder() {
const defaultOrder = [0, 1, 2];
let shuffleOrder;
player.addPlayerListener((state) => {
shuffleOrder = state.shuffleOrder;
});
await player.addQueueItems(0, util.queue.slice(0, 3), defaultOrder);
assertArrayEquals(defaultOrder, shuffleOrder);
player.setShuffleOrder_([2, 1, 0]);
assertArrayEquals([2, 1, 0], player.shuffleOrder_);
},
/** Tests setting a new playback order with incorrect length. */
async testSetShuffleOrder_incorrectLength() {
const defaultOrder = [0, 1, 2];
let shuffleOrder;
player.addPlayerListener((state) => {
shuffleOrder = state.shuffleOrder;
});
await player.addQueueItems(0, util.queue.slice(0, 3), defaultOrder);
assertArrayEquals(defaultOrder, shuffleOrder);
shuffleOrder = undefined;
player.setShuffleOrder_([2, 1]);
assertUndefined(shuffleOrder);
},
/** Tests falling into ENDED when prepared with empty queue. */
testPrepare_withEmptyQueue() {
player.seekToUuid('uuid1000', 1000);
assertEquals('uuid1000', player.uuidToPrepare_);
player.prepare();
assertEquals('ENDED', player.getPlaybackState());
assertNull(player.uuidToPrepare_);
player.seekToUuid('uuid1000', 1000);
assertNull(player.uuidToPrepare_);
},
});