@microsoft/live-share-media 1.0.0-preview.11 → 1.0.0-preview.13
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/EphemeralMediaSession.d.ts +102 -0
- package/bin/EphemeralMediaSession.d.ts.map +1 -0
- package/bin/EphemeralMediaSession.js +226 -0
- package/bin/EphemeralMediaSession.js.map +1 -0
- package/bin/EphemeralMediaSessionCoordinator.d.ts +228 -0
- package/bin/EphemeralMediaSessionCoordinator.d.ts.map +1 -0
- package/bin/EphemeralMediaSessionCoordinator.js +396 -0
- package/bin/EphemeralMediaSessionCoordinator.js.map +1 -0
- package/bin/EphemeralMediaSessionCoordinatorSuspension.d.ts +20 -0
- package/bin/EphemeralMediaSessionCoordinatorSuspension.d.ts.map +1 -0
- package/bin/EphemeralMediaSessionCoordinatorSuspension.js +28 -0
- package/bin/EphemeralMediaSessionCoordinatorSuspension.js.map +1 -0
- package/bin/IMediaPlayer.d.ts +21 -0
- package/bin/IMediaPlayer.d.ts.map +1 -0
- package/bin/IMediaPlayer.js +7 -0
- package/bin/IMediaPlayer.js.map +1 -0
- package/bin/LiveMediaSession.d.ts +96 -0
- package/bin/LiveMediaSession.d.ts.map +1 -0
- package/bin/LiveMediaSession.js +236 -0
- package/bin/LiveMediaSession.js.map +1 -0
- package/bin/LiveMediaSessionCoordinator.d.ts +239 -0
- package/bin/LiveMediaSessionCoordinator.d.ts.map +1 -0
- package/bin/LiveMediaSessionCoordinator.js +477 -0
- package/bin/LiveMediaSessionCoordinator.js.map +1 -0
- package/bin/LiveMediaSessionCoordinatorSuspension.d.ts +20 -0
- package/bin/LiveMediaSessionCoordinatorSuspension.d.ts.map +1 -0
- package/bin/LiveMediaSessionCoordinatorSuspension.js +28 -0
- package/bin/LiveMediaSessionCoordinatorSuspension.js.map +1 -0
- package/bin/MediaPlayerSynchronizer.d.ts +174 -0
- package/bin/MediaPlayerSynchronizer.d.ts.map +1 -0
- package/bin/MediaPlayerSynchronizer.js +492 -0
- package/bin/MediaPlayerSynchronizer.js.map +1 -0
- package/bin/MediaSessionActionThrottler.d.ts +12 -0
- package/bin/MediaSessionActionThrottler.d.ts.map +1 -0
- package/bin/MediaSessionActionThrottler.js +14 -0
- package/bin/MediaSessionActionThrottler.js.map +1 -0
- package/bin/MediaSessionExtensions.d.ts +35 -0
- package/bin/MediaSessionExtensions.d.ts.map +1 -0
- package/bin/MediaSessionExtensions.js +13 -0
- package/bin/MediaSessionExtensions.js.map +1 -0
- package/bin/RepeatedActionThrottler.d.ts +20 -0
- package/bin/RepeatedActionThrottler.d.ts.map +1 -0
- package/bin/RepeatedActionThrottler.js +63 -0
- package/bin/RepeatedActionThrottler.js.map +1 -0
- package/bin/VolumeLimiter.d.ts +70 -0
- package/bin/VolumeLimiter.d.ts.map +1 -0
- package/bin/VolumeLimiter.js +170 -0
- package/bin/VolumeLimiter.js.map +1 -0
- package/bin/VolumeManager.d.ts +84 -0
- package/bin/VolumeManager.d.ts.map +1 -0
- package/bin/VolumeManager.js +175 -0
- package/bin/VolumeManager.js.map +1 -0
- package/bin/index.d.ts +14 -0
- package/bin/index.d.ts.map +1 -0
- package/bin/index.js +30 -0
- package/bin/index.js.map +1 -0
- package/bin/internals/GroupCoordinatorState.d.ts +94 -0
- package/bin/internals/GroupCoordinatorState.d.ts.map +1 -0
- package/bin/internals/GroupCoordinatorState.js +408 -0
- package/bin/internals/GroupCoordinatorState.js.map +1 -0
- package/bin/internals/GroupPlaybackPosition.d.ts +68 -0
- package/bin/internals/GroupPlaybackPosition.d.ts.map +1 -0
- package/bin/internals/GroupPlaybackPosition.js +167 -0
- package/bin/internals/GroupPlaybackPosition.js.map +1 -0
- package/bin/internals/GroupPlaybackTrack.d.ts +46 -0
- package/bin/internals/GroupPlaybackTrack.d.ts.map +1 -0
- package/bin/internals/GroupPlaybackTrack.js +122 -0
- package/bin/internals/GroupPlaybackTrack.js.map +1 -0
- package/bin/internals/GroupPlaybackTrackData.d.ts +40 -0
- package/bin/internals/GroupPlaybackTrackData.d.ts.map +1 -0
- package/bin/internals/GroupPlaybackTrackData.js +70 -0
- package/bin/internals/GroupPlaybackTrackData.js.map +1 -0
- package/bin/internals/GroupTransportState.d.ts +50 -0
- package/bin/internals/GroupTransportState.d.ts.map +1 -0
- package/bin/internals/GroupTransportState.js +112 -0
- package/bin/internals/GroupTransportState.js.map +1 -0
- package/bin/internals/consts.d.ts +76 -0
- package/bin/internals/consts.d.ts.map +1 -0
- package/bin/internals/consts.js +85 -0
- package/bin/internals/consts.js.map +1 -0
- package/bin/internals/index.d.ts +11 -0
- package/bin/internals/index.d.ts.map +1 -0
- package/bin/internals/index.js +27 -0
- package/bin/internals/index.js.map +1 -0
- package/package.json +4 -4
- package/src/LiveMediaSession.ts +24 -12
- package/src/LiveMediaSessionCoordinator.ts +101 -29
- package/src/MediaPlayerSynchronizer.ts +30 -14
- package/src/internals/GroupCoordinatorState.ts +49 -35
- package/src/internals/GroupPlaybackPosition.ts +6 -2
- 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/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
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
* Licensed under the Microsoft Live Share SDK License.
|
|
5
|
+
*/
|
|
6
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
7
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
8
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
9
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
10
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
11
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
12
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
16
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.GroupCoordinatorState = exports.GroupCoordinatorStateEvents = void 0;
|
|
20
|
+
const live_share_1 = require("@microsoft/live-share");
|
|
21
|
+
const events_1 = __importDefault(require("events"));
|
|
22
|
+
const GroupPlaybackTrack_1 = require("./GroupPlaybackTrack");
|
|
23
|
+
const GroupTransportState_1 = require("./GroupTransportState");
|
|
24
|
+
const GroupPlaybackPosition_1 = require("./GroupPlaybackPosition");
|
|
25
|
+
const GroupTransportState_2 = require("./GroupTransportState");
|
|
26
|
+
const GroupPlaybackTrackData_1 = require("./GroupPlaybackTrackData");
|
|
27
|
+
const consts_1 = require("./consts");
|
|
28
|
+
/**
|
|
29
|
+
* @hidden
|
|
30
|
+
*/
|
|
31
|
+
var GroupCoordinatorStateEvents;
|
|
32
|
+
(function (GroupCoordinatorStateEvents) {
|
|
33
|
+
GroupCoordinatorStateEvents["newwaitpoint"] = "newwaitpoint";
|
|
34
|
+
GroupCoordinatorStateEvents["triggeraction"] = "triggeraction";
|
|
35
|
+
})(GroupCoordinatorStateEvents = exports.GroupCoordinatorStateEvents || (exports.GroupCoordinatorStateEvents = {}));
|
|
36
|
+
/**
|
|
37
|
+
* @hidden
|
|
38
|
+
*/
|
|
39
|
+
class GroupCoordinatorState extends events_1.default {
|
|
40
|
+
constructor(runtime, liveRuntime, maxPlaybackDrift, positionUpdateInterval, getMediaPlayerState) {
|
|
41
|
+
super();
|
|
42
|
+
// Suspension tracking
|
|
43
|
+
this._suspensionCnt = 0;
|
|
44
|
+
// "Soft Suspension" tracking
|
|
45
|
+
// - Soft suspensions temporarily disconnect the local media session when transitioning between
|
|
46
|
+
// paused, playing, and none states. This is to give the local client time to finish any inprogress
|
|
47
|
+
// operations like sending a transport command or ending a suspension.
|
|
48
|
+
this._lastStateChange = "none";
|
|
49
|
+
this._lastStateChangeTime = 0;
|
|
50
|
+
this._runtime = runtime;
|
|
51
|
+
this._liveRuntime = liveRuntime;
|
|
52
|
+
this._logger = new live_share_1.LiveTelemetryLogger(runtime, liveRuntime);
|
|
53
|
+
this._maxPlaybackDrift = maxPlaybackDrift;
|
|
54
|
+
this._playbackTrack = new GroupPlaybackTrack_1.GroupPlaybackTrack(getMediaPlayerState);
|
|
55
|
+
this._playbackTrackData = new GroupPlaybackTrackData_1.GroupPlaybackTrackData(this._playbackTrack);
|
|
56
|
+
this._transportState = new GroupTransportState_1.GroupTransportState(this._playbackTrack, getMediaPlayerState, this._liveRuntime);
|
|
57
|
+
this._playbackPosition = new GroupPlaybackPosition_1.GroupPlaybackPosition(this._transportState, this._runtime, this._liveRuntime, positionUpdateInterval);
|
|
58
|
+
this._getMediaPlayerState = getMediaPlayerState;
|
|
59
|
+
// Listen track related events
|
|
60
|
+
this._playbackTrack.on(GroupPlaybackTrack_1.GroupPlaybackTrackEvents.trackChange, (evt) => {
|
|
61
|
+
if (!this.isSuspended) {
|
|
62
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.GroupCoordinator.TrackChanged);
|
|
63
|
+
this.emitSetTrack(evt.metadata);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.GroupCoordinator.TrackChangeDelayed);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
// Listen for track data changes
|
|
70
|
+
this._playbackTrackData.on(GroupPlaybackTrackData_1.PlaybackTrackDataEvents.dataChange, (evt) => {
|
|
71
|
+
if (!this.isSuspended && !this.isWaiting) {
|
|
72
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.GroupCoordinator.TrackDataChanged);
|
|
73
|
+
this.emitTriggerAction({
|
|
74
|
+
action: "datachange",
|
|
75
|
+
data: evt.data,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.GroupCoordinator.TrackDataChangeDelayed);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
// Listen to transport related events
|
|
83
|
+
this._transportState.on(GroupTransportState_2.GroupTransportStateEvents.transportStateChange, (evt) => {
|
|
84
|
+
if (!this.isSuspended && !this.isWaiting) {
|
|
85
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.GroupCoordinator.TransportStateChanged, null, {
|
|
86
|
+
action: evt.action,
|
|
87
|
+
seekTime: evt.seekTime,
|
|
88
|
+
});
|
|
89
|
+
// Trigger action
|
|
90
|
+
switch (evt.action) {
|
|
91
|
+
case "play":
|
|
92
|
+
this.emitTriggerAction({
|
|
93
|
+
action: "play",
|
|
94
|
+
seekTime: evt.seekTime,
|
|
95
|
+
});
|
|
96
|
+
break;
|
|
97
|
+
case "pause":
|
|
98
|
+
this.emitTriggerAction({
|
|
99
|
+
action: "pause",
|
|
100
|
+
seekTime: evt.seekTime,
|
|
101
|
+
});
|
|
102
|
+
break;
|
|
103
|
+
case "seekto":
|
|
104
|
+
this.emitTriggerAction({
|
|
105
|
+
action: "seekto",
|
|
106
|
+
seekTime: evt.seekTime,
|
|
107
|
+
});
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.GroupCoordinator
|
|
113
|
+
.TransportStateChangeDelayed, null, {
|
|
114
|
+
action: evt.action,
|
|
115
|
+
seekTime: evt.seekTime,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
get playbackTrack() {
|
|
121
|
+
return this._playbackTrack;
|
|
122
|
+
}
|
|
123
|
+
get playbackTrackData() {
|
|
124
|
+
return this._playbackTrackData;
|
|
125
|
+
}
|
|
126
|
+
get transportState() {
|
|
127
|
+
return this._transportState;
|
|
128
|
+
}
|
|
129
|
+
get playbackPosition() {
|
|
130
|
+
return this._playbackPosition;
|
|
131
|
+
}
|
|
132
|
+
get waitingAt() {
|
|
133
|
+
return this._waitPoint;
|
|
134
|
+
}
|
|
135
|
+
get isSuspended() {
|
|
136
|
+
return this._suspensionCnt > 0;
|
|
137
|
+
}
|
|
138
|
+
get isWaiting() {
|
|
139
|
+
return !!this._waitPoint;
|
|
140
|
+
}
|
|
141
|
+
beginSuspension(waitPoint) {
|
|
142
|
+
this._suspensionCnt++;
|
|
143
|
+
if (waitPoint) {
|
|
144
|
+
// Save most recent wait point
|
|
145
|
+
this._waitPoint = waitPoint;
|
|
146
|
+
// Add to track state if dynamic wait point
|
|
147
|
+
this.playbackTrack.addWaitPoint(waitPoint);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
endSuspension(syncState) {
|
|
151
|
+
if (this._suspensionCnt == 0) {
|
|
152
|
+
throw new Error(`Too many suspensions.`);
|
|
153
|
+
}
|
|
154
|
+
this._suspensionCnt--;
|
|
155
|
+
if (this._suspensionCnt == 0 && syncState) {
|
|
156
|
+
// Sync media session to group
|
|
157
|
+
this.syncLocalMediaSession();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
createPositionUpdateEvent(state) {
|
|
161
|
+
const { positionState, playbackState } = state;
|
|
162
|
+
if (this.isSuspended) {
|
|
163
|
+
// Report suspension state
|
|
164
|
+
return {
|
|
165
|
+
track: this.playbackTrack.current,
|
|
166
|
+
trackData: this.playbackTrackData.current,
|
|
167
|
+
transport: this.transportState.current,
|
|
168
|
+
playbackState: "suspended",
|
|
169
|
+
position: (positionState === null || positionState === void 0 ? void 0 : positionState.position) || 0.0,
|
|
170
|
+
waitPoint: this._waitPoint,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
// Report current position
|
|
175
|
+
return {
|
|
176
|
+
track: this.playbackTrack.current,
|
|
177
|
+
trackData: this.playbackTrackData.current,
|
|
178
|
+
transport: this.transportState.current,
|
|
179
|
+
playbackState: this._waitPoint ? "waiting" : playbackState,
|
|
180
|
+
position: (positionState === null || positionState === void 0 ? void 0 : positionState.position) || 0.0,
|
|
181
|
+
waitPoint: this._waitPoint,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
handleSetTrack(event, local) {
|
|
186
|
+
// Update shared track
|
|
187
|
+
// - Will trigger 'trackChange' event to update media session
|
|
188
|
+
const updated = this.playbackTrack.updateTrack({
|
|
189
|
+
metadata: event.data.metadata,
|
|
190
|
+
waitPoints: event.data.waitPoints,
|
|
191
|
+
timestamp: event.timestamp,
|
|
192
|
+
clientId: event.clientId || "",
|
|
193
|
+
});
|
|
194
|
+
if (updated) {
|
|
195
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.SessionCoordinator.RemoteSetTrackReceived, null, {
|
|
196
|
+
correlationId: live_share_1.LiveTelemetryLogger.formatCorrelationId(event.clientId, event.timestamp),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
handleSetTrackData(event, local) {
|
|
201
|
+
// Update shared track data
|
|
202
|
+
// - Will trigger 'dataChange' event to update media session
|
|
203
|
+
const updated = this.playbackTrackData.updateData({
|
|
204
|
+
data: event.data.data,
|
|
205
|
+
timestamp: event.timestamp,
|
|
206
|
+
clientId: event.clientId || "",
|
|
207
|
+
});
|
|
208
|
+
if (updated) {
|
|
209
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.SessionCoordinator.RemoteSetTrackReceived, null, {
|
|
210
|
+
correlationId: live_share_1.LiveTelemetryLogger.formatCorrelationId(event.clientId, event.timestamp),
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
handleTransportCommand(event, local) {
|
|
215
|
+
// Ensure change is for current track
|
|
216
|
+
// - Will trigger a 'trackChange' event if newer track.
|
|
217
|
+
this.playbackTrack.updateTrack(event.data.track);
|
|
218
|
+
if (this.playbackTrack.compare(event.data.track.metadata)) {
|
|
219
|
+
// Update playback state
|
|
220
|
+
let playbackState = this.transportState.playbackState;
|
|
221
|
+
switch (event.name) {
|
|
222
|
+
case "play":
|
|
223
|
+
playbackState = "playing";
|
|
224
|
+
break;
|
|
225
|
+
case "pause":
|
|
226
|
+
playbackState = "paused";
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
// Try to update playback state
|
|
230
|
+
const newState = {
|
|
231
|
+
playbackState: playbackState,
|
|
232
|
+
startPosition: event.data.position,
|
|
233
|
+
timestamp: event.timestamp,
|
|
234
|
+
clientId: event.clientId || "",
|
|
235
|
+
};
|
|
236
|
+
const updated = this.transportState.updateState(newState);
|
|
237
|
+
if (updated) {
|
|
238
|
+
const correlationId = live_share_1.LiveTelemetryLogger.formatCorrelationId(event.clientId, event.timestamp);
|
|
239
|
+
switch (event.name) {
|
|
240
|
+
case "play":
|
|
241
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.SessionCoordinator
|
|
242
|
+
.RemotePlayReceived, null, {
|
|
243
|
+
correlationId: correlationId,
|
|
244
|
+
});
|
|
245
|
+
break;
|
|
246
|
+
case "pause":
|
|
247
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.SessionCoordinator
|
|
248
|
+
.RemotePauseReceived, null, {
|
|
249
|
+
correlationId: correlationId,
|
|
250
|
+
});
|
|
251
|
+
break;
|
|
252
|
+
case "seekTo":
|
|
253
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.SessionCoordinator
|
|
254
|
+
.RemoteSeekToReceived, null, {
|
|
255
|
+
correlationId: correlationId,
|
|
256
|
+
});
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
handlePositionUpdate(event, local) {
|
|
263
|
+
// Ensure change is for current track
|
|
264
|
+
// - Will trigger a 'trackChange' event if newer track.
|
|
265
|
+
this.playbackTrack.updateTrack(event.data.track);
|
|
266
|
+
if (this.playbackTrack.compare(event.data.track.metadata)) {
|
|
267
|
+
// Ensure we have the latest track data
|
|
268
|
+
this.playbackTrackData.updateData(event.data.trackData);
|
|
269
|
+
// Update transport state if needed
|
|
270
|
+
// - Ignore transport state changes if the client has ended as this will cause the local
|
|
271
|
+
// player to start playback even though the video may have ended for everyone.
|
|
272
|
+
if (event.data.playbackState != "ended") {
|
|
273
|
+
this.transportState.updateState(event.data.transport);
|
|
274
|
+
}
|
|
275
|
+
// Ensure change is for current transport state
|
|
276
|
+
if (this.transportState.compare(event.data.transport)) {
|
|
277
|
+
// Update playback position
|
|
278
|
+
const position = {
|
|
279
|
+
playbackState: event.data.playbackState,
|
|
280
|
+
waitPoint: event.data.waitPoint,
|
|
281
|
+
position: event.data.position,
|
|
282
|
+
timestamp: event.timestamp,
|
|
283
|
+
clientId: event.clientId || "",
|
|
284
|
+
};
|
|
285
|
+
this.playbackPosition.UpdatePlaybackPosition(position);
|
|
286
|
+
// Ensure local media session is in sync with group
|
|
287
|
+
if (local && !this.isSuspended) {
|
|
288
|
+
// Begin a "soft suspension" on select state changes
|
|
289
|
+
// - This is needed because the catchup logic can try to sink the client with
|
|
290
|
+
// the rest of the group while the local player is trying to to seek to a
|
|
291
|
+
// new position.
|
|
292
|
+
switch (event.data.playbackState) {
|
|
293
|
+
case "none":
|
|
294
|
+
case "paused":
|
|
295
|
+
case "playing":
|
|
296
|
+
if (event.data.playbackState !=
|
|
297
|
+
this._lastStateChange) {
|
|
298
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.GroupCoordinator
|
|
299
|
+
.BeginSoftSuspension, null, { playbackState: event.data.playbackState });
|
|
300
|
+
this._lastStateChange =
|
|
301
|
+
event.data.playbackState;
|
|
302
|
+
this._lastStateChangeTime =
|
|
303
|
+
this._liveRuntime.getTimestamp();
|
|
304
|
+
}
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
// Are we waiting?
|
|
308
|
+
if (this.isWaiting) {
|
|
309
|
+
// Check for end of waiting
|
|
310
|
+
if (this.playbackPosition.clientsWaiting == 0) {
|
|
311
|
+
this._waitPoint = undefined;
|
|
312
|
+
// Start syncing again
|
|
313
|
+
this.syncLocalMediaSession();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
// Sync client with group
|
|
318
|
+
this.syncLocalMediaSession();
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
syncLocalMediaSession() {
|
|
325
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
326
|
+
// Skip further syncs if we're waiting or in a "soft suspension".
|
|
327
|
+
const softSuspensionDelta = this._liveRuntime.getTimestamp() - this._lastStateChangeTime;
|
|
328
|
+
if (!this.isWaiting && softSuspensionDelta >= 1000) {
|
|
329
|
+
let { metadata, trackData, positionState, playbackState } = this._getMediaPlayerState();
|
|
330
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.GroupCoordinator.CheckingForSyncIssues);
|
|
331
|
+
// Check for track change
|
|
332
|
+
if (!this.playbackTrack.compare(metadata)) {
|
|
333
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.GroupCoordinator.TrackOutOfSync);
|
|
334
|
+
this.emitSetTrack(this.playbackTrack.metadata);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
// Once local playback has ended there's no need to further sync the client. In fact
|
|
338
|
+
// doing so could cause the player to loop.
|
|
339
|
+
// - The playbackPosition.trackEnded check is to catch late joiners and prevents syncing if everyone
|
|
340
|
+
// else has finished the video.
|
|
341
|
+
// - Should another user seek or press play after the video has ended that will cause
|
|
342
|
+
// a transport action to trigger which will take the player out of the ended state.
|
|
343
|
+
if (playbackState != "ended" &&
|
|
344
|
+
!this._playbackPosition.trackEnded) {
|
|
345
|
+
// Ensure we have a position
|
|
346
|
+
let position = positionState === null || positionState === void 0 ? void 0 : positionState.position;
|
|
347
|
+
if (position == undefined) {
|
|
348
|
+
position = 0.0;
|
|
349
|
+
}
|
|
350
|
+
// Check for catchup
|
|
351
|
+
// - Target can return -1 in cases where there is no position tracking data
|
|
352
|
+
const target = this.playbackPosition.targetPosition;
|
|
353
|
+
if (target >= 0.0 &&
|
|
354
|
+
Math.abs(target - position) >=
|
|
355
|
+
this._maxPlaybackDrift.seconds) {
|
|
356
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.GroupCoordinator.PositionOutOfSync, null, {
|
|
357
|
+
current: position,
|
|
358
|
+
target: target,
|
|
359
|
+
});
|
|
360
|
+
yield this.emitTriggerAction({
|
|
361
|
+
action: "catchup",
|
|
362
|
+
seekTime: target,
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
// Sync transport state
|
|
366
|
+
if (this.transportState.playbackState != playbackState) {
|
|
367
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.GroupCoordinator.TransportOutOfSync, null, {
|
|
368
|
+
current: playbackState,
|
|
369
|
+
target: this.transportState.playbackState,
|
|
370
|
+
});
|
|
371
|
+
switch (this.transportState.playbackState) {
|
|
372
|
+
case "playing":
|
|
373
|
+
yield this.emitTriggerAction({ action: "play" });
|
|
374
|
+
break;
|
|
375
|
+
case "paused":
|
|
376
|
+
yield this.emitTriggerAction({ action: "pause" });
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
// Sync track data
|
|
381
|
+
if (JSON.stringify(this.playbackTrackData.data) !=
|
|
382
|
+
JSON.stringify(trackData)) {
|
|
383
|
+
this._logger.sendTelemetryEvent(consts_1.TelemetryEvents.GroupCoordinator.TrackDataOutOfSync);
|
|
384
|
+
yield this.emitTriggerAction({
|
|
385
|
+
action: "datachange",
|
|
386
|
+
data: this.playbackTrackData.data,
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
emitSetTrack(metadata) {
|
|
394
|
+
// Reset tracking states
|
|
395
|
+
this._waitPoint = undefined;
|
|
396
|
+
// Trigger settrack action
|
|
397
|
+
this.emitTriggerAction({ action: "settrack", metadata: metadata });
|
|
398
|
+
}
|
|
399
|
+
emitTriggerAction(details) {
|
|
400
|
+
const evt = {
|
|
401
|
+
name: GroupCoordinatorStateEvents.triggeraction,
|
|
402
|
+
details: details,
|
|
403
|
+
};
|
|
404
|
+
this.emit(GroupCoordinatorStateEvents.triggeraction, evt);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
exports.GroupCoordinatorState = GroupCoordinatorState;
|
|
408
|
+
//# sourceMappingURL=GroupCoordinatorState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GroupCoordinatorState.js","sourceRoot":"","sources":["../../src/internals/GroupCoordinatorState.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;AAEH,sDAO+B;AAC/B,oDAAkC;AAOlC,6DAI8B;AAC9B,+DAA6E;AAC7E,mEAGiC;AAEjC,+DAAkE;AAClE,qEAIkC;AAClC,qCAA2C;AA4C3C;;GAEG;AACH,IAAY,2BAGX;AAHD,WAAY,2BAA2B;IACnC,4DAA6B,CAAA;IAC7B,8DAA+B,CAAA;AACnC,CAAC,EAHW,2BAA2B,GAA3B,mCAA2B,KAA3B,mCAA2B,QAGtC;AAED;;GAEG;AACH,MAAa,qBAAsB,SAAQ,gBAAY;IAwBnD,YACI,OAAyB,EACzB,WAA6B,EAC7B,gBAA8B,EAC9B,sBAAoC,EACpC,mBAA4C;QAE5C,KAAK,EAAE,CAAC;QAlBZ,sBAAsB;QACd,mBAAc,GAAW,CAAC,CAAC;QAGnC,6BAA6B;QAC7B,+FAA+F;QAC/F,qGAAqG;QACrG,wEAAwE;QAChE,qBAAgB,GAAsC,MAAM,CAAC;QAC7D,yBAAoB,GAAW,CAAC,CAAC;QAUrC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QACxB,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,OAAO,GAAG,IAAI,gCAAmB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAC7D,IAAI,CAAC,iBAAiB,GAAG,gBAAgB,CAAC;QAC1C,IAAI,CAAC,cAAc,GAAG,IAAI,uCAAkB,CAAC,mBAAmB,CAAC,CAAC;QAClE,IAAI,CAAC,kBAAkB,GAAG,IAAI,+CAAsB,CAChD,IAAI,CAAC,cAAc,CACtB,CAAC;QACF,IAAI,CAAC,eAAe,GAAG,IAAI,yCAAmB,CAC1C,IAAI,CAAC,cAAc,EACnB,mBAAmB,EACnB,IAAI,CAAC,YAAY,CACpB,CAAC;QACF,IAAI,CAAC,iBAAiB,GAAG,IAAI,6CAAqB,CAC9C,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,YAAY,EACjB,sBAAsB,CACzB,CAAC;QACF,IAAI,CAAC,oBAAoB,GAAG,mBAAmB,CAAC;QAEhD,8BAA8B;QAC9B,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,6CAAwB,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE;YACjE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;gBACnB,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,gBAAgB,CAAC,YAAY,CAChD,CAAC;gBACF,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAS,CAAC,CAAC;aACpC;iBAAM;gBACH,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,gBAAgB,CAAC,kBAAkB,CACtD,CAAC;aACL;QACL,CAAC,CAAC,CAAC;QAEH,gCAAgC;QAChC,IAAI,CAAC,kBAAkB,CAAC,EAAE,CACtB,gDAAuB,CAAC,UAAU,EAClC,CAAC,GAAG,EAAE,EAAE;YACJ,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;gBACtC,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,gBAAgB,CAAC,gBAAgB,CACpD,CAAC;gBACF,IAAI,CAAC,iBAAiB,CAAC;oBACnB,MAAM,EAAE,YAAY;oBACpB,IAAI,EAAE,GAAG,CAAC,IAAI;iBACjB,CAAC,CAAC;aACN;iBAAM;gBACH,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,gBAAgB,CAAC,sBAAsB,CAC1D,CAAC;aACL;QACL,CAAC,CACJ,CAAC;QAEF,qCAAqC;QACrC,IAAI,CAAC,eAAe,CAAC,EAAE,CACnB,+CAAyB,CAAC,oBAAoB,EAC9C,CAAC,GAAG,EAAE,EAAE;YACJ,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;gBACtC,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,gBAAgB,CAAC,qBAAqB,EACtD,IAAI,EACJ;oBACI,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,QAAQ,EAAE,GAAG,CAAC,QAAQ;iBACzB,CACJ,CAAC;gBAEF,iBAAiB;gBACjB,QAAQ,GAAG,CAAC,MAAM,EAAE;oBAChB,KAAK,MAAM;wBACP,IAAI,CAAC,iBAAiB,CAAC;4BACnB,MAAM,EAAE,MAAM;4BACd,QAAQ,EAAE,GAAG,CAAC,QAAQ;yBACzB,CAAC,CAAC;wBACH,MAAM;oBAEV,KAAK,OAAO;wBACR,IAAI,CAAC,iBAAiB,CAAC;4BACnB,MAAM,EAAE,OAAO;4BACf,QAAQ,EAAE,GAAG,CAAC,QAAQ;yBACzB,CAAC,CAAC;wBACH,MAAM;oBAEV,KAAK,QAAQ;wBACT,IAAI,CAAC,iBAAiB,CAAC;4BACnB,MAAM,EAAE,QAAQ;4BAChB,QAAQ,EAAE,GAAG,CAAC,QAAQ;yBACzB,CAAC,CAAC;wBACH,MAAM;iBACb;aACJ;iBAAM;gBACH,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,gBAAgB;qBAC3B,2BAA2B,EAChC,IAAI,EACJ;oBACI,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,QAAQ,EAAE,GAAG,CAAC,QAAQ;iBACzB,CACJ,CAAC;aACL;QACL,CAAC,CACJ,CAAC;IACN,CAAC;IAED,IAAW,aAAa;QACpB,OAAO,IAAI,CAAC,cAAc,CAAC;IAC/B,CAAC;IAED,IAAW,iBAAiB;QACxB,OAAO,IAAI,CAAC,kBAAkB,CAAC;IACnC,CAAC;IAED,IAAW,cAAc;QACrB,OAAO,IAAI,CAAC,eAAe,CAAC;IAChC,CAAC;IAED,IAAW,gBAAgB;QACvB,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAClC,CAAC;IAED,IAAW,SAAS;QAChB,OAAO,IAAI,CAAC,UAAU,CAAC;IAC3B,CAAC;IAED,IAAW,WAAW;QAClB,OAAO,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;IACnC,CAAC;IAED,IAAW,SAAS;QAChB,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;IAC7B,CAAC;IAEM,eAAe,CAAC,SAAiC;QACpD,IAAI,CAAC,cAAc,EAAE,CAAC;QAEtB,IAAI,SAAS,EAAE;YACX,8BAA8B;YAC9B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;YAE5B,2CAA2C;YAC3C,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;SAC9C;IACL,CAAC;IAEM,aAAa,CAAC,SAAkB;QACnC,IAAI,IAAI,CAAC,cAAc,IAAI,CAAC,EAAE;YAC1B,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;SAC5C;QAED,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,IAAI,CAAC,cAAc,IAAI,CAAC,IAAI,SAAS,EAAE;YACvC,8BAA8B;YAC9B,IAAI,CAAC,qBAAqB,EAAE,CAAC;SAChC;IACL,CAAC;IAEM,yBAAyB,CAC5B,KAAwB;QAExB,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;QAC/C,IAAI,IAAI,CAAC,WAAW,EAAE;YAClB,0BAA0B;YAC1B,OAAO;gBACH,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO;gBACjC,SAAS,EAAE,IAAI,CAAC,iBAAiB,CAAC,OAAO;gBACzC,SAAS,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO;gBACtC,aAAa,EAAE,WAAW;gBAC1B,QAAQ,EAAE,CAAA,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAE,QAAQ,KAAI,GAAG;gBACxC,SAAS,EAAE,IAAI,CAAC,UAAU;aAC7B,CAAC;SACL;aAAM;YACH,0BAA0B;YAC1B,OAAO;gBACH,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO;gBACjC,SAAS,EAAE,IAAI,CAAC,iBAAiB,CAAC,OAAO;gBACzC,SAAS,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO;gBACtC,aAAa,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa;gBAC1D,QAAQ,EAAE,CAAA,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAE,QAAQ,KAAI,GAAG;gBACxC,SAAS,EAAE,IAAI,CAAC,UAAU;aAC7B,CAAC;SACL;IACL,CAAC;IAEM,cAAc,CACjB,KAAiC,EACjC,KAAc;QAEd,sBAAsB;QACtB,6DAA6D;QAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC;YAC3C,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ;YAC7B,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU;YACjC,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,EAAE;SACjC,CAAC,CAAC;QAEH,IAAI,OAAO,EAAE;YACT,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,kBAAkB,CAAC,sBAAsB,EACzD,IAAI,EACJ;gBACI,aAAa,EAAE,gCAAmB,CAAC,mBAAmB,CAClD,KAAK,CAAC,QAAQ,EACd,KAAK,CAAC,SAAS,CAClB;aACJ,CACJ,CAAC;SACL;IACL,CAAC;IAEM,kBAAkB,CACrB,KAAqC,EACrC,KAAc;QAEd,2BAA2B;QAC3B,4DAA4D;QAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC;YAC9C,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI;YACrB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,EAAE;SACjC,CAAC,CAAC;QAEH,IAAI,OAAO,EAAE;YACT,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,kBAAkB,CAAC,sBAAsB,EACzD,IAAI,EACJ;gBACI,aAAa,EAAE,gCAAmB,CAAC,mBAAmB,CAClD,KAAK,CAAC,QAAQ,EACd,KAAK,CAAC,SAAS,CAClB;aACJ,CACJ,CAAC;SACL;IACL,CAAC;IAEM,sBAAsB,CACzB,KAAyC,EACzC,KAAc;QAEd,qCAAqC;QACrC,uDAAuD;QACvD,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjD,IAAI,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE;YACvD,wBAAwB;YACxB,IAAI,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC;YACtD,QAAQ,KAAK,CAAC,IAAI,EAAE;gBAChB,KAAK,MAAM;oBACP,aAAa,GAAG,SAAS,CAAC;oBAC1B,MAAM;gBACV,KAAK,OAAO;oBACR,aAAa,GAAG,QAAQ,CAAC;oBACzB,MAAM;aACb;YAED,+BAA+B;YAC/B,MAAM,QAAQ,GAAoB;gBAC9B,aAAa,EAAE,aAAa;gBAC5B,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ;gBAClC,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,EAAE;aACjC,CAAC;YACF,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;YAE1D,IAAI,OAAO,EAAE;gBACT,MAAM,aAAa,GAAG,gCAAmB,CAAC,mBAAmB,CACzD,KAAK,CAAC,QAAQ,EACd,KAAK,CAAC,SAAS,CAClB,CAAC;gBACF,QAAQ,KAAK,CAAC,IAAI,EAAE;oBAChB,KAAK,MAAM;wBACP,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,kBAAkB;6BAC7B,kBAAkB,EACvB,IAAI,EACJ;4BACI,aAAa,EAAE,aAAa;yBAC/B,CACJ,CAAC;wBACF,MAAM;oBACV,KAAK,OAAO;wBACR,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,kBAAkB;6BAC7B,mBAAmB,EACxB,IAAI,EACJ;4BACI,aAAa,EAAE,aAAa;yBAC/B,CACJ,CAAC;wBACF,MAAM;oBACV,KAAK,QAAQ;wBACT,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,kBAAkB;6BAC7B,oBAAoB,EACzB,IAAI,EACJ;4BACI,aAAa,EAAE,aAAa;yBAC/B,CACJ,CAAC;wBACF,MAAM;iBACb;aACJ;SACJ;IACL,CAAC;IAEM,oBAAoB,CACvB,KAAqD,EACrD,KAAc;QAEd,qCAAqC;QACrC,uDAAuD;QACvD,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjD,IAAI,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE;YACvD,uCAAuC;YACvC,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAExD,mCAAmC;YACnC,wFAAwF;YACxF,gFAAgF;YAChF,IAAI,KAAK,CAAC,IAAI,CAAC,aAAa,IAAI,OAAO,EAAE;gBACrC,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;aACzD;YAED,+CAA+C;YAC/C,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;gBACnD,2BAA2B;gBAC3B,MAAM,QAAQ,GAA6B;oBACvC,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,aAAa;oBACvC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS;oBAC/B,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ;oBAC7B,SAAS,EAAE,KAAK,CAAC,SAAS;oBAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,EAAE;iBACjC,CAAC;gBACF,IAAI,CAAC,gBAAgB,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC;gBAEvD,mDAAmD;gBACnD,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;oBAC5B,oDAAoD;oBACpD,6EAA6E;oBAC7E,0EAA0E;oBAC1E,iBAAiB;oBACjB,QAAQ,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE;wBAC9B,KAAK,MAAM,CAAC;wBACZ,KAAK,QAAQ,CAAC;wBACd,KAAK,SAAS;4BACV,IACI,KAAK,CAAC,IAAI,CAAC,aAAa;gCACxB,IAAI,CAAC,gBAAgB,EACvB;gCACE,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,gBAAgB;qCAC3B,mBAAmB,EACxB,IAAI,EACJ,EAAE,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,CAC9C,CAAC;gCACF,IAAI,CAAC,gBAAgB;oCACjB,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC;gCAC7B,IAAI,CAAC,oBAAoB;oCACrB,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC;6BACxC;4BACD,MAAM;qBACb;oBAED,kBAAkB;oBAClB,IAAI,IAAI,CAAC,SAAS,EAAE;wBAChB,2BAA2B;wBAC3B,IAAI,IAAI,CAAC,gBAAgB,CAAC,cAAc,IAAI,CAAC,EAAE;4BAC3C,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;4BAE5B,sBAAsB;4BACtB,IAAI,CAAC,qBAAqB,EAAE,CAAC;yBAChC;qBACJ;yBAAM;wBACH,yBAAyB;wBACzB,IAAI,CAAC,qBAAqB,EAAE,CAAC;qBAChC;iBACJ;aACJ;SACJ;IACL,CAAC;IAEY,qBAAqB;;YAC9B,iEAAiE;YACjE,MAAM,mBAAmB,GACrB,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC,oBAAoB,CAAC;YACjE,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,mBAAmB,IAAI,IAAI,EAAE;gBAChD,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,GACrD,IAAI,CAAC,oBAAoB,EAAE,CAAC;gBAChC,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,gBAAgB,CAAC,qBAAqB,CACzD,CAAC;gBAEF,yBAAyB;gBACzB,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;oBACvC,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,gBAAgB,CAAC,cAAc,CAClD,CAAC;oBACF,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,QAAS,CAAC,CAAC;oBAChD,OAAO;iBACV;gBAED,oFAAoF;gBACpF,2CAA2C;gBAC3C,oGAAoG;gBACpG,iCAAiC;gBACjC,qFAAqF;gBACrF,qFAAqF;gBACrF,IACI,aAAa,IAAI,OAAO;oBACxB,CAAC,IAAI,CAAC,iBAAiB,CAAC,UAAU,EACpC;oBACE,4BAA4B;oBAC5B,IAAI,QAAQ,GAAG,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAE,QAAQ,CAAC;oBACvC,IAAI,QAAQ,IAAI,SAAS,EAAE;wBACvB,QAAQ,GAAG,GAAG,CAAC;qBAClB;oBAED,oBAAoB;oBACpB,2EAA2E;oBAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC;oBACpD,IACI,MAAM,IAAI,GAAG;wBACb,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,QAAQ,CAAC;4BACvB,IAAI,CAAC,iBAAiB,CAAC,OAAO,EACpC;wBACE,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,gBAAgB,CAAC,iBAAiB,EAClD,IAAI,EACJ;4BACI,OAAO,EAAE,QAAQ;4BACjB,MAAM,EAAE,MAAM;yBACjB,CACJ,CAAC;wBACF,MAAM,IAAI,CAAC,iBAAiB,CAAC;4BACzB,MAAM,EAAE,SAAS;4BACjB,QAAQ,EAAE,MAAM;yBACnB,CAAC,CAAC;qBACN;oBAED,uBAAuB;oBACvB,IAAI,IAAI,CAAC,cAAc,CAAC,aAAa,IAAI,aAAa,EAAE;wBACpD,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,gBAAgB,CAAC,kBAAkB,EACnD,IAAI,EACJ;4BACI,OAAO,EAAE,aAAa;4BACtB,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,aAAa;yBAC5C,CACJ,CAAC;wBACF,QAAQ,IAAI,CAAC,cAAc,CAAC,aAAa,EAAE;4BACvC,KAAK,SAAS;gCACV,MAAM,IAAI,CAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;gCACjD,MAAM;4BACV,KAAK,QAAQ;gCACT,MAAM,IAAI,CAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;gCAClD,MAAM;yBACb;qBACJ;oBAED,kBAAkB;oBAClB,IACI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC;wBAC3C,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAC3B;wBACE,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAC3B,wBAAe,CAAC,gBAAgB,CAAC,kBAAkB,CACtD,CAAC;wBACF,MAAM,IAAI,CAAC,iBAAiB,CAAC;4BACzB,MAAM,EAAE,YAAY;4BACpB,IAAI,EAAE,IAAI,CAAC,iBAAiB,CAAC,IAAI;yBACpC,CAAC,CAAC;qBACN;iBACJ;aACJ;QACL,CAAC;KAAA;IAEO,YAAY,CAAC,QAA+B;QAChD,wBAAwB;QACxB,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAE5B,0BAA0B;QAC1B,IAAI,CAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;IACvE,CAAC;IAEO,iBAAiB,CACrB,OAA0C;QAE1C,MAAM,GAAG,GAAwB;YAC7B,IAAI,EAAE,2BAA2B,CAAC,aAAa;YAC/C,OAAO,EAAE,OAAO;SACnB,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,2BAA2B,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IAC9D,CAAC;CACJ;AAhhBD,sDAghBC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the Microsoft Live Share SDK License.
|
|
4
|
+
*/
|
|
5
|
+
import { IRuntimeSignaler, TimeInterval, LiveShareRuntime } from "@microsoft/live-share";
|
|
6
|
+
import { GroupTransportState } from "./GroupTransportState";
|
|
7
|
+
import { CoordinationWaitPoint, ExtendedMediaSessionPlaybackState } from "../MediaSessionExtensions";
|
|
8
|
+
/**
|
|
9
|
+
*Per client position
|
|
10
|
+
* @hidden
|
|
11
|
+
*/
|
|
12
|
+
export interface ICurrentPlaybackPosition {
|
|
13
|
+
playbackState: ExtendedMediaSessionPlaybackState;
|
|
14
|
+
waitPoint?: CoordinationWaitPoint;
|
|
15
|
+
position: number;
|
|
16
|
+
duration?: number;
|
|
17
|
+
timestamp: number;
|
|
18
|
+
clientId: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* @hidden
|
|
22
|
+
*/
|
|
23
|
+
export declare class GroupPlaybackPosition {
|
|
24
|
+
private _transportState;
|
|
25
|
+
private _runtime;
|
|
26
|
+
private _liveRuntime;
|
|
27
|
+
private _updateInterval;
|
|
28
|
+
private _positions;
|
|
29
|
+
constructor(transportState: GroupTransportState, runtime: IRuntimeSignaler, liveRuntime: LiveShareRuntime, updateInterval: TimeInterval);
|
|
30
|
+
/**
|
|
31
|
+
* Returns the latest position info for the local client.
|
|
32
|
+
*/
|
|
33
|
+
get localPosition(): ICurrentPlaybackPosition | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Returns the total number of clients actively being tracked.
|
|
36
|
+
*/
|
|
37
|
+
get totalClients(): number;
|
|
38
|
+
/**
|
|
39
|
+
* Returns true if all clients being tracked are reporting that they have
|
|
40
|
+
* either ended or haven't started.
|
|
41
|
+
*/
|
|
42
|
+
get trackEnded(): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Returns the number of clients we're waiting for before we can stop waiting.
|
|
45
|
+
*/
|
|
46
|
+
get clientsWaiting(): number;
|
|
47
|
+
/**
|
|
48
|
+
* Returns the max playback position relative to the start position.
|
|
49
|
+
*
|
|
50
|
+
* @remarks
|
|
51
|
+
* This is called when calculating the current seekTo position.
|
|
52
|
+
*/
|
|
53
|
+
get maxPosition(): number;
|
|
54
|
+
/**
|
|
55
|
+
* Optional media duration if known.
|
|
56
|
+
*/
|
|
57
|
+
mediaDuration?: number;
|
|
58
|
+
get targetPosition(): number;
|
|
59
|
+
/**
|
|
60
|
+
* Enumerates every reported playback position.
|
|
61
|
+
* @param callbackFn Function applied to each position,
|
|
62
|
+
*/
|
|
63
|
+
forEach(callbackFn: (position: ICurrentPlaybackPosition, projectedPosition: number) => void): void;
|
|
64
|
+
UpdatePlaybackPosition(position: ICurrentPlaybackPosition): void;
|
|
65
|
+
private getMostProgressedPosition;
|
|
66
|
+
private limitProjectedPosition;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=GroupPlaybackPosition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GroupPlaybackPosition.d.ts","sourceRoot":"","sources":["../../src/internals/GroupPlaybackPosition.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACH,gBAAgB,EAChB,YAAY,EAEZ,gBAAgB,EACnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EACH,qBAAqB,EACrB,iCAAiC,EACpC,MAAM,2BAA2B,CAAC;AAEnC;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACrC,aAAa,EAAE,iCAAiC,CAAC;IACjD,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,qBAAqB;IAC9B,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,YAAY,CAAmB;IACvC,OAAO,CAAC,eAAe,CAAe;IACtC,OAAO,CAAC,UAAU,CAAwC;gBAGtD,cAAc,EAAE,mBAAmB,EACnC,OAAO,EAAE,gBAAgB,EACzB,WAAW,EAAE,gBAAgB,EAC7B,cAAc,EAAE,YAAY;IAmBhC;;OAEG;IACH,IAAW,aAAa,IAAI,wBAAwB,GAAG,SAAS,CAE/D;IAED;;OAEG;IACH,IAAW,YAAY,IAAI,MAAM,CAIhC;IAED;;;OAGG;IACH,IAAW,UAAU,IAAI,OAAO,CAe/B;IAED;;OAEG;IACH,IAAW,cAAc,IAAI,MAAM,CAqBlC;IAED;;;;;OAKG;IACH,IAAW,WAAW,IAAI,MAAM,CAU/B;IAED;;OAEG;IACI,aAAa,CAAC,EAAE,MAAM,CAAC;IAE9B,IAAW,cAAc,IAAI,MAAM,CAMlC;IAED;;;OAGG;IACI,OAAO,CACV,UAAU,EAAE,CACR,QAAQ,EAAE,wBAAwB,EAClC,iBAAiB,EAAE,MAAM,KACxB,IAAI,GACV,IAAI;IAoBA,sBAAsB,CAAC,QAAQ,EAAE,wBAAwB,GAAG,IAAI;IAkBvE,OAAO,CAAC,yBAAyB;IAoBjC,OAAO,CAAC,sBAAsB;CAKjC"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
* Licensed under the Microsoft Live Share SDK License.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.GroupPlaybackPosition = void 0;
|
|
8
|
+
const GroupPlaybackTrack_1 = require("./GroupPlaybackTrack");
|
|
9
|
+
/**
|
|
10
|
+
* @hidden
|
|
11
|
+
*/
|
|
12
|
+
class GroupPlaybackPosition {
|
|
13
|
+
constructor(transportState, runtime, liveRuntime, updateInterval) {
|
|
14
|
+
this._transportState = transportState;
|
|
15
|
+
this._runtime = runtime;
|
|
16
|
+
this._liveRuntime = liveRuntime;
|
|
17
|
+
this._updateInterval = updateInterval;
|
|
18
|
+
this._positions = new Map();
|
|
19
|
+
// Listen for track change
|
|
20
|
+
this._transportState.track.on(GroupPlaybackTrack_1.GroupPlaybackTrackEvents.trackChange, (_) => {
|
|
21
|
+
// Reset position tracking and duration
|
|
22
|
+
this._positions = new Map();
|
|
23
|
+
this.mediaDuration = undefined;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Returns the latest position info for the local client.
|
|
28
|
+
*/
|
|
29
|
+
get localPosition() {
|
|
30
|
+
return this._positions.get(this._runtime.clientId);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Returns the total number of clients actively being tracked.
|
|
34
|
+
*/
|
|
35
|
+
get totalClients() {
|
|
36
|
+
let cnt = 0;
|
|
37
|
+
this.forEach((_) => cnt++);
|
|
38
|
+
return cnt;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Returns true if all clients being tracked are reporting that they have
|
|
42
|
+
* either ended or haven't started.
|
|
43
|
+
*/
|
|
44
|
+
get trackEnded() {
|
|
45
|
+
let playing = 0;
|
|
46
|
+
this.forEach((position, projectedPosition) => {
|
|
47
|
+
switch (position.playbackState) {
|
|
48
|
+
case "none":
|
|
49
|
+
case "ended":
|
|
50
|
+
// not playing.
|
|
51
|
+
break;
|
|
52
|
+
default:
|
|
53
|
+
playing++;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return playing == 0;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Returns the number of clients we're waiting for before we can stop waiting.
|
|
61
|
+
*/
|
|
62
|
+
get clientsWaiting() {
|
|
63
|
+
var _a;
|
|
64
|
+
let cnt = 0;
|
|
65
|
+
const waitPoint = (_a = this.localPosition) === null || _a === void 0 ? void 0 : _a.waitPoint;
|
|
66
|
+
if (waitPoint &&
|
|
67
|
+
(waitPoint.maxClients == undefined ||
|
|
68
|
+
this.totalClients <= waitPoint.maxClients)) {
|
|
69
|
+
this.forEach((position, projectedPosition) => {
|
|
70
|
+
if (position.playbackState == "suspended" &&
|
|
71
|
+
position.waitPoint) {
|
|
72
|
+
cnt++;
|
|
73
|
+
}
|
|
74
|
+
else if (position.position < waitPoint.position) {
|
|
75
|
+
cnt++;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return cnt;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Returns the max playback position relative to the start position.
|
|
83
|
+
*
|
|
84
|
+
* @remarks
|
|
85
|
+
* This is called when calculating the current seekTo position.
|
|
86
|
+
*/
|
|
87
|
+
get maxPosition() {
|
|
88
|
+
if (this._transportState.playbackState == "playing") {
|
|
89
|
+
const now = this._liveRuntime.getTimestamp();
|
|
90
|
+
const projected = this._transportState.startPosition +
|
|
91
|
+
(now - this._transportState.timestamp) / 1000;
|
|
92
|
+
return this.limitProjectedPosition(projected);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
return this._transportState.startPosition;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
get targetPosition() {
|
|
99
|
+
if (this._transportState.playbackState == "playing") {
|
|
100
|
+
return this.getMostProgressedPosition();
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
return this._transportState.startPosition;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Enumerates every reported playback position.
|
|
108
|
+
* @param callbackFn Function applied to each position,
|
|
109
|
+
*/
|
|
110
|
+
forEach(callbackFn) {
|
|
111
|
+
var _a;
|
|
112
|
+
const now = this._liveRuntime.getTimestamp();
|
|
113
|
+
const ignoreBefore = now - this._updateInterval.milliseconds * 2;
|
|
114
|
+
const shouldProject = !((_a = this._transportState.track.metadata) === null || _a === void 0 ? void 0 : _a.liveStream);
|
|
115
|
+
this._positions.forEach((value, key) => {
|
|
116
|
+
const position = this._positions.get(key);
|
|
117
|
+
// Ignore any old updates
|
|
118
|
+
if (position.timestamp > ignoreBefore) {
|
|
119
|
+
// Compute projected playback position
|
|
120
|
+
// - This computation does not take into account future wait points.
|
|
121
|
+
const projected = position.playbackState == "playing" && shouldProject
|
|
122
|
+
? position.position + (now - position.timestamp) / 1000
|
|
123
|
+
: position.position;
|
|
124
|
+
callbackFn(position, this.limitProjectedPosition(projected));
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
UpdatePlaybackPosition(position) {
|
|
129
|
+
// Update duration
|
|
130
|
+
if (position.duration != undefined) {
|
|
131
|
+
this.mediaDuration = position.duration;
|
|
132
|
+
}
|
|
133
|
+
// Save last position
|
|
134
|
+
if (this._positions.has(position.clientId)) {
|
|
135
|
+
// Only update if newer position
|
|
136
|
+
const current = this._positions.get(position.clientId);
|
|
137
|
+
if (position.timestamp >= current.timestamp) {
|
|
138
|
+
this._positions.set(position.clientId, position);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
this._positions.set(position.clientId, position);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
getMostProgressedPosition() {
|
|
146
|
+
// Compute the max possible position for the current transport state.
|
|
147
|
+
// - This is needed to properly handle seeking backwards in time. Some playback heads may
|
|
148
|
+
// not have performed their seek yet and will therefore be ahead of the local player.
|
|
149
|
+
const maxPosition = this.maxPosition;
|
|
150
|
+
// Compute max progress
|
|
151
|
+
let progress = -1;
|
|
152
|
+
this.forEach((position, projectedPosition) => {
|
|
153
|
+
if (projectedPosition <= maxPosition &&
|
|
154
|
+
projectedPosition > progress) {
|
|
155
|
+
progress = projectedPosition;
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
return progress;
|
|
159
|
+
}
|
|
160
|
+
limitProjectedPosition(position) {
|
|
161
|
+
return this.mediaDuration != undefined
|
|
162
|
+
? Math.min(position, this.mediaDuration)
|
|
163
|
+
: position;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
exports.GroupPlaybackPosition = GroupPlaybackPosition;
|
|
167
|
+
//# sourceMappingURL=GroupPlaybackPosition.js.map
|