I want to stop my audio app when iOS sleep timer gets called.
Just like Pandora app.
http://help.pandora.com/customer/portal/articles/24324-ios-sleep-timer-with-pandora
Tap the Clock app, Tap Timer, Select a time, Tap When Timer Ends, Tap Stop
Playing
This will sleep your Pandora app if it is running.
I can see inInterruptionState == kAudioSessionBeginInterruption gets called when iOS sleep timer ends, but how can I detect if it's sleep timer or just interruptions like phone call?
Here is my codes.
Currently, my app just starts playing again after iOS sleep timer ends.
// Audio Interruption Listener
void MyInterruptionListener(void *inClientData, UInt32 inInterruptionState) {
if (inInterruptionState == kAudioSessionBeginInterruption) {
[[DOSpeechManager sharedInstance] audioSessionBeginInterruption];
}
if (inInterruptionState == kAudioSessionEndInterruption) {
[[DOSpeechManager sharedInstance] audioSessionEndInterruption];
}
}
- (void)audioSessionBeginInterruption {
if ([_MyAcaTTS isSpeaking] && [_MyAcaTTS isPaused] == NO) {
[_MyAcaTTS pauseSpeakingAtBoundary:AcapelaSpeechImmediateBoundary];
[self setAudioSettionStatus:NO];
_audioInterruptedWhileSpeaking = YES;
}
}
- (void)audioSessionEndInterruption {
if (_audioInterruptedWhileSpeaking) {
[self setAudioSettionStatus:YES];
[_MyAcaTTS continueSpeaking];
}
}
- (void)setAudioSettionStatus:(BOOL)status {
AudioSessionSetActive(status);
[_MyAcaTTS setActive:status];
//cancel audio interrupted flag
if (status) {
_audioInterruptedWhileSpeaking = NO;
}
}
The trick is not to detect the source of the interruption, but to know whether your app should resume after the interruption.
The AVAudioSession API will send a notification when the audio session is interrupted. Within this notification, the OS gives a "hint" as to whether the app should resume playback or not.
See below:
//Add notification observer
__weak typeof(self) weakSelf = self;
self.audioSessionInterruptionNotification =
[[NSNotificationCenter defaultCenter] addObserverForName:AVAudioSessionInterruptionNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
NSNumber* interruptionType = note.userInfo[AVAudioSessionInterruptionTypeKey];
NSNumber* interruptionOption = note.userInfo[AVAudioSessionInterruptionOptionKey];
BOOL shouldResume = interruptionOption.integerValue == AVAudioSessionInterruptionOptionShouldResume;
switch (interruptionType.integerValue) {
case AVAudioSessionInterruptionTypeBegan:
[weakSelf beginInterruption];
break;
case AVAudioSessionInterruptionTypeEnded:
[weakSelf endInterruption:shouldResume];
break;
default:
break;
}
}];
}
Related
I need to check whether the background music is playing every seconds, and if it's not playing, then i will randomly start to play another song.
This method gets called every seconds
- (void)private_checkMusicEnds {
if (NUM_BGMUSIC > 0) {
if ([ModuleHelper audio_isBackgroundMusicEnabled]) {
//ERROR: BACKGROUND MUSIC NOT PLAYING BUT ALWAYS IS PLAYING???
if ([SimpleAudioEngine sharedEngine].isBackgroundMusicPlaying == NO) {
if ([CacheHelper isFirstTimeSetDefaultBGMusic]) {
_currentPlayingMusic = DEFAULT_BGMUSIC_INDEX;
}
else {
//song start at 1
_currentPlayingMusic = [Helper getRandomIntBothInclusiveLow:1 high:NUM_BGMUSIC];
}
NSString *fn = [NSString stringWithFormat:FORMAT_STRING_SONG_FILE_NAME, _currentPlayingMusic];
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:fn loop:NO];
}
}
}
}
When the song is finished playing, [SimpleAudioEngine sharedEngine].isBackgroundMusicPlaying is still YES.
I have also tried [[CDAudioManager sharedManager].backgroundMusic isPlaying] but I get the same.
How do you prevent the Game Center "Welcome Back" message from displaying every time your app wakes up from sleep? Some apps (like Scramble CE, Jetpack Joyride, and Bubblin) handle it correctly (just one welcome message on launch), while others (like Backgammon NJ) don't (welcome message every time the device wakes up).
The block code that's running is no longer in my control (sent to authenticateWithCompletionHandler), and the welcome message appears even if the block is empty anyway.
This behavior started happening with iOS 5.0 (was fine in 4.x), and happens in both the Simulator and real devices, in the Sandbox and not.
Thanks!
I'm from BivisSoft. We've developed Bubblin.
We have a Singleton that controls GameCenter.
Here is our code...
It's based on tutorial by Jacob Gundersen - http://www.raywenderlich.com/5480/beginning-turn-based-gaming-with-ios-5-part-1.
You can try it!
#pragma mark Singleton
static BSGameCenterManager *sharedHelper = nil;
+ (BSGameCenterManager *) sharedInstance {
if (!sharedHelper) {
sharedHelper = [[BSGameCenterManager alloc] init];
}
return sharedHelper;
}
#pragma mark Initializers
- (id)init {
if ((self = [super init])) {
gameCenterAvailable = [self isGameCenterAvailable];
if (gameCenterAvailable) {
self.localPlayerId = #"";
NSNotificationCenter *nc =
[NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(authenticationChanged)
name:GKPlayerAuthenticationDidChangeNotificationName
object:nil];
}
}
return self;
}
// Check if GameCenter is Avaiable
- (BOOL)isGameCenterAvailable {
// check for presence of GKLocalPlayer API
Class gcClass = (NSClassFromString(#"GKLocalPlayer"));
// check if the device is running iOS 4.1 or later
NSString *reqSysVer = #"4.1";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
BOOL osVersionSupported = ([currSysVer compare:reqSysVer
options:NSNumericSearch] != NSOrderedAscending);
return (gcClass && osVersionSupported);
}
#pragma mark Authentication
- (void)authenticationChanged {
if ([GKLocalPlayer localPlayer].isAuthenticated &&
!self.userAuthenticated) {
NSLog(#"GameCenter authentication changed: player authenticated.");
self.userAuthenticated = TRUE;
self.localPlayerId = [[GKLocalPlayer localPlayer] playerID];
[[NSNotificationCenter defaultCenter] postNotificationName: #"gameCenterPlayerAuthenticated" object: nil userInfo: nil];
[self checkNotSentScores];
} else if (![GKLocalPlayer localPlayer].isAuthenticated &&
self.userAuthenticated) {
NSLog(#"GameCenter authentication changed: player not authenticated");
self.userAuthenticated = FALSE;
self.localPlayerId = #"";
}
}
- (void)authenticateLocalUser {
if (!gameCenterAvailable) return;
NSLog(#"GameCenter authenticating local user...");
if ([GKLocalPlayer localPlayer].authenticated == NO) {
[[GKLocalPlayer localPlayer]
authenticateWithCompletionHandler:nil];
} else {
NSLog(#"GameCenter already authenticated!");
}
}
In the Game Kit programming guide I found this bit of documentation:
All games that support Game Center must authenticate the local player
before using any of Game Center’s features. Your game should
authenticate the player as early as possible after launching. Ideally,
authentication should happen as soon as your game can present a user
interface to the player. When your game authenticates a player, Game
Kit first checks to see whether there is already an authenticated
player on the device. If there is an authenticated player, Game Kit
briefly displays a welcome banner to the player.
It doesn't seem as if you can change this behavior with the public API's.
In My app Song play through buffering,
I have two music player in my app,
But it plays both musicplayer songs together. It does not pause the first song even when I try to pause.
i refer this tutorial:
http://cocoawithlove.com/2008/09/streaming-and-playing-live-mp3-stream.html
for that i try to call
[streamer pause];
- (void)pause
{
#synchronized(self)
{
if (state == AS_PLAYING)
{
err = AudioQueuePause(audioQueue);
if (err)
{
[self failWithErrorCode:AS_AUDIO_QUEUE_PAUSE_FAILED];
return;
}
self.state = AS_PAUSED;
}
else if (state == AS_PAUSED)
{
err = AudioQueueStart(audioQueue, NULL);
if (err)
{
[self failWithErrorCode:AS_AUDIO_QUEUE_START_FAILED];
return;
}
self.state = AS_PLAYING;
}
}
}
streamer calls the pause method of buffering.
How can i do that?
if (audioPlayer.playing==YES) {
[audioPlayer pause];
}
try this.
According to Apple's MPMoviePlayerController doc:
MPMoviePlayerPlaybackDidFinishNotification -
This notification is not sent in cases where the movie player is displaying in fullscreen mode and the user taps the Done button.
Seems to me this is dead wrong. Using the code below, playerPlaybackDidFinish gets called when I tap the done button.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playerPlaybackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:self.player];
- (void) playerPlaybackDidFinish:(NSNotification*)notification
{
NSLog(#"WHY?");
self.player.fullscreen = NO;
}
I need to distinguish between the user tapping the done button and the movie finishing all the way through playback. playerPlaybackDidFinish does get called when the movie ends, but like I said it also gets called when you tap Done.
Here is how you check the MPMoviePlayerPlaybackDidFinishReasonUserInfoKey which is part of the notification of MPMoviePlayerPlaybackDidFinishNotification
- (void) playbackDidFinish:(NSNotification*)notification {
int reason = [[[notification userInfo] valueForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
if (reason == MPMovieFinishReasonPlaybackEnded) {
//movie finished playin
}else if (reason == MPMovieFinishReasonUserExited) {
//user hit the done button
}else if (reason == MPMovieFinishReasonPlaybackError) {
//error
}
}
I am using the following to do something when a movie is played all the way to the end:
- (void)playbackDidFinish:(NSNotification*)notification
{
BOOL playbackEnded = ([[[notification userInfo] valueForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue] == MPMovieFinishReasonPlaybackEnded);
BOOL endReached = (self.player.currentPlaybackTime == self.player.playableDuration);
if (playbackEnded && endReached) {
// Movie Ended
}
}
When you get the notification you can check the player's endPlaybackTime. If it's -1 then the movie finished all the way back naturally.
For streamed content, you can check the MPMoviePlayerPlaybackDidFinishReasonUserInfoKey inside the userInfo on the MPMoviePlayerPlaybackDidFinishNotification.
If it's equal to MPMovieFinishReasonUserExited then it's the user stopped playing the content.
Make sure for
moviePlayer.repeatMode = MPMovieRepeatModeNone;
I'm currently working on a project that involves playing music from the iphone music library within the app inside. I'm using MPMediaPickerController to allow the user to select their music and play it using the iPod music player within the iPhone.
However, i ran into problem when the user insert his earpiece and removes it. The music will suddenly stop playing for no reason. After some testing, i found out that the iPod player will pause playing when the user unplug his earpiece from the device. So is there any way to programatically detect if the earpiece has been unplug so that i can resume playing the music? Or is there any way to prevent iPod player from pausing when the user unplug his earpiece?
You should register for AudioRoute changed notification and implement how you want to handle the rout changes
// Registers the audio route change listener callback function
AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange,
audioRouteChangeListenerCallback,
self);
and within the callback, you can get the reason for route change
CFDictionaryRef routeChangeDictionary = inPropertyValue;
CFNumberRef routeChangeReasonRef =
CFDictionaryGetValue (routeChangeDictionary,
CFSTR (kAudioSession_AudioRouteChangeKey_Reason));
SInt32 routeChangeReason;
CFNumberGetValue (routeChangeReasonRef, kCFNumberSInt32Type, &routeChangeReason);
if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable)
{
// Headset is unplugged..
}
if (routeChangeReason == kAudioSessionRouteChangeReason_NewDeviceAvailable)
{
// Headset is plugged in..
}
If you just want to check whether headphones are plugged in at any given time, without listening to route changes, you can simply do the following:
OSStatus error = AudioSessionInitialize(NULL, NULL, NULL, NULL);
if (error)
NSLog("Error %d while initializing session", error);
UInt32 routeSize = sizeof (CFStringRef);
CFStringRef route;
error = AudioSessionGetProperty (kAudioSessionProperty_AudioRoute,
&routeSize,
&route);
if (error)
NSLog("Error %d while retrieving audio property", error);
else if (route == NULL) {
NSLog(#"Silent switch is currently on");
} else if([route isEqual:#"Headset"]) {
NSLog(#"Using headphones");
} else {
NSLog(#"Using %#", route);
}
Cheers,
Raffaello Colasante
I see you are using the MPMediaPlayer Framework however the microphone handling is done using the AVAudioPlayer framework, which you will need to add to your project.
Apple's website has code from the AVAudioPlayer framework which I use to handle interruptions from a user plugging in or removing the Apple microphone headphones.
Check out Apple's iPhone Dev Center Audio Session Programming Guide.
- (void) beginInterruption {
if (playing) {
playing = NO;
interruptedWhilePlaying = YES;
[self updateUserInterface];
}
}
NSError *activationError = nil;
- (void) endInterruption {
if (interruptedWhilePlaying) {
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
[player play];
playing = YES;
interruptedWhilePlaying = NO;
[self updateUserInterface];
}
}
My code is a little different and some of this may help you:
void interruptionListenerCallback (
void *inUserData,
UInt32 interruptionState
) {
// This callback, being outside the implementation block, needs a reference
// to the AudioViewController object
RecordingListViewController *controller = (RecordingListViewController *) inUserData;
if (interruptionState == kAudioSessionBeginInterruption) {
//NSLog (#"Interrupted. Stopping playback or recording.");
if (controller.audioRecorder) {
// if currently recording, stop
[controller recordOrStop: (id) controller];
} else if (controller.audioPlayer) {
// if currently playing, pause
[controller pausePlayback];
controller.interruptedOnPlayback = YES;
}
} else if ((interruptionState == kAudioSessionEndInterruption) && controller.interruptedOnPlayback) {
// if the interruption was removed, and the app had been playing, resume playback
[controller resumePlayback];
controller.interruptedOnPlayback = NO;
}
}
void recordingListViewMicrophoneListener (
void *inUserData,
AudioSessionPropertyID inPropertyID,
UInt32 inPropertyValueSize,
const void *isMicConnected
) {
// ensure that this callback was invoked for a change to microphone connection
if (inPropertyID != kAudioSessionProperty_AudioInputAvailable) {
return;
}
RecordingListViewController *controller = (RecordingListViewController *) inUserData;
// kAudioSessionProperty_AudioInputAvailable is a UInt32 (see Apple Audio Session Services Reference documentation)
// to read isMicConnected, convert the const void pointer to a UInt32 pointer
// then dereference the memory address contained in that pointer
UInt32 connected = * (UInt32 *) isMicConnected;
if (connected){
[controller setMicrophoneConnected : YES];
}
else{
[controller setMicrophoneConnected: NO];
}
// check to see if microphone disconnected while recording
// cancel the recording if it was
if(controller.isRecording && !connected){
[controller cancelDueToMicrophoneError];
}
}
Hey guys just check AddMusic sample app. Will solve all your iPod related issues
First register iPod player for notification with following code
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter
addObserver: self
selector: #selector (handle_PlaybackStateChanged:)
name: MPMusicPlayerControllerPlaybackStateDidChangeNotification
object: musicPlayer];
[musicPlayer beginGeneratingPlaybackNotifications];
And implement the following code in the notification
- (void) handle_PlaybackStateChanged: (id) notification
{
MPMusicPlaybackState playbackState = [musicPlayer playbackState];
if (playbackState == MPMusicPlaybackStatePaused)
{
[self playiPodMusic];
}
else if (playbackState == MPMusicPlaybackStatePlaying)
{
}
else if (playbackState == MPMusicPlaybackStateStopped)
{
[musicPlayer stop];
}
}