Bug 1404977 - Part 17 - Re-implement the workaround for the lack of input device enumeration on Android. r=pehrsons
authorPaul Adenot <paul@paul.cx>
Wed, 04 Jul 2018 18:00:57 +0200
changeset 487816 d3fc55ebb24ab7117d5bbe740653af807dfe05b0
parent 487815 edc7a43bb7592c5407564151feeeb38c3684281f
child 487817 acbf4a97ecca6ff4a0b5f2c08115f91523e41461
push id1815
push userffxbld-merge
push dateMon, 15 Oct 2018 10:40:45 +0000
treeherdermozilla-release@18d4c09e9378 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspehrsons
bugs1404977
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1404977 - Part 17 - Re-implement the workaround for the lack of input device enumeration on Android. r=pehrsons MozReview-Commit-ID: 5EiQ6a3OaIR
dom/media/gtest/TestAudioDeviceEnumerator.cpp
dom/media/webrtc/MediaEngineWebRTC.cpp
dom/media/webrtc/MediaEngineWebRTCAudio.cpp
--- 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);
   }