I am trying to gather some knowledge about how to read metadata from an HLS stream inside an iOS app. The following HLS stream has some ID3 tags which I want to read: HLS test stream
In the web inspector in Safari, I am able to see lots of data objects in the console, each one has metadata:

In the network tab of the web inspector, I can read the playlist file:
#EXTM3U
#EXT-X-VERSION:5
#EXT-X-MEDIA-SEQUENCE:89147
#EXT-X-TARGETDURATION:20
#EXT-X-PROGRAM-DATE-TIME:2019-09-25T11:35:23.401Z
#EXTINF:19.970,
05-20190925T113523Z.aac
#EXTINF:19.970,
05-20190925T113543Z.aac
#EXTINF:19.970,
05-20190925T113603Z.aac
#EXTINF:19.970,
05-20190925T113623Z.aac
#EXTINF:19.970,
05-20190925T113643Z.aac
#EXTINF:19.970,
05-20190925T113703Z.aac
So far I've implemented a class which uses an AVPlayer instance to play this stream. It is working properly. 
I printed all sorts of properties from the AVPlayer and AVPlayerItem to the Xcode console. 
However, the only property I can interpret is AVPlayerItem.currentTime which gives me the value of EXT-X-PROGRAM-DATE-TIME from the playlist file.
All other properties don't seem to have something to do with the information I see in the playlist and the id3 tags.
Is there any way I can read the metadata contained in each id3 tag? 
How can I read EXT-X-TARGETDURATION from the playlist? 
I read about AVPlayerItemMetadataCollector, but I don't understand what it is supposed to do and if this would help me reading metadata in the HLS stream. 
This is how I achieved it:
import UIKit
import AVKit
import AVFoundation
import MediaPlayer
class ViewController: UIViewController{
    let player = AVPlayer()
    var playerItem: AVPlayerItem!
    let asset = AVAsset(url: URL(string: "https://db2.indexcom.com/bucket/ram/00/05/05.m3u8")!)
    override func viewDidLoad() {
        prepareToPlay()
        player.play()
    }
    func prepareToPlay() {
        playerItem = AVPlayerItem(asset: asset)
        playerItem.addObserver(self, forKeyPath: "timedMetadata", options: [], context: nil)
        player.replaceCurrentItem(with: playerItem)
        printTimeStamp()
    }
    func printTimeStamp() {
        print("▼⎺▼⎺▼⎺▼⎺▼⎺▼⎺▼⎺▼")
        print("PROGRAM-DATE-TIME: ")
        print(playerItem.currentDate() ?? "No timeStamp")
        print("▲_▲_▲_▲_▲_▲_▲_▲\n\n")
    }
    override func observeValue(forKeyPath: String?, of: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if forKeyPath != "timedMetadata" { return }
        printTimeStamp()
        let data: AVPlayerItem = of as! AVPlayerItem
        guard let timedMetadata = data.timedMetadata else { return }
        for item in timedMetadata {
            switch item.commonKey {
            case .commonKeyAlbumName?:
                print("AlbumName: \(item.value!)")
            case .commonKeyArtist?:
                print("Artist: \(item.value!)")
            case .commonKeyArtwork?:
                print("Artwork: \(item.value!)")
            case .commonKeyAuthor?:
                print("Author: \(item.value!)")
            case .commonKeyContributor?:
                print("Contributor: \(item.value!)")
            case .commonKeyCopyrights?:
                print("Copyrights: \(item.value!)")
            case .commonKeyCreationDate?:
                print("CreationDate: \(item.value!)")
            case .commonKeyCreator?:
                print("creator: \(item.value!)")
            case .commonKeyDescription?:
                print("Description: \(item.value!)")
            case .commonKeyFormat?:
                print("Format: \(item.value!)")
            case .commonKeyIdentifier?:
                print("Identifier: \(item.value!)")
            case .commonKeyLanguage?:
                print("Language: \(item.value!)")
            case .commonKeyMake?:
                print("Make: \(item.value!)")
            case .commonKeyModel?:
                print("Model: \(item.value!)")
            case .commonKeyPublisher?:
                print("Publisher: \(item.value!)")
            case .commonKeyRelation?:
                print("Relation: \(item.value!)")
            case .commonKeySoftware?:
                print("Software: \(item.value!)")
            case .commonKeySubject?:
                print("Subject: \(item.value!)")
            case .commonKeyTitle?:
                print("Title: \(item.value!)")
            case .commonKeyType?:
                print("Type: \(item.value!)")
            case .id3MetadataKeyAlbumTitle?:
                print("id3MetadataKeyAlbumTitle: \(item.value!)")
            default:
                print("other data: \(item.value!)")
            }
        }
    }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With