@microsoft/live-share-media 1.0.0-preview.1 → 1.0.0-preview.11

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.
Files changed (111) hide show
  1. package/README.md +15 -13
  2. package/package.json +11 -9
  3. package/src/IMediaPlayer.ts +10 -2
  4. package/src/LiveMediaSession.ts +138 -71
  5. package/src/LiveMediaSessionCoordinator.ts +302 -142
  6. package/src/LiveMediaSessionCoordinatorSuspension.ts +13 -5
  7. package/src/MediaPlayerSynchronizer.ts +329 -149
  8. package/src/MediaSessionActionThrottler.ts +5 -3
  9. package/src/MediaSessionExtensions.ts +15 -5
  10. package/src/RepeatedActionThrottler.ts +27 -9
  11. package/src/VolumeManager.ts +24 -12
  12. package/src/index.ts +9 -10
  13. package/src/internals/GroupCoordinatorState.ts +275 -114
  14. package/src/internals/GroupPlaybackPosition.ts +63 -29
  15. package/src/internals/GroupPlaybackTrack.ts +51 -22
  16. package/src/internals/GroupPlaybackTrackData.ts +24 -16
  17. package/src/internals/GroupTransportState.ts +54 -24
  18. package/src/internals/consts.ts +73 -55
  19. package/src/internals/index.ts +6 -6
  20. package/src/test/GroupPlaybackPosition.spec.ts +371 -111
  21. package/src/test/GroupPlaybackTrack.spec.ts +91 -35
  22. package/src/test/SharedMediaSession.spec.ts +64 -28
  23. package/src/test/SharedMediaSessionCoordinator.spec.ts +86 -46
  24. package/src/test/VolumeManager.spec.ts +38 -31
  25. package/tsconfig.json +1 -0
  26. package/.vscode/launch.json +0 -29
  27. package/.vscode/settings.json +0 -2
  28. package/bin/EphemeralMediaSession.d.ts +0 -102
  29. package/bin/EphemeralMediaSession.d.ts.map +0 -1
  30. package/bin/EphemeralMediaSession.js +0 -226
  31. package/bin/EphemeralMediaSession.js.map +0 -1
  32. package/bin/EphemeralMediaSessionCoordinator.d.ts +0 -228
  33. package/bin/EphemeralMediaSessionCoordinator.d.ts.map +0 -1
  34. package/bin/EphemeralMediaSessionCoordinator.js +0 -396
  35. package/bin/EphemeralMediaSessionCoordinator.js.map +0 -1
  36. package/bin/EphemeralMediaSessionCoordinatorSuspension.d.ts +0 -20
  37. package/bin/EphemeralMediaSessionCoordinatorSuspension.d.ts.map +0 -1
  38. package/bin/EphemeralMediaSessionCoordinatorSuspension.js +0 -28
  39. package/bin/EphemeralMediaSessionCoordinatorSuspension.js.map +0 -1
  40. package/bin/IMediaPlayer.d.ts +0 -21
  41. package/bin/IMediaPlayer.d.ts.map +0 -1
  42. package/bin/IMediaPlayer.js +0 -7
  43. package/bin/IMediaPlayer.js.map +0 -1
  44. package/bin/LiveMediaSession.d.ts +0 -95
  45. package/bin/LiveMediaSession.d.ts.map +0 -1
  46. package/bin/LiveMediaSession.js +0 -217
  47. package/bin/LiveMediaSession.js.map +0 -1
  48. package/bin/LiveMediaSessionCoordinator.d.ts +0 -228
  49. package/bin/LiveMediaSessionCoordinator.d.ts.map +0 -1
  50. package/bin/LiveMediaSessionCoordinator.js +0 -396
  51. package/bin/LiveMediaSessionCoordinator.js.map +0 -1
  52. package/bin/LiveMediaSessionCoordinatorSuspension.d.ts +0 -20
  53. package/bin/LiveMediaSessionCoordinatorSuspension.d.ts.map +0 -1
  54. package/bin/LiveMediaSessionCoordinatorSuspension.js +0 -28
  55. package/bin/LiveMediaSessionCoordinatorSuspension.js.map +0 -1
  56. package/bin/MediaPlayerSynchronizer.d.ts +0 -164
  57. package/bin/MediaPlayerSynchronizer.d.ts.map +0 -1
  58. package/bin/MediaPlayerSynchronizer.js +0 -414
  59. package/bin/MediaPlayerSynchronizer.js.map +0 -1
  60. package/bin/MediaSessionActionThrottler.d.ts +0 -12
  61. package/bin/MediaSessionActionThrottler.d.ts.map +0 -1
  62. package/bin/MediaSessionActionThrottler.js +0 -14
  63. package/bin/MediaSessionActionThrottler.js.map +0 -1
  64. package/bin/MediaSessionExtensions.d.ts +0 -35
  65. package/bin/MediaSessionExtensions.d.ts.map +0 -1
  66. package/bin/MediaSessionExtensions.js +0 -13
  67. package/bin/MediaSessionExtensions.js.map +0 -1
  68. package/bin/RepeatedActionThrottler.d.ts +0 -20
  69. package/bin/RepeatedActionThrottler.d.ts.map +0 -1
  70. package/bin/RepeatedActionThrottler.js +0 -57
  71. package/bin/RepeatedActionThrottler.js.map +0 -1
  72. package/bin/VolumeLimiter.d.ts +0 -70
  73. package/bin/VolumeLimiter.d.ts.map +0 -1
  74. package/bin/VolumeLimiter.js +0 -170
  75. package/bin/VolumeLimiter.js.map +0 -1
  76. package/bin/VolumeManager.d.ts +0 -84
  77. package/bin/VolumeManager.d.ts.map +0 -1
  78. package/bin/VolumeManager.js +0 -173
  79. package/bin/VolumeManager.js.map +0 -1
  80. package/bin/index.d.ts +0 -14
  81. package/bin/index.d.ts.map +0 -1
  82. package/bin/index.js +0 -30
  83. package/bin/index.js.map +0 -1
  84. package/bin/internals/GroupCoordinatorState.d.ts +0 -93
  85. package/bin/internals/GroupCoordinatorState.d.ts.map +0 -1
  86. package/bin/internals/GroupCoordinatorState.js +0 -367
  87. package/bin/internals/GroupCoordinatorState.js.map +0 -1
  88. package/bin/internals/GroupPlaybackPosition.d.ts +0 -67
  89. package/bin/internals/GroupPlaybackPosition.d.ts.map +0 -1
  90. package/bin/internals/GroupPlaybackPosition.js +0 -158
  91. package/bin/internals/GroupPlaybackPosition.js.map +0 -1
  92. package/bin/internals/GroupPlaybackTrack.d.ts +0 -46
  93. package/bin/internals/GroupPlaybackTrack.d.ts.map +0 -1
  94. package/bin/internals/GroupPlaybackTrack.js +0 -112
  95. package/bin/internals/GroupPlaybackTrack.js.map +0 -1
  96. package/bin/internals/GroupPlaybackTrackData.d.ts +0 -40
  97. package/bin/internals/GroupPlaybackTrackData.d.ts.map +0 -1
  98. package/bin/internals/GroupPlaybackTrackData.js +0 -66
  99. package/bin/internals/GroupPlaybackTrackData.js.map +0 -1
  100. package/bin/internals/GroupTransportState.d.ts +0 -49
  101. package/bin/internals/GroupTransportState.d.ts.map +0 -1
  102. package/bin/internals/GroupTransportState.js +0 -97
  103. package/bin/internals/GroupTransportState.js.map +0 -1
  104. package/bin/internals/consts.d.ts +0 -73
  105. package/bin/internals/consts.d.ts.map +0 -1
  106. package/bin/internals/consts.js +0 -82
  107. package/bin/internals/consts.js.map +0 -1
  108. package/bin/internals/index.d.ts +0 -11
  109. package/bin/internals/index.d.ts.map +0 -1
  110. package/bin/internals/index.js +0 -27
  111. package/bin/internals/index.js.map +0 -1
