@capgo/native-audio 6.4.20 → 6.4.22

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.
@@ -13,6 +13,7 @@ public class AudioAsset {
13
13
  private int playIndex = 0;
14
14
  private final String assetId;
15
15
  protected final NativeAudio owner;
16
+ protected AudioCompletionListener completionListener;
16
17
 
17
18
  AudioAsset(
18
19
  NativeAudio owner,
@@ -167,4 +168,14 @@ public class AudioAsset {
167
168
 
168
169
  return audioList.get(playIndex).isPlaying();
169
170
  }
171
+
172
+ public void setCompletionListener(AudioCompletionListener listener) {
173
+ this.completionListener = listener;
174
+ }
175
+
176
+ protected void notifyCompletion() {
177
+ if (completionListener != null) {
178
+ completionListener.onCompletion(this.assetId);
179
+ }
180
+ }
170
181
  }
@@ -0,0 +1,5 @@
1
+ package ee.forgr.audio;
2
+
3
+ public interface AudioCompletionListener {
4
+ void onCompletion(String assetId);
5
+ }
@@ -118,7 +118,7 @@ public class AudioDispatcher
118
118
  this.stop();
119
119
 
120
120
  if (this.owner != null) {
121
- this.owner.dispatchComplete();
121
+ this.owner.notifyCompletion();
122
122
  }
123
123
  }
124
124
  } catch (Exception ex) {
@@ -504,6 +504,7 @@ public class NativeAudio
504
504
  audioChannelNum,
505
505
  volume
506
506
  );
507
+ remoteAudioAsset.setCompletionListener(this::dispatchComplete);
507
508
  audioAssetList.put(audioId, remoteAudioAsset);
508
509
  } else if (
509
510
  uri.getScheme() != null && uri.getScheme().equals("file")
@@ -535,6 +536,7 @@ public class NativeAudio
535
536
  audioChannelNum,
536
537
  volume
537
538
  );
539
+ asset.setCompletionListener(this::dispatchComplete);
538
540
  audioAssetList.put(audioId, asset);
