Solves crash in ADM API unit test for Core Audio on Windows
Review URL: http://webrtc-codereview.appspot.com/244009 git-svn-id: http://webrtc.googlecode.com/svn/trunk@812 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
5423bc2d0b
commit
a6c23357c0
@ -192,43 +192,20 @@ bool AudioDeviceWindowsCore::CoreAudioIsSupported()
|
||||
TCHAR buf[MAXERRORLENGTH];
|
||||
LPCTSTR errorText;
|
||||
|
||||
// 1) Initialize the COM library (make Windows load the DLLs).
|
||||
//
|
||||
// CoInitializeEx must be called at least once, and is usually called only once,
|
||||
// for each thread that uses the COM library. Multiple calls to CoInitializeEx
|
||||
// by the same thread are allowed as long as they pass the same concurrency flag,
|
||||
// but subsequent valid calls return S_FALSE.
|
||||
// To close the COM library gracefully on a thread, each successful call to
|
||||
// CoInitializeEx, including any call that returns S_FALSE, must be balanced
|
||||
// 1) Initializes the COM library for use by the calling thread.
|
||||
|
||||
// The COM init wrapper sets the thread's concurrency model to MTA,
|
||||
// and creates a new apartment for the thread if one is required. The
|
||||
// wrapper also ensures that each call to CoInitializeEx is balanced
|
||||
// by a corresponding call to CoUninitialize.
|
||||
//
|
||||
hr = CoInitializeEx(NULL, COM_THREADING_MODEL);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// Avoid calling CoUninitialize() since CoInitializeEx() failed.
|
||||
coUninitializeIsRequired = false;
|
||||
|
||||
if (RPC_E_CHANGED_MODE == hr)
|
||||
{
|
||||
// Calling thread has already initialized COM to be used in a single-threaded
|
||||
// apartment (STA). We are then prevented from using MTA.
|
||||
// Details: hr = 0x80010106 <=> "Cannot change thread mode after it is set".
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, -1,
|
||||
"AudioDeviceWindowsCore::CoreAudioIsSupported() CoInitializeEx(NULL, COM_THREADING_MODEL) => RPC_E_CHANGED_MODE");
|
||||
}
|
||||
_com_error error(hr);
|
||||
WEBRTC_TRACE(kTraceError, kTraceAudioDevice, -1,
|
||||
"AudioDeviceWindowsCore::CoreAudioIsSupported() Failed to initialize the COM library", hr);
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, -1,
|
||||
"AudioDeviceWindowsCore::CoreAudioIsSupported() CoInitializeEx(COM_THREADING_MODEL) failed (hr=0x%x)", hr);
|
||||
StringCchPrintf(buf, MAXERRORLENGTH, TEXT("Error details: "));
|
||||
errorText = error.ErrorMessage();
|
||||
StringCchCat(buf, MAXERRORLENGTH, errorText);
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, -1, "%s", buf);
|
||||
ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);
|
||||
if (!com_init.succeeded()) {
|
||||
// Things will work even if an STA thread is calling this method but we
|
||||
// want to ensure that MTA is used and therefore return false here.
|
||||
return false;
|
||||
}
|
||||
|
||||
// ...it is OK to enter this scope even if CoInitializeEx() failed
|
||||
|
||||
|
||||
// 2) Check if the MMDevice API is available.
|
||||
//
|
||||
// The Windows Multimedia Device (MMDevice) API enables audio clients to
|
||||
@ -280,17 +257,7 @@ bool AudioDeviceWindowsCore::CoreAudioIsSupported()
|
||||
SAFE_RELEASE(pIMMD);
|
||||
}
|
||||
|
||||
// 3) Uninitialize COM but only if required.
|
||||
//
|
||||
// COM will be reinitialized again when the Core Audio ADM is created.
|
||||
//
|
||||
if (coUninitializeIsRequired)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, -1, "AudioDeviceWindowsCore::CoreAudioIsSupported() calls CoUninitialize()");
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
// 4) Verify that we can create and initialize our Core Audio class.
|
||||
// 3) Verify that we can create and initialize our Core Audio class.
|
||||
//
|
||||
// Also, perform a limited "API test" to ensure that Core Audio is supported for all devices.
|
||||
//
|
||||
@ -377,6 +344,7 @@ bool AudioDeviceWindowsCore::CoreAudioIsSupported()
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
AudioDeviceWindowsCore::AudioDeviceWindowsCore(const WebRtc_Word32 id) :
|
||||
_comInit(ScopedCOMInitializer::kMTA),
|
||||
_critSect(*CriticalSectionWrapper::CreateCriticalSection()),
|
||||
_volumeMutex(*CriticalSectionWrapper::CreateCriticalSection()),
|
||||
_id(id),
|
||||
@ -422,7 +390,6 @@ AudioDeviceWindowsCore::AudioDeviceWindowsCore(const WebRtc_Word32 id) :
|
||||
_hSetCaptureVolumeThread(NULL),
|
||||
_hSetCaptureVolumeEvent(NULL),
|
||||
_hMmTask(NULL),
|
||||
_coUninitializeIsRequired(true),
|
||||
_initialized(false),
|
||||
_recording(false),
|
||||
_playing(false),
|
||||
@ -447,6 +414,7 @@ AudioDeviceWindowsCore::AudioDeviceWindowsCore(const WebRtc_Word32 id) :
|
||||
_newMicLevel(0)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, id, "%s created", __FUNCTION__);
|
||||
assert(_comInit.succeeded());
|
||||
|
||||
// Try to load the Avrt DLL
|
||||
if (!_avrtLibrary)
|
||||
@ -500,36 +468,20 @@ AudioDeviceWindowsCore::AudioDeviceWindowsCore(const WebRtc_Word32 id) :
|
||||
_playChannelsPrioList[0] = 2; // stereo is prio 1
|
||||
_playChannelsPrioList[1] = 1; // mono is prio 2
|
||||
|
||||
// Initialize the COM library
|
||||
HRESULT hr = CoInitializeEx(NULL, COM_THREADING_MODEL);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_coUninitializeIsRequired = false;
|
||||
if (hr == RPC_E_CHANGED_MODE)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
|
||||
"AudioDeviceWindowsCore::AudioDeviceWindowsCore() "
|
||||
"CoInitializeEx(NULL, COM_THREADING_MODEL) => "
|
||||
"RPC_E_CHANGED_MODE");
|
||||
}
|
||||
}
|
||||
HRESULT hr;
|
||||
|
||||
// We know that this API will work since it has already been verified in
|
||||
// CoreAudioIsSupported, hence no need to check for errors here as well.
|
||||
|
||||
// Retrive the IMMDeviceEnumerator API (should load the MMDevAPI.dll)
|
||||
// TODO(henrika): we should probably move this allocation to Init() instead
|
||||
// and deallocate in Terminate() to make the implementation more symmetric.
|
||||
CoCreateInstance(
|
||||
__uuidof(MMDeviceEnumerator),
|
||||
NULL,
|
||||
CLSCTX_ALL,
|
||||
__uuidof(IMMDeviceEnumerator),
|
||||
reinterpret_cast<void**>(&_ptrEnumerator));
|
||||
|
||||
if (_coUninitializeIsRequired)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
|
||||
"AudioDeviceWindowsCore::AudioDeviceWindowsCore() matching call to CoUninitialize() is required");
|
||||
}
|
||||
assert(NULL != _ptrEnumerator);
|
||||
|
||||
// DMO initialization for built-in WASAPI AEC.
|
||||
@ -561,13 +513,11 @@ AudioDeviceWindowsCore::~AudioDeviceWindowsCore()
|
||||
|
||||
Terminate();
|
||||
|
||||
_ptrAudioBuffer = NULL;
|
||||
// The IMMDeviceEnumerator is created during construction. Must release
|
||||
// it here and not in Terminate() since we don't recreate it in Init().
|
||||
SAFE_RELEASE(_ptrEnumerator);
|
||||
|
||||
if (_coUninitializeIsRequired)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioDeviceWindowsCore::~AudioDeviceWindowsCore() calling CoUninitialize()...");
|
||||
CoUninitialize();
|
||||
}
|
||||
_ptrAudioBuffer = NULL;
|
||||
|
||||
if (NULL != _hRenderSamplesReadyEvent)
|
||||
{
|
||||
@ -706,13 +656,16 @@ WebRtc_Word32 AudioDeviceWindowsCore::Terminate()
|
||||
|
||||
CriticalSectionScoped lock(_critSect);
|
||||
|
||||
if (!_initialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_initialized = false;
|
||||
_speakerIsInitialized = false;
|
||||
_microphoneIsInitialized = false;
|
||||
_playing = false;
|
||||
_recording = false;
|
||||
|
||||
SAFE_RELEASE(_ptrEnumerator);
|
||||
SAFE_RELEASE(_ptrRenderCollection);
|
||||
SAFE_RELEASE(_ptrCaptureCollection);
|
||||
SAFE_RELEASE(_ptrDeviceOut);
|
||||
|
||||
@ -44,6 +44,42 @@ const float MIN_CORE_MICROPHONE_VOLUME = 0.0f;
|
||||
const WebRtc_UWord16 CORE_SPEAKER_VOLUME_STEP_SIZE = 1;
|
||||
const WebRtc_UWord16 CORE_MICROPHONE_VOLUME_STEP_SIZE = 1;
|
||||
|
||||
// Utility class which initializes COM in the constructor (STA or MTA),
|
||||
// and uninitializes COM in the destructor.
|
||||
class ScopedCOMInitializer {
|
||||
public:
|
||||
// Enum value provided to initialize the thread as an MTA instead of STA.
|
||||
enum SelectMTA { kMTA };
|
||||
|
||||
// Constructor for STA initialization.
|
||||
ScopedCOMInitializer() {
|
||||
Initialize(COINIT_APARTMENTTHREADED);
|
||||
}
|
||||
|
||||
// Constructor for MTA initialization.
|
||||
explicit ScopedCOMInitializer(SelectMTA mta) {
|
||||
Initialize(COINIT_MULTITHREADED);
|
||||
}
|
||||
|
||||
ScopedCOMInitializer::~ScopedCOMInitializer() {
|
||||
if (SUCCEEDED(hr_))
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
bool succeeded() const { return SUCCEEDED(hr_); }
|
||||
|
||||
private:
|
||||
void Initialize(COINIT init) {
|
||||
hr_ = CoInitializeEx(NULL, init);
|
||||
}
|
||||
|
||||
HRESULT hr_;
|
||||
|
||||
ScopedCOMInitializer(const ScopedCOMInitializer&);
|
||||
void operator=(const ScopedCOMInitializer&);
|
||||
};
|
||||
|
||||
|
||||
class AudioDeviceWindowsCore : public AudioDeviceGeneric
|
||||
{
|
||||
public:
|
||||
@ -235,6 +271,7 @@ private:
|
||||
WebRtc_Word32 InitRecordingDMO();
|
||||
|
||||
private:
|
||||
ScopedCOMInitializer _comInit;
|
||||
AudioDeviceBuffer* _ptrAudioBuffer;
|
||||
CriticalSectionWrapper& _critSect;
|
||||
CriticalSectionWrapper& _volumeMutex;
|
||||
@ -304,7 +341,6 @@ private: // WASAPI
|
||||
float _avgCPULoad;
|
||||
|
||||
private:
|
||||
bool _coUninitializeIsRequired;
|
||||
bool _initialized;
|
||||
bool _recording;
|
||||
bool _playing;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user