I am using the following to play a video named intro
- (IBAction)PlayIntro:(id)sender {
NSString *videoPath = [[NSBundle mainBundle] pathForResource:#"intro" ofType:#"m4v"];
introplayer = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:videoPath]];
[self presentMoviePlayerViewControllerAnimated:introplayer];
}
I am having trouble setting up a notification so that once the video is finished playing the following would take place [self performSegueWithIdentifier:#"IntroS" sender:sender]; any help would be appreciated.
You should set up KVO for your MPMoviePlayerController. When the state of the movie changes, this fires giving you a chance to compare total playback time with the current playback time.
Given your snippet of code, this line will give you the current playback value:
NSLog(#"Movie player state: %g", introplayer.currentPlaybackTime);
I provided a brief overview on how KVO works with an example unrelated to video playback.
Though the topic is unrelated to video, it works just the same regardless of what variable you're watching using KVO.
Related
I've found 1 question on SO about the same issue and it remains unanswered.
AVAudioPlayer affects system sounds
AVAudioSessionCategoryAmbient is not the answer as that only allows the app to play its audio simultaneously with another app's audio, that's not it.
I play sound effects such as button clicking sounds etc with SystemSound and background music with AVAudioPlayer. When AVAudioPlayer starts while SystemSound is being played, that particular system sound becomes like 5 times louder all of a sudden. Has anyone else experienced that? What could be the fix?
These are in SoundControl.m and I'm playing gameBG right after transition.
-(void)gameBG {
self.sharedSoundControl = [SoundControl sharedSoundControl];
if (self.sharedSoundControl.musicOff == NO) {
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:#"bgm" withExtension:#"mp3"] error:nil];
self.audioPlayer.numberOfLoops = -1;
self.audioPlayer.volume = 0.3f;
[self.audioPlayer play];
}}
-(void)transition {
if (self.sharedSoundControl.effectOff == NO) {
NSString *soundPath = [[NSBundle mainBundle] pathForResource:#"transition" ofType:#"caf"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:soundPath], &soundID);
AudioServicesPlaySystemSound(soundID);
}}
EDIT
Just realized that if another instance of AVAudioPlayer is already being played anywhere, such behavior does not occur. It happens when there's no active AVAudioPlayer and you play system sound followed by AVAudioPlayer then voila, that system sound you just played became REALLY loud all of a sudden.
I'm thinking, if I get no answers, I'm just gonna have to play some random muted AVAudioPlayer right before playing system sound so this won't happen but I'm hoping to get some "real" fix for this.
Please do not suggest to play some random muted AVAudioPlayer right before playing system sound because that's what I just said..
I am doing a somewhat strange implementation. My application uses GPS data continuously and using that I have to do some task. Also I have implemented accelerometer stuff to detect whether device is stationary or moving. When the device is stationary I stop GPS fetching by calling stopUpdatingLocation, and when device is moving I call startUpdatingLocation. This works fine both in the foreground and background.
But I want my application to be started in the background when the device is restarted. This works fine. I have added "voip" key in plist and in applicationDidFinishLaunch I have started GPS fetching code and started accelerometer.
But I found that once the device is kept stationary (stopUpdatingLocation), the accelerometer is not getting called. Because of that I cannot detect device movement. The accelerometer callback is not getting called. Here is a sample of the code I'm using:
mMotionManager = [[CMMotionManager alloc] init];
if (mMotionManager.accelerometerAvailable) {
mMotionManager.accelerometerUpdateInterval = 1.0/10.0;
mOperationQueue = [[NSOperationQueue alloc] init];
[mMotionManager startAccelerometerUpdatesToQueue:mOperationQueue withHandler:^(CMAccelerometerData *data, NSError *error){
dispatch_async(dispatch_get_main_queue(), ^{
//[self onDeviceMotion];
[mAccelerometerReadings addObject: data];
[self updateViewsWithFilteredAcceleration:data.acceleration];
});
}];
Can someone help me solve this? Is it possible?
Hi! I am capturing the thumbnail image of video from video url. And I am using following code to capture the thumbnail
MPMoviePlayerController *moviePlayer = [[MPMoviePlayerController alloc]initWithContentURL:movieURL];
[moviePlayer setControlStyle:MPMovieControlStyleFullscreen];
[moviePlayer setFullscreen:YES];
moviePlayer.useApplicationAudioSession = NO;
UIImage *image = [moviePlayer thumbnailImageAtTime:(NSTimeInterval)1.0 timeOption: MPMovieTimeOptionNearestKeyFrame];
I am using threading for this. I am getting the following error:
Movie player has wrong activation state (1)
Can anybody help me?
When you are initing the movie player, you already have one. There can be only one MPMoviePlayerController. You are probably doing this in a loop. You need to set your last one to nil or keep reusing the same one over and over.
Disclaimer: I'm relatively new to iOS programming, and am trying to teach myself the basics as I go along just for fun... so be gentle :-)
I'm building an app that plays a series of .mp3 files strung together using AVAudioplayer. So far, that part is working good. IBActions, and IBOutlets hooked up. Click the button, and the audio plays.
My problem is this:
My play button has been added directly to the main.storyboard, set and custom with it's initial state defined in Interface Builder. When I click the play, I want to change the image of the button to indicate that it's playing. However, as soon as the audio starts, it almost seems like the view is... paused, or something. The button image stays the same, until the audio done playing. Only then, will the button image update itself -- hardly useful.
I've also just tried to set the image of of another random UIImageView that's not attached to this particular button. Same experience. As soon as I comment out my playAudioArray method, the button swaps work immediately.
-(IBAction)start_playing:(UIButton*)pressed_button {
[_btn_start setImage:[UIImage imageNamed:#"btn_on-active"] forState:UIControlStateNormal];
[self playAudioArray];
}
I hope I've left enough to go on... Any thoughts / comments / suggestions??
Thanks a million
- Drew
#
Update:
I've found that updating the view breaks down when I have my audio player in a lopp. This code works fine...
if (audioPlayer.playing == YES) {
[audioPlayer pause];
[sender setImage:[UIImage imageNamed:#"btn_on.png"] forState:UIControlStateNormal];
[_btn_stop setImage:[UIImage imageNamed:#"btn_off.png"] forState:UIControlStateNormal];
} else {
NSString *path = [[NSBundle mainBundle] pathForResource:#"audio_file1" ofType:#"mp3"];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
audioPlayer.volume = 1.0;
audioPlayer.numberOfLoops = 0;
[audioPlayer setMeteringEnabled: YES];
[audioPlayer play];
//changes the image when the button is pressed
[sender setImage:[UIImage imageNamed:#"btn_on.png"] forState:UIControlStateNormal];
[_btn_stop setImage:[UIImage imageNamed:#"btn_off.png"] forState:UIControlStateNormal];
}
But this code doesn't below doesn't.
} else {
//changes the image when the button is pressed
[sender setImage:[UIImage imageNamed:#"btn_on.png"] forState:UIControlStateNormal];
[_btn_stop setImage:[UIImage imageNamed:#"btn_off.png"] forState:UIControlStateNormal];
NSArray *theSoundArray = [NSArray arrayWithObjects:#"audio1",#"audio2",#"audio3",nil];
for (int i = 0; i < totalSoundsInQueue;) {
NSString *sound = [theSoundArray objectAtIndex:i];
// Wait until the audio player is not playing anything
while(![audioPlayer isPlaying]){
NSString *path = [[NSBundle mainBundle] pathForResource:#"mom" ofType:#"mp3"];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
audioPlayer.volume = 1.0;
audioPlayer.numberOfLoops = 0;
[audioPlayer setMeteringEnabled: YES];
[audioPlayer play];
i++;
}
}
}
The audio plays fine, loops through all my sounds and no errors occur. Only, the 'on-state' of my button only gets set AFTER the loop is done playing. I've tried this with a number of different types of looping methods. For, for each, while... every time I start to loop through sounds audio playback works great, but the display looses all focus.
Which reminds me. Once I'm in the loop, my "Stop" button looses it's a clickable (tappable) nature. Until the loop has finished running. If I'm not in a loop, the stop button works fine, no problems.
Sorry if I'm making a total newb mistake here... thoughts / comments anyone?
Your for loop is tying up the main thread, making it your UI unresponsive. Instead of running the for loop continuously, set yourself as the delegate of AVAudioPlayer. Once the audio player is done playing it will send the delegate the message - (void) audioPlayerDidReachEnd; (which you'll have to implement). Then you can play the next audio file in the queue in that implementation. You really want to set yourself up as the delegate anyway. AVAudioPlayer will send your delegate messages for interruptions (like a call coming in) and decode errors. You want to handle these events gracefully.
I think the reason the audio is playing fine is that is has a higher priority and runs on a separate thread. The reason the UI becomes un-responsive is even though animations/UI changes occur on a separate thread, they're initiated from the main thread. But all UI changes are queued to the end of a run-loop (so optimizations can be made). However, that run loop never ends because your for loop never ends until all the audio files are played. The audio files can be played in order because they're initiated in that for loop and run on a separate thread. Makes sense? In general, you really don't want to tie up the main thread.
I have a program which plays two sounds. I want the user to know which sound is being played, so I have two large images of buttons. I have three different views that I would like to swap between - one where both buttons are red (nothing is playing), and two where one of the two buttons is green (to show which is playing).
The main problem I am getting is that my sound plays and finishes before the view has swapped! (I am using [window setContentView:firstSound] before the sounds are played)
The altered view eventually does show up, but only after the method playing the wavs has finished.
I am playing the sound files using NSSound (they are both short wav files, so I thought it appropriate)
Anyone know what I have done wrong? Or if there is another way I could do this? Thanks heaps!!
Edit: I have followed the advice to make it so that only the image is changed (rather than the view), but the same problem occurs. The update happens after the sounds have finished playing.
Here's the code:
-(void)readWavs{
//[window setContentView:firstWav];
[redButton setHidden:YES];
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"fish" ofType:#"wav"];
NSSound *sound = [[NSSound alloc] initWithContentsOfFile:resourcePath byReference:YES];
[sound play];
sleep(3); //needed so that the sound will actually play
[sound stop];
[sound release];
//[redButton setHidden:NO];
//[window setContentView:testView];
sleep(2);
//[window setContentView:secondWav];
NSString *resourcePath2 = [[NSBundle mainBundle] pathForResource:#"fish" ofType:#"wav"];
NSSound *sound2 = [[NSSound alloc] initWithContentsOfFile:resourcePath2 byReference:YES];
[sound2 play];
sleep(3);
[sound2 stop];
[sound2 release];
}
The green 'on' button should show up before the sound plays, but it only does so after the method is done.
I'm not sure if I'm understanding correctly, but what it sounds like you are trying to switch to a whole different view when a sound is played that displays which sound is being played (by images)? If so, you should just use imageView.hidden = YES and imageView.hidden = NO to display the correct images based on the sound. Better yet, you could use one image view and change the image displayed in the image view based on the sound.
You're blocking the run loop with those sleep()s. The display isn't updated until all the processing for the current event is finished, and that doesn't happen until this readWavs method is finished.
If you want to do something after the sound is finished, assign it a delegate (probably the same object that started the sound) and implement the NSSoundDelegate -sound:didFinishPlaying: method. Then, in readWavs, just start the sound and return - your delegate method will be called when it finishes, and because readWavs returns immediately, it won't block the run loop.