IOS AudioSession

来源:互联网 发布:联通大数据公司 编辑:程序博客网 时间:2024/05/18 02:57

文章转载自:http://supershll.blog.163.com/blog/static/37070436201281421849521/

一、概述

用户可能插上耳机、电话可能打来、alarm可能开始响起来。确实,音频环境是非常复杂的。iOS让你通过audio session api让你使用很少的代码来响应这些系统请求。

1、一个Audio Session封装了一组Audio行为
在启动时,应用程序将自动获得一个单例audio Session。

2、Categories代表Audio Roles
最主要的表示audio意图的机制就是设置audio Session category。一个Category是一个key,标识一系列audio行为。通过设置Category,你指示你的audio在屏幕锁定时是否应该继续,你是否想iPod audio与你的audio一同播放,等等。
六个audio Session Category,同一套override和modifier开关,让你个性化audio 行为。不同的Category支持播放、录音、播放与录音,和offline audio 处理。当系统知道了你的app的audio role,这让你可以适当的访问硬件资源。系统还保证设备上的其他audio具有相同的行为;例如,如果你需要iPod audio静音,it is。

3、代理支持中断处理
audio中断是你的应用的audio Session的去激活--它立即停止你的audio。中断发生于一个内置的应用程序的audio Session,并且这个audio Session的Category不能和你的audio Session混合在一起。(也就是说内置的应用的audio Session优先级更高)。当你的audio Session变得不活跃时,系统发送了一个“你被中断了”消息,你可以利用这个消息来保存状态,更新用户界面,等等。
要处理中断,需要实现AV Foundation框架提供的Objective-C中断代理方法。写你的beginInterruption和endInterruption方法来确保最小化破坏,最大化恢复。

4、回调支持Audio Route Change Handling(音频输出变更处理?)
例如插入耳机时,写一个C 回调函数,并注册其到你的Audio Session。

二、Audio Session Basics
阅读这个章节来学习Audio Session能解决什么问题。
1、为什么iOS需要管理Audio?
在你早上去上班的地铁上,你解锁了你的iPhone然后开始听podcast的一段插曲,从内置的扬声器播放。然后你的同座人皱眉了,你只好插上耳机,然后声音转到耳机输出,并且使用你的耳机之前使用的音量开始播放。或许了开始了一个数独游戏,它播放自己的音效,podcast的输出和游戏声音效果混合在了一起。又过了一会,podcast渐渐安静了,因为一个alarm声音响起并且一个alert出现了。你取消了alert。然后podcast渐渐恢复并继续播放。你的数独游戏的声音也继续工作。
一个Audio Session使你能提供无缝的Audio体验。实际上,任何使用AV Foundation Framework,Audio Queue Services,OpenAL,或I/O audio unit的应用都必须使用audio Session Programming Interface来满足Apple的推荐规范。

2、什么是Audio Session?
一个Audio Session是用来配置Audio行为。在启动时,应用程序将自动获得一个单例audio Session。你配置它来表现你的Audio意图,例如:
1)你是否打算混合你的应用的声音和其他应用(例如iPod)的声音,或你是否打算静音其他的Audio?
2)你想你的应用如何响应Audio中断,例如Clock Alarm?
3)当用户插入或拔出耳机时,你的应用要如何响应?
除了你播放的声音效果,Audio Session的配置影响所有的Audio活动---在你的应用运行过程中。你可以查询Audio Session来发现设备的硬件特性---例如声道数(channel count)、采样率(sample rate)、和音频输入的可用性(availability of audio unit)。
你可以显式地激活和去激活你的Audio Session。要播放声音,或录制,Audio Session必须是Active的。系统还可以去激活你的Audio Session--例如当电话来到时或一个alarm响起时,系统会这么做。 这样的去激活被称为Audio Session的中断(Interruption)。Audio session APIs提供了方法来响应中断和从中断中恢复。

