@readium/navigator 1.2.0
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/LICENSE +28 -0
- package/README.MD +11 -0
- package/dist/assets/AccessibleDfA.otf +0 -0
- package/dist/assets/iAWriterDuospace-Regular.ttf +0 -0
- package/dist/index.js +6263 -0
- package/dist/index.umd.cjs +107 -0
- package/package.json +65 -0
- package/src/Navigator.ts +66 -0
- package/src/audio/engine/AudioEngine.ts +136 -0
- package/src/audio/engine/WebAudioEngine.ts +286 -0
- package/src/audio/engine/index.ts +2 -0
- package/src/audio/index.ts +1 -0
- package/src/epub/EpubNavigator.ts +507 -0
- package/src/epub/frame/FrameBlobBuilder.ts +211 -0
- package/src/epub/frame/FrameComms.ts +142 -0
- package/src/epub/frame/FrameManager.ts +134 -0
- package/src/epub/frame/FramePoolManager.ts +179 -0
- package/src/epub/frame/index.ts +3 -0
- package/src/epub/fxl/FXLCoordinator.ts +152 -0
- package/src/epub/fxl/FXLFrameManager.ts +286 -0
- package/src/epub/fxl/FXLFramePoolManager.ts +632 -0
- package/src/epub/fxl/FXLPeripherals.ts +587 -0
- package/src/epub/fxl/FXLPeripheralsDebug.ts +46 -0
- package/src/epub/fxl/FXLSpreader.ts +95 -0
- package/src/epub/fxl/index.ts +5 -0
- package/src/epub/index.ts +3 -0
- package/src/helpers/sML.ts +120 -0
- package/src/index.ts +3 -0
- package/types/src/Navigator.d.ts +41 -0
- package/types/src/audio/engine/AudioEngine.d.ts +114 -0
- package/types/src/audio/engine/WebAudioEngine.d.ts +107 -0
- package/types/src/audio/engine/index.d.ts +2 -0
- package/types/src/audio/index.d.ts +1 -0
- package/types/src/epub/EpubNavigator.d.ts +66 -0
- package/types/src/epub/frame/FrameBlobBuilder.d.ts +13 -0
- package/types/src/epub/frame/FrameComms.d.ts +26 -0
- package/types/src/epub/frame/FrameManager.d.ts +21 -0
- package/types/src/epub/frame/FramePoolManager.d.ts +17 -0
- package/types/src/epub/frame/index.d.ts +3 -0
- package/types/src/epub/fxl/FXLCoordinator.d.ts +37 -0
- package/types/src/epub/fxl/FXLFrameManager.d.ts +41 -0
- package/types/src/epub/fxl/FXLFramePoolManager.d.ts +93 -0
- package/types/src/epub/fxl/FXLPeripherals.d.ts +97 -0
- package/types/src/epub/fxl/FXLPeripheralsDebug.d.ts +13 -0
- package/types/src/epub/fxl/FXLSpreader.d.ts +12 -0
- package/types/src/epub/fxl/index.d.ts +5 -0
- package/types/src/epub/index.d.ts +3 -0
- package/types/src/helpers/sML.d.ts +51 -0
- package/types/src/index.d.ts +3 -0
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@readium/navigator",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Next generation SDK for publications in Web Apps",
|
|
6
|
+
"author": "readium",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/readium/ts-toolkit.git",
|
|
10
|
+
"directory": "navigator"
|
|
11
|
+
},
|
|
12
|
+
"license": "BSD-3-Clause",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/readium/ts-toolkit/issues"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/readium/ts-toolkit",
|
|
17
|
+
"keywords": [
|
|
18
|
+
"readium",
|
|
19
|
+
"epub",
|
|
20
|
+
"webpub",
|
|
21
|
+
"divina",
|
|
22
|
+
"reflowable",
|
|
23
|
+
"fixed-layout",
|
|
24
|
+
"publication",
|
|
25
|
+
"ebook",
|
|
26
|
+
"reader",
|
|
27
|
+
"viewer"
|
|
28
|
+
],
|
|
29
|
+
"main": "./dist/index.umd.cjs",
|
|
30
|
+
"module": "./dist/index.js",
|
|
31
|
+
"types": "./types/src/index.d.ts",
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"import": "./dist/index.js",
|
|
35
|
+
"require": "./dist/index.umd.cjs",
|
|
36
|
+
"types": "./types/src/index.d.ts"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"dist",
|
|
41
|
+
"src",
|
|
42
|
+
"types"
|
|
43
|
+
],
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@laynezh/vite-plugin-lib-assets": "^0.5.24",
|
|
49
|
+
"@readium/navigator-html-injectables": "0.0.1",
|
|
50
|
+
"@readium/shared": "1.2.0",
|
|
51
|
+
"@types/path-browserify": "^1.0.0",
|
|
52
|
+
"css-selector-generator": "^3.6.4",
|
|
53
|
+
"readium-css": "github:readium/readium-css",
|
|
54
|
+
"tslib": "^2.5.2",
|
|
55
|
+
"typescript": "^5.4.5",
|
|
56
|
+
"typescript-plugin-css-modules": "^5.1.0",
|
|
57
|
+
"vite": "^4.4.9"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"path-browserify": "^1.0.1"
|
|
61
|
+
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"build": "tsc && vite build"
|
|
64
|
+
}
|
|
65
|
+
}
|
package/src/Navigator.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Link, Locator, Publication, ReadingProgression } from "@readium/shared";
|
|
2
|
+
|
|
3
|
+
type cbb = (ok: boolean) => void;
|
|
4
|
+
|
|
5
|
+
export abstract class Navigator {
|
|
6
|
+
abstract get publication(): Publication; // Publication rendered by this navigator.
|
|
7
|
+
abstract get currentLocator(): Locator; // Current position (detailed) in the publication. Can be used to save a bookmark to the current position.
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Moves to the position in the publication corresponding to the given {Locator}.
|
|
11
|
+
*/
|
|
12
|
+
abstract go(locator: Locator, animated: boolean, cb: cbb): void;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Moves to the position in the publication targeted by the given link.
|
|
16
|
+
*/
|
|
17
|
+
abstract goLink(link: Link, animated: boolean, cb: cbb): void;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Moves to the next content portion (eg. page) in the reading progression direction.
|
|
21
|
+
*/
|
|
22
|
+
abstract goForward(animated: boolean, cb: cbb): void;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Moves to the previous content portion (eg. page) in the reading progression direction.
|
|
26
|
+
*/
|
|
27
|
+
abstract goBackward(animated: boolean, cb: cbb): void;
|
|
28
|
+
|
|
29
|
+
// TODO listener
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Destroy all resources associated with this navigator. Synonymous with "unmount"
|
|
33
|
+
*/
|
|
34
|
+
abstract destroy(): void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export abstract class VisualNavigator extends Navigator {
|
|
38
|
+
/**
|
|
39
|
+
* Current reading progression direction.
|
|
40
|
+
*/
|
|
41
|
+
abstract get readingProgression(): ReadingProgression;
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Moves to the left content portion (eg. page) relative to the reading progression direction.
|
|
46
|
+
*/
|
|
47
|
+
goLeft(animated = false, completion: cbb) {
|
|
48
|
+
if(this.readingProgression === ReadingProgression.ltr || this.readingProgression === ReadingProgression.ttb || this.readingProgression === ReadingProgression.auto)
|
|
49
|
+
this.goBackward(animated, completion);
|
|
50
|
+
else if(this.readingProgression === ReadingProgression.rtl || this.readingProgression === ReadingProgression.btt)
|
|
51
|
+
this.goForward(animated, completion);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Moves to the right content portion (eg. page) relative to the reading progression direction.
|
|
56
|
+
*/
|
|
57
|
+
goRight(animated = false, completion: cbb) {
|
|
58
|
+
if(this.readingProgression === ReadingProgression.ltr || this.readingProgression === ReadingProgression.ttb || this.readingProgression === ReadingProgression.auto)
|
|
59
|
+
this.goForward(animated, completion);
|
|
60
|
+
else if(this.readingProgression === ReadingProgression.rtl || this.readingProgression === ReadingProgression.btt)
|
|
61
|
+
this.goBackward(animated, completion);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
// TODO MediaNavigator
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { Locator } from '@readium/shared';
|
|
2
|
+
import { Publication } from '@readium/shared';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Initial state of the audio engine playback.
|
|
6
|
+
*/
|
|
7
|
+
export interface PlaybackState {
|
|
8
|
+
/**
|
|
9
|
+
* The current time of the audio resource.
|
|
10
|
+
*/
|
|
11
|
+
currentTime: number;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The duration of the audio resource.
|
|
15
|
+
*/
|
|
16
|
+
duration: number;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The volume of the audio resource.
|
|
20
|
+
*/
|
|
21
|
+
volume: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Playback interface for an audio engine state
|
|
26
|
+
* @state The initial [PlaybackState].
|
|
27
|
+
* @playWhenReady Indicates if the navigator should play as soon as the state is Ready.
|
|
28
|
+
* @index Index of the reading order item currently being played.
|
|
29
|
+
* @offset Position of the playback in the current item.
|
|
30
|
+
* @buffered Position in the current item until which the content is buffered.
|
|
31
|
+
*
|
|
32
|
+
*/
|
|
33
|
+
export interface Playback {
|
|
34
|
+
state: PlaybackState;
|
|
35
|
+
playWhenReady: boolean;
|
|
36
|
+
index: number;
|
|
37
|
+
offset?: number;
|
|
38
|
+
buffered?: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* An audio engine that plays audio resources from a publication.
|
|
43
|
+
* @playback - The current [Playback] state.
|
|
44
|
+
*/
|
|
45
|
+
export interface AudioEngine {
|
|
46
|
+
/**
|
|
47
|
+
* The current playback state.
|
|
48
|
+
*/
|
|
49
|
+
playback: Playback;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Plays the audio resource at the given locator.
|
|
53
|
+
*/
|
|
54
|
+
playLocator(publication: Publication, locator: Locator): Promise<void>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Adds an event listener to the audio engine.
|
|
58
|
+
* @param event The event name to listen.
|
|
59
|
+
* @param callback Callback function to be called when the event is triggered.
|
|
60
|
+
*/
|
|
61
|
+
on(event: string, callback: (data: any) => void): void;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Removes an event listener from the audio engine.
|
|
65
|
+
* @param event The event name to remove the listener.
|
|
66
|
+
* @param callback Callback function to be removed.
|
|
67
|
+
*/
|
|
68
|
+
off(event: string, callback: (data: any) => void): void;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Loads the audio resource at the given URL.
|
|
72
|
+
* @param url The URL of the audio resource.
|
|
73
|
+
*/
|
|
74
|
+
loadAudio(url: string): void;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Plays the current audio resource.
|
|
78
|
+
*/
|
|
79
|
+
play(): void;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Pauses the currently playing audio resource.
|
|
83
|
+
*/
|
|
84
|
+
pause(): void;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Stops the currently playing audio resource.
|
|
88
|
+
*/
|
|
89
|
+
stop(): void;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Skips [duration] either forward or backward if [duration] is negative.
|
|
93
|
+
*/
|
|
94
|
+
skip(duration: number): void;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Returns the duration of the audio resource.
|
|
98
|
+
*/
|
|
99
|
+
duration(): number;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Returns whether the audio resource is currently playing.
|
|
103
|
+
*/
|
|
104
|
+
isPlaying(): boolean;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Returns whether the audio resource is currently paused.
|
|
108
|
+
*/
|
|
109
|
+
isPaused(): boolean;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Returns whether the audio resource is currently stopped.
|
|
113
|
+
*/
|
|
114
|
+
isStopped(): boolean;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Returns whether the audio resource is currently loading.
|
|
118
|
+
*/
|
|
119
|
+
isLoading(): boolean;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Returns whether the audio resource is currently loaded.
|
|
123
|
+
*/
|
|
124
|
+
isLoaded(): boolean;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Returns whether the audio resource is currently ended.
|
|
128
|
+
*/
|
|
129
|
+
isEnded(): boolean;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Returns whether the audio resource is currently muted.
|
|
133
|
+
*/
|
|
134
|
+
isMuted(): boolean;
|
|
135
|
+
|
|
136
|
+
}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/* Implements the AudioEngine interface using the Web Audio API. */
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
AudioEngine,
|
|
5
|
+
Playback,
|
|
6
|
+
} from "./AudioEngine";
|
|
7
|
+
|
|
8
|
+
import { Publication } from "@readium/shared";
|
|
9
|
+
import { Locator } from "@readium/shared";
|
|
10
|
+
|
|
11
|
+
type EventCallback = (data: any) => void;
|
|
12
|
+
|
|
13
|
+
export class WebAudioEngine implements AudioEngine {
|
|
14
|
+
/* Defines the current playback state. */
|
|
15
|
+
public readonly playback: Playback;
|
|
16
|
+
private audioContext: AudioContext;
|
|
17
|
+
private mediaElement: HTMLAudioElement;
|
|
18
|
+
private sourceNode: MediaElementAudioSourceNode | null = null;
|
|
19
|
+
private gainNode: GainNode;
|
|
20
|
+
private listeners: { [event: string]: EventCallback[] } = {};
|
|
21
|
+
private isMutedValue: boolean = false;
|
|
22
|
+
private isPlayingValue: boolean = false;
|
|
23
|
+
private isPausedValue: boolean = false;
|
|
24
|
+
private isLoadingValue: boolean = false;
|
|
25
|
+
private isLoadedValue: boolean = false;
|
|
26
|
+
private isEndedValue: boolean = false;
|
|
27
|
+
|
|
28
|
+
constructor(values: { playback: Playback; audioContext: AudioContext }) {
|
|
29
|
+
this.playback = values.playback;
|
|
30
|
+
this.audioContext = values.audioContext;
|
|
31
|
+
this.gainNode = this.audioContext?.createGain();
|
|
32
|
+
this.setVolume(this.playback.state.volume); // Default initial volume
|
|
33
|
+
|
|
34
|
+
// Create an HTML audio element
|
|
35
|
+
this.mediaElement = document.createElement("audio");
|
|
36
|
+
this.mediaElement.crossOrigin = "use-credentials"; // Optional: Handle cross-origin audio files
|
|
37
|
+
|
|
38
|
+
// Event listeners (to report the client app about some async events)
|
|
39
|
+
this.mediaElement.addEventListener(
|
|
40
|
+
"canplaythrough",
|
|
41
|
+
this.onCanPlayThrough.bind(this)
|
|
42
|
+
);
|
|
43
|
+
this.mediaElement.addEventListener(
|
|
44
|
+
"timeupdate",
|
|
45
|
+
this.onTimeUpdate.bind(this)
|
|
46
|
+
);
|
|
47
|
+
this.mediaElement.addEventListener("error", this.onError.bind(this));
|
|
48
|
+
this.mediaElement.addEventListener("ended", this.onEnded.bind(this));
|
|
49
|
+
|
|
50
|
+
//Set the start time
|
|
51
|
+
this.mediaElement.currentTime = this.playback.state.currentTime;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Adds an event listener to the audio engine.
|
|
56
|
+
* @param event - event name to be listened.
|
|
57
|
+
* @param callback - callback function to be called when the event is triggered.
|
|
58
|
+
*/
|
|
59
|
+
public on(event: string, callback: EventCallback) {
|
|
60
|
+
if (!this.listeners[event]) {
|
|
61
|
+
this.listeners[event] = [];
|
|
62
|
+
}
|
|
63
|
+
this.listeners[event].push(callback);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Removes an event listener from the audio engine.
|
|
68
|
+
* @param event - event name to be removed from the listeners.
|
|
69
|
+
* @param callback - callback function to be removed.
|
|
70
|
+
*/
|
|
71
|
+
public off(event: string, callback: EventCallback) {
|
|
72
|
+
if (!this.listeners[event]) return;
|
|
73
|
+
this.listeners[event] = this.listeners[event].filter(
|
|
74
|
+
(cb) => cb !== callback
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Load the audio resource at the given URL.
|
|
80
|
+
* @param url The URL of the audio resource.
|
|
81
|
+
* */
|
|
82
|
+
public loadAudio(url: string): void {
|
|
83
|
+
this.isLoadingValue = true;
|
|
84
|
+
this.mediaElement.src = url;
|
|
85
|
+
this.mediaElement.load();
|
|
86
|
+
|
|
87
|
+
// Create a new source node only if it doesn't exist
|
|
88
|
+
if (!this.sourceNode) {
|
|
89
|
+
this.sourceNode = new MediaElementAudioSourceNode(this.audioContext, {
|
|
90
|
+
mediaElement: this.mediaElement,
|
|
91
|
+
});
|
|
92
|
+
this.sourceNode.connect(this.gainNode);
|
|
93
|
+
this.gainNode.connect(this.audioContext.destination);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Ensure AudioContext is running
|
|
98
|
+
private async ensureAudioContextRunning() {
|
|
99
|
+
if (this.audioContext.state === "suspended") {
|
|
100
|
+
await this.audioContext.resume();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Event handler for timeupdate
|
|
105
|
+
private onTimeUpdate() {
|
|
106
|
+
// Continuously track the current time of the media element
|
|
107
|
+
// You can update UI elements or perform other tasks here
|
|
108
|
+
this.emit("timeupdate", this.mediaElement.currentTime);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Event handler for canplaythrough
|
|
112
|
+
private onCanPlayThrough() {
|
|
113
|
+
this.isLoadingValue = false;
|
|
114
|
+
this.isLoadedValue = true;
|
|
115
|
+
this.emit("canplaythrough", null);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Event handler for error
|
|
119
|
+
private onError() {
|
|
120
|
+
console.error("Error loading media element");
|
|
121
|
+
this.emit("error", this.mediaElement.error);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Event handle for ended
|
|
125
|
+
private onEnded() {
|
|
126
|
+
this.isPlayingValue = false;
|
|
127
|
+
this.isPausedValue = false;
|
|
128
|
+
this.isEndedValue = true;
|
|
129
|
+
this.emit("ended", null);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Used to emit some events like timeupdate or ended
|
|
133
|
+
private emit(event: string, data: any) {
|
|
134
|
+
if (!this.listeners[event]) return;
|
|
135
|
+
this.listeners[event].forEach((callback) => callback(data));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Plays the audio resource at the given locator.
|
|
140
|
+
*/
|
|
141
|
+
public async playLocator(
|
|
142
|
+
_publication: Publication,
|
|
143
|
+
_locator: Locator
|
|
144
|
+
): Promise<void> {
|
|
145
|
+
// Implementation details.
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Plays the current audio resource.
|
|
150
|
+
*/
|
|
151
|
+
public async play(): Promise<void> {
|
|
152
|
+
await this.ensureAudioContextRunning();
|
|
153
|
+
|
|
154
|
+
if (this.isPlayingValue) {
|
|
155
|
+
this.stop();
|
|
156
|
+
console.error("Audio is already playing");
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
await this.mediaElement.play();
|
|
162
|
+
this.isPlayingValue = true;
|
|
163
|
+
this.isPausedValue = false;
|
|
164
|
+
} catch (err) {
|
|
165
|
+
console.error("error trying to play media element", err);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Pauses the currently playing audio resource.
|
|
171
|
+
*/
|
|
172
|
+
public pause(): void {
|
|
173
|
+
this.mediaElement.pause();
|
|
174
|
+
this.isPlayingValue = false;
|
|
175
|
+
this.isPausedValue = true;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Stops the currently playing audio resource.
|
|
180
|
+
*/
|
|
181
|
+
public stop(): void {
|
|
182
|
+
// Stop the audio and reset the current time
|
|
183
|
+
this.mediaElement.pause();
|
|
184
|
+
this.mediaElement.currentTime = 0;
|
|
185
|
+
this.isPlayingValue = false;
|
|
186
|
+
this.isPausedValue = false;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Adjusts the [volume] of the audio resource.
|
|
191
|
+
* @volume The volume to set, in the range [0, 1].
|
|
192
|
+
*/
|
|
193
|
+
public setVolume(volume: number): void {
|
|
194
|
+
if (volume < 0) {
|
|
195
|
+
this.gainNode.gain.value = 0;
|
|
196
|
+
this.isMutedValue = true;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (volume > 1) {
|
|
200
|
+
this.setVolume(volume / 100);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
this.gainNode.gain.value = volume;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Skips [seconds] either forward or backward if [seconds] is negative.
|
|
208
|
+
*/
|
|
209
|
+
public skip(seconds: number): void {
|
|
210
|
+
if (!this.mediaElement) {
|
|
211
|
+
console.error("Audio not loaded");
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const newTime = this.mediaElement.currentTime + seconds;
|
|
216
|
+
if (newTime < 0) this.mediaElement.currentTime = 0;
|
|
217
|
+
else if (newTime > this.mediaElement.duration)
|
|
218
|
+
this.mediaElement.currentTime = this.mediaElement.duration;
|
|
219
|
+
else this.mediaElement.currentTime = newTime;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Returns de current time in the audio resource.
|
|
224
|
+
*/
|
|
225
|
+
public currentTime(): number {
|
|
226
|
+
return this.mediaElement.currentTime;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Returns the duration in seconds of the current media element resource.
|
|
231
|
+
*/
|
|
232
|
+
public duration(): number {
|
|
233
|
+
// Implementation details.
|
|
234
|
+
return this.mediaElement.duration;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Returns whether the audio resource is currently playing.
|
|
239
|
+
*/
|
|
240
|
+
public isPlaying(): boolean {
|
|
241
|
+
return this.isPlayingValue;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Returns whether the audio resource is currently paused.
|
|
246
|
+
*/
|
|
247
|
+
public isPaused(): boolean {
|
|
248
|
+
return this.isPausedValue;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Returns whether the audio resource is currently stopped.
|
|
253
|
+
*/
|
|
254
|
+
public isStopped(): boolean {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Returns whether the audio resource is currently loading.
|
|
260
|
+
*/
|
|
261
|
+
public isLoading(): boolean {
|
|
262
|
+
return this.isLoadingValue;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Returns whether the audio resource is currently loaded.
|
|
267
|
+
*/
|
|
268
|
+
public isLoaded(): boolean {
|
|
269
|
+
return this.isLoadedValue;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Returns whether the audio resource is currently ended.
|
|
274
|
+
*/
|
|
275
|
+
public isEnded(): boolean {
|
|
276
|
+
return this.isEndedValue;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Returns whether the audio resource is currently muted.
|
|
281
|
+
*/
|
|
282
|
+
public isMuted(): boolean {
|
|
283
|
+
return this.isMutedValue;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './engine';
|