SwiftAudioEx
SwiftAudioEx copied to clipboard
Main thread blocked by synchronous property query on not-yet-loaded property
Describe the bug Main thread is blocked by synchronous property queries on not-yet-loaded asset properties for HTTP(S) assets, causing significant performance issues and UI freezing, especially on slow networks:
Main thread blocked by synchronous property query on not-yet-loaded property (assetProperty_CommonMetadata) for HTTP(S) asset. This could have been a problem if this asset were being read from a slow network.
Main thread blocked by synchronous property query on not-yet-loaded property (assetProperty_AvailableMetadataFormats) for HTTP(S) asset. This could have been a problem if this asset were being read from a slow network.
Main thread blocked by synchronous property query on not-yet-loaded property (Duration) for HTTP(S) asset. This could have been a problem if this asset were being read from a slow network.
To Reproduce I will provide minimal code to reproduce later... The key point is to play stream item, clear the player before it fully loaded and try to play item again.
Additional context
It appears that pendingAsset.loadValuesAsynchronously and DispatchQueue.main.async in the AVPlayerWrapper load() method are causing issues. Migrating to the new async/await assets.load(.type) seems to be a solution. I used AI assistance to migrate and verify the solution, and I can confirm that this migration resolves the issue. However, I'm not deeply familiar with implementing this solution in a production environment. Has anyone performed such a migration?
Here is the migrated code (I think this code has its own problems and needs to be reworked):
// AVPlayerWrapper line 230
func load() {
if (state == .failed) {
recreateAVPlayer()
} else {
clearCurrentItem()
}
if let url = url {
let pendingAsset = AVURLAsset(url: url, options: urlOptions)
asset = pendingAsset
state = .loading
Task { @MainActor in
do {
// Load common metadata
let commonMetadata = try await pendingAsset.load(.commonMetadata)
if !commonMetadata.isEmpty {
delegate?.AVWrapper(didReceiveCommonMetadata: commonMetadata)
}
// Load chapter metadata
let chapterLocales = try await pendingAsset.load(.availableChapterLocales)
if chapterLocales.count > 0 {
for locale in chapterLocales {
let chapters = try await pendingAsset.loadChapterMetadataGroups(withTitleLocale: locale)
delegate?.AVWrapper(didReceiveChapterMetadata: chapters)
}
} else {
// Fallback to timed metadata if no chapters
let formats = try await pendingAsset.load(.availableMetadataFormats)
for format in formats {
let timeRange = CMTimeRange(
start: CMTime(seconds: 0, preferredTimescale: 1000),
end: try await pendingAsset.load(.duration)
)
let metadataItems = try await pendingAsset.loadMetadata(for: format)
let group = AVTimedMetadataGroup(items: metadataItems, timeRange: timeRange)
delegate?.AVWrapper(didReceiveTimedMetadata: [group])
}
}
// Check if asset is playable
let isPlayable = try await pendingAsset.load(.isPlayable)
guard isPlayable else {
playbackFailed(error: AudioPlayerError.PlaybackError.itemWasUnplayable)
return
}
// Create player item
let item = AVPlayerItem(asset: pendingAsset)
self.item = item
item.preferredForwardBufferDuration = bufferDuration
avPlayer.replaceCurrentItem(with: item)
startObservingAVPlayer(item: item)
applyAVPlayerRate()
// Seek to initial time if needed
if let initialTime = timeToSeekToAfterLoading {
timeToSeekToAfterLoading = nil
seek(to: initialTime)
}
} catch {
playbackFailed(error: AudioPlayerError.PlaybackError.failedToLoadKeyValue)
}
}
}
}
bump. We are facing some issues getting the itemWasUnplayable using the RN-track-player on some devices with ios>=18. Can't repro it on my end but I am guessing the deprecation is the cause