Bug 1404977 - Part 17 - Re-implement the workaround for the lack of input device enumeration on Android. r?pehrsons
MozReview-Commit-ID: 5EiQ6a3OaIR
--- a/dom/media/gtest/TestAudioDeviceEnumerator.cpp
+++ b/dom/media/gtest/TestAudioDeviceEnumerator.cpp
@@ -125,16 +125,19 @@ public:
}
// Cubeb backend implementation
// This allows passing this class as a cubeb* instance.
cubeb* AsCubebContext() { return reinterpret_cast<cubeb*>(this); }
// Fill in the collection parameter with all devices of aType.
int EnumerateDevices(cubeb_device_type aType,
cubeb_device_collection* collection)
{
+#ifdef ANDROID
+ EXPECT_TRUE(false) << "This is not to be called on Android.";
+#endif
size_t count = 0;
if (aType & CUBEB_DEVICE_TYPE_INPUT) {
count += mInputDevices.Length();
}
if (aType & CUBEB_DEVICE_TYPE_OUTPUT) {
count += mOutputDevices.Length();
}
collection->device = new cubeb_device_info[count];
@@ -509,16 +512,17 @@ TestEnumeration(MockCubeb* aMock,
if (DEBUG_PRINTS) {
for (uint32_t i = 0; i < inputDevices.Length(); i++) {
printf("=== After removal\n");
PrintDevice(inputDevices[i]);
}
}
}
+#ifndef ANDROID
TEST(CubebDeviceEnumerator, EnumerateSimple)
{
// It looks like we're leaking this object, but in fact it will be freed by
// gecko sometime later: `cubeb_destroy` is called when layout statics are
// shutdown and we cast back to a MockCubeb* and call the dtor.
MockCubeb* mock = new MockCubeb();
mozilla::CubebUtils::ForceSetCubebContext(mock->AsCubebContext());
@@ -547,8 +551,24 @@ TEST(CubebDeviceEnumerator, EnumerateSim
mock->AddDevice(device);
}
mock->SetSupportDeviceChangeCallback(supports);
TestEnumeration(mock, device_count, op);
}
}
}
+#else // building for Android, which has no device enumeration support
+TEST(CubebDeviceEnumerator, EnumerateAndroid)
+{
+ MockCubeb* mock = new MockCubeb();
+ mozilla::CubebUtils::ForceSetCubebContext(mock->AsCubebContext());
+
+ CubebDeviceEnumerator enumerator;
+
+ nsTArray<RefPtr<AudioDeviceInfo>> inputDevices;
+ enumerator.EnumerateAudioInputDevices(inputDevices);
+ 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]->DeviceID(), nullptr) << "It's always the default device.";
+ EXPECT_TRUE(inputDevices[0]->Preferred()) << "it's always the prefered device.";
+}
+#endif
--- a/dom/media/webrtc/MediaEngineWebRTC.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTC.cpp
@@ -189,17 +189,19 @@ MediaEngineWebRTC::EnumerateMicrophoneDe
}
nsTArray<RefPtr<AudioDeviceInfo>> devices;
mEnumerator->EnumerateAudioInputDevices(devices);
DebugOnly<bool> foundPreferredDevice = false;
for (uint32_t i = 0; i < devices.Length(); i++) {
+#ifndef ANDROID
MOZ_ASSERT(devices[i]->DeviceID());
+#endif
LOG(("Cubeb device %u: type 0x%x, state 0x%x, name %s, id %p",
i,
devices[i]->Type(),
devices[i]->State(),
NS_ConvertUTF16toUTF8(devices[i]->Name()).get(),
devices[i]->DeviceID()));
if (devices[i]->State() == CUBEB_DEVICE_STATE_ENABLED) {
@@ -382,31 +384,57 @@ CubebDeviceEnumerator::~CubebDeviceEnume
NS_WARNING("Could not unregister the audio input"
" device collection changed callback.");
}
}
void
CubebDeviceEnumerator::EnumerateAudioInputDevices(nsTArray<RefPtr<AudioDeviceInfo>>& aOutDevices)
{
+ aOutDevices.Clear();
+
+#ifdef ANDROID
+ // Bug 1473346: enumerating devices is not supported on Android in cubeb,
+ // simply state that there is a single mic, that it is the default, and has a
+ // single channel. All the other values are made up and are not to be used.
+ RefPtr<AudioDeviceInfo> info = new AudioDeviceInfo(nullptr,
+ NS_ConvertUTF8toUTF16(""),
+ NS_ConvertUTF8toUTF16(""),
+ NS_ConvertUTF8toUTF16(""),
+ CUBEB_DEVICE_TYPE_INPUT,
+ CUBEB_DEVICE_STATE_ENABLED,
+ CUBEB_DEVICE_PREF_ALL,
+ CUBEB_DEVICE_FMT_ALL,
+ CUBEB_DEVICE_FMT_S16NE,
+ 1,
+ 44100,
+ 44100,
+ 41000,
+ 410,
+ 128);
+ if (mDevices.IsEmpty()) {
+ mDevices.AppendElement(info);
+ }
+ aOutDevices.AppendElements(mDevices);
+#else
cubeb* context = GetCubebContext();
if (!context) {
return;
}
MutexAutoLock lock(mMutex);
if (mDevices.IsEmpty() || mManualInvalidation) {
mDevices.Clear();
CubebUtils::GetDeviceCollection(mDevices, CubebUtils::Input);
}
- aOutDevices.Clear();
aOutDevices.AppendElements(mDevices);
+#endif
}
already_AddRefed<AudioDeviceInfo>
CubebDeviceEnumerator::DeviceInfoFromID(CubebUtils::AudioDeviceID aID)
{
MutexAutoLock lock(mMutex);
for (uint32_t i = 0; i < mDevices.Length(); i++) {
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -47,17 +47,17 @@ LogModule* GetMediaManagerLog();
#define LOG_FRAMES(msg) MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Verbose, msg)
LogModule* AudioLogModule() {
static mozilla::LazyLogModule log("AudioLatency");
return static_cast<LogModule*>(log);
}
void
-WebRTCAudioDataListener::NotifyOutputData(MediaStreamGraph* aGraph,
+WebRTCAudioDataListener::NotifyOutputData(MediaStreamGraphImpl* aGraph,
AudioDataValue* aBuffer,
size_t aFrames,
TrackRate aRate,
uint32_t aChannels)
{
MOZ_ASSERT(aGraph->CurrentDriver()->OnThread());
if (mAudioSource) {
mAudioSource->NotifyOutputData(aGraph, aBuffer, aFrames, aRate, aChannels);
@@ -140,17 +140,19 @@ MediaEngineWebRTCMicrophoneSource::Media
// It would be great if it did but we're already on the media thread.
/* aStrict = */ false))
, mRequestedInputChannelCount(aMaxChannelCount)
, mTotalFrames(0)
, mLastLogFrames(0)
, mSkipProcessing(false)
, mInputDownmixBuffer(MAX_SAMPLING_FREQ * MAX_CHANNELS / 100)
{
+#ifndef ANDROID
MOZ_ASSERT(mDeviceInfo->DeviceID());
+#endif
// We'll init lazily as needed
mSettings->mEchoCancellation.Construct(0);
mSettings->mAutoGainControl.Construct(0);
mSettings->mNoiseSuppression.Construct(0);
mSettings->mChannelCount.Construct(0);
mState = kReleased;
@@ -1297,23 +1299,16 @@ MediaEngineWebRTCMicrophoneSource::Disco
MOZ_ASSERT(!mListener);
}
void
MediaEngineWebRTCMicrophoneSource::Shutdown()
{
AssertIsOnOwningThread();
- if (mListener) {
- // breaks a cycle, since the WebRTCAudioDataListener has a RefPtr to us
- mListener->Shutdown();
- // Don't release the webrtc.org pointers yet until the Listener is (async) shutdown
- mListener = nullptr;
- }
-
if (mState == kStarted) {
for (const Allocation& allocation : mAllocations) {
if (allocation.mEnabled) {
Stop(allocation.mHandle);
}
}
MOZ_ASSERT(mState == kStopped);
}