@capgo/native-audio 6.1.35 → 6.2.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/android/src/main/java/ee/forgr/audio/NativeAudio.java +39 -10
- package/android/src/main/java/ee/forgr/audio/RemoteAudioAsset.java +87 -0
- package/ios/Plugin/AudioAsset.swift +1 -1
- package/ios/Plugin/Plugin.swift +10 -9
- package/ios/Plugin/RemoteAudioAsset.swift +74 -0
- package/package.json +1 -1
@@ -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
|
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 (
|
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
|
-
|
469
|
-
|
470
|
-
|
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
|
+
}
|
@@ -75,7 +75,7 @@ public class AudioAsset: NSObject, AVAudioPlayerDelegate {
|
|
75
75
|
player = channels[playIndex]
|
76
76
|
player.currentTime = time
|
77
77
|
player.numberOfLoops = 0
|
78
|
-
if
|
78
|
+
if delay > 0 {
|
79
79
|
player.play(atTime: player.deviceCurrentTime + delay)
|
80
80
|
} else {
|
81
81
|
player.play()
|
package/ios/Plugin/Plugin.swift
CHANGED
@@ -35,12 +35,9 @@ public class NativeAudio: CAPPlugin {
|
|
35
35
|
}
|
36
36
|
|
37
37
|
let focus = call.getBool(Constant.FocusAudio) ?? false
|
38
|
-
|
39
38
|
do {
|
40
|
-
|
41
39
|
if focus {
|
42
|
-
|
43
|
-
try self.session.setCategory(AVAudioSession.Category.playback)
|
40
|
+
try self.session.setCategory(AVAudioSession.Category.playback, options: .duckOthers)
|
44
41
|
|
45
42
|
}
|
46
43
|
|
@@ -78,7 +75,7 @@ public class NativeAudio: CAPPlugin {
|
|
78
75
|
|
79
76
|
if focus {
|
80
77
|
|
81
|
-
try self.session.setCategory(AVAudioSession.Category.ambient)
|
78
|
+
try self.session.setCategory(AVAudioSession.Category.ambient, options: .duckOthers)
|
82
79
|
|
83
80
|
} else {
|
84
81
|
|
@@ -263,7 +260,7 @@ public class NativeAudio: CAPPlugin {
|
|
263
260
|
let channels: Int?
|
264
261
|
let volume: Float?
|
265
262
|
let delay: Float?
|
266
|
-
|
263
|
+
var isLocalUrl: Bool = call.getBool("isUrl") ?? false // Existing flag for local URLs
|
267
264
|
|
268
265
|
if audioId != "" {
|
269
266
|
var assetPath: String = call.getString(Constant.AssetPathKey) ?? ""
|
@@ -272,12 +269,11 @@ public class NativeAudio: CAPPlugin {
|
|
272
269
|
volume = call.getFloat("volume") ?? 1.0
|
273
270
|
channels = call.getInt("channels") ?? 1
|
274
271
|
delay = call.getFloat("delay") ?? 1.0
|
275
|
-
isUrl = call.getBool("isUrl") ?? false
|
276
272
|
} else {
|
277
273
|
channels = 0
|
278
274
|
volume = 0
|
279
275
|
delay = 0
|
280
|
-
|
276
|
+
isLocalUrl = false
|
281
277
|
}
|
282
278
|
|
283
279
|
if audioList.isEmpty {
|
@@ -289,7 +285,12 @@ public class NativeAudio: CAPPlugin {
|
|
289
285
|
queue.async {
|
290
286
|
if asset == nil {
|
291
287
|
var basePath: String?
|
292
|
-
if
|
288
|
+
if let url = URL(string: assetPath), url.scheme != nil {
|
289
|
+
// Handle remote URL
|
290
|
+
let remoteAudioAsset = RemoteAudioAsset(owner: self, withAssetId: audioId, withPath: assetPath, withChannels: channels, withVolume: volume, withFadeDelay: delay)
|
291
|
+
self.audioList[audioId] = remoteAudioAsset
|
292
|
+
call.resolve()
|
293
|
+
} else if isLocalUrl == false {
|
293
294
|
// if assetPath dont start with public/ add it
|
294
295
|
assetPath = assetPath.starts(with: "public/") ? assetPath : "public/" + assetPath
|
295
296
|
|
@@ -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
|
+
}
|