@microsoft/live-share-media 0.5.1 → 1.0.0-preview.3

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