Bug 979716: Proxy incoming audio to another thread before calling AppendToTrack() r=gcp a=lmandel
authorRandell Jesup <rjesup@jesup.org>
Tue, 08 Jul 2014 15:02:40 -0400
changeset 207794 4e13d7c9fcf7a6b79fe571f6f3c2bb7a4e4278ba
parent 207793 75893b6e88ac9ef78206d81d9cac101c9221f628
child 207795 aaea56c38e4598a477e42e1b9882d7171f1e71a7
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgcp, lmandel
bugs979716
milestone32.0a2
Bug 979716: Proxy incoming audio to another thread before calling AppendToTrack() r=gcp a=lmandel
content/media/webrtc/MediaEngineWebRTC.cpp
content/media/webrtc/MediaEngineWebRTC.h
content/media/webrtc/MediaEngineWebRTCAudio.cpp
--- a/content/media/webrtc/MediaEngineWebRTC.cpp
+++ b/content/media/webrtc/MediaEngineWebRTC.cpp
@@ -58,16 +58,19 @@ MediaEngineWebRTC::MediaEngineWebRTC(Med
   if (compMgr) {
     compMgr->IsContractIDRegistered(NS_TABSOURCESERVICE_CONTRACTID, &mHasTabVideoSource);
   }
 #else
   AsyncLatencyLogger::Get()->AddRef();
 #endif
   // XXX
   gFarendObserver = new AudioOutputObserver();
+
+  NS_NewNamedThread("AudioGUM", getter_AddRefs(mThread));
+  MOZ_ASSERT(mThread);
 }
 
 void
 MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >* aVSources)
 {
 #ifdef MOZ_B2G_CAMERA
   MutexAutoLock lock(mMutex);
 
@@ -287,17 +290,17 @@ MediaEngineWebRTC::EnumerateAudioDevices
 
     nsRefPtr<MediaEngineWebRTCAudioSource> aSource;
     NS_ConvertUTF8toUTF16 uuid(uniqueId);
     if (mAudioSources.Get(uuid, getter_AddRefs(aSource))) {
       // We've already seen this device, just append.
       aASources->AppendElement(aSource.get());
     } else {
       aSource = new MediaEngineWebRTCAudioSource(
-        mVoiceEngine, i, deviceName, uniqueId
+        mThread, mVoiceEngine, i, deviceName, uniqueId
       );
       mAudioSources.Put(uuid, aSource); // Hashtable takes ownership.
       aASources->AppendElement(aSource);
     }
   }
 }
 
 void
@@ -316,11 +319,16 @@ MediaEngineWebRTC::Shutdown()
   if (mVoiceEngine) {
     mAudioSources.Clear();
     mVoiceEngine->SetTraceCallback(nullptr);
     webrtc::VoiceEngine::Delete(mVoiceEngine);
   }
 
   mVideoEngine = nullptr;
   mVoiceEngine = nullptr;
+
+  if (mThread) {
+    mThread->Shutdown();
+    mThread = nullptr;
+  }
 }
 
 }
--- a/content/media/webrtc/MediaEngineWebRTC.h
+++ b/content/media/webrtc/MediaEngineWebRTC.h
@@ -260,20 +260,21 @@ private:
   void GuessCapability(const VideoTrackConstraintsN &aConstraints,
                        const MediaEnginePrefs &aPrefs);
 };
 
 class MediaEngineWebRTCAudioSource : public MediaEngineAudioSource,
                                      public webrtc::VoEMediaProcess
 {
 public:
-  MediaEngineWebRTCAudioSource(webrtc::VoiceEngine* aVoiceEnginePtr, int aIndex,
-    const char* name, const char* uuid)
+  MediaEngineWebRTCAudioSource(nsIThread *aThread, webrtc::VoiceEngine* aVoiceEnginePtr,
+                               int aIndex, const char* name, const char* uuid)
     : mVoiceEngine(aVoiceEnginePtr)
     , mMonitor("WebRTCMic.Monitor")
+    , mThread(aThread)
     , mCapIndex(aIndex)
     , mChannel(-1)
     , mInitDone(false)
     , mStarted(false)
     , mSamples(0)
     , mEchoOn(false), mAgcOn(false), mNoiseOn(false)
     , mEchoCancel(webrtc::kEcDefault)
     , mAGC(webrtc::kAgcDefault)
@@ -333,16 +334,17 @@ private:
   ScopedCustomReleasePtr<webrtc::VoEAudioProcessing> mVoEProcessing;
   ScopedCustomReleasePtr<webrtc::VoECallReport> mVoECallReport;
 
   // 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<SourceMediaStream *> mSources; // When this goes empty, we shut down HW
+  nsCOMPtr<nsIThread> mThread;
 
   int mCapIndex;
   int mChannel;
   TrackID mTrackID;
   bool mInitDone;
   bool mStarted;
   int mSamples; // int to avoid conversions when comparing/etc to samplingFreq & length
 
@@ -375,16 +377,18 @@ private:
     Shutdown();
 #ifdef MOZ_B2G_CAMERA
     AsyncLatencyLogger::Get()->Release();
 #endif
     // XXX
     gFarendObserver = nullptr;
   }
 
