在AVPlayer的请求中添加自定义标头字段

时间:2013-03-16 23:56:32

标签: ios avfoundation avplayer

使用AVPlayer时,是否可以将带有http请求的标头发送到音频文件?我需要能够在服务器收到时检查标头的内容,以限制对所请求文件的访问。

6 个答案:

答案 0 :(得分:50)

您可以使用AVURLAssetHTTPHeaderFieldsKey的{​​{1}}初始化选项来修改请求标头。

例如:

AVURLAsset

注意:我在WebKit的源代码中找到了此密钥,但这是一个私有选项密钥,因此如果您使用此应用程序,您的应用可能会被AppStore拒绝。

答案 1 :(得分:9)

您需要通过NSURLConnection等通用HTTP连接机制自行请求数据。如果NSHTTPURLResponse的标题通过了您的测试,那么您应将其保存到NSCachesDirectory并将此资源的网址传递给AVPlayer,如下所示:

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

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

答案 2 :(得分:2)

考虑使用AVURLAsset。对于AVURLAsset,您可以设置resourceLoader委托。在委托方法中,您可以手动发出请求,指定必要的标题。

此方法的好处是您可以完全控制数据加载。

您必须使用自定义网址方案才能使此解决方案正常工作(http和https不会触发委托方法!):

-(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;
}

完整代码示例位于https://developer.apple.com/library/content/samplecode/sc1791/Introduction/Intro.html

答案 3 :(得分:2)

我花了几周的时间为HLS视频流正式寻找方法。对于任何寻找适用于播放列表和块请求的请求和响应的方法的人来说,我能够找到的唯一方法是通过反向代理传递回放请求,使用它可以拦截请求,添加标头,将其发送到真实服务器,然后从响应中提取标头,然后将其返回到AVPlayer。

我在这里制作了一个简单的示例项目(包含大量注释和文档): https://github.com/kevinjameshunt/AVPlayer-HTTP-Headers-Example

答案 4 :(得分:1)

在Swift中,AVURLAssetHTTPHeaderFieldsKey选项将像超级按钮一样工作。

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

答案 5 :(得分:-3)

完整代码可能看起来像这样

  #pragma Mark Sound Stuff

- (void)playSound:(NSString *)filePath
{
    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:[NSURL fileURLWithPath:filePath]];
    [playerItem addObserver:self forKeyPath:@"status" options:0 context:0];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemDidFinishPlaying) name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];
    self.audioPlayer = [[AVPlayer alloc] initWithPlayerItem:playerItem];
    [self.audioPlayer play];
}

- (void)initSoundPrelisten
{
    //NSLog(@"begin: %s", __FUNCTION__);
    self.activityIndicator.hidden = NO;
    [self.activityIndicator startAnimating];

    // verification delegate : register
    dataProtocol = [[StoreConnection alloc] init];
    [dataProtocol setDelegate:self];
    [dataProtocol requestDataFromServer:[NSString stringWithFormat:@"sound/%@/audio/sample", [self.sound objectForKey:@"globalId"]]];
}

- (void)dataSuccessful:(BOOL)success successData:(NSMutableData *)data;
{
    NSLog(@"%s", __FUNCTION__);
    if (success) {
        //NSLog(@"sound data: %@", data);
        NSString *cacheDirectory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        NSString *filePath = [cacheDirectory stringByAppendingPathComponent:@"sample.mp3"];
        //NSLog(@"filePath: %@", filePath);
        [data writeToFile:filePath atomically:YES];
        [self playSound:filePath];

    } else
    {
        UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"Store Error" message:[NSString stringWithFormat:@"An Error occured while trying to download sound. Please try again"] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        alertView.tag = 1;
        [alertView show];
    }
}