@microsoft/live-share-media 1.0.0-preview.9 → 1.0.1
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/LICENSE +64 -61
- package/README.md +7 -13
- package/bin/IMediaPlayer.d.ts +20 -20
- package/bin/IMediaPlayer.js +6 -6
- package/bin/LiveMediaSession.d.ts +90 -94
- package/bin/LiveMediaSession.d.ts.map +1 -1
- package/bin/LiveMediaSession.js +228 -231
- package/bin/LiveMediaSession.js.map +1 -1
- package/bin/LiveMediaSessionCoordinator.d.ts +238 -227
- package/bin/LiveMediaSessionCoordinator.d.ts.map +1 -1
- package/bin/LiveMediaSessionCoordinator.js +476 -407
- package/bin/LiveMediaSessionCoordinator.js.map +1 -1
- package/bin/LiveMediaSessionCoordinatorSuspension.d.ts +19 -19
- package/bin/LiveMediaSessionCoordinatorSuspension.js +27 -27
- package/bin/MediaPlayerSynchronizer.d.ts +174 -163
- package/bin/MediaPlayerSynchronizer.d.ts.map +1 -1
- package/bin/MediaPlayerSynchronizer.js +503 -468
- package/bin/MediaPlayerSynchronizer.js.map +1 -1
- package/bin/MediaSessionActionThrottler.d.ts +11 -11
- package/bin/MediaSessionActionThrottler.js +13 -13
- package/bin/MediaSessionExtensions.d.ts +34 -34
- package/bin/MediaSessionExtensions.d.ts.map +1 -1
- package/bin/MediaSessionExtensions.js +12 -12
- package/bin/RepeatedActionThrottler.d.ts +19 -19
- package/bin/RepeatedActionThrottler.js +62 -62
- package/bin/RepeatedActionThrottler.js.map +1 -1
- package/bin/VolumeManager.d.ts +83 -83
- package/bin/VolumeManager.d.ts.map +1 -1
- package/bin/VolumeManager.js +174 -174
- package/bin/VolumeManager.js.map +1 -1
- package/bin/index.d.ts +13 -13
- package/bin/index.js +29 -29
- package/bin/internals/GroupCoordinatorState.d.ts +93 -92
- package/bin/internals/GroupCoordinatorState.d.ts.map +1 -1
- package/bin/internals/GroupCoordinatorState.js +407 -404
- package/bin/internals/GroupCoordinatorState.js.map +1 -1
- package/bin/internals/GroupPlaybackPosition.d.ts +67 -66
- package/bin/internals/GroupPlaybackPosition.d.ts.map +1 -1
- package/bin/internals/GroupPlaybackPosition.js +165 -166
- package/bin/internals/GroupPlaybackPosition.js.map +1 -1
- package/bin/internals/GroupPlaybackTrack.d.ts +45 -45
- package/bin/internals/GroupPlaybackTrack.d.ts.map +1 -1
- package/bin/internals/GroupPlaybackTrack.js +121 -121
- package/bin/internals/GroupPlaybackTrackData.d.ts +39 -39
- package/bin/internals/GroupPlaybackTrackData.d.ts.map +1 -1
- package/bin/internals/GroupPlaybackTrackData.js +69 -69
- package/bin/internals/GroupTransportState.d.ts +49 -48
- package/bin/internals/GroupTransportState.d.ts.map +1 -1
- package/bin/internals/GroupTransportState.js +111 -111
- package/bin/internals/GroupTransportState.js.map +1 -1
- package/bin/internals/consts.d.ts +75 -72
- package/bin/internals/consts.d.ts.map +1 -1
- package/bin/internals/consts.js +84 -81
- package/bin/internals/consts.js.map +1 -1
- package/bin/internals/index.d.ts +10 -10
- package/bin/internals/index.js +26 -26
- package/package.json +16 -9
- package/src/LiveMediaSession.ts +24 -20
- package/src/LiveMediaSessionCoordinator.ts +101 -29
- package/src/MediaPlayerSynchronizer.ts +47 -15
- package/src/VolumeManager.ts +4 -1
- package/src/internals/GroupCoordinatorState.ts +50 -35
- package/src/internals/GroupPlaybackPosition.ts +8 -7
- package/src/internals/GroupPlaybackTrack.ts +2 -2
- package/src/internals/GroupPlaybackTrackData.ts +2 -2
- package/src/internals/GroupTransportState.ts +11 -4
- package/src/internals/consts.ts +4 -0
- package/typedoc.json +10 -0
- package/bin/EphemeralMediaSession.d.ts +0 -102
- package/bin/EphemeralMediaSession.d.ts.map +0 -1
- package/bin/EphemeralMediaSession.js +0 -226
- package/bin/EphemeralMediaSession.js.map +0 -1
- package/bin/EphemeralMediaSessionCoordinator.d.ts +0 -228
- package/bin/EphemeralMediaSessionCoordinator.d.ts.map +0 -1
- package/bin/EphemeralMediaSessionCoordinator.js +0 -396
- package/bin/EphemeralMediaSessionCoordinator.js.map +0 -1
- package/bin/EphemeralMediaSessionCoordinatorSuspension.d.ts +0 -20
- package/bin/EphemeralMediaSessionCoordinatorSuspension.d.ts.map +0 -1
- package/bin/EphemeralMediaSessionCoordinatorSuspension.js +0 -28
- package/bin/EphemeralMediaSessionCoordinatorSuspension.js.map +0 -1
- package/bin/VolumeLimiter.d.ts +0 -70
- package/bin/VolumeLimiter.d.ts.map +0 -1
- package/bin/VolumeLimiter.js +0 -170
- package/bin/VolumeLimiter.js.map +0 -1
- package/src/test/GroupPlaybackPosition.spec.ts +0 -600
- package/src/test/GroupPlaybackTrack.spec.ts +0 -122
- package/src/test/SharedMediaSession.spec.ts +0 -149
- package/src/test/SharedMediaSessionCoordinator.spec.ts +0 -271
- package/src/test/VolumeManager.spec.ts +0 -219
|
@@ -7,18 +7,15 @@ import {
|
|
|
7
7
|
LiveEventScope,
|
|
8
8
|
LiveTelemetryLogger,
|
|
9
9
|
LiveEventTarget,
|
|
10
|
-
ILiveEvent,
|
|
11
10
|
IRuntimeSignaler,
|
|
12
11
|
TimeInterval,
|
|
13
12
|
UserMeetingRole,
|
|
13
|
+
LiveShareRuntime,
|
|
14
14
|
} from "@microsoft/live-share";
|
|
15
15
|
import {
|
|
16
16
|
CoordinationWaitPoint,
|
|
17
|
-
ExtendedMediaSessionActionDetails,
|
|
18
17
|
ExtendedMediaMetadata,
|
|
19
18
|
ExtendedMediaSessionPlaybackState,
|
|
20
|
-
MediaSessionCoordinatorEvents,
|
|
21
|
-
MediaSessionCoordinatorState,
|
|
22
19
|
MediaSessionCoordinatorSuspension,
|
|
23
20
|
} from "./MediaSessionExtensions";
|
|
24
21
|
import {
|
|
@@ -28,7 +25,6 @@ import {
|
|
|
28
25
|
IPositionUpdateEvent,
|
|
29
26
|
GroupCoordinatorState,
|
|
30
27
|
GroupCoordinatorStateEvents,
|
|
31
|
-
ITriggerActionEvent,
|
|
32
28
|
ISetTrackDataEvent,
|
|
33
29
|
} from "./internals";
|
|
34
30
|
import { LiveMediaSessionCoordinatorSuspension } from "./LiveMediaSessionCoordinatorSuspension";
|
|
@@ -69,6 +65,7 @@ export interface IMediaPlayerState {
|
|
|
69
65
|
*/
|
|
70
66
|
export class LiveMediaSessionCoordinator extends EventEmitter {
|
|
71
67
|
private readonly _runtime: IRuntimeSignaler;
|
|
68
|
+
private readonly _liveRuntime: LiveShareRuntime;
|
|
72
69
|
private readonly _logger: LiveTelemetryLogger;
|
|
73
70
|
private readonly _getPlayerState: () => IMediaPlayerState;
|
|
74
71
|
private _positionUpdateInterval = new TimeInterval(2000);
|
|
@@ -83,22 +80,26 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
|
|
|
83
80
|
private _setTrackEvent?: LiveEventTarget<ISetTrackEvent>;
|
|
84
81
|
private _setTrackDataEvent?: LiveEventTarget<ISetTrackDataEvent>;
|
|
85
82
|
private _positionUpdateEvent?: LiveEventTarget<IPositionUpdateEvent>;
|
|
86
|
-
private _joinedEvent?: LiveEventTarget<
|
|
83
|
+
private _joinedEvent?: LiveEventTarget<undefined>;
|
|
87
84
|
|
|
88
85
|
// Distributed state
|
|
89
86
|
private _groupState?: GroupCoordinatorState;
|
|
90
87
|
|
|
88
|
+
private _allowedRoles?: UserMeetingRole[];
|
|
89
|
+
|
|
91
90
|
/**
|
|
92
91
|
* @hidden
|
|
93
92
|
* Applications shouldn't directly create new coordinator instances.
|
|
94
93
|
*/
|
|
95
94
|
constructor(
|
|
96
95
|
runtime: IRuntimeSignaler,
|
|
96
|
+
liveRuntime: LiveShareRuntime,
|
|
97
97
|
getPlayerState: () => IMediaPlayerState
|
|
98
98
|
) {
|
|
99
99
|
super();
|
|
100
100
|
this._runtime = runtime;
|
|
101
|
-
this.
|
|
101
|
+
this._liveRuntime = liveRuntime;
|
|
102
|
+
this._logger = new LiveTelemetryLogger(runtime, liveRuntime);
|
|
102
103
|
this._getPlayerState = getPlayerState;
|
|
103
104
|
}
|
|
104
105
|
|
|
@@ -201,8 +202,10 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
|
|
|
201
202
|
* @remarks
|
|
202
203
|
* Throws an exception if the session/coordinator hasn't been initialized, no track has been
|
|
203
204
|
* loaded, or `canPlayPause` is false.
|
|
205
|
+
*
|
|
206
|
+
* @returns a void promise that resolves once complete, throws if user does not have proper roles
|
|
204
207
|
*/
|
|
205
|
-
public play(): void {
|
|
208
|
+
public async play(): Promise<void> {
|
|
206
209
|
if (!this._hasInitialized) {
|
|
207
210
|
throw new Error(
|
|
208
211
|
`LiveMediaSessionCoordinator.play() called before initialize() called.`
|
|
@@ -230,7 +233,7 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
|
|
|
230
233
|
null,
|
|
231
234
|
{ position: position }
|
|
232
235
|
);
|
|
233
|
-
this._playEvent!.sendEvent({
|
|
236
|
+
await this._playEvent!.sendEvent({
|
|
234
237
|
track: this._groupState.playbackTrack.current,
|
|
235
238
|
position: position,
|
|
236
239
|
});
|
|
@@ -242,8 +245,10 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
|
|
|
242
245
|
* @remarks
|
|
243
246
|
* Throws an exception if the session/coordinator hasn't been initialized, no track has been
|
|
244
247
|
* loaded, or `canPlayPause` is false.
|
|
248
|
+
*
|
|
249
|
+
* @returns a void promise that resolves once complete, throws if user does not have proper roles
|
|
245
250
|
*/
|
|
246
|
-
public pause(): void {
|
|
251
|
+
public async pause(): Promise<void> {
|
|
247
252
|
if (!this._hasInitialized) {
|
|
248
253
|
throw new Error(
|
|
249
254
|
`LiveMediaSessionCoordinator.pause() called before initialize() called.`
|
|
@@ -271,7 +276,7 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
|
|
|
271
276
|
null,
|
|
272
277
|
{ position: position }
|
|
273
278
|
);
|
|
274
|
-
this._pauseEvent!.sendEvent({
|
|
279
|
+
await this._pauseEvent!.sendEvent({
|
|
275
280
|
track: this._groupState.playbackTrack.current,
|
|
276
281
|
position: position,
|
|
277
282
|
});
|
|
@@ -284,8 +289,9 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
|
|
|
284
289
|
* Throws an exception if the session/coordinator hasn't been initialized, no track has been
|
|
285
290
|
* loaded, or `canSeek` is false.
|
|
286
291
|
* @param time Playback position in seconds to seek to.
|
|
292
|
+
* @returns a void promise that resolves once complete, throws if user does not have proper roles
|
|
287
293
|
*/
|
|
288
|
-
public seekTo(time: number): void {
|
|
294
|
+
public async seekTo(time: number): Promise<void> {
|
|
289
295
|
if (!this._hasInitialized) {
|
|
290
296
|
throw new Error(
|
|
291
297
|
`LiveMediaSessionCoordinator.seekTo() called before initialize() called.`
|
|
@@ -310,10 +316,15 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
|
|
|
310
316
|
null,
|
|
311
317
|
{ position: time }
|
|
312
318
|
);
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
319
|
+
try {
|
|
320
|
+
await this._seekToEvent!.sendEvent({
|
|
321
|
+
track: this._groupState.playbackTrack.current,
|
|
322
|
+
position: time,
|
|
323
|
+
});
|
|
324
|
+
} catch (err) {
|
|
325
|
+
await this._groupState!.syncLocalMediaSession();
|
|
326
|
+
throw err;
|
|
327
|
+
}
|
|
317
328
|
}
|
|
318
329
|
|
|
319
330
|
/**
|
|
@@ -324,11 +335,12 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
|
|
|
324
335
|
* false.
|
|
325
336
|
* @param metadata The track to load or `null` to indicate that the end of the track is reached.
|
|
326
337
|
* @param waitPoints Optional. List of static wait points to configure for the track. Dynamic wait points can be added via the `beginSuspension()` call.
|
|
338
|
+
* @returns a void promise that resolves once complete, throws if user does not have proper roles
|
|
327
339
|
*/
|
|
328
|
-
public setTrack(
|
|
340
|
+
public async setTrack(
|
|
329
341
|
metadata: ExtendedMediaMetadata | null,
|
|
330
342
|
waitPoints?: CoordinationWaitPoint[]
|
|
331
|
-
): void {
|
|
343
|
+
): Promise<void> {
|
|
332
344
|
if (!this._hasInitialized) {
|
|
333
345
|
throw new Error(
|
|
334
346
|
`LiveMediaSessionCoordinator.setTrack() called before initialize() called.`
|
|
@@ -345,7 +357,7 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
|
|
|
345
357
|
this._logger.sendTelemetryEvent(
|
|
346
358
|
TelemetryEvents.SessionCoordinator.SetTrackCalled
|
|
347
359
|
);
|
|
348
|
-
this._setTrackEvent!.sendEvent({
|
|
360
|
+
await this._setTrackEvent!.sendEvent({
|
|
349
361
|
metadata: metadata,
|
|
350
362
|
waitPoints: waitPoints || [],
|
|
351
363
|
});
|
|
@@ -361,8 +373,9 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
|
|
|
361
373
|
* Throws an exception if the session/coordinator hasn't been initialized or `canSetTrackData` is
|
|
362
374
|
* false.
|
|
363
375
|
* @param data New data object to sync with the group. This value will be synchronized using a last writer wins strategy.
|
|
376
|
+
* @returns a void promise that resolves once complete, throws if user does not have proper roles
|
|
364
377
|
*/
|
|
365
|
-
public setTrackData(data: object | null): void {
|
|
378
|
+
public async setTrackData(data: object | null): Promise<void> {
|
|
366
379
|
if (!this._hasInitialized) {
|
|
367
380
|
throw new Error(
|
|
368
381
|
`LiveMediaSessionCoordinator.setTrackData() called before initialize() called.`
|
|
@@ -379,7 +392,7 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
|
|
|
379
392
|
this._logger.sendTelemetryEvent(
|
|
380
393
|
TelemetryEvents.SessionCoordinator.SetTrackDataCalled
|
|
381
394
|
);
|
|
382
|
-
this._setTrackDataEvent!.sendEvent({
|
|
395
|
+
await this._setTrackDataEvent!.sendEvent({
|
|
383
396
|
data: data,
|
|
384
397
|
});
|
|
385
398
|
}
|
|
@@ -520,23 +533,51 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
|
|
|
520
533
|
}
|
|
521
534
|
|
|
522
535
|
// Send position update event
|
|
523
|
-
|
|
524
|
-
|
|
536
|
+
this.verifyLocalUserRoles()
|
|
537
|
+
.then((valid) => {
|
|
538
|
+
const evt = this._groupState!.createPositionUpdateEvent(state);
|
|
539
|
+
if (!valid) {
|
|
540
|
+
// We still need to update _groupState with the local user's position.
|
|
541
|
+
// So we do this here rather than on the receiving end.
|
|
542
|
+
this._groupState!.handlePositionUpdate(
|
|
543
|
+
{
|
|
544
|
+
clientId: this._runtime.clientId ?? "",
|
|
545
|
+
timestamp: this._liveRuntime.getTimestamp(),
|
|
546
|
+
data: evt,
|
|
547
|
+
},
|
|
548
|
+
true
|
|
549
|
+
);
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
return this._positionUpdateEvent?.sendEvent(evt);
|
|
553
|
+
})
|
|
554
|
+
.catch((err) => {
|
|
555
|
+
this._logger.sendErrorEvent(
|
|
556
|
+
TelemetryEvents.SessionCoordinator.PositionUpdateEventError,
|
|
557
|
+
err
|
|
558
|
+
);
|
|
559
|
+
});
|
|
525
560
|
}
|
|
526
561
|
|
|
527
562
|
protected async createChildren(
|
|
528
563
|
acceptTransportChangesFrom?: UserMeetingRole[]
|
|
529
564
|
): Promise<void> {
|
|
565
|
+
this._allowedRoles = acceptTransportChangesFrom;
|
|
530
566
|
// Create event scopes
|
|
531
567
|
const scope = new LiveEventScope(
|
|
532
568
|
this._runtime,
|
|
569
|
+
this._liveRuntime,
|
|
533
570
|
acceptTransportChangesFrom
|
|
534
571
|
);
|
|
535
|
-
const unrestrictedScope = new LiveEventScope(
|
|
572
|
+
const unrestrictedScope = new LiveEventScope(
|
|
573
|
+
this._runtime,
|
|
574
|
+
this._liveRuntime
|
|
575
|
+
);
|
|
536
576
|
|
|
537
577
|
// Initialize internal coordinator state
|
|
538
578
|
this._groupState = new GroupCoordinatorState(
|
|
539
579
|
this._runtime,
|
|
580
|
+
this._liveRuntime,
|
|
540
581
|
this._maxPlaybackDrift,
|
|
541
582
|
this._positionUpdateInterval,
|
|
542
583
|
this._getPlayerState
|
|
@@ -596,14 +637,22 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
|
|
|
596
637
|
}
|
|
597
638
|
);
|
|
598
639
|
const state = this._getPlayerState();
|
|
599
|
-
|
|
600
|
-
this._groupState!.createPositionUpdateEvent(state);
|
|
601
|
-
this._positionUpdateEvent?.sendEvent(update);
|
|
640
|
+
this.sendPositionUpdate(state);
|
|
602
641
|
}
|
|
603
642
|
);
|
|
604
643
|
|
|
605
|
-
|
|
606
|
-
|
|
644
|
+
this.verifyLocalUserRoles()
|
|
645
|
+
.then((verified) => {
|
|
646
|
+
if (!verified) return;
|
|
647
|
+
// Send initial joined event
|
|
648
|
+
return this._joinedEvent?.sendEvent(undefined);
|
|
649
|
+
})
|
|
650
|
+
.catch((err) => {
|
|
651
|
+
this._logger.sendErrorEvent(
|
|
652
|
+
TelemetryEvents.SessionCoordinator.SendJoinedEventError,
|
|
653
|
+
err
|
|
654
|
+
);
|
|
655
|
+
});
|
|
607
656
|
}
|
|
608
657
|
|
|
609
658
|
private getPlayerPosition(): number {
|
|
@@ -618,4 +667,27 @@ export class LiveMediaSessionCoordinator extends EventEmitter {
|
|
|
618
667
|
: 0.0;
|
|
619
668
|
}
|
|
620
669
|
}
|
|
670
|
+
|
|
671
|
+
private async verifyLocalUserRoles(): Promise<boolean> {
|
|
672
|
+
const clientId = await this.waitUntilConnected();
|
|
673
|
+
return this._liveRuntime.verifyRolesAllowed(
|
|
674
|
+
clientId,
|
|
675
|
+
this._allowedRoles ?? []
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
private waitUntilConnected(): Promise<string> {
|
|
680
|
+
return new Promise((resolve) => {
|
|
681
|
+
const onConnected = (clientId: string) => {
|
|
682
|
+
this._runtime.off("connected", onConnected);
|
|
683
|
+
resolve(clientId);
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
if (this._runtime.clientId && this._runtime.connected) {
|
|
687
|
+
resolve(this._runtime.clientId);
|
|
688
|
+
} else {
|
|
689
|
+
this._runtime.on("connected", onConnected);
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
}
|
|
621
693
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
3
|
* Licensed under the Microsoft Live Share SDK License.
|
|
4
4
|
*/
|
|
5
|
-
import { LiveTelemetryLogger,
|
|
5
|
+
import { LiveTelemetryLogger, ILiveEvent } from "@microsoft/live-share";
|
|
6
6
|
import EventEmitter from "events";
|
|
7
7
|
import {
|
|
8
8
|
ExtendedMediaSessionAction,
|
|
@@ -21,7 +21,7 @@ import { TelemetryEvents } from "./internals";
|
|
|
21
21
|
/**
|
|
22
22
|
* Event data returned by `MediaPlayerSynchronizer` object.
|
|
23
23
|
*/
|
|
24
|
-
export interface IMediaPlayerSynchronizerEvent extends
|
|
24
|
+
export interface IMediaPlayerSynchronizerEvent extends ILiveEvent {
|
|
25
25
|
/**
|
|
26
26
|
* Event details.
|
|
27
27
|
*/
|
|
@@ -82,6 +82,7 @@ export class MediaPlayerSynchronizer extends EventEmitter {
|
|
|
82
82
|
private _seekSuspension?: MediaSessionCoordinatorSuspension;
|
|
83
83
|
private _viewOnly = false;
|
|
84
84
|
private _expectedPlaybackState: ExtendedMediaSessionPlaybackState = "none";
|
|
85
|
+
private _metadata: ExtendedMediaMetadata | null = null;
|
|
85
86
|
private _trackData: object | null = null;
|
|
86
87
|
|
|
87
88
|
/**
|
|
@@ -120,8 +121,15 @@ export class MediaPlayerSynchronizer extends EventEmitter {
|
|
|
120
121
|
playbackState = "playing";
|
|
121
122
|
}
|
|
122
123
|
|
|
124
|
+
// Metadata equality check in `GroupPlaybackTrack` would return false if only providing src.
|
|
125
|
+
// Use full metadata if this._metadata has same src
|
|
126
|
+
const metadata =
|
|
127
|
+
this._metadata && this._metadata.trackIdentifier === src
|
|
128
|
+
? this._metadata
|
|
129
|
+
: ({ trackIdentifier: src } as ExtendedMediaMetadata);
|
|
130
|
+
|
|
123
131
|
const state = {
|
|
124
|
-
metadata:
|
|
132
|
+
metadata: metadata,
|
|
125
133
|
playbackState: playbackState,
|
|
126
134
|
positionState: {
|
|
127
135
|
position: this._player.currentTime,
|
|
@@ -164,7 +172,13 @@ export class MediaPlayerSynchronizer extends EventEmitter {
|
|
|
164
172
|
TelemetryEvents.MediaPlayerSynchronizer
|
|
165
173
|
.UserTappedVideoToPlay
|
|
166
174
|
);
|
|
167
|
-
this.play()
|
|
175
|
+
this.play().catch((err) => {
|
|
176
|
+
this._logger.sendErrorEvent(
|
|
177
|
+
TelemetryEvents.MediaPlayerSynchronizer
|
|
178
|
+
.UserTappedVideoToPlayError,
|
|
179
|
+
err
|
|
180
|
+
);
|
|
181
|
+
});
|
|
168
182
|
}
|
|
169
183
|
}
|
|
170
184
|
// block play if player state is playing when expected synced state is paused and coordinator is not suspended.
|
|
@@ -295,6 +309,14 @@ export class MediaPlayerSynchronizer extends EventEmitter {
|
|
|
295
309
|
.SetTrackAction
|
|
296
310
|
);
|
|
297
311
|
this._expectedPlaybackState = "none";
|
|
312
|
+
this._metadata = details.metadata ?? null;
|
|
313
|
+
if (
|
|
314
|
+
this._player.src ===
|
|
315
|
+
details.metadata?.trackIdentifier
|
|
316
|
+
) {
|
|
317
|
+
// Don't set duplicate src and load again.
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
298
320
|
this._player.src =
|
|
299
321
|
details.metadata!.trackIdentifier;
|
|
300
322
|
this._player.load();
|
|
@@ -498,13 +520,15 @@ export class MediaPlayerSynchronizer extends EventEmitter {
|
|
|
498
520
|
* @remarks
|
|
499
521
|
* For proper operation apps should avoid calling `mediaSession.coordinator.play()` directly
|
|
500
522
|
* and instead use the synchronizers `play()` method.
|
|
523
|
+
*
|
|
524
|
+
* @returns a void promise that resolves once complete, throws if user does not have proper roles
|
|
501
525
|
*/
|
|
502
|
-
public play(): void {
|
|
526
|
+
public async play(): Promise<void> {
|
|
503
527
|
this._logger.sendTelemetryEvent(
|
|
504
528
|
TelemetryEvents.MediaPlayerSynchronizer.PlayCalled
|
|
505
529
|
);
|
|
506
530
|
this._expectedPlaybackState = "playing";
|
|
507
|
-
this._mediaSession.coordinator.play();
|
|
531
|
+
await this._mediaSession.coordinator.play();
|
|
508
532
|
|
|
509
533
|
this.dispatchUserAction({ action: "play" });
|
|
510
534
|
}
|
|
@@ -515,13 +539,15 @@ export class MediaPlayerSynchronizer extends EventEmitter {
|
|
|
515
539
|
* @remarks
|
|
516
540
|
* For proper operation apps should avoid calling `mediaSession.coordinator.pause()` directly
|
|
517
541
|
* and instead use the synchronizers `pause()` method.
|
|
542
|
+
*
|
|
543
|
+
* @returns a void promise that resolves once complete, throws if user does not have proper roles
|
|
518
544
|
*/
|
|
519
|
-
public pause(): void {
|
|
545
|
+
public async pause(): Promise<void> {
|
|
520
546
|
this._logger.sendTelemetryEvent(
|
|
521
547
|
TelemetryEvents.MediaPlayerSynchronizer.PauseCalled
|
|
522
548
|
);
|
|
523
549
|
this._expectedPlaybackState = "paused";
|
|
524
|
-
this._mediaSession.coordinator.pause();
|
|
550
|
+
await this._mediaSession.coordinator.pause();
|
|
525
551
|
|
|
526
552
|
this.dispatchUserAction({ action: "pause" });
|
|
527
553
|
}
|
|
@@ -532,8 +558,10 @@ export class MediaPlayerSynchronizer extends EventEmitter {
|
|
|
532
558
|
* @remarks
|
|
533
559
|
* For proper operation apps should avoid calling `mediaSession.coordinator.seekTo()` directly
|
|
534
560
|
* and instead use the synchronizers `seekTo()` method.
|
|
561
|
+
*
|
|
562
|
+
* @returns a void promise that resolves once complete, throws if user does not have proper roles
|
|
535
563
|
*/
|
|
536
|
-
public seekTo(time: number): void {
|
|
564
|
+
public async seekTo(time: number): Promise<void> {
|
|
537
565
|
// Always seek player to new time.
|
|
538
566
|
// - This resolves an issue where the timeline scrubber can temporarily snap back to the original
|
|
539
567
|
// location.
|
|
@@ -544,7 +572,7 @@ export class MediaPlayerSynchronizer extends EventEmitter {
|
|
|
544
572
|
null,
|
|
545
573
|
{ position: time }
|
|
546
574
|
);
|
|
547
|
-
this._mediaSession.coordinator.seekTo(time);
|
|
575
|
+
await this._mediaSession.coordinator.seekTo(time);
|
|
548
576
|
|
|
549
577
|
this.dispatchUserAction({ action: "seekto", seekTime: time });
|
|
550
578
|
}
|
|
@@ -555,15 +583,17 @@ export class MediaPlayerSynchronizer extends EventEmitter {
|
|
|
555
583
|
* @remarks
|
|
556
584
|
* For proper operation apps should avoid calling `mediaSession.coordinator.setTrack()` directly
|
|
557
585
|
* and instead use the synchronizers `setTrack()` method.
|
|
586
|
+
*
|
|
587
|
+
* @returns a void promise that resolves once complete, throws if user does not have proper roles
|
|
558
588
|
*/
|
|
559
|
-
public setTrack(
|
|
589
|
+
public async setTrack(
|
|
560
590
|
track: ExtendedMediaMetadata,
|
|
561
591
|
waitPoints?: CoordinationWaitPoint[]
|
|
562
|
-
): void {
|
|
592
|
+
): Promise<void> {
|
|
563
593
|
this._logger.sendTelemetryEvent(
|
|
564
594
|
TelemetryEvents.MediaPlayerSynchronizer.SetTrackCalled
|
|
565
595
|
);
|
|
566
|
-
this._mediaSession.coordinator.setTrack(track, waitPoints);
|
|
596
|
+
await this._mediaSession.coordinator.setTrack(track, waitPoints);
|
|
567
597
|
|
|
568
598
|
this.dispatchUserAction({ action: "settrack", metadata: track });
|
|
569
599
|
}
|
|
@@ -574,13 +604,15 @@ export class MediaPlayerSynchronizer extends EventEmitter {
|
|
|
574
604
|
* @remarks
|
|
575
605
|
* For proper operation apps should avoid calling `mediaSession.coordinator.setTrackData()` directly
|
|
576
606
|
* and instead use the synchronizers `setTrackData()` method.
|
|
607
|
+
*
|
|
608
|
+
* @returns a void promise that resolves once complete, throws if user does not have proper roles
|
|
577
609
|
*/
|
|
578
|
-
public setTrackData(data: object | null): void {
|
|
610
|
+
public async setTrackData(data: object | null): Promise<void> {
|
|
579
611
|
this._logger.sendTelemetryEvent(
|
|
580
612
|
TelemetryEvents.MediaPlayerSynchronizer.SetTrackDataCalled
|
|
581
613
|
);
|
|
582
614
|
this._trackData = data;
|
|
583
|
-
this._mediaSession.coordinator.setTrackData(data);
|
|
615
|
+
await this._mediaSession.coordinator.setTrackData(data);
|
|
584
616
|
|
|
585
617
|
this.dispatchUserAction({ action: "datachange", data: data });
|
|
586
618
|
}
|
package/src/VolumeManager.ts
CHANGED
|
@@ -161,7 +161,10 @@ export class VolumeManager {
|
|
|
161
161
|
if (typeof requestAnimationFrame == "function") {
|
|
162
162
|
requestAnimationFrame(callback);
|
|
163
163
|
} else {
|
|
164
|
-
setTimeout(
|
|
164
|
+
setTimeout(
|
|
165
|
+
callback,
|
|
166
|
+
Math.min(this._volumeChangeDuration.milliseconds / 25, 20)
|
|
167
|
+
);
|
|
165
168
|
}
|
|
166
169
|
}
|
|
167
170
|
|