@clockworkdog/cogs-client 3.0.0-alpha.9 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +20 -9
  2. package/dist/CogsConnection.d.ts +0 -4
  3. package/dist/CogsConnection.js +0 -10
  4. package/dist/browser/index.mjs +1901 -2707
  5. package/dist/browser/index.umd.js +13 -13
  6. package/dist/index.d.ts +1 -5
  7. package/dist/index.js +1 -3
  8. package/dist/state-based/MediaClipManager.d.ts +66 -0
  9. package/dist/state-based/MediaClipManager.js +420 -0
  10. package/dist/state-based/MediaPreloader.d.ts +14 -0
  11. package/dist/state-based/MediaPreloader.js +93 -0
  12. package/dist/state-based/SurfaceManager.d.ts +8 -1
  13. package/dist/state-based/SurfaceManager.js +36 -9
  14. package/dist/types/MediaSchema.d.ts +6 -0
  15. package/dist/types/MediaSchema.js +2 -0
  16. package/dist/utils/device.d.ts +2 -0
  17. package/dist/utils/device.js +4 -0
  18. package/dist/utils/getStateAtTime.d.ts +12 -2
  19. package/dist/utils/getStateAtTime.js +6 -1
  20. package/dist/utils/modulo.d.ts +6 -0
  21. package/dist/utils/modulo.js +17 -0
  22. package/package.json +3 -6
  23. package/dist/AudioPlayer.d.ts +0 -49
  24. package/dist/AudioPlayer.js +0 -474
  25. package/dist/VideoPlayer.d.ts +0 -49
  26. package/dist/VideoPlayer.js +0 -385
  27. package/dist/state-based/AudioManager.d.ts +0 -15
  28. package/dist/state-based/AudioManager.js +0 -116
  29. package/dist/state-based/ClipManager.d.ts +0 -22
  30. package/dist/state-based/ClipManager.js +0 -53
  31. package/dist/state-based/ImageManager.d.ts +0 -9
  32. package/dist/state-based/ImageManager.js +0 -53
  33. package/dist/state-based/VideoManager.d.ts +0 -15
  34. package/dist/state-based/VideoManager.js +0 -129
  35. package/dist/types/AllMediaClipStatesMessage.d.ts +0 -5
  36. package/dist/types/AllMediaClipStatesMessage.js +0 -1
  37. package/dist/types/AudioState.d.ts +0 -39
  38. package/dist/types/AudioState.js +0 -1
  39. package/dist/types/MediaClipStateMessage.d.ts +0 -7
  40. package/dist/types/MediaClipStateMessage.js +0 -1
  41. package/dist/types/VideoState.d.ts +0 -26
  42. package/dist/types/VideoState.js +0 -5
