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 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);
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【nvm最新解决方案】Node.js v16.20.2 is not yet released or available

【nvm最新解决方案】Node.js v16.20.2 is not yet released or available 解决办法&#xff1a;下载想安装的node压缩包&#xff0c;放入nvm对应目录。 2024年最新node压缩包地址&#xff1a;https://nodejs.org/dist/ 1、选择对应的node版本&#xff1a;例如&#xff0c;我选的…

如何创建响应式HTML电子邮件模板

在这个适合初学者的指南中&#xff0c;你将学习如何创建一个响应式电子邮件模板。你将跟随逐步说明以及代码片段设计一个在任何设备上都看起来很棒的电子邮件模板。 这个项目非常适合渴望掌握电子邮件设计基础的新手&#xff01; &#xff08;本文视频讲解&#xff1a;java56…

怎么用手机远程控制电脑 远程控制怎么用

怎么用手机远程控制电脑&#xff1a;远程控制怎么用 在这个科技日新月异的时代&#xff0c;远程控制电脑已经成为了很多人的需求。有时&#xff0c;我们可能在外出时突然需要访问家中的电脑&#xff0c;或者在工作中需要远程操控办公室的电脑。这时&#xff0c;如果能用手机远…

Spring 声明式事务控制

1. 编程式事务控制相关对象 1.1 PlatformTransactionManager PlatformTransactionManager 接口是 spring 的事务管理器&#xff0c;它提供了我们常用的操作事务的方法。 PlatformTransactionManager 是接口类型&#xff0c;不同的 Dao 层技术则有不同的实现类。例如:Dao层技…

【Spring】Spring源码中占位符解析器PropertyPlaceholderHelper的使用

开发中经常需要使用到占位符&#xff0c;情况较为复杂时总是手工替换处理显得比较的繁琐&#xff0c;加之往往手工所写效率比不上框架自带的现有方法来的更好更快。Spring在处理yml配置文件时&#xff0c;对于yml文件名的占位符替换处理便是使用了占位符解析器PropertyPlacehol…

深入了解PBKDF2:密码学中的关键推导函数

title: 深入了解PBKDF2&#xff1a;密码学中的关键推导函数 date: 2024/4/20 20:37:35 updated: 2024/4/20 20:37:35 tags: 密码学对称加密哈希函数KDFPBKDF2安全密钥派生 第一章&#xff1a;密码学基础 对称加密和哈希函数 对称加密&#xff1a;对称加密是一种加密技术&…

Windows COM技术:COM介绍、代码演示。

目录 步骤一&#xff1a;理解COM技术 介绍COM的基础知识 1. COM的目的和特点 2. COM的关键概念 3. COM的实现 4. COM与DCOM、ActiveX 讨论COM的用途 1. 软件自动化 2. 插件和扩展 3. 跨语言开发 4. 分布式计算 5. 系统级组件 6. 网络浏览器插件 步骤二&#xff1a…

开源贡献代码之​探索一下CPython

探索一下Cython 本篇文章将会围绕最近给Apache提的一个feature为背景&#xff0c;展开讲讲CPython遇到的问题&#xff0c;以及尝试自己从0写一个库出来&#xff0c;代码也已经放星球了&#xff0c;感兴趣的同学可以去下载学习。 0.背景 最近在给apache arrow提的一个feature因为…

【做一名健康的CSDNer】程序员如何早日脱单?

程序员脱单的策略可以从以下几个方面着手&#xff1a; 拓展社交圈&#xff1a;参加技术交流会、行业聚会、开源社区活动等&#xff0c;不仅可以提升技术能力&#xff0c;还可以结识更多志同道合的人&#xff0c;其中可能就包括潜在的伴侣65。 改善形象和性格&#xff1a;注意个…

【GIS教程】ArcGIS做日照分析(附练习数据下载)

我国对住宅日照标准的规定是:冬至日住宅底层日照不少于1小时或大寒日住宅层日照不少于2小时(通常以当地冬至日正午12时的太阳高度角作为依据)。因冬至日太阳高度角最低&#xff0c;照射范围最小&#xff0c;如果冬至日12&#xff1a;00建筑物底层能够接收到阳光&#xff0c;那么…

探索边缘计算:技术的新疆界

探索边缘计算&#xff1a;技术的新疆界 在当今迅速发展的数字化时代&#xff0c;云计算作为数据处理的主力军已广泛应用。但是&#xff0c;随着物联网&#xff08;IoT&#xff09;设备的急剧增加和数据生成速率的加快&#xff0c;云计算面临着种种挑战。边缘计算因此诞生&…

python爬虫-----深入了解 requests 库下篇(第二十五天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

[阅读笔记15][Orca]Progressive Learning from Complex Explanation Traces of GPT-4

接下来是微软的Orca这篇论文&#xff0c;23年6月挂到了arxiv上。 目前利用大模型输出来训练小模型的研究都是在模仿&#xff0c;它们倾向于学习大模型的风格而不是它们的推理过程&#xff0c;这导致这些小模型的质量不高。Orca是一个有13B参数的小模型&#xff0c;它可以学习到…

从零自制docker-11-【pivotRoot切换实现文件系统隔离】

文章目录 busyboxdocker run -d busybox topcontainerId(docker ps --filter "ancestorbusybox:latest"|grep -v IMAGE|awk {print $1})docker export -o busybox.tar $containerId or sudo docker export 09bbf421d93f > ./busybox.tar tar -xvf busybox.tar -C …

修复vite中使用react提示Fast refresh only works when a file only exports components.

前言 我通过 vite 构建了一个 react 应用并使用 react.lazy 来懒加载组件&#xff0c;但是在使用过程中 一直提示 Fast refresh only works when a file only exports components. Move your component(s) to a separate file.eslint(react-refresh/only-export-components)。…

编译OpenWRT固件

前言 编译环境&#xff0c;我是使用Ubuntu16.04.07 LTS 64位版 1.安装Ubuntu16.04.07 LTS 64 作者写这篇文章的时候lede源码使用debian11编译&#xff0c;对于的就是Ubuntu 20&#xff0c;至于为什么要安装ub16是因为最开始我不清楚要使用ub20安装&#xff0c;用ub16安装的时…

CCF-CSP真题《202312-2 因子化简》思路+python,c++满分题解

想查看其他题的真题及题解的同学可以前往查看&#xff1a;CCF-CSP真题附题解大全 试题编号&#xff1a;202312-2试题名称&#xff1a;因子化简时间限制&#xff1a;2.0s内存限制&#xff1a;512.0MB问题描述&#xff1a; 题目背景 质数&#xff08;又称“素数”&#xff09;是指…

RAG部署 | 使用TensorRT-LLM在Windows上部署检索增强生成聊天机器人RAG

项目应用场景 面向 Windows 平台部署 RAG 检索增强生成聊天机器人场景&#xff0c;项目采用 TensorRT-LLM 进行 GPU 加速推理&#xff0c;注意项目需要 RT4090 及以上的英伟达显卡支持。 项目效果 项目细节 > 具体参见项目 README.md (1) 下载构建好的 Llama2 TensorRT 模型…

Web开发:ASP.NET CORE的前端demo(纯前端)

目录 一、建立项目 二、删除无用文件 三、样式添加 四、写一个登录页面 五、登录主界面 一、建立项目 二、删除无用文件 三、样式添加 将你的图片资源添加在wwwroot下方&#xff0c;例如pics/logo.png 四、写一个登录页面 将Privacy.cshtml改为 Forget.cshtml &#xff0…

AJAX——图书管理案例

1.渲染列表 自己的图书数据&#xff1a;给自己起个外号&#xff0c;并告诉服务器&#xff0c;默认会有三本书&#xff0c;基于这三本书做数据的增删改查。 // 目标1&#xff1a;渲染图书列表 // 1.1 获取数据 // 1.2 渲染数据const creator 哈哈 // 封装-获取并渲染图书列表函…