@@ -3,10 +3,35 @@
3
3
  * Licensed under the Microsoft Live Share SDK License.
4
4
  */
5
5
 
6
- import { LiveEventScope, LiveTelemetryLogger, LiveEventTarget, ILiveEvent, IRuntimeSignaler, TimeInterval, UserMeetingRole } from '@microsoft/live-share';
7
- import { CoordinationWaitPoint, ExtendedMediaSessionActionDetails, ExtendedMediaMetadata, ExtendedMediaSessionPlaybackState, MediaSessionCoordinatorEvents, MediaSessionCoordinatorState, MediaSessionCoordinatorSuspension } from './MediaSessionExtensions';
8
- import { TelemetryEvents, ITransportCommandEvent, ISetTrackEvent, IPositionUpdateEvent, GroupCoordinatorState, GroupCoordinatorStateEvents, ITriggerActionEvent, ISetTrackDataEvent } from './internals';
9
- import { LiveMediaSessionCoordinatorSuspension } from './LiveMediaSessionCoordinatorSuspension';
6
+ import {
7
+ LiveEventScope,
8
+ LiveTelemetryLogger,
9
+ LiveEventTarget,
10
+ ILiveEvent,
11
+ IRuntimeSignaler,
12
+ TimeInterval,
13
+ UserMeetingRole,
14
+ } from "@microsoft/live-share";
15
+ import {
16
+ CoordinationWaitPoint,
17
+ ExtendedMediaSessionActionDetails,
18
+ ExtendedMediaMetadata,
19
+ ExtendedMediaSessionPlaybackState,
20
+ MediaSessionCoordinatorEvents,
21
+ MediaSessionCoordinatorState,
22
+ MediaSessionCoordinatorSuspension,
23
+ } from "./MediaSessionExtensions";
24
+ import {
25
+ TelemetryEvents,
26
+ ITransportCommandEvent,
27
+ ISetTrackEvent,
28
+ IPositionUpdateEvent,
29
+ GroupCoordinatorState,
30
+ GroupCoordinatorStateEvents,
31
+ ITriggerActionEvent,
32
+ ISetTrackDataEvent,
33
+ } from "./internals";
34
+ import { LiveMediaSessionCoordinatorSuspension } from "./LiveMediaSessionCoordinatorSuspension";
10
35
  import EventEmitter from "events";
