AVQueuePlayer gapless playback - ios

I am trying to dynamically add .aac chunks (usually 10 seconds) during the playback to AVQueuePlayer to mimic the AVPlayer hls playback.
However it plays songs one after another as I wished, there is about 200ms to 400 ms gap between songs.
following question seems to have the answer it to this question but it doesn't work for me.
AVQueuePlayer playback without gap and freeze
I have a singleton player and a singleton avplayeritem to keep track of the last item.
then with following code I can successfully play the songs with gap.
NSURL *url = [NSURL URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
//NSData *urlData = [NSData dataWithContentsOfURL:url];
GlobalPlayer *singleton=[GlobalPlayer sharedManager];
//AVPlayerItem *item=[AVPlayerItem playerItemWithURL:url];
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:url options:nil];
NSArray *keys = [NSArray arrayWithObject:#"playable"];
if (singleton.lastItem==nil) {
//initilize player
//NSArray *playerArray=[[NSArray alloc] initWithObjects:item, nil];
//singleton.globPlayer=[[AVQueuePlayer alloc] initWithItems:playerArray];
//[singleton.globPlayer play];
singleton.globPlayer=[[AVQueuePlayer alloc] init];
singleton.lastItem=[AVPlayerItem alloc];
__block AVPlayerItem *playerItem;
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^()
{
dispatch_async(dispatch_get_main_queue(), ^
{
playerItem = [[AVPlayerItem alloc] initWithAsset:asset];
[singleton.globPlayer insertItem:playerItem afterItem:nil];
singleton.lastItem=playerItem;
[singleton.globPlayer play];
});
}];
}
else
{
//[singleton.globPlayer insertItem:item afterItem:singleton.lastItem];
__block AVPlayerItem *playerItem;
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^()
{
dispatch_async(dispatch_get_main_queue(), ^
{
playerItem = [[AVPlayerItem alloc] initWithAsset:asset];
[singleton.globPlayer insertItem:playerItem afterItem:singleton.lastItem];
singleton.lastItem=playerItem;
});
}];
}
Do I have to decode the chunks then feed the PCM to AVQueuePlayer? If that is the only solution how do I feed NSData that holds pcm to the AVPlayerItem ?

Related

Playing itunes song previews from cocos2d app

