@capgo/native-audio 6.4.5 → 6.4.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,7 +12,7 @@ public class AudioAsset {
12
12
  private final ArrayList<AudioDispatcher> audioList;
13
13
  private int playIndex = 0;
14
14
  private final String assetId;
15
- private final NativeAudio owner;
15
+ protected final NativeAudio owner;
16
16
 
17
17
  AudioAsset(
18
18
  NativeAudio owner,
@@ -29,7 +29,11 @@ import com.getcapacitor.PluginMethod;
29
29
  import com.getcapacitor.annotation.CapacitorPlugin;
30
30
  import com.getcapacitor.annotation.Permission;
31
31
  import java.io.File;
32
+ import java.io.FileDescriptor;
33
+ import java.io.FileInputStream;
34
+ import java.io.IOException;
32
35
  import java.net.URI;
36
+ import java.net.URL;
33
37
  import java.util.ArrayList;
34
38
  import java.util.HashMap;
35
39
 
@@ -56,6 +60,8 @@ public class NativeAudio
56
60
 
57
61
  this.audioManager = (AudioManager) this.getActivity()
58
62
  .getSystemService(Context.AUDIO_SERVICE);
63
+
64
+ audioAssetList = new HashMap<>();
59
65
  }
60
66
 
61
67
  @Override
@@ -448,88 +454,132 @@ public class NativeAudio
448
454
  initSoundPool();
449
455
 
450
456
  String audioId = call.getString(ASSET_ID);
451
-
452
- boolean isLocalUrl = Boolean.TRUE.equals(call.getBoolean("isUrl", false));
453
-
454
457
  if (!isStringValid(audioId)) {
455
458
  call.reject(ERROR_AUDIO_ID_MISSING + " - " + audioId);
456
459
  return;
457
460
  }
458
461
 
459
- if (!audioAssetList.containsKey(audioId)) {
460
- String assetPath = call.getString(ASSET_PATH);
462
+ String assetPath = call.getString(ASSET_PATH);
463
+ if (!isStringValid(assetPath)) {
464
+ call.reject(
465
+ ERROR_ASSET_PATH_MISSING + " - " + audioId + " - " + assetPath
466
+ );
467
+ return;
468
+ }
461
469
 
462
- if (!isStringValid(assetPath)) {
463
- call.reject(
464
- ERROR_ASSET_PATH_MISSING + " - " + audioId + " - " + assetPath
465
- );
466
- return;
467
- }
470
+ boolean isLocalUrl = call.getBoolean("isUrl", false);
471
+ boolean isComplex = call.getBoolean("isComplex", false);
468
472
 
469
- String fullPath = assetPath; //"raw/".concat(assetPath);
473
+ Log.d(
474
+ "AudioPlugin",
475
+ "Debug: audioId = " +
476
+ audioId +
477
+ ", assetPath = " +
478
+ assetPath +
479
+ ", isLocalUrl = " +
480
+ isLocalUrl
481
+ );
470
482
 
483
+ if (audioAssetList.containsKey(audioId)) {
484
+ call.reject(ERROR_AUDIO_EXISTS + " - " + audioId);
485
+ return;
486
+ }
487
+
488
+ if (isComplex) {
471
489
  volume = call.getFloat(VOLUME, 1F);
472
490
  audioChannelNum = call.getInt(AUDIO_CHANNEL_NUM, 1);
491
+ }
473
492
 
474
- AssetFileDescriptor assetFileDescriptor;
475
- if (isLocalUrl) {
476
- File f = new File(new URI(fullPath));
477
- ParcelFileDescriptor p = ParcelFileDescriptor.open(
478
- f,
479
- ParcelFileDescriptor.MODE_READ_ONLY
480
- );
481
- assetFileDescriptor = new AssetFileDescriptor(p, 0, -1);
482
- } else {
483
- try {
484
- Uri uri = Uri.parse(fullPath); // Now Uri class should be recognized
485
- if (
486
- uri.getScheme() != null &&
487
- (uri.getScheme().equals("http") ||
488
- uri.getScheme().equals("https"))
489
- ) {
490
- // It's a remote URL
491
- RemoteAudioAsset remoteAudioAsset = new RemoteAudioAsset(
492
- this,
493
- audioId,
494
- uri,
495
- audioChannelNum,
496
- volume
493
+ if (isLocalUrl) {
494
+ // Handle URL (both remote and local file URLs)
495
+ Log.d("AudioPlugin", "Debug: Handling URL");
496
+ try {
497
+ Uri uri = Uri.parse(assetPath);
498
+ if (
499
+ uri.getScheme() != null &&
500
+ (uri.getScheme().equals("http") || uri.getScheme().equals("https"))
501
+ ) {
502
+ // Remote URL
503
+ Log.d(
504
+ "AudioPlugin",
505
+ "Debug: Remote URL detected: " + uri.toString()
506
+ );
507
+ RemoteAudioAsset remoteAudioAsset = new RemoteAudioAsset(
508
+ this,
509
+ audioId,
510
+ uri,
511
+ audioChannelNum,
512
+ volume
513
+ );
514
+ audioAssetList.put(audioId, remoteAudioAsset);
515
+ } else if (
516
+ uri.getScheme() != null && uri.getScheme().equals("file")
517
+ ) {
518
+ // Local file URL
519
+ Log.d("AudioPlugin", "Debug: Local file URL detected");
520
+ File file = new File(uri.getPath());
521
+ if (!file.exists()) {
522
+ Log.e(
523
+ "AudioPlugin",
524
+ "Error: File does not exist - " + file.getAbsolutePath()
497
525
  );
498
- audioAssetList.put(audioId, remoteAudioAsset);
499
- call.resolve(status);
526
+ call.reject(ERROR_ASSET_PATH_MISSING + " - " + assetPath);
500
527
  return;
501
- } else {
502
- // It's a local file path
503
- // Check if fullPath starts with "public/" and prepend if necessary
504
- if (!fullPath.startsWith("public/")) {
505
- fullPath = "public/".concat(fullPath);
506
- }
507
- Context ctx = getContext().getApplicationContext(); // Use getContext() directly
508
- AssetManager am = ctx.getResources().getAssets();
509
- // Remove the redefinition of assetFileDescriptor
510
- assetFileDescriptor = am.openFd(fullPath);
511
528
  }
512
- } catch (Exception e) {
513
- call.reject("Error loading audio", e);
514
- return;
529
+ ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
530
+ file,
531
+ ParcelFileDescriptor.MODE_READ_ONLY
532
+ );
533
+ AssetFileDescriptor afd = new AssetFileDescriptor(
534
+ pfd,
535
+ 0,
536
+ AssetFileDescriptor.UNKNOWN_LENGTH
537
+ );
538
+ AudioAsset asset = new AudioAsset(
539
+ this,
540
+ audioId,
541
+ afd,
542
+ audioChannelNum,
543
+ volume
544
+ );
545
+ audioAssetList.put(audioId, asset);
546
+ } else {
547
+ throw new IllegalArgumentException(
548
+ "Invalid URL scheme: " + uri.getScheme()
549
+ );
515
550
  }
551
+ call.resolve(status);
552
+ } catch (Exception e) {
553
+ Log.e("AudioPlugin", "Error handling URL", e);
554
+ call.reject("Error handling URL: " + e.getMessage());
516
555
  }
517
-
518
- AudioAsset asset = new AudioAsset(
519
- this,
520
- audioId,
521
- assetFileDescriptor,
522
- audioChannelNum,
523
- volume
524
- );
525
- audioAssetList.put(audioId, asset);
526
-
527
- call.resolve(status);
528
556
  } else {
529
- call.reject(ERROR_AUDIO_EXISTS);
557
+ // Handle asset in public folder
558
+ Log.d("AudioPlugin", "Debug: Handling asset in public folder");
559
+ if (!assetPath.startsWith("public/")) {
560
+ assetPath = "public/" + assetPath;
561
+ }
562
+ try {
563
+ Context ctx = getContext().getApplicationContext();
564
+ AssetManager am = ctx.getResources().getAssets();
565
+ AssetFileDescriptor assetFileDescriptor = am.openFd(assetPath);
566
+ AudioAsset asset = new AudioAsset(
567
+ this,
568
+ audioId,
569
+ assetFileDescriptor,
570
+ audioChannelNum,
571
+ volume
572
+ );
573
+ audioAssetList.put(audioId, asset);
574
+ call.resolve(status);
575
+ } catch (IOException e) {
576
+ Log.e("AudioPlugin", "Error opening asset: " + assetPath, e);
577
+ call.reject(ERROR_ASSET_PATH_MISSING + " - " + assetPath);
578
+ }
530
579
  }
531
580
  } catch (Exception ex) {
532
- call.reject(ex.getMessage());
581
+ Log.e("AudioPlugin", "Error in preloadAsset", ex);
582
+ call.reject("Error in preloadAsset: " + ex.getMessage());
533
583
  }
534
584
  }
535
585
 
@@ -2,10 +2,17 @@ package ee.forgr.audio;
2
2
 
3
3
  import android.media.MediaPlayer;
4
4
  import android.net.Uri;
5
+ import android.util.Log;
6
+ import java.util.ArrayList;
5
7
 
6
8
  public class RemoteAudioAsset extends AudioAsset {
7
9
 
8
- private MediaPlayer mediaPlayer;
10
+ private static final String TAG = "RemoteAudioAsset";
11
+ private final ArrayList<MediaPlayer> mediaPlayers;
12
+ private int playIndex = 0;
13
+ private final Uri uri;
14
+ private float volume;
15
+ private boolean isPrepared = false;
9
16
 
10
17
  public RemoteAudioAsset(
11
18
  NativeAudio owner,
@@ -14,74 +21,155 @@ public class RemoteAudioAsset extends AudioAsset {
14
21
  int audioChannelNum,
15
22
  float volume
16
23
  ) throws Exception {
17
- super(owner, assetId, null, audioChannelNum, volume);
18
- mediaPlayer = new MediaPlayer();
19
- mediaPlayer.setDataSource(owner.getContext(), uri);
20
- mediaPlayer.setVolume(volume, volume);
21
- mediaPlayer.prepareAsync(); // Prepare asynchronously to not block the main thread
24
+ super(owner, assetId, null, 0, volume);
25
+ this.uri = uri;
26
+ this.volume = volume;
27
+ this.mediaPlayers = new ArrayList<>();
28
+
29
+ if (audioChannelNum < 1) {
30
+ audioChannelNum = 1;
31
+ }
32
+
33
+ for (int i = 0; i < audioChannelNum; i++) {
34
+ MediaPlayer mediaPlayer = new MediaPlayer();
35
+ mediaPlayers.add(mediaPlayer);
36
+ initializeMediaPlayer(mediaPlayer);
37
+ }
38
+ }
39
+
40
+ private void initializeMediaPlayer(MediaPlayer mediaPlayer) {
41
+ try {
42
+ mediaPlayer.setDataSource(owner.getContext(), uri);
43
+ mediaPlayer.setVolume(volume, volume);
44
+ mediaPlayer.setOnPreparedListener(mp -> {
45
+ isPrepared = true;
46
+ Log.d(TAG, "MediaPlayer prepared for " + uri.toString());
47
+ });
48
+ mediaPlayer.setOnErrorListener((mp, what, extra) -> {
49
+ Log.e(TAG, "MediaPlayer error: " + what + ", " + extra);
50
+ return false;
51
+ });
52
+ mediaPlayer.prepareAsync();
53
+ } catch (Exception e) {
54
+ Log.e(TAG, "Error initializing MediaPlayer", e);
55
+ }
22
56
  }
23
57
 
24
58
  @Override
25
59
  public void play(Double time) throws Exception {
26
- if (mediaPlayer != null) {
27
- if (time != null) {
28
- mediaPlayer.seekTo((int) (time * 1000));
29
- }
30
- mediaPlayer.start();
60
+ if (mediaPlayers.isEmpty()) {
61
+ throw new Exception("No MediaPlayer available");
62
+ }
63
+
64
+ MediaPlayer mediaPlayer = mediaPlayers.get(playIndex);
65
+ if (!isPrepared) {
66
+ Log.d(TAG, "MediaPlayer not yet prepared, waiting...");
67
+ mediaPlayer.setOnPreparedListener(mp -> {
68
+ isPrepared = true;
69
+ try {
70
+ playInternal(mediaPlayer, time);
71
+ } catch (Exception e) {
72
+ Log.e(TAG, "Error playing after prepare", e);
73
+ }
74
+ });
31
75
  } else {
32
- throw new Exception("MediaPlayer is null");
76
+ playInternal(mediaPlayer, time);
77
+ }
78
+
79
+ playIndex = (playIndex + 1) % mediaPlayers.size();
80
+ }
81
+
82
+ private void playInternal(MediaPlayer mediaPlayer, Double time)
83
+ throws Exception {
84
+ if (time != null) {
85
+ mediaPlayer.seekTo((int) (time * 1000));
33
86
  }
87
+ mediaPlayer.start();
34
88
  }
35
89
 
36
90
  @Override
37
91
  public boolean pause() throws Exception {
38
- if (mediaPlayer != null && mediaPlayer.isPlaying()) {
39
- mediaPlayer.pause();
40
- return true; // Return true to indicate that the audio was paused
92
+ boolean wasPlaying = false;
93
+ for (MediaPlayer mediaPlayer : mediaPlayers) {
94
+ if (mediaPlayer.isPlaying()) {
95
+ mediaPlayer.pause();
96
+ wasPlaying = true;
97
+ }
41
98
  }
42
- return false;
99
+ return wasPlaying;
43
100
  }
44
101
 
45
102
  @Override
46
103
  public void resume() throws Exception {
47
- if (mediaPlayer != null && !mediaPlayer.isPlaying()) {
48
- mediaPlayer.start();
104
+ for (MediaPlayer mediaPlayer : mediaPlayers) {
105
+ if (!mediaPlayer.isPlaying()) {
106
+ mediaPlayer.start();
107
+ }
49
108
  }
50
109
  }
51
110
 
52
111
  @Override
53
112
  public void stop() throws Exception {
54
- if (mediaPlayer != null) {
55
- mediaPlayer.stop();
56
- mediaPlayer.prepare(); // Call prepare to reset the MediaPlayer to the Idle state
113
+ for (MediaPlayer mediaPlayer : mediaPlayers) {
114
+ if (mediaPlayer.isPlaying()) {
115
+ mediaPlayer.stop();
116
+ }
117
+ // Reset the MediaPlayer to make it ready for future playback
118
+ mediaPlayer.reset();
119
+ initializeMediaPlayer(mediaPlayer);
57
120
  }
121
+ isPrepared = false;
58
122
  }
59
123
 
60
124
  @Override
61
125
  public void loop() throws Exception {
62
- if (mediaPlayer != null) {
126
+ if (!mediaPlayers.isEmpty()) {
127
+ MediaPlayer mediaPlayer = mediaPlayers.get(playIndex);
63
128
  mediaPlayer.setLooping(true);
64
129
  mediaPlayer.start();
130
+ playIndex = (playIndex + 1) % mediaPlayers.size();
65
131
  }
66
132
  }
67
133
 
68
134
  @Override
69
135
  public void unload() throws Exception {
70
- if (mediaPlayer != null) {
136
+ for (MediaPlayer mediaPlayer : mediaPlayers) {
71
137
  mediaPlayer.release();
72
- mediaPlayer = null;
73
138
  }
139
+ mediaPlayers.clear();
74
140
  }
75
141
 
76
142
  @Override
77
143
  public void setVolume(float volume) throws Exception {
78
- if (mediaPlayer != null) {
144
+ this.volume = volume;
145
+ for (MediaPlayer mediaPlayer : mediaPlayers) {
79
146
  mediaPlayer.setVolume(volume, volume);
80
147
  }
81
148
  }
82
149
 
83
150
  @Override
84
151
  public boolean isPlaying() throws Exception {
85
- return mediaPlayer != null && mediaPlayer.isPlaying();
152
+ for (MediaPlayer mediaPlayer : mediaPlayers) {
153
+ if (mediaPlayer.isPlaying()) {
154
+ return true;
155
+ }
156
+ }
157
+ return false;
158
+ }
159
+
160
+ @Override
161
+ public double getDuration() {
162
+ if (!mediaPlayers.isEmpty() && isPrepared) {
163
+ return mediaPlayers.get(0).getDuration() / 1000.0;
164
+ }
165
+ return 0;
166
+ }
167
+
168
+ @Override
169
+ public double getCurrentPosition() {
170
+ if (!mediaPlayers.isEmpty() && isPrepared) {
171
+ return mediaPlayers.get(0).getCurrentPosition() / 1000.0;
172
+ }
173
+ return 0;
86
174
  }
87
175
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/native-audio",
3
- "version": "6.4.5",
3
+ "version": "6.4.7",
4
4
  "description": "A native plugin for native audio engine",
5
5
  "main": "dist/plugin.js",
6
6
  "module": "dist/esm/index.js",