@@ -1,129 +0,0 @@
1
- import { defaultVideoOptions } from '../types/MediaSchema';
2
- import { getStateAtTime } from '../utils/getStateAtTime';
3
- import { ClipManager } from './ClipManager';
4
- const NO_VIDEO_POLLING = 1_000;
5
- const VIDEO_PLAYBACK_POLLING = 100;
6
- const SEEKING_POLLING = 10;
7
- const TARGET_SYNC_THRESHOLD_MS = 10; // If we're closer than this we're good enough
8
- const MAX_SYNC_THRESHOLD_MS = 1_000; // If we're further away than this, we'll seek instead
9
- const SEEK_LOOKAHEAD_MS = 200; // We won't seek ahead instantly, so lets seek ahead
10
- const MAX_PLAYBACK_RATE_ADJUSTMENT = 0.5;
11
- // We smoothly ramp playbackRate up and down
12
- const PLAYBACK_ADJUSTMENT_SMOOTHING = 0.3;
13
- function playbackSmoothing(deltaTime) {
14
- return Math.sign(deltaTime) * Math.pow(Math.abs(deltaTime) / MAX_SYNC_THRESHOLD_MS, PLAYBACK_ADJUSTMENT_SMOOTHING) * MAX_PLAYBACK_RATE_ADJUSTMENT;
15
- }
16
- export class VideoManager extends ClipManager {
17
- videoElement;
18
- isSeeking = false;
19
- constructor(surfaceElement, clipElement, state) {
20
- super(surfaceElement, clipElement, state);
21
- this.clipElement = clipElement;
22
- }
23
- updateVideoElement() {
24
- this.destroy();
25
- this.videoElement = document.createElement('video');
26
- this.clipElement.replaceChildren(this.videoElement);
27
- this.videoElement.style.position = 'absolute';
28
- this.videoElement.style.width = '100%';
29
- this.videoElement.style.height = '100%';
30
- }
31
- /**
32
- * Helper function to seek to a specified time.
33
- * Works with the update loop to poll until seeked event has fired.
34
- */
35
- seekTo(ms) {
36
- if (!this.videoElement)
37
- return;
38
- this.delay = SEEKING_POLLING;
39
- this.isSeeking = true;
40
- this.videoElement.addEventListener('seeked', () => {
41
- this.isSeeking = false;
42
- }, { once: true, passive: true });
43
- this.videoElement.currentTime = ms / 1_000;
44
- }
45
- update() {
46
- // Update loop used to poll until seek finished
47
- if (this.isSeeking)
48
- return;
49
- this.delay = NO_VIDEO_POLLING;
50
- // Does the <video /> element need adding/removing?
51
- const currentState = getStateAtTime(this._state, Date.now());
52
- if (currentState) {
53
- if (!this.videoElement || !this.isConnected(this.videoElement)) {
54
- this.updateVideoElement();
55
- }
56
- }
57
- else {
58
- this.videoElement?.remove();
59
- this.videoElement = undefined;
60
- }
61
- if (!currentState || !this.videoElement)
62
- return;
63
- const { t, rate, volume } = { ...defaultVideoOptions, ...currentState };
64
- // this.videoElement.src will be a fully qualified URL
65
- if (!this.videoElement.src.endsWith(this._state.file)) {
66
- this.videoElement.src = this._state.file;
67
- }
68
- if (this.videoElement.style.objectFit !== this._state.fit) {
69
- this.videoElement.style.objectFit = this._state.fit;
70
- }
71
- const opacityString = String(currentState.opacity);
72
- if (this.videoElement.style.opacity !== opacityString) {
73
- this.videoElement.style.opacity = opacityString;
74
- }
75
- const zIndex = Math.round(currentState.zIndex ?? defaultVideoOptions.zIndex);
76
- if (parseInt(this.videoElement.style.zIndex) !== zIndex) {
77
- this.videoElement.style.zIndex = String(zIndex);
78
- }
79
- if (this.videoElement.volume !== volume) {
80
- this.videoElement.volume = volume;
81
- }
82
- // Should the element be playing?
83
- if (this.videoElement.paused && rate > 0) {
84
- this.videoElement.play().catch(() => {
85
- // Do nothing - this will be retried in the next loop
86
- });
87
- }
88
- const currentTime = this.videoElement.currentTime * 1000;
89
- const deltaTime = currentTime - t;
90
- const deltaTimeAbs = Math.abs(deltaTime);
91
- this.delay = VIDEO_PLAYBACK_POLLING;
92
- switch (true) {
93
- case deltaTimeAbs <= TARGET_SYNC_THRESHOLD_MS:
94
- // We are on course:
95
- // - The video is within accepted latency of the server time
96
- // - The playback rate is aligned with the server rate
97
- if (this.videoElement.playbackRate !== rate) {
98
- this.videoElement.playbackRate = rate;
99
- }
100
- break;
101
- case rate > 0 && deltaTimeAbs > TARGET_SYNC_THRESHOLD_MS && deltaTimeAbs <= MAX_SYNC_THRESHOLD_MS: {
102
- // We are close, we can smoothly adjust with playbackRate:
103
- // - The video must be playing
104
- // - We must be close in time to the server time
105
- const playbackRateAdjustment = playbackSmoothing(deltaTime);
106
- const adjustedPlaybackRate = Math.max(0, rate - playbackRateAdjustment);
107
- if (this.videoElement.playbackRate !== adjustedPlaybackRate) {
108
- this.videoElement.playbackRate = adjustedPlaybackRate;
109
- }
110
- break;
111
- }
112
- default: {
113
- // We cannot smoothly recover:
114
- // - We seek just ahead of server time
115
- if (this.videoElement.playbackRate !== rate) {
116
- this.videoElement.playbackRate = rate;
117
- }
118
- this.seekTo(t + rate * SEEK_LOOKAHEAD_MS);
119
- break;
120
- }
121
- }
122
- }
123
- destroy() {
124
- if (this.videoElement) {
125
- this.videoElement.src = '';
126
- this.videoElement.remove();
127
- }
128
- }
129
- }
@@ -1,5 +0,0 @@
1
- export type MediaStatus = 'playing' | 'paused' | 'stopped';
2
- export default interface AllMediaClipStatesMessage {
3
- mediaType: 'audio' | 'video';
4
- files: [string, MediaStatus][];
5
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,39 +0,0 @@
1
- export type ActiveAudioClipState = {
2
- type: 'paused';
3
- } | {
4
- type: 'pause_requested';
5
- fade: number | undefined;
6
- } | {
7
- type: 'pausing';
8
- } | {
9
- type: 'playing';
10
- } | {
11
- type: 'play_requested';
12
- } | {
13
- type: 'stopping';
14
- } | {
15
- type: 'stop_requested';
16
- fade: number | undefined;
17
- };
18
- export interface AudioClip {
19
- config: {
20
- preload: boolean;
21
- ephemeral: boolean;
22
- };
23
- activeClips: {
24
- [soundId: number]: ActiveClip;
25
- };
26
- }
27
- export interface ActiveClip {
28
- state: ActiveAudioClipState;
29
- loop: boolean;
30
- volume: number;
31
- playId: string;
32
- }
33
- export interface AudioState {
34
- isPlaying: boolean;
35
- globalVolume: number;
36
- clips: {
37
- [path: string]: AudioClip;
38
- };
39
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,7 +0,0 @@
1
- export type MediaStatus = 'playing' | 'paused' | 'stopped';
2
- export default interface MediaClipStateMessage {
3
- playId: string;
4
- mediaType: 'audio' | 'video';
5
- file: string;
6
- status: MediaStatus;
7
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,26 +0,0 @@
1
- import { MediaObjectFit } from '..';
2
- export declare enum ActiveVideoClipState {
3
- Paused = "paused",
4
- Playing = "playing"
5
- }
6
- export interface VideoClip {
7
- config: {
8
- preload: 'auto' | 'metadata' | 'none';
9
- ephemeral: boolean;
10
- fit: MediaObjectFit;
11
- };
12
- }
13
- export interface ActiveClip {
14
- path: string;
15
- state: ActiveVideoClipState;
16
- loop: boolean;
17
- volume: number;
18
- }
19
- export interface VideoState {
20
- isPlaying: boolean;
21
- globalVolume: number;
22
- clips: {
23
- [path: string]: VideoClip;
24
- };
25
- activeClip?: ActiveClip;
26
- }
@@ -1,5 +0,0 @@
1
- export var ActiveVideoClipState;
2
- (function (ActiveVideoClipState) {
3
- ActiveVideoClipState["Paused"] = "paused";
4
- ActiveVideoClipState["Playing"] = "playing";
5
- })(ActiveVideoClipState || (ActiveVideoClipState = {}));