3、什么是Audio Session Category?
一个Category是一个key,表示一组Audio行为。通过设置Category,你指示你的audio在屏幕锁定时是否应该继续,你是否想iPod audio与你的audio一同播放,等等。
每个Audio Session Category为下面的行为指定了一各特定的yes和no的值:
1)Allows mixing:如果是yes,其他应用的audio可以在你播放声音时继续播放。
2)Silenced by the Silent switch and by screen locking:如果是yes,当用户切换到静音和屏幕锁定时,你的audio也静音。
3)Supports audio input:如果yes,允许录音
4)Supports audio output:如果yes,允许播放

大多数应用只需要设置一次Category即可,在启动时。这就是说,你可以按照你的需要来更改Category,而且不用贯你的audio Session是否active。如果你的Session是不活跃的,你的Category request在你的Session active时被发送。如果你的Session已经是活跃的,你的Category request就立即呗发送。

4、Audio Session 默认的行为:
一个Audio Session带来了一些默认行为。尤其是:
1)播放是启用的,录音是禁用的。
2)如果用户设置了静音,那么你的Audio也会被静音。
3)手机锁定时,你的Audio被静音。
4)当你的Audio 开始时,设备上的其他Audio--例如iPod Audio正在播放---被静音。

这些行为被封装进AVAudioSessionCategorySoloAmbient Category--默认的Category。
你的Audio Session在应用启动时自动被激活。这允许你播放(录制,如果设置了其他支持录音的Category)。然而,依赖默认的激活是冒险的。例如,如果一个IPhone响铃了,并且用户忽略了这个电话--让你的应用运行--那么你的Audio可能不再播放。

5、为什么默认的Audio Session 通常不是你想要的?
1)如果你需要在屏幕锁定后继续播放声音,使用AVAudioSessionCategoryPlayback Category。
2)如果你需要混合其他应用的Audio,使用AVAudioSessionCategoryAmbient Category。
3)要在中断后继续播放,需要编写中断方法或写一个Audio Session 回调函数来允许你的应用自动继续播放或允许用户手动恢复播放。

6、系统如何解决Audio Demands的竞争?
可以把iPhone想像成一个机场,应用为客机,系统的服务为指挥塔。你的应用发布Audio request并陈述他的希望的优先级,但最终在跑道上的发生的鉴权来自于系统。你通过Audio Session与指挥塔通信。如图所示:
Audio Session Programming Guide - supershll - 记忆里
 
第一步:应用请求Core Audio要激活Audio Session。
第二步:系统考虑激活请求列表。尤其地,他考虑你指定给Audio Session的Category。图示中的Category要求其他应用的Audio静音。
第三步\第四步:系统去激活iPod应用的Audio Session,停止其Audio的播放。
第五步:系统激活你的应用的Audio Session,然后播放可以开始了。

系统遵循“the phone always wins”原则。没有应用,不管它多么尽力地要求优先级,可以战胜phone。当一个电话来到时,用户获得通知并且你的应用被中断--不管什么Audio Operation正在进行,而且不管你设置了什么Category。
为了确保你的Audio不被这些中断(例如电话和Clock alarm)破坏,用户必须调到飞行模式。另一个原则是:”用户,而不是应用,在控制设备“。例如,没有代码的方式来让Clock Alarm静音。要阻止一个Alarm破坏录音,用户必须取消alarm。类似的,也没有代码的方式来设置硬件播放音量。用户总是使用设备侧面的音量按钮来控制硬件音量。

7、两个Audio Session APIs:
1)AVAudioSession类,在AVAudioSession Class Reference中描述。提供了一个Objective-C界面,和其他Objective-C代码协同工作很好。这个API提供访问一组Audio Session的特色。
AVAudioSession有两个关键优势。
第一个优势:当你使用它获得Audio Session的共享实例时,Session被隐式的初始化,使用C API,没有这个初始化。 
第二个优势:你可以使用简单的代理方法来处理audio中断和硬件配置的更改(例如采样率和声道数量的改变)
2)Audio Session Services,在Audio Session Services Reference中描述,是一个C API,提供对Audio Session的所有基本和高级特色的访问。
你需要使用这个API来处理Audio硬件route changes的更改(例如插入耳机),和修改Audio Session Category的默认行为。例如,kAudioSessionProperty_OverrideAudioRoute属性允许你switch playback from the receiver to the speaker---当正在使用“play and record” audio Session Category。这个API还提供了回调函数机制来处理中断。

