@microsoft/live-share-media 2.0.0-internal.18 → 2.0.0-internal.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/esm/LiveMediaSession.js +82 -92
- package/bin/esm/LiveMediaSession.js.map +1 -1
- package/bin/esm/LiveMediaSessionCoordinator.js +264 -276
- package/bin/esm/LiveMediaSessionCoordinator.js.map +1 -1
- package/bin/esm/LiveMediaSessionCoordinatorSuspension.js +2 -0
- package/bin/esm/LiveMediaSessionCoordinatorSuspension.js.map +1 -1
- package/bin/esm/MediaPlayerSynchronizer.js +102 -118
- package/bin/esm/MediaPlayerSynchronizer.js.map +1 -1
- package/bin/esm/RepeatedActionThrottler.js +9 -10
- package/bin/esm/RepeatedActionThrottler.js.map +1 -1
- package/bin/esm/VolumeManager.js +10 -9
- package/bin/esm/VolumeManager.js.map +1 -1
- package/bin/esm/internals/GroupCoordinatorState.js +138 -139
- package/bin/esm/internals/GroupCoordinatorState.js.map +1 -1
- package/bin/esm/internals/GroupPlaybackPosition.js +12 -4
- package/bin/esm/internals/GroupPlaybackPosition.js.map +1 -1
- package/bin/esm/internals/GroupPlaybackRate.js +1 -0
- package/bin/esm/internals/GroupPlaybackRate.js.map +1 -1
- package/bin/esm/internals/GroupPlaybackTrack.js +2 -0
- package/bin/esm/internals/GroupPlaybackTrack.js.map +1 -1
- package/bin/esm/internals/GroupPlaybackTrackData.js +2 -0
- package/bin/esm/internals/GroupPlaybackTrackData.js.map +1 -1
- package/bin/esm/internals/GroupTransportState.js +5 -0
- package/bin/esm/internals/GroupTransportState.js.map +1 -1
- package/bin/esm/internals/PriorityTimeInterval.js +12 -0
- package/bin/esm/internals/PriorityTimeInterval.js.map +1 -1
- package/package.json +11 -21
- package/tsconfig.json +3 -4
- package/bin/IMediaPlayer.d.ts +0 -21
- package/bin/IMediaPlayer.d.ts.map +0 -1
- package/bin/IMediaPlayer.js +0 -7
- package/bin/IMediaPlayer.js.map +0 -1
- package/bin/LiveMediaSession.d.ts +0 -90
- package/bin/LiveMediaSession.d.ts.map +0 -1
- package/bin/LiveMediaSession.js +0 -255
- package/bin/LiveMediaSession.js.map +0 -1
- package/bin/LiveMediaSessionCoordinator.d.ts +0 -259
- package/bin/LiveMediaSessionCoordinator.d.ts.map +0 -1
- package/bin/LiveMediaSessionCoordinator.js +0 -472
- package/bin/LiveMediaSessionCoordinator.js.map +0 -1
- package/bin/LiveMediaSessionCoordinatorSuspension.d.ts +0 -20
- package/bin/LiveMediaSessionCoordinatorSuspension.d.ts.map +0 -1
- package/bin/LiveMediaSessionCoordinatorSuspension.js +0 -28
- package/bin/LiveMediaSessionCoordinatorSuspension.js.map +0 -1
- package/bin/MediaPlayerSynchronizer.d.ts +0 -189
- package/bin/MediaPlayerSynchronizer.d.ts.map +0 -1
- package/bin/MediaPlayerSynchronizer.js +0 -577
- package/bin/MediaPlayerSynchronizer.js.map +0 -1
- package/bin/MediaSessionActionThrottler.d.ts +0 -12
- package/bin/MediaSessionActionThrottler.d.ts.map +0 -1
- package/bin/MediaSessionActionThrottler.js +0 -14
- package/bin/MediaSessionActionThrottler.js.map +0 -1
- package/bin/MediaSessionExtensions.d.ts +0 -177
- package/bin/MediaSessionExtensions.d.ts.map +0 -1
- package/bin/MediaSessionExtensions.js +0 -26
- package/bin/MediaSessionExtensions.js.map +0 -1
- package/bin/RepeatedActionThrottler.d.ts +0 -20
- package/bin/RepeatedActionThrottler.d.ts.map +0 -1
- package/bin/RepeatedActionThrottler.js +0 -63
- package/bin/RepeatedActionThrottler.js.map +0 -1
- package/bin/VolumeManager.d.ts +0 -84
- package/bin/VolumeManager.d.ts.map +0 -1
- package/bin/VolumeManager.js +0 -175
- package/bin/VolumeManager.js.map +0 -1
- package/bin/cjs/IMediaPlayer.d.ts +0 -21
- package/bin/cjs/IMediaPlayer.d.ts.map +0 -1
- package/bin/cjs/IMediaPlayer.js +0 -7
- package/bin/cjs/IMediaPlayer.js.map +0 -1
- package/bin/cjs/LiveMediaSession.d.ts +0 -97
- package/bin/cjs/LiveMediaSession.d.ts.map +0 -1
- package/bin/cjs/LiveMediaSession.js +0 -261
- package/bin/cjs/LiveMediaSession.js.map +0 -1
- package/bin/cjs/LiveMediaSessionCoordinator.d.ts +0 -304
- package/bin/cjs/LiveMediaSessionCoordinator.d.ts.map +0 -1
- package/bin/cjs/LiveMediaSessionCoordinator.js +0 -560
- package/bin/cjs/LiveMediaSessionCoordinator.js.map +0 -1
- package/bin/cjs/LiveMediaSessionCoordinatorSuspension.d.ts +0 -20
- package/bin/cjs/LiveMediaSessionCoordinatorSuspension.d.ts.map +0 -1
- package/bin/cjs/LiveMediaSessionCoordinatorSuspension.js +0 -28
- package/bin/cjs/LiveMediaSessionCoordinatorSuspension.js.map +0 -1
- package/bin/cjs/MediaPlayerSynchronizer.d.ts +0 -204
- package/bin/cjs/MediaPlayerSynchronizer.d.ts.map +0 -1
- package/bin/cjs/MediaPlayerSynchronizer.js +0 -574
- package/bin/cjs/MediaPlayerSynchronizer.js.map +0 -1
- package/bin/cjs/MediaSessionActionThrottler.d.ts +0 -12
- package/bin/cjs/MediaSessionActionThrottler.d.ts.map +0 -1
- package/bin/cjs/MediaSessionActionThrottler.js +0 -14
- package/bin/cjs/MediaSessionActionThrottler.js.map +0 -1
- package/bin/cjs/MediaSessionExtensions.d.ts +0 -177
- package/bin/cjs/MediaSessionExtensions.d.ts.map +0 -1
- package/bin/cjs/MediaSessionExtensions.js +0 -26
- package/bin/cjs/MediaSessionExtensions.js.map +0 -1
- package/bin/cjs/RepeatedActionThrottler.d.ts +0 -20
- package/bin/cjs/RepeatedActionThrottler.d.ts.map +0 -1
- package/bin/cjs/RepeatedActionThrottler.js +0 -63
- package/bin/cjs/RepeatedActionThrottler.js.map +0 -1
- package/bin/cjs/VolumeManager.d.ts +0 -84
- package/bin/cjs/VolumeManager.d.ts.map +0 -1
- package/bin/cjs/VolumeManager.js +0 -175
- package/bin/cjs/VolumeManager.js.map +0 -1
- package/bin/cjs/index.d.ts +0 -14
- package/bin/cjs/index.d.ts.map +0 -1
- package/bin/cjs/index.js +0 -30
- package/bin/cjs/index.js.map +0 -1
- package/bin/cjs/internals/GroupCoordinatorState.d.ts +0 -110
- package/bin/cjs/internals/GroupCoordinatorState.d.ts.map +0 -1
- package/bin/cjs/internals/GroupCoordinatorState.js +0 -516
- package/bin/cjs/internals/GroupCoordinatorState.js.map +0 -1
- package/bin/cjs/internals/GroupPlaybackPosition.d.ts +0 -71
- package/bin/cjs/internals/GroupPlaybackPosition.d.ts.map +0 -1
- package/bin/cjs/internals/GroupPlaybackPosition.js +0 -170
- package/bin/cjs/internals/GroupPlaybackPosition.js.map +0 -1
- package/bin/cjs/internals/GroupPlaybackRate.d.ts +0 -38
- package/bin/cjs/internals/GroupPlaybackRate.d.ts.map +0 -1
- package/bin/cjs/internals/GroupPlaybackRate.js +0 -59
- package/bin/cjs/internals/GroupPlaybackRate.js.map +0 -1
- package/bin/cjs/internals/GroupPlaybackTrack.d.ts +0 -45
- package/bin/cjs/internals/GroupPlaybackTrack.d.ts.map +0 -1
- package/bin/cjs/internals/GroupPlaybackTrack.js +0 -122
- package/bin/cjs/internals/GroupPlaybackTrack.js.map +0 -1
- package/bin/cjs/internals/GroupPlaybackTrackData.d.ts +0 -40
- package/bin/cjs/internals/GroupPlaybackTrackData.d.ts.map +0 -1
- package/bin/cjs/internals/GroupPlaybackTrackData.js +0 -70
- package/bin/cjs/internals/GroupPlaybackTrackData.js.map +0 -1
- package/bin/cjs/internals/GroupTransportState.d.ts +0 -52
- package/bin/cjs/internals/GroupTransportState.d.ts.map +0 -1
- package/bin/cjs/internals/GroupTransportState.js +0 -120
- package/bin/cjs/internals/GroupTransportState.js.map +0 -1
- package/bin/cjs/internals/PriorityTimeInterval.d.ts +0 -33
- package/bin/cjs/internals/PriorityTimeInterval.d.ts.map +0 -1
- package/bin/cjs/internals/PriorityTimeInterval.js +0 -45
- package/bin/cjs/internals/PriorityTimeInterval.js.map +0 -1
- package/bin/cjs/internals/consts.d.ts +0 -83
- package/bin/cjs/internals/consts.d.ts.map +0 -1
- package/bin/cjs/internals/consts.js +0 -92
- package/bin/cjs/internals/consts.js.map +0 -1
- package/bin/cjs/internals/errors.d.ts +0 -17
- package/bin/cjs/internals/errors.d.ts.map +0 -1
- package/bin/cjs/internals/errors.js +0 -34
- package/bin/cjs/internals/errors.js.map +0 -1
- package/bin/cjs/internals/interfaces.d.ts +0 -23
- package/bin/cjs/internals/interfaces.d.ts.map +0 -1
- package/bin/cjs/internals/interfaces.js +0 -3
- package/bin/cjs/internals/interfaces.js.map +0 -1
- package/bin/cjs/package.json +0 -1
- package/bin/index.d.ts +0 -14
- package/bin/index.d.ts.map +0 -1
- package/bin/index.js +0 -30
- package/bin/index.js.map +0 -1
- package/bin/internals/GroupCoordinatorState.d.ts +0 -107
- package/bin/internals/GroupCoordinatorState.d.ts.map +0 -1
- package/bin/internals/GroupCoordinatorState.js +0 -519
- package/bin/internals/GroupCoordinatorState.js.map +0 -1
- package/bin/internals/GroupPlaybackPosition.d.ts +0 -70
- package/bin/internals/GroupPlaybackPosition.d.ts.map +0 -1
- package/bin/internals/GroupPlaybackPosition.js +0 -170
- package/bin/internals/GroupPlaybackPosition.js.map +0 -1
- package/bin/internals/GroupPlaybackRate.d.ts +0 -38
- package/bin/internals/GroupPlaybackRate.d.ts.map +0 -1
- package/bin/internals/GroupPlaybackRate.js +0 -62
- package/bin/internals/GroupPlaybackRate.js.map +0 -1
- package/bin/internals/GroupPlaybackTrack.d.ts +0 -45
- package/bin/internals/GroupPlaybackTrack.d.ts.map +0 -1
- package/bin/internals/GroupPlaybackTrack.js +0 -125
- package/bin/internals/GroupPlaybackTrack.js.map +0 -1
- package/bin/internals/GroupPlaybackTrackData.d.ts +0 -40
- package/bin/internals/GroupPlaybackTrackData.d.ts.map +0 -1
- package/bin/internals/GroupPlaybackTrackData.js +0 -73
- package/bin/internals/GroupPlaybackTrackData.js.map +0 -1
- package/bin/internals/GroupTransportState.d.ts +0 -52
- package/bin/internals/GroupTransportState.d.ts.map +0 -1
- package/bin/internals/GroupTransportState.js +0 -123
- package/bin/internals/GroupTransportState.js.map +0 -1
- package/bin/internals/consts.d.ts +0 -83
- package/bin/internals/consts.d.ts.map +0 -1
- package/bin/internals/consts.js +0 -92
- package/bin/internals/consts.js.map +0 -1
- package/bin/internals/errors.d.ts +0 -17
- package/bin/internals/errors.d.ts.map +0 -1
- package/bin/internals/errors.js +0 -34
- package/bin/internals/errors.js.map +0 -1
- package/bin/internals/index.d.ts +0 -13
- package/bin/internals/index.d.ts.map +0 -1
- package/bin/internals/index.js +0 -29
- package/bin/internals/index.js.map +0 -1
- package/bin/internals/interfaces.d.ts +0 -10
- package/bin/internals/interfaces.d.ts.map +0 -1
- package/bin/internals/interfaces.js +0 -3
- package/bin/internals/interfaces.js.map +0 -1
- package/tsconfig.cjs.json +0 -14
|
@@ -2,15 +2,6 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
3
|
* Licensed under the Microsoft Live Share SDK License.
|
|
4
4
|
*/
|
|
5
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
6
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
7
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
8
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
9
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
10
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
11
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
12
|
-
});
|
|
13
|
-
};
|
|
14
5
|
import { LiveTelemetryLogger, LiveDataObjectInitializeState, LiveDataObjectInitializeNotNeededError, LiveDataObjectNotInitializedError, } from "@microsoft/live-share";
|
|
15
6
|
import { LiveEventScope, LiveEventTarget, LiveObjectSynchronizer, isErrorLike, } from "@microsoft/live-share/internal";
|
|
16
7
|
import { GroupCoordinatorState, GroupCoordinatorStateEvents, } from "./internals/GroupCoordinatorState.js";
|
|
@@ -25,109 +16,128 @@ import { TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
|
25
16
|
* in sync with the group.
|
|
26
17
|
*/
|
|
27
18
|
export class LiveMediaSessionCoordinator extends TypedEventEmitter {
|
|
19
|
+
_id;
|
|
20
|
+
_runtime;
|
|
21
|
+
_liveRuntime;
|
|
22
|
+
_logger;
|
|
23
|
+
_getPlayerState;
|
|
24
|
+
_positionUpdateInterval = new PriorityTimeInterval(2000,
|
|
25
|
+
// Scale by function
|
|
26
|
+
() => {
|
|
27
|
+
const audience = this._liveRuntime.audience;
|
|
28
|
+
if (!audience)
|
|
29
|
+
return 1;
|
|
30
|
+
// As the audience size gets bigger, we relax the update interval, since more variance is expected
|
|
31
|
+
const count = audience.getMembers().size;
|
|
32
|
+
return 1 + count / 5;
|
|
33
|
+
});
|
|
34
|
+
_maxPlaybackDrift = new PriorityTimeInterval(1500, // Scale by function
|
|
35
|
+
() => {
|
|
36
|
+
const audience = this._liveRuntime.audience;
|
|
37
|
+
if (!audience)
|
|
38
|
+
return 1;
|
|
39
|
+
// As the audience size gets bigger, we relax the playback drift, since more variance is expected
|
|
40
|
+
const count = audience.getMembers().size;
|
|
41
|
+
return 1 + count / 25;
|
|
42
|
+
});
|
|
43
|
+
_lastWaitPoint;
|
|
44
|
+
initializeState = LiveDataObjectInitializeState.needed;
|
|
45
|
+
// Broadcast events
|
|
46
|
+
_playEvent;
|
|
47
|
+
_pauseEvent;
|
|
48
|
+
_seekToEvent;
|
|
49
|
+
_rateChangeEvent;
|
|
50
|
+
_setTrackEvent;
|
|
51
|
+
_setTrackDataEvent;
|
|
52
|
+
_positionUpdateEvent;
|
|
53
|
+
// Synchronizer does not play a significant role in LiveMediaSession beyond being able to
|
|
54
|
+
// use "connect" events to replace old "joined" events when sending position data to new clients.
|
|
55
|
+
_synchronizer;
|
|
56
|
+
// Distributed state
|
|
57
|
+
_groupState;
|
|
28
58
|
/**
|
|
29
59
|
* @hidden
|
|
30
60
|
* Applications shouldn't directly create new coordinator instances.
|
|
31
61
|
*/
|
|
32
62
|
constructor(id, runtime, liveRuntime, getPlayerState) {
|
|
33
63
|
super();
|
|
34
|
-
this._positionUpdateInterval = new PriorityTimeInterval(2000,
|
|
35
|
-
// Scale by function
|
|
36
|
-
() => {
|
|
37
|
-
const audience = this._liveRuntime.audience;
|
|
38
|
-
if (!audience)
|
|
39
|
-
return 1;
|
|
40
|
-
// As the audience size gets bigger, we relax the update interval, since more variance is expected
|
|
41
|
-
const count = audience.getMembers().size;
|
|
42
|
-
return 1 + count / 5;
|
|
43
|
-
});
|
|
44
|
-
this._maxPlaybackDrift = new PriorityTimeInterval(1500, // Scale by function
|
|
45
|
-
() => {
|
|
46
|
-
const audience = this._liveRuntime.audience;
|
|
47
|
-
if (!audience)
|
|
48
|
-
return 1;
|
|
49
|
-
// As the audience size gets bigger, we relax the playback drift, since more variance is expected
|
|
50
|
-
const count = audience.getMembers().size;
|
|
51
|
-
return 1 + count / 25;
|
|
52
|
-
});
|
|
53
|
-
this.initializeState = LiveDataObjectInitializeState.needed;
|
|
54
|
-
/**
|
|
55
|
-
* Controls whether or not the local client is allowed to instruct the group to play or pause.
|
|
56
|
-
*
|
|
57
|
-
* @remarks
|
|
58
|
-
* This flag largely meant to influence decisions made by the coordinator and can be used by
|
|
59
|
-
* the UI to determine what controls should be shown to the user. It does not provide any
|
|
60
|
-
* security in itself.
|
|
61
|
-
*
|
|
62
|
-
* If your app is running in a semi-trusted environment where only some clients are allowed
|
|
63
|
-
* to play/pause media, you should use "role based verification" to enforce those policies.
|
|
64
|
-
*/
|
|
65
|
-
this.canPlayPause = true;
|
|
66
|
-
/**
|
|
67
|
-
* Controls whether or not the local client is allowed to seek the group to a new playback
|
|
68
|
-
* position.
|
|
69
|
-
*
|
|
70
|
-
* @remarks
|
|
71
|
-
* This flag largely meant to influence decisions made by the coordinator and can be used by
|
|
72
|
-
* the UI to determine what controls should be shown to the user. It does not provide any
|
|
73
|
-
* security in itself.
|
|
74
|
-
*
|
|
75
|
-
* If your app is running in a semi-trusted environment where only some clients are allowed
|
|
76
|
-
* to change the playback position, you should use "role based verification" to enforce those policies.
|
|
77
|
-
*/
|
|
78
|
-
this.canSeek = true;
|
|
79
|
-
/**
|
|
80
|
-
* Controls whether or not the local client is allowed to change tracks.
|
|
81
|
-
*
|
|
82
|
-
* @remarks
|
|
83
|
-
* This flag largely meant to influence decisions made by the coordinator and can be used by
|
|
84
|
-
* the UI to determine what controls should be shown to the user. It does not provide any
|
|
85
|
-
* security in itself.
|
|
86
|
-
*
|
|
87
|
-
* If your app is running in a semi-trusted environment where only some clients are allowed
|
|
88
|
-
* to change tracks, you should use "role based verification" to enforce those policies.
|
|
89
|
-
*/
|
|
90
|
-
this.canSetTrack = true;
|
|
91
|
-
/**
|
|
92
|
-
* Controls whether or not the local client is allowed to change the tracks custom data object.
|
|
93
|
-
*
|
|
94
|
-
* @remarks
|
|
95
|
-
* This flag largely meant to influence decisions made by the coordinator and can be used by
|
|
96
|
-
* the UI to determine what controls should be shown to the user. It does not provide any
|
|
97
|
-
* security in itself.
|
|
98
|
-
*
|
|
99
|
-
* If your app is running in a semi-trusted environment where only some clients are allowed
|
|
100
|
-
* to change the tracks data object, you should use "role based verification" to enforce those
|
|
101
|
-
* policies.
|
|
102
|
-
*/
|
|
103
|
-
this.canSetTrackData = true;
|
|
104
|
-
/**
|
|
105
|
-
* Controls whether or not the local client is allowed to change the playback rate.
|
|
106
|
-
*
|
|
107
|
-
* @remarks
|
|
108
|
-
* This flag largely meant to influence decisions made by the coordinator and can be used by
|
|
109
|
-
* the UI to determine what controls should be shown to the user. It does not provide any
|
|
110
|
-
* security in itself.
|
|
111
|
-
*
|
|
112
|
-
* If your app is running in a semi-trusted environment where only some clients are allowed
|
|
113
|
-
* to change the tracks data object, you should use "role based verification" to enforce those
|
|
114
|
-
* policies.
|
|
115
|
-
*/
|
|
116
|
-
this.canSetPlaybackRate = true;
|
|
117
|
-
/**
|
|
118
|
-
* Controls whether or not the local client is allowed to send position updates to the group.
|
|
119
|
-
*
|
|
120
|
-
* @remarks
|
|
121
|
-
* This flag largely meant to limit the number of signals sent to the group for performance reasons.
|
|
122
|
-
* It does not provide any security in itself.
|
|
123
|
-
*/
|
|
124
|
-
this.canSendPositionUpdates = true;
|
|
125
64
|
this._id = id;
|
|
126
65
|
this._runtime = runtime;
|
|
127
66
|
this._liveRuntime = liveRuntime;
|
|
128
67
|
this._logger = new LiveTelemetryLogger(runtime, liveRuntime);
|
|
129
68
|
this._getPlayerState = getPlayerState;
|
|
130
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Controls whether or not the local client is allowed to instruct the group to play or pause.
|
|
72
|
+
*
|
|
73
|
+
* @remarks
|
|
74
|
+
* This flag largely meant to influence decisions made by the coordinator and can be used by
|
|
75
|
+
* the UI to determine what controls should be shown to the user. It does not provide any
|
|
76
|
+
* security in itself.
|
|
77
|
+
*
|
|
78
|
+
* If your app is running in a semi-trusted environment where only some clients are allowed
|
|
79
|
+
* to play/pause media, you should use "role based verification" to enforce those policies.
|
|
80
|
+
*/
|
|
81
|
+
canPlayPause = true;
|
|
82
|
+
/**
|
|
83
|
+
* Controls whether or not the local client is allowed to seek the group to a new playback
|
|
84
|
+
* position.
|
|
85
|
+
*
|
|
86
|
+
* @remarks
|
|
87
|
+
* This flag largely meant to influence decisions made by the coordinator and can be used by
|
|
88
|
+
* the UI to determine what controls should be shown to the user. It does not provide any
|
|
89
|
+
* security in itself.
|
|
90
|
+
*
|
|
91
|
+
* If your app is running in a semi-trusted environment where only some clients are allowed
|
|
92
|
+
* to change the playback position, you should use "role based verification" to enforce those policies.
|
|
93
|
+
*/
|
|
94
|
+
canSeek = true;
|
|
95
|
+
/**
|
|
96
|
+
* Controls whether or not the local client is allowed to change tracks.
|
|
97
|
+
*
|
|
98
|
+
* @remarks
|
|
99
|
+
* This flag largely meant to influence decisions made by the coordinator and can be used by
|
|
100
|
+
* the UI to determine what controls should be shown to the user. It does not provide any
|
|
101
|
+
* security in itself.
|
|
102
|
+
*
|
|
103
|
+
* If your app is running in a semi-trusted environment where only some clients are allowed
|
|
104
|
+
* to change tracks, you should use "role based verification" to enforce those policies.
|
|
105
|
+
*/
|
|
106
|
+
canSetTrack = true;
|
|
107
|
+
/**
|
|
108
|
+
* Controls whether or not the local client is allowed to change the tracks custom data object.
|
|
109
|
+
*
|
|
110
|
+
* @remarks
|
|
111
|
+
* This flag largely meant to influence decisions made by the coordinator and can be used by
|
|
112
|
+
* the UI to determine what controls should be shown to the user. It does not provide any
|
|
113
|
+
* security in itself.
|
|
114
|
+
*
|
|
115
|
+
* If your app is running in a semi-trusted environment where only some clients are allowed
|
|
116
|
+
* to change the tracks data object, you should use "role based verification" to enforce those
|
|
117
|
+
* policies.
|
|
118
|
+
*/
|
|
119
|
+
canSetTrackData = true;
|
|
120
|
+
/**
|
|
121
|
+
* Controls whether or not the local client is allowed to change the playback rate.
|
|
122
|
+
*
|
|
123
|
+
* @remarks
|
|
124
|
+
* This flag largely meant to influence decisions made by the coordinator and can be used by
|
|
125
|
+
* the UI to determine what controls should be shown to the user. It does not provide any
|
|
126
|
+
* security in itself.
|
|
127
|
+
*
|
|
128
|
+
* If your app is running in a semi-trusted environment where only some clients are allowed
|
|
129
|
+
* to change the tracks data object, you should use "role based verification" to enforce those
|
|
130
|
+
* policies.
|
|
131
|
+
*/
|
|
132
|
+
canSetPlaybackRate = true;
|
|
133
|
+
/**
|
|
134
|
+
* Controls whether or not the local client is allowed to send position updates to the group.
|
|
135
|
+
*
|
|
136
|
+
* @remarks
|
|
137
|
+
* This flag largely meant to limit the number of signals sent to the group for performance reasons.
|
|
138
|
+
* It does not provide any security in itself.
|
|
139
|
+
*/
|
|
140
|
+
canSendPositionUpdates = true;
|
|
131
141
|
/**
|
|
132
142
|
* Returns true if the local client is in a suspended state.
|
|
133
143
|
*/
|
|
@@ -202,25 +212,22 @@ export class LiveMediaSessionCoordinator extends TypedEventEmitter {
|
|
|
202
212
|
*
|
|
203
213
|
* @returns a void promise that resolves once complete, throws if user does not have proper roles
|
|
204
214
|
*/
|
|
205
|
-
play() {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
this.
|
|
215
|
-
|
|
216
|
-
track: this._groupState.playbackTrack.current,
|
|
217
|
-
position: position,
|
|
218
|
-
});
|
|
219
|
-
if (this.canSendPositionUpdates) {
|
|
220
|
-
// User has taken initiative to send event, give priority for sending position updates
|
|
221
|
-
this._positionUpdateInterval.hasPriority = true;
|
|
222
|
-
}
|
|
215
|
+
async play() {
|
|
216
|
+
LiveDataObjectNotInitializedError.assert("LiveMediaSessionCoordinator:play", "play", this.initializeState);
|
|
217
|
+
TrackMetadataNotSetError.assert(!!this._groupState?.playbackTrack.current.metadata, "LiveMediaSessionCoordinator:play", "play");
|
|
218
|
+
ActionBlockedError.assert(this.canPlayPause, "LiveMediaSessionCoordinator:play", "play", "canPlayPause");
|
|
219
|
+
// Get projected position
|
|
220
|
+
const position = this.getPlayerPosition();
|
|
221
|
+
// Send transport command
|
|
222
|
+
this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.PlayCalled, null, { position: position });
|
|
223
|
+
await this._playEvent.sendEvent({
|
|
224
|
+
track: this._groupState.playbackTrack.current,
|
|
225
|
+
position: position,
|
|
223
226
|
});
|
|
227
|
+
if (this.canSendPositionUpdates) {
|
|
228
|
+
// User has taken initiative to send event, give priority for sending position updates
|
|
229
|
+
this._positionUpdateInterval.hasPriority = true;
|
|
230
|
+
}
|
|
224
231
|
}
|
|
225
232
|
/**
|
|
226
233
|
* Instructs the group to pause the current track.
|
|
@@ -231,25 +238,22 @@ export class LiveMediaSessionCoordinator extends TypedEventEmitter {
|
|
|
231
238
|
*
|
|
232
239
|
* @returns a void promise that resolves once complete, throws if user does not have proper roles
|
|
233
240
|
*/
|
|
234
|
-
pause() {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
this.
|
|
244
|
-
|
|
245
|
-
track: this._groupState.playbackTrack.current,
|
|
246
|
-
position: position,
|
|
247
|
-
});
|
|
248
|
-
if (this.canSendPositionUpdates) {
|
|
249
|
-
// User has taken initiative to send event, give priority for sending position updates
|
|
250
|
-
this._positionUpdateInterval.hasPriority = true;
|
|
251
|
-
}
|
|
241
|
+
async pause() {
|
|
242
|
+
LiveDataObjectNotInitializedError.assert("LiveMediaSessionCoordinator:pause", "pause", this.initializeState);
|
|
243
|
+
TrackMetadataNotSetError.assert(!!this._groupState?.playbackTrack.current.metadata, "LiveMediaSessionCoordinator:pause", "pause");
|
|
244
|
+
ActionBlockedError.assert(this.canPlayPause, "LiveMediaSessionCoordinator:pause", "pause", "canPlayPause");
|
|
245
|
+
// Get projected position
|
|
246
|
+
const position = this.getPlayerPosition();
|
|
247
|
+
// Send transport command
|
|
248
|
+
this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.PauseCalled, null, { position: position });
|
|
249
|
+
await this._pauseEvent.sendEvent({
|
|
250
|
+
track: this._groupState.playbackTrack.current,
|
|
251
|
+
position: position,
|
|
252
252
|
});
|
|
253
|
+
if (this.canSendPositionUpdates) {
|
|
254
|
+
// User has taken initiative to send event, give priority for sending position updates
|
|
255
|
+
this._positionUpdateInterval.hasPriority = true;
|
|
256
|
+
}
|
|
253
257
|
}
|
|
254
258
|
/**
|
|
255
259
|
* Instructs the group to seek to a new position within the current track.
|
|
@@ -260,29 +264,26 @@ export class LiveMediaSessionCoordinator extends TypedEventEmitter {
|
|
|
260
264
|
* @param time Playback position in seconds to seek to.
|
|
261
265
|
* @returns a void promise that resolves once complete, throws if user does not have proper roles
|
|
262
266
|
*/
|
|
263
|
-
seekTo(time) {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
this.
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
// User has taken initiative to send event, give priority for sending position updates
|
|
278
|
-
this._positionUpdateInterval.hasPriority = true;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
catch (err) {
|
|
282
|
-
yield this._groupState.syncLocalMediaSession();
|
|
283
|
-
throw err;
|
|
267
|
+
async seekTo(time) {
|
|
268
|
+
LiveDataObjectNotInitializedError.assert("LiveMediaSessionCoordinator:seekTo", "seekTo", this.initializeState);
|
|
269
|
+
TrackMetadataNotSetError.assert(!!this._groupState?.playbackTrack.current.metadata, "LiveMediaSessionCoordinator:seekTo", "seekTo");
|
|
270
|
+
ActionBlockedError.assert(this.canSeek, "LiveMediaSessionCoordinator:seekTo", "seekTo", "canSeek");
|
|
271
|
+
// Send transport command
|
|
272
|
+
this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.SeekToCalled, null, { position: time });
|
|
273
|
+
try {
|
|
274
|
+
await this._seekToEvent.sendEvent({
|
|
275
|
+
track: this._groupState.playbackTrack.current,
|
|
276
|
+
position: time,
|
|
277
|
+
});
|
|
278
|
+
if (this.canSendPositionUpdates) {
|
|
279
|
+
// User has taken initiative to send event, give priority for sending position updates
|
|
280
|
+
this._positionUpdateInterval.hasPriority = true;
|
|
284
281
|
}
|
|
285
|
-
}
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
await this._groupState.syncLocalMediaSession();
|
|
285
|
+
throw err;
|
|
286
|
+
}
|
|
286
287
|
}
|
|
287
288
|
/**
|
|
288
289
|
* Sets the playback rate for everyone in the session.
|
|
@@ -292,17 +293,15 @@ export class LiveMediaSessionCoordinator extends TypedEventEmitter {
|
|
|
292
293
|
* @throws
|
|
293
294
|
* Throws an exception if the session/coordinator hasn't been initialized or {@link canSetPlaybackRate} is false.
|
|
294
295
|
*/
|
|
295
|
-
setPlaybackRate(playbackRate) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
});
|
|
296
|
+
async setPlaybackRate(playbackRate) {
|
|
297
|
+
LiveDataObjectNotInitializedError.assert("LiveMediaSessionCoordinator:setPlaybackRate", "setPlaybackRate", this.initializeState);
|
|
298
|
+
ActionBlockedError.assert(this.canSetPlaybackRate, "LiveMediaSessionCoordinator:setPlaybackRate", "setPlaybackRate", "canSetPlaybackRate");
|
|
299
|
+
this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.SetPlaybackRateCalled, null, { playbackRate });
|
|
300
|
+
await this._rateChangeEvent.sendEvent({ playbackRate });
|
|
301
|
+
if (this.canSendPositionUpdates) {
|
|
302
|
+
// User has taken initiative to send event, give priority for sending position updates
|
|
303
|
+
this._positionUpdateInterval.hasPriority = true;
|
|
304
|
+
}
|
|
306
305
|
}
|
|
307
306
|
/**
|
|
308
307
|
* Instructs the group to load a new track.
|
|
@@ -314,21 +313,19 @@ export class LiveMediaSessionCoordinator extends TypedEventEmitter {
|
|
|
314
313
|
* @param waitPoints Optional. List of static wait points to configure for the track. Dynamic wait points can be added via the `beginSuspension()` call.
|
|
315
314
|
* @returns a void promise that resolves once complete, throws if user does not have proper roles
|
|
316
315
|
*/
|
|
317
|
-
setTrack(metadata, waitPoints) {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
waitPoints: waitPoints || [],
|
|
326
|
-
});
|
|
327
|
-
if (this.canSendPositionUpdates) {
|
|
328
|
-
// User has taken initiative to send event, give priority for sending position updates
|
|
329
|
-
this._positionUpdateInterval.hasPriority = true;
|
|
330
|
-
}
|
|
316
|
+
async setTrack(metadata, waitPoints) {
|
|
317
|
+
LiveDataObjectNotInitializedError.assert("LiveMediaSessionCoordinator:setTrack", "setTrack", this.initializeState);
|
|
318
|
+
ActionBlockedError.assert(this.canSetTrack, "LiveMediaSessionCoordinator:setTrack", "setTrack", "canSetTrack");
|
|
319
|
+
// Send transport command
|
|
320
|
+
this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.SetTrackCalled);
|
|
321
|
+
await this._setTrackEvent.sendEvent({
|
|
322
|
+
metadata: metadata,
|
|
323
|
+
waitPoints: waitPoints || [],
|
|
331
324
|
});
|
|
325
|
+
if (this.canSendPositionUpdates) {
|
|
326
|
+
// User has taken initiative to send event, give priority for sending position updates
|
|
327
|
+
this._positionUpdateInterval.hasPriority = true;
|
|
328
|
+
}
|
|
332
329
|
}
|
|
333
330
|
/**
|
|
334
331
|
* Updates the track data object for the current track.
|
|
@@ -342,20 +339,18 @@ export class LiveMediaSessionCoordinator extends TypedEventEmitter {
|
|
|
342
339
|
* @param data New data object to sync with the group. This value will be synchronized using a last writer wins strategy.
|
|
343
340
|
* @returns a void promise that resolves once complete, throws if user does not have proper roles
|
|
344
341
|
*/
|
|
345
|
-
setTrackData(data) {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
data: data,
|
|
353
|
-
});
|
|
354
|
-
if (this.canSendPositionUpdates) {
|
|
355
|
-
// User has taken initiative to send event, give priority for sending position updates
|
|
356
|
-
this._positionUpdateInterval.hasPriority = true;
|
|
357
|
-
}
|
|
342
|
+
async setTrackData(data) {
|
|
343
|
+
LiveDataObjectNotInitializedError.assert("LiveMediaSessionCoordinator:setTrackData", "setTrackData", this.initializeState);
|
|
344
|
+
ActionBlockedError.assert(this.canSetTrackData, "LiveMediaSessionCoordinator:setTrackData", "setTrackData", "canSetTrackData");
|
|
345
|
+
// Send transport command
|
|
346
|
+
this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.SetTrackDataCalled);
|
|
347
|
+
await this._setTrackDataEvent.sendEvent({
|
|
348
|
+
data: data,
|
|
358
349
|
});
|
|
350
|
+
if (this.canSendPositionUpdates) {
|
|
351
|
+
// User has taken initiative to send event, give priority for sending position updates
|
|
352
|
+
this._positionUpdateInterval.hasPriority = true;
|
|
353
|
+
}
|
|
359
354
|
}
|
|
360
355
|
/**
|
|
361
356
|
* Begins a new local suspension.
|
|
@@ -382,9 +377,8 @@ export class LiveMediaSessionCoordinator extends TypedEventEmitter {
|
|
|
382
377
|
* @returns The suspension object. Call `end()` on the returned suspension to end the suspension.
|
|
383
378
|
*/
|
|
384
379
|
beginSuspension(waitPoint) {
|
|
385
|
-
var _a;
|
|
386
380
|
LiveDataObjectNotInitializedError.assert("LiveMediaSessionCoordinator:beginSuspension", "beginSuspension", this.initializeState);
|
|
387
|
-
TrackMetadataNotSetError.assert(!!
|
|
381
|
+
TrackMetadataNotSetError.assert(!!this._groupState?.playbackTrack.current.metadata, "LiveMediaSessionCoordinator:beginSuspension", "beginSuspension");
|
|
388
382
|
// Tell group state that suspension is started
|
|
389
383
|
if (waitPoint) {
|
|
390
384
|
this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.BeginSuspensionAndWait, null, {
|
|
@@ -400,7 +394,6 @@ export class LiveMediaSessionCoordinator extends TypedEventEmitter {
|
|
|
400
394
|
}
|
|
401
395
|
// Return new suspension object
|
|
402
396
|
return new LiveMediaSessionCoordinatorSuspension(waitPoint, (time) => {
|
|
403
|
-
var _a, _b;
|
|
404
397
|
if (waitPoint) {
|
|
405
398
|
this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.EndSuspensionAndWait, null, {
|
|
406
399
|
position: waitPoint.position,
|
|
@@ -412,8 +405,8 @@ export class LiveMediaSessionCoordinator extends TypedEventEmitter {
|
|
|
412
405
|
}
|
|
413
406
|
this._groupState.endSuspension(time == undefined);
|
|
414
407
|
if (time != undefined &&
|
|
415
|
-
!
|
|
416
|
-
!
|
|
408
|
+
!this._groupState?.isSuspended &&
|
|
409
|
+
!this._groupState?.isWaiting) {
|
|
417
410
|
// Seek to new position
|
|
418
411
|
this.seekTo(Math.max(time, 0.0));
|
|
419
412
|
}
|
|
@@ -430,55 +423,52 @@ export class LiveMediaSessionCoordinator extends TypedEventEmitter {
|
|
|
430
423
|
* @hidden
|
|
431
424
|
* Called by MediaSession to start coordinator.
|
|
432
425
|
*/
|
|
433
|
-
initialize(acceptTransportChangesFrom) {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
.LiveObjectSynchronizerStartError, error);
|
|
460
|
-
}
|
|
461
|
-
});
|
|
426
|
+
async initialize(acceptTransportChangesFrom) {
|
|
427
|
+
LiveDataObjectInitializeNotNeededError.assert("LiveMediaSessionCoordinator:initialize", this.initializeState);
|
|
428
|
+
this.initializeState = LiveDataObjectInitializeState.pending;
|
|
429
|
+
try {
|
|
430
|
+
// Create children
|
|
431
|
+
await this.createChildren(acceptTransportChangesFrom);
|
|
432
|
+
}
|
|
433
|
+
catch (error) {
|
|
434
|
+
this.initializeState = LiveDataObjectInitializeState.needed;
|
|
435
|
+
throw error;
|
|
436
|
+
}
|
|
437
|
+
this.initializeState = LiveDataObjectInitializeState.succeeded;
|
|
438
|
+
try {
|
|
439
|
+
// start needs to happen after setting initializedState to "succeeded"
|
|
440
|
+
await this._synchronizer?.start({
|
|
441
|
+
initialState: undefined,
|
|
442
|
+
updateState: async (evt, sender, local) => false,
|
|
443
|
+
getLocalUserCanSend: async (connecting) => true,
|
|
444
|
+
enableBackgroundUpdates: false,
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
catch (error) {
|
|
448
|
+
// not a fatal error for LiveMediaSession, only used for "connect" event to send new clients position updates.
|
|
449
|
+
this._logger.sendErrorEvent(TelemetryEvents.SessionCoordinator
|
|
450
|
+
.LiveObjectSynchronizerStartError, error);
|
|
451
|
+
}
|
|
462
452
|
}
|
|
463
453
|
/**
|
|
464
454
|
* @hidden
|
|
465
455
|
* Called by the MediaSession to detect if a wait point has been hit.
|
|
466
456
|
*/
|
|
467
457
|
findNextWaitPoint() {
|
|
468
|
-
|
|
469
|
-
return (((_a = this._groupState) === null || _a === void 0 ? void 0 : _a.playbackTrack.findNextWaitPoint(this._lastWaitPoint)) || null);
|
|
458
|
+
return (this._groupState?.playbackTrack.findNextWaitPoint(this._lastWaitPoint) || null);
|
|
470
459
|
}
|
|
471
460
|
/**
|
|
472
461
|
* @hidden
|
|
473
462
|
* Called by MediaSession to trigger the sending of a position update.
|
|
474
463
|
*/
|
|
475
464
|
sendPositionUpdate(state, targetClientId) {
|
|
476
|
-
var _a, _b;
|
|
477
465
|
LiveDataObjectNotInitializedError.assert("LiveMediaSessionCoordinator:sendPositionUpdate", "sendPositionUpdate", this.initializeState);
|
|
478
466
|
if (this.canSendPositionUpdates) {
|
|
479
467
|
// Send position update event
|
|
480
468
|
const evt = this._groupState.createPositionUpdateEvent(state);
|
|
481
|
-
|
|
469
|
+
this._positionUpdateEvent
|
|
470
|
+
?.sendEvent(evt, targetClientId)
|
|
471
|
+
.catch((err) => {
|
|
482
472
|
this._logger.sendErrorEvent(TelemetryEvents.SessionCoordinator
|
|
483
473
|
.PositionUpdateEventError, err);
|
|
484
474
|
});
|
|
@@ -487,7 +477,7 @@ export class LiveMediaSessionCoordinator extends TypedEventEmitter {
|
|
|
487
477
|
// send a local only position update event that was not sent as a signal, and use to handle local
|
|
488
478
|
// position update for clients that have canSendPositionUpdates==false, but are suspending
|
|
489
479
|
const evt = this._groupState.createPositionUpdateEvent(state);
|
|
490
|
-
|
|
480
|
+
this._positionUpdateEvent?.sendLocalEvent(evt).catch((err) => {
|
|
491
481
|
this._logger.sendErrorEvent(TelemetryEvents.SessionCoordinator.PositionUpdateEventError, err);
|
|
492
482
|
});
|
|
493
483
|
}
|
|
@@ -496,49 +486,47 @@ export class LiveMediaSessionCoordinator extends TypedEventEmitter {
|
|
|
496
486
|
this._groupState.syncLocalMediaSession();
|
|
497
487
|
}
|
|
498
488
|
}
|
|
499
|
-
createChildren(acceptTransportChangesFrom) {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
this.
|
|
516
|
-
|
|
489
|
+
async createChildren(acceptTransportChangesFrom) {
|
|
490
|
+
// Create event scopes
|
|
491
|
+
const scope = new LiveEventScope(this._runtime, this._liveRuntime, acceptTransportChangesFrom);
|
|
492
|
+
const unrestrictedScope = new LiveEventScope(this._runtime, this._liveRuntime);
|
|
493
|
+
// Initialize internal coordinator state
|
|
494
|
+
this._groupState = new GroupCoordinatorState(this._runtime, this._liveRuntime, this._maxPlaybackDrift, this._positionUpdateInterval, this._getPlayerState);
|
|
495
|
+
this._groupState.on(GroupCoordinatorStateEvents.triggeraction, (evt) => this.emit(evt.name, evt));
|
|
496
|
+
this._groupState.on(GroupCoordinatorStateEvents.triggeractionignored, (evt) => this.emit(evt.name, evt));
|
|
497
|
+
// Listen for track changes
|
|
498
|
+
this._setTrackEvent = new LiveEventTarget(scope, "setTrack", (event, local) => this._groupState.handleSetTrack(event, local));
|
|
499
|
+
this._setTrackDataEvent = new LiveEventTarget(scope, "setTrackData", (event, local) => this._groupState.handleSetTrackData(event, local));
|
|
500
|
+
// Listen for transport commands
|
|
501
|
+
this._playEvent = new LiveEventTarget(scope, "play", (event, local) => this._groupState.handleTransportCommand(event, local));
|
|
502
|
+
this._pauseEvent = new LiveEventTarget(scope, "pause", (event, local) => this._groupState.handleTransportCommand(event, local));
|
|
503
|
+
this._seekToEvent = new LiveEventTarget(scope, "seekTo", (event, local) => this._groupState.handleTransportCommand(event, local));
|
|
504
|
+
this._rateChangeEvent = new LiveEventTarget(scope, "rateChange", (event, local) => {
|
|
505
|
+
this._groupState.handleRateChangeCommand(event, local);
|
|
506
|
+
});
|
|
507
|
+
// Listen for position updates
|
|
508
|
+
this._positionUpdateEvent = new LiveEventTarget(unrestrictedScope, "positionUpdate", (event, local) => this._groupState.handlePositionUpdate(event, local));
|
|
509
|
+
this._synchronizer = new LiveObjectSynchronizer(this._id, this._runtime, this._liveRuntime);
|
|
510
|
+
this._synchronizer.onJoinedListener = (clientId, timestamp) => {
|
|
511
|
+
this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.RemoteConnectReceived, null, {
|
|
512
|
+
correlationId: LiveTelemetryLogger.formatCorrelationId(clientId, timestamp),
|
|
517
513
|
});
|
|
518
|
-
//
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
this
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
}
|
|
532
|
-
catch (err) {
|
|
533
|
-
// if player is not setup yet, local client might have also just joined and can't send its position.
|
|
534
|
-
const playerNotSetup = isErrorLike(err) &&
|
|
535
|
-
err.message.includes("LiveMediaSession:getCurrentPlayerState");
|
|
536
|
-
if (!playerNotSetup) {
|
|
537
|
-
throw err;
|
|
538
|
-
}
|
|
514
|
+
// Immediately send a position update
|
|
515
|
+
try {
|
|
516
|
+
const state = this._getPlayerState();
|
|
517
|
+
// Send only to the user that joined the session using the targetClientId prop.
|
|
518
|
+
// This ensures that only the user that connected receives this one-time position update, minimizing costs.
|
|
519
|
+
this.sendPositionUpdate(state, clientId);
|
|
520
|
+
}
|
|
521
|
+
catch (err) {
|
|
522
|
+
// if player is not setup yet, local client might have also just joined and can't send its position.
|
|
523
|
+
const playerNotSetup = isErrorLike(err) &&
|
|
524
|
+
err.message.includes("LiveMediaSession:getCurrentPlayerState");
|
|
525
|
+
if (!playerNotSetup) {
|
|
526
|
+
throw err;
|
|
539
527
|
}
|
|
540
|
-
}
|
|
541
|
-
}
|
|
528
|
+
}
|
|
529
|
+
};
|
|
542
530
|
}
|
|
543
531
|
getPlayerPosition() {
|
|
544
532
|
const { positionState, playbackState } = this._getPlayerState();
|