@microsoft/live-share-media 1.0.0-preview.1 → 1.0.0-preview.11
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 +15 -13
- package/package.json +11 -9
- package/src/IMediaPlayer.ts +10 -2
- package/src/LiveMediaSession.ts +138 -71
- package/src/LiveMediaSessionCoordinator.ts +302 -142
- package/src/LiveMediaSessionCoordinatorSuspension.ts +13 -5
- package/src/MediaPlayerSynchronizer.ts +329 -149
- 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 +275 -114
- package/src/internals/GroupPlaybackPosition.ts +63 -29
- package/src/internals/GroupPlaybackTrack.ts +51 -22
- package/src/internals/GroupPlaybackTrackData.ts +24 -16
- package/src/internals/GroupTransportState.ts +54 -24
- 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/.vscode/launch.json +0 -29
- package/.vscode/settings.json +0 -2
- 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/IMediaPlayer.d.ts +0 -21
- package/bin/IMediaPlayer.d.ts.map +0 -1
- package/bin/IMediaPlayer.js +0 -7
- package/bin/IMediaPlayer.js.map +0 -1
- package/bin/LiveMediaSession.d.ts +0 -95
- package/bin/LiveMediaSession.d.ts.map +0 -1
- package/bin/LiveMediaSession.js +0 -217
- package/bin/LiveMediaSession.js.map +0 -1
- package/bin/LiveMediaSessionCoordinator.d.ts +0 -228
- package/bin/LiveMediaSessionCoordinator.d.ts.map +0 -1
- package/bin/LiveMediaSessionCoordinator.js +0 -396
- package/bin/LiveMediaSessionCoordinator.js.map +0 -1
- package/bin/LiveMediaSessionCoordinatorSuspension.d.ts +0 -20
- package/bin/LiveMediaSessionCoordinatorSuspension.d.ts.map +0 -1
- package/bin/LiveMediaSessionCoordinatorSuspension.js +0 -28
- package/bin/LiveMediaSessionCoordinatorSuspension.js.map +0 -1
- package/bin/MediaPlayerSynchronizer.d.ts +0 -164
- package/bin/MediaPlayerSynchronizer.d.ts.map +0 -1
- package/bin/MediaPlayerSynchronizer.js +0 -414
- package/bin/MediaPlayerSynchronizer.js.map +0 -1
- package/bin/MediaSessionActionThrottler.d.ts +0 -12
- package/bin/MediaSessionActionThrottler.d.ts.map +0 -1
- package/bin/MediaSessionActionThrottler.js +0 -14
- package/bin/MediaSessionActionThrottler.js.map +0 -1
- package/bin/MediaSessionExtensions.d.ts +0 -35
- package/bin/MediaSessionExtensions.d.ts.map +0 -1
- package/bin/MediaSessionExtensions.js +0 -13
- package/bin/MediaSessionExtensions.js.map +0 -1
- package/bin/RepeatedActionThrottler.d.ts +0 -20
- package/bin/RepeatedActionThrottler.d.ts.map +0 -1
- package/bin/RepeatedActionThrottler.js +0 -57
- package/bin/RepeatedActionThrottler.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
- package/bin/VolumeManager.d.ts +0 -84
- package/bin/VolumeManager.d.ts.map +0 -1
- package/bin/VolumeManager.js +0 -173
- package/bin/VolumeManager.js.map +0 -1
- package/bin/index.d.ts +0 -14
- package/bin/index.d.ts.map +0 -1
- package/bin/index.js +0 -30
- package/bin/index.js.map +0 -1
- package/bin/internals/GroupCoordinatorState.d.ts +0 -93
- package/bin/internals/GroupCoordinatorState.d.ts.map +0 -1
- package/bin/internals/GroupCoordinatorState.js +0 -367
- package/bin/internals/GroupCoordinatorState.js.map +0 -1
- package/bin/internals/GroupPlaybackPosition.d.ts +0 -67
- package/bin/internals/GroupPlaybackPosition.d.ts.map +0 -1
- package/bin/internals/GroupPlaybackPosition.js +0 -158
- package/bin/internals/GroupPlaybackPosition.js.map +0 -1
- package/bin/internals/GroupPlaybackTrack.d.ts +0 -46
- package/bin/internals/GroupPlaybackTrack.d.ts.map +0 -1
- package/bin/internals/GroupPlaybackTrack.js +0 -112
- package/bin/internals/GroupPlaybackTrack.js.map +0 -1
- package/bin/internals/GroupPlaybackTrackData.d.ts +0 -40
- package/bin/internals/GroupPlaybackTrackData.d.ts.map +0 -1
- package/bin/internals/GroupPlaybackTrackData.js +0 -66
- package/bin/internals/GroupPlaybackTrackData.js.map +0 -1
- package/bin/internals/GroupTransportState.d.ts +0 -49
- package/bin/internals/GroupTransportState.d.ts.map +0 -1
- package/bin/internals/GroupTransportState.js +0 -97
- package/bin/internals/GroupTransportState.js.map +0 -1
- package/bin/internals/consts.d.ts +0 -73
- package/bin/internals/consts.d.ts.map +0 -1
- package/bin/internals/consts.js +0 -82
- package/bin/internals/consts.js.map +0 -1
- package/bin/internals/index.d.ts +0 -11
- package/bin/internals/index.d.ts.map +0 -1
- package/bin/internals/index.js +0 -27
- package/bin/internals/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -11,15 +11,13 @@ You can find our API reference documentation at [aka.ms/livesharedocs](https://a
|
|
|
11
11
|
To add the latest version of the SDK to your application using NPM:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npm install @microsoft/live-share --save
|
|
15
|
-
npm install @microsoft/live-share-media --save
|
|
14
|
+
npm install fluid-framework @fluidframework/azure-client @microsoft/live-share @microsoft/live-share-media --save
|
|
16
15
|
```
|
|
17
16
|
|
|
18
17
|
or using [Yarn](https://yarnpkg.com/):
|
|
19
18
|
|
|
20
19
|
```bash
|
|
21
|
-
yarn add @microsoft/live-share
|
|
22
|
-
yarn add @microsoft/live-share-media
|
|
20
|
+
yarn add fluid-framework @fluidframework/azure-client @microsoft/live-share @microsoft/live-share-media
|
|
23
21
|
```
|
|
24
22
|
|
|
25
23
|
## Building package
|
|
@@ -50,15 +48,16 @@ This will use lerna to hoist and build all dependencies.
|
|
|
50
48
|
```
|
|
51
49
|
|
|
52
50
|
```javascript
|
|
53
|
-
import
|
|
54
|
-
import {
|
|
51
|
+
import { app, LiveShareHost } from "@microsoft/teams-js";
|
|
52
|
+
import { LiveShareClient } from "@microsoft/live-share";
|
|
55
53
|
import { LiveMediaSession } from "@microsoft/live-share-media";
|
|
56
54
|
|
|
57
55
|
// Initialize the Teams Client SDK
|
|
58
56
|
await microsoftTeams.app.initialize();
|
|
59
57
|
|
|
60
58
|
// Setup the Fluid container
|
|
61
|
-
const
|
|
59
|
+
const host = LiveShareHost.create();
|
|
60
|
+
const client = new LiveShareClient(host);
|
|
62
61
|
const schema = {
|
|
63
62
|
initialObjects: {
|
|
64
63
|
mediaSession: LiveMediaSession,
|
|
@@ -112,11 +111,14 @@ The Live Share SDK contains dependencies for [@microsoft/teams-js](https://www.n
|
|
|
112
111
|
|
|
113
112
|
**It is critical that your app use the package dependencies listed in the table below.** Lookup the version of the `@microsoft/live-share` you're using and set any other dependencies in your package.json file to match:
|
|
114
113
|
|
|
115
|
-
| @microsoft/live-share | @microsoft/teams-js | fluid-framework | @microsoft/live-share
|
|
116
|
-
| --------------------- | -------------------- | --------------- |
|
|
117
|
-
| 1.0.0-preview.
|
|
118
|
-
|
|
|
119
|
-
|
|
|
114
|
+
| @microsoft/live-share | @microsoft/teams-js | fluid-framework | @microsoft/live-share-\* | @fluidframework/azure-client | @microsoft/TeamsFx | @microsoft/TeamsFx-react |
|
|
115
|
+
| --------------------- | -------------------- | --------------- | -------------------------- | ---------------------------- | ------------------------------- | ------------------------------- |
|
|
116
|
+
| 1.0.0-preview.11 | ^2.11.0 | ^1.2.3 | 1.0.0-preview.11 (optional) | ^1.0.0 (optional) | ^2.5.0 (optional) | ^2.5.0 (optional) |
|
|
117
|
+
| 1.0.0-preview.10 | ^2.10.1 | ~1.2.3 | 1.0.0-preview.10 (optional) | ~1.0.2 (optional) | ^2.5.0 (optional) | ^2.5.0 (optional) |
|
|
118
|
+
| 1.0.0-preview.8 | ^2.5.0 | ~1.2.3 | 1.0.0-preview.10 (optional) | ~1.0.2 (optional) | ^2.5.0 (optional) | ^2.5.0 (optional) |
|
|
119
|
+
| 1.0.0-preview.3 | 2.0.0-experimental.1 | ~1.2.3 | 1.0.0-preview.3 (optional) | ~1.0.2 (optional) | 2.0.0-experimental.0 (optional) | 2.0.0-experimental.0 (optional) |
|
|
120
|
+
| ~0.5.1 | 2.0.0-experimental.1 | ~1.2.3 | ~0.5.1 (optional) | ~1.0.2 (optional) | 2.0.0-experimental.0 (optional) | 2.0.0-experimental.0 (optional) |
|
|
121
|
+
| ~0.3.1 | 2.0.0-experimental.0 | ~0.59.0 | ~0.3.1 (optional) | ~0.59.0 (optional) | 2.0.0-experimental.0 (optional) | 2.0.0-experimental.0 (optional) |
|
|
120
122
|
|
|
121
123
|
## Contributing
|
|
122
124
|
|
|
@@ -131,7 +133,7 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope
|
|
|
131
133
|
|
|
132
134
|
## Reporting Security Issues
|
|
133
135
|
|
|
134
|
-
Security issues and bugs should be reported privately, via email, to the Microsoft Security Response Center (MSRC) at secure@microsoft.com. You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the [MSRC PGP](https://technet.microsoft.com/
|
|
136
|
+
Security issues and bugs should be reported privately, via email, to the Microsoft Security Response Center (MSRC) at secure@microsoft.com. You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the [MSRC PGP](https://technet.microsoft.com/security/dn606155) key, can be found in the [Security TechCenter](https://technet.microsoft.com/security/default).
|
|
135
137
|
|
|
136
138
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
137
139
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@microsoft/live-share-media",
|
|
3
|
-
"version": "1.0.0-preview.
|
|
3
|
+
"version": "1.0.0-preview.11",
|
|
4
4
|
"description": "Live Share classes that synchronize media playback across clients.",
|
|
5
5
|
"author": "Microsoft",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -13,19 +13,21 @@
|
|
|
13
13
|
"test:debug": "ts-mocha src/**/*.spec.ts --inspect-brk",
|
|
14
14
|
"test:coverage": "nyc --reporter=html --reporter=text --reporter=text-summary npm test"
|
|
15
15
|
},
|
|
16
|
-
"dependencies": {
|
|
17
|
-
"fluid-framework": "~1.2.3",
|
|
18
|
-
"@microsoft/live-share": "1.0.0-preview.1"
|
|
19
|
-
},
|
|
20
16
|
"devDependencies": {
|
|
17
|
+
"@microsoft/live-share": "1.0.0-preview.11",
|
|
21
18
|
"@types/assert": "^1.5.6",
|
|
22
|
-
"@types/mocha": "^
|
|
23
|
-
"@types/node": "^
|
|
24
|
-
"
|
|
19
|
+
"@types/mocha": "^10.0.1",
|
|
20
|
+
"@types/node": "^18.11.18",
|
|
21
|
+
"fluid-framework": "^1.3.6",
|
|
22
|
+
"mocha": "^10.2.0",
|
|
25
23
|
"nyc": "^15.1.0",
|
|
26
|
-
"ts-mocha": "^
|
|
24
|
+
"ts-mocha": "^10.0.0",
|
|
27
25
|
"typescript": "^4.6.4"
|
|
28
26
|
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@microsoft/live-share": "1.0.0-preview.11",
|
|
29
|
+
"fluid-framework": "^1.2.3"
|
|
30
|
+
},
|
|
29
31
|
"repository": {
|
|
30
32
|
"directory": "packages/live-share-media",
|
|
31
33
|
"type": "git",
|
package/src/IMediaPlayer.ts
CHANGED
|
@@ -16,6 +16,14 @@ export interface IMediaPlayer {
|
|
|
16
16
|
load(): void;
|
|
17
17
|
pause(): void;
|
|
18
18
|
play(): Promise<void>;
|
|
19
|
-
addEventListener(
|
|
20
|
-
|
|
19
|
+
addEventListener(
|
|
20
|
+
type: string,
|
|
21
|
+
listener: EventListenerOrEventListenerObject,
|
|
22
|
+
options?: boolean | AddEventListenerOptions
|
|
23
|
+
): void;
|
|
24
|
+
removeEventListener(
|
|
25
|
+
type: string,
|
|
26
|
+
listener: EventListenerOrEventListenerObject,
|
|
27
|
+
options?: boolean | EventListenerOptions
|
|
28
|
+
): void;
|
|
21
29
|
}
|
package/src/LiveMediaSession.ts
CHANGED
|
@@ -3,40 +3,49 @@
|
|
|
3
3
|
* Licensed under the Microsoft Live Share SDK License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { DataObject, DataObjectFactory } from
|
|
7
|
-
import { LiveTelemetryLogger, UserMeetingRole } from
|
|
8
|
-
import { MediaPlayerSynchronizer } from
|
|
9
|
-
import { ITriggerActionEvent, TelemetryEvents } from
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
import { DataObject, DataObjectFactory } from "@fluidframework/aqueduct";
|
|
7
|
+
import { DynamicObjectRegistry, LiveTelemetryLogger, UserMeetingRole } from "@microsoft/live-share";
|
|
8
|
+
import { MediaPlayerSynchronizer } from "./MediaPlayerSynchronizer";
|
|
9
|
+
import { ITriggerActionEvent, TelemetryEvents } from "./internals";
|
|
10
|
+
import {
|
|
11
|
+
MediaSessionCoordinatorEvents,
|
|
12
|
+
ExtendedMediaSessionAction,
|
|
13
|
+
ExtendedMediaSessionActionDetails,
|
|
14
|
+
} from "./MediaSessionExtensions";
|
|
15
|
+
import {
|
|
16
|
+
LiveMediaSessionCoordinator,
|
|
17
|
+
IMediaPlayerState,
|
|
18
|
+
} from "./LiveMediaSessionCoordinator";
|
|
19
|
+
import { MediaSessionActionThrottler } from "./MediaSessionActionThrottler";
|
|
20
|
+
import { RepeatedActionThrottler } from "./RepeatedActionThrottler";
|
|
21
|
+
import { IMediaPlayer } from "./IMediaPlayer";
|
|
15
22
|
|
|
16
23
|
/**
|
|
17
24
|
* Live fluid object that synchronizes media playback across multiple clients.
|
|
18
25
|
*/
|
|
19
|
-
|
|
20
|
-
private _actionThrottler: MediaSessionActionThrottler =
|
|
26
|
+
export class LiveMediaSession extends DataObject {
|
|
27
|
+
private _actionThrottler: MediaSessionActionThrottler =
|
|
28
|
+
new RepeatedActionThrottler();
|
|
21
29
|
private _logger?: LiveTelemetryLogger;
|
|
22
30
|
private _requestPlayerStateHandler?: () => IMediaPlayerState;
|
|
23
31
|
private _coordinator?: LiveMediaSessionCoordinator;
|
|
24
|
-
private readonly _actionHandlers: Map<string, MediaSessionActionHandler> =
|
|
32
|
+
private readonly _actionHandlers: Map<string, MediaSessionActionHandler> =
|
|
33
|
+
new Map();
|
|
25
34
|
private _synchronizing?: MediaPlayerSynchronizer;
|
|
26
35
|
|
|
27
36
|
// Position update timer
|
|
28
37
|
private _updateTimer: any;
|
|
29
38
|
private _lastUpdateTime: number = 0;
|
|
30
|
-
|
|
39
|
+
|
|
31
40
|
/**
|
|
32
41
|
* The objects fluid type name.
|
|
33
42
|
*/
|
|
34
|
-
|
|
43
|
+
public static readonly TypeName = `@microsoft/fluid-media:SharedMediaSession`;
|
|
35
44
|
|
|
36
45
|
/**
|
|
37
46
|
* The objects fluid type factory.
|
|
38
47
|
*/
|
|
39
|
-
|
|
48
|
+
public static readonly factory = new DataObjectFactory(
|
|
40
49
|
LiveMediaSession.TypeName,
|
|
41
50
|
LiveMediaSession,
|
|
42
51
|
[],
|
|
@@ -46,15 +55,15 @@ import { IMediaPlayer } from './IMediaPlayer';
|
|
|
46
55
|
/**
|
|
47
56
|
* Extension point that lets applications replace the default logic for throttling the sessions
|
|
48
57
|
* local sync behavior.
|
|
49
|
-
*
|
|
58
|
+
*
|
|
50
59
|
* @remarks
|
|
51
|
-
* The `LiveMediaCoordinator` is fairly aggressive at wanting to keep the local media player
|
|
52
|
-
* in sync with the rest of the group. This aggressiveness can result in the coordinator sending
|
|
53
|
-
* new sync actions before the local player has finished responding to the previous sync action.
|
|
60
|
+
* The `LiveMediaCoordinator` is fairly aggressive at wanting to keep the local media player
|
|
61
|
+
* in sync with the rest of the group. This aggressiveness can result in the coordinator sending
|
|
62
|
+
* new sync actions before the local player has finished responding to the previous sync action.
|
|
54
63
|
* The `ActionThrottler` gives apps fine grain control over how aggressive they want sync to be.
|
|
55
|
-
*
|
|
56
|
-
* By default, a `RepeatedAction` throttler is used which prevents the same sync action from
|
|
57
|
-
* being sent within an adjustable time period.
|
|
64
|
+
*
|
|
65
|
+
* By default, a `RepeatedAction` throttler is used which prevents the same sync action from
|
|
66
|
+
* being sent within an adjustable time period.
|
|
58
67
|
*/
|
|
59
68
|
public get actionThrottler(): MediaSessionActionThrottler {
|
|
60
69
|
return this._actionThrottler;
|
|
@@ -76,7 +85,7 @@ import { IMediaPlayer } from './IMediaPlayer';
|
|
|
76
85
|
* Returns true if the object has been initialized.
|
|
77
86
|
*/
|
|
78
87
|
public get isStarted(): boolean {
|
|
79
|
-
return this.isInitialized
|
|
88
|
+
return this.isInitialized;
|
|
80
89
|
}
|
|
81
90
|
|
|
82
91
|
/**
|
|
@@ -88,7 +97,7 @@ import { IMediaPlayer } from './IMediaPlayer';
|
|
|
88
97
|
|
|
89
98
|
/**
|
|
90
99
|
* Returns the logger used by the session and coordinator.
|
|
91
|
-
*
|
|
100
|
+
*
|
|
92
101
|
* @remarks
|
|
93
102
|
* This is used by the `MediaPlayerSynchronizer` to log events.
|
|
94
103
|
*/
|
|
@@ -98,10 +107,12 @@ import { IMediaPlayer } from './IMediaPlayer';
|
|
|
98
107
|
|
|
99
108
|
/**
|
|
100
109
|
* initialize the object.
|
|
101
|
-
* @param acceptTransportChangesFrom Optional. List of roles allowed to group transport
|
|
110
|
+
* @param acceptTransportChangesFrom Optional. List of roles allowed to group transport
|
|
102
111
|
* operations like play/pause/seek/setTrack.
|
|
103
112
|
*/
|
|
104
|
-
|
|
113
|
+
public initialize(
|
|
114
|
+
acceptTransportChangesFrom?: UserMeetingRole[]
|
|
115
|
+
): Promise<void> {
|
|
105
116
|
return this.coordinator.initialize(acceptTransportChangesFrom);
|
|
106
117
|
}
|
|
107
118
|
|
|
@@ -110,11 +121,13 @@ import { IMediaPlayer } from './IMediaPlayer';
|
|
|
110
121
|
* @param action Name of the action to register a handler for.
|
|
111
122
|
* @param handler Function called when the action is triggered.
|
|
112
123
|
*/
|
|
113
|
-
public setActionHandler(
|
|
124
|
+
public setActionHandler(
|
|
125
|
+
action: ExtendedMediaSessionAction,
|
|
126
|
+
handler: MediaSessionActionHandler | null
|
|
127
|
+
): void {
|
|
114
128
|
if (handler) {
|
|
115
129
|
// add handler
|
|
116
130
|
this._actionHandlers.set(action, handler);
|
|
117
|
-
|
|
118
131
|
} else if (this._actionHandlers.has(action)) {
|
|
119
132
|
// remove handler
|
|
120
133
|
this._actionHandlers.delete(action);
|
|
@@ -122,8 +135,8 @@ import { IMediaPlayer } from './IMediaPlayer';
|
|
|
122
135
|
}
|
|
123
136
|
|
|
124
137
|
/**
|
|
125
|
-
* Registers a handler that will be queried anytime the group coordinate needs to know the
|
|
126
|
-
* local players transport state and position.
|
|
138
|
+
* Registers a handler that will be queried anytime the group coordinate needs to know the
|
|
139
|
+
* local players transport state and position.
|
|
127
140
|
*/
|
|
128
141
|
public setRequestPlayerStateHandler(handler: () => IMediaPlayerState) {
|
|
129
142
|
this._requestPlayerStateHandler = handler;
|
|
@@ -142,7 +155,9 @@ import { IMediaPlayer } from './IMediaPlayer';
|
|
|
142
155
|
|
|
143
156
|
// Start position update timer
|
|
144
157
|
if (!this._updateTimer) {
|
|
145
|
-
this.logger.sendTelemetryEvent(
|
|
158
|
+
this.logger.sendTelemetryEvent(
|
|
159
|
+
TelemetryEvents.MediaSession.BeginPositionUpdateTimer
|
|
160
|
+
);
|
|
146
161
|
this._updateTimer = setInterval(() => {
|
|
147
162
|
// Get current state
|
|
148
163
|
const state = this.getCurrentPlayerState();
|
|
@@ -153,7 +168,10 @@ import { IMediaPlayer } from './IMediaPlayer';
|
|
|
153
168
|
// Send position update if interval hit
|
|
154
169
|
const now = new Date().getTime();
|
|
155
170
|
const delta = (now - this._lastUpdateTime) / 1000;
|
|
156
|
-
if (
|
|
171
|
+
if (
|
|
172
|
+
this.coordinator.isInitialized &&
|
|
173
|
+
delta >= this.coordinator.positionUpdateInterval
|
|
174
|
+
) {
|
|
157
175
|
this._lastUpdateTime = now;
|
|
158
176
|
this.coordinator.sendPositionUpdate(state);
|
|
159
177
|
}
|
|
@@ -166,73 +184,122 @@ import { IMediaPlayer } from './IMediaPlayer';
|
|
|
166
184
|
}
|
|
167
185
|
|
|
168
186
|
protected async hasInitialized(): Promise<void> {
|
|
169
|
-
this.
|
|
187
|
+
this._logger = new LiveTelemetryLogger(this.runtime);
|
|
170
188
|
|
|
171
189
|
// Create coordinator and listen for triggered actions
|
|
172
|
-
this._coordinator = new LiveMediaSessionCoordinator(this.runtime, () =>
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
190
|
+
this._coordinator = new LiveMediaSessionCoordinator(this.runtime, () =>
|
|
191
|
+
this.getCurrentPlayerState()
|
|
192
|
+
);
|
|
193
|
+
this._coordinator.on(
|
|
194
|
+
MediaSessionCoordinatorEvents.triggeraction,
|
|
195
|
+
(event: ITriggerActionEvent) => {
|
|
196
|
+
// Pre-process actions
|
|
197
|
+
const details = event.details;
|
|
198
|
+
const seekTime =
|
|
199
|
+
typeof details.seekTime == "number" ? details.seekTime : -1;
|
|
200
|
+
switch (details.action) {
|
|
201
|
+
case "play":
|
|
202
|
+
this.logger.sendTelemetryEvent(
|
|
203
|
+
TelemetryEvents.MediaSession.PlayAction,
|
|
204
|
+
null,
|
|
205
|
+
{
|
|
206
|
+
position: seekTime,
|
|
207
|
+
}
|
|
208
|
+
);
|
|
209
|
+
break;
|
|
210
|
+
case "pause":
|
|
211
|
+
this.logger.sendTelemetryEvent(
|
|
212
|
+
TelemetryEvents.MediaSession.PauseAction,
|
|
213
|
+
null,
|
|
214
|
+
{
|
|
215
|
+
position: seekTime,
|
|
216
|
+
}
|
|
217
|
+
);
|
|
218
|
+
break;
|
|
219
|
+
case "seekto":
|
|
220
|
+
this.logger.sendTelemetryEvent(
|
|
221
|
+
TelemetryEvents.MediaSession.SeekToAction,
|
|
222
|
+
null,
|
|
223
|
+
{
|
|
224
|
+
position: seekTime,
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
break;
|
|
228
|
+
case "settrack":
|
|
229
|
+
this.logger.sendTelemetryEvent(
|
|
230
|
+
TelemetryEvents.MediaSession.SetTrackAction
|
|
231
|
+
);
|
|
232
|
+
break;
|
|
233
|
+
case "datachange":
|
|
234
|
+
this.logger.sendTelemetryEvent(
|
|
235
|
+
TelemetryEvents.MediaSession.DataChangeAction
|
|
236
|
+
);
|
|
237
|
+
break;
|
|
238
|
+
case "catchup":
|
|
239
|
+
// Default to seekto if catchup not implemented
|
|
240
|
+
this.logger.sendTelemetryEvent(
|
|
241
|
+
TelemetryEvents.MediaSession.CatchUpAction,
|
|
242
|
+
null,
|
|
243
|
+
{
|
|
244
|
+
position: seekTime,
|
|
245
|
+
}
|
|
246
|
+
);
|
|
247
|
+
if (!this._actionHandlers.has("catchup")) {
|
|
248
|
+
details.action = "seekto";
|
|
249
|
+
}
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
201
252
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
253
|
+
// Dispatch action
|
|
254
|
+
this.dispatchAction(details);
|
|
255
|
+
}
|
|
256
|
+
);
|
|
205
257
|
}
|
|
206
258
|
|
|
207
259
|
private checkWaitPointHit(state: IMediaPlayerState): void {
|
|
208
260
|
// Was a wait point hit?
|
|
209
261
|
if (state.positionState && this.coordinator.isInitialized) {
|
|
210
262
|
const waitPoint = this.coordinator.findNextWaitPoint();
|
|
211
|
-
if (
|
|
263
|
+
if (
|
|
264
|
+
waitPoint &&
|
|
265
|
+
state.positionState.position != undefined &&
|
|
266
|
+
state.positionState.position >= waitPoint.position
|
|
267
|
+
) {
|
|
212
268
|
// Ensure handler registered
|
|
213
|
-
if (!this._actionHandlers.has(
|
|
214
|
-
throw new Error(
|
|
269
|
+
if (!this._actionHandlers.has("wait")) {
|
|
270
|
+
throw new Error(
|
|
271
|
+
`SharedMediaSession: wait point hit but no 'wait' action registered.`
|
|
272
|
+
);
|
|
215
273
|
}
|
|
216
274
|
|
|
217
275
|
// Begin suspension for wait point
|
|
218
276
|
const suspension = this.coordinator.beginSuspension(waitPoint);
|
|
219
|
-
this.dispatchAction({action:
|
|
277
|
+
this.dispatchAction({ action: "wait", suspension: suspension });
|
|
220
278
|
}
|
|
221
279
|
}
|
|
222
280
|
}
|
|
223
281
|
|
|
224
282
|
private getCurrentPlayerState(): IMediaPlayerState {
|
|
225
283
|
if (!this._requestPlayerStateHandler) {
|
|
226
|
-
throw new Error(
|
|
284
|
+
throw new Error(
|
|
285
|
+
`SharedMediaSession: no getPlayerState callback configured.`
|
|
286
|
+
);
|
|
227
287
|
}
|
|
228
288
|
|
|
229
289
|
return this._requestPlayerStateHandler();
|
|
230
290
|
}
|
|
231
291
|
|
|
232
|
-
private dispatchAction(
|
|
292
|
+
private dispatchAction(
|
|
293
|
+
details: MediaSessionActionDetails | ExtendedMediaSessionActionDetails
|
|
294
|
+
): void {
|
|
233
295
|
if (this._actionHandlers.has(details.action)) {
|
|
234
296
|
const handler = this._actionHandlers.get(details.action);
|
|
235
297
|
this._actionThrottler.throttled(details, handler);
|
|
236
298
|
}
|
|
237
299
|
}
|
|
238
300
|
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Register `LiveMediaSession` as an available `LoadableObjectClass` for use in packages that support dynamic object loading, such as `@microsoft/live-share-turbo`.
|
|
304
|
+
*/
|
|
305
|
+
DynamicObjectRegistry.registerObjectClass(LiveMediaSession, LiveMediaSession.TypeName);
|