Bug 1404977 - Part 7 - Make each MediaEngineWebRTCMicrophoneSource independent. r?pehrsons draft
authorPaul Adenot <paul@paul.cx>
Mon, 30 Apr 2018 15:37:18 +0200
changeset 798184 d632a9498a8e31724225af88f62a9a816374a987
parent 798183 d203db6261e38cf02390a38b13d1d10ff02d68bc
child 798185 aa4fa933490da6fcc97462f52094d5124d630836
push id110687
push userachronop@gmail.com
push dateTue, 22 May 2018 14:13:17 +0000
reviewerspehrsons
bugs1404977
milestone62.0a1
Bug 1404977 - Part 7 - Make each MediaEngineWebRTCMicrophoneSource independent. r?pehrsons MozReview-Commit-ID: 1RSsT6AV3iI
dom/media/webrtc/MediaEngineWebRTC.cpp
dom/media/webrtc/MediaEngineWebRTC.h
dom/media/webrtc/MediaEngineWebRTCAudio.cpp
--- a/dom/media/webrtc/MediaEngineWebRTC.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTC.cpp
@@ -199,18 +199,17 @@ MediaEngineWebRTC::EnumerateMicrophoneDe
          NS_ConvertUTF16toUTF8(devices[i]->FriendlyName()).get(),
          devices[i]->GetDeviceID().ref()));
 
     if (devices[i]->State() == CUBEB_DEVICE_STATE_ENABLED) {
       MOZ_ASSERT(devices[i]->Type() == CUBEB_DEVICE_TYPE_INPUT);
       // XXX do something for the default device.
       RefPtr<MediaEngineSource> source =
         new MediaEngineWebRTCMicrophoneSource(
-          mEnumerator,
-          devices[i]->GetDeviceID().ref(),
+          devices[i],
           devices[i]->FriendlyName(),
           // Lie and provide the name as UUID
           NS_LossyConvertUTF16toASCII(devices[i]->FriendlyName()),
           devices[i]->MaxChannels(),
           mDelayAgnostic,
           mExtendedFilter);
       aSources->AppendElement(source);
     }
