Bug 1245216: Fix getUserMedia input in full_duplex mode coming from the wrong place r?padenot
Also cleanup of an leftover overrridden interface, and re-add a line lost in merges
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -47,17 +47,16 @@ struct AutoProfilerUnregisterThread
}
};
GraphDriver::GraphDriver(MediaStreamGraphImpl* aGraphImpl)
: mIterationStart(0),
mIterationEnd(0),
mGraphImpl(aGraphImpl),
mWaitState(WAITSTATE_RUNNING),
- mAudioInput(nullptr),
mCurrentTimeStamp(TimeStamp::Now()),
mPreviousDriver(nullptr),
mNextDriver(nullptr)
{ }
void GraphDriver::SetGraphTime(GraphDriver* aPreviousDriver,
GraphTime aLastSwitchNextIterationStart,
GraphTime aLastSwitchNextIterationEnd)
@@ -541,16 +540,17 @@ StreamAndPromiseForOperation::StreamAndP
, mOperation(aOperation)
{
// MOZ_ASSERT(aPromise);
}
AudioCallbackDriver::AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl)
: GraphDriver(aGraphImpl)
, mSampleRate(0)
+ , mInputChannels(1)
, mIterationDurationMS(MEDIA_GRAPH_TARGET_PERIOD_MS)
, mStarted(false)
, mAudioInput(nullptr)
, mAudioChannel(aGraphImpl->AudioChannel())
, mAddedMixer(false)
, mInCallback(false)
, mMicrophoneActive(false)
#ifdef XP_MACOSX
@@ -599,17 +599,17 @@ AudioCallbackDriver::Init()
}
if (cubeb_get_min_latency(CubebUtils::GetCubebContext(), output, &latency) != CUBEB_OK) {
NS_WARNING("Could not get minimal latency from cubeb.");
return;
}
input = output;
- input.channels = 1; // change to support optional stereo capture
+ input.channels = mInputChannels; // change to support optional stereo capture
cubeb_stream* stream;
// 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.
if (cubeb_stream_init(CubebUtils::GetCubebContext(), &stream,
"AudioCallbackDriver",
mGraphImpl->mInputDeviceID,
@@ -924,17 +924,17 @@ AudioCallbackDriver::DataCallback(const
mGraphImpl->NotifyOutputData(aOutputBuffer, static_cast<size_t>(aFrames),
mSampleRate, ChannelCount);
// Process mic data if any/needed -- after inserting far-end data for AEC!
if (aInputBuffer) {
if (mAudioInput) { // for this specific input-only or full-duplex stream
mAudioInput->NotifyInputData(mGraphImpl, aInputBuffer,
static_cast<size_t>(aFrames),
- mSampleRate, ChannelCount);
+ mSampleRate, mInputChannels);
}
}
bool switching = false;
{
MonitorAutoLock mon(mGraphImpl->GetMonitor());
switching = !!NextDriver();
}
--- a/dom/media/GraphDriver.h
+++ b/dom/media/GraphDriver.h
@@ -192,25 +192,16 @@ public:
void EnsureNextIterationLocked();
MediaStreamGraphImpl* GraphImpl() {
return mGraphImpl;
}
virtual bool OnThread() = 0;
- // These are invoked on the MSG thread (or MainThread in shutdown)
- virtual void SetInputListener(AudioDataListener *aListener) {
- mAudioInput = aListener;
- }
- // XXX do we need the param? probably no
- virtual void RemoveInputListener(AudioDataListener *aListener) {
- mAudioInput = nullptr;
- }
-
protected:
GraphTime StateComputedTime() const;
// Time of the start of this graph iteration. This must be accessed while
// having the monitor.
GraphTime mIterationStart;
// Time of the end of this graph iteration. This must be accessed while having
// the monitor.
@@ -231,19 +222,16 @@ protected:
WAITSTATE_WAITING_INDEFINITELY,
// Something has signaled RunThread() to wake up immediately,
// but it hasn't done so yet
WAITSTATE_WAKING_UP
};
// This must be access with the monitor.
WaitState mWaitState;
- // Callback for mic data, if any
- AudioDataListener *mAudioInput;
-
// This is used on the main thread (during initialization), and the graph
// thread. No monitor needed because we know the graph thread does not run
// during the initialization.
TimeStamp mCurrentTimeStamp;
// This is non-null only when this driver has recently switched from an other
// driver, and has not cleaned it up yet (for example because the audio stream
// is currently calling the callback during initialization).
//
@@ -416,16 +404,27 @@ public:
/* This function gets called when the graph has produced the audio frames for
* this iteration. */
void MixerCallback(AudioDataValue* aMixedBuffer,
AudioSampleFormat aFormat,
uint32_t aChannels,
uint32_t aFrames,
uint32_t aSampleRate) override;
+ // These are invoked on the MSG thread (we don't call this if not LIFECYCLE_RUNNING)
+ virtual void SetInputListener(AudioDataListener *aListener) {
+ MOZ_ASSERT(OnThread());
+ mAudioInput = aListener;
+ }
+ // XXX do we need the param? probably no
+ virtual void RemoveInputListener(AudioDataListener *aListener) {
+ MOZ_ASSERT(OnThread());
+ mAudioInput = nullptr;
+ }
+
AudioCallbackDriver* AsAudioCallbackDriver() override {
return this;
}
/* Enqueue a promise that is going to be resolved when a specific operation
* occurs on the cubeb stream. */
void EnqueueStreamAndPromiseForOperation(MediaStream* aStream,
void* aPromise,
@@ -481,16 +480,19 @@ private:
* callback thread. */
AudioCallbackBufferWrapper<AudioDataValue, ChannelCount> mBuffer;
/* cubeb stream for this graph. This is guaranteed to be non-null after Init()
* has been called, and is synchronized internaly. */
nsAutoRef<cubeb_stream> mAudioStream;
/* 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;
/* 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. */
uint32_t mIterationDurationMS;
/* cubeb_stream_init calls the audio callback to prefill the buffers. The
* previous driver has to be kept alive until the audio stream has been
* started, because it is responsible to call cubeb_stream_start, so we delay
* the cleanup of the previous driver until it has started the audio stream.
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -939,16 +939,17 @@ MediaStreamGraphImpl::OpenAudioInputImpl
// we close cubeb.
mInputDeviceID = aID;
mAudioInputs.AppendElement(aListener); // always monitor speaker data
// Switch Drivers since we're adding input (to input-only or full-duplex)
MonitorAutoLock mon(mMonitor);
if (mLifecycleState == LIFECYCLE_RUNNING) {
AudioCallbackDriver* driver = new AudioCallbackDriver(this);
+ driver->SetInputListener(aListener);
CurrentDriver()->SwitchAtNextIteration(driver);
}
}
nsresult
MediaStreamGraphImpl::OpenAudioInput(CubebUtils::AudioDeviceID aID,
AudioDataListener *aListener)
{
@@ -978,17 +979,20 @@ MediaStreamGraphImpl::OpenAudioInput(Cub
return NS_OK;
}
void
MediaStreamGraphImpl::CloseAudioInputImpl(AudioDataListener *aListener)
{
mInputDeviceID = nullptr;
mInputWanted = false;
- CurrentDriver()->RemoveInputListener(aListener);
+ AudioCallbackDriver *driver = CurrentDriver()->AsAudioCallbackDriver();
+ if (driver) {
+ driver->RemoveInputListener(aListener);
+ }
mAudioInputs.RemoveElement(aListener);
// Switch Drivers since we're adding or removing an input (to nothing/system or output only)
bool audioTrackPresent = false;
for (uint32_t i = 0; i < mStreams.Length(); ++i) {
MediaStream* stream = mStreams[i];
// If this is a AudioNodeStream, force a AudioCallbackDriver.
if (stream->AsAudioNodeStream()) {
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -369,25 +369,27 @@ MediaEngineWebRTCMicrophoneSource::Start
// Register output observer
// XXX
MOZ_ASSERT(gFarendObserver);
gFarendObserver->Clear();
if (mVoEBase->StartReceive(mChannel)) {
return NS_ERROR_FAILURE;
}
+
+ // Must be *before* StartSend() so it will notice we selected external input (full_duplex)
+ mAudioInput->StartRecording(aStream->Graph(), mListener);
+
if (mVoEBase->StartSend(mChannel)) {
return NS_ERROR_FAILURE;
}
// Attach external media processor, so this::Process will be called.
mVoERender->RegisterExternalMediaProcessing(mChannel, webrtc::kRecordingPerChannel, *this);
- mAudioInput->StartRecording(aStream->Graph(), mListener);
-
return NS_OK;
}
nsresult
MediaEngineWebRTCMicrophoneSource::Stop(SourceMediaStream *aSource, TrackID aID)
{
AssertIsOnOwningThread();
{