HLS元数据ID3标签失效:TableView点击音频单元格无法获取元数据
Hey there, let's troubleshoot why your HLS ID3 metadata isn't working as expected with your AVPlayer setup. I've run into similar issues before, so let's break down the fixes step by step:
Common Issues & Solutions
1. Fix Forced Unwrapping & URL Validation
Your current code uses force unwraps (!) which can crash if the URL is invalid—plus a malformed URL will prevent the HLS stream (and its metadata) from loading at all. Start with safe optional handling:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // Safely validate and encode the audio URL guard let originalAudioUrl = channelSelected.audioUrl, let encodedUrlString = originalAudioUrl.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed), let audioUrl = URL(string: encodedUrlString) else { print("Invalid or malformed audio URL") return } // Rest of your code will go here... }
2. Ensure Proper Observer Management
You're adding an observer but not removing it when switching audio streams, which can cause memory leaks or duplicate metadata callbacks. Always clean up old observers before adding new ones:
// Inside didSelectRowAt, after validating the URL: // Remove observer from previous player item (if exists) if let oldPlayerItem = player?.currentItem { oldPlayerItem.removeObserver(self, forKeyPath: "timedMetadata") } // Create new player item and add observer let playerItem = AVPlayerItem(url: audioUrl) playerItem.addObserver(self, forKeyPath: "timedMetadata", options: .new, context: nil)
3. Correctly Link Player to Player Item
Your code cuts off at player = AVPlayer(...)—make sure you're initializing or updating the player with the new playerItem, otherwise the observer won't track an active playback item:
// Inside didSelectRowAt: if let existingPlayer = player { // Replace current item if player already exists existingPlayer.replaceCurrentItem(with: playerItem) } else { // Initialize player with the new item player = AVPlayer(playerItem: playerItem) } // Start playback if needed player?.play()
4. Implement the Observer Callback Correctly
You might be missing the observeValue(forKeyPath:...) method, or not handling the metadata properly. Here's a robust implementation:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { // Only handle timedMetadata changes guard keyPath == "timedMetadata", let playerItem = object as? AVPlayerItem, let metadataItems = playerItem.timedMetadata, !metadataItems.isEmpty else { // Pass unhandled observations to super super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) return } // Process ID3 metadata items for item in metadataItems { if let commonKey = item.commonKey?.rawValue, let value = item.value as? String { print("ID3 Metadata: \(commonKey) = \(value)") // Update your UI or handle the metadata here } } }
5. Clean Up Observers on Deinit
Don't forget to remove the observer when your view controller is deallocated to avoid crashes:
deinit { player?.currentItem?.removeObserver(self, forKeyPath: "timedMetadata") }
Additional Checks
- Verify the HLS Stream: Use a tool like
ffprobeto confirm your HLS stream actually includes ID3 metadata. Runffprobe -show_format -show_streams your-hls-url.m3u8and check for metadata-related fields. - iOS Version Support: Ensure your deployment target is at least iOS 10.0—older versions have limited HLS metadata support.
内容的提问来源于stack exchange,提问作者Lawrence Gimenez

