Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to restore the audio session after an audio interruption in iOS 7?

In iOS 7, after my audio interruption listener gets called, any attempt to restore the audio session seems to fail silently.

My interruption listener calls

NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive:YES error:&activationError];

But the app's audio session is dead as soon as the alarm clock rings. The listener gets called with appropriate begin and end states.

It worked just fine on iOS 6.

I have heard that this is a bug in iOS 7 and that there is a workaround, but can't find it.

Does anyone know a link to a workaround or Technical Note from Apple?

EDIT: I found that I HAVE to use AVAudioSessionCategoryPlayback instead of kAudioSessionCategory_AmbientSound. Now it works. But it is not the category I wanted.

like image 895
openfrog Avatar asked Nov 01 '22 11:11

openfrog


2 Answers

Based on Apple's Audio session programming guide, you should listen and react to changes in your interruption handler. This means that your code can/should handle the end of the interruptions too, based on the received parameter interruptionState.

Check out "Audio Interruption Handling Techniques" on this link, I think it will help you a lot: https://developer.apple.com/library/ios/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/HandlingAudioInterruptions/HandlingAudioInterruptions.html

Good luck, Z.

like image 95
Zoltán Avatar answered Nov 14 '22 14:11

Zoltán


You can see my code below. But First,

You should select this bit target | Background Modes | Audio, Airplay and Picture in Picture from Capabilities.

//  ViewController.m
//  AVAudioPlayer

#import "ViewController.h"

@import AVFoundation;
@import MediaPlayer;

@interface ViewController ()

@property (strong, nonatomic) AVAudioPlayer *audioPlayer;
@property (weak, nonatomic) IBOutlet UISlider *volumeSlider;
@property (weak, nonatomic) IBOutlet UISlider *rateSlider;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self setupAudio];
}

- (void) setupAudio {
    NSError *error;
    [[AVAudioSession sharedInstance] setActive:YES error:&error];
    if (error != nil) {
        NSAssert(error == nil, @"");
    }

    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
    if (error != nil) {
        NSAssert(error == nil, @"");
    }

    NSURL *soundURL = [[NSBundle mainBundle] URLForResource:@"SoManyTimes" withExtension:@"mp3"];
    self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:&error];
    if (error != nil) {
        NSAssert(error == nil, @"");
    }

    //[self.audioPlayer setVolume:0.8];
    self.audioPlayer.enableRate = YES;
    [self.audioPlayer prepareToPlay];
    [self.audioPlayer setVolume:self.volumeSlider.value];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioInterrupt:) name:AVAudioSessionInterruptionNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChanged:) name:AVAudioSessionRouteChangeNotification object:nil];

    MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
    [commandCenter.playCommand addTarget:self action:@selector(playButtonPressed:)];
    [commandCenter.stopCommand addTarget:self action:@selector(stopButtonPressed:)];
    [commandCenter.pauseCommand addTarget:self action:@selector(stopButtonPressed:)];

}

- (void) audioRouteChanged:(NSNotification*)notification {
    NSNumber *reason = (NSNumber*)[notification.userInfo valueForKey:AVAudioSessionRouteChangeReasonKey];
    switch ([reason integerValue]) {
        case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
        case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
            [self stopButtonPressed:nil];
            break;

        default:
            break;
    }
}

- (void) audioInterrupt:(NSNotification*)notification {
    NSNumber *interruptionType = (NSNumber*)[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey];
    switch ([interruptionType integerValue]) {
        case AVAudioSessionInterruptionTypeBegan:
            [self stopButtonPressed:nil];
            break;
        case AVAudioSessionInterruptionTypeEnded:
        {
            if ([(NSNumber*)[notification.userInfo valueForKey:AVAudioSessionInterruptionOptionKey] intValue] == AVAudioSessionInterruptionOptionShouldResume) {
                [self playButtonPressed:nil];
            }
            break;
        }
        default:
            break;
    }
}

- (IBAction)playButtonPressed:(id)sender {
    BOOL played = [self.audioPlayer play];
    if (!played) {
        NSLog(@"Error");
    }

    MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:@"CoverArt"]];

    NSDictionary *songInfo = @{

                               MPMediaItemPropertyTitle:@"So Many Times",
                               MPMediaItemPropertyArtist:@"The Jellybricks",
                               MPMediaItemPropertyAlbumTitle:@"Soap Opera",
                               MPMediaItemPropertyArtwork:albumArt,
                               MPMediaItemPropertyPlaybackDuration:@(self.audioPlayer.duration),
                               MPNowPlayingInfoPropertyElapsedPlaybackTime:@(self.audioPlayer.currentTime),

                               };

    [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo];

}

- (IBAction)stopButtonPressed:(id)sender {
    [self.audioPlayer stop];
}

- (IBAction)volumeSliderChanged:(UISlider*)sender {
    [self.audioPlayer setVolume:sender.value];
}

- (IBAction)rateSliderChanged:(UISlider*)sender {
    [self.audioPlayer setRate:sender.value];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void) dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end
like image 34
Durul Dalkanat Avatar answered Nov 14 '22 15:11

Durul Dalkanat