I have about 200 audio assets about 5 seconds each that are loaded into an AVQueuePlayer
. I do this so it plays all the assets as one full song, but allowing the user to view or jump to a specific verse.
The issue is the main thread gets locked when I load them in like this:
let items = urls
.map(AVAsset.init)
.map(AVPlayerItem.init)
let player = AVQueuePlayer(items: items)
Then I discovered I must asynchronously load them into the player so tried something like this:
let items = urls
.map(AVAsset.init)
.map(AVPlayerItem.init)
let player = AVQueuePlayer()
// Below does NOT compile!!
await withThrowingTaskGroup(of: Void.self) { group in
for var item in items {
group.addTask { _ = try await item.asset.load(.duration) }
for try await result in group {
player?.insert(item, after: nil)
}
}
}
I’m only supporting iOS 16+ so I’m trying to make use of the new Swift Concurrency APIs available in AVFoundation
. I tried following this document but there’s a lot of gaps I can’t quite get. What is the proper way of loading up that many assets into the queue player without locking up the main thread?
2
Answers
How about something like this?
Since it seems that you are trying to directly affect
items
andplayer
I would useactor
. To keep everything together and synchronized.To bypass
captured var 'item' in concurrently-executing code
you can use.enumerated()
Then just call
loadItems
withTask
orTask.detached