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

#ifndef CONTENT_RENDERER_MEDIA_RENDERER_WEBAUDIODEVICE_IMPL_H_
#define CONTENT_RENDERER_MEDIA_RENDERER_WEBAUDIODEVICE_IMPL_H_

#include <stdint.h>

#include <memory>
#include <string>

#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/threading/thread_checker.h"
#include "content/common/content_export.h"
#include "media/base/audio_parameters.h"
#include "media/base/audio_renderer_sink.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/platform/web_audio_device.h"
#include "third_party/blink/public/platform/web_audio_latency_hint.h"
#include "third_party/blink/public/platform/web_audio_sink_descriptor.h"

namespace base {
class SingleThreadTaskRunner;
}

namespace media {
class SilentSinkSuspender;
class SpeechRecognitionClient;
}

namespace content {

// The actual implementation of Blink "WebAudioDevice" that handles the
// connection between Blink Web Audio API and the media renderer.
class CONTENT_EXPORT RendererWebAudioDeviceImpl
    : public blink::WebAudioDevice,
      public media::AudioRendererSink::RenderCallback {
 public:
  RendererWebAudioDeviceImpl(const RendererWebAudioDeviceImpl&) = delete;
  RendererWebAudioDeviceImpl& operator=(const RendererWebAudioDeviceImpl&) =
      delete;

  ~RendererWebAudioDeviceImpl() override;

  static std::unique_ptr<RendererWebAudioDeviceImpl> Create(
      const blink::WebAudioSinkDescriptor& sink_descriptor,
      int number_of_output_channels,
      const blink::WebAudioLatencyHint& latency_hint,
      std::optional<float> context_sample_rate,
      media::AudioRendererSink::RenderCallback* webaudio_callback);
  static int GetOutputBufferSize(const blink::WebAudioLatencyHint& latency_hint,
                                 int resolved_context_sample_rate,
                                 const media::AudioParameters& hardware_params);

  // blink::WebAudioDevice implementation.
  void Start() override;
  void Stop() override;
  void Pause() override;
  void Resume() override;
  double SampleRate() override;
  int FramesPerBuffer() override;
  int MaxChannelCount() override;

  // Sets the detect silence flag for SilentSinkSuspender. Invoked by Blink Web
  // Audio.
  void SetDetectSilence(bool enable_silence_detection) override;

  // AudioRendererSink::RenderCallback implementation.
  int Render(base::TimeDelta delay,
             base::TimeTicks delay_timestamp,
             const media::AudioGlitchInfo& glitch_info,
             media::AudioBus* dest) override;

  // This callback method may be called in two different scenarios:
  // 1) When the constructor's audio device activation fails. (main thread)
  // 2) When the audio infra reports an device/render error. (audio thread)
  void OnRenderError() override;

  // Notifies the client (e.g. Blink WebAudio) of device/renderer-related
  // errors. Intended to be executed via a task runner asynchronously.
  void NotifyRenderError();

  void SetSilentSinkTaskRunnerForTesting(
      scoped_refptr<base::SingleThreadTaskRunner> task_runner);

  const media::AudioParameters& get_sink_params_for_testing() {
    return current_sink_params_;
  }

  // Creates a new sink if one hasn't been created yet, and returns the sink
  // status.
  media::OutputDeviceStatus MaybeCreateSinkAndGetStatus() override;

  const media::AudioParameters& GetOriginalSinkParamsForTesting() const {
    return original_sink_params_;
  }

 protected:
  // Callback to get output device params (for tests).
  using OutputDeviceParamsCallback = base::OnceCallback<media::AudioParameters(
      const blink::LocalFrameToken& frame_token,
      const std::string& device_id)>;

  using CreateSilentSinkCallback =
      base::RepeatingCallback<scoped_refptr<media::AudioRendererSink>(
          const scoped_refptr<base::SequencedTaskRunner>& task_runner)>;

  RendererWebAudioDeviceImpl(
      const blink::WebAudioSinkDescriptor& sink_descriptor,
      media::ChannelLayoutConfig layout_config,
      const blink::WebAudioLatencyHint& latency_hint,
      std::optional<float> context_sample_rate,
      media::AudioRendererSink::RenderCallback* webaudio_callback,
      OutputDeviceParamsCallback device_params_cb,
      CreateSilentSinkCallback create_silent_sink_cb);

 private:
  scoped_refptr<base::SingleThreadTaskRunner> GetSilentSinkTaskRunner();

  void SendLogMessage(const std::string& message);

  // Create and initialize an instance of AudioRendererSink. Should only be
  // called when `sink_` is nullptr.
  void CreateAudioRendererSink();

  // This is queried from the underlying sink device and then modified according
  // to the WebAudio renderer's needs.
  media::AudioParameters current_sink_params_;
  // This is the unmodified parameters obtained from the underlying sink device.
  // Used to provide the original hardware capacity.
  media::AudioParameters original_sink_params_;

  // To cache the device identifier for sink creation.
  const blink::WebAudioSinkDescriptor sink_descriptor_;

  const blink::WebAudioLatencyHint latency_hint_;

  // The WebAudio renderer's callback; directs to `AudioDestination::Render()`.
  const raw_ptr<media::AudioRendererSink::RenderCallback> webaudio_callback_;

  // To avoid the need for locking, ensure the control methods of the
  // blink::WebAudioDevice implementation are called on the same thread.
  base::ThreadChecker thread_checker_;

  scoped_refptr<media::AudioRendererSink> sink_;

  // Used to suspend |sink_| usage when silence has been detected for too long.
  std::unique_ptr<media::SilentSinkSuspender> silent_sink_suspender_;

  // Render frame token for the current context.
  blink::LocalFrameToken frame_token_;

  // An alternative task runner for `silent_sink_suspender_` or a silent audio
  // sink.
  scoped_refptr<base::SingleThreadTaskRunner> silent_sink_task_runner_;

  // Mainly to bubble up the OnRenderError to the Blink WebAudio module.
  scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;

  // Used to trigger one single textlog indicating that rendering started as
  // intended. Set to true once in the first call to the Render callback.
  bool is_rendering_ = false;

  CreateSilentSinkCallback create_silent_sink_cb_;

  // Used to indicate if device is stopped.
  bool is_stopped_ = true;

  std::unique_ptr<media::SpeechRecognitionClient> speech_recognition_client_;

  base::WeakPtrFactory<RendererWebAudioDeviceImpl> weak_ptr_factory_{this};

  FRIEND_TEST_ALL_PREFIXES(RendererWebAudioDeviceImplTest,
                           CreateSinkAndGetDeviceStatus_HealthyDevice);
  FRIEND_TEST_ALL_PREFIXES(RendererWebAudioDeviceImplTest,
                           CreateSinkAndGetDeviceStatus_ErrorDevice);
  FRIEND_TEST_ALL_PREFIXES(RendererWebAudioDeviceImplTest,
                           CreateSinkAndGetDeviceStatus_SilentSink);
};

}  // namespace content

#endif  // CONTENT_RENDERER_MEDIA_RENDERER_WEBAUDIODEVICE_IMPL_H_