Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 14:04:28 +01:00
parent 81b91f4139
commit f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions

View file

@ -0,0 +1,196 @@
/*
* 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/ref_count.h"
#include "api/scoped_refptr.h"
#include "api/task_queue/task_queue_factory.h"
#include "modules/audio_device/include/audio_device_defines.h"
namespace webrtc {
class AudioDeviceModuleForTest;
class AudioDeviceModule : public webrtc::RefCountInterface {
public:
enum AudioLayer {
kPlatformDefaultAudio = 0,
kWindowsCoreAudio,
kWindowsCoreAudio2,
kLinuxAlsaAudio,
kLinuxPulseAudio,
kAndroidJavaAudio,
kAndroidOpenSLESAudio,
kAndroidJavaInputAndOpenSLESOutputAudio,
kAndroidAAudioAudio,
kAndroidJavaInputAndAAudioOutputAudio,
kDummyAudio,
kAndroidScreenAudio,
kAndroidMergedScreenAudio
};
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_

View file

@ -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_

View file

@ -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_

View file

@ -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_

View file

@ -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

View file

@ -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_

View file

@ -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 {}
webrtc::RefCountReleaseStatus Release() const override {
return webrtc::RefCountReleaseStatus::kDroppedLastRef;
}
};
} // namespace webrtc
#endif // MODULES_AUDIO_DEVICE_INCLUDE_FAKE_AUDIO_DEVICE_H_

View file

@ -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_

View file

@ -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_

View file

@ -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 "api/task_queue/task_queue_factory.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_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

View file

@ -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_

View file

@ -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::OutputPathWithRandomDirectory() +
"BoundedWavFileWriterTest_" +
test_info->name() + ".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::OutputPathWithRandomDirectory() +
"WavFileReaderTest_RepeatedTrue_" +
".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::OutputPathWithRandomDirectory() +
"RawFileTest_" + test_info->name() +
".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::OutputPathWithRandomDirectory() +
"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