使用 AVPlayer 时是否可以将带有 http 请求的标头发送到音频文件?我需要能够在服务器接收到标头时检查标头的内容,以限制对所请求文件的访问。
6 回答
您可以使用AVURLAssetHTTPHeaderFieldsKey
' AVURLAsset
s init 选项来修改请求标头。
例如:
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];
注意:我在 WebKit 的源代码中找到了这个密钥,但这是一个私有选项密钥,所以如果你使用它,你的应用程序可能会被 AppStore 拒绝。
在 Swift 中回答,AVURLAssetHTTPHeaderFieldsKey
选项将像一个魅力。
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)
您需要通过通用 HTTP 连接机制自己请求数据,例如NSURLConnection
. 如果NSHTTPURLResponse
的标头通过了您的测试,那么您应该将其保存到NSCachesDirectory
并将该资源的 URL 传递给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]];
//...
我花了数周时间为 HLS 视频流寻找正式的方法。对于正在寻找一种适用于播放列表和块请求的请求和响应的方法的任何人,我能够找到有效的唯一方法是通过反向代理传递播放请求,使用它可以拦截请求,添加headers,将其发送到真实服务器,然后从响应中提取headers,然后将其返回给AVPlayer。
我在这里做了一个简单的示例项目(有很多评论和文档): https ://github.com/kevinjameshunt/AVPlayer-HTTP-Headers-Example
考虑使用AVURLAsset
. 因为AVURLAsset
您可以设置一个 resourceLoader 委托。在委托方法中,您可以手动发出请求并指定必要的标头。
这种方法的好处是您可以完全控制数据加载。
您必须使用自定义 url 方案才能使此解决方案正常工作(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获得
完整的代码看起来像这样
#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];
}
}