iOS 音频流播(一)

前言

学习AudioToolBox有一段时间了,期间有遇到不少坑(主要还是英文不够好,看官方文档不甚明了)。随着一路踩坑填坑,倒是积累了不少音频相关的知识。在这里分享一下心得,算是给后来的人一点帮助吧。
  这一篇是基础篇,主要介绍音频基础知识,顺便讲讲iOS上实现音频流播的几种方式和需要掌握的知识。
  开源项目DOUAudioStreamer对我帮助很大(感谢开源社区),而我最开始的知识来自这一系列博客,大家也可以去学习一下。很多知识我就直接引用了(其实是copy过来),这里先说明一下。

音频基础知识

音频文件的生成过程是将连续的离散信号(真实的声音信号)采样、量化再编码转化为离散的数字信号的过程,这一过程被称为脉冲编码调制(Pulse Code Modulation,PCM)。采样必须遵循奈奎斯特抽样定理(只有采样频率高于声音信号最高频率的两倍时,才能把数字信号表示的声音还原成为原来的声音),而人耳能听到的声音,频率最低从20Hz起到20KHz,所以音频文件的采样率一般在40KHz以上,比如最常见的44.1KHz和48KHz。

采样(sampling)

把模拟音频转成数字音频的过程,就称作采样。采样的过程实际上是将通常的模拟音频信号的电信号转换成二进制码0和1,这些0和1便构成了数字音频文件。要正确理解音频采样可以分为采样的频率和采样的位数。

采样频率(sample rate)

也称为采样速度或者采样率(单位Hz),定义了每秒从连续信号中提取并组成离散信号的采样个数。通俗的讲采样频率是指计算机每秒钟采集多少个信号样本,采样频率越高声音的还原就越真实越自然。

采样位数

也称为采样精度(单位bit),采样位数可以理解为采集卡处理声音的解析度。这个数值越大,解析度就越高,录制和回放的声音就越真实。移动端常见的采样位数为8或16。8位代表2的8次方--256,16位则代表2的16次方--64K。比较一下,一段相同的音乐信息,16位声卡能把它分为64K个精度单位进行处理,而8位声卡只能处理256个精度单位,造成了较大的信号损失,最终的采样效果自然是无法相提并论的。

通道数(channel)

分为单声道和立体声。当然还存在更多的通道数。举个列子,声道多,效果好,两个声道,说明只有左右两边有声音传过来, 四声道,说明前后左右都有声音传过来。

样本(sample),帧(frame),包(packet)
  • 一个音频样本是单个音频通道的单一数值。
  • 一个音频帧是时间重合的样本的集合。例如,立体声文件每帧有两个样本,一个用于左声道,一个用于右声道。
  • 一个音频包是一个或多个连续的帧的集合。在线性PCM音频中,音频包始终是单个帧。在压缩格式中,一般是多个帧。在给定的音频格式中,音频包定义了最小且具有意义的一组音频帧的集合。
比特率(bit rate)

也叫码率,声音中的比特率是指将模拟声音信号转换成数字声音信号后,单位时间内的二进制数据量,是间接衡量音频质量的一个指标(比特率越高音质越好)。计算公式:比特率 = 采样率 x 采样位数 x 声道数,单位bps(Bit Per Second)。例如一个48KHz采样率,双声道,16位采样率,它的比特率为 48KHz * 2 * 16bit = 1536kbps(这里的k是1000)。下图是网易云音乐提供的音频码率。


netease@2x.png
音频压缩

一个采样率为44.1KHz,采样位数为16bit/s,双声道的PCM编码的音频文件,它的数据速率则为 44.1K * 16 * 2=1411.2 kbps。 将码率除以8(进制转换,1Byte=8Bit),就可以得到数据速率,即176.4KB/s。这表示存储一秒钟采样率为44.1KHz,采样大小为16bit/s,双声道的PCM 编码的音频信号,需要176.4KB的空间,1分钟则约为10.34M,这对大部分用户是不可接受的,尤其是喜欢在电脑上听音乐的朋友,要降低磁盘占用, 只有2种方法,降低采样指标或者压缩,而降低指标是不可取的,就只能压缩了。对于原始音频数据,如PCM,每一个数据包只有一个音频帧,而对于压缩音频,如MP3,一个数据包往往对应着多个音频帧。

audioUnitPlay.jpg
编码方式VBR、CBR

VBR(Variable Bitrate)动态比特率 也就是没有固定的比特率,压缩软件在压缩时根据音频数据即时确定使用什么比特率,这是以质量为前提兼顾文件大小的方式,推荐编码模式;
  CBR(Constant Bitrate),常数比特率 指文件从头到尾都是一种位速率。相对于VBR和ABR来讲,它压缩出来的文件体积很大,而且音质相对于VBR和ABR不会有明显的提高

