本文主要是介绍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);
}
这篇关于Parade Series - CoreAudio Loopback的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!