audio_capturer.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #include "audio_capturer.h"
  2. #include "basic/basic.h"
  3. #define DEFAULT_SAMPLE_RATE 48000 // 默认采样率:48kHz
  4. #define DEFAULT_BITS_PER_SAMPLE 16 // 默认位深:16bit
  5. #define DEFAULT_CHANNELS 1 // 默认音频通道数:1
  6. #define DEFAULT_AUDIO_PACKET_INTERVAL 10 // 默认音频包发送间隔:10ms
  7. bool AudioCapturer::Init(Type deviceType)
  8. {
  9. Stop();
  10. _deviceType = deviceType;
  11. __CheckBool(_CreateDeviceEnumerator(&_pDeviceEnumerator));
  12. __CheckBool(_CreateDevice(_pDeviceEnumerator, &_pDevice));
  13. __CheckBool(_CreateAudioClient(_pDevice, &_pAudioClient));
  14. if (!_IsFormatSupported(_pAudioClient)) {
  15. __CheckBool(_GetPreferFormat(_pAudioClient, &_formatex));
  16. }
  17. __CheckBool(_InitAudioClient(_pAudioClient, &_formatex));
  18. __CheckBool(_CreateAudioCaptureClient(_pAudioClient, &_pAudioCaptureClient));
  19. _format.sampleRate = _formatex.Format.nSamplesPerSec;
  20. _format.channels = _formatex.Format.nChannels;
  21. _format.bitsPerSample = _formatex.Format.wBitsPerSample;
  22. _format.avgBytesPerSec = _formatex.Format.nAvgBytesPerSec;
  23. _format.blockAlign = _formatex.Format.nBlockAlign;
  24. _isInit = true;
  25. return true;
  26. }
  27. bool AudioCapturer::Start()
  28. {
  29. __CheckBool(_isInit);
  30. _loopFlag = true;
  31. PlaySoundA("./rc/mute.wav", nullptr, SND_FILENAME | SND_ASYNC | SND_LOOP);
  32. _captureThread = new std::thread(
  33. [this] { _ThreadRun(_pAudioClient, _pAudioCaptureClient); });
  34. return true;
  35. }
  36. void AudioCapturer::Stop()
  37. {
  38. // CoUninitialize();
  39. _isInit = false;
  40. _loopFlag = false;
  41. Free(_captureThread, [this] {
  42. _captureThread->join();
  43. delete _captureThread;
  44. });
  45. Free(_pAudioCaptureClient, [this] { _pAudioCaptureClient->Release(); });
  46. if (_pAudioClient != nullptr) {
  47. _pAudioClient->Stop();
  48. }
  49. PlaySoundA(nullptr, nullptr, SND_FILENAME | SND_ASYNC | SND_LOOP);
  50. Free(_pAudioClient, [this] { _pAudioClient->Release(); });
  51. Free(_pDevice, [this] { _pDevice->Release(); });
  52. Free(_pDeviceEnumerator, [this] { _pDeviceEnumerator->Release(); });
  53. }
  54. bool AudioCapturer::_CreateDeviceEnumerator(IMMDeviceEnumerator** enumerator)
  55. {
  56. // __CheckBool(SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED)));
  57. // __CheckBool(SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)));
  58. __CheckBool(SUCCEEDED(CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,
  59. __uuidof(IMMDeviceEnumerator),
  60. reinterpret_cast<void**>(enumerator))));
  61. return true;
  62. }
  63. bool AudioCapturer::_CreateDevice(IMMDeviceEnumerator* enumerator, IMMDevice** device)
  64. {
  65. EDataFlow enDataFlow = _deviceType == Microphone ? eCapture : eRender;
  66. ERole enRole = eConsole;
  67. __CheckBool(SUCCEEDED(enumerator->GetDefaultAudioEndpoint(enDataFlow, enRole, device)));
  68. return true;
  69. }
  70. bool AudioCapturer::_CreateAudioClient(IMMDevice* device, IAudioClient** audioClient)
  71. {
  72. __CheckBool(SUCCEEDED(device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL,
  73. (void**)audioClient)));
  74. return true;
  75. }
  76. bool AudioCapturer::_IsFormatSupported(IAudioClient* audioClient)
  77. {
  78. memset(&_formatex, 0, sizeof(_formatex));
  79. WAVEFORMATEX* format = &_formatex.Format;
  80. format->nSamplesPerSec = DEFAULT_SAMPLE_RATE;
  81. format->wBitsPerSample = DEFAULT_BITS_PER_SAMPLE;
  82. format->nChannels = DEFAULT_CHANNELS;
  83. WAVEFORMATEX* closestMatch = nullptr;
  84. HRESULT hr = audioClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,
  85. format, &closestMatch);
  86. if (hr == AUDCLNT_E_UNSUPPORTED_FORMAT) // 0x88890008
  87. {
  88. if (closestMatch == nullptr) // 如果找不到最相近的格式,closestMatch可能为nullptr
  89. {
  90. return false;
  91. }
  92. format->nSamplesPerSec = closestMatch->nSamplesPerSec;
  93. format->wBitsPerSample = closestMatch->wBitsPerSample;
  94. format->nChannels = closestMatch->nChannels;
  95. return true;
  96. }
  97. return false;
  98. }
  99. bool AudioCapturer::_GetPreferFormat(IAudioClient* audioClient,
  100. WAVEFORMATEXTENSIBLE* formatex)
  101. {
  102. WAVEFORMATEX* format = nullptr;
  103. __CheckBool(SUCCEEDED(audioClient->GetMixFormat(&format)));
  104. formatex->Format.nSamplesPerSec = format->nSamplesPerSec;
  105. formatex->Format.wBitsPerSample = format->wBitsPerSample;
  106. formatex->Format.nChannels = format->nChannels;
  107. return true;
  108. }
  109. bool AudioCapturer::_InitAudioClient(IAudioClient* audioClient,
  110. WAVEFORMATEXTENSIBLE* formatex)
  111. {
  112. AUDCLNT_SHAREMODE shareMode = AUDCLNT_SHAREMODE_SHARED; // share Audio Engine with other applications
  113. DWORD streamFlags = _deviceType == Microphone ? 0 : AUDCLNT_STREAMFLAGS_LOOPBACK;
  114. streamFlags |= AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM; // A channel matrixer and a sample
  115. // rate converter are inserted
  116. streamFlags |= AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY; // a sample rate converter
  117. // with better quality than
  118. // the default conversion but
  119. // with a higher performance
  120. // cost is used
  121. REFERENCE_TIME hnsBufferDuration = 0;
  122. WAVEFORMATEX* format = &formatex->Format;
  123. format->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  124. format->nBlockAlign = (format->wBitsPerSample >> 3) * format->nChannels;
  125. format->nAvgBytesPerSec = format->nBlockAlign * format->nSamplesPerSec;
  126. format->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
  127. formatex->Samples.wValidBitsPerSample = format->wBitsPerSample;
  128. formatex->dwChannelMask = format->nChannels == 1 ? KSAUDIO_SPEAKER_MONO : KSAUDIO_SPEAKER_STEREO;
  129. formatex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
  130. __CheckBool(SUCCEEDED(audioClient->Initialize(shareMode, streamFlags, hnsBufferDuration, 0,
  131. format, nullptr)));
  132. return true;
  133. }
  134. bool AudioCapturer::_CreateAudioCaptureClient(IAudioClient* audioClient,
  135. IAudioCaptureClient** audioCaptureClient)
  136. {
  137. __CheckBool(SUCCEEDED(audioClient->GetService(IID_PPV_ARGS(audioCaptureClient))));
  138. return true;
  139. }
  140. bool AudioCapturer::_ThreadRun(IAudioClient* audio_client,
  141. IAudioCaptureClient* audio_capture_client)
  142. {
  143. UINT32 num_success = 0;
  144. BYTE* p_audio_data = nullptr;
  145. UINT32 num_frames_to_read = 0;
  146. DWORD dw_flag = 0;
  147. UINT32 num_frames_in_next_packet = 0;
  148. audio_client->Start();
  149. while (_loopFlag) {
  150. SleepMs(5);
  151. while (true) {
  152. __CheckBool(SUCCEEDED(audio_capture_client->GetNextPacketSize(&num_frames_in_next_packet)));
  153. if (num_frames_in_next_packet == 0) {
  154. break;
  155. }
  156. __CheckBool(SUCCEEDED(audio_capture_client->GetBuffer(&p_audio_data, &num_frames_to_read,
  157. &dw_flag, nullptr, nullptr)));
  158. size_t size = (_formatex.Format.wBitsPerSample >> 3) * _formatex.Format.nChannels * num_frames_to_read;
  159. {
  160. std::lock_guard<std::mutex> lock(_bufferMutex);
  161. size_t oldSize = _buffer.size();
  162. _buffer.resize(oldSize + size);
  163. memcpy(_buffer.data() + oldSize, p_audio_data, size);
  164. }
  165. __CheckBool(SUCCEEDED(audio_capture_client->ReleaseBuffer(num_frames_to_read)));
  166. }
  167. }
  168. audio_client->Stop();
  169. return true;
  170. }
  171. int AudioCapturer::readAudioData(char* buf, int maxLen)
  172. {
  173. std::lock_guard<std::mutex> lock(_bufferMutex);
  174. int toRead = std::min<int>(maxLen, _buffer.size());
  175. if (toRead > 0) {
  176. memcpy(buf, _buffer.data(), toRead);
  177. _buffer.erase(_buffer.begin(), _buffer.begin() + toRead);
  178. }
  179. return toRead;
  180. }