Bug 1473469 - Make MediaStreamGraph run on a single thread with AudioWorklets enabled. r=padenot

Differential Revision: https://phabricator.services.mozilla.com/D20828

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andreas Pehrson 2019-03-06 20:12:25 +00:00
Родитель aab777d346
Коммит acf9d0ab88
9 изменённых файлов: 334 добавлений и 47 удалений

Просмотреть файл

@ -41,7 +41,7 @@ GraphDriver::GraphDriver(MediaStreamGraphImpl* aGraphImpl)
void GraphDriver::SetGraphTime(GraphDriver* aPreviousDriver,
GraphTime aLastSwitchNextIterationStart,
GraphTime aLastSwitchNextIterationEnd) {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
// We set mIterationEnd here, because the first thing a driver do when it
// does an iteration is to update graph times, so we are in fact setting
@ -63,7 +63,7 @@ void GraphDriver::SetGraphTime(GraphDriver* aPreviousDriver,
}
void GraphDriver::SwitchAtNextIteration(GraphDriver* aNextDriver) {
MOZ_ASSERT(OnThread());
MOZ_ASSERT(OnGraphThread());
MOZ_ASSERT(aNextDriver);
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
@ -87,14 +87,20 @@ GraphTime GraphDriver::StateComputedTime() const {
void GraphDriver::EnsureNextIteration() { GraphImpl()->EnsureNextIteration(); }
#ifdef DEBUG
bool GraphDriver::OnGraphThread() {
return GraphImpl()->RunByGraphDriver(this);
}
#endif
bool GraphDriver::Switching() {
MOZ_ASSERT(OnThread());
MOZ_ASSERT(OnGraphThread());
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
return mNextDriver || mPreviousDriver;
}
void GraphDriver::SwitchToNextDriver() {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
MOZ_ASSERT(NextDriver());
@ -105,19 +111,19 @@ void GraphDriver::SwitchToNextDriver() {
}
GraphDriver* GraphDriver::NextDriver() {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
return mNextDriver;
}
GraphDriver* GraphDriver::PreviousDriver() {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
return mPreviousDriver;
}
void GraphDriver::SetNextDriver(GraphDriver* aNextDriver) {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
MOZ_ASSERT(aNextDriver != this);
MOZ_ASSERT(aNextDriver != mNextDriver);
@ -133,7 +139,7 @@ void GraphDriver::SetNextDriver(GraphDriver* aNextDriver) {
}
void GraphDriver::SetPreviousDriver(GraphDriver* aPreviousDriver) {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
mPreviousDriver = aPreviousDriver;
}
@ -659,7 +665,7 @@ bool AudioCallbackDriver::Init() {
void AudioCallbackDriver::Start() {
MOZ_ASSERT(!IsStarted());
MOZ_ASSERT(NS_IsMainThread() || OnCubebOperationThread() ||
(PreviousDriver() && PreviousDriver()->OnThread()));
(PreviousDriver() && PreviousDriver()->OnGraphThread()));
if (mPreviousDriver) {
if (mPreviousDriver->AsAudioCallbackDriver()) {
LOG(LogLevel::Debug, ("Releasing audio driver off main thread."));
@ -723,7 +729,7 @@ void AudioCallbackDriver::Revive() {
}
void AudioCallbackDriver::RemoveMixerCallback() {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
if (mAddedMixer) {
GraphImpl()->mMixer.RemoveCallback(this);
@ -732,7 +738,7 @@ void AudioCallbackDriver::RemoveMixerCallback() {
}
void AudioCallbackDriver::AddMixerCallback() {
MOZ_ASSERT(OnThread());
MOZ_ASSERT(OnGraphThread());
if (!mAddedMixer) {
mGraphImpl->mMixer.AddCallback(this);
@ -949,7 +955,7 @@ long AudioCallbackDriver::DataCallback(const AudioDataValue* aInputBuffer,
}
void AudioCallbackDriver::StateCallback(cubeb_state aState) {
MOZ_ASSERT(!OnThread());
MOZ_ASSERT(!OnGraphThread());
LOG(LogLevel::Debug, ("AudioCallbackDriver State: %d", aState));
// Clear the flag for the not running
@ -972,7 +978,7 @@ void AudioCallbackDriver::MixerCallback(AudioDataValue* aMixedBuffer,
AudioSampleFormat aFormat,
uint32_t aChannels, uint32_t aFrames,
uint32_t aSampleRate) {
MOZ_ASSERT(OnThread());
MOZ_ASSERT(OnGraphThread());
uint32_t toWrite = mBuffer.Available();
if (!mBuffer.Available()) {
@ -1028,7 +1034,7 @@ void AudioCallbackDriver::PanOutputIfNeeded(bool aMicrophoneActive) {
}
void AudioCallbackDriver::DeviceChangedCallback() {
MOZ_ASSERT(!OnThread());
MOZ_ASSERT(!OnGraphThread());
// Tell the audio engine the device has changed, it might want to reset some
// state.
MonitorAutoLock mon(mGraphImpl->GetMonitor());
@ -1039,7 +1045,7 @@ void AudioCallbackDriver::DeviceChangedCallback() {
}
uint32_t AudioCallbackDriver::IterationDuration() {
MOZ_ASSERT(OnThread());
MOZ_ASSERT(OnGraphThread());
// The real fix would be to have an API in cubeb to give us the number. Short
// of that, we approximate it here. bug 1019507
return mIterationDurationMS;
@ -1050,7 +1056,7 @@ bool AudioCallbackDriver::IsStarted() { return mStarted; }
void AudioCallbackDriver::EnqueueStreamAndPromiseForOperation(
MediaStream* aStream, void* aPromise,
dom::AudioContextOperation aOperation) {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
MonitorAutoLock mon(mGraphImpl->GetMonitor());
mPromisesForOperation.AppendElement(
StreamAndPromiseForOperation(aStream, aPromise, aOperation));

Просмотреть файл

@ -55,12 +55,17 @@ static const int SCHEDULE_SAFETY_MARGIN_MS = 10;
static const int AUDIO_TARGET_MS =
2 * MEDIA_GRAPH_TARGET_PERIOD_MS + SCHEDULE_SAFETY_MARGIN_MS;
class MediaStream;
class MediaStreamGraphImpl;
class AudioCallbackDriver;
class OfflineClockDriver;
class SystemClockDriver;
namespace dom {
enum class AudioContextOperation;
}
/**
* A driver is responsible for the scheduling of the processing, the thread
* management, and give the different clocks to a MediaStreamGraph. This is an
@ -180,18 +185,15 @@ class GraphDriver {
*/
void EnsureNextIteration();
/**
* Same thing, but not locked.
*/
void EnsureNextIterationLocked();
MediaStreamGraphImpl* GraphImpl() const { return mGraphImpl; }
#ifdef DEBUG
// True if the current thread is driving the MSG.
bool OnGraphThread();
#endif
// True if the current thread is the GraphDriver's thread.
// This is the thread that drives the MSG.
virtual bool OnThread() = 0;
// GraphDriver's thread has started and the thread is running.
// This is the thread that drives the MSG.
virtual bool ThreadRunning() = 0;
protected:
@ -251,6 +253,8 @@ class ThreadedDriver : public GraphDriver {
friend class MediaStreamGraphInitThreadRunnable;
uint32_t IterationDuration() override { return MEDIA_GRAPH_TARGET_PERIOD_MS; }
nsIThread* Thread() { return mThread; }
bool OnThread() override {
return !mThread || mThread->EventTarget()->IsOnCurrentThread();
}
@ -412,6 +416,8 @@ class AudioCallbackDriver : public GraphDriver,
MediaStream* aStream, void* aPromise,
dom::AudioContextOperation aOperation);
std::thread::id ThreadId() { return mAudioThreadId.load(); }
bool OnThread() override {
return mAudioThreadId.load() == std::this_thread::get_id();
}

120
dom/media/GraphRunner.cpp Normal file
Просмотреть файл

@ -0,0 +1,120 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "GraphRunner.h"
#include "GraphDriver.h"
#include "MediaStreamGraph.h"
#include "MediaStreamGraphImpl.h"
#include "nsISupportsImpl.h"
#include "prthread.h"
#include "Tracing.h"
namespace mozilla {
static void Start(void* aArg) {
GraphRunner* th = static_cast<GraphRunner*>(aArg);
th->Run();
}
GraphRunner::GraphRunner(MediaStreamGraphImpl* aGraph)
: mMonitor("GraphRunner::mMonitor"),
mGraph(aGraph),
mThread(PR_CreateThread(PR_SYSTEM_THREAD, &Start, this,
PR_PRIORITY_URGENT, PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD, 0)) {
MOZ_COUNT_CTOR(GraphRunner);
}
GraphRunner::~GraphRunner() {
MOZ_COUNT_DTOR(GraphRunner);
#ifdef DEBUG
{
MonitorAutoLock lock(mMonitor);
MOZ_ASSERT(mShutdown);
}
#endif
PR_JoinThread(mThread);
}
void GraphRunner::Shutdown() {
MonitorAutoLock lock(mMonitor);
mShutdown = true;
mMonitor.Notify();
}
bool GraphRunner::OneIteration(GraphTime aStateEnd) {
TRACE_AUDIO_CALLBACK();
MonitorAutoLock lock(mMonitor);
MOZ_ASSERT(!mShutdown);
mStateEnd = aStateEnd;
if (!mStarted) {
mMonitor.Wait();
MOZ_ASSERT(mStarted);
}
#ifdef DEBUG
if (auto audioDriver = mGraph->CurrentDriver()->AsAudioCallbackDriver()) {
mAudioDriverThreadId = audioDriver->ThreadId();
} else if (auto clockDriver =
mGraph->CurrentDriver()->AsSystemClockDriver()) {
mClockDriverThread = clockDriver->Thread();
} else {
MOZ_CRASH("Unknown GraphDriver");
}
#endif
mMonitor.Notify(); // Signal that mStateEnd was updated
mMonitor.Wait(); // Wait for mStillProcessing to update
#ifdef DEBUG
mAudioDriverThreadId = std::thread::id();
mClockDriverThread = nullptr;
#endif
return mStillProcessing;
}
void GraphRunner::Run() {
PR_SetCurrentThreadName("GraphRunner");
MonitorAutoLock lock(mMonitor);
mStarted = true;
mMonitor.Notify(); // Signal that mStarted was set, in case the audio
// callback is already waiting for us
while (true) {
mMonitor.Wait(); // Wait for mStateEnd or mShutdown to update
if (mShutdown) {
break;
}
TRACE();
mStillProcessing = mGraph->OneIterationImpl(mStateEnd);
mMonitor.Notify(); // Signal that mStillProcessing was updated
}
}
bool GraphRunner::OnThread() { return PR_GetCurrentThread() == mThread; }
#ifdef DEBUG
bool GraphRunner::RunByGraphDriver(GraphDriver* aDriver) {
if (!OnThread()) {
return false;
}
if (auto audioDriver = aDriver->AsAudioCallbackDriver()) {
return audioDriver->ThreadId() == mAudioDriverThreadId;
}
if (auto clockDriver = aDriver->AsSystemClockDriver()) {
return clockDriver->Thread() == mClockDriverThread;
}
MOZ_CRASH("Unknown driver");
}
#endif
} // namespace mozilla

88
dom/media/GraphRunner.h Normal file
Просмотреть файл

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#ifndef mozilla_GraphRunner_h
#define mozilla_GraphRunner_h
#include "MediaSegment.h"
#include "mozilla/Monitor.h"
#include <thread>
struct PRThread;
namespace mozilla {
class GraphDriver;
class MediaStreamGraphImpl;
class GraphRunner {
public:
explicit GraphRunner(MediaStreamGraphImpl* aGraph);
~GraphRunner();
/**
* Marks us as shut down and signals mThread, so that it runs until the end.
*/
void Shutdown();
/**
* Signals one iteration of mGraph. Hands aStateEnd over to mThread and runs
* the iteration there.
*/
bool OneIteration(GraphTime aStateEnd);
/**
* Runs mGraph until it shuts down.
*/
void Run();
/**
* Returns true if called on mThread.
*/
bool OnThread();
#ifdef DEBUG
/**
* Returns true if called on mThread, and aDriver was the driver that called
* OneIteration() last.
*/
bool RunByGraphDriver(GraphDriver* aDriver);
#endif
private:
// Monitor used for yielding mThread through Wait(), and scheduling mThread
// through Signal() from a GraphDriver.
Monitor mMonitor;
// The MediaStreamGraph we're running. Weakptr beecause this graph owns us and
// guarantees that our lifetime will not go beyond that of itself.
MediaStreamGraphImpl* const mGraph;
// The thread running mGraph.
PRThread* const mThread;
// GraphTime being handed over to the graph through OneIteration. Protected by
// mMonitor.
GraphTime mStateEnd = 0;
// Reply from mGraph's OneIteration. Protected by mMonitor.
bool mStillProcessing = true;
// True after Shutdown(). Protected by mMonitor.
bool mShutdown = false;
// True after mThread has started running and has entered its main loop.
// Protected by mMonitor.
bool mStarted = false;
#ifdef DEBUG
// Set to mGraph's audio callback driver's thread id, if run by an
// AudioCallbackDriver, while OneIteration() is running.
std::thread::id mAudioDriverThreadId = std::thread::id();
// Set to mGraph's system clock driver's thread, if run by a
// SystemClockDriver, while OneIteration() is running.
nsIThread* mClockDriverThread = nullptr;
#endif
};
} // namespace mozilla
#endif

Просмотреть файл

@ -32,6 +32,7 @@
#include "mozilla/Unused.h"
#include "mtransport/runnable_utils.h"
#include "VideoUtils.h"
#include "GraphRunner.h"
#include "Tracing.h"
#include "webaudio/blink/DenormalDisabler.h"
@ -1011,22 +1012,20 @@ void MediaStreamGraphImpl::ReevaluateInputDevice() {
}
}
bool MediaStreamGraph::OnGraphThreadOrNotRunning() const {
bool MediaStreamGraphImpl::OnGraphThreadOrNotRunning() const {
// either we're on the right thread (and calling CurrentDriver() is safe),
// or we're going to fail the assert anyway, so don't cross-check
// via CurrentDriver().
MediaStreamGraphImpl const* graph =
static_cast<MediaStreamGraphImpl const*>(this);
return graph->mDetectedNotRunning ? NS_IsMainThread()
: graph->mDriver->OnThread();
return mDetectedNotRunning ? NS_IsMainThread() : OnGraphThread();
}
bool MediaStreamGraph::OnGraphThread() const {
bool MediaStreamGraphImpl::OnGraphThread() const {
// we're on the right thread (and calling mDriver is safe),
MediaStreamGraphImpl const* graph =
static_cast<MediaStreamGraphImpl const*>(this);
MOZ_ASSERT(graph->mDriver);
return graph->mDriver->OnThread();
MOZ_ASSERT(mDriver);
if (mGraphRunner && mGraphRunner->OnThread()) {
return true;
}
return mDriver->OnThread();
}
bool MediaStreamGraphImpl::ShouldUpdateMainThread() {
@ -1379,13 +1378,23 @@ bool MediaStreamGraphImpl::UpdateMainThreadState() {
}
bool MediaStreamGraphImpl::OneIteration(GraphTime aStateEnd) {
if (mGraphRunner) {
return mGraphRunner->OneIteration(aStateEnd);
}
return OneIterationImpl(aStateEnd);
}
bool MediaStreamGraphImpl::OneIterationImpl(GraphTime aStateEnd) {
TRACE_AUDIO_CALLBACK();
// Changes to LIFECYCLE_RUNNING occur before starting or reviving the graph
// thread, and so the monitor need not be held to check mLifecycleState.
// LIFECYCLE_THREAD_NOT_STARTED is possible when shutting down offline
// graphs that have not started.
MOZ_DIAGNOSTIC_ASSERT(mLifecycleState <= LIFECYCLE_RUNNING);
MOZ_ASSERT(OnGraphThread());
WebCore::DenormalDisabler disabler;
// Process graph message from the main thread for this iteration.
@ -1499,6 +1508,10 @@ class MediaStreamGraphShutDownRunnable : public Runnable {
}
#endif
if (mGraph->mGraphRunner) {
mGraph->mGraphRunner->Shutdown();
}
mGraph->mDriver
->Shutdown(); // This will wait until it's shutdown since
// we'll start tearing down the graph after this
@ -3160,9 +3173,12 @@ void ProcessedMediaStream::DestroyImpl() {
}
MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
GraphRunType aRunTypeRequested,
TrackRate aSampleRate,
AbstractThread* aMainThread)
: MediaStreamGraph(aSampleRate),
mGraphRunner(aRunTypeRequested == SINGLE_THREAD ? new GraphRunner(this)
: nullptr),
mFirstCycleBreaker(0)
// An offline graph is not initially processing.
,
@ -3217,6 +3233,13 @@ AbstractThread* MediaStreamGraph::AbstractMainThread() {
return static_cast<MediaStreamGraphImpl*>(this)->mAbstractMainThread;
}
#ifdef DEBUG
bool MediaStreamGraphImpl::RunByGraphDriver(GraphDriver* aDriver) {
return aDriver->OnThread() ||
(mGraphRunner && mGraphRunner->RunByGraphDriver(aDriver));
}
#endif
void MediaStreamGraphImpl::Destroy() {
// First unregister from memory reporting.
UnregisterWeakMemoryReporter(this);
@ -3298,8 +3321,14 @@ MediaStreamGraph* MediaStreamGraph::GetInstance(
// Uncommon case, only for some old configuration of webspeech.
mainThread = AbstractThread::MainThread();
}
graph =
new MediaStreamGraphImpl(aGraphDriverRequested, sampleRate, mainThread);
GraphRunType runType = DIRECT_DRIVER;
if (aGraphDriverRequested != OFFLINE_THREAD_DRIVER &&
Preferences::GetBool("dom.audioworklet.enabled", false)) {
runType = SINGLE_THREAD;
}
graph = new MediaStreamGraphImpl(aGraphDriverRequested, runType, sampleRate,
mainThread);
uint32_t hashkey = WindowToHash(aWindow, sampleRate);
gGraphs.Put(hashkey, graph);
@ -3316,7 +3345,7 @@ MediaStreamGraph* MediaStreamGraph::CreateNonRealtimeInstance(
MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
MediaStreamGraphImpl* graph = new MediaStreamGraphImpl(
OFFLINE_THREAD_DRIVER, aSampleRate,
OFFLINE_THREAD_DRIVER, DIRECT_DRIVER, aSampleRate,
aWindow->AsGlobal()->AbstractMainThreadFor(TaskCategory::Other));
LOG(LogLevel::Debug, ("Starting up Offline MediaStreamGraph %p", graph));

Просмотреть файл

@ -1205,6 +1205,14 @@ class MediaStreamGraph {
SYSTEM_THREAD_DRIVER,
OFFLINE_THREAD_DRIVER
};
// A MediaStreamGraph running an AudioWorklet must always be run from the
// same thread, in order to run js. To acheive this, create the graph with
// a SINGLE_THREAD RunType. DIRECT_DRIVER will run the graph directly off
// the GraphDriver's thread.
enum GraphRunType {
DIRECT_DRIVER,
SINGLE_THREAD,
};
static const uint32_t AUDIO_CALLBACK_DRIVER_SHUTDOWN_TIMEOUT = 20 * 1000;
static const TrackRate REQUEST_DEFAULT_SAMPLE_RATE = 0;
@ -1324,8 +1332,8 @@ class MediaStreamGraph {
// Intended only for assertions, either on graph thread or not running (in
// which case we must be on the main thread).
bool OnGraphThreadOrNotRunning() const;
bool OnGraphThread() const;
virtual bool OnGraphThreadOrNotRunning() const = 0;
virtual bool OnGraphThread() const = 0;
/**
* Sample rate at which this graph runs. For real time graphs, this is

Просмотреть файл

@ -31,6 +31,7 @@ class ShutdownTicket;
template <typename T>
class LinkedList;
class GraphRunner;
/**
* A per-stream update message passed from the media graph thread to the
@ -109,8 +110,22 @@ class MediaStreamGraphImpl : public MediaStreamGraph,
* implement OfflineAudioContext. They do not support MediaStream inputs.
*/
explicit MediaStreamGraphImpl(GraphDriverType aGraphDriverRequested,
GraphRunType aRunTypeRequested,
TrackRate aSampleRate, AbstractThread* aWindow);
// Intended only for assertions, either on graph thread or not running (in
// which case we must be on the main thread).
bool OnGraphThreadOrNotRunning() const override;
bool OnGraphThread() const override;
#ifdef DEBUG
/**
* True if we're on aDriver's thread, or if we're on mGraphRunner's thread
* and mGraphRunner is currently run by aDriver.
*/
bool RunByGraphDriver(GraphDriver* aDriver);
#endif
/**
* Unregisters memory reporting and deletes this instance. This should be
* called instead of calling the destructor directly.
@ -180,10 +195,18 @@ class MediaStreamGraphImpl : public MediaStreamGraph,
bool UpdateMainThreadState();
/**
* Returns true if this MediaStreamGraph should keep running
* Proxy method called by GraphDriver to iterate the graph.
* If this graph was created with GraphRunType SINGLE_THREAD, mGraphRunner
* will take care of calling OneIterationImpl from its thread. Otherwise,
* OneIterationImpl is called directly.
*/
bool OneIteration(GraphTime aStateEnd);
/**
* Returns true if this MediaStreamGraph should keep running
*/
bool OneIterationImpl(GraphTime aStateEnd);
/**
* Called from the driver, when the graph thread is about to stop, to tell
* the main thread to attempt to begin cleanup. The main thread may either
@ -242,7 +265,7 @@ class MediaStreamGraphImpl : public MediaStreamGraph,
void UpdateGraph(GraphTime aEndBlockingDecisions);
void SwapMessageQueues() {
MOZ_ASSERT(CurrentDriver()->OnThread());
MOZ_ASSERT(OnGraphThread());
MOZ_ASSERT(mFrontMessageQueue.IsEmpty());
mMonitor.AssertCurrentThreadOwns();
mFrontMessageQueue.SwapElements(mBackMessageQueue);
@ -504,7 +527,7 @@ class MediaStreamGraphImpl : public MediaStreamGraph,
* We can also switch from Revive() (on MainThread). Monitor must be held.
*/
void SetCurrentDriver(GraphDriver* aDriver) {
MOZ_ASSERT(mDriver->OnThread() || !mDriver->ThreadRunning());
MOZ_ASSERT(RunByGraphDriver(mDriver) || !mDriver->ThreadRunning());
#ifdef DEBUG
mMonitor.AssertCurrentThreadOwns();
#endif
@ -588,7 +611,13 @@ class MediaStreamGraphImpl : public MediaStreamGraph,
StreamSet AllStreams() { return StreamSet(*this); }
// Data members
//
/*
* If set, the GraphRunner class handles handing over data from audio
* callbacks to a common single thread, shared across GraphDrivers.
*/
const UniquePtr<GraphRunner> mGraphRunner;
/**
* Graphs own owning references to their driver, until shutdown. When a driver
* switch occur, previous driver is either deleted, or it's ownership is

Просмотреть файл

@ -240,6 +240,7 @@ UNIFIED_SOURCES += [
'FileMediaResource.cpp',
'GetUserMediaRequest.cpp',
'GraphDriver.cpp',
'GraphRunner.cpp',
'ImageToI420.cpp',
'MediaCache.cpp',
'MediaContainerType.cpp',

Просмотреть файл

@ -654,7 +654,7 @@ AudioInputProcessing::AudioInputProcessing(
void AudioInputProcessing::Disconnect(MediaStreamGraphImpl* aGraph) {
// This method is just for asserts.
MOZ_ASSERT(aGraph->CurrentDriver()->OnThread());
MOZ_ASSERT(aGraph->OnGraphThread());
}
void MediaEngineWebRTCMicrophoneSource::Shutdown() {
@ -671,7 +671,7 @@ void MediaEngineWebRTCMicrophoneSource::Shutdown() {
}
bool AudioInputProcessing::PassThrough(MediaStreamGraphImpl* aGraph) const {
MOZ_ASSERT(aGraph->CurrentDriver()->OnThread());
MOZ_ASSERT(aGraph->OnGraphThread());
return mSkipProcessing;
}
@ -851,7 +851,7 @@ void AudioInputProcessing::NotifyOutputData(MediaStreamGraphImpl* aGraph,
AudioDataValue* aBuffer,
size_t aFrames, TrackRate aRate,
uint32_t aChannels) {
MOZ_ASSERT(aGraph->CurrentDriver()->OnThread());
MOZ_ASSERT(aGraph->OnGraphThread());
MOZ_ASSERT(mEnabled);
if (!mPacketizerOutput || mPacketizerOutput->PacketSize() != aRate / 100u ||
@ -1096,7 +1096,7 @@ void AudioInputProcessing::NotifyInputData(MediaStreamGraphImpl* aGraph,
const AudioDataValue* aBuffer,
size_t aFrames, TrackRate aRate,
uint32_t aChannels) {
MOZ_ASSERT(aGraph->CurrentDriver()->OnThread());
MOZ_ASSERT(aGraph->OnGraphThread());
TRACE_AUDIO_CALLBACK();
MOZ_ASSERT(mEnabled);
@ -1132,7 +1132,7 @@ void AudioInputProcessing::NotifyInputData(MediaStreamGraphImpl* aGraph,
} while (0)
void AudioInputProcessing::DeviceChanged(MediaStreamGraphImpl* aGraph) {
MOZ_ASSERT(aGraph->CurrentDriver()->OnThread());
MOZ_ASSERT(aGraph->OnGraphThread());
// Reset some processing
ResetProcessingIfNeeded(gain_control);
ResetProcessingIfNeeded(echo_cancellation);