зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
102dbec90b
Коммит
1b78f72fe7
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/* -*- 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);
|
||||
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;
|
||||
|
||||
#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() {
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
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
|
|
@ -0,0 +1,85 @@
|
|||
/* -*- 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;
|
||||
|
||||
#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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче