mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-12 10:39:57 +00:00
Minor media session tweaks
This commit is contained in:
@@ -23,8 +23,8 @@ import {
|
|||||||
import type { LoadRequest, QueueLoadRequest, QueueItem } from "./media/classes";
|
import type { LoadRequest, QueueLoadRequest, QueueItem } from "./media/classes";
|
||||||
import Media, {
|
import Media, {
|
||||||
createMedia,
|
createMedia,
|
||||||
MediaLastUpdateTimes,
|
mediaLastUpdateTimes,
|
||||||
MediaUpdateListeners,
|
mediaUpdateListeners,
|
||||||
NS_MEDIA
|
NS_MEDIA
|
||||||
} from "./media/Media";
|
} from "./media/Media";
|
||||||
|
|
||||||
@@ -36,10 +36,11 @@ const logger = new Logger("fx_cast [sdk :: cast.Session]");
|
|||||||
*/
|
*/
|
||||||
export function updateMedia(media: Media, status: MediaStatus) {
|
export function updateMedia(media: Media, status: MediaStatus) {
|
||||||
if (status.currentTime) {
|
if (status.currentTime) {
|
||||||
MediaLastUpdateTimes.set(media, Date.now());
|
mediaLastUpdateTimes.set(media, Date.now());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy basic props
|
// Copy basic props
|
||||||
|
if (status.breakStatus) media.breakStatus = status.breakStatus;
|
||||||
if (status.currentTime) media.currentTime = status.currentTime;
|
if (status.currentTime) media.currentTime = status.currentTime;
|
||||||
if (status.customData) media.customData = status.customData;
|
if (status.customData) media.customData = status.customData;
|
||||||
if (status.idleReason) media.idleReason = status.idleReason;
|
if (status.idleReason) media.idleReason = status.idleReason;
|
||||||
@@ -87,20 +88,20 @@ export function updateMedia(media: Media, status: MediaStatus) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SessionMessageListeners = new WeakMap<
|
export const sessionMessageListeners = new WeakMap<
|
||||||
Session,
|
Session,
|
||||||
Map<string, Set<MessageListener>>
|
Map<string, Set<MessageListener>>
|
||||||
>();
|
>();
|
||||||
export const SessionUpdateListeners = new WeakMap<
|
export const sessionUpdateListeners = new WeakMap<
|
||||||
Session,
|
Session,
|
||||||
Set<UpdateListener>
|
Set<UpdateListener>
|
||||||
>();
|
>();
|
||||||
export const SessionSendMessageCallbacks = new WeakMap<
|
export const sessionSendMessageCallbacks = new WeakMap<
|
||||||
Session,
|
Session,
|
||||||
Map<string, SendMessageCallback>
|
Map<string, SendMessageCallback>
|
||||||
>();
|
>();
|
||||||
|
|
||||||
export const SessionLeaveSuccessCallback = new WeakMap<
|
export const sessionLeaveSuccessCallback = new WeakMap<
|
||||||
Session,
|
Session,
|
||||||
Optional<() => void>
|
Optional<() => void>
|
||||||
>();
|
>();
|
||||||
@@ -108,24 +109,58 @@ export const SessionLeaveSuccessCallback = new WeakMap<
|
|||||||
type SendMediaMessage = (
|
type SendMediaMessage = (
|
||||||
message: DistributiveOmit<SenderMediaMessage, "requestId">
|
message: DistributiveOmit<SenderMediaMessage, "requestId">
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
export const SessionSendMediaMessage = new WeakMap<Session, SendMediaMessage>();
|
export const sessionSendMediaMessage = new WeakMap<Session, SendMediaMessage>();
|
||||||
|
|
||||||
|
interface MediaRequest {
|
||||||
|
successCallback: () => void;
|
||||||
|
errorCallback: (error: CastError) => void;
|
||||||
|
message: SenderMediaMessage;
|
||||||
|
requestId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sessionMediaRequests = new WeakMap<Session, Map<number, MediaRequest>>();
|
||||||
|
|
||||||
/** Creates a Session object and initializes private data. */
|
/** Creates a Session object and initializes private data. */
|
||||||
export function createSession(
|
export function createSession(
|
||||||
sessionArgs: ConstructorParameters<typeof Session>
|
sessionArgs: ConstructorParameters<typeof Session>
|
||||||
) {
|
) {
|
||||||
const session = new Session(...sessionArgs);
|
const session = new Session(...sessionArgs);
|
||||||
SessionUpdateListeners.set(session, new Set());
|
sessionUpdateListeners.set(session, new Set());
|
||||||
SessionSendMessageCallbacks.set(session, new Map());
|
sessionSendMessageCallbacks.set(session, new Map());
|
||||||
|
|
||||||
SessionSendMediaMessage.set(session, message => {
|
// Record of pending media requests
|
||||||
|
// FIXME: Handle request timeouts
|
||||||
|
const mediaRequests = new Map<number, MediaRequest>();
|
||||||
|
sessionMediaRequests.set(session, mediaRequests);
|
||||||
|
|
||||||
|
// Current media request ID
|
||||||
|
let mediaRequestId = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores callbacks for request response, then adds current request
|
||||||
|
* ID to the message and sends it.
|
||||||
|
*/
|
||||||
|
sessionSendMediaMessage.set(session, message => {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
session.sendMessage(
|
const requestId = mediaRequestId++;
|
||||||
NS_MEDIA,
|
const request: MediaRequest = {
|
||||||
{ ...message, requestId: 0 },
|
successCallback: () => {
|
||||||
resolve,
|
mediaRequests.delete(requestId);
|
||||||
reject
|
resolve();
|
||||||
);
|
},
|
||||||
|
errorCallback: () => {
|
||||||
|
mediaRequests.delete(requestId);
|
||||||
|
reject();
|
||||||
|
},
|
||||||
|
message: { ...message, requestId },
|
||||||
|
requestId
|
||||||
|
};
|
||||||
|
|
||||||
|
mediaRequests.set(request.requestId, request);
|
||||||
|
session.sendMessage(NS_MEDIA, request.message, undefined, () => {
|
||||||
|
mediaRequests.delete(requestId);
|
||||||
|
reject();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -142,36 +177,43 @@ export default class Session {
|
|||||||
#loadMediaErrorCallback?: (err: CastError) => void;
|
#loadMediaErrorCallback?: (err: CastError) => void;
|
||||||
|
|
||||||
get #messageListeners() {
|
get #messageListeners() {
|
||||||
const messageListeners = SessionMessageListeners.get(this);
|
const messageListeners = sessionMessageListeners.get(this);
|
||||||
if (!messageListeners)
|
if (!messageListeners)
|
||||||
throw logger.error("Missing session message listeners!");
|
throw logger.error("Missing session message listeners!");
|
||||||
return messageListeners;
|
return messageListeners;
|
||||||
}
|
}
|
||||||
get #updateListeners() {
|
get #updateListeners() {
|
||||||
const updateListeners = SessionUpdateListeners.get(this);
|
const updateListeners = sessionUpdateListeners.get(this);
|
||||||
if (!updateListeners)
|
if (!updateListeners)
|
||||||
throw logger.error("Missing session update listeners!");
|
throw logger.error("Missing session update listeners!");
|
||||||
return updateListeners;
|
return updateListeners;
|
||||||
}
|
}
|
||||||
get #sendMessageCallbacks() {
|
get #sendMessageCallbacks() {
|
||||||
const sendMessageCallback = SessionSendMessageCallbacks.get(this);
|
const sendMessageCallback = sessionSendMessageCallbacks.get(this);
|
||||||
if (!sendMessageCallback)
|
if (!sendMessageCallback)
|
||||||
throw logger.error("Missing session sendMessage callback!");
|
throw logger.error("Missing session sendMessage callback!");
|
||||||
return sendMessageCallback;
|
return sendMessageCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
get #sendMediaMessage() {
|
get #sendMediaMessage() {
|
||||||
const sendMediaMessage = SessionSendMediaMessage.get(this);
|
const sendMediaMessage = sessionSendMediaMessage.get(this);
|
||||||
if (!sendMediaMessage)
|
if (!sendMediaMessage)
|
||||||
throw logger.error("Missing send media message function!");
|
throw logger.error("Missing send media message function!");
|
||||||
return sendMediaMessage;
|
return sendMediaMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get #mediaRequests() {
|
||||||
|
const mediaRequests = sessionMediaRequests.get(this);
|
||||||
|
if (!mediaRequests)
|
||||||
|
throw logger.error("Missing session media requests!");
|
||||||
|
return mediaRequests;
|
||||||
|
}
|
||||||
|
|
||||||
get #leaveSuccessCallback() {
|
get #leaveSuccessCallback() {
|
||||||
return SessionLeaveSuccessCallback.get(this);
|
return sessionLeaveSuccessCallback.get(this);
|
||||||
}
|
}
|
||||||
set #leaveSuccessCallback(successCallback: Optional<() => void>) {
|
set #leaveSuccessCallback(successCallback: Optional<() => void>) {
|
||||||
SessionLeaveSuccessCallback.set(this, successCallback);
|
sessionLeaveSuccessCallback.set(this, successCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
media: Media[] = [];
|
media: Media[] = [];
|
||||||
@@ -190,42 +232,48 @@ export default class Session {
|
|||||||
) {
|
) {
|
||||||
this.transportId = sessionId || "";
|
this.transportId = sessionId || "";
|
||||||
|
|
||||||
SessionMessageListeners.set(this, new Map());
|
sessionMessageListeners.set(this, new Map());
|
||||||
this.addMessageListener(NS_MEDIA, this.#mediaMessageListener);
|
this.addMessageListener(NS_MEDIA, this.#mediaMessageListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
#mediaMessageListener = (namespace: string, messageString: string) => {
|
#mediaMessageListener = (namespace: string, messageString: string) => {
|
||||||
if (namespace !== NS_MEDIA) return;
|
if (namespace !== NS_MEDIA) return;
|
||||||
|
|
||||||
const message: ReceiverMediaMessage = JSON.parse(messageString);
|
const message: ReceiverMediaMessage = JSON.parse(messageString);
|
||||||
switch (message.type) {
|
if (message.type !== "MEDIA_STATUS") return;
|
||||||
case "MEDIA_STATUS": {
|
|
||||||
// Update media
|
|
||||||
for (const mediaStatus of message.status) {
|
|
||||||
let media = this.media.find(
|
|
||||||
media =>
|
|
||||||
media.mediaSessionId === mediaStatus.mediaSessionId
|
|
||||||
);
|
|
||||||
|
|
||||||
// Handle Media creation
|
for (const status of message.status) {
|
||||||
if (!media) {
|
let media = this.media.find(
|
||||||
media = createMedia(
|
media => media.mediaSessionId === status.mediaSessionId
|
||||||
[this.sessionId, mediaStatus.mediaSessionId],
|
);
|
||||||
this.#sendMediaMessage
|
|
||||||
);
|
|
||||||
|
|
||||||
this.media.push(media);
|
if (!media) {
|
||||||
updateMedia(media, mediaStatus);
|
media = createMedia(
|
||||||
this.#loadMediaSuccessCallback?.(media);
|
[this.sessionId, status.mediaSessionId],
|
||||||
} else {
|
this.#sendMediaMessage
|
||||||
updateMedia(media, mediaStatus);
|
);
|
||||||
const updateListeners = MediaUpdateListeners.get(media);
|
updateMedia(media, status);
|
||||||
if (updateListeners) {
|
this.media.push(media);
|
||||||
for (const listener of updateListeners) {
|
} else {
|
||||||
listener(true);
|
updateMedia(media, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Handle media request responses
|
||||||
|
const mediaRequest = this.#mediaRequests.get(message.requestId);
|
||||||
|
if (mediaRequest) {
|
||||||
|
mediaRequest.successCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const status of message.status) {
|
||||||
|
const media = this.media.find(
|
||||||
|
media => media.mediaSessionId === status.mediaSessionId
|
||||||
|
);
|
||||||
|
if (!media) continue;
|
||||||
|
|
||||||
|
const updateListeners = mediaUpdateListeners.get(media);
|
||||||
|
if (updateListeners) {
|
||||||
|
for (const listener of updateListeners) {
|
||||||
|
listener(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,7 +355,11 @@ export default class Session {
|
|||||||
this.#loadMediaErrorCallback = errorCallback;
|
this.#loadMediaErrorCallback = errorCallback;
|
||||||
|
|
||||||
loadRequest.sessionId = this.sessionId;
|
loadRequest.sessionId = this.sessionId;
|
||||||
this.#sendMediaMessage(loadRequest).catch(errorCallback);
|
this.#sendMediaMessage(loadRequest)
|
||||||
|
.then(() => {
|
||||||
|
successCallback?.(this.media[this.media.length - 1]);
|
||||||
|
})
|
||||||
|
.catch(errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
queueLoad(
|
queueLoad(
|
||||||
|
|||||||
@@ -33,11 +33,11 @@ import {
|
|||||||
|
|
||||||
import Session, {
|
import Session, {
|
||||||
createSession,
|
createSession,
|
||||||
SessionLeaveSuccessCallback,
|
sessionLeaveSuccessCallback,
|
||||||
SessionMessageListeners,
|
sessionMessageListeners,
|
||||||
SessionSendMediaMessage,
|
sessionSendMediaMessage,
|
||||||
SessionSendMessageCallbacks,
|
sessionSendMessageCallbacks,
|
||||||
SessionUpdateListeners,
|
sessionUpdateListeners,
|
||||||
updateMedia
|
updateMedia
|
||||||
} from "./Session";
|
} from "./Session";
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ export default class {
|
|||||||
const media = createMedia(
|
const media = createMedia(
|
||||||
[status.sessionId, status.media.mediaSessionId],
|
[status.sessionId, status.media.mediaSessionId],
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
SessionSendMediaMessage.get(session)!
|
sessionSendMediaMessage.get(session)!
|
||||||
);
|
);
|
||||||
updateMedia(media, status.media);
|
updateMedia(media, status.media);
|
||||||
session.media = [media];
|
session.media = [media];
|
||||||
@@ -223,7 +223,7 @@ export default class {
|
|||||||
session.namespaces = status.namespaces;
|
session.namespaces = status.namespaces;
|
||||||
session.receiver.volume = status.volume;
|
session.receiver.volume = status.volume;
|
||||||
|
|
||||||
const updateListeners = SessionUpdateListeners.get(session);
|
const updateListeners = sessionUpdateListeners.get(session);
|
||||||
if (updateListeners) {
|
if (updateListeners) {
|
||||||
for (const listener of updateListeners) {
|
for (const listener of updateListeners) {
|
||||||
listener(session.status !== SessionStatus.STOPPED);
|
listener(session.status !== SessionStatus.STOPPED);
|
||||||
@@ -238,7 +238,7 @@ export default class {
|
|||||||
if (session?.status === SessionStatus.CONNECTED) {
|
if (session?.status === SessionStatus.CONNECTED) {
|
||||||
session.status = SessionStatus.STOPPED;
|
session.status = SessionStatus.STOPPED;
|
||||||
|
|
||||||
const updateListeners = SessionUpdateListeners.get(session);
|
const updateListeners = sessionUpdateListeners.get(session);
|
||||||
if (updateListeners) {
|
if (updateListeners) {
|
||||||
for (const listener of updateListeners) {
|
for (const listener of updateListeners) {
|
||||||
listener(false);
|
listener(false);
|
||||||
@@ -254,9 +254,9 @@ export default class {
|
|||||||
if (session?.status === SessionStatus.CONNECTED) {
|
if (session?.status === SessionStatus.CONNECTED) {
|
||||||
session.status = SessionStatus.DISCONNECTED;
|
session.status = SessionStatus.DISCONNECTED;
|
||||||
|
|
||||||
SessionLeaveSuccessCallback.get(session)?.();
|
sessionLeaveSuccessCallback.get(session)?.();
|
||||||
|
|
||||||
const updateListeners = SessionUpdateListeners.get(session);
|
const updateListeners = sessionUpdateListeners.get(session);
|
||||||
if (updateListeners) {
|
if (updateListeners) {
|
||||||
for (const listener of updateListeners) {
|
for (const listener of updateListeners) {
|
||||||
listener(true);
|
listener(true);
|
||||||
@@ -271,8 +271,9 @@ export default class {
|
|||||||
const { sessionId, namespace, messageData } = message.data;
|
const { sessionId, namespace, messageData } = message.data;
|
||||||
const session = this.#sessions.get(sessionId);
|
const session = this.#sessions.get(sessionId);
|
||||||
if (session) {
|
if (session) {
|
||||||
const listeners =
|
const listeners = sessionMessageListeners
|
||||||
SessionMessageListeners.get(session)?.get(namespace);
|
.get(session)
|
||||||
|
?.get(namespace);
|
||||||
if (listeners) {
|
if (listeners) {
|
||||||
for (const listener of listeners) {
|
for (const listener of listeners) {
|
||||||
listener(namespace, messageData);
|
listener(namespace, messageData);
|
||||||
@@ -291,8 +292,9 @@ export default class {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sendMessageCallback =
|
const sendMessageCallback = sessionSendMessageCallbacks
|
||||||
SessionSendMessageCallbacks.get(session)?.get(messageId);
|
.get(session)
|
||||||
|
?.get(messageId);
|
||||||
if (sendMessageCallback) {
|
if (sendMessageCallback) {
|
||||||
const [successCallback, errorCallback] =
|
const [successCallback, errorCallback] =
|
||||||
sendMessageCallback;
|
sendMessageCallback;
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ type MediaMessageCallback = (
|
|||||||
message: DistributiveOmit<SenderMediaMessage, "requestId">
|
message: DistributiveOmit<SenderMediaMessage, "requestId">
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
|
|
||||||
const MediaMessageCallbacks = new WeakMap<Media, MediaMessageCallback>();
|
const mediaMessageCallbacks = new WeakMap<Media, MediaMessageCallback>();
|
||||||
export const MediaUpdateListeners = new WeakMap<Media, Set<UpdateListener>>();
|
export const mediaUpdateListeners = new WeakMap<Media, Set<UpdateListener>>();
|
||||||
export const MediaLastUpdateTimes = new WeakMap<Media, number>();
|
export const mediaLastUpdateTimes = new WeakMap<Media, number>();
|
||||||
|
|
||||||
/** Creates a Media object and initializes private data. */
|
/** Creates a Media object and initializes private data. */
|
||||||
export function createMedia(
|
export function createMedia(
|
||||||
@@ -48,9 +48,9 @@ export function createMedia(
|
|||||||
mediaMessageCallback: MediaMessageCallback
|
mediaMessageCallback: MediaMessageCallback
|
||||||
) {
|
) {
|
||||||
const media = new Media(...mediaArgs);
|
const media = new Media(...mediaArgs);
|
||||||
MediaMessageCallbacks.set(media, mediaMessageCallback);
|
mediaMessageCallbacks.set(media, mediaMessageCallback);
|
||||||
MediaUpdateListeners.set(media, new Set());
|
mediaUpdateListeners.set(media, new Set());
|
||||||
MediaLastUpdateTimes.set(media, 0);
|
mediaLastUpdateTimes.set(media, 0);
|
||||||
|
|
||||||
return media;
|
return media;
|
||||||
}
|
}
|
||||||
@@ -61,18 +61,18 @@ export default class Media {
|
|||||||
#id = uuid();
|
#id = uuid();
|
||||||
|
|
||||||
get #updateListeners() {
|
get #updateListeners() {
|
||||||
const updateListeners = MediaUpdateListeners.get(this);
|
const updateListeners = mediaUpdateListeners.get(this);
|
||||||
if (!updateListeners)
|
if (!updateListeners)
|
||||||
throw logger.error("Missing media update listeners!");
|
throw logger.error("Missing media update listeners!");
|
||||||
return updateListeners;
|
return updateListeners;
|
||||||
}
|
}
|
||||||
get #mediaMessageCallback() {
|
get #mediaMessageCallback() {
|
||||||
const callback = MediaMessageCallbacks.get(this);
|
const callback = mediaMessageCallbacks.get(this);
|
||||||
if (!callback) throw logger.error("Missing media message callback!");
|
if (!callback) throw logger.error("Missing media message callback!");
|
||||||
return callback;
|
return callback;
|
||||||
}
|
}
|
||||||
get #lastUpdateTime() {
|
get #lastUpdateTime() {
|
||||||
const lastUpdateTime = MediaLastUpdateTimes.get(this);
|
const lastUpdateTime = mediaLastUpdateTimes.get(this);
|
||||||
if (lastUpdateTime === undefined)
|
if (lastUpdateTime === undefined)
|
||||||
throw logger.error("Missing last update time!");
|
throw logger.error("Missing last update time!");
|
||||||
return lastUpdateTime;
|
return lastUpdateTime;
|
||||||
@@ -127,18 +127,15 @@ export default class Media {
|
|||||||
* information reported by the receiver.
|
* information reported by the receiver.
|
||||||
*/
|
*/
|
||||||
getEstimatedBreakClipTime() {
|
getEstimatedBreakClipTime() {
|
||||||
if (!this.breakStatus?.currentBreakClipTime) return;
|
if (this.breakStatus?.currentBreakClipTime === undefined) return;
|
||||||
|
if (this.playerState === PlayerState.PLAYING) {
|
||||||
|
return getEstimatedTime({
|
||||||
|
currentTime: this.breakStatus.currentBreakClipTime,
|
||||||
|
lastUpdateTime: this.#lastUpdateTime
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const currentBreakClip = this.media?.breakClips?.find(
|
return this.breakStatus.currentBreakClipTime;
|
||||||
breakClip => breakClip.id === this.breakStatus?.breakClipId
|
|
||||||
);
|
|
||||||
if (!currentBreakClip) return;
|
|
||||||
|
|
||||||
return getEstimatedTime({
|
|
||||||
currentTime: this.breakStatus.currentBreakClipTime,
|
|
||||||
lastUpdateTime: this.#lastUpdateTime,
|
|
||||||
duration: currentBreakClip.duration
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -146,18 +143,15 @@ export default class Media {
|
|||||||
* information reported by the receiver.
|
* information reported by the receiver.
|
||||||
*/
|
*/
|
||||||
getEstimatedBreakTime() {
|
getEstimatedBreakTime() {
|
||||||
if (!this.breakStatus?.currentBreakTime) return;
|
if (this.breakStatus?.currentBreakTime === undefined) return;
|
||||||
|
if (this.playerState === PlayerState.PLAYING) {
|
||||||
|
return getEstimatedTime({
|
||||||
|
currentTime: this.breakStatus.currentBreakTime,
|
||||||
|
lastUpdateTime: this.#lastUpdateTime
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const currentBreak = this.media?.breaks?.find(
|
return this.breakStatus.currentBreakTime;
|
||||||
break_ => break_.id === this.breakStatus?.breakId
|
|
||||||
);
|
|
||||||
if (!currentBreak) return;
|
|
||||||
|
|
||||||
return getEstimatedTime({
|
|
||||||
currentTime: this.breakStatus.currentBreakTime,
|
|
||||||
lastUpdateTime: this.#lastUpdateTime,
|
|
||||||
duration: currentBreak.duration
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getEstimatedLiveSeekableRange() {
|
getEstimatedLiveSeekableRange() {
|
||||||
@@ -173,6 +167,7 @@ export default class Media {
|
|||||||
return getEstimatedTime({
|
return getEstimatedTime({
|
||||||
currentTime: this.currentTime,
|
currentTime: this.currentTime,
|
||||||
lastUpdateTime: this.#lastUpdateTime,
|
lastUpdateTime: this.#lastUpdateTime,
|
||||||
|
playbackRate: this.playbackRate,
|
||||||
duration: this.media?.duration
|
duration: this.media?.duration
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { SenderApplication, Volume, Image } from "./classes";
|
import type { SenderApplication, Volume, Image } from "./classes";
|
||||||
import type { MediaInfo, QueueItem } from "./media/classes";
|
import type {
|
||||||
|
BreakStatus,
|
||||||
|
LiveSeekableRange,
|
||||||
|
MediaInfo,
|
||||||
|
QueueItem
|
||||||
|
} from "./media/classes";
|
||||||
import type {
|
import type {
|
||||||
IdleReason,
|
IdleReason,
|
||||||
PlayerState,
|
PlayerState,
|
||||||
@@ -14,18 +19,20 @@ import type {
|
|||||||
|
|
||||||
export interface MediaStatus {
|
export interface MediaStatus {
|
||||||
activeTrackIds?: number[];
|
activeTrackIds?: number[];
|
||||||
|
breakStatus?: BreakStatus;
|
||||||
currentItemId?: number;
|
currentItemId?: number;
|
||||||
mediaSessionId: number;
|
currentTime: Nullable<number>;
|
||||||
media?: MediaInfo;
|
customData: unknown;
|
||||||
playbackRate: number;
|
|
||||||
playerState: PlayerState;
|
|
||||||
idleReason?: IdleReason;
|
idleReason?: IdleReason;
|
||||||
items?: QueueItem[];
|
items?: QueueItem[];
|
||||||
currentTime: Nullable<number>;
|
liveSeekableRange?: LiveSeekableRange;
|
||||||
supportedMediaCommands: number;
|
media?: MediaInfo;
|
||||||
|
mediaSessionId: number;
|
||||||
|
playbackRate: number;
|
||||||
|
playerState: PlayerState;
|
||||||
repeatMode?: RepeatMode;
|
repeatMode?: RepeatMode;
|
||||||
|
supportedMediaCommands: number;
|
||||||
volume: Volume;
|
volume: Volume;
|
||||||
customData: unknown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReceiverApplication {
|
export interface ReceiverApplication {
|
||||||
|
|||||||
@@ -77,11 +77,13 @@ export function convertSupportedMediaCommandsFlags(flags: _MediaCommand) {
|
|||||||
interface GetEstimatedTimeOpts {
|
interface GetEstimatedTimeOpts {
|
||||||
currentTime: number;
|
currentTime: number;
|
||||||
lastUpdateTime: number;
|
lastUpdateTime: number;
|
||||||
|
playbackRate?: number;
|
||||||
duration?: Nullable<number>;
|
duration?: Nullable<number>;
|
||||||
}
|
}
|
||||||
export function getEstimatedTime(opts: GetEstimatedTimeOpts) {
|
export function getEstimatedTime(opts: GetEstimatedTimeOpts) {
|
||||||
let estimatedTime =
|
let estimatedTime =
|
||||||
opts.currentTime + (Date.now() - opts.lastUpdateTime) / 1000;
|
opts.currentTime +
|
||||||
|
(opts.playbackRate ?? 1) * ((Date.now() - opts.lastUpdateTime) / 1000);
|
||||||
|
|
||||||
// Enforce valid range
|
// Enforce valid range
|
||||||
if (estimatedTime < 0) {
|
if (estimatedTime < 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user