I am optimizing a game so that when there is an incoming call or if it is moved to the background for any other reason, it should stop the music, timers and pause correctly.
It works great other than the fact that for some reason the music doesn't stop playing even though I issued a command for it to stop. What's weirder is that when the game returns to the foreground there's 2 background musics playing instead of one.
Here is my some of my code, nothing too complicated or out of the ordinary:
...
NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;
NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, handleActivate);
NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, handleDeactivate);
...
private function handleActivate(event:Event):void
{
stage.frameRate = previousFrameRate;
//if the music was on when the game is moved to the background, then replay it when its moved back to the foreground
if(musicOn)
{
BGMusic.play();
}
}
private function handleDeactivate(event:Event):void
{
BGMusic.stop();
stage.frameRate = 0;
}
It is worth noting that if I don't replay the music when then game returns to the foreground (i.e. when I don't use BGMuusic.play() in handleActivate), there won't be any music as expected. It is only when I stop the music AND resume it later when moving to the foreground that the background music doesn't stop and I get two playing tracks.
Any ideas? As I said, everything else works fine, and the game correctly pauses. I am testing this on Flash builder Emulator since I don't have the necessarily certificates to test it directly on the iphone. So maybe it is a problem with the emulator itself rather than the code.
Thanks in advance
EDIT: Am writing this with flash and adobe air
Well that was stupid of me. Everything is working fine I just forgot to add another condition to the if statement. So instead of:
if(musicOn)
{
BGMusic.play();
}
It should be
if(musicOn && !BGMusic.isPlaying())
{
BGMusic.play();
}
Everything works fine now...I will change the variable name of musicOn to something clearer like musicButtonOn.
Anyways thanks for help. If you have any tips or comments feel free to tell me =D
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
NSLog(#"Playing stoped");
[player stop];
}
Related
Im playing two tracks in sync. This works well, they sound like one song.
What im trying to do is allow player to switch one track on and of by toggling mute or setting volume to 0 or 1. The muted track continues playing in sync with other track but cant be heard.
But the volume change /muting is lagging. So even if you switch the sound on exactly on beat you wont hear that beat cause it takes a split second for the code to react. There must be a way to make the change instant?
Below is a part of the music manager that handles this. The full code also includes how sound is loaded and starts playing and can be seen here:
https://github.com/Lautaro/AudioTest/blob/master/Assets/MusicManager.cs
// Update is called once per frame
void Update()
{
if (Input.anyKeyDown)
{
if (Input.GetKeyDown(KeyCode.Space))
{
Toggle();
}
}
}
void Toggle()
{
var clip = Sources.First(s => s.clip.name == "ExtraBeat");
// Same result if setting clip.volume instead of mute
clip.mute = !clip.mute;
}
The complete project with audio tracks can be cloned here. Use space to toggle sound.
https://github.com/Lautaro/AudioTest.git
I'm having difficulty pausing the game when I leave and switch back to it.
I'm trying to pause the SKSpriteNode called main, which contains all my sprites, when the view returns from the background. In-game, I can touch the pause button and the game pauses, and the resume button and it resumes.
This is my code:
func didBecomeActive() {
println("didBecomeActive")
main.paused = true
}
The first time this runs is when the app opens for the first time, and everything is paused as it should be. The second time, is when it returns from the background, and suddenly all the animations (SKActions, particles, etc.) start working.
I've confirmed that the method is running, and I've also tried setting main.paused to false and then true, and even self.paused to true. Nothing works.
I'm completely stumped. Anyone know what the issue is here?
Setting self.scene.paused = YES should fix this. I have tried it with a game I am developing and it works fine.
Just set self.scene.paused = YES when the game enters the background, then when it return to the foreground, it should stay paused till you resume it, i.e. set self.scene.paused = NO.
I am using audioPlayerEndInterruption to bring back game music after an 'interruption'.
It seems to work perfectly for all scenarios tested, except:
if a call is received but the caller hangs up (before being answered), the game comes back, but the audio track does not.
As I say, all other call interruption scenarios work, the track does come back. I wonder if this is some kind of iOS bug? Has anyone heard of this problem? Seems strange.
I'm inclined to forget it for the time being, but it is annoying!
My code is like this:
-(void)audioPlayerEndInterruption:(AVAudioPlayer *)player withFlags:(NSUInteger)flags{
if(flags == AVAudioSessionInterruptionFlags_ShouldResume && player != nil){
[player play];
}
}
Would appreciate any advice. Thanks.
Better late than never.
I'm also experiencing this issue. It looks like a bug (at least in ios 5.1) because if all AVAudioPlayers are stopped, and openAL sounds are playing only, AVAudioSession delegate methods are called as expected (yet AVAudioPlayer's do not).
So if AVAudioPlayer is running I use a workaround:
just add to AppDelegate::applicationDidBecomeActive call to your audioPlayerEndInterruption handler with some checks if appropriate (if sound manager exist and so on). This works for me.
Ok I want to disable the idletimer in my app. I put the code below in appdelegate in the applicationDidFinishLaunching method, and it works fine (the device remains unlocked)
[application setIdleTimerDisabled:YES];
Though, when I play a music through MPMusicPlayer methods, the idletimer seems to be enabled back again... and soon the device goes into dimmed mode and soon after, "locked" mode.
I tried to find in google for other methods, but ultimately there are NONE that are effective. I also tried putting the above code in another function and calling that function every seconds using NSTimer when the music is playing, but to no avail. It just won't work.
How can I solve this issue?
Ugh. I hate answering my own questions. But here you go, the answer is here:
How to stop MPMusicPlayerController from enabling screen locking
See the reply from henning. Works like a charm!
I have an audio app in the store. It works fine with versions of the iPhone OS before iOS 4.0. I am working on a new version, starting by bringing the app into compliance with the new iOS multitasking capabilities. (I have iOS 4.0 on my iPhone, and have upgraded to the latest xCode and SDK.)
The result has been a show-stopper.
o When I install the app on the iPhone and run in the debugger, or start the app after the iPhone was powered down, the app acts just fine - playing audio as I push buttons, or restarting audio from "state" that was saved the previous time the app was run.
o If I try to push the Home button and then restart the app from the background, the audio - a and mix of 1-n audio streams - comes out with a stuttering sound that only I could recognize.
o If - while the audio is cleanly - I call the iPhone, I can either answer or decline the call. In both cases the app comes back cleanly, playing as it should.
Note that I am not trying to play anything while in background mode. I simply want to shut things off and bring them back when asked.
Technology: All of the audio logic uses RemoteIO. (I have plans for someday doing some fairly sophisticated signal processing.)
Please excuse the pseudo code narrative - some of the real code is pretty extensive.
MainViewController:
o viewDidLoad - nothing special
o didBecomeActive
set self as audio session delegate;
set the AudioSessionCategory to MediaPlayback;
set the AudioSessionActive;
create a Player (see below);
restart any sounds that were previously playing;
o willResignActive
save the state of what was playing;
stopAllSounds;
stop the player;
set the audio session inactive;
o didEnterBackground - nothing (method is registered, but no content.)
o willEnterForeground - nothing (method is registered, but no content.)
Overview of Player - my class:
The Player is a singleton. I make sure that the singleton instance is destroyed, and a new one created, in didBecomeActive. Instantiating the singleton actually starts the AudioUnit.
constructor
setupRemoteIO;
start
AudioOutputUnitStart;
stop
AudioOutputUnitStop;
player callback
the usual stuff;
>
Here are some methods from my MainViewController:
(void)willResignActive:(NSNotification *)note {
[ self saveState ];
[ [ NaturePlayer getInstance ] stopAllSounds ];
[ [ NaturePlayer getInstance ] stop ];
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: NO error: &activationError];
[NaturePlayer destroy];
}
- (void)didBecomeActive:(NSNotification *)note {
[ self setupAudioSession ];
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
[ self restartSounds ];
[ self setViewState ];
}
- (void)didEnterBackground:(NSNotification *)note {
int xxx = 1;
}
- (void)willEnterForeground:(NSNotification *)note {
int xxx = 1;
}
- (void) applicationWillTerminate: (NSNotification*) notification {
int xxx = 1;
}
Here is a method from the NaturePlayer:
/**
* Stop the playback process.
*/
void NaturePlayerDelegate::stop() {
if (isPlaying_) {
AudioOutputUnitStop(outputUnit_);
isPlaying_ = FALSE ;
}
}
I checked: stop() is being called, and in turn calls AudioOutputUnitStop();
Also checked: The doc on AudioOutputUnitStop says it blocks until all activity has completed.
Hard to say without more details on the audio code. But I suggest you might want to examine your Player object teardown code to make sure the audio unit and the audio session are completely stopped (buffer callback thread drained) before releasing stuff.
Are you initializing and un-initializing AudioUnits within your code? I have recently found an issue that AudioUnits being created and destroyed then leaving and returning to your App will cause stuttering.
I was able to fix this in my application by never uninitializing the AudioUnits.
More info on my problem and my AudioUnit code.
I had the same problem in a project of mine. I found that if I called AudioOutputUnitStop() from a button click before suspending the app, then called AudioOutputUnitStart() when the app resumed, I had no problems. But if I called AudioOutputUnitStop() automatically from the viewDidUnload handler or as a response to the UIApplicationWillResignActiveNotification, I had the stuttering, feedback-like sound described above.
I also noticed that if I stopped the audio unit manually, then suspended the app, the interruption listener was called. But if I suspended the app while the audio unit was still running, the interruption listener was not called. The interruption listener is supposed to stop the audio unit, so that's not doing me much good.
After several hours of tracing this, I found a way to finish my task without audio units, and took them out of my app. So I'm afraid I don't have a complete answer. But hopefully these clues will help someone. I may need to do this again in the future, so I'll check back here to see if someone else has figured it out.