实现AudioUnit播放音频
demo地址
从配置环境到播放成功的以下步骤详解
一、设置AVAudioSession
该类具有以下作用
- 此类用来管理多个APP对音频资源的利用,
- 设置自己的APP是否和其他APP音频同时存在,还是中断其他APP声音
- 在手机调到静音模式下,自己的APP音频是否可以播放出声音
- 电话或者其他APP中断自己APP的音频的事件处理
- 指定音频输入和输出的设备(比如是听筒输出声音,还是扬声器输出声音)
- 是否支持录音,录音同时是否支持音频播放
NSError *error = nil;
AVAudioSession* session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:&error];
[session setActive:YES error:nil];
类具体的参考资料:iOS 音频-AVAudioSession
二、设置Audiocomponentdescription
音频单元描述
struct AudioComponentDescription {
OSType componentType; //一个音频组件通用的独特的四字节码标识
OSType componentSubType;//由上面决定,设置相应的类型
OSType componentManufacturer;//厂商身份验证
UInt32 componentFlags;//没有明确的指定,设置0
UInt32 componentFlagsMask;//没有明确的指定,设置0
}
2.1、得到AudioComponent
AudioComponentFindNext得到AudioComponent :
AudioComponent outputComponent = AudioComponentFindNext(NULL, &outputDesc);
2.2、最后调用AudioComponentInstanceNew(参数, &参数地址);得到audio的实例
三、初始化 AudioBufferList
用到的关键结构体
struct AudioBufferList
{
UInt32 mNumberBuffers;// audiobuffer的数目
AudioBuffer mBuffers[1]; // this is a variable length array of mNumberBuffers elements
}
//结构体 Audiobuffer
struct AudioBuffer
{
UInt32 mNumberChannels;//声道数目
UInt32 mDataByteSize;//是buffer的大小
void* __nullable mData;//音频数据的buffer
}
四、设置输出格式描述
struct AudioStreamBasicDescription
{
Float64 mSampleRate; //音频频率,也是采样频率
AudioFormatID mFormatID;//音频格式
AudioFormatFlags mFormatFlags;//格式标签
UInt32 mBytesPerPacket;//每个数据包的字节数
UInt32 mFramesPerPacket;//每个数据包的帧数
UInt32 mBytesPerFrame;//每一帧的字节数
UInt32 mChannelsPerFrame;//每一帧声道数,单声道和双声道 1/2
UInt32 mBitsPerChannel;//采样位数/采样精度 8/16
UInt32 mReserved;//保留
};
AudioUnitSetProperty配置表
//1、 设置的这几个参数的含义
CF_ENUM(AudioUnitScope) {
kAudioUnitScope_Global = 0,//设置回调函数
kAudioUnitScope_Input = 1,
kAudioUnitScope_Output = 2,//设置音频格式描述的时候
kAudioUnitScope_Group = 3,
kAudioUnitScope_Part = 4,
kAudioUnitScope_Note = 5,
kAudioUnitScope_Layer = 6,
kAudioUnitScope_LayerItem = 7
};
五、设置应用音频格式描述
OSStatus status = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
kOutputBus,
&_outputFormat,
sizeof(_outputFormat));
六、设置回调函数
//播放回调函数
static OSStatus outputCallBackFun(void * inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * __nullable ioData)
{
memset(ioData->mBuffers[0].mData, 0, ioData->mBuffers[0].mDataByteSize);
ViewController *strongSelf = (__bridge ViewController *)(inRefCon);
__weak typeof(strongSelf) weakSelf = strongSelf;
strongSelf->_bufferList->mBuffers[0].mDataByteSize = CONST_BUFFER_SIZE;
OSStatus status = ExtAudioFileRead(strongSelf->_audioFile, &inNumberFrames, strongSelf->_bufferList);
//把资源内存拷贝到目标内存
memcpy(ioData->mBuffers[0].mData, strongSelf->_bufferList->mBuffers[0].mData, strongSelf->_bufferList->mBuffers[0].mDataByteSize);
ioData->mBuffers[0].mDataByteSize = strongSelf->_bufferList->mBuffers[0].mDataByteSize;
if (ioData->mBuffers[0].mDataByteSize == 0){
[weakSelf stop];
}
strongSelf->_readedFrame += ioData->mBuffers[0].mDataByteSize / strongSelf->_outputFormat.mBytesPerFrame;
CheckError(status, "转换格式失败");
if (inNumberFrames == 0) NSLog(@"播放结束");
NSLog(@"%f",[strongSelf getProgress]);
return noErr;
}