Parade Series - CoreAudio Loopback

Scenario

鉴于业务场景需要, 经过技术路径探索, 发现 comtypes 兼容性过于混乱,故而考虑整合一个 CoreAudio 的轮子dll来解决实际问题!

在这里插入图片描述
在这里插入图片描述
std::StringStream ⇒ std::ios::binary ⇒ std::ofstream
在这里插入图片描述
在这里插入图片描述

Loopback.dll

#ifndef _DLL_CORE_AUDIO_LOOPBACK_LOCK
#define _DLL_CORE_AUDIO_LOOPBACK_LOCK#pragma data_seg("Shared")
HANDLE hMutex = NULL;
UINT   liveIndex = 0;
CComPtr<IMMDeviceEnumerator> pEnumerator;
#pragma data_seg()
#pragma comment(linker, "/section:Shared,rws")
class TimespanGuard {
public:TimespanGuard(){this->_bof_time = GetTickCount();this->_token = "Timespan";}TimespanGuard(std::string token){this->_bof_time = GetTickCount();_token = token;}~TimespanGuard(){this->_eof_time = GetTickCount();std::cout << "" << this->_token << " > " << (this->_eof_time - this->_bof_time) << "ms elapsed" << std::endl;}private:DWORD _bof_time, _eof_time;std::string _token;
};
CORE_AUDIO_LOOPBACK_API BOOL WINAPI init(UINT devNum)
{TimespanGuard timespanGuard("init");HRESULT hr{};CoInitializeGuard coInitializeGuard;if (FAILED(coInitializeGuard.result())) {return (FALSE);    // BOOL FALSE 0x0000}hr = pEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator));if (FAILED(hr)) {return (FALSE);    // BOOL FALSE 0x0000}Sleep(10);return (TRUE);         // BOOL TRUE  0x0001
}

在这里插入图片描述

CORE_AUDIO_LOOPBACK_API BOOL WINAPI getChunk(UINT devNum, UINT (*dtChunk)[2], UINT nDimension)
{TimespanGuard timespanGuard("getChunk");HRESULT hr{};CoInitializeGuard coInitializeGuard;if (FAILED(coInitializeGuard.result())) {return (FALSE);    // BOOL FALSE 0x0000}hr = pEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator));if (FAILED(hr)) {return (FALSE);    // BOOL FALSE 0x0000}std::cout << "getChunk > " << (nDimension) << "x" << (2) << std::endl;for (int i = 0; i < nDimension; i++) {printf("\t#%.4d ", i);for (int j = 0; j < 2; j++) {printf("%8d ", dtChunk[i][j]);dtChunk[i][j] = dtChunk[i][j] + 100;}printf("\n");}Sleep(10);return (TRUE);         // BOOL TRUE  0x0001
}
CORE_AUDIO_LOOPBACK_API BOOL WINAPI release(UINT devNum)
{TimespanGuard timespanGuard("release");CoUninitialize();return (TRUE);         // BOOL TRUE  0x0001
}

XAudio.py

import ctypesif True:loopback = ctypes.CDLL("loopback.dll")if True:loopback.getAudio.argtypes = [c_int, c_char_p, c_int]loopback.getAudio.restype = c_intdevNum = c_int(0)bytesSize = 256bytesName = (' ' * bytesSize).encode('utf-8')result = loopback.getAudio(devNum, bytesName, bytesSize)print('DLL invoked > ', result, (bytesName.decode('gb2312')))

GetBitmapBits 后位图颠倒

	dumpCache(dataBuff, result);GetBitmapBits(hOutputBitmap, nBytesSize, rawData); // 获取位图的位for (int i = 0; i < nBytesSize; i++) {int row, column = 0;row = (sHeight - (i / bm.bmWidthBytes)) - 1;column = (i % bm.bmWidthBytes);dataBuff[result + row * bm.bmWidthBytes + column] = (rawData[i] & 0x00FF);}result += nBytesSize;
dumpCache(dataBuff, result);

dumpCache

BOOL dumpCache(BYTE* dataBuff, UINT buffSize)
{for (int i = 0; i < buffSize; i++) {printf("%.2X ", dataBuff[i]);if (i % 16 == 15)printf("\n");}printf("\n");return (TRUE);
}

getBitmapHeader

UINT getBitmapHeader(HDC hDC, HBITMAP hBitmap, BYTE* dataBuff, UINT buffSize)
{UINT result = 0;int iBits;//当前显示分辨率下每个像素所占字节数WORD wBitCount;//位图中每个像素所占字节数//定义调色板大小, 位图中像素字节大小 , 位图文件大小 , 写入文件字节数DWORD dwPaletteSize = 0, dwBmBitsSize, dwDIBSize, dwWritten;BITMAP Bitmap;//位图属性结构BITMAPFILEHEADER bmfHdr;//位图文件头结构BITMAPINFOHEADER bi;//位图信息头结构LPBITMAPINFOHEADER lpbi;//指向位图信息头结构HANDLE fh, hDib, hPal;HPALETTE hOldPal = NULL;//定义文件,分配内存句柄,调色板句柄//计算位图文件每个像素所占字节数iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);if (iBits <= 1)wBitCount = 1;else if (iBits <= 4)wBitCount = 4;else if (iBits <= 8)wBitCount = 8;else if (iBits <= 24)wBitCount = 24;elsewBitCount = 32;//计算调色板大小if (wBitCount <= 8)dwPaletteSize = (1 << wBitCount) * sizeof(RGBQUAD);//设置位图信息头结构GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);bi.biSize = sizeof(BITMAPINFOHEADER);bi.biWidth = Bitmap.bmWidth;bi.biHeight = Bitmap.bmHeight;bi.biPlanes = 1;bi.biBitCount = wBitCount;bi.biCompression = BI_RGB;bi.biSizeImage = 0;bi.biXPelsPerMeter = 0;bi.biYPelsPerMeter = 0;bi.biClrUsed = 0;bi.biClrImportant = 0;dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight;//为位图内容分配内存hDib = GlobalAlloc(GHND, dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);*lpbi = bi;// 处理调色板  hPal = GetStockObject(DEFAULT_PALETTE);if (hPal){hDC = ::GetDC(NULL);hOldPal = SelectPalette(hDC, (HPALETTE)hPal, FALSE);RealizePalette(hDC);}// 获取该调色板下新的像素值GetDIBits(hDC, hBitmap, 0, (UINT)Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER) + dwPaletteSize, (BITMAPINFO*)lpbi, DIB_RGB_COLORS);//恢复调色板  if (hOldPal){SelectPalette(hDC, hOldPal, TRUE);RealizePalette(hDC);::ReleaseDC(NULL, hDC);}// 设置位图文件头bmfHdr.bfType = 0x4D42; // "BM"dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;bmfHdr.bfSize = dwDIBSize;bmfHdr.bfReserved1 = 0;bmfHdr.bfReserved2 = 0;bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize;// 写入位图文件头memcpy(dataBuff, (BYTE*)&bmfHdr, sizeof(BITMAPFILEHEADER));result += sizeof(BITMAPFILEHEADER);memcpy((dataBuff + result), (BYTE*)lpbi, ((DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize));result += sizeof(BITMAPINFOHEADER);result += dwPaletteSize;//清除  GlobalUnlock(hDib);GlobalFree(hDib);return (result);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/1134.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数学建模--非线性规划模型+MATLAB代码保姆式解析

目录 1.简单介绍 2.求解方法 3.适用赛题 4.典型例题及相关分析 &#xff08;1&#xff09;问题引入 &#xff08;2&#xff09;决策变量&约束条件 &#xff08;3&#xff09;确定目标函数 &#xff08;4&#xff09;建立数学模型 5.MATLAB代码祝逐字句讲解 1.简单…

批量添加集合元素

方法一: Collections.addAll() 方法内部会迭代传递给它的元素列表&#xff0c;并将每个元素添加到目标集合中。 List<Integer> list new ArrayList<>();Collections.addAll(list,1,2,3,4,5); 方式二: ArrayList 类有一个构造函数&#xff0c;它接受一个 Colle…

Redis系列之Cluster集群搭建

在上一篇博客&#xff0c;我们学习Redis哨兵Sentinel集群的搭建&#xff0c;redis的哨兵模式提供了比如监控、自动故障转移等高可用方案&#xff0c;但是这种方案&#xff0c;容量相对固定&#xff0c;要进行持续扩容或者数据分片就不适合&#xff0c;所以有另外一种更复杂的集…

CentOS常见命令

以下是一些常见的CentOS命令&#xff1a; 管理文件和目录&#xff1a; ls&#xff1a;列出目录中的文件和子目录。cd&#xff1a;切换目录。mkdir&#xff1a;创建一个新的目录。rm&#xff1a;删除文件或目录。cp&#xff1a;复制文件或目录。mv&#xff1a;移动或重命名文件…

探索Java设计模式:桥接模式

探索Java设计模式&#xff1a;深入理解与实践桥接模式 桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式&#xff0c;它将抽象部分与其实现部分分离&#xff0c;使它们可以独立变化。在Java编程中&#xff0c;桥接模式常用于实现多维度变化、降低类的层次…

图像处理的魔法师:Pillow 库探秘

文章目录 图像处理的魔法师&#xff1a;Pillow 库探秘第一部分&#xff1a;背景介绍第二部分&#xff1a;库是什么&#xff1f;第三部分&#xff1a;如何安装这个库&#xff1f;第四部分&#xff1a;库函数使用方法第五部分&#xff1a;场景应用第六部分&#xff1a;常见Bug及解…

YOLOv9改进策略 | 添加注意力篇 | 利用ILSVRC冠军得主SENetV1改善网络模型特征提取能力

一、本文介绍 本文给大家带来的改进机制是SENet&#xff08;Squeeze-and-Excitation Networks&#xff09;其是一种通过调整卷积网络中的通道关系来提升性能的网络结构。SENet并不是一个独立的网络模型&#xff0c;而是一个可以和现有的任何一个模型相结合的模块(可以看作是一…

最新Java面试题3【2024中级】

互联网大厂面试题 1&#xff1a;阿里巴巴Java面试题 2&#xff1a;阿里云Java面试题-实习生岗 3&#xff1a;腾讯Java面试题-高级 4&#xff1a;字节跳动Java面试题 5&#xff1a;字节跳动Java面试题-大数据方向 6&#xff1a;百度Java面试题 7&#xff1a;蚂蚁金服Java…

消息转化器(解决由于后端给前端响应的格式中不能处理Long类型,因为js只会处理前16位,这样会导致后面的精度丢失)

问题描述&#xff1a;由于后端给前端响应的格式中不能处理Long类型&#xff0c;因为js只会处理前16位&#xff0c;这样会导致后面的精度丢失。 解决方法&#xff0c;将后端响应给前端的数据转化位JSON格式&#xff0c;将long类型的序列化一下 下面为具体方法(JAVA对象转化为J…

PyCharm,终端conda环境无法切换的问题(二个解决方案)

问题 PyCharm终端&#xff0c;环境切换无效&#xff0c;默认始终为base 解决一 Settings->Tools->Terminal->ShellPath&#xff0c;将powershell修改为cmd.exe 解决二 conda config --show在输出中找到 auto_activate_base 的行&#xff0c;发现被设置为 true&#x…

HTML作业

作业1: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style>.down…

腾讯云开通幻兽帕鲁服务器需要多少钱?30元

腾讯云开通一个幻兽帕鲁服务器需要多少钱&#xff1f;32元1个月&#xff0c;腾讯云专用幻兽帕鲁服务器最低只要32元1个月&#xff0c;配置为4核16G12M&#xff0c;96元3个月、156元6个月。幻兽帕鲁专用服务器8核32G22M配置115元1个月、345元3个月。幻兽帕鲁服务器活动页面 txyb…

GateWay基本配置

在现代的微服务架构中&#xff0c;网关是一个非常重要的组件&#xff0c;它充当了所有外部请求的入口&#xff0c;负责路由、过滤、监控等功能。Spring Cloud Gateway是一个基于Spring Framework 5、Project Reactor和Spring Boot 2的网关服务&#xff0c;它提供了一种简单而有…

Android Studio Iguana | 2023.2.1配置优化

一. 前言 本篇文章记录最新版本的Android Studio的配置优化&#xff0c;写这篇文章的是由于电脑中的AS工具更新版本覆盖安装后&#xff0c;AS会经常卡死&#xff0c;Debug的时候也经常莫名其妙的断掉&#xff0c;非常影响工作效率&#xff0c;所以重新把配置环境整理一下&#…

Beautiful Soup 库介绍

Beautiful Soup 是一个用于解析和处理 HTML 或 XML 文档的 Python 库。它提供了一套简单易用的工具&#xff0c;可以帮助您从网页中提取数据、导航文档结构、修改文档内容等。 主要功能: 解析 HTML 或 XML 文档: Beautiful Soup 可以将 HTML 或 XML 文档解析为树状结构&#…

11.事件处理

事件处理 我们可以使用 v-on 指令 (简写为 ) 来监听 DOM 事件&#xff0c;并在事件触发时执行对应的 JavaScript。用法&#xff1a;v-on:click"methodName" 或 click"handler" 事件处理器的值可以是 内联事件处理器&#xff1a;事件被触发时执行的内联 J…

[阅读笔记21][RA-CM3]Retrieval-Augmented Multimodal Language Modeling

这篇论文是meta联合斯坦福在23年4月发表的论文&#xff0c;提出了一个使用外部知识检索增强的多模态模型。 这篇模型提出的RA-CM3模型是第一个能够检索并生成图像文本的多模态模型&#xff0c;在图像文本生成任务上优于现有的多模态模型&#xff0c;同时使用更少的训练量。 RA-…

.NET StackExchange.Redis 操作redis

下面是一个简单的示例&#xff0c;展示了如何使用 C# 中的 StackExchange.Redis 库与 Redis 进行交互&#xff0c;包括字符串&#xff08;String&#xff09;、哈希&#xff08;Hash&#xff09;、列表&#xff08;List&#xff09;、集合&#xff08;Set&#xff09;和有序集合…

区间图着色问题:贪心算法设计及实现

区间图着色问题&#xff1a;贪心算法设计及实现 1. 问题定义2. 贪心算法设计2.1 活动排序2.2 分配教室2.3 算法终止 3. 伪代码4. C语言实现5. 算法分析6. 结论7. 参考文献 在本文中&#xff0c;我们将探讨如何使用贪心算法解决一个特定的资源分配问题&#xff0c;即区间图着色问…

物联网实战--驱动篇之(九)NB-IOT(BC260)

目录 一、NB-IOT简介 二、NB-IOT要素 三、代码详解 四、平台端 一、NB-IOT简介 实际上&#xff0c;就是NB-Iot彻底引爆了物联网的&#xff0c;大概2018年左右&#xff0c;NB推广如火如荼&#xff0c;同时广域网、低功耗的LPWAN网络也逐渐传开&#xff0c;现在回头来看&…