@capgo/native-audio 6.1.36 → 6.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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",