Repo created
This commit is contained in:
parent
81b91f4139
commit
f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions
|
|
@ -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_
|
||||
|
|
@ -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_
|
||||
|
|
@ -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_
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
|
@ -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_
|
||||
|
|
@ -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_
|
||||
|
|
@ -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_
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue