AudioUnit的播放音频文件

这一段研究了一下如果用 AudioUnit 播放音频文件。其中播放mp3和播放pcm是不一样的。下面分别介绍一下,当做总结

1. 播放 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);

2.播放mp3

播放 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);

你可能感兴趣的:(ios开发学习)