/** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Microsoft Live Share SDK License. */ import { UserMeetingRole } from "@microsoft/live-share"; import { IRuntimeSignaler, LiveShareRuntime } from "@microsoft/live-share/internal"; import { CoordinationWaitPoint, ExtendedMediaMetadata, ExtendedMediaSessionPlaybackState, MediaSessionCoordinatorSuspension } from "./MediaSessionExtensions.js"; import { TypedEventEmitter } from "@fluid-internal/client-utils"; import { IEvent } from "@fluidframework/core-interfaces"; /** * Most recent state of the media session. */ export interface IMediaPlayerState { /** * Metadata for the sessions current track. */ metadata: ExtendedMediaMetadata | null; /** * Optional track data object being synchronized. * * @remarks * This can be used to sync things like pitch, roll, and yaw when watching 360 videos together. */ trackData: object | null; /** * Sessions current playback state. */ playbackState: ExtendedMediaSessionPlaybackState; /** * Sessions current position state if known. */ positionState?: MediaPositionState; } /** * @hidden */ export interface ILiveMediaSessionCoordinatorEvents extends IEvent { /** * Event listener for events emitted * @param event update * @param listener listener function * @param listener.event the event instance */ (event: string, listener: (event: any) => void): void; } /** * The `LiveMediaSessionCoordinator` tracks the playback & position state of all other * clients being synchronized with. It is responsible for keeping the local media player * in sync with the group. */ export declare class LiveMediaSessionCoordinator extends TypedEventEmitter { private readonly _id; private readonly _runtime; private readonly _liveRuntime; private readonly _logger; private readonly _getPlayerState; private _positionUpdateInterval; private _maxPlaybackDrift; private _lastWaitPoint?; private initializeState; private _playEvent?; private _pauseEvent?; private _seekToEvent?; private _rateChangeEvent?; private _setTrackEvent?; private _setTrackDataEvent?; private _positionUpdateEvent?; private _synchronizer?; private _groupState?; /** * @hidden * Applications shouldn't directly create new coordinator instances. */ constructor(id: string, runtime: IRuntimeSignaler, liveRuntime: LiveShareRuntime, getPlayerState: () => IMediaPlayerState); /** * Controls whether or not the local client is allowed to instruct the group to play or pause. * * @remarks * This flag largely meant to influence decisions made by the coordinator and can be used by * the UI to determine what controls should be shown to the user. It does not provide any * security in itself. * * If your app is running in a semi-trusted environment where only some clients are allowed * to play/pause media, you should use "role based verification" to enforce those policies. */ canPlayPause: boolean; /** * Controls whether or not the local client is allowed to seek the group to a new playback * position. * * @remarks * This flag largely meant to influence decisions made by the coordinator and can be used by * the UI to determine what controls should be shown to the user. It does not provide any * security in itself. * * If your app is running in a semi-trusted environment where only some clients are allowed * to change the playback position, you should use "role based verification" to enforce those policies. */ canSeek: boolean; /** * Controls whether or not the local client is allowed to change tracks. * * @remarks * This flag largely meant to influence decisions made by the coordinator and can be used by * the UI to determine what controls should be shown to the user. It does not provide any * security in itself. * * If your app is running in a semi-trusted environment where only some clients are allowed * to change tracks, you should use "role based verification" to enforce those policies. */ canSetTrack: boolean; /** * Controls whether or not the local client is allowed to change the tracks custom data object. * * @remarks * This flag largely meant to influence decisions made by the coordinator and can be used by * the UI to determine what controls should be shown to the user. It does not provide any * security in itself. * * If your app is running in a semi-trusted environment where only some clients are allowed * to change the tracks data object, you should use "role based verification" to enforce those * policies. */ canSetTrackData: boolean; /** * Controls whether or not the local client is allowed to change the playback rate. * * @remarks * This flag largely meant to influence decisions made by the coordinator and can be used by * the UI to determine what controls should be shown to the user. It does not provide any * security in itself. * * If your app is running in a semi-trusted environment where only some clients are allowed * to change the tracks data object, you should use "role based verification" to enforce those * policies. */ canSetPlaybackRate: boolean; /** * Controls whether or not the local client is allowed to send position updates to the group. * * @remarks * This flag largely meant to limit the number of signals sent to the group for performance reasons. * It does not provide any security in itself. */ canSendPositionUpdates: boolean; /** * Returns true if the local client is in a suspended state. */ get isSuspended(): boolean; /** * Controls whether or not to scale {@link maxPlaybackDrift} by the number of users in the session. * * @remarks * As more clients join a session, it is more likely that some users will fall behind the presenter. * It is also less likely that users will notice drift as more clients are added. * It is usually helpful to be more lenient as more clients are added so everyone can watch all the content. * Default value is true. */ get shouldScaleMaxPlaybackDrift(): boolean; set shouldScaleMaxPlaybackDrift(value: boolean); /** * Max amount of playback drift allowed in seconds. * This will scale automatically according to the number of participants in the session when {@link shouldScaleMaxPlaybackDrift} is true. * * @remarks * Should the local clients playback position lag by more than the specified value, the coordinator will trigger a `catchup` action. * Default value is `1.5` seconds. */ get maxPlaybackDrift(): number; set maxPlaybackDrift(value: number); /** * Controls whether or not to compute {@link positionUpdateInterval} based on whether user has initiated a playback command. * Default value is true. * * @remarks * When true, users that are simply watching but not controlling playback will report their positions less frequently. * When a user has sent a transport command, they will begin sending position updates more frequently. * Most Live Share apps have a concept of a primary presenter, and don't allow anyone to pause/play for the group. * By ensuring only one/few users broadcast updates frequently, the server load is reduced considerably. */ get shouldScalePositionUpdateInterval(): boolean; set shouldScalePositionUpdateInterval(value: boolean); /** * Frequency with which position updates are broadcast to the rest of the group in seconds. * When {@link shouldScalePositionUpdateInterval} is set to `true`, the value set is the minimum value. * The value returned is the actual value used to send updates by the local user, which may be larger than the value set. * * @remarks * Defaults to a minimum value of `2` seconds. */ get positionUpdateInterval(): number; set positionUpdateInterval(value: number); /** * Instructs the group to play the current track. * * @remarks * Throws an exception if the session/coordinator hasn't been initialized, no track has been * loaded, or `canPlayPause` is false. * * @returns a void promise that resolves once complete, throws if user does not have proper roles */ play(): Promise; /** * Instructs the group to pause the current track. * * @remarks * Throws an exception if the session/coordinator hasn't been initialized, no track has been * loaded, or `canPlayPause` is false. * * @returns a void promise that resolves once complete, throws if user does not have proper roles */ pause(): Promise; /** * Instructs the group to seek to a new position within the current track. * * @remarks * Throws an exception if the session/coordinator hasn't been initialized, no track has been * loaded, or `canSeek` is false. * @param time Playback position in seconds to seek to. * @returns a void promise that resolves once complete, throws if user does not have proper roles */ seekTo(time: number): Promise; /** * Sets the playback rate for everyone in the session. * * @param playbackRate the playback rate to set. * * @throws * Throws an exception if the session/coordinator hasn't been initialized or {@link canSetPlaybackRate} is false. */ setPlaybackRate(playbackRate: number): Promise; /** * Instructs the group to load a new track. * * @remarks * Throws an exception if the session/coordinator hasn't been initialized or `canSetTrack` is * false. * @param metadata The track to load or `null` to indicate that the end of the track is reached. * @param waitPoints Optional. List of static wait points to configure for the track. Dynamic wait points can be added via the `beginSuspension()` call. * @returns a void promise that resolves once complete, throws if user does not have proper roles */ setTrack(metadata: ExtendedMediaMetadata | null, waitPoints?: CoordinationWaitPoint[]): Promise; /** * Updates the track data object for the current track. * * @remarks * The track data object can be used by applications to synchronize things like pitch, roll, * and yaw of a 360 video. This data object will be reset to null anytime the track changes. * * Throws an exception if the session/coordinator hasn't been initialized or `canSetTrackData` is * false. * @param data New data object to sync with the group. This value will be synchronized using a last writer wins strategy. * @returns a void promise that resolves once complete, throws if user does not have proper roles */ setTrackData(data: object | null): Promise; /** * Begins a new local suspension. * * @remarks * Suspension temporarily suspend the clients local synchronization with the group. This can * be useful for displaying ads to users or temporarily disconnecting from the session while * the user seeks the video using a timeline scrubber. * * Multiple simultaneous suspensions are allowed and when the last suspension ends the local * client will be immediately re-synchronized with the group. * * A "Dynamic Wait Point" can be specified when `beginSuspension()` is called and the wait * point will be broadcast to all other clients in the group. Those clients will then * automatically enter a suspension state once they reach the positions specified by the * wait point. Clients that are passed the wait point will immediately suspend. * * Any wait point based suspension (dynamic or static) will result in all clients remaining * in a suspension state until the list client ends their suspension. This behavior can be * conditionally bypassed by settings the wait points `maxClients` value. * * Throws an exception if the session/coordinator hasn't been initialized. * @param waitPoint Optional. Dynamic wait point to broadcast to all of the clients. * @returns The suspension object. Call `end()` on the returned suspension to end the suspension. */ beginSuspension(waitPoint?: CoordinationWaitPoint): MediaSessionCoordinatorSuspension; /** * @hidden * Called by MediaSession to verify the coordinator has been initialized. */ get isInitialized(): boolean; /** * @hidden * Called by MediaSession to start coordinator. */ initialize(acceptTransportChangesFrom?: UserMeetingRole[]): Promise; /** * @hidden * Called by the MediaSession to detect if a wait point has been hit. */ findNextWaitPoint(): CoordinationWaitPoint | null; /** * @hidden * Called by MediaSession to trigger the sending of a position update. */ sendPositionUpdate(state: IMediaPlayerState, targetClientId?: string): void; protected createChildren(acceptTransportChangesFrom?: UserMeetingRole[]): Promise; private getPlayerPosition; } //# sourceMappingURL=LiveMediaSessionCoordinator.d.ts.map