#include
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 Captured if(inOperationID == kAudioServerPlugInIOOperationReadInput) { return sendDataToOtherApp(inIOBufferFrameSize, inIOCycleInfo, ioMainBuffer); } // other app -> virutal device if(inOperationID == kAudioServerPlugInIOOperationWriteMix) { return getDataFromOtherApp(inIOBufferFrameSize, inIOCycleInfo, ioMainBuffer); }
//这个函数可以不管
static OSStatus xxx_EndIOOperation(...)
//准备获取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); //轮询列表获取合适的id AudioObjectGetPropertyData(deviceID, &address, 0, NULL, &size, &prop); //创建和析构监听 AudioObjectAddPropertyListener(...kAudioDevicePropertyDeviceIsAlive) AudioObjectRemovePropertyListener(...kAudioDevicePropertyNominalSampleRate)
#import
#import
//绑定
OSStatus status = AudioDeviceCreateIOProcID(设备ID, deviceIOProcFunc/*回调函数*/, this, &mDeviceIOProcID/*创建的io句柄*/);
//开始
OSStatus status = AudioDeviceStart(mDevice.getNeedID(), mDeviceIOProcID);
//回调
。。。
//销毁
AudioDeviceDestroyIOProcID(mDevice.getNeedID(), mDeviceIOProcID);
头文件 #include
//创建转换对象 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的资源
//创建Audioqueue对象,并配置callback AudioQueueNewOutput(&inASBD, callback, UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()), nil, nil, 0, &self.audioQueue)
//自定义输出设备,如果不想用默认的话 var cuStr = "FC-E8-06-DB-74-1D:output" as CFString AudioQueueSetProperty(self.audioQueue!, kAudioQueueProperty_CurrentDevice, &cuStr, size)
//获取输出设备的 asbd, 方便后面转码 AudioQueueGetProperty(self.audioQueue!, kAudioQueueProperty_StreamDescription, &outADSB, &size)
//创建三个默认的Audioqueue队列。并塞入静音数据,手动调用一次callback for _ in 0..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)
//开始后会自动回调callback private let callback: AudioQueueOutputCallback = { inUserData, queue, bufferRef in .... //判断数据是否足够,从circle bufer拿出数据,进行转码 //将合适的格式大小的数据,塞入播放队列 AudioQueueEnqueueBuffer(queue, bufferRef, 0, nil) }
//stop AudioQueueStop(self.audioQueue!, true) AudioQueueDispose(self.audioQueue!, true)
//创建 queue JBAssertNoError(AudioQueueNewInput(&_mDataFormat, captureAudioDataCallback, (__bridge void *)(self), NULL, kCFRunLoopCommonModes, 0, &_mQueue), //获取asbd AudioQueueGetProperty(_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"); static void captureAudioDataCallback(void *__nullable inUserData,...) { //写入和拷贝数据 ... //释放队列 AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL), } //关闭 JBAssertNoError(AudioQueueStop(_mQueue, true),@"AudioQueueStop"); JBAssertNoError(AudioQueueDispose(_mQueue, true), @"AudioQueueDispose");
上一篇:【专栏目录】