AVAudioPlayer initializes fine, but refuses to play - ios

I have a curious problem with the AVAudioPlayer class. I create a player, get a non-nil reference from the initializer, but the -play message returns NO and the player doesn’t play. I have implemented the player delegate methods and -audioPlayerDecodeErrorDidOccur:error: is not called. The error from the initializer is not set.
I have checked the usual suspects. I do set the audio session category, I also activate it. The audio file for the player is recorded by the app just before playing. When I initialize the player with a different sound (from the app bundle), it plays. When I copy the recorded file into the app bundle and then initialize the player with this copy, it plays. When I check for file existence before loading it, the file is there, is readable and has a non-zero size.
I have tried both the Simulator and the device, no difference.
What am I missing?

It helped to wait 1/10 of a second between the end of recording and playback:
dispatch_time_t moment = dispatch_time(DISPATCH_TIME_NOW, 1e8);
dispatch_after(moment, dispatch_get_main_queue(), ^{
[statusLabel setText:#"Playing"];
[self setPlayer:[[AVAudioPlayer alloc]
initWithContentsOfURL:[self recordingURL]
error:NULL]];
[player play];
});
This of course is not a proper solution, so after a bit of searching I realized I wasn’t properly finishing the recording, leaving the file buffers unflushed before creating the player. Now that I flush the buffers before calling the player everything works fine.

Related

iOS: AVQueuePlayer does not indicate that it has stopped playback

I have an AVQueuePlayer which loads URLs to play audio files and it works well for the most part. However, I have run into a problem where after the player finishes playing a file (with another file in the queue), it will simply stop playing. Normally, the app would be able to use the player's rate, status, and items. In this case, I have gone through with the debugger and everything looks normal.
Everything appears to be playing, except for the player itself. After forcing the player to play, the player will skip to the next track, indicating that the AVPlayerItem it had was not loaded (I can confirm the audio urls are valid).
Does anyone have any ideas how I catch this programatically?
You need to have the delegate method:
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;
Once this method is finished, start the new audio.

Changing the queue while MPMusicPlayerController is playing

I am using [MPMusicPlayerController iPodMusicPlayer] to handle playback. The app starts with a playlist and eventually while listening to a track, if the user takes a certain action I want to change the part of the playlist AFTER the nowPlayingItem.
Since I generate the original playlist and the new one, I am able to create a new queue that represents the previously played MPMediaItems and the new ones. Everything works fine until I try pausing, scrubbing or doing anything that affects playback. It will immediately skip to the track after the nowPlayingItem.
Example code:
- (void)exampleAction{
//Remove tracks after currentItem
[self.playbackQueue removeObjectsInRange:NSMakeRange(self.indexInQueue+1, self.playbackQueue.count-self.indexInQueue-1)];
NSMutableArray *newQueue = [NSMutableArray array];
//ADD ITEMS TO newQueue here
[self.playbackQueue addObjectsFromArray:newQueue];
MPMediaItemCollection *collection = [MPMediaItemCollection collectionWithItems:self.playbackQueue];
[self.playbackController setQueueWithItemCollection:collection];
}
Playback of the nowPlayingItem cannot be interrupted. Using this method, if I do not attempt to alter playback (play\pause\scrub) and the track finishes normally, everything works as it should and continues to work properly for the remainder of the playlist. It seems that modifying the playback queue during playback has some sort of side-effect that I don't understand. Can anyone give me some insight on how I can achieve what I am trying to do? This bug is killing me.
Have you tried calling play on your MPMusicPlayerController immediately after setting the playback queue? It should produce at most a momentary blip in playback.

MPMoviePlayerController stalling frequently

I'm using MPMoviePlayerController to play remote mp4 files which are not quite big, about 20 - 30 MB each. This is how the player is set up:
player.movieSourceType = MPMovieSourceTypeFile;
player.shouldAutoplay = YES;
The problem is that the player stops frequently with the following console output:
Took background task assertion ... for playback stall // stops
Ending background task assertion ... for playback stall // resumes
I possibly could have taken this behavior as granted, but on the other hand when I try to play the video in other streaming player (e.g. GoodPlayer) - it plays nicely and never stops. So the problem is in my approach itself, not in the Internet connection.
Are there any ways to make MPMoviePlayerController to load seamlessly, or do I have to change components used in my app? If yes, which ones would you recommend?
Try to assign (declare) MPMoviePlayerController as #property in your .h file, rather than a local variable.

iOS: play audio file at a specific time and stop after a specific duration

I have an audio file with length of 500 miniseconds for my app. I want app users to play the audio at minisecond 100 (by pressing a button) and the audio will automatically stops at minisecond 150. This is a code that I have done so far:
AVAudioPlayer *audioPlayer = [[[AVAudioPlayer alloc]
initWithContentsOfURL:[NSURL fileURLWithPath:filePath]
error:nil] autorelease];
[audioPlayer setCurrentTime:100.00f];
[audioPlayer play];
Would you please help me with the stopping part? Thank you
You could create an instance of NSTimer with the desired play interval, then when the timer fires, stop audio. Create the timer on the main thread, and in a place in your code in an applicable area where you can get a reference for the audioPlayer. Make sure you handle interruptions, IE, User pauses or stops audio somehow, or if the audioPlayer is deallocated somewhere, your app goes into the background, or whatever else you need to handle, by invalidating and disposing of the timer. See the docs for information on NSTimer. http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nstimer_Class/Reference/NSTimer.html

IOS: AVAudioPlayer

In my app I have 52 mp3 and when I load my view controller I alloc all 52 mp3 in this way:
NSString *pathFrase1 = [NSString stringWithFormat:#"%#/%#",[[NSBundle mainBundle] resourcePath],[NSString stringWithFormat:#"a%d_1a.mp3",set]];
NSURL *filePath1 = [NSURL fileURLWithPath:pathFrase1 isDirectory:NO];
f1 = [[AVAudioPlayer alloc] initWithContentsOfURL:filePath1 error:nil];
[f1 prepareToPlay];
but it's very slow when I open viewcontroller, then is there a way to alloc mp3 when I use it? and release its AVAudioPlayer??
It's a little more complicated to handle, but instead of using AVAudioPlayer, use AVPlayer. AVPlayer is designed to play AVAssets, which can be preloaded files. Specifically, you'll want to use a subclass of AVAsset called AVURLAssets, which can load up your URL: Loading AVAsset. You can then use AVAsset to create an AVPlayerItem. An AVPlayerItem is a lightweight wrapper that AVPlayer uses to keep track of play state for an AVAsset. The nice thing about using AVPlayer is that it can play an AVMutableComposition, which itself can contain multiple AVAssets. AVPlayer can also play a queue of AVAssets and provide you with information on when it is beginning to play a new AVAsset, and which one. If you load your MP3's into a bunch of AVURlAssets you can load them and keep them around, creating AVPlayerItem & AVPlayer only when you want to play one (or more) of the MP3's.
AVAudioPlayer is designed to play single files, but it uses AVAssets (and probably AVPlayer) behind the scenes. It's nice for simple situations, but anything more complex and you really want to use AVPlayer.
I should also point out that AVPlayerItem & AVPlayer are light weight objects. They don't take long at all to instantiate. It's loading the AVAsset that takes all the time. So you can feel free to create and destroy AVPlayerItem & AVPlayer objects as you need.
Finally, AVAsset and AVPlayer sometimes rely on blocks for notifications. So, for example, you may need to use c-blocks when loading up AVURLAsset to get notification on when an Asset if fully loaded. Just be aware that those blocks aren't called on the main thread. So if you try to update any UI elements or do any animations from that block it won't work right. You need to dispatch another block on to the main thread to do this, for example: dispatch_async(dispatch_get_main_queue(),^{....update UI element code....});. For more information about about dispatching blocks see Apple's Concurrency Programming Guide and Block Programming Guide.
Sure, but there will be a delay as the AVAudioPlayer is allocated and prepared for playing. Can you predict what will play and when? If so, maybe you can load a couple of seconds before you need a particular mp3 to play.
An alternative, which may not work depending on your timing requirements, is the following:
- (void)prepareAudioPlayer {
static int index = -1;
index = index + 1;
if (index < [[self FileNames] count]) {
NSError *err = nil;
NSString *audioFilePath = #""; // Figure out how to get each file name here
NSURL *audioFileURL = [NSURL fileURLWithPath:audioFilePath];
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileURL error:&err];
if (err) {
NSLog(#"Audio Player Error: %#", [err description]);
}
[player prepareToPlay];
// Add this player to the "AudioPlayers" array
[[self AudioPlayers] addObject:player];
// Recurse until all players are loaded
[self prepareAudioPlayer];
}
}
This solution requires properties of FileNames and AudioPlayers.
Once this is set up, you could do something like the following (probably in viewDidLoad):
// Make the file name array
[self setFileNames:[NSMutableArray array]];
// Initiate the audio player loading
[self performSelectorInBackground:#selector(prepareAudioPlayer) withObject:nil];
Later, when you need to play a particular file, you can find the index of the file name in the FileNames array and the call play on the AVAudioPlayer for that index in the AudioPlayers array.
This seems like maybe not the best way to do things, but it might work if you require it this way.
Here is the using method , If the sound is playing, current Time is the offset of the current playback position, measured in seconds from the start of the sound. If the sound is not playing, current Time is the offset of where playing starts upon calling the play method, measured in seconds from the start of the sound.
By setting this property you can seek to a specific point in a sound file or implement audio fast-forward and rewind functions.
The value of this property increases monotonically while an audio player is playing or paused.
If more than one audio player is connected to the audio output device, device time continues incrementing as long as at least one of the players is playing or paused.
If the audio output device has no connected audio players that are either playing or paused, device time reverts to 0.
Use this property to indicate “now” when calling the play AtTime: instance method. By configuring multiple audio players to play at a specified offset from deviceCurrent Time, you can perform precise synchronization—as described in the discussion for that method.To learn more visit..enter link description here

Resources