Bug 1250934: Split WebRTC MediaEngine shutdown into two stages to allow async shutdown r?padenot draft
authorRandell Jesup <rjesup@jesup.org>
Fri, 26 Feb 2016 10:22:46 -0500
changeset 334934 b5465e15157e9d6219a1fd6169e734c13d852087
parent 334850 6cb2edec5523c7851dd89c855353e63cf784dc9b
child 515033 2f53a78706f40b23d1b18f0898c0a618e0bfa590
push id11677
push userrjesup@wgate.com
push dateFri, 26 Feb 2016 15:23:09 +0000
reviewerspadenot
bugs1250934
milestone47.0a1
Bug 1250934: Split WebRTC MediaEngine shutdown into two stages to allow async shutdown r?padenot MozReview-Commit-ID: 7LeFAbaTHMY
dom/media/webrtc/MediaEngine.h
dom/media/webrtc/MediaEngineDefault.h
dom/media/webrtc/MediaEngineRemoteVideoSource.h
dom/media/webrtc/MediaEngineTabVideoSource.h
dom/media/webrtc/MediaEngineWebRTC.h
dom/media/webrtc/MediaEngineWebRTCAudio.cpp
--- a/dom/media/webrtc/MediaEngine.h
+++ b/dom/media/webrtc/MediaEngine.h
@@ -84,16 +84,17 @@ public:
   // code inside webrtc.org assumes these sizes; don't use anything smaller
   // without verifying it's ok
   static const unsigned int kMaxDeviceNameLength = 128;
   static const unsigned int kMaxUniqueIdLength = 256;
 
   virtual ~MediaEngineSource() {}
 
   virtual void Shutdown() = 0;
+  virtual void ReleaseInterfaces() = 0;
 
   /* Populate the human readable name of this device in the nsAString */
   virtual void GetName(nsAString&) = 0;
 
   /* Populate the UUID of this device in the nsACString */
   virtual void GetUUID(nsACString&) = 0;
 
   /* Release the device back to the system. */
--- a/dom/media/webrtc/MediaEngineDefault.h
+++ b/dom/media/webrtc/MediaEngineDefault.h
@@ -34,16 +34,17 @@ class MediaEngineDefault;
 class MediaEngineDefaultVideoSource : public nsITimerCallback,
                                       public MediaEngineVideoSource,
                                       private MediaConstraintsHelper
 {
 public:
   MediaEngineDefaultVideoSource();
 
   void Shutdown() override {};
+  void ReleaseInterfaces() override {};
 
   void GetName(nsAString&) override;
   void GetUUID(nsACString&) override;
 
   nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
                     const MediaEnginePrefs &aPrefs,
                     const nsString& aDeviceId,
                     const nsACString& aOrigin) override;
@@ -104,16 +105,17 @@ class SineWaveGenerator;
 class MediaEngineDefaultAudioSource : public nsITimerCallback,
                                       public MediaEngineAudioSource,
                                       private MediaConstraintsHelper
 {
 public:
   MediaEngineDefaultAudioSource();
 
   void Shutdown() override {};
+  void ReleaseInterfaces() override {};
 
   void GetName(nsAString&) override;
   void GetUUID(nsACString&) override;
 
   nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
                     const MediaEnginePrefs &aPrefs,
                     const nsString& aDeviceId,
                     const nsACString& aOrigin) override;
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.h
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.h
@@ -91,16 +91,17 @@ public:
 
   bool ChooseCapability(const dom::MediaTrackConstraints &aConstraints,
                         const MediaEnginePrefs &aPrefs,
                         const nsString& aDeviceId) override;
 
   void Refresh(int aIndex);
 
   void Shutdown() override;
+  void ReleaseInterfaces() override {}
 
 protected:
   ~MediaEngineRemoteVideoSource() { Shutdown(); }
 
 private:
   // Initialize the needed Video engine interfaces.
   void Init();
   size_t NumCapabilities() override;