8、使用 Audio Session APIs开发:
使用模拟器,你不能:
1)调用一个中断
2)更改设置中的静音模式。
3)模拟屏幕锁定
4)模拟耳机的插入
5)查询Audio route信息或测试Audio Session Category行为
6)测试Audio mixing行为--就是说,播放你的Audio的同时播放其他应用的Audio(例如iPod)

要测试你的Audio Session代码的行为,你需要在设备上运行。对于某些使用模拟器时的开发技巧,查阅"Running Your App in the Simulator"。

三、Configuring Your Audio Session:配置你的Audio Session:
1、初始化Audio Session:
在你的应用启动后,系统会自动给你一个Audio Session对象。在使用Session工作前,你必须初始化它。你如何初始化它取决于你想如何处理Audio中断:
1)如果使用AV Foundation框架来管理中断,使用隐式初始化,在你获得一个AVAudioSession对象时,Session就被自动初始化了。如下所示:
AVAudioSession *session=[AVAudioSession sharedInstance];
在你使用AVAudioSession累的中断代理方法来处理Audio中断,或使用AVAudioPlayer和AVAudioRecorder累的代理方法,苹果推荐使用隐式初始化。
2)或者,你可以写一个C 回调函数来处理Audio中断。你必须使用显式初始化Audio Session,使用函数AudioSessionInitialize。一般,你应该在你的应用的main Controller类的初始化方法里初始化Audio Session。

2、激活和去激活Audio Session:
系统在你的应用启动时,自动激活你的Audio Session。但是Apple建议你显式激活你的Session---一般在viewDidLoad方法中。这给你一个机会来测试激活是否成功。同样的,当更改你的Audio Session的active和inactive状态时,检查其来确保调用成功。如果系统拒绝激活你的额Session,你就需要写代码来处理。
系统会在 时钟或日历 alarm或电话来临时 使你的Audio Session无效。当用户取消了alarm或忽略了来电,系统允许你的Session重新被激活。
苹果推荐你使用AVAudioSessionDelegate来实现对中断和恢复的处理。
大多数应用程序不需要显式 无效他们的Audio Session。重要的例外包括VoIP应用的录音应用。
1)VoIP应用,话费大量时间在后台运行,应该确保其Session在应用处理一个call时是活动的。在后台,表示正在准备接听一个电话,VoIP应用的Audio Session应该不是活跃的。
2)使用录音Category的应用应该确保其Audio Session在录音过程中是活跃的。在录音之前和录音停止之后,确保你的Session是不活跃的。或者说,如果你的录音应用还支持播放,那么你应该在没有录音时切换到Playback Category来允许播放。

3、选择最好的Category:
iOS有6个Audio Session Category:
3个用来播放
1个用来录音
1一个支持播放和录音--不需要同时发生,如果需要也是可以的。
1个用来offline Audio processing
要选择最好的Category,考虑下面的因素:
1)最好的Category是最接近支持你的需要的。你想播放、录制,还是两者都做,还是只是指向offline Audio processing?
2)你要播放的Audio对于你的应用来说是必要的还是次要的?如果是必要的,最好的Category就是在Ring/Silent切换到silent时支持播放。如果是次要的,就选择在Ring/Silent切换到silent时你的Audio也静音的Category。
3)在你的应用启动时是否其他的应用(例如iPod audio)正在播放音乐?在启动中检查这个是你能进行分支处理。例如,一个游戏应用可能选择一个Category配置来允许iPod Audio继续播放--如果它已经开始播放了,否则选择一个不同的Category配置来支持内置的app soundtrack。

下面介绍Categories:第一个Category允许其他Audio继续播放;其余的Categories指示你想其他的Audio在你的Audio Session活跃时停止播放。然而,你可以自定义非混合”Playback“和”Play and record“Categories来允许混合。
1)AVAudioSessionCategoryAmbient或kAudioSessionCategory_AmbientSound----允许混合Audio、静音时静音
2)AVAudioSessionCategorySoloAmbient或kAudioSessionCategory_SoloAmbientSound--这是默认的Category,不允许混合
3)AVAudioSessionCategoryPlayback和kAudioSessionCategory_MediaPlayback--静音时不静音
4)AVAudioSessionCategoryRecord或kAudioSessionCategory_RecordAudio--不允许混合
5)AVAudioSessionCategoryPlayAndRecord或kAudioSessionCategory_PlayAndRecord--用在聊天的应用中
6)AVAudioSessionCategoryAudioProcessing或kAudioSessionCategory_AudioProcessing--来执行离线audio处理,而不播放或录音。

