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

作者: 落影loyinglin | 来源:发表于2017-10-09 09:04 被阅读879次

前言

相关文章:
使用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

相关文章

网友评论

  • 明天过后_c789:这个输入流是文件,我需求是把麦克风的PCM作为输入转码成nsdata传输,有什么办法吗?
    落影loyinglin:@明天过后_c789 aac编码 和 你说的ulaw编码,不是一个层次的,aac是对pcm数据进行压缩,ulaw是编码。core audio是支持的
    明天过后_c789:@落影loyinglin 我的转码目标格式是ulaw,必须实时的,麦克风的输入好像固定是44100,我必须得把pcm转码成ulaw,我看你之前编码aac示例是只针对aac把输出配置改下能达到编码成ulaw吗?
    落影loyinglin:@明天过后_c789 编码成aac音频文件 再当做二进制流发送。或者直接pcm当成二进制流发送 这样就没有音频的格式信息
  • Liusr:林哥,在用AVCaptureAudioDataOutput得到音频数据的时候,不能用audioSettings配置采样率,位数声道等参数。比如录制得到采样率是44k,我想得到16k的pcm这个功能用Audio Converter可以完成吗?我看了apple的例子读文件是可以的,但是对应到数据流,AudioConverterFillComplexBuffer这里总是报错1768846202
    Liusr:@落影loyinglin 多谢你百忙中的回复
    落影loyinglin:@Liu_sr 有demo吗 我看看

本文标题:Audio Unit播放aac/m4a/mp3等文件

本文链接:https://www.haomeiwen.com/subject/bqfoextx.html