Saturday, June 13, 2026
HomeiOS Developmentios - use AVComposition as an alternative of AVQueuePlayer?

ios – use AVComposition as an alternative of AVQueuePlayer?

[ad_1]

I’ve about 200 native audio recordsdata displayed in a desk that I want to play so as. As every audio file performs, it can auto-scroll to the row.

Initially, I used to be attempting to make use of AVQueuePlayer, however issues bought actually sophisticated when attempting to derive the full time participant, implement searching for/scrubbing, integrating MPNowPlayingInfoCenter, and different performance. Additionally the time is uneven within the participant because it strikes from one audio file to the following. I am doing one thing like this:

@Printed public non-public(set) var gadgets = [AVPlayerItem]()
@Printed public non-public(set) var queuedItems = [AVPlayerItem]()
@Printed public non-public(set) var previousItems = [AVPlayerItem]()
@Printed public non-public(set) var currentItem: AVPlayerItem?
@Printed public non-public(set) var time: TimeInterval = 0
@Printed public non-public(set) var length: TimeInterval = 0
@Printed public non-public(set) var totalTime: TimeInterval = 0
@Printed public non-public(set) var totalDuration: TimeInterval = 0
@Printed public non-public(set) var remainingTime: TimeInterval = 0
@Printed public non-public(set) var progress = 0.0
non-public var participant: AVQueuePlayer?
non-public var previousDuration: TimeInterval = 0
non-public var cancellable = Set<AnyCancellable>()
non-public var timeObserverToken: Any?

// begin
gadgets = urls
  .map(AVAsset.init)
  .map(AVPlayerItem.init)

participant = AVQueuePlayer(gadgets: gadgets)

participant?.writer(for: .currentItem, choices: [.new, .old, .initial])
    .scan(currentItem) { [weak self] in self?.replace(previousItem: $0, currentItem: $1); return $1 }
    .assign(to: &$currentItem)

$gadgets
    .map { $0.cut back(into: 0.0) { $0 += $1.asset.length.seconds } }
    .assign(to: &$totalDuration)

timeObserverToken = participant?.addPeriodicTimeObserver(
    forInterval: CMTime(seconds: 0.5, preferredTimescale: CMTimeScale(NSEC_PER_SEC)),
    queue: .foremost,
) { [weak self] _ in
    self?.updateProgress()
}

// helpers
func replace(previousItem: AVPlayerItem?, currentItem: AVPlayerItem?) {
    queuedItems = Array(participant?.gadgets().drop { $0 == currentItem } ?? [])
    participant?.gadgets().isEmpty == false ? previousItem.map { previousItems.append($0) } : nil // Skip if resetting
    previousDuration = previousItems.cut back(into: 0.0) { $0 += $1.asset.length.seconds }

    guard let currentItem = currentItem else {
        time = 0
        length = 0
        return
    }

    length = currentItem.asset.length.seconds
    updateProgress()
    updateNowPlaying()
}

func updateProgress() {
    guard let currentItem = currentItem else { return }
    time = min(currentItem.currentTime().seconds, currentItem.asset.length.seconds)
    totalTime = min(previousDuration + time, totalDuration)
    remainingTime = max(totalDuration - totalTime, 0)
    progress = totalDuration > 0 ? 1 - min(remainingTime / totalDuration, 1) : 0
}

func updateNowPlaying() {
    guard let currentItem = currentItem else { return }
    var data = MPNowPlayingInfoCenter.default().nowPlayingInfo ?? [String: Any]()

    data[MPMediaItemPropertyTitle] = currentItem.url?.lastPathComponent ?? ""
    data[MPMediaItemPropertyAlbumTitle] = "My playlist"
    data[MPMediaItemPropertyPlaybackDuration] = totalDuration
    data[MPNowPlayingInfoPropertyElapsedPlaybackTime] = totalTime
    data[MPNowPlayingInfoPropertyPlaybackRate] = participant?.price ?? 0
    data[MPNowPlayingInfoPropertyPlaybackQueueIndex] = gadgets.firstIndex(of: currentItem) ?? 0
    data[MPNowPlayingInfoPropertyPlaybackQueueCount] = gadgets.depend
    data[MPMediaItemPropertyArtwork] = UIImage(named: "cover-image")
        .map { picture in MPMediaItemArtwork(boundsSize: CGSize(width: 1080, peak: 1080)) { _ in picture } }

    MPNowPlayingInfoCenter.default().nowPlayingInfo = data
}

I then stumbled upon AVComposition and looks as if it might be a cleaner method to merge all 200 audio recordsdata into one giant one, and add time segments to it to deal with the auto-scrolling of the listing and updating MPNowPlayingInfoCenter.

How can I exploit AVComposition to merge all of the recordsdata and add time marks, but in addition How might I inform which audio is enjoying? Would this be the correct method or ought to I’m going again to AVQueuePlayer and hold refactoring what I’ve above? Thanks for any assist or perception.

[ad_2]

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments