@capgo/native-audio 4.0.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/CapgoNativeAudio.podspec +16 -0
- package/LICENSE +21 -0
- package/README.md +394 -0
- package/android/build.gradle +55 -0
- package/android/src/main/AndroidManifest.xml +5 -0
- package/android/src/main/java/ee/forgr/audio/AudioAsset.java +140 -0
- package/android/src/main/java/ee/forgr/audio/AudioDispatcher.java +178 -0
- package/android/src/main/java/ee/forgr/audio/Constant.java +18 -0
- package/android/src/main/java/ee/forgr/audio/NativeAudio.java +471 -0
- package/android/src/main/res/layout/bridge_layout_main.xml +15 -0
- package/android/src/main/res/values/colors.xml +3 -0
- package/android/src/main/res/values/strings.xml +3 -0
- package/android/src/main/res/values/styles.xml +3 -0
- package/dist/docs.json +279 -0
- package/dist/esm/audio-asset.d.ts +4 -0
- package/dist/esm/audio-asset.js +6 -0
- package/dist/esm/audio-asset.js.map +1 -0
- package/dist/esm/definitions.d.ts +53 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +52 -0
- package/dist/esm/web.js +113 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +134 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +137 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Plugin/AudioAsset.swift +184 -0
- package/ios/Plugin/Constant.swift +20 -0
- package/ios/Plugin/Info.plist +24 -0
- package/ios/Plugin/Plugin.h +10 -0
- package/ios/Plugin/Plugin.m +19 -0
- package/ios/Plugin/Plugin.swift +276 -0
- package/package.json +91 -0
@@ -0,0 +1,178 @@
|
|
1
|
+
package ee.forgr.audio;
|
2
|
+
|
3
|
+
import android.content.res.AssetFileDescriptor;
|
4
|
+
import android.media.AudioAttributes;
|
5
|
+
import android.media.MediaPlayer;
|
6
|
+
import android.os.Build;
|
7
|
+
import android.os.SystemClock;
|
8
|
+
import android.util.Log;
|
9
|
+
import java.util.concurrent.Callable;
|
10
|
+
|
11
|
+
public class AudioDispatcher
|
12
|
+
implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnSeekCompleteListener {
|
13
|
+
|
14
|
+
private final String TAG = "AudioDispatcher";
|
15
|
+
|
16
|
+
private final int INVALID = 0;
|
17
|
+
private final int PREPARED = 1;
|
18
|
+
private final int PENDING_PLAY = 2;
|
19
|
+
private final int PLAYING = 3;
|
20
|
+
private final int PENDING_LOOP = 4;
|
21
|
+
private final int LOOPING = 5;
|
22
|
+
private final int PAUSE = 6;
|
23
|
+
|
24
|
+
private MediaPlayer mediaPlayer;
|
25
|
+
private int mediaState;
|
26
|
+
private AudioAsset owner;
|
27
|
+
|
28
|
+
public AudioDispatcher(AssetFileDescriptor assetFileDescriptor, float volume) throws Exception {
|
29
|
+
mediaState = INVALID;
|
30
|
+
|
31
|
+
mediaPlayer = new MediaPlayer();
|
32
|
+
mediaPlayer.setOnCompletionListener(this);
|
33
|
+
mediaPlayer.setOnPreparedListener(this);
|
34
|
+
mediaPlayer.setDataSource(
|
35
|
+
assetFileDescriptor.getFileDescriptor(),
|
36
|
+
assetFileDescriptor.getStartOffset(),
|
37
|
+
assetFileDescriptor.getLength()
|
38
|
+
);
|
39
|
+
mediaPlayer.setOnSeekCompleteListener(this);
|
40
|
+
mediaPlayer.setAudioAttributes(
|
41
|
+
new AudioAttributes.Builder()
|
42
|
+
.setUsage(AudioAttributes.USAGE_MEDIA)
|
43
|
+
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
44
|
+
.build()
|
45
|
+
);
|
46
|
+
mediaPlayer.setVolume(volume, volume);
|
47
|
+
mediaPlayer.prepare();
|
48
|
+
}
|
49
|
+
|
50
|
+
public void setOwner(AudioAsset asset) {
|
51
|
+
owner = asset;
|
52
|
+
}
|
53
|
+
|
54
|
+
public double getDuration() {
|
55
|
+
return mediaPlayer.getDuration() / 1000.0;
|
56
|
+
}
|
57
|
+
|
58
|
+
public double getCurrentPosition() {
|
59
|
+
return mediaPlayer.getCurrentPosition() / 1000.0;
|
60
|
+
}
|
61
|
+
|
62
|
+
public void play(Double time, Callable<Void> callable) throws Exception {
|
63
|
+
invokePlay(time, false);
|
64
|
+
}
|
65
|
+
|
66
|
+
public boolean pause() throws Exception {
|
67
|
+
if (mediaPlayer.isPlaying()) {
|
68
|
+
mediaPlayer.pause();
|
69
|
+
mediaState = PAUSE;
|
70
|
+
return true;
|
71
|
+
}
|
72
|
+
|
73
|
+
return false;
|
74
|
+
}
|
75
|
+
|
76
|
+
public void resume() throws Exception {
|
77
|
+
mediaPlayer.start();
|
78
|
+
}
|
79
|
+
|
80
|
+
public void stop() throws Exception {
|
81
|
+
if (mediaPlayer.isPlaying()) {
|
82
|
+
mediaState = INVALID;
|
83
|
+
mediaPlayer.pause();
|
84
|
+
mediaPlayer.seekTo(0);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
public void setVolume(float volume) throws Exception {
|
89
|
+
mediaPlayer.setVolume(volume, volume);
|
90
|
+
}
|
91
|
+
|
92
|
+
public void loop() throws Exception {
|
93
|
+
mediaPlayer.setLooping(true);
|
94
|
+
}
|
95
|
+
|
96
|
+
public void unload() throws Exception {
|
97
|
+
this.stop();
|
98
|
+
mediaPlayer.release();
|
99
|
+
}
|
100
|
+
|
101
|
+
@Override
|
102
|
+
public void onCompletion(MediaPlayer mp) {
|
103
|
+
try {
|
104
|
+
if (mediaState != LOOPING) {
|
105
|
+
this.mediaState = INVALID;
|
106
|
+
|
107
|
+
this.stop();
|
108
|
+
|
109
|
+
if (this.owner != null) {
|
110
|
+
this.owner.dispatchComplete();
|
111
|
+
}
|
112
|
+
}
|
113
|
+
} catch (Exception ex) {
|
114
|
+
Log.d(TAG, "Caught exception while listening for onCompletion: " + ex.getLocalizedMessage());
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
118
|
+
@Override
|
119
|
+
public void onPrepared(MediaPlayer mp) {
|
120
|
+
try {
|
121
|
+
if (mediaState == PENDING_PLAY) {
|
122
|
+
mediaPlayer.setLooping(false);
|
123
|
+
} else if (mediaState == PENDING_LOOP) {
|
124
|
+
mediaPlayer.setLooping(true);
|
125
|
+
} else {
|
126
|
+
mediaState = PREPARED;
|
127
|
+
}
|
128
|
+
} catch (Exception ex) {
|
129
|
+
Log.d(TAG, "Caught exception while listening for onPrepared: " + ex.getLocalizedMessage());
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
private void seek(Double time) {
|
134
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
135
|
+
mediaPlayer.seekTo((int) (time * 1000), MediaPlayer.SEEK_NEXT_SYNC);
|
136
|
+
} else {
|
137
|
+
mediaPlayer.seekTo((int) (time * 1000));
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
private void invokePlay(Double time, Boolean loop) {
|
142
|
+
try {
|
143
|
+
boolean playing = mediaPlayer.isPlaying();
|
144
|
+
|
145
|
+
if (playing) {
|
146
|
+
mediaPlayer.pause();
|
147
|
+
mediaPlayer.setLooping(loop);
|
148
|
+
mediaState = PENDING_PLAY;
|
149
|
+
seek(time);
|
150
|
+
} else {
|
151
|
+
if (mediaState == PREPARED) {
|
152
|
+
mediaState = (loop ? PENDING_LOOP : PENDING_PLAY);
|
153
|
+
onPrepared(mediaPlayer);
|
154
|
+
seek(time);
|
155
|
+
} else {
|
156
|
+
mediaState = (loop ? PENDING_LOOP : PENDING_PLAY);
|
157
|
+
mediaPlayer.setLooping(loop);
|
158
|
+
seek(time);
|
159
|
+
}
|
160
|
+
}
|
161
|
+
} catch (Exception ex) {
|
162
|
+
Log.d(TAG, "Caught exception while invoking audio: " + ex.getLocalizedMessage());
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
@Override
|
167
|
+
public void onSeekComplete(MediaPlayer mp) {
|
168
|
+
if (mediaState == PENDING_PLAY || mediaState == PENDING_LOOP) {
|
169
|
+
Log.w("AudioDispatcher", "play " + mediaState);
|
170
|
+
mediaPlayer.start();
|
171
|
+
mediaState = PLAYING;
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
public boolean isPlaying() throws Exception {
|
176
|
+
return mediaPlayer.isPlaying();
|
177
|
+
}
|
178
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
package ee.forgr.audio;
|
2
|
+
|
3
|
+
public class Constant {
|
4
|
+
|
5
|
+
public static final String ERROR_AUDIO_ID_MISSING = "Audio Id is missing";
|
6
|
+
public static final String ERROR_AUDIO_ASSET_MISSING = "Audio Asset is missing";
|
7
|
+
public static final String ERROR_AUDIO_EXISTS = "Audio Asset already exists";
|
8
|
+
public static final String ERROR_ASSET_PATH_MISSING = "Asset Path is missing";
|
9
|
+
public static final String ERROR_ASSET_NOT_LOADED = "Asset is not loaded";
|
10
|
+
|
11
|
+
public static final String ASSET_ID = "assetId";
|
12
|
+
public static final String ASSET_PATH = "assetPath";
|
13
|
+
public static final String OPT_FADE_MUSIC = "fade";
|
14
|
+
public static final String OPT_FOCUS_AUDIO = "focus";
|
15
|
+
public static final String VOLUME = "volume";
|
16
|
+
public static final String AUDIO_CHANNEL_NUM = "audioChannelNum";
|
17
|
+
public static final String LOOP = "loop";
|
18
|
+
}
|
@@ -0,0 +1,471 @@
|
|
1
|
+
package ee.forgr.audio;
|
2
|
+
|
3
|
+
import static ee.forgr.audio.Constant.ASSET_ID;
|
4
|
+
import static ee.forgr.audio.Constant.ASSET_PATH;
|
5
|
+
import static ee.forgr.audio.Constant.AUDIO_CHANNEL_NUM;
|
6
|
+
import static ee.forgr.audio.Constant.ERROR_ASSET_NOT_LOADED;
|
7
|
+
import static ee.forgr.audio.Constant.ERROR_ASSET_PATH_MISSING;
|
8
|
+
import static ee.forgr.audio.Constant.ERROR_AUDIO_ASSET_MISSING;
|
9
|
+
import static ee.forgr.audio.Constant.ERROR_AUDIO_EXISTS;
|
10
|
+
import static ee.forgr.audio.Constant.ERROR_AUDIO_ID_MISSING;
|
11
|
+
import static ee.forgr.audio.Constant.LOOP;
|
12
|
+
import static ee.forgr.audio.Constant.OPT_FADE_MUSIC;
|
13
|
+
import static ee.forgr.audio.Constant.OPT_FOCUS_AUDIO;
|
14
|
+
import static ee.forgr.audio.Constant.VOLUME;
|
15
|
+
|
16
|
+
import android.Manifest;
|
17
|
+
import android.content.Context;
|
18
|
+
import android.content.res.AssetFileDescriptor;
|
19
|
+
import android.content.res.AssetManager;
|
20
|
+
import android.media.AudioManager;
|
21
|
+
import android.os.ParcelFileDescriptor;
|
22
|
+
import android.util.Log;
|
23
|
+
import com.getcapacitor.JSObject;
|
24
|
+
import com.getcapacitor.Plugin;
|
25
|
+
import com.getcapacitor.PluginCall;
|
26
|
+
import com.getcapacitor.PluginMethod;
|
27
|
+
import com.getcapacitor.annotation.CapacitorPlugin;
|
28
|
+
import com.getcapacitor.annotation.Permission;
|
29
|
+
import java.io.File;
|
30
|
+
import java.net.URI;
|
31
|
+
import java.util.ArrayList;
|
32
|
+
import java.util.HashMap;
|
33
|
+
import java.util.concurrent.Callable;
|
34
|
+
|
35
|
+
@CapacitorPlugin(
|
36
|
+
permissions = {
|
37
|
+
@Permission(strings = { Manifest.permission.MODIFY_AUDIO_SETTINGS }),
|
38
|
+
@Permission(strings = { Manifest.permission.WRITE_EXTERNAL_STORAGE }),
|
39
|
+
@Permission(strings = { Manifest.permission.READ_PHONE_STATE })
|
40
|
+
}
|
41
|
+
)
|
42
|
+
public class NativeAudio extends Plugin implements AudioManager.OnAudioFocusChangeListener {
|
43
|
+
|
44
|
+
public static final String TAG = "NativeAudio";
|
45
|
+
|
46
|
+
private static HashMap<String, AudioAsset> audioAssetList;
|
47
|
+
private static ArrayList<AudioAsset> resumeList;
|
48
|
+
private boolean fadeMusic = false;
|
49
|
+
private AudioManager audioManager;
|
50
|
+
|
51
|
+
@Override
|
52
|
+
public void load() {
|
53
|
+
super.load();
|
54
|
+
|
55
|
+
this.audioManager = (AudioManager) getBridge().getActivity().getSystemService(Context.AUDIO_SERVICE);
|
56
|
+
}
|
57
|
+
|
58
|
+
@Override
|
59
|
+
public void onAudioFocusChange(int focusChange) {
|
60
|
+
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {} else if (
|
61
|
+
focusChange == AudioManager.AUDIOFOCUS_LOSS
|
62
|
+
) {}
|
63
|
+
}
|
64
|
+
|
65
|
+
@Override
|
66
|
+
protected void handleOnPause() {
|
67
|
+
super.handleOnPause();
|
68
|
+
|
69
|
+
try {
|
70
|
+
if (audioAssetList != null) {
|
71
|
+
for (HashMap.Entry<String, AudioAsset> entry : audioAssetList.entrySet()) {
|
72
|
+
AudioAsset audio = entry.getValue();
|
73
|
+
|
74
|
+
if (audio != null) {
|
75
|
+
boolean wasPlaying = audio.pause();
|
76
|
+
|
77
|
+
if (wasPlaying) {
|
78
|
+
resumeList.add(audio);
|
79
|
+
}
|
80
|
+
}
|
81
|
+
}
|
82
|
+
}
|
83
|
+
} catch (Exception ex) {
|
84
|
+
Log.d(TAG, "Exception caught while listening for handleOnPause: " + ex.getLocalizedMessage());
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
@Override
|
89
|
+
protected void handleOnResume() {
|
90
|
+
super.handleOnResume();
|
91
|
+
|
92
|
+
try {
|
93
|
+
if (resumeList != null) {
|
94
|
+
while (!resumeList.isEmpty()) {
|
95
|
+
AudioAsset audio = resumeList.remove(0);
|
96
|
+
|
97
|
+
if (audio != null) {
|
98
|
+
audio.resume();
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
} catch (Exception ex) {
|
103
|
+
Log.d(TAG, "Exception caught while listening for handleOnResume: " + ex.getLocalizedMessage());
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
@PluginMethod
|
108
|
+
public void configure(PluginCall call) {
|
109
|
+
initSoundPool();
|
110
|
+
|
111
|
+
if (call.hasOption(OPT_FADE_MUSIC)) this.fadeMusic = call.getBoolean(OPT_FADE_MUSIC);
|
112
|
+
|
113
|
+
if (call.hasOption(OPT_FOCUS_AUDIO) && this.audioManager != null) {
|
114
|
+
if (call.getBoolean(OPT_FOCUS_AUDIO)) {
|
115
|
+
this.audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
116
|
+
} else {
|
117
|
+
this.audioManager.abandonAudioFocus(this);
|
118
|
+
}
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
@PluginMethod
|
123
|
+
public void preload(final PluginCall call) {
|
124
|
+
new Thread(
|
125
|
+
new Runnable() {
|
126
|
+
@Override
|
127
|
+
public void run() {
|
128
|
+
preloadAsset(call);
|
129
|
+
}
|
130
|
+
}
|
131
|
+
)
|
132
|
+
.start();
|
133
|
+
}
|
134
|
+
|
135
|
+
@PluginMethod
|
136
|
+
public void play(final PluginCall call) {
|
137
|
+
getBridge()
|
138
|
+
.getActivity()
|
139
|
+
.runOnUiThread(
|
140
|
+
new Runnable() {
|
141
|
+
@Override
|
142
|
+
public void run() {
|
143
|
+
playOrLoop("play", call);
|
144
|
+
}
|
145
|
+
}
|
146
|
+
);
|
147
|
+
}
|
148
|
+
|
149
|
+
@PluginMethod
|
150
|
+
public void getCurrentTime(final PluginCall call) {
|
151
|
+
try {
|
152
|
+
initSoundPool();
|
153
|
+
|
154
|
+
String audioId = call.getString(ASSET_ID);
|
155
|
+
|
156
|
+
if (!isStringValid(audioId)) {
|
157
|
+
call.reject(ERROR_AUDIO_ID_MISSING + " - " + audioId);
|
158
|
+
return;
|
159
|
+
}
|
160
|
+
|
161
|
+
if (audioAssetList.containsKey(audioId)) {
|
162
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
163
|
+
if (asset != null) {
|
164
|
+
call.resolve(new JSObject().put("currentTime", asset.getCurrentPosition()));
|
165
|
+
}
|
166
|
+
} else {
|
167
|
+
call.reject(ERROR_AUDIO_ASSET_MISSING + " - " + audioId);
|
168
|
+
}
|
169
|
+
} catch (Exception ex) {
|
170
|
+
call.reject(ex.getMessage());
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
@PluginMethod
|
175
|
+
public void getDuration(final PluginCall call) {
|
176
|
+
try {
|
177
|
+
initSoundPool();
|
178
|
+
|
179
|
+
String audioId = call.getString(ASSET_ID);
|
180
|
+
|
181
|
+
if (!isStringValid(audioId)) {
|
182
|
+
call.reject(ERROR_AUDIO_ID_MISSING + " - " + audioId);
|
183
|
+
return;
|
184
|
+
}
|
185
|
+
|
186
|
+
if (audioAssetList.containsKey(audioId)) {
|
187
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
188
|
+
if (asset != null) {
|
189
|
+
call.resolve(new JSObject().put("duration", asset.getDuration()));
|
190
|
+
}
|
191
|
+
} else {
|
192
|
+
call.reject(ERROR_AUDIO_ASSET_MISSING + " - " + audioId);
|
193
|
+
}
|
194
|
+
} catch (Exception ex) {
|
195
|
+
call.reject(ex.getMessage());
|
196
|
+
}
|
197
|
+
}
|
198
|
+
|
199
|
+
@PluginMethod
|
200
|
+
public void loop(final PluginCall call) {
|
201
|
+
getBridge()
|
202
|
+
.getActivity()
|
203
|
+
.runOnUiThread(
|
204
|
+
new Runnable() {
|
205
|
+
@Override
|
206
|
+
public void run() {
|
207
|
+
playOrLoop("loop", call);
|
208
|
+
}
|
209
|
+
}
|
210
|
+
);
|
211
|
+
}
|
212
|
+
|
213
|
+
@PluginMethod
|
214
|
+
public void pause(PluginCall call) {
|
215
|
+
try {
|
216
|
+
initSoundPool();
|
217
|
+
String audioId = call.getString(ASSET_ID);
|
218
|
+
|
219
|
+
if (audioAssetList.containsKey(audioId)) {
|
220
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
221
|
+
if (asset != null) {
|
222
|
+
boolean wasPlaying = asset.pause();
|
223
|
+
|
224
|
+
if (wasPlaying) {
|
225
|
+
resumeList.add(asset);
|
226
|
+
}
|
227
|
+
}
|
228
|
+
} else {
|
229
|
+
call.reject(ERROR_ASSET_NOT_LOADED + " - " + audioId);
|
230
|
+
}
|
231
|
+
} catch (Exception ex) {
|
232
|
+
call.reject(ex.getMessage());
|
233
|
+
}
|
234
|
+
}
|
235
|
+
|
236
|
+
@PluginMethod
|
237
|
+
public void resume(PluginCall call) {
|
238
|
+
try {
|
239
|
+
initSoundPool();
|
240
|
+
String audioId = call.getString(ASSET_ID);
|
241
|
+
|
242
|
+
if (audioAssetList.containsKey(audioId)) {
|
243
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
244
|
+
if (asset != null) {
|
245
|
+
asset.resume();
|
246
|
+
resumeList.add(asset);
|
247
|
+
}
|
248
|
+
} else {
|
249
|
+
call.reject(ERROR_ASSET_NOT_LOADED + " - " + audioId);
|
250
|
+
}
|
251
|
+
} catch (Exception ex) {
|
252
|
+
call.reject(ex.getMessage());
|
253
|
+
}
|
254
|
+
}
|
255
|
+
|
256
|
+
@PluginMethod
|
257
|
+
public void stop(PluginCall call) {
|
258
|
+
try {
|
259
|
+
initSoundPool();
|
260
|
+
String audioId = call.getString(ASSET_ID);
|
261
|
+
|
262
|
+
if (audioAssetList.containsKey(audioId)) {
|
263
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
264
|
+
if (asset != null) {
|
265
|
+
asset.stop();
|
266
|
+
}
|
267
|
+
} else {
|
268
|
+
call.reject(ERROR_ASSET_NOT_LOADED + " - " + audioId);
|
269
|
+
}
|
270
|
+
} catch (Exception ex) {
|
271
|
+
call.reject(ex.getMessage());
|
272
|
+
}
|
273
|
+
}
|
274
|
+
|
275
|
+
@PluginMethod
|
276
|
+
public void unload(PluginCall call) {
|
277
|
+
try {
|
278
|
+
initSoundPool();
|
279
|
+
new JSObject();
|
280
|
+
JSObject status;
|
281
|
+
|
282
|
+
if (isStringValid(call.getString(ASSET_ID))) {
|
283
|
+
String audioId = call.getString(ASSET_ID);
|
284
|
+
|
285
|
+
if (audioAssetList.containsKey(audioId)) {
|
286
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
287
|
+
if (asset != null) {
|
288
|
+
asset.unload();
|
289
|
+
audioAssetList.remove(audioId);
|
290
|
+
|
291
|
+
status = new JSObject();
|
292
|
+
status.put("status", "OK");
|
293
|
+
call.resolve(status);
|
294
|
+
} else {
|
295
|
+
status = new JSObject();
|
296
|
+
status.put("status", false);
|
297
|
+
call.resolve(status);
|
298
|
+
}
|
299
|
+
} else {
|
300
|
+
status = new JSObject();
|
301
|
+
status.put("status", ERROR_AUDIO_ASSET_MISSING + " - " + audioId);
|
302
|
+
call.resolve(status);
|
303
|
+
}
|
304
|
+
} else {
|
305
|
+
status = new JSObject();
|
306
|
+
status.put("status", ERROR_AUDIO_ID_MISSING);
|
307
|
+
call.resolve(status);
|
308
|
+
}
|
309
|
+
} catch (Exception ex) {
|
310
|
+
call.reject(ex.getMessage());
|
311
|
+
}
|
312
|
+
}
|
313
|
+
|
314
|
+
@PluginMethod
|
315
|
+
public void setVolume(PluginCall call) {
|
316
|
+
try {
|
317
|
+
initSoundPool();
|
318
|
+
|
319
|
+
String audioId = call.getString(ASSET_ID);
|
320
|
+
float volume = call.getFloat(VOLUME);
|
321
|
+
|
322
|
+
if (audioAssetList.containsKey(audioId)) {
|
323
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
324
|
+
if (asset != null) {
|
325
|
+
asset.setVolume(volume);
|
326
|
+
}
|
327
|
+
} else {
|
328
|
+
call.reject(ERROR_AUDIO_ASSET_MISSING);
|
329
|
+
}
|
330
|
+
} catch (Exception ex) {
|
331
|
+
call.reject(ex.getMessage());
|
332
|
+
}
|
333
|
+
}
|
334
|
+
|
335
|
+
@PluginMethod
|
336
|
+
public void isPlaying(final PluginCall call) {
|
337
|
+
try {
|
338
|
+
initSoundPool();
|
339
|
+
|
340
|
+
String audioId = call.getString(ASSET_ID);
|
341
|
+
|
342
|
+
if (!isStringValid(audioId)) {
|
343
|
+
call.reject(ERROR_AUDIO_ID_MISSING + " - " + audioId);
|
344
|
+
return;
|
345
|
+
}
|
346
|
+
|
347
|
+
if (audioAssetList.containsKey(audioId)) {
|
348
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
349
|
+
if (asset != null) {
|
350
|
+
call.resolve(new JSObject().put("isPlaying", asset.isPlaying()));
|
351
|
+
}
|
352
|
+
} else {
|
353
|
+
call.reject(ERROR_AUDIO_ASSET_MISSING + " - " + audioId);
|
354
|
+
}
|
355
|
+
} catch (Exception ex) {
|
356
|
+
call.reject(ex.getMessage());
|
357
|
+
}
|
358
|
+
}
|
359
|
+
|
360
|
+
public void dispatchComplete(String assetId) {
|
361
|
+
JSObject ret = new JSObject();
|
362
|
+
ret.put("assetId", assetId);
|
363
|
+
notifyListeners("complete", ret);
|
364
|
+
}
|
365
|
+
|
366
|
+
private void preloadAsset(PluginCall call) {
|
367
|
+
double volume = 1.0;
|
368
|
+
int audioChannelNum = 1;
|
369
|
+
|
370
|
+
try {
|
371
|
+
initSoundPool();
|
372
|
+
|
373
|
+
String audioId = call.getString(ASSET_ID);
|
374
|
+
|
375
|
+
boolean isUrl = call.getBoolean("isUrl", false);
|
376
|
+
|
377
|
+
if (!isStringValid(audioId)) {
|
378
|
+
call.reject(ERROR_AUDIO_ID_MISSING + " - " + audioId);
|
379
|
+
return;
|
380
|
+
}
|
381
|
+
|
382
|
+
if (!audioAssetList.containsKey(audioId)) {
|
383
|
+
String assetPath = call.getString(ASSET_PATH);
|
384
|
+
|
385
|
+
if (!isStringValid(assetPath)) {
|
386
|
+
call.reject(ERROR_ASSET_PATH_MISSING + " - " + audioId + " - " + assetPath);
|
387
|
+
return;
|
388
|
+
}
|
389
|
+
|
390
|
+
String fullPath = assetPath; //"raw/".concat(assetPath);
|
391
|
+
|
392
|
+
if (call.getDouble(VOLUME) == null) {
|
393
|
+
volume = 1.0;
|
394
|
+
} else {
|
395
|
+
volume = call.getDouble(VOLUME, 0.5);
|
396
|
+
}
|
397
|
+
|
398
|
+
if (call.getInt(AUDIO_CHANNEL_NUM) == null) {
|
399
|
+
audioChannelNum = 1;
|
400
|
+
} else {
|
401
|
+
audioChannelNum = call.getInt(AUDIO_CHANNEL_NUM);
|
402
|
+
}
|
403
|
+
|
404
|
+
AssetFileDescriptor assetFileDescriptor;
|
405
|
+
if (isUrl) {
|
406
|
+
File f = new File(new URI(fullPath));
|
407
|
+
ParcelFileDescriptor p = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
|
408
|
+
assetFileDescriptor = new AssetFileDescriptor(p, 0, -1);
|
409
|
+
} else {
|
410
|
+
Context ctx = getBridge().getActivity().getApplicationContext();
|
411
|
+
AssetManager am = ctx.getResources().getAssets();
|
412
|
+
assetFileDescriptor = am.openFd(fullPath);
|
413
|
+
}
|
414
|
+
|
415
|
+
AudioAsset asset = new AudioAsset(this, audioId, assetFileDescriptor, audioChannelNum, (float) volume);
|
416
|
+
audioAssetList.put(audioId, asset);
|
417
|
+
|
418
|
+
JSObject status = new JSObject();
|
419
|
+
status.put("STATUS", "OK");
|
420
|
+
call.resolve(status);
|
421
|
+
} else {
|
422
|
+
call.reject(ERROR_AUDIO_EXISTS);
|
423
|
+
}
|
424
|
+
} catch (Exception ex) {
|
425
|
+
call.reject(ex.getMessage());
|
426
|
+
}
|
427
|
+
}
|
428
|
+
|
429
|
+
private void playOrLoop(String action, final PluginCall call) {
|
430
|
+
try {
|
431
|
+
initSoundPool();
|
432
|
+
|
433
|
+
final String audioId = call.getString(ASSET_ID);
|
434
|
+
final Double time = call.getDouble("time", 0.0);
|
435
|
+
if (audioAssetList.containsKey(audioId)) {
|
436
|
+
AudioAsset asset = audioAssetList.get(audioId);
|
437
|
+
if (LOOP.equals(action) && asset != null) {
|
438
|
+
asset.loop();
|
439
|
+
} else if (asset != null) {
|
440
|
+
asset.play(
|
441
|
+
time,
|
442
|
+
new Callable<Void>() {
|
443
|
+
@Override
|
444
|
+
public Void call() throws Exception {
|
445
|
+
call.resolve(new JSObject().put(ASSET_ID, audioId));
|
446
|
+
|
447
|
+
return null;
|
448
|
+
}
|
449
|
+
}
|
450
|
+
);
|
451
|
+
}
|
452
|
+
}
|
453
|
+
} catch (Exception ex) {
|
454
|
+
call.reject(ex.getMessage());
|
455
|
+
}
|
456
|
+
}
|
457
|
+
|
458
|
+
private void initSoundPool() {
|
459
|
+
if (audioAssetList == null) {
|
460
|
+
audioAssetList = new HashMap<>();
|
461
|
+
}
|
462
|
+
|
463
|
+
if (resumeList == null) {
|
464
|
+
resumeList = new ArrayList<>();
|
465
|
+
}
|
466
|
+
}
|
467
|
+
|
468
|
+
private boolean isStringValid(String value) {
|
469
|
+
return (value != null && !value.isEmpty() && !value.equals("null"));
|
470
|
+
}
|
471
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
3
|
+
xmlns:app="http://schemas.android.com/apk/res-auto"
|
4
|
+
xmlns:tools="http://schemas.android.com/tools"
|
5
|
+
android:layout_width="match_parent"
|
6
|
+
android:layout_height="match_parent"
|
7
|
+
tools:context="com.getcapacitor.BridgeActivity"
|
8
|
+
>
|
9
|
+
|
10
|
+
<WebView
|
11
|
+
android:id="@+id/webview"
|
12
|
+
android:layout_width="fill_parent"
|
13
|
+
android:layout_height="fill_parent" />
|
14
|
+
|
15
|
+
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|