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使用date模块进行日期处理的终极指南

《Python使用date模块进行日期处理的终极指南》在处理与时间相关的数据时,Python的date模块是开发者最趁手的工具之一,本文将用通俗的语言,结合真实案例,带您掌握date模块的六大核心功能... 目录引言一、date模块的核心功能1.1 日期表示1.2 日期计算1.3 日期比较二、六大常用方法详

使用Python实现文本转语音(TTS)并播放音频

《使用Python实现文本转语音(TTS)并播放音频》在开发涉及语音交互或需要语音提示的应用时,文本转语音(TTS)技术是一个非常实用的工具,下面我们来看看如何使用gTTS和playsound库将文本... 目录什么是 gTTS 和 playsound安装依赖库实现步骤 1. 导入库2. 定义文本和语言 3

java常见报错及解决方案总结

《java常见报错及解决方案总结》:本文主要介绍Java编程中常见错误类型及示例,包括语法错误、空指针异常、数组下标越界、类型转换异常、文件未找到异常、除以零异常、非法线程操作异常、方法未定义异常... 目录1. 语法错误 (Syntax Errors)示例 1:解决方案:2. 空指针异常 (NullPoi

python中time模块的常用方法及应用详解

《python中time模块的常用方法及应用详解》在Python开发中,时间处理是绕不开的刚需场景,从性能计时到定时任务,从日志记录到数据同步,时间模块始终是开发者最得力的工具之一,本文将通过真实案例... 目录一、时间基石:time.time()典型场景:程序性能分析进阶技巧:结合上下文管理器实现自动计时

Python解析器安装指南分享(Mac/Windows/Linux)

《Python解析器安装指南分享(Mac/Windows/Linux)》:本文主要介绍Python解析器安装指南(Mac/Windows/Linux),具有很好的参考价值,希望对大家有所帮助,如有... 目NMNkN录1js. 安装包下载1.1 python 下载官网2.核心安装方式3. MACOS 系统安

详解如何使用Python提取视频文件中的音频

《详解如何使用Python提取视频文件中的音频》在多媒体处理中,有时我们需要从视频文件中提取音频,本文为大家整理了几种使用Python编程语言提取视频文件中的音频的方法,大家可以根据需要进行选择... 目录引言代码部分方法扩展引言在多媒体处理中,有时我们需要从视频文件中提取音频,以便进一步处理或分析。本文

Java反转字符串的五种方法总结

《Java反转字符串的五种方法总结》:本文主要介绍五种在Java中反转字符串的方法,包括使用StringBuilder的reverse()方法、字符数组、自定义StringBuilder方法、直接... 目录前言方法一:使用StringBuilder的reverse()方法方法二:使用字符数组方法三:使用自

如何关闭 Mac 触发角功能或设置修饰键? mac电脑防止误触设置技巧

《如何关闭Mac触发角功能或设置修饰键?mac电脑防止误触设置技巧》从Windows换到iOS大半年来,触发角是我觉得值得吹爆的MacBook效率神器,成为一大说服理由,下面我们就来看看mac电... MAC 的「触发角」功能虽然提高了效率,但过于灵敏也让不少用户感到头疼。特别是在关键时刻,一不小心就可能触

Python依赖库的几种离线安装方法总结

《Python依赖库的几种离线安装方法总结》:本文主要介绍如何在Python中使用pip工具进行依赖库的安装和管理,包括如何导出和导入依赖包列表、如何下载和安装单个或多个库包及其依赖,以及如何指定... 目录前言一、如何copy一个python环境二、如何下载一个包及其依赖并安装三、如何导出requirem

Node.js net模块的使用示例

《Node.jsnet模块的使用示例》本文主要介绍了Node.jsnet模块的使用示例,net模块支持TCP通信,处理TCP连接和数据传输,具有一定的参考价值,感兴趣的可以了解一下... 目录简介引入 net 模块核心概念TCP (传输控制协议)Socket服务器TCP 服务器创建基本服务器服务器配置选项服