Bug 1221587: Base update of the MSG API for full-duplex r=padenot

--HG--
extra : commitid : Kf1JpZKH7LH
This commit is contained in:
Randell Jesup 2016-01-21 11:51:35 -05:00
Родитель 3121c632b9
Коммит 6d7d97d7bc
5 изменённых файлов: 148 добавлений и 0 удалений

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

@ -885,6 +885,23 @@ AudioCallbackDriver::DataCallback(AudioDataValue* aBuffer, long aFrames)
mBuffer.BufferFilled(); mBuffer.BufferFilled();
// Callback any observers for the AEC speaker data. Note that one
// (maybe) of these will be full-duplex, the others will get their input
// data off separate cubeb callbacks. Take care with how stuff is
// removed/added to this list and TSAN issues, but input and output will
// use separate callback methods.
mGraphImpl->NotifySpeakerData(aOutputBuffer, static_cast<size_t>(aFrames),
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),
ChannelCount);
}
}
bool switching = false; bool switching = false;
{ {
MonitorAutoLock mon(mGraphImpl->GetMonitor()); MonitorAutoLock mon(mGraphImpl->GetMonitor());

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

@ -196,6 +196,16 @@ public:
virtual bool OnThread() = 0; virtual bool OnThread() = 0;
// XXX Thread-safety! Do these via commands to avoid TSAN issues
// and crashes!!!
virtual void SetInputListener(MediaStreamListener *aListener) {
mAudioInput = aListener;
}
// XXX do we need the param? probably no
virtual void RemoveInputListener(MediaStreamListener *aListener) {
mAudioInput = nullptr;
}
protected: protected:
GraphTime StateComputedTime() const; GraphTime StateComputedTime() const;
@ -226,6 +236,9 @@ protected:
// This must be access with the monitor. // This must be access with the monitor.
WaitState mWaitState; WaitState mWaitState;
// Callback for mic data, if any
RefPtr<MediaStreamListener> mAudioInput;
// This is used on the main thread (during initialization), and the graph // 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 // thread. No monitor needed because we know the graph thread does not run
// during the initialization. // during the initialization.
@ -488,6 +501,8 @@ private:
* This is synchronized by the Graph's monitor. * This is synchronized by the Graph's monitor.
* */ * */
bool mStarted; bool mStarted;
/* Listener for mic input, if any. */
RefPtr<MediaStreamListener> mAudioInput;
struct AutoInCallback struct AutoInCallback
{ {

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

@ -30,6 +30,7 @@
#ifdef MOZ_WEBRTC #ifdef MOZ_WEBRTC
#include "AudioOutputObserver.h" #include "AudioOutputObserver.h"
#endif #endif
#include "mtransport/runnable_utils.h"
#include "webaudio/blink/HRTFDatabaseLoader.h" #include "webaudio/blink/HRTFDatabaseLoader.h"
@ -922,6 +923,85 @@ MediaStreamGraphImpl::PlayVideo(MediaStream* aStream)
} }
} }
void
MediaStreamGraphImpl::OpenAudioInputImpl(char *aName, MediaStreamListener *aListener)
{
if (CurrentDriver()->AsAudioCallbackDriver()) {
CurrentDriver()->SetInputListener(aListener);
} else {
// XXX Switch to callback driver
}
mAudioInputs.AppendElement(aListener); // always monitor speaker data
}
nsresult
MediaStreamGraphImpl::OpenAudioInput(char *aName, MediaStreamListener *aListener)
{
// XXX So, so, so annoying. Can't AppendMessage except on Mainthread
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(WrapRunnable(this,
&MediaStreamGraphImpl::OpenAudioInput,
aName, aListener)); // XXX Fix! string need to copied
return NS_OK;
}
class Message : public ControlMessage {
public:
Message(MediaStreamGraphImpl *aGraph, char *aName, MediaStreamListener *aListener) :
ControlMessage(nullptr), mGraph(aGraph), mName(aName), mListener(aListener) {}
virtual void Run()
{
mGraph->OpenAudioInputImpl(mName, mListener);
}
MediaStreamGraphImpl *mGraph;
char *mName; // XXX needs to copy
MediaStreamListener *mListener;
};
this->AppendMessage(new Message(this, aName, aListener));
return NS_OK;
}
void
MediaStreamGraphImpl::CloseAudioInputImpl(MediaStreamListener *aListener)
{
CurrentDriver()->RemoveInputListener(aListener);
mAudioInputs.RemoveElement(aListener);
}
void
MediaStreamGraphImpl::CloseAudioInput(MediaStreamListener *aListener)
{
// XXX So, so, so annoying. Can't AppendMessage except on Mainthread
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(WrapRunnable(this,
&MediaStreamGraphImpl::CloseAudioInput,
aListener));
return;
}
class Message : public ControlMessage {
public:
Message(MediaStreamGraphImpl *aGraph, MediaStreamListener *aListener) :
ControlMessage(nullptr), mGraph(aGraph), mListener(aListener) {}
virtual void Run()
{
mGraph->CloseAudioInputImpl(mListener);
}
MediaStreamGraphImpl *mGraph;
MediaStreamListener *mListener;
};
this->AppendMessage(new Message(this, aListener));
}
// All AudioInput listeners get the same speaker data (at least for now).
void
MediaStreamGraph::NotifySpeakerData(AudioDataValue* aBuffer, size_t aFrames,
uint32_t aChannels)
{
for (auto& listener : mAudioInputs) {
listener->NotifySpeakerData(this, aBuffer, aFrames, aChannels);
}
}
bool bool
MediaStreamGraphImpl::ShouldUpdateMainThread() MediaStreamGraphImpl::ShouldUpdateMainThread()
{ {

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

@ -181,6 +181,23 @@ public:
* are also notified of atomically to MediaStreamListeners. * are also notified of atomically to MediaStreamListeners.
*/ */
virtual void NotifyFinishedTrackCreation(MediaStreamGraph* aGraph) {} virtual void NotifyFinishedTrackCreation(MediaStreamGraph* aGraph) {}
/* These are for cubeb audio input & output streams: */
/**
* Output data to speakers, for use as the "far-end" data for echo
* cancellation. This is not guaranteed to be in any particular size
* chunks.
*/
virtual void NotifySpeakerData(MediaStreamGraph* aGraph,
AudioDataValue* aBuffer, size_t aFrames,
uint32_t aChannels) {}
/**
* Input data from a microphone (or other audio source. This is not
* guaranteed to be in any particular size chunks.
*/
virtual void NotifyInputData(MediaStreamGraph* aGraph,
AudioDataValue* aBuffer, size_t aFrames,
uint32_t aChannels) {}
}; };
/** /**
@ -1175,6 +1192,11 @@ public:
// Idempotent // Idempotent
static void DestroyNonRealtimeInstance(MediaStreamGraph* aGraph); static void DestroyNonRealtimeInstance(MediaStreamGraph* aGraph);
virtual nsresult OpenAudioInput(char *aName, MediaStreamListener *aListener) {
return NS_ERROR_FAILURE;
}
virtual void CloseAudioInput(MediaStreamListener *aListener) {}
// Control API. // Control API.
/** /**
* Create a stream that a media decoder (or some other source of * Create a stream that a media decoder (or some other source of
@ -1254,6 +1276,13 @@ public:
already_AddRefed<MediaInputPort> ConnectToCaptureStream( already_AddRefed<MediaInputPort> ConnectToCaptureStream(
uint64_t aWindowId, MediaStream* aMediaStream); uint64_t aWindowId, MediaStream* aMediaStream);
/**
* Data going to the speakers from the GraphDriver's DataCallback
* to notify any listeners (for echo cancellation).
*/
void NotifySpeakerData(AudioDataValue* aBuffer, size_t aFrames,
uint32_t aChannels);
protected: protected:
explicit MediaStreamGraph(TrackRate aSampleRate) explicit MediaStreamGraph(TrackRate aSampleRate)
: mSampleRate(aSampleRate) : mSampleRate(aSampleRate)
@ -1274,6 +1303,8 @@ protected:
* at construction. * at construction.
*/ */
TrackRate mSampleRate; TrackRate mSampleRate;
nsTArray<RefPtr<MediaStreamListener>> mAudioInputs;
}; };
} // namespace mozilla } // namespace mozilla

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

@ -350,6 +350,11 @@ public:
* at the current buffer end point. The StreamBuffer's tracks must be * at the current buffer end point. The StreamBuffer's tracks must be
* explicitly set to finished by the caller. * explicitly set to finished by the caller.
*/ */
void OpenAudioInputImpl(char *aName, MediaStreamListener *aListener);
virtual nsresult OpenAudioInput(char *aName, MediaStreamListener *aListener) override;
void CloseAudioInputImpl(MediaStreamListener *aListener);
virtual void CloseAudioInput(MediaStreamListener *aListener) override;
void FinishStream(MediaStream* aStream); void FinishStream(MediaStream* aStream);
/** /**
* Compute how much stream data we would like to buffer for aStream. * Compute how much stream data we would like to buffer for aStream.