上一节《7-21 StartRecording处理逻辑
本节源码分析录制麦克风流程,最终是调用StartRecording开始录制,该函数里面创建并启动了一个采集线程,线程函数是AudioDeviceWindowsCore::DoCaptureThreadPollDMO,注意默认是在打开了aec回声消除功能。

WebRtcVoiceMediaChannel::SetSend

  1. void WebRtcVoiceMediaChannel::SetSend(bool send) {
  2. ***
  3. // Change the settings on each send channel.
  4. for (auto& kv : send_streams_) {
  5. kv.second->SetSend(send);
  6. }
  7. send_ = send;
  8. }

-》

SetSend

  1. void SetSend(bool send) {
  2. RTC_DCHECK_RUN_ON(&worker_thread_checker_);
  3. send_ = send;
  4. UpdateSendState();
  5. }

-》

UpdateSendState

  1. void UpdateSendState() {
  2. RTC_DCHECK_RUN_ON(&worker_thread_checker_);
  3. RTC_DCHECK(stream_);
  4. RTC_DCHECK_EQ(1UL, rtp_parameters_.encodings.size());
  5. if (send_ && source_ != nullptr && rtp_parameters_.encodings[0].active) {
  6. stream_->Start();
  7. } else { // !send || source_ = nullptr
  8. stream_->Stop();
  9. }
  10. }

-》

AudioSendStream::Start

  1. void AudioSendStream::Start() {
  2. RTC_DCHECK_RUN_ON(&worker_thread_checker_);
  3. if (sending_) {
  4. return;
  5. }
  6. if (!config_.has_dscp && config_.min_bitrate_bps != -1 &&
  7. config_.max_bitrate_bps != -1 &&
  8. (allocate_audio_without_feedback_ || TransportSeqNumId(config_) != 0)) {
  9. rtp_transport_->AccountForAudioPacketsInPacedSender(true);
  10. if (send_side_bwe_with_overhead_)
  11. rtp_transport_->IncludeOverheadInPacedSender();
  12. rtp_rtcp_module_->SetAsPartOfAllocation(true);
  13. ConfigureBitrateObserver();
  14. } else {
  15. rtp_rtcp_module_->SetAsPartOfAllocation(false);
  16. }
  17. channel_send_->StartSend();
  18. sending_ = true;
  19. audio_state()->AddSendingStream(this, encoder_sample_rate_hz_,
  20. encoder_num_channels_);
  21. }

—》

AudioState::AddSendingStream

  1. void (webrtc::AudioSendStream* stream,
  2. int sample_rate_hz,
  3. size_t num_channels) {
  4. RTC_DCHECK(thread_checker_.IsCurrent());
  5. auto& properties = sending_streams_[stream];
  6. properties.sample_rate_hz = sample_rate_hz;
  7. properties.num_channels = num_channels;
  8. UpdateAudioTransportWithSendingStreams();
  9. // Make sure recording is initialized; start recording if enabled.
  10. auto* adm = config_.audio_device_module.get();
  11. if (!adm->Recording()) {
  12. if (adm->InitRecording() == 0) {
  13. if (recording_enabled_) {
  14. adm->StartRecording();
  15. }
  16. } else {
  17. RTC_DLOG_F(LS_ERROR) << "Failed to initialize recording.";
  18. }
  19. }
  20. }

—》

AudioDeviceModuleImpl::StartRecording

  1. int32_t AudioDeviceModuleImpl::StartRecording() {
  2. RTC_LOG(INFO) << __FUNCTION__;
  3. CHECKinitialized_();
  4. if (Recording()) {
  5. return 0;
  6. }
  7. audio_device_buffer_.StartRecording();
  8. int32_t result = audio_device_->StartRecording();
  9. RTC_LOG(INFO) << "output: " << result;
  10. RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.StartRecordingSuccess",
  11. static_cast<int>(result == 0));
  12. return result;
  13. }

—》

AudioDeviceWindowsCore::StartRecording

  1. int32_t AudioDeviceWindowsCore::StartRecording() {
  2. if (!_recIsInitialized) {
  3. return -1;
  4. }
  5. if (_hRecThread != NULL) {
  6. return 0;
  7. }
  8. if (_recording) {
  9. return 0;
  10. }
  11. {
  12. MutexLock lockScoped(&mutex_);
  13. // Create thread which will drive the capturing
  14. LPTHREAD_START_ROUTINE lpStartAddress = WSAPICaptureThread;
  15. if (_builtInAecEnabled) { // 如果使用AEC,则重定向使用DMO采集音频
  16. // Redirect to the DMO polling method.
  17. lpStartAddress = WSAPICaptureThreadPollDMO;
  18. if (!_playing) {
  19. // The DMO won't provide us captured output data unless we
  20. // give it render data to process.
  21. RTC_LOG(LS_ERROR)
  22. << "Playout must be started before recording when using"
  23. " the built-in AEC";
  24. return -1;
  25. }
  26. }
  27. // 前面的,如果使用了_builtInAecEnabled,则真正执行的是WSAPICaptureThreadPollDMO
  28. assert(_hRecThread == NULL);
  29. _hRecThread = CreateThread(NULL, 0, lpStartAddress, this, 0, NULL);
  30. if (_hRecThread == NULL) {
  31. RTC_LOG(LS_ERROR) << "failed to create the recording thread";
  32. return -1;
  33. }
  34. // Set thread priority to highest possible
  35. // 设置线程优先级别
  36. SetThreadPriority(_hRecThread, THREAD_PRIORITY_TIME_CRITICAL);
  37. } // critScoped
  38. // 当前线程挂起
  39. DWORD ret = WaitForSingleObject(_hCaptureStartedEvent, 1000);
  40. if (ret != WAIT_OBJECT_0) {
  41. RTC_LOG(LS_VERBOSE) << "capturing did not start up properly";
  42. return -1;
  43. }
  44. RTC_LOG(LS_VERBOSE) << "capture audio stream has now started...";
  45. _recording = true;
  46. return 0;
  47. }

WSAPICaptureThreadPollDMO
DWORD WINAPI AudioDeviceWindowsCore::WSAPICaptureThreadPollDMO(LPVOID context) {
return reinterpret_cast(context) ->DoCaptureThreadPollDMO();
}

采集音频线程

AudioDeviceWindowsCore::DoCaptureThreadPollDMO

  1. DWORD AudioDeviceWindowsCore::DoCaptureThreadPollDMO() {
  2. assert(_mediaBuffer != NULL);
  3. bool keepRecording = true;
  4. // Initialize COM as MTA in this thread.
  5. ScopedCOMInitializer comInit(ScopedCOMInitializer::kMTA);
  6. if (!comInit.Succeeded()) {
  7. RTC_LOG(LS_ERROR) << "failed to initialize COM in polling DMO thread";
  8. return 1;
  9. }
  10. HRESULT hr = InitCaptureThreadPriority();
  11. if (FAILED(hr)) {
  12. return hr;
  13. }
  14. // Set event which will ensure that the calling thread modifies the
  15. // recording state to true.
  16. SetEvent(_hCaptureStartedEvent);
  17. // >> ---------------------------- THREAD LOOP ----------------------------
  18. while (keepRecording) {
  19. // Poll the DMO every 5 ms.
  20. // (The same interval used in the Wave implementation.)
  21. DWORD waitResult = WaitForSingleObject(_hShutdownCaptureEvent, 5);
  22. switch (waitResult) {
  23. case WAIT_OBJECT_0: // _hShutdownCaptureEvent
  24. keepRecording = false;
  25. break;
  26. case WAIT_TIMEOUT: // timeout notification
  27. break;
  28. default: // unexpected error
  29. RTC_LOG(LS_WARNING) << "Unknown wait termination on capture side";
  30. hr = -1; // To signal an error callback.
  31. keepRecording = false;
  32. break;
  33. }
  34. // 真正采集的核心逻辑
  35. while (keepRecording) {
  36. MutexLock lockScoped(&mutex_);
  37. DWORD dwStatus = 0;
  38. {
  39. DMO_OUTPUT_DATA_BUFFER dmoBuffer = {0};
  40. dmoBuffer.pBuffer = _mediaBuffer;//必须是继承IMediaBuffer的
  41. dmoBuffer.pBuffer->AddRef();
  42. // Poll the DMO for AEC processed capture data. The DMO will
  43. // copy available data to |dmoBuffer|, and should only return
  44. // 10 ms frames. The value of |dwStatus| should be ignored.
  45. hr = _dmo->ProcessOutput(0, 1, &dmoBuffer, &dwStatus);
  46. SAFE_RELEASE(dmoBuffer.pBuffer);
  47. dwStatus = dmoBuffer.dwStatus;
  48. }
  49. if (FAILED(hr)) {
  50. _TraceCOMError(hr);
  51. keepRecording = false;
  52. assert(false);
  53. break;
  54. }
  55. ULONG bytesProduced = 0;
  56. BYTE* data;
  57. // Get a pointer to the data buffer. This should be valid until
  58. // the next call to ProcessOutput.
  59. // 获取buffer数据和数据大小
  60. // bytesProduced=320,输出采样率16000,每个采样2个字节,每次采集10ms数据
  61. hr = _mediaBuffer->GetBufferAndLength(&data, &bytesProduced);
  62. if (FAILED(hr)) {
  63. _TraceCOMError(hr);
  64. keepRecording = false;
  65. assert(false);
  66. break;
  67. }
  68. if (bytesProduced > 0) {
  69. //断点值 160 = 320/2
  70. const int kSamplesProduced = bytesProduced / _recAudioFrameSize;
  71. // TODO(andrew): verify that this is always satisfied. It might
  72. // be that ProcessOutput will try to return more than 10 ms if
  73. // we fail to call it frequently enough.
  74. assert(kSamplesProduced == static_cast<int>(_recBlockSize));
  75. assert(sizeof(BYTE) == sizeof(int8_t));
  76. _ptrAudioBuffer->SetRecordedBuffer(reinterpret_cast<int8_t*>(data),
  77. kSamplesProduced);
  78. _ptrAudioBuffer->SetVQEData(0, 0);
  79. _UnLock(); // Release lock while making the callback.
  80. // 将数据输送到上层逻辑去处理
  81. _ptrAudioBuffer->DeliverRecordedData();
  82. _Lock();
  83. }
  84. // Reset length to indicate buffer availability.
  85. hr = _mediaBuffer->SetLength(0);
  86. if (FAILED(hr)) {
  87. _TraceCOMError(hr);
  88. keepRecording = false;
  89. assert(false);
  90. break;
  91. }
  92. if (!(dwStatus & DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE)) {
  93. // The DMO cannot currently produce more data. This is the
  94. // normal case; otherwise it means the DMO had more than 10 ms
  95. // of data available and ProcessOutput should be called again.
  96. break;
  97. }
  98. }
  99. }
  100. // ---------------------------- THREAD LOOP ---------------------------- <<
  101. RevertCaptureThreadPriority();
  102. if (FAILED(hr)) {
  103. RTC_LOG(LS_ERROR)
  104. << "Recording error: capturing thread has ended prematurely";
  105. } else {
  106. RTC_LOG(LS_VERBOSE) << "Capturing thread is now terminated properly";
  107. }
  108. return hr;
  109. }

将数据输送到上层逻辑去处理

_ptrAudioBuffer->DeliverRecordedData();

  1. AudioDeviceBuffer::DeliverRecordedData
  2. -》
  3. audio_transport_cb_->RecordedDataIsAvailable(
  4. rec_buffer_.data(), frames, bytes_per_frame, rec_channels_,
  5. rec_sample_rate_, total_delay_ms, 0, 0, typing_status_,
  6. new_mic_level_dummy);

H:\webrtc-20210315\webrtc-20210315\webrtc\webrtc-checkout\src\modules\audio_device\audio_device_data_observer.cc

  1. // AudioTransport methods overrides.
  2. int32_t RecordedDataIsAvailable(const void* audioSamples,
  3. const size_t nSamples,
  4. const size_t nBytesPerSample,
  5. const size_t nChannels,
  6. const uint32_t samples_per_sec,
  7. const uint32_t total_delay_ms,
  8. const int32_t clockDrift,
  9. const uint32_t currentMicLevel,
  10. const bool keyPressed,
  11. uint32_t& newMicLevel) override {
  12. int32_t res = 0;
  13. // Capture PCM data of locally captured audio.
  14. // std::unique_ptr<AudioDeviceDataObserver> observer_;
  15. if (observer_) {
  16. observer_->OnCaptureData(audioSamples, nSamples, nBytesPerSample,
  17. nChannels, samples_per_sec);
  18. }
  19. // Send to the actual audio transport.
  20. if (audio_transport_) {
  21. res = audio_transport_->RecordedDataIsAvailable(
  22. audioSamples, nSamples, nBytesPerSample, nChannels, samples_per_sec,
  23. total_delay_ms, clockDrift, currentMicLevel, keyPressed, newMicLevel);
  24. }
  25. return res;
  26. }

1 外面应用层调用

observer的值来自
ADMWrapper(rtc::scoped_refptr impl,
AudioDeviceDataObserver* legacy_observer,
std::unique_ptr observer)
: impl
(impl),
legacyobserver(legacyobserver),
observer
(std::move(observer))
-》
rtc::scoped_refptr CreateAudioDeviceWithDataObserver(
AudioDeviceModule::AudioLayer audio_layer,
TaskQueueFactory task_queue_factory,
AudioDeviceDataObserver
legacy_observer) {
rtc::scoped_refptr audio_device(
new rtc::RefCountedObject(audio_layer, task_queue_factory,
legacy_observer, nullptr));
*

2 拷贝到每个发送流进行传输

if (audiotransport) {
res = audiotransport->RecordedDataIsAvailable(
audioSamples, nSamples, nBytesPerSample, nChannels, samples_per_sec,
total_delay_ms, clockDrift, currentMicLevel, keyPressed, newMicLevel);
}

audiotransport的值为RegisterAudioCallback传参值。
// Override AudioDeviceModule’s RegisterAudioCallback method to remember the
// actual audio transport (e.g.: voice engine).
int32t RegisterAudioCallback(AudioTransport* audio_callback) override {
// Remember the audio callback to forward PCM data
audio_transport
= audio_callback;
return 0;
}

学习资料

https://blog.csdn.net/linalg/article/details/123376296