11
36
 
12
37
  /**
@@ -16,15 +41,15 @@ export interface IMediaPlayerState {
16
41
  /**
17
42
  * Metadata for the sessions current track.
18
43
  */
19
- metadata: ExtendedMediaMetadata|null;
44
+ metadata: ExtendedMediaMetadata | null;
20
45
 
21
46
  /**
22
47
  * Optional track data object being synchronized.
23
- *
48
+ *
24
49
  * @remarks
25
50
  * This can be used to sync things like pitch, roll, and yaw when watching 360 videos together.
26
51
  */
27
- trackData: object|null;
52
+ trackData: object | null;
28
53
 
29
54
  /**
30
55
  * Sessions current playback state.
@@ -38,11 +63,11 @@ export interface IMediaPlayerState {
38
63
  }
39
64
 
40
65
  /**
41
- * The `LiveMediaSessionCoordinator` tracks the playback & position state of all other
66
+ * The `LiveMediaSessionCoordinator` tracks the playback & position state of all other
42
67
  * clients being synchronized with. It is responsible for keeping the local media player
43
- * in sync with the group.
68
+ * in sync with the group.
44
69
  */
45
- export class LiveMediaSessionCoordinator extends EventEmitter {
70
+ export class LiveMediaSessionCoordinator extends EventEmitter {
46
71
  private readonly _runtime: IRuntimeSignaler;
47
72
  private readonly _logger: LiveTelemetryLogger;
48
73
  private readonly _getPlayerState: () => IMediaPlayerState;
@@ -62,70 +87,72 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
62
87
 
63
88
  // Distributed state
64
89
  private _groupState?: GroupCoordinatorState;
65
-
90
+
66
91
  /**
67
92
  * @hidden
68
93
  * Applications shouldn't directly create new coordinator instances.
69
94
  */
70
- constructor(runtime: IRuntimeSignaler, getPlayerState: () => IMediaPlayerState) {
95
+ constructor(
96
+ runtime: IRuntimeSignaler,
97
+ getPlayerState: () => IMediaPlayerState
98
+ ) {
71
99
  super();
72
100
  this._runtime = runtime;
73
101
  this._logger = new LiveTelemetryLogger(runtime);
74
102
  this._getPlayerState = getPlayerState;
75
103
  }
76
104
 
77
-
78
105
  /**
79
106
  * Controls whether or not the local client is allowed to instruct the group to play or pause.
80
- *
107
+ *
81
108
  * @remarks
82
- * This flag largely meant to influence decisions made by the coordinator and can be used by
83
- * the UI to determine what controls should be shown to the user. It does not provide any
84
- * security in itself.
85
- *
86
- * If your app is running in a semi-trusted environment where only some clients are allowed
87
- * to play/pause media, you should use "role based verification" to enforce those policies.
109
+ * This flag largely meant to influence decisions made by the coordinator and can be used by
110
+ * the UI to determine what controls should be shown to the user. It does not provide any
111
+ * security in itself.
112
+ *
113
+ * If your app is running in a semi-trusted environment where only some clients are allowed
114
+ * to play/pause media, you should use "role based verification" to enforce those policies.
88
115
  */
89
116
  public canPlayPause: boolean = true;
90
117
 
91
118
  /**
92
- * Controls whether or not the local client is allowed to seek the group to a new playback
119
+ * Controls whether or not the local client is allowed to seek the group to a new playback
93
120
  * position.
94
- *
121
+ *
95
122
  * @remarks
96
- * This flag largely meant to influence decisions made by the coordinator and can be used by
97
- * the UI to determine what controls should be shown to the user. It does not provide any
98
- * security in itself.
99
- *
100
- * If your app is running in a semi-trusted environment where only some clients are allowed
101
- * to change the playback position, you should use "role based verification" to enforce those policies.
123
+ * This flag largely meant to influence decisions made by the coordinator and can be used by
124
+ * the UI to determine what controls should be shown to the user. It does not provide any
125
+ * security in itself.
126
+ *
127
+ * If your app is running in a semi-trusted environment where only some clients are allowed
128
+ * to change the playback position, you should use "role based verification" to enforce those policies.
102
129
  */
103
130
  public canSeek: boolean = true;
104
131
 
105
132
  /**
106
133
  * Controls whether or not the local client is allowed to change tracks.
107
- *
134
+ *
108
135
  * @remarks
109
- * This flag largely meant to influence decisions made by the coordinator and can be used by
110
- * the UI to determine what controls should be shown to the user. It does not provide any
111
- * security in itself.
112
- *
113
- * If your app is running in a semi-trusted environment where only some clients are allowed
114
- * to change tracks, you should use "role based verification" to enforce those policies.
136
+ * This flag largely meant to influence decisions made by the coordinator and can be used by
137
+ * the UI to determine what controls should be shown to the user. It does not provide any
138
+ * security in itself.
139
+ *
140
+ * If your app is running in a semi-trusted environment where only some clients are allowed
141
+ * to change tracks, you should use "role based verification" to enforce those policies.
115
142
  */
116
143
  public canSetTrack: boolean = true;
117
144
 
118
145
  /**
119
146
  * Controls whether or not the local client is allowed to change the tracks custom data object.
120
- *
147
+ *
121
148
  * @remarks
122
- * This flag largely meant to influence decisions made by the coordinator and can be used by
123
- * the UI to determine what controls should be shown to the user. It does not provide any
124
- * security in itself.
125
- *
126
- * If your app is running in a semi-trusted environment where only some clients are allowed
127
- * to change the tracks data object, you should use "role based verification" to enforce those
128
- * policies.
149
+ * This flag largely meant to influence decisions made by the coordinator and can be used by
150
+ * the UI to determine what controls should be shown to the user. It does not provide any
151
+ * security in itself.
152
+ *
153
+ * If your app is running in a semi-trusted environment where only some clients are allowed
154
+ * to change the tracks data object, you should use "role based verification" to enforce those
155
+ * policies.
129
156
  */
130
157
  public canSetTrackData: boolean = true;
131
158
 
@@ -138,11 +165,11 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
138
165
 
139
166
  /**
140
167
  * Max amount of playback drift allowed in seconds.
141
- *
168
+ *
142
169
  * @remarks
143
- * Should the local clients playback position lag by more than the specified value, the
144
- * coordinator will trigger a `catchup` action.
145
- *
170
+ * Should the local clients playback position lag by more than the specified value, the
171
+ * coordinator will trigger a `catchup` action.
172
+ *
146
173
  * Defaults to a value of `1` second.
147
174
  */
148
175
  public get maxPlaybackDrift(): number {
@@ -154,11 +181,11 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
154
181
  }
155
182
 
156
183
  /**
157
- * Frequency with which position updates are broadcast to the rest of the group in
184
+ * Frequency with which position updates are broadcast to the rest of the group in
158
185
  * seconds.
159
- *
186
+ *
160
187
  * @remarks
161
- * Defaults to a value of `2` seconds.
188
+ * Defaults to a value of `2` seconds.
162
189
  */
163
190
  public get positionUpdateInterval(): number {
164
191
  return this._positionUpdateInterval.seconds;
@@ -170,200 +197,273 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
170
197
 
171
198
  /**
172
199
  * Instructs the group to play the current track.
173
- *
200
+ *
174
201
  * @remarks
175
- * Throws an exception if the session/coordinator hasn't been initialized, no track has been
202
+ * Throws an exception if the session/coordinator hasn't been initialized, no track has been
176
203
  * loaded, or `canPlayPause` is false.
177
204
  */
178
205
  public play(): void {
179
206
  if (!this._hasInitialized) {
180
- throw new Error(`LiveMediaSessionCoordinator.play() called before initialize() called.`);
207
+ throw new Error(
208
+ `LiveMediaSessionCoordinator.play() called before initialize() called.`
209
+ );
181
210
  }
182
211
 
183
212
  if (!this._groupState?.playbackTrack.current.metadata) {
184
- throw new Error(`LiveMediaSessionCoordinator.play() called before MediaSession.metadata assigned.`);
213
+ throw new Error(
214
+ `LiveMediaSessionCoordinator.play() called before MediaSession.metadata assigned.`
215
+ );
185
216
  }
186
217
 
187
218
  if (!this.canPlayPause) {
188
- throw new Error(`LiveMediaSessionCoordinator.play() operation blocked.`);
219
+ throw new Error(
220
+ `LiveMediaSessionCoordinator.play() operation blocked.`
221
+ );
189
222
  }
190
223
 
191
224
  // Get projected position
192
225
  const position = this.getPlayerPosition();
193
226
 
194
227
  // Send transport command
195
- this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.PlayCalled, null, {position: position});
228
+ this._logger.sendTelemetryEvent(
229
+ TelemetryEvents.SessionCoordinator.PlayCalled,
230
+ null,
231
+ { position: position }
232
+ );
196
233
  this._playEvent!.sendEvent({
197
234
  track: this._groupState.playbackTrack.current,
198
- position: position
235
+ position: position,
199
236
  });
200
237
  }
201
-
238
+
202
239
  /**
203
240
  * Instructs the group to pause the current track.
204
- *
241
+ *
205
242
  * @remarks
206
- * Throws an exception if the session/coordinator hasn't been initialized, no track has been
243
+ * Throws an exception if the session/coordinator hasn't been initialized, no track has been
207
244
  * loaded, or `canPlayPause` is false.
208
245
  */
209
246
  public pause(): void {
210
247
  if (!this._hasInitialized) {
211
- throw new Error(`LiveMediaSessionCoordinator.pause() called before initialize() called.`);
248
+ throw new Error(
249
+ `LiveMediaSessionCoordinator.pause() called before initialize() called.`
250
+ );
212
251
  }
213
252
 
214
253
  if (!this._groupState?.playbackTrack.current.metadata) {
215
- throw new Error(`LiveMediaSessionCoordinator.pause() called before MediaSession.metadata assigned.`);
254
+ throw new Error(
255
+ `LiveMediaSessionCoordinator.pause() called before MediaSession.metadata assigned.`
256
+ );
216
257
  }
217
258
 
218
259
  if (!this.canPlayPause) {
219
- throw new Error(`LiveMediaSessionCoordinator.pause() operation blocked.`);
260
+ throw new Error(
261
+ `LiveMediaSessionCoordinator.pause() operation blocked.`
262
+ );
220
263
  }
221
264
 
222
265
  // Get projected position
223
266
  const position = this.getPlayerPosition();
224
267
 
225
268
  // Send transport command
226
- this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.PauseCalled, null, {position: position});
269
+ this._logger.sendTelemetryEvent(
270
+ TelemetryEvents.SessionCoordinator.PauseCalled,
271
+ null,
272
+ { position: position }
273
+ );
227
274
  this._pauseEvent!.sendEvent({
228
275
  track: this._groupState.playbackTrack.current,
229
- position: position
276
+ position: position,
230
277
  });
231
278
  }
232
279
 
233
280
  /**
234
281
  * Instructs the group to seek to a new position within the current track.
235
- *
282
+ *
236
283
  * @remarks
237
- * Throws an exception if the session/coordinator hasn't been initialized, no track has been
284
+ * Throws an exception if the session/coordinator hasn't been initialized, no track has been
238
285
  * loaded, or `canSeek` is false.
239
286
  * @param time Playback position in seconds to seek to.
240
287
  */
241
288
  public seekTo(time: number): void {
242
289
  if (!this._hasInitialized) {
243
- throw new Error(`LiveMediaSessionCoordinator.seekTo() called before initialize() called.`);
290
+ throw new Error(
291
+ `LiveMediaSessionCoordinator.seekTo() called before initialize() called.`
292
+ );
244
293
  }
245
294
 
246
295
  if (!this._groupState?.playbackTrack.current.metadata) {
247
- throw new Error(`LiveMediaSessionCoordinator.seekTo() called before MediaSession.metadata assigned.`);
296
+ throw new Error(
297
+ `LiveMediaSessionCoordinator.seekTo() called before MediaSession.metadata assigned.`
298
+ );
248
299
  }
249
300
 
250
301
  if (!this.canSeek) {
251
- throw new Error(`LiveMediaSessionCoordinator.seekTo() operation blocked.`);
302
+ throw new Error(
303
+ `LiveMediaSessionCoordinator.seekTo() operation blocked.`
304
+ );
252
305
  }
253
306
 
254
307
  // Send transport command
255
- this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.SeekToCalled, null, {position: time});
308
+ this._logger.sendTelemetryEvent(
309
+ TelemetryEvents.SessionCoordinator.SeekToCalled,
310
+ null,
311
+ { position: time }
312
+ );
256
313
  this._seekToEvent!.sendEvent({
257
314
  track: this._groupState.playbackTrack.current,
258
- position: time
315
+ position: time,
259
316
  });
260
317
  }
261
318
 
262
319
  /**
263
320
  * Instructs the group to load a new track.
264
- *
321
+ *
265
322
  * @remarks
266
- * Throws an exception if the session/coordinator hasn't been initialized or `canSetTrack` is
323
+ * Throws an exception if the session/coordinator hasn't been initialized or `canSetTrack` is
267
324
  * false.
268
325
  * @param metadata The track to load or `null` to indicate that the end of the track is reached.
269
326
  * @param waitPoints Optional. List of static wait points to configure for the track. Dynamic wait points can be added via the `beginSuspension()` call.
270
327
  */
271
- public setTrack(metadata: ExtendedMediaMetadata|null, waitPoints?: CoordinationWaitPoint[]): void {
328
+ public setTrack(
329
+ metadata: ExtendedMediaMetadata | null,
330
+ waitPoints?: CoordinationWaitPoint[]
331
+ ): void {
272
332
  if (!this._hasInitialized) {
273
- throw new Error(`LiveMediaSessionCoordinator.setTrack() called before initialize() called.`);
333
+ throw new Error(
334
+ `LiveMediaSessionCoordinator.setTrack() called before initialize() called.`
335
+ );
274
336
  }
275
337
 
276
338
  if (!this.canSetTrack) {
277
- throw new Error(`LiveMediaSessionCoordinator.setTrack() operation blocked.`);
339
+ throw new Error(
340
+ `LiveMediaSessionCoordinator.setTrack() operation blocked.`
341
+ );
278
342
  }
279
343
 
280
344
  // Send transport command
281
- this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.SetTrackCalled);
345
+ this._logger.sendTelemetryEvent(
346
+ TelemetryEvents.SessionCoordinator.SetTrackCalled
347
+ );
282
348
  this._setTrackEvent!.sendEvent({
283
349
  metadata: metadata,
284
- waitPoints: waitPoints || []
350
+ waitPoints: waitPoints || [],
285
351
  });
286
352
  }
287
353
 
288
354
  /**
289
355
  * Updates the track data object for the current track.
290
- *
356
+ *
291
357
  * @remarks
292
- * The track data object can be used by applications to synchronize things like pitch, roll,
293
- * and yaw of a 360 video. This data object will be reset to null anytime the track changes.
294
- *
295
- * Throws an exception if the session/coordinator hasn't been initialized or `canSetTrackData` is
358
+ * The track data object can be used by applications to synchronize things like pitch, roll,
359
+ * and yaw of a 360 video. This data object will be reset to null anytime the track changes.
360
+ *
361
+ * Throws an exception if the session/coordinator hasn't been initialized or `canSetTrackData` is
296
362
  * false.
297
- * @param data New data object to sync with the group. This value will be synchronized using a last writer wins strategy.
363
+ * @param data New data object to sync with the group. This value will be synchronized using a last writer wins strategy.
298
364
  */
299
- public setTrackData(data: object|null): void {
365
+ public setTrackData(data: object | null): void {
300
366
  if (!this._hasInitialized) {
301
- throw new Error(`LiveMediaSessionCoordinator.setTrackData() called before initialize() called.`);
367
+ throw new Error(
368
+ `LiveMediaSessionCoordinator.setTrackData() called before initialize() called.`
369
+ );
302
370
  }
303
371
 
304
372
  if (!this.canSetTrackData) {
305
- throw new Error(`LiveMediaSessionCoordinator.setTrackData() operation blocked.`);
373
+ throw new Error(
374
+ `LiveMediaSessionCoordinator.setTrackData() operation blocked.`
375
+ );
306
376
  }
307
377
 
308
378
  // Send transport command
309
- this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.SetTrackDataCalled);
379
+ this._logger.sendTelemetryEvent(
380
+ TelemetryEvents.SessionCoordinator.SetTrackDataCalled
381
+ );
310
382
  this._setTrackDataEvent!.sendEvent({
311
- data: data
383
+ data: data,
312
384
  });
313
385
  }
314
386
 
315
387
  /**
316
388
  * Begins a new local suspension.
317
- *
389
+ *
318
390
  * @remarks
319
- * Suspension temporarily suspend the clients local synchronization with the group. This can
320
- * be useful for displaying ads to users or temporarily disconnecting from the session while
321
- * the user seeks the video using a timeline scrubber.
322
- *
323
- * Multiple simultaneous suspensions are allowed and when the last suspension ends the local
391
+ * Suspension temporarily suspend the clients local synchronization with the group. This can
392
+ * be useful for displaying ads to users or temporarily disconnecting from the session while
393
+ * the user seeks the video using a timeline scrubber.
394
+ *
395
+ * Multiple simultaneous suspensions are allowed and when the last suspension ends the local
324
396
  * client will be immediately re-synchronized with the group.
325
- *
326
- * A "Dynamic Wait Point" can be specified when `beginSuspension()` is called and the wait
327
- * point will be broadcast to all other clients in the group. Those clients will then
328
- * automatically enter a suspension state once they reach the positions specified by the
329
- * wait point. Clients that are passed the wait point will immediately suspend.
330
- *
331
- * Any wait point based suspension (dynamic or static) will result in all clients remaining
397
+ *
398
+ * A "Dynamic Wait Point" can be specified when `beginSuspension()` is called and the wait
399
+ * point will be broadcast to all other clients in the group. Those clients will then
400
+ * automatically enter a suspension state once they reach the positions specified by the
401
+ * wait point. Clients that are passed the wait point will immediately suspend.
402
+ *
403
+ * Any wait point based suspension (dynamic or static) will result in all clients remaining
332
404
  * in a suspension state until the list client ends their suspension. This behavior can be
333
405
  * conditionally bypassed by settings the wait points `maxClients` value.
334
- *
406
+ *
335
407
  * Throws an exception if the session/coordinator hasn't been initialized.
336
- * @param waitPoint Optional. Dynamic wait point to broadcast to all of the clients.
408
+ * @param waitPoint Optional. Dynamic wait point to broadcast to all of the clients.
337
409
  * @returns The suspension object. Call `end()` on the returned suspension to end the suspension.
338
410
  */
339
- public beginSuspension(waitPoint?: CoordinationWaitPoint): MediaSessionCoordinatorSuspension {
411
+ public beginSuspension(
412
+ waitPoint?: CoordinationWaitPoint
413
+ ): MediaSessionCoordinatorSuspension {
340
414
  if (!this._hasInitialized) {
341
- throw new Error(`LiveMediaSessionCoordinator.beginSuspension() called before initialize() called.`);
415
+ throw new Error(
416
+ `LiveMediaSessionCoordinator.beginSuspension() called before initialize() called.`
417
+ );
342
418
  }
343
419
 
344
420
  if (!this._groupState?.playbackTrack.current.metadata) {
345
- throw new Error(`LiveMediaSessionCoordinator.beginSuspension() called before MediaSession.metadata assigned.`);
421
+ throw new Error(
422
+ `LiveMediaSessionCoordinator.beginSuspension() called before MediaSession.metadata assigned.`
423
+ );
346
424
  }
347
425
 
348
426
  // Tell group state that suspension is started
349
427
  if (waitPoint) {
350
- this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.BeginSuspensionAndWait, null, {position: waitPoint.position, maxClients: waitPoint.maxClients});
428
+ this._logger.sendTelemetryEvent(
429
+ TelemetryEvents.SessionCoordinator.BeginSuspensionAndWait,
430
+ null,
431
+ {
432
+ position: waitPoint.position,
433
+ maxClients: waitPoint.maxClients,
434
+ }
435
+ );
351
436
  this._lastWaitPoint = waitPoint;
352
437
  this._groupState.beginSuspension(waitPoint);
353
438
  } else {
354
- this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.BeginSuspension);
439
+ this._logger.sendTelemetryEvent(
440
+ TelemetryEvents.SessionCoordinator.BeginSuspension
441
+ );
355
442
  this._groupState.beginSuspension();
356
443
  }
357
444
 
358
445
  // Return new suspension object
359
- return new LiveMediaSessionCoordinatorSuspension(waitPoint, time => {
446
+ return new LiveMediaSessionCoordinatorSuspension(waitPoint, (time) => {
360
447
  if (waitPoint) {
361
- this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.EndSuspensionAndWait, null, {position: waitPoint.position, maxClients: waitPoint.maxClients});
448
+ this._logger.sendTelemetryEvent(
449
+ TelemetryEvents.SessionCoordinator.EndSuspensionAndWait,
450
+ null,
451
+ {
452
+ position: waitPoint.position,
453
+ maxClients: waitPoint.maxClients,
454
+ }
455
+ );
362
456
  } else {
363
- this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.EndSuspension);
457
+ this._logger.sendTelemetryEvent(
458
+ TelemetryEvents.SessionCoordinator.EndSuspension
459
+ );
364
460
  }
365
461
  this._groupState!.endSuspension(time == undefined);
366
- if (time != undefined && !this._groupState?.isSuspended && !this._groupState?.isWaiting) {
462
+ if (
463
+ time != undefined &&
464
+ !this._groupState?.isSuspended &&
465
+ !this._groupState?.isWaiting
466
+ ) {
367
467
  // Seek to new position
368
468
  this.seekTo(Math.max(time, 0.0));
369
469
  }
@@ -374,7 +474,7 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
374
474
  * @hidden
375
475
  * Called by MediaSession to verify the coordinator has been initialized.
376
476
  */
377
- public get isInitialized(): boolean {
477
+ public get isInitialized(): boolean {
378
478
  return this._hasInitialized;
379
479
  }
380
480
 
@@ -382,9 +482,13 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
382
482
  * @hidden
383
483
  * Called by MediaSession to start coordinator.
384
484
  */
385
- public async initialize(acceptTransportChangesFrom?: UserMeetingRole[]): Promise<void> {
485
+ public async initialize(
486
+ acceptTransportChangesFrom?: UserMeetingRole[]
487
+ ): Promise<void> {
386
488
  if (this._hasInitialized) {
387
- throw new Error(`LiveMediaSessionCoordinator.initialize() already initialized.`);
489
+ throw new Error(
490
+ `LiveMediaSessionCoordinator.initialize() already initialized.`
491
+ );
388
492
  }
389
493
 
390
494
  // Create children
@@ -396,8 +500,12 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
396
500
  * @hidden
397
501
  * Called by the MediaSession to detect if a wait point has been hit.
398
502
  */
399
- public findNextWaitPoint(): CoordinationWaitPoint|null {
400
- return this._groupState?.playbackTrack.findNextWaitPoint(this._lastWaitPoint) || null;
503
+ public findNextWaitPoint(): CoordinationWaitPoint | null {
504
+ return (
505
+ this._groupState?.playbackTrack.findNextWaitPoint(
506
+ this._lastWaitPoint
507
+ ) || null
508
+ );
401
509
  }
402
510
 
403
511
  /**
@@ -406,43 +514,93 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
406
514
  */
407
515
  public sendPositionUpdate(state: IMediaPlayerState): void {
408
516
  if (!this._hasInitialized) {
409
- throw new Error(`LiveMediaSessionCoordinator.sendPositionUpdate() called before initialize() called.`);
517
+ throw new Error(
518
+ `LiveMediaSessionCoordinator.sendPositionUpdate() called before initialize() called.`
519
+ );
410
520
  }
411
521
 
412
522
  // Send position update event
413
523
  const evt = this._groupState!.createPositionUpdateEvent(state);
414
524
  this._positionUpdateEvent?.sendEvent(evt);
415
525
  }
416
-
417
- protected async createChildren(acceptTransportChangesFrom?: UserMeetingRole[]): Promise<void> {
526
+
527
+ protected async createChildren(
528
+ acceptTransportChangesFrom?: UserMeetingRole[]
529
+ ): Promise<void> {
418
530
  // Create event scopes
419
- const scope = new LiveEventScope(this._runtime, acceptTransportChangesFrom);
531
+ const scope = new LiveEventScope(
532
+ this._runtime,
533
+ acceptTransportChangesFrom
534
+ );
420
535
  const unrestrictedScope = new LiveEventScope(this._runtime);
421
536
 
422
537
  // Initialize internal coordinator state
423
- this._groupState = new GroupCoordinatorState(this._runtime, this._maxPlaybackDrift, this._positionUpdateInterval, this._getPlayerState);
424
- this._groupState.on(GroupCoordinatorStateEvents.triggeraction, evt => this.emit(evt.name, evt));
538
+ this._groupState = new GroupCoordinatorState(
539
+ this._runtime,
540
+ this._maxPlaybackDrift,
541
+ this._positionUpdateInterval,
542
+ this._getPlayerState
543
+ );
544
+ this._groupState.on(GroupCoordinatorStateEvents.triggeraction, (evt) =>
545
+ this.emit(evt.name, evt)
546
+ );
425
547
 
426
548
  // Listen for track changes
427
- this._setTrackEvent = new LiveEventTarget<ISetTrackEvent>(scope, 'setTrack', (event, local) => this._groupState!.handleSetTrack(event, local));
428
- this._setTrackDataEvent = new LiveEventTarget<ISetTrackDataEvent>(scope, 'setTrackData', (event, local) => this._groupState!.handleSetTrackData(event, local));
549
+ this._setTrackEvent = new LiveEventTarget<ISetTrackEvent>(
550
+ scope,
551
+ "setTrack",
552
+ (event, local) => this._groupState!.handleSetTrack(event, local)
553
+ );
554
+ this._setTrackDataEvent = new LiveEventTarget<ISetTrackDataEvent>(
555
+ scope,
556
+ "setTrackData",
557
+ (event, local) => this._groupState!.handleSetTrackData(event, local)
558
+ );
429
559
 
430
560
  // Listen for transport commands
431
- this._playEvent = new LiveEventTarget(scope, 'play', (event, local) => this._groupState!.handleTransportCommand(event, local));
432
- this._pauseEvent = new LiveEventTarget(scope, 'pause', (event, local) => this._groupState!.handleTransportCommand(event, local));
433
- this._seekToEvent = new LiveEventTarget(scope, 'seekTo', (event, local) => this._groupState!.handleTransportCommand(event, local));
561
+ this._playEvent = new LiveEventTarget(scope, "play", (event, local) =>
562
+ this._groupState!.handleTransportCommand(event, local)
563
+ );
564
+ this._pauseEvent = new LiveEventTarget(scope, "pause", (event, local) =>
565
+ this._groupState!.handleTransportCommand(event, local)
566
+ );
567
+ this._seekToEvent = new LiveEventTarget(
568
+ scope,
569
+ "seekTo",
570
+ (event, local) =>
571
+ this._groupState!.handleTransportCommand(event, local)
572
+ );
434
573
 
435
574
  // Listen for position updates
436
- this._positionUpdateEvent = new LiveEventTarget(unrestrictedScope, 'positionUpdate', (event, local) => this._groupState!.handlePositionUpdate(event, local));
575
+ this._positionUpdateEvent = new LiveEventTarget(
576
+ unrestrictedScope,
577
+ "positionUpdate",
578
+ (event, local) =>
579
+ this._groupState!.handlePositionUpdate(event, local)
580
+ );
437
581
 
438
582
  // Listen for joined event
439
- this._joinedEvent = new LiveEventTarget(unrestrictedScope, 'joined', (evt, local) => {
440
- // Immediately send a position update
441
- this._logger.sendTelemetryEvent(TelemetryEvents.SessionCoordinator.RemoteJoinReceived, null, {correlationId: LiveTelemetryLogger.formatCorrelationId(evt.clientId, evt.timestamp)});
442
- const state = this._getPlayerState();
443
- const update = this._groupState!.createPositionUpdateEvent(state);
444
- this._positionUpdateEvent?.sendEvent(update);
445
- });
583
+ this._joinedEvent = new LiveEventTarget(
584
+ unrestrictedScope,
585
+ "joined",
586
+ (evt, local) => {
587
+ // Immediately send a position update
588
+ this._logger.sendTelemetryEvent(
589
+ TelemetryEvents.SessionCoordinator.RemoteJoinReceived,
590
+ null,
591
+ {
592
+ correlationId: LiveTelemetryLogger.formatCorrelationId(
593
+ evt.clientId,
594
+ evt.timestamp
595
+ ),
596
+ }
597
+ );
598
+ const state = this._getPlayerState();
599
+ const update =
600
+ this._groupState!.createPositionUpdateEvent(state);
601
+ this._positionUpdateEvent?.sendEvent(update);
602
+ }
603
+ );
446
604
 
447
605
  // Send initial joined event
448
606
  this._joinedEvent.sendEvent({});
@@ -451,11 +609,13 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
451
609
  private getPlayerPosition(): number {
452
610
  const { positionState, playbackState } = this._getPlayerState();
453
611
  switch (playbackState) {
454
- case 'none':
455
- case 'ended':
612
+ case "none":
613
+ case "ended":
456
614
  return 0.0;
457
615
  default:
458
- return positionState && positionState.position != undefined ? positionState.position : 0.0;
616
+ return positionState && positionState.position != undefined
617
+ ? positionState.position
618
+ : 0.0;
459
619
  }
460
- }
620
+ }
461
621
  }