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

news/2024/7/20 21:10:55 标签: 音视频, 开发语言, macos, ios

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 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(...)

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);
    //轮询列表获取合适的id
    AudioObjectGetPropertyData(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对象,并配置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..<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)
//开始后会自动回调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)

5. AudioQueue 采集

  //创建 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");

6. AudioUnit 采集


http://www.niftyadmin.cn/n/5260790.html

相关文章

数据结构实验任务八:排序算法的实现与分析

问题描述 统计成绩&#xff1a;给出 n 个学生的考试成绩表&#xff0c;每条信息由姓名和分数组成&#xff0c;试设 计一个算法&#xff1a; 1.按分数高低次序&#xff0c;打印出每个学生在考试中获得的名次&#xff0c;分数相同的为同 一名次&#xff1b; 2.按名次列出每个学生…

Visual Studio Code (Vscode)配置LaTeX

Visual Studio Code (Vscode)配置LaTeX 实操记录 第一步高效检索&#xff0c;找到官方的、靠谱的安装教程&#xff0c;最好多找几个&#xff0c;英文、中文教程都需要 LaTeX WorkshopInstallation and basic settingsHow to install LaTeX (with previews & autocomplete…

css 使用flex 完成瀑布流布局

瀑布流布局在商城类、文章类 app、网页中都是常用的&#xff0c;使用这样的形式&#xff0c;能过让整个页面更加的活波&#xff0c;也能让图片根据实际的大小来显示&#xff0c;更好的展示图片内容。那么代码如何实现呢 实现的效果 代码 <template><view class"…

【Azure 架构师学习笔记】- Azure Databricks (3) - 再次认识DataBricks

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Databricks】系列。 接上文 【Azure 架构师学习笔记】- Azure Databricks (2) -集群 前言 在对Databricks有了初步了解之后&#xff0c;如果要深入使用则需要对其进行更深层次的了解。 Databricks ADB 是一个统一的…

设计模式——观察者模式(Observer Pattern)

概述 观察者模式是使用频率最高的设计模式之一&#xff0c;它用于建立一种对象与对象之间的依赖关系&#xff0c;一个对象发生改变时将自动通知其他对象&#xff0c;其他对象将相应作出反应。在观察者模式中&#xff0c;发生改变的对象称为观察目标&#xff0c;而被通知的对象称…

YashanDB携手深智城集团联合发布智慧城市解决方案

近日&#xff0c;在YashanDB 2023年度发布会上&#xff0c;深圳计算科学研究院携手深圳市智慧城市科技发展集团有限公司&#xff08;简称“深智城集团”&#xff09;重磅推出基于崖山数据库YashanDB的智慧城市解决方案&#xff0c;该联合解决方案高效支撑了深圳市CIM平台的建设…

计算机网络 第三章(数据链路层)【中】

参考教程&#xff1a;3.6.1 媒体接入控制的基本概念_哔哩哔哩_bilibili 六、媒体接入控制 1、共享信道需要解决的问题 &#xff08;1&#xff09;下图所示是一根同轴电缆&#xff0c;有多台主机连接到这根同轴电缆上&#xff0c;它们共享这根传输媒体&#xff0c;形成了一个…

rk3568 RGMII KSZ8795 MAC TO MAC

RK3568与KSZ8795交换机芯片连接&#xff0c;直接MAC TO MAC方式&#xff0c;这样一下就扩展会4路网口&#xff0c;应该场合比较多&#xff0c;移植过程如下&#xff1a; 参考《Rockchip_Developer_Guide_Linux_MAC_TO_MAC_CN.pdf》 《rockchip RGMIImv88e6390 管理型交换机功…