@capgo/native-audio 6.4.20 → 6.4.22

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