@microsoft/live-share-media 1.0.0-preview.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.
- package/README.md +1 -1
- package/bin/IMediaPlayer.d.ts.map +1 -1
- package/bin/LiveMediaSession.d.ts +7 -7
- package/bin/LiveMediaSession.d.ts.map +1 -1
- package/bin/LiveMediaSession.js +28 -17
- package/bin/LiveMediaSession.js.map +1 -1
- package/bin/LiveMediaSessionCoordinator.d.ts +2 -2
- package/bin/LiveMediaSessionCoordinator.d.ts.map +1 -1
- package/bin/LiveMediaSessionCoordinator.js +34 -22
- package/bin/LiveMediaSessionCoordinator.js.map +1 -1
- package/bin/LiveMediaSessionCoordinatorSuspension.d.ts +1 -1
- package/bin/LiveMediaSessionCoordinatorSuspension.d.ts.map +1 -1
- package/bin/LiveMediaSessionCoordinatorSuspension.js.map +1 -1
- package/bin/MediaPlayerSynchronizer.d.ts +7 -7
- package/bin/MediaPlayerSynchronizer.d.ts.map +1 -1
- package/bin/MediaPlayerSynchronizer.js +121 -69
- package/bin/MediaPlayerSynchronizer.js.map +1 -1
- package/bin/MediaSessionActionThrottler.d.ts +1 -1
- package/bin/MediaSessionActionThrottler.d.ts.map +1 -1
- package/bin/MediaSessionActionThrottler.js.map +1 -1
- package/bin/MediaSessionExtensions.d.ts.map +1 -1
- package/bin/RepeatedActionThrottler.d.ts +2 -2
- package/bin/RepeatedActionThrottler.d.ts.map +1 -1
- package/bin/RepeatedActionThrottler.js +9 -3
- package/bin/RepeatedActionThrottler.js.map +1 -1
- package/bin/VolumeManager.d.ts +1 -1
- package/bin/VolumeManager.d.ts.map +1 -1
- package/bin/VolumeManager.js +4 -2
- package/bin/VolumeManager.js.map +1 -1
- package/bin/index.d.ts +9 -9
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js.map +1 -1
- package/bin/internals/GroupCoordinatorState.d.ts +8 -8
- package/bin/internals/GroupCoordinatorState.d.ts.map +1 -1
- package/bin/internals/GroupCoordinatorState.js +91 -53
- package/bin/internals/GroupCoordinatorState.js.map +1 -1
- package/bin/internals/GroupPlaybackPosition.d.ts +3 -3
- package/bin/internals/GroupPlaybackPosition.d.ts.map +1 -1
- package/bin/internals/GroupPlaybackPosition.js +22 -13
- package/bin/internals/GroupPlaybackPosition.js.map +1 -1
- package/bin/internals/GroupPlaybackTrack.d.ts +4 -4
- package/bin/internals/GroupPlaybackTrack.d.ts.map +1 -1
- package/bin/internals/GroupPlaybackTrack.js +14 -4
- package/bin/internals/GroupPlaybackTrack.js.map +1 -1
- package/bin/internals/GroupPlaybackTrackData.d.ts +3 -3
- package/bin/internals/GroupPlaybackTrackData.d.ts.map +1 -1
- package/bin/internals/GroupPlaybackTrackData.js +8 -4
- package/bin/internals/GroupPlaybackTrackData.js.map +1 -1
- package/bin/internals/GroupTransportState.d.ts +5 -5
- package/bin/internals/GroupTransportState.d.ts.map +1 -1
- package/bin/internals/GroupTransportState.js +27 -12
- package/bin/internals/GroupTransportState.js.map +1 -1
- package/bin/internals/consts.d.ts.map +1 -1
- package/bin/internals/consts.js +54 -54
- package/bin/internals/consts.js.map +1 -1
- package/bin/internals/index.d.ts +6 -6
- package/package.json +3 -3
- package/src/IMediaPlayer.ts +10 -2
- package/src/LiveMediaSession.ts +133 -71
- package/src/LiveMediaSessionCoordinator.ts +302 -142
- package/src/LiveMediaSessionCoordinatorSuspension.ts +13 -5
- package/src/MediaPlayerSynchronizer.ts +317 -146
- package/src/MediaSessionActionThrottler.ts +5 -3
- package/src/MediaSessionExtensions.ts +15 -5
- package/src/RepeatedActionThrottler.ts +27 -9
- package/src/VolumeManager.ts +24 -12
- package/src/index.ts +9 -10
- package/src/internals/GroupCoordinatorState.ts +274 -114
- package/src/internals/GroupPlaybackPosition.ts +61 -27
- package/src/internals/GroupPlaybackTrack.ts +51 -22
- package/src/internals/GroupPlaybackTrackData.ts +24 -16
- package/src/internals/GroupTransportState.ts +53 -23
- package/src/internals/consts.ts +73 -55
- package/src/internals/index.ts +6 -6
- package/src/test/GroupPlaybackPosition.spec.ts +371 -111
- package/src/test/GroupPlaybackTrack.spec.ts +91 -35
- package/src/test/SharedMediaSession.spec.ts +64 -28
- package/src/test/SharedMediaSessionCoordinator.spec.ts +86 -46
- package/src/test/VolumeManager.spec.ts +38 -31
- package/tsconfig.json +1 -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
|
@@ -3,16 +3,39 @@
|
|
|
3
3
|
* Licensed under the Microsoft Live Share SDK License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import
|
|
15
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
IEvent,
|
|
8
|
+
ILiveEvent,
|
|
9
|
+
LiveEvent,
|
|
10
|
+
TimeInterval,
|
|
11
|
+
IRuntimeSignaler,
|
|
12
|
+
LiveTelemetryLogger,
|
|
13
|
+
} from "@microsoft/live-share";
|
|
14
|
+
import EventEmitter from "events";
|
|
15
|
+
import {
|
|
16
|
+
ExtendedMediaMetadata,
|
|
17
|
+
CoordinationWaitPoint,
|
|
18
|
+
ExtendedMediaSessionPlaybackState,
|
|
19
|
+
ExtendedMediaSessionActionDetails,
|
|
20
|
+
} from "../MediaSessionExtensions";
|
|
21
|
+
import {
|
|
22
|
+
GroupPlaybackTrack,
|
|
23
|
+
GroupPlaybackTrackEvents,
|
|
24
|
+
IPlaybackTrack,
|
|
25
|
+
} from "./GroupPlaybackTrack";
|
|
26
|
+
import { GroupTransportState, ITransportState } from "./GroupTransportState";
|
|
27
|
+
import {
|
|
28
|
+
GroupPlaybackPosition,
|
|
29
|
+
ICurrentPlaybackPosition,
|
|
30
|
+
} from "./GroupPlaybackPosition";
|
|
31
|
+
import { IMediaPlayerState } from "../LiveMediaSessionCoordinator";
|
|
32
|
+
import { GroupTransportStateEvents } from "./GroupTransportState";
|
|
33
|
+
import {
|
|
34
|
+
GroupPlaybackTrackData,
|
|
35
|
+
PlaybackTrackDataEvents,
|
|
36
|
+
IPlaybackTrackData,
|
|
37
|
+
} from "./GroupPlaybackTrackData";
|
|
38
|
+
import { TelemetryEvents } from "./consts";
|
|
16
39
|
|
|
17
40
|
/**
|
|
18
41
|
* @hidden
|
|
@@ -38,7 +61,7 @@ export interface ITransportCommandEvent extends ILiveEvent {
|
|
|
38
61
|
* @hidden
|
|
39
62
|
*/
|
|
40
63
|
export interface ISetTrackEvent extends ILiveEvent {
|
|
41
|
-
metadata: ExtendedMediaMetadata|null;
|
|
64
|
+
metadata: ExtendedMediaMetadata | null;
|
|
42
65
|
waitPoints: CoordinationWaitPoint[];
|
|
43
66
|
}
|
|
44
67
|
|
|
@@ -46,13 +69,13 @@ export interface ISetTrackEvent extends ILiveEvent {
|
|
|
46
69
|
* @hidden
|
|
47
70
|
*/
|
|
48
71
|
export interface ISetTrackDataEvent extends ILiveEvent {
|
|
49
|
-
data: object|null;
|
|
72
|
+
data: object | null;
|
|
50
73
|
}
|
|
51
74
|
|
|
52
75
|
/**
|
|
53
76
|
* @hidden
|
|
54
77
|
*/
|
|
55
|
-
|
|
78
|
+
export interface ITriggerActionEvent extends IEvent {
|
|
56
79
|
details: ExtendedMediaSessionActionDetails;
|
|
57
80
|
}
|
|
58
81
|
|
|
@@ -60,14 +83,14 @@ export interface ISetTrackDataEvent extends ILiveEvent {
|
|
|
60
83
|
* @hidden
|
|
61
84
|
*/
|
|
62
85
|
export enum GroupCoordinatorStateEvents {
|
|
63
|
-
newwaitpoint =
|
|
64
|
-
triggeraction =
|
|
86
|
+
newwaitpoint = "newwaitpoint",
|
|
87
|
+
triggeraction = "triggeraction",
|
|
65
88
|
}
|
|
66
89
|
|
|
67
90
|
/**
|
|
68
91
|
* @hidden
|
|
69
92
|
*/
|
|
70
|
-
|
|
93
|
+
export class GroupCoordinatorState extends EventEmitter {
|
|
71
94
|
private readonly _runtime: IRuntimeSignaler;
|
|
72
95
|
private readonly _logger: LiveTelemetryLogger;
|
|
73
96
|
private readonly _maxPlaybackDrift: TimeInterval;
|
|
@@ -87,69 +110,118 @@ export enum GroupCoordinatorStateEvents {
|
|
|
87
110
|
// - Soft suspensions temporarily disconnect the local media session when transitioning between
|
|
88
111
|
// paused, playing, and none states. This is to give the local client time to finish any inprogress
|
|
89
112
|
// operations like sending a transport command or ending a suspension.
|
|
90
|
-
private _lastStateChange: ExtendedMediaSessionPlaybackState =
|
|
113
|
+
private _lastStateChange: ExtendedMediaSessionPlaybackState = "none";
|
|
91
114
|
private _lastStateChangeTime: number = 0;
|
|
92
115
|
|
|
93
|
-
constructor
|
|
116
|
+
constructor(
|
|
117
|
+
runtime: IRuntimeSignaler,
|
|
118
|
+
maxPlaybackDrift: TimeInterval,
|
|
119
|
+
positionUpdateInterval: TimeInterval,
|
|
120
|
+
getMediaPlayerState: () => IMediaPlayerState
|
|
121
|
+
) {
|
|
94
122
|
super();
|
|
95
123
|
this._runtime = runtime;
|
|
96
124
|
this._logger = new LiveTelemetryLogger(runtime);
|
|
97
125
|
this._maxPlaybackDrift = maxPlaybackDrift;
|
|
98
126
|
this._playbackTrack = new GroupPlaybackTrack(getMediaPlayerState);
|
|
99
|
-
this._playbackTrackData = new GroupPlaybackTrackData(
|
|
100
|
-
|
|
101
|
-
|
|
127
|
+
this._playbackTrackData = new GroupPlaybackTrackData(
|
|
128
|
+
this._playbackTrack
|
|
129
|
+
);
|
|
130
|
+
this._transportState = new GroupTransportState(
|
|
131
|
+
this._playbackTrack,
|
|
132
|
+
getMediaPlayerState
|
|
133
|
+
);
|
|
134
|
+
this._playbackPosition = new GroupPlaybackPosition(
|
|
135
|
+
this._transportState,
|
|
136
|
+
this._runtime,
|
|
137
|
+
positionUpdateInterval
|
|
138
|
+
);
|
|
102
139
|
this._getMediaPlayerState = getMediaPlayerState;
|
|
103
140
|
|
|
104
141
|
// Listen track related events
|
|
105
|
-
this._playbackTrack.on(GroupPlaybackTrackEvents.trackChange, evt => {
|
|
142
|
+
this._playbackTrack.on(GroupPlaybackTrackEvents.trackChange, (evt) => {
|
|
106
143
|
if (!this.isSuspended) {
|
|
107
|
-
this._logger.sendTelemetryEvent(
|
|
144
|
+
this._logger.sendTelemetryEvent(
|
|
145
|
+
TelemetryEvents.GroupCoordinator.TrackChanged
|
|
146
|
+
);
|
|
108
147
|
this.emitSetTrack(evt.metadata!);
|
|
109
148
|
} else {
|
|
110
|
-
this._logger.sendTelemetryEvent(
|
|
149
|
+
this._logger.sendTelemetryEvent(
|
|
150
|
+
TelemetryEvents.GroupCoordinator.TrackChangeDelayed
|
|
151
|
+
);
|
|
111
152
|
}
|
|
112
153
|
});
|
|
113
154
|
|
|
114
155
|
// Listen for track data changes
|
|
115
|
-
this._playbackTrackData.on(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
this.
|
|
119
|
-
|
|
120
|
-
|
|
156
|
+
this._playbackTrackData.on(
|
|
157
|
+
PlaybackTrackDataEvents.dataChange,
|
|
158
|
+
(evt) => {
|
|
159
|
+
if (!this.isSuspended && !this.isWaiting) {
|
|
160
|
+
this._logger.sendTelemetryEvent(
|
|
161
|
+
TelemetryEvents.GroupCoordinator.TrackDataChanged
|
|
162
|
+
);
|
|
163
|
+
this.emitTriggerAction({
|
|
164
|
+
action: "datachange",
|
|
165
|
+
data: evt.data,
|
|
166
|
+
});
|
|
167
|
+
} else {
|
|
168
|
+
this._logger.sendTelemetryEvent(
|
|
169
|
+
TelemetryEvents.GroupCoordinator.TrackDataChangeDelayed
|
|
170
|
+
);
|
|
171
|
+
}
|
|
121
172
|
}
|
|
122
|
-
|
|
173
|
+
);
|
|
123
174
|
|
|
124
175
|
// Listen to transport related events
|
|
125
|
-
this._transportState.on(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
176
|
+
this._transportState.on(
|
|
177
|
+
GroupTransportStateEvents.transportStateChange,
|
|
178
|
+
(evt) => {
|
|
179
|
+
if (!this.isSuspended && !this.isWaiting) {
|
|
180
|
+
this._logger.sendTelemetryEvent(
|
|
181
|
+
TelemetryEvents.GroupCoordinator.TransportStateChanged,
|
|
182
|
+
null,
|
|
183
|
+
{
|
|
184
|
+
action: evt.action,
|
|
185
|
+
seekTime: evt.seekTime,
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
// Trigger action
|
|
190
|
+
switch (evt.action) {
|
|
191
|
+
case "play":
|
|
192
|
+
this.emitTriggerAction({
|
|
193
|
+
action: "play",
|
|
194
|
+
seekTime: evt.seekTime,
|
|
195
|
+
});
|
|
196
|
+
break;
|
|
137
197
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
198
|
+
case "pause":
|
|
199
|
+
this.emitTriggerAction({
|
|
200
|
+
action: "pause",
|
|
201
|
+
seekTime: evt.seekTime,
|
|
202
|
+
});
|
|
203
|
+
break;
|
|
141
204
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
205
|
+
case "seekto":
|
|
206
|
+
this.emitTriggerAction({
|
|
207
|
+
action: "seekto",
|
|
208
|
+
seekTime: evt.seekTime,
|
|
209
|
+
});
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
this._logger.sendTelemetryEvent(
|
|
214
|
+
TelemetryEvents.GroupCoordinator
|
|
215
|
+
.TransportStateChangeDelayed,
|
|
216
|
+
null,
|
|
217
|
+
{
|
|
218
|
+
action: evt.action,
|
|
219
|
+
seekTime: evt.seekTime,
|
|
220
|
+
}
|
|
221
|
+
);
|
|
145
222
|
}
|
|
146
|
-
} else {
|
|
147
|
-
this._logger.sendTelemetryEvent(TelemetryEvents.GroupCoordinator.TransportStateChangeDelayed, null, {
|
|
148
|
-
action: evt.action,
|
|
149
|
-
seekTime: evt.seekTime
|
|
150
|
-
});
|
|
151
223
|
}
|
|
152
|
-
|
|
224
|
+
);
|
|
153
225
|
}
|
|
154
226
|
|
|
155
227
|
public get playbackTrack(): GroupPlaybackTrack {
|
|
@@ -168,7 +240,7 @@ export enum GroupCoordinatorStateEvents {
|
|
|
168
240
|
return this._playbackPosition;
|
|
169
241
|
}
|
|
170
242
|
|
|
171
|
-
public get waitingAt(): CoordinationWaitPoint|undefined {
|
|
243
|
+
public get waitingAt(): CoordinationWaitPoint | undefined {
|
|
172
244
|
return this._waitPoint;
|
|
173
245
|
}
|
|
174
246
|
|
|
@@ -204,7 +276,9 @@ export enum GroupCoordinatorStateEvents {
|
|
|
204
276
|
}
|
|
205
277
|
}
|
|
206
278
|
|
|
207
|
-
public createPositionUpdateEvent(
|
|
279
|
+
public createPositionUpdateEvent(
|
|
280
|
+
state: IMediaPlayerState
|
|
281
|
+
): Partial<IPositionUpdateEvent> {
|
|
208
282
|
const { positionState, playbackState } = state;
|
|
209
283
|
if (this.isSuspended) {
|
|
210
284
|
// Report suspension state
|
|
@@ -212,9 +286,9 @@ export enum GroupCoordinatorStateEvents {
|
|
|
212
286
|
track: this.playbackTrack.current,
|
|
213
287
|
trackData: this.playbackTrackData.current,
|
|
214
288
|
transport: this.transportState.current,
|
|
215
|
-
playbackState:
|
|
289
|
+
playbackState: "suspended",
|
|
216
290
|
position: positionState?.position || 0.0,
|
|
217
|
-
waitPoint: this._waitPoint
|
|
291
|
+
waitPoint: this._waitPoint,
|
|
218
292
|
};
|
|
219
293
|
} else {
|
|
220
294
|
// Report current position
|
|
@@ -222,9 +296,9 @@ export enum GroupCoordinatorStateEvents {
|
|
|
222
296
|
track: this.playbackTrack.current,
|
|
223
297
|
trackData: this.playbackTrackData.current,
|
|
224
298
|
transport: this.transportState.current,
|
|
225
|
-
playbackState: this._waitPoint ?
|
|
299
|
+
playbackState: this._waitPoint ? "waiting" : playbackState,
|
|
226
300
|
position: positionState?.position || 0.0,
|
|
227
|
-
waitPoint: this._waitPoint
|
|
301
|
+
waitPoint: this._waitPoint,
|
|
228
302
|
};
|
|
229
303
|
}
|
|
230
304
|
}
|
|
@@ -236,11 +310,20 @@ export enum GroupCoordinatorStateEvents {
|
|
|
236
310
|
metadata: event.metadata,
|
|
237
311
|
waitPoints: event.waitPoints,
|
|
238
312
|
timestamp: event.timestamp,
|
|
239
|
-
clientId: event.clientId ||
|
|
313
|
+
clientId: event.clientId || "",
|
|
240
314
|
});
|
|
241
315
|
|
|
242
316
|
if (updated) {
|
|
243
|
-
this._logger.sendTelemetryEvent(
|
|
317
|
+
this._logger.sendTelemetryEvent(
|
|
318
|
+
TelemetryEvents.SessionCoordinator.RemoteSetTrackReceived,
|
|
319
|
+
null,
|
|
320
|
+
{
|
|
321
|
+
correlationId: LiveTelemetryLogger.formatCorrelationId(
|
|
322
|
+
event.clientId,
|
|
323
|
+
event.timestamp
|
|
324
|
+
),
|
|
325
|
+
}
|
|
326
|
+
);
|
|
244
327
|
}
|
|
245
328
|
}
|
|
246
329
|
|
|
@@ -250,15 +333,27 @@ export enum GroupCoordinatorStateEvents {
|
|
|
250
333
|
const updated = this.playbackTrackData.updateData({
|
|
251
334
|
data: event.data,
|
|
252
335
|
timestamp: event.timestamp,
|
|
253
|
-
clientId: event.clientId ||
|
|
336
|
+
clientId: event.clientId || "",
|
|
254
337
|
});
|
|
255
338
|
|
|
256
339
|
if (updated) {
|
|
257
|
-
this._logger.sendTelemetryEvent(
|
|
340
|
+
this._logger.sendTelemetryEvent(
|
|
341
|
+
TelemetryEvents.SessionCoordinator.RemoteSetTrackReceived,
|
|
342
|
+
null,
|
|
343
|
+
{
|
|
344
|
+
correlationId: LiveTelemetryLogger.formatCorrelationId(
|
|
345
|
+
event.clientId,
|
|
346
|
+
event.timestamp
|
|
347
|
+
),
|
|
348
|
+
}
|
|
349
|
+
);
|
|
258
350
|
}
|
|
259
351
|
}
|
|
260
352
|
|
|
261
|
-
public handleTransportCommand(
|
|
353
|
+
public handleTransportCommand(
|
|
354
|
+
event: ITransportCommandEvent,
|
|
355
|
+
local: boolean
|
|
356
|
+
): void {
|
|
262
357
|
// Ensure change is for current track
|
|
263
358
|
// - Will trigger a 'trackChange' event if newer track.
|
|
264
359
|
this.playbackTrack.updateTrack(event.track);
|
|
@@ -266,11 +361,11 @@ export enum GroupCoordinatorStateEvents {
|
|
|
266
361
|
// Update playback state
|
|
267
362
|
let playbackState = this.transportState.playbackState;
|
|
268
363
|
switch (event.name) {
|
|
269
|
-
case
|
|
270
|
-
playbackState =
|
|
364
|
+
case "play":
|
|
365
|
+
playbackState = "playing";
|
|
271
366
|
break;
|
|
272
|
-
case
|
|
273
|
-
playbackState =
|
|
367
|
+
case "pause":
|
|
368
|
+
playbackState = "paused";
|
|
274
369
|
break;
|
|
275
370
|
}
|
|
276
371
|
|
|
@@ -279,29 +374,55 @@ export enum GroupCoordinatorStateEvents {
|
|
|
279
374
|
playbackState: playbackState,
|
|
280
375
|
startPosition: event.position,
|
|
281
376
|
timestamp: event.timestamp,
|
|
282
|
-
clientId: event.clientId ||
|
|
377
|
+
clientId: event.clientId || "",
|
|
283
378
|
};
|
|
284
379
|
const updated = this.transportState.updateState(newState);
|
|
285
380
|
|
|
286
381
|
if (updated) {
|
|
287
|
-
const correlationId = LiveTelemetryLogger.formatCorrelationId(
|
|
382
|
+
const correlationId = LiveTelemetryLogger.formatCorrelationId(
|
|
383
|
+
event.clientId,
|
|
384
|
+
event.timestamp
|
|
385
|
+
);
|
|
288
386
|
switch (event.name) {
|
|
289
|
-
case
|
|
290
|
-
this._logger.sendTelemetryEvent(
|
|
387
|
+
case "play":
|
|
388
|
+
this._logger.sendTelemetryEvent(
|
|
389
|
+
TelemetryEvents.SessionCoordinator
|
|
390
|
+
.RemotePlayReceived,
|
|
391
|
+
null,
|
|
392
|
+
{
|
|
393
|
+
correlationId: correlationId,
|
|
394
|
+
}
|
|
395
|
+
);
|
|
291
396
|
break;
|
|
292
|
-
case
|
|
293
|
-
this._logger.sendTelemetryEvent(
|
|
397
|
+
case "pause":
|
|
398
|
+
this._logger.sendTelemetryEvent(
|
|
399
|
+
TelemetryEvents.SessionCoordinator
|
|
400
|
+
.RemotePauseReceived,
|
|
401
|
+
null,
|
|
402
|
+
{
|
|
403
|
+
correlationId: correlationId,
|
|
404
|
+
}
|
|
405
|
+
);
|
|
294
406
|
break;
|
|
295
|
-
case
|
|
296
|
-
this._logger.sendTelemetryEvent(
|
|
407
|
+
case "seekTo":
|
|
408
|
+
this._logger.sendTelemetryEvent(
|
|
409
|
+
TelemetryEvents.SessionCoordinator
|
|
410
|
+
.RemoteSeekToReceived,
|
|
411
|
+
null,
|
|
412
|
+
{
|
|
413
|
+
correlationId: correlationId,
|
|
414
|
+
}
|
|
415
|
+
);
|
|
297
416
|
break;
|
|
298
417
|
}
|
|
299
|
-
|
|
300
418
|
}
|
|
301
419
|
}
|
|
302
420
|
}
|
|
303
421
|
|
|
304
|
-
public handlePositionUpdate(
|
|
422
|
+
public handlePositionUpdate(
|
|
423
|
+
event: IPositionUpdateEvent,
|
|
424
|
+
local: boolean
|
|
425
|
+
): void {
|
|
305
426
|
// Ensure change is for current track
|
|
306
427
|
// - Will trigger a 'trackChange' event if newer track.
|
|
307
428
|
this.playbackTrack.updateTrack(event.track);
|
|
@@ -312,7 +433,7 @@ export enum GroupCoordinatorStateEvents {
|
|
|
312
433
|
// Update transport state if needed
|
|
313
434
|
// - Ignore transport state changes if the client has ended as this will cause the local
|
|
314
435
|
// player to start playback even though the video may have ended for everyone.
|
|
315
|
-
if (event.playbackState !=
|
|
436
|
+
if (event.playbackState != "ended") {
|
|
316
437
|
this.transportState.updateState(event.transport);
|
|
317
438
|
}
|
|
318
439
|
|
|
@@ -324,7 +445,7 @@ export enum GroupCoordinatorStateEvents {
|
|
|
324
445
|
waitPoint: event.waitPoint,
|
|
325
446
|
position: event.position,
|
|
326
447
|
timestamp: event.timestamp,
|
|
327
|
-
clientId: event.clientId ||
|
|
448
|
+
clientId: event.clientId || "",
|
|
328
449
|
};
|
|
329
450
|
this.playbackPosition.UpdatePlaybackPosition(position);
|
|
330
451
|
|
|
@@ -335,13 +456,19 @@ export enum GroupCoordinatorStateEvents {
|
|
|
335
456
|
// the rest of the group while the local player is trying to to seek to a
|
|
336
457
|
// new position.
|
|
337
458
|
switch (event.playbackState) {
|
|
338
|
-
case
|
|
339
|
-
case
|
|
340
|
-
case
|
|
459
|
+
case "none":
|
|
460
|
+
case "paused":
|
|
461
|
+
case "playing":
|
|
341
462
|
if (event.playbackState != this._lastStateChange) {
|
|
342
|
-
this._logger.sendTelemetryEvent(
|
|
463
|
+
this._logger.sendTelemetryEvent(
|
|
464
|
+
TelemetryEvents.GroupCoordinator
|
|
465
|
+
.BeginSoftSuspension,
|
|
466
|
+
null,
|
|
467
|
+
{ playbackState: event.playbackState }
|
|
468
|
+
);
|
|
343
469
|
this._lastStateChange = event.playbackState;
|
|
344
|
-
this._lastStateChangeTime =
|
|
470
|
+
this._lastStateChangeTime =
|
|
471
|
+
LiveEvent.getTimestamp();
|
|
345
472
|
}
|
|
346
473
|
break;
|
|
347
474
|
}
|
|
@@ -366,14 +493,20 @@ export enum GroupCoordinatorStateEvents {
|
|
|
366
493
|
|
|
367
494
|
public async syncLocalMediaSession(): Promise<void> {
|
|
368
495
|
// Skip further syncs if we're waiting or in a "soft suspension".
|
|
369
|
-
const softSuspensionDelta =
|
|
496
|
+
const softSuspensionDelta =
|
|
497
|
+
LiveEvent.getTimestamp() - this._lastStateChangeTime;
|
|
370
498
|
if (!this.isWaiting && softSuspensionDelta >= 1000) {
|
|
371
|
-
let { metadata, trackData, positionState, playbackState } =
|
|
372
|
-
|
|
499
|
+
let { metadata, trackData, positionState, playbackState } =
|
|
500
|
+
this._getMediaPlayerState();
|
|
501
|
+
this._logger.sendTelemetryEvent(
|
|
502
|
+
TelemetryEvents.GroupCoordinator.CheckingForSyncIssues
|
|
503
|
+
);
|
|
373
504
|
|
|
374
505
|
// Check for track change
|
|
375
506
|
if (!this.playbackTrack.compare(metadata)) {
|
|
376
|
-
this._logger.sendTelemetryEvent(
|
|
507
|
+
this._logger.sendTelemetryEvent(
|
|
508
|
+
TelemetryEvents.GroupCoordinator.TrackOutOfSync
|
|
509
|
+
);
|
|
377
510
|
this.emitSetTrack(this.playbackTrack.metadata!);
|
|
378
511
|
return;
|
|
379
512
|
}
|
|
@@ -384,7 +517,10 @@ export enum GroupCoordinatorStateEvents {
|
|
|
384
517
|
// else has finished the video.
|
|
385
518
|
// - Should another user seek or press play after the video has ended that will cause
|
|
386
519
|
// a transport action to trigger which will take the player out of the ended state.
|
|
387
|
-
if (
|
|
520
|
+
if (
|
|
521
|
+
playbackState != "ended" &&
|
|
522
|
+
!this._playbackPosition.trackEnded
|
|
523
|
+
) {
|
|
388
524
|
// Ensure we have a position
|
|
389
525
|
let position = positionState?.position;
|
|
390
526
|
if (position == undefined) {
|
|
@@ -394,37 +530,59 @@ export enum GroupCoordinatorStateEvents {
|
|
|
394
530
|
// Check for catchup
|
|
395
531
|
// - Target can return -1 in cases where there is no position tracking data
|
|
396
532
|
const target = this.playbackPosition.targetPosition;
|
|
397
|
-
if (
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
533
|
+
if (
|
|
534
|
+
target >= 0.0 &&
|
|
535
|
+
Math.abs(target - position) >=
|
|
536
|
+
this._maxPlaybackDrift.seconds
|
|
537
|
+
) {
|
|
538
|
+
this._logger.sendTelemetryEvent(
|
|
539
|
+
TelemetryEvents.GroupCoordinator.PositionOutOfSync,
|
|
540
|
+
null,
|
|
541
|
+
{
|
|
542
|
+
current: position,
|
|
543
|
+
target: target,
|
|
544
|
+
}
|
|
545
|
+
);
|
|
546
|
+
await this.emitTriggerAction({
|
|
547
|
+
action: "catchup",
|
|
548
|
+
seekTime: target,
|
|
401
549
|
});
|
|
402
|
-
await this.emitTriggerAction({action: 'catchup', seekTime: target});
|
|
403
550
|
}
|
|
404
551
|
|
|
405
552
|
// Sync transport state
|
|
406
553
|
if (this.transportState.playbackState != playbackState) {
|
|
407
|
-
this._logger.sendTelemetryEvent(
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
554
|
+
this._logger.sendTelemetryEvent(
|
|
555
|
+
TelemetryEvents.GroupCoordinator.TransportOutOfSync,
|
|
556
|
+
null,
|
|
557
|
+
{
|
|
558
|
+
current: playbackState,
|
|
559
|
+
target: this.transportState.playbackState,
|
|
560
|
+
}
|
|
561
|
+
);
|
|
411
562
|
switch (this.transportState.playbackState) {
|
|
412
|
-
case
|
|
413
|
-
await this.emitTriggerAction({action:
|
|
563
|
+
case "playing":
|
|
564
|
+
await this.emitTriggerAction({ action: "play" });
|
|
414
565
|
break;
|
|
415
|
-
case
|
|
416
|
-
await this.emitTriggerAction({action:
|
|
566
|
+
case "paused":
|
|
567
|
+
await this.emitTriggerAction({ action: "pause" });
|
|
417
568
|
break;
|
|
418
569
|
}
|
|
419
570
|
}
|
|
420
571
|
|
|
421
572
|
// Sync track data
|
|
422
|
-
if (
|
|
423
|
-
|
|
424
|
-
|
|
573
|
+
if (
|
|
574
|
+
JSON.stringify(this.playbackTrackData.data) !=
|
|
575
|
+
JSON.stringify(trackData)
|
|
576
|
+
) {
|
|
577
|
+
this._logger.sendTelemetryEvent(
|
|
578
|
+
TelemetryEvents.GroupCoordinator.TrackDataOutOfSync
|
|
579
|
+
);
|
|
580
|
+
await this.emitTriggerAction({
|
|
581
|
+
action: "datachange",
|
|
582
|
+
data: this.playbackTrackData.data,
|
|
583
|
+
});
|
|
425
584
|
}
|
|
426
585
|
}
|
|
427
|
-
|
|
428
586
|
}
|
|
429
587
|
}
|
|
430
588
|
|
|
@@ -433,14 +591,16 @@ export enum GroupCoordinatorStateEvents {
|
|
|
433
591
|
this._waitPoint = undefined;
|
|
434
592
|
|
|
435
593
|
// Trigger settrack action
|
|
436
|
-
this.emitTriggerAction({action:
|
|
594
|
+
this.emitTriggerAction({ action: "settrack", metadata: metadata });
|
|
437
595
|
}
|
|
438
596
|
|
|
439
|
-
private emitTriggerAction(
|
|
597
|
+
private emitTriggerAction(
|
|
598
|
+
details: ExtendedMediaSessionActionDetails
|
|
599
|
+
): void {
|
|
440
600
|
const evt: ITriggerActionEvent = {
|
|
441
601
|
name: GroupCoordinatorStateEvents.triggeraction,
|
|
442
|
-
details: details
|
|
602
|
+
details: details,
|
|
443
603
|
};
|
|
444
|
-
|
|
604
|
+
this.emit(GroupCoordinatorStateEvents.triggeraction, evt);
|
|
445
605
|
}
|
|
446
|
-
}
|
|
606
|
+
}
|