通过audio Session的kAudioSessionProperty_OtherAudioIsPlaying属性来在应用启动时检查其他应用的audio有没有正在播放。

4、Category是如何影响encoding和decoding的?
在iOS中,你可以encode未压缩的音频到一组压缩格式。你也可以decode这些格式来播放。
硬件相关的编码器只有在你配置你的audio Session为静音其他audio时才可用。

5、设置和更改audio Session Category:
6、微调Category:
基于Category,你可以:
1)允许其他audio混合你的audio
2)更改audio output route从Receiver到speaker
3)允许bluetooth audio Input
4)制定其他audio在你的audio播放时 其应该减少音量。

你可以覆盖AVAudioSessionCategoryPlayback的non-mixing特性或AVAudioSessionCategoryPlayAndRecord的特性。来执行override,应用kAudioSessionProperty_OverrideCategoryMixWIthOthers属性到你的audio Session。

应用kAudioSessionProerty_OtherMixableAudioShouldDuck属性到你的audio Session。

四、处理Audio中断
1、音频中断处理技术:
有两种技术来响应中断:
1)使用AV Foundation框架提供的Objective-C中断代理方法。在大多数情形下,这个技术是简单而且好用的。
2)使用Audio Session Services使用的C-Based中断回调函数。这需要你 通过使用一个显式Audio Session初始化调用来注册你的回调函数到Audio Session。

使用哪种技术取决于你使用哪种Audio技术和你使用Audio的用途--播放、录制、Audio格式转换、读取流音频包、等等。一般来说,你需要确保最小化的中断破坏,和最大可能的恢复。
下面列出了中断时产生的事件的顺序,当使用AVAudioPlayer或AVAudioRecorder对象时,一些步骤自动被系统处理。
1)在中断开始后:
a)检查是否支持恢复音频过程。
b)保存状态和context
c)更新用户界面

2)在中断结束后:
a)恢复state和context
b)重新激活Audio Session
c)更新用户界面

下面列出了各种技术如何处理Audio中断。
1)使用AV Foundation Framework:AVAudioPlayer和AVAudioRecorder类提供了代理方法来处理中断的开始和结束。
2)使用Audio Queue Services,I/O Audio unit:使用这些技术让你的应用能控制处理中断。你需要负责保存播放或录音位置和重新激活你的Audio Session。实现AVAudioSession中断代理方法或写一个中断监听回调函数。
3)使用OpenAL:当你使用OpenAL播放时,实现AVAudioSession中断代理方法或写一个中断监听回调函数。就像试用Audio Queue Services一样,但是需要在代码里添加管理OpenAL context的代码。
4)使用System Sound Services:System Sound Services播放的声音会在中断开始的时候静音。它们可以在中断结束后自动恢复播放。应用不能控制这种技术的播放的中断行为。

2、中断生命周期:
下图显示了事件发生的顺序。
Audio Session Programming Guide - supershll - 记忆里

3、使用代理方法处理中断:
AVAudioSession 类提供了代理方法,在AVAudioSessionDelegate协议中指定,来响应中断。你可以实现这些方法来响应中断而不管你使用的是哪种技术:
1)beginInterruption:在你的AudioSession被中断后调用。
2)endInterruption:在你的Audio Session中断结束后被调用。如果没有使用AVAudioPlayer或AVAudioRecorder对象(她们会自动重新激活Audio Session),你需要显式重新激活你的Audio Session。

AVAudiorecorer和AVAudioPlayer类提供了它们自己的代理方法来响应中断:
1)audioPlayerBeiginInterruption:
2)audioPlayerEndInterruption:
3)audioRecorderBeginInterruption:
4)audioRecorderEndInterruption:

