近期处理了一个挂断电话后,莫名手机开始播放音乐的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. windows下cmd时复制dos中的内容 错误信息等

    16:28 2015/11/23小发现 windows下cmd时复制dos中的内容,错误信息等:鼠标右键选择标记,然后ctrl c 即可.

  2. 通过data:image/png;base64把图片直接写在src里

    从网上下了个源文件查看时候发现了引用图片的地址不是在本地上的,而是后面跟了一大串字符data:image/png;base64...查了一下资料分析如下: 关于用base64存储图片 网页上有些图片的 ...

  3. 【noiOJ】p8211 (PS:二分浮点数的精度问题)

    05:派 查看 提交 统计 提问 总时间限制:  1000ms 内存限制:  65536kB 描述 我的生日要到了!根据习俗,我需要将一些派分给大家.我有N个不同口味.不同大小的派.有F个朋友会来参加 ...

  4. 【bzoj3160】万径人踪灭 FFT

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3160 我是一个傻叉 微笑脸 #include<bits/stdc++.h> #de ...

  5. 你用java的swing可以做出这么炫的mp3播放器吗?

    这个mp3播放器是基于java的swing编写的,我认为界面还是可以拿出来和大家看一看评一评. 先说说创作的初衷,由于前段时间工作不是很忙,与其闲着,还不如找一些东西来给自己捣腾捣腾,在 之前写的 j ...

  6. HDU 1102 最小生成树裸题,kruskal,prim

    1.HDU  1102  Constructing Roads    最小生成树 2.总结: 题意:修路,裸题 (1)kruskal //kruskal #include<iostream> ...

  7. Java_过滤字符串中非汉子的内容

    /** * 去除“第”之前的所有非汉字内容 */ private String clearNotChinese(String buff){ String tmpString =buff.replace ...

  8. 通过MongoDB的samus驱动实现基本数据操作

    一.MongoDB的驱动 MongoDB支持多种语言的驱动: 在此我们只介绍 C# 的驱动.仅C#驱动都有很多种,每种驱动的形式大致相同,但是细节各有千秋,因此代码不能通用.比较常用的是官方驱动和sa ...

  9. 选择Nodejs的N个理由

    选择Nodejs的N个理由 作者 马德奎 发布于 2014年9月25日 Caleb Madrigal是 来自美国密尔沃基市的一名软件顾问.四年前,他在听说“将JavaScript用作服务器端语言”这样 ...

  10. OpenStack 二次开发环境和开发工具的选择

    OpenStack网上安装教程很多,就不介绍安装了,OpenStack所有组件都安装完后,dashboard web里面进行一些操作,没有报错或提示权限问题,就可以直接下载pycharm或者eclip ...