🤖 Merge PR #49255 Update interceptors and ErrorData to better support error management in chromecast-caf-receiver. by @Serabe

* First pass at adding error handling.

* Move to Type map

* Fix lint

* Fix CI

* Somo more fixes
This commit is contained in:
Sergio Arbeo
2020-12-15 11:05:02 +01:00
committed by GitHub
parent 2b1c9a14df
commit b8f2db0bc4
5 changed files with 115 additions and 267 deletions

View File

@@ -18,7 +18,7 @@ export enum LoggerLevel {
INFO = 800,
WARNING = 900,
ERROR = 1000,
NONE = 1500
NONE = 1500,
}
export enum ContentProtection {
@@ -194,6 +194,47 @@ export class QueueBase {
shuffle(): messages.QueueItem[] | Promise<messages.QueueItem[]>;
}
// So we can have some auxiliary private types.
export {};
type MessageInterceptor<MessageType> =
| ((data: MessageType) => MessageType | messages.ErrorData)
| ((data: MessageType) => Promise<MessageType | messages.ErrorData>)
| ((data: MessageType) => null)
| null;
interface MessageEventToMessageTypeMap {
[messages.MessageType.CLOUD_STATUS]: messages.CloudMediaStatus;
[messages.MessageType.CUSTOM_COMMAND]: messages.CustomCommandRequestData;
[messages.MessageType.DISPLAY_STATUS]: messages.DisplayStatusRequestData;
[messages.MessageType.EDIT_AUDIO_TRACKS]: messages.EditAudioTracksRequestData;
[messages.MessageType.EDIT_TRACKS_INFO]: messages.EditTracksInfoRequestData;
[messages.MessageType.FOCUS_STATE]: messages.FocusStateRequestData;
[messages.MessageType.GET_STATUS]: messages.GetStatusRequestData;
[messages.MessageType.LOAD]: messages.LoadRequestData;
[messages.MessageType.LOAD_BY_ENTITY]: messages.LoadByEntityRequestData;
[messages.MessageType.MEDIA_STATUS]: messages.MediaStatus;
[messages.MessageType.PRECACHE]: messages.PrecacheRequestData;
[messages.MessageType.PRELOAD]: messages.PreloadRequestData;
[messages.MessageType.QUEUE_CHANGE]: messages.QueueChange;
[messages.MessageType.QUEUE_GET_ITEMS]: messages.GetItemsInfoRequestData;
[messages.MessageType.QUEUE_GET_ITEM_RANGE]: messages.FetchItemsRequestData;
[messages.MessageType.QUEUE_INSERT]: messages.QueueInsertRequestData;
[messages.MessageType.QUEUE_ITEMS]: messages.ItemsInfo;
[messages.MessageType.QUEUE_ITEM_IDS]: messages.QueueIds;
[messages.MessageType.QUEUE_LOAD]: messages.QueueLoadRequestData;
[messages.MessageType.QUEUE_REMOVE]: messages.QueueRemoveRequestData;
[messages.MessageType.QUEUE_REORDER]: messages.QueueReorderRequestData;
[messages.MessageType.QUEUE_UPDATE]: messages.QueueUpdateRequestData;
[messages.MessageType.RESUME_SESSION]: messages.ResumeSessionRequestData;
[messages.MessageType.SEEK]: messages.SeekRequestData;
[messages.MessageType.SESSION_STATE]: messages.StoreSessionRequestData;
[messages.MessageType.SET_CREDENTIALS]: messages.SetCredentialsRequestData;
[messages.MessageType.SET_PLAYBACK_RATE]: messages.SetPlaybackRateRequestData;
[messages.MessageType.SET_VOLUME]: messages.VolumeRequestData;
[messages.MessageType.STORE_SESSION]: messages.StoreSessionRequestData;
[messages.MessageType.USER_ACTION]: messages.UserActionRequestData;
}
/**
* Controls and monitors media playback.
*/
@@ -663,254 +704,11 @@ export class PlayerManager {
* provided, and no interceptor is provided for preload - the load
* interceptor will be called for preload messages.
*/
setMessageInterceptor(
type: messages.MessageType.CLOUD_STATUS,
interceptor:
| ((messageData: messages.CloudMediaStatus) => messages.CloudMediaStatus)
| ((messageData: messages.CloudMediaStatus) => Promise<messages.CloudMediaStatus>)
| ((messageData: messages.CloudMediaStatus) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.CUSTOM_COMMAND,
interceptor:
| ((messageData: messages.CustomCommandRequestData) => messages.CustomCommandRequestData)
| ((messageData: messages.CustomCommandRequestData) => Promise<messages.CustomCommandRequestData>)
| ((messageData: messages.CustomCommandRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.DISPLAY_STATUS,
interceptor:
| ((messageData: messages.DisplayStatusRequestData) => messages.DisplayStatusRequestData)
| ((messageData: messages.DisplayStatusRequestData) => Promise<messages.DisplayStatusRequestData>)
| ((messageData: messages.DisplayStatusRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.EDIT_AUDIO_TRACKS,
interceptor:
| ((messageData: messages.EditAudioTracksRequestData) => messages.EditAudioTracksRequestData)
| ((messageData: messages.EditAudioTracksRequestData) => Promise<messages.EditAudioTracksRequestData>)
| ((messageData: messages.EditAudioTracksRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.EDIT_TRACKS_INFO,
interceptor:
| ((messageData: messages.EditTracksInfoRequestData) => messages.EditTracksInfoRequestData)
| ((messageData: messages.EditTracksInfoRequestData) => Promise<messages.EditTracksInfoRequestData>)
| ((messageData: messages.EditTracksInfoRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.FOCUS_STATE,
interceptor:
| ((messageData: messages.FocusStateRequestData) => messages.FocusStateRequestData)
| ((messageData: messages.FocusStateRequestData) => Promise<messages.FocusStateRequestData>)
| ((messageData: messages.FocusStateRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.GET_STATUS,
interceptor:
| ((messageData: messages.GetStatusRequestData) => messages.GetStatusRequestData)
| ((messageData: messages.GetStatusRequestData) => Promise<messages.GetStatusRequestData>)
| ((messageData: messages.GetStatusRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.LOAD,
interceptor:
| ((messageData: messages.LoadRequestData) => messages.LoadRequestData)
| ((messageData: messages.LoadRequestData) => Promise<messages.LoadRequestData>)
| ((messageData: messages.LoadRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.LOAD_BY_ENTITY,
interceptor:
| ((messageData: messages.LoadByEntityRequestData) => messages.LoadByEntityRequestData)
| ((messageData: messages.LoadByEntityRequestData) => Promise<messages.LoadByEntityRequestData>)
| ((messageData: messages.LoadByEntityRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.MEDIA_STATUS,
interceptor:
| ((messageData: messages.MediaStatus) => messages.MediaStatus)
| ((messageData: messages.MediaStatus) => Promise<messages.MediaStatus>)
| ((messageData: messages.MediaStatus) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.PRECACHE,
interceptor:
| ((messageData: messages.PrecacheRequestData) => messages.PrecacheRequestData)
| ((messageData: messages.PrecacheRequestData) => Promise<messages.PrecacheRequestData>)
| ((messageData: messages.PrecacheRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.PRELOAD,
interceptor:
| ((messageData: messages.PreloadRequestData) => messages.PreloadRequestData)
| ((messageData: messages.PreloadRequestData) => Promise<messages.PreloadRequestData>)
| ((messageData: messages.PreloadRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.QUEUE_CHANGE,
interceptor:
| ((messageData: messages.QueueChange) => messages.QueueChange)
| ((messageData: messages.QueueChange) => Promise<messages.QueueChange>)
| ((messageData: messages.QueueChange) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.QUEUE_GET_ITEMS,
interceptor:
| ((messageData: messages.GetItemsInfoRequestData) => messages.GetItemsInfoRequestData)
| ((messageData: messages.GetItemsInfoRequestData) => Promise<messages.GetItemsInfoRequestData>)
| ((messageData: messages.GetItemsInfoRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.QUEUE_GET_ITEM_RANGE,
interceptor:
| ((messageData: messages.FetchItemsRequestData) => messages.FetchItemsRequestData)
| ((messageData: messages.FetchItemsRequestData) => Promise<messages.FetchItemsRequestData>)
| ((messageData: messages.FetchItemsRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.QUEUE_INSERT,
interceptor:
| ((messageData: messages.QueueInsertRequestData) => messages.QueueInsertRequestData)
| ((messageData: messages.QueueInsertRequestData) => Promise<messages.QueueInsertRequestData>)
| ((messageData: messages.QueueInsertRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.QUEUE_ITEMS,
interceptor:
| ((messageData: messages.ItemsInfo) => messages.ItemsInfo)
| ((messageData: messages.ItemsInfo) => Promise<messages.ItemsInfo>)
| ((messageData: messages.ItemsInfo) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.QUEUE_ITEM_IDS,
interceptor:
| ((messageData: messages.QueueIds) => messages.QueueIds)
| ((messageData: messages.QueueIds) => Promise<messages.QueueIds>)
| ((messageData: messages.QueueIds) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.QUEUE_LOAD,
interceptor:
| ((messageData: messages.QueueLoadRequestData) => messages.QueueLoadRequestData)
| ((messageData: messages.QueueLoadRequestData) => Promise<messages.QueueLoadRequestData>)
| ((messageData: messages.QueueLoadRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.QUEUE_REMOVE,
interceptor:
| ((messageData: messages.QueueRemoveRequestData) => messages.QueueRemoveRequestData)
| ((messageData: messages.QueueRemoveRequestData) => Promise<messages.QueueRemoveRequestData>)
| ((messageData: messages.QueueRemoveRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.QUEUE_REORDER,
interceptor:
| ((messageData: messages.QueueReorderRequestData) => messages.QueueReorderRequestData)
| ((messageData: messages.QueueReorderRequestData) => Promise<messages.QueueReorderRequestData>)
| ((messageData: messages.QueueReorderRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.QUEUE_UPDATE,
interceptor:
| ((messageData: messages.QueueUpdateRequestData) => messages.QueueUpdateRequestData)
| ((messageData: messages.QueueUpdateRequestData) => Promise<messages.QueueUpdateRequestData>)
| ((messageData: messages.QueueUpdateRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.RESUME_SESSION,
interceptor:
| ((messageData: messages.ResumeSessionRequestData) => messages.ResumeSessionRequestData)
| ((messageData: messages.ResumeSessionRequestData) => Promise<messages.ResumeSessionRequestData>)
| ((messageData: messages.ResumeSessionRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.SEEK,
interceptor:
| ((messageData: messages.SeekRequestData) => messages.SeekRequestData)
| ((messageData: messages.SeekRequestData) => Promise<messages.SeekRequestData>)
| ((messageData: messages.SeekRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.SESSION_STATE,
interceptor:
| ((messageData: messages.StoreSessionResponseData) => messages.StoreSessionResponseData)
| ((messageData: messages.StoreSessionResponseData) => Promise<messages.StoreSessionResponseData>)
| ((messageData: messages.StoreSessionResponseData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.SET_CREDENTIALS,
interceptor:
| ((messageData: messages.SetCredentialsRequestData) => messages.SetCredentialsRequestData)
| ((messageData: messages.SetCredentialsRequestData) => Promise<messages.SetCredentialsRequestData>)
| ((messageData: messages.SetCredentialsRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.SET_PLAYBACK_RATE,
interceptor:
| ((messageData: messages.SetPlaybackRateRequestData) => messages.SetPlaybackRateRequestData)
| ((messageData: messages.SetPlaybackRateRequestData) => Promise<messages.SetPlaybackRateRequestData>)
| ((messageData: messages.SetPlaybackRateRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.SET_VOLUME,
interceptor:
| ((messageData: messages.VolumeRequestData) => messages.VolumeRequestData)
| ((messageData: messages.VolumeRequestData) => Promise<messages.VolumeRequestData>)
| ((messageData: messages.VolumeRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.STORE_SESSION,
interceptor:
| ((messageData: messages.StoreSessionRequestData) => messages.StoreSessionRequestData)
| ((messageData: messages.StoreSessionRequestData) => Promise<messages.StoreSessionRequestData>)
| ((messageData: messages.StoreSessionRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType.USER_ACTION,
interceptor:
| ((messageData: messages.UserActionRequestData) => messages.UserActionRequestData)
| ((messageData: messages.UserActionRequestData) => Promise<messages.UserActionRequestData>)
| ((messageData: messages.UserActionRequestData) => null)
| null,
): void;
setMessageInterceptor(
type: messages.MessageType,
interceptor:
| ((messageData: messages.RequestData) => messages.RequestData)
| ((messageData: messages.RequestData) => Promise<messages.RequestData>)
| ((messageData: messages.RequestData) => null)
| null,
setMessageInterceptor<MessageEvent extends keyof MessageEventToMessageTypeMap>(
type: MessageEvent,
interceptor: MessageInterceptor<MessageEventToMessageTypeMap[MessageEvent]>,
): void;
setMessageInterceptor(type: messages.MessageType, interceptor: MessageInterceptor<messages.RequestData>): void;
/**
* Sets playback configuration on the PlayerManager.

View File

@@ -1,4 +1,11 @@
import { RequestData, MediaInformation, Track, MediaStatus, LiveSeekableRange } from './cast.framework.messages';
import {
ErrorReason,
RequestData,
MediaInformation,
Track,
MediaStatus,
LiveSeekableRange,
} from './cast.framework.messages';
import * as category from './cast.framework.events.category';
export import category = category;
@@ -429,7 +436,7 @@ export class BitrateChangedEvent extends Event {
* Event data for @see{@link EventType.ERROR} event.
*/
export class ErrorEvent extends Event {
constructor(detailedErrorCode?: DetailedErrorCode, error?: any, reason?: cast.framework.messages.ErrorReason);
constructor(detailedErrorCode?: DetailedErrorCode, error?: any, reason?: ErrorReason);
/**
* An error code representing the cause of the error.
@@ -444,7 +451,7 @@ export class ErrorEvent extends Event {
/**
* Optional error reason.
*/
reason?: cast.framework.messages.ErrorReason;
reason?: ErrorReason;
}
/**

View File

@@ -499,7 +499,7 @@ export class VastAdsRequest {
* UserAction request data.
*/
export class UserActionRequestData extends RequestData {
constructor()
constructor();
/**
* Indicate request for clearing of a user action (i.e. undo like).
@@ -740,7 +740,7 @@ export class SetPlaybackRateRequestData extends RequestData {
* SetCredentials request data.
*/
export class SetCredentialsRequestData extends RequestData {
constructor()
constructor();
/**
* Credentials to use by receiver.
@@ -1167,7 +1167,7 @@ export class QueueInsertRequestData extends RequestData {
* Represents a data message containing the full list of queue ids.
*/
export class QueueIds {
constructor()
constructor();
/**
* List of queue item ids.
@@ -1290,7 +1290,7 @@ export class QueueData {
* Represents a queue change message, such as insert, remove, and update.
*/
export class QueueChange {
constructor()
constructor();
/**
* The actual queue change type.
@@ -1347,7 +1347,7 @@ export class PrecacheRequestData extends LoadRequestData {
/**
* @param data Application precache data.
*/
constructor(data?: string)
constructor(data?: string);
/**
* Application precache data.
@@ -1857,7 +1857,7 @@ export class LiveSeekableRange {
* Represents a data message containing item information for each requested ids.
*/
export class ItemsInfo {
constructor()
constructor();
/**
* List of changed itemIds.
@@ -2022,10 +2022,22 @@ export class ErrorData {
*/
customData?: any;
/**
* Optional detailed error code from player.
*/
detailedErrorCode?: DetailedErrorCode;
/**
* The error reason.
*/
reason?: ErrorReason;
/**
* Id of the request; used to correlate request/response.
*/
requestId?: number;
type: ErrorType;
}
/**

View File

@@ -1,3 +1,4 @@
import { ApplicationData } from 'chromecast-caf-receiver/cast.framework.system';
import {
MediaMetadata,
LoadRequestData,
@@ -6,7 +7,8 @@ import {
TrackType,
MessageType,
} from 'chromecast-caf-receiver/cast.framework.messages';
import { DetailedErrorCode, EventType } from 'chromecast-caf-receiver/cast.framework.events';
import { DetailedErrorCode, EventType, MediaFinishedEvent } from 'chromecast-caf-receiver/cast.framework.events';
import { BreakManager } from 'chromecast-caf-receiver/cast.framework.breaks';
// The following test showcases how you can import individual types directly from the namespace:
@@ -44,7 +46,7 @@ pManager.addEventListener(cast.framework.events.category.FINE, () => {});
pManager.addEventListener(cast.framework.events.category.REQUEST, () => {});
pManager.addEventListener(
EventType.MEDIA_FINISHED,
(event: cast.framework.events.MediaFinishedEvent) => `${event.currentMediaTime} ${event.endedReason}`,
(event: MediaFinishedEvent) => `${event.currentMediaTime} ${event.endedReason}`,
);
// tslint:disable-next-line
const ttManager = new cast.framework.TextTracksManager();
@@ -58,7 +60,7 @@ const breakSeekData = new cast.framework.breaks.BreakSeekData(0, 100, []);
// tslint:disable-next-line
const breakClipLoadContext = new cast.framework.breaks.BreakClipLoadInterceptorContext(adBreak);
// tslint:disable-next-line
const breakManager: cast.framework.breaks.BreakManager = {
const breakManager: BreakManager = {
getBreakById: () => adBreak,
getBreakClipById: () => breakClip,
getBreakClips: () => [breakClip],
@@ -90,7 +92,7 @@ lrd.media = {
lrd.queueData = {};
// tslint:disable-next-line
const appData: cast.framework.system.ApplicationData = {
const appData: ApplicationData = {
id: () => 'id',
launchingSenderId: () => 'launch-id',
name: () => 'name',
@@ -204,3 +206,28 @@ const controls = cast.framework.ui.Controls.getInstance();
controls.assignButton(cast.framework.ui.ControlsSlot.SLOT_SECONDARY_1, cast.framework.ui.ControlsButton.LIKE);
controls.assignButton(cast.framework.ui.ControlsSlot.SLOT_SECONDARY_2, cast.framework.ui.ControlsButton.DISLIKE);
const playerManager = cast.framework.CastReceiverContext.getInstance().getPlayerManager();
playerManager.setMessageInterceptor(MessageType.CLOUD_STATUS, (messageData: messages.CloudMediaStatus):
| messages.CloudMediaStatus
| messages.ErrorData => {
if (Math.random() > 0.5) {
const errorData = new cast.framework.messages.ErrorData(cast.framework.messages.ErrorType.INVALID_REQUEST);
errorData.reason = cast.framework.messages.ErrorReason.NOT_SUPPORTED;
return errorData;
}
return messageData;
});
playerManager.setMessageInterceptor(MessageType.DISPLAY_STATUS, (messageData: messages.DisplayStatusRequestData):
| messages.DisplayStatusRequestData
| messages.ErrorData => {
if (Math.random() > 0.5) {
const errorData = new cast.framework.messages.ErrorData(cast.framework.messages.ErrorType.INVALID_REQUEST);
errorData.reason = cast.framework.messages.ErrorReason.NOT_SUPPORTED;
return errorData;
}
return messageData;
});

View File

@@ -14,8 +14,8 @@
/// <reference path="./cast.framework.system.d.ts" />
/// <reference path="./cast.framework.ui.d.ts" />
import * as debug from './cast.debug';
import * as framework from './cast.framework';
import * as debugNs from './cast.debug';
import * as frameworkNs from './cast.framework';
import { PlayerDataChangedEvent } from './cast.framework.ui';
import { Event as SystemEvent } from './cast.framework.system';
import {
@@ -41,13 +41,17 @@ import {
LiveStatusEvent,
} from './cast.framework.events';
export as namespace cast;
export { debug, framework };
export namespace cast {
const debug: typeof debugNs;
const framework: typeof frameworkNs;
}
export { debugNs as debug, frameworkNs as framework };
declare global {
const cast: {
debug: typeof debug;
framework: typeof framework;
debug: typeof debugNs;
framework: typeof frameworkNs;
};
type EventHandler = (event: Event) => void;