@microsoft/live-share-media 1.0.2 → 1.2.0

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 (44) hide show
  1. package/bin/LiveMediaSession.d.ts +9 -10
  2. package/bin/LiveMediaSession.d.ts.map +1 -1
  3. package/bin/LiveMediaSession.js +35 -17
  4. package/bin/LiveMediaSession.js.map +1 -1
  5. package/bin/LiveMediaSessionCoordinator.d.ts +8 -3
  6. package/bin/LiveMediaSessionCoordinator.d.ts.map +1 -1
  7. package/bin/LiveMediaSessionCoordinator.js +19 -27
  8. package/bin/LiveMediaSessionCoordinator.js.map +1 -1
  9. package/bin/MediaPlayerSynchronizer.d.ts +3 -2
  10. package/bin/MediaPlayerSynchronizer.d.ts.map +1 -1
  11. package/bin/MediaPlayerSynchronizer.js +46 -36
  12. package/bin/MediaPlayerSynchronizer.js.map +1 -1
  13. package/bin/MediaSessionActionThrottler.d.ts +2 -2
  14. package/bin/MediaSessionActionThrottler.d.ts.map +1 -1
  15. package/bin/MediaSessionActionThrottler.js.map +1 -1
  16. package/bin/MediaSessionExtensions.d.ts +4 -0
  17. package/bin/MediaSessionExtensions.d.ts.map +1 -1
  18. package/bin/RepeatedActionThrottler.d.ts +1 -1
  19. package/bin/RepeatedActionThrottler.d.ts.map +1 -1
  20. package/bin/RepeatedActionThrottler.js.map +1 -1
  21. package/bin/internals/GroupCoordinatorState.d.ts +1 -1
  22. package/bin/internals/GroupCoordinatorState.d.ts.map +1 -1
  23. package/bin/internals/GroupCoordinatorState.js +23 -6
  24. package/bin/internals/GroupCoordinatorState.js.map +1 -1
  25. package/bin/internals/GroupPlaybackTrack.d.ts.map +1 -1
  26. package/bin/internals/GroupPlaybackTrack.js +1 -0
  27. package/bin/internals/GroupPlaybackTrack.js.map +1 -1
  28. package/bin/internals/GroupPlaybackTrackData.d.ts.map +1 -1
  29. package/bin/internals/GroupPlaybackTrackData.js +1 -0
  30. package/bin/internals/GroupPlaybackTrackData.js.map +1 -1
  31. package/bin/internals/GroupTransportState.d.ts.map +1 -1
  32. package/bin/internals/GroupTransportState.js +3 -0
  33. package/bin/internals/GroupTransportState.js.map +1 -1
  34. package/package.json +4 -4
  35. package/src/LiveMediaSession.ts +42 -19
  36. package/src/LiveMediaSessionCoordinator.ts +22 -34
  37. package/src/MediaPlayerSynchronizer.ts +51 -43
  38. package/src/MediaSessionActionThrottler.ts +6 -3
  39. package/src/MediaSessionExtensions.ts +5 -0
  40. package/src/RepeatedActionThrottler.ts +4 -2
  41. package/src/internals/GroupCoordinatorState.ts +30 -7
  42. package/src/internals/GroupPlaybackTrack.ts +1 -0
  43. package/src/internals/GroupPlaybackTrackData.ts +1 -0
  44. package/src/internals/GroupTransportState.ts +4 -5
@@ -2,7 +2,11 @@
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Licensed under the Microsoft Live Share SDK License.
4
4
  */
5
- import { LiveTelemetryLogger, ILiveEvent } from "@microsoft/live-share";
5
+ import {
6
+ LiveTelemetryLogger,
7
+ ILiveEvent,
8
+ IRuntimeSignaler,
9
+ } from "@microsoft/live-share";
6
10
  import EventEmitter from "events";