+  nsCOMPtr<nsIThread> mThread;
+
   Mutex mMutex;
   // protected with mMutex:
 
   webrtc::VideoEngine* mVideoEngine;
   webrtc::VoiceEngine* mVoiceEngine;
 
   // Need this to avoid unneccesary WebRTC calls while enumerating.
   bool mVideoEngineInit;
--- a/content/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/content/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaEngineWebRTC.h"
 #include <stdio.h>
 #include <algorithm>
 #include "mozilla/Assertions.h"
 #include "MediaTrackConstraints.h"
+#include "mtransport/runnable_utils.h"
 
 // scoped_ptr.h uses FF
 #ifdef FF
 #undef FF
 #endif
 #include "webrtc/modules/audio_device/opensl/single_rw_fifo.h"
 
 #define CHANNELS 1
@@ -564,32 +565,35 @@ MediaEngineWebRTCAudioSource::Process(in
 
   uint32_t len = mSources.Length();
   for (uint32_t i = 0; i < len; i++) {
     nsRefPtr<SharedBuffer> buffer = SharedBuffer::Create(length * sizeof(sample));
 
     sample* dest = static_cast<sample*>(buffer->Data());
     memcpy(dest, audio10ms, length * sizeof(sample));
 
-    AudioSegment segment;
+    nsAutoPtr<AudioSegment> segment(new AudioSegment());
     nsAutoTArray<const sample*,1> channels;
     channels.AppendElement(dest);
-    segment.AppendFrames(buffer.forget(), channels, length);
+    segment->AppendFrames(buffer.forget(), channels, length);
     TimeStamp insertTime;
-    segment.GetStartTime(insertTime);
+    segment->GetStartTime(insertTime);
 
-    SourceMediaStream *source = mSources[i];
-    if (source) {
+    if (mSources[i]) {
+      // Make sure we include the stream and the track.
+      // The 0:1 is a flag to note when we've done the final insert for a given input block.
+      LogTime(AsyncLatencyLogger::AudioTrackInsertion, LATENCY_STREAM_ID(mSources[i], mTrackID),
+              (i+1 < len) ? 0 : 1, insertTime);
+
       // This is safe from any thread, and is safe if the track is Finished
       // or Destroyed.
-      // Make sure we include the stream and the track.
-      // The 0:1 is a flag to note when we've done the final insert for a given input block.
-      LogTime(AsyncLatencyLogger::AudioTrackInsertion, LATENCY_STREAM_ID(source, mTrackID),
-              (i+1 < len) ? 0 : 1, insertTime);
-
-      source->AppendToTrack(mTrackID, &segment);
+      // Note: due to evil magic, the nsAutoPtr<AudioSegment>'s ownership transfers to
+      // the Runnable (AutoPtr<> = AutoPtr<>)
+      RUN_ON_THREAD(mThread, WrapRunnable(mSources[i], &SourceMediaStream::AppendToTrack,
+                                          mTrackID, segment, (AudioSegment *) nullptr),
+                    NS_DISPATCH_NORMAL);
     }
   }
 
   return;
 }
 
 }