Bug 1404977 - Part 9 - Propagate the changes to the GraphDrivers, simplifying them, and brokering all access through the MSG. r=pehrsons

For an AudioCallbackDriver, the number of input channels is immutable, and
passed at construction, so that it's less necessary to rely on global state.

MozReview-Commit-ID: F9TL1H92z3W

--HG--
extra : rebase_source : 5193488592ca97273eb2b6f43d4c7a0e4beb0a33
This commit is contained in:
Paul Adenot 2018-04-30 16:01:56 +02:00
Родитель 064d4d9b47
Коммит 6622a3551d
3 изменённых файлов: 78 добавлений и 109 удалений

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

@ -74,7 +74,14 @@ void GraphDriver::SwitchAtNextIteration(GraphDriver* aNextDriver)
aNextDriver,
aNextDriver->AsAudioCallbackDriver() ? "AudioCallbackDriver"
: "SystemClockDriver"));
if (mNextDriver &&
mNextDriver != GraphImpl()->CurrentDriver()) {
LOG(LogLevel::Debug,
("Discarding previous next driver: %p (%s)",
mNextDriver.get(),
mNextDriver->AsAudioCallbackDriver() ? "AudioCallbackDriver"
: "SystemClockDriver"));
}
SetNextDriver(aNextDriver);
}
@ -538,19 +545,17 @@ StreamAndPromiseForOperation::StreamAndPromiseForOperation(MediaStream* aStream,
// MOZ_ASSERT(aPromise);
}
AudioCallbackDriver::AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl)
AudioCallbackDriver::AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl, uint32_t aInputChannelCount)
: GraphDriver(aGraphImpl)
, mOutputChannels(0)
, mSampleRate(0)
, mInputChannels(1)
, mInputChannelCount(aInputChannelCount)
, mIterationDurationMS(MEDIA_GRAPH_TARGET_PERIOD_MS)
, mStarted(false)
, mAudioInput(nullptr)
, mInitShutdownThread(SharedThreadPool::Get(NS_LITERAL_CSTRING("CubebOperation"), 1))
, mAddedMixer(false)
, mAudioThreadId(std::thread::id())
, mAudioThreadRunning(false)
, mMicrophoneActive(false)
, mShouldFallbackIfError(false)
, mFromFallback(false)
{
@ -637,7 +642,7 @@ AudioCallbackDriver::Init()
}
// Query and set the number of channels this AudioCallbackDriver will use.
mOutputChannels = mGraphImpl->AudioChannelCount();
mOutputChannels = GraphImpl()->AudioOutputChannelCount();
if (!mOutputChannels) {
LOG(LogLevel::Warning, ("Output number of channels is 0."));
MonitorAutoLock lock(GraphImpl()->GetMonitor());
@ -661,81 +666,62 @@ AudioCallbackDriver::Init()
}
input = output;
input.channels = mInputChannels;
input.channels = mInputChannelCount;
input.layout = CUBEB_LAYOUT_UNDEFINED;
#ifdef MOZ_WEBRTC
if (mGraphImpl->mInputWanted) {
StaticMutexAutoLock lock(AudioInputCubeb::Mutex());
uint32_t userChannels = 0;
AudioInputCubeb::GetUserChannelCount(mGraphImpl->mInputDeviceID, userChannels);
input.channels = mInputChannels = std::min<uint32_t>(8, userChannels);
}
#endif
cubeb_stream* stream = nullptr;
CubebUtils::AudioDeviceID input_id = nullptr, output_id = nullptr;
// We have to translate the deviceID values to cubeb devid's since those can be
// freed whenever enumerate is called.
{
#ifdef MOZ_WEBRTC
StaticMutexAutoLock lock(AudioInputCubeb::Mutex());
#endif
if ((!mGraphImpl->mInputWanted
#ifdef MOZ_WEBRTC
|| AudioInputCubeb::GetDeviceID(mGraphImpl->mInputDeviceID, input_id)
#endif
) &&
(mGraphImpl->mOutputDeviceID == -1 // pass nullptr for ID for default output
#ifdef MOZ_WEBRTC
// XXX we should figure out how we would use a deviceID for output without webrtc.
// Currently we don't set this though, so it's ok
|| AudioInputCubeb::GetDeviceID(mGraphImpl->mOutputDeviceID, output_id)
#endif
) &&
// XXX Only pass input input if we have an input listener. Always
// set up output because it's easier, and it will just get silence.
// XXX Add support for adding/removing an input listener later.
cubeb_stream_init(cubebContext, &stream,
"AudioCallbackDriver",
input_id,
mGraphImpl->mInputWanted ? &input : nullptr,
output_id,
mGraphImpl->mOutputWanted ? &output : nullptr, latency_frames,
DataCallback_s, StateCallback_s, this) == CUBEB_OK) {
mAudioStream.own(stream);
DebugOnly<int> rv = cubeb_stream_set_volume(mAudioStream, CubebUtils::GetVolumeScale());
NS_WARNING_ASSERTION(
rv == CUBEB_OK,
"Could not set the audio stream volume in GraphDriver.cpp");
CubebUtils::ReportCubebBackendUsed();
} else {
#ifdef MOZ_WEBRTC
StaticMutexAutoUnlock unlock(AudioInputCubeb::Mutex());
#endif
NS_WARNING("Could not create a cubeb stream for MediaStreamGraph, falling back to a SystemClockDriver");
// Only report failures when we're not coming from a driver that was
// created itself as a fallback driver because of a previous audio driver
// failure.
if (!mFromFallback) {
CubebUtils::ReportCubebStreamInitFailure(firstStream);
}
MonitorAutoLock lock(GraphImpl()->GetMonitor());
FallbackToSystemClockDriver();
return true;
bool inputWanted = mInputChannelCount > 0;
CubebUtils::AudioDeviceID output_id = GraphImpl()->mOutputDeviceID;
CubebUtils::AudioDeviceID input_id = GraphImpl()->mInputDeviceID;
// XXX Only pass input input if we have an input listener. Always
// set up output because it's easier, and it will just get silence.
if (cubeb_stream_init(cubebContext,
&stream,
"AudioCallbackDriver",
input_id,
inputWanted ? &input : nullptr,
output_id,
&output,
latency_frames,
DataCallback_s,
StateCallback_s,
this) == CUBEB_OK) {
mAudioStream.own(stream);
DebugOnly<int> rv =
cubeb_stream_set_volume(mAudioStream, CubebUtils::GetVolumeScale());
NS_WARNING_ASSERTION(
rv == CUBEB_OK,
"Could not set the audio stream volume in GraphDriver.cpp");
CubebUtils::ReportCubebBackendUsed();
} else {
NS_WARNING("Could not create a cubeb stream for MediaStreamGraph, falling "
"back to a SystemClockDriver");
// Only report failures when we're not coming from a driver that was
// created itself as a fallback driver because of a previous audio driver
// failure.
if (!mFromFallback) {
CubebUtils::ReportCubebStreamInitFailure(firstStream);
}
MonitorAutoLock lock(GraphImpl()->GetMonitor());
FallbackToSystemClockDriver();
return true;
}
SetMicrophoneActive(mGraphImpl->mInputWanted);
cubeb_stream_register_device_changed_callback(mAudioStream,
AudioCallbackDriver::DeviceChangedCallback_s);
#ifdef XP_MACOSX
PanOutputIfNeeded(inputWanted);
#endif
cubeb_stream_register_device_changed_callback(
mAudioStream, AudioCallbackDriver::DeviceChangedCallback_s);
if (!StartStream()) {
LOG(LogLevel::Warning, ("AudioCallbackDriver couldn't start stream."));
LOG(LogLevel::Warning, ("%p: AudioCallbackDriver couldn't start a cubeb stream.", GraphImpl()));
return false;
}
LOG(LogLevel::Debug, ("AudioCallbackDriver started."));
LOG(LogLevel::Debug, ("%p: AudioCallbackDriver started.", GraphImpl()));
return true;
}
@ -1150,21 +1136,9 @@ AudioCallbackDriver::DeviceChangedCallback()
// Tell the audio engine the device has changed, it might want to reset some
// state.
MonitorAutoLock mon(mGraphImpl->GetMonitor());
if (mAudioInput) {
mAudioInput->DeviceChanged();
}
GraphImpl()->DeviceChanged();
#ifdef XP_MACOSX
PanOutputIfNeeded(mMicrophoneActive);
#endif
}
void
AudioCallbackDriver::SetMicrophoneActive(bool aActive)
{
mMicrophoneActive = aActive;
#ifdef XP_MACOSX
PanOutputIfNeeded(mMicrophoneActive);
PanOutputIfNeeded(mInputChannelCount);
#endif
}

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