I am trying to get itunes song previews to play in my app. I have found some other questions like this but none of the solutions have worked for me. I am already signed up with the Affiliate program that apple has. Here are some of the things I have tried:
This got me the itunes preview URL that I am trying
NSUInteger numberOfResults = 200;
NSString *searchString = #"AC/DC";
NSString *encodedSearchString = [searchString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *finalSearchString = [NSString stringWithFormat:#"https://itunes.apple.com/search?term=%#&entity=song&limit=%u",encodedSearchString,numberOfResults];
NSURL *searchURL = [NSURL URLWithString:finalSearchString];
dispatch_queue_t iTunesQueryQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, kNilOptions);
dispatch_async(iTunesQueryQueue, ^{
NSError *error = nil;
NSData *data = [[NSData alloc] initWithContentsOfURL:searchURL options:NSDataReadingUncached error:&error];
if (data && !error) {
NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
NSArray *array = [JSON objectForKey:#"results"];
NSLog(#"Array is:%#",array);
}
});
This plays nothing
NSURL *url = [NSURL URLWithString:[_backgroundPreviewList objectAtIndex:randomPreview]];
NSData *_objectData = [NSData dataWithContentsOfURL:url];
NSError *error;
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithData:_objectData error:&error];
audioPlayer.numberOfLoops = 0;
audioPlayer.volume = 1.0f;
[audioPlayer prepareToPlay];
if (audioPlayer == nil)
{
NSLog(#"%#", [error description]);
}
else
{
[audioPlayer play];
}
This also played nothing
AVPlayer* aPlayer = [AVPlayer playerWithURL:url];
[aPlayer play];
I even tried this that didn't work
MPMoviePlayerController* player = [[MPMoviePlayerController alloc] initWithContentURL:url];
[player play];
If anyone has done this can they let me know how to play the songs.
This is released and working using MPMoviePlayerController, which I believe is the recommended approach for the streaming previews. Depending on what you are trying to do, you might have to work through some steps to enable play in the background. Good luck. p.s. if you get the AVPlayer working there are more docs available with solutions for background play see Technical QA doc 1668 from Apple
{
self.songPreview = [[MPMoviePlayerController alloc] init];
self.songPreview.movieSourceType = MPMovieSourceTypeStreaming;
/// set your URL from wherever you are getting it
[self.songPreview setContentURL:self.previewArtWorkButton.currentPreviewURL];
[self.view addSubview:self.songPreview.view];
/// i have set this next property to hidden because i am controlling volume and play programmatically
[self.songPreview.view setHidden:YES];
/// i have this next property set to No because I am using another trigger to play the /// song and not auto play after the buffering has completed
[self.songPreview setShouldAutoplay:NO];
[self.songPreview prepareToPlay];
}
/// later i call the play method
[self.songPreview play];
I have got it working. One of the things I changed is I took that specific class out of ARC to make sure things were staying around. Here is the code I am using now
NSURL *url = [NSURL URLWithString:#"URL"];
AVPlayerItem* playerItem = [AVPlayerItem playerItemWithURL:url];
NSLog(#"The url is: %#", url);
if(_player)
{
[_player release];
}
_player = [[AVPlayer playerWithPlayerItem:playerItem] retain];
[_player play];
_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
Where _player is an AVPlayer object

Playing video from within app?

I am trying to play a local video from my app using AVPlayer. I have looked everywhere but can't find any useful tutorials/demos/documentation. Here is what I am trying, but it is not playing. Any idea why? The URL is valid because I was using the same one to play a video using MPMoviePlayer successfully.
Video *currentVideo = [videoArray objectAtIndex:0];
NSString *filepath = currentVideo.videoURL;
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
AVURLAsset *asset = [AVURLAsset assetWithURL: fileURL];
AVPlayerItem *item = [AVPlayerItem playerItemWithAsset: asset];
self.player = [[AVPlayer alloc] initWithPlayerItem: item];
AVPlayerLayer *layer = [AVPlayerLayer playerLayerWithPlayer:self.player];
self.player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
layer.frame = CGRectMake(0, 0, 1024, 768);
[self.view.layer addSublayer: layer];
[self.player play];
I believe the problem is that you're assuming that after executing this line AVURLAsset *asset = [AVURLAsset assetWithURL: fileURL]; the asset is ready to use. This is not the case as noted in the AV Foundation Programming Guide:
You create an asset from a URL using AVURLAsset. Creating the asset, however,
does not necessarily mean that it’s ready for use. To be used, an asset must
have loaded its tracks.
After creating the asset try loading it's tracks:
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
NSString *tracksKey = #"tracks";
[asset loadValuesAsynchronouslyForKeys:#[tracksKey] completionHandler:
^{
NSError *error;
AVKeyValueStatus status = [asset statusOfValueForKey:tracksKey error:&error];
if (status == AVKeyValueStatusLoaded) {
// At this point you know the asset is ready
self.playerItem = [AVPlayerItem playerItemWithAsset:asset];
...
}
}];
Please refer to this link to see the complete example.
Hope this helps!

how can i play remote .mp3 file in my ios application?

I'm trying to play remote .mp3 file
but its giving the following error.
The operation couldn’t be completed. (OSStatus error -43.)
here is my code :
- (void)viewDidLoad
{
[super viewDidLoad];
isPlaying = NO;
/*
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"Dar-e-Nabi-Per" ofType:#"mp3"]];
*/
NSURL *url = [NSURL
URLWithString:#"http://megdadhashem.wapego.ru/files/56727/tubidy_mp3_e2afc5.mp3"];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:url
error:&error];
if (error)
{
NSLog(#"Error in audioPlayer: %#",
[error localizedDescription]);
}
else
{
audioPlayer.delegate = self;
[audioPlayer prepareToPlay];
}
}
Can anyone please guide me where i'm doing mistake
For steaming audio from a remote server, use AVPlayer instead of AVAudioPLayer.
AVPlayer Documentation
Sample Code:
- (void)playSampleSong:(NSString *)iSongName {
NSString *aSongURL = [NSString stringWithFormat:#"http://megdadhashem.wapego.ru/files/56727/tubidy_mp3_e2afc5.mp3"];
// NSLog(#"Song URL : %#", aSongURL);
AVPlayerItem *aPlayerItem = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:aSongURL]];
AVPlayer *anAudioStreamer = [[AVPlayer alloc] initWithPlayerItem:aPlayerItem];
[anAudioStreamer play];
// Access Current Time
NSTimeInterval aCurrentTime = CMTimeGetSeconds(anAudioStreamer.currentTime);
// Access Duration
NSTimeInterval aDuration = CMTimeGetSeconds(anAudioStreamer.currentItem.asset.duration);
}
Use this to play song from URL
NSData *songData=[NSData dataWithContentsOfURL:url];
self.player = [[AVAudioPlayer alloc] initWithData:songData error:nil];
self.player.numberOfLoops=0;
_player.delegate=self;
[_player prepareToPlay];
[_player play]

iOS stream audio with no extension

I am looking to play a live audio stream within my app using AVAudioPlayer or AVPlayer, however the link has no extension and so whenever I try to set it up, it fails. Does anyone have any suggestions?
Code:
NSString *path = #"http://audio7.radioreference.com/24705802";
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:path]];
NSError *error;
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithData:data error:&error];
player.volume = 1.0f;
player.numberOfLoops = -1.0f;
[player prepareToPlay];
if (player == nil) {
NSLog(#"Error: %# Description: %#", error.localizedDescription, error.description);
}
else {
[player play];
}
NSData does not constitute a stream, but static data (eg sound data that you created or data loaded from a file). You want to create an AVPlayer object with an NSURL pointing to the stream. For example:
AVPlayer *player = [[AVPlayer alloc] initWithURL:[NSURL URLWithString:path]];
[player play];

AVPlayer error during mp3 playback

I would like to know why my AVPlayer crashes when I want it to play "some" songs.
Song #1
Song #2
That is the way I play these songs:
AVPlayerItem *item = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:#"http://www.iwheelbuy.com/Player/Test/1.mp3"]];
AVPlayer *player = [[AVPlayer alloc] init];
[player replaceCurrentItemWithPlayerItem:item];
[player setRate:1.0f];
I have some KVO observers, one of them observes AVPlayer status and when I try to play one of these songs it gives me an error:
Domain=AVFoundationErrorDomain Code=-11800
UserInfo=0x1cdc3be0 {NSLocalizedDescription=..., NSUnderlyingError=0x1cdc14c0
"The operation couldn’t be completed. (OSStatus error -303.)"
Is there a way to play these songs? Any help is appreciated.
EDIT:
I have succeeded to make these songs play well
__block AVPlayer *currentPlayerBlock = _currentPlayer;
__block NSURL *urlBlock = url;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:urlBlock options:nil];
AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:asset];
dispatch_sync(dispatch_get_main_queue(), ^{
[currentPlayerBlock replaceCurrentItemWithPlayerItem:item];
[currentPlayerBlock setRate:1.0f];
});
});
__block AVPlayer *currentPlayerBlock = _currentPlayer;
__block NSURL *urlBlock = url;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:urlBlock options:nil];
AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:asset];
dispatch_sync(dispatch_get_main_queue(), ^{
[currentPlayerBlock replaceCurrentItemWithPlayerItem:item];
[currentPlayerBlock setRate:1.0f];
});
});
This way it works

Resources