AVAudioRecorder和AVAudioPlayer在中断时自动暂停。你不需要保存录音和播放位置--除非你想保存它们另作他用。另外,系统自动重新激活audio Session,这让你可以在中断结束后恢复播放和录音。

4、试用一个C 回调函数来处理中断:
如果你选择一个C-language来处理中断,按照AudioSessionInterruptionListener原型来写一个自己的监听回调函数。
当系统调用你的回调时,他发送两个值:一个是你初始化Audio Session时指定的数据的引用,另一个是指示中断状态的常量。下面列出了AudioSessionInterruptionListener回调的原型:
typedef void (*AudioSessionInterruptionListener) (
   void *inClientData,
   UInt32 inInterruptionState
);
有两个中断状态:
1)kAudioSessionBeginInterruption:
2)kAudioSessionEndInterruption:

4、OpenAL和Audio Interruptions:
实现AVAudioSession代理方法。在中断开始后,设置OpenAL的contex为NULL,在中断结束后,设置OpenAL的context为之前的状态。

5、硬件相关的编码器和Audio Interruption:

五、处理Audio Hardware route Changes:
下图列出了不同的route Changes发生于播放和录音时的事件发生的顺序。
Audio Session Programming Guide - supershll - 记忆里
 
1、响应Audio Hardware route Changes:
有3部分来配置你的应用响应route Changes:
1)实现route change时要被调用的方法。
2)实现一个属性Listener回调函数,来响应route changes并使用第一步写好的函数。
3)注册回调函数到Audio Session上。
callback原型为AudioSessionPropertyListener,如下例所示:
void MyPropertyListener(
 void  *inClientData,
 AudioSesssionPropertyID inID,
 UInt32  inDataSize,
 const void *inData
);
对于一个route change事件,系统发送kAudioSessionProperty_AudioRouteChanges在inID参数。
inData参数包含一个CFDictionaryRef对象,用来描述:
1)为什么route changed?
2)上一个route是什么?
这个字典的key在Audio Route Change Dictionary Keys中描述。route changed的原因通过kAudioSession_AudioRouteChangeKey_Reason键来获得,这个键在Audio Session Route Change Reasons中描述。上一个route通过键kAudioSession_AudioRouteChangeKey_OldRoute键来获得,其值为一个字符串,例如”Headphone“或”Speaker“。

提供给回调函数的信息一般足够你决定采取什么动作。例如,如果route change的原因是kAudioSessionRouteChangeReason_OldDeviceUnavailable和前一个route是Headphone,你就知道用户指示拔出了耳机。如果你还需要指导什么是新的route,那么在你的回调函数中调用AudioSessionGetProperty函数获得kAudioSessionProperty_AudioRoute属性的值。

在IOS中有一种Audio route change的原因是kAudioSessionRouteChangeReason_CategoryChange。显然如果你只想处理耳机的插入和拔出,那就应该忽略这种类型的route change。

六、设备硬件的优化:
通过使用Audio Session的属性,你可以在运行时优化你的设备硬件的Audio行为。这让你的代码可以采用设备的特性。
Audio Session属性机制允许你:
1)指定优先的硬件设置 采样率和I/O buffer duration。
2)查询很多硬件特性,包括输入和输出的延迟、输入和输出的channel计数‘硬件采样率’硬件音量设置 和是否音频输入可用。
3)写回调函数来响应属性更改事件。
最常使用的属性更改事件是route changes。你还可以写回调函数来监听硬件输出音量的更改、音频输入的可用性更改。

1、指定优先的硬件设置:
1)优先的采样率:例如44.1khz和8khz,越高则标识更高的音频质量和更大的文件尺寸
2)优先的I/O buffer duration:例如500mS和5mS,越高则标识更少的硬盘访问和更长的延迟。
根据你的应用的需要设置相应的采样率和I/O buffer duration。
要设置硬件Preferences,使用AudioSessionSetProperty函数,使用kAudioSessionProperty_PreferredHardwareSampleRate和kAudioSessionProperty_PreferredHardwareIOBufferDuration属性标识符。
重要提示:虽然你可以在Audio Session初始化后,安全地在任何时间指定硬件Preferences,但是最好的体验是在Session 不活跃时就设置好。在你设置好Hardware Preferences之后,激活Audio Session,然后查询其获得实际的值。这最后的一步非常重要,因为系统可能不能提供你请求的东西。

2、查询硬件特性:
你的Audio Session可以告诉你许多设备硬件特性。这些特性可以在运行时更改。例如,在用户插入耳机后,采样率可能你会发生改变。有些特性的更改有回调函数可以监听。对于其他属性,可以直接查询。
重要提示:要获得有意义的硬件特性,需要确保你的Audio Session已经被初始化并且是活跃的。
一些很游泳的Audio Session硬件属性如下所示:
1)kAudioSesssionProperty_CurrentHardwareSampleRate:这个属性没有回调函数。
2)kAudioSessionProperty_CurrentHardwareOutputVolume:设备音量
3)kAudioSessionProperty_CurrentHardwareOutputLatency:输出延迟,没有回调函数
4)kAudioSessionProperty_AudioInputAvailable:使用这个属性来确定是否可以录音。
全部的Audio Session Property在Audio Session Services Reference中描述,在Audio Session Services Property Identifiers枚举中。

3、响应属性更改事件:

七、使用Movies和iPod Music工作
Movie Player使你能播放电影--通过文件或网络流。Music Player使你能播放用户的iPod Library中的音频内容。要使用这些对象,你必须考虑它们的Audio Session特性。
1)Music Player(MPMusicPlayerController类的实例)总是使用一个系统提供的Audio Session
2)Movie Player(MPMoviePlayerController类的实例)默认使用你的应用的Audio Session,但是你可以配置其使用系统提供的Audio Session。
重要提示:在IOS3.1.3之前,一个Movie Player总是使用系统提供的Audio Session。要在IOS3.2之后也获得相同的行为,你需要设置Movie Player的useApplicationAudioSession属性为NO。

1、使用Music Player工作:
要播放用户的iPod Library中的音频和你自己的声音,你必须试用一个所谓的可混合的Category。有两个方法来配置Audio Session为可混合的:
1)使用AVAudioSessionCategoryAmbient
2)使用可混合的Category override Property  kAudioSessionProperty_OverrideCategoryMixWithOthers,来使非可混合的Playback Category变得可混合。

因为你使用了一个可混合的Category,因此你不能访问硬件编码器来播放和录音。
系统自动为Music Player处理Route changes和中断。你不能影响这个内置的行为。如果已经正确配置了你的Audio Session,那么你可以信赖Music Player处理插入耳机、alarm响起或电话来到事件。
你可以配置你的Audio Session,当你的Application播放时,Music Player的sound声音变小。

2、使用Movie Players工作
默认地,Movie Player共享你的应用的Audio Session。也可以通过设置起useApplicationAudioSession属性为NO,来使用系统提供的Audio Session。
使用Movie Player时,配置Audio Session
1)播放电影时让所有其他音频都静音:
     a)如果你的应用不自己播放音频,那就不需要配置Audio Session。
     b)如果你的应用播放音频,配置一个Audio Session并且根据你是否想混合iPod和其他Audio来设置你的Audio Session的可混合性。
     c)在任何一种情形下,告诉Movie Player使用其自己的Audio Session:myMoviePlayer.useApplicationAudioSession=NO;
2)Movie和Application Audio mix,但是其他Audio,包括iPod,都被静音了。
    a)配置一个Audio Session,使用非可混合的Category。
    b)设置Movie Player的Audio Session使用应用的AudioSession:myMoviePlayer.useApplicationAudioSession=YES;
3)所有的音频都混合:
    a)配置Audio Session为可混合的Category。
    b)设置Movie Player的Audio Session使用应用的AudioSession:myMoviePlayer.useApplicationAudioSession=YES;

