ios
ios

Reputation: 6164

iPhone app: not resuming audio session in AVAudio Player

In my iPhone app I am playing music using AVAudioPlayer. When my app runs in background that time also it is running for that I wrote this code

in AppDelegate on

-- application didFinishLaunchingWithOptions

  audioManager= [[AudioManager alloc] init];
  audioManager.delegate=self;
   audioManager.soundFile=[[[NSBundle mainBundle] pathForResource:@"mysong" ofType:@"wav"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  [audioManager setFileForPlay];
  [audioManager.player setNumberOfLoops:-1];
  [audioManager.player setVolume:.5];
  [audioManager play];



 -(void) playerBeginInterruption:(AVAudioPlayer *)p{


[usdef setValue:@"START" forKey:@"LOCATIONMANAGER"];

[locationManager startUpdatingLocation];
[p pause];
// audioManager=nil;

  }

 -(void) playerBeginInterruptionInBackground:(AVAudioPlayer *)p{

 [usdef setValue:@"START" forKey:@"LOCATIONMANAGER"];
[locationManager startUpdatingLocation];
[p pause];
//audioManager=nil;

}

 -(void) playerEndInterruption:(AVAudioPlayer *)p{
 NSLog(@"Inteerpt END");

  [p prepareToPlay];
  [p play];
  [usdef setValue:@"STOP" forKey:@"LOCATIONMANAGER"];



}

 -(void) playerEndInterruptionInBackgroud:(AVAudioPlayer *)p{
  NSLog(@"Inteerpt END BG");
 // [self performSelector:@selector(allocaudioManager)];  
  [p prepareToPlay];
  [p play];

  [usdef setValue:@"STOP" forKey:@"LOCATIONMANAGER"];
  // [locationManager stopUpdatingLocation];

}

Now I have created separate classes for audio manager which handles the delegate methods.

in .h file

  #import <Foundation/Foundation.h>
  #import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
 @protocol AudioManagerDelegate;
 @interface AudioManager : NSObject <AVAudioPlayerDelegate> {
AVAudioPlayer                       *player;

NSString                            *soundFile;
BOOL                                inBackground;
id<AudioManagerDelegate>            delegate;

 }
@property (nonatomic, assign)   id<AudioManagerDelegate>delegate;
@property (nonatomic, retain)   NSString        *soundFile;

@property (nonatomic, assign)   AVAudioPlayer   *player;
@property (nonatomic, assign)   BOOL            inBackground;
 - (void)play;
 - (void)pause;
 - (void)stop;
 - (void)registerForBackgroundNotifications;
 -( void) setFileForPlay;
  @end
  @protocol AudioManagerDelegate <NSObject>
  @optional
   - (void)playerDidFinishPlayingInBackground:(AVAudioPlayer*)p;
  - (void)playerDidFinishPlaying:(AVAudioPlayer*)p;
  - (void)playerBeginInterruption:(AVAudioPlayer*)p;
  - (void)playerBeginInterruptionInBackground:(AVAudioPlayer*)p;
  - (void)playerEndInterruption:(AVAudioPlayer *)p;
   - (void)playerEndInterruptionInBackgroud:(AVAudioPlayer *)p;
 @end

in .m file

    @implementation AudioManager
  @synthesize delegate;
  @synthesize player;
  @synthesize inBackground;
  @synthesize soundFile;
  
   void RouteChangeListener(void *inClientData, AudioSessionPropertyID  inID,UInt32 inDataSize, const void *inData);

 -(id) init
{
     if((self=[super init]))
    {
    
    OSStatus result = AudioSessionInitialize(NULL, NULL, NULL, NULL);
    if (result)
        NSLog(@"Error initializing audio session! %ld", result);
    
    [[AVAudioSession sharedInstance] setDelegate: self];
    NSError *setCategoryError = nil;
    [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: &setCategoryError];
    if (setCategoryError)
        NSLog(@"Error setting category! %@", setCategoryError);
    
    result = AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange, RouteChangeListener, self);
    if (result) 
        NSLog(@"Could not add property listener! %ld", result);
    
    return self;
}
return nil;
 }


 -(void) setFileForPlay{
     self.player=nil;
       player = [[AVAudioPlayer alloc]   initWithData:[NSData dataWithContentsOfFile:self.soundFile] error:nil];//initWithContentsOfURL:[NSURL URLWithString:self.soundFile]  error:nil];

    if (self.player)
     {
          player.delegate = self;
      }

   }


 -(void) play{

  [self.player play];

  }
  -(void)pause{
    [self.player pause];
    NSLog(@"in Pause");
  }
 -(void)stop{
    [self.player stop];
     NSLog(@"in stop");
  }



              void RouteChangeListener(void *inClientData, AudioSessionPropertyID   inID,UInt32 inDataSize, const void *inData){
      AudioManager* This = (AudioManager*)inClientData;

        if (inID == kAudioSessionProperty_AudioRouteChange) {
    
        CFDictionaryRef routeDict = (CFDictionaryRef)inData;
    NSNumber* reasonValue = (NSNumber*)CFDictionaryGetValue(routeDict, CFSTR(kAudioSession_AudioRouteChangeKey_Reason));
    
    int reason = [reasonValue intValue];
    
    if (reason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) {
         
        [This stop];
    }
}

  }
   - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)p successfully:(BOOL)flag
    {
if (flag == NO)
    NSLog(@"Playback finished unsuccessfully");

[p setCurrentTime:0.];
if (inBackground)
{
    [delegate playerDidFinishPlayingInBackground:p];
}
else
{
    [delegate playerDidFinishPlaying:p];
}
    }
     - (void)playerDecodeErrorDidOccur:(AVAudioPlayer *)p error:(NSError *)error
   {
NSLog(@"ERROR IN DECODE: %@\n", error); 
    }
  // we will only get these notifications if playback was interrupted
  - (void)audioPlayerBeginInterruption:(AVAudioPlayer *)p
    {
NSLog(@"Interruption begin ");
// the object has already been paused,  we just need to update UI
if (inBackground)
{
    [delegate playerBeginInterruptionInBackground:p];
}
else
{
    [delegate playerBeginInterruption:p];
}

    }


     - (void)audioPlayerEndInterruption:(AVAudioPlayer *)p withFlags:(NSUInteger)flags
    {
    if(inBackground)
      {
      [delegate playerEndInterruptionInBackgroud:p];
    }
        else
    {
    [delegate playerEndInterruption:p];
    }
        NSLog(@"Interruption ended. Resuming playback");
     }

    - (void)registerForBackgroundNotifications
    {
[[NSNotificationCenter defaultCenter] addObserver:self
                                                    selector:@selector(setInBackgroundFlag)
                                                   name:UIApplicationWillResignActiveNotification
                                             object:nil];

      [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(clearInBackgroundFlag)
                                               name:UIApplicationWillEnterForegroundNotification
                                           object:nil];
  }

 - (void)setInBackgroundFlag
   {
inBackground = true;
   }

- (void)clearInBackgroundFlag
   {
inBackground = false;
   }

   @end

Now the problem is if I am Playing any songs form iPod library and stop the song and closing the iPod library, my original avaudioplayer which was playing before starting ipos library is not resuming means it is not playing song again.

What could be wrong?

Is there any demo project or sample code which can help?

Upvotes: 4

Views: 3416

Answers (1)

Michael Behan
Michael Behan

Reputation: 3443

You shouldn't have to call pause on the AVAudioPlayer (p in your code) in audioPlayerBeginInterruption: the player should not be playing at that stage because of the interruption. In audioPlayerEndInterruption: the following usually works for me:

[p prepareToPlay];
[p play];

The Audio Session Cookbook in the iOS docs has a section on "Handling Interruptions with the AVAudioPlayer Class" that should also help.

Upvotes: 4

Related Questions