@microsoft/live-share-media 0.5.0-beta.1 → 0.5.0-beta.2

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.
@@ -1,14 +1,14 @@
1
- /**
2
- * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Licensed under the Microsoft Live Share SDK License.
4
- */
5
-
6
- import { ExtendedMediaSessionActionDetails } from './MediaSessionExtensions';
7
-
8
- /**
9
- * Base class for action throttlers.
10
- */
11
- export abstract class MediaSessionActionThrottler {
12
- public abstract throttled(details: ExtendedMediaSessionActionDetails, handler?: MediaSessionActionHandler): void;
13
- }
14
-
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the Microsoft Live Share SDK License.
4
+ */
5
+
6
+ import { ExtendedMediaSessionActionDetails } from './MediaSessionExtensions';
7
+
8
+ /**
9
+ * Base class for action throttlers.
10
+ */
11
+ export abstract class MediaSessionActionThrottler {
12
+ public abstract throttled(details: ExtendedMediaSessionActionDetails, handler?: MediaSessionActionHandler): void;
13
+ }
14
+
@@ -1,42 +1,42 @@
1
- /**
2
- * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Licensed under the Microsoft Live Share SDK License.
4
- */
5
-
6
- export interface MediaSessionCoordinatorSuspension {
7
- waitPoint?: CoordinationWaitPoint;
8
- end(seekTo?: number): void;
9
- }
10
-
11
- export type MediaSessionCoordinatorState = "closed" | "waiting" | "joined";
12
-
13
- export enum MediaSessionCoordinatorEvents {
14
- coordinatorstatechange = 'coordinatorstatechange',
15
- triggeraction = 'triggeraction'
16
- }
17
-
18
- export type ExtendedMediaSessionAction = MediaSessionAction | "settrack" | "wait" | "catchup" | "datachange" | "blocked";
19
-
20
- export type ExtendedMediaSessionPlaybackState = MediaSessionPlaybackState | "suspended" | "waiting" | "ended";
21
-
22
- export interface ExtendedMediaMetadata extends MediaMetadata {
23
- trackIdentifier: string;
24
- liveStream: boolean;
25
- }
26
-
27
- export interface CoordinationWaitPoint {
28
- position: number;
29
- reason?: string;
30
- maxClients?: number;
31
- }
32
-
33
- export interface ExtendedMediaSessionActionDetails {
34
- action: ExtendedMediaSessionAction;
35
- fastSeek?: boolean | null;
36
- seekOffset?: number | null;
37
- seekTime?: number | null;
38
- metadata?: ExtendedMediaMetadata | null;
39
- suspension?: MediaSessionCoordinatorSuspension | null;
40
- data?: object | null;
41
- blocked?: ExtendedMediaSessionAction | null;
42
- }
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the Microsoft Live Share SDK License.
4
+ */
5
+
6
+ export interface MediaSessionCoordinatorSuspension {
7
+ waitPoint?: CoordinationWaitPoint;
8
+ end(seekTo?: number): void;
9
+ }
10
+
11
+ export type MediaSessionCoordinatorState = "closed" | "waiting" | "joined";
12
+
13
+ export enum MediaSessionCoordinatorEvents {
14
+ coordinatorstatechange = 'coordinatorstatechange',
15
+ triggeraction = 'triggeraction'
16
+ }
17
+
18
+ export type ExtendedMediaSessionAction = MediaSessionAction | "settrack" | "wait" | "catchup" | "datachange" | "blocked";
19
+
20
+ export type ExtendedMediaSessionPlaybackState = MediaSessionPlaybackState | "suspended" | "waiting" | "ended";
21
+
22
+ export interface ExtendedMediaMetadata extends MediaMetadata {
23
+ trackIdentifier: string;
24
+ liveStream: boolean;
25
+ }
26
+
27
+ export interface CoordinationWaitPoint {
28
+ position: number;
29
+ reason?: string;
30
+ maxClients?: number;
31
+ }
32
+
33
+ export interface ExtendedMediaSessionActionDetails {
34
+ action: ExtendedMediaSessionAction;
35
+ fastSeek?: boolean | null;
36
+ seekOffset?: number | null;
37
+ seekTime?: number | null;
38
+ metadata?: ExtendedMediaMetadata | null;
39
+ suspension?: MediaSessionCoordinatorSuspension | null;
40
+ data?: object | null;
41
+ blocked?: ExtendedMediaSessionAction | null;
42
+ }
@@ -1,56 +1,56 @@
1
- /**
2
- * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Licensed under the Microsoft Live Share SDK License.
4
- */
5
-
6
- import { TimeInterval } from '@microsoft/live-share';
7
- import { MediaSessionActionThrottler } from './MediaSessionActionThrottler';
8
- import { ExtendedMediaSessionActionDetails, ExtendedMediaSessionAction } from './MediaSessionExtensions';
9
-
10
- /**
11
- * A Throttler that passes through all actions but will only let an action be repeated once every 2 seconds.
12
- */
13
- export class RepeatedActionThrottler extends MediaSessionActionThrottler {
14
- private static FILTERED_ACTIONS: ExtendedMediaSessionAction[] = ['play', 'pause', 'seekto', 'catchup'];
15
- private _repeatInterval = new TimeInterval(2000);
16
- private _lastActionSentTime?: number;
17
- private _lastActionSent?: string;
18
-
19
- public get repeatInterval(): number {
20
- return this._repeatInterval.seconds;
21
- }
22
-
23
- public set repeatInterval(value: number) {
24
- this._repeatInterval.seconds = value;
25
- }
26
-
27
- public throttled(details: ExtendedMediaSessionActionDetails, handler?: MediaSessionActionHandler): void {
28
- if (handler) {
29
- if (RepeatedActionThrottler.FILTERED_ACTIONS.indexOf(details.action) >= 0) {
30
- const changeKey = this.getChangeKey(details);
31
- const now = new Date().getTime();
32
- if (this._lastActionSent && changeKey == this._lastActionSent) {
33
- if (now - this._lastActionSentTime! >= this._repeatInterval.milliseconds) {
34
- handler(details as MediaSessionActionDetails);
35
- this._lastActionSentTime = now;
36
- }
37
- } else {
38
- handler(details as MediaSessionActionDetails);
39
- this._lastActionSent = changeKey;
40
- this._lastActionSentTime = now;
41
- }
42
- } else {
43
- handler(details as MediaSessionActionDetails);
44
- }
45
- }
46
- }
47
-
48
- private getChangeKey(details: ExtendedMediaSessionActionDetails): string {
49
- switch (details.action) {
50
- case 'seekto':
51
- return `seekto:${details.seekTime}`;
52
- default:
53
- return details.action;
54
- }
55
- }
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the Microsoft Live Share SDK License.
4
+ */
5
+
6
+ import { TimeInterval } from '@microsoft/live-share';
7
+ import { MediaSessionActionThrottler } from './MediaSessionActionThrottler';
8
+ import { ExtendedMediaSessionActionDetails, ExtendedMediaSessionAction } from './MediaSessionExtensions';
9
+
10
+ /**
11
+ * A Throttler that passes through all actions but will only let an action be repeated once every 2 seconds.
12
+ */
13
+ export class RepeatedActionThrottler extends MediaSessionActionThrottler {
14
+ private static FILTERED_ACTIONS: ExtendedMediaSessionAction[] = ['play', 'pause', 'seekto', 'catchup'];
15
+ private _repeatInterval = new TimeInterval(2000);
16
+ private _lastActionSentTime?: number;
17
+ private _lastActionSent?: string;
18
+
19
+ public get repeatInterval(): number {
20
+ return this._repeatInterval.seconds;
21
+ }
22
+
23
+ public set repeatInterval(value: number) {
24
+ this._repeatInterval.seconds = value;
25
+ }
26
+
27
+ public throttled(details: ExtendedMediaSessionActionDetails, handler?: MediaSessionActionHandler): void {
28
+ if (handler) {
29
+ if (RepeatedActionThrottler.FILTERED_ACTIONS.indexOf(details.action) >= 0) {
30
+ const changeKey = this.getChangeKey(details);
31
+ const now = new Date().getTime();
32
+ if (this._lastActionSent && changeKey == this._lastActionSent) {
33
+ if (now - this._lastActionSentTime! >= this._repeatInterval.milliseconds) {
34
+ handler(details as MediaSessionActionDetails);
35
+ this._lastActionSentTime = now;
36
+ }
37
+ } else {
38
+ handler(details as MediaSessionActionDetails);
39
+ this._lastActionSent = changeKey;
40
+ this._lastActionSentTime = now;
41
+ }
42
+ } else {
43
+ handler(details as MediaSessionActionDetails);
44
+ }
45
+ }
46
+ }
47
+
48
+ private getChangeKey(details: ExtendedMediaSessionActionDetails): string {
49
+ switch (details.action) {
50
+ case 'seekto':
51
+ return `seekto:${details.seekTime}`;
52
+ default:
53
+ return details.action;
54
+ }
55
+ }
56
56
  }
@@ -1,182 +1,182 @@
1
- /**
2
- * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Licensed under the Microsoft Live Share SDK License.
4
- */
5
-
6
- import { TimeInterval } from '@microsoft/live-share';
7
- import { IMediaPlayer } from './IMediaPlayer';
8
-
9
- export enum LevelType { fixed, percentage }
10
-
11
- export class VolumeLimiter {
12
- private readonly _player: IMediaPlayer;
13
-
14
- // Settings
15
- private readonly _duration = new TimeInterval(2000);
16
- private readonly _rampDownDuration = new TimeInterval(500);
17
- private readonly _rampUpDuration = new TimeInterval(500);
18
- private _level: number = 0.1
19
- private _levelType: LevelType = LevelType.fixed;
20
-
21
- // Running state
22
- private _running = false;
23
- private _endTime = 0;
24
- private _startTime = 0;
25
- private _startVolume = 0;
26
- private _inRamp = false;
27
-
28
- constructor(player: IMediaPlayer) {
29
- this._player = player;
30
- }
31
-
32
- /**
33
- * Time, in seconds, that the volume should be lowered.
34
- *
35
- * @remarks
36
- * Applications should periodically call `lowerVolume()` to keep the volume lowered.
37
- */
38
- public get duration(): number {
39
- return this._duration.seconds;
40
- }
41
-
42
- public set duration(value: number) {
43
- this._duration.seconds = Math.abs(value);
44
- }
45
-
46
- /**
47
- * Target level to lower volume to.
48
- *
49
- * @remarks
50
- * Expressed as a value between 0.0 and 1.0. The value is applied based upon the configured
51
- * `levelType`. The default value is 0.2.
52
- *
53
- * For a level type of `LevelType.fixed` the value is the exact level the volume will be
54
- * lowered to. The default value of 0.2 would cause the volume to be lowered to 0.2.
55
- *
56
- * For a level type of `LevelType.percentage` the value is the percentage by which the volume
57
- * level should be lowered to. The default value of 0.2 would cause the volume to be lowered
58
- * to 20% of its starting value.
59
- */
60
- public get level(): number {
61
- return this._level;
62
- }
63
-
64
- public set level(value: number) {
65
- if (value < 0 || value > 1.0) {
66
- throw new Error(`VolumeLimiter: cannot set level to ${value}. Level must be between 0.0 and 1.0.`);
67
- }
68
-
69
- this._level = value;
70
- }
71
-
72
- /**
73
- * The type of level represented by the `level` property.
74
- */
75
- public get levelType(): LevelType {
76
- return this._levelType;
77
- }
78
-
79
- public set levelType(value: LevelType) {
80
- this._levelType = value;
81
- }
82
-
83
- /**
84
- * Amount of time, in seconds, it should take to ramp the volume down to the desired level.
85
- */
86
- public get rampDownDuration(): number {
87
- return this._rampDownDuration.seconds;
88
- }
89
-
90
- public set rampDownDuration(value: number) {
91
- this._rampDownDuration.seconds = Math.abs(value);
92
- }
93
-
94
- /**
95
- * Amount of time, in seconds, it should take to ramp the volume back up to the original level.
96
- */
97
- public get rampUpDuration(): number {
98
- return this._rampUpDuration.seconds;
99
- }
100
-
101
- public set rampUpDuration(value: number) {
102
- this._rampUpDuration.seconds = Math.abs(value);
103
- }
104
-
105
- /**
106
- * Temporarily lowers an audio sources volume.
107
- */
108
- public lowerVolume(): void {
109
- this._endTime = new Date().getTime() + this._duration.milliseconds;
110
- if (!this._running) {
111
- this.startLimiter();
112
- }
113
- }
114
-
115
- private startLimiter(): void {
116
- const adjustVolume = () => {
117
- const now = new Date().getTime();
118
- if (now < this._endTime) {
119
- // Make no adjustment if muted
120
- if (!this._player.muted) {
121
- // Compute adjusted volume level
122
- let volume: number;
123
- const targetVolume = this.computeTargetVolume();
124
- const rampRange = this._startVolume - targetVolume;
125
- const rampUpStart = this._endTime - this._rampUpDuration.milliseconds;
126
- const rampDownEnd = this._startTime + this._rampDownDuration.milliseconds;
127
- if (now > rampUpStart) {
128
- // We're about to end so ramping up
129
- const progress = (now - rampUpStart) / this._rampUpDuration.milliseconds;
130
- volume = targetVolume + (rampRange * progress);
131
- this._player.volume = volume;
132
- this._inRamp = true;
133
- } else if (now < rampDownEnd) {
134
- // We just begun so ramping down
135
- const remaining = (rampDownEnd - now) / this._rampUpDuration.milliseconds;
136
- volume = targetVolume + (rampRange * remaining);
137
- this._player.volume = volume;
138
- this._inRamp = true;
139
- } else if (this._inRamp) {
140
- // We're at the end of a ramp
141
- volume = targetVolume;
142
- this._player.volume = volume;
143
- this._inRamp = false;
144
- }
145
- }
146
-
147
- // Schedule next animation frame
148
- this.scheduleAnimationFrame(adjustVolume);
149
- } else {
150
- // Reset volume to original level
151
- this._player.volume = this._startVolume;
152
- this._running = false;
153
- this._endTime = 0;
154
- this._startTime = 0;
155
- this._startVolume = 0;
156
- }
157
- };
158
-
159
- this._running = true;
160
- this._startTime = new Date().getTime();
161
- this._startVolume = this._player.volume;
162
- this.scheduleAnimationFrame(adjustVolume)
163
- }
164
-
165
- private scheduleAnimationFrame(callback: FrameRequestCallback): void {
166
- if (requestAnimationFrame) {
167
- requestAnimationFrame(callback);
168
- } else {
169
- setTimeout(callback, 20);
170
- }
171
- }
172
-
173
- private computeTargetVolume(): number {
174
- switch (this._levelType) {
175
- case LevelType.percentage:
176
- return this._startVolume * this._level;
177
- case LevelType.fixed:
178
- default:
179
- return this._level;
180
- }
181
- }
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the Microsoft Live Share SDK License.
4
+ */
5
+
6
+ import { TimeInterval } from '@microsoft/live-share';
7
+ import { IMediaPlayer } from './IMediaPlayer';
8
+
9
+ export enum LevelType { fixed, percentage }
10
+
11
+ export class VolumeLimiter {
12
+ private readonly _player: IMediaPlayer;
13
+
14
+ // Settings
15
+ private readonly _duration = new TimeInterval(2000);
16
+ private readonly _rampDownDuration = new TimeInterval(500);
17
+ private readonly _rampUpDuration = new TimeInterval(500);
18
+ private _level: number = 0.1
19
+ private _levelType: LevelType = LevelType.fixed;
20
+
21
+ // Running state
22
+ private _running = false;
23
+ private _endTime = 0;
24
+ private _startTime = 0;
25
+ private _startVolume = 0;
26
+ private _inRamp = false;
27
+
28
+ constructor(player: IMediaPlayer) {
29
+ this._player = player;
30
+ }
31
+
32
+ /**
33
+ * Time, in seconds, that the volume should be lowered.
34
+ *
35
+ * @remarks
36
+ * Applications should periodically call `lowerVolume()` to keep the volume lowered.
37
+ */
38
+ public get duration(): number {
39
+ return this._duration.seconds;
40
+ }
41
+
42
+ public set duration(value: number) {
43
+ this._duration.seconds = Math.abs(value);
44
+ }
45
+
46
+ /**
47
+ * Target level to lower volume to.
48
+ *
49
+ * @remarks
50
+ * Expressed as a value between 0.0 and 1.0. The value is applied based upon the configured
51
+ * `levelType`. The default value is 0.2.
52
+ *
53
+ * For a level type of `LevelType.fixed` the value is the exact level the volume will be
54
+ * lowered to. The default value of 0.2 would cause the volume to be lowered to 0.2.
55
+ *
56
+ * For a level type of `LevelType.percentage` the value is the percentage by which the volume
57
+ * level should be lowered to. The default value of 0.2 would cause the volume to be lowered
58
+ * to 20% of its starting value.
59
+ */
60
+ public get level(): number {
61
+ return this._level;
62
+ }
63
+
64
+ public set level(value: number) {
65
+ if (value < 0 || value > 1.0) {
66
+ throw new Error(`VolumeLimiter: cannot set level to ${value}. Level must be between 0.0 and 1.0.`);
67
+ }
68
+
69
+ this._level = value;
70
+ }
71
+
72
+ /**
73
+ * The type of level represented by the `level` property.
74
+ */
75
+ public get levelType(): LevelType {
76
+ return this._levelType;
77
+ }
78
+
79
+ public set levelType(value: LevelType) {
80
+ this._levelType = value;
81
+ }
82
+
83
+ /**
84
+ * Amount of time, in seconds, it should take to ramp the volume down to the desired level.
85
+ */
86
+ public get rampDownDuration(): number {
87
+ return this._rampDownDuration.seconds;
88
+ }
89
+
90
+ public set rampDownDuration(value: number) {
91
+ this._rampDownDuration.seconds = Math.abs(value);
92
+ }
93
+
94
+ /**
95
+ * Amount of time, in seconds, it should take to ramp the volume back up to the original level.
96
+ */
97
+ public get rampUpDuration(): number {
98
+ return this._rampUpDuration.seconds;
99
+ }
100
+
101
+ public set rampUpDuration(value: number) {
102
+ this._rampUpDuration.seconds = Math.abs(value);
103
+ }
104
+
105
+ /**
106
+ * Temporarily lowers an audio sources volume.
107
+ */
108
+ public lowerVolume(): void {
109
+ this._endTime = new Date().getTime() + this._duration.milliseconds;
110
+ if (!this._running) {
111
+ this.startLimiter();
112
+ }
113
+ }
114
+
115
+ private startLimiter(): void {
116
+ const adjustVolume = () => {
117
+ const now = new Date().getTime();
118
+ if (now < this._endTime) {
119
+ // Make no adjustment if muted
120
+ if (!this._player.muted) {
121
+ // Compute adjusted volume level
122
+ let volume: number;
123
+ const targetVolume = this.computeTargetVolume();
124
+ const rampRange = this._startVolume - targetVolume;
125
+ const rampUpStart = this._endTime - this._rampUpDuration.milliseconds;
126
+ const rampDownEnd = this._startTime + this._rampDownDuration.milliseconds;
127
+ if (now > rampUpStart) {
128
+ // We're about to end so ramping up
129
+ const progress = (now - rampUpStart) / this._rampUpDuration.milliseconds;
130
+ volume = targetVolume + (rampRange * progress);
131
+ this._player.volume = volume;
132
+ this._inRamp = true;
133
+ } else if (now < rampDownEnd) {
134
+ // We just begun so ramping down
135
+ const remaining = (rampDownEnd - now) / this._rampUpDuration.milliseconds;
136
+ volume = targetVolume + (rampRange * remaining);
137
+ this._player.volume = volume;
138
+ this._inRamp = true;
139
+ } else if (this._inRamp) {
140
+ // We're at the end of a ramp
141
+ volume = targetVolume;
142
+ this._player.volume = volume;
143
+ this._inRamp = false;
144
+ }
145
+ }
146
+
147
+ // Schedule next animation frame
148
+ this.scheduleAnimationFrame(adjustVolume);
149
+ } else {
150
+ // Reset volume to original level
151
+ this._player.volume = this._startVolume;
152
+ this._running = false;
153
+ this._endTime = 0;
154
+ this._startTime = 0;
155
+ this._startVolume = 0;
156
+ }
157
+ };
158
+
159
+ this._running = true;
160
+ this._startTime = new Date().getTime();
161
+ this._startVolume = this._player.volume;
162
+ this.scheduleAnimationFrame(adjustVolume)
163
+ }
164
+
165
+ private scheduleAnimationFrame(callback: FrameRequestCallback): void {
166
+ if (requestAnimationFrame) {
167
+ requestAnimationFrame(callback);
168
+ } else {
169
+ setTimeout(callback, 20);
170
+ }
171
+ }
172
+
173
+ private computeTargetVolume(): number {
174
+ switch (this._levelType) {
175
+ case LevelType.percentage:
176
+ return this._startVolume * this._level;
177
+ case LevelType.fixed:
178
+ default:
179
+ return this._level;
180
+ }
181
+ }
182
182
  }
package/src/index.ts CHANGED
@@ -1,15 +1,15 @@
1
- /**
2
- * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Licensed under the Microsoft Live Share SDK License.
4
- */
5
-
6
-
7
- export * from './EphemeralMediaSession';
8
- export * from './EphemeralMediaSessionCoordinator';
9
- export * from './EphemeralMediaSessionCoordinatorSuspension';
10
- export * from './IMediaPlayer';
11
- export * from './MediaPlayerSynchronizer';
12
- export * from './MediaSessionActionThrottler';
13
- export * from './MediaSessionExtensions';
14
- export * from './RepeatedActionThrottler';
15
- export * from './VolumeLimiter';
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the Microsoft Live Share SDK License.
4
+ */
5
+
6
+
7
+ export * from './EphemeralMediaSession';
8
+ export * from './EphemeralMediaSessionCoordinator';
9
+ export * from './EphemeralMediaSessionCoordinatorSuspension';
10
+ export * from './IMediaPlayer';
11
+ export * from './MediaPlayerSynchronizer';
12
+ export * from './MediaSessionActionThrottler';
13
+ export * from './MediaSessionExtensions';
14
+ export * from './RepeatedActionThrottler';
15
+ export * from './VolumeLimiter';