八、Audio Session Cookbook
1、初始化一个Audio Session:
如果使用AV Foundation代理方法来处理Audio 中断,你可以隐式初始化AudioSession。
如果使用C-based回调函数来处理Audio 中断。需要显式初始化Audio Session,使用AudioSessionInitialize函数。并注册中断处理回调函数。
例子,初始化一个Session和注册一个中断回调
AudioSessionInitialize (
    NULL,                            // 1
    NULL,                            // 2
    interruptionListenerCallback,    // 3
    userData                         // 4
);
1)第一个参数为NULL,标识使用默认的(main)run loop
2)第二个参数为NULL,标识使用Default run loop mode
3)第三个参数为中断处理回调函数
4)第四个参数为传递给回调函数的数据。


2、激活和去激活Audio Session
激活Audio Session:
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
//去激活就是传递参数No给 setActive

//C-based函数来激活、去激活AudioSession
OSStatus activationResult=NULL;
result=AudioSessionSetActivie(true);//or false

3、设置Category:
Objective-C界面 使用setCategory:error:
NSError *setCategoryError = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryAmbient error: &setCategoryError];
if (setCategoryError) { /* handle the error condition */ }

C-based界面 使用Audio Session Services的
UInt32 sessionCategory = kAudioSessionCategory_AmbientSound;    // 1
 
AudioSessionSetProperty (
    kAudioSessionProperty_AudioCategory,                        // 2
    sizeof (sessionCategory),                                   // 3
    &sessionCategory                                            // 4
);
1)第一步:声明一个新的UInt32类型的变量并初始化其为Category标识符。
2)第二步:设置AudioSession的Category属性。
3)第三步:属性值的尺寸
4)第四步:你想要设置的SessionCategory。

4、在应用启动时检查其他Audio是否正在播放:
UInt32 otherAudioIsPlaying;                                   // 1
UInt32 propertySize = sizeof (otherAudioIsPlaying);
 
AudioSessionGetProperty (                                     // 2
    kAudioSessionProperty_OtherAudioIsPlaying,
    &propertySize,
    &otherAudioIsPlaying
);
 
if (otherAudioIsPlaying) {                                    // 3
    [[AVAudioSession sharedInstance]  setCategory: AVAudioSessionCategoryAmbient  error: nil];
} else {
    [[AVAudioSession sharedInstance]   setCategory: AVAudioSessionCategorySoloAmbient  error: nil];
}

1)定义一个变量来准备存储Audio Session的kAudioSessionProperty_OtherAudioIsPlaying属性的值
2)获得kAudioSessionProperty_OtherAudioIsPlaying的值,并将其指定给otherAudioIsPlaying变量。
3)设置不同的Category。

5、修改Playback mixing behavior:
两个在一般情况下静音其他Audio的播放Category,可以被修改为支持混合。它们是AVAudioSessionCategoryPlayback和AVAudioSessionCategory_PlayAndRecord。要允许混合,你需要设置一个特定的Audio Session Property:
OSStatus propertySetError = 0;
UInt32 allowMixing = true;
 
propertySetError = AudioSessionSetProperty (
                       kAudioSessionProperty_OverrideCategoryMixWithOthers,  // 1
                       sizeof (allowMixing),                                 // 2
                       &allowMixing                                          // 3
                   );
1)你想设Audio Session的属性的标识符 或者叫做键。
2)值的长度
3)要设置的属性值
在设置完之后要检查是否设置成功或失败,并且作出适当的响应。

6、确保在屏幕锁定时Audio继续播放:
你需要设置合适的Category。如果你使用Audio unit来播放,你可能还需要配置Audio Units。
你不能依赖默认的Audio Session,AVAudioSessionCategorySoloAmbient。
使用AVAudioSessionCategoryPlayback Category。

7、配置Audio Unit,在屏幕锁定时继续播放
8、优化最小化的Power Consumption:
你需要调整你正在使用的Audio Unit的kAudioProperty_MaximumFramesPerSlice属性的值。
默认地,系统调用I/O unit的render 回调,使用一个slice size 1024 frames。
设置一个Audio unit的Maximum-frames-per-slice Property
UInt32 maximumFramesPerSlice = 4096;
 
AudioUnitSetProperty (
    mixerUnit,
    kAudioUnitProperty_MaximumFramesPerSlice,
    kAudioUnitScope_Global,
    0,                        // global scope always uses element 0
    &maximumFramesPerSlice,
    sizeof (maximumFramesPerSlice)
);

