How to make avaudioplayer stop in a different class - objective-c

In my app delegate I have this code in the application did finish launching method:
NSString *music = [[NSBundle mainBundle]
pathForResource:#"appsong" ofType:#"m4a"];
self.audio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:music] error:NULL];
audio.delegate = self;
[audio play];
audio.numberOfLoops = -1;
I have a page where another peice of music should play, how can i say that the avaudioplayer in the app delegate should stop and start again WHEN I QUIT THAT VIEW.

Well since your global player is in your app delegate, the view that wants to play it's own music might add:
-(void)viewWillAppear:(BOOL)animated {
// ...
[(YourSpecificAppDelClass*)[UIApplication sharedApplication].delegate pauseAudioPlayer];
}
and
-(void)viewWillDisappear:(BOOL)animated {
// ...
[(YourSpecificAppDelClass*)[UIApplication sharedApplication].delegate startAudioPlayer];
}
where startAudioPlayer and stopAudioPlayer are exposed in your app delegates header file.

Call a function that stops the player thats in the appdelegate class from ur view class?

Related

Cannot push a viewController inside a ViewDidload method in another Viewcontroller

I want to do something like this in my iOS application.
I alredy have a splash screen and a login screen,, After the Splashviewcontroller it displays the LoginViewcontroller.
Im checking some conditions inside the ViewDidloadand in a particular condition I want to push to an another viewcontroller. This is working in ios 5,and 6 but in ios 7 this is not loading when this condition is true.
This is my code
-(void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.navigationController.navigationBar.hidden=YES;
mutArrLoggedUsrarray=[[NSMutableArray alloc]init];
newuser=[NEWLoginUSER sharedManager];
nws=[NEWWebservice sharedManager];
alertObject=[AlertsString sharedManager];
alert=[CreateProgressAlert sharedManager];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *strLogStatus=[defaults objectForKey:#"LOGWAY"];
if ([strLogStatus isEqualToString:#"EMAIL"]) {
phoneLiginView.hidden=YES;
emailLoginView.hidden=NO;
isCurrentViewPhone=NO;
KeychainItemWrapper *keychainItemPHONE = [[KeychainItemWrapper alloc] initWithIdentifier:#"PHONENO" accessGroup:nil];
NSString *userTypedEmail=[keychainItemPHONE objectForKey:(__bridge id)(kSecAttrAccount)];
NSString *userTypedPassword=[keychainItemPHONE objectForKey:(__bridge id)(kSecValueData)];
newuser.strEmail=userTypedEmail;
TxtEmail.text=newuser.strEmail;
// [changeBoxbtn setTitle:#"LOGIN WITH PHONE NUMBER" forState:UIControlStateNormal];
changeBoxbtn.hidden=YES;
}
else if([strLogStatus isEqualToString:#"PHONE"])
{
txtUsrname.text=[newuser.strPhoneNum stringByReplacingOccurrencesOfString:#"+94" withString:#""];
isCurrentViewPhone=YES;
//[changeBoxbtn setTitle:#"LOGIN WITH EMAIL ID" forState:UIControlStateNormal];
changeBoxbtn.hidden=YES;
}
else{
isCurrentViewPhone=YES;
RegisterViewController *regvieww=[[RegisterViewController alloc] initWithNibName:#"RegisterViewController" bundle:nil];
[regvieww.view addSubview:regvieww.viewVerify];
[regvieww.view addSubview:regvieww.viewTop];
[regvieww.view addSubview:regvieww.regViaEmailView];
[regvieww.view addSubview:regvieww.selectorView];
[self.navigationController pushViewController:regvieww animated:YES];
}
originalCenter=self.view.center;
if ([UIScreen mainScreen].bounds.size.height==480) {
originalCenter.y=240;
}
}
Can u tell me what is the problem with this. And how to solve this
Try moving your conditions to your AppDelegate in the method:
didFinishLaunching
And set the first viewController accordingly.
You can also try moving your code from viewDidLoad to viewWillAppear.
Pushing a viewController animated in viewDidLoad won't work.

Custom iOS UILocalNotification sound does not play (possibly related to Xcode update)

I'm trying to get a custom sound working on a UILocalNotification, and I'm just getting no sound at all. If I use UILocalNotificationDefaultSoundName, I indeed get the default sound, but when the custom sound is specified, there is no sound, just the message. The sound is less than 30 seconds and it's in the right format, as far as I can tell. Here's a screenshot of the file info:
I've inspected the .app directory in XCode's DerivedData directory, and the alarm.caf file is at the root of the app, which I believe means it's in the bundle (right?).
I'm pretty sure this was working a while ago, and I've since upgraded Xcode. Maybe that is a hint?
I've also tried deleting/reinstalling/rebooting as mentioned in other answers. As you can see, I'm calling cancelAllLocalNotifications first.
Does anyone have any idea what could be wrong?
[[UIApplication sharedApplication] cancelAllLocalNotifications];
NSLog(#"installing alarm");
[arguments pop]; // name
[arguments pop]; // title
alarm.alertBody = [arguments pop];
alarm.fireDate = [[NSDate date] addTimeInterval:[[arguments pop] intValue]/1000];
//alarm.soundName = UILocalNotificationDefaultSoundName;
alarm.soundName = #"alarm.caf";
[[UIApplication sharedApplication] scheduleLocalNotification:alarm];
Your code seems to be good.
Try to clean your project, uninstall your app from your device/simulator, then re-install it. It could help maybe :)
I don't know the reason (and I didn't read documentation too), I just turned on the action property notification setHasAction:YES and the sound began to play.
please make sure that the iPhone is not in silent mode( because your code seems to be good )
just check the button on the side of your iPhone
Ok, so here's what happened. I forgot how the app handles the notification itself if it is still running. My code was only displaying a UIAlertView and not playing the sound. I'm not sure why it worked with the default sound. In any case, I added code like this to my AppDelegate:
- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification
{
NSLog(#"didReceiveLocalNotification");
if (application.applicationState == UIApplicationStateActive) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"MarkMyTime"
message:notification.alertBody
delegate:self cancelButtonTitle:#"OK"
otherButtonTitles:nil];
NSString *soundFilePath = [[NSBundle mainBundle]
pathForResource:notification.soundName ofType:nil];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL error: nil];
[fileURL release];
player.delegate = self;
[player prepareToPlay];
[player play];
[alertView show];
if (alertView) {
[alertView release];
}
}
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
NSLog(#"Releasing player");
[player release];
}
This will show a UIAlertView and play the sound on the notification object. You also need to add the AVAudioPlayerDelegate interface to the AppDelegate to be able to assign the delegat to the player. I think if you are using ARC, this code could be simplified a bit.
#interface AppDelegate : PhoneGapDelegate <AVAudioPlayerDelegate> {
I'm not sure if this is the best approach, so feel free to chime in with any improvements.
Maybe you do not add the sound file (*.caf) in Xcode project: Build Phases/Copy Bundle Resources.
Your code is good, but check your iPhone setting
setting -> Notification center -> Your App -> Sound - > "On"
the sound should be "On".
So, to enable this, checked Inter App Audio at Capabilities in Targets of the application and it was Off Capabilities in Inter-app audio
change this to On.
Then local notification sound is working.

Resuming execution of code after interruption while app is in background

I have spent days researching on SO and other websites for the answer to this but without any luck.
Essentially, the challenge I've set for myself is to create an alarm clock app for iOS that will sound no matter where the user may be (foreground or background). This I have already accomplished by using an AVAudioPlayer instance and starting to play an empty sound file when the user sets the alarm in order for the app to keep running in the background. When it is time for the alarm to go off (ie when the NSTimer is fired) a second player, which has already been initiated and prepared to play, starts playing the ringtone to which the user wakes up.
Also, I have managed to handle interruptions by a phone call, system timer or alarm clock by implementing the AVAudioSessionDelegate methods beginInterruption and endInterruptionWithFlags. It works both in background and foreground modes, but the strangest thing happens:
When the interruption ends, the AVAudioPlayer resumes playing BUT I cannot execute any other code in my app unless I bring the app to the foreground again.
To get to the bottom of this, I have experimented with a much simpler project which I am posting below.
What this app does is, as soon as you enter the app, an instance of the AVAudioPlayer class starts looping a certain sound. Then when you bring it to the background, the player continues to loop the sound. When an interruption occurs I pause the player and when it ends I use a dispatch to wait a couple of seconds before it calls two methods, ie (void)playPlayer, a method that contains the code to resume playing the file and (void)tester, a method that contains a timer, which is set to stop the player 5 seconds after the interruption (or 7 seconds to be exact) has ended. Both the methods get called as indicated by the NSLogs I have put in both of them, but the timer never gets fired and the player continues to play indefinitely.
Here is the code for the .h file:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
#interface InterruptionTest3ViewController : UIViewController <AVAudioSessionDelegate, AVAudioPlayerDelegate>
{
AVAudioSession *mySession;
AVAudioPlayer *myPlayer;
}
-(void) playPlayer;
-(void) pausePlayer;
-(void) tester;
#end
Here is the code for the .m file:
#import "InterruptionTest3ViewController.h"
#interface InterruptionTest3ViewController ()
#end
#implementation InterruptionTest3ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
mySession = [AVAudioSession sharedInstance];
NSError *setActiveError = nil;
[mySession setActive:YES withFlags:AVAudioSessionSetActiveFlags_NotifyOthersOnDeactivation error:&setActiveError];
if (setActiveError) {
NSLog(#"Session failed to activate within viewDidLoad");
}
else {
NSLog(#"Session was activated within viewDidLoad");
}
NSError *setCategoryError = nil;
[mySession setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];
if (setCategoryError) {
NSLog(#"Category failed to be set");
}
else {
NSLog(#"Category has been set");
}
[mySession setDelegate:self];
NSString *path = [[NSBundle mainBundle] pathForResource:#"headspin" ofType:#"wav"];
NSError *initMyPlayerError = nil;
myPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&initMyPlayerError];
if (initMyPlayerError) {
NSLog(#"myPlayer failed to initiate");
}
else {
NSLog(#"myPlayer has been initiated");
}
[myPlayer prepareToPlay];
[self playPlayer];
OSStatus propertySetError = 0;
UInt32 allowMixing = true;
propertySetError = AudioSessionSetProperty (
kAudioSessionProperty_OverrideCategoryMixWithOthers,
sizeof (allowMixing),
&allowMixing
);
[myPlayer setNumberOfLoops:-1];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
-(void) beginInterruption
{
[myPlayer pause];
}
-(void) endInterruptionWithFlags:(NSUInteger)flags
{
if (flags) {
if (AVAudioSessionInterruptionFlags_ShouldResume)
{
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC),dispatch_get_main_queue(), ^{
[self playPlayer];
[self tester];
});
}
}
}
}
-(void) tester
{
[NSTimer timerWithTimeInterval:5.0 target:self selector:#selector(pausePlayer) userInfo:nil repeats:NO];
NSLog(#"tester method has been called");
}
-(void) playPlayer
{
[NSTimer timerWithTimeInterval:5.0 target:myPlayer selector:#selector(stop) userInfo:nil repeats:NO];
[myPlayer play];
NSLog(#"playPlayer method has been called");
}
-(void) pausePlayer
{
[myPlayer pause];
}
//viewDidUnload etc not listed.
So, this is it folks. Again, why is the timer not being fired after an interruption while the app is in the background? Do I need to set something in the applicationDidEnterBackground method?
Thank you very much in advance!
please use "[NSTimer scheduledTimerWithTimeInterval:5.0 target:myPlayer selector:#selector(stop) userInfo:nil repeats:NO]";
Not to avoid the question, but the play-an-empty-sound-in-the-background bit is a hack. The ability to play a sound in the background is provided so that you can play music or other sound for the user's benefit, not to keep a background process alive.
Consider using local notifications instead if you want to play a sound or otherwise alert the user at a particular time.
why is the timer not being fired after an interruption while the app is in the background?
If I remember correctly, timers are either suspended or cancelled when your app enters the background. The documentation explicitly says that you should "stop timers and other periodic tasks" when your app is interrupted, i.e. when it's sent to the background.

Play Video immediately when UIView is loaded

Howdy! I'm writing an iPad app, and I need to be able to play a video when a UIView loads. However, I was getting a BAD_EXC_ACCESS if I try to message my MPMoviePlayerController anywhere after I initialize it. I removed the MPMediaPlayerController from my *.h file, then declared it entirely in the implementation file, and now I'm getting the message at the bottom below my code. There are no issues in Build and Analyze about memory leaks (or any issues, for that matter), and I cannot find any posts about this. Here's my code:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
NSString *url = [[NSBundle mainBundle] pathForResource:#"p0600c0100cmpintro" ofType:#"m4v"];
MPMoviePlayerController *movie = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL fileURLWithPath:url]];
NSLog(#"%#", movie);
movie.view.frame = CGRectMake(5, 0, 1035, 768);
movie.view.contentMode = UIViewContentModeScaleToFill;
[[movie view] setCenter:CGPointMake(movie.view.center.x-10, movie.view.center.y)];
[movie setControlStyle:MPMovieControlStyleNone];
[movie setShouldAutoplay:YES];
[[self view] addSubview:[movie view]];
return self;
}
The NSLog of "movie" gives "MPMoviePlayerController: 0x1b77f0", but then the error message upon crash is "* -[MPMoviePlayerController playbackState]: message sent to deallocated instance 0x1473a0". Help?
According to the documentation it looks like the frame of the movie view needs to match the view of its parent. Also try moving your code out of the initWithNibName:bundle: into viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
UIView *movieContainer = [[UIView alloc] initWithFrame:CGRectMake(5, 0, 300, 400)];
//Do any other positioning of the view you would like
NSString *path = [[NSBundle mainBundle] pathForResource:#"p0600c0100cmpintro" ofType:#"m4v"];
NSURL *url = [NSURL fileURLWithPath:path];
MPMoviePlayerController *movie = [[MPMoviePlayerController alloc] initWithContentURL:url];
movie.view.frame = movieContainer.bounds; //Make sure this is the bounds of its parent view
movie.scalingMode = MPMovieScalingModeFill;
movie.controlStyle = MPMovieControlStyleNone;
movie.shouldAutoplay = YES;
[movieContainer addSubview:movie.view];
[self.view addSubview:movieContainer];
[movieContainer release];
}
One last suggestion would be to keep a reference of the movie so that you can dealloc it once the view controller gets deallocated
I would suggest creating your MoviePlayer in viewDidLoad, then in viewDidAppear make the movie play, for best results.
Alright, so I have another MPMoviePlayerController instance which was being deallocated earlier, but when I try to create another instance of MPMoviePlayerController, all the messages sent to this one were being sent to the deallocated instance, resulting in the memory problem. So I just removed the part where I released the first instance, and it works perfectly fine. My question now is this: is there a way to deallocate this first instance so that it isn't a burden on memory when it isn't needed? I feel that there should be a more elegant solution to this problem. I will need to play videos frequently in this application.
I found the solution a number of weeks ago and forgot about this post. I wasn't successfully releasing the MPMoviePlayerController. For those curious, in order to release an MPMoviePlayerController, we must first remove the notification from the NSNotificationCenter (if one was set), stop the movie (even if it's done playing), THEN release it. I wasn't doing this earlier in the application with my first MPMoviePlayerController, so it was trying to reference the deallocated instance. When the movie is done playing, here is the code to release the movie successfully:
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackStateDidChangeNotification object:movie];
[movie.view removeFromSuperview];
[movie stop];
[movie release];

MPMoviePlayerController: How can I make my video loop?

Thank you in advance for any help, I am a newbie and would appreciate any help here..
I have this code to play a movie and it works great. Can somebody PLEASE tell me how to make this movie loop and replay from the beginning non stop ( any code would help). Also I would like to know how to play 2 movies, one after the other, preferably with a fade or smooth transition. Thank you for any help
#import "MyAppViewController.h"
#implementation MyAppViewController
-(IBAction)button:(id)sender{
NSString *path = [[NSBundle mainBundle]
pathForResource:#"mymovie" ofType:#"mp4"];
player = [[MPMoviePlayerViewController alloc]
initWithContentURL:[NSURL fileURLWithPath:path]];
[self presentMoviePlayerViewControllerAnimated:player];
}
Set the repeatMode property of your MPMoviePlayerController to MPMovieRepeatModeOne
player = [[MPMoviePlayerViewController alloc]
initWithContentURL:[NSURL fileURLWithPath:path]];
player.moviePlayer.repeatMode = MPMovieRepeatModeOne;
MPMovieRepeatModeOne is nice but it doesn't loop the video very smoothly. Try this below (copied from another post) :
(I just got this working on my iPad 3 running iOS 5.1.1, base SDK iOS 5.1.)
When setting up the movie player, set the repeat mode to MPMovieRepeatModeNone then add the notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.moviePlayer];
Then set up your selector to filter when the movie finishes playing:
- (void)moviePlayerDidFinish:(NSNotification *)note
{
if (note.object == self.moviePlayer) {
NSInteger reason = [[note.userInfo objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] integerValue];
if (reason == MPMovieFinishReasonPlaybackEnded)
{
[self.moviePlayer play];
}
}
}
For the timer you can create an Int variable that has the value of your slider and then use a performSelector afterDelay:
int delayInt = 8; // Substitute the 8 for the value of your slider
[self performSelector:#selector(myMethod) withObject:nil afterDelay:delayInt];
And then in your "myMethod"
-(void) myMethod{
//the code to stop your player and remove view controller
}