MP3格式

MP3是目前最常用的音频格式。MP3格式中的数据通常由两部分组成,一部分为ID3用来存储歌名、演唱者、专辑、音轨数等信息,另一部分为音频数据。音频数据部分以帧(frame)为单位存储,每个音频都有自己的帧头。MP3中的每一个帧都有自己的帧头,其中存储了采样率等解码必须的信息,所以每一个帧都可以独立于文件存在和播放,这个特性加上高压缩比使得MP3文件成为了音频流播放的主流格式(也正是因为这个,于是出现了VBR技术,可以让MP3文件的每一段甚至每一帧都可以有单独的bitrate,这样做的好处就是在保证音质的前提下最大程度的限制了文件的大小)。帧头之后存储着音频数据,这些音频数据是若干个PCM数据帧经过压缩算法压缩得到的,对CBR的MP3数据来说每个帧中包含的PCM数据帧是固定的,而VBR是可变的。

单个音频包的持续时间

  packetDuration = framesPerPacket / sampleRate * 1000,也就是说单个包的持续时间(毫秒) = 单个包的帧数 / 采样频率 * 1000
  例如,对于一个采样率44.1KHz的MP3文件,一个音频包有1152个音频帧(固定的),根据公式计算可得 packetDuration = 1152 / 44.1KHz * 1000 = 26.1224...(约等于26ms),即一个MP3音频包的持续时间是26ms。这个知识点在seek时会发挥比较大的作用,可以用于求出seek后对应的音频包位置。

iOS音频播放总览

了解了基础概念之后我们就可以列出一个经典的音频播放流程(以MP3为例):
1、读取MP3文件
2、解析采样率、码率、时长等信息,分离MP3中的音频帧
3、对分离出来的音频帧解码得到PCM数据
4、对PCM数据进行音效处理(均衡器、混响器等,非必须)
5、把PCM数据解码成音频信号
6、把音频信号交给硬件播放
7、重复1-6步直到播放完成

在iOS系统中apple对上述的流程进行了封装并提供了不同层次的接口,下面对其中的中高层接口进行功能说明:

  • Audio File Services:读写音频数据,可以完成播放流程中的第2步;
  • Audio File Stream Services:对音频进行解码,可以完成播放流程中的第2步;
  • Audio Converter services:音频数据转换,可以完成播放流程中的第3步;
  • Audio Processing Graph Services:音效处理模块,可以完成播放流程中的第4步;
  • Audio Unit Services:播放音频数据:可以完成播放流程中的第5步、第6步;
  • Extended Audio File Services:Audio File Services和Audio Converter services的结合体;
  • AVAudioPlayer/AVPlayer(AVFoundation):高级接口,可以完成整个音频播放的过程(包括本地文件和网络流播放,第4步除外);
  • Audio Queue Services:高级接口,可以进行录音和播放,可以完成播放流程中的第3、5、6步;

我们可以自身需求,选择不同的接口:

  • 如果只是想实现音频的播放,没有其他需求AVFoundation会很好的满足你的需求。它的接口使用简单、不用关心其中的细节;
  • 如果想实现一个音频流播放器,有几种选择:
    • CFNetwork + AudioFileStream + AudioQueue。用CFReadStream读取音频数据并交给AudioFileStream或者AudioFile解析分离音频帧,分离出来的音频帧可以送给AudioQueue进行解码和播放。如果是本地文件用NSFileHandle直接读取文件解析即可。开源播放器AudioStreamer就是这种思路。
    • CFNetwork + AudioFile + AudioConverter + AudioUnit。同样用CFReadStream读取音频数据并交给AudioFile解析分离音频帧,分离出来的音频帧交给AudioConverter转换成PCM数据,再把PCM数据交给AudioUnit进行播放。这是开源播放器DOUAudioStreamer的搭建方式,也是这一系列文章要讲述的方式。

为什么选择CFNetwork而不是NSURLSession?
  由于NSURLSession是异步请求,这样就会涉及到多线程之间的通信问题,比较复杂,并且读取到的数据大小不好控制,而使用CFNetwork则不一样,可以精确控制每次读取到的数据大小,并且读取数据是在本线程中,所以虽然说CFNetwork是底层网络,但是使用CFNetwork反而比使用NSURLSession更加简单。
  
  下篇将会介绍iOS中的音频小管家,AVAudioSession

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249

推荐阅读更多精彩内容