--- a/dom/media/webrtc/MediaEngineWebRTC.h
+++ b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -187,20 +187,20 @@ private:
   Mutex mMutex;
   RefPtr<MediaEngineWebRTCMicrophoneSource> mAudioSource;
 };
 
 class MediaEngineWebRTCMicrophoneSource : public MediaEngineSource,
                                           public AudioDataListenerInterface
 {
 public:
-  MediaEngineWebRTCMicrophoneSource(mozilla::AudioInput* aAudioInput,
-                                    int aIndex,
-                                    const char* name,
-                                    const char* uuid,
+  MediaEngineWebRTCMicrophoneSource(RefPtr<AudioDeviceInfo> aInfo,
+                                    const nsString& name,
+                                    const nsCString& uuid,
+                                    uint32_t maxChannelCount,
                                     bool aDelayAgnostic,
                                     bool aExtendedFilter);
 
   bool RequiresSharing() const override
   {
     return true;
   }
 
@@ -243,16 +243,21 @@ public:
                         AudioDataValue* aBuffer, size_t aFrames,
                         TrackRate aRate, uint32_t aChannels) override;
   void NotifyInputData(MediaStreamGraph* aGraph,
                        const AudioDataValue* aBuffer, size_t aFrames,
                        TrackRate aRate, uint32_t aChannels) override;
 
   void DeviceChanged() override;
 
+  uint32_t InputChannelCount() override
+  {
+    return GetUserInputChannelCount();
+  }
+
   dom::MediaSourceEnum GetMediaSource() const override
   {
     return dom::MediaSourceEnum::Microphone;
   }
 
   nsresult TakePhoto(MediaEnginePhotoCallback* aCallback) override
   {
     return NS_ERROR_NOT_IMPLEMENTED;
@@ -360,24 +365,28 @@ private:
 
   // This is true when all processing is disabled, we can skip
   // packetization, resampling and other processing passes.
   // Graph thread only.
   bool PassThrough() const;
 
   // Graph thread only.
   void SetPassThrough(bool aPassThrough);
+  uint32_t GetUserInputChannelCount();
+  void SetUserInputChannelCount(uint32_t aUserInputChannelCount);
 
   // Owning thread only.
   RefPtr<WebRTCAudioDataListener> mListener;
+  RefPtr<mozilla::CubebDeviceEnumerator> mEnumerator;
 
-  // Note: shared across all microphone sources. Owning thread only.
-  static int sChannelsOpen;
+  RefPtr<AudioDeviceInfo> mDeviceInfo;
 
-  const RefPtr<mozilla::AudioInput> mAudioInput;
+  // Number of times this device has been opened for this MSG.
+  int mChannelsOpen;
+
   const UniquePtr<webrtc::AudioProcessing> mAudioProcessing;
 
   // accessed from the GraphDriver thread except for deletion.
   nsAutoPtr<AudioPacketizer<AudioDataValue, float>> mPacketizerInput;
   nsAutoPtr<AudioPacketizer<AudioDataValue, float>> mPacketizerOutput;
 
   // mMutex protects some of our members off the owning thread.
   Mutex mMutex;
@@ -386,28 +395,31 @@ private:
   // Both the array and the Allocation members are modified under mMutex on
   // the owning thread. Accessed under one of the two.
   nsTArray<Allocation> mAllocations;
 
   // Current state of the shared resource for this source.
   // Set under mMutex on the owning thread. Accessed under one of the two
   MediaEngineSourceState mState = kReleased;
 
-  int mCapIndex;
   bool mDelayAgnostic;
   bool mExtendedFilter;
   bool mStarted;
 
   const nsString mDeviceName;
   const nsCString mDeviceUUID;
 
   // The current settings for the underlying device.
   // Member access is main thread only after construction.
   const nsMainThreadPtrHandle<media::Refcountable<dom::MediaTrackSettings>> mSettings;
 
+  // The number of channels asked for by content, after clamping to the range of
+  // legal channel count for this particular device. This is the number of
+  // channels of the input buffer received.
+  uint32_t mRequestedInputChannelCount;
   uint64_t mTotalFrames;
   uint64_t mLastLogFrames;
 
   // mSkipProcessing is true if none of the processing passes are enabled,
   // because of prefs or constraints. This allows simply copying the audio into
   // the MSG, skipping resampling and the whole webrtc.org code.
   // This is read and written to only on the MSG thread.
   bool mSkipProcessing;
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -101,54 +101,54 @@ WebRTCAudioDataListener::Shutdown()
 {
   MutexAutoLock lock(mMutex);
   mAudioSource = nullptr;
 }
 
 /**
  * WebRTC Microphone MediaEngineSource.
  */
-int MediaEngineWebRTCMicrophoneSource::sChannelsOpen = 0;
 
 MediaEngineWebRTCMicrophoneSource::Allocation::Allocation(
     const RefPtr<AllocationHandle>& aHandle)
   : mHandle(aHandle)
 {}
 
 MediaEngineWebRTCMicrophoneSource::Allocation::~Allocation() = default;
 
 MediaEngineWebRTCMicrophoneSource::MediaEngineWebRTCMicrophoneSource(
-    mozilla::AudioInput* aAudioInput,
-    int aIndex,
-    const char* aDeviceName,
-    const char* aDeviceUUID,
+    RefPtr<AudioDeviceInfo> aInfo,
+    const nsString& aDeviceName,
+    const nsCString& aDeviceUUID,
+    uint32_t maxChannelCount,
     bool aDelayAgnostic,
     bool aExtendedFilter)
-  : mAudioInput(aAudioInput)
+  : mDeviceInfo(aInfo)
+  , mChannelsOpen(0)
   , mAudioProcessing(AudioProcessing::Create())
   , mMutex("WebRTCMic::Mutex")
-  , mCapIndex(aIndex)
   , mDelayAgnostic(aDelayAgnostic)
   , mExtendedFilter(aExtendedFilter)
   , mStarted(false)
-  , mDeviceName(NS_ConvertUTF8toUTF16(aDeviceName))
+  , mDeviceName(aDeviceName)
   , mDeviceUUID(aDeviceUUID)
   , mSettings(
       new nsMainThreadPtrHolder<media::Refcountable<dom::MediaTrackSettings>>(
         "MediaEngineWebRTCMicrophoneSource::mSettings",
         new media::Refcountable<dom::MediaTrackSettings>(),
         // Non-strict means it won't assert main thread for us.
         // It would be great if it did but we're already on the media thread.
         /* aStrict = */ false))
+  , mRequestedInputChannelCount(maxChannelCount)
   , mTotalFrames(0)
   , mLastLogFrames(0)
   , mSkipProcessing(false)
   , mInputDownmixBuffer(MAX_SAMPLING_FREQ * MAX_CHANNELS / 100)
 {
-  MOZ_ASSERT(aAudioInput);
+  MOZ_ASSERT(mDeviceInfo->GetDeviceID().isSome());
   mSettings->mEchoCancellation.Construct(0);
   mSettings->mAutoGainControl.Construct(0);
   mSettings->mNoiseSuppression.Construct(0);
   mSettings->mChannelCount.Construct(0);
   // We'll init lazily as needed
 }
 
 nsString
@@ -421,125 +421,129 @@ MediaEngineWebRTCMicrophoneSource::Updat
   AssertIsOnOwningThread();
 
   FlattenedConstraints c(aNetConstraints);
 
   MediaEnginePrefs prefs = aPrefs;
   prefs.mAecOn = c.mEchoCancellation.Get(prefs.mAecOn);
   prefs.mAgcOn = c.mAutoGainControl.Get(prefs.mAgcOn);
   prefs.mNoiseOn = c.mNoiseSuppression.Get(prefs.mNoiseOn);
-  uint32_t maxChannels = 1;
-  if (mAudioInput->GetMaxAvailableChannels(maxChannels) != 0) {
-    return NS_ERROR_FAILURE;
-  }
-  // Check channelCount violation
-  if (static_cast<int32_t>(maxChannels) < c.mChannelCount.mMin ||
-      static_cast<int32_t>(maxChannels) > c.mChannelCount.mMax) {
+
+  // Determine an actual channel count to use for this source. Three factors at
+  // play here: the device capabilities, the constraints passed in by content,
+  // and a pref that can force things (for testing)
+
+  // First, check channelCount violation wrt constraints. This fails in case of
+  // error.
+  if (static_cast<int32_t>(mDeviceInfo->MaxChannels()) < c.mChannelCount.mMin ||
+      static_cast<int32_t>(mDeviceInfo->MaxChannels()) > c.mChannelCount.mMax) {
     *aOutBadConstraint = "channelCount";
     return NS_ERROR_FAILURE;
   }
-  // Clamp channelCount to a valid value
+  // A pref can force the channel count to use. If the pref has a value of zero
+  // or lower, it has no effect.
   if (prefs.mChannels <= 0) {
-    prefs.mChannels = static_cast<int32_t>(maxChannels);
+    prefs.mChannels = static_cast<int32_t>(mDeviceInfo->MaxChannels());
   }
+
+  // Get the number of channels asked for by content, and clamp it between the
+  // pref and the maximum number of channels that the device supports.
   prefs.mChannels = c.mChannelCount.Get(std::min(prefs.mChannels,
-                                        static_cast<int32_t>(maxChannels)));
-  // Clamp channelCount to a valid value
-  prefs.mChannels = std::max(1, std::min(prefs.mChannels, static_cast<int32_t>(maxChannels)));
+                                        static_cast<int32_t>(mDeviceInfo->MaxChannels())));
 
   LOG(("Audio config: aec: %d, agc: %d, noise: %d, channels: %d",
       prefs.mAecOn ? prefs.mAec : -1,
       prefs.mAgcOn ? prefs.mAgc : -1,
       prefs.mNoiseOn ? prefs.mNoise : -1,
       prefs.mChannels));
 
   switch (mState) {
     case kReleased:
       MOZ_ASSERT(aHandle);
-      if (sChannelsOpen != 0) {
-        // Until we fix (or wallpaper) support for multiple mic input
-        // (Bug 1238038) fail allocation for a second device
-        return NS_ERROR_FAILURE;
-      }
-      if (mAudioInput->SetRecordingDevice(mCapIndex)) {
-         return NS_ERROR_FAILURE;
-      }
-      mAudioInput->SetUserChannelCount(prefs.mChannels);
       {
         MutexAutoLock lock(mMutex);
         mState = kAllocated;
+        mChannelsOpen++;
       }
-      sChannelsOpen++;
-      LOG(("Audio device %d allocated", mCapIndex));
-      {
-        // Update with the actual applied channelCount in order
-        // to store it in settings.
-        uint32_t channelCount = 0;
-        mAudioInput->GetChannelCount(channelCount);
-        MOZ_ASSERT(channelCount > 0);
-        prefs.mChannels = channelCount;
-      }
+      LOG(("Audio device %s allocated", NS_ConvertUTF16toUTF8(mDeviceInfo->FriendlyName()).get()));
       break;
 
     case kStarted:
     case kStopped:
-      if (prefs.mChannels != mNetPrefs.mChannels) {
-        // If the channel count changed, tell the MSG to open a new driver with
-        // the correct channel count.
-        MOZ_ASSERT(!mAllocations.IsEmpty());
-        RefPtr<SourceMediaStream> stream;
-        for (const Allocation& allocation : mAllocations) {
-          if (allocation.mStream && allocation.mStream->GraphImpl()) {
-            stream = allocation.mStream;
-            break;
-          }
-        }
-        MOZ_ASSERT(stream);
-
-        mAudioInput->SetUserChannelCount(prefs.mChannels);
-        // Get validated number of channel
-        uint32_t channelCount = 0;
-        mAudioInput->GetChannelCount(channelCount);
-        MOZ_ASSERT(channelCount > 0 && mNetPrefs.mChannels > 0);
-        if (!stream->OpenNewAudioCallbackDriver(mListener)) {
-          MOZ_LOG(GetMediaManagerLog(), LogLevel::Error, ("Could not open a new AudioCallbackDriver for input"));
-          return NS_ERROR_FAILURE;
-        }
+      LOG(("Audio device %s %s", NS_ConvertUTF16toUTF8(mDeviceInfo->FriendlyName()).get()
+                               , mState == kStarted ? "started" : "stopped"));
+      if (prefs == mNetPrefs) {
+        return NS_OK;
       }
       break;
 
     default:
-      LOG(("Audio device %d in ignored state %d", mCapIndex, mState));
+      LOG(("Audio device %s in ignored state %d", NS_ConvertUTF16toUTF8(mDeviceInfo->FriendlyName()).get(), mState));
       break;
   }
 
-  if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) {
-    if (mAllocations.IsEmpty()) {
-      LOG(("Audio device %d reallocated", mCapIndex));
-    } else {
-      LOG(("Audio device %d allocated shared", mCapIndex));
-    }
-  }
-
-  if (sChannelsOpen > 0) {
+  if (mChannelsOpen > 0) {
     UpdateAGCSettingsIfNeeded(prefs.mAgcOn, static_cast<AgcModes>(prefs.mAgc));
     UpdateNSSettingsIfNeeded(prefs.mNoiseOn, static_cast<NsModes>(prefs.mNoise));
     UpdateAECSettingsIfNeeded(prefs.mAecOn, static_cast<EcModes>(prefs.mAec));
 
     webrtc::Config config;
     config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(mExtendedFilter));
     config.Set<webrtc::DelayAgnostic>(new webrtc::DelayAgnostic(mDelayAgnostic));
     mAudioProcessing->SetExtraOptions(config);
   }
   mNetPrefs = prefs;
   return NS_OK;
 }
 
 #undef HANDLE_APM_ERROR
 
