I'm having an issue using AVAudioPlayer where I want to reset a player if it's currently playing and have it play again.
I try the following with no luck:
The sound plays once but then the second time i select the button it stops the sound, the third time starts the sound up again.
//Stop the player and restart it
if (player.playing) {
NSLog(#"Reset sound: %#", selectedSound);
[player stop];
[player play];
} else {
NSLog(#"playSound: %#", selectedSound);
[player play];
}
I've also tried using player.currentTime = 0 which indicates that would reset the player, that didn't work, I also tried resetting currentTime = 0 and then calling play that didn't work.
//Stop the player and restart it
if (player.playing) {
NSLog(#"Reset sound: %#", selectedSound);
player.currentTime = 0;
[player play];
} else {
NSLog(#"playSound: %#", selectedSound);
[player play];
}
For your situation I would try the following
//Pause the player and restart it
if (player.playing) {
NSLog(#"Reset sound: %#", selectedSound);
[player pause];
}
player.currentTime = 0;
[player play];
If you are going to immediately play the sound again, I would suggest pause instead of stop. Calling stop "Stops playback and undoes the setup needed for playback."
As indicated, if you want the sound to play again, you should avoid disabling the AVAudioPlayer instance with a stop but rather, just issue a reset of the position where it is playing. So, don't use stop() or pause() but as Plumenator mentioned, just issue .currentTime=0. So in your case, you would simply do:
if (player.isPlaying) {
player.currentTime = 0
} else {
player.play()
}
Swift example:
player.currentTime = 0.0;
Related
I know this is a duplicate question but I didn't find out the exact answer. I am working with AVAudioPlayer. Now I have two buttons forward & rewind. When the user will tap the forward button the audio will move 5 second forward & when the user will tap the rewind button the audio will move 5 second rewind. How can i do this exactly? Thanks in advance for any help.
Put below methods for forward and rewind player time
- (IBAction)btnForwardClicked:(id)sender
{
int currentTime = [player currentTime];
[player setCurrentTime:currentTime+5];
}
- (IBAction)btnBackwardClicked:(id)sender
{
int currentTime = [player currentTime];
[player setCurrentTime:currentTime-5];
}
here player is avaudio player's object
AVAudioPlayer *player;
- (IBAction)btnForwardClicked:(id)sender
{
NSTimeInterval *time = [player currentTime];
time+=SKIP_TIME;
//for reverse time-=SKIP_TIME
//SKIP_TIME is time which is jumped i-e 5 seconds
[player setCurrentTime:time];
}
I just created AVPlayer and it plays music well. I have two questions
How to play another music from another URL (should I stop current player?)
How to show current time of the song in UISlider (actually is it a method that called when the song is playing?)
Use -[AVPlayer replaceCurrentItemWithPlayerItem] to replace the current playing item reusing the player instance. You can create an item with an URL or with an asset.
In order to know when a given item finishes playing use the notification AVPlayerItemDidPlayToEndTimeNotification.
Use -[AVPlayer addPeriodicTimeObserverForInterval] to perform some action periodically while the player is playing. See this example:
[self.player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100)
queue:nil
usingBlock:^(CMTime time) {
<# your code will be called each 1/10th second #>
}];
1) If you used - (id)initWithURL:(NSURL *)URL then you should stop player with pause, dealloc it and create new instance.
AVPlayer *player = [AVPlayer alloc] initWithURL:[NSURL URLWithString:#"http:/someurl.com"]];
[player play];
[player pause];
[player release];
player = [AVPlayer alloc] initWithURL:[NSURL URLWithString:#"http:/someurl2.com"]];
[player pause];
[player release];
If you used playerWithURL, then just call the same line again.
2). The easiest is the get duration of the current item https://stackoverflow.com/a/3999238/619434 and then update the UISlider with that value. You can use NSTimer to periodically check the duration.
self.player.currentItem.asset.duration
I have 2 views in my app, that are identical, they just load in a different array of sound files to use with their respective AVAudioPlayer.
However, ON THE DEVICE ONLY, on my second view, the sound seems to only play once after initialization, then it doesn't play until I initialize the player again.
This is my play button code:
- (IBAction)play:(id)sender {
if (((int)buttonCount % 2) == 0) {
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
self.audioPlayer.currentTime = 0;
self.audioPlayer.volume = volumeSlider.value;
[self.audioPlayer play];
[playButton setTitle:#"Stop..." forState:UIControlStateNormal];
buttonCount++;
[self fadePickerAnimation:NO];
NSLog(#"Should play");
}
else {
[self initializeSoundAfterStop:YES];
NSLog(#"Shouldn't play");
}
NSLog(#"buttoncount %i",buttonCount);
NSLog(#"What is the playing state? %i", self.audioPlayer.playing);
}
and the function it calls under the else clause:
- (void)initializeSoundAfterStop:(BOOL)addToButtonCount {
//Initialize audioPlayer once completely stopped
[self.audioPlayer stop];
[self.audioPlayer prepareToPlay];
[playButton setTitle:#"Chime!" forState:UIControlStateNormal];
if (addToButtonCount == YES) {
buttonCount++;
}}
The NSLogs in the above code output this as I continuously press the play button:
Should play
buttoncount 1
What is the playing state? 1
Shouldn't play
buttoncount 2
What is the playing state? 0
Should play
buttoncount 3
What is the playing state? 0
Shouldn't play
buttoncount 4
What is the playing state? 0
Should play
buttoncount 5
What is the playing state? 0
Shouldn't play
buttoncount 6
What is the playing state? 0
So as you can see, it gets stuck in a non-playing mode for some reason.
This method is used in exactly the same fashion in my first view, and it works without any problem. And it all works fine on the simulator, just not on my iPhone 4. Cannot figure this out. The play method of audioPlayer gets called when I setup a breakpoint, so I dunno!
Thanks!
Couldn't find out why this was happening, however, I fixed it by simply adding in my AVAdioPlayer initializer function at the top of the play IBAction.
Might not be the most graceful solution, but it works.
Just beware of memory allocation if you decide to do this.
So I have an application and I want to keep it working even if the screen is turned off.
Previously when I wanted to do that I used this hack/trick - I play a silent/empty sound in a loop in the background (AudioServicesPlaySystemSound) so if user presses the on/off button the application still works in the background - so it never allow iPhone to go to sleep mode - it just turned off the screen and maybe things like wifi or bluetooth (and on the iPod Touch accelerometers as far as I remember). And it worked. I wanted to use the same trick in my new application but when I was testing it now it seems it doesn't work anymore. The sound in the background plays (when I replace "empty" audio file with some sound I can hear it play) even with screen turned off but the sound it should play (using AVAudioPlayer) doesn't play (even when I turn the screen on again).
I don't know at which point it stopped working (it worked on 3.x OS for sure). Am I doing something wrong? Did Apple changed/fixed the "hack" that allowed your app to work even with screen turned off? Is there another way to allow the device to go to sleep (and drain the battery less) but continue to work?
This is the code I use to play background/silent sound:
-(void) playSilentSound
{
CFBundleRef mainBundle = CFBundleGetMainBundle ();
CFURLRef silentUrl = CFBundleCopyResourceURL (mainBundle, CFSTR ("silence"), CFSTR ("aiff"), NULL);
AudioServicesCreateSystemSoundID (silentUrl, &silentSound);
silentTimer = [NSTimer scheduledTimerWithTimeInterval: 2.0 target: self selector:#selector(playSilence) userInfo: nil repeats: YES];
}
-(void) playSilence
{
AudioServicesPlaySystemSound (silentSound);
}
And this is how I play the sound that should play even if the screen is turned off:
-(BOOL) playSound: (NSString *) path withLoops: (BOOL) loops stopAfter: (int) seconds
{
NSError *error;
player = [[AVAudioPlayer alloc] initWithContentsOfURL: [NSURL fileURLWithPath: path] error: &error];
player.delegate = self;
player.numberOfLoops = 0;
player.volume = volume;
secondsPlayed = 0;
loop = loops;
BOOL played = [player play];
if(played && seconds > 0)
{
timer = [[NSTimer scheduledTimerWithTimeInterval: 0.5 target: self selector: #selector(stopPlaying:) userInfo: [NSNumber numberWithInt: seconds] repeats: YES] retain];
secondsLimit = seconds;
} else {
secondsLimit = -1;
}
}
-(void) stopPlaying:(NSTimer*)theTimer
{
if(secondsLimit > 0 && (secondsPlayed + [player currentTime]) >= secondsLimit)
{
[player stop];
[timer release];
timer = nil;
}
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)sender successfully:(BOOL)flag
{
if(sender == player)
{
if(flag) { secondsPlayed += sender.duration; }
if(loop) { [player play]; }
}
}
The code is a bit complicated maybe - it could be just the first few lines - it's made that way so you can play only X seconds of sound (if sound is shorter than X it will play few loops until the total time is >= X). And of course everything is working fine when the screen is left on.
Also - if you find the code useful in your projects (like playSound:withLoops:stopAfter:) - feel free to use it (but it would be cool if you send me a message so I would know that I helped :)).
So the answer is to set session category. Some categories just turn off sound when the device is being locked. For me the best option was AVAudioSessionCategoryPlayback
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: nil];
I don't know about Apple fixing stuff, but in iOS 4 there are now official ways to continue doing things in the background which you should take advantage of.
I've tried the code to avoid the sleep mode interruption. It's working, but now I have a problem with interruptions when a call or sms is coming in to the iPhone. The song in my music application is stopped at that time. I want to automatically resume the song where it was stopped once the call is over.
- (void) audioPlayerBeginInterruption: (AVAudioPlayer *) player {
if (playing) {
playing = NO;
interruptedOnPlayback = YES;
[self updateViewForPlayerState];
}
}
- (void) audioPlayerEndInterruption: (AVAudioPlayer *) player {
if (interruptedOnPlayback) {
[player prepareToPlay];
[player play];
playing = YES;
interruptedOnPlayback = NO;
}
}
But it doesn't work. Please help me here, thanks in advance.
Try Apple's guide to Audio Interruptions.