前言
相关文章:
使用VideoToolbox硬编码H.264
使用VideoToolbox硬解码H.264
使用AudioToolbox编码AAC
使用AudioToolbox播放AAC
HLS点播实现(H.264和AAC码流)
HLS推流的实现(iOS和OS X系统)
iOS在线音频流播放
Audio Unit播放PCM文件
Audio Unit录音(播放伴奏+耳返)
前面两篇介绍了Audio Unit播放PCM文件和边录边播,这次引入AudioConvert实现aac/m4a/mp3格式的播放。
正文
1、格式转换
音频数据的格式转换包括采样率改变,单声道到多声道的转变、音调的升高降低等,audio unit有一个专门格式转换unit(kAudioUnitType_FormatConverter,type of 'aufc'
)。
AudioUnit不支持vbr的数据,也不支持从一个有损压缩格式转换为pcm或者pcm转换为有损格式,对于有损格式的音频数据转换,需要用CoreAudio的Audio Converter API。
2、AudioFile API 和 Converter
AudioFile API提供了API对音频文件的创建、打开、修改和保存;
Audio Converters 用于音频文件的编解码,还可以用于sample rate的改变、int到float的转变,最常见是将音频文件转成pcm播放;
下面Converter的两个格式:
Source Format
Sample Rate: 44100
Format ID: .mp3
Format Flags: 0
Bytes per Packet: 0
Frames per Packet: 1152
Bytes per Frame: 0
Channels per Frame: 2
Bits per Channel: 0
Target Format
Sample Rate: 44100
Format ID: lpcm
Format Flags: 4
Bytes per Packet: 2
Frames per Packet: 1
Bytes per Frame: 2
Channels per Frame: 1
Bits per Channel: 16
3、具体细节
1、初始化AudioFile,通过AudioFileOpenURL
打开音频文件,并读取对应的音频格式(AudioStreamBasicDescription
);这里和Audio Unit播放PCM文件不同的是,还需要读取kAudioFilePropertyMaximumPacketSize
和kAudioFilePropertyAudioDataPacketCount
两个属性,分别是单个package的最大size和packet的数量,并通过缓存的大小和package的size创建AudioStreamPacketDescription
的数组;
2、初始化AudioUnit,设置AVAudioSession的Category为AVAudioSessionCategoryPlayback
;初始化AudioBufferList,设置AudioUnit的playback回调;
3、在AudioUnit的playback回调中,调用AudioConvert的AudioConverterFillComplexBuffer
函数并设置好回调方法lyInInputDataProc
;在回调的lyInInputDataProc
中,通过AudioFileReadPacketData
读取音频数据并把读取的AudioStreamPacketDescription回传;
4、AudioConvert转换后的音频数据会填入参数buffList,将对应的数据复制给AudioUnit的playback参数;
遇到的问题
1、API替换
一开始用的是AudioFileReadPackets
方法读取音频数据,后面在遇到问题后发现AudioFileReadPackets
被替换成AudioFileReadPacketData
,参数类似;
2、AudioConverter的转换函数的返回值
调用AudioConverterFillComplexBuffer
后,在回调方法lyInInputDataProc
中,如果设置 *ioNumberDataPackets = 0
,并且返回 noErr
, AudioConverter 会进入 Finished
的状态;
返回非零的值,表示数据未完成,比如在demo中返回了
NO_MORE_DATA
,NO_MORE_DATA
是自定义的非零返回值;
3、AudioConverterNewSpecific返回-50
通过OSStatus
,可以看到-50是AVAudioSessionErrorCodeBadParam 参数不一致;
检查代码,发现是在使用AudioConverterNewSpecific() 创建转换器的时候输入流格式与输出流格式的声道数设置不同;(解决方案就是声道数改成一致)
4、AudioConverterFillComplexBuffer返回561015652
通过OSStatus
,查到561015652是kAudioConverterErr_RequiresPacketDescriptionsError = '!pkd'
,意思是没有回调AudioStreamPacketDescriptions
参数;
对于音频格式mBytesPerPacket=0
的数据,需要AudioStreamPacketDescriptions
参数来辅助转换音频数据;
解决方案就是新建AudioStreamPacketDescriptions
数组,并且在读取后赋值给outDataPacketDescription
(见demo);
总结
AudioUnit和AudioConvert的API虽然简单,却是功能强大。
文章中的介绍更多是自己在学习过程中的一些收获,对于知识点的介绍很多是不够全面和仔细的,对此建议看看参考目录。
Extended Audio File Services
是Audio File Services
和 Audio Converter Services
的结合,提供统一的接口进行处理,下篇可能会是Extended Audio File
相关。
参考
Playing a sound file using the Default Output Audio Unit
Supported Audio File and Data Formats in OS X