Reputation: 865
I play an audio online with AVPlayer,and want to save the data/stream of audio to local when avplayer finish loading stream.
I implementt it as the following:
let fileUrl = NSURL(string: strUrl)!
let asset = AVURLAsset(URL: fileUrl)
asset.resourceLoader.setDelegate(self, queue:dispatch_queue_create("AVARLDelegateDemo loader", nil))
self.pendingRequests = [AVAssetResourceLoadingRequest]()
asset.loadValuesAsynchronouslyForKeys(["playable"]){
dispatch_async( dispatch_get_main_queue()){
self.prepareToPlayAsset(asset, requestedKeys: ["playable"])
}
}
func resourceLoader(resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
.......
return false
}
When url is http/https, it does not call resourceLoader(resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource.... -, when url is customize (eg.:'test'), it call resourceLoader(resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource...
Who know the reason, Does resourceLoader not support http/https?
Upvotes: 5
Views: 5374
Reputation: 31
When player doesn't know how to load a file, it calls resourceLoader(resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource...
method. So since it knows how to load URL, it wont call this method, so you have to pass custom URL.
Upvotes: 3
Reputation: 27
Here you can find full Swift solution based on native AVPlayerItem with custom loader.
Upvotes: 0
Reputation: 246
This sample project and tutorial seems to detail what you're looking for.
the link above details setting a custom URL scheme and setting an AVAssetResourceLoaderDelegate to handle the resource as it loads. This is initialised as:
NSURL *url = [NSURL URLWithString:@"customscheme://host/audio.mp3"];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];
[asset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()];
AVPlayerItem *item = [AVPlayerItem playerItemWithAsset:asset];
[self addObserversForPlayerItem:item];
self.player = [AVPlayer playerWithPlayerItem:playerItem];
[self addObserversForPlayer];
The implementation of the delegate methods would then look similar to the following:
- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest*)loadingRequest{
NSURL *resourceURL = [loadingRequest.request URL];
if([resourceURL.scheme isEqualToString:@"customscheme"]){
LSFilePlayerResourceLoader *loader = [self resourceLoaderForRequest:loadingRequest];
if(loader==nil){
loader = [[LSFilePlayerResourceLoader alloc] initWithResourceURL:resourceURL session:self.session];
loader.delegate = self;
[self.resourceLoaders setObject:loader forKey:[self keyForResourceLoaderWithURL:resourceURL]];
}
[loader addRequest:loadingRequest];
return YES;
}
return NO;
}
- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest{
LSFilePlayerResourceLoader *loader = [self resourceLoaderForRequest:loadingRequest];
[loader removeRequest:loadingRequest];
}
Where LSFilePlayerResourceLoader and LSFilePlayerResourceLoader are custom objects for handling the data being received (detailed in the link).
Upvotes: 2