0


Cocoa Mac音频模块关键步骤总结

1. .driver 插件

#include <CoreAudio/AudioServerPlugIn.h>

头文件

static AudioServerPlugInDriverInterface gAudioServerPlugInDriverInterface =

静态函数struct, 返回一系列回调的函数指针
//开始io,代表有对象链接进来了,如果是第一个启动引擎, 创建circle buffer

static OSStatus xxx_StartIO(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID)

//如果是最后一个的话,关闭引擎,销毁circle buffer

static OSStatus xxx_StopIO(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID)

//真正的方法

static OSStatus CamStudioAudio_DoIOOperation(....)
里面真正执行任务,接收和发送都在这里完成。
  // virutal device -> Other Capturedif(inOperationID == kAudioServerPlugInIOOperationReadInput){returnsendDataToOtherApp(inIOBufferFrameSize, inIOCycleInfo, ioMainBuffer);}// other app -> virutal deviceif(inOperationID == kAudioServerPlugInIOOperationWriteMix){returngetDataFromOtherApp(inIOBufferFrameSize, inIOCycleInfo, ioMainBuffer);}

//这个函数可以不管

static OSStatus xxx_EndIOOperation(...)

2. CoreAudio 驱动

//准备获取ID

    AudioObjectPropertyAddress address =makeOutputPropertyAddress(kAudioHardwarePropertyDevices);
    UInt32 devicesDataSize;//获取具体列表的内存大小
    OSStatus status =AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,&address,0,NULL,&devicesDataSize);RETBOOL(status,"findMyAudioDevice-AudioObjectGetPropertyDataSize")//判断长度,并请求填充内存int count = devicesDataSize /sizeof(AudioDeviceID);
    AudioDeviceID deviceIDs[count];
    status =AudioObjectGetPropertyData(kAudioObjectSystemObject,&address,0,NULL,&devicesDataSize,
                                        deviceIDs);//轮询列表获取合适的idAudioObjectGetPropertyData(deviceID,&address,0,NULL,&size,&prop);//创建和析构监听AudioObjectAddPropertyListener(...kAudioDevicePropertyDeviceIsAlive)AudioObjectRemovePropertyListener(...kAudioDevicePropertyNominalSampleRate)
#import <CoreAudio/CoreAudio.h>
#import <CoreAudio/AudioHardware.h>

//绑定

OSStatus status = AudioDeviceCreateIOProcID(设备ID, deviceIOProcFunc/*回调函数*/, this, &mDeviceIOProcID/*创建的io句柄*/);

//开始

OSStatus status = AudioDeviceStart(mDevice.getNeedID(), mDeviceIOProcID);

//回调
。。。
//销毁

AudioDeviceDestroyIOProcID(mDevice.getNeedID(), mDeviceIOProcID);

3. AudioConvertRef 转码

头文件

#include <AudioToolbox/AudioToolbox.h>
//创建转换对象
    AudioConverterRef audioConverter;AudioConverterNew(&_inASBD,&_outASBD,&audioConverter);

//重新从 Audio Convert 获取被校正过的 ASBD数据

AudioConverterGetProperty(audioConverter, kAudioConverterCurrentInputStreamDescription, &size, &_inASBD);

//将获取的MagicCookie 设置到 converter 中

AudioConverterSetProperty(converter,kAudioConverterDecompressionMagicCookie,cookieDataSize,cookieData),

//计算输入缓冲区的大小,及缓冲区能容纳的packet 数量

_inBuffer = malloc(4096*8)

//vbr 需要从文件中读取。kAudioFilePropertyPacketSizeUpperBound是预估不是打开计算

AudioFileGetProperty(_inFile, kAudioFilePropertyPacketSizeUpperBound, &size, &inSizePerPacket)

//计算和开辟输出缓冲区
//vbr得到最大输入的每包最大输出大小

AudioConverterGetProperty(audioConverter, kAudioConverterPropertyMaximumOutputPacketSize, &size, outData);

//写入Magic cookie