7
11
  import {
8
12
  ExtendedMediaSessionAction,
@@ -17,6 +21,7 @@ import { VolumeManager } from "./VolumeManager";
17
21
  import { LiveMediaSession } from "./LiveMediaSession";
18
22
  import { IMediaPlayer } from "./IMediaPlayer";
19
23
  import { TelemetryEvents } from "./internals";
24
+ import { waitUntilConnected } from "@microsoft/live-share/bin/internals";
20
25
 
21
26
  /**
22
27
  * Event data returned by `MediaPlayerSynchronizer` object.
@@ -76,6 +81,7 @@ export class MediaPlayerSynchronizer extends EventEmitter {
76
81
  private _logger: LiveTelemetryLogger;
77
82
  private _player: IMediaPlayer;
78
83
  private _mediaSession: LiveMediaSession;
84
+ private _runtime: IRuntimeSignaler;
79
85
  private _volumeManager: VolumeManager;
80
86
  private _onEnd?: () => void;
81
87
  private _onPlayerEvent: EventListener;
@@ -94,11 +100,13 @@ export class MediaPlayerSynchronizer extends EventEmitter {
94
100
  constructor(
95
101
  player: IMediaPlayer,
96
102
  mediaSession: LiveMediaSession,
103
+ runtime: IRuntimeSignaler,
97
104
  onEnd: () => void
98
105
  ) {
99
106
  super();
100
107
  this._player = player;
101
108
  this._mediaSession = mediaSession;
109
+ this._runtime = runtime;
102
110
  this._logger = mediaSession.logger;
103
111
  this._volumeManager = new VolumeManager(player);
104
112
  this._onEnd = onEnd;
@@ -352,7 +360,7 @@ export class MediaPlayerSynchronizer extends EventEmitter {
352
360
  }
353
361
  }
354
362
 
355
- this.dispatchGroupAction(details, false, error);
363
+ this.dispatchGroupAction(details, error);
356
364
  }
357
365
  );
358
366
  }
@@ -513,7 +521,13 @@ export class MediaPlayerSynchronizer extends EventEmitter {
513
521
  );
514
522
  suspension.end(seekTo);
515
523
 
516
- this.dispatchUserAction({ action: "seekto", seekTime: seekTo });
524
+ waitUntilConnected(this._runtime).then((clientId: string) => {
525
+ this.dispatchUserAction({
526
+ action: "seekto",
527
+ clientId,
528
+ seekTime: seekTo,
529
+ });
530
+ });
517
531
  }
518
532
 
519
533
  /**
@@ -532,7 +546,10 @@ export class MediaPlayerSynchronizer extends EventEmitter {
532
546
  this._expectedPlaybackState = "playing";
533
547
  await this._mediaSession.coordinator.play();
534
548
 
535
- this.dispatchUserAction({ action: "play" });
549
+ this.dispatchUserAction({
550
+ action: "play",
551
+ clientId: await waitUntilConnected(this._runtime),
552
+ });
536
553
  }
537
554
 
538
555
  /**
@@ -551,7 +568,10 @@ export class MediaPlayerSynchronizer extends EventEmitter {
551
568
  this._expectedPlaybackState = "paused";
552
569
  await this._mediaSession.coordinator.pause();
553
570
 
554
- this.dispatchUserAction({ action: "pause" });
571
+ this.dispatchUserAction({
572
+ action: "pause",
573
+ clientId: await waitUntilConnected(this._runtime),
574
+ });
555
575
  }
556
576
 
557
577
  /**
@@ -576,7 +596,11 @@ export class MediaPlayerSynchronizer extends EventEmitter {
576
596
  );
577
597
  await this._mediaSession.coordinator.seekTo(time);
578
598
 
579
- this.dispatchUserAction({ action: "seekto", seekTime: time });
599
+ this.dispatchUserAction({
600
+ action: "seekto",
601
+ clientId: await waitUntilConnected(this._runtime),
602
+ seekTime: time,
603
+ });
580
604
  }
581
605
 
582
606
  /**
@@ -597,7 +621,11 @@ export class MediaPlayerSynchronizer extends EventEmitter {
597
621
  );
598
622
  await this._mediaSession.coordinator.setTrack(track, waitPoints);
599
623
 
600
- this.dispatchUserAction({ action: "settrack", metadata: track });
624
+ this.dispatchUserAction({
625
+ action: "settrack",
626
+ clientId: await waitUntilConnected(this._runtime),
627
+ metadata: track,
628
+ });
601
629
  }
602
630
 
603
631
  /**
@@ -616,52 +644,32 @@ export class MediaPlayerSynchronizer extends EventEmitter {
616
644
  this._trackData = data;
617
645
  await this._mediaSession.coordinator.setTrackData(data);
618
646
 
619
- this.dispatchUserAction({ action: "datachange", data: data });
647
+ this.dispatchUserAction({
648
+ action: "datachange",
649
+ clientId: await waitUntilConnected(this._runtime),
650
+ data: data,
651
+ });
620
652
  }
621
653
 
654
+ // TODO: what is delay useful for? we do not use, delete?
622
655
  private dispatchGroupAction(
623
656
  details: ExtendedMediaSessionActionDetails,
624
- delay = false,
625
657
  error: Error | undefined
626
658
  ): void {
627
- if (delay) {
628
- setTimeout(
629
- () =>
630
- this.emit(MediaPlayerSynchronizerEvents.groupaction, {
631
- type: MediaPlayerSynchronizerEvents.groupaction,
632
- details: details,
633
- playerError: error,
634
- }),
635
- 50
636
- );
637
- } else {
638
- this.emit(MediaPlayerSynchronizerEvents.groupaction, {
639
- type: MediaPlayerSynchronizerEvents.groupaction,
640
- details: details,
641
- error,
642
- });
643
- }
659
+ this.emit(MediaPlayerSynchronizerEvents.groupaction, {
660
+ type: MediaPlayerSynchronizerEvents.groupaction,
661
+ details: details,
662
+ error,
663
+ });
644
664
  }
645
665
 
646
666
  private dispatchUserAction(
647
- details: ExtendedMediaSessionActionDetails,
648
- delay = false
667
+ details: ExtendedMediaSessionActionDetails
649
668
  ): void {
650
- if (delay) {
651
- setTimeout(
652
- () =>
653
- this.emit(MediaPlayerSynchronizerEvents.useraction, {
654
- type: MediaPlayerSynchronizerEvents.useraction,
655
- details: details,
656
- }),
657
- 50
658
- );
659
- } else {
660
- this.emit(MediaPlayerSynchronizerEvents.useraction, {
661
- type: MediaPlayerSynchronizerEvents.useraction,
662
- details: details,
663
- });
664
- }
669
+ this.emit(MediaPlayerSynchronizerEvents.useraction, {
670
+ type: MediaPlayerSynchronizerEvents.useraction,
671
+ details: details,
672
+ });
665
673
  }
666
674
 
667
675
  private async catchupPlayer(time: number): Promise<void> {
@@ -3,14 +3,17 @@
3
3
  * Licensed under the Microsoft Live Share SDK License.
4
4
  */
5
5
 
6
- import { ExtendedMediaSessionActionDetails } from "./MediaSessionExtensions";
6
+ import {
7
+ ExtendedMediaSessionActionDetails,
8
+ ExtendedMediaSessionActionHandler,
9
+ } from "./MediaSessionExtensions";
7
10
 
8
11
  /**
9
12
  * Base class for action throttlers.
10
13
  */
11
14
  export abstract class MediaSessionActionThrottler {
12
15
  public abstract throttled(
13
- details: ExtendedMediaSessionActionDetails,
14
- handler?: MediaSessionActionHandler
16
+ details: MediaSessionActionDetails | ExtendedMediaSessionActionDetails,
17
+ handler?: MediaSessionActionHandler | ExtendedMediaSessionActionHandler
15
18
  ): void;
16
19
  }
@@ -42,6 +42,7 @@ export interface CoordinationWaitPoint {
42
42
 
43
43
  export interface ExtendedMediaSessionActionDetails {
44
44
  action: ExtendedMediaSessionAction;
45
+ clientId: string;
45
46
  fastSeek?: boolean | null;
46
47
  seekOffset?: number | null;
47
48
  seekTime?: number | null;
@@ -50,3 +51,7 @@ export interface ExtendedMediaSessionActionDetails {
50
51
  data?: object | null;
51
52
  blocked?: ExtendedMediaSessionAction | null;
52
53
  }
54
+
55
+ export interface ExtendedMediaSessionActionHandler {
56
+ (details: ExtendedMediaSessionActionDetails): void;
57
+ }
@@ -33,7 +33,7 @@ export class RepeatedActionThrottler extends MediaSessionActionThrottler {
33
33
  }
34
34
 
35
35
  public throttled(
36
- details: ExtendedMediaSessionActionDetails,
36
+ details: MediaSessionActionDetails | ExtendedMediaSessionActionDetails,
37
37
  handler?: MediaSessionActionHandler
38
38
  ): void {
39
39
  if (handler) {
@@ -63,7 +63,9 @@ export class RepeatedActionThrottler extends MediaSessionActionThrottler {
63
63
  }
64
64
  }
65
65
 
66
- private getChangeKey(details: ExtendedMediaSessionActionDetails): string {
66
+ private getChangeKey(
67
+ details: MediaSessionActionDetails | ExtendedMediaSessionActionDetails
68
+ ): string {
67
69
  switch (details.action) {
68
70
  case "seekto":
69
71
  return `seekto:${details.seekTime}`;
@@ -36,6 +36,7 @@ import {
36
36
  IPlaybackTrackData,
37
37
  } from "./GroupPlaybackTrackData";
38
38
  import { TelemetryEvents } from "./consts";
39
+ import { waitUntilConnected } from "@microsoft/live-share/bin/internals";
39
40
 
40
41
  /**
41
42
  * @hidden
@@ -149,7 +150,7 @@ export class GroupCoordinatorState extends EventEmitter {
149
150
  this._logger.sendTelemetryEvent(
150
151
  TelemetryEvents.GroupCoordinator.TrackChanged
151
152
  );
152
- this.emitSetTrack(evt.metadata!);
153
+ this.emitSetTrack(evt.clientId, evt.metadata!);
153
154
  } else {
154
155
  this._logger.sendTelemetryEvent(
155
156
  TelemetryEvents.GroupCoordinator.TrackChangeDelayed
@@ -168,6 +169,7 @@ export class GroupCoordinatorState extends EventEmitter {
168
169
  this.emitTriggerAction({
169
170
  action: "datachange",
170
171
  data: evt.data,
172
+ clientId: evt.clientId,
171
173
  });
172
174
  } else {
173
175
  this._logger.sendTelemetryEvent(
@@ -196,6 +198,7 @@ export class GroupCoordinatorState extends EventEmitter {
196
198
  case "play":
197
199
  this.emitTriggerAction({
198
200
  action: "play",
201
+ clientId: evt.clientId,
199
202
  seekTime: evt.seekTime,
200
203
  });
201
204
  break;
@@ -203,6 +206,7 @@ export class GroupCoordinatorState extends EventEmitter {
203
206
  case "pause":
204
207
  this.emitTriggerAction({
205
208
  action: "pause",
209
+ clientId: evt.clientId,
206
210
  seekTime: evt.seekTime,
207
211
  });
208
212
  break;
@@ -210,6 +214,7 @@ export class GroupCoordinatorState extends EventEmitter {
210
214
  case "seekto":
211
215
  this.emitTriggerAction({
212
216
  action: "seekto",
217
+ clientId: evt.clientId,
213
218
  seekTime: evt.seekTime,
214
219
  });
215
220
  break;
@@ -431,7 +436,7 @@ export class GroupCoordinatorState extends EventEmitter {
431
436
  }
432
437
 
433
438
  public handlePositionUpdate(
434
- event: Omit<ILiveEvent<IPositionUpdateEvent>, "name">,
439
+ event: ILiveEvent<IPositionUpdateEvent>,
435
440
  local: boolean
436
441
  ): void {
437
442
  // Ensure change is for current track
@@ -522,7 +527,10 @@ export class GroupCoordinatorState extends EventEmitter {
522
527
  this._logger.sendTelemetryEvent(
523
528
  TelemetryEvents.GroupCoordinator.TrackOutOfSync
524
529
  );
525
- this.emitSetTrack(this.playbackTrack.metadata!);
530
+ this.emitSetTrack(
531
+ this.playbackTrack.current.clientId,
532
+ this.playbackTrack.metadata!
533
+ );
526
534
  return;
527
535
  }
528
536
 
@@ -560,6 +568,7 @@ export class GroupCoordinatorState extends EventEmitter {
560
568
  );
561
569
  await this.emitTriggerAction({
562
570
  action: "catchup",
571
+ clientId: await waitUntilConnected(this._runtime),
563
572
  seekTime: target,
564
573
  });
565
574
  }
@@ -576,10 +585,16 @@ export class GroupCoordinatorState extends EventEmitter {
576
585
  );
577
586
  switch (this.transportState.playbackState) {
578
587
  case "playing":
579
- await this.emitTriggerAction({ action: "play" });
588
+ await this.emitTriggerAction({
589
+ action: "play",
590
+ clientId: this.transportState.current.clientId,
591
+ });
580
592
  break;
581
593
  case "paused":
582
- await this.emitTriggerAction({ action: "pause" });
594
+ await this.emitTriggerAction({
595
+ action: "pause",
596
+ clientId: this.transportState.current.clientId,
597
+ });
583
598
  break;
584
599
  }
585
600
  }
@@ -594,6 +609,7 @@ export class GroupCoordinatorState extends EventEmitter {
594
609
  );
595
610
  await this.emitTriggerAction({
596
611
  action: "datachange",
612
+ clientId: this.playbackTrackData.current.clientId,
597
613
  data: this.playbackTrackData.data,
598
614
  });
599
615
  }
@@ -601,12 +617,19 @@ export class GroupCoordinatorState extends EventEmitter {
601
617
  }
602
618
  }
603
619
 
604
- private emitSetTrack(metadata: ExtendedMediaMetadata): void {
620
+ private emitSetTrack(
621
+ clientId: string,
622
+ metadata: ExtendedMediaMetadata
623
+ ): void {
605
624
  // Reset tracking states
606
625
  this._waitPoint = undefined;
607
626
 
608
627
  // Trigger settrack action
609
- this.emitTriggerAction({ action: "settrack", metadata: metadata });
628
+ this.emitTriggerAction({
629
+ action: "settrack",
630
+ clientId,
631
+ metadata,
632
+ });
610
633
  }
611
634
 
612
635
  private emitTriggerAction(
@@ -147,6 +147,7 @@ export class GroupPlaybackTrack extends EventEmitter {
147
147
  // Notify listeners
148
148
  this.emit(GroupPlaybackTrackEvents.trackChange, {
149
149
  name: GroupPlaybackTrackEvents.trackChange,
150
+ clientId: track.clientId,
150
151
  metadata: track.metadata,
151
152
  });
152
153
 
@@ -90,6 +90,7 @@ export class GroupPlaybackTrackData extends EventEmitter {
90
90
  // Notify listeners
91
91
  this.emit(PlaybackTrackDataEvents.dataChange, {
92
92
  type: PlaybackTrackDataEvents.dataChange,
93
+ clientId: event.clientId,
93
94
  data: event.data,
94
95
  });
95
96
 
@@ -3,11 +3,7 @@
3
3
  * Licensed under the Microsoft Live Share SDK License.
4
4
  */
5
5
 
6
- import {
7
- ILiveEvent,
8
- LiveShareRuntime,
9
- LiveShareClient,
10
- } from "@microsoft/live-share";
6
+ import { ILiveEvent, LiveShareRuntime } from "@microsoft/live-share";
11
7
  import EventEmitter from "events";
12
8
  import { IMediaPlayerState } from "../LiveMediaSessionCoordinator";
13
9
  import {
@@ -140,6 +136,7 @@ export class GroupTransportState extends EventEmitter {
140
136
  this.emit(GroupTransportStateEvents.transportStateChange, {
141
137
  type: GroupTransportStateEvents.transportStateChange,
142
138
  action: "seekto",
139
+ clientId: state.clientId,
143
140
  seekTime: state.startPosition,
144
141
  });
145
142
  } else if (state.playbackState == "playing") {
@@ -149,12 +146,14 @@ export class GroupTransportState extends EventEmitter {
149
146
  this.emit(GroupTransportStateEvents.transportStateChange, {
150
147
  type: GroupTransportStateEvents.transportStateChange,
151
148
  action: "play",
149
+ clientId: state.clientId,
152
150
  seekTime: projectedPosition,
153
151
  });
154
152
  } else {
155
153
  this.emit(GroupTransportStateEvents.transportStateChange, {
156
154
  type: GroupTransportStateEvents.transportStateChange,
157
155
  action: "pause",
156
+ clientId: state.clientId,
158
157
  seekTime: state.startPosition,
159
158
  });
160
159
  }