Search code examples
iosswiftavaudioplayeravaudioplayernodereact-native-bridge

AVPlayer.addPeriodicTimeObserver equivalent on AVAudioPlayerNode


I'am refactoring a react-native package that using AVPlayer, into AVAudioEngine and AVAudioPlayerNode. But I confuse how to turn AVPlayer.addPeriodicTimeObserver using AVAudioPlayerNode. The idea is i need to get time data when music is playing, hence in this addPeriodicTimeObserver closure need to send with interval, so in that regard how to use it on AVAudioPlayerNode, thanks!

func addPeriodicTimeObserver() {
    let timeScale = CMTimeScale(NSEC_PER_SEC)
    let time = CMTime(seconds: subscriptionDuration, preferredTimescale: timeScale)
  
    timeObserverToken = audioPlayer.addPeriodicTimeObserver(forInterval: time,
                                                            queue: .main) {_ in
        if (self.audioPlayer != nil) {
            self.sendEvent(withName: "rn-playback", body: [
                "isMuted": self.audioPlayer.isMuted,
                "currentPosition": self.audioPlayerItem.currentTime().seconds * 1000,
                "duration": self.audioPlayerItem.duration.seconds * 1000,
            ])
        }
    }
}

Solution

  • I ended up using timer to observe.

    @objc(setupPlayer:rejecter:)
      func setupPlayer(
        resolve: @escaping RCTPromiseResolveBlock,
        rejecter reject: @escaping RCTPromiseRejectBlock
      ) {
        ...
        do {
          try engine.start()
          startPlaybackTimer()
    
        } catch let err {
          ...
        }
      }
    
      @objc(updatePlaybackProgress:)
      public func updatePlaybackProgress(timer: Timer) -> Void {
        if player.isPlaying {
        
        let status = [
          "currentPosition": getCurrentPos(),
          "duration": getCurrentDuration(),
        ] as [String : Any];
        
          self.sendEvent(withName: "playbackData", body: status)
        }
      }
    
      @objc(startPlaybackTimer)
      func startPlaybackTimer() -> Void {
        DispatchQueue.main.async {
          self.timer = Timer.scheduledTimer(
            timeInterval: self.subscriptionDuration,
            target: self,
            selector: #selector(self.updatePlaybackProgress),
            userInfo: nil,
            repeats: true
          )
        }
      }