539
541
  } else {
540
542
  throw new IllegalArgumentException(
@@ -45,6 +45,9 @@ public class RemoteAudioAsset extends AudioAsset {
45
45
  isPrepared = true;
46
46
  Log.d(TAG, "MediaPlayer prepared for " + uri.toString());
47
47
  });
48
+ mediaPlayer.setOnCompletionListener(mp -> {
49
+ notifyCompletion();
50
+ });
48
51
  mediaPlayer.setOnErrorListener((mp, what, extra) -> {
49
52
  Log.e(TAG, "MediaPlayer error: " + what + ", " + extra);
50
53
  return false;
@@ -1,74 +1,118 @@
1
1
  import AVFoundation
2
2
 
3
3
  public class RemoteAudioAsset: AudioAsset {
4
- var playerItem: AVPlayerItem?
5
- var player: AVPlayer?
4
+ var playerItems: [AVPlayerItem] = []
5
+ var players: [AVPlayer] = []
6
+ var playerObservers: [NSKeyValueObservation] = []
6
7
 
7
8
  override init(owner: NativeAudio, withAssetId assetId: String, withPath path: String!, withChannels channels: Int!, withVolume volume: Float!, withFadeDelay delay: Float!) {
8
9
  super.init(owner: owner, withAssetId: assetId, withPath: path, withChannels: channels, withVolume: volume, withFadeDelay: delay)
9
10
 
10
11
  if let url = URL(string: path) {
11
- self.playerItem = AVPlayerItem(url: url)
12
- self.player = AVPlayer(playerItem: self.playerItem)
13
- self.player?.volume = volume
12
+ for _ in 0..<channels {
13
+ let playerItem = AVPlayerItem(url: url)
14
+ let player = AVPlayer(playerItem: playerItem)
15
+ player.volume = volume
16
+ self.playerItems.append(playerItem)
17
+ self.players.append(player)
18
+
19
+ // Add observer for playback finished
20
+ let observer = player.observe(\.timeControlStatus) { [weak self] player, _ in
21
+ if player.timeControlStatus == .paused && player.currentItem?.currentTime() == player.currentItem?.duration {
22
+ self?.playerDidFinishPlaying(player: player)
23
+ }
24
+ }
25
+ self.playerObservers.append(observer)
26
+ }
14
27
  }
15
28
  }
16
29
 
30
+ func playerDidFinishPlaying(player: AVPlayer) {
31
+ self.owner.notifyListeners("complete", data: [
32
+ "assetId": self.assetId
33
+ ])
34
+ }
35
+
17
36
  override func play(time: TimeInterval, delay: TimeInterval) {
18
- guard let player = self.player else { return }
37
+ guard !players.isEmpty else { return }
38
+ let player = players[playIndex]
19
39
  if delay > 0 {
20
- // Calculate the future time to play
21
40
  let timeToPlay = CMTimeAdd(CMTimeMakeWithSeconds(player.currentTime().seconds, preferredTimescale: 1), CMTimeMakeWithSeconds(delay, preferredTimescale: 1))
22
41
  player.seek(to: timeToPlay)
23
42
  } else {
24
43
  player.seek(to: CMTimeMakeWithSeconds(time, preferredTimescale: 1))
25
44
  }
26
45
  player.play()
46
+ playIndex = (playIndex + 1) % players.count
27
47
  }
28
48
 
29
49
  override func pause() {
30
- player?.pause()
50
+ guard !players.isEmpty else { return }
51
+ let player = players[playIndex]
52
+ player.pause()
31
53
  }
32
54
 
33
55
  override func resume() {
34
- player?.play()
56
+ guard !players.isEmpty else { return }
57
+ let player = players[playIndex]
58
+ player.play()
35
59
  }
36
60
 
37
61
  override func stop() {
38
- player?.pause()
39
- player?.seek(to: CMTime.zero)
62
+ for player in players {
63
+ player.pause()
64
+ player.seek(to: CMTime.zero)
65
+ }
40
66
  }
41
67
 
42
68
  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()
69
+ for player in players {
70
+ player.actionAtItemEnd = .none
71
+ NotificationCenter.default.addObserver(self,
72
+ selector: #selector(playerItemDidReachEnd(notification:)),
73
+ name: .AVPlayerItemDidPlayToEndTime,
74
+ object: player.currentItem)
75
+ player.play()
76
+ }
49
77
  }
50
78
 
51
79
  @objc func playerItemDidReachEnd(notification: Notification) {
52
- player?.seek(to: CMTime.zero)
53
- player?.play()
80
+ guard let player = notification.object as? AVPlayer else { return }
81
+ player.seek(to: CMTime.zero)
82
+ player.play()
54
83
  }
55
84
 
56
85
  override func unload() {
57
86
  stop()
58
87
  NotificationCenter.default.removeObserver(self)
59
- player = nil
60
- playerItem = nil
88
+ // Remove KVO observers
89
+ for observer in playerObservers {
90
+ observer.invalidate()
91
+ }
92
+ playerObservers = []
93
+ players = []
94
+ playerItems = []
61
95
  }
62
96
 
63
97
  override func setVolume(volume: NSNumber!) {
64
- player?.volume = volume.floatValue
98
+ for player in players {
99
+ player.volume = volume.floatValue
100
+ }
65
101
  }
66
102
 
67
103
  override func setRate(rate: NSNumber!) {
68
- player?.rate = rate.floatValue
104
+ for player in players {
105
+ player.rate = rate.floatValue
106
+ }
69
107
  }
70
108
 
71
109
  override func isPlaying() -> Bool {
72
- return player?.timeControlStatus == .playing
110
+ return players.contains { $0.timeControlStatus == .playing }
111
+ }
112
+
113
+ override func getCurrentTime() -> TimeInterval {
114
+ guard !players.isEmpty else { return 0 }
115
+ let player = players[playIndex]
116
+ return player.currentTime().seconds
73
117
  }
74
118
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/native-audio",
3
- "version": "6.4.20",
3
+ "version": "6.4.22",
4
4
  "description": "A native plugin for native audio engine",
5
5
  "main": "dist/plugin.js",
6
6
  "module": "dist/esm/index.js",