status =AudioConverterGetProperty(converter, kAudioConverterDecompressionMagicCookie,&cookieDataSize, cookies);
status =AudioFileSetProperty(_outFile, kAudioFilePropertyMagicCookieData, cookieDataSize, cookies);

//死循环进行数据转换

AudioConverterFillComplexBuffer(....)

//会在这里的回调里面填充input数据,内部进行转换,返回值之后,获取到的就是转换后的数据

AudioFileWritePackets

写入文件

outFilePacketOffset += ioOutDataPacketsPerOut;

//下次输出文件的时候,需要增加这次输出的数量

AudioConverterDispose(audioConverter)

//关闭和释放AudioConverter的资源

4. AudioQueue output 输出

//创建Audioqueue对象,并配置callbackAudioQueueNewOutput(&inASBD,
                                          callback,UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()),nil,nil,0,&self.audioQueue)
//自定义输出设备,如果不想用默认的话var cuStr ="FC-E8-06-DB-74-1D:output"asCFStringAudioQueueSetProperty(self.audioQueue!,kAudioQueueProperty_CurrentDevice,&cuStr, size)
//获取输出设备的 asbd, 方便后面转码AudioQueueGetProperty(self.audioQueue!,kAudioQueueProperty_StreamDescription,&outADSB,&size)
//创建三个默认的Audioqueue队列。并塞入静音数据,手动调用一次callbackfor_in0..<self.audioQueueNum {var buffer:AudioQueueBufferRef?AudioQueueAllocateBuffer(self.audioQueue!,self.byteSizeInBuffer,&buffer)//往buffer 中填充默认的静音数据let buf =UnsafeMutableRawPointer.allocate(byteCount:Int(self.byteSizeInBuffer), alignment:1)memset(buf,0,Int(self.byteSizeInBuffer))TPCircularBufferProduceBytes(&self.tpBuffer, buf,self.byteSizeInBuffer)
            buf.deallocate()callback(UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()),self.audioQueue!, buffer!)}
//正式开始AudioQueueStart(self.audioQueue!,nil)
//开始后会自动回调callbackprivatelet callback:AudioQueueOutputCallback={
        inUserData, queue,  bufferRef in....//判断数据是否足够,从circle bufer拿出数据,进行转码//将合适的格式大小的数据,塞入播放队列AudioQueueEnqueueBuffer(queue,
                                              bufferRef,0,nil)}
//stopAudioQueueStop(self.audioQueue!,true)AudioQueueDispose(self.audioQueue!,true)

5. AudioQueue 采集

//创建 queueJBAssertNoError(AudioQueueNewInput(&_mDataFormat,
                                       captureAudioDataCallback,(__bridge void*)(self),NULL,
                                       kCFRunLoopCommonModes,0,&_mQueue),//获取asbdAudioQueueGetProperty(_mQueue,kAudioQueueProperty_StreamDescription,&_mDataFormat,&size),//内存分配,入队for(int i =0; i != KNumberBuffers; i++){JBAssertNoError(AudioQueueAllocateBuffer(_mQueue, bufferByteSize,&_mBuffers[i]), @"AudioQueueAllocateBuffer");JBAssertNoError(AudioQueueEnqueueBuffer(_mQueue, _mBuffers[i],0,NULL), @"AudioQueueEnqueueBuffer");}//启动audio queue , 第二个参数设置为NULL表示立即开始采集数据.JBAssertNoError(AudioQueueStart(_mQueue,NULL), @"AudioQueueStart");staticvoidcaptureAudioDataCallback(void*__nullable  inUserData,...){//写入和拷贝数据...//释放队列AudioQueueEnqueueBuffer(inAQ, inBuffer,0,NULL),}//关闭JBAssertNoError(AudioQueueStop(_mQueue, true),@"AudioQueueStop");JBAssertNoError(AudioQueueDispose(_mQueue, true), @"AudioQueueDispose");

6. AudioUnit 采集


本文转载自: https://blog.csdn.net/goldWave01/article/details/134974429
版权归原作者 jimboRen 所有, 如有侵权,请联系我们删除。

“Cocoa Mac音频模块关键步骤总结”的评论:

还没有评论