@capgo/native-audio 7.1.7 → 7.3.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/README.md +56 -8
- package/android/build.gradle +14 -5
- package/android/src/main/java/ee/forgr/audio/AudioAsset.java +276 -133
- package/android/src/main/java/ee/forgr/audio/AudioCompletionListener.java +1 -1
- package/android/src/main/java/ee/forgr/audio/AudioDispatcher.java +168 -182
- package/android/src/main/java/ee/forgr/audio/Constant.java +20 -21
- package/android/src/main/java/ee/forgr/audio/NativeAudio.java +596 -506
- package/android/src/main/java/ee/forgr/audio/RemoteAudioAsset.java +599 -166
- package/android/src/main/java/ee/forgr/audio/StreamAudioAsset.java +499 -0
- package/dist/docs.json +96 -3
- package/dist/esm/definitions.d.ts +33 -2
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +4 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +4 -3
- package/dist/esm/web.js +23 -20
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +22 -19
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +22 -19
- package/dist/plugin.js.map +1 -1
- package/ios/Plugin/AudioAsset.swift +200 -94
- package/ios/Plugin/Plugin.swift +56 -50
- package/ios/Plugin/RemoteAudioAsset.swift +217 -62
- package/package.json +18 -20
@@ -20,8 +20,11 @@ import android.content.res.AssetManager;
|
|
20
20
|
import android.media.AudioManager;
|
21
21
|
import android.net.Uri;
|
22
22
|
import android.os.Build;
|
23
|
+
import android.os.Handler;
|
24
|
+
import android.os.Looper;
|
23
25
|
import android.os.ParcelFileDescriptor;
|
24
26
|
import android.util.Log;
|
27
|
+
import androidx.media3.common.util.UnstableApi;
|
25
28
|
import com.getcapacitor.JSObject;
|
26
29
|
import com.getcapacitor.Plugin;
|
27
30
|
import com.getcapacitor.PluginCall;
|
@@ -36,584 +39,671 @@ import java.net.URI;
|
|
36
39
|
import java.net.URL;
|
37
40
|
import java.util.ArrayList;
|
38
41
|
import java.util.HashMap;
|
42
|
+
import java.util.Map;
|
39
43
|
|
44
|
+
@UnstableApi
|
40
45
|
@CapacitorPlugin(
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
}
|
46
|
-
)
|
47
|
-
public class NativeAudio
|
48
|
-
extends Plugin
|
49
|
-
implements AudioManager.OnAudioFocusChangeListener {
|
50
|
-
|
51
|
-
public static final String TAG = "NativeAudio";
|
52
|
-
|
53
|
-
private static HashMap<String, AudioAsset> audioAssetList;
|
54
|
-
private static ArrayList<AudioAsset> resumeList;
|
55
|
-
private AudioManager audioManager;
|
56
|
-
|
57
|
-
@Override
|
58
|
-
public void load() {
|
59
|
-
super.load();
|
60
|
-
|
61
|
-
this.audioManager = (AudioManager) this.getActivity()
|
62
|
-
.getSystemService(Context.AUDIO_SERVICE);
|
63
|
-
|
64
|
-
audioAssetList = new HashMap<>();
|
65
|
-
}
|
66
|
-
|
67
|
-
@Override
|
68
|
-
public void onAudioFocusChange(int focusChange) {
|
69
|
-
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {} else if (
|
70
|
-
focusChange == AudioManager.AUDIOFOCUS_GAIN
|
71
|
-
) {} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {}
|
72
|
-
}
|
73
|
-
|
74
|
-
@Override
|
75
|
-
protected void handleOnPause() {
|
76
|
-
super.handleOnPause();
|
77
|
-
|
78
|
-
try {
|
79
|
-
if (audioAssetList != null) {
|
80
|
-
for (HashMap.Entry<
|
81
|
-
String,
|
82
|
-
AudioAsset
|
83
|
-
> entry : audioAssetList.entrySet()) {
|
84
|
-
AudioAsset audio = entry.getValue();
|
85
|
-
|
86
|
-
if (audio != null) {
|
87
|
-
boolean wasPlaying = audio.pause();
|
88
|
-
|
89
|
-
if (wasPlaying) {
|
90
|
-
resumeList.add(audio);
|
91
|
-
}
|
92
|
-
}
|
93
|
-
}
|
94
|
-
}
|
95
|
-
} catch (Exception ex) {
|
96
|
-
Log.d(
|
97
|
-
TAG,
|
98
|
-
"Exception caught while listening for handleOnPause: " +
|
99
|
-
ex.getLocalizedMessage()
|
100
|
-
);
|
46
|
+
permissions = {
|
47
|
+
@Permission(strings = { Manifest.permission.MODIFY_AUDIO_SETTINGS }),
|
48
|
+
@Permission(strings = { Manifest.permission.WRITE_EXTERNAL_STORAGE }),
|
49
|
+
@Permission(strings = { Manifest.permission.READ_PHONE_STATE })
|
101
50
|
}
|
102
|
-
|
51
|
+
)
|
52
|
+
public class NativeAudio extends Plugin implements AudioManager.OnAudioFocusChangeListener {
|
53
|
+
|
54
|
+
public static final String TAG = "NativeAudio";
|
55
|
+
|
56
|
+
private static HashMap<String, AudioAsset> audioAssetList = new HashMap<>();
|
57
|
+
private static ArrayList<AudioAsset> resumeList;
|
58
|
+
private AudioManager audioManager;
|
59
|
+
private boolean fadeMusic = false;
|
60
|
+
|
61
|
+
private final Map<String, PluginCall> pendingDurationCalls = new HashMap<>();
|
62
|
+
|
63
|
+
@Override
|
64
|
+
public void load() {
|
65
|
+
super.load();
|
103
66
|
|
104
|
-
|
105
|
-
protected void handleOnResume() {
|
106
|
-
super.handleOnResume();
|
67
|
+
this.audioManager = (AudioManager) this.getActivity().getSystemService(Context.AUDIO_SERVICE);
|
107
68
|
|
108
|
-
|
109
|
-
|
110
|
-
while (!resumeList.isEmpty()) {
|
111
|
-
AudioAsset audio = resumeList.remove(0);
|
69
|
+
audioAssetList = new HashMap<>();
|
70
|
+
}
|
112
71
|
|
113
|
-
|
114
|
-
|
115
|
-
|
72
|
+
@Override
|
73
|
+
public void onAudioFocusChange(int focusChange) {
|
74
|
+
try {
|
75
|
+
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
|
76
|
+
// Pause playback - temporary loss
|
77
|
+
for (AudioAsset audio : audioAssetList.values()) {
|
78
|
+
if (audio.isPlaying()) {
|
79
|
+
audio.pause();
|
80
|
+
resumeList.add(audio);
|
81
|
+
}
|
82
|
+
}
|
83
|
+
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
|
84
|
+
// Resume playback
|
85
|
+
if (resumeList != null) {
|
86
|
+
while (!resumeList.isEmpty()) {
|
87
|
+
AudioAsset audio = resumeList.remove(0);
|
88
|
+
audio.resume();
|
89
|
+
}
|
90
|
+
}
|
91
|
+
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
|
92
|
+
// Stop playback - permanent loss
|
93
|
+
for (AudioAsset audio : audioAssetList.values()) {
|
94
|
+
audio.stop();
|
95
|
+
}
|
96
|
+
audioManager.abandonAudioFocus(this);
|
97
|
+
}
|
98
|
+
} catch (Exception ex) {
|
99
|
+
Log.e(TAG, "Error handling audio focus change", ex);
|
116
100
|
}
|
117
|
-
}
|
118
|
-
} catch (Exception ex) {
|
119
|
-
Log.d(
|
120
|
-
TAG,
|
121
|
-
"Exception caught while listening for handleOnResume: " +
|
122
|
-
ex.getLocalizedMessage()
|
123
|
-
);
|
124
101
|
}
|
125
|
-
}
|
126
102
|
|
127
|
-
|
128
|
-
|
129
|
-
|
103
|
+
@Override
|
104
|
+
protected void handleOnPause() {
|
105
|
+
super.handleOnPause();
|
130
106
|
|
131
|
-
|
132
|
-
|
133
|
-
|
107
|
+
try {
|
108
|
+
if (audioAssetList != null) {
|
109
|
+
for (HashMap.Entry<String, AudioAsset> entry : audioAssetList.entrySet()) {
|
110
|
+
AudioAsset audio = entry.getValue();
|
111
|
+
|
112
|
+
if (audio != null) {
|
113
|
+
boolean wasPlaying = audio.pause();
|
114
|
+
|
115
|
+
if (wasPlaying) {
|
116
|
+
resumeList.add(audio);
|
117
|
+
}
|
118
|
+
}
|
119
|
+
}
|
120
|
+
}
|
121
|
+
} catch (Exception ex) {
|
122
|
+
Log.d(TAG, "Exception caught while listening for handleOnPause: " + ex.getLocalizedMessage());
|
123
|
+
}
|
134
124
|
}
|
135
125
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
AudioManager.STREAM_MUSIC,
|
140
|
-
AudioManager.AUDIOFOCUS_GAIN
|
141
|
-
);
|
142
|
-
} else {
|
143
|
-
this.audioManager.abandonAudioFocus(this);
|
144
|
-
}
|
145
|
-
call.resolve();
|
146
|
-
}
|
126
|
+
@Override
|
127
|
+
protected void handleOnResume() {
|
128
|
+
super.handleOnResume();
|
147
129
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
130
|
+
try {
|
131
|
+
if (resumeList != null) {
|
132
|
+
while (!resumeList.isEmpty()) {
|
133
|
+
AudioAsset audio = resumeList.remove(0);
|
134
|
+
|
135
|
+
if (audio != null) {
|
136
|
+
audio.resume();
|
137
|
+
}
|
138
|
+
}
|
139
|
+
}
|
140
|
+
} catch (Exception ex) {
|
141
|
+
Log.d(TAG, "Exception caught while listening for handleOnResume: " + ex.getLocalizedMessage());
|
142
|
+
}
|
143
|
+
}
|
155
144
|
|
156
|
-
|
145
|
+
@PluginMethod
|
146
|
+
public void configure(PluginCall call) {
|
147
|
+
initSoundPool();
|
157
148
|
|
158
|
-
|
159
|
-
call.
|
149
|
+
if (this.audioManager == null) {
|
150
|
+
call.resolve();
|
160
151
|
return;
|
161
|
-
}
|
162
|
-
call.resolve(
|
163
|
-
new JSObject().put("found", audioAssetList.containsKey(audioId))
|
164
|
-
);
|
165
152
|
}
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
public void run() {
|
189
|
-
playOrLoop("play", call);
|
190
|
-
}
|
153
|
+
|
154
|
+
boolean focus = call.getBoolean(OPT_FOCUS_AUDIO, false);
|
155
|
+
boolean background = call.getBoolean("background", false);
|
156
|
+
this.fadeMusic = call.getBoolean("fade", false);
|
157
|
+
|
158
|
+
try {
|
159
|
+
if (focus) {
|
160
|
+
// Request audio focus for playback with ducking
|
161
|
+
int result =
|
162
|
+
this.audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK); // Allow other audio to play quietly
|
163
|
+
} else {
|
164
|
+
this.audioManager.abandonAudioFocus(this);
|
165
|
+
}
|
166
|
+
|
167
|
+
if (background) {
|
168
|
+
// Set playback to continue in background
|
169
|
+
this.audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
170
|
+
} else {
|
171
|
+
this.audioManager.setMode(AudioManager.MODE_NORMAL);
|
172
|
+
}
|
173
|
+
} catch (Exception ex) {
|
174
|
+
Log.e(TAG, "Error configuring audio", ex);
|
191
175
|
}
|
192
|
-
);
|
193
|
-
}
|
194
176
|
|
195
|
-
|
196
|
-
|
197
|
-
try {
|
198
|
-
initSoundPool();
|
177
|
+
call.resolve();
|
178
|
+
}
|
199
179
|
|
200
|
-
|
180
|
+
@PluginMethod
|
181
|
+
public void isPreloaded(final PluginCall call) {
|
182
|
+
new Thread(
|
183
|
+
new Runnable() {
|
184
|
+
@Override
|
185
|
+
public void run() {
|
186
|
+
initSoundPool();
|
187
|
+
|
188
|
+
String audioId = call.getString(ASSET_ID);
|
189
|
+
|
190
|
+
if (!isStringValid(audioId)) {
|
191
|
+
call.reject(ERROR_AUDIO_ID_MISSING + " - " + audioId);
|
192
|
+
return;
|
193
|
+
}
|
194
|
+
call.resolve(new JSObject().put("found", audioAssetList.containsKey(audioId)));
|
195
|
+
}
|
196
|
+
}
|
197
|
+
).start();
|
198
|
+
}
|
201
199
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
200
|
+
@PluginMethod
|
201
|
+
public void preload(final PluginCall call) {
|
202
|
+
this.getActivity()
|
203
|
+
.runOnUiThread(
|
204
|
+
new Runnable() {
|
205
|
+
@Override
|
206
|
+
public void run() {
|
207
|
+
preloadAsset(call);
|
208
|
+
}
|
209
|
+
}
|
210
|
+
);
|
211
|
+
}
|
206
212
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
call.reject(ex.getMessage());
|
213
|
+
@PluginMethod
|
214
|
+
public void play(final PluginCall call) {
|
215
|
+
this.getActivity()
|
216
|
+
.runOnUiThread(
|
217
|
+
new Runnable() {
|
218
|
+
@Override
|
219
|
+
public void run() {
|
220
|
+
playOrLoop("play", call);
|
221
|
+
}
|
222
|
+
}
|
223
|
+
);
|
219
224
|
}
|
220
|
-
}
|
221
225
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
+
@PluginMethod
|
227
|
+
public void getCurrentTime(final PluginCall call) {
|
228
|
+
try {
|
229
|
+
initSoundPool();
|
226
230
|
|
227
|
-
|
231
|
+
String audioId = call.getString(ASSET_ID);
|
228
232
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
+
if (!isStringValid(audioId)) {
|
234
|
+
call.reject(ERROR_AUDIO_ID_MISSING + " - " + audioId);
|
235
|
+
return;
|
236
|
+
}
|
233
237
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
+
if (audioAssetList.containsKey(audioId)) {
|
239
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
240
|
+
if (asset != null) {
|
241
|
+
call.resolve(new JSObject().put("currentTime", asset.getCurrentPosition()));
|
242
|
+
}
|
243
|
+
} else {
|
244
|
+
call.reject(ERROR_AUDIO_ASSET_MISSING + " - " + audioId);
|
245
|
+
}
|
246
|
+
} catch (Exception ex) {
|
247
|
+
call.reject(ex.getMessage());
|
238
248
|
}
|
239
|
-
} else {
|
240
|
-
call.reject(ERROR_AUDIO_ASSET_MISSING + " - " + audioId);
|
241
|
-
}
|
242
|
-
} catch (Exception ex) {
|
243
|
-
call.reject(ex.getMessage());
|
244
249
|
}
|
245
|
-
}
|
246
|
-
|
247
|
-
@PluginMethod
|
248
|
-
public void loop(final PluginCall call) {
|
249
|
-
this.getActivity()
|
250
|
-
.runOnUiThread(
|
251
|
-
new Runnable() {
|
252
|
-
@Override
|
253
|
-
public void run() {
|
254
|
-
playOrLoop("loop", call);
|
255
|
-
}
|
256
|
-
}
|
257
|
-
);
|
258
|
-
}
|
259
250
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
251
|
+
@PluginMethod
|
252
|
+
public void getDuration(PluginCall call) {
|
253
|
+
try {
|
254
|
+
String audioId = call.getString(ASSET_ID);
|
255
|
+
if (!isStringValid(audioId)) {
|
256
|
+
call.reject(ERROR_AUDIO_ID_MISSING + " - " + audioId);
|
257
|
+
return;
|
258
|
+
}
|
265
259
|
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
260
|
+
if (audioAssetList.containsKey(audioId)) {
|
261
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
262
|
+
if (asset != null) {
|
263
|
+
double duration = asset.getDuration();
|
264
|
+
if (duration > 0) {
|
265
|
+
JSObject ret = new JSObject();
|
266
|
+
ret.put("duration", duration);
|
267
|
+
call.resolve(ret);
|
268
|
+
} else {
|
269
|
+
// Save the call to resolve it later when duration is available
|
270
|
+
saveDurationCall(audioId, call);
|
271
|
+
}
|
272
|
+
} else {
|
273
|
+
call.reject(ERROR_ASSET_NOT_LOADED + " - " + audioId);
|
274
|
+
}
|
275
|
+
} else {
|
276
|
+
call.reject(ERROR_ASSET_NOT_LOADED + " - " + audioId);
|
277
|
+
}
|
278
|
+
} catch (Exception ex) {
|
279
|
+
call.reject(ex.getMessage());
|
277
280
|
}
|
278
|
-
} else {
|
279
|
-
call.reject(ERROR_ASSET_NOT_LOADED + " - " + audioId);
|
280
|
-
}
|
281
|
-
} catch (Exception ex) {
|
282
|
-
call.reject(ex.getMessage());
|
283
281
|
}
|
284
|
-
}
|
285
282
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
283
|
+
@PluginMethod
|
284
|
+
public void loop(final PluginCall call) {
|
285
|
+
this.getActivity()
|
286
|
+
.runOnUiThread(
|
287
|
+
new Runnable() {
|
288
|
+
@Override
|
289
|
+
public void run() {
|
290
|
+
playOrLoop("loop", call);
|
291
|
+
}
|
292
|
+
}
|
293
|
+
);
|
294
|
+
}
|
291
295
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
296
|
+
@PluginMethod
|
297
|
+
public void pause(PluginCall call) {
|
298
|
+
try {
|
299
|
+
initSoundPool();
|
300
|
+
String audioId = call.getString(ASSET_ID);
|
301
|
+
|
302
|
+
if (audioAssetList.containsKey(audioId)) {
|
303
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
304
|
+
if (asset != null) {
|
305
|
+
boolean wasPlaying = asset.pause();
|
306
|
+
|
307
|
+
if (wasPlaying) {
|
308
|
+
resumeList.add(asset);
|
309
|
+
}
|
310
|
+
call.resolve();
|
311
|
+
} else {
|
312
|
+
call.reject(ERROR_ASSET_NOT_LOADED + " - " + audioId);
|
313
|
+
}
|
314
|
+
} else {
|
315
|
+
call.reject(ERROR_ASSET_NOT_LOADED + " - " + audioId);
|
316
|
+
}
|
317
|
+
} catch (Exception ex) {
|
318
|
+
call.reject(ex.getMessage());
|
300
319
|
}
|
301
|
-
} else {
|
302
|
-
call.reject(ERROR_ASSET_NOT_LOADED + " - " + audioId);
|
303
|
-
}
|
304
|
-
} catch (Exception ex) {
|
305
|
-
call.reject(ex.getMessage());
|
306
320
|
}
|
307
|
-
}
|
308
321
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
322
|
+
@PluginMethod
|
323
|
+
public void resume(PluginCall call) {
|
324
|
+
try {
|
325
|
+
initSoundPool();
|
326
|
+
String audioId = call.getString(ASSET_ID);
|
327
|
+
|
328
|
+
if (audioAssetList.containsKey(audioId)) {
|
329
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
330
|
+
if (asset != null) {
|
331
|
+
asset.resume();
|
332
|
+
resumeList.add(asset);
|
333
|
+
call.resolve();
|
334
|
+
} else {
|
335
|
+
call.reject(ERROR_ASSET_NOT_LOADED + " - " + audioId);
|
336
|
+
}
|
337
|
+
} else {
|
338
|
+
call.reject(ERROR_ASSET_NOT_LOADED + " - " + audioId);
|
339
|
+
}
|
340
|
+
} catch (Exception ex) {
|
341
|
+
call.reject(ex.getMessage());
|
342
|
+
}
|
343
|
+
}
|
314
344
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
345
|
+
@PluginMethod
|
346
|
+
public void stop(final PluginCall call) {
|
347
|
+
this.getActivity()
|
348
|
+
.runOnUiThread(
|
349
|
+
new Runnable() {
|
350
|
+
@Override
|
351
|
+
public void run() {
|
352
|
+
try {
|
353
|
+
String audioId = call.getString(ASSET_ID);
|
354
|
+
if (!isStringValid(audioId)) {
|
355
|
+
call.reject(ERROR_AUDIO_ID_MISSING + " - " + audioId);
|
356
|
+
return;
|
357
|
+
}
|
358
|
+
stopAudio(audioId);
|
359
|
+
call.resolve();
|
360
|
+
} catch (Exception ex) {
|
361
|
+
call.reject(ex.getMessage());
|
362
|
+
}
|
363
|
+
}
|
364
|
+
}
|
365
|
+
);
|
366
|
+
}
|
367
|
+
|
368
|
+
@PluginMethod
|
369
|
+
public void unload(PluginCall call) {
|
370
|
+
try {
|
371
|
+
initSoundPool();
|
372
|
+
new JSObject();
|
373
|
+
JSObject status;
|
374
|
+
|
375
|
+
if (isStringValid(call.getString(ASSET_ID))) {
|
376
|
+
String audioId = call.getString(ASSET_ID);
|
377
|
+
|
378
|
+
if (audioAssetList.containsKey(audioId)) {
|
379
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
380
|
+
if (asset != null) {
|
381
|
+
asset.unload();
|
382
|
+
audioAssetList.remove(audioId);
|
383
|
+
call.resolve();
|
384
|
+
} else {
|
385
|
+
call.reject(ERROR_AUDIO_ASSET_MISSING + " - " + audioId);
|
386
|
+
}
|
387
|
+
} else {
|
388
|
+
call.reject(ERROR_AUDIO_ASSET_MISSING + " - " + audioId);
|
389
|
+
}
|
390
|
+
} else {
|
391
|
+
call.reject(ERROR_AUDIO_ID_MISSING);
|
392
|
+
}
|
393
|
+
} catch (Exception ex) {
|
394
|
+
call.reject(ex.getMessage());
|
322
395
|
}
|
323
|
-
} else {
|
324
|
-
call.reject(ERROR_ASSET_NOT_LOADED + " - " + audioId);
|
325
|
-
}
|
326
|
-
} catch (Exception ex) {
|
327
|
-
call.reject(ex.getMessage());
|
328
396
|
}
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
397
|
+
|
398
|
+
@PluginMethod
|
399
|
+
public void setVolume(PluginCall call) {
|
400
|
+
try {
|
401
|
+
initSoundPool();
|
402
|
+
|
403
|
+
String audioId = call.getString(ASSET_ID);
|
404
|
+
float volume = call.getFloat(VOLUME, 1F);
|
405
|
+
|
406
|
+
if (audioAssetList.containsKey(audioId)) {
|
407
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
408
|
+
if (asset != null) {
|
409
|
+
asset.setVolume(volume);
|
410
|
+
call.resolve();
|
411
|
+
} else {
|
412
|
+
call.reject(ERROR_AUDIO_ASSET_MISSING);
|
413
|
+
}
|
414
|
+
} else {
|
415
|
+
call.reject(ERROR_AUDIO_ASSET_MISSING);
|
416
|
+
}
|
417
|
+
} catch (Exception ex) {
|
418
|
+
call.reject(ex.getMessage());
|
419
|
+
}
|
420
|
+
}
|
421
|
+
|
422
|
+
@PluginMethod
|
423
|
+
public void setRate(PluginCall call) {
|
424
|
+
try {
|
425
|
+
initSoundPool();
|
426
|
+
|
427
|
+
String audioId = call.getString(ASSET_ID);
|
428
|
+
float rate = call.getFloat(RATE, 1F);
|
429
|
+
|
430
|
+
if (audioAssetList.containsKey(audioId)) {
|
431
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
432
|
+
if (asset != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
433
|
+
asset.setRate(rate);
|
434
|
+
}
|
435
|
+
call.resolve();
|
436
|
+
} else {
|
437
|
+
call.reject(ERROR_AUDIO_ASSET_MISSING);
|
438
|
+
}
|
439
|
+
} catch (Exception ex) {
|
440
|
+
call.reject(ex.getMessage());
|
352
441
|
}
|
353
|
-
} else {
|
354
|
-
call.reject(ERROR_AUDIO_ID_MISSING);
|
355
|
-
}
|
356
|
-
} catch (Exception ex) {
|
357
|
-
call.reject(ex.getMessage());
|
358
442
|
}
|
359
|
-
}
|
360
443
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
444
|
+
@PluginMethod
|
445
|
+
public void isPlaying(final PluginCall call) {
|
446
|
+
try {
|
447
|
+
initSoundPool();
|
365
448
|
|
366
|
-
|
367
|
-
float volume = call.getFloat(VOLUME, 1F);
|
449
|
+
String audioId = call.getString(ASSET_ID);
|
368
450
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
451
|
+
if (!isStringValid(audioId)) {
|
452
|
+
call.reject(ERROR_AUDIO_ID_MISSING + " - " + audioId);
|
453
|
+
return;
|
454
|
+
}
|
455
|
+
|
456
|
+
if (audioAssetList.containsKey(audioId)) {
|
457
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
458
|
+
if (asset != null) {
|
459
|
+
call.resolve(new JSObject().put("isPlaying", asset.isPlaying()));
|
460
|
+
} else {
|
461
|
+
call.reject(ERROR_AUDIO_ASSET_MISSING + " - " + audioId);
|
462
|
+
}
|
463
|
+
} else {
|
464
|
+
call.reject(ERROR_AUDIO_ASSET_MISSING + " - " + audioId);
|
465
|
+
}
|
466
|
+
} catch (Exception ex) {
|
467
|
+
call.reject(ex.getMessage());
|
376
468
|
}
|
377
|
-
} else {
|
378
|
-
call.reject(ERROR_AUDIO_ASSET_MISSING);
|
379
|
-
}
|
380
|
-
} catch (Exception ex) {
|
381
|
-
call.reject(ex.getMessage());
|
382
469
|
}
|
383
|
-
}
|
384
470
|
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
471
|
+
@PluginMethod
|
472
|
+
public void clearCache(PluginCall call) {
|
473
|
+
RemoteAudioAsset.clearCache(getContext());
|
474
|
+
call.resolve();
|
475
|
+
}
|
476
|
+
|
477
|
+
@PluginMethod
|
478
|
+
public void setCurrentTime(final PluginCall call) {
|
479
|
+
try {
|
480
|
+
initSoundPool();
|
389
481
|
|
390
|
-
|
391
|
-
|
482
|
+
String audioId = call.getString(ASSET_ID);
|
483
|
+
Double time = call.getDouble("time", 0.0);
|
392
484
|
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
485
|
+
if (!isStringValid(audioId)) {
|
486
|
+
call.reject(ERROR_AUDIO_ID_MISSING + " - " + audioId);
|
487
|
+
return;
|
488
|
+
}
|
489
|
+
|
490
|
+
if (audioAssetList.containsKey(audioId)) {
|
491
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
492
|
+
if (asset != null) {
|
493
|
+
this.getActivity()
|
494
|
+
.runOnUiThread(
|
495
|
+
new Runnable() {
|
496
|
+
@Override
|
497
|
+
public void run() {
|
498
|
+
try {
|
499
|
+
asset.setCurrentTime(time);
|
500
|
+
call.resolve();
|
501
|
+
} catch (Exception e) {
|
502
|
+
call.reject("Error setting current time: " + e.getMessage());
|
503
|
+
}
|
504
|
+
}
|
505
|
+
}
|
506
|
+
);
|
507
|
+
} else {
|
508
|
+
call.reject(ERROR_ASSET_NOT_LOADED + " - " + audioId);
|
509
|
+
}
|
510
|
+
} else {
|
511
|
+
call.reject(ERROR_ASSET_NOT_LOADED + " - " + audioId);
|
512
|
+
}
|
513
|
+
} catch (Exception ex) {
|
514
|
+
call.reject(ex.getMessage());
|
397
515
|
}
|
398
|
-
call.resolve();
|
399
|
-
} else {
|
400
|
-
call.reject(ERROR_AUDIO_ASSET_MISSING);
|
401
|
-
}
|
402
|
-
} catch (Exception ex) {
|
403
|
-
call.reject(ex.getMessage());
|
404
516
|
}
|
405
|
-
}
|
406
517
|
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
518
|
+
public void dispatchComplete(String assetId) {
|
519
|
+
JSObject ret = new JSObject();
|
520
|
+
ret.put("assetId", assetId);
|
521
|
+
notifyListeners("complete", ret);
|
522
|
+
}
|
411
523
|
|
412
|
-
|
524
|
+
public void notifyCurrentTime(String assetId, double currentTime) {
|
525
|
+
// Round to nearest 100ms
|
526
|
+
double roundedTime = Math.round(currentTime * 10.0) / 10.0;
|
527
|
+
JSObject ret = new JSObject();
|
528
|
+
ret.put("currentTime", roundedTime);
|
529
|
+
ret.put("assetId", assetId);
|
530
|
+
notifyListeners("currentTime", ret);
|
531
|
+
}
|
413
532
|
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
533
|
+
private void preloadAsset(PluginCall call) {
|
534
|
+
float volume = 1F;
|
535
|
+
int audioChannelNum = 1;
|
536
|
+
JSObject status = new JSObject();
|
537
|
+
status.put("STATUS", "OK");
|
418
538
|
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
539
|
+
try {
|
540
|
+
initSoundPool();
|
541
|
+
|
542
|
+
String audioId = call.getString(ASSET_ID);
|
543
|
+
if (!isStringValid(audioId)) {
|
544
|
+
call.reject(ERROR_AUDIO_ID_MISSING + " - " + audioId);
|
545
|
+
return;
|
546
|
+
}
|
547
|
+
|
548
|
+
String assetPath = call.getString(ASSET_PATH);
|
549
|
+
if (!isStringValid(assetPath)) {
|
550
|
+
call.reject(ERROR_ASSET_PATH_MISSING + " - " + audioId + " - " + assetPath);
|
551
|
+
return;
|
552
|
+
}
|
553
|
+
|
554
|
+
boolean isLocalUrl = call.getBoolean("isUrl", false);
|
555
|
+
boolean isComplex = call.getBoolean("isComplex", false);
|
556
|
+
|
557
|
+
Log.d("AudioPlugin", "Debug: audioId = " + audioId + ", assetPath = " + assetPath + ", isLocalUrl = " + isLocalUrl);
|
558
|
+
|
559
|
+
if (audioAssetList.containsKey(audioId)) {
|
560
|
+
call.reject(ERROR_AUDIO_EXISTS + " - " + audioId);
|
561
|
+
return;
|
562
|
+
}
|
563
|
+
|
564
|
+
if (isComplex) {
|
565
|
+
volume = call.getFloat(VOLUME, 1F);
|
566
|
+
audioChannelNum = call.getInt(AUDIO_CHANNEL_NUM, 1);
|
567
|
+
}
|
568
|
+
|
569
|
+
if (isLocalUrl) {
|
570
|
+
try {
|
571
|
+
Uri uri = Uri.parse(assetPath);
|
572
|
+
if (uri.getScheme() != null && (uri.getScheme().equals("http") || uri.getScheme().equals("https"))) {
|
573
|
+
// Remote URL
|
574
|
+
Log.d("AudioPlugin", "Debug: Remote URL detected: " + uri.toString());
|
575
|
+
if (assetPath.endsWith(".m3u8")) {
|
576
|
+
// HLS Stream - resolve immediately since it's a stream
|
577
|
+
StreamAudioAsset streamAudioAsset = new StreamAudioAsset(this, audioId, uri, volume);
|
578
|
+
audioAssetList.put(audioId, streamAudioAsset);
|
579
|
+
call.resolve(status);
|
580
|
+
} else {
|
581
|
+
// Regular remote audio
|
582
|
+
RemoteAudioAsset remoteAudioAsset = new RemoteAudioAsset(this, audioId, uri, audioChannelNum, volume);
|
583
|
+
remoteAudioAsset.setCompletionListener(this::dispatchComplete);
|
584
|
+
audioAssetList.put(audioId, remoteAudioAsset);
|
585
|
+
call.resolve(status);
|
586
|
+
}
|
587
|
+
} else if (uri.getScheme() != null && uri.getScheme().equals("file")) {
|
588
|
+
// Local file URL
|
589
|
+
Log.d("AudioPlugin", "Debug: Local file URL detected");
|
590
|
+
File file = new File(uri.getPath());
|
591
|
+
if (!file.exists()) {
|
592
|
+
Log.e("AudioPlugin", "Error: File does not exist - " + file.getAbsolutePath());
|
593
|
+
call.reject(ERROR_ASSET_PATH_MISSING + " - " + assetPath);
|
594
|
+
return;
|
595
|
+
}
|
596
|
+
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
|
597
|
+
AssetFileDescriptor afd = new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH);
|
598
|
+
AudioAsset asset = new AudioAsset(this, audioId, afd, audioChannelNum, volume);
|
599
|
+
asset.setCompletionListener(this::dispatchComplete);
|
600
|
+
audioAssetList.put(audioId, asset);
|
601
|
+
call.resolve(status);
|
602
|
+
} else {
|
603
|
+
throw new IllegalArgumentException("Invalid URL scheme: " + uri.getScheme());
|
604
|
+
}
|
605
|
+
} catch (Exception e) {
|
606
|
+
Log.e("AudioPlugin", "Error handling URL", e);
|
607
|
+
call.reject("Error handling URL: " + e.getMessage());
|
608
|
+
}
|
609
|
+
} else {
|
610
|
+
// Handle asset in public folder
|
611
|
+
Log.d("AudioPlugin", "Debug: Handling asset in public folder");
|
612
|
+
if (!assetPath.startsWith("public/")) {
|
613
|
+
assetPath = "public/" + assetPath;
|
614
|
+
}
|
615
|
+
try {
|
616
|
+
Context ctx = getContext().getApplicationContext();
|
617
|
+
AssetManager am = ctx.getResources().getAssets();
|
618
|
+
AssetFileDescriptor assetFileDescriptor = am.openFd(assetPath);
|
619
|
+
AudioAsset asset = new AudioAsset(this, audioId, assetFileDescriptor, audioChannelNum, volume);
|
620
|
+
audioAssetList.put(audioId, asset);
|
621
|
+
call.resolve(status);
|
622
|
+
} catch (IOException e) {
|
623
|
+
Log.e("AudioPlugin", "Error opening asset: " + assetPath, e);
|
624
|
+
call.reject(ERROR_ASSET_PATH_MISSING + " - " + assetPath);
|
625
|
+
}
|
626
|
+
}
|
627
|
+
} catch (Exception ex) {
|
628
|
+
Log.e("AudioPlugin", "Error in preloadAsset", ex);
|
629
|
+
call.reject("Error in preloadAsset: " + ex.getMessage());
|
425
630
|
}
|
426
|
-
} else {
|
427
|
-
call.reject(ERROR_AUDIO_ASSET_MISSING + " - " + audioId);
|
428
|
-
}
|
429
|
-
} catch (Exception ex) {
|
430
|
-
call.reject(ex.getMessage());
|
431
631
|
}
|
432
|
-
|
433
|
-
|
434
|
-
public void dispatchComplete(String assetId) {
|
435
|
-
JSObject ret = new JSObject();
|
436
|
-
ret.put("assetId", assetId);
|
437
|
-
notifyListeners("complete", ret);
|
438
|
-
}
|
439
|
-
|
440
|
-
private void preloadAsset(PluginCall call) {
|
441
|
-
float volume = 1F;
|
442
|
-
int audioChannelNum = 1;
|
443
|
-
JSObject status = new JSObject();
|
444
|
-
status.put("STATUS", "OK");
|
445
|
-
|
446
|
-
try {
|
447
|
-
initSoundPool();
|
448
|
-
|
449
|
-
String audioId = call.getString(ASSET_ID);
|
450
|
-
if (!isStringValid(audioId)) {
|
451
|
-
call.reject(ERROR_AUDIO_ID_MISSING + " - " + audioId);
|
452
|
-
return;
|
453
|
-
}
|
454
|
-
|
455
|
-
String assetPath = call.getString(ASSET_PATH);
|
456
|
-
if (!isStringValid(assetPath)) {
|
457
|
-
call.reject(
|
458
|
-
ERROR_ASSET_PATH_MISSING + " - " + audioId + " - " + assetPath
|
459
|
-
);
|
460
|
-
return;
|
461
|
-
}
|
462
|
-
|
463
|
-
boolean isLocalUrl = call.getBoolean("isUrl", false);
|
464
|
-
boolean isComplex = call.getBoolean("isComplex", false);
|
465
|
-
|
466
|
-
Log.d(
|
467
|
-
"AudioPlugin",
|
468
|
-
"Debug: audioId = " +
|
469
|
-
audioId +
|
470
|
-
", assetPath = " +
|
471
|
-
assetPath +
|
472
|
-
", isLocalUrl = " +
|
473
|
-
isLocalUrl
|
474
|
-
);
|
475
|
-
|
476
|
-
if (audioAssetList.containsKey(audioId)) {
|
477
|
-
call.reject(ERROR_AUDIO_EXISTS + " - " + audioId);
|
478
|
-
return;
|
479
|
-
}
|
480
|
-
|
481
|
-
if (isComplex) {
|
482
|
-
volume = call.getFloat(VOLUME, 1F);
|
483
|
-
audioChannelNum = call.getInt(AUDIO_CHANNEL_NUM, 1);
|
484
|
-
}
|
485
|
-
|
486
|
-
if (isLocalUrl) {
|
487
|
-
// Handle URL (both remote and local file URLs)
|
488
|
-
Log.d("AudioPlugin", "Debug: Handling URL");
|
632
|
+
|
633
|
+
private void playOrLoop(String action, final PluginCall call) {
|
489
634
|
try {
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
File file = new File(uri.getPath());
|
515
|
-
if (!file.exists()) {
|
516
|
-
Log.e(
|
517
|
-
"AudioPlugin",
|
518
|
-
"Error: File does not exist - " + file.getAbsolutePath()
|
519
|
-
);
|
520
|
-
call.reject(ERROR_ASSET_PATH_MISSING + " - " + assetPath);
|
521
|
-
return;
|
635
|
+
final String audioId = call.getString(ASSET_ID);
|
636
|
+
final Double time = call.getDouble("time", 0.0);
|
637
|
+
Log.d(TAG, "Playing asset: " + audioId + ", action: " + action + ", assets count: " + audioAssetList.size());
|
638
|
+
|
639
|
+
if (audioAssetList.containsKey(audioId)) {
|
640
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
641
|
+
Log.d(TAG, "Found asset: " + audioId + ", type: " + asset.getClass().getSimpleName());
|
642
|
+
|
643
|
+
if (asset != null) {
|
644
|
+
if (LOOP.equals(action)) {
|
645
|
+
asset.loop();
|
646
|
+
} else {
|
647
|
+
if (fadeMusic) {
|
648
|
+
asset.playWithFade(time);
|
649
|
+
} else {
|
650
|
+
asset.play(time);
|
651
|
+
}
|
652
|
+
}
|
653
|
+
call.resolve();
|
654
|
+
} else {
|
655
|
+
call.reject("Asset is null: " + audioId);
|
656
|
+
}
|
657
|
+
} else {
|
658
|
+
call.reject("Asset not found: " + audioId);
|
522
659
|
}
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
);
|
527
|
-
AssetFileDescriptor afd = new AssetFileDescriptor(
|
528
|
-
pfd,
|
529
|
-
0,
|
530
|
-
AssetFileDescriptor.UNKNOWN_LENGTH
|
531
|
-
);
|
532
|
-
AudioAsset asset = new AudioAsset(
|
533
|
-
this,
|
534
|
-
audioId,
|
535
|
-
afd,
|
536
|
-
audioChannelNum,
|
537
|
-
volume
|
538
|
-
);
|
539
|
-
asset.setCompletionListener(this::dispatchComplete);
|
540
|
-
audioAssetList.put(audioId, asset);
|
541
|
-
} else {
|
542
|
-
throw new IllegalArgumentException(
|
543
|
-
"Invalid URL scheme: " + uri.getScheme()
|
544
|
-
);
|
545
|
-
}
|
546
|
-
call.resolve(status);
|
547
|
-
} catch (Exception e) {
|
548
|
-
Log.e("AudioPlugin", "Error handling URL", e);
|
549
|
-
call.reject("Error handling URL: " + e.getMessage());
|
660
|
+
} catch (Exception ex) {
|
661
|
+
Log.e(TAG, "Error in playOrLoop", ex);
|
662
|
+
call.reject(ex.getMessage());
|
550
663
|
}
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
if (
|
555
|
-
|
664
|
+
}
|
665
|
+
|
666
|
+
private void initSoundPool() {
|
667
|
+
if (audioAssetList == null) {
|
668
|
+
audioAssetList = new HashMap<>();
|
556
669
|
}
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
AssetFileDescriptor assetFileDescriptor = am.openFd(assetPath);
|
561
|
-
AudioAsset asset = new AudioAsset(
|
562
|
-
this,
|
563
|
-
audioId,
|
564
|
-
assetFileDescriptor,
|
565
|
-
audioChannelNum,
|
566
|
-
volume
|
567
|
-
);
|
568
|
-
audioAssetList.put(audioId, asset);
|
569
|
-
call.resolve(status);
|
570
|
-
} catch (IOException e) {
|
571
|
-
Log.e("AudioPlugin", "Error opening asset: " + assetPath, e);
|
572
|
-
call.reject(ERROR_ASSET_PATH_MISSING + " - " + assetPath);
|
670
|
+
|
671
|
+
if (resumeList == null) {
|
672
|
+
resumeList = new ArrayList<>();
|
573
673
|
}
|
574
|
-
}
|
575
|
-
} catch (Exception ex) {
|
576
|
-
Log.e("AudioPlugin", "Error in preloadAsset", ex);
|
577
|
-
call.reject("Error in preloadAsset: " + ex.getMessage());
|
578
674
|
}
|
579
|
-
}
|
580
675
|
|
581
|
-
|
582
|
-
|
583
|
-
|
676
|
+
private boolean isStringValid(String value) {
|
677
|
+
return (value != null && !value.isEmpty() && !value.equals("null"));
|
678
|
+
}
|
679
|
+
|
680
|
+
private void stopAudio(String audioId) throws Exception {
|
681
|
+
if (!audioAssetList.containsKey(audioId)) {
|
682
|
+
throw new Exception(ERROR_ASSET_NOT_LOADED);
|
683
|
+
}
|
584
684
|
|
585
|
-
final String audioId = call.getString(ASSET_ID);
|
586
|
-
final Double time = call.getDouble("time", 0.0);
|
587
|
-
if (audioAssetList.containsKey(audioId)) {
|
588
685
|
AudioAsset asset = audioAssetList.get(audioId);
|
589
|
-
if (
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
} else {
|
596
|
-
call.reject("Error with asset");
|
686
|
+
if (asset != null) {
|
687
|
+
if (fadeMusic) {
|
688
|
+
asset.stopWithFade();
|
689
|
+
} else {
|
690
|
+
asset.stop();
|
691
|
+
}
|
597
692
|
}
|
598
|
-
} else {
|
599
|
-
call.reject("Error with asset");
|
600
|
-
}
|
601
|
-
} catch (Exception ex) {
|
602
|
-
call.reject(ex.getMessage());
|
603
693
|
}
|
604
|
-
}
|
605
694
|
|
606
|
-
|
607
|
-
|
608
|
-
|
695
|
+
private void saveDurationCall(String audioId, PluginCall call) {
|
696
|
+
Log.d(TAG, "Saving duration call for later: " + audioId);
|
697
|
+
pendingDurationCalls.put(audioId, call);
|
609
698
|
}
|
610
699
|
|
611
|
-
|
612
|
-
|
700
|
+
public void notifyDurationAvailable(String assetId, double duration) {
|
701
|
+
Log.d(TAG, "Duration available for " + assetId + ": " + duration);
|
702
|
+
PluginCall savedCall = pendingDurationCalls.remove(assetId);
|
703
|
+
if (savedCall != null) {
|
704
|
+
JSObject ret = new JSObject();
|
705
|
+
ret.put("duration", duration);
|
706
|
+
savedCall.resolve(ret);
|
707
|
+
}
|
613
708
|
}
|
614
|
-
}
|
615
|
-
|
616
|
-
private boolean isStringValid(String value) {
|
617
|
-
return (value != null && !value.isEmpty() && !value.equals("null"));
|
618
|
-
}
|
619
709
|
}
|