--- a/dom/media/webrtc/MediaEngineTabVideoSource.h
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.h
@@ -14,16 +14,17 @@ namespace mozilla {
 class MediaEngineTabVideoSource : public MediaEngineVideoSource, nsIDOMEventListener, nsITimerCallback {
   public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIDOMEVENTLISTENER
     NS_DECL_NSITIMERCALLBACK
     MediaEngineTabVideoSource();
 
     void Shutdown() override {};
+    void ReleaseInterfaces() override {}
     void GetName(nsAString_internal&) override;
     void GetUUID(nsACString_internal&) override;
     nsresult Allocate(const dom::MediaTrackConstraints &,
                       const mozilla::MediaEnginePrefs&,
                       const nsString& aDeviceId,
                       const nsACString& aOrigin) override;
     nsresult Deallocate() override;
     nsresult Start(mozilla::SourceMediaStream*, mozilla::TrackID) override;
--- a/dom/media/webrtc/MediaEngineWebRTC.h
+++ b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -83,16 +83,17 @@ public:
   {
     // Nothing to do here, everything is managed in MediaManager.cpp
     return NS_OK;
   }
   void Shutdown() override
   {
     // Nothing to do here, everything is managed in MediaManager.cpp
   }
+  void ReleaseInterfaces() override {}
   nsresult Start(SourceMediaStream* aMediaStream, TrackID aId) override;
   nsresult Stop(SourceMediaStream* aMediaStream, TrackID aId) override;
   nsresult Restart(const dom::MediaTrackConstraints& aConstraints,
                    const MediaEnginePrefs &aPrefs,
                    const nsString& aDeviceId) override;
   void SetDirectListeners(bool aDirect) override
   {}
   void NotifyOutputData(MediaStreamGraph* aGraph,
@@ -337,17 +338,20 @@ protected:
   // Protected destructor, to discourage deletion outside of Release():
   ~AudioInputWebRTC() {}
 };
 
 class WebRTCAudioDataListener : public AudioDataListener
 {
 protected:
   // Protected destructor, to discourage deletion outside of Release():
-  virtual ~WebRTCAudioDataListener() {}
+  virtual ~WebRTCAudioDataListener()
+  {
+    mAudioSource->ReleaseInterfaces();
+  }
 
 public:
   explicit WebRTCAudioDataListener(MediaEngineAudioSource* aAudioSource) :
     mAudioSource(aAudioSource)
   {}
 
   // AudioDataListenerInterface methods
   virtual void NotifyOutputData(MediaStreamGraph* aGraph,
@@ -450,35 +454,41 @@ public:
       const nsString& aDeviceId) override;
 
   // VoEMediaProcess.
   void Process(int channel, webrtc::ProcessingTypes type,
                int16_t audio10ms[], int length,
                int samplingFreq, bool isStereo) override;
 
   void Shutdown() override;
+  void ReleaseInterfaces() override;
 
   NS_DECL_THREADSAFE_ISUPPORTS
 
 protected:
-  ~MediaEngineWebRTCMicrophoneSource() { Shutdown(); }
+  ~MediaEngineWebRTCMicrophoneSource() {
+    Shutdown();
+    ReleaseInterfaces();
+  }
 
 private:
   void Init();
 
   webrtc::VoiceEngine* mVoiceEngine;
   RefPtr<mozilla::AudioInput> mAudioInput;
   RefPtr<WebRTCAudioDataListener> mListener;
 
   ScopedCustomReleasePtr<webrtc::VoEBase> mVoEBase;
   ScopedCustomReleasePtr<webrtc::VoEExternalMedia> mVoERender;
   ScopedCustomReleasePtr<webrtc::VoENetwork> mVoENetwork;
   ScopedCustomReleasePtr<webrtc::VoEAudioProcessing> mVoEProcessing;
 
+  // accessed from the GraphDriver thread except for deletion
   nsAutoPtr<AudioPacketizer<AudioDataValue, int16_t>> mPacketizer;
+  ScopedCustomReleasePtr<webrtc::VoEExternalMedia> mVoERenderListener;
 
   // mMonitor protects mSources[] access/changes, and transitions of mState
   // from kStarted to kStopped (which are combined with EndTrack()).
   // mSources[] is accessed from webrtc threads.
   Monitor mMonitor;
   nsTArray<RefPtr<SourceMediaStream>> mSources;
   nsCOMPtr<nsIThread> mThread;
   int mCapIndex;
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -446,17 +446,18 @@ void
 MediaEngineWebRTCMicrophoneSource::NotifyOutputData(MediaStreamGraph* aGraph,
                                                     AudioDataValue* aBuffer,
                                                     size_t aFrames,
                                                     TrackRate aRate,
                                                     uint32_t aChannels)
 {
 }
 
-// Called back on GraphDriver thread
+// Called back on GraphDriver thread!
+// Note this can be called back after ::Shutdown()
 void
 MediaEngineWebRTCMicrophoneSource::NotifyInputData(MediaStreamGraph* aGraph,
                                                    const AudioDataValue* aBuffer,
                                                    size_t aFrames,
                                                    TrackRate aRate,
                                                    uint32_t aChannels)
 {
   // This will call Process() with data coming out of the AEC/NS/AGC/etc chain
@@ -585,27 +586,32 @@ MediaEngineWebRTCMicrophoneSource::Shutd
   if (mState == kAllocated || mState == kStopped) {
     Deallocate();
   }
 
   mVoEBase->Terminate();
   if (mChannel != -1) {
     mVoENetwork->DeRegisterExternalTransport(mChannel);
   }
+  // Don't release the webrtc.org pointers yet until the Listener is (async) shutdown
+  mListener = nullptr; // breaks a cycle, since the WebRTCAudioDataListener has a RefPtr to us
+}
 
+void
+MediaEngineWebRTCMicrophoneSource::ReleaseInterfaces()
+{
   delete mNullTransport;
   mNullTransport = nullptr;
 
   mVoEProcessing = nullptr;
   mVoENetwork = nullptr;
   mVoERender = nullptr;
   mVoEBase = nullptr;
 
   mAudioInput = nullptr;
-  mListener = nullptr; // breaks a cycle, since the WebRTCAudioDataListener has a RefPtr to us
 
   mState = kReleased;
   mInitDone = false;
 }
 
 typedef int16_t sample;
 
 void