@capgo/native-audio 8.2.11 → 8.2.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 +147 -34
- package/android/build.gradle +1 -1
- package/android/src/main/java/ee/forgr/audio/AudioAsset.java +352 -74
- package/android/src/main/java/ee/forgr/audio/AudioDispatcher.java +24 -3
- package/android/src/main/java/ee/forgr/audio/Constant.java +9 -1
- package/android/src/main/java/ee/forgr/audio/Logger.java +55 -0
- package/android/src/main/java/ee/forgr/audio/NativeAudio.java +336 -57
- package/android/src/main/java/ee/forgr/audio/RemoteAudioAsset.java +307 -98
- package/android/src/main/java/ee/forgr/audio/StreamAudioAsset.java +285 -96
- package/dist/docs.json +307 -41
- package/dist/esm/definitions.d.ts +116 -38
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +52 -41
- package/dist/esm/web.js +386 -41
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +386 -41
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +386 -41
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/NativeAudioPlugin/AudioAsset+Fade.swift +104 -0
- package/ios/Sources/NativeAudioPlugin/AudioAsset.swift +168 -324
- package/ios/Sources/NativeAudioPlugin/Constant.swift +17 -4
- package/ios/Sources/NativeAudioPlugin/Logger.swift +43 -0
- package/ios/Sources/NativeAudioPlugin/Plugin.swift +176 -87
- package/ios/Sources/NativeAudioPlugin/RemoteAudioAsset+Fade.swift +110 -0
- package/ios/Sources/NativeAudioPlugin/RemoteAudioAsset.swift +117 -273
- package/ios/Tests/NativeAudioPluginTests/PluginTests.swift +47 -72
- package/package.json +1 -1
package/dist/plugin.js
CHANGED
|
@@ -14,21 +14,62 @@ var capacitorCapacitorNativeAudio = (function (exports, core) {
|
|
|
14
14
|
class NativeAudioWeb extends core.WebPlugin {
|
|
15
15
|
constructor() {
|
|
16
16
|
super();
|
|
17
|
+
this.debugMode = false;
|
|
18
|
+
this.currentTimeIntervals = new Map();
|
|
19
|
+
this.zeroVolume = 0.0001;
|
|
17
20
|
}
|
|
18
21
|
async resume(options) {
|
|
22
|
+
var _a, _b;
|
|
19
23
|
const audio = this.getAudioAsset(options.assetId).audio;
|
|
24
|
+
const data = this.getAudioAssetData(options.assetId);
|
|
25
|
+
const targetVolume = (_b = (_a = data.volumeBeforePause) !== null && _a !== void 0 ? _a : data.volume) !== null && _b !== void 0 ? _b : 1;
|
|
26
|
+
if (options.fadeIn) {
|
|
27
|
+
const fadeDuration = options.fadeInDuration || NativeAudioWeb.DEFAULT_FADE_DURATION_SEC;
|
|
28
|
+
this.doFadeIn(audio, fadeDuration, targetVolume);
|
|
29
|
+
}
|
|
30
|
+
else if (audio.volume <= this.zeroVolume) {
|
|
31
|
+
audio.volume = targetVolume;
|
|
32
|
+
this.setGainNodeVolume(audio, targetVolume);
|
|
33
|
+
}
|
|
34
|
+
this.clearFadeOutToStopTimer(options.assetId);
|
|
35
|
+
return this.doResume(options.assetId);
|
|
36
|
+
}
|
|
37
|
+
async doResume(assetId) {
|
|
38
|
+
const audio = this.getAudioAsset(assetId).audio;
|
|
39
|
+
this.startCurrentTimeUpdates(assetId);
|
|
20
40
|
if (audio.paused) {
|
|
21
41
|
return audio.play();
|
|
22
42
|
}
|
|
23
43
|
}
|
|
24
44
|
async pause(options) {
|
|
45
|
+
var _a;
|
|
25
46
|
const audio = this.getAudioAsset(options.assetId).audio;
|
|
26
|
-
|
|
47
|
+
this.cancelGainNodeRamp(audio);
|
|
48
|
+
const data = this.getAudioAssetData(options.assetId);
|
|
49
|
+
data.volumeBeforePause = (_a = data.volume) !== null && _a !== void 0 ? _a : audio.volume;
|
|
50
|
+
this.setAudioAssetData(options.assetId, data);
|
|
51
|
+
if (!audio.paused && options.fadeOut) {
|
|
52
|
+
const fadeOutDuration = options.fadeOutDuration || NativeAudioWeb.DEFAULT_FADE_DURATION_SEC;
|
|
53
|
+
this.doFadeOut(audio, fadeOutDuration);
|
|
54
|
+
data.fadeOutToStopTimer = window.setTimeout(() => {
|
|
55
|
+
this.doPause(options.assetId).catch(() => {
|
|
56
|
+
// no-op
|
|
57
|
+
});
|
|
58
|
+
}, fadeOutDuration * 1000);
|
|
59
|
+
this.setAudioAssetData(options.assetId, data);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
return this.doPause(options.assetId);
|
|
63
|
+
}
|
|
64
|
+
async doPause(assetId) {
|
|
65
|
+
const audio = this.getAudioAsset(assetId).audio;
|
|
66
|
+
this.clearFadeOutToStopTimer(assetId);
|
|
67
|
+
this.stopCurrentTimeUpdates(assetId);
|
|
68
|
+
audio.pause();
|
|
27
69
|
}
|
|
28
70
|
async setCurrentTime(options) {
|
|
29
71
|
const audio = this.getAudioAsset(options.assetId).audio;
|
|
30
72
|
audio.currentTime = options.time;
|
|
31
|
-
return;
|
|
32
73
|
}
|
|
33
74
|
async getCurrentTime(options) {
|
|
34
75
|
const audio = this.getAudioAsset(options.assetId).audio;
|
|
@@ -44,6 +85,12 @@ var capacitorCapacitorNativeAudio = (function (exports, core) {
|
|
|
44
85
|
}
|
|
45
86
|
return { duration: audio.duration };
|
|
46
87
|
}
|
|
88
|
+
async setDebugMode(options) {
|
|
89
|
+
this.debugMode = options.enabled;
|
|
90
|
+
if (this.debugMode) {
|
|
91
|
+
this.logInfo('Debug mode enabled');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
47
94
|
async configure(options) {
|
|
48
95
|
throw `configure is not supported for web: ${JSON.stringify(options)}`;
|
|
49
96
|
}
|
|
@@ -51,55 +98,70 @@ var capacitorCapacitorNativeAudio = (function (exports, core) {
|
|
|
51
98
|
try {
|
|
52
99
|
return { found: !!this.getAudioAsset(options.assetId) };
|
|
53
100
|
}
|
|
54
|
-
catch (
|
|
101
|
+
catch (_a) {
|
|
55
102
|
return { found: false };
|
|
56
103
|
}
|
|
57
104
|
}
|
|
58
105
|
async preload(options) {
|
|
59
106
|
var _a;
|
|
107
|
+
this.logInfo(`Preloading audio asset with options: ${JSON.stringify(options)}`);
|
|
60
108
|
if (NativeAudioWeb.AUDIO_ASSET_BY_ASSET_ID.has(options.assetId)) {
|
|
61
109
|
throw 'AssetId already exists. Unload first if like to change!';
|
|
62
110
|
}
|
|
63
111
|
if (!((_a = options.assetPath) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
64
112
|
throw 'no assetPath provided';
|
|
65
113
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
audio.
|
|
76
|
-
|
|
77
|
-
|
|
114
|
+
NativeAudioWeb.AUDIO_PRELOAD_OPTIONS_MAP.set(options.assetId, options);
|
|
115
|
+
await new Promise((resolve, reject) => {
|
|
116
|
+
var _a;
|
|
117
|
+
if (!options.isUrl && !new RegExp('^/?' + NativeAudioWeb.FILE_LOCATION).test(options.assetPath)) {
|
|
118
|
+
const slashPrefix = options.assetPath.startsWith('/') ? '' : '/';
|
|
119
|
+
options.assetPath = `${NativeAudioWeb.FILE_LOCATION}${slashPrefix}${options.assetPath}`;
|
|
120
|
+
}
|
|
121
|
+
const audio = document.createElement('audio');
|
|
122
|
+
audio.id = options.assetId;
|
|
123
|
+
audio.crossOrigin = 'anonymous';
|
|
124
|
+
audio.src = options.assetPath;
|
|
125
|
+
audio.autoplay = false;
|
|
126
|
+
audio.loop = false;
|
|
127
|
+
audio.preload = 'metadata';
|
|
128
|
+
audio.addEventListener('loadedmetadata', () => {
|
|
129
|
+
resolve();
|
|
130
|
+
});
|
|
131
|
+
audio.addEventListener('error', (errEvt) => {
|
|
132
|
+
this.logError(`Error loading audio file: ${options.assetPath}, error: ${String(errEvt)}`);
|
|
133
|
+
reject('Error loading audio file');
|
|
134
|
+
});
|
|
135
|
+
const data = this.getAudioAssetData(options.assetId);
|
|
136
|
+
if (typeof options.volume === 'number') {
|
|
137
|
+
audio.volume = options.volume;
|
|
138
|
+
data.volume = options.volume;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
data.volume = audio.volume;
|
|
142
|
+
}
|
|
143
|
+
NativeAudioWeb.AUDIO_ASSET_BY_ASSET_ID.set(options.assetId, new AudioAsset(audio));
|
|
144
|
+
this.setAudioAssetData(options.assetId, data);
|
|
145
|
+
this.setGainNodeVolume(audio, (_a = data.volume) !== null && _a !== void 0 ? _a : 1);
|
|
146
|
+
});
|
|
78
147
|
}
|
|
79
148
|
async playOnce(options) {
|
|
80
149
|
var _a;
|
|
81
|
-
// Generate a unique temporary asset ID
|
|
82
150
|
const assetId = `playOnce_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
83
151
|
NativeAudioWeb.playOnceAssets.add(assetId);
|
|
84
|
-
const autoPlay = options.autoPlay !== false;
|
|
152
|
+
const autoPlay = options.autoPlay !== false;
|
|
85
153
|
const deleteAfterPlay = (_a = options.deleteAfterPlay) !== null && _a !== void 0 ? _a : false;
|
|
86
154
|
try {
|
|
87
|
-
// Preload the asset
|
|
88
155
|
await this.preload({
|
|
89
156
|
assetId,
|
|
90
157
|
assetPath: options.assetPath,
|
|
91
158
|
volume: options.volume,
|
|
92
159
|
isUrl: options.isUrl,
|
|
93
160
|
});
|
|
94
|
-
// Set up automatic cleanup on completion
|
|
95
|
-
const audio = this.getAudioAsset(assetId).audio;
|
|
96
161
|
const cleanupHandler = async () => {
|
|
97
162
|
try {
|
|
98
|
-
// Unload the asset
|
|
99
163
|
await this.unload({ assetId });
|
|
100
164
|
NativeAudioWeb.playOnceAssets.delete(assetId);
|
|
101
|
-
// Delete file if requested (Web can't actually delete files from disk)
|
|
102
|
-
// This is a no-op on web, but we keep the interface consistent
|
|
103
165
|
if (deleteAfterPlay) {
|
|
104
166
|
console.warn('[NativeAudio] deleteAfterPlay is not supported on web platform. File deletion is ignored.');
|
|
105
167
|
}
|
|
@@ -108,21 +170,23 @@ var capacitorCapacitorNativeAudio = (function (exports, core) {
|
|
|
108
170
|
console.error('[NativeAudio] Error during playOnce cleanup:', error);
|
|
109
171
|
}
|
|
110
172
|
};
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
173
|
+
if (autoPlay) {
|
|
174
|
+
await this.doPlay({ assetId, volume: options.volume }, false);
|
|
175
|
+
}
|
|
176
|
+
const currentAudio = this.getAudioAsset(assetId).audio;
|
|
177
|
+
currentAudio.addEventListener('ended', () => {
|
|
178
|
+
cleanupHandler().catch((error) => {
|
|
179
|
+
console.error('[NativeAudio] Error during ended cleanup:', error);
|
|
180
|
+
});
|
|
181
|
+
}, { once: true });
|
|
182
|
+
currentAudio.addEventListener('error', () => {
|
|
114
183
|
cleanupHandler().catch((error) => {
|
|
115
184
|
console.error('[NativeAudio] Error during error cleanup:', error);
|
|
116
185
|
});
|
|
117
186
|
}, { once: true });
|
|
118
|
-
// Auto-play if requested
|
|
119
|
-
if (autoPlay) {
|
|
120
|
-
await this.play({ assetId });
|
|
121
|
-
}
|
|
122
187
|
return { assetId };
|
|
123
188
|
}
|
|
124
189
|
catch (error) {
|
|
125
|
-
// Cleanup on failure
|
|
126
190
|
try {
|
|
127
191
|
await this.unload({ assetId });
|
|
128
192
|
NativeAudioWeb.playOnceAssets.delete(assetId);
|
|
@@ -134,43 +198,196 @@ var capacitorCapacitorNativeAudio = (function (exports, core) {
|
|
|
134
198
|
}
|
|
135
199
|
}
|
|
136
200
|
onEnded(assetId) {
|
|
201
|
+
this.logDebug(`Playback ended for assetId: ${assetId}`);
|
|
137
202
|
this.notifyListeners('complete', { assetId });
|
|
138
203
|
}
|
|
139
204
|
async play(options) {
|
|
205
|
+
this.logInfo(`Playing audio asset with options: ${JSON.stringify(options)}`);
|
|
206
|
+
this.clearFadeOutToStopTimer(options.assetId);
|
|
207
|
+
const { delay = 0 } = options;
|
|
208
|
+
if (delay > 0) {
|
|
209
|
+
const data = this.getAudioAssetData(options.assetId);
|
|
210
|
+
data.startTimer = window.setTimeout(() => {
|
|
211
|
+
this.doPlay(options).catch((error) => {
|
|
212
|
+
this.logError(`Delayed play failed: ${String(error)}`);
|
|
213
|
+
});
|
|
214
|
+
data.startTimer = undefined;
|
|
215
|
+
this.setAudioAssetData(options.assetId, data);
|
|
216
|
+
}, delay * 1000);
|
|
217
|
+
this.setAudioAssetData(options.assetId, data);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
await this.doPlay(options);
|
|
221
|
+
}
|
|
222
|
+
async doPlay(options, recreateAudioElement = true) {
|
|
140
223
|
const { assetId, time = 0 } = options;
|
|
224
|
+
if (!NativeAudioWeb.AUDIO_PRELOAD_OPTIONS_MAP.has(assetId)) {
|
|
225
|
+
throw `no asset for assetId "${assetId}" available. Call preload first!`;
|
|
226
|
+
}
|
|
227
|
+
if (recreateAudioElement) {
|
|
228
|
+
const preloadOptions = NativeAudioWeb.AUDIO_PRELOAD_OPTIONS_MAP.get(assetId);
|
|
229
|
+
await this.unload({ assetId });
|
|
230
|
+
await this.preload(preloadOptions);
|
|
231
|
+
}
|
|
141
232
|
const audio = this.getAudioAsset(assetId).audio;
|
|
142
|
-
|
|
233
|
+
audio.id = assetId;
|
|
143
234
|
audio.loop = false;
|
|
144
235
|
audio.currentTime = time;
|
|
145
236
|
audio.addEventListener('ended', () => this.onEnded(assetId), {
|
|
146
237
|
once: true,
|
|
147
238
|
});
|
|
148
|
-
|
|
239
|
+
const data = this.getAudioAssetData(assetId);
|
|
240
|
+
if (typeof options.volume === 'number') {
|
|
241
|
+
audio.volume = options.volume;
|
|
242
|
+
data.volume = options.volume;
|
|
243
|
+
this.setGainNodeVolume(audio, options.volume);
|
|
244
|
+
}
|
|
245
|
+
else if (typeof data.volume !== 'number') {
|
|
246
|
+
data.volume = audio.volume;
|
|
247
|
+
}
|
|
248
|
+
await audio.play();
|
|
249
|
+
this.startCurrentTimeUpdates(assetId);
|
|
250
|
+
if (options.fadeIn) {
|
|
251
|
+
this.logDebug(`Fading in audio asset with assetId: ${assetId}`);
|
|
252
|
+
const fadeDuration = options.fadeInDuration || NativeAudioWeb.DEFAULT_FADE_DURATION_SEC;
|
|
253
|
+
this.doFadeIn(audio, fadeDuration);
|
|
254
|
+
}
|
|
255
|
+
if (options.fadeOut && !Number.isNaN(audio.duration) && Number.isFinite(audio.duration)) {
|
|
256
|
+
this.logDebug(`Scheduling fade out for audio asset with assetId: ${assetId}`);
|
|
257
|
+
const fadeOutDuration = options.fadeOutDuration || NativeAudioWeb.DEFAULT_FADE_DURATION_SEC;
|
|
258
|
+
const fadeOutStartTime = options.fadeOutStartTime || audio.duration - fadeOutDuration;
|
|
259
|
+
data.fadeOut = true;
|
|
260
|
+
data.fadeOutStartTime = fadeOutStartTime;
|
|
261
|
+
data.fadeOutDuration = fadeOutDuration;
|
|
262
|
+
}
|
|
263
|
+
this.setAudioAssetData(assetId, data);
|
|
264
|
+
}
|
|
265
|
+
doFadeIn(audio, fadeDuration, targetVolume) {
|
|
266
|
+
var _a;
|
|
267
|
+
const data = this.getAudioAssetData(audio.id);
|
|
268
|
+
this.setGainNodeVolume(audio, this.zeroVolume);
|
|
269
|
+
const fadeToVolume = (_a = targetVolume !== null && targetVolume !== void 0 ? targetVolume : data.volume) !== null && _a !== void 0 ? _a : 1;
|
|
270
|
+
this.linearRampGainNodeVolume(audio, fadeToVolume, fadeDuration);
|
|
271
|
+
data.fadeInTimer = window.setTimeout(() => {
|
|
272
|
+
data.fadeInTimer = undefined;
|
|
273
|
+
this.setAudioAssetData(audio.id, data);
|
|
274
|
+
}, fadeDuration * 1000);
|
|
275
|
+
this.setAudioAssetData(audio.id, data);
|
|
276
|
+
}
|
|
277
|
+
doFadeOut(audio, fadeDuration) {
|
|
278
|
+
this.linearRampGainNodeVolume(audio, this.zeroVolume, fadeDuration);
|
|
149
279
|
}
|
|
150
280
|
async loop(options) {
|
|
281
|
+
this.logInfo(`Looping audio asset with options: ${JSON.stringify(options)}`);
|
|
151
282
|
const audio = this.getAudioAsset(options.assetId).audio;
|
|
152
|
-
|
|
283
|
+
this.reset(audio);
|
|
153
284
|
audio.loop = true;
|
|
285
|
+
this.startCurrentTimeUpdates(options.assetId);
|
|
154
286
|
return audio.play();
|
|
155
287
|
}
|
|
156
288
|
async stop(options) {
|
|
289
|
+
this.logInfo(`Stopping audio asset with options: ${JSON.stringify(options)}`);
|
|
157
290
|
const audio = this.getAudioAsset(options.assetId).audio;
|
|
291
|
+
const data = this.getAudioAssetData(options.assetId);
|
|
292
|
+
this.clearFadeOutToStopTimer(options.assetId);
|
|
293
|
+
this.cancelGainNodeRamp(audio);
|
|
294
|
+
if (!audio.paused && options.fadeOut) {
|
|
295
|
+
const fadeDuration = options.fadeOutDuration || NativeAudioWeb.DEFAULT_FADE_DURATION_SEC;
|
|
296
|
+
this.doFadeOut(audio, fadeDuration);
|
|
297
|
+
data.fadeOutToStopTimer = window.setTimeout(() => {
|
|
298
|
+
this.doStop(audio, options);
|
|
299
|
+
}, fadeDuration * 1000);
|
|
300
|
+
this.setAudioAssetData(options.assetId, data);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
this.doStop(audio, options);
|
|
304
|
+
}
|
|
305
|
+
doStop(audio, options) {
|
|
158
306
|
audio.pause();
|
|
159
|
-
|
|
307
|
+
this.onEnded(options.assetId);
|
|
308
|
+
this.reset(audio);
|
|
309
|
+
}
|
|
310
|
+
reset(audio) {
|
|
311
|
+
var _a;
|
|
160
312
|
audio.currentTime = 0;
|
|
313
|
+
for (const [assetId, asset] of NativeAudioWeb.AUDIO_ASSET_BY_ASSET_ID.entries()) {
|
|
314
|
+
if (asset.audio === audio) {
|
|
315
|
+
this.stopCurrentTimeUpdates(assetId);
|
|
316
|
+
this.clearFadeOutToStopTimer(assetId);
|
|
317
|
+
this.clearStartTimer(assetId);
|
|
318
|
+
this.cancelGainNodeRamp(audio);
|
|
319
|
+
const data = this.getAudioAssetData(assetId);
|
|
320
|
+
const initialVolume = (_a = data.volume) !== null && _a !== void 0 ? _a : 1;
|
|
321
|
+
this.setGainNodeVolume(audio, initialVolume);
|
|
322
|
+
this.setAudioAssetData(assetId, data);
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
clearFadeOutToStopTimer(assetId) {
|
|
328
|
+
const data = this.getAudioAssetData(assetId);
|
|
329
|
+
if (data.fadeOutToStopTimer) {
|
|
330
|
+
clearTimeout(data.fadeOutToStopTimer);
|
|
331
|
+
data.fadeOutToStopTimer = undefined;
|
|
332
|
+
this.setAudioAssetData(assetId, data);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
clearStartTimer(assetId) {
|
|
336
|
+
const data = this.getAudioAssetData(assetId);
|
|
337
|
+
if (data.startTimer) {
|
|
338
|
+
clearTimeout(data.startTimer);
|
|
339
|
+
data.startTimer = undefined;
|
|
340
|
+
this.setAudioAssetData(assetId, data);
|
|
341
|
+
}
|
|
161
342
|
}
|
|
162
343
|
async unload(options) {
|
|
163
|
-
|
|
344
|
+
this.logInfo(`Unloading audio asset with options: ${JSON.stringify(options)}`);
|
|
345
|
+
const audio = this.getAudioAsset(options.assetId).audio;
|
|
346
|
+
this.reset(audio);
|
|
164
347
|
NativeAudioWeb.AUDIO_ASSET_BY_ASSET_ID.delete(options.assetId);
|
|
348
|
+
NativeAudioWeb.AUDIO_PRELOAD_OPTIONS_MAP.delete(options.assetId);
|
|
349
|
+
NativeAudioWeb.AUDIO_DATA_MAP.delete(options.assetId);
|
|
350
|
+
this.cleanupAudioContext(audio);
|
|
351
|
+
}
|
|
352
|
+
cleanupAudioContext(audio) {
|
|
353
|
+
const gainNode = NativeAudioWeb.GAIN_NODE_MAP.get(audio);
|
|
354
|
+
if (gainNode) {
|
|
355
|
+
gainNode.disconnect();
|
|
356
|
+
NativeAudioWeb.GAIN_NODE_MAP.delete(audio);
|
|
357
|
+
}
|
|
358
|
+
const sourceNode = NativeAudioWeb.MEDIA_ELEMENT_SOURCE_MAP.get(audio);
|
|
359
|
+
if (sourceNode) {
|
|
360
|
+
sourceNode.disconnect();
|
|
361
|
+
NativeAudioWeb.MEDIA_ELEMENT_SOURCE_MAP.delete(audio);
|
|
362
|
+
}
|
|
363
|
+
const audioContext = NativeAudioWeb.AUDIO_CONTEXT_MAP.get(audio);
|
|
364
|
+
if (audioContext) {
|
|
365
|
+
audioContext.close().catch(() => {
|
|
366
|
+
// no-op
|
|
367
|
+
});
|
|
368
|
+
NativeAudioWeb.AUDIO_CONTEXT_MAP.delete(audio);
|
|
369
|
+
}
|
|
165
370
|
}
|
|
166
371
|
async setVolume(options) {
|
|
372
|
+
this.logInfo(`Setting volume for audio asset with options: ${JSON.stringify(options)}`);
|
|
167
373
|
if (typeof (options === null || options === void 0 ? void 0 : options.volume) !== 'number') {
|
|
168
374
|
throw 'no volume provided';
|
|
169
375
|
}
|
|
376
|
+
const { volume, duration = 0 } = options;
|
|
377
|
+
const data = this.getAudioAssetData(options.assetId);
|
|
378
|
+
data.volume = volume;
|
|
379
|
+
this.setAudioAssetData(options.assetId, data);
|
|
170
380
|
const audio = this.getAudioAsset(options.assetId).audio;
|
|
171
|
-
audio
|
|
381
|
+
this.cancelGainNodeRamp(audio);
|
|
382
|
+
if (duration > 0) {
|
|
383
|
+
this.exponentialRampGainNodeVolume(audio, volume, duration);
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
audio.volume = volume;
|
|
387
|
+
this.setGainNodeVolume(audio, volume);
|
|
172
388
|
}
|
|
173
389
|
async setRate(options) {
|
|
390
|
+
this.logInfo(`Setting playback rate for audio asset with options: ${JSON.stringify(options)}`);
|
|
174
391
|
if (typeof (options === null || options === void 0 ? void 0 : options.rate) !== 'number') {
|
|
175
392
|
throw 'no rate provided';
|
|
176
393
|
}
|
|
@@ -182,8 +399,7 @@ var capacitorCapacitorNativeAudio = (function (exports, core) {
|
|
|
182
399
|
return { isPlaying: !audio.paused };
|
|
183
400
|
}
|
|
184
401
|
async clearCache() {
|
|
185
|
-
|
|
186
|
-
return;
|
|
402
|
+
this.logWarning('clearCache is not supported for web. No cache to clear.');
|
|
187
403
|
}
|
|
188
404
|
getAudioAsset(assetId) {
|
|
189
405
|
this.checkAssetId(assetId);
|
|
@@ -200,19 +416,148 @@ var capacitorCapacitorNativeAudio = (function (exports, core) {
|
|
|
200
416
|
throw 'no assetId provided';
|
|
201
417
|
}
|
|
202
418
|
}
|
|
419
|
+
getOrCreateAudioContext(audio) {
|
|
420
|
+
if (NativeAudioWeb.AUDIO_CONTEXT_MAP.has(audio)) {
|
|
421
|
+
return NativeAudioWeb.AUDIO_CONTEXT_MAP.get(audio);
|
|
422
|
+
}
|
|
423
|
+
const audioContext = new AudioContext();
|
|
424
|
+
NativeAudioWeb.AUDIO_CONTEXT_MAP.set(audio, audioContext);
|
|
425
|
+
return audioContext;
|
|
426
|
+
}
|
|
427
|
+
getOrCreateMediaElementSource(audioContext, audio) {
|
|
428
|
+
if (NativeAudioWeb.MEDIA_ELEMENT_SOURCE_MAP.has(audio)) {
|
|
429
|
+
return NativeAudioWeb.MEDIA_ELEMENT_SOURCE_MAP.get(audio);
|
|
430
|
+
}
|
|
431
|
+
const sourceNode = audioContext.createMediaElementSource(audio);
|
|
432
|
+
NativeAudioWeb.MEDIA_ELEMENT_SOURCE_MAP.set(audio, sourceNode);
|
|
433
|
+
return sourceNode;
|
|
434
|
+
}
|
|
435
|
+
getOrCreateGainNode(audio, track) {
|
|
436
|
+
const audioContext = this.getOrCreateAudioContext(audio);
|
|
437
|
+
if (NativeAudioWeb.GAIN_NODE_MAP.has(audio)) {
|
|
438
|
+
return NativeAudioWeb.GAIN_NODE_MAP.get(audio);
|
|
439
|
+
}
|
|
440
|
+
const gainNode = audioContext.createGain();
|
|
441
|
+
track.connect(gainNode).connect(audioContext.destination);
|
|
442
|
+
NativeAudioWeb.GAIN_NODE_MAP.set(audio, gainNode);
|
|
443
|
+
return gainNode;
|
|
444
|
+
}
|
|
445
|
+
setGainNodeVolume(audio, volume, time) {
|
|
446
|
+
const audioContext = this.getOrCreateAudioContext(audio);
|
|
447
|
+
const track = this.getOrCreateMediaElementSource(audioContext, audio);
|
|
448
|
+
const gainNode = this.getOrCreateGainNode(audio, track);
|
|
449
|
+
if (time !== undefined) {
|
|
450
|
+
gainNode.gain.setValueAtTime(volume, time);
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
gainNode.gain.setValueAtTime(volume, audioContext.currentTime);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
exponentialRampGainNodeVolume(audio, volume, duration) {
|
|
457
|
+
const audioContext = this.getOrCreateAudioContext(audio);
|
|
458
|
+
const track = this.getOrCreateMediaElementSource(audioContext, audio);
|
|
459
|
+
const gainNode = this.getOrCreateGainNode(audio, track);
|
|
460
|
+
const adjustedVolume = volume < this.zeroVolume ? this.zeroVolume : volume;
|
|
461
|
+
gainNode.gain.exponentialRampToValueAtTime(adjustedVolume, audioContext.currentTime + duration);
|
|
462
|
+
}
|
|
463
|
+
linearRampGainNodeVolume(audio, volume, duration) {
|
|
464
|
+
const audioContext = this.getOrCreateAudioContext(audio);
|
|
465
|
+
const track = this.getOrCreateMediaElementSource(audioContext, audio);
|
|
466
|
+
const gainNode = this.getOrCreateGainNode(audio, track);
|
|
467
|
+
gainNode.gain.linearRampToValueAtTime(volume, audioContext.currentTime + duration);
|
|
468
|
+
}
|
|
469
|
+
cancelGainNodeRamp(audio) {
|
|
470
|
+
const gainNode = NativeAudioWeb.GAIN_NODE_MAP.get(audio);
|
|
471
|
+
if (gainNode) {
|
|
472
|
+
gainNode.gain.cancelScheduledValues(0);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
startCurrentTimeUpdates(assetId) {
|
|
476
|
+
this.stopCurrentTimeUpdates(assetId);
|
|
477
|
+
const audio = this.getAudioAsset(assetId).audio;
|
|
478
|
+
const intervalId = window.setInterval(() => {
|
|
479
|
+
var _a;
|
|
480
|
+
if (!audio.paused) {
|
|
481
|
+
const currentTime = Math.round(audio.currentTime * 10) / 10;
|
|
482
|
+
this.notifyListeners('currentTime', { assetId, currentTime });
|
|
483
|
+
this.logDebug(`Current time update for assetId: ${assetId}, currentTime: ${currentTime}`);
|
|
484
|
+
const data = this.getAudioAssetData(assetId);
|
|
485
|
+
if (data.fadeOut && typeof data.fadeOutStartTime === 'number' && currentTime >= data.fadeOutStartTime) {
|
|
486
|
+
this.cancelGainNodeRamp(audio);
|
|
487
|
+
const fadeOutDuration = (_a = data.fadeOutDuration) !== null && _a !== void 0 ? _a : NativeAudioWeb.DEFAULT_FADE_DURATION_SEC;
|
|
488
|
+
this.doFadeOut(audio, fadeOutDuration);
|
|
489
|
+
data.fadeOut = false;
|
|
490
|
+
this.setAudioAssetData(assetId, data);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
this.stopCurrentTimeUpdates(assetId);
|
|
495
|
+
}
|
|
496
|
+
}, NativeAudioWeb.CURRENT_TIME_UPDATE_INTERVAL);
|
|
497
|
+
this.currentTimeIntervals.set(assetId, intervalId);
|
|
498
|
+
}
|
|
499
|
+
stopCurrentTimeUpdates(assetId) {
|
|
500
|
+
if (assetId) {
|
|
501
|
+
const intervalId = this.currentTimeIntervals.get(assetId);
|
|
502
|
+
if (intervalId) {
|
|
503
|
+
clearInterval(intervalId);
|
|
504
|
+
this.currentTimeIntervals.delete(assetId);
|
|
505
|
+
}
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
for (const intervalId of this.currentTimeIntervals.values()) {
|
|
509
|
+
clearInterval(intervalId);
|
|
510
|
+
}
|
|
511
|
+
this.currentTimeIntervals.clear();
|
|
512
|
+
}
|
|
513
|
+
getAudioAssetData(assetId) {
|
|
514
|
+
return NativeAudioWeb.AUDIO_DATA_MAP.get(assetId) || {};
|
|
515
|
+
}
|
|
516
|
+
setAudioAssetData(assetId, data) {
|
|
517
|
+
const currentData = NativeAudioWeb.AUDIO_DATA_MAP.get(assetId) || {};
|
|
518
|
+
const newData = Object.assign(Object.assign({}, currentData), data);
|
|
519
|
+
NativeAudioWeb.AUDIO_DATA_MAP.set(assetId, newData);
|
|
520
|
+
}
|
|
521
|
+
logError(message) {
|
|
522
|
+
if (!this.debugMode)
|
|
523
|
+
return;
|
|
524
|
+
console.error(`${NativeAudioWeb.LOG_TAG} Error: ${message}`);
|
|
525
|
+
}
|
|
526
|
+
logWarning(message) {
|
|
527
|
+
if (!this.debugMode)
|
|
528
|
+
return;
|
|
529
|
+
console.warn(`${NativeAudioWeb.LOG_TAG} Warning: ${message}`);
|
|
530
|
+
}
|
|
531
|
+
logInfo(message) {
|
|
532
|
+
if (!this.debugMode)
|
|
533
|
+
return;
|
|
534
|
+
console.info(`${NativeAudioWeb.LOG_TAG} Info: ${message}`);
|
|
535
|
+
}
|
|
536
|
+
logDebug(message) {
|
|
537
|
+
if (!this.debugMode)
|
|
538
|
+
return;
|
|
539
|
+
console.debug(`${NativeAudioWeb.LOG_TAG} Debug: ${message}`);
|
|
540
|
+
}
|
|
203
541
|
async getPluginVersion() {
|
|
204
542
|
return { version: 'web' };
|
|
205
543
|
}
|
|
206
544
|
async deinitPlugin() {
|
|
207
|
-
// Stop and unload all audio assets
|
|
208
545
|
for (const [assetId] of NativeAudioWeb.AUDIO_ASSET_BY_ASSET_ID) {
|
|
209
546
|
await this.unload({ assetId });
|
|
210
547
|
}
|
|
211
|
-
|
|
548
|
+
this.stopCurrentTimeUpdates();
|
|
212
549
|
}
|
|
213
550
|
}
|
|
551
|
+
NativeAudioWeb.LOG_TAG = '[NativeAudioWeb]';
|
|
214
552
|
NativeAudioWeb.FILE_LOCATION = '';
|
|
553
|
+
NativeAudioWeb.DEFAULT_FADE_DURATION_SEC = 1;
|
|
554
|
+
NativeAudioWeb.CURRENT_TIME_UPDATE_INTERVAL = 100;
|
|
555
|
+
NativeAudioWeb.AUDIO_PRELOAD_OPTIONS_MAP = new Map();
|
|
556
|
+
NativeAudioWeb.AUDIO_DATA_MAP = new Map();
|
|
215
557
|
NativeAudioWeb.AUDIO_ASSET_BY_ASSET_ID = new Map();
|
|
558
|
+
NativeAudioWeb.AUDIO_CONTEXT_MAP = new Map();
|
|
559
|
+
NativeAudioWeb.MEDIA_ELEMENT_SOURCE_MAP = new Map();
|
|
560
|
+
NativeAudioWeb.GAIN_NODE_MAP = new Map();
|
|
216
561
|
NativeAudioWeb.playOnceAssets = new Set();
|
|
217
562
|
new NativeAudioWeb();
|
|
218
563
|
|