iOS: 音效和音乐的播放,封装的工具类
在iOS中音频播放从形式上可以分为音效播放和音乐播放。前者主要指的是一些短音频播放,通常作为点缀音频,对于这类音频不需要进行进度、循环等控制。后者指的是一些较长的音频,通常是主音频,对于这些音频的播放通常需要进行精确的控制。在iOS中播放两类音频分别使用AudioToolbox.framework和AVFoundation.framework来完成音效和音乐播放。
音效
AudioToolbox.framework是一套基于C语言的框架,使用它来播放音效其本质是将短音频注册到系统声音服务(System Sound Service)。System Sound Service是一种简单、底层的声音播放服务,但是它本身也存在着一些限制:
- 音频播放时间不能超过30s
- 数据必须是PCM或者IMA4格式
- 音频文件必须打包成.caf、.aif、.wav中的一种(注意这是官方文档的说法,实际测试发现一些.mp3也可以播放)
使用System Sound Service 播放音效的步骤如下:
- 调用AudioServicesCreateSystemSoundID( CFURLRef inFileURL, SystemSoundID* outSystemSoundID)函数获得系统声音ID。
- 如果需要监听播放完成操作,则使用AudioServicesAddSystemSoundCompletion( SystemSoundID inSystemSoundID,
CFRunLoopRef inRunLoop, CFStringRef inRunLoopMode, AudioServicesSystemSoundCompletionProc inCompletionRoutine, void* inClientData)方法注册回调函数。 - 调用AudioServicesPlaySystemSound(SystemSoundID inSystemSoundID) 或者AudioServicesPlayAlertSound(SystemSoundID inSystemSoundID) 方法播放音效(后者带有震动效果)。
音乐
如果播放较大的音频或者要对音频有精确的控制则System Sound Service可能就很难满足实际需求了,通常这种情况会选择使用AVFoundation.framework中的AVAudioPlayer来实现。AVAudioPlayer可以看成一个播放器,它支持多种音频格式,而且能够进行进度、音量、播放速度等控制。首先简单看一下AVAudioPlayer常用的属性和方法:
| 属性 | 说明 |
| @property(readonly, getter=isPlaying) BOOL playing | 是否正在播放,只读 |
| @property(readonly) NSUInteger numberOfChannels | 音频声道数,只读 |
| @property(readonly) NSTimeInterval duration | 音频时长 |
| @property(readonly) NSURL *url | 音频文件路径,只读 |
| @property(readonly) NSData *data | 音频数据,只读 |
| @property float pan | 立体声平衡,如果为-1.0则完全左声道,如果0.0则左右声道平衡,如果为1.0则完全为右声道 |
| @property float volume | 音量大小,范围0-1.0 |
| @property BOOL enableRate | 是否允许改变播放速率 |
| @property float rate | 播放速率,范围0.5-2.0,如果为1.0则正常播放,如果要修改播放速率则必须设置enableRate为YES |
| @property NSTimeInterval currentTime | 当前播放时长 |
| @property(readonly) NSTimeInterval deviceCurrentTime | 输出设备播放音频的时间,注意如果播放中被暂停此时间也会继续累加 |
| @property NSInteger numberOfLoops | 循环播放次数,如果为0则不循环,如果小于0则无限循环,大于0则表示循环次数 |
| @property(readonly) NSDictionary *settings | 音频播放设置信息,只读 |
| @property(getter=isMeteringEnabled) BOOL meteringEnabled | 是否启用音频测量,默认为NO,一旦启用音频测量可以通过updateMeters方法更新测量值 |
| 对象方法 | 说明 |
| - (instancetype)initWithContentsOfURL:(NSURL *)url error:(NSError **)outError | 使用文件URL初始化播放器,注意这个URL不能是HTTP URL,AVAudioPlayer不支持加载网络媒体流,只能播放本地文件 |
| - (instancetype)initWithData:(NSData *)data error:(NSError **)outError | 使用NSData初始化播放器,注意使用此方法时必须文件格式和文件后缀一致,否则出错,所以相比此方法更推荐使用上述方法或- (instancetype)initWithData:(NSData *)data fileTypeHint:(NSString *)utiString error:(NSError **)outError方法进行初始化 |
| - (BOOL)prepareToPlay; | 加载音频文件到缓冲区,注意即使在播放之前音频文件没有加载到缓冲区程序也会隐式调用此方法。 |
| - (BOOL)play; | 播放音频文件 |
| - (BOOL)playAtTime:(NSTimeInterval)time | 在指定的时间开始播放音频 |
| - (void)pause; | 暂停播放 |
| - (void)stop; | 停止播放 |
| - (void)updateMeters | 更新音频测量值,注意如果要更新音频测量值必须设置meteringEnabled为YES,通过音频测量值可以即时获得音频分贝等信息 |
| - (float)peakPowerForChannel:(NSUInteger)channelNumber; | 获得指定声道的分贝峰值,注意如果要获得分贝峰值必须在此之前调用updateMeters方法 |
| - (float)averagePowerForChannel:(NSUInteger)channelNumber | 获得指定声道的分贝平均值,注意如果要获得分贝平均值必须在此之前调用updateMeters方法 |
| @property(nonatomic, copy) NSArray *channelAssignments | 获得或设置播放声道 |
| 代理方法 | 说明 |
| - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag | 音频播放完成 |
| - (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error | 音频解码发生错误 |
音频会话
事实上上面的播放器还存在一些问题,例如通常我们看到的播放器即使退出到后台也是可以播放的,而这个播放器如果退出到后台它会自动暂停。如果要支持后台播放需要做下面几件事情:
事实上上面的播放器还存在一些问题,例如通常我们看到的播放器即使退出到后台也是可以播放的,而这个播放器如果退出到后台它会自动暂停。如果要支持后台播放需要做下面几件事情:
1.设置后台运行模式:在plist文件中添加Required background modes,并且设置item 0=App plays audio or streams audio/video using AirPlay(其实可以直接通过Xcode在Project Targets-Capabilities-Background Modes中设置)

2.设置AVAudioSession的类型为AVAudioSessionCategoryPlayback并且调用setActive::方法启动会话。
AVAudioSession *audioSession=[AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:YES error:nil];
3.为了能够让应用退到后台之后支持耳机控制,建议添加远程控制事件(这一步不是后台播放必须的)
前两步是后台播放所必须设置的,第三步主要用于接收远程事件,这部分内容之前的文章中有详细介绍,如果这一步不设置虽让也能够在后台播放,但是无法获得音频控制权(如果在使用当前应用之前使用其他播放器播放音乐的话,此时如果按耳机播放键或者控制中心的播放按钮则会播放前一个应用的音频),并且不能使用耳机进行音频控制。第一步操作相信大家都很容易理解,如果应用程序要允许运行到后台必须设置,正常情况下应用如果进入后台会被挂起,通过该设置可以上应用程序继续在后台运行。但是第二步使用的AVAudioSession有必要进行一下详细的说明。
在iOS中每个应用都有一个音频会话,这个会话就通过AVAudioSession来表示。AVAudioSession同样存在于AVFoundation框架中,它是单例模式设计,通过sharedInstance进行访问。在使用Apple设备时大家会发现有些应用只要打开其他音频播放就会终止,而有些应用却可以和其他应用同时播放,在多种音频环境中如何去控制播放的方式就是通过音频会话来完成的。下面是音频会话的几种会话模式:
| 会话类型 | 说明 | 是否要求输入 | 是否要求输出 | 是否遵从静音键 |
| AVAudioSessionCategoryAmbient | 混音播放,可以与其他音频应用同时播放 | 否 | 是 | 是 |
| AVAudioSessionCategorySoloAmbient | 独占播放 | 否 | 是 | 是 |
| AVAudioSessionCategoryPlayback | 后台播放,也是独占的 | 否 | 是 | 否 |
| AVAudioSessionCategoryRecord | 录音模式,用于录音时使用 | 是 | 否 | 否 |
| AVAudioSessionCategoryPlayAndRecord | 播放和录音,此时可以录音也可以播放 | 是 | 是 | 否 |
| AVAudioSessionCategoryAudioProcessing | 硬件解码音频,此时不能播放和录制 | 否 | 否 | 否 |
| AVAudioSessionCategoryMultiRoute | 多种输入输出,例如可以耳机、USB设备同时播放 | 是 | 是 | 否 |
注意:是否遵循静音键表示在播放过程中如果用户通过硬件设置为静音是否能关闭声音。
好了,基本的特点和属性已经介绍的差不多了,为此,我写了一个框架,专门用来播放音视频文件,地址如下:
github:https://github.com/xiayuanquan/XYQPlayer
cnblogs:http://www.cnblogs.com/XYQ-208910/p/6685412.html
iOS: 音效和音乐的播放,封装的工具类的更多相关文章
- .NET3.5中JSON用法以及封装JsonUtils工具类
.NET3.5中JSON用法以及封装JsonUtils工具类 我们讲到JSON的简单使用,现在我们来研究如何进行封装微软提供的JSON基类,达到更加方便.简单.强大且重用性高的效果. 首先创建一个类 ...
- MySQL数据库学习笔记(十一)----DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- MySQL数据库学习笔记(十)----JDBC事务处理、封装JDBC工具类
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- JAVA中封装JSONUtils工具类及使用
在JAVA中用json-lib-2.3-jdk15.jar包中提供了JSONObject和JSONArray基类,用于JSON的序列化和反序列化的操作.但是我们更习惯将其进一步封装,达到更好的重用. ...
- MySQL JDBC事务处理、封装JDBC工具类
MySQL数据库学习笔记(十)----JDBC事务处理.封装JDBC工具类 一.JDBC事务处理: 我们已经知道,事务的概念即:所有的操作要么同时成功,要么同时失败.在MySQL中提供了Commit. ...
- DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)
DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类) 一.DAO模式简介 DAO即Data Access Object,数据访问接口.数据访问:故名思义就是与数据库打交道.夹在业务逻辑与数据 ...
- Workbook导出excel封装的工具类
在实际中导出excel非常常见,于是自己封装了一个导出数据到excel的工具类,先附上代码,最后会写出实例和解释.支持03和07两个版本的 excel. HSSF导出的是xls的excel,XSSF导 ...
- 封装JDBC工具类
JDBC连接数据库基本的步骤是固定的,这样就可以考虑封装一个工具类来简化数据库操作. 封装时用到了Java中的properties配置文件,是以一种键值对的形式存在的,可以把连接数据库要动态的信息保存 ...
- writeValueAsString封装成工具类
封装成工具类 <span style="font-family:Microsoft YaHei;">public static String toJsonByObjec ...
随机推荐
- spring boot thymeleaf常用方式
动态和静态区别 静态页面的return默认是跳转到/static/index.html,当在pom.xml中引入了thymeleaf组件,动态跳转会覆盖默认的静态跳转,默认就会跳转到/template ...
- perf工具crash的问题
perf抓取时系统crash的情况.找前同事了解到perf工具导致系统crash的一种情况, perf工具默认是使用cycles,这个硬件事件是使用NMI,可能会导致内核错误. 之前文档上的perf命 ...
- C#连接操作MySQL数据库详细步骤 帮助类等(二次改进版)
最近准备写一个仓库管理的项目 客户要求使用C#编写MySQL存储数据 为了方便,整理了数据库操作的工具类 首先在项目App.config 文件下添加节点 <connectionStrings&g ...
- Centos7 如何减少/home分区,扩大/root分区
把/home内容备份,然后将/home文件系统所在的逻辑卷删除,扩大/root文件系统,新建/home:tar cvf /tmp/home.tar /home #备份/home umount /hom ...
- ONVIF开发实例
<开发过过程中的经验总结> ➤工具的使用 (1)首先将文件soapClientLib.c 中"代码"的第二行和第三行注释掉,实际上该文件根本没有用,为了保险起见 ...
- LOJ P3953 逛公园 NOIP dp 最短路 拓扑排序
https://www.luogu.org/problemnew/show/P3953 开o2过了不开o2re一个点...写法如题 顺便一提这道题在我校oj是a不了的因为我校土豆服务器速度奇慢1s时限 ...
- shellcode在栈溢出中的利用与优化
0x00 前言 在<Windows Shellcode学习笔记——shellcode的提取与测试>中介绍了如何对shellcode作初步优化,动态获取Windows API地址并调用,并通 ...
- hdu 5317 RGCDQ (2015多校第三场第2题)素数打表+前缀和相减求后缀(DP)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5317 题意:F(x) 表示x的不同质因子的个数结果是求L,R区间中最大的gcd( F(i) , F(j ...
- Java并发(二十):线程本地变量ThreadLocal
ThreadLocal是一个本地线程副本变量工具类. 主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不同的 ...
- 仅100行的JavaScript DOM操作类库
如果你构建过Web引用程序,你可能处理过很多DOM操作.访问和操作DOM元素几乎是每一个Web应用程序的通用需求.我们我们经常从不同的控件收集信息,我们需要设置value值,修改div或span标签的 ...