summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/modules/audio_device/include
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/modules/audio_device/include')
-rw-r--r--third_party/libwebrtc/modules/audio_device/include/audio_device.h194
-rw-r--r--third_party/libwebrtc/modules/audio_device/include/audio_device_data_observer.h72
-rw-r--r--third_party/libwebrtc/modules/audio_device/include/audio_device_default.h132
-rw-r--r--third_party/libwebrtc/modules/audio_device/include/audio_device_defines.h177
-rw-r--r--third_party/libwebrtc/modules/audio_device/include/audio_device_factory.cc53
-rw-r--r--third_party/libwebrtc/modules/audio_device/include/audio_device_factory.h59
-rw-r--r--third_party/libwebrtc/modules/audio_device/include/fake_audio_device.h33
-rw-r--r--third_party/libwebrtc/modules/audio_device/include/mock_audio_device.h156
-rw-r--r--third_party/libwebrtc/modules/audio_device/include/mock_audio_transport.h81
-rw-r--r--third_party/libwebrtc/modules/audio_device/include/test_audio_device.cc540
-rw-r--r--third_party/libwebrtc/modules/audio_device/include/test_audio_device.h155
-rw-r--r--third_party/libwebrtc/modules/audio_device/include/test_audio_device_unittest.cc528
12 files changed, 2180 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/audio_device/include/audio_device.h b/third_party/libwebrtc/modules/audio_device/include/audio_device.h
new file mode 100644
index 0000000000..936ee6cb04
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_device/include/audio_device.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_H_
+#define MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_H_
+
+#include "absl/types/optional.h"
+#include "api/scoped_refptr.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "modules/audio_device/include/audio_device_defines.h"
+#include "rtc_base/ref_count.h"
+
+namespace webrtc {
+
+class AudioDeviceModuleForTest;
+
+class AudioDeviceModule : public rtc::RefCountInterface {
+ public:
+ enum AudioLayer {
+ kPlatformDefaultAudio = 0,
+ kWindowsCoreAudio,
+ kWindowsCoreAudio2,
+ kLinuxAlsaAudio,
+ kLinuxPulseAudio,
+ kAndroidJavaAudio,
+ kAndroidOpenSLESAudio,
+ kAndroidJavaInputAndOpenSLESOutputAudio,
+ kAndroidAAudioAudio,
+ kAndroidJavaInputAndAAudioOutputAudio,
+ kDummyAudio,
+ };
+
+ enum WindowsDeviceType {
+ kDefaultCommunicationDevice = -1,
+ kDefaultDevice = -2
+ };
+
+ struct Stats {
+ // The fields below correspond to similarly-named fields in the WebRTC stats
+ // spec. https://w3c.github.io/webrtc-stats/#playoutstats-dict*
+ double synthesized_samples_duration_s = 0;
+ uint64_t synthesized_samples_events = 0;
+ double total_samples_duration_s = 0;
+ double total_playout_delay_s = 0;
+ uint64_t total_samples_count = 0;
+ };
+
+ public:
+ // Creates a default ADM for usage in production code.
+ static rtc::scoped_refptr<AudioDeviceModule> Create(
+ AudioLayer audio_layer,
+ TaskQueueFactory* task_queue_factory);
+ // Creates an ADM with support for extra test methods. Don't use this factory
+ // in production code.
+ static rtc::scoped_refptr<AudioDeviceModuleForTest> CreateForTest(
+ AudioLayer audio_layer,
+ TaskQueueFactory* task_queue_factory);
+
+ // Retrieve the currently utilized audio layer
+ virtual int32_t ActiveAudioLayer(AudioLayer* audioLayer) const = 0;
+
+ // Full-duplex transportation of PCM audio
+ virtual int32_t RegisterAudioCallback(AudioTransport* audioCallback) = 0;
+
+ // Main initialization and termination
+ virtual int32_t Init() = 0;
+ virtual int32_t Terminate() = 0;
+ virtual bool Initialized() const = 0;
+
+ // Device enumeration
+ virtual int16_t PlayoutDevices() = 0;
+ virtual int16_t RecordingDevices() = 0;
+ virtual int32_t PlayoutDeviceName(uint16_t index,
+ char name[kAdmMaxDeviceNameSize],
+ char guid[kAdmMaxGuidSize]) = 0;
+ virtual int32_t RecordingDeviceName(uint16_t index,
+ char name[kAdmMaxDeviceNameSize],
+ char guid[kAdmMaxGuidSize]) = 0;
+
+ // Device selection
+ virtual int32_t SetPlayoutDevice(uint16_t index) = 0;
+ virtual int32_t SetPlayoutDevice(WindowsDeviceType device) = 0;
+ virtual int32_t SetRecordingDevice(uint16_t index) = 0;
+ virtual int32_t SetRecordingDevice(WindowsDeviceType device) = 0;
+
+ // Audio transport initialization
+ virtual int32_t PlayoutIsAvailable(bool* available) = 0;
+ virtual int32_t InitPlayout() = 0;
+ virtual bool PlayoutIsInitialized() const = 0;
+ virtual int32_t RecordingIsAvailable(bool* available) = 0;
+ virtual int32_t InitRecording() = 0;
+ virtual bool RecordingIsInitialized() const = 0;
+
+ // Audio transport control
+ virtual int32_t StartPlayout() = 0;
+ virtual int32_t StopPlayout() = 0;
+ virtual bool Playing() const = 0;
+ virtual int32_t StartRecording() = 0;
+ virtual int32_t StopRecording() = 0;
+ virtual bool Recording() const = 0;
+
+ // Audio mixer initialization
+ virtual int32_t InitSpeaker() = 0;
+ virtual bool SpeakerIsInitialized() const = 0;
+ virtual int32_t InitMicrophone() = 0;
+ virtual bool MicrophoneIsInitialized() const = 0;
+
+ // Speaker volume controls
+ virtual int32_t SpeakerVolumeIsAvailable(bool* available) = 0;
+ virtual int32_t SetSpeakerVolume(uint32_t volume) = 0;
+ virtual int32_t SpeakerVolume(uint32_t* volume) const = 0;
+ virtual int32_t MaxSpeakerVolume(uint32_t* maxVolume) const = 0;
+ virtual int32_t MinSpeakerVolume(uint32_t* minVolume) const = 0;
+
+ // Microphone volume controls
+ virtual int32_t MicrophoneVolumeIsAvailable(bool* available) = 0;
+ virtual int32_t SetMicrophoneVolume(uint32_t volume) = 0;
+ virtual int32_t MicrophoneVolume(uint32_t* volume) const = 0;
+ virtual int32_t MaxMicrophoneVolume(uint32_t* maxVolume) const = 0;
+ virtual int32_t MinMicrophoneVolume(uint32_t* minVolume) const = 0;
+
+ // Speaker mute control
+ virtual int32_t SpeakerMuteIsAvailable(bool* available) = 0;
+ virtual int32_t SetSpeakerMute(bool enable) = 0;
+ virtual int32_t SpeakerMute(bool* enabled) const = 0;
+
+ // Microphone mute control
+ virtual int32_t MicrophoneMuteIsAvailable(bool* available) = 0;
+ virtual int32_t SetMicrophoneMute(bool enable) = 0;
+ virtual int32_t MicrophoneMute(bool* enabled) const = 0;
+
+ // Stereo support
+ virtual int32_t StereoPlayoutIsAvailable(bool* available) const = 0;
+ virtual int32_t SetStereoPlayout(bool enable) = 0;
+ virtual int32_t StereoPlayout(bool* enabled) const = 0;
+ virtual int32_t StereoRecordingIsAvailable(bool* available) const = 0;
+ virtual int32_t SetStereoRecording(bool enable) = 0;
+ virtual int32_t StereoRecording(bool* enabled) const = 0;
+
+ // Playout delay
+ virtual int32_t PlayoutDelay(uint16_t* delayMS) const = 0;
+
+ // Only supported on Android.
+ virtual bool BuiltInAECIsAvailable() const = 0;
+ virtual bool BuiltInAGCIsAvailable() const = 0;
+ virtual bool BuiltInNSIsAvailable() const = 0;
+
+ // Enables the built-in audio effects. Only supported on Android.
+ virtual int32_t EnableBuiltInAEC(bool enable) = 0;
+ virtual int32_t EnableBuiltInAGC(bool enable) = 0;
+ virtual int32_t EnableBuiltInNS(bool enable) = 0;
+
+ // Play underrun count. Only supported on Android.
+ // TODO(alexnarest): Make it abstract after upstream projects support it.
+ virtual int32_t GetPlayoutUnderrunCount() const { return -1; }
+
+ // Used to generate RTC stats. If not implemented, RTCAudioPlayoutStats will
+ // not be present in the stats.
+ virtual absl::optional<Stats> GetStats() const { return absl::nullopt; }
+
+// Only supported on iOS.
+#if defined(WEBRTC_IOS)
+ virtual int GetPlayoutAudioParameters(AudioParameters* params) const = 0;
+ virtual int GetRecordAudioParameters(AudioParameters* params) const = 0;
+#endif // WEBRTC_IOS
+
+ protected:
+ ~AudioDeviceModule() override {}
+};
+
+// Extends the default ADM interface with some extra test methods.
+// Intended for usage in tests only and requires a unique factory method.
+class AudioDeviceModuleForTest : public AudioDeviceModule {
+ public:
+ // Triggers internal restart sequences of audio streaming. Can be used by
+ // tests to emulate events corresponding to e.g. removal of an active audio
+ // device or other actions which causes the stream to be disconnected.
+ virtual int RestartPlayoutInternally() = 0;
+ virtual int RestartRecordingInternally() = 0;
+
+ virtual int SetPlayoutSampleRate(uint32_t sample_rate) = 0;
+ virtual int SetRecordingSampleRate(uint32_t sample_rate) = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_H_
diff --git a/third_party/libwebrtc/modules/audio_device/include/audio_device_data_observer.h b/third_party/libwebrtc/modules/audio_device/include/audio_device_data_observer.h
new file mode 100644
index 0000000000..36dc45f19e
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_device/include/audio_device_data_observer.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_DATA_OBSERVER_H_
+#define MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_DATA_OBSERVER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "absl/base/attributes.h"
+#include "api/scoped_refptr.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "modules/audio_device/include/audio_device.h"
+
+namespace webrtc {
+
+// This interface will capture the raw PCM data of both the local captured as
+// well as the mixed/rendered remote audio.
+class AudioDeviceDataObserver {
+ public:
+ virtual void OnCaptureData(const void* audio_samples,
+ size_t num_samples,
+ size_t bytes_per_sample,
+ size_t num_channels,
+ uint32_t samples_per_sec) = 0;
+
+ virtual void OnRenderData(const void* audio_samples,
+ size_t num_samples,
+ size_t bytes_per_sample,
+ size_t num_channels,
+ uint32_t samples_per_sec) = 0;
+
+ AudioDeviceDataObserver() = default;
+ virtual ~AudioDeviceDataObserver() = default;
+};
+
+// Creates an ADMWrapper around an ADM instance that registers
+// the provided AudioDeviceDataObserver.
+rtc::scoped_refptr<AudioDeviceModule> CreateAudioDeviceWithDataObserver(
+ rtc::scoped_refptr<AudioDeviceModule> impl,
+ std::unique_ptr<AudioDeviceDataObserver> observer);
+
+// Creates an ADMWrapper around an ADM instance that registers
+// the provided AudioDeviceDataObserver.
+ABSL_DEPRECATED("")
+rtc::scoped_refptr<AudioDeviceModule> CreateAudioDeviceWithDataObserver(
+ rtc::scoped_refptr<AudioDeviceModule> impl,
+ AudioDeviceDataObserver* observer);
+
+// Creates an ADM instance with AudioDeviceDataObserver registered.
+rtc::scoped_refptr<AudioDeviceModule> CreateAudioDeviceWithDataObserver(
+ AudioDeviceModule::AudioLayer audio_layer,
+ TaskQueueFactory* task_queue_factory,
+ std::unique_ptr<AudioDeviceDataObserver> observer);
+
+// Creates an ADM instance with AudioDeviceDataObserver registered.
+ABSL_DEPRECATED("")
+rtc::scoped_refptr<AudioDeviceModule> CreateAudioDeviceWithDataObserver(
+ AudioDeviceModule::AudioLayer audio_layer,
+ TaskQueueFactory* task_queue_factory,
+ AudioDeviceDataObserver* observer);
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_DATA_OBSERVER_H_
diff --git a/third_party/libwebrtc/modules/audio_device/include/audio_device_default.h b/third_party/libwebrtc/modules/audio_device/include/audio_device_default.h
new file mode 100644
index 0000000000..3779d6fb3b
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_device/include/audio_device_default.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_DEFAULT_H_
+#define MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_DEFAULT_H_
+
+#include "modules/audio_device/include/audio_device.h"
+
+namespace webrtc {
+namespace webrtc_impl {
+
+// AudioDeviceModuleDefault template adds default implementation for all
+// AudioDeviceModule methods to the class, which inherits from
+// AudioDeviceModuleDefault<T>.
+template <typename T>
+class AudioDeviceModuleDefault : public T {
+ public:
+ AudioDeviceModuleDefault() {}
+ virtual ~AudioDeviceModuleDefault() {}
+
+ int32_t RegisterAudioCallback(AudioTransport* audioCallback) override {
+ return 0;
+ }
+ int32_t Init() override { return 0; }
+ int32_t InitSpeaker() override { return 0; }
+ int32_t SetPlayoutDevice(uint16_t index) override { return 0; }
+ int32_t SetPlayoutDevice(
+ AudioDeviceModule::WindowsDeviceType device) override {
+ return 0;
+ }
+ int32_t SetStereoPlayout(bool enable) override { return 0; }
+ int32_t StopPlayout() override { return 0; }
+ int32_t InitMicrophone() override { return 0; }
+ int32_t SetRecordingDevice(uint16_t index) override { return 0; }
+ int32_t SetRecordingDevice(
+ AudioDeviceModule::WindowsDeviceType device) override {
+ return 0;
+ }
+ int32_t SetStereoRecording(bool enable) override { return 0; }
+ int32_t StopRecording() override { return 0; }
+
+ int32_t Terminate() override { return 0; }
+
+ int32_t ActiveAudioLayer(
+ AudioDeviceModule::AudioLayer* audioLayer) const override {
+ return 0;
+ }
+ bool Initialized() const override { return true; }
+ int16_t PlayoutDevices() override { return 0; }
+ int16_t RecordingDevices() override { return 0; }
+ int32_t PlayoutDeviceName(uint16_t index,
+ char name[kAdmMaxDeviceNameSize],
+ char guid[kAdmMaxGuidSize]) override {
+ return 0;
+ }
+ int32_t RecordingDeviceName(uint16_t index,
+ char name[kAdmMaxDeviceNameSize],
+ char guid[kAdmMaxGuidSize]) override {
+ return 0;
+ }
+ int32_t PlayoutIsAvailable(bool* available) override { return 0; }
+ int32_t InitPlayout() override { return 0; }
+ bool PlayoutIsInitialized() const override { return true; }
+ int32_t RecordingIsAvailable(bool* available) override { return 0; }
+ int32_t InitRecording() override { return 0; }
+ bool RecordingIsInitialized() const override { return true; }
+ int32_t StartPlayout() override { return 0; }
+ bool Playing() const override { return false; }
+ int32_t StartRecording() override { return 0; }
+ bool Recording() const override { return false; }
+ bool SpeakerIsInitialized() const override { return true; }
+ bool MicrophoneIsInitialized() const override { return true; }
+ int32_t SpeakerVolumeIsAvailable(bool* available) override { return 0; }
+ int32_t SetSpeakerVolume(uint32_t volume) override { return 0; }
+ int32_t SpeakerVolume(uint32_t* volume) const override { return 0; }
+ int32_t MaxSpeakerVolume(uint32_t* maxVolume) const override { return 0; }
+ int32_t MinSpeakerVolume(uint32_t* minVolume) const override { return 0; }
+ int32_t MicrophoneVolumeIsAvailable(bool* available) override { return 0; }
+ int32_t SetMicrophoneVolume(uint32_t volume) override { return 0; }
+ int32_t MicrophoneVolume(uint32_t* volume) const override { return 0; }
+ int32_t MaxMicrophoneVolume(uint32_t* maxVolume) const override { return 0; }
+ int32_t MinMicrophoneVolume(uint32_t* minVolume) const override { return 0; }
+ int32_t SpeakerMuteIsAvailable(bool* available) override { return 0; }
+ int32_t SetSpeakerMute(bool enable) override { return 0; }
+ int32_t SpeakerMute(bool* enabled) const override { return 0; }
+ int32_t MicrophoneMuteIsAvailable(bool* available) override { return 0; }
+ int32_t SetMicrophoneMute(bool enable) override { return 0; }
+ int32_t MicrophoneMute(bool* enabled) const override { return 0; }
+ int32_t StereoPlayoutIsAvailable(bool* available) const override {
+ *available = false;
+ return 0;
+ }
+ int32_t StereoPlayout(bool* enabled) const override { return 0; }
+ int32_t StereoRecordingIsAvailable(bool* available) const override {
+ *available = false;
+ return 0;
+ }
+ int32_t StereoRecording(bool* enabled) const override { return 0; }
+ int32_t PlayoutDelay(uint16_t* delayMS) const override {
+ *delayMS = 0;
+ return 0;
+ }
+ bool BuiltInAECIsAvailable() const override { return false; }
+ int32_t EnableBuiltInAEC(bool enable) override { return -1; }
+ bool BuiltInAGCIsAvailable() const override { return false; }
+ int32_t EnableBuiltInAGC(bool enable) override { return -1; }
+ bool BuiltInNSIsAvailable() const override { return false; }
+ int32_t EnableBuiltInNS(bool enable) override { return -1; }
+
+ int32_t GetPlayoutUnderrunCount() const override { return -1; }
+
+#if defined(WEBRTC_IOS)
+ int GetPlayoutAudioParameters(AudioParameters* params) const override {
+ return -1;
+ }
+ int GetRecordAudioParameters(AudioParameters* params) const override {
+ return -1;
+ }
+#endif // WEBRTC_IOS
+};
+
+} // namespace webrtc_impl
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_DEFAULT_H_
diff --git a/third_party/libwebrtc/modules/audio_device/include/audio_device_defines.h b/third_party/libwebrtc/modules/audio_device/include/audio_device_defines.h
new file mode 100644
index 0000000000..d677d41f69
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_device/include/audio_device_defines.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_DEFINES_H_
+#define MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_DEFINES_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+
+static const int kAdmMaxDeviceNameSize = 128;
+static const int kAdmMaxFileNameSize = 512;
+static const int kAdmMaxGuidSize = 128;
+
+static const int kAdmMinPlayoutBufferSizeMs = 10;
+static const int kAdmMaxPlayoutBufferSizeMs = 250;
+
+// ----------------------------------------------------------------------------
+// AudioTransport
+// ----------------------------------------------------------------------------
+
+class AudioTransport {
+ public:
+ // TODO(bugs.webrtc.org/13620) Deprecate this function
+ virtual int32_t RecordedDataIsAvailable(const void* audioSamples,
+ size_t nSamples,
+ size_t nBytesPerSample,
+ size_t nChannels,
+ uint32_t samplesPerSec,
+ uint32_t totalDelayMS,
+ int32_t clockDrift,
+ uint32_t currentMicLevel,
+ bool keyPressed,
+ uint32_t& newMicLevel) = 0; // NOLINT
+
+ virtual int32_t RecordedDataIsAvailable(
+ const void* audioSamples,
+ size_t nSamples,
+ size_t nBytesPerSample,
+ size_t nChannels,
+ uint32_t samplesPerSec,
+ uint32_t totalDelayMS,
+ int32_t clockDrift,
+ uint32_t currentMicLevel,
+ bool keyPressed,
+ uint32_t& newMicLevel,
+ absl::optional<int64_t> estimatedCaptureTimeNS) { // NOLINT
+ // TODO(webrtc:13620) Make the default behaver of the new API to behave as
+ // the old API. This can be pure virtual if all uses of the old API is
+ // removed.
+ return RecordedDataIsAvailable(
+ audioSamples, nSamples, nBytesPerSample, nChannels, samplesPerSec,
+ totalDelayMS, clockDrift, currentMicLevel, keyPressed, newMicLevel);
+ }
+
+ // Implementation has to setup safe values for all specified out parameters.
+ virtual int32_t NeedMorePlayData(size_t nSamples,
+ size_t nBytesPerSample,
+ size_t nChannels,
+ uint32_t samplesPerSec,
+ void* audioSamples,
+ size_t& nSamplesOut, // NOLINT
+ int64_t* elapsed_time_ms,
+ int64_t* ntp_time_ms) = 0; // NOLINT
+
+ // Method to pull mixed render audio data from all active VoE channels.
+ // The data will not be passed as reference for audio processing internally.
+ virtual void PullRenderData(int bits_per_sample,
+ int sample_rate,
+ size_t number_of_channels,
+ size_t number_of_frames,
+ void* audio_data,
+ int64_t* elapsed_time_ms,
+ int64_t* ntp_time_ms) = 0;
+
+ protected:
+ virtual ~AudioTransport() {}
+};
+
+// Helper class for storage of fundamental audio parameters such as sample rate,
+// number of channels, native buffer size etc.
+// Note that one audio frame can contain more than one channel sample and each
+// sample is assumed to be a 16-bit PCM sample. Hence, one audio frame in
+// stereo contains 2 * (16/8) = 4 bytes of data.
+class AudioParameters {
+ public:
+ // This implementation does only support 16-bit PCM samples.
+ static const size_t kBitsPerSample = 16;
+ AudioParameters()
+ : sample_rate_(0),
+ channels_(0),
+ frames_per_buffer_(0),
+ frames_per_10ms_buffer_(0) {}
+ AudioParameters(int sample_rate, size_t channels, size_t frames_per_buffer)
+ : sample_rate_(sample_rate),
+ channels_(channels),
+ frames_per_buffer_(frames_per_buffer),
+ frames_per_10ms_buffer_(static_cast<size_t>(sample_rate / 100)) {}
+ void reset(int sample_rate, size_t channels, size_t frames_per_buffer) {
+ sample_rate_ = sample_rate;
+ channels_ = channels;
+ frames_per_buffer_ = frames_per_buffer;
+ frames_per_10ms_buffer_ = static_cast<size_t>(sample_rate / 100);
+ }
+ size_t bits_per_sample() const { return kBitsPerSample; }
+ void reset(int sample_rate, size_t channels, double buffer_duration) {
+ reset(sample_rate, channels,
+ static_cast<size_t>(sample_rate * buffer_duration + 0.5));
+ }
+ void reset(int sample_rate, size_t channels) {
+ reset(sample_rate, channels, static_cast<size_t>(0));
+ }
+ int sample_rate() const { return sample_rate_; }
+ size_t channels() const { return channels_; }
+ size_t frames_per_buffer() const { return frames_per_buffer_; }
+ size_t frames_per_10ms_buffer() const { return frames_per_10ms_buffer_; }
+ size_t GetBytesPerFrame() const { return channels_ * kBitsPerSample / 8; }
+ size_t GetBytesPerBuffer() const {
+ return frames_per_buffer_ * GetBytesPerFrame();
+ }
+ // The WebRTC audio device buffer (ADB) only requires that the sample rate
+ // and number of channels are configured. Hence, to be "valid", only these
+ // two attributes must be set.
+ bool is_valid() const { return ((sample_rate_ > 0) && (channels_ > 0)); }
+ // Most platforms also require that a native buffer size is defined.
+ // An audio parameter instance is considered to be "complete" if it is both
+ // "valid" (can be used by the ADB) and also has a native frame size.
+ bool is_complete() const { return (is_valid() && (frames_per_buffer_ > 0)); }
+ size_t GetBytesPer10msBuffer() const {
+ return frames_per_10ms_buffer_ * GetBytesPerFrame();
+ }
+ double GetBufferSizeInMilliseconds() const {
+ if (sample_rate_ == 0)
+ return 0.0;
+ return frames_per_buffer_ / (sample_rate_ / 1000.0);
+ }
+ double GetBufferSizeInSeconds() const {
+ if (sample_rate_ == 0)
+ return 0.0;
+ return static_cast<double>(frames_per_buffer_) / (sample_rate_);
+ }
+ std::string ToString() const {
+ char ss_buf[1024];
+ rtc::SimpleStringBuilder ss(ss_buf);
+ ss << "AudioParameters: ";
+ ss << "sample_rate=" << sample_rate() << ", channels=" << channels();
+ ss << ", frames_per_buffer=" << frames_per_buffer();
+ ss << ", frames_per_10ms_buffer=" << frames_per_10ms_buffer();
+ ss << ", bytes_per_frame=" << GetBytesPerFrame();
+ ss << ", bytes_per_buffer=" << GetBytesPerBuffer();
+ ss << ", bytes_per_10ms_buffer=" << GetBytesPer10msBuffer();
+ ss << ", size_in_ms=" << GetBufferSizeInMilliseconds();
+ return ss.str();
+ }
+
+ private:
+ int sample_rate_;
+ size_t channels_;
+ size_t frames_per_buffer_;
+ size_t frames_per_10ms_buffer_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_DEFINES_H_
diff --git a/third_party/libwebrtc/modules/audio_device/include/audio_device_factory.cc b/third_party/libwebrtc/modules/audio_device/include/audio_device_factory.cc
new file mode 100644
index 0000000000..130e096e6d
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_device/include/audio_device_factory.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_device/include/audio_device_factory.h"
+
+#include <memory>
+
+#if defined(WEBRTC_WIN)
+#include "modules/audio_device/win/audio_device_module_win.h"
+#include "modules/audio_device/win/core_audio_input_win.h"
+#include "modules/audio_device/win/core_audio_output_win.h"
+#include "modules/audio_device/win/core_audio_utility_win.h"
+#endif
+
+#include "api/task_queue/task_queue_factory.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+rtc::scoped_refptr<AudioDeviceModule> CreateWindowsCoreAudioAudioDeviceModule(
+ TaskQueueFactory* task_queue_factory,
+ bool automatic_restart) {
+ RTC_DLOG(LS_INFO) << __FUNCTION__;
+ return CreateWindowsCoreAudioAudioDeviceModuleForTest(task_queue_factory,
+ automatic_restart);
+}
+
+rtc::scoped_refptr<AudioDeviceModuleForTest>
+CreateWindowsCoreAudioAudioDeviceModuleForTest(
+ TaskQueueFactory* task_queue_factory,
+ bool automatic_restart) {
+ RTC_DLOG(LS_INFO) << __FUNCTION__;
+ // Returns NULL if Core Audio is not supported or if COM has not been
+ // initialized correctly using ScopedCOMInitializer.
+ if (!webrtc_win::core_audio_utility::IsSupported()) {
+ RTC_LOG(LS_ERROR)
+ << "Unable to create ADM since Core Audio is not supported";
+ return nullptr;
+ }
+ return CreateWindowsCoreAudioAudioDeviceModuleFromInputAndOutput(
+ std::make_unique<webrtc_win::CoreAudioInput>(automatic_restart),
+ std::make_unique<webrtc_win::CoreAudioOutput>(automatic_restart),
+ task_queue_factory);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_device/include/audio_device_factory.h b/third_party/libwebrtc/modules/audio_device/include/audio_device_factory.h
new file mode 100644
index 0000000000..edd7686b8e
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_device/include/audio_device_factory.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_FACTORY_H_
+#define MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_FACTORY_H_
+
+#include <memory>
+
+#include "api/task_queue/task_queue_factory.h"
+#include "modules/audio_device/include/audio_device.h"
+
+namespace webrtc {
+
+// Creates an AudioDeviceModule (ADM) for Windows based on the Core Audio API.
+// The creating thread must be a COM thread; otherwise nullptr will be returned.
+// By default `automatic_restart` is set to true and it results in support for
+// automatic restart of audio if e.g. the existing device is removed. If set to
+// false, no attempt to restart audio is performed under these conditions.
+//
+// Example (assuming webrtc namespace):
+//
+// public:
+// rtc::scoped_refptr<AudioDeviceModule> CreateAudioDevice() {
+// task_queue_factory_ = CreateDefaultTaskQueueFactory();
+// // Tell COM that this thread shall live in the MTA.
+// com_initializer_ = std::make_unique<ScopedCOMInitializer>(
+// ScopedCOMInitializer::kMTA);
+// if (!com_initializer_->Succeeded()) {
+// return nullptr;
+// }
+// // Create the ADM with support for automatic restart if devices are
+// // unplugged.
+// return CreateWindowsCoreAudioAudioDeviceModule(
+// task_queue_factory_.get());
+// }
+//
+// private:
+// std::unique_ptr<ScopedCOMInitializer> com_initializer_;
+// std::unique_ptr<TaskQueueFactory> task_queue_factory_;
+//
+rtc::scoped_refptr<AudioDeviceModule> CreateWindowsCoreAudioAudioDeviceModule(
+ TaskQueueFactory* task_queue_factory,
+ bool automatic_restart = true);
+
+rtc::scoped_refptr<AudioDeviceModuleForTest>
+CreateWindowsCoreAudioAudioDeviceModuleForTest(
+ TaskQueueFactory* task_queue_factory,
+ bool automatic_restart = true);
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_FACTORY_H_
diff --git a/third_party/libwebrtc/modules/audio_device/include/fake_audio_device.h b/third_party/libwebrtc/modules/audio_device/include/fake_audio_device.h
new file mode 100644
index 0000000000..2322ce0263
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_device/include/fake_audio_device.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_DEVICE_INCLUDE_FAKE_AUDIO_DEVICE_H_
+#define MODULES_AUDIO_DEVICE_INCLUDE_FAKE_AUDIO_DEVICE_H_
+
+#include "modules/audio_device/include/audio_device.h"
+#include "modules/audio_device/include/audio_device_default.h"
+
+namespace webrtc {
+
+class FakeAudioDeviceModule
+ : public webrtc_impl::AudioDeviceModuleDefault<AudioDeviceModule> {
+ public:
+ // TODO(bugs.webrtc.org/12701): Fix all users of this class to managed
+ // references using scoped_refptr. Current code doesn't always use refcounting
+ // for this class.
+ void AddRef() const override {}
+ rtc::RefCountReleaseStatus Release() const override {
+ return rtc::RefCountReleaseStatus::kDroppedLastRef;
+ }
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_DEVICE_INCLUDE_FAKE_AUDIO_DEVICE_H_
diff --git a/third_party/libwebrtc/modules/audio_device/include/mock_audio_device.h b/third_party/libwebrtc/modules/audio_device/include/mock_audio_device.h
new file mode 100644
index 0000000000..73fbdd547d
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_device/include/mock_audio_device.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_DEVICE_INCLUDE_MOCK_AUDIO_DEVICE_H_
+#define MODULES_AUDIO_DEVICE_INCLUDE_MOCK_AUDIO_DEVICE_H_
+
+#include <string>
+
+#include "api/make_ref_counted.h"
+#include "modules/audio_device/include/audio_device.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+namespace test {
+
+class MockAudioDeviceModule : public AudioDeviceModule {
+ public:
+ static rtc::scoped_refptr<MockAudioDeviceModule> CreateNice() {
+ return rtc::make_ref_counted<::testing::NiceMock<MockAudioDeviceModule>>();
+ }
+ static rtc::scoped_refptr<MockAudioDeviceModule> CreateStrict() {
+ return rtc::make_ref_counted<
+ ::testing::StrictMock<MockAudioDeviceModule>>();
+ }
+
+ // AudioDeviceModule.
+ MOCK_METHOD(int32_t,
+ ActiveAudioLayer,
+ (AudioLayer * audioLayer),
+ (const, override));
+ MOCK_METHOD(int32_t,
+ RegisterAudioCallback,
+ (AudioTransport * audioCallback),
+ (override));
+ MOCK_METHOD(int32_t, Init, (), (override));
+ MOCK_METHOD(int32_t, Terminate, (), (override));
+ MOCK_METHOD(bool, Initialized, (), (const, override));
+ MOCK_METHOD(int16_t, PlayoutDevices, (), (override));
+ MOCK_METHOD(int16_t, RecordingDevices, (), (override));
+ MOCK_METHOD(int32_t,
+ PlayoutDeviceName,
+ (uint16_t index,
+ char name[kAdmMaxDeviceNameSize],
+ char guid[kAdmMaxGuidSize]),
+ (override));
+ MOCK_METHOD(int32_t,
+ RecordingDeviceName,
+ (uint16_t index,
+ char name[kAdmMaxDeviceNameSize],
+ char guid[kAdmMaxGuidSize]),
+ (override));
+ MOCK_METHOD(int32_t, SetPlayoutDevice, (uint16_t index), (override));
+ MOCK_METHOD(int32_t,
+ SetPlayoutDevice,
+ (WindowsDeviceType device),
+ (override));
+ MOCK_METHOD(int32_t, SetRecordingDevice, (uint16_t index), (override));
+ MOCK_METHOD(int32_t,
+ SetRecordingDevice,
+ (WindowsDeviceType device),
+ (override));
+ MOCK_METHOD(int32_t, PlayoutIsAvailable, (bool* available), (override));
+ MOCK_METHOD(int32_t, InitPlayout, (), (override));
+ MOCK_METHOD(bool, PlayoutIsInitialized, (), (const, override));
+ MOCK_METHOD(int32_t, RecordingIsAvailable, (bool* available), (override));
+ MOCK_METHOD(int32_t, InitRecording, (), (override));
+ MOCK_METHOD(bool, RecordingIsInitialized, (), (const, override));
+ MOCK_METHOD(int32_t, StartPlayout, (), (override));
+ MOCK_METHOD(int32_t, StopPlayout, (), (override));
+ MOCK_METHOD(bool, Playing, (), (const, override));
+ MOCK_METHOD(int32_t, StartRecording, (), (override));
+ MOCK_METHOD(int32_t, StopRecording, (), (override));
+ MOCK_METHOD(bool, Recording, (), (const, override));
+ MOCK_METHOD(int32_t, InitSpeaker, (), (override));
+ MOCK_METHOD(bool, SpeakerIsInitialized, (), (const, override));
+ MOCK_METHOD(int32_t, InitMicrophone, (), (override));
+ MOCK_METHOD(bool, MicrophoneIsInitialized, (), (const, override));
+ MOCK_METHOD(int32_t, SpeakerVolumeIsAvailable, (bool* available), (override));
+ MOCK_METHOD(int32_t, SetSpeakerVolume, (uint32_t volume), (override));
+ MOCK_METHOD(int32_t, SpeakerVolume, (uint32_t * volume), (const, override));
+ MOCK_METHOD(int32_t,
+ MaxSpeakerVolume,
+ (uint32_t * maxVolume),
+ (const, override));
+ MOCK_METHOD(int32_t,
+ MinSpeakerVolume,
+ (uint32_t * minVolume),
+ (const, override));
+ MOCK_METHOD(int32_t,
+ MicrophoneVolumeIsAvailable,
+ (bool* available),
+ (override));
+ MOCK_METHOD(int32_t, SetMicrophoneVolume, (uint32_t volume), (override));
+ MOCK_METHOD(int32_t,
+ MicrophoneVolume,
+ (uint32_t * volume),
+ (const, override));
+ MOCK_METHOD(int32_t,
+ MaxMicrophoneVolume,
+ (uint32_t * maxVolume),
+ (const, override));
+ MOCK_METHOD(int32_t,
+ MinMicrophoneVolume,
+ (uint32_t * minVolume),
+ (const, override));
+ MOCK_METHOD(int32_t, SpeakerMuteIsAvailable, (bool* available), (override));
+ MOCK_METHOD(int32_t, SetSpeakerMute, (bool enable), (override));
+ MOCK_METHOD(int32_t, SpeakerMute, (bool* enabled), (const, override));
+ MOCK_METHOD(int32_t,
+ MicrophoneMuteIsAvailable,
+ (bool* available),
+ (override));
+ MOCK_METHOD(int32_t, SetMicrophoneMute, (bool enable), (override));
+ MOCK_METHOD(int32_t, MicrophoneMute, (bool* enabled), (const, override));
+ MOCK_METHOD(int32_t,
+ StereoPlayoutIsAvailable,
+ (bool* available),
+ (const, override));
+ MOCK_METHOD(int32_t, SetStereoPlayout, (bool enable), (override));
+ MOCK_METHOD(int32_t, StereoPlayout, (bool* enabled), (const, override));
+ MOCK_METHOD(int32_t,
+ StereoRecordingIsAvailable,
+ (bool* available),
+ (const, override));
+ MOCK_METHOD(int32_t, SetStereoRecording, (bool enable), (override));
+ MOCK_METHOD(int32_t, StereoRecording, (bool* enabled), (const, override));
+ MOCK_METHOD(int32_t, PlayoutDelay, (uint16_t * delayMS), (const, override));
+ MOCK_METHOD(bool, BuiltInAECIsAvailable, (), (const, override));
+ MOCK_METHOD(bool, BuiltInAGCIsAvailable, (), (const, override));
+ MOCK_METHOD(bool, BuiltInNSIsAvailable, (), (const, override));
+ MOCK_METHOD(int32_t, EnableBuiltInAEC, (bool enable), (override));
+ MOCK_METHOD(int32_t, EnableBuiltInAGC, (bool enable), (override));
+ MOCK_METHOD(int32_t, EnableBuiltInNS, (bool enable), (override));
+ MOCK_METHOD(int32_t, GetPlayoutUnderrunCount, (), (const, override));
+#if defined(WEBRTC_IOS)
+ MOCK_METHOD(int,
+ GetPlayoutAudioParameters,
+ (AudioParameters * params),
+ (const, override));
+ MOCK_METHOD(int,
+ GetRecordAudioParameters,
+ (AudioParameters * params),
+ (const, override));
+#endif // WEBRTC_IOS
+};
+} // namespace test
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_DEVICE_INCLUDE_MOCK_AUDIO_DEVICE_H_
diff --git a/third_party/libwebrtc/modules/audio_device/include/mock_audio_transport.h b/third_party/libwebrtc/modules/audio_device/include/mock_audio_transport.h
new file mode 100644
index 0000000000..b886967319
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_device/include/mock_audio_transport.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_DEVICE_INCLUDE_MOCK_AUDIO_TRANSPORT_H_
+#define MODULES_AUDIO_DEVICE_INCLUDE_MOCK_AUDIO_TRANSPORT_H_
+
+#include "modules/audio_device/include/audio_device_defines.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+namespace test {
+
+class MockAudioTransport : public AudioTransport {
+ public:
+ MockAudioTransport() {}
+ ~MockAudioTransport() {}
+
+ MOCK_METHOD(int32_t,
+ RecordedDataIsAvailable,
+ (const void* audioSamples,
+ size_t nSamples,
+ size_t nBytesPerSample,
+ size_t nChannels,
+ uint32_t samplesPerSec,
+ uint32_t totalDelayMS,
+ int32_t clockDrift,
+ uint32_t currentMicLevel,
+ bool keyPressed,
+ uint32_t& newMicLevel),
+ (override));
+
+ MOCK_METHOD(int32_t,
+ RecordedDataIsAvailable,
+ (const void* audioSamples,
+ size_t nSamples,
+ size_t nBytesPerSample,
+ size_t nChannels,
+ uint32_t samplesPerSec,
+ uint32_t totalDelayMS,
+ int32_t clockDrift,
+ uint32_t currentMicLevel,
+ bool keyPressed,
+ uint32_t& newMicLevel,
+ absl::optional<int64_t> estimated_capture_time_ns),
+ (override));
+
+ MOCK_METHOD(int32_t,
+ NeedMorePlayData,
+ (size_t nSamples,
+ size_t nBytesPerSample,
+ size_t nChannels,
+ uint32_t samplesPerSec,
+ void* audioSamples,
+ size_t& nSamplesOut,
+ int64_t* elapsed_time_ms,
+ int64_t* ntp_time_ms),
+ (override));
+
+ MOCK_METHOD(void,
+ PullRenderData,
+ (int bits_per_sample,
+ int sample_rate,
+ size_t number_of_channels,
+ size_t number_of_frames,
+ void* audio_data,
+ int64_t* elapsed_time_ms,
+ int64_t* ntp_time_ms),
+ (override));
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_DEVICE_INCLUDE_MOCK_AUDIO_TRANSPORT_H_
diff --git a/third_party/libwebrtc/modules/audio_device/include/test_audio_device.cc b/third_party/libwebrtc/modules/audio_device/include/test_audio_device.cc
new file mode 100644
index 0000000000..4c29c98f2c
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_device/include/test_audio_device.cc
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "modules/audio_device/include/test_audio_device.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <cstdlib>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "api/make_ref_counted.h"
+#include "common_audio/wav_file.h"
+#include "modules/audio_device/audio_device_impl.h"
+#include "modules/audio_device/include/audio_device_default.h"
+#include "modules/audio_device/test_audio_device_impl.h"
+#include "rtc_base/buffer.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/event.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/platform_thread.h"
+#include "rtc_base/random.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "rtc_base/task_queue.h"
+#include "rtc_base/task_utils/repeating_task.h"
+#include "rtc_base/thread_annotations.h"
+#include "rtc_base/time_utils.h"
+
+namespace webrtc {
+
+namespace {
+
+constexpr int kFrameLengthUs = 10000;
+constexpr int kFramesPerSecond = rtc::kNumMicrosecsPerSec / kFrameLengthUs;
+
+class TestAudioDeviceModuleImpl : public AudioDeviceModuleImpl {
+ public:
+ TestAudioDeviceModuleImpl(
+ TaskQueueFactory* task_queue_factory,
+ std::unique_ptr<TestAudioDeviceModule::Capturer> capturer,
+ std::unique_ptr<TestAudioDeviceModule::Renderer> renderer,
+ float speed = 1)
+ : AudioDeviceModuleImpl(
+ AudioLayer::kDummyAudio,
+ std::make_unique<TestAudioDevice>(task_queue_factory,
+ std::move(capturer),
+ std::move(renderer),
+ speed),
+ task_queue_factory,
+ /*create_detached=*/true) {}
+
+ ~TestAudioDeviceModuleImpl() override = default;
+};
+
+// A fake capturer that generates pulses with random samples between
+// -max_amplitude and +max_amplitude.
+class PulsedNoiseCapturerImpl final
+ : public TestAudioDeviceModule::PulsedNoiseCapturer {
+ public:
+ // Assuming 10ms audio packets.
+ PulsedNoiseCapturerImpl(int16_t max_amplitude,
+ int sampling_frequency_in_hz,
+ int num_channels)
+ : sampling_frequency_in_hz_(sampling_frequency_in_hz),
+ fill_with_zero_(false),
+ random_generator_(1),
+ max_amplitude_(max_amplitude),
+ num_channels_(num_channels) {
+ RTC_DCHECK_GT(max_amplitude, 0);
+ }
+
+ int SamplingFrequency() const override { return sampling_frequency_in_hz_; }
+
+ int NumChannels() const override { return num_channels_; }
+
+ bool Capture(rtc::BufferT<int16_t>* buffer) override {
+ fill_with_zero_ = !fill_with_zero_;
+ int16_t max_amplitude;
+ {
+ MutexLock lock(&lock_);
+ max_amplitude = max_amplitude_;
+ }
+ buffer->SetData(
+ TestAudioDeviceModule::SamplesPerFrame(sampling_frequency_in_hz_) *
+ num_channels_,
+ [&](rtc::ArrayView<int16_t> data) {
+ if (fill_with_zero_) {
+ std::fill(data.begin(), data.end(), 0);
+ } else {
+ std::generate(data.begin(), data.end(), [&]() {
+ return random_generator_.Rand(-max_amplitude, max_amplitude);
+ });
+ }
+ return data.size();
+ });
+ return true;
+ }
+
+ void SetMaxAmplitude(int16_t amplitude) override {
+ MutexLock lock(&lock_);
+ max_amplitude_ = amplitude;
+ }
+
+ private:
+ int sampling_frequency_in_hz_;
+ bool fill_with_zero_;
+ Random random_generator_;
+ Mutex lock_;
+ int16_t max_amplitude_ RTC_GUARDED_BY(lock_);
+ const int num_channels_;
+};
+
+class WavFileReader final : public TestAudioDeviceModule::Capturer {
+ public:
+ WavFileReader(absl::string_view filename,
+ int sampling_frequency_in_hz,
+ int num_channels,
+ bool repeat)
+ : WavFileReader(std::make_unique<WavReader>(filename),
+ sampling_frequency_in_hz,
+ num_channels,
+ repeat) {}
+
+ int SamplingFrequency() const override { return sampling_frequency_in_hz_; }
+
+ int NumChannels() const override { return num_channels_; }
+
+ bool Capture(rtc::BufferT<int16_t>* buffer) override {
+ buffer->SetData(
+ TestAudioDeviceModule::SamplesPerFrame(sampling_frequency_in_hz_) *
+ num_channels_,
+ [&](rtc::ArrayView<int16_t> data) {
+ size_t read = wav_reader_->ReadSamples(data.size(), data.data());
+ if (read < data.size() && repeat_) {
+ do {
+ wav_reader_->Reset();
+ size_t delta = wav_reader_->ReadSamples(
+ data.size() - read, data.subview(read).data());
+ RTC_CHECK_GT(delta, 0) << "No new data read from file";
+ read += delta;
+ } while (read < data.size());
+ }
+ return read;
+ });
+ return buffer->size() > 0;
+ }
+
+ private:
+ WavFileReader(std::unique_ptr<WavReader> wav_reader,
+ int sampling_frequency_in_hz,
+ int num_channels,
+ bool repeat)
+ : sampling_frequency_in_hz_(sampling_frequency_in_hz),
+ num_channels_(num_channels),
+ wav_reader_(std::move(wav_reader)),
+ repeat_(repeat) {
+ RTC_CHECK_EQ(wav_reader_->sample_rate(), sampling_frequency_in_hz);
+ RTC_CHECK_EQ(wav_reader_->num_channels(), num_channels);
+ }
+
+ const int sampling_frequency_in_hz_;
+ const int num_channels_;
+ std::unique_ptr<WavReader> wav_reader_;
+ const bool repeat_;
+};
+
+class WavFileWriter final : public TestAudioDeviceModule::Renderer {
+ public:
+ WavFileWriter(absl::string_view filename,
+ int sampling_frequency_in_hz,
+ int num_channels)
+ : WavFileWriter(std::make_unique<WavWriter>(filename,
+ sampling_frequency_in_hz,
+ num_channels),
+ sampling_frequency_in_hz,
+ num_channels) {}
+
+ int SamplingFrequency() const override { return sampling_frequency_in_hz_; }
+
+ int NumChannels() const override { return num_channels_; }
+
+ bool Render(rtc::ArrayView<const int16_t> data) override {
+ wav_writer_->WriteSamples(data.data(), data.size());
+ return true;
+ }
+
+ private:
+ WavFileWriter(std::unique_ptr<WavWriter> wav_writer,
+ int sampling_frequency_in_hz,
+ int num_channels)
+ : sampling_frequency_in_hz_(sampling_frequency_in_hz),
+ wav_writer_(std::move(wav_writer)),
+ num_channels_(num_channels) {}
+
+ int sampling_frequency_in_hz_;
+ std::unique_ptr<WavWriter> wav_writer_;
+ const int num_channels_;
+};
+
+class BoundedWavFileWriter : public TestAudioDeviceModule::Renderer {
+ public:
+ BoundedWavFileWriter(absl::string_view filename,
+ int sampling_frequency_in_hz,
+ int num_channels)
+ : sampling_frequency_in_hz_(sampling_frequency_in_hz),
+ wav_writer_(filename, sampling_frequency_in_hz, num_channels),
+ num_channels_(num_channels),
+ silent_audio_(
+ TestAudioDeviceModule::SamplesPerFrame(sampling_frequency_in_hz) *
+ num_channels,
+ 0),
+ started_writing_(false),
+ trailing_zeros_(0) {}
+
+ int SamplingFrequency() const override { return sampling_frequency_in_hz_; }
+
+ int NumChannels() const override { return num_channels_; }
+
+ bool Render(rtc::ArrayView<const int16_t> data) override {
+ const int16_t kAmplitudeThreshold = 5;
+
+ const int16_t* begin = data.begin();
+ const int16_t* end = data.end();
+ if (!started_writing_) {
+ // Cut off silence at the beginning.
+ while (begin < end) {
+ if (std::abs(*begin) > kAmplitudeThreshold) {
+ started_writing_ = true;
+ break;
+ }
+ ++begin;
+ }
+ }
+ if (started_writing_) {
+ // Cut off silence at the end.
+ while (begin < end) {
+ if (*(end - 1) != 0) {
+ break;
+ }
+ --end;
+ }
+ if (begin < end) {
+ // If it turns out that the silence was not final, need to write all the
+ // skipped zeros and continue writing audio.
+ while (trailing_zeros_ > 0) {
+ const size_t zeros_to_write =
+ std::min(trailing_zeros_, silent_audio_.size());
+ wav_writer_.WriteSamples(silent_audio_.data(), zeros_to_write);
+ trailing_zeros_ -= zeros_to_write;
+ }
+ wav_writer_.WriteSamples(begin, end - begin);
+ }
+ // Save the number of zeros we skipped in case this needs to be restored.
+ trailing_zeros_ += data.end() - end;
+ }
+ return true;
+ }
+
+ private:
+ int sampling_frequency_in_hz_;
+ WavWriter wav_writer_;
+ const int num_channels_;
+ std::vector<int16_t> silent_audio_;
+ bool started_writing_;
+ size_t trailing_zeros_;
+};
+
+class DiscardRenderer final : public TestAudioDeviceModule::Renderer {
+ public:
+ explicit DiscardRenderer(int sampling_frequency_in_hz, int num_channels)
+ : sampling_frequency_in_hz_(sampling_frequency_in_hz),
+ num_channels_(num_channels) {}
+
+ int SamplingFrequency() const override { return sampling_frequency_in_hz_; }
+
+ int NumChannels() const override { return num_channels_; }
+
+ bool Render(rtc::ArrayView<const int16_t> data) override { return true; }
+
+ private:
+ int sampling_frequency_in_hz_;
+ const int num_channels_;
+};
+
+class RawFileReader final : public TestAudioDeviceModule::Capturer {
+ public:
+ RawFileReader(absl::string_view input_file_name,
+ int sampling_frequency_in_hz,
+ int num_channels,
+ bool repeat)
+ : input_file_name_(input_file_name),
+ sampling_frequency_in_hz_(sampling_frequency_in_hz),
+ num_channels_(num_channels),
+ repeat_(repeat),
+ read_buffer_(
+ TestAudioDeviceModule::SamplesPerFrame(sampling_frequency_in_hz) *
+ num_channels * 2,
+ 0) {
+ input_file_ = FileWrapper::OpenReadOnly(input_file_name_);
+ RTC_CHECK(input_file_.is_open())
+ << "Failed to open audio input file: " << input_file_name_;
+ }
+
+ ~RawFileReader() override { input_file_.Close(); }
+
+ int SamplingFrequency() const override { return sampling_frequency_in_hz_; }
+
+ int NumChannels() const override { return num_channels_; }
+
+ bool Capture(rtc::BufferT<int16_t>* buffer) override {
+ buffer->SetData(
+ TestAudioDeviceModule::SamplesPerFrame(SamplingFrequency()) *
+ NumChannels(),
+ [&](rtc::ArrayView<int16_t> data) {
+ rtc::ArrayView<int8_t> read_buffer_view = ReadBufferView();
+ size_t size = data.size() * 2;
+ size_t read = input_file_.Read(read_buffer_view.data(), size);
+ if (read < size && repeat_) {
+ do {
+ input_file_.Rewind();
+ size_t delta = input_file_.Read(
+ read_buffer_view.subview(read).data(), size - read);
+ RTC_CHECK_GT(delta, 0) << "No new data to read from file";
+ read += delta;
+ } while (read < size);
+ }
+ memcpy(data.data(), read_buffer_view.data(), size);
+ return read / 2;
+ });
+ return buffer->size() > 0;
+ }
+
+ private:
+ rtc::ArrayView<int8_t> ReadBufferView() { return read_buffer_; }
+
+ const std::string input_file_name_;
+ const int sampling_frequency_in_hz_;
+ const int num_channels_;
+ const bool repeat_;
+ FileWrapper input_file_;
+ std::vector<int8_t> read_buffer_;
+};
+
+class RawFileWriter : public TestAudioDeviceModule::Renderer {
+ public:
+ RawFileWriter(absl::string_view output_file_name,
+ int sampling_frequency_in_hz,
+ int num_channels)
+ : output_file_name_(output_file_name),
+ sampling_frequency_in_hz_(sampling_frequency_in_hz),
+ num_channels_(num_channels),
+ silent_audio_(
+ TestAudioDeviceModule::SamplesPerFrame(sampling_frequency_in_hz) *
+ num_channels * 2,
+ 0),
+ write_buffer_(
+ TestAudioDeviceModule::SamplesPerFrame(sampling_frequency_in_hz) *
+ num_channels * 2,
+ 0),
+ started_writing_(false),
+ trailing_zeros_(0) {
+ output_file_ = FileWrapper::OpenWriteOnly(output_file_name_);
+ RTC_CHECK(output_file_.is_open())
+ << "Failed to open playout file" << output_file_name_;
+ }
+ ~RawFileWriter() override { output_file_.Close(); }
+
+ int SamplingFrequency() const override { return sampling_frequency_in_hz_; }
+
+ int NumChannels() const override { return num_channels_; }
+
+ bool Render(rtc::ArrayView<const int16_t> data) override {
+ const int16_t kAmplitudeThreshold = 5;
+
+ const int16_t* begin = data.begin();
+ const int16_t* end = data.end();
+ if (!started_writing_) {
+ // Cut off silence at the beginning.
+ while (begin < end) {
+ if (std::abs(*begin) > kAmplitudeThreshold) {
+ started_writing_ = true;
+ break;
+ }
+ ++begin;
+ }
+ }
+ if (started_writing_) {
+ // Cut off silence at the end.
+ while (begin < end) {
+ if (*(end - 1) != 0) {
+ break;
+ }
+ --end;
+ }
+ if (begin < end) {
+ // If it turns out that the silence was not final, need to write all the
+ // skipped zeros and continue writing audio.
+ while (trailing_zeros_ > 0) {
+ const size_t zeros_to_write =
+ std::min(trailing_zeros_, silent_audio_.size());
+ output_file_.Write(silent_audio_.data(), zeros_to_write * 2);
+ trailing_zeros_ -= zeros_to_write;
+ }
+ WriteInt16(begin, end);
+ }
+ // Save the number of zeros we skipped in case this needs to be restored.
+ trailing_zeros_ += data.end() - end;
+ }
+ return true;
+ }
+
+ private:
+ void WriteInt16(const int16_t* begin, const int16_t* end) {
+ int size = (end - begin) * sizeof(int16_t);
+ memcpy(write_buffer_.data(), begin, size);
+ output_file_.Write(write_buffer_.data(), size);
+ }
+
+ const std::string output_file_name_;
+ const int sampling_frequency_in_hz_;
+ const int num_channels_;
+ FileWrapper output_file_;
+ std::vector<int8_t> silent_audio_;
+ std::vector<int8_t> write_buffer_;
+ bool started_writing_;
+ size_t trailing_zeros_;
+};
+
+} // namespace
+
+size_t TestAudioDeviceModule::SamplesPerFrame(int sampling_frequency_in_hz) {
+ return rtc::CheckedDivExact(sampling_frequency_in_hz, kFramesPerSecond);
+}
+
+rtc::scoped_refptr<AudioDeviceModule> TestAudioDeviceModule::Create(
+ TaskQueueFactory* task_queue_factory,
+ std::unique_ptr<TestAudioDeviceModule::Capturer> capturer,
+ std::unique_ptr<TestAudioDeviceModule::Renderer> renderer,
+ float speed) {
+ auto audio_device = rtc::make_ref_counted<TestAudioDeviceModuleImpl>(
+ task_queue_factory, std::move(capturer), std::move(renderer), speed);
+
+ // Ensure that the current platform is supported.
+ if (audio_device->CheckPlatform() == -1) {
+ return nullptr;
+ }
+
+ // Create the platform-dependent implementation.
+ if (audio_device->CreatePlatformSpecificObjects() == -1) {
+ return nullptr;
+ }
+
+ // Ensure that the generic audio buffer can communicate with the platform
+ // specific parts.
+ if (audio_device->AttachAudioBuffer() == -1) {
+ return nullptr;
+ }
+
+ return audio_device;
+}
+
+std::unique_ptr<TestAudioDeviceModule::PulsedNoiseCapturer>
+TestAudioDeviceModule::CreatePulsedNoiseCapturer(int16_t max_amplitude,
+ int sampling_frequency_in_hz,
+ int num_channels) {
+ return std::make_unique<PulsedNoiseCapturerImpl>(
+ max_amplitude, sampling_frequency_in_hz, num_channels);
+}
+
+std::unique_ptr<TestAudioDeviceModule::Renderer>
+TestAudioDeviceModule::CreateDiscardRenderer(int sampling_frequency_in_hz,
+ int num_channels) {
+ return std::make_unique<DiscardRenderer>(sampling_frequency_in_hz,
+ num_channels);
+}
+
+std::unique_ptr<TestAudioDeviceModule::Capturer>
+TestAudioDeviceModule::CreateWavFileReader(absl::string_view filename,
+ int sampling_frequency_in_hz,
+ int num_channels) {
+ return std::make_unique<WavFileReader>(filename, sampling_frequency_in_hz,
+ num_channels, false);
+}
+
+std::unique_ptr<TestAudioDeviceModule::Capturer>
+TestAudioDeviceModule::CreateWavFileReader(absl::string_view filename,
+ bool repeat) {
+ WavReader reader(filename);
+ int sampling_frequency_in_hz = reader.sample_rate();
+ int num_channels = rtc::checked_cast<int>(reader.num_channels());
+ return std::make_unique<WavFileReader>(filename, sampling_frequency_in_hz,
+ num_channels, repeat);
+}
+
+std::unique_ptr<TestAudioDeviceModule::Renderer>
+TestAudioDeviceModule::CreateWavFileWriter(absl::string_view filename,
+ int sampling_frequency_in_hz,
+ int num_channels) {
+ return std::make_unique<WavFileWriter>(filename, sampling_frequency_in_hz,
+ num_channels);
+}
+
+std::unique_ptr<TestAudioDeviceModule::Renderer>
+TestAudioDeviceModule::CreateBoundedWavFileWriter(absl::string_view filename,
+ int sampling_frequency_in_hz,
+ int num_channels) {
+ return std::make_unique<BoundedWavFileWriter>(
+ filename, sampling_frequency_in_hz, num_channels);
+}
+
+std::unique_ptr<TestAudioDeviceModule::Capturer>
+TestAudioDeviceModule::CreateRawFileReader(absl::string_view filename,
+ int sampling_frequency_in_hz,
+ int num_channels,
+ bool repeat) {
+ return std::make_unique<RawFileReader>(filename, sampling_frequency_in_hz,
+ num_channels, repeat);
+}
+
+std::unique_ptr<TestAudioDeviceModule::Renderer>
+TestAudioDeviceModule::CreateRawFileWriter(absl::string_view filename,
+ int sampling_frequency_in_hz,
+ int num_channels) {
+ return std::make_unique<RawFileWriter>(filename, sampling_frequency_in_hz,
+ num_channels);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_device/include/test_audio_device.h b/third_party/libwebrtc/modules/audio_device/include/test_audio_device.h
new file mode 100644
index 0000000000..4b2d755ae1
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_device/include/test_audio_device.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef MODULES_AUDIO_DEVICE_INCLUDE_TEST_AUDIO_DEVICE_H_
+#define MODULES_AUDIO_DEVICE_INCLUDE_TEST_AUDIO_DEVICE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "api/scoped_refptr.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "modules/audio_device/include/audio_device.h"
+#include "modules/audio_device/include/audio_device_defines.h"
+#include "rtc_base/buffer.h"
+
+namespace webrtc {
+
+// This is test API and is in development, so it can be changed/removed without
+// notice.
+
+// This class exists for historical reasons. For now it only contains static
+// methods to create test AudioDeviceModule. Implementation details of that
+// module are considered private. This class isn't intended to be instantiated.
+class TestAudioDeviceModule {
+ public:
+ // Returns the number of samples that Capturers and Renderers with this
+ // sampling frequency will work with every time Capture or Render is called.
+ static size_t SamplesPerFrame(int sampling_frequency_in_hz);
+
+ class Capturer {
+ public:
+ virtual ~Capturer() {}
+ // Returns the sampling frequency in Hz of the audio data that this
+ // capturer produces.
+ virtual int SamplingFrequency() const = 0;
+ // Returns the number of channels of captured audio data.
+ virtual int NumChannels() const = 0;
+ // Replaces the contents of `buffer` with 10ms of captured audio data
+ // (see TestAudioDeviceModule::SamplesPerFrame). Returns true if the
+ // capturer can keep producing data, or false when the capture finishes.
+ virtual bool Capture(rtc::BufferT<int16_t>* buffer) = 0;
+ };
+
+ class Renderer {
+ public:
+ virtual ~Renderer() {}
+ // Returns the sampling frequency in Hz of the audio data that this
+ // renderer receives.
+ virtual int SamplingFrequency() const = 0;
+ // Returns the number of channels of audio data to be required.
+ virtual int NumChannels() const = 0;
+ // Renders the passed audio data and returns true if the renderer wants
+ // to keep receiving data, or false otherwise.
+ virtual bool Render(rtc::ArrayView<const int16_t> data) = 0;
+ };
+
+ // A fake capturer that generates pulses with random samples between
+ // -max_amplitude and +max_amplitude.
+ class PulsedNoiseCapturer : public Capturer {
+ public:
+ ~PulsedNoiseCapturer() override {}
+
+ virtual void SetMaxAmplitude(int16_t amplitude) = 0;
+ };
+
+ // Creates a new TestAudioDeviceModule. When capturing or playing, 10 ms audio
+ // frames will be processed every 10ms / `speed`.
+ // `capturer` is an object that produces audio data. Can be nullptr if this
+ // device is never used for recording.
+ // `renderer` is an object that receives audio data that would have been
+ // played out. Can be nullptr if this device is never used for playing.
+ // Use one of the Create... functions to get these instances.
+ static rtc::scoped_refptr<AudioDeviceModule> Create(
+ TaskQueueFactory* task_queue_factory,
+ std::unique_ptr<Capturer> capturer,
+ std::unique_ptr<Renderer> renderer,
+ float speed = 1);
+
+ // Returns a Capturer instance that generates a signal of `num_channels`
+ // channels where every second frame is zero and every second frame is evenly
+ // distributed random noise with max amplitude `max_amplitude`.
+ static std::unique_ptr<PulsedNoiseCapturer> CreatePulsedNoiseCapturer(
+ int16_t max_amplitude,
+ int sampling_frequency_in_hz,
+ int num_channels = 1);
+
+ // Returns a Renderer instance that does nothing with the audio data.
+ static std::unique_ptr<Renderer> CreateDiscardRenderer(
+ int sampling_frequency_in_hz,
+ int num_channels = 1);
+
+ // WavReader and WavWriter creation based on file name.
+
+ // Returns a Capturer instance that gets its data from a WAV file. The sample
+ // rate and channels will be checked against the Wav file.
+ static std::unique_ptr<Capturer> CreateWavFileReader(
+ absl::string_view filename,
+ int sampling_frequency_in_hz,
+ int num_channels = 1);
+
+ // Returns a Capturer instance that gets its data from a file.
+ // Automatically detects sample rate and num of channels.
+ // `repeat` - if true, the file will be replayed from the start when we reach
+ // the end of file.
+ static std::unique_ptr<Capturer> CreateWavFileReader(
+ absl::string_view filename,
+ bool repeat = false);
+
+ // Returns a Renderer instance that writes its data to a file.
+ static std::unique_ptr<Renderer> CreateWavFileWriter(
+ absl::string_view filename,
+ int sampling_frequency_in_hz,
+ int num_channels = 1);
+
+ // Returns a Renderer instance that writes its data to a WAV file, cutting
+ // off silence at the beginning (not necessarily perfect silence, see
+ // kAmplitudeThreshold) and at the end (only actual 0 samples in this case).
+ static std::unique_ptr<Renderer> CreateBoundedWavFileWriter(
+ absl::string_view filename,
+ int sampling_frequency_in_hz,
+ int num_channels = 1);
+
+ // Returns a Capturer instance that gets its data from a raw file (*.raw).
+ static std::unique_ptr<Capturer> CreateRawFileReader(
+ absl::string_view filename,
+ int sampling_frequency_in_hz = 48000,
+ int num_channels = 2,
+ bool repeat = true);
+
+ // Returns a Renderer instance that writes its data to a raw file (*.raw),
+ // cutting off silence at the beginning (not necessarily perfect silence, see
+ // kAmplitudeThreshold) and at the end (only actual 0 samples in this case).
+ static std::unique_ptr<Renderer> CreateRawFileWriter(
+ absl::string_view filename,
+ int sampling_frequency_in_hz = 48000,
+ int num_channels = 2);
+
+ private:
+ TestAudioDeviceModule() = default;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_DEVICE_INCLUDE_TEST_AUDIO_DEVICE_H_
diff --git a/third_party/libwebrtc/modules/audio_device/include/test_audio_device_unittest.cc b/third_party/libwebrtc/modules/audio_device/include/test_audio_device_unittest.cc
new file mode 100644
index 0000000000..7a122ca84b
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_device/include/test_audio_device_unittest.cc
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_device/include/test_audio_device.h"
+
+#include <algorithm>
+#include <array>
+#include <memory>
+#include <utility>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "common_audio/wav_file.h"
+#include "common_audio/wav_header.h"
+#include "modules/audio_device/include/audio_device_defines.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+#include "test/time_controller/simulated_time_controller.h"
+
+namespace webrtc {
+namespace {
+
+void RunWavTest(const std::vector<int16_t>& input_samples,
+ const std::vector<int16_t>& expected_samples) {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+
+ const std::string output_filename =
+ test::OutputPath() + "BoundedWavFileWriterTest_" + test_info->name() +
+ "_" + std::to_string(std::rand()) + ".wav";
+
+ static const size_t kSamplesPerFrame = 8;
+ static const int kSampleRate = kSamplesPerFrame * 100;
+ EXPECT_EQ(TestAudioDeviceModule::SamplesPerFrame(kSampleRate),
+ kSamplesPerFrame);
+
+ // Test through file name API.
+ {
+ std::unique_ptr<TestAudioDeviceModule::Renderer> writer =
+ TestAudioDeviceModule::CreateBoundedWavFileWriter(output_filename, 800);
+
+ for (size_t i = 0; i < input_samples.size(); i += kSamplesPerFrame) {
+ EXPECT_TRUE(writer->Render(rtc::ArrayView<const int16_t>(
+ &input_samples[i],
+ std::min(kSamplesPerFrame, input_samples.size() - i))));
+ }
+ }
+
+ {
+ WavReader reader(output_filename);
+ std::vector<int16_t> read_samples(expected_samples.size());
+ EXPECT_EQ(expected_samples.size(),
+ reader.ReadSamples(read_samples.size(), read_samples.data()));
+ EXPECT_EQ(expected_samples, read_samples);
+
+ EXPECT_EQ(0u, reader.ReadSamples(read_samples.size(), read_samples.data()));
+ }
+
+ remove(output_filename.c_str());
+}
+
+TEST(BoundedWavFileWriterTest, NoSilence) {
+ static const std::vector<int16_t> kInputSamples = {
+ 75, 1234, 243, -1231, -22222, 0, 3, 88,
+ 1222, -1213, -13222, -7, -3525, 5787, -25247, 8};
+ static const std::vector<int16_t> kExpectedSamples = kInputSamples;
+ RunWavTest(kInputSamples, kExpectedSamples);
+}
+
+TEST(BoundedWavFileWriterTest, SomeStartSilence) {
+ static const std::vector<int16_t> kInputSamples = {
+ 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, -13222, -7, -3525, 5787, -25247, 8};
+ static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin() + 10,
+ kInputSamples.end());
+ RunWavTest(kInputSamples, kExpectedSamples);
+}
+
+TEST(BoundedWavFileWriterTest, NegativeStartSilence) {
+ static const std::vector<int16_t> kInputSamples = {
+ 0, -4, -6, 0, 3, 0, 0, 0, 0, 3, -13222, -7, -3525, 5787, -25247, 8};
+ static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin() + 2,
+ kInputSamples.end());
+ RunWavTest(kInputSamples, kExpectedSamples);
+}
+
+TEST(BoundedWavFileWriterTest, SomeEndSilence) {
+ static const std::vector<int16_t> kInputSamples = {
+ 75, 1234, 243, -1231, -22222, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin(),
+ kInputSamples.end() - 9);
+ RunWavTest(kInputSamples, kExpectedSamples);
+}
+
+TEST(BoundedWavFileWriterTest, DoubleEndSilence) {
+ static const std::vector<int16_t> kInputSamples = {
+ 75, 1234, 243, -1231, -22222, 0, 0, 0,
+ 0, -1213, -13222, -7, -3525, 5787, 0, 0};
+ static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin(),
+ kInputSamples.end() - 2);
+ RunWavTest(kInputSamples, kExpectedSamples);
+}
+
+TEST(BoundedWavFileWriterTest, DoubleSilence) {
+ static const std::vector<int16_t> kInputSamples = {0, -1213, -13222, -7,
+ -3525, 5787, 0, 0};
+ static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin() + 1,
+ kInputSamples.end() - 2);
+ RunWavTest(kInputSamples, kExpectedSamples);
+}
+
+TEST(BoundedWavFileWriterTest, EndSilenceCutoff) {
+ static const std::vector<int16_t> kInputSamples = {
+ 75, 1234, 243, -1231, -22222, 0, 1, 0, 0, 0, 0};
+ static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin(),
+ kInputSamples.end() - 4);
+ RunWavTest(kInputSamples, kExpectedSamples);
+}
+
+TEST(WavFileReaderTest, RepeatedTrueWithSingleFrameFileReadTwice) {
+ static const std::vector<int16_t> kInputSamples = {75, 1234, 243, -1231,
+ -22222, 0, 3, 88};
+ static const rtc::BufferT<int16_t> kExpectedSamples(kInputSamples.data(),
+ kInputSamples.size());
+
+ const std::string output_filename = test::OutputPath() +
+ "WavFileReaderTest_RepeatedTrue_" +
+ std::to_string(std::rand()) + ".wav";
+
+ static const size_t kSamplesPerFrame = 8;
+ static const int kSampleRate = kSamplesPerFrame * 100;
+ EXPECT_EQ(TestAudioDeviceModule::SamplesPerFrame(kSampleRate),
+ kSamplesPerFrame);
+
+ // Create raw file to read.
+ {
+ std::unique_ptr<TestAudioDeviceModule::Renderer> writer =
+ TestAudioDeviceModule::CreateWavFileWriter(output_filename, 800);
+
+ for (size_t i = 0; i < kInputSamples.size(); i += kSamplesPerFrame) {
+ EXPECT_TRUE(writer->Render(rtc::ArrayView<const int16_t>(
+ &kInputSamples[i],
+ std::min(kSamplesPerFrame, kInputSamples.size() - i))));
+ }
+ }
+
+ {
+ std::unique_ptr<TestAudioDeviceModule::Capturer> reader =
+ TestAudioDeviceModule::CreateWavFileReader(output_filename, true);
+ rtc::BufferT<int16_t> buffer(kExpectedSamples.size());
+ EXPECT_TRUE(reader->Capture(&buffer));
+ EXPECT_EQ(kExpectedSamples, buffer);
+ EXPECT_TRUE(reader->Capture(&buffer));
+ EXPECT_EQ(kExpectedSamples, buffer);
+ }
+
+ remove(output_filename.c_str());
+}
+
+void RunRawTestNoRepeat(const std::vector<int16_t>& input_samples,
+ const std::vector<int16_t>& expected_samples) {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+
+ const std::string output_filename = test::OutputPath() + "RawFileTest_" +
+ test_info->name() + "_" +
+ std::to_string(std::rand()) + ".raw";
+
+ static const size_t kSamplesPerFrame = 8;
+ static const int kSampleRate = kSamplesPerFrame * 100;
+ EXPECT_EQ(TestAudioDeviceModule::SamplesPerFrame(kSampleRate),
+ kSamplesPerFrame);
+
+ // Test through file name API.
+ {
+ std::unique_ptr<TestAudioDeviceModule::Renderer> writer =
+ TestAudioDeviceModule::CreateRawFileWriter(
+ output_filename, /*sampling_frequency_in_hz=*/800);
+
+ for (size_t i = 0; i < input_samples.size(); i += kSamplesPerFrame) {
+ EXPECT_TRUE(writer->Render(rtc::ArrayView<const int16_t>(
+ &input_samples[i],
+ std::min(kSamplesPerFrame, input_samples.size() - i))));
+ }
+ }
+
+ {
+ std::unique_ptr<TestAudioDeviceModule::Capturer> reader =
+ TestAudioDeviceModule::CreateRawFileReader(
+ output_filename, /*sampling_frequency_in_hz=*/800,
+ /*num_channels=*/2, /*repeat=*/false);
+ rtc::BufferT<int16_t> buffer(expected_samples.size());
+ rtc::BufferT<int16_t> expected_buffer(expected_samples.size());
+ expected_buffer.SetData(expected_samples);
+ EXPECT_TRUE(reader->Capture(&buffer));
+ EXPECT_EQ(expected_buffer, buffer);
+ EXPECT_FALSE(reader->Capture(&buffer));
+ EXPECT_TRUE(buffer.empty());
+ }
+
+ remove(output_filename.c_str());
+}
+
+TEST(RawFileWriterTest, NoSilence) {
+ static const std::vector<int16_t> kInputSamples = {
+ 75, 1234, 243, -1231, -22222, 0, 3, 88,
+ 1222, -1213, -13222, -7, -3525, 5787, -25247, 8};
+ static const std::vector<int16_t> kExpectedSamples = kInputSamples;
+ RunRawTestNoRepeat(kInputSamples, kExpectedSamples);
+}
+
+TEST(RawFileWriterTest, SomeStartSilence) {
+ static const std::vector<int16_t> kInputSamples = {
+ 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, -13222, -7, -3525, 5787, -25247, 8};
+ static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin() + 10,
+ kInputSamples.end());
+ RunRawTestNoRepeat(kInputSamples, kExpectedSamples);
+}
+
+TEST(RawFileWriterTest, NegativeStartSilence) {
+ static const std::vector<int16_t> kInputSamples = {
+ 0, -4, -6, 0, 3, 0, 0, 0, 0, 3, -13222, -7, -3525, 5787, -25247, 8};
+ static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin() + 2,
+ kInputSamples.end());
+ RunRawTestNoRepeat(kInputSamples, kExpectedSamples);
+}
+
+TEST(RawFileWriterTest, SomeEndSilence) {
+ static const std::vector<int16_t> kInputSamples = {
+ 75, 1234, 243, -1231, -22222, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin(),
+ kInputSamples.end() - 9);
+ RunRawTestNoRepeat(kInputSamples, kExpectedSamples);
+}
+
+TEST(RawFileWriterTest, DoubleEndSilence) {
+ static const std::vector<int16_t> kInputSamples = {
+ 75, 1234, 243, -1231, -22222, 0, 0, 0,
+ 0, -1213, -13222, -7, -3525, 5787, 0, 0};
+ static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin(),
+ kInputSamples.end() - 2);
+ RunRawTestNoRepeat(kInputSamples, kExpectedSamples);
+}
+
+TEST(RawFileWriterTest, DoubleSilence) {
+ static const std::vector<int16_t> kInputSamples = {0, -1213, -13222, -7,
+ -3525, 5787, 0, 0};
+ static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin() + 1,
+ kInputSamples.end() - 2);
+ RunRawTestNoRepeat(kInputSamples, kExpectedSamples);
+}
+
+TEST(RawFileWriterTest, EndSilenceCutoff) {
+ static const std::vector<int16_t> kInputSamples = {
+ 75, 1234, 243, -1231, -22222, 0, 1, 0, 0, 0, 0};
+ static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin(),
+ kInputSamples.end() - 4);
+ RunRawTestNoRepeat(kInputSamples, kExpectedSamples);
+}
+
+TEST(RawFileWriterTest, Repeat) {
+ static const std::vector<int16_t> kInputSamples = {
+ 75, 1234, 243, -1231, -22222, 0, 3, 88,
+ 1222, -1213, -13222, -7, -3525, 5787, -25247, 8};
+ static const rtc::BufferT<int16_t> kExpectedSamples(kInputSamples.data(),
+ kInputSamples.size());
+
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+
+ const std::string output_filename = test::OutputPath() + "RawFileTest_" +
+ test_info->name() + "_" +
+ std::to_string(std::rand()) + ".raw";
+
+ static const size_t kSamplesPerFrame = 8;
+ static const int kSampleRate = kSamplesPerFrame * 100;
+ EXPECT_EQ(TestAudioDeviceModule::SamplesPerFrame(kSampleRate),
+ kSamplesPerFrame);
+
+ // Test through file name API.
+ {
+ std::unique_ptr<TestAudioDeviceModule::Renderer> writer =
+ TestAudioDeviceModule::CreateRawFileWriter(
+ output_filename, /*sampling_frequency_in_hz=*/800);
+
+ for (size_t i = 0; i < kInputSamples.size(); i += kSamplesPerFrame) {
+ EXPECT_TRUE(writer->Render(rtc::ArrayView<const int16_t>(
+ &kInputSamples[i],
+ std::min(kSamplesPerFrame, kInputSamples.size() - i))));
+ }
+ }
+
+ {
+ std::unique_ptr<TestAudioDeviceModule::Capturer> reader =
+ TestAudioDeviceModule::CreateRawFileReader(
+ output_filename, /*sampling_frequency_in_hz=*/800,
+ /*num_channels=*/2, /*repeat=*/true);
+ rtc::BufferT<int16_t> buffer(kExpectedSamples.size());
+ EXPECT_TRUE(reader->Capture(&buffer));
+ EXPECT_EQ(kExpectedSamples, buffer);
+ EXPECT_TRUE(reader->Capture(&buffer));
+ EXPECT_EQ(kExpectedSamples, buffer);
+ }
+
+ remove(output_filename.c_str());
+}
+
+TEST(PulsedNoiseCapturerTest, SetMaxAmplitude) {
+ const int16_t kAmplitude = 50;
+ std::unique_ptr<TestAudioDeviceModule::PulsedNoiseCapturer> capturer =
+ TestAudioDeviceModule::CreatePulsedNoiseCapturer(
+ kAmplitude, /*sampling_frequency_in_hz=*/8000);
+ rtc::BufferT<int16_t> recording_buffer;
+
+ // Verify that the capturer doesn't create entries louder than than
+ // kAmplitude. Since the pulse generator alternates between writing
+ // zeroes and actual entries, we need to do the capturing twice.
+ capturer->Capture(&recording_buffer);
+ capturer->Capture(&recording_buffer);
+ int16_t max_sample =
+ *std::max_element(recording_buffer.begin(), recording_buffer.end());
+ EXPECT_LE(max_sample, kAmplitude);
+
+ // Increase the amplitude and verify that the samples can now be louder
+ // than the previous max.
+ capturer->SetMaxAmplitude(kAmplitude * 2);
+ capturer->Capture(&recording_buffer);
+ capturer->Capture(&recording_buffer);
+ max_sample =
+ *std::max_element(recording_buffer.begin(), recording_buffer.end());
+ EXPECT_GT(max_sample, kAmplitude);
+}
+
+using ::testing::ElementsAre;
+
+constexpr Timestamp kStartTime = Timestamp::Millis(10000);
+
+class TestAudioTransport : public AudioTransport {
+ public:
+ enum class Mode { kPlaying, kRecording };
+
+ explicit TestAudioTransport(Mode mode) : mode_(mode) {}
+ ~TestAudioTransport() override = default;
+
+ int32_t RecordedDataIsAvailable(
+ const void* audioSamples,
+ size_t samples_per_channel,
+ size_t bytes_per_sample,
+ size_t number_of_channels,
+ uint32_t samples_per_second,
+ uint32_t total_delay_ms,
+ int32_t clock_drift,
+ uint32_t current_mic_level,
+ bool key_pressed,
+ uint32_t& new_mic_level,
+ absl::optional<int64_t> estimated_capture_time_ns) override {
+ new_mic_level = 1;
+
+ if (mode_ != Mode::kRecording) {
+ EXPECT_TRUE(false)
+ << "NeedMorePlayData mustn't be called when mode isn't kRecording";
+ return -1;
+ }
+
+ MutexLock lock(&mutex_);
+ samples_per_channel_.push_back(samples_per_channel);
+ number_of_channels_.push_back(number_of_channels);
+ bytes_per_sample_.push_back(bytes_per_sample);
+ samples_per_second_.push_back(samples_per_second);
+ return 0;
+ }
+
+ int32_t NeedMorePlayData(size_t samples_per_channel,
+ size_t bytes_per_sample,
+ size_t number_of_channels,
+ uint32_t samples_per_second,
+ void* audio_samples,
+ size_t& samples_out,
+ int64_t* elapsed_time_ms,
+ int64_t* ntp_time_ms) override {
+ const size_t num_bytes = samples_per_channel * number_of_channels;
+ std::memset(audio_samples, 1, num_bytes);
+ samples_out = samples_per_channel * number_of_channels;
+ *elapsed_time_ms = 0;
+ *ntp_time_ms = 0;
+
+ if (mode_ != Mode::kPlaying) {
+ EXPECT_TRUE(false)
+ << "NeedMorePlayData mustn't be called when mode isn't kPlaying";
+ return -1;
+ }
+
+ MutexLock lock(&mutex_);
+ samples_per_channel_.push_back(samples_per_channel);
+ number_of_channels_.push_back(number_of_channels);
+ bytes_per_sample_.push_back(bytes_per_sample);
+ samples_per_second_.push_back(samples_per_second);
+ return 0;
+ }
+
+ int32_t RecordedDataIsAvailable(const void* audio_samples,
+ size_t samples_per_channel,
+ size_t bytes_per_sample,
+ size_t number_of_channels,
+ uint32_t samples_per_second,
+ uint32_t total_delay_ms,
+ int32_t clockDrift,
+ uint32_t current_mic_level,
+ bool key_pressed,
+ uint32_t& new_mic_level) override {
+ RTC_CHECK(false) << "This methods should be never executed";
+ }
+
+ void PullRenderData(int bits_per_sample,
+ int sample_rate,
+ size_t number_of_channels,
+ size_t number_of_frames,
+ void* audio_data,
+ int64_t* elapsed_time_ms,
+ int64_t* ntp_time_ms) override {
+ RTC_CHECK(false) << "This methods should be never executed";
+ }
+
+ std::vector<size_t> samples_per_channel() const {
+ MutexLock lock(&mutex_);
+ return samples_per_channel_;
+ }
+ std::vector<size_t> number_of_channels() const {
+ MutexLock lock(&mutex_);
+ return number_of_channels_;
+ }
+ std::vector<size_t> bytes_per_sample() const {
+ MutexLock lock(&mutex_);
+ return bytes_per_sample_;
+ }
+ std::vector<size_t> samples_per_second() const {
+ MutexLock lock(&mutex_);
+ return samples_per_second_;
+ }
+
+ private:
+ const Mode mode_;
+
+ mutable Mutex mutex_;
+ std::vector<size_t> samples_per_channel_ RTC_GUARDED_BY(mutex_);
+ std::vector<size_t> number_of_channels_ RTC_GUARDED_BY(mutex_);
+ std::vector<size_t> bytes_per_sample_ RTC_GUARDED_BY(mutex_);
+ std::vector<size_t> samples_per_second_ RTC_GUARDED_BY(mutex_);
+};
+
+TEST(TestAudioDeviceModuleTest, CreatedADMCanRecord) {
+ GlobalSimulatedTimeController time_controller(kStartTime);
+ TestAudioTransport audio_transport(TestAudioTransport::Mode::kRecording);
+ std::unique_ptr<TestAudioDeviceModule::PulsedNoiseCapturer> capturer =
+ TestAudioDeviceModule::CreatePulsedNoiseCapturer(
+ /*max_amplitude=*/1000,
+ /*sampling_frequency_in_hz=*/48000, /*num_channels=*/2);
+
+ rtc::scoped_refptr<AudioDeviceModule> adm = TestAudioDeviceModule::Create(
+ time_controller.GetTaskQueueFactory(), std::move(capturer),
+ /*renderer=*/nullptr);
+
+ ASSERT_EQ(adm->RegisterAudioCallback(&audio_transport), 0);
+ ASSERT_EQ(adm->Init(), 0);
+
+ EXPECT_FALSE(adm->RecordingIsInitialized());
+ ASSERT_EQ(adm->InitRecording(), 0);
+ EXPECT_TRUE(adm->RecordingIsInitialized());
+ ASSERT_EQ(adm->StartRecording(), 0);
+ time_controller.AdvanceTime(TimeDelta::Millis(10));
+ ASSERT_TRUE(adm->Recording());
+ time_controller.AdvanceTime(TimeDelta::Millis(10));
+ ASSERT_EQ(adm->StopRecording(), 0);
+
+ EXPECT_THAT(audio_transport.samples_per_channel(),
+ ElementsAre(480, 480, 480));
+ EXPECT_THAT(audio_transport.number_of_channels(), ElementsAre(2, 2, 2));
+ EXPECT_THAT(audio_transport.bytes_per_sample(), ElementsAre(4, 4, 4));
+ EXPECT_THAT(audio_transport.samples_per_second(),
+ ElementsAre(48000, 48000, 48000));
+}
+
+TEST(TestAudioDeviceModuleTest, CreatedADMCanPlay) {
+ GlobalSimulatedTimeController time_controller(kStartTime);
+ TestAudioTransport audio_transport(TestAudioTransport::Mode::kPlaying);
+ std::unique_ptr<TestAudioDeviceModule::Renderer> renderer =
+ TestAudioDeviceModule::CreateDiscardRenderer(
+ /*sampling_frequency_in_hz=*/48000, /*num_channels=*/2);
+
+ rtc::scoped_refptr<AudioDeviceModule> adm =
+ TestAudioDeviceModule::Create(time_controller.GetTaskQueueFactory(),
+ /*capturer=*/nullptr, std::move(renderer));
+
+ ASSERT_EQ(adm->RegisterAudioCallback(&audio_transport), 0);
+ ASSERT_EQ(adm->Init(), 0);
+
+ EXPECT_FALSE(adm->PlayoutIsInitialized());
+ ASSERT_EQ(adm->InitPlayout(), 0);
+ EXPECT_TRUE(adm->PlayoutIsInitialized());
+ ASSERT_EQ(adm->StartPlayout(), 0);
+ time_controller.AdvanceTime(TimeDelta::Millis(10));
+ ASSERT_TRUE(adm->Playing());
+ time_controller.AdvanceTime(TimeDelta::Millis(10));
+ ASSERT_EQ(adm->StopPlayout(), 0);
+
+ EXPECT_THAT(audio_transport.samples_per_channel(),
+ ElementsAre(480, 480, 480));
+ EXPECT_THAT(audio_transport.number_of_channels(), ElementsAre(2, 2, 2));
+ EXPECT_THAT(audio_transport.bytes_per_sample(), ElementsAre(4, 4, 4));
+ EXPECT_THAT(audio_transport.samples_per_second(),
+ ElementsAre(48000, 48000, 48000));
+}
+
+} // namespace
+} // namespace webrtc