Audio Session Interruption
近期处理了一个挂断电话后,莫名手机开始播放音乐的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的更多相关文章
- IOS Audio session
iOS实现长时间后台的两种方法:Audio session和VOIP socket 十二月 04 我们知道 iOS 开启后台任务后可以获得最多 600 秒的执行时间,而一些需要在后台下载或者与服务器保 ...
- AVAudioSession(2):定义一个 Audio Session
本文转自:AVAudioSession(2):定义一个 Audio Session | www.samirchen.com 本文内容主要来源于 Defining an Audio Session. A ...
- audio session config
#pragma mark - #pragma mark - audio session config - (void)setAudioSessionConfig { NSError *error; A ...
- AVAudioSession(3):定制 Audio Session 的 Category
本文转自:AVAudioSession(3):定制 Audio Session 的 Category | www.samirchen.com 本文内容主要来源于 Working with Catego ...
- AVAudioSession(1):iOS Audio Session 概览
本文转自:AVAudioSession(1):iOS Audio Session 概览 | www.samirchen.com 本文内容主要来源于 Audio Session Programming ...
- Audio Session Programming Guide
http://www.cocoachina.com/ios/20150615/12119.html
- iOS播放器 - AVAudioPlayer
今天记录一下AVAudioPlayer,这个播放器类苹果提供了一些代理方法,主要用来播放本地音频. 其实也可以用来播放网络音频,只不过是将整个网络文件下载下来而已,在实际开发中会比较耗费流量不做推荐. ...
- iOS -- AVAudioPlayer播放音乐
一. AVAudioPlayer: 声明音乐控件AVAudioPlayer,必须声明为全局属性变量,否则可能不会播放,AVAudioPlayer只能播 ...
- AVFoundation 框架初探究(一)
夜深时动笔 前面一篇文章写了视频播放的几种基本的方式,算是给这个系列开了一个头,这里面最想说和探究的就是AVFoundation框架,很想把这个框架不敢说是完全理解,但至少想把它弄明白它里面到底有什么 ...
随机推荐
- android service 如何弹出dialog
在service中弹出toast,需要使用handler, handler.post(new Runnable() { @Override public void run() { Toast.make ...
- BZOJ4519: [Cqoi2016]不同的最小割
Description 学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成 两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割.对于带权图来说,将 ...
- Controller 通信 发布接收广播
在Angularjs开发一些经验总结随笔中提到我们需要按照业务却分angular controller,避免过大无所不能的上帝controller,我们把controller分离开了,但是有时候我们需 ...
- msnodesql的使用
msnodesql的安装 npm install msnodesql 使用msnodesql写的增删改查 var sql=require('msnodesql'); var conn_str= ...
- java&testng中Assert
用testng中的assert做断言时,如果断言失败,则在当前方法中失败的语句后的语句将不会再执行: 如图: 看控制台输出语句:
- kinderEditor + Struts2整合
环境: kinderEditor4.1.5 Struts2.3.5 Spring3.0.5 Hibernate3.6 代码: FileManageAction package com.hcsoft.p ...
- 用clip剪裁实现半圆
定义和用法 clip 属性剪裁绝对定位元素. 说明 这个属性用于定义一个剪裁矩形.对于一个绝对定义元素,在这个矩形内的内容才可见.出了这个剪裁区域的内容会根据 overflow 的值来处理.剪裁区域可 ...
- [LintCode] Coins in a Line II 一条线上的硬币之二
There are n coins with different value in a line. Two players take turns to take one or two coins fr ...
- android-BaseAdapter自定义控件深刻理解
一.自定义控件的实现 自定义控件需要继承BaseAdapter抽象类,该类实现了ListAdapter, SpinnerAdapter两个接口,这两个接口继承了Adapter接口类,没错.是继承Ada ...
- CCS样式表
一.css样式表 1.样式表分类 1.内联式 <p style="font-size:18px;">This is an apple</p> 2.内嵌样式表 ...