@ -263,8 +263,7 @@ public:
*/
void RunThread();
friend class MediaStreamGraphInitThreadRunnable;
uint32_t IterationDuration() override
{
uint32_t IterationDuration() override {
return MEDIA_GRAPH_TARGET_PERIOD_MS;
}
@ -400,7 +399,8 @@ class AudioCallbackDriver : public GraphDriver,
#endif
{
public:
explicit AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl);
/** If aInputChannelCount is zero, then this driver is output-only. */
AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl, uint32_t aInputChannelCount);
virtual ~AudioCallbackDriver();
void Start() override;
@ -418,15 +418,16 @@ public:
const void * aInputBuffer,
void * aOutputBuffer,
long aFrames);
static void StateCallback_s(cubeb_stream* aStream, void * aUser,
cubeb_state aState);
static void StateCallback_s(cubeb_stream* aStream, void * aUser, cubeb_state aState);
static void DeviceChangedCallback_s(void * aUser);
/* This function is called by the underlying audio backend when a refill is
* needed. This is what drives the whole graph when it is used to output
* audio. If the return value is exactly aFrames, this function will get
* called again. If it is less than aFrames, the stream will go in draining
* mode, and this function will not be called again. */
long DataCallback(const AudioDataValue* aInputBuffer, AudioDataValue* aOutputBuffer, long aFrames);
long DataCallback(const AudioDataValue* aInputBuffer,
AudioDataValue* aOutputBuffer,
long aFrames);
/* This function is called by the underlying audio backend, but is only used
* for informational purposes at the moment. */
void StateCallback(cubeb_state aState);
@ -463,6 +464,11 @@ public:
return mOutputChannels;
}
uint32_t InputChannelCount()
{
return mInputChannelCount;
}
/* Enqueue a promise that is going to be resolved when a specific operation
* occurs on the cubeb stream. */
void EnqueueStreamAndPromiseForOperation(MediaStream* aStream,
@ -483,10 +489,6 @@ public:
* mStarted for details. */
bool IsStarted();
/* Tell the driver whether this process is using a microphone or not. This is
* thread safe. */
void SetMicrophoneActive(bool aActive);
void CompleteAudioContextOperations(AsyncCubebOperation aOperation);
private:
@ -536,9 +538,9 @@ private:
/* The sample rate for the aforementionned cubeb stream. This is set on
* initialization and can be read safely afterwards. */
uint32_t mSampleRate;
/* The number of input channels from cubeb. Should be set before opening cubeb
* and then be static. */
uint32_t mInputChannels;
/* The number of input channels from cubeb. Set before opening cubeb. If it is
* zero then the driver is output-only. */
const uint32_t mInputChannelCount;
/* Approximation of the time between two callbacks. This is used to schedule
* video frames. This is in milliseconds. Only even used (after
* inizatialization) on the audio callback thread. */
@ -558,8 +560,6 @@ private:
* This is synchronized by the Graph's monitor.
* */
Atomic<bool> mStarted;
/* Listener for mic input, if any. */
RefPtr<AudioDataListener> mAudioInput;
struct AutoInCallback
{
@ -585,10 +585,6 @@ private:
/* True when audio thread is running. False before
* starting and after stopping it the audio thread. */
Atomic<bool> mAudioThreadRunning;
/**
* True if microphone is being used by this process. This is synchronized by
* the graph's monitor. */
Atomic<bool> mMicrophoneActive;
/* Indication of whether a fallback SystemClockDriver should be started if
* StateCallback() receives an error. No mutex need be held during access.
* The transition to true happens before cubeb_stream_start() is called.

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

@ -411,7 +411,7 @@ MediaStreamGraphImpl::UpdateStreamOrder()
!switching) {
MonitorAutoLock mon(mMonitor);
if (LifecycleStateRef() == LIFECYCLE_RUNNING) {
AudioCallbackDriver* driver = new AudioCallbackDriver(this);
AudioCallbackDriver* driver = new AudioCallbackDriver(this, AudioInputChannelCount());
CurrentDriver()->SwitchAtNextIteration(driver);
}
}
@ -666,7 +666,7 @@ MediaStreamGraphImpl::CreateOrDestroyAudioStreams(MediaStream* aStream)
!switching) {
MonitorAutoLock mon(mMonitor);
if (LifecycleStateRef() == LIFECYCLE_RUNNING) {
AudioCallbackDriver* driver = new AudioCallbackDriver(this);
AudioCallbackDriver* driver = new AudioCallbackDriver(this, AudioInputChannelCount());
CurrentDriver()->SwitchAtNextIteration(driver);
}
}
@ -822,8 +822,7 @@ MediaStreamGraphImpl::OpenAudioInputImpl(CubebUtils::AudioDeviceID aID,
AudioCallbackDriver* driver = new AudioCallbackDriver(this, AudioInputChannelCount());
LOG(
LogLevel::Debug,
("OpenAudioInput: starting new AudioCallbackDriver(input) %p", driver));
driver->SetInputListener(aListener);
("%p OpenAudioInput: starting new AudioCallbackDriver(input) %p", this, driver));
CurrentDriver()->SwitchAtNextIteration(driver);
} else {
LOG(LogLevel::Error, ("OpenAudioInput in shutdown!"));
@ -3668,8 +3667,8 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
{
if (mRealtime) {
if (aDriverRequested == AUDIO_THREAD_DRIVER) {
AudioCallbackDriver* driver = new AudioCallbackDriver(this);
mDriver = driver;
// Always start with zero input channels.
mDriver = new AudioCallbackDriver(this, 0);
} else {
mDriver = new SystemClockDriver(this);
}
@ -4198,7 +4197,7 @@ MediaStreamGraphImpl::ApplyAudioContextOperationImpl(
MOZ_ASSERT(nextDriver->AsAudioCallbackDriver());
driver = nextDriver->AsAudioCallbackDriver();
} else {
driver = new AudioCallbackDriver(this);
driver = new AudioCallbackDriver(this, AudioInputChannelCount());
MonitorAutoLock lock(mMonitor);
CurrentDriver()->SwitchAtNextIteration(driver);
}