3

I'm using AVFoundation framework for live streaming playback. Now I have a playlist like below

#EXT-X-VERSION:4
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:8148007
#EXT-X-TARGETDURATION:6
#EXT-X-PROGRAM-DATE-TIME:1972-04-14T08:51:01.497Z

I think AVPlayer make a request to get this playlist. Can I use classes in AVFoundation to extract EXT-X-TARGETDURATION and EXT-X-PROGRAM-DATE-TIME. If not, any other ways? Thanks

RayChen
  • 1,417
  • 2
  • 17
  • 36

2 Answers2

7

#EXT-X-PROGRAM-DATE-TIME is available via AVPlayerItem's currentDate property. It doesn't report the date of the tag directly, but rather the date of the last tag before the current playback position, plus any played interval since then.

#EXT-X-TARGETDURATION is not available directly. You will have to either load the playlist yourself, or insert yourself in the loading process. I've had success with AVAssetResourceLoader and AVAssetResourceLoaderDelegate. You can rewrite URL schemes to something the loader doesn't recognize (anything other than http or https), and performing the loading on the player's behalf.

Fabian
  • 6,973
  • 2
  • 26
  • 27
1

I don't think AVFoundation provides access to all of those tags. However when I need to debug the streams, I use a custom NSURLProtocol to intercept all traffic. I think sometimes it's better to see the raw playlist and the HTTP response because AVPlayer does not give good error message(e.g. "The operation cannot be completed")

A good tutorial on NSURLProtocol can be found here: https://www.raywenderlich.com/59982/nsurlprotocol-tutorial

First let the url loading system know you can handle HLS request by calling [NSURLProtocol registerClass:/* your class */] and override +(BOOL)canInitWithRequest:

+(BOOL)canInitWithRequest:(NSURLRequest *)request {
    BOOL handled = [[NSURLProtocol propertyForKey:@"handled" inRequest:request] boolValue];
    return [request.URL.pathExtension isEqualToString:@"m3u8"] && !handled;
}

Then override -(void)startLoading in your custom URLProtocol

-(void)startLoading {
    newRequest = [self.request mutableCopy];
    [NSURLProtocol setProperty:@YES forKey:@"handled" inRequest:newRequest];
    NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:newRequest
        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

            /* Inspect response body(playlist) and error */
            NSString *responseBody = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

            /* Return data and control to AVPlayer*/
            [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
            [self.client URLProtocol:self didLoadData:data];
            [self.client URLProtocolDidFinishLoading:self];
    }];

    [task resume];
}
  • According to https://forums.developer.apple.com/thread/75328 AVPlayer does go through the URL loading system, but those requests are made in a helper process (mediaserverd) and thus don’t ‘see’ custom NSURLProtocol subclass. – Alexander Algashev Jan 20 '22 at 07:22