9、Optimizing for Low Latency:
10、重定向Output Audio:
有两个方法:
1)使用一个Category routing Override。
2)更改默认的Output route。在下次设置Category之前这会一直生效。

下面显示了使用Category routing Override的例子,在执行这段代码之前,你需要设置Audio Session Category为AVAudioSessionCategoryRecord:
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;  // 1
 
AudioSessionSetProperty (
    kAudioSessionProperty_OverrideAudioRoute,                         // 2
    sizeof (audioRouteOverride),                                      // 3
    &audioRouteOverride                                               // 4
);
1)定义重定向输出音频的标识符
2)要修改的属性的键
3)属性值的长度
4)属性值

下面的例子是修改默认的Output Audio route:
UInt32 doChangeDefaultRoute = 1;
 
AudioSessionSetProperty (
    kAudioSessionProperty_OverrideCategoryDefaultToSpeaker,
    sizeof (doChangeDefaultRoute),
    &doChangeDefaultRoute
);

11、支持Bluetooth Audio Input:
// First, set an audio session category that allows input. Use the
//    AVAudioSessionCategoryRecord or the equivalent kAudioSessionCategory_Record
//    category, or the AVAudioSessionCategoryPlayAndRecord or the equivalent
//    kAudioSessionCategory_PlayAndRecord category. Then proceed as shown here:
 
UInt32 allowBluetoothInput = 1;
 
AudioSessionSetProperty (
    kAudioSessionProperty_OverrideCategoryEnableBluetoothInput,
    sizeof (allowBluetoothInput),
    &allowBluetoothInput
);

12、响应Audio Session的中断:
i)使用AVAudioSessionDelegate:
- (void) beginInterruption {
    if (playing) {
        playing = NO;
        interruptedWhilePlaying = YES;
        [self updateUserInterface];
    }
}
 
NSError *activationError = nil;
- (void) endInterruption {
    if (interruptedWhilePlaying) {
        [[AVAudioSession sharedInstance] setActive: YES error: &activationError];
        [player play];
        playing = YES;
        interruptedWhilePlaying = NO;
        [self updateUserInterface];
    }
}

ii)AVAudioPlayer的中断代理:
- (void) audioPlayerBeginInterruption: (AVAudioPlayer *) player {
    if (playing) {
        playing = NO;
        interruptedOnPlayback = YES;
        [self updateUserInterface];
    }
}

- (void) audioPlayerEndInterruption: (AVAudioPlayer *) player {
    if (interruptedOnPlayback) {
        [player prepareToPlay];
        [player play];
        playing = YES;
        interruptedOnPlayback = NO;
    }
}

iii)定义中断方法:
一个中断方法的例子:
- (void) resumePlayback {
    UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;  // 1
    AudioSessionSetProperty (                                      // 2
        kAudioSessionProperty_AudioCategory,                       // 3
        sizeof (sessionCategory),                                  // 4
        &sessionCategory                                           // 5
    );
    AudioSessionSetActive (true);                                  // 6
    [self.audioPlayer resume];                                     // 7
}

1)定义一个Category标识符
2)设置Audio Session的属性
3)设置Audio Session的Category属性
4)属性值的长度
5)属性值
6)重新激活Audio Session
7)调用AudioPlayer的resume方法。

iv)定义一个中断监听回调函数:
void interruptionListenerCallback (
    void    *inUserData,                                                // 1
    UInt32  interruptionState                                           // 2
) {
    AudioViewController *controller = (AudioViewController *) inUserData;                             // 3
 
    if (interruptionState == kAudioSessionBeginInterruption) {          // 4
        if (controller.audioRecorder) {
            [controller recordOrStop: (id) controller];                 // 5
        } else if (controller.audioPlayer) {
            [controller pausePlayback];                                 // 6
            controller.interruptedOnPlayback = YES;                     // 7
        }
    } else if ((interruptionState == kAudioSessionEndInterruption) && controller.interruptedOnPlayback) { // 8
        [controller resumePlayback];
        controller.interruptedOnPlayback = NO;
    }
}

v)注册中断回调到Audio Session:

13、使用OpenAL时响应中断:
0 0
原创粉丝点击