How do I display an UIImageView while a sound is playing? - iphone

I'm trying to display an image while a sound is playing. I can get it to appear, but I'm having trouble making it disappear once the sound has finished playing.
My code:
-(IBAction)guitarChord:(id)sender
{
if (theAudio.playing == YES) {
theAudio.stop;
theAnimation.stop;
} else {
theAudio.play;
theAnimation.play;
}
}
I'm using AVAudioPlayer.
Any ideas what I am doing wrong?
How do I detect a sound has stopped?

Briefly, you need to take a look at AVAudioPlayerDelegate and audioPlayerDidFinishPlaying.

Related

playing audio in background and recording that background audio with video on iphone

In my app i want to play background audio and video recording both audio and video will be record....
How can i do this functionality???
// Setup cam
-(void)setupDivAvCam
{
self.capturingWindow.delegate = self;
[self.capturingWindow setupWithOptions:#{DIYAVSettingCameraPosition : [NSNumber numberWithInt:AVCaptureDevicePositionBack] }];
[self.capturingWindow setCamMode:DIYAVModeVideo];
}
#pragma mark - Rec video methods Start
-(IBAction)captureVideo:(id)sender
{
[self startCapturingVideo];
}
-(IBAction)stopVideo:(id)sender
{
[self stopCapturingVideo];
}
//To start video recording
-(void)startCapturingVideo
{
{
{
if(![[UIDevice currentDevice].model isEqualToString:#"iPhone Simulator"])
{
//To disable the camera button for some time untill image loads
_cameraButton.userInteractionEnabled = NO;
[self.capturingWindow captureVideoStart];
}
}
}
}
//To stop video recording
-(void)stopCapturingVideo
{
[self.capturingWindow captureVideoStop];
}
The above code is to get the video
I looked in several forums and they all couldn't deliver a satisfying answer.
My wish is to be able to play and record video while playing music at the background. I managed to do that with the help of a snippet I found. here is the code:

How to use a activity indicator before the video starts playing using MPMoviePlayerController?

I need to play a video in my UIViewcontroller using MPMoviePlayerController. So before playing the video i need to show an activity Indicator View before the video is buffered. Once the video starts playing i need to remove the Activity Indicator. I am not able to find out on how to get notified as soon as the video starts playing. Any suggestion on this would be of great help. Thanks.
Your probably looking for something like this:
- (void)viewDidAppear:(BOOL)animated {
NSLog(#"VIEW DID LOAD");
// Register to receive a notification that the movie is now in memory and ready to play
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieLoadStateDidChange:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
}
-(void)movieLoadStateDidChange:(id)sender{
NSLog(#"STATE CHANGED");
if(MPMovieLoadStatePlaythroughOK ) {
NSLog(#"State is Playable OK");
NSLog(#"Enough data has been buffered for playback to continue uninterrupted..");
aiv.hidden = YES;
[aiv stopAnimating];
}
}
I also found that from this link which may help you out too: http://www.sdkboy.com/?p=48
if(MPMovieLoadStatePlaythroughOK ) { - this check is incorect. It's always TRUE.
Take a look:
Can a UIActivityIndicator be displayed over a MPMoviePlayerController in full screen mode?

AVPlayer buffering, pausing notification, and poster frame

I have some questions related to AVPlayer which are:
When we pause the AVPlayer through [player pause] does the AVPlayer keep buffering the video from the network or does it just stop? I couldn't get any info related to this in apple's documentation. Also, is it possible to force the AVPlayer to keep buffering while in pause, so that if we have the paused video is in waiting for the first video to be ended then we wouldn't find any gap in between the videos?
On pausing the AVPlayer can we have any event on [player pause].
Can we show still image on AVPlayer for some seconds?
Thanks
1) AVPlayer will buffer the video in several cases, none cleary documented. I'd say you can expect buffering when you init the video, and when you replace the current item.
You can observe currentItem.loadedTimeRanges to know what's going on. That property will tell you which video time ranges has been loaded.
Also, there is a few other currentItem properties that may help you: playbackLikelyToKeepUp, playbackBufferFull and playbackBufferEmpty.
Achieving a perfect gapless playback is not easy.
/* player is an instance of AVPlayer */
[player addObserver:self
forKeyPath:#"currentItem.loadedTimeRanges"
options:NSKeyValueObservingOptionNew
context:kTimeRangesKVO];
In observeValueForKeyPath:ofObject:change:context::
if (kTimeRangesKVO == context) {
NSArray *timeRanges = (NSArray *)[change objectForKey:NSKeyValueChangeNewKey];
if (timeRanges && [timeRanges count]) {
CMTimeRange timerange = [[timeRanges objectAtIndex:0] CMTimeRangeValue];
NSLog(#" . . . %.5f -> %.5f", CMTimeGetSeconds(timerange.start), CMTimeGetSeconds(CMTimeAdd(timerange.start, timerange.duration)));
}
}
2) Just keep an eye on player.rate.
[player addObserver:self
forKeyPath:#"rate"
options:NSKeyValueObservingOptionNew
context:kRateDidChangeKVO];
Then in your observeValueForKeyPath:ofObject:change:context::
if (kRateDidChangeKVO == context) {
NSLog(#"Player playback rate changed: %.5f", player.rate);
if (player.rate == 0.0) {
NSLog(#" . . . PAUSED (or just started)");
}
}
3) You can build a movie of a given length using a still image but it's easier to use a regular UIImageView on top of the player. Hide/show it when needed.
Sample project: feel free to play with the code I wrote to support my answer.

Getting wrong playback state in MP Music Player Controller in ios 5

i am getting wrong playback state in MP music player.
while playing a song i am getting pause state.
My app is working fine in ios 4.but i am having this issue in ios 5.
can anybody Help me ??
My code is here.
[musicPlayer stop];
if (userMediaItemCollection)
{
userMediaItemCollection=nil;
}
musicPlayer.nowPlayingItem=nil;
userMediaItemCollection=[MPMediaItemCollection collectionWithItems:[mediaItemCollection items]];
[musicPlayer setQueueWithItemCollection:userMediaItemCollection];
[musicPlayer setNowPlayingItem:
[[userMediaItemCollectionitems]objectAtIndex:indexOfCurrentObject]];
[self enablePrevAndNextButtons];
[musicPlayer play];
}
-(void)playbackStateDidChanged:(NSNotification *)notification
{
if (musicPlayer.playbackState!=MPMusicPlaybackStatePlaying)
{
[playPauseButton setBackgroundImage:[UIImage imageNamed:#"play_iPad.png"] forState:UIControlStateNormal];
}
else if(musicPlayer.playbackState==MPMusicPlaybackStatePlaying)
{
[playPauseButton setBackgroundImage:[UIImage imageNamed:#"pause_iPad.png"] forState:UIControlStateNormal];
}
I have also reported this bug to Apple. I was able to reproduce it 100% of the time by doing the following:
Launch application that uses MPMusicPlayerController.
Launch the "Music" App.
Hit Play, Skip, Skip, Pause, Play, Pause
Open the original application and the MPMusicPlaybackState of MPMusicPlayerController will be incorrect.
None of the proposed solutions here worked for me. The solution that did work was to keep track of when the bug was occurring and updating the UI specially in these cases.
When the UIApplicationDidBecomeActiveNotification notification is received (see matbur post for more details on this), see if audio is actually not playing when the MPMusicPlaybackState said it was:
-(BOOL) isPlaybackStateBugActive {
MPMusicPlaybackState playbackState = self.musicPlayer.playbackState;
if (playbackState == MPMusicPlaybackStatePlaying) {
AudioSessionInitialize (NULL, NULL, NULL, NULL);
UInt32 sessionCategory = kAudioSessionCategory_AmbientSound;
AudioSessionSetProperty (kAudioSessionProperty_AudioCategory, sizeof (sessionCategory), &sessionCategory);
AudioSessionSetActive (true);
UInt32 audioIsPlaying;
UInt32 size = sizeof(audioIsPlaying);
AudioSessionGetProperty(kAudioSessionProperty_OtherAudioIsPlaying, &size, &audioIsPlaying);
if (!audioIsPlaying){
NSLog(#"PlaybackState bug is active");
return YES;
}
}
return NO;
}
Don't forget to import the AudioToolbox framework.
None of these workarounds fix the issue for my app. It is a bug in iOS, and my app will never function properly until Apple fixes it.
I have a music player with a play/pause button. When music is playing, the button shows the "pause" icon. When music is paused, the button shows the "play" icon - just like all music apps. I can replicate the bug at any time by doing the following:
1. Play music in my app (the play/pause button shows the "pause" icon correctly)
2. Background my app and lock my phone for ~10 minutes
3. Double tap home and hit the pause button from the iPod controls
4. Unlock my phone and open my app again
5. Music will be stopped, but my app still shows the "pause" icon when it should so "play"
I've done extensive debugging and logging to ensure that the method that updates my play/pause button is always called when my application becomes active. The issue is that when I re-enter my app, the playback state of MPMusicPlayer is still set to MPMusicPlaybackStatePlaying even when music is stopped/paused.
I filed a bug report for this about a year ago and haven't heard anything from Apple. If someone else would file one it would be greatly appreciated.
I have the same problem but when I play/pause many times when my app is in background, I reported the bug to Apple and hope to get an amswer soon, I want to know if my coding is wrong or there is an API problem. If this was the error you were having, this may be helpful. I came to a workaround which even though isnt the best solution, for my app is acceptable:
In the viewDidLoad, add this:
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver: self
selector: #selector (handle_ApplicationDidBecomeActive:)
name: UIApplicationDidBecomeActiveNotification
object: nil];
Then, create a handle_ApplicationDidBecomeActive method, and add this:
- (void) handle_ApplicationDidBecomeActive: (id) notification
{
if (musicPlayer.playbackState!=MPMusicPlaybackStatePlaying)
{
[playPauseButton setBackgroundImage:[UIImage imageNamed:#"play_iPad.png"] forState:UIControlStateNormal];
[musicPlayer pause];
}
else if(musicPlayer.playbackState==MPMusicPlaybackStatePlaying)
{
[playPauseButton setBackgroundImage:[UIImage imageNamed:#"pause_iPad.png"] forState:UIControlStateNormal];
[musicPlayer pause];
}
}
(dont put this code inside your playbackStateDidChanged method as this may generate an endless loop)
This will sync the state of your buttons and music player to the one reported by the API. in the cases in which there is a coincidence, there will be no impact of any type, in the other cases, the player will pause/play accordingly.
I experienced the same problem with the release of iOS 5. I found that the playbackState property does get updated, but after a delay, so it's not yet set when your playbackStateDidChanged method runs.
My workaround was to set my own instance variable called musicPlayerRecentlyStartedPlaying whenever I start playback. Then I use a method called from a timer to check both that variable and the playbackState property to find out if the player is really playing:
- (void)playMusic {
[self.musicPlayer play];
self.musicPlayerRecentlyStartedPlaying = TRUE;
self.musicControlsUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(updateMusicControls:) userInfo:nil repeats:TRUE];
}
- (void)stopMusic {
[self.musicPlayer stop];
self.musicPlayerRecentlyStartedPlaying = FALSE;
[self.musicControlsUpdateTimer invalidate];
}
- (void)updateMusicControls:(NSTimer *)timer {
BOOL playing = (([self.musicPlayer playbackState] == MPMusicPlaybackStatePlaying)&&(self.musicPlayer.nowPlayingItem));
if (!playing) {
// check to see if we recently started playing
if (self.musicPlayerRecentlyStartedPlaying) {
playing = TRUE;
}
} else {
// once the property is updated, we no longer need this
self.musicPlayerRecentlyStartedPlaying = FALSE;
}
}
You might not need to call updateMusicControls from a timer, but I do because I'm also updating the position of a progress bar as the music plays.
This code using when previous Button click Previous song will be play
- (IBAction)playPreviousSongInList:(id)sender {
static NSTimeInterval skipToBeginningOfSongIfElapsedTimeLongerThan = 3.5;
NSTimeInterval playbackTime = self.musicPlayer.currentPlaybackTime;
if (playbackTime <= skipToBeginningOfSongIfElapsedTimeLongerThan) {
[self.musicPlayer skipToPreviousItem];
} else {
[self.musicPlayer skipToBeginning];
}
}

Touch Drag Inside triggers sound repeatedly & Touch Up Inside doesn't work

I'm trying to do an app where a short sound sample is supposed to be played while the person using the app is dragging his/her finger(s) across the screen. When the finger(s) are lifted away from the screen - the sound will stop.
This is the function that triggers the sound:
-(IBAction) playSound:(id)sender{
NSString *soundPath = [[NSBundle mainBundle]pathForResource:#"sound" ofType:#"wav"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:soundPath];
newPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:fileURL error:nil];
newPlayer.numberOfLoops = -1;
[newPlayer play];
}
This is the function that stops the sound:
-(IBAction) stopSound{
if ([newPlayer isPlaying]) {
[newPlayer stop];
}
[newPlayer release];
}
I first started out using the Touch Down event, which looped the sound seamlessly. At this point the stopSound worked together with the "Touch Up Inside" event.
The point, as I said, is the sound is supposed to be generated when the user drags his/her finger(s) across the screen. But when I tried to the tie the playSound function to the "Touch Drag Inside" the sound loops repeatedly over itself, instead of one at the time, making it hell to use. The stopSound function doesn't work after i changed to the Drag Event.
I tried to use NSTimer to create some kind of way to handle the loops, but without any success.
My advice would be to create to generate a method that loops your audio clip (whatever duration, overlap, pausing, etc you want). Setup the method so that when you call it to play, it plays the way you want it to indefinitely.
The method might look like:
-(void) beginOrContinuePlayingAudioLoop:(BOOL)shouldPlay {
//if touchesMoved called, shouldPlay will be YES
//if touchesEnded called, shouldPlay will be NO
if (shouldPlay == NO) {
//cease playing
currentlyPlaying = NO;
}
if (currentlyPlaying == YES) {
return;
} else {
//begin playing audio
currentlyPlaying = YES;
}
}
In your ViewController class, define a BOOL (currentlyPlaying) that indicates whether the audio loop is currently playing.
As opposed to using canned IBAction gesture recognizers, consider overriding the more generic touch responder calls, touchesMoved and touchesEnded on your view.
In touchesMoved, set your VC's BOOL to YES and then fire your audio looping method to start playing. The "playing" method should always check and see if the audio is already playing, and only start playing
Also place a check in your method that returns/exits your method when the audio loop is already playing, this will avoid overlapping.
In touchesEnded, kill your audio via whatever method you choose, and reset the BOOL to NO.