Bug 1266438 - Reset the AEC and other processing when audio devices change. r=jesup

MozReview-Commit-ID: Jrr9E9ZSukv
This commit is contained in:
Paul Adenot 2016-04-22 16:24:17 +02:00
parent 6edc6b4ddd
commit b3adcea90b
7 changed files with 69 additions and 34 deletions

View File

@ -23,7 +23,7 @@ extern mozilla::LazyLogModule gMediaStreamGraphLog;
// We don't use NSPR log here because we want this interleaved with adb logcat
// on Android/B2G
// #define ENABLE_LIFECYCLE_LOG
#define ENABLE_LIFECYCLE_LOG
#ifdef ENABLE_LIFECYCLE_LOG
#ifdef ANDROID
#include "android/log.h"
@ -660,12 +660,9 @@ AudioCallbackDriver::Init()
return;
}
}
#ifdef XP_MACOSX
// Currently, only mac cares about this
bool aec;
Unused << mGraphImpl->AudioTrackPresent(aec);
SetMicrophoneActive(aec);
#endif
cubeb_stream_register_device_changed_callback(mAudioStream,
AudioCallbackDriver::DeviceChangedCallback_s);
@ -1070,34 +1067,14 @@ void AudioCallbackDriver::PanOutputIfNeeded(bool aMicrophoneActive)
void
AudioCallbackDriver::DeviceChangedCallback() {
#ifdef XP_MACOSX
// Tell the audio engine the device has changed, it might want to reset some
// state.
MonitorAutoLock mon(mGraphImpl->GetMonitor());
if (mAudioInput) {
mAudioInput->DeviceChanged();
}
#ifdef XP_MACOSX
PanOutputIfNeeded(mMicrophoneActive);
// On OSX, changing the output device causes the audio thread to no call the
// audio callback, so we're unable to process real-time input data, and this
// results in latency building up.
// We switch to a system driver until audio callbacks are called again, so we
// still pull from the input stream, so that everything works apart from the
// audio output.
// Don't bother doing the device switching dance if the graph is not RUNNING
// (starting up, shutting down), because we haven't started pulling from the
// SourceMediaStream.
if (!GraphImpl()->Running()) {
return;
}
if (mSelfReference) {
return;
}
STREAM_LOG(LogLevel::Error, ("Switching to SystemClockDriver during output switch"));
mSelfReference.Take(this);
mCallbackReceivedWhileSwitching = 0;
SetNextDriver(new SystemClockDriver(GraphImpl()));
RemoveCallback();
mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
mGraphImpl->SetCurrentDriver(mNextDriver);
mNextDriver->Start();
#endif
}

View File

@ -530,13 +530,14 @@ private:
/* This is atomic and is set by the audio callback thread. It can be read by
* any thread safely. */
Atomic<bool> mInCallback;
#ifdef XP_MACOSX
/**
* True if microphone is being used by this process. This is synchronized by
* the graph's monitor. */
bool mMicrophoneActive;
#ifdef XP_MACOSX
/* Implements the workaround for the osx audio stack when changing output
* devices. See comments in .cpp */
bool OSXDeviceSwitchingWorkaround();

View File

@ -46,7 +46,7 @@ namespace mozilla {
LazyLogModule gMediaStreamGraphLog("MediaStreamGraph");
#define STREAM_LOG(type, msg) MOZ_LOG(gMediaStreamGraphLog, type, msg)
// #define ENABLE_LIFECYCLE_LOG
#define ENABLE_LIFECYCLE_LOG
// We don't use NSPR log here because we want this interleaved with adb logcat
// on Android/B2G
@ -138,7 +138,7 @@ MediaStreamGraphImpl::RemoveStreamGraphThread(MediaStream* aStream)
}
STREAM_LOG(LogLevel::Debug, ("Removed media stream %p from graph %p, count %lu",
aStream, this, mStreams.Length()))
aStream, this, mStreams.Length()));
LIFECYCLE_LOG("Removed media stream %p from graph %p, count %lu",
aStream, this, mStreams.Length());

View File

@ -209,6 +209,11 @@ public:
virtual void NotifyInputData(MediaStreamGraph* aGraph,
const AudioDataValue* aBuffer, size_t aFrames,
TrackRate aRate, uint32_t aChannels) = 0;
/**
* Called when the underlying audio device has changed.
*/
virtual void DeviceChanged() = 0;
};
class AudioDataListener : public AudioDataListenerInterface {

View File

@ -149,6 +149,8 @@ public:
const AudioDataValue* aBuffer, size_t aFrames,
TrackRate aRate, uint32_t aChannels) override
{}
void DeviceChanged() override
{}
bool IsFake() override {
return true;
}

View File

@ -103,6 +103,8 @@ public:
AudioDataValue* aBuffer, size_t aFrames,
TrackRate aRate, uint32_t aChannels) override
{}
void DeviceChanged() override
{}
void NotifyInputData(MediaStreamGraph* aGraph,
const AudioDataValue* aBuffer, size_t aFrames,
TrackRate aRate, uint32_t aChannels) override
@ -391,6 +393,12 @@ public:
mAudioSource->NotifyInputData(aGraph, aBuffer, aFrames, aRate, aChannels);
}
}
virtual void DeviceChanged() override
{
if (mAudioSource) {
mAudioSource->DeviceChanged();
}
}
void Shutdown()
{
@ -471,6 +479,8 @@ public:
const AudioDataValue* aBuffer, size_t aFrames,
TrackRate aRate, uint32_t aChannels) override;
void DeviceChanged() override;
bool IsFake() override {
return false;
}

View File

@ -499,6 +499,46 @@ MediaEngineWebRTCMicrophoneSource::NotifyInputData(MediaStreamGraph* aGraph,
}
}
#define ResetProcessingIfNeeded(_processing) \
do { \
webrtc::_processing##Modes mode; \
int rv = mVoEProcessing->Get##_processing##Status(enabled, mode); \
if (rv) { \
NS_WARNING("Could not get the status of the " \
#_processing " on device change."); \
return; \
} \
\
if (enabled) { \
rv = mVoEProcessing->Set##_processing##Status(!enabled); \
if (rv) { \
NS_WARNING("Could not reset the status of the " \
#_processing " on device change."); \
return; \
} \
\
rv = mVoEProcessing->Set##_processing##Status(enabled); \
if (rv) { \
NS_WARNING("Could not reset the status of the " \
#_processing " on device change."); \
return; \
} \
} \
} while(0)
void
MediaEngineWebRTCMicrophoneSource::DeviceChanged() {
// Reset some processing
bool enabled;
ResetProcessingIfNeeded(Agc);
ResetProcessingIfNeeded(Ec);
ResetProcessingIfNeeded(Ns);
}
void
MediaEngineWebRTCMicrophoneSource::Init()
{