Audio Unit播放aac/m4a/mp3等文件

0.378字数 961阅读 2844

前言

相关文章:
使用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文件不同的是,还需要读取kAudioFilePropertyMaximumPacketSizekAudioFilePropertyAudioDataPacketCount两个属性,分别是单个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_DATANO_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 ServicesAudio File ServicesAudio Converter Services 的结合,提供统一的接口进行处理,下篇可能会是Extended Audio File相关。

参考

Playing a sound file using the Default Output Audio Unit
Supported Audio File and Data Formats in OS X

推荐阅读更多精彩内容