+bool
+MediaEngineWebRTCMicrophoneSource::PassThrough() const
+{
+  MOZ_ASSERT(!mAllocations.IsEmpty() &&
+             mAllocations[0].mStream &&
+             mAllocations[0].mStream->GraphImpl()->CurrentDriver()->OnThread());
+  return mSkipProcessing;
+}
+void
+MediaEngineWebRTCMicrophoneSource::SetPassThrough(bool aPassThrough)
+{
+  if (mAllocations.IsEmpty()) {
+    return;
+  }
+  MOZ_ASSERT(!mAllocations.IsEmpty() &&
+             mAllocations[0].mStream &&
+             mAllocations[0].mStream->GraphImpl()->CurrentDriver()->OnThread());
+  mSkipProcessing = aPassThrough;
+}
+
+uint32_t
+MediaEngineWebRTCMicrophoneSource::GetUserInputChannelCount()
+{
+  MOZ_ASSERT(!mAllocations.IsEmpty() &&
+             mAllocations[0].mStream &&
+             mAllocations[0].mStream->GraphImpl()->CurrentDriver()->OnThread());
+  return mRequestedInputChannelCount;
+}
+
+void
+MediaEngineWebRTCMicrophoneSource::SetUserInputChannelCount(
+  uint32_t aUserInputChannelCount)
+  {
+    if (mAllocations.IsEmpty()) {
+      return;
+  }
+  MOZ_ASSERT(!mAllocations.IsEmpty() &&
+             mAllocations[0].mStream &&
+             mAllocations[0].mStream->GraphImpl()->CurrentDriver()->OnThread());
+  mRequestedInputChannelCount = aUserInputChannelCount;
+  mAllocations[0].mStream->GraphImpl()->ReevaluateInputDevice();
+}
+
 void
 MediaEngineWebRTCMicrophoneSource::ApplySettings(const MediaEnginePrefs& aPrefs,
                                                  RefPtr<MediaStreamGraphImpl> aGraph)
 {
   AssertIsOnOwningThread();
   MOZ_DIAGNOSTIC_ASSERT(aGraph);
 
   RefPtr<MediaEngineWebRTCMicrophoneSource> that = this;
@@ -547,35 +551,41 @@ MediaEngineWebRTCMicrophoneSource::Apply
     that->mSettings->mEchoCancellation.Value() = aPrefs.mAecOn;
     that->mSettings->mAutoGainControl.Value() = aPrefs.mAgcOn;
     that->mSettings->mNoiseSuppression.Value() = aPrefs.mNoiseOn;
     that->mSettings->mChannelCount.Value() = aPrefs.mChannels;
 
     class Message : public ControlMessage {
     public:
       Message(MediaEngineWebRTCMicrophoneSource* aSource,
-              bool aPassThrough)
+              bool aPassThrough,
+              uint32_t aUserInputChannelCount)
         : ControlMessage(nullptr)
         , mMicrophoneSource(aSource)
         , mPassThrough(aPassThrough)
+        , mUserInputChannelCount(aUserInputChannelCount)
         {}
 
       void Run() override
       {
         mMicrophoneSource->SetPassThrough(mPassThrough);
+        mMicrophoneSource->SetUserInputChannelCount(mUserInputChannelCount);
       }
 
     protected:
       RefPtr<MediaEngineWebRTCMicrophoneSource> mMicrophoneSource;
       bool mPassThrough;
+      uint32_t mUserInputChannelCount;
     };
 
     bool passThrough = !(aPrefs.mAecOn || aPrefs.mAgcOn || aPrefs.mNoiseOn);
     if (graph) {
-      graph->AppendMessage(MakeUnique<Message>(that, passThrough));
+      graph->AppendMessage(MakeUnique<Message>(that,
+                                               passThrough,
+                                               aPrefs.mChannels));
     }
 
     return NS_OK;
   }));
 }
 
 nsresult
 MediaEngineWebRTCMicrophoneSource::Allocate(const dom::MediaTrackConstraints &aConstraints,
@@ -612,59 +622,51 @@ MediaEngineWebRTCMicrophoneSource::Deall
 {
   AssertIsOnOwningThread();
 
   size_t i = mAllocations.IndexOf(aHandle, 0, AllocationHandleComparator());
   MOZ_DIAGNOSTIC_ASSERT(i != mAllocations.NoIndex);
   MOZ_DIAGNOSTIC_ASSERT(!mAllocations[i].mEnabled,
                         "Source should be stopped for the track before removing");
 
-  LOG(("Mic source %p allocation %p Deallocate()", this, aHandle.get()));
-
   if (mAllocations[i].mStream && IsTrackIDExplicit(mAllocations[i].mTrackID)) {
     mAllocations[i].mStream->EndTrack(mAllocations[i].mTrackID);
   }
 
   {
     MutexAutoLock lock(mMutex);
     mAllocations.RemoveElementAt(i);
   }
 
   if (mAllocations.IsEmpty()) {
     // If empty, no callbacks to deliver data should be occuring
     MOZ_ASSERT(mState != kReleased, "Source not allocated");
     MOZ_ASSERT(mState != kStarted, "Source not stopped");
-    MOZ_ASSERT(sChannelsOpen > 0);
-    --sChannelsOpen;
+    MOZ_ASSERT(mChannelsOpen > 0);
+    --mChannelsOpen;
 
     MutexAutoLock lock(mMutex);
     mState = kReleased;
-    LOG(("Audio device %d deallocated", mCapIndex));
+    LOG(("Audio device %s deallocated", NS_ConvertUTF16toUTF8(mDeviceName).get()));
   } else {
-    LOG(("Audio device %d deallocated but still in use", mCapIndex));
+    LOG(("Audio device %s deallocated but still in use", NS_ConvertUTF16toUTF8(mDeviceName).get()));
   }
   return NS_OK;
 }
 
 nsresult
 MediaEngineWebRTCMicrophoneSource::SetTrack(const RefPtr<const AllocationHandle>& aHandle,
                                             const RefPtr<SourceMediaStream>& aStream,
                                             TrackID aTrackID,
                                             const PrincipalHandle& aPrincipal)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aStream);
   MOZ_ASSERT(IsTrackIDExplicit(aTrackID));
 
-  LOG(("Mic source %p allocation %p SetTrack() stream=%p, track=%" PRId32,
-       this, aHandle.get(), aStream.get(), aTrackID));
-
-  // Until we fix bug 1400488 we need to block a second tab (OuterWindow)
-  // from opening an already-open device.  If it's the same tab, they
-  // will share a Graph(), and we can allow it.
   if (!mAllocations.IsEmpty() &&
       mAllocations[0].mStream &&
       mAllocations[0].mStream->Graph() != aStream->Graph()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   size_t i = mAllocations.IndexOf(aHandle, 0, AllocationHandleComparator());
   MOZ_DIAGNOSTIC_ASSERT(i != mAllocations.NoIndex);
@@ -692,28 +694,31 @@ MediaEngineWebRTCMicrophoneSource::SetTr
   LOG(("Stream %p registered for microphone capture", aStream.get()));
   return NS_OK;
 }
 
 nsresult
 MediaEngineWebRTCMicrophoneSource::Start(const RefPtr<const AllocationHandle>& aHandle)
 {
   AssertIsOnOwningThread();
-
-  if (sChannelsOpen == 0) {
-    return NS_ERROR_FAILURE;
-  }
-
-  LOG(("Mic source %p allocation %p Start()", this, aHandle.get()));
+  MOZ_ASSERT(mChannelsOpen);
 
   size_t i = mAllocations.IndexOf(aHandle, 0, AllocationHandleComparator());
   MOZ_DIAGNOSTIC_ASSERT(i != mAllocations.NoIndex,
                         "Can't start track that hasn't been added");
   Allocation& allocation = mAllocations[i];
 
+  CubebUtils::AudioDeviceID deviceID = mDeviceInfo->GetDeviceID().ref();
+  // For now, we only allow opening a single audio input device per page,
+  // because we can only have one MSG per document.
+  if (allocation.mStream->GraphImpl()->InputDeviceID() &&
+      allocation.mStream->GraphImpl()->InputDeviceID() != deviceID) {
+    return NS_ERROR_FAILURE;
+  }
+
   MOZ_ASSERT(!allocation.mEnabled, "Source already started");
   {
     // This spans setting both the enabled state and mState.
     MutexAutoLock lock(mMutex);
     allocation.mEnabled = true;
 
 #ifdef DEBUG
     // Ensure that callback-tracking state is reset when callbacks start coming.
@@ -724,18 +729,17 @@ MediaEngineWebRTCMicrophoneSource::Start
 
     if (!mListener) {
       mListener = new WebRTCAudioDataListener(this);
     }
 
     // Make sure logger starts before capture
     AsyncLatencyLogger::Get(true);
 
-    // Must be *before* StartSend() so it will notice we selected external input (full_duplex)
-    mAudioInput->StartRecording(allocation.mStream, mListener);
+    allocation.mStream->OpenAudioInput(deviceID, mListener);
 
     MOZ_ASSERT(mState != kReleased);
     mState = kStarted;
   }
 
   ApplySettings(mNetPrefs, allocation.mStream->GraphImpl());
 
   return NS_OK;
@@ -758,17 +762,18 @@ MediaEngineWebRTCMicrophoneSource::Stop(
     return NS_OK;
   }
 
   {
     // This spans setting both the enabled state and mState.
     MutexAutoLock lock(mMutex);
     allocation.mEnabled = false;
 
-    mAudioInput->StopRecording(allocation.mStream);
+    CubebUtils::AudioDeviceID deviceID = mDeviceInfo->GetDeviceID().ref();
+    allocation.mStream->CloseAudioInput(deviceID, mListener);
 
     if (HasEnabledTrack()) {
       // Another track is keeping us from stopping
       return NS_OK;
     }
 
     MOZ_ASSERT(mState == kStarted, "Should be started when stopping");
     mState = kStopped;
@@ -793,16 +798,17 @@ MediaEngineWebRTCMicrophoneSource::GetSe
 void
 MediaEngineWebRTCMicrophoneSource::Pull(const RefPtr<const AllocationHandle>& aHandle,
                                         const RefPtr<SourceMediaStream>& aStream,
                                         TrackID aTrackID,
                                         StreamTime aDesiredTime,
                                         const PrincipalHandle& aPrincipalHandle)
 {
   StreamTime delta;
+  LOG_FRAMES(("NotifyPull, desired = %" PRId64, (int64_t) aDesiredTime));
 
   {
     MutexAutoLock lock(mMutex);
     size_t i = mAllocations.IndexOf(aHandle, 0, AllocationHandleComparator());
     if (i == mAllocations.NoIndex) {
       // This handle must have been deallocated. That's fine, and its track
       // will already be ended. No need to do anything.
       return;
@@ -828,17 +834,18 @@ MediaEngineWebRTCMicrophoneSource::Pull(
       return;
     }
 
     LOG_FRAMES(("Pulling %" PRId64 " frames of silence for allocation %p",
                 delta, mAllocations[i].mHandle.get()));
 
     // This assertion fails when we append silence here in the same iteration
     // as there were real audio samples already appended by the audio callback.
-    // Note that this is exempted until live samples and a subsequent chunk of silence have been appended to the track. This will cover cases like:
+    // Note that this is exempted until live samples and a subsequent chunk of
+    // silence have been appended to the track. This will cover cases like:
     // - After Start(), there is silence (maybe multiple times) appended before
     //   the first audio callback.
     // - After Start(), there is real data (maybe multiple times) appended
     //   before the first graph iteration.
     // And other combinations of order of audio sample sources.
     MOZ_ASSERT_IF(
       mAllocations[i].mEnabled &&
       mAllocations[i].mLiveFramesAppended &&
@@ -1073,28 +1080,16 @@ MediaEngineWebRTCMicrophoneSource::Packe
                            processedOutputChannelPointersConst,
                            mPacketizerInput->PacketSize(),
                            allocation.mPrincipal);
       allocation.mStream->AppendToTrack(allocation.mTrackID, &segment);
     }
   }
 }
 
-bool
-MediaEngineWebRTCMicrophoneSource::PassThrough() const
-{
-  return mSkipProcessing;
-}
-
-void
-MediaEngineWebRTCMicrophoneSource::SetPassThrough(bool aPassThrough)
-{
-  mSkipProcessing = aPassThrough;
-}
-
 template<typename T>
 void
 MediaEngineWebRTCMicrophoneSource::InsertInGraph(const T* aBuffer,
                                                  size_t aFrames,
                                                  uint32_t aChannels)
 {
   MutexAutoLock lock(mMutex);