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

2023-12-17 12:30

本文主要是介绍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){return sendDataToOtherApp(inIOBufferFrameSize, inIOCycleInfo, ioMainBuffer);}// other app -> virutal deviceif(inOperationID == kAudioServerPlugInIOOperationWriteMix){return getDataFromOtherApp(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" as CFStringAudioQueueSetProperty(self.audioQueue!, kAudioQueueProperty_CurrentDevice, &cuStr, size)
//获取输出设备的 asbd, 方便后面转码
AudioQueueGetProperty(self.audioQueue!, kAudioQueueProperty_StreamDescription, &outADSB, &size)
//创建三个默认的Audioqueue队列。并塞入静音数据,手动调用一次callbackfor _ in 0..<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)
//开始后会自动回调callbackprivate let 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");static void captureAudioDataCallback(void *__nullable  inUserData,...) {
//写入和拷贝数据
...
//释放队列AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL),
}
//关闭JBAssertNoError(AudioQueueStop(_mQueue, true),@"AudioQueueStop");JBAssertNoError(AudioQueueDispose(_mQueue, true), @"AudioQueueDispose");

6. AudioUnit 采集

这篇关于Cocoa Mac音频模块关键步骤总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/504366

相关文章

Python实现视频转换为音频的方法详解

《Python实现视频转换为音频的方法详解》这篇文章主要为大家详细Python如何将视频转换为音频并将音频文件保存到特定文件夹下,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. python需求的任务2. Python代码的实现3. 代码修改的位置4. 运行结果5. 注意事项

Python利用自带模块实现屏幕像素高效操作

《Python利用自带模块实现屏幕像素高效操作》这篇文章主要为大家详细介绍了Python如何利用自带模块实现屏幕像素高效操作,文中的示例代码讲解详,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、获取屏幕放缩比例2、获取屏幕指定坐标处像素颜色3、一个简单的使用案例4、总结1、获取屏幕放缩比例from

nginx-rtmp-module模块实现视频点播的示例代码

《nginx-rtmp-module模块实现视频点播的示例代码》本文主要介绍了nginx-rtmp-module模块实现视频点播,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录预置条件Nginx点播基本配置点播远程文件指定多个播放位置参考预置条件配置点播服务器 192.

Python中连接不同数据库的方法总结

《Python中连接不同数据库的方法总结》在数据驱动的现代应用开发中,Python凭借其丰富的库和强大的生态系统,成为连接各种数据库的理想编程语言,下面我们就来看看如何使用Python实现连接常用的几... 目录一、连接mysql数据库二、连接PostgreSQL数据库三、连接SQLite数据库四、连接Mo

C++实现获取本机MAC地址与IP地址

《C++实现获取本机MAC地址与IP地址》这篇文章主要为大家详细介绍了C++实现获取本机MAC地址与IP地址的两种方式,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 实际工作中,项目上常常需要获取本机的IP地址和MAC地址,在此使用两种方案获取1.MFC中获取IP和MAC地址获取

C/C++通过IP获取局域网网卡MAC地址

《C/C++通过IP获取局域网网卡MAC地址》这篇文章主要为大家详细介绍了C++如何通过Win32API函数SendARP从IP地址获取局域网内网卡的MAC地址,感兴趣的小伙伴可以跟随小编一起学习一下... C/C++通过IP获取局域网网卡MAC地址通过win32 SendARP获取MAC地址代码#i

Git提交代码详细流程及问题总结

《Git提交代码详细流程及问题总结》:本文主要介绍Git的三大分区,分别是工作区、暂存区和版本库,并详细描述了提交、推送、拉取代码和合并分支的流程,文中通过代码介绍的非常详解,需要的朋友可以参考下... 目录1.git 三大分区2.Git提交、推送、拉取代码、合并分支详细流程3.问题总结4.git push

Kubernetes常用命令大全近期总结

《Kubernetes常用命令大全近期总结》Kubernetes是用于大规模部署和管理这些容器的开源软件-在希腊语中,这个词还有“舵手”或“飞行员”的意思,使用Kubernetes(有时被称为“... 目录前言Kubernetes 的工作原理为什么要使用 Kubernetes?Kubernetes常用命令总

2.1/5.1和7.1声道系统有什么区别? 音频声道的专业知识科普

《2.1/5.1和7.1声道系统有什么区别?音频声道的专业知识科普》当设置环绕声系统时,会遇到2.1、5.1、7.1、7.1.2、9.1等数字,当一遍又一遍地看到它们时,可能想知道它们是什... 想要把智能电视自带的音响升级成专业级的家庭影院系统吗?那么你将面临一个重要的选择——使用 2.1、5.1 还是

mac中资源库在哪? macOS资源库文件夹详解

《mac中资源库在哪?macOS资源库文件夹详解》经常使用Mac电脑的用户会发现,找不到Mac电脑的资源库,我们怎么打开资源库并使用呢?下面我们就来看看macOS资源库文件夹详解... 在 MACOS 系统中,「资源库」文件夹是用来存放操作系统和 App 设置的核心位置。虽然平时我们很少直接跟它打交道,但了