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

1028 lines
35 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 receiver.
*/
goog.module('exoplayer.cast.test.receiver');
goog.setTestOnly();
const ConfigurationFactory = goog.require('exoplayer.cast.ConfigurationFactory');
const MessageDispatcher = goog.require('exoplayer.cast.MessageDispatcher');
const Player = goog.require('exoplayer.cast.Player');
const Receiver = goog.require('exoplayer.cast.Receiver');
const mocks = goog.require('exoplayer.cast.test.mocks');
const testSuite = goog.require('goog.testing.testSuite');
const util = goog.require('exoplayer.cast.test.util');
/** @type {?Player|undefined} */
let player;
/** @type {!Array<!MediaItem>} */
let queue = [];
let shakaFake;
let castContextMock;
/**
* Sends a message to the receiver under test.
*
* @param {!Object} message The message to send as json.
*/
const sendMessage = function(message) {
mocks.state().customMessageListener({
data: message,
senderId: 'sender0',
});
};
/**
* Creates a valid media item with the suffix appended to each field.
*
* @param {string} suffix The suffix to append to the fields value.
* @return {!Object} The media item.
*/
const createMediaItem = function(suffix) {
return {
uuid: 'uuid' + suffix,
media: {uri: 'uri' + suffix},
mimeType: 'application/dash+xml',
};
};
let messageSequence = 0;
/**
* Creates a message in the format sent bey the sender app.
*
* @param {string} method The name of the method.
* @param {?Object} args The arguments.
* @return {!Object} The message.
*/
const createMessage = function (method, args) {
return {
method: method,
args: args,
sequenceNumber: ++messageSequence,
};
};
/**
* Asserts the `playerState` is in the same state as just after creation of the
* player.
*
* @param {!PlayerState} playerState The player state to assert.
* @param {string} playbackState The expected playback state.
*/
const assertInitialState = function(playerState, playbackState) {
assertEquals(playbackState, playerState.playbackState);
// Assert the state is in initial state.
assertArrayEquals([], queue);
assertEquals(0, playerState.windowCount);
assertEquals(0, playerState.windowIndex);
assertUndefined(playerState.playbackError);
assertNull(playerState.playbackPosition);
// Assert player properties.
assertEquals(0, player.getDurationMs());
assertArrayEquals([], Object.entries(player.mediaItemInfoMap_));
assertEquals(0, player.windowPeriodIndex_);
assertEquals(999, player.playbackType_);
assertEquals(0, player.getCurrentWindowIndex());
assertEquals(Player.DUMMY_MEDIA_ITEM_INFO, player.windowMediaItemInfo_);
};
testSuite({
setUp() {
mocks.setUp();
shakaFake = mocks.createShakaFake();
castContextMock = mocks.createCastReceiverContextFake();
player = new Player(shakaFake, new ConfigurationFactory());
player.addPlayerListener((playerState) => {
queue = playerState.mediaQueue;
});
const messageDispatcher = new MessageDispatcher(
'urn:x-cast:com.google.exoplayer.cast', castContextMock);
new Receiver(player, castContextMock, messageDispatcher);
},
tearDown() {
queue = [];
},
/** Tests whether a status was sent to the sender on connect. */
testNotifyClientConnected() {
assertUndefined(mocks.state().outputMessages['sender0']);
sendMessage(createMessage('player.onClientConnected', {}));
const message = mocks.state().outputMessages['sender0'][0];
assertEquals(messageSequence, message.sequenceNumber);
},
/**
* Tests whether a custom message listener has been registered after
* construction.
*/
testCustomMessageListener() {
assertTrue(goog.isFunction(mocks.state().customMessageListener));
},
/** Tests set playWhenReady. */
testSetPlayWhenReady() {
let playWhenReady;
player.addPlayerListener((playerState) => {
playWhenReady = playerState.playWhenReady;
});
sendMessage(createMessage(
'player.setPlayWhenReady',
{ playWhenReady: true }
));
assertTrue(playWhenReady);
sendMessage(createMessage(
'player.setPlayWhenReady',
{ playWhenReady: false }
));
assertFalse(playWhenReady);
},
/** Tests setting repeat modes. */
testSetRepeatMode() {
let repeatMode;
player.addQueueItems(0, util.queue.slice(0, 3));
player.prepare();
player.addPlayerListener((playerState) => {
repeatMode = playerState.repeatMode;
});
sendMessage(createMessage(
'player.setRepeatMode',
{ repeatMode: Player.RepeatMode.ONE }
));
assertEquals(Player.RepeatMode.ONE, repeatMode);
assertEquals(0, player.getNextWindowIndex());
assertEquals(0, player.getPreviousWindowIndex());
sendMessage(createMessage(
'player.setRepeatMode',
{ repeatMode: Player.RepeatMode.ALL }
));
assertEquals(Player.RepeatMode.ALL, repeatMode);
assertEquals(1, player.getNextWindowIndex());
assertEquals(2, player.getPreviousWindowIndex());
sendMessage(createMessage(
'player.setRepeatMode',
{ repeatMode: Player.RepeatMode.OFF }
));
assertEquals(Player.RepeatMode.OFF, repeatMode);
assertEquals(1, player.getNextWindowIndex());
assertTrue(player.getPreviousWindowIndex() < 0);
},
/** Tests setting an invalid repeat mode value. */
testSetRepeatMode_invalid_noStateChange() {
let repeatMode;
player.addPlayerListener((playerState) => {
repeatMode = playerState.repeatMode;
});
sendMessage(createMessage(
'player.setRepeatMode',
{ repeatMode: "UNKNOWN" }
));
assertEquals(Player.RepeatMode.OFF, player.repeatMode_);
assertUndefined(repeatMode);
player.invalidate();
assertEquals(Player.RepeatMode.OFF, repeatMode);
},
/** Tests enabling and disabling shuffle mode. */
testSetShuffleModeEnabled() {
const enableMessage = createMessage('player.setShuffleModeEnabled', {
shuffleModeEnabled: true,
});
const disableMessage = createMessage('player.setShuffleModeEnabled', {
shuffleModeEnabled: false,
});
let shuffleModeEnabled;
player.addPlayerListener((state) => {
shuffleModeEnabled = state.shuffleModeEnabled;
});
assertFalse(player.shuffleModeEnabled_);
sendMessage(enableMessage);
assertTrue(shuffleModeEnabled);
sendMessage(disableMessage);
assertFalse(shuffleModeEnabled);
},
/** Tests adding a single media item to the queue. */
testAddMediaItem_single() {
const suffix = '0';
const jsonMessage = createMessage('player.addItems', {
index: 0,
items: [
createMediaItem(suffix),
],
shuffleOrder: [0],
});
sendMessage(jsonMessage);
assertEquals(1, queue.length);
assertEquals('uuid0', queue[0].uuid);
assertEquals('uri0', queue[0].media.uri);
assertArrayEquals([0], player.shuffleOrder_);
},
/** Tests adding multiple media items to the queue. */
testAddMediaItem_multiple() {
const shuffleOrder = [0, 2, 1];
const jsonMessage = createMessage('player.addItems', {
index: 0,
items: [
createMediaItem('0'),
createMediaItem('1'),
createMediaItem('2'),
],
shuffleOrder: shuffleOrder,
});
sendMessage(jsonMessage);
assertArrayEquals(['uuid0', 'uuid1', 'uuid2'], queue.map((x) => x.uuid));
assertArrayEquals(shuffleOrder, player.shuffleOrder_);
},
/** Tests adding a media item to end of the queue by omitting the index. */
testAddMediaItem_noindex_addstoend() {
const shuffleOrder = [1, 3, 2, 0];
const jsonMessage = createMessage('player.addItems', {
items: [createMediaItem('99')],
shuffleOrder: shuffleOrder,
});
player.addQueueItems(0, util.queue.slice(0, 3), [0, 2, 1]);
let queue = [];
player.addPlayerListener((playerState) => {
queue = playerState.mediaQueue;
});
sendMessage(jsonMessage);
assertEquals(4, queue.length);
assertEquals('uuid99', queue[3].uuid);
assertArrayEquals(shuffleOrder, player.shuffleOrder_);
},
/** Tests adding items with a shuffle order of invalid length. */
testAddMediaItems_invalidShuffleOrderLength() {
const shuffleOrder = [1, 3, 2];
const jsonMessage = createMessage('player.addItems', {
items: [createMediaItem('99')],
shuffleOrder: shuffleOrder,
});
player.addQueueItems(0, util.queue.slice(0, 3), [0, 2, 1]);
let queue = [];
player.addPlayerListener((playerState) => {
queue = playerState.mediaQueue;
});
sendMessage(jsonMessage);
assertEquals(4, queue.length);
assertEquals('uuid99', queue[3].uuid);
assertEquals(4, player.shuffleOrder_.length);
},
/** Tests inserting a media item to the queue. */
testAddMediaItem_insert() {
const index = 1;
const shuffleOrder = [1, 0, 3, 2, 4];
const firstInsertionMessage = createMessage('player.addItems', {
index,
items: [
createMediaItem('99'),
createMediaItem('100'),
],
shuffleOrder,
});
const prepareMessage = createMessage('player.prepare', {});
const secondInsertionMessage = createMessage('player.addItems', {
index,
items: [
createMediaItem('199'),
createMediaItem('1100'),
],
shuffleOrder,
});
// fill with three items
player.addQueueItems(0, util.queue.slice(0, 3), [0, 2, 1]);
player.seekToUuid('uuid99', 0);
sendMessage(firstInsertionMessage);
// The window index does not change when IDLE.
assertEquals(1, player.getCurrentWindowIndex());
assertEquals(5, queue.length);
assertArrayEquals(shuffleOrder, player.shuffleOrder_);
util.assertUuidIndexMap(player.queueUuidIndexMap_, queue);
// Prepare sets the index by the uuid to which we seeked.
sendMessage(prepareMessage);
assertEquals(1, player.getCurrentWindowIndex());
util.assertUuidIndexMap(player.queueUuidIndexMap_, queue);
// Add two items at the current window index.
sendMessage(secondInsertionMessage);
// Current window index is adjusted.
assertEquals(3, player.getCurrentWindowIndex());
assertEquals(7, queue.length);
assertEquals('uuid199', queue[index].uuid);
assertEquals(7, player.shuffleOrder_.length);
util.assertUuidIndexMap(player.queueUuidIndexMap_, queue);
},
/** Tests adding a media item with an index larger than the queue size. */
testAddMediaItem_indexLargerThanQueueSize_addsToEnd() {
const index = 4;
const jsonMessage = createMessage('player.addItems', {
index: index,
items: [
createMediaItem('99'),
createMediaItem('100'),
],
shuffleOrder: [],
});
player.addQueueItems(0, util.queue.slice(0, 3), [0, 2, 1]);
assertArrayEquals(['uuid0', 'uuid1', 'uuid2'], queue.map((x) => x.uuid));
sendMessage(jsonMessage);
assertArrayEquals(['uuid0', 'uuid1', 'uuid2', 'uuid99', 'uuid100'],
queue.map((x) => x.uuid));
util.assertUuidIndexMap(player.queueUuidIndexMap_, queue);
},
/** Tests removing an item from the queue. */
testRemoveMediaItem() {
const jsonMessage =
createMessage('player.removeItems', {uuids: ['uuid1', 'uuid0']});
player.addQueueItems(0, util.queue.slice(0, 3), [0, 2, 1]);
assertArrayEquals(['uuid0', 'uuid1', 'uuid2'], queue.map((x) => x.uuid));
sendMessage(jsonMessage);
assertArrayEquals(['uuid2'], queue.map((x) => x.uuid));
assertArrayEquals([0], player.shuffleOrder_);
util.assertUuidIndexMap(player.queueUuidIndexMap_, queue);
},
/** Tests removing the currently playing item from the queue. */
async testRemoveMediaItem_currentItem() {
const jsonMessage =
createMessage('player.removeItems', {uuids: ['uuid1', 'uuid0']});
player.addQueueItems(0, util.queue.slice(0, 3), [0, 2, 1]);
player.seekToWindow(1, 0);
player.prepare();
await sendMessage(jsonMessage);
assertArrayEquals(['uuid2'], queue.map((x) => x.uuid));
assertEquals(0, player.getCurrentWindowIndex());
assertEquals(util.queue[2].media.uri, shakaFake.getMediaElement().src);
assertArrayEquals([0], player.shuffleOrder_);
util.assertUuidIndexMap(player.queueUuidIndexMap_, queue);
},
/** Tests removing items which affect the current window index. */
async testRemoveMediaItem_affectsWindowIndex() {
const jsonMessage =
createMessage('player.removeItems', {uuids: ['uuid1', 'uuid0']});
const currentUri = util.queue[4].media.uri;
player.addQueueItems(0, util.queue.slice(0, 6), [3, 2, 1, 4, 0, 5]);
player.prepare();
await player.seekToWindow(4, 2000);
assertEquals(currentUri, shakaFake.getMediaElement().src);
sendMessage(jsonMessage);
assertEquals(4, queue.length);
assertEquals('uuid4', queue[player.getCurrentWindowIndex()].uuid);
assertEquals(2, player.getCurrentWindowIndex());
assertEquals(currentUri, shakaFake.getMediaElement().src);
assertArrayEquals([1, 0, 2, 3], player.shuffleOrder_);
util.assertUuidIndexMap(player.queueUuidIndexMap_, queue);
},
/** Tests removing the last item of the queue. */
testRemoveMediaItem_firstItem_windowIndexIsCorrect() {
const jsonMessage =
createMessage('player.removeItems', {uuids: ['uuid0']});
player.addQueueItems(0, util.queue.slice(0, 3), [0, 2, 1]);
player.seekToWindow(1, 0);
sendMessage(jsonMessage);
assertArrayEquals(['uuid1', 'uuid2'], queue.map((x) => x.uuid));
assertEquals(0, player.getCurrentWindowIndex());
assertArrayEquals([1, 0], player.shuffleOrder_);
util.assertUuidIndexMap(player.queueUuidIndexMap_, queue);
},
/** Tests removing the last item of the queue. */
testRemoveMediaItem_lastItem_windowIndexIsCorrect() {
const jsonMessage =
createMessage('player.removeItems', {uuids: ['uuid2']});
player.addQueueItems(0, util.queue.slice(0, 3), [0, 2, 1]);
player.seekToWindow(2, 0);
player.prepare();
mocks.state().isSilent = true;
const states = [];
player.addPlayerListener((playerState) => {
states.push(playerState);
});
sendMessage(jsonMessage);
assertArrayEquals(['uuid0', 'uuid1'], queue.map((x) => x.uuid));
assertEquals(1, player.getCurrentWindowIndex());
assertArrayEquals([0, 1], player.shuffleOrder_);
assertEquals(1, states.length);
assertEquals(Player.PlaybackState.BUFFERING, states[0].playbackState);
assertEquals(
Player.DiscontinuityReason.PERIOD_TRANSITION,
states[0].playbackPosition.discontinuityReason);
assertEquals(
Player.DUMMY_MEDIA_ITEM_INFO, states[0].mediaItemsInfo['uuid1']);
util.assertUuidIndexMap(player.queueUuidIndexMap_, queue);
},
/** Tests removing items all items. */
testRemoveMediaItem_removeAll() {
const jsonMessage = createMessage('player.removeItems',
{uuids: ['uuid1', 'uuid0', 'uuid2']});
player.addQueueItems(0, util.queue.slice(0, 3));
player.seekToWindow(2, 2000);
player.prepare();
let playerState;
player.addPlayerListener((state) => {
playerState = state;
});
sendMessage(jsonMessage);
assertInitialState(playerState, 'ENDED');
assertEquals(0, player.getCurrentWindowIndex());
assertArrayEquals([], player.shuffleOrder_);
assertEquals(Player.PlaybackState.ENDED, player.getPlaybackState());
util.assertUuidIndexMap(player.queueUuidIndexMap_, []);
},
/** Tests moving an item in the queue. */
testMoveItem() {
let shuffleOrder = [0, 2, 1];
const jsonMessage = createMessage('player.moveItem', {
uuid: 'uuid2',
index: 0,
shuffleOrder: shuffleOrder,
});
player.addQueueItems(0, util.queue.slice(0, 3));
assertArrayEquals(['uuid0', 'uuid1', 'uuid2'], queue.map((x) => x.uuid));
sendMessage(jsonMessage);
assertArrayEquals(['uuid2', 'uuid0', 'uuid1'], queue.map((x) => x.uuid));
assertArrayEquals(shuffleOrder, player.shuffleOrder_);
util.assertUuidIndexMap(player.queueUuidIndexMap_, queue);
},
/** Tests moving the currently playing item in the queue. */
testMoveItem_currentWindowIndex() {
let shuffleOrder = [0, 2, 1];
const jsonMessage = createMessage('player.moveItem', {
uuid: 'uuid2',
index: 0,
shuffleOrder: shuffleOrder,
});
player.addQueueItems(0, util.queue.slice(0, 3));
player.prepare();
player.seekToUuid('uuid2', 0);
assertEquals(2, player.getCurrentWindowIndex());
assertArrayEquals(['uuid0', 'uuid1', 'uuid2'], queue.map((x) => x.uuid));
sendMessage(jsonMessage);
assertArrayEquals(['uuid2', 'uuid0', 'uuid1'], queue.map((x) => x.uuid));
assertEquals(0, player.getCurrentWindowIndex());
assertArrayEquals(shuffleOrder, player.shuffleOrder_);
util.assertUuidIndexMap(player.queueUuidIndexMap_, queue);
},
/** Tests moving an item from before to after the currently playing item. */
testMoveItem_decreaseCurrentWindowIndex() {
const jsonMessage = createMessage('player.moveItem', {
uuid: 'uuid0',
index: 5,
shuffleOrder: [],
});
player.addQueueItems(0, util.queue.slice(0, 6));
player.prepare();
player.seekToWindow(2, 0);
assertEquals(2, player.getCurrentWindowIndex());
assertArrayEquals(['uuid0', 'uuid1', 'uuid2', 'uuid3', 'uuid4', 'uuid5'],
queue.map((x) => x.uuid));
sendMessage(jsonMessage);
assertArrayEquals(['uuid1', 'uuid2', 'uuid3', 'uuid4', 'uuid5', 'uuid0'],
queue.map((x) => x.uuid));
assertEquals(1, player.getCurrentWindowIndex());
util.assertUuidIndexMap(player.queueUuidIndexMap_, queue);
},
/** Tests moving an item from after to before the currently playing item. */
testMoveItem_increaseCurrentWindowIndex() {
const jsonMessage = createMessage('player.moveItem', {
uuid: 'uuid5',
index: 0,
shuffleOrder: [],
});
player.addQueueItems(0, util.queue.slice(0, 6));
player.prepare();
player.seekToWindow(2, 0);
assertEquals(2, player.getCurrentWindowIndex());
assertArrayEquals(['uuid0', 'uuid1', 'uuid2', 'uuid3', 'uuid4', 'uuid5'],
queue.map((x) => x.uuid));
sendMessage(jsonMessage);
assertArrayEquals(['uuid5', 'uuid0', 'uuid1', 'uuid2', 'uuid3', 'uuid4'],
queue.map((x) => x.uuid));
assertEquals(3, player.getCurrentWindowIndex());
util.assertUuidIndexMap(player.queueUuidIndexMap_, queue);
},
/** Tests moving an item from after to the current window index. */
testMoveItem_toCurrentWindowIndex_fromAfter() {
const jsonMessage = createMessage('player.moveItem', {
uuid: 'uuid5',
index: 2,
shuffleOrder: [],
});
player.addQueueItems(0, util.queue.slice(0, 6));
player.prepare();
player.seekToWindow(2, 0);
assertEquals(2, player.getCurrentWindowIndex());
assertArrayEquals(['uuid0', 'uuid1', 'uuid2', 'uuid3', 'uuid4', 'uuid5'],
queue.map((x) => x.uuid));
sendMessage(jsonMessage);
assertArrayEquals(['uuid0', 'uuid1', 'uuid5', 'uuid2', 'uuid3', 'uuid4'],
queue.map((x) => x.uuid));
assertEquals(3, player.getCurrentWindowIndex());
util.assertUuidIndexMap(player.queueUuidIndexMap_, queue);
},
/** Tests moving an item from before to the current window index. */
testMoveItem_toCurrentWindowIndex_fromBefore() {
const jsonMessage = createMessage('player.moveItem', {
uuid: 'uuid0',
index: 2,
shuffleOrder: [],
});
player.addQueueItems(0, util.queue.slice(0, 6));
player.prepare();
player.seekToWindow(2, 0);
assertEquals(2, player.getCurrentWindowIndex());
assertArrayEquals(['uuid0', 'uuid1', 'uuid2', 'uuid3', 'uuid4', 'uuid5'],
queue.map((x) => x.uuid));
sendMessage(jsonMessage);
assertArrayEquals(['uuid1', 'uuid2', 'uuid0', 'uuid3', 'uuid4', 'uuid5'],
queue.map((x) => x.uuid));
assertEquals(1, player.getCurrentWindowIndex());
util.assertUuidIndexMap(player.queueUuidIndexMap_, queue);
},
/** Tests seekTo. */
testSeekTo() {
const jsonMessage = createMessage('player.seekTo',
{
'uuid': 'uuid1',
'positionMs': 2000
});
player.addQueueItems(0, util.queue.slice(0, 3));
player.prepare();
sendMessage(jsonMessage);
assertEquals(2000, player.getCurrentPositionMs());
assertEquals(1, player.getCurrentWindowIndex());
},
/** Tests seekTo to unknown uuid. */
testSeekTo_unknownUuid() {
const jsonMessage = createMessage('player.seekTo',
{
'uuid': 'unknown',
});
player.addQueueItems(0, util.queue.slice(0, 3));
player.prepare();
player.seekToWindow(1, 2000);
assertEquals(2000, player.getCurrentPositionMs());
assertEquals(1, player.getCurrentWindowIndex());
sendMessage(jsonMessage);
assertEquals(2000, player.getCurrentPositionMs());
assertEquals(1, player.getCurrentWindowIndex());
},
/** Tests seekTo without position. */
testSeekTo_noPosition_defaultsToZero() {
const jsonMessage = createMessage('player.seekTo',
{
'uuid': 'uuid1',
});
player.addQueueItems(0, util.queue.slice(0, 3));
player.prepare();
sendMessage(jsonMessage);
assertEquals(0, player.getCurrentPositionMs());
assertEquals(1, player.getCurrentWindowIndex());
},
/** Tests seekTo to negative position. */
testSeekTo_negativePosition_defaultsToZero() {
const jsonMessage = createMessage('player.seekTo',
{
'uuid': 'uuid2',
'positionMs': -1,
});
player.addQueueItems(0, util.queue.slice(0, 3));
player.prepare();
player.seekToWindow(1, 2000);
assertEquals(2000, player.getCurrentPositionMs());
assertEquals(1, player.getCurrentWindowIndex());
sendMessage(jsonMessage);
assertEquals(0, player.getCurrentPositionMs());
assertEquals(2, player.getCurrentWindowIndex());
},
/** Tests whether validation is turned on. */
testMediaItemValidation_isOn() {
const index = 0;
const mediaItem = createMediaItem('99');
delete mediaItem.uuid;
const jsonMessage = createMessage('player.addItems', {
index: index,
items: [mediaItem],
shuffleOrder: [],
});
sendMessage(jsonMessage);
assertEquals(0, queue.length);
},
/** Tests whether the state is sent to sender apps on state transition. */
testPlayerStateIsSent_withCorrectSequenceNumber() {
assertUndefined(mocks.state().outputMessages['sender0']);
const playMessage =
createMessage('player.setPlayWhenReady', {playWhenReady: true});
sendMessage(playMessage);
const playerState = mocks.state().outputMessages['sender0'][0];
assertTrue(playerState.playWhenReady);
assertEquals(playMessage.sequenceNumber, playerState.sequenceNumber);
},
/** Tests whether a connect of a sender app sends the current player state. */
testSenderConnection() {
const onSenderConnected = mocks.state().onSenderConnected;
assertTrue(goog.isFunction(onSenderConnected));
onSenderConnected({senderId: 'sender0'});
const playerState = mocks.state().outputMessages['sender0'][0];
assertEquals(Player.RepeatMode.OFF, playerState.repeatMode);
assertEquals('IDLE', playerState.playbackState);
assertArrayEquals([], playerState.mediaQueue);
assertEquals(-1, playerState.sequenceNumber);
},
/** Tests whether a disconnect of a sender notifies the message dispatcher. */
testSenderDisconnection_callsMessageDispatcher() {
mocks.setUp();
let notifiedSenderId;
const myPlayer = new Player(mocks.createShakaFake());
const myManagerFake = mocks.createCastReceiverContextFake();
new Receiver(myPlayer, myManagerFake, {
registerActionHandler() {},
notifySenderDisconnected(senderId) {
notifiedSenderId = senderId;
},
});
const onSenderDisconnected = mocks.state().onSenderDisconnected;
assertTrue(goog.isFunction(onSenderDisconnected));
onSenderDisconnected({senderId: 'sender0'});
assertEquals('sender0', notifiedSenderId);
},
/**
* Tests whether the state right after creation of the player matches
* expectations.
*/
testInitialState() {
mocks.state().isSilent = true;
let playerState;
player.addPlayerListener((state) => {
playerState = state;
});
assertEquals(0, player.getCurrentPositionMs());
// Dump a player state to the listener.
player.invalidate();
// Asserts the state just after creation.
assertInitialState(playerState, 'IDLE');
},
/** Tests whether user properties can be changed when in IDLE state */
testChangingUserPropertiesWhenIdle() {
mocks.state().isSilent = true;
const states = [];
let counter = 0;
player.addPlayerListener((state) => {
states.push(state);
});
// Adding items when IDLE.
player.addQueueItems(0, util.queue.slice(0, 3));
counter++;
assertEquals(counter, states.length);
assertEquals(Player.PlaybackState.IDLE, states[counter - 1].playbackState);
assertArrayEquals(
['uuid0', 'uuid1', 'uuid2'],
states[counter - 1].mediaQueue.map((i) => i.uuid));
// Set playWhenReady when IDLE.
assertFalse(player.getPlayWhenReady());
player.setPlayWhenReady(true);
counter++;
assertTrue(player.getPlayWhenReady());
assertEquals(counter, states.length);
assertEquals(Player.PlaybackState.IDLE, states[counter - 1].playbackState);
// Seeking when IDLE.
player.seekToUuid('uuid2', 1000);
counter++;
// Window index not set when idle.
assertEquals(2, player.getCurrentWindowIndex());
assertEquals(1000, player.getCurrentPositionMs());
assertEquals(counter, states.length);
assertEquals(Player.PlaybackState.IDLE, states[counter - 1].playbackState);
// But window index is set when prepared.
player.prepare();
assertEquals(2, player.getCurrentWindowIndex());
},
/** Tests the state after calling prepare. */
testPrepare() {
mocks.state().isSilent = true;
const states = [];
let counter = 0;
player.addPlayerListener((state) => {
states.push(state);
});
const prepareMessage = createMessage('player.prepare', {});
player.addQueueItems(0, util.queue.slice(0, 3));
player.seekToWindow(1, 1000);
counter += 2;
// Sends prepare message.
sendMessage(prepareMessage);
counter++;
assertEquals(counter, states.length);
assertEquals('uuid1', states[counter - 1].playbackPosition.uuid);
assertEquals(
Player.PlaybackState.BUFFERING, states[counter - 1].playbackState);
// Fakes Shaka events.
mocks.state().isSilent = false;
mocks.notifyListeners('streaming');
mocks.notifyListeners('loadeddata');
counter += 2;
assertEquals(counter, states.length);
assertEquals(Player.PlaybackState.READY, states[counter - 1].playbackState);
},
/** Tests stopping the player with `reset=true`. */
testStop_resetTrue() {
mocks.state().isSilent = true;
let playerState;
player.addPlayerListener((state) => {
playerState = state;
});
const stopMessage = createMessage('player.stop', {reset: true});
player.setRepeatMode(Player.RepeatMode.ALL);
player.setShuffleModeEnabled(true);
player.setPlayWhenReady(true);
player.addQueueItems(0, util.queue.slice(0, 3));
player.prepare();
mocks.state().isSilent = false;
mocks.notifyListeners('loadeddata');
assertArrayEquals(['uuid0', 'uuid1', 'uuid2'], queue.map((i) => i.uuid));
assertEquals(0, playerState.windowIndex);
assertNotEquals(Player.DUMMY_MEDIA_ITEM_INFO, player.windowMediaItemInfo_);
assertEquals(1, player.playbackType_);
// Stop the player.
sendMessage(stopMessage);
// Asserts the state looks the same as just after creation.
assertInitialState(playerState, 'IDLE');
assertNull(playerState.playbackPosition);
// Assert player properties are preserved.
assertTrue(playerState.shuffleModeEnabled);
assertTrue(playerState.playWhenReady);
assertEquals(Player.RepeatMode.ALL, playerState.repeatMode);
},
/** Tests stopping the player with `reset=false`. */
testStop_resetFalse() {
mocks.state().isSilent = true;
let playerState;
player.addPlayerListener((state) => {
playerState = state;
});
const stopMessage = createMessage('player.stop', {reset: false});
player.addQueueItems(0, util.queue.slice(0, 3));
player.prepare();
player.seekToUuid('uuid1', 1000);
mocks.state().isSilent = false;
mocks.notifyListeners('streaming');
mocks.notifyListeners('trackschanged');
mocks.notifyListeners('loadeddata');
assertArrayEquals(['uuid0', 'uuid1', 'uuid2'], queue.map((i) => i.uuid));
assertEquals(1, playerState.windowIndex);
assertNotEquals(Player.DUMMY_MEDIA_ITEM_INFO, player.windowMediaItemInfo_);
assertEquals(2, player.playbackType_);
// Stop the player.
sendMessage(stopMessage);
assertEquals('IDLE', playerState.playbackState);
assertUndefined(playerState.playbackError);
// Assert the timeline is preserved.
assertEquals(3, queue.length);
assertEquals(3, playerState.windowCount);
assertEquals(1, player.windowIndex_);
assertEquals(1, playerState.windowIndex);
// Assert the playback position is correct.
assertEquals(1000, playerState.playbackPosition.positionMs);
assertEquals('uuid1', playerState.playbackPosition.uuid);
assertEquals(0, playerState.playbackPosition.periodId);
assertNull(playerState.playbackPosition.discontinuityReason);
assertEquals(1000, player.getCurrentPositionMs());
// Assert player properties are preserved.
assertEquals(20000, player.getDurationMs());
assertEquals(2, Object.entries(player.mediaItemInfoMap_).length);
assertEquals(0, player.windowPeriodIndex_);
assertEquals(1, player.getCurrentWindowIndex());
assertEquals(1, player.windowIndex_);
assertNotEquals(Player.DUMMY_MEDIA_ITEM_INFO, player.windowMediaItemInfo_);
assertEquals(999, player.playbackType_);
assertEquals('uuid1', player.uuidToPrepare_);
},
/**
* Tests the state after having removed the last item in the queue. This
* resolves to the same state like calling `stop(true)` except that the state
* is ENDED and the queue is naturally empty and hence the windowIndex is
* unset.
*/
testRemoveLastQueueItem() {
mocks.state().isSilent = true;
let playerState;
player.addPlayerListener((state) => {
playerState = state;
});
const removeAllItemsMessage = createMessage(
'player.removeItems', {uuids: ['uuid0', 'uuid1', 'uuid2']});
player.addQueueItems(0, util.queue.slice(0, 3));
player.seekToWindow(0, 1000);
player.prepare();
mocks.state().isSilent = false;
mocks.notifyListeners('loadeddata');
// Remove all items.
sendMessage(removeAllItemsMessage);
// Assert the state after removal of all items.
assertInitialState(playerState, 'ENDED');
},
/** Tests whether a player state is sent when no item is added. */
testAddItem_noop() {
mocks.state().isSilent = true;
let playerStates = [];
player.addPlayerListener((state) => {
playerStates.push(state);
});
const noOpMessage = createMessage('player.addItems', {
index: 0,
items: [
util.queue[0],
],
shuffleOrder: [0],
});
player.addQueueItems(0, [util.queue[0]], []);
player.prepare();
assertEquals(2, playerStates.length);
assertEquals(2, mocks.state().outputMessages['sender0'].length);
sendMessage(noOpMessage);
assertEquals(2, playerStates.length);
assertEquals(3, mocks.state().outputMessages['sender0'].length);
},
/** Tests whether a player state is sent when no item is removed. */
testRemoveItem_noop() {
mocks.state().isSilent = true;
let playerStates = [];
player.addPlayerListener((state) => {
playerStates.push(state);
});
const noOpMessage =
createMessage('player.removeItems', {uuids: ['uuid00']});
player.addQueueItems(0, util.queue.slice(0, 3));
player.prepare();
assertEquals(2, playerStates.length);
assertEquals(2, mocks.state().outputMessages['sender0'].length);
sendMessage(noOpMessage);
assertEquals(2, playerStates.length);
assertEquals(3, mocks.state().outputMessages['sender0'].length);
},
/** Tests whether a player state is sent when item is not moved. */
testMoveItem_noop() {
mocks.state().isSilent = true;
let playerStates = [];
player.addPlayerListener((state) => {
playerStates.push(state);
});
const noOpMessage = createMessage('player.moveItem', {
uuid: 'uuid00',
index: 0,
shuffleOrder: [],
});
player.addQueueItems(0, util.queue.slice(0, 3));
player.prepare();
assertEquals(2, playerStates.length);
assertEquals(2, mocks.state().outputMessages['sender0'].length);
sendMessage(noOpMessage);
assertEquals(2, playerStates.length);
assertEquals(3, mocks.state().outputMessages['sender0'].length);
},
/** Tests whether playback actions send a state when no-op */
testNoOpPlaybackActionsSendPlayerState() {
mocks.state().isSilent = true;
let playerStates = [];
let parsedMessage;
player.addPlayerListener((state) => {
playerStates.push(state);
});
player.addQueueItems(0, util.queue.slice(0, 3));
player.prepare();
const outputMessages = mocks.state().outputMessages['sender0'];
const setupMessageCount = playerStates.length;
let totalMessageCount = setupMessageCount;
assertEquals(setupMessageCount, playerStates.length);
assertEquals(totalMessageCount, outputMessages.length);
const firstNoOpMessage = createMessage('player.setPlayWhenReady', {
playWhenReady: false,
});
let expectedSequenceNumber = firstNoOpMessage.sequenceNumber;
sendMessage(firstNoOpMessage);
totalMessageCount++;
assertEquals(setupMessageCount, playerStates.length);
assertEquals(totalMessageCount, outputMessages.length);
parsedMessage = outputMessages[totalMessageCount - 1];
assertEquals(expectedSequenceNumber++, parsedMessage.sequenceNumber);
sendMessage(createMessage('player.setRepeatMode', {
repeatMode: 'OFF',
}));
totalMessageCount++;
assertEquals(setupMessageCount, playerStates.length);
assertEquals(totalMessageCount, outputMessages.length);
parsedMessage = outputMessages[totalMessageCount - 1];
assertEquals(expectedSequenceNumber++, parsedMessage.sequenceNumber);
sendMessage(createMessage('player.setShuffleModeEnabled', {
shuffleModeEnabled: false,
}));
totalMessageCount++;
assertEquals(setupMessageCount, playerStates.length);
assertEquals(totalMessageCount, outputMessages.length);
parsedMessage = outputMessages[totalMessageCount - 1];
assertEquals(expectedSequenceNumber++, parsedMessage.sequenceNumber);
sendMessage(createMessage('player.seekTo', {
uuid: 'not_existing',
positionMs: 0,
}));
totalMessageCount++;
assertEquals(setupMessageCount, playerStates.length);
assertEquals(totalMessageCount, outputMessages.length);
parsedMessage = outputMessages[totalMessageCount - 1];
assertEquals(expectedSequenceNumber++, parsedMessage.sequenceNumber);
},
});