chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder_unittest.cc

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/modules/mediarecorder/audio_track_recorder.h"

#include <stdint.h>

#include <optional>
#include <string>

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/test/gmock_callback_support.h"
#include "base/time/time.h"
#include "media/audio/simple_sources.h"
#include "media/base/audio_buffer.h"
#include "media/base/audio_decoder.h"
#include "media/base/audio_encoder.h"
#include "media/base/audio_sample_types.h"
#include "media/base/channel_layout.h"
#include "media/base/decoder_status.h"
#include "media/base/mock_media_log.h"
#include "media/media_buildflags.h"
#include "media/mojo/buildflags.h"
#include "media/mojo/mojom/audio_encoder.mojom.h"
#include "media/mojo/mojom/interface_factory.mojom.h"
#include "media/mojo/services/mojo_audio_encoder_service.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/unique_receiver_set.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/public/web/web_heap.h"
#include "third_party/blink/renderer/modules/mediarecorder/audio_track_mojo_encoder.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/heap/weak_cell.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_component_impl.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/testing/task_environment.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/opus/src/include/opus.h"

#if BUILDFLAG(IS_WIN)
#include <objbase.h>

#include "media/gpu/windows/mf_audio_encoder.h"
#define HAS_AAC_ENCODER
#endif  //  BUILDFLAG(IS_WIN)

#if BUILDFLAG(IS_MAC) && BUILDFLAG(USE_PROPRIETARY_CODECS)
#include "media/filters/mac/audio_toolbox_audio_encoder.h"
#define HAS_AAC_ENCODER
#endif  // BUILDFLAG(IS_MAC) && BUILDFLAG(USE_PROPRIETARY_CODECS)

#if BUILDFLAG(ENABLE_FFMPEG) && BUILDFLAG(USE_PROPRIETARY_CODECS)
#include "media/filters/ffmpeg_audio_decoder.h"
#define HAS_AAC_DECODER
#endif  // BUILDFLAG(ENABLE_FFMPEG) && BUILDFLAG(USE_PROPRIETARY_CODECS)

TimeTicks;
RunOnceClosure;
_;
Invoke;

namespace {

constexpr int kExpectedNumOutputs =;
constexpr int kDefaultSampleRate =;

// The duration of the frames that make up the test data we will provide to the
// `AudioTrackRecorder`.
constexpr int kMediaStreamAudioTrackBufferDurationMs =;

// This is the preferred opus buffer duration (60 ms), which corresponds to a
// value of 2880 frames per buffer at a sample rate of 48 khz.
constexpr int kOpusBufferDurationMs =;

// AAC puts 1024 PCM samples into each AAC frame, which corresponds to a
// duration of 21 and 1/3 milliseconds at a sample rate of 48 khz.
constexpr int kAacFramesPerBuffer =;

int FramesPerInputBuffer(int sample_rate) {}

#if HAS_AAC_ENCODER
// Other end of remote `InterfaceFactory` requested by `AudioTrackMojoEncoder`.
// Used to create real `media::mojom::AudioEncoders`.
class TestInterfaceFactory : public media::mojom::InterfaceFactory {
 public:
  TestInterfaceFactory() = default;
  ~TestInterfaceFactory() override {
#if BUILDFLAG(IS_WIN)
    ::CoUninitialize();
#endif  // BUILDFLAG(IS_WIN)
  }

  void BindRequest(mojo::ScopedMessagePipeHandle handle) {
    receiver_.Bind(mojo::PendingReceiver<media::mojom::InterfaceFactory>(
        std::move(handle)));

    // Each `AudioTrackMojoEncoder` instance will try to open a connection to
    // this factory, so we must clean up after each one is destroyed.
    receiver_.set_disconnect_handler(WTF::BindOnce(
        &TestInterfaceFactory::OnConnectionError, base::Unretained(this)));
  }

  void OnConnectionError() { receiver_.reset(); }

  // Implement this one interface from mojom::InterfaceFactory.
  void CreateAudioEncoder(
      mojo::PendingReceiver<media::mojom::AudioEncoder> receiver) override {
    // While we'd like to use the real `GpuMojoMediaFactory` here, it requires
    // quite a bit more of scaffolding to setup and isn't really needed.
#if BUILDFLAG(IS_MAC)
    auto platform_audio_encoder =
        std::make_unique<media::AudioToolboxAudioEncoder>();
#elif BUILDFLAG(IS_WIN)
    HRESULT hr = ::CoInitializeEx(
        nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    DCHECK(SUCCEEDED(hr));
    auto platform_audio_encoder = std::make_unique<media::MFAudioEncoder>(
        blink::scheduler::GetSequencedTaskRunnerForTesting());
#else
#error "Unknown platform encoder."
#endif
    audio_encoder_receivers_.Add(
        std::make_unique<media::MojoAudioEncoderService>(
            std::move(platform_audio_encoder)),
        std::move(receiver));
  }

  // Stub out other `mojom::InterfaceFactory` interfaces.
  void CreateVideoDecoder(
      mojo::PendingReceiver<media::mojom::VideoDecoder> receiver,
      mojo::PendingRemote<media::stable::mojom::StableVideoDecoder>
          dst_video_decoder) override {}
  void CreateAudioDecoder(
      mojo::PendingReceiver<media::mojom::AudioDecoder> receiver) override {}
  void CreateDefaultRenderer(
      const std::string& audio_device_id,
      mojo::PendingReceiver<media::mojom::Renderer> receiver) override {}
#if BUILDFLAG(ENABLE_CAST_RENDERER)
  void CreateCastRenderer(
      const base::UnguessableToken& overlay_plane_id,
      mojo::PendingReceiver<media::mojom::Renderer> receiver) override {}
#endif
#if BUILDFLAG(IS_ANDROID)
  void CreateMediaPlayerRenderer(
      mojo::PendingRemote<media::mojom::MediaPlayerRendererClientExtension>
          client_extension_remote,
      mojo::PendingReceiver<media::mojom::Renderer> receiver,
      mojo::PendingReceiver<media::mojom::MediaPlayerRendererExtension>
          renderer_extension_receiver) override {}
  void CreateFlingingRenderer(
      const std::string& presentation_id,
      mojo::PendingRemote<media::mojom::FlingingRendererClientExtension>
          client_extension,
      mojo::PendingReceiver<media::mojom::Renderer> receiver) override {}
#endif  // BUILDFLAG(IS_ANDROID)
  void CreateCdm(const media::CdmConfig& cdm_config,
                 CreateCdmCallback callback) override {
    std::move(callback).Run(mojo::NullRemote(), nullptr,
                            media::CreateCdmStatus::kCdmNotSupported);
  }

#if BUILDFLAG(IS_WIN)
  void CreateMediaFoundationRenderer(
      mojo::PendingRemote<media::mojom::MediaLog> media_log_remote,
      mojo::PendingReceiver<media::mojom::Renderer> receiver,
      mojo::PendingReceiver<media::mojom::MediaFoundationRendererExtension>
          renderer_extension_receiver,
      mojo::PendingRemote<
          ::media::mojom::MediaFoundationRendererClientExtension>
          client_extension_remote) override {}
#endif  // BUILDFLAG(IS_WIN)
 private:
  mojo::Receiver<media::mojom::InterfaceFactory> receiver_{this};
  mojo::UniqueReceiverSet<media::mojom::AudioEncoder> audio_encoder_receivers_;
};
#endif  // HAS_AAC_ENCODER

}  // namespace

namespace blink {

struct ATRTestParams {};

const ATRTestParams kATRTestParams[] =;

std::string ParamsToString(
    const ::testing::TestParamInfo<ATRTestParams>& info) {}

class MockAudioTrackRecorderCallbackInterface
    : public GarbageCollected<MockAudioTrackRecorderCallbackInterface>,
      public AudioTrackRecorder::CallbackInterface {};

class AudioTrackRecorderTest : public testing::TestWithParam<ATRTestParams> {};

TEST_P(AudioTrackRecorderTest, RecordAndValidate) {}

TEST_P(AudioTrackRecorderTest, ChangeFormatMidRecording) {}

TEST_P(AudioTrackRecorderTest, ChangeFormatWhilePaused) {}

TEST_P(AudioTrackRecorderTest, SameFormat) {}

TEST_P(AudioTrackRecorderTest, PacketSize) {}

TEST_P(AudioTrackRecorderTest, PauseResume) {}

TEST_P(AudioTrackRecorderTest, PauseMidStream) {}

#if BUILDFLAG(IS_MAC)
// This test is flaky on Mac. See https://crbug.com/1370195.
#define MAYBE_PauseTwice
#else
#define MAYBE_PauseTwice
#endif
TEST_P(AudioTrackRecorderTest, MAYBE_PauseTwice) {}

TEST_P(AudioTrackRecorderTest, ResumeWithoutPausing) {}

INSTANTIATE_TEST_SUITE_P();

}  // namespace blink