Parade Series - CoreAudio Loopback

news2024/12/25 8:51:13

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 ctypes

if True:
	loopback = ctypes.CDLL("loopback.dll")
    if True:
        loopback.getAudio.argtypes = [c_int, c_char_p, c_int]
        loopback.getAudio.restype = c_int

        devNum = c_int(0)
        bytesSize = 256
        bytesName = (' ' * 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;
	else
		wBitCount = 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.coloradmin.cn/o/1611403.html

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

相关文章

第63天:服务攻防-框架安全CVE 复现DjangoFlaskNode.JSJQuery

目录 思维导图 案例一&#xff1a;JavaScript-开发框架安全-Jquery&Node node.js目录穿越 CVE-2021-21315命令执行 Jquery CVE-2018-9207 案例二&#xff1a;Python-开发框架安全-Django&Flask django cve_2019_14234 CVE-2021-35042 flask ssti 思维导图 案…

LeetCode刷题实战4:寻找两个正序数组的中位数

题目内容 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&#xff09;数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。 算法的时间复杂度应该为 O(log (mn)) 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,3], nums2 [2] 输出&#xff1a;2.0…

Three.js--》探秘虚拟现实VR展厅的视觉盛宴

今天简单实现一个three.js的小Demo&#xff0c;加强自己对three知识的掌握与学习&#xff0c;只有在项目中才能灵活将所学知识运用起来&#xff0c;话不多说直接开始。 目录 项目搭建 初始化three代码 camera-controls控制器使用 添加画框 画框处理事件 添加机器人模型 …

一文学会 ts 构建工具 —— tsup

文章目录 能打包什么&#xff1f;安装用法自定义配置文件条件配置在 package.json 中配置多入口打包生成类型声明文件sourcemap生成格式自定义输出文件代码分割产物目标环境支持 es5编译的环境变量对开发命令行工具友好监听模式 watch提供成功构建的钩子 onSuccess压缩产物 min…

LLMs之Llama3:Llama 3的简介、安装和使用方法、案例应用之详细攻略

LLMs之Llama3&#xff1a;Llama 3的简介、安装和使用方法、案例应用之详细攻略 导读&#xff1a;2024年4月18日&#xff0c;Meta 重磅推出了Meta Llama 3&#xff0c;本文章主要介绍了Meta推出的新的开源大语言模型Meta Llama 3。模型架构 Llama 3 是一种自回归语言模型&#x…

gdb 调试常用命令

运行命令 run简写r 运行程序&#xff0c;当遇到断点后&#xff0c;程序会在断点处停止运行continue简写c 运行到下一个断点next简写n 执行下一步语句&#xff0c;不进入函数step简写s 执行下一步语句until运行到循环体结束until 行数运行到某一行call 函数(参数)调用函数finis…

Windows10安装配置nodejs环境

一、下载 下载地址&#xff1a;https://nodejs.cn/download/ ​ 二、安装 1、找到node-v16.17.0-x64.msi安装包, 根据默认提示安装, 过程中间的弹窗不勾选 2、安装完成后, 打开powershell(管理员身份) ​ 3、命令行输入 node -v 和 npm -v 如下图所示则nodejs安装成功 ​ 三…

人大金仓参与编写《通信行业信息技术应用创新发展白皮书(2024年)》正式发布...

近日&#xff0c;由中国信息通信研究院技术与标准研究所主办的通信行业信创发展分论坛在京成功举办&#xff0c;人大金仓受邀分享行业信创实践经验及成果。论坛上正式发布了人大金仓参与编写的《通信行业信息技术应用创新发展白皮书&#xff08;2024年&#xff09;》。 本次论坛…

pycharm创建的项目

pycharm生成django templates删出 settings.py

解锁ApplicationContext vs BeanFactory: 谁更具选择性?

目录 一、聚焦源码回顾 &#xff08;一&#xff09;源码分析和理解 &#xff08;二&#xff09;简短的回顾对比建议 二、ApplicationContext vs BeanFactory特性对比 &#xff08;一&#xff09;主要特性总结 &#xff08;二&#xff09;直接建议 三、案例简单说明 &am…

21.组件组成

组件组成 组件最大的优势就是可复用性 当使用构建步骤时&#xff0c;我们一般会将 Vue 组件定义在一个单独的 .vue 文件中&#xff0c;这被叫做单文件组件(简称 SFC) 组件组成结构 <template><div>承载标签</div> </template> <script> expor…

矽塔SA8321 单通道 2.7-12.0V 持续电流 3.0A H 桥驱动芯片

描述 SA8321是为消费类产品&#xff0c;玩具和其他低压或者电池供电的运动控制类应用提供了一个集成的电机驱动器解决方案。此器件能够驱动一个直流无刷电机&#xff0c;由一个内部电荷泵生成所需的栅极驱动电压电路和4个功率 NMOS组成H桥驱动&#xff0c;集成了电机正转/反…

【ThinkPHP框架教程·Part-01】ThinkPHP6.x框架安装教程

文章目录 一、框架介绍1、框架简介和版本选择2、主要新特性 二、安装步骤1、下载并运行Composer-Setup.exe2、安装TP前切换镜像3、安装稳定版4、测试运行 一、框架介绍 1、框架简介和版本选择 Thinkphp是一种基于php的开源web应用程序开发框架ThinkPHP框架&#xff0c;是免费开…

封装个js分页插件

// 分页插件类 class PaginationPlugin {constructor(fetchDataURL, options {}) {this.fetchDataURL fetchDataURL;this.options {containerId: options.containerId || paginationContainer,dataSizeAttr: options.dataSizeAttr || toatalsize, // 修改为实际API返回的数据…

easyx库的学习(文字绘制)

前言 昨天刚刚写完了基本图形的制作&#xff0c;今天直接可以来看看&#xff0c;在easyx中使用文字 直接看代码吧 文字绘制 void drawTest() {printf("hello,EasyX");//指的是在控制台打印//设置字体大小&#xff0c;样式settextstyle(30, 0, "微软雅黑&quo…

二维码门楼牌管理应用平台建设:核实与审核的关键作用

文章目录 前言一、二维码门楼牌管理应用平台的建设背景二、核实与审核在二维码门楼牌管理中的应用三、核实与审核的重要性四、优化建议 前言 随着信息技术的快速发展&#xff0c;二维码门楼牌管理应用平台在社区管理中发挥着越来越重要的作用。本文将深入探讨该平台建设过程中…

数据结构––kmp算法(串)

kmp算法作为串的一个重要内容&#xff0c;必然有一定的难度&#xff0c;而在看到各类教辅书里的概念与解释后&#xff0c;其晦涩难懂的内容直接劝退一部分人&#xff0c;现在&#xff0c;让我们来看看吧 KMP解决的问题类型 KMP算法的作用就是在一个已知的字符串中查找子串的位…

一次Redis访问超时的“捉虫”之旅

01 引言 作为后端开发人员&#xff0c;对Redis肯定不陌生&#xff0c;它是一款基于内存的数据库&#xff0c;读写速度非常快。在爱奇艺海外后端的项目中&#xff0c;我们也广泛使用Redis&#xff0c;主要用于缓存、消息队列和分布式锁等场景。最近在对一个老项目使用的docker镜…

HTML、CSS常用的vscode插件 +Css reset 和Normalize.css

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 ✍HTML、CSS常用的vscode插件&#x1f34e;1 HTML 标签同步重命名 – Auto Re…

ardunio中自定义的库文件

1、Arduino的扩展库都是放在 libraries目录下的。完整路径为&#xff1a;C:\Users\41861\AppData\Local\Arduino15\libraries 所以我们需要在这个目录下创建一个文件夹&#xff0c;比如上面的例子是esp32上led灯控制程序&#xff0c;于是我创建了 m_led文件夹&#xff08;前面加…