Integrate the built-in WASAPI AEC DMO to VoE.
Review URL: http://webrtc-codereview.appspot.com/108006 git-svn-id: http://webrtc.googlecode.com/svn/trunk@592 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
b1b3e67c97
commit
a3c6d61c44
@ -17,6 +17,7 @@ modules/audio_device/main/source/Mac/portaudio/pa_ringbuffer.c
|
||||
modules/audio_processing/utility/fft4g.c
|
||||
modules/audio_processing/aec/main/source/aec_core_rdft.c
|
||||
system_wrappers/interface/fix_interlocked_exchange_pointer_windows.h
|
||||
system_wrappers/interface/scoped_refptr.h
|
||||
system_wrappers/source/condition_variable_windows.cc
|
||||
system_wrappers/source/spreadsortlib/constants.hpp
|
||||
system_wrappers/source/spreadsortlib/spreadsort.hpp
|
||||
|
@ -184,6 +184,17 @@ class AudioDeviceModule : public RefCountedModule {
|
||||
virtual int32_t SetLoudspeakerStatus(bool enable) = 0;
|
||||
virtual int32_t GetLoudspeakerStatus(bool* enabled) const = 0;
|
||||
|
||||
// *Experimental - not recommended for use.*
|
||||
// Enables the Windows Core Audio built-in AEC. Fails on other platforms.
|
||||
//
|
||||
// Must be called before InitRecording(). When enabled:
|
||||
// 1. StartPlayout() must be called before StartRecording().
|
||||
// 2. StopRecording() should be called before StopPlayout().
|
||||
// The reverse order may cause garbage audio to be rendered or the
|
||||
// capture side to halt util StopRecording() is called.
|
||||
virtual int32_t EnableBuiltInAEC(bool enable) { return -1; }
|
||||
virtual bool BuiltInAECIsEnabled() const { return false; }
|
||||
|
||||
protected:
|
||||
virtual ~AudioDeviceModule() {};
|
||||
};
|
||||
|
@ -139,6 +139,17 @@
|
||||
],
|
||||
},
|
||||
}],
|
||||
['OS=="win"', {
|
||||
'link_settings': {
|
||||
'libraries': [
|
||||
# Required for the built-in WASAPI AEC.
|
||||
'-ldmoguids.lib',
|
||||
'-lwmcodecdspuuid.lib',
|
||||
'-lamstrmid.lib',
|
||||
'-lmsdmo.lib',
|
||||
],
|
||||
},
|
||||
}],
|
||||
], # conditions
|
||||
}], # include_internal_audio_device==1
|
||||
], # conditions
|
||||
|
@ -54,9 +54,23 @@ WebRtc_Word32 AudioDeviceGeneric::SoundDeviceControl(unsigned int par1,
|
||||
unsigned int par2, unsigned int par3, unsigned int par4)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceError, kTraceAudioDevice, -1,
|
||||
"Reset audio device not supported on this platform");
|
||||
"Sound device control not supported on this platform");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t AudioDeviceGeneric::EnableBuiltInAEC(bool enable)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceError, kTraceAudioDevice, -1,
|
||||
"Windows AEC not supported on this platform");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool AudioDeviceGeneric::BuiltInAECIsEnabled() const
|
||||
{
|
||||
WEBRTC_TRACE(kTraceError, kTraceAudioDevice, -1,
|
||||
"Windows AEC not supported on this platform");
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
|
@ -157,6 +157,10 @@ class AudioDeviceGeneric
|
||||
unsigned int par3 = 0,
|
||||
unsigned int par4 = 0);
|
||||
|
||||
// Windows Core Audio only.
|
||||
virtual int32_t EnableBuiltInAEC(bool enable);
|
||||
virtual bool BuiltInAECIsEnabled() const;
|
||||
|
||||
public:
|
||||
virtual bool PlayoutWarning() const = 0;
|
||||
virtual bool PlayoutError() const = 0;
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "audio_device_config.h"
|
||||
#include "system_wrappers/interface/ref_count.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
@ -2106,6 +2106,22 @@ WebRtc_Word32 AudioDeviceModuleImpl::GetLoudspeakerStatus(bool* enabled) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t AudioDeviceModuleImpl::EnableBuiltInAEC(bool enable)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceModuleCall, kTraceAudioDevice, _id, "%s", __FUNCTION__);
|
||||
CHECK_INITIALIZED();
|
||||
|
||||
return _ptrAudioDevice->EnableBuiltInAEC(enable);
|
||||
}
|
||||
|
||||
bool AudioDeviceModuleImpl::BuiltInAECIsEnabled() const
|
||||
{
|
||||
WEBRTC_TRACE(kTraceModuleCall, kTraceAudioDevice, _id, "%s", __FUNCTION__);
|
||||
CHECK_INITIALIZED_BOOL();
|
||||
|
||||
return _ptrAudioDevice->BuiltInAECIsEnabled();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Private Methods
|
||||
// ============================================================================
|
||||
|
@ -202,6 +202,9 @@ public:
|
||||
virtual WebRtc_Word32 SetLoudspeakerStatus(bool enable);
|
||||
virtual WebRtc_Word32 GetLoudspeakerStatus(bool* enabled) const;
|
||||
|
||||
virtual int32_t EnableBuiltInAEC(bool enable);
|
||||
virtual bool BuiltInAECIsEnabled() const;
|
||||
|
||||
public:
|
||||
WebRtc_Word32 Id() {return _id;}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,13 +16,17 @@
|
||||
#include "audio_device_generic.h"
|
||||
|
||||
#pragma once
|
||||
#include <Mmdeviceapi.h> // MMDevice
|
||||
#include <Audioclient.h> // WASAPI
|
||||
#include <avrt.h> // Avrt
|
||||
#include <endpointvolume.h>
|
||||
#include <wmcodecdsp.h> // CLSID_CWMAudioAEC
|
||||
// (must be before audioclient.h)
|
||||
#include <Audioclient.h> // WASAPI
|
||||
#include <Audiopolicy.h>
|
||||
#include <avrt.h> // Avrt
|
||||
#include <endpointvolume.h>
|
||||
#include <mediaobj.h> // IMediaObject
|
||||
#include <Mmdeviceapi.h> // MMDevice
|
||||
|
||||
#include "critical_section_wrapper.h"
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
// Use Multimedia Class Scheduler Service (MMCSS) to boost the thread priority
|
||||
#pragma comment( lib, "avrt.lib" )
|
||||
@ -148,6 +152,9 @@ public:
|
||||
// CPU load
|
||||
virtual WebRtc_Word32 CPULoad(WebRtc_UWord16& load) const;
|
||||
|
||||
virtual int32_t EnableBuiltInAEC(bool enable);
|
||||
virtual bool BuiltInAECIsEnabled() const;
|
||||
|
||||
public:
|
||||
virtual bool PlayoutWarning() const;
|
||||
virtual bool PlayoutError() const;
|
||||
@ -169,8 +176,13 @@ private: // avrt function pointers
|
||||
bool _winSupportAvrt;
|
||||
|
||||
private: // thread functions
|
||||
DWORD InitCaptureThreadPriority();
|
||||
void RevertCaptureThreadPriority();
|
||||
static DWORD WINAPI WSAPICaptureThread(LPVOID context);
|
||||
DWORD DoCaptureThread();
|
||||
|
||||
static DWORD WINAPI WSAPICaptureThreadPollDMO(LPVOID context);
|
||||
DWORD DoCaptureThreadPollDMO();
|
||||
|
||||
static DWORD WINAPI WSAPIRenderThread(LPVOID context);
|
||||
DWORD DoRenderThread();
|
||||
@ -189,6 +201,16 @@ private:
|
||||
WebRtc_Word32 Id() {return _id;}
|
||||
|
||||
private:
|
||||
int SetDMOProperties();
|
||||
|
||||
int SetBoolProperty(IPropertyStore* ptrPS,
|
||||
REFPROPERTYKEY key,
|
||||
VARIANT_BOOL value);
|
||||
|
||||
int SetVtI4Property(IPropertyStore* ptrPS,
|
||||
REFPROPERTYKEY key,
|
||||
LONG value);
|
||||
|
||||
WebRtc_Word32 _EnumerateEndpointDevicesAll(EDataFlow dataFlow) const;
|
||||
void _TraceCOMError(HRESULT hr) const;
|
||||
|
||||
@ -199,6 +221,7 @@ private:
|
||||
WebRtc_Word32 _GetDeviceName(IMMDevice* pDevice, LPWSTR pszBuffer, int bufferLen);
|
||||
WebRtc_Word32 _GetListDeviceID(EDataFlow dir, int index, LPWSTR szBuffer, int bufferLen);
|
||||
WebRtc_Word32 _GetDefaultDeviceID(EDataFlow dir, ERole role, LPWSTR szBuffer, int bufferLen);
|
||||
WebRtc_Word32 _GetDefaultDeviceIndex(EDataFlow dir, ERole role, int* index);
|
||||
WebRtc_Word32 _GetDeviceID(IMMDevice* pDevice, LPWSTR pszBuffer, int bufferLen);
|
||||
WebRtc_Word32 _GetDefaultDevice(EDataFlow dir, ERole role, IMMDevice** ppDevice);
|
||||
WebRtc_Word32 _GetListDevice(EDataFlow dir, int index, IMMDevice** ppDevice);
|
||||
@ -209,6 +232,8 @@ private:
|
||||
// Does nothing if UNICODE is undefined.
|
||||
char* WideToUTF8(const TCHAR* src) const;
|
||||
|
||||
WebRtc_Word32 InitRecordingDMO();
|
||||
|
||||
private:
|
||||
AudioDeviceBuffer* _ptrAudioBuffer;
|
||||
CriticalSectionWrapper& _critSect;
|
||||
@ -231,6 +256,11 @@ private: // WASAPI
|
||||
ISimpleAudioVolume* _ptrRenderSimpleVolume;
|
||||
IAudioEndpointVolume* _ptrRenderEndpointVolume;
|
||||
|
||||
// DirectX Media Object (DMO) for the built-in AEC.
|
||||
scoped_refptr<IMediaObject> _dmo;
|
||||
scoped_refptr<IMediaBuffer> _mediaBuffer;
|
||||
bool _builtInAecEnabled;
|
||||
|
||||
HANDLE _hRenderSamplesReadyEvent;
|
||||
HANDLE _hPlayThread;
|
||||
HANDLE _hRenderStartedEvent;
|
||||
@ -245,6 +275,8 @@ private: // WASAPI
|
||||
HANDLE _hSetCaptureVolumeThread;
|
||||
HANDLE _hSetCaptureVolumeEvent;
|
||||
|
||||
HANDLE _hMmTask;
|
||||
|
||||
UINT _playAudioFrameSize;
|
||||
WebRtc_UWord32 _playSampleRate;
|
||||
WebRtc_UWord32 _devicePlaySampleRate;
|
||||
|
137
src/system_wrappers/interface/scoped_refptr.h
Normal file
137
src/system_wrappers/interface/scoped_refptr.h
Normal file
@ -0,0 +1,137 @@
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file under third_party_mods/chromium or at:
|
||||
// http://src.chromium.org/svn/trunk/src/LICENSE
|
||||
|
||||
#ifndef SYSTEM_WRAPPERS_INTERFACE_SCOPED_REFPTR_H_
|
||||
#define SYSTEM_WRAPPERS_INTERFACE_SCOPED_REFPTR_H_
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Extracted from Chromium's src/base/memory/ref_counted.h.
|
||||
|
||||
//
|
||||
// A smart pointer class for reference counted objects. Use this class instead
|
||||
// of calling AddRef and Release manually on a reference counted object to
|
||||
// avoid common memory leaks caused by forgetting to Release an object
|
||||
// reference. Sample usage:
|
||||
//
|
||||
// class MyFoo : public RefCounted<MyFoo> {
|
||||
// ...
|
||||
// };
|
||||
//
|
||||
// void some_function() {
|
||||
// scoped_refptr<MyFoo> foo = new MyFoo();
|
||||
// foo->Method(param);
|
||||
// // |foo| is released when this function returns
|
||||
// }
|
||||
//
|
||||
// void some_other_function() {
|
||||
// scoped_refptr<MyFoo> foo = new MyFoo();
|
||||
// ...
|
||||
// foo = NULL; // explicitly releases |foo|
|
||||
// ...
|
||||
// if (foo)
|
||||
// foo->Method(param);
|
||||
// }
|
||||
//
|
||||
// The above examples show how scoped_refptr<T> acts like a pointer to T.
|
||||
// Given two scoped_refptr<T> classes, it is also possible to exchange
|
||||
// references between the two objects, like so:
|
||||
//
|
||||
// {
|
||||
// scoped_refptr<MyFoo> a = new MyFoo();
|
||||
// scoped_refptr<MyFoo> b;
|
||||
//
|
||||
// b.swap(a);
|
||||
// // now, |b| references the MyFoo object, and |a| references NULL.
|
||||
// }
|
||||
//
|
||||
// To make both |a| and |b| in the above example reference the same MyFoo
|
||||
// object, simply use the assignment operator:
|
||||
//
|
||||
// {
|
||||
// scoped_refptr<MyFoo> a = new MyFoo();
|
||||
// scoped_refptr<MyFoo> b;
|
||||
//
|
||||
// b = a;
|
||||
// // now, |a| and |b| each own a reference to the same MyFoo object.
|
||||
// }
|
||||
//
|
||||
template <class T>
|
||||
class scoped_refptr {
|
||||
public:
|
||||
scoped_refptr() : ptr_(NULL) {
|
||||
}
|
||||
|
||||
scoped_refptr(T* p) : ptr_(p) {
|
||||
if (ptr_)
|
||||
ptr_->AddRef();
|
||||
}
|
||||
|
||||
scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
|
||||
if (ptr_)
|
||||
ptr_->AddRef();
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
|
||||
if (ptr_)
|
||||
ptr_->AddRef();
|
||||
}
|
||||
|
||||
~scoped_refptr() {
|
||||
if (ptr_)
|
||||
ptr_->Release();
|
||||
}
|
||||
|
||||
T* get() const { return ptr_; }
|
||||
operator T*() const { return ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
|
||||
// Release a pointer.
|
||||
// The return value is the current pointer held by this object.
|
||||
// If this object holds a NULL pointer, the return value is NULL.
|
||||
// After this operation, this object will hold a NULL pointer,
|
||||
// and will not own the object any more.
|
||||
T* release() {
|
||||
T* retVal = ptr_;
|
||||
ptr_ = NULL;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
scoped_refptr<T>& operator=(T* p) {
|
||||
// AddRef first so that self assignment should work
|
||||
if (p)
|
||||
p->AddRef();
|
||||
if (ptr_ )
|
||||
ptr_->Release();
|
||||
ptr_ = p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
|
||||
return *this = r.ptr_;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
|
||||
return *this = r.get();
|
||||
}
|
||||
|
||||
void swap(T** pp) {
|
||||
T* p = ptr_;
|
||||
ptr_ = *pp;
|
||||
*pp = p;
|
||||
}
|
||||
|
||||
void swap(scoped_refptr<T>& r) {
|
||||
swap(&r.ptr_);
|
||||
}
|
||||
|
||||
protected:
|
||||
T* ptr_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // SYSTEM_WRAPPERS_INTERFACE_SCOPED_REFPTR_H_
|
@ -1,6 +1,10 @@
|
||||
# Copyright (c) 2009 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
# 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.
|
||||
|
||||
# TODO: Rename files to use *_linux.cpp etc. names, to automatically include relevant files. Remove conditions section.
|
||||
|
||||
@ -32,11 +36,13 @@
|
||||
'../interface/data_log_impl.h',
|
||||
'../interface/event_wrapper.h',
|
||||
'../interface/file_wrapper.h',
|
||||
'../interface/fix_interlocked_exchange_pointer_windows.h',
|
||||
'../interface/list_wrapper.h',
|
||||
'../interface/map_wrapper.h',
|
||||
'../interface/ref_count.h',
|
||||
'../interface/rw_lock_wrapper.h',
|
||||
'../interface/scoped_ptr.h',
|
||||
'../interface/scoped_refptr.h',
|
||||
'../interface/sort.h',
|
||||
'../interface/thread_wrapper.h',
|
||||
'../interface/tick_util.h',
|
||||
@ -71,6 +77,7 @@
|
||||
'thread.cc',
|
||||
'thread_posix.h',
|
||||
'thread_windows.h',
|
||||
'thread_windows_set_name.h',
|
||||
'trace_impl.cc',
|
||||
'trace_impl.h',
|
||||
'trace_posix.h',
|
||||
|
@ -110,6 +110,25 @@ public:
|
||||
// Not supported
|
||||
virtual int GetLoudspeakerStatus(bool& enabled) = 0;
|
||||
|
||||
// *Experimental - not recommended for use.*
|
||||
// Enables the Windows Core Audio built-in AEC. Fails on other platforms.
|
||||
//
|
||||
// Currently incompatible with the standard VoE AEC and AGC; don't attempt
|
||||
// to enable them while this is active.
|
||||
//
|
||||
// Must be called before VoEBase::StartSend(). When enabled:
|
||||
// 1. VoEBase::StartPlayout() must be called before VoEBase::StartSend().
|
||||
// 2. VoEBase::StopSend() should be called before VoEBase::StopPlayout().
|
||||
// The reverse order may cause garbage audio to be rendered or the
|
||||
// capture side to halt util StopSend() is called.
|
||||
//
|
||||
// As a consequence, SetPlayoutDevice() should be used with caution
|
||||
// during a call. It will function, but may cause the above issues for
|
||||
// the duration it takes to complete. (In practice, it should complete
|
||||
// fast enough to avoid audible degradation).
|
||||
virtual int EnableBuiltInAEC(bool enable) = 0;
|
||||
virtual bool BuiltInAECIsEnabled() const = 0;
|
||||
|
||||
protected:
|
||||
VoEHardware() {}
|
||||
virtual ~VoEHardware() {}
|
||||
|
@ -815,6 +815,32 @@ int VoEHardwareImpl::GetSystemCPULoad(int& loadPercent)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int VoEHardwareImpl::EnableBuiltInAEC(bool enable)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"%s", __FUNCTION__);
|
||||
if (!_engineStatistics.Initialized())
|
||||
{
|
||||
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _audioDevicePtr->EnableBuiltInAEC(enable);
|
||||
}
|
||||
|
||||
bool VoEHardwareImpl::BuiltInAECIsEnabled() const
|
||||
{
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"%s", __FUNCTION__);
|
||||
if (!_engineStatistics.Initialized())
|
||||
{
|
||||
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return false;
|
||||
}
|
||||
|
||||
return _audioDevicePtr->BuiltInAECIsEnabled();
|
||||
}
|
||||
|
||||
#endif // WEBRTC_VOICE_ENGINE_HARDWARE_API
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -67,6 +67,9 @@ public:
|
||||
|
||||
virtual int GetLoudspeakerStatus(bool& enabled);
|
||||
|
||||
virtual int EnableBuiltInAEC(bool enable);
|
||||
virtual bool BuiltInAECIsEnabled() const;
|
||||
|
||||
protected:
|
||||
VoEHardwareImpl();
|
||||
virtual ~VoEHardwareImpl();
|
||||
|
@ -2004,6 +2004,80 @@ int VoETestManager::DoStandardTest()
|
||||
SLEEP(2000);
|
||||
#endif // #ifdef MAC_IPHONE
|
||||
|
||||
TEST_LOG("\nBuilt-in WASAPI AEC tests\n");
|
||||
TEST_MUSTPASS(base->StopSend(0));
|
||||
TEST_MUSTPASS(base->StopPlayout(0));
|
||||
|
||||
TEST_MUSTPASS(hardware->GetAudioDeviceLayer(givenLayer));
|
||||
if (givenLayer != kAudioWindowsCore)
|
||||
{
|
||||
TEST_MUSTFAIL(hardware->EnableBuiltInAEC(true));
|
||||
TEST_MUSTFAIL(hardware->EnableBuiltInAEC(false));
|
||||
}
|
||||
else
|
||||
{
|
||||
TEST_MUSTPASS(base->StartSend(0));
|
||||
// Can't be set after StartSend().
|
||||
TEST_MUSTFAIL(hardware->EnableBuiltInAEC(true));
|
||||
TEST_MUSTFAIL(hardware->EnableBuiltInAEC(false));
|
||||
|
||||
TEST_MUSTPASS(base->StopSend(0));
|
||||
TEST_MUSTPASS(hardware->EnableBuiltInAEC(true));
|
||||
|
||||
// Can't be called before StartPlayout().
|
||||
TEST_MUSTFAIL(base->StartSend(0));
|
||||
|
||||
TEST_MUSTPASS(base->StartPlayout(0));
|
||||
TEST_MUSTPASS(base->StartSend(0));
|
||||
TEST_LOG("Processing capture data with built-in AEC...\n");
|
||||
SLEEP(2000);
|
||||
|
||||
TEST_LOG("Looping through capture devices...\n");
|
||||
TEST_MUSTPASS(hardware->GetNumOfRecordingDevices(nRec));
|
||||
for (idx = 0; idx < nRec; idx++)
|
||||
{
|
||||
TEST_MUSTPASS(hardware->GetRecordingDeviceName(idx,
|
||||
devName,
|
||||
guidName));
|
||||
TEST_LOG("%d: %s\n", idx, devName);
|
||||
TEST_MUSTPASS(hardware->SetRecordingDevice(idx));
|
||||
SLEEP(2000);
|
||||
}
|
||||
|
||||
TEST_MUSTPASS(hardware->SetPlayoutDevice(-1));
|
||||
TEST_MUSTPASS(hardware->SetRecordingDevice(-1));
|
||||
|
||||
TEST_LOG("Looping through render devices, restarting for each "
|
||||
"device...\n");
|
||||
TEST_MUSTPASS(hardware->GetNumOfPlayoutDevices(nPlay));
|
||||
for (idx = 0; idx < nPlay; idx++)
|
||||
{
|
||||
TEST_MUSTPASS(hardware->GetPlayoutDeviceName(idx,
|
||||
devName,
|
||||
guidName));
|
||||
TEST_LOG("%d: %s\n", idx, devName);
|
||||
TEST_MUSTPASS(hardware->SetPlayoutDevice(idx));
|
||||
SLEEP(2000);
|
||||
}
|
||||
|
||||
TEST_LOG("Using default devices...\n");
|
||||
TEST_MUSTPASS(hardware->SetRecordingDevice(-1));
|
||||
TEST_MUSTPASS(hardware->SetPlayoutDevice(-1));
|
||||
SLEEP(2000);
|
||||
|
||||
// Possible, but not recommended before StopSend().
|
||||
TEST_MUSTPASS(base->StopPlayout(0));
|
||||
|
||||
TEST_MUSTPASS(base->StopSend(0));
|
||||
TEST_MUSTPASS(base->StopPlayout(0));
|
||||
SLEEP(2000); // To verify that there is no garbage audio.
|
||||
|
||||
TEST_LOG("Disabling built-in AEC.\n");
|
||||
TEST_MUSTPASS(hardware->EnableBuiltInAEC(false));
|
||||
|
||||
TEST_MUSTPASS(base->StartSend(0));
|
||||
TEST_MUSTPASS(base->StartPlayout(0));
|
||||
}
|
||||
#else
|
||||
TEST_LOG("\n\n+++ More hardware tests NOT ENABLED +++\n");
|
||||
#endif
|
||||
|
@ -27,7 +27,7 @@
|
||||
#endif
|
||||
|
||||
// Select the tests to execute, list order below is same as they will be
|
||||
// executed. Note that, all settings below will be overrided by sub-API
|
||||
// executed. Note that, all settings below will be overriden by sub-API
|
||||
// settings in engine_configurations.h.
|
||||
#define _TEST_BASE_
|
||||
#define _TEST_RTP_RTCP_
|
||||
|
Loading…
x
Reference in New Issue
Block a user