Bug 979716: Proxy incoming audio to another thread before calling AppendToTrack() r=gcp a=lmandel
--- 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;
}
}