ios remote sometimes defaults to native music player instead of my app - iphone

About 1 in 20 times my app (after launch) does not seems to 'beginReceivingRemoteControlEvents' and hence the ios remote defaults to the native music player. Because of this my app has been rejected (at an update, not initial release), the thing is I can never see it happen when the iPhone is plugged into mac and xcode only when running the app on the phone, below is my audio initialization routine.
Hope someone can help, thanks Mike.
-(void)viewDidAppear:(BOOL)animated
{
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
[[AVAudioSession sharedInstance] setDelegate: self];
//Set the audio category of this app to playback.
NSError *setCategoryError = nil; [[AVAudioSession sharedInstance]
setCategory: AVAudioSessionCategoryPlayback error: &setCategoryError];
if (setCategoryError)
{
ShowMessageBox(#"Audio error", #"Category failed");
}
//Activate the audio session
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
if (activationError) {
ShowMessageBox(#"Audio error", #"Activate failed");
}
}
// And also
- (BOOL)canBecomeFirstResponder
{
return YES;
}

Related

kAudioSessionProperty_OtherAudioIsPlaying Always Returns True

I have followed as many different examples as I can, most of them in the Apple documentation, but I cannot find out the reason why kAudioSessionProperty_OtherAudioIsPlaying always returns a positive on my devices.
I have initialized and activated the session, yet it still returns positives when my music is paused.
Here is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
AVAudioSession* session = [AVAudioSession sharedInstance];
NSError *activationError = nil;
BOOL success = [session setActive: YES error: &activationError];
if (!success) { NSLog(#"%#", activationError); }
UInt32 otherAudioIsPlaying;
UInt32 propertySize = sizeof (otherAudioIsPlaying);
AudioSessionGetProperty (
kAudioSessionProperty_OtherAudioIsPlaying,
&propertySize,
&otherAudioIsPlaying
);
if (otherAudioIsPlaying) {
[session setCategory: AVAudioSessionCategoryAmbient error: nil];
} else {
[session setCategory: AVAudioSessionCategorySoloAmbient error: nil];
}
}
What am I doing wrong?
I had the same problem, managed to fix it by ensuring that an AVAudiosession has been instantiated BEFORE checking the property as follows:
AVAudioSession *session = [AVAudioSession sharedInstance];
Make sure that this occurs before you attempt to check before any other audio is playing and it should work fine :)

AVPlayer doesn't resume playback on endinterruption on iPhone but does so on iPad

I'm writing a radio app for both iPhone and iPad and am running into some weird behaviour when handling pausing and playing the audio with interruptions. I'm using the AVAudioSessionDelegate methods beginInterruption and endInterruption to respectively pause and play the AVPlayer. Below is the relevant play code.
Now, the following situations seem to happen consistently:
On iPad: If I force an interruption (Facetime call), beginInterruption is called as expected and playback stops. If the interruption stops, endInterruption is called as expected, and the playback resumes as expected.
On iPhone: Pressing the play and pause button, triggers pause and play exactly the same as beginInterruption and endInterruption would. Playback behaves as expected.
On iPhone: Forcing an interruption (by calling the phone), calls endInterruption as expected and playback pauses as expected. However, when the interruption is finished, beginInterruption is called as expected, play is called as expected, it actually reaches and executes the [self.player play] line, but playback does not resume! I hear nothing.
Situation 3 above is extremely weird, so I'm wondering if I may have overlooked something. Any ideas?
Play code
- (void)play {
NSError* error = nil;
AVKeyValueStatus keyStatus = [currentAsset statusOfValueForKey:#"tracks" error:&error];
if(error){
DLog(#"Error %#", [error localizedDescription]);
}
else {
DLog(#"Current Key Status: %i", keyStatus);
if(keyStatus == AVKeyValueStatusLoaded){
DLog(#"Continue playing source: %#", self.source);
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
if (error) {
DLog(#"Error during play while setting AVAudioSessionCategory: %#", [error localizedDescription]);
}
[[AVAudioSession sharedInstance] setActive:YES error:&error];
if (error) {
DLog(#"Error during play while setting AVAudioSessionCategory: %#", [error localizedDescription]);
}
[[AVAudioSession sharedInstance] setDelegate:self];
if(backgroundTaskID != UIBackgroundTaskInvalid){
[[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID];
}
backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
[self.player play];
[self setStatus:kNPOMediaPlayerStatusPlaying];
}
else {
DLog(#"PlaySource: %#", self.source);
[self playSource:self.source];
}
}}
I had the same issue. Issue disappeared after I implemented remote control event handling. I called [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];when starting playback.
It turns out that this is a known bug in iOS, which requires some careful work-arounds in the applicationDidBecomeActive to handle beginInterruption. Sadly, I couldn't figure out another solution.

How to play even background mode using MPMoviePlayerController

Audio Live Streaming Service using IIS7 is prepared.
Audio Live streaming server setting is very complex, but have succeeded.
I obtained a URL for streaming like this(#"http://xxx.xxx.xx.xx/liveStream.isml/manifest(format=m3u8-aapl).m3u8").
My using code is unexpectedly simple.
self.theURL = [NSURL URLWithString:#"http://xxx.xxx.xx.xx/liveStream.isml/manifest(format=m3u8-aapl).m3u8"];
if(moviePlayer == nil)
{
moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:theURL];
}
[moviePlayer play];
Hm... I can't control music player as I wished.
Question is like this.
I don't want to stop to play music even though backgroundMode.
Please tell me some advice. Thanks.
please check in only device.I have also done in my Application. My code is given below.i am talking about iOS5
And in plist i made an array named "Required background mode" and insert an item in array name, "App Plays Audio". some times URL problem is occurs check this URL MPMoviePlayer sound working in Simulators and ipad device, but not Working in iPhone Device
- (void)viewDidLoad
{
[super viewDidLoad];
NSError *setCategoryErr = nil;
NSError *activationErr = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: &setCategoryErr];
[[AVAudioSession sharedInstance] setActive: YES error: &activationErr];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
}

How to resume AVAudioPlayer after interrupted in background

I am playing music using AVAudioPlayer in background. The problem is: if there is a incoming calling interrupts the player, it will never resume unless switch to foreground and do it manually.
The code is simple, to play it in background:
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayAndRecord error: nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
url = [[NSURL alloc] initFileURLWithPath:...];
audio_player = [[AVAudioPlayer alloc] initWithContentsOfURL: url error:NULL];
audio_player.delegate = self;
bool ret = [audio_player play];
delegate to handle interruptions:
-(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
{
//tried this, not working [[AVAudioSession sharedInstance] setActive: NO error: nil];
NSLog(#"-- interrupted --");
}
//----------- THIS PART NOT WORKING WHEN RUNNING IN BACKGROUND ----------
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player
{
NSLog(#"resume!");
//--- tried, not working: [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayAndRecord error: nil];
//--- tried, not working: [[AVAudioSession sharedInstance] setActive: YES error: nil];
//--- tried, not working: [audio_player prepareToPlay];
[audio_player play];
}
Can any one help me?
Found the solution!
I had the same problem, my app was resuming the audio nicely after an interruption, only if my app was open. When it was on the background it failed ro resume playing the audio after an interruption.
I fixed this by adding the following lines of code:
Add this line whenever your app start playing audio.[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
And on the endInterruption method, wait 1 or 2 seconds before resume playing the audio. This to allow the OS to stop using the audio channel.
- (void)endInterruptionWithFlags:(NSUInteger)flags {
// Validate if there are flags available.
if (flags) {
// Validate if the audio session is active and immediately ready to be used.
if (AVAudioSessionInterruptionFlags_ShouldResume) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1), dispatch_get_main_queue(), ^{
// Resume playing the audio.
});
}
}
}
You can also add this line when your app stops (not pause) playing audio. But is not required.
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
Try this
-(void)audioPlayerEndInterruption:(AVAudioPlayer *)audioPlayer withFlags:(NSUInteger)flags{
if (flags == AVAudioSessionFlags_ResumePlay) {
[audioPlayer play];
}
Hope it helps.

playing background audio on iphone

How can I play a background audio while my application is running?
Thanks.
Okay. This is a solution for background sound on iOS4 & iOS5 (definitely works up to iOS 5.0.1), and I have tested it only with AVPlayer. It should probably work for MPMusicPlayerController too.
Required frameworks:
AVFoundation.framework
AudioToolbox.framework
In your Info.plist, for the key UIBackgroundModes, add audio.
In MyAppDelegate.h:
reference <AVFoundation/AVFoundation.h> & <AudioToolbox/AudioToolbox.h>
implement the protocol AVAudioSessionDelegate:
#interface MyAppDelegate : NSObject <UIApplicationDelegate, AVAudioSessionDelegate>
define a method ensureAudio:
// Ensures the audio routes are setup correctly
- (BOOL) ensureAudio;
In MyAppDelegate.m:
implement the ensureAudio method:
- (BOOL) ensureAudio
{
// Registers this class as the delegate of the audio session (to get background sound)
[[AVAudioSession sharedInstance] setDelegate: self];
// Set category
NSError *categoryError = nil;
if (![[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&categoryError]) {
NSLog(#"Audio session category could not be set");
return NO;
}
// Activate session
NSError *activationError = nil;
if (![[AVAudioSession sharedInstance] setActive: YES error: &activationError]) {
NSLog(#"Audio session could not be activated");
return NO;
}
// Allow the audio to mix with other apps (necessary for background sound)
UInt32 doChangeDefaultRoute = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(doChangeDefaultRoute), &doChangeDefaultRoute);
return YES;
}
in the application:didFinishLaunchingWithOptions: method, before you assign the root view controller, run [self ensureAudio]:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Configure audio session
[self ensureAudio];
// Add the navigation controller's view to the window and display.
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
implement the AVAudioSessionDelegate methods like this:
#pragma mark - AVAudioSessionDelegate
- (void) beginInterruption
{
}
- (void) endInterruption
{
// Sometimes the audio session will be reset/stopped by an interruption
[self ensureAudio];
}
- (void) inputIsAvailableChanged:(BOOL)isInputAvailable
{
}
ensure that your app continues to run in the background. You can use the ol' [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler] if you want, but I think there are better ways.
play the actual audio (note I'm using ARC, that's why there are no release calls):
NSURL * file = [[NSBundle mainBundle] URLForResource:#"beep" withExtension:#"aif"];
AVURLAsset * asset = [[AVURLAsset alloc] initWithURL:file options:nil];
AVPlayerItem * item = [[AVPlayerItem alloc] initWithAsset:asset];
__block AVPlayer * player = [[AVPlayer alloc]initWithPlayerItem:item];
__block id finishObserver = [[NSNotificationCenter defaultCenter] addObserverForName:AVPlayerItemDidPlayToEndTimeNotification
object:player.currentItem
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
[[NSNotificationCenter defaultCenter] removeObserver:finishObserver];
// Reference the 'player' variable so ARC doesn't release it until it's
// finished playing.
player = nil;
}];
// Trigger asynchronous load
[asset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:#"tracks"] completionHandler:^{
// Start playing the beep (watch out - we're not on the main thread here)!
[player play];
}];
And it shooooooooooooould work!
If you are using your app also for recording - then don't forget to change setCategory to AVAudioSessionCategoryPlayAndRecord. In other case you won't be able to record
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayAndRecord error:&setCategoryErr];