Bug 1404977 - Part 17 - Re-implement the workaround for the lack of input device enumeration on Android. r?pehrsons draft
authorPaul Adenot <paul@paul.cx>
Wed, 04 Jul 2018 18:00:57 +0200
changeset 825398 c8a360fa07faa04428264958364f3c975ee2d3b5
parent 825397 19596059c23dc4ea86c9315c54fe5ebaef75578c
push id118097
push userpaul@paul.cx
push dateWed, 01 Aug 2018 17:03:19 +0000
reviewerspehrsons
bugs1404977
milestone63.0a1
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);
   }