capacitor-plugin-playlist 0.1.30 → 0.1.33

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.
@@ -15,9 +15,9 @@ import UIKit
15
15
  extension String: Error {}
16
16
 
17
17
  final class RmxAudioPlayer: NSObject {
18
-
18
+
19
19
  var statusUpdater: StatusUpdater? = nil
20
-
20
+
21
21
  private var playbackTimeObserver: Any?
22
22
  private var wasPlayingInterrupted = false
23
23
  private var commandCenterRegistered = false
@@ -37,11 +37,11 @@ final class RmxAudioPlayer: NSObject {
37
37
  activateAudioSession()
38
38
  observeLifeCycle()
39
39
  }
40
-
40
+
41
41
  deinit {
42
42
  releaseResources()
43
43
  }
44
-
44
+
45
45
  func setOptions(_ options: [String:Any]) {
46
46
  print("RmxAudioPlayer.execute=setOptions, \(options)")
47
47
  resetStreamOnPause = (options["resetStreamOnPause"] as? NSNumber)?.boolValue ?? false
@@ -49,20 +49,20 @@ final class RmxAudioPlayer: NSObject {
49
49
 
50
50
  func initialize() {
51
51
  print("RmxAudioPlayer.execute=initialize")
52
-
52
+
53
53
  avQueuePlayer.actionAtItemEnd = .advance
54
54
  avQueuePlayer.addObserver(self, forKeyPath: "currentItem", options: .new, context: nil)
55
55
  avQueuePlayer.addObserver(self, forKeyPath: "rate", options: .new, context: nil)
56
56
  avQueuePlayer.addObserver(self, forKeyPath: "timeControlStatus", options: .new, context: nil)
57
-
57
+
58
58
  let interval = CMTimeMakeWithSeconds(Float64(1.0), preferredTimescale: Int32(Double(NSEC_PER_SEC)))
59
59
  playbackTimeObserver = avQueuePlayer.addPeriodicTimeObserver(forInterval: interval, queue: .main, using: { [weak self] time in
60
60
  self?.executePeriodicUpdate(time)
61
61
  })
62
-
62
+
63
63
  onStatus(.rmxstatus_REGISTER, trackId: "INIT", param: nil)
64
64
  }
65
-
65
+
66
66
  func setPlaylistItems(_ items: [AudioTrack], options: [String:Any]) {
67
67
  print("RmxAudioPlayer.execute=setPlaylistItems, \(options), \(items)")
68
68
 
@@ -74,11 +74,11 @@ final class RmxAudioPlayer: NSObject {
74
74
 
75
75
  let startPaused = options["startPaused"] != nil ? (options["startPaused"] as? Bool) ?? false : true
76
76
 
77
- if retainPosition {
77
+ if playFromPosition > 0.0 {
78
+ seekToPosition = playFromPosition
79
+ }
80
+ else if retainPosition {
78
81
  seekToPosition = getTrackCurrentTime(nil)
79
- if playFromPosition > 0.0 {
80
- seekToPosition = playFromPosition
81
- }
82
82
  }
83
83
 
84
84
  let result = findTrack(byId: playFromId)
@@ -89,7 +89,7 @@ final class RmxAudioPlayer: NSObject {
89
89
  avQueuePlayer.setCurrentIndex(idx)
90
90
  }
91
91
  }
92
-
92
+
93
93
  // This will wait for the AVPlayerItemStatusReadyToPlay status change, and then trigger playback.
94
94
  isWaitingToStartPlayback = !startPaused
95
95
  if isWaitingToStartPlayback {
@@ -136,7 +136,7 @@ final class RmxAudioPlayer: NSObject {
136
136
 
137
137
  }
138
138
  }
139
-
139
+
140
140
  return removed
141
141
  }
142
142
 
@@ -149,8 +149,10 @@ final class RmxAudioPlayer: NSObject {
149
149
  guard (0..<avQueuePlayer.queuedAudioTracks.count).contains(index) else {
150
150
  throw "Provided index is out of bounds"
151
151
  }
152
-
153
- avQueuePlayer.setCurrentIndex(index)
152
+
153
+ if avQueuePlayer.currentIndex() != index {
154
+ avQueuePlayer.setCurrentIndex(index)
155
+ }
154
156
  playCommand(false)
155
157
 
156
158
  if positionTime != nil {
@@ -162,15 +164,17 @@ final class RmxAudioPlayer: NSObject {
162
164
  guard !avQueuePlayer.queuedAudioTracks.isEmpty else {
163
165
  throw "The playlist is empty!"
164
166
  }
165
- let result = findTrack(byId: trackId)
166
- let idx = result?["index"] as? Int ?? -1
167
- guard idx >= 0 else {
168
- throw "Track ID not found"
167
+
168
+ if avQueuePlayer.currentAudioTrack?.trackId != trackId {
169
+ let result = findTrack(byId: trackId)
170
+ let idx = result?["index"] as? Int ?? -1
171
+ guard idx >= 0 else {
172
+ throw "Track ID not found"
173
+ }
174
+ avQueuePlayer.setCurrentIndex(idx)
169
175
  }
170
-
171
- avQueuePlayer.setCurrentIndex(idx)
172
176
  playCommand(false)
173
-
177
+
174
178
  if positionTime != nil {
175
179
  seek(to: positionTime!, isCommand: false)
176
180
  }
@@ -187,7 +191,7 @@ final class RmxAudioPlayer: NSObject {
187
191
 
188
192
  func setLoopAll(_ loop: Bool) {
189
193
  self.loop = loop
190
-
194
+
191
195
  print("RmxAudioPlayer.execute=setLoopAll, \(loop)")
192
196
  }
193
197
 
@@ -227,18 +231,18 @@ final class RmxAudioPlayer: NSObject {
227
231
  removeTrackObservers(item)
228
232
  avQueuePlayer.remove(item)
229
233
  }
230
-
234
+
231
235
  func removeItem(_ id: String) throws {
232
236
  let result = findTrack(byId: id)
233
237
  let idx = (result?["index"] as? NSNumber)?.intValue ?? 0
234
238
  let track = result?["track"] as? AudioTrack
235
-
239
+
236
240
  guard idx >= 0 else {
237
241
  throw "Could not find track by id" + id
238
242
  }
239
243
  // AudioTrack* item = [self avQueuePlayer].itemsForPlayer[idx];
240
244
  removeTrackObservers(track)
241
-
245
+
242
246
  if let track = track {
243
247
  avQueuePlayer.remove(track)
244
248
  }
@@ -257,14 +261,13 @@ final class RmxAudioPlayer: NSObject {
257
261
  if resetStreamOnPause,
258
262
  let currentTrack = avQueuePlayer.currentAudioTrack,
259
263
  currentTrack.isStream {
264
+ print( "music-stream-play")
260
265
  avQueuePlayer.seek(to: .positiveInfinity, toleranceBefore: .zero, toleranceAfter: .zero)
261
266
  currentTrack.seek(to: .positiveInfinity, toleranceBefore: .zero, toleranceAfter: .zero, completionHandler: nil)
262
267
  }
263
268
 
264
- if isCommand {
265
- let action = "music-controls-play"
266
- print("\(action)")
267
- }
269
+ print( "music-controls-play ")
270
+
268
271
  avQueuePlayer.play()
269
272
  }
270
273
 
@@ -284,7 +287,7 @@ final class RmxAudioPlayer: NSObject {
284
287
  avQueuePlayer.seek(to: .positiveInfinity, toleranceBefore: .zero, toleranceAfter: .zero)
285
288
  currentTrack.seek(to: .positiveInfinity, toleranceBefore: .zero, toleranceAfter: .zero, completionHandler: nil)
286
289
  }
287
-
290
+
288
291
  if isCommand {
289
292
  let action = "music-controls-pause"
290
293
  print("\(action)")
@@ -316,7 +319,7 @@ final class RmxAudioPlayer: NSObject {
316
319
  func playNext(_ isCommand: Bool) {
317
320
  wasPlayingInterrupted = false
318
321
  initializeMPCommandCenter()
319
-
322
+
320
323
  avQueuePlayer.advanceToNextItem()
321
324
 
322
325
  if isCommand {
@@ -353,18 +356,18 @@ final class RmxAudioPlayer: NSObject {
353
356
  ])
354
357
  }
355
358
  }
356
-
359
+
357
360
  func setVolume(_ volume: Float) {
358
361
  avQueuePlayer.volume = volume
359
362
  }
360
-
363
+
361
364
  func addTracks(_ tracks: [AudioTrack], startPosition: Float) {
362
365
  for playerItem in tracks {
363
366
  addTrackObservers(playerItem)
364
367
  }
365
368
 
366
369
  avQueuePlayer.appendItems(tracks)
367
-
370
+
368
371
  if startPosition > 0 {
369
372
  seek(to: startPosition, isCommand: false)
370
373
  }
@@ -445,7 +448,7 @@ final class RmxAudioPlayer: NSObject {
445
448
  // This happens when the network is insufficient to continue playback.
446
449
  let playerItem = avQueuePlayer.currentAudioTrack
447
450
  let trackStatus = getStatusItem(playerItem)
448
-
451
+
449
452
  onStatus(.rmxstatus_STALLED, trackId: playerItem?.trackId, param: trackStatus)
450
453
  }
451
454
 
@@ -474,7 +477,7 @@ final class RmxAudioPlayer: NSObject {
474
477
  interruptionNotification?.userInfo?[AVAudioSessionInterruptionTypeKey] as Any)
475
478
  return
476
479
  }
477
-
480
+
478
481
  switch interruptionType {
479
482
  case AVAudioSession.InterruptionType.began:
480
483
  let suspended = (interruptionNotification?.userInfo?[AVAudioSessionInterruptionWasSuspendedKey] as? NSNumber)?.boolValue ?? false
@@ -523,24 +526,28 @@ final class RmxAudioPlayer: NSObject {
523
526
  guard let change = change else {
524
527
  return
525
528
  }
526
-
529
+
527
530
  switch keyPath {
528
531
  case "currentItem":
529
532
  // only fire on real change!
530
533
  let player = object as? AVBidirectionalQueuePlayer
531
534
  let playerItem = player?.currentAudioTrack
532
- guard lastTrackId != playerItem?.trackId else {
535
+ if playerItem != nil {
536
+ guard self.lastTrackId != playerItem?.trackId else {
533
537
  return // todo should call super instead or?
534
538
  }
535
- lastTrackId = playerItem?.trackId
539
+ print("observe change currentItem: lastTrackId \(self.lastTrackId) playerItem: \(playerItem?.trackId)")
540
+ self.lastTrackId = playerItem?.trackId
536
541
  handleCurrentItemChanged(playerItem)
542
+ }
543
+
537
544
  case "rate":
538
545
  guard lastRate != change[.newKey] as? Float else {
539
546
  return // todo should call super instead or?
540
547
  }
541
548
  self.lastRate = change[.newKey] as? Float
542
549
  let player = object as? AVBidirectionalQueuePlayer
543
-
550
+
544
551
  guard let playerItem = player?.currentAudioTrack else { return }
545
552
 
546
553
  let trackStatus = getStatusItem(playerItem)
@@ -559,7 +566,7 @@ final class RmxAudioPlayer: NSObject {
559
566
  case "timeControlStatus":
560
567
  DispatchQueue.main.debounce(interval: 0.2, context: self, action: { [self] in
561
568
  let player = object as? AVBidirectionalQueuePlayer
562
-
569
+
563
570
  guard let playerItem = player?.currentAudioTrack else {
564
571
  return
565
572
  }
@@ -594,7 +601,6 @@ final class RmxAudioPlayer: NSObject {
594
601
  }
595
602
 
596
603
  func updateNowPlayingTrackInfo(_ playerItem: AudioTrack?, updateTrackData: Bool) {
597
-
598
604
  let currentItem = playerItem ?? avQueuePlayer.currentAudioTrack
599
605
  let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
600
606
  if updatedNowPlayingInfo == nil {
@@ -628,7 +634,7 @@ final class RmxAudioPlayer: NSObject {
628
634
  updatedNowPlayingInfo![MPNowPlayingInfoPropertyPlaybackRate] = 1.0
629
635
 
630
636
  MPNowPlayingInfoCenter.default().nowPlayingInfo = updatedNowPlayingInfo
631
-
637
+
632
638
  let commandCenter = MPRemoteCommandCenter.shared()
633
639
  commandCenter.nextTrackCommand.isEnabled = !avQueuePlayer.isAtEnd
634
640
  commandCenter.previousTrackCommand.isEnabled = !avQueuePlayer.isAtBeginning
@@ -638,11 +644,10 @@ final class RmxAudioPlayer: NSObject {
638
644
  guard let coverUri = coverUriOrNil else {
639
645
  return nil
640
646
  }
641
-
642
647
  var coverImage: UIImage? = nil
643
648
  if coverUri.hasPrefix("http://") || coverUri.hasPrefix("https://") {
644
649
  let coverImageUrl = URL(string: coverUri)!
645
-
650
+
646
651
  do {
647
652
  let coverImageData = try Data(contentsOf: coverImageUrl)
648
653
  coverImage = UIImage(data: coverImageData)
@@ -654,7 +659,7 @@ final class RmxAudioPlayer: NSObject {
654
659
  coverImage = UIImage(contentsOfFile: coverUri)
655
660
  }
656
661
  }
657
-
662
+
658
663
  if isCoverImageValid(coverImage) {
659
664
  return MPMediaItemArtwork.init(boundsSize: coverImage!.size, requestHandler: { (size) -> UIImage in
660
665
  return coverImage!
@@ -662,7 +667,7 @@ final class RmxAudioPlayer: NSObject {
662
667
  }
663
668
  return nil;
664
669
  }
665
-
670
+
666
671
  func downloadImage(url: URL, completion: @escaping ((_ image: UIImage?) -> Void)){
667
672
  print("Started downloading \"\(url.deletingPathExtension().lastPathComponent)\".")
668
673
  self.getImageDataFromUrl(url) { (_ data: Data?) in
@@ -754,9 +759,10 @@ final class RmxAudioPlayer: NSObject {
754
759
  isWaitingToStartPlayback = false
755
760
  var errorMsg = ""
756
761
  if playerItem.error != nil {
762
+ print("\(playerItem.error)")
757
763
  errorMsg = "Error playing audio track: \((playerItem.error as NSError?)?.localizedFailureReason ?? "")"
758
764
  }
759
- print("AVPlayerItemStatusFailed: Error playing audio track: \(errorMsg)")
765
+ print("AVPlayerItemStatusFailed: \(errorMsg)")
760
766
  let errorParam = createError(withCode: .rmxerr_DECODE, message: errorMsg)
761
767
  onStatus(.rmxstatus_ERROR, trackId: playerItem.trackId, param: errorParam)
762
768
  case .unknown:
@@ -773,9 +779,9 @@ final class RmxAudioPlayer: NSObject {
773
779
  // It doesn't always fire, and it is not needed because the queue's periodic update can also
774
780
  // deliver this info.
775
781
  //NSString* name = ((AVURLAsset*)playerItem.asset).URL.pathComponents.lastObject;
776
-
782
+
777
783
  guard let playerItem = playerItem else { return }
778
-
784
+
779
785
  if !CMTIME_IS_INDEFINITE(playerItem.duration) {
780
786
  let duration = CMTimeGetSeconds(playerItem.duration)
781
787
  print("The track duration was changed [\(playerItem.trackId ?? "")]: \(duration)")
@@ -860,7 +866,7 @@ final class RmxAudioPlayer: NSObject {
860
866
  status = "paused"
861
867
  }
862
868
  }
863
-
869
+
864
870
  return [
865
871
  "trackId": currentItem.trackId ?? "",
866
872
  "isStream": currentItem.isStream ? NSNumber(value: 1) : NSNumber(value: 0),
@@ -896,10 +902,10 @@ final class RmxAudioPlayer: NSObject {
896
902
  "duration": NSNumber(value: 0.0)
897
903
  ]
898
904
  }
899
-
905
+
900
906
  let duration = Float(CMTimeGetSeconds(playerItem.duration))
901
907
  let timeRanges = playerItem.loadedTimeRanges
902
-
908
+
903
909
  guard !timeRanges.isEmpty else {
904
910
  return [
905
911
  "start": NSNumber(value: 0.0),
@@ -908,7 +914,7 @@ final class RmxAudioPlayer: NSObject {
908
914
  "duration": NSNumber(value: duration)
909
915
  ]
910
916
  }
911
-
917
+
912
918
  let timerange = timeRanges[0].timeRangeValue
913
919
  let start = Float(CMTimeGetSeconds(timerange.start))
914
920
  let rangeEnd = Float(CMTimeGetSeconds(timerange.duration))
@@ -959,7 +965,7 @@ final class RmxAudioPlayer: NSObject {
959
965
  else {
960
966
  return nil
961
967
  }
962
-
968
+
963
969
  return [
964
970
  "track": track,
965
971
  "index": NSNumber(value: index)
@@ -989,9 +995,6 @@ final class RmxAudioPlayer: NSObject {
989
995
  }
990
996
 
991
997
  func removeTrackObservers(_ playerItem: AudioTrack?) {
992
- playerItem?.removeObserver(self, forKeyPath: "status")
993
- playerItem?.removeObserver(self, forKeyPath: "duration")
994
- playerItem?.removeObserver(self, forKeyPath: "loadedTimeRanges")
995
998
  NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: playerItem)
996
999
  NotificationCenter.default.removeObserver(self, name: .AVPlayerItemPlaybackStalled, object: playerItem)
997
1000
 
@@ -1024,10 +1027,6 @@ final class RmxAudioPlayer: NSObject {
1024
1027
  func observeLifeCycle() {
1025
1028
  let listener = NotificationCenter.default
1026
1029
 
1027
- // These aren't really needed. the AVQueuePlayer handles this for us.
1028
- // [listener addObserver:self selector:@selector(handleEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
1029
- // [listener addObserver:self selector:@selector(handleEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
1030
-
1031
1030
  // We do need these.
1032
1031
  listener.addObserver(self, selector: #selector(handleAudioSessionInterruption(_:)), name: AVAudioSession.interruptionNotification, object: AVAudioSession.sharedInstance())
1033
1032
 
@@ -1060,11 +1059,6 @@ final class RmxAudioPlayer: NSObject {
1060
1059
 
1061
1060
  /// Cleanup
1062
1061
  func deregisterMusicControlsEventListener() {
1063
- // We don't use the remote control, and no need to remove observer on
1064
- // NSNotificationCenter, that is done automatically
1065
- // [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
1066
- // [[NSNotificationCenter defaultCenter] removeObserver:self name:@"receivedEvent" object:nil];
1067
-
1068
1062
  let commandCenter = MPRemoteCommandCenter.shared()
1069
1063
  commandCenter.playCommand.removeTarget(self)
1070
1064
  commandCenter.pauseCommand.removeTarget(self)
@@ -1076,10 +1070,9 @@ final class RmxAudioPlayer: NSObject {
1076
1070
 
1077
1071
  commandCenterRegistered = false
1078
1072
  }
1079
-
1073
+
1080
1074
  func onReset() {
1081
1075
  // Override to cancel any long-running requests when the WebView navigates or refreshes.
1082
- //super.onReset()
1083
1076
  releaseResources()
1084
1077
  }
1085
1078
 
@@ -1087,9 +1080,6 @@ final class RmxAudioPlayer: NSObject {
1087
1080
  if let playbackTimeObserver = playbackTimeObserver {
1088
1081
  avQueuePlayer.removeTimeObserver(playbackTimeObserver)
1089
1082
  }
1090
- avQueuePlayer.removeObserver(self as NSObject, forKeyPath: "currentItem")
1091
- avQueuePlayer.removeObserver(self as NSObject, forKeyPath: "rate")
1092
- avQueuePlayer.removeObserver(self as NSObject, forKeyPath: "timeControlStatus")
1093
1083
  deregisterMusicControlsEventListener()
1094
1084
 
1095
1085
  removeAllTracks()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-plugin-playlist",
3
- "version": "0.1.30",
3
+ "version": "0.1.33",
4
4
  "description": "Playlist ",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -1 +0,0 @@
1
- /build
@@ -1 +0,0 @@
1
- /build