910e62b5创建于 1月15日历史提交
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "services/audio/audio_processor_handler.h"

#include <algorithm>

#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/trace_event/trace_event.h"
#include "media/base/audio_bus.h"
#include "media/base/audio_parameters.h"
#include "media/base/media_switches.h"
#include "services/audio/ml_model_manager.h"

namespace audio {

AudioProcessorHandler::AudioProcessorHandler(
    const media::AudioProcessingSettings& settings,
    const media::AudioParameters& input_format,
    const media::AudioParameters& output_format,
    LogCallback log_callback,
    DeliverProcessedAudioCallback deliver_processed_audio_callback,
    ReferenceStreamErrorCallback reference_stream_error_callback,
    mojo::PendingReceiver<media::mojom::AudioProcessorControls>
        controls_receiver,
    media::AecdumpRecordingManager* aecdump_recording_manager,
    raw_ptr<MlModelManager> ml_model_manager)
    : residual_echo_estimation_model_handle_(
          ml_model_manager ? ml_model_manager->GetResidualEchoEstimationModel()
                           : nullptr),
      audio_processor_(media::AudioProcessor::Create(
          // Unretained is safe because this class owns audio_processor_, so it
          // will be destroyed first.
          base::BindRepeating(&AudioProcessorHandler::DeliverProcessedAudio,
                              base::Unretained(this)),
          std::move(log_callback),
          settings,
          input_format,
          output_format,
          residual_echo_estimation_model_handle_
              ? residual_echo_estimation_model_handle_->Get()
              : nullptr)),
      deliver_processed_audio_callback_(
          std::move(deliver_processed_audio_callback)),
      reference_stream_error_callback_(
          std::move(reference_stream_error_callback)),
      receiver_(this, std::move(controls_receiver)),
      aecdump_recording_manager_(aecdump_recording_manager) {
  DCHECK(settings.NeedWebrtcAudioProcessing());
  if (aecdump_recording_manager_) {
    aecdump_recording_manager->RegisterAecdumpSource(this);
  }
  if (media::IsAudioProcessMlModelUsageEnabled() &&
      settings.echo_cancellation) {
    // Only log model availability when model management is enabled and echo
    // cancellation is requested, in order to avoid diluting the metric.
    // We log it here, in the audio service, because lower layers are also
    // used from render processes where this feature is not available.
    bool is_model_available = residual_echo_estimation_model_handle_ != nullptr;
    base::UmaHistogramBoolean(
        "Media.Audio.Capture.NeuralResidualEchoEstimationModelAvailable",
        is_model_available);
  }
}

AudioProcessorHandler::~AudioProcessorHandler() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  if (aecdump_recording_manager_) {
    // If an aecdump is currently ongoing, this will trigger a StopAecdump()
    // call.
    aecdump_recording_manager_->DeregisterAecdumpSource(this);
  }
}

void AudioProcessorHandler::ProcessCapturedAudio(
    const media::AudioBus& audio_source,
    base::TimeTicks audio_capture_time,
    double volume,
    const media::AudioGlitchInfo& audio_glitch_info) {
  glitch_info_accumulator_.Add(audio_glitch_info);
  const int num_preferred_channels =
      num_preferred_channels_.load(std::memory_order_acquire);
  audio_processor_->ProcessCapturedAudio(audio_source, audio_capture_time,
                                         num_preferred_channels, volume);
}

void AudioProcessorHandler::OnPlayoutData(const media::AudioBus& audio_bus,
                                          int sample_rate,
                                          base::TimeDelta delay) {
  TRACE_EVENT2("audio", "AudioProcessorHandler::OnPlayoutData", " this ",
               static_cast<void*>(this), "delay", delay.InMillisecondsF());
  audio_processor_->OnPlayoutData(audio_bus, sample_rate, delay);
}

void AudioProcessorHandler::OnReferenceStreamError() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  reference_stream_error_callback_.Run();
}

void AudioProcessorHandler::GetStats(GetStatsCallback callback) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  media::AudioProcessingStats stats;
  const webrtc::AudioProcessingStats processor_stats =
      audio_processor_->GetStats();
  stats.echo_return_loss = processor_stats.echo_return_loss;
  stats.echo_return_loss_enhancement =
      processor_stats.echo_return_loss_enhancement;
  std::move(callback).Run(stats);
}

void AudioProcessorHandler::SetPreferredNumCaptureChannels(
    int32_t num_preferred_channels) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  num_preferred_channels = std::clamp(
      num_preferred_channels, 1, audio_processor_->output_format().channels());
  num_preferred_channels_.store(num_preferred_channels,
                                std::memory_order_release);
}

void AudioProcessorHandler::StartAecdump(base::File aecdump_file) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  audio_processor_->OnStartDump(std::move(aecdump_file));
}

void AudioProcessorHandler::StopAecdump() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  audio_processor_->OnStopDump();
}

void AudioProcessorHandler::DeliverProcessedAudio(
    const media::AudioBus& audio_bus,
    base::TimeTicks audio_capture_time,
    std::optional<double> new_volume) {
  deliver_processed_audio_callback_.Run(audio_bus, audio_capture_time,
                                        new_volume,
                                        glitch_info_accumulator_.GetAndReset());
}
}  // namespace audio