近期处理了一个挂断电话后,莫名手机开始播放音乐的Bug。 所以顺便在这总结一下,对于IOS的AudioSession中断的几种处理情况。

一、通过C语言的init方法配置interruptionl回调。建议用这种方法,但有些细节需要注意,后续会谈到。

AudioSessionInitialize (
NULL, //
NULL, //
interruptionListenerCallback, //
userData //
);

然后在回调,实现如下逻辑代码:

void interruptionListenerCallback ( void *inUserData,  UInt32  interruptionState ) {
AudioViewController *controller = (AudioViewController *)inUserData;
if (interruptionState == kAudioSessionBeginInterruption) {
if (controller.audioRecorder) {
[controller recordOrStop: (id) controller];
} else if (controller.audioPlayer) {
[controller pausePlayback];
controller.interruptedOnPlayback = YES;
}
} else if ((interruptionState == kAudioSessionEndInterruption) && controller.interruptedOnPlayback) {
[controller resumePlayback];
controller.interruptedOnPlayback = NO;
}
}

二、使用AVAudioSessionDelegate。如果你使用的是AVAudioPlayer或AVAudioRecorder,还可以使用对应的AVAudioPlayerDelegate和 AVAudioRecorderDelegate。但AVAudioSessionDelegate在6.0后被弃用,所以使用有局限性。后者没有被弃用。

- (void) beginInterruption {
if (playing) {
playing = NO;
interruptedWhilePlaying = YES;
[self updateUserInterface];
}
}
NSError *activationError = nil;
- (void) endInterruption {
if (interruptedWhilePlaying) {
BOOL success = [[AVAudioSession sharedInstance] setActive: YES error: &activationError];
if (!success) { /* handle the error in activationError */ }
[player play];
playing = YES;
interruptedWhilePlaying = NO;
[self updateUserInterface];
}
}

三、如上所说,6.0弃用了AVAudioSessionDelegate。所以6.0之后使用AVAudioSessionInterruptionNotification来实现类似的功能。AVAudioSessionInterruptionNotification的userInfo中包括AVAudioSessionInterruptionTypeKey和AVAudioSessionInterruptionTypeEnded。

四、使用RouteChange的回调。对于音乐播放,如果当然当前是耳机模式,拔掉耳机一般是希望音乐暂停的。类似这种拔插设备,播放语音等声音设备切换,一般通过RouteChange的回调来控制。

注册RouteChange的回调:

   AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange,audioRouteChangeListenerCallback,nil);

回调处理代码:

void audioRouteChangeListenerCallback(void *inUserData, AudioSessionPropertyID inPropertyID, UInt32 inPropertyValueSize, const void *inPropertyValue) {
if (inPropertyID != kAudioSessionProperty_AudioRouteChange)
return; CFDictionaryRef routeChangeDictionary = inPropertyValue;
CFNumberRef routeChangeReasonRef = CFDictionaryGetValue (routeChangeDictionary, CFSTR(kAudioSession_AudioRouteChangeKey_Reason)); CFStringRef oldRouteRef = CFDictionaryGetValue (routeChangeDictionary,
CFSTR (kAudioSession_AudioRouteChangeKey_OldRoute));
NSString *oldRouteString = (NSString *)oldRouteRef; SInt32 routeChangeReason;
CFNumberGetValue (routeChangeReasonRef, kCFNumberSInt32Type, &routeChangeReason);
if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) {
if (oldRouteStringplaying ) { //需判断不可用Route为耳机时
playing = NO;
interruptedWhilePlaying = NO; //清除中断标识,如电话中拔掉耳机挂断时,不需要继续播放
}
}
}

对于AudioSession的Route,有如下几种模式:

/* Known values of route:
*"Headset"
* "Headphone"
* "Speaker"
* "SpeakerAndMicrophone"
* "HeadphonesAndMicrophone"
* "HeadsetInOut"
* "ReceiverAndMicrophone"
* "Lineout"
*/ //ios5以后可使用的一些类型
const CFStringRef kAudioSessionOutputRoute_LineOut;
const CFStringRef kAudioSessionOutputRoute_Headphones;
const CFStringRef kAudioSessionOutputRoute_BluetoothHFP;
const CFStringRef kAudioSessionOutputRoute_BluetoothA2DP;
const CFStringRef kAudioSessionOutputRoute_BuiltInReceiver;
const CFStringRef kAudioSessionOutputRoute_BuiltInSpeaker;
const CFStringRef kAudioSessionOutputRoute_USBAudio;
const CFStringRef kAudioSessionOutputRoute_HDMI;
const CFStringRef kAudioSessionOutputRoute_AirPlay;

关于其他的一些总结:

1、对于SDK6.0,AudioSession中断是一个Bug版本。不会响应AVAudioSessionDelegate,且不响应AVAudioSessionInterruptionNotification。C语言中断,当使用AVPlayer后,不响应kAudioSessionBeginInterruption,但响应kAudioSessionEndInterruption。 这是苹果的Bug。对上这种Case,有如下处理办法:

  1)当收到kAudioSessionEndInterruption时,调用暂停播放更新UI。

  2)使用RouteChange来判断电话的接通和挂断情境。但如果是耳机模式,电话的接通和挂断,经测试,使用的是同一种Route。所以,对于SDK6.0,播放过程中未接耳机时,可通过RouteChange来恢复播放。而耳机模式播放时,来电恢复播放,目前看来无完善的处理方式。

2、当后台播放歌曲时,打开游戏之类APP,声道会被其APP占用。这种Case会有kAudioSessionBeginInterruption。但返回时不会有kAudioSessionEndInterruption。所以,这种Case在回到APP时,需要interruptedWhilePlaying这个变量重置。

Audio Session Interruption的更多相关文章

  1. IOS Audio session

    iOS实现长时间后台的两种方法:Audio session和VOIP socket 十二月 04 我们知道 iOS 开启后台任务后可以获得最多 600 秒的执行时间,而一些需要在后台下载或者与服务器保 ...

  2. AVAudioSession(2):定义一个 Audio Session

    本文转自:AVAudioSession(2):定义一个 Audio Session | www.samirchen.com 本文内容主要来源于 Defining an Audio Session. A ...

  3. audio session config

    #pragma mark - #pragma mark - audio session config - (void)setAudioSessionConfig { NSError *error; A ...

  4. AVAudioSession(3):定制 Audio Session 的 Category

    本文转自:AVAudioSession(3):定制 Audio Session 的 Category | www.samirchen.com 本文内容主要来源于 Working with Catego ...

  5. AVAudioSession(1):iOS Audio Session 概览

    本文转自:AVAudioSession(1):iOS Audio Session 概览 | www.samirchen.com 本文内容主要来源于 Audio Session Programming ...

  6. Audio Session Programming Guide

    http://www.cocoachina.com/ios/20150615/12119.html

  7. iOS播放器 - AVAudioPlayer

    今天记录一下AVAudioPlayer,这个播放器类苹果提供了一些代理方法,主要用来播放本地音频. 其实也可以用来播放网络音频,只不过是将整个网络文件下载下来而已,在实际开发中会比较耗费流量不做推荐. ...

  8. iOS -- AVAudioPlayer播放音乐

    一. AVAudioPlayer:                          声明音乐控件AVAudioPlayer,必须声明为全局属性变量,否则可能不会播放,AVAudioPlayer只能播 ...

  9. AVFoundation 框架初探究(一)

    夜深时动笔 前面一篇文章写了视频播放的几种基本的方式,算是给这个系列开了一个头,这里面最想说和探究的就是AVFoundation框架,很想把这个框架不敢说是完全理解,但至少想把它弄明白它里面到底有什么 ...

随机推荐

  1. 将类似 12.56MB 36.89KB 转成 以K为单位的数字【备忘】

    select case RIGHT(RESOURCE_SIZE,2) when 'MB' THEN SUBSTRING_INDEX(RESOURCE_SIZE,'MB',1)*1024 ELSE SU ...

  2. 【BZOJ】1987: Zju2672 Fibonacci Subsequence

    题意 给出一个序列\(A\),求一个最长的满足fib性质的子序列,输出其长度及其元素(如果多种方案,输出位置最靠前的).(\(n \le 3000\)) 题解 容易想到dp,即\(d(i, j)\)表 ...

  3. Ubuntu Gnome 14.04.2 lts 折腾笔记

    unity感觉不爽,于是来折腾gnome3 = = 首先去官网下载ubuntu gnome 14.04.2 lts的包(种子:http://cdimage.ubuntu.com/ubuntu-gnom ...

  4. AIX日常维护

    1  /etc/security/limits与limit命令 AIX 5.3上 下面是文件/etc/security/limits文件里面有关软限制和硬限制的部分. * * Sizes are in ...

  5. 关于SASS--->推荐使用

    作为前端(html.javascript.css)的三大马车之一的css,一直以静态语言存在,HTML5火遍大江南北了.javascript由于NODE.JS而成为目前前后端统一开发语言的不二之选.只 ...

  6. Flex与.net进行URL参数传递编码处理

    在JS中用到的三种编码方式escape 对应于Flex中是一样的,并且支持相互的解码 var a:String = "超越梦想#"; trace(escape(a)); //%u8 ...

  7. signal(SIGPIPE, SIG_IGN)

    文章来源:http://blog.163.com/niuxiangshan@126/blog/static/170596595201221942952676/   当服务器close一个连接时,若cl ...

  8. [LintCode] 3Sum 三数之和

    Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all un ...

  9. ETL

     1.ETL的定义 ETL分别是“Extract”.“ Transform” .“Load”三个单词的首字母缩写也就是“抽取”.“转换”.“装载”,但我们日常往往简称其为数据抽取. ETL是BI/DW ...

  10. Ajax请求中的Redirect()

    页面中有一个IsLogin()方法,用以判断该请求的触发者是否登录,如果登录了,则执行查询操作,如果没有登录,则Redirect()至登录界面 页面使用了较多的Ajax请求来获取数据,而在Ajax请求 ...