这一段研究了一下如果用 AudioUnit 播放音频文件。其中播放mp3和播放pcm是不一样的。下面分别介绍一下,当做总结
1)初始化
AudioUnit的初始化比较啰嗦,而且方法比较多。这里采用一种比较简单的。
AudioComponentDescription outputUinitDesc; //定义AudioUnit描述,下面是设置 unit 的类型。
memset(&outputUinitDesc, 0, sizeof(AudioComponentDescription));
outputUinitDesc.componentType = kAudioUnitType_Output;//输出类型
outputUinitDesc.componentSubType = kAudioUnitSubType_RemoteIO;
outputUinitDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
outputUinitDesc.componentFlags = 0;
outputUinitDesc.componentFlagsMask = 0;
AudioComponent outComponent = AudioComponentFindNext(NULL, &outputUinitDesc);
OSStatus status = AudioComponentInstanceNew(outComponent, &_outAudioUinit);
接下来要设置一下AudioUnit的属性,都是通过AudioUnitSetProperty这个接口来设置
AudioStreamBasicDescription pcmStreamDesc = PCMStreamDescription();
AudioUnitSetProperty(_outAudioUinit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &pcmStreamDesc, sizeof(pcmStreamDesc));
这段代码是用来设置 pcm 文件的格式,包括采样率,位深等等。
接着设置回调接口,在这个接口中用来把解析来的数据填入到相应的数据结构中,为 AudioUnit 来播放
AURenderCallbackStruct callBackStruct;
callBackStruct.inputProc = BXAURenderCallback;//回调函数
callBackStruct.inputProcRefCon = (__bridge void * _Nullable)(self);
AudioUnitSetProperty(_outAudioUinit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callBackStruct, sizeof(AURenderCallbackStruct));//回调函数和 AudioUnit 的关联
回调函数定义如下
OSStatus BXAURenderCallback(void *inRefCon,AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp *inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames, AudioBufferList * __nullable ioData)
初始化 AudioUnit
OSStatus result = AudioUnitInitialize(_outAudioUinit);
NSLog(@"result %d", result);
貌似不写这个函数也行
开始播放
OSStatus status = AudioOutputUnitStart(_outAudioUinit);
assert(status == noErr);
播放 MP3比播放pcm多了个步骤就是要把mp3转换成LPCM,AudioUnit才能播放。
首先初始化的步骤都一样,设置了播放的回调函数以后,还要设置一下converter使用的 bufferList
AudioBufferList *renderBufferList;
UInt32 bufferSize = 4096*4;
renderBufferSize = bufferSize;
renderBufferList = (AudioBufferList*)calloc(1, sizeof(UInt32)+sizeof(AudioBuffer));
renderBufferList->mNumberBuffers = 1;
renderBufferList->mBuffers[0].mData = calloc(1, bufferSize);
renderBufferList->mBuffers[0].mDataByteSize = bufferSize;
renderBufferList->mBuffers[0].mNumberChannels = 2;
调用接口设置转换对象和音频的格式
extern OSStatus
AudioConverterNew( const AudioStreamBasicDescription * inSourceFormat,//被转换的音频格式
const AudioStreamBasicDescription * inDestinationFormat,//转换后的音频格式
AudioConverterRef __nullable * __nonnull outAudioConverter);
然后在output的render callback中,使用Converter 把mp3的数据转换成LPCM的数据
extern OSStatus
AudioConverterFillComplexBuffer( AudioConverterRef inAudioConverter,//AudioConverter的指针
AudioConverterComplexInputDataProc inInputDataProc,//提供输入数据的callback的回调函数,从这个回调函数中获得数据,并填满自定义的AudioBufferList
void * __nullable inInputDataProcUserData,//自定义的类
UInt32 * ioOutputDataPacketSize,//如果为输入参数,则是定义的formate中数据的大小。输出参数,转换后的数据的大小
AudioBufferList * outOutputData,//转换后的数据
AudioStreamPacketDescription * __nullable outPacketDescription);