@microsoft/live-share-media 1.3.0 → 1.4.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 (78) hide show
  1. package/.nycrc.json +10 -10
  2. package/LICENSE +90 -90
  3. package/README.md +135 -135
  4. package/bin/LiveMediaSession.d.ts.map +1 -1
  5. package/bin/LiveMediaSession.js +9 -1
  6. package/bin/LiveMediaSession.js.map +1 -1
  7. package/bin/LiveMediaSessionCoordinator.d.ts +18 -2
  8. package/bin/LiveMediaSessionCoordinator.d.ts.map +1 -1
  9. package/bin/LiveMediaSessionCoordinator.js +52 -13
  10. package/bin/LiveMediaSessionCoordinator.js.map +1 -1
  11. package/bin/MediaPlayerSynchronizer.d.ts +6 -4
  12. package/bin/MediaPlayerSynchronizer.d.ts.map +1 -1
  13. package/bin/MediaPlayerSynchronizer.js +41 -12
  14. package/bin/MediaPlayerSynchronizer.js.map +1 -1
  15. package/bin/MediaSessionExtensions.d.ts +17 -8
  16. package/bin/MediaSessionExtensions.d.ts.map +1 -1
  17. package/bin/MediaSessionExtensions.js +4 -0
  18. package/bin/MediaSessionExtensions.js.map +1 -1
  19. package/bin/internals/GroupCoordinatorState.d.ts +15 -1
  20. package/bin/internals/GroupCoordinatorState.d.ts.map +1 -1
  21. package/bin/internals/GroupCoordinatorState.js +123 -57
  22. package/bin/internals/GroupCoordinatorState.js.map +1 -1
  23. package/bin/internals/GroupPlaybackPosition.d.ts +3 -1
  24. package/bin/internals/GroupPlaybackPosition.d.ts.map +1 -1
  25. package/bin/internals/GroupPlaybackPosition.js +7 -3
  26. package/bin/internals/GroupPlaybackPosition.js.map +1 -1
  27. package/bin/internals/GroupPlaybackRate.d.ts +39 -0
  28. package/bin/internals/GroupPlaybackRate.d.ts.map +1 -0
  29. package/bin/internals/GroupPlaybackRate.js +62 -0
  30. package/bin/internals/GroupPlaybackRate.js.map +1 -0
  31. package/bin/internals/GroupPlaybackTrack.d.ts +2 -2
  32. package/bin/internals/GroupPlaybackTrack.d.ts.map +1 -1
  33. package/bin/internals/GroupPlaybackTrack.js +3 -2
  34. package/bin/internals/GroupPlaybackTrack.js.map +1 -1
  35. package/bin/internals/GroupPlaybackTrackData.d.ts +3 -3
  36. package/bin/internals/GroupPlaybackTrackData.d.ts.map +1 -1
  37. package/bin/internals/GroupPlaybackTrackData.js +12 -11
  38. package/bin/internals/GroupPlaybackTrackData.js.map +1 -1
  39. package/bin/internals/GroupTransportState.d.ts +6 -3
  40. package/bin/internals/GroupTransportState.d.ts.map +1 -1
  41. package/bin/internals/GroupTransportState.js +16 -11
  42. package/bin/internals/GroupTransportState.js.map +1 -1
  43. package/bin/internals/consts.d.ts +10 -3
  44. package/bin/internals/consts.d.ts.map +1 -1
  45. package/bin/internals/consts.js +10 -3
  46. package/bin/internals/consts.js.map +1 -1
  47. package/bin/internals/index.d.ts +1 -0
  48. package/bin/internals/index.d.ts.map +1 -1
  49. package/bin/internals/index.js +1 -0
  50. package/bin/internals/index.js.map +1 -1
  51. package/bin/internals/interfaces.d.ts +10 -0
  52. package/bin/internals/interfaces.d.ts.map +1 -0
  53. package/bin/internals/interfaces.js +3 -0
  54. package/bin/internals/interfaces.js.map +1 -0
  55. package/package.json +45 -45
  56. package/src/IMediaPlayer.ts +29 -29
  57. package/src/LiveMediaSession.ts +349 -336
  58. package/src/LiveMediaSessionCoordinator.ts +760 -678
  59. package/src/LiveMediaSessionCoordinatorSuspension.ts +39 -39
  60. package/src/MediaPlayerSynchronizer.ts +754 -714
  61. package/src/MediaSessionActionThrottler.ts +19 -19
  62. package/src/MediaSessionExtensions.ts +198 -187
  63. package/src/RepeatedActionThrottler.ts +76 -76
  64. package/src/VolumeManager.ts +200 -200
  65. package/src/index.ts +14 -14
  66. package/src/internals/GroupCoordinatorState.ts +802 -685
  67. package/src/internals/GroupPlaybackPosition.ts +235 -228
  68. package/src/internals/GroupPlaybackRate.ts +90 -0
  69. package/src/internals/GroupPlaybackTrack.ts +183 -182
  70. package/src/internals/GroupPlaybackTrackData.ts +105 -104
  71. package/src/internals/GroupTransportState.ts +179 -170
  72. package/src/internals/consts.ts +115 -102
  73. package/src/internals/errors.ts +42 -42
  74. package/src/internals/index.ts +13 -12
  75. package/src/internals/interfaces.ts +10 -0
  76. package/tsconfig.build.json +8 -8
  77. package/tsconfig.json +76 -76
  78. package/typedoc.json +10 -10
@@ -1,182 +1,183 @@
1
- /**
2
- * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Licensed under the Microsoft Live Share SDK License.
4
- */
5
-
6
- import { ILiveEvent } from "@microsoft/live-share";
7
- import EventEmitter from "events";
8
- import { IMediaPlayerState } from "../LiveMediaSessionCoordinator";
9
- import {
10
- CoordinationWaitPoint,
11
- ExtendedMediaMetadata,
12
- ExtendedMediaSessionActionSource,
13
- } from "../MediaSessionExtensions";
14
-
15
- /**
16
- * @hidden
17
- */
18
- export interface IPlaybackTrack {
19
- metadata: ExtendedMediaMetadata | null;
20
- waitPoints: CoordinationWaitPoint[];
21
- timestamp: number;
22
- clientId: string;
23
- }
24
-
25
- /**
26
- * @hidden
27
- */
28
- export enum GroupPlaybackTrackEvents {
29
- trackChange = "trackChange",
30
- }
31
-
32
- /**
33
- * @hidden
34
- */
35
- export interface IPlaybackTrackChangeEvent extends ILiveEvent {
36
- metadata: ExtendedMediaMetadata | null;
37
- }
38
-
39
- /**
40
- * @hidden
41
- */
42
- export class GroupPlaybackTrack extends EventEmitter {
43
- private readonly _getMediaPlayerState: () => IMediaPlayerState;
44
- private _current: IPlaybackTrack;
45
-
46
- constructor(getMediaPlayerState: () => IMediaPlayerState) {
47
- super();
48
- this._current = {
49
- metadata: null,
50
- waitPoints: [],
51
- timestamp: 0,
52
- clientId: "",
53
- };
54
- this._getMediaPlayerState = getMediaPlayerState;
55
- }
56
-
57
- public get current(): Readonly<IPlaybackTrack> {
58
- // Populate with sessions current metadata if null
59
- if (!this._current.metadata) {
60
- this._current.metadata = this._getMediaPlayerState().metadata;
61
- }
62
-
63
- return this._current;
64
- }
65
-
66
- public get metadata(): ExtendedMediaMetadata | null {
67
- return this.current.metadata;
68
- }
69
-
70
- public addWaitPoint(waitPoint: CoordinationWaitPoint): boolean {
71
- for (let i = 0; i < this._current.waitPoints.length; i++) {
72
- const current = this._current.waitPoints[i];
73
- if (current.position == waitPoint.position) {
74
- // Already exists
75
- return false;
76
- } else if (current.position > waitPoint.position) {
77
- // Insert before current position
78
- this._current.waitPoints.splice(i, 0, waitPoint);
79
- return true;
80
- }
81
- }
82
-
83
- // Append to list
84
- this._current.waitPoints.push(waitPoint);
85
- return true;
86
- }
87
-
88
- public findNextWaitPoint(
89
- lastWaitPoint: CoordinationWaitPoint | undefined
90
- ): CoordinationWaitPoint | undefined {
91
- const waitPoints = this._current.waitPoints || [];
92
- for (const waitPoint of waitPoints) {
93
- if (lastWaitPoint && waitPoint.position <= lastWaitPoint.position) {
94
- continue;
95
- }
96
-
97
- return waitPoint;
98
- }
99
-
100
- return undefined;
101
- }
102
-
103
- public updateTrack(
104
- track: IPlaybackTrack,
105
- source: ExtendedMediaSessionActionSource
106
- ): boolean {
107
- // Guard against missing waitPoints collection
108
- if (!Array.isArray(track.waitPoints)) {
109
- track.waitPoints = [];
110
- }
111
-
112
- // Is this the same track?
113
- const current = this.current;
114
- if (
115
- GroupPlaybackTrack.compareMetadata(
116
- this.current.metadata,
117
- track.metadata
118
- )
119
- ) {
120
- // Add any dynamic wait points.
121
- track.waitPoints.forEach((waitPoint) => {
122
- this.addWaitPoint(waitPoint);
123
- });
124
-
125
- // Ignore if same playback state
126
- if (
127
- track.timestamp == current.timestamp &&
128
- track.clientId == current.clientId
129
- ) {
130
- return false;
131
- }
132
- }
133
-
134
- // Ignore state changes that are older
135
- if (track.timestamp < current.timestamp) {
136
- return false;
137
- }
138
-
139
- // Ignore state changes that are from a clientId that sorts higher then the current one.
140
- // - current.clientId should not be empty if current.timestamp != 0
141
- if (
142
- track.timestamp == current.timestamp &&
143
- track.clientId.localeCompare(current.clientId) > 0
144
- ) {
145
- return false;
146
- }
147
-
148
- // Update current track
149
- this._current = track;
150
-
151
- // Notify listeners
152
- this.emit(GroupPlaybackTrackEvents.trackChange, {
153
- name: GroupPlaybackTrackEvents.trackChange,
154
- clientId: track.clientId,
155
- metadata: track.metadata,
156
- source,
157
- });
158
-
159
- return true;
160
- }
161
-
162
- public compare(metadata: ExtendedMediaMetadata | null): boolean {
163
- return GroupPlaybackTrack.compareMetadata(
164
- this.current.metadata,
165
- metadata
166
- );
167
- }
168
-
169
- public static compareMetadata(
170
- current: ExtendedMediaMetadata | null,
171
- metadata: ExtendedMediaMetadata | null
172
- ): boolean {
173
- // Only compare when we have two metadata instances
174
- if (current && metadata) {
175
- return JSON.stringify(current) == JSON.stringify(metadata);
176
- } else if (!current && metadata) {
177
- return false;
178
- }
179
-
180
- return true;
181
- }
182
- }
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the Microsoft Live Share SDK License.
4
+ */
5
+
6
+ import EventEmitter from "events";
7
+ import { IMediaPlayerState } from "../LiveMediaSessionCoordinator";
8
+ import {
9
+ CoordinationWaitPoint,
10
+ ExtendedMediaMetadata,
11
+ ExtendedMediaSessionActionSource,
12
+ } from "../MediaSessionExtensions";
13
+ import { IGroupStateEvent } from "./interfaces";
14
+
15
+ /**
16
+ * @hidden
17
+ */
18
+ export interface IPlaybackTrack {
19
+ metadata: ExtendedMediaMetadata | null;
20
+ waitPoints: CoordinationWaitPoint[];
21
+ timestamp: number;
22
+ clientId: string;
23
+ }
24
+
25
+ /**
26
+ * @hidden
27
+ */
28
+ export enum GroupPlaybackTrackEvents {
29
+ trackChange = "trackChange",
30
+ }
31
+
32
+ /**
33
+ * @hidden
34
+ */
35
+ export interface IPlaybackTrackChangeEvent extends IGroupStateEvent {
36
+ metadata: ExtendedMediaMetadata | null;
37
+ }
38
+
39
+ /**
40
+ * @hidden
41
+ */
42
+ export class GroupPlaybackTrack extends EventEmitter {
43
+ private readonly _getMediaPlayerState: () => IMediaPlayerState;
44
+ private _current: IPlaybackTrack;
45
+
46
+ constructor(getMediaPlayerState: () => IMediaPlayerState) {
47
+ super();
48
+ this._current = {
49
+ metadata: null,
50
+ waitPoints: [],
51
+ timestamp: 0,
52
+ clientId: "",
53
+ };
54
+ this._getMediaPlayerState = getMediaPlayerState;
55
+ }
56
+
57
+ public get current(): Readonly<IPlaybackTrack> {
58
+ // Populate with sessions current metadata if null
59
+ if (!this._current.metadata) {
60
+ this._current.metadata = this._getMediaPlayerState().metadata;
61
+ }
62
+
63
+ return this._current;
64
+ }
65
+
66
+ public get metadata(): ExtendedMediaMetadata | null {
67
+ return this.current.metadata;
68
+ }
69
+
70
+ public addWaitPoint(waitPoint: CoordinationWaitPoint): boolean {
71
+ for (let i = 0; i < this._current.waitPoints.length; i++) {
72
+ const current = this._current.waitPoints[i];
73
+ if (current.position == waitPoint.position) {
74
+ // Already exists
75
+ return false;
76
+ } else if (current.position > waitPoint.position) {
77
+ // Insert before current position
78
+ this._current.waitPoints.splice(i, 0, waitPoint);
79
+ return true;
80
+ }
81
+ }
82
+
83
+ // Append to list
84
+ this._current.waitPoints.push(waitPoint);
85
+ return true;
86
+ }
87
+
88
+ public findNextWaitPoint(
89
+ lastWaitPoint: CoordinationWaitPoint | undefined
90
+ ): CoordinationWaitPoint | undefined {
91
+ const waitPoints = this._current.waitPoints || [];
92
+ for (const waitPoint of waitPoints) {
93
+ if (lastWaitPoint && waitPoint.position <= lastWaitPoint.position) {
94
+ continue;
95
+ }
96
+
97
+ return waitPoint;
98
+ }
99
+
100
+ return undefined;
101
+ }
102
+
103
+ public updateTrack(
104
+ track: IPlaybackTrack,
105
+ source: ExtendedMediaSessionActionSource
106
+ ): boolean {
107
+ // Guard against missing waitPoints collection
108
+ if (!Array.isArray(track.waitPoints)) {
109
+ track.waitPoints = [];
110
+ }
111
+
112
+ // Is this the same track?
113
+ const current = this.current;
114
+ if (
115
+ GroupPlaybackTrack.compareMetadata(
116
+ this.current.metadata,
117
+ track.metadata
118
+ )
119
+ ) {
120
+ // Add any dynamic wait points.
121
+ track.waitPoints.forEach((waitPoint) => {
122
+ this.addWaitPoint(waitPoint);
123
+ });
124
+
125
+ // Ignore if same playback state
126
+ if (
127
+ track.timestamp == current.timestamp &&
128
+ track.clientId == current.clientId
129
+ ) {
130
+ return false;
131
+ }
132
+ }
133
+
134
+ // Ignore state changes that are older
135
+ if (track.timestamp < current.timestamp) {
136
+ return false;
137
+ }
138
+
139
+ // Ignore state changes that are from a clientId that sorts higher then the current one.
140
+ // - current.clientId should not be empty if current.timestamp != 0
141
+ if (
142
+ track.timestamp == current.timestamp &&
143
+ track.clientId.localeCompare(current.clientId) > 0
144
+ ) {
145
+ return false;
146
+ }
147
+
148
+ // Update current track
149
+ this._current = track;
150
+
151
+ // Notify listeners
152
+ const event: IPlaybackTrackChangeEvent = {
153
+ name: GroupPlaybackTrackEvents.trackChange,
154
+ clientId: track.clientId,
155
+ metadata: track.metadata,
156
+ source,
157
+ };
158
+ this.emit(GroupPlaybackTrackEvents.trackChange, event);
159
+
160
+ return true;
161
+ }
162
+
163
+ public compare(metadata: ExtendedMediaMetadata | null): boolean {
164
+ return GroupPlaybackTrack.compareMetadata(
165
+ this.current.metadata,
166
+ metadata
167
+ );
168
+ }
169
+
170
+ public static compareMetadata(
171
+ current: ExtendedMediaMetadata | null,
172
+ metadata: ExtendedMediaMetadata | null
173
+ ): boolean {
174
+ // Only compare when we have two metadata instances
175
+ if (current && metadata) {
176
+ return JSON.stringify(current) == JSON.stringify(metadata);
177
+ } else if (!current && metadata) {
178
+ return false;
179
+ }
180
+
181
+ return true;
182
+ }
183
+ }
@@ -1,104 +1,105 @@
1
- /**
2
- * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Licensed under the Microsoft Live Share SDK License.
4
- */
5
-
6
- import { ILiveEvent } from "@microsoft/live-share";
7
- import EventEmitter from "events";
8
- import {
9
- GroupPlaybackTrack,
10
- GroupPlaybackTrackEvents,
11
- } from "./GroupPlaybackTrack";
12
- import { ExtendedMediaSessionActionSource } from "../MediaSessionExtensions";
13
-
14
- /**
15
- * @hidden
16
- */
17
- export interface IPlaybackTrackData {
18
- data: object | null;
19
- timestamp: number;
20
- clientId: string;
21
- }
22
-
23
- /**
24
- * @hidden
25
- */
26
- export enum PlaybackTrackDataEvents {
27
- dataChange = "dataChange",
28
- }
29
-
30
- /**
31
- * @hidden
32
- */
33
- export interface IPlaybackTrackDataChangeEvent extends ILiveEvent {
34
- data: object | null;
35
- }
36
-
37
- /**
38
- * @hidden
39
- */
40
- export class GroupPlaybackTrackData extends EventEmitter {
41
- private _track: GroupPlaybackTrack;
42
- private _current: IPlaybackTrackData;
43
-
44
- constructor(track: GroupPlaybackTrack) {
45
- super();
46
- this._track = track;
47
- this._current = { data: null, timestamp: 0, clientId: "" };
48
-
49
- // Listen for track changes
50
- this._track.on(GroupPlaybackTrackEvents.trackChange, () => {
51
- // Track changed so reset state to empty object
52
- this._current = {
53
- data: null,
54
- timestamp: this._track.current.timestamp,
55
- clientId: this._track.current.clientId,
56
- };
57
- });
58
- }
59
-
60
- public get current(): Readonly<IPlaybackTrackData> {
61
- return this._current;
62
- }
63
-
64
- public get data(): object | null {
65
- return this.current.data;
66
- }
67
-
68
- public updateData(
69
- event: IPlaybackTrackData,
70
- source: ExtendedMediaSessionActionSource
71
- ): boolean {
72
- // Ignore state changes that are older
73
- const current = this.current;
74
- if (event.timestamp < current.timestamp) {
75
- return false;
76
- }
77
-
78
- // Ignore state changes that have the same timestamp and the clientId sorts higher.
79
- if (
80
- event.timestamp == current.timestamp &&
81
- event.clientId.localeCompare(current.clientId) > 0
82
- ) {
83
- return false;
84
- }
85
-
86
- // Ignore state changes for same data object
87
- if (JSON.stringify(current.data) == JSON.stringify(event.data)) {
88
- return false;
89
- }
90
-
91
- // Update current data
92
- this._current = event;
93
-
94
- // Notify listeners
95
- this.emit(PlaybackTrackDataEvents.dataChange, {
96
- type: PlaybackTrackDataEvents.dataChange,
97
- clientId: event.clientId,
98
- data: event.data,
99
- source,
100
- });
101
-
102
- return true;
103
- }
104
- }
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the Microsoft Live Share SDK License.
4
+ */
5
+
6
+ import EventEmitter from "events";
7
+ import {
8
+ GroupPlaybackTrack,
9
+ GroupPlaybackTrackEvents,
10
+ } from "./GroupPlaybackTrack";
11
+ import { ExtendedMediaSessionActionSource } from "../MediaSessionExtensions";
12
+ import { IGroupStateEvent } from "./interfaces";
13
+
14
+ /**
15
+ * @hidden
16
+ */
17
+ export interface IPlaybackTrackData {
18
+ data: object | null;
19
+ timestamp: number;
20
+ clientId: string;
21
+ }
22
+
23
+ /**
24
+ * @hidden
25
+ */
26
+ export enum PlaybackTrackDataEvents {
27
+ dataChange = "dataChange",
28
+ }
29
+
30
+ /**
31
+ * @hidden
32
+ */
33
+ export interface IPlaybackTrackDataChangeEvent extends IGroupStateEvent {
34
+ data: object | null;
35
+ }
36
+
37
+ /**
38
+ * @hidden
39
+ */
40
+ export class GroupPlaybackTrackData extends EventEmitter {
41
+ private _track: GroupPlaybackTrack;
42
+ private _current: IPlaybackTrackData;
43
+
44
+ constructor(track: GroupPlaybackTrack) {
45
+ super();
46
+ this._track = track;
47
+ this._current = { data: null, timestamp: 0, clientId: "" };
48
+
49
+ // Listen for track changes
50
+ this._track.on(GroupPlaybackTrackEvents.trackChange, () => {
51
+ // Track changed so reset state to empty object
52
+ this._current = {
53
+ data: null,
54
+ timestamp: this._track.current.timestamp,
55
+ clientId: this._track.current.clientId,
56
+ };
57
+ });
58
+ }
59
+
60
+ public get current(): Readonly<IPlaybackTrackData> {
61
+ return this._current;
62
+ }
63
+
64
+ public get data(): object | null {
65
+ return this.current.data;
66
+ }
67
+
68
+ public updateData(
69
+ trackData: IPlaybackTrackData,
70
+ source: ExtendedMediaSessionActionSource
71
+ ): boolean {
72
+ // Ignore state changes that are older
73
+ const current = this.current;
74
+ if (trackData.timestamp < current.timestamp) {
75
+ return false;
76
+ }
77
+
78
+ // Ignore state changes that have the same timestamp and the clientId sorts higher.
79
+ if (
80
+ trackData.timestamp == current.timestamp &&
81
+ trackData.clientId.localeCompare(current.clientId) > 0
82
+ ) {
83
+ return false;
84
+ }
85
+
86
+ // Ignore state changes for same data object
87
+ if (JSON.stringify(current.data) == JSON.stringify(trackData.data)) {
88
+ return false;
89
+ }
90
+
91
+ // Update current data
92
+ this._current = trackData;
93
+
94
+ // Notify listeners
95
+ const event: IPlaybackTrackDataChangeEvent = {
96
+ name: PlaybackTrackDataEvents.dataChange,
97
+ clientId: trackData.clientId,
98
+ data: trackData.data,
99
+ source,
100
+ };
101
+ this.emit(PlaybackTrackDataEvents.dataChange, event);
102
+
103
+ return true;
104
+ }
105
+ }