react-native-mp3-player 1.0.3 → 1.0.4

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/README.md CHANGED
@@ -79,8 +79,8 @@ TrackPlayer.registerPlaybackService(() => PlaybackService);
79
79
  - **Lifecycle:** `setupPlayer(options?, background?)`, `registerPlaybackService(factory)`, `reset()`
80
80
  - **Queue:** `add()`, `load()`, `remove()`, `skip()`, `skipToNext()`, `skipToPrevious()`, `setQueue()`, `getQueue()`, **`getActiveTrack()`** (current track), `getActiveTrackIndex()`
81
81
  - **Playback:** `play()`, `pause()`, `stop()`, `seekTo()`, `seekBy()`, `setVolume()`, `setRate()`, `setRepeatMode()`
82
- - **State:** `getPlaybackState()`, `getProgress()`, `getVolume()`, `getRate()`
83
- - **Events:** `addEventListener(event, listener)` – see `Event` enum.
82
+ - **State & progress:** **`getPlaybackState()`** (returns `{ state }`; use this, not `getState`), **`getProgress()`** (returns `{ position, duration, buffered }` in seconds), **`getPosition()`** and **`getDuration()`** (convenience wrappers around `getProgress()`), `getVolume()`, `getRate()`
83
+ - **Events:** `addEventListener(event, listener)` – see `Event` enum. Listen for `Event.PlaybackState` so the UI stays in sync when the user taps play/pause.
84
84
  - **Hooks:** **`useProgress(updateInterval?, background?)`** (interval in **milliseconds**; e.g. `useProgress(250)` = every 250 ms), `usePlaybackState()`, `useActiveTrack()`, `useIsPlaying()`, `useTrackPlayerEvents()`, etc.
85
85
 
86
86
  **Setup options** (e.g. in `setupPlayer` / `updateOptions`): `iosCategory` (e.g. `'playback'`), `iosCategoryOptions` (e.g. `['allowAirPlay','allowBluetooth','duckOthers']`), `autoHandleInterruptions`, `autoUpdateMetadata`, `waitForBuffer`, `minBuffer` / buffer-related options, `forwardJumpInterval` / `backwardJumpInterval` (seconds, e.g. 15), `progressUpdateEventInterval` (seconds). Types and options are in the package TypeScript definitions.
@@ -27,6 +27,9 @@ public class RNTrackPlayer: NSObject, AudioSessionControllerDelegate {
27
27
  private var forwardJumpInterval: NSNumber? = nil;
28
28
  private var backwardJumpInterval: NSNumber? = nil;
29
29
  private var sessionCategory: AVAudioSession.Category = .playback
30
+ /// Timer work item for updating Now Playing elapsed/duration every second so the lock screen widget stays in sync.
31
+ private var nowPlayingUpdateWorkItem: DispatchWorkItem? = nil
32
+ private let nowPlayingUpdateQueue = DispatchQueue.main
30
33
  private var sessionCategoryMode: AVAudioSession.Mode = .default
31
34
  private var sessionCategoryPolicy: AVAudioSession.RouteSharingPolicy = .longFormAudio
32
35
  private var sessionCategoryOptions: AVAudioSession.CategoryOptions = []
@@ -531,6 +534,7 @@ public class RNTrackPlayer: NSObject, AudioSessionControllerDelegate {
531
534
  public func reset(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
532
535
  if (rejectWhenNotInitialized(reject: reject)) { return }
533
536
 
537
+ stopNowPlayingUpdateTimer()
534
538
  player.stop()
535
539
  player.clear()
536
540
  resolve(NSNull())
@@ -541,6 +545,8 @@ public class RNTrackPlayer: NSObject, AudioSessionControllerDelegate {
541
545
  if (rejectWhenNotInitialized(reject: reject)) { return }
542
546
  player.play()
543
547
  resolve(NSNull())
548
+ // Emit PlaybackState immediately so in-app UI (play/pause button) updates without waiting for native state transition.
549
+ emit(event: EventType.PlaybackState, body: getPlaybackStateBodyKeyValues(state: .playing))
544
550
  }
545
551
 
546
552
  @objc(pause:rejecter:)
@@ -549,6 +555,8 @@ public class RNTrackPlayer: NSObject, AudioSessionControllerDelegate {
549
555
 
550
556
  player.pause()
551
557
  resolve(NSNull())
558
+ // Emit PlaybackState immediately so in-app UI (play/pause button) updates without waiting for native state transition.
559
+ emit(event: EventType.PlaybackState, body: getPlaybackStateBodyKeyValues(state: .paused))
552
560
  }
553
561
 
554
562
  @objc(setPlayWhenReady:resolver:rejecter:)
@@ -823,6 +831,33 @@ public class RNTrackPlayer: NSObject, AudioSessionControllerDelegate {
823
831
  "position": player.currentTime,
824
832
  ] as [String : Any])
825
833
  }
834
+ // Keep Now Playing widget elapsed/duration in sync: update every second when we have a current item and are ready/playing/paused.
835
+ switch state {
836
+ case .ready, .playing, .paused:
837
+ if player.currentItem != nil && player.automaticallyUpdateNowPlayingInfo {
838
+ scheduleNextNowPlayingUpdate()
839
+ } else {
840
+ stopNowPlayingUpdateTimer()
841
+ }
842
+ default:
843
+ stopNowPlayingUpdateTimer()
844
+ }
845
+ }
846
+
847
+ private func scheduleNextNowPlayingUpdate() {
848
+ stopNowPlayingUpdateTimer()
849
+ let workItem = DispatchWorkItem { [weak self] in
850
+ guard let self = self, self.player.currentItem != nil, self.player.automaticallyUpdateNowPlayingInfo else { return }
851
+ self.player.updateNowPlayingPlaybackValues()
852
+ self.scheduleNextNowPlayingUpdate()
853
+ }
854
+ nowPlayingUpdateWorkItem = workItem
855
+ nowPlayingUpdateQueue.asyncAfter(deadline: .now() + 1.0, execute: workItem)
856
+ }
857
+
858
+ private func stopNowPlayingUpdateTimer() {
859
+ nowPlayingUpdateWorkItem?.cancel()
860
+ nowPlayingUpdateWorkItem = nil
826
861
  }
827
862
 
828
863
  func handleAudioPlayerCommonMetadataReceived(metadata: [AVMetadataItem]) {
@@ -269,6 +269,14 @@ export declare function getActiveTrack(): Promise<Track | undefined>;
269
269
  * duration in seconds.
270
270
  */
271
271
  export declare function getProgress(): Promise<Progress>;
272
+ /**
273
+ * Gets the current playback position in seconds. Convenience wrapper around getProgress().
274
+ */
275
+ export declare function getPosition(): Promise<number>;
276
+ /**
277
+ * Gets the duration of the current track in seconds. Convenience wrapper around getProgress().
278
+ */
279
+ export declare function getDuration(): Promise<number>;
272
280
  /**
273
281
  * Gets the playback state of the player.
274
282
  *
@@ -474,6 +474,20 @@ export async function getProgress() {
474
474
  // @ts-expect-error codegen issues
475
475
  return TrackPlayer.getProgress();
476
476
  }
477
+ /**
478
+ * Gets the current playback position in seconds. Convenience wrapper around getProgress().
479
+ */
480
+ export async function getPosition() {
481
+ const { position } = await getProgress();
482
+ return position;
483
+ }
484
+ /**
485
+ * Gets the duration of the current track in seconds. Convenience wrapper around getProgress().
486
+ */
487
+ export async function getDuration() {
488
+ const { duration } = await getProgress();
489
+ return duration;
490
+ }
477
491
  /**
478
492
  * Gets the playback state of the player.
479
493
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-mp3-player",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "React Native audio player with reliable iOS background playback. Media controls, queue, hooks. Built for stability and long-running playback.",
5
5
  "main": "lib/src/index.js",
6
6
  "types": "lib/src/index.d.ts",
@@ -633,6 +633,22 @@ export async function getProgress(): Promise<Progress> {
633
633
  return TrackPlayer.getProgress();
634
634
  }
635
635
 
636
+ /**
637
+ * Gets the current playback position in seconds. Convenience wrapper around getProgress().
638
+ */
639
+ export async function getPosition(): Promise<number> {
640
+ const { position } = await getProgress();
641
+ return position;
642
+ }
643
+
644
+ /**
645
+ * Gets the duration of the current track in seconds. Convenience wrapper around getProgress().
646
+ */
647
+ export async function getDuration(): Promise<number> {
648
+ const { duration } = await getProgress();
649
+ return duration;
650
+ }
651
+
636
652
  /**
637
653
  * Gets the playback state of the player.
638
654
  *