|
|
@@ -11,15 +11,15 @@ bool AudioCapturer::Init(Type deviceType)
|
|
|
{
|
|
|
Stop();
|
|
|
_deviceType = deviceType;
|
|
|
- __CheckBool(_CreateDeviceEnumerator(&_pDeviceEnumerator));
|
|
|
- __CheckBool(_CreateDevice(_pDeviceEnumerator, &_pDevice));
|
|
|
- __CheckBool(_CreateAudioClient(_pDevice, &_pAudioClient));
|
|
|
+ if (!_CreateDeviceEnumerator(&_pDeviceEnumerator)) { __DebugPrint("_CreateDeviceEnumerator failed"); return false; }
|
|
|
+ if (!_CreateDevice(_pDeviceEnumerator, &_pDevice)) { __DebugPrint("_CreateDevice failed"); return false; }
|
|
|
+ if (!_CreateAudioClient(_pDevice, &_pAudioClient)) { __DebugPrint("_CreateAudioClient failed"); return false; }
|
|
|
|
|
|
if (!_IsFormatSupported(_pAudioClient)) {
|
|
|
- __CheckBool(_GetPreferFormat(_pAudioClient, &_formatex));
|
|
|
+ if (!_GetPreferFormat(_pAudioClient, &_formatex)) { __DebugPrint("_GetPreferFormat failed"); return false; }
|
|
|
}
|
|
|
- __CheckBool(_InitAudioClient(_pAudioClient, &_formatex));
|
|
|
- __CheckBool(_CreateAudioCaptureClient(_pAudioClient, &_pAudioCaptureClient));
|
|
|
+ if (!_InitAudioClient(_pAudioClient, &_formatex)) { __DebugPrint("_InitAudioClient failed"); return false; }
|
|
|
+ if (!_CreateAudioCaptureClient(_pAudioClient, &_pAudioCaptureClient)) { __DebugPrint("_CreateAudioCaptureClient failed"); return false; }
|
|
|
|
|
|
_format.sampleRate = _formatex.Format.nSamplesPerSec;
|
|
|
_format.channels = _formatex.Format.nChannels;
|
|
|
@@ -33,7 +33,7 @@ bool AudioCapturer::Init(Type deviceType)
|
|
|
|
|
|
bool AudioCapturer::Start()
|
|
|
{
|
|
|
- __CheckBool(_isInit);
|
|
|
+ if (!_isInit) { return false; }
|
|
|
|
|
|
// 如果是麦克风设备,启动静音播放器确保音频引擎活跃
|
|
|
if (_deviceType == Microphone) {
|
|
|
@@ -78,22 +78,25 @@ bool AudioCapturer::_CreateDeviceEnumerator(IMMDeviceEnumerator** enumerator)
|
|
|
{
|
|
|
// __CheckBool(SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED)));
|
|
|
// __CheckBool(SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)));
|
|
|
- __CheckBool(SUCCEEDED(CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,
|
|
|
+ HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,
|
|
|
__uuidof(IMMDeviceEnumerator),
|
|
|
- reinterpret_cast<void**>(enumerator))));
|
|
|
+ reinterpret_cast<void**>(enumerator));
|
|
|
+ if (FAILED(hr)) { __DebugPrint("CoCreateInstance for MMDeviceEnumerator failed, hr=0x%08lx", static_cast<unsigned long>(hr)); return false; }
|
|
|
return true;
|
|
|
}
|
|
|
bool AudioCapturer::_CreateDevice(IMMDeviceEnumerator* enumerator, IMMDevice** device)
|
|
|
{
|
|
|
EDataFlow enDataFlow = _deviceType == Microphone ? eCapture : eRender;
|
|
|
ERole enRole = eConsole;
|
|
|
- __CheckBool(SUCCEEDED(enumerator->GetDefaultAudioEndpoint(enDataFlow, enRole, device)));
|
|
|
+ HRESULT hr = enumerator->GetDefaultAudioEndpoint(enDataFlow, enRole, device);
|
|
|
+ if (FAILED(hr)) { __DebugPrint("GetDefaultAudioEndpoint failed, hr=0x%08lx", static_cast<unsigned long>(hr)); return false; }
|
|
|
return true;
|
|
|
}
|
|
|
bool AudioCapturer::_CreateAudioClient(IMMDevice* device, IAudioClient** audioClient)
|
|
|
{
|
|
|
- __CheckBool(SUCCEEDED(device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL,
|
|
|
- (void**)audioClient)));
|
|
|
+ HRESULT hr = device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL,
|
|
|
+ (void**)audioClient);
|
|
|
+ if (FAILED(hr)) { __DebugPrint("IAudioClient Activate failed, hr=0x%08lx", static_cast<unsigned long>(hr)); return false; }
|
|
|
return true;
|
|
|
}
|
|
|
bool AudioCapturer::_IsFormatSupported(IAudioClient* audioClient)
|
|
|
@@ -128,10 +131,12 @@ bool AudioCapturer::_GetPreferFormat(IAudioClient* audioClient,
|
|
|
WAVEFORMATEXTENSIBLE* formatex)
|
|
|
{
|
|
|
WAVEFORMATEX* format = nullptr;
|
|
|
- __CheckBool(SUCCEEDED(audioClient->GetMixFormat(&format)));
|
|
|
+ HRESULT hr = audioClient->GetMixFormat(&format);
|
|
|
+ if (FAILED(hr)) { __DebugPrint("GetMixFormat failed, hr=0x%08lx", static_cast<unsigned long>(hr)); return false; }
|
|
|
formatex->Format.nSamplesPerSec = format->nSamplesPerSec;
|
|
|
formatex->Format.wBitsPerSample = format->wBitsPerSample;
|
|
|
formatex->Format.nChannels = format->nChannels;
|
|
|
+ CoTaskMemFree(format);
|
|
|
return true;
|
|
|
}
|
|
|
bool AudioCapturer::_InitAudioClient(IAudioClient* audioClient,
|
|
|
@@ -156,21 +161,30 @@ bool AudioCapturer::_InitAudioClient(IAudioClient* audioClient,
|
|
|
formatex->dwChannelMask = format->nChannels == 1 ? KSAUDIO_SPEAKER_MONO : KSAUDIO_SPEAKER_STEREO;
|
|
|
formatex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
|
|
|
|
|
|
- __CheckBool(SUCCEEDED(audioClient->Initialize(shareMode, streamFlags, hnsBufferDuration, 0,
|
|
|
- format, nullptr)));
|
|
|
+ HRESULT hr = audioClient->Initialize(shareMode, streamFlags, hnsBufferDuration, 0,
|
|
|
+ format, nullptr);
|
|
|
+ if (FAILED(hr)) { __DebugPrint("IAudioClient Initialize failed, hr=0x%08lx", static_cast<unsigned long>(hr)); return false; }
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool AudioCapturer::_CreateAudioCaptureClient(IAudioClient* audioClient,
|
|
|
IAudioCaptureClient** audioCaptureClient)
|
|
|
{
|
|
|
- __CheckBool(SUCCEEDED(audioClient->GetService(IID_PPV_ARGS(audioCaptureClient))));
|
|
|
+ HRESULT hr = audioClient->GetService(IID_PPV_ARGS(audioCaptureClient));
|
|
|
+ if (FAILED(hr)) { __DebugPrint("GetService(IAudioCaptureClient) failed, hr=0x%08lx", static_cast<unsigned long>(hr)); return false; }
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool AudioCapturer::_ThreadRun(IAudioClient* audio_client,
|
|
|
IAudioCaptureClient* audio_capture_client)
|
|
|
{
|
|
|
+ // 初始化COM到MTA,确保当前线程可安全调用COM接口
|
|
|
+ HRESULT hrCoInit = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
|
|
+ if (FAILED(hrCoInit)) {
|
|
|
+ __DebugPrint("CoInitializeEx failed, hr=0x%08lx", static_cast<unsigned long>(hrCoInit));
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
UINT32 num_success = 0;
|
|
|
BYTE* p_audio_data = nullptr;
|
|
|
UINT32 num_frames_to_read = 0;
|
|
|
@@ -180,13 +194,15 @@ bool AudioCapturer::_ThreadRun(IAudioClient* audio_client,
|
|
|
while (_loopFlag) {
|
|
|
SleepMs(5);
|
|
|
while (true) {
|
|
|
- __CheckBool(SUCCEEDED(audio_capture_client->GetNextPacketSize(&num_frames_in_next_packet)));
|
|
|
+ HRESULT hr = audio_capture_client->GetNextPacketSize(&num_frames_in_next_packet);
|
|
|
+ if (FAILED(hr)) { __DebugPrint("GetNextPacketSize failed, hr=0x%08lx", static_cast<unsigned long>(hr)); audio_client->Stop(); CoUninitialize(); return false; }
|
|
|
if (num_frames_in_next_packet == 0) {
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- __CheckBool(SUCCEEDED(audio_capture_client->GetBuffer(&p_audio_data, &num_frames_to_read,
|
|
|
- &dw_flag, nullptr, nullptr)));
|
|
|
+ hr = audio_capture_client->GetBuffer(&p_audio_data, &num_frames_to_read,
|
|
|
+ &dw_flag, nullptr, nullptr);
|
|
|
+ if (FAILED(hr)) { __DebugPrint("GetBuffer failed, hr=0x%08lx", static_cast<unsigned long>(hr)); audio_client->Stop(); CoUninitialize(); return false; }
|
|
|
|
|
|
size_t size = (_formatex.Format.wBitsPerSample >> 3) * _formatex.Format.nChannels * num_frames_to_read;
|
|
|
{
|
|
|
@@ -195,25 +211,16 @@ bool AudioCapturer::_ThreadRun(IAudioClient* audio_client,
|
|
|
_buffer.resize(oldSize + size);
|
|
|
memcpy(_buffer.data() + oldSize, p_audio_data, size);
|
|
|
}
|
|
|
- __CheckBool(SUCCEEDED(audio_capture_client->ReleaseBuffer(num_frames_to_read)));
|
|
|
+ hr = audio_capture_client->ReleaseBuffer(num_frames_to_read);
|
|
|
+ if (FAILED(hr)) { __DebugPrint("ReleaseBuffer failed, hr=0x%08lx", static_cast<unsigned long>(hr)); audio_client->Stop(); CoUninitialize(); return false; }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
audio_client->Stop();
|
|
|
+ CoUninitialize();
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-int AudioCapturer::readAudioData(char* buf, int maxLen)
|
|
|
-{
|
|
|
- std::lock_guard<std::mutex> lock(_bufferMutex);
|
|
|
- int toRead = std::min<int>(maxLen, _buffer.size());
|
|
|
- if (toRead > 0) {
|
|
|
- memcpy(buf, _buffer.data(), toRead);
|
|
|
- _buffer.erase(_buffer.begin(), _buffer.begin() + toRead);
|
|
|
- }
|
|
|
- return toRead;
|
|
|
-}
|
|
|
-
|
|
|
// 静音播放器实现
|
|
|
bool AudioCapturer::_InitializeSilencePlayer()
|
|
|
{
|
|
|
@@ -273,43 +280,33 @@ bool AudioCapturer::_InitializeSilencePlayer()
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-void AudioCapturer::_CleanupSilencePlayer()
|
|
|
+void AudioCapturer::_SilencePlayerThreadFunc()
|
|
|
{
|
|
|
- // 停止静音播放线程
|
|
|
- if (_silencePlayerRunning) {
|
|
|
- _silencePlayerRunning = false;
|
|
|
- if (_silencePlayerThread && _silencePlayerThread->joinable()) {
|
|
|
- _silencePlayerThread->join();
|
|
|
- delete _silencePlayerThread;
|
|
|
- _silencePlayerThread = nullptr;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 清理 WASAPI 资源
|
|
|
- if (_pSilenceAudioClient) {
|
|
|
- _pSilenceAudioClient->Stop();
|
|
|
- _pSilenceAudioClient->Release();
|
|
|
- _pSilenceAudioClient = nullptr;
|
|
|
- }
|
|
|
-
|
|
|
- if (_pSilenceRenderClient) {
|
|
|
- _pSilenceRenderClient->Release();
|
|
|
- _pSilenceRenderClient = nullptr;
|
|
|
- }
|
|
|
-
|
|
|
- if (_pSilenceDevice) {
|
|
|
- _pSilenceDevice->Release();
|
|
|
- _pSilenceDevice = nullptr;
|
|
|
+ // 线程内初始化COM
|
|
|
+ HRESULT hrCoInit = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
|
|
+ if (FAILED(hrCoInit)) {
|
|
|
+ __DebugPrint("CoInitializeEx for silence thread failed, hr=0x%08lx", static_cast<unsigned long>(hrCoInit));
|
|
|
+ return;
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-void AudioCapturer::_SilencePlayerThreadFunc()
|
|
|
-{
|
|
|
UINT32 bufferFrameCount;
|
|
|
HRESULT hr = _pSilenceAudioClient->GetBufferSize(&bufferFrameCount);
|
|
|
if (FAILED(hr)) {
|
|
|
+ CoUninitialize();
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+ // 计算每帧字节数(使用设备混音格式)
|
|
|
+ WAVEFORMATEX* pMix = nullptr;
|
|
|
+ UINT32 frameBytes = 0;
|
|
|
+ hr = _pSilenceAudioClient->GetMixFormat(&pMix);
|
|
|
+ if (SUCCEEDED(hr) && pMix) {
|
|
|
+ frameBytes = pMix->nBlockAlign;
|
|
|
+ CoTaskMemFree(pMix);
|
|
|
+ } else {
|
|
|
+ // 回退:猜测为立体声float(安全起见仍可为0填充任何格式)
|
|
|
+ frameBytes = sizeof(float) * 2;
|
|
|
+ }
|
|
|
|
|
|
while (_silencePlayerRunning) {
|
|
|
UINT32 numFramesPadding;
|
|
|
@@ -325,11 +322,54 @@ void AudioCapturer::_SilencePlayerThreadFunc()
|
|
|
hr = _pSilenceRenderClient->GetBuffer(numFramesAvailable, &pData);
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
// 填充静音数据(全零)
|
|
|
- memset(pData, 0, numFramesAvailable * sizeof(float) * 2); // 假设立体声
|
|
|
- hr = _pSilenceRenderClient->ReleaseBuffer(numFramesAvailable, 0);
|
|
|
+ memset(pData, 0, numFramesAvailable * frameBytes);
|
|
|
+ _pSilenceRenderClient->ReleaseBuffer(numFramesAvailable, 0);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Sleep(10); // 10ms 间隔
|
|
|
}
|
|
|
+
|
|
|
+ CoUninitialize();
|
|
|
+}
|
|
|
+
|
|
|
+int AudioCapturer::readAudioData(char* buf, int maxLen)
|
|
|
+{
|
|
|
+ std::lock_guard<std::mutex> lock(_bufferMutex);
|
|
|
+ int toRead = std::min<int>(maxLen, _buffer.size());
|
|
|
+ if (toRead > 0) {
|
|
|
+ memcpy(buf, _buffer.data(), toRead);
|
|
|
+ _buffer.erase(_buffer.begin(), _buffer.begin() + toRead);
|
|
|
+ }
|
|
|
+ return toRead;
|
|
|
+}
|
|
|
+
|
|
|
+void AudioCapturer::_CleanupSilencePlayer()
|
|
|
+{
|
|
|
+ // 停止静音播放线程
|
|
|
+ if (_silencePlayerRunning) {
|
|
|
+ _silencePlayerRunning = false;
|
|
|
+ if (_silencePlayerThread && _silencePlayerThread->joinable()) {
|
|
|
+ _silencePlayerThread->join();
|
|
|
+ delete _silencePlayerThread;
|
|
|
+ _silencePlayerThread = nullptr;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清理 WASAPI 资源
|
|
|
+ if (_pSilenceAudioClient) {
|
|
|
+ _pSilenceAudioClient->Stop();
|
|
|
+ _pSilenceAudioClient->Release();
|
|
|
+ _pSilenceAudioClient = nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_pSilenceRenderClient) {
|
|
|
+ _pSilenceRenderClient->Release();
|
|
|
+ _pSilenceRenderClient = nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_pSilenceDevice) {
|
|
|
+ _pSilenceDevice->Release();
|
|
|
+ _pSilenceDevice = nullptr;
|
|
|
+ }
|
|
|
}
|