Ist es möglich, Header mit einer HTTP-Anfrage an eine Audiodatei senden, wenn Sie AVPlayer verwenden? Ich muss in der Lage sein, den Inhalt des Headers zu überprüfen, wenn er vom Server empfangen wird, um den Zugriff auf die angeforderte Datei zu beschränken.Senden Header mit AVPlayer Anfrage in iOS
Antwort
Sie müssen die Daten über einen generischen HTTP-Verbindungsmechanismus wie z. B. NSURLConnection
anfordern. Wenn die NSHTTPURLResponse
‚s Header Ihr Test zu bestehen, dann sollten Sie es in die NSCachesDirectory
speichern und die URL zu dieser Ressource an den AVPlayer
wie so abgehen:
NSData *data = //your downloaded data.
NSString *filePath = //generate random path under NSCachesDirectory
[data writeToFile:filePath atomically:YES];
AVPlayer *player = [AVPlayer playerWithURL:[NSURL fileURLWithPath:filePath]];
//...
den vollständigen Code könnte wie folgt aussehen
#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];
}
}
Sie können die Init-Option AVURLAssetHTTPHeaderFieldsKey
von AVURLAsset
verwenden, um Anforderungsheader zu ändern.
Zum Beispiel:
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];
Hinweis: Ich habe diesen Schlüssel in Quellen von WebKit gefunden, aber das ist eine Privat Optionstaste, so dass Ihre App von App Store ablehnen können, wenn Sie diese verwenden.
Verwenden Sie AVURLAsset
. Für AVURLAsset
können Sie einen ResourceLoader-Delegaten einrichten. Innerhalb der Delegate-Methode können Sie eine Anfrage manuell eingeben und notwendige Header angeben.
Der Vorteil dieses Ansatzes besteht darin, dass Sie die Daten vollständig laden können.
Sie haben eine eigene URL-Schema verwenden, um diese Lösung arbeiten zu lassen (http und https nicht die delegierte Methode auslösen!):
-(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;
}
Vollcodebeispiel bei https://developer.apple.com/library/content/samplecode/sc1791/Introduction/Intro.html verfügbar ist
Dieser Ansatz funktioniert, aber Sie müssen die Verantwortung dafür übernehmen, dem AVPlayer nach meiner Erfahrung Stücke usw. zur Verfügung zu stellen. Die einzige Möglichkeit, dies für Wiedergabelisten UND Chunk-Anfragen und -Antworten zu tun, war die Ausführung eines Reverse-Proxy auf dem Gerät. –
Ich habe Wochen damit verbracht, nach einer Möglichkeit zu suchen, dies offiziell für HLS-Video-Streaming zu tun. Für alle, die nach einem Ansatz suchten, der sowohl für Anfragen als auch für Antworten auf die Playlist- und Chunk-Anfragen funktionierte, konnte ich die Abspielanforderung nur über einen Reverse Proxy abfragen, mit dem Sie die Anfrage abfangen können Fügen Sie Header hinzu, senden Sie sie an den echten Server und extrahieren Sie dann die Header aus der Antwort, bevor Sie sie an den AVPlayer zurücksenden.
Ich habe ein einfaches Beispiel-Projekt (mit vielen Kommentaren und Dokumentation) hier: https://github.com/kevinjameshunt/AVPlayer-HTTP-Headers-Example
+1 für völlig richtige Antwort. Um es von einer anderen Seite anzugehen; Sie haben keine direkte Möglichkeit, die HTTP-Kommunikation von 'AVPlayer' zu stören. – Till
Eine andere Option, aber WIRKLICH kompliziert, wäre ein On-Device-Proxy - Grobentwurf: Erstellen Sie einen Client, der Daten über HTTP (auf Ihrem Gerät) anfordert, erstellen Sie einen Server, der diese Daten über HTTP (auf Ihrem Gerät) anbietet, Lassen Sie den AVPlayer über HTTP mit Ihrem lokalen Server verbinden. Wie gesagt, wirklich kompliziert, aber manchmal die einzige Option - z. wenn du YouTube-Inhalte nativ in deiner App wiedergeben möchtest. – Till
danke dafür! funktioniert perfekt! aufgewertet! – rockstarberlin