Bug 1482150 - Make CubebDeviceEnumerator singleton. r=padenot

Differential Revision: https://phabricator.services.mozilla.com/D7604

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Alex Chronopoulos 2018-11-08 12:33:26 +00:00
Родитель bc5ee0931a
Коммит aaea0ba012
6 изменённых файлов: 51 добавлений и 15 удалений

Просмотреть файл

@ -6,6 +6,9 @@
#include "CubebUtils.h" #include "CubebUtils.h"
#ifdef MOZ_WEBRTC
#include "CubebDeviceEnumerator.h"
#endif
#include "MediaInfo.h" #include "MediaInfo.h"
#include "mozilla/AbstractThread.h" #include "mozilla/AbstractThread.h"
#include "mozilla/dom/ContentChild.h" #include "mozilla/dom/ContentChild.h"
@ -607,6 +610,11 @@ void ShutdownLibrary()
Preferences::UnregisterCallbacks(PrefChanged, gInitCallbackPrefs); Preferences::UnregisterCallbacks(PrefChanged, gInitCallbackPrefs);
Preferences::UnregisterCallbacks(PrefChanged, gCallbackPrefs); Preferences::UnregisterCallbacks(PrefChanged, gCallbackPrefs);
#ifdef MOZ_WEBRTC
// This must be done before cubeb destroy.
CubebDeviceEnumerator::Shutdown();
#endif
StaticMutexAutoLock lock(sMutex); StaticMutexAutoLock lock(sMutex);
if (sCubebContext) { if (sCubebContext) {
cubeb_destroy(sCubebContext); cubeb_destroy(sCubebContext);

Просмотреть файл

@ -4,7 +4,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#define ENABLE_SET_CUBEB_BACKEND 1 #define ENABLE_SET_CUBEB_BACKEND 1
#include "AudioDeviceInfo.h"
#include "CubebDeviceEnumerator.h" #include "CubebDeviceEnumerator.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
@ -478,11 +477,11 @@ TestEnumeration(MockCubeb* aMock,
uint32_t aExpectedDeviceCount, uint32_t aExpectedDeviceCount,
DeviceOperation aOperation) DeviceOperation aOperation)
{ {
CubebDeviceEnumerator enumerator; RefPtr<CubebDeviceEnumerator> enumerator = CubebDeviceEnumerator::GetInstance();
nsTArray<RefPtr<AudioDeviceInfo>> inputDevices; nsTArray<RefPtr<AudioDeviceInfo>> inputDevices;
enumerator.EnumerateAudioInputDevices(inputDevices); enumerator->EnumerateAudioInputDevices(inputDevices);
EXPECT_EQ(inputDevices.Length(), aExpectedDeviceCount) EXPECT_EQ(inputDevices.Length(), aExpectedDeviceCount)
<< "Device count is correct when enumerating"; << "Device count is correct when enumerating";
@ -500,7 +499,7 @@ TestEnumeration(MockCubeb* aMock,
aMock->AddDevice(InputDeviceTemplate(reinterpret_cast<cubeb_devid>(123))); aMock->AddDevice(InputDeviceTemplate(reinterpret_cast<cubeb_devid>(123)));
} }
enumerator.EnumerateAudioInputDevices(inputDevices); enumerator->EnumerateAudioInputDevices(inputDevices);
uint32_t newExpectedDeviceCount = aOperation == DeviceOperation::REMOVE uint32_t newExpectedDeviceCount = aOperation == DeviceOperation::REMOVE
? aExpectedDeviceCount - 1 ? aExpectedDeviceCount - 1
@ -555,6 +554,7 @@ TEST(CubebDeviceEnumerator, EnumerateSimple)
TestEnumeration(mock, device_count, op); TestEnumeration(mock, device_count, op);
} }
} }
CubebDeviceEnumerator::Shutdown();
} }
#else // building for Android, which has no device enumeration support #else // building for Android, which has no device enumeration support
TEST(CubebDeviceEnumerator, EnumerateAndroid) TEST(CubebDeviceEnumerator, EnumerateAndroid)
@ -562,23 +562,27 @@ TEST(CubebDeviceEnumerator, EnumerateAndroid)
MockCubeb* mock = new MockCubeb(); MockCubeb* mock = new MockCubeb();
mozilla::CubebUtils::ForceSetCubebContext(mock->AsCubebContext()); mozilla::CubebUtils::ForceSetCubebContext(mock->AsCubebContext());
CubebDeviceEnumerator enumerator; RefPtr<CubebDeviceEnumerator> enumerator = CubebDeviceEnumerator::GetInstance();
nsTArray<RefPtr<AudioDeviceInfo>> inputDevices; nsTArray<RefPtr<AudioDeviceInfo>> inputDevices;
enumerator.EnumerateAudioInputDevices(inputDevices); enumerator->EnumerateAudioInputDevices(inputDevices);
EXPECT_EQ(inputDevices.Length(), 1u) << "Android always exposes a single input device."; EXPECT_EQ(inputDevices.Length(), 1u) << "Android always exposes a single input device.";
EXPECT_EQ(inputDevices[0]->MaxChannels(), 1u) << "With a single channel."; EXPECT_EQ(inputDevices[0]->MaxChannels(), 1u) << "With a single channel.";
EXPECT_EQ(inputDevices[0]->DeviceID(), nullptr) << "It's always the default device."; EXPECT_EQ(inputDevices[0]->DeviceID(), nullptr) << "It's always the default device.";
EXPECT_TRUE(inputDevices[0]->Preferred()) << "it's always the prefered device."; EXPECT_TRUE(inputDevices[0]->Preferred()) << "it's always the prefered device.";
CubebDeviceEnumerator::Shutdown();
} }
#endif #endif
TEST(CubebDeviceEnumerator, ForceNullCubebContext) TEST(CubebDeviceEnumerator, ForceNullCubebContext)
{ {
mozilla::CubebUtils::ForceSetCubebContext(nullptr); mozilla::CubebUtils::ForceSetCubebContext(nullptr);
CubebDeviceEnumerator enumerator; RefPtr<CubebDeviceEnumerator> enumerator = CubebDeviceEnumerator::GetInstance();
nsTArray<RefPtr<AudioDeviceInfo>> inputDevices; nsTArray<RefPtr<AudioDeviceInfo>> inputDevices;
enumerator.EnumerateAudioInputDevices(inputDevices); enumerator->EnumerateAudioInputDevices(inputDevices);
EXPECT_EQ(inputDevices.Length(), 0u) << "Enumeration must fail device list must be empty."; EXPECT_EQ(inputDevices.Length(), 0u) << "Enumeration must fail device list must be empty.";
enumerator->Shutdown();
CubebDeviceEnumerator::Shutdown();
} }

Просмотреть файл

@ -1,10 +1,22 @@
#include "CubebDeviceEnumerator.h" #include "CubebDeviceEnumerator.h"
#include "nsTArray.h" #include "mozilla/StaticPtr.h"
namespace mozilla { namespace mozilla {
using namespace CubebUtils; using namespace CubebUtils;
/* static */ StaticRefPtr<CubebDeviceEnumerator> CubebDeviceEnumerator::sInstance;
/* static */ already_AddRefed<CubebDeviceEnumerator>
CubebDeviceEnumerator::GetInstance()
{
if (!sInstance) {
sInstance = new CubebDeviceEnumerator();
}
RefPtr<CubebDeviceEnumerator> instance = sInstance.get();
return instance.forget();
}
CubebDeviceEnumerator::CubebDeviceEnumerator() CubebDeviceEnumerator::CubebDeviceEnumerator()
: mMutex("CubebDeviceListMutex") : mMutex("CubebDeviceListMutex")
, mManualInvalidation(false) , mManualInvalidation(false)
@ -21,6 +33,14 @@ CubebDeviceEnumerator::CubebDeviceEnumerator()
} }
} }
/* static */ void
CubebDeviceEnumerator::Shutdown()
{
if (sInstance) {
sInstance = nullptr;
}
}
CubebDeviceEnumerator::~CubebDeviceEnumerator() CubebDeviceEnumerator::~CubebDeviceEnumerator()
{ {
int rv = cubeb_register_device_collection_changed(GetCubebContext(), int rv = cubeb_register_device_collection_changed(GetCubebContext(),

Просмотреть файл

@ -17,8 +17,10 @@ namespace mozilla {
class CubebDeviceEnumerator final class CubebDeviceEnumerator final
{ {
public: public:
CubebDeviceEnumerator(); NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CubebDeviceEnumerator)
~CubebDeviceEnumerator();
static already_AddRefed<CubebDeviceEnumerator> GetInstance();
static void Shutdown();
// This method returns a list of all the input and output audio devices // This method returns a list of all the input and output audio devices
// available on this machine. // available on this machine.
// This method is safe to call from all threads. // This method is safe to call from all threads.
@ -30,6 +32,8 @@ public:
DeviceInfoFromID(CubebUtils::AudioDeviceID aID); DeviceInfoFromID(CubebUtils::AudioDeviceID aID);
private: private:
CubebDeviceEnumerator();
~CubebDeviceEnumerator();
// Static function called by cubeb when the audio input device list changes // Static function called by cubeb when the audio input device list changes
// (i.e. when a new device is made available, or non-available). This // (i.e. when a new device is made available, or non-available). This
// re-binds to the MediaEngineWebRTC that instantiated this // re-binds to the MediaEngineWebRTC that instantiated this
@ -45,6 +49,8 @@ private:
// list each time instead of relying on automatic invalidation of the cache by // list each time instead of relying on automatic invalidation of the cache by
// cubeb itself. Set in the constructor and then can be access on any thread. // cubeb itself. Set in the constructor and then can be access on any thread.
bool mManualInvalidation; bool mManualInvalidation;
static StaticRefPtr<CubebDeviceEnumerator> sInstance;
}; };
} }

Просмотреть файл

@ -185,9 +185,7 @@ MediaEngineWebRTC::EnumerateMicrophoneDevices(uint64_t aWindowId,
{ {
mMutex.AssertCurrentThreadOwns(); mMutex.AssertCurrentThreadOwns();
if (!mEnumerator) { mEnumerator = CubebDeviceEnumerator::GetInstance();
mEnumerator.reset(new CubebDeviceEnumerator());
}
nsTArray<RefPtr<AudioDeviceInfo>> devices; nsTArray<RefPtr<AudioDeviceInfo>> devices;
mEnumerator->EnumerateAudioInputDevices(devices); mEnumerator->EnumerateAudioInputDevices(devices);

Просмотреть файл

@ -79,7 +79,7 @@ private:
// gUM runnables can e.g. Enumerate from multiple threads // gUM runnables can e.g. Enumerate from multiple threads
Mutex mMutex; Mutex mMutex;
UniquePtr<mozilla::CubebDeviceEnumerator> mEnumerator; RefPtr<mozilla::CubebDeviceEnumerator> mEnumerator;
const bool mDelayAgnostic; const bool mDelayAgnostic;
const bool mExtendedFilter; const bool mExtendedFilter;
// This also is set in the ctor and then never changed, but we can't make it // This also is set in the ctor and then never changed, but we can't make it