Add custom header field in request of AVPlayer

21,016

Solution 1

You'll need to request the data yourself via a generic HTTP connection mechanism such as NSURLConnection. If the NSHTTPURLResponse's headers pass your test, then you should save it into the NSCachesDirectory and pass off the URL to this resource to the AVPlayer like so:

NSData *data = //your downloaded data.
NSString *filePath = //generate random path under NSCachesDirectory
[data writeToFile:filePath atomically:YES];

AVPlayer *player = [AVPlayer playerWithURL:[NSURL fileURLWithPath:filePath]];
//...

Solution 2

You can use AVURLAssetHTTPHeaderFieldsKey of AVURLAsset's init option to modify request headers.

For example:

NSMutableDictionary * headers = [NSMutableDictionary dictionary];
[headers setObject:@"Your UA" forKey:@"User-Agent"];
AVURLAsset * asset = [AVURLAsset URLAssetWithURL:URL options:@{@"AVURLAssetHTTPHeaderFieldsKey" : headers}];
AVPlayerItem * item = [AVPlayerItem playerItemWithAsset:asset];
self.player = [[AVPlayer alloc] initWithPlayerItem:item];

Note: I found this key in sources of WebKit, but this is a Private option key, So your app may reject by AppStore if you use this.

Solution 3

Answer in Swift, AVURLAssetHTTPHeaderFieldsKey option will work like a charm.

 let headers: [String: String] = [
    "custome_header": "custome value"
 ]
 let asset = AVURLAsset(url: URL, options: ["AVURLAssetHTTPHeaderFieldsKey": headers])
 let playerItem = AVPlayerItem(asset: asset)
 player = AVPlayer(playerItem: item)

Solution 4

I spent weeks looking for a way to do this officially for HLS video streaming. For anyone looking for an approach that would work for both requests and responses for the playlist and chunk requests, the only way I was able to find that worked was by passing the playback request through a reverse proxy, with which allows you to intercept the request, add headers, send it to the real server, and then extract the headers from the response before returning it to the AVPlayer.

I made a simple example project (with lots of comments and documentation) here: https://github.com/kevinjameshunt/AVPlayer-HTTP-Headers-Example

Solution 5

Consider using AVURLAsset. For AVURLAsset you can set up a resourceLoader delegate. Inside the delegate method you can issue a request manually a specify necessary headers.

The benefit of this approach is that you have a full control on data loading.

You have to use a custom url scheme in order to make this solution work (http and https will not trigger the delegate method!):

-(void) play {
  NSURL * url = [URL URLWithString:@"mycustomscheme://tungsten.aaplimg.com/VOD/bipbop_adv_fmp4_example/master.m3u8"];
  AVURLAsset * asset = [AVURLAsset URLAssetWithURL: options:nil];
  [asset.resourceLoader setDelegate:self queue:dispatch_queue_create("TGLiveStreamController loader", nil)];
  AVPlayerItem * playerItem = [AVPlayerItem playerItemWithAsset:asset];
  // Use player item ...
  ...
}

#pragma mark - AVAssetResourceLoaderDelegate

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest {
  dispatch_async(resourceLoader.delegateQueue, ^{
    NSURL * url = [URL URLWithString:@"https://tungsten.aaplimg.com/VOD/bipbop_adv_fmp4_example/master.m3u8"];
    NSMutableURLRequest *request = [loadingRequest.request mutableCopy];
    request.URL = url;

    // Add header
    [request setValue:@"Foo" forHTTPHeaderField:@"Bar"];

    NSURLResponse *response = nil;
    NSError *firstError = nil;

    // Issue request
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&firstError];

    [loadingRequest.dataRequest respondWithData:data];
    if (firstError) {
      [loadingRequest finishLoadingWithError:firstError];
    } else {
      [loadingRequest finishLoading];
    }
  });
  return YES;
}

Full code example is available at https://developer.apple.com/library/content/samplecode/sc1791/Introduction/Intro.html

Share:
21,016

Related videos on Youtube

user732538
Author by

user732538

Updated on May 28, 2020

Comments

  • user732538
    user732538 almost 4 years

    Is it possible to send headers with an http request to an audio file when using AVPlayer? I need to be able to inspect the content of the header when received by the server in order to restrict access to the file being requested.

  • mostafa tourad
    mostafa tourad about 11 years
    +1 for entirely correct answer. To tackle it from a different side; you have no direct way of interfering with the HTTP-communication of AVPlayer.
  • mostafa tourad
    mostafa tourad about 11 years
    Another option, but REALLY complicated, would be using an on-device-proxy - rough draft: build a client that requests data via HTTP (on your device), build a server that offers that data via HTTP (on your device), let AVPlayer connect with your local server via HTTP. As said, really complicated but sometimes the only option - e.g. if you are trying to play YouTube content natively in your app.
  • Chance
    Chance almost 10 years
    It's not possible to interfere with the http communication that AVPlayer does but it is possible to take over control of the HTTP communication completely and supply data to AVPlayer on demand without setting up an HTTP proxy - vombat.tumblr.com/post/86294492874/…
  • Micky
    Micky over 9 years
    @Anurag good solution. unfortunately this does not work if you stream via http live streaming, as you can't create the AVAssets yourself and the HLS stream has to be provided via http. We are using a local http server for that. Or do you know of a solution without a local server that works with HLS?
  • Chance
    Chance over 9 years
    Actually I don't think there is a solution for HLS currently. I had the same problem but Apple's docs on HLS prohibit proxying requests via a local HTTP server so that wasn't an option for me.
  • mixtly87
    mixtly87 almost 9 years
    This is exactly what I'm doing. Can someone verify whether the app is going to be rejected by Apple for using this key?
  • Javier Gonzalez
    Javier Gonzalez over 8 years
    @mixtly87 did you have any problem uploading your app to the AppStore using that key?
  • mixtly87
    mixtly87 over 8 years
    @JavierGonzalez No problems at all.
  • Kevin James Hunt
    Kevin James Hunt over 7 years
    This approach will work, but you have to take ownership of providing chunks, etc to the AVPlayer, in my experience. The only way I was able to do this for playlists AND chunk requests and responses was by running a reverse proxy on the device.
  • azizj
    azizj about 7 years
    How would you send multiple Set-Cookies through this? I get an error saying duplicates not allowed :\
  • naituw
    naituw over 6 years
    @AzizJaved There is another public option AVURLAssetHTTPCookiesKey, which seems match your needs.
  • Brian Sachetta
    Brian Sachetta almost 6 years
    Thanks for this answer. It's working for me. I found this answer helpful as well (for generating a path within the Caches Directory): stackoverflow.com/questions/1567134/…
  • Pavan
    Pavan over 5 years
    Hey Kevin, I have two category of headers to send. One will be sent with the manifest request, the other set of headers will go with the chunk requests. How would that be possible with your example?
  • umakanta
    umakanta over 4 years
    AVURLAssetHTTPCookiesKey crashing for me.
  • umakanta
    umakanta over 4 years
    And the above solution also not working for me. My url is encrypted format. iOS13
  • SamB
    SamB over 3 years
    AVURLAssetHTTPCookiesKey solution developer.apple.com/forums/thread/126011