@capgo/native-audio 6.1.36 → 6.2.1

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.
@@ -20,6 +20,7 @@ import android.content.Context;
20
20
  import android.content.res.AssetFileDescriptor;
21
21
  import android.content.res.AssetManager;
22
22
  import android.media.AudioManager;
23
+ import android.net.Uri;
23
24
  import android.os.Build;
24
25
  import android.os.ParcelFileDescriptor;
25
26
  import android.util.Log;
@@ -419,13 +420,15 @@ public class NativeAudio
419
420
  private void preloadAsset(PluginCall call) {
420
421
  double volume = 1.0;
421
422
  int audioChannelNum = 1;
423
+ JSObject status = new JSObject();
424
+ status.put("STATUS", "OK");
422
425
 
423
426
  try {
424
427
  initSoundPool();
425
428
 
426
429
  String audioId = call.getString(ASSET_ID);
427
430
 
428
- boolean isUrl = call.getBoolean("isUrl", false);
431
+ boolean isLocalUrl = Boolean.TRUE.equals(call.getBoolean("isUrl", false));
429
432
 
430
433
  if (!isStringValid(audioId)) {
431
434
  call.reject(ERROR_AUDIO_ID_MISSING + " - " + audioId);
@@ -457,7 +460,7 @@ public class NativeAudio
457
460
  }
458
461
 
459
462
  AssetFileDescriptor assetFileDescriptor;
460
- if (isUrl) {
463
+ if (isLocalUrl) {
461
464
  File f = new File(new URI(fullPath));
462
465
  ParcelFileDescriptor p = ParcelFileDescriptor.open(
463
466
  f,
@@ -465,13 +468,41 @@ public class NativeAudio
465
468
  );
466
469
  assetFileDescriptor = new AssetFileDescriptor(p, 0, -1);
467
470
  } else {
468
- // if fullPath dont start with public/ add it
469
- if (!fullPath.startsWith("public/")) {
470
- fullPath = "public/".concat(fullPath);
471
+ try {
472
+ Uri uri = Uri.parse(fullPath); // Now Uri class should be recognized
473
+ if (
474
+ uri.getScheme() != null &&
475
+ (
476
+ uri.getScheme().equals("http") ||
477
+ uri.getScheme().equals("https")
478
+ )
479
+ ) {
480
+ // It's a remote URL
481
+ RemoteAudioAsset remoteAudioAsset = new RemoteAudioAsset(
482
+ this,
483
+ audioId,
484
+ uri,
485
+ audioChannelNum,
486
+ (float) volume
487
+ );
488
+ audioAssetList.put(audioId, remoteAudioAsset);
489
+ call.resolve(status);
490
+ return;
491
+ } else {
492
+ // It's a local file path
493
+ // Check if fullPath starts with "public/" and prepend if necessary
494
+ if (!fullPath.startsWith("public/")) {
495
+ fullPath = "public/".concat(fullPath);
496
+ }
497
+ Context ctx = getContext().getApplicationContext(); // Use getContext() directly
498
+ AssetManager am = ctx.getResources().getAssets();
499
+ // Remove the redefinition of assetFileDescriptor
500
+ assetFileDescriptor = am.openFd(fullPath);
501
+ }
502
+ } catch (Exception e) {
503
+ call.reject("Error loading audio", e);
504
+ return;
471
505
  }
472
- Context ctx = (Application) this.getContext().getApplicationContext();
473
- AssetManager am = ctx.getResources().getAssets();
474
- assetFileDescriptor = am.openFd(fullPath);
475
506
  }
476
507
 
477
508
  AudioAsset asset = new AudioAsset(
@@ -483,8 +514,6 @@ public class NativeAudio
483
514
  );
484
515
  audioAssetList.put(audioId, asset);
485
516
 
486
- JSObject status = new JSObject();
487
- status.put("STATUS", "OK");
488
517
  call.resolve(status);
489
518
  } else {
490
519
  call.reject(ERROR_AUDIO_EXISTS);
@@ -0,0 +1,87 @@
1
+ package ee.forgr.audio;
2
+
3
+ import android.media.MediaPlayer;
4
+ import android.net.Uri;
5
+
6
+ public class RemoteAudioAsset extends AudioAsset {
7
+
8
+ private MediaPlayer mediaPlayer;
9
+
10
+ public RemoteAudioAsset(
11
+ NativeAudio owner,
12
+ String assetId,
13
+ Uri uri,
14
+ int audioChannelNum,
15
+ float volume
16
+ ) 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
22
+ }
23
+
24
+ @Override
25
+ 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();
31
+ } else {
32
+ throw new Exception("MediaPlayer is null");
33
+ }
34
+ }
35
+
36
+ @Override
37
+ 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
41
+ }
42
+ return false;
43
+ }
44
+
45
+ @Override
46
+ public void resume() throws Exception {
47
+ if (mediaPlayer != null && !mediaPlayer.isPlaying()) {
48
+ mediaPlayer.start();
49
+ }
50
+ }
51
+
52
+ @Override
53
+ 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
57
+ }
58
+ }
59
+
60
+ @Override
61
+ public void loop() throws Exception {
62
+ if (mediaPlayer != null) {
63
+ mediaPlayer.setLooping(true);
64
+ mediaPlayer.start();
65
+ }
66
+ }
67
+
68
+ @Override
69
+ public void unload() throws Exception {
70
+ if (mediaPlayer != null) {
71
+ mediaPlayer.release();
72
+ mediaPlayer = null;
73
+ }
74
+ }
75
+
76
+ @Override
77
+ public void setVolume(float volume) throws Exception {
78
+ if (mediaPlayer != null) {
79
+ mediaPlayer.setVolume(volume, volume);
80
+ }
81
+ }
82
+
83
+ @Override
84
+ public boolean isPlaying() throws Exception {
85
+ return mediaPlayer != null && mediaPlayer.isPlaying();
86
+ }
87
+ }
@@ -32,6 +32,7 @@ public class AudioAsset: NSObject, AVAudioPlayerDelegate {
32
32
  for _ in 0..<channels {
33
33
  do {
34
34
  let player: AVAudioPlayer! = try AVAudioPlayer(contentsOf: pathUrl)
35
+ player.delegate = owner
35
36
 
36
37
  if player != nil {
37
38
  player.enableRate = true
@@ -75,7 +76,7 @@ public class AudioAsset: NSObject, AVAudioPlayerDelegate {
75
76
  player = channels[playIndex]
76
77
  player.currentTime = time
77
78
  player.numberOfLoops = 0
78
- if (delay > 0) {
79
+ if delay > 0 {
79
80
  player.play(atTime: player.deviceCurrentTime + delay)
80
81
  } else {
81
82
  player.play()
@@ -10,7 +10,7 @@ enum MyError: Error {
10
10
  /// Please read the Capacitor iOS Plugin Development Guide
11
11
  /// here: https://capacitor.ionicframework.com/docs/plugins/ios
12
12
  @objc(NativeAudio)
13
- public class NativeAudio: CAPPlugin {
13
+ public class NativeAudio: CAPPlugin, AVAudioPlayerDelegate {
14
14
 
15
15
  var audioList: [String: Any] = [:]
16
16
  var fadeMusic = false
@@ -101,6 +101,26 @@ public class NativeAudio: CAPPlugin {
101
101
  preloadAsset(call, isComplex: true)
102
102
  }
103
103
 
104
+ func activateSession() {
105
+ do {
106
+ try self.session.setActive(true)
107
+ } catch {
108
+ print("Failed to set session active")
109
+ }
110
+ }
111
+
112
+ func endSession() {
113
+ do {
114
+ try self.session.setActive(false, options: .notifyOthersOnDeactivation)
115
+ } catch {
116
+ print("Failed to deactivate audio session")
117
+ }
118
+ }
119
+
120
+ public func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
121
+ self.endSession()
122
+ }
123
+
104
124
  @objc func play(_ call: CAPPluginCall) {
105
125
  let audioId = call.getString(Constant.AssetIdKey) ?? ""
106
126
  let time = call.getDouble("time") ?? 0
@@ -115,7 +135,7 @@ public class NativeAudio: CAPPlugin {
115
135
  if asset != nil {
116
136
  if asset is AudioAsset {
117
137
  let audioAsset = asset as? AudioAsset
118
-
138
+ self.activateSession()
119
139
  if self.fadeMusic {
120
140
  audioAsset?.playWithFade(time: time)
121
141
  } else {
@@ -124,6 +144,7 @@ public class NativeAudio: CAPPlugin {
124
144
  call.resolve()
125
145
  } else if asset is Int32 {
126
146
  let audioAsset = asset as? NSNumber ?? 0
147
+ self.activateSession()
127
148
  AudioServicesPlaySystemSound(SystemSoundID(audioAsset.intValue))
128
149
  call.resolve()
129
150
  } else {
@@ -175,7 +196,7 @@ public class NativeAudio: CAPPlugin {
175
196
  guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
176
197
  return
177
198
  }
178
-
199
+ self.activateSession()
179
200
  audioAsset.resume()
180
201
  call.resolve()
181
202
  }
@@ -186,6 +207,7 @@ public class NativeAudio: CAPPlugin {
186
207
  }
187
208
 
188
209
  audioAsset.pause()
210
+ self.endSession()
189
211
  call.resolve()
190
212
  }
191
213
 
@@ -194,6 +216,7 @@ public class NativeAudio: CAPPlugin {
194
216
 
195
217
  do {
196
218
  try stopAudio(audioId: audioId)
219
+ self.endSession()
197
220
  } catch {
198
221
  call.reject(Constant.ErrorAssetNotFound)
199
222
  }
@@ -260,7 +283,7 @@ public class NativeAudio: CAPPlugin {
260
283
  let channels: Int?
261
284
  let volume: Float?
262
285
  let delay: Float?
263
- let isUrl: Bool?
286
+ var isLocalUrl: Bool = call.getBool("isUrl") ?? false // Existing flag for local URLs
264
287
 
265
288
  if audioId != "" {
266
289
  var assetPath: String = call.getString(Constant.AssetPathKey) ?? ""
@@ -269,12 +292,11 @@ public class NativeAudio: CAPPlugin {
269
292
  volume = call.getFloat("volume") ?? 1.0
270
293
  channels = call.getInt("channels") ?? 1
271
294
  delay = call.getFloat("delay") ?? 1.0
272
- isUrl = call.getBool("isUrl") ?? false
273
295
  } else {
274
296
  channels = 0
275
297
  volume = 0
276
298
  delay = 0
277
- isUrl = false
299
+ isLocalUrl = false
278
300
  }
279
301
 
280
302
  if audioList.isEmpty {
@@ -286,7 +308,12 @@ public class NativeAudio: CAPPlugin {
286
308
  queue.async {
287
309
  if asset == nil {
288
310
  var basePath: String?
289
- if isUrl == false {
311
+ if let url = URL(string: assetPath), url.scheme != nil {
312
+ // Handle remote URL
313
+ let remoteAudioAsset = RemoteAudioAsset(owner: self, withAssetId: audioId, withPath: assetPath, withChannels: channels, withVolume: volume, withFadeDelay: delay)
314
+ self.audioList[audioId] = remoteAudioAsset
315
+ call.resolve()
316
+ } else if isLocalUrl == false {
290
317
  // if assetPath dont start with public/ add it
291
318
  assetPath = assetPath.starts(with: "public/") ? assetPath : "public/" + assetPath
292
319
 
@@ -0,0 +1,74 @@
1
+ import AVFoundation
2
+
3
+ public class RemoteAudioAsset: AudioAsset {
4
+ var playerItem: AVPlayerItem?
5
+ var player: AVPlayer?
6
+
7
+ override init(owner: NativeAudio, withAssetId assetId: String, withPath path: String!, withChannels channels: Int!, withVolume volume: Float!, withFadeDelay delay: Float!) {
8
+ super.init(owner: owner, withAssetId: assetId, withPath: path, withChannels: channels, withVolume: volume, withFadeDelay: delay)
9
+
10
+ if let url = URL(string: path) {
11
+ self.playerItem = AVPlayerItem(url: url)
12
+ self.player = AVPlayer(playerItem: self.playerItem)
13
+ self.player?.volume = volume
14
+ }
15
+ }
16
+
17
+ override func play(time: TimeInterval, delay: TimeInterval) {
18
+ guard let player = self.player else { return }
19
+ if delay > 0 {
20
+ // Calculate the future time to play
21
+ let timeToPlay = CMTimeAdd(CMTimeMakeWithSeconds(player.currentTime().seconds, preferredTimescale: 1), CMTimeMakeWithSeconds(delay, preferredTimescale: 1))
22
+ player.seek(to: timeToPlay)
23
+ } else {
24
+ player.seek(to: CMTimeMakeWithSeconds(time, preferredTimescale: 1))
25
+ }
26
+ player.play()
27
+ }
28
+
29
+ override func pause() {
30
+ player?.pause()
31
+ }
32
+
33
+ override func resume() {
34
+ player?.play()
35
+ }
36
+
37
+ override func stop() {
38
+ player?.pause()
39
+ player?.seek(to: CMTime.zero)
40
+ }
41
+
42
+ override func loop() {
43
+ player?.actionAtItemEnd = .none
44
+ NotificationCenter.default.addObserver(self,
45
+ selector: #selector(playerItemDidReachEnd(notification:)),
46
+ name: .AVPlayerItemDidPlayToEndTime,
47
+ object: player?.currentItem)
48
+ player?.play()
49
+ }
50
+
51
+ @objc func playerItemDidReachEnd(notification: Notification) {
52
+ player?.seek(to: CMTime.zero)
53
+ player?.play()
54
+ }
55
+
56
+ override func unload() {
57
+ stop()
58
+ NotificationCenter.default.removeObserver(self)
59
+ player = nil
60
+ playerItem = nil
61
+ }
62
+
63
+ override func setVolume(volume: NSNumber!) {
64
+ player?.volume = volume.floatValue
65
+ }
66
+
67
+ override func setRate(rate: NSNumber!) {
68
+ player?.rate = rate.floatValue
69
+ }
70
+
71
+ override func isPlaying() -> Bool {
72
+ return player?.timeControlStatus == .playing
73
+ }
74
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/native-audio",
3
- "version": "6.1.36",
3
+ "version": "6.2.1",
4
4
  "description": "A native plugin for native audio engine",
5
5
  "main": "dist/plugin.js",
6
6
  "module": "dist/esm/index.js",