Parade Series - CoreAudio Loopback

Scenario

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

在这里插入图片描述
DLL init & release automatically

#pragma data_seg("Shared")
CORE_AUDIO_LOOPBACK_API HANDLE  hMutex = NULL;
CORE_AUDIO_LOOPBACK_API UINT    liveIndex = 0;
CORE_AUDIO_LOOPBACK_API HRESULT _dll_handle_result_{};
#pragma data_seg()
#pragma comment(linker, "/section:Shared,rws")
class ObjectGuard {
	enum OBJECT_TYPE {
		OBJ_TYPE_DEFAULT = 0,
		OBJ_TYPE_GET_DC = 1,
		OBJ_TYPE_CREATE_DC = 2,
		OBJ_TYPE_CREATE_COMPATIBLE_DC = 3,
		OBJ_TYPE_CREATE_COMPATIBLE_BITMAP = 4,
		OBJ_TYPE_RESERVED = 9
	};

public:
	ObjectGuard() {
		this->type = OBJ_TYPE_GET_DC;
		this->_self_dc = GetDC(NULL);
		debug();
	}
	ObjectGuard(LPCWSTR deviceName) {
		this->type = OBJ_TYPE_CREATE_DC;
		this->_self_dc = CreateDC(deviceName, NULL, NULL, NULL);
		debug();
	}
	ObjectGuard(HDC hDC) {
		this->type = OBJ_TYPE_CREATE_COMPATIBLE_DC;
		this->_self_dc = CreateCompatibleDC(hDC);
		debug();
	}
	HDC getDC() {
		return (this->_self_dc);
	}

	ObjectGuard(HDC hDC, INT nWidth, INT nHeight) {
		this->type = OBJ_TYPE_CREATE_COMPATIBLE_BITMAP;
		this->_self_bitmap = CreateCompatibleBitmap(hDC, nWidth, nHeight);
		debug();
	}
	HBITMAP getBitmap() {
		return (this->_self_bitmap);
	}

	~ObjectGuard()
	{
		if (this->type == OBJ_TYPE_GET_DC) {
			ReleaseDC(NULL, this->_self_dc);
		}
		if (this->type == OBJ_TYPE_CREATE_DC) {
			DeleteDC(this->_self_dc);
		}
		if (this->type == OBJ_TYPE_CREATE_COMPATIBLE_DC) {
			DeleteDC(this->_self_dc);
		}
		if (this->type == OBJ_TYPE_CREATE_COMPATIBLE_DC) {
			DeleteObject(this->_self_bitmap);
		}
		debug();
	}

	void debug() {
		Sleep(3);
		printf("<<<< %d : 0x%.16X\n", this->type, this->_self_dc);
	}

private:
	INT type = OBJ_TYPE_GET_DC;
	HDC _self_dc = NULL;
	HBITMAP _self_bitmap = NULL;
};

CCoreAudioLoopbackApp::CCoreAudioLoopbackApp()
{
	// TODO:  在此处添加构造代码,
	// 将所有重要的初始化放置在 InitInstance 中

	//
	init(0);
	//
}


// 唯一的 CCoreAudioLoopbackApp 对象

CCoreAudioLoopbackApp theApp;


// CCoreAudioLoopbackApp 初始化

BOOL CCoreAudioLoopbackApp::InitInstance()
{
	CWinApp::InitInstance();

	//
	release(0);
	//

	return TRUE;
}

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

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

Init & Release

CORE_AUDIO_LOOPBACK_API BOOL WINAPI init(UINT devNum)
{
	TimespanGuard timespanGuard("init");

	_dll_handle_result_ = CoInitializeEx(nullptr, COINIT::COINIT_MULTITHREADED);

	return (TRUE);         // BOOL TRUE  0x0001
}
CORE_AUDIO_LOOPBACK_API BOOL WINAPI release(UINT devNum)
{
	TimespanGuard timespanGuard("release");

	if (_dll_handle_result_ == S_OK || _dll_handle_result_ == S_FALSE) {
		CoUninitialize();
	}

	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
}

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);
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值