зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1238038 - Add a base type of MediaTrack for different devices r=padenot
Separate common interfaces that will be used for NonNativeInputTrack class, from NativeInputTrack, into a base class: DeviceInputTrack, where the NonNativeInputTrack will be implemented in the next patch. Differential Revision: https://phabricator.services.mozilla.com/D137782
This commit is contained in:
Родитель
e24a32d029
Коммит
086c0af18e
|
@ -33,7 +33,7 @@ namespace mozilla {
|
||||||
# undef TRACK_GRAPH_LOG_INTERNAL
|
# undef TRACK_GRAPH_LOG_INTERNAL
|
||||||
#endif // TRACK_GRAPH_LOG_INTERNAL
|
#endif // TRACK_GRAPH_LOG_INTERNAL
|
||||||
#define TRACK_GRAPH_LOG_INTERNAL(level, msg, ...) \
|
#define TRACK_GRAPH_LOG_INTERNAL(level, msg, ...) \
|
||||||
LOG_INTERNAL(level, "(Graph %p, Driver %p) NativeInputTrack %p, " msg, \
|
LOG_INTERNAL(level, "(Graph %p, Driver %p) DeviceInputTrack %p, " msg, \
|
||||||
this->mGraph, this->mGraph->CurrentDriver(), this, \
|
this->mGraph, this->mGraph->CurrentDriver(), this, \
|
||||||
##__VA_ARGS__)
|
##__VA_ARGS__)
|
||||||
|
|
||||||
|
@ -50,12 +50,12 @@ namespace mozilla {
|
||||||
TRACK_GRAPH_LOG_INTERNAL(Verbose, msg, ##__VA_ARGS__)
|
TRACK_GRAPH_LOG_INTERNAL(Verbose, msg, ##__VA_ARGS__)
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
Result<RefPtr<NativeInputTrack>, nsresult> NativeInputTrack::OpenAudio(
|
Result<RefPtr<DeviceInputTrack>, nsresult> DeviceInputTrack::OpenAudio(
|
||||||
MediaTrackGraphImpl* aGraph, CubebUtils::AudioDeviceID aDeviceId,
|
MediaTrackGraphImpl* aGraph, CubebUtils::AudioDeviceID aDeviceId,
|
||||||
const PrincipalHandle& aPrincipalHandle, AudioDataListener* aListener) {
|
const PrincipalHandle& aPrincipalHandle, AudioDataListener* aListener) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
RefPtr<NativeInputTrack> track = aGraph->GetNativeInputTrack();
|
RefPtr<DeviceInputTrack> track = aGraph->GetNativeInputTrack();
|
||||||
if (!track) {
|
if (!track) {
|
||||||
track =
|
track =
|
||||||
new NativeInputTrack(aGraph->GraphRate(), aDeviceId, aPrincipalHandle);
|
new NativeInputTrack(aGraph->GraphRate(), aDeviceId, aPrincipalHandle);
|
||||||
|
@ -77,7 +77,7 @@ Result<RefPtr<NativeInputTrack>, nsresult> NativeInputTrack::OpenAudio(
|
||||||
MOZ_ASSERT(track->mDeviceId == aDeviceId);
|
MOZ_ASSERT(track->mDeviceId == aDeviceId);
|
||||||
|
|
||||||
track->mUserCount += 1;
|
track->mUserCount += 1;
|
||||||
LOG("NativeInputTrack %p (device %p) in MTG %p has %d users now", track.get(),
|
LOG("DeviceInputTrack %p (device %p) in MTG %p has %d users now", track.get(),
|
||||||
track->mDeviceId, aGraph, track->mUserCount);
|
track->mDeviceId, aGraph, track->mUserCount);
|
||||||
if (track->mUserCount > 1) {
|
if (track->mUserCount > 1) {
|
||||||
track->ReevaluateInputDevice();
|
track->ReevaluateInputDevice();
|
||||||
|
@ -87,7 +87,7 @@ Result<RefPtr<NativeInputTrack>, nsresult> NativeInputTrack::OpenAudio(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
void NativeInputTrack::CloseAudio(RefPtr<NativeInputTrack>&& aTrack,
|
void DeviceInputTrack::CloseAudio(RefPtr<DeviceInputTrack>&& aTrack,
|
||||||
AudioDataListener* aListener) {
|
AudioDataListener* aListener) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(aTrack);
|
MOZ_ASSERT(aTrack);
|
||||||
|
@ -95,7 +95,7 @@ void NativeInputTrack::CloseAudio(RefPtr<NativeInputTrack>&& aTrack,
|
||||||
|
|
||||||
aTrack->RemoveDataListener(aListener);
|
aTrack->RemoveDataListener(aListener);
|
||||||
aTrack->mUserCount -= 1;
|
aTrack->mUserCount -= 1;
|
||||||
LOG("NativeInputTrack %p (device %p) in MTG %p has %d users now",
|
LOG("DeviceInputTrack %p (device %p) in MTG %p has %d users now",
|
||||||
aTrack.get(), aTrack->mDeviceId, aTrack->GraphImpl(), aTrack->mUserCount);
|
aTrack.get(), aTrack->mDeviceId, aTrack->GraphImpl(), aTrack->mUserCount);
|
||||||
if (aTrack->mUserCount == 0) {
|
if (aTrack->mUserCount == 0) {
|
||||||
aTrack->GraphImpl()->CloseAudioInput(aTrack);
|
aTrack->GraphImpl()->CloseAudioInput(aTrack);
|
||||||
|
@ -105,16 +105,111 @@ void NativeInputTrack::CloseAudio(RefPtr<NativeInputTrack>&& aTrack,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeInputTrack::NativeInputTrack(TrackRate aSampleRate,
|
DeviceInputTrack::DeviceInputTrack(TrackRate aSampleRate,
|
||||||
CubebUtils::AudioDeviceID aDeviceId,
|
CubebUtils::AudioDeviceID aDeviceId,
|
||||||
const PrincipalHandle& aPrincipalHandle)
|
const PrincipalHandle& aPrincipalHandle)
|
||||||
: ProcessedMediaTrack(aSampleRate, MediaSegment::AUDIO, new AudioSegment()),
|
: ProcessedMediaTrack(aSampleRate, MediaSegment::AUDIO, new AudioSegment()),
|
||||||
mDeviceId(aDeviceId),
|
mDeviceId(aDeviceId),
|
||||||
mPrincipalHandle(aPrincipalHandle),
|
mPrincipalHandle(aPrincipalHandle),
|
||||||
mIsBufferingAppended(false),
|
|
||||||
mInputChannels(0),
|
|
||||||
mUserCount(0) {}
|
mUserCount(0) {}
|
||||||
|
|
||||||
|
uint32_t DeviceInputTrack::MaxRequestedInputChannels() const {
|
||||||
|
MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
|
||||||
|
uint32_t maxInputChannels = 0;
|
||||||
|
for (const auto& listener : mListeners) {
|
||||||
|
maxInputChannels = std::max(maxInputChannels,
|
||||||
|
listener->RequestedInputChannelCount(mGraph));
|
||||||
|
}
|
||||||
|
return maxInputChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceInputTrack::HasVoiceInput() const {
|
||||||
|
MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
|
||||||
|
for (const auto& listener : mListeners) {
|
||||||
|
if (listener->IsVoiceInput(mGraph)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceInputTrack::DeviceChanged(MediaTrackGraphImpl* aGraph) const {
|
||||||
|
MOZ_ASSERT(aGraph->OnGraphThreadOrNotRunning());
|
||||||
|
MOZ_ASSERT(aGraph == mGraph,
|
||||||
|
"Receive device changed signal from another graph");
|
||||||
|
TRACK_GRAPH_LOG("DeviceChanged");
|
||||||
|
for (const auto& listener : mListeners) {
|
||||||
|
listener->DeviceChanged(aGraph);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceInputTrack::ReevaluateInputDevice() {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
class Message : public ControlMessage {
|
||||||
|
public:
|
||||||
|
explicit Message(MediaTrackGraphImpl* aGraph)
|
||||||
|
: ControlMessage(nullptr), mGraph(aGraph) {}
|
||||||
|
void Run() override {
|
||||||
|
TRACE("DeviceInputTrack::ReevaluateInputDevice ControlMessage");
|
||||||
|
mGraph->ReevaluateInputDevice();
|
||||||
|
}
|
||||||
|
MediaTrackGraphImpl* mGraph;
|
||||||
|
};
|
||||||
|
mGraph->AppendMessage(MakeUnique<Message>(mGraph));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceInputTrack::AddDataListener(AudioDataListener* aListener) {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
class Message : public ControlMessage {
|
||||||
|
public:
|
||||||
|
Message(DeviceInputTrack* aInputTrack, AudioDataListener* aListener)
|
||||||
|
: ControlMessage(nullptr),
|
||||||
|
mInputTrack(aInputTrack),
|
||||||
|
mListener(aListener) {}
|
||||||
|
void Run() override {
|
||||||
|
TRACE("DeviceInputTrack::AddDataListener ControlMessage");
|
||||||
|
MOZ_ASSERT(!mInputTrack->mListeners.Contains(mListener.get()),
|
||||||
|
"Don't add a listener twice.");
|
||||||
|
mInputTrack->mListeners.AppendElement(mListener.get());
|
||||||
|
}
|
||||||
|
RefPtr<DeviceInputTrack> mInputTrack;
|
||||||
|
RefPtr<AudioDataListener> mListener;
|
||||||
|
};
|
||||||
|
|
||||||
|
mGraph->AppendMessage(MakeUnique<Message>(this, aListener));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceInputTrack::RemoveDataListener(AudioDataListener* aListener) {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
class Message : public ControlMessage {
|
||||||
|
public:
|
||||||
|
Message(DeviceInputTrack* aInputTrack, AudioDataListener* aListener)
|
||||||
|
: ControlMessage(nullptr),
|
||||||
|
mInputTrack(aInputTrack),
|
||||||
|
mListener(aListener) {}
|
||||||
|
void Run() override {
|
||||||
|
TRACE("DeviceInputTrack::RemoveDataListener ControlMessage");
|
||||||
|
DebugOnly<bool> wasPresent =
|
||||||
|
mInputTrack->mListeners.RemoveElement(mListener.get());
|
||||||
|
MOZ_ASSERT(wasPresent, "Remove an unknown listener");
|
||||||
|
mListener->Disconnect(mInputTrack->GraphImpl());
|
||||||
|
}
|
||||||
|
RefPtr<DeviceInputTrack> mInputTrack;
|
||||||
|
RefPtr<AudioDataListener> mListener;
|
||||||
|
};
|
||||||
|
|
||||||
|
mGraph->AppendMessage(MakeUnique<Message>(this, aListener));
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeInputTrack::NativeInputTrack(TrackRate aSampleRate,
|
||||||
|
CubebUtils::AudioDeviceID aDeviceId,
|
||||||
|
const PrincipalHandle& aPrincipalHandle)
|
||||||
|
: DeviceInputTrack(aSampleRate, aDeviceId, aPrincipalHandle),
|
||||||
|
mIsBufferingAppended(false),
|
||||||
|
mInputChannels(0) {}
|
||||||
|
|
||||||
void NativeInputTrack::DestroyImpl() {
|
void NativeInputTrack::DestroyImpl() {
|
||||||
MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
|
MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
|
||||||
mPendingData.Clear();
|
mPendingData.Clear();
|
||||||
|
@ -126,7 +221,7 @@ void NativeInputTrack::ProcessInput(GraphTime aFrom, GraphTime aTo,
|
||||||
MOZ_ASSERT(mGraph->OnGraphThread());
|
MOZ_ASSERT(mGraph->OnGraphThread());
|
||||||
TRACE_COMMENT("NativeInputTrack::ProcessInput", "%p", this);
|
TRACE_COMMENT("NativeInputTrack::ProcessInput", "%p", this);
|
||||||
|
|
||||||
TRACK_GRAPH_LOGV("ProcessInput from %" PRId64 " to %" PRId64
|
TRACK_GRAPH_LOGV("(Native) ProcessInput from %" PRId64 " to %" PRId64
|
||||||
", needs %" PRId64 " frames",
|
", needs %" PRId64 " frames",
|
||||||
aFrom, aTo, aTo - aFrom);
|
aFrom, aTo, aTo - aFrom);
|
||||||
|
|
||||||
|
@ -158,7 +253,7 @@ void NativeInputTrack::NotifyInputStopped(MediaTrackGraphImpl* aGraph) {
|
||||||
MOZ_ASSERT(aGraph->OnGraphThreadOrNotRunning());
|
MOZ_ASSERT(aGraph->OnGraphThreadOrNotRunning());
|
||||||
MOZ_ASSERT(aGraph == mGraph,
|
MOZ_ASSERT(aGraph == mGraph,
|
||||||
"Receive input stopped signal from another graph");
|
"Receive input stopped signal from another graph");
|
||||||
TRACK_GRAPH_LOG("NotifyInputStopped");
|
TRACK_GRAPH_LOG("(Native) NotifyInputStopped");
|
||||||
mInputChannels = 0;
|
mInputChannels = 0;
|
||||||
mIsBufferingAppended = false;
|
mIsBufferingAppended = false;
|
||||||
mPendingData.Clear();
|
mPendingData.Clear();
|
||||||
|
@ -196,96 +291,6 @@ void NativeInputTrack::NotifyInputData(MediaTrackGraphImpl* aGraph,
|
||||||
mPrincipalHandle);
|
mPrincipalHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeInputTrack::DeviceChanged(MediaTrackGraphImpl* aGraph) {
|
|
||||||
MOZ_ASSERT(aGraph->OnGraphThreadOrNotRunning());
|
|
||||||
MOZ_ASSERT(aGraph == mGraph,
|
|
||||||
"Receive device changed signal from another graph");
|
|
||||||
TRACK_GRAPH_LOG("DeviceChanged");
|
|
||||||
for (auto& listener : mDataUsers) {
|
|
||||||
listener->DeviceChanged(aGraph);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t NativeInputTrack::MaxRequestedInputChannels() const {
|
|
||||||
MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
|
|
||||||
uint32_t maxInputChannels = 0;
|
|
||||||
for (const auto& listener : mDataUsers) {
|
|
||||||
maxInputChannels = std::max(maxInputChannels,
|
|
||||||
listener->RequestedInputChannelCount(mGraph));
|
|
||||||
}
|
|
||||||
return maxInputChannels;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NativeInputTrack::HasVoiceInput() const {
|
|
||||||
MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
|
|
||||||
for (const auto& listener : mDataUsers) {
|
|
||||||
if (listener->IsVoiceInput(mGraph)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NativeInputTrack::ReevaluateInputDevice() {
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
class Message : public ControlMessage {
|
|
||||||
public:
|
|
||||||
explicit Message(MediaTrackGraphImpl* aGraph)
|
|
||||||
: ControlMessage(nullptr), mGraph(aGraph) {}
|
|
||||||
void Run() override {
|
|
||||||
TRACE("NativeInputTrack::ReevaluateInputDevice ControlMessage");
|
|
||||||
mGraph->ReevaluateInputDevice();
|
|
||||||
}
|
|
||||||
MediaTrackGraphImpl* mGraph;
|
|
||||||
};
|
|
||||||
mGraph->AppendMessage(MakeUnique<Message>(mGraph));
|
|
||||||
}
|
|
||||||
|
|
||||||
void NativeInputTrack::AddDataListener(AudioDataListener* aListener) {
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
class Message : public ControlMessage {
|
|
||||||
public:
|
|
||||||
Message(NativeInputTrack* aInputTrack, AudioDataListener* aListener)
|
|
||||||
: ControlMessage(nullptr),
|
|
||||||
mInputTrack(aInputTrack),
|
|
||||||
mListener(aListener) {}
|
|
||||||
void Run() override {
|
|
||||||
TRACE("NativeInputTrack::AddDataListener ControlMessage");
|
|
||||||
MOZ_ASSERT(!mInputTrack->mDataUsers.Contains(mListener.get()),
|
|
||||||
"Don't add a listener twice.");
|
|
||||||
mInputTrack->mDataUsers.AppendElement(mListener.get());
|
|
||||||
}
|
|
||||||
RefPtr<NativeInputTrack> mInputTrack;
|
|
||||||
RefPtr<AudioDataListener> mListener;
|
|
||||||
};
|
|
||||||
|
|
||||||
mGraph->AppendMessage(MakeUnique<Message>(this, aListener));
|
|
||||||
}
|
|
||||||
|
|
||||||
void NativeInputTrack::RemoveDataListener(AudioDataListener* aListener) {
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
class Message : public ControlMessage {
|
|
||||||
public:
|
|
||||||
Message(NativeInputTrack* aInputTrack, AudioDataListener* aListener)
|
|
||||||
: ControlMessage(nullptr),
|
|
||||||
mInputTrack(aInputTrack),
|
|
||||||
mListener(aListener) {}
|
|
||||||
void Run() override {
|
|
||||||
TRACE("NativeInputTrack::RemoveDataListener ControlMessage");
|
|
||||||
DebugOnly<bool> wasPresent =
|
|
||||||
mInputTrack->mDataUsers.RemoveElement(mListener.get());
|
|
||||||
MOZ_ASSERT(wasPresent, "Remove an unknown listener");
|
|
||||||
mListener->Disconnect(mInputTrack->GraphImpl());
|
|
||||||
}
|
|
||||||
RefPtr<NativeInputTrack> mInputTrack;
|
|
||||||
RefPtr<AudioDataListener> mListener;
|
|
||||||
};
|
|
||||||
|
|
||||||
mGraph->AppendMessage(MakeUnique<Message>(this, aListener));
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef LOG_INTERNAL
|
#undef LOG_INTERNAL
|
||||||
#undef LOG
|
#undef LOG
|
||||||
#undef LOGE
|
#undef LOGE
|
||||||
|
|
|
@ -12,15 +12,18 @@
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
// MediaTrack subclass storing the raw audio data from microphone.
|
class NativeInputTrack;
|
||||||
class NativeInputTrack : public ProcessedMediaTrack {
|
|
||||||
|
class DeviceInputTrack : public ProcessedMediaTrack {
|
||||||
public:
|
public:
|
||||||
// Main Thread APIs:
|
// Main Thread APIs:
|
||||||
// The following two APIs can create and destroy a NativeInputTrack reference
|
// The following two APIs can create and destroy a DeviceInputTrack reference
|
||||||
// on main thread, then open and close the paired audio device accordingly on
|
// on main thread, then open and close the underlying audio device accordingly
|
||||||
// the graph thread. The user who wants to read the audio input from a certain
|
// on the graph thread. The user who wants to read the audio input from a
|
||||||
// device should use these APIs to obtain a NativeInputTrack reference and
|
// certain device should use these APIs to obtain a DeviceInputTrack reference
|
||||||
// return the reference when the user no longer needs the audio data.
|
// and release the reference when the user no longer needs the audio data.
|
||||||
|
//
|
||||||
|
// Currently, all the DeviceInputTrack is NativeInputTrack.
|
||||||
//
|
//
|
||||||
// There is only one NativeInputTrack per MediaTrackGraph and it will be
|
// There is only one NativeInputTrack per MediaTrackGraph and it will be
|
||||||
// created when the first user who requests the audio data. Once the
|
// created when the first user who requests the audio data. Once the
|
||||||
|
@ -35,82 +38,96 @@ class NativeInputTrack : public ProcessedMediaTrack {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// // On main thread
|
// // On main thread
|
||||||
// RefPtr<NativeInputTrack> track = NativeInputTrack::OpenAudio(...);
|
// RefPtr<DeviceInputTrack> track = DeviceInputTrack::OpenAudio(...);
|
||||||
// ...
|
// ...
|
||||||
// // On graph thread
|
// // On graph thread
|
||||||
// AudioSegmen* data = track->GetData<AudioSegment>();
|
// AudioSegmen* data = track->GetData<AudioSegment>();
|
||||||
// ...
|
// ...
|
||||||
// // On main thread
|
// // On main thread
|
||||||
// NativeInputTrack::CloseAudio(std::move(track), ...);
|
// DeviceInputTrack::CloseAudio(std::move(track), ...);
|
||||||
//
|
//
|
||||||
// Returns a reference of NativeInputTrack, storing the input audio data from
|
// Returns a reference of DeviceInputTrack, storing the input audio data from
|
||||||
// the given device, in the given MediaTrackGraph, if the MediaTrackGraph has
|
// the given device, in the given MediaTrackGraph, if the MediaTrackGraph has
|
||||||
// no audio input device, or the given device is the same as the one currently
|
// no audio input device, or the given device is the same as the one currently
|
||||||
// running in the MediaTrackGraph. Otherwise, return an error. The paired
|
// running in the MediaTrackGraph. Otherwise, return an error. The paired
|
||||||
// audio device will be opened accordingly in the successful case. The
|
// audio device will be opened accordingly in the successful case. The
|
||||||
// NativeInputTrack will access its user's audio settings via the attached
|
// DeviceInputTrack will access its user's audio settings via the attached
|
||||||
// AudioDataListener when it needs.
|
// AudioDataListener when it needs.
|
||||||
static Result<RefPtr<NativeInputTrack>, nsresult> OpenAudio(
|
static Result<RefPtr<DeviceInputTrack>, nsresult> OpenAudio(
|
||||||
MediaTrackGraphImpl* aGraph, CubebUtils::AudioDeviceID aDeviceId,
|
MediaTrackGraphImpl* aGraph, CubebUtils::AudioDeviceID aDeviceId,
|
||||||
const PrincipalHandle& aPrincipalHandle, AudioDataListener* aListener);
|
const PrincipalHandle& aPrincipalHandle, AudioDataListener* aListener);
|
||||||
// Destroy the NativeInputTrack reference obtained by the above API. The
|
// Destroy the DeviceInputTrack reference obtained by the above API. The
|
||||||
// paired audio device will be closed accordingly.
|
// paired audio device will be closed accordingly.
|
||||||
static void CloseAudio(RefPtr<NativeInputTrack>&& aTrack,
|
static void CloseAudio(RefPtr<DeviceInputTrack>&& aTrack,
|
||||||
AudioDataListener* aListener);
|
AudioDataListener* aListener);
|
||||||
|
|
||||||
// Graph Thread APIs, for ProcessedMediaTrack
|
// Graph thread APIs:
|
||||||
|
// Query audio settings from its users.
|
||||||
|
uint32_t MaxRequestedInputChannels() const;
|
||||||
|
bool HasVoiceInput() const;
|
||||||
|
// Deliver notification to its users.
|
||||||
|
void DeviceChanged(MediaTrackGraphImpl* aGraph) const;
|
||||||
|
|
||||||
|
// Any thread:
|
||||||
|
DeviceInputTrack* AsDeviceInputTrack() override { return this; }
|
||||||
|
virtual NativeInputTrack* AsNativeInputTrack() { return nullptr; }
|
||||||
|
|
||||||
|
// Any thread:
|
||||||
|
const CubebUtils::AudioDeviceID mDeviceId;
|
||||||
|
const PrincipalHandle mPrincipalHandle;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
DeviceInputTrack(TrackRate aSampleRate, CubebUtils::AudioDeviceID aDeviceId,
|
||||||
|
const PrincipalHandle& aPrincipalHandle);
|
||||||
|
~DeviceInputTrack() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Main thread APIs:
|
||||||
|
void ReevaluateInputDevice();
|
||||||
|
void AddDataListener(AudioDataListener* aListener);
|
||||||
|
void RemoveDataListener(AudioDataListener* aListener);
|
||||||
|
|
||||||
|
// Only accessed on the main thread.
|
||||||
|
// When this becomes zero, this DeviceInputTrack is no longer needed.
|
||||||
|
int32_t mUserCount = 0;
|
||||||
|
|
||||||
|
// Only accessed on the graph thread.
|
||||||
|
nsTArray<RefPtr<AudioDataListener>> mListeners;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NativeInputTrack final : public DeviceInputTrack {
|
||||||
|
public:
|
||||||
|
// Do not call this directly. This can only be called in DeviceInputTrack or
|
||||||
|
// tests.
|
||||||
|
NativeInputTrack(TrackRate aSampleRate, CubebUtils::AudioDeviceID aDeviceId,
|
||||||
|
const PrincipalHandle& aPrincipalHandle);
|
||||||
|
|
||||||
|
// Graph Thread APIs, for ProcessedMediaTrack.
|
||||||
void DestroyImpl() override;
|
void DestroyImpl() override;
|
||||||
void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) override;
|
void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) override;
|
||||||
uint32_t NumberOfChannels() const override;
|
uint32_t NumberOfChannels() const override;
|
||||||
|
|
||||||
// Graph thread APIs: Redirect calls from GraphDriver to mDataUsers
|
// Graph thread APIs: Get input audio data and event from graph.
|
||||||
void DeviceChanged(MediaTrackGraphImpl* aGraph);
|
|
||||||
|
|
||||||
// Graph thread APIs: Get input audio data and event from graph
|
|
||||||
void NotifyInputStopped(MediaTrackGraphImpl* aGraph);
|
void NotifyInputStopped(MediaTrackGraphImpl* aGraph);
|
||||||
void NotifyInputData(MediaTrackGraphImpl* aGraph,
|
void NotifyInputData(MediaTrackGraphImpl* aGraph,
|
||||||
const AudioDataValue* aBuffer, size_t aFrames,
|
const AudioDataValue* aBuffer, size_t aFrames,
|
||||||
TrackRate aRate, uint32_t aChannels,
|
TrackRate aRate, uint32_t aChannels,
|
||||||
uint32_t aAlreadyBuffered);
|
uint32_t aAlreadyBuffered);
|
||||||
|
|
||||||
// Graph thread APIs
|
|
||||||
uint32_t MaxRequestedInputChannels() const;
|
|
||||||
bool HasVoiceInput() const;
|
|
||||||
|
|
||||||
// Any thread
|
// Any thread
|
||||||
NativeInputTrack* AsNativeInputTrack() override { return this; }
|
NativeInputTrack* AsNativeInputTrack() override { return this; }
|
||||||
|
|
||||||
// Any thread
|
|
||||||
const CubebUtils::AudioDeviceID mDeviceId;
|
|
||||||
const PrincipalHandle mPrincipalHandle;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NativeInputTrack(TrackRate aSampleRate, CubebUtils::AudioDeviceID aDeviceId,
|
|
||||||
const PrincipalHandle& aPrincipalHandle);
|
|
||||||
~NativeInputTrack() = default;
|
~NativeInputTrack() = default;
|
||||||
|
|
||||||
// Main thread APIs
|
// Graph thread only members:
|
||||||
void ReevaluateInputDevice();
|
|
||||||
void AddDataListener(AudioDataListener* aListener);
|
|
||||||
void RemoveDataListener(AudioDataListener* aListener);
|
|
||||||
|
|
||||||
// Indicate whether we append extra frames in mPendingData. The extra number
|
// Indicate whether we append extra frames in mPendingData. The extra number
|
||||||
// of frames is in [0, WEBAUDIO_BLOCK_SIZE] range.
|
// of frames is in [0, WEBAUDIO_BLOCK_SIZE] range.
|
||||||
bool mIsBufferingAppended;
|
bool mIsBufferingAppended = false;
|
||||||
|
// Queue the audio input data coming from NotifyInputData.
|
||||||
// Queue the audio input data coming from NotifyInputData. Used in graph
|
|
||||||
// thread only.
|
|
||||||
AudioSegment mPendingData;
|
AudioSegment mPendingData;
|
||||||
|
// The input channel count for the audio data.
|
||||||
// Only accessed on the graph thread.
|
|
||||||
uint32_t mInputChannels = 0;
|
uint32_t mInputChannels = 0;
|
||||||
|
|
||||||
// Only accessed on the main thread.
|
|
||||||
// When this becomes zero, this NativeInputTrack is no longer needed.
|
|
||||||
int32_t mUserCount = 0;
|
|
||||||
|
|
||||||
// Only accessed on the graph thread.
|
|
||||||
nsTArray<RefPtr<AudioDataListener>> mDataUsers;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -682,11 +682,12 @@ void MediaTrackGraphImpl::OpenAudioInputImpl(NativeInputTrack* aTrack) {
|
||||||
SwitchAtNextIteration(driver);
|
SwitchAtNextIteration(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaTrackGraphImpl::OpenAudioInput(NativeInputTrack* aTrack) {
|
void MediaTrackGraphImpl::OpenAudioInput(DeviceInputTrack* aTrack) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(aTrack);
|
MOZ_ASSERT(aTrack);
|
||||||
|
MOZ_ASSERT(aTrack->AsNativeInputTrack());
|
||||||
|
|
||||||
LOG(LogLevel::Debug, ("%p OpenInput: NativeInputTrack %p for device %p", this,
|
LOG(LogLevel::Debug, ("%p OpenInput: DeviceInputTrack %p for device %p", this,
|
||||||
aTrack, aTrack->mDeviceId));
|
aTrack, aTrack->mDeviceId));
|
||||||
|
|
||||||
class Message : public ControlMessage {
|
class Message : public ControlMessage {
|
||||||
|
@ -702,10 +703,10 @@ void MediaTrackGraphImpl::OpenAudioInput(NativeInputTrack* aTrack) {
|
||||||
};
|
};
|
||||||
|
|
||||||
MOZ_ASSERT(!mNativeInputTrackOnMain);
|
MOZ_ASSERT(!mNativeInputTrackOnMain);
|
||||||
mNativeInputTrackOnMain = aTrack;
|
mNativeInputTrackOnMain = aTrack->AsNativeInputTrack();
|
||||||
|
|
||||||
// XXX Check not destroyed!
|
// XXX Check not destroyed!
|
||||||
this->AppendMessage(MakeUnique<Message>(this, aTrack));
|
this->AppendMessage(MakeUnique<Message>(this, aTrack->AsNativeInputTrack()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaTrackGraphImpl::CloseAudioInputImpl(CubebUtils::AudioDeviceID aID) {
|
void MediaTrackGraphImpl::CloseAudioInputImpl(CubebUtils::AudioDeviceID aID) {
|
||||||
|
@ -782,8 +783,11 @@ void MediaTrackGraphImpl::UnregisterAudioOutput(MediaTrack* aTrack,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaTrackGraphImpl::CloseAudioInput(NativeInputTrack* aTrack) {
|
void MediaTrackGraphImpl::CloseAudioInput(DeviceInputTrack* aTrack) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
MOZ_ASSERT(aTrack);
|
||||||
|
MOZ_ASSERT(aTrack->AsNativeInputTrack());
|
||||||
|
|
||||||
class Message : public ControlMessage {
|
class Message : public ControlMessage {
|
||||||
public:
|
public:
|
||||||
Message(MediaTrackGraphImpl* aGraph, CubebUtils::AudioDeviceID aID)
|
Message(MediaTrackGraphImpl* aGraph, CubebUtils::AudioDeviceID aID)
|
||||||
|
|
|
@ -97,7 +97,7 @@ class MediaTrack;
|
||||||
class MediaTrackGraph;
|
class MediaTrackGraph;
|
||||||
class MediaTrackGraphImpl;
|
class MediaTrackGraphImpl;
|
||||||
class MediaTrackListener;
|
class MediaTrackListener;
|
||||||
class NativeInputTrack;
|
class DeviceInputTrack;
|
||||||
class ProcessedMediaTrack;
|
class ProcessedMediaTrack;
|
||||||
class SourceMediaTrack;
|
class SourceMediaTrack;
|
||||||
|
|
||||||
|
@ -359,7 +359,7 @@ class MediaTrack : public mozilla::LinkedListElement<MediaTrack> {
|
||||||
virtual ForwardedInputTrack* AsForwardedInputTrack() { return nullptr; }
|
virtual ForwardedInputTrack* AsForwardedInputTrack() { return nullptr; }
|
||||||
virtual CrossGraphTransmitter* AsCrossGraphTransmitter() { return nullptr; }
|
virtual CrossGraphTransmitter* AsCrossGraphTransmitter() { return nullptr; }
|
||||||
virtual CrossGraphReceiver* AsCrossGraphReceiver() { return nullptr; }
|
virtual CrossGraphReceiver* AsCrossGraphReceiver() { return nullptr; }
|
||||||
virtual NativeInputTrack* AsNativeInputTrack() { return nullptr; }
|
virtual DeviceInputTrack* AsDeviceInputTrack() { return nullptr; }
|
||||||
|
|
||||||
// These Impl methods perform the core functionality of the control methods
|
// These Impl methods perform the core functionality of the control methods
|
||||||
// above, on the media graph thread.
|
// above, on the media graph thread.
|
||||||
|
@ -1031,8 +1031,8 @@ class MediaTrackGraph {
|
||||||
// Idempotent
|
// Idempotent
|
||||||
void ForceShutDown();
|
void ForceShutDown();
|
||||||
|
|
||||||
virtual void OpenAudioInput(NativeInputTrack* aTrack) = 0;
|
virtual void OpenAudioInput(DeviceInputTrack* aTrack) = 0;
|
||||||
virtual void CloseAudioInput(NativeInputTrack* aTrack) = 0;
|
virtual void CloseAudioInput(DeviceInputTrack* aTrack) = 0;
|
||||||
|
|
||||||
// Control API.
|
// Control API.
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -411,7 +411,7 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
|
||||||
void OpenAudioInputImpl(NativeInputTrack* aTrack);
|
void OpenAudioInputImpl(NativeInputTrack* aTrack);
|
||||||
/* Called on the main thread when something requests audio from an input
|
/* Called on the main thread when something requests audio from an input
|
||||||
* audio device aID. */
|
* audio device aID. */
|
||||||
virtual void OpenAudioInput(NativeInputTrack* aTrack) override;
|
virtual void OpenAudioInput(DeviceInputTrack* aTrack) override;
|
||||||
|
|
||||||
/* Runs off a message on the graph when input audio from aID is not needed
|
/* Runs off a message on the graph when input audio from aID is not needed
|
||||||
* anymore, for a particular track. It can be that other tracks still need
|
* anymore, for a particular track. It can be that other tracks still need
|
||||||
|
@ -420,7 +420,7 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
|
||||||
/* Called on the main thread when input audio from aID is not needed
|
/* Called on the main thread when input audio from aID is not needed
|
||||||
* anymore, for a particular track. It can be that other tracks still need
|
* anymore, for a particular track. It can be that other tracks still need
|
||||||
* audio from this audio input device. */
|
* audio from this audio input device. */
|
||||||
virtual void CloseAudioInput(NativeInputTrack* aTrack) override;
|
virtual void CloseAudioInput(DeviceInputTrack* aTrack) override;
|
||||||
|
|
||||||
/* Add or remove an audio output for this track. All tracks that have an
|
/* Add or remove an audio output for this track. All tracks that have an
|
||||||
* audio output are mixed and written to a single audio output stream. */
|
* audio output are mixed and written to a single audio output stream. */
|
||||||
|
|
|
@ -84,10 +84,12 @@ TEST_F(TestDeviceInputTrack, NativeInputTrackData) {
|
||||||
const PrincipalHandle testPrincipal =
|
const PrincipalHandle testPrincipal =
|
||||||
MakePrincipalHandle(nsContentUtils::GetSystemPrincipal());
|
MakePrincipalHandle(nsContentUtils::GetSystemPrincipal());
|
||||||
|
|
||||||
auto r = NativeInputTrack::OpenAudio(mGraph.get(), deviceId, testPrincipal,
|
// Setup: Create a NativeInputTrack and add it to mGraph
|
||||||
nullptr);
|
RefPtr<NativeInputTrack> track =
|
||||||
ASSERT_TRUE(r.isOk());
|
new NativeInputTrack(mGraph->GraphRate(), deviceId, testPrincipal);
|
||||||
RefPtr<NativeInputTrack> track = r.unwrap();
|
mGraph->AddTrack(track);
|
||||||
|
|
||||||
|
// Main test below:
|
||||||
|
|
||||||
generator.GenerateInterleaved(buffer.Elements(), nrFrames);
|
generator.GenerateInterleaved(buffer.Elements(), nrFrames);
|
||||||
track->NotifyInputData(mGraph.get(), buffer.Elements(), nrFrames, mRate,
|
track->NotifyInputData(mGraph.get(), buffer.Elements(), nrFrames, mRate,
|
||||||
|
@ -123,7 +125,9 @@ TEST_F(TestDeviceInputTrack, NativeInputTrackData) {
|
||||||
EXPECT_EQ(chunk.mPrincipalHandle, testPrincipal);
|
EXPECT_EQ(chunk.mPrincipalHandle, testPrincipal);
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeInputTrack::CloseAudio(std::move(track), nullptr);
|
// Tear down: Destroy the NativeInputTrack and remove it from mGraph.
|
||||||
|
track->Destroy();
|
||||||
|
mGraph->RemoveTrackGraphThread(track);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestDeviceInputTrack, OpenTwiceWithoutCloseFirst) {
|
TEST_F(TestDeviceInputTrack, OpenTwiceWithoutCloseFirst) {
|
||||||
|
@ -136,7 +140,8 @@ TEST_F(TestDeviceInputTrack, OpenTwiceWithoutCloseFirst) {
|
||||||
auto r1 = NativeInputTrack::OpenAudio(mGraph.get(), deviceId1, testPrincipal,
|
auto r1 = NativeInputTrack::OpenAudio(mGraph.get(), deviceId1, testPrincipal,
|
||||||
nullptr);
|
nullptr);
|
||||||
ASSERT_TRUE(r1.isOk());
|
ASSERT_TRUE(r1.isOk());
|
||||||
RefPtr<NativeInputTrack> track1 = r1.unwrap();
|
RefPtr<NativeInputTrack> track1 = r1.unwrap()->AsNativeInputTrack();
|
||||||
|
ASSERT_TRUE(track1);
|
||||||
|
|
||||||
auto r2 = NativeInputTrack::OpenAudio(mGraph.get(), deviceId2, testPrincipal,
|
auto r2 = NativeInputTrack::OpenAudio(mGraph.get(), deviceId2, testPrincipal,
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
|
@ -1332,12 +1332,13 @@ nsresult AudioProcessingTrack::ConnectDeviceInput(
|
||||||
mInputListener = aListener;
|
mInputListener = aListener;
|
||||||
mDeviceId.emplace(aId);
|
mDeviceId.emplace(aId);
|
||||||
|
|
||||||
auto r = NativeInputTrack::OpenAudio(GraphImpl(), aId, aPrincipal,
|
auto r = DeviceInputTrack::OpenAudio(GraphImpl(), aId, aPrincipal,
|
||||||
mInputListener.get());
|
mInputListener.get());
|
||||||
if (r.isErr()) {
|
if (r.isErr()) {
|
||||||
NS_WARNING("Failed to open audio device.");
|
NS_WARNING("Failed to open audio device.");
|
||||||
return r.unwrapErr();
|
return r.unwrapErr();
|
||||||
}
|
}
|
||||||
|
|
||||||
mDeviceInputTrack = r.unwrap();
|
mDeviceInputTrack = r.unwrap();
|
||||||
MOZ_ASSERT(mDeviceInputTrack);
|
MOZ_ASSERT(mDeviceInputTrack);
|
||||||
LOG("Open device %p (InputTrack=%p) for Mic source %p", aId,
|
LOG("Open device %p (InputTrack=%p) for Mic source %p", aId,
|
||||||
|
@ -1354,10 +1355,11 @@ void AudioProcessingTrack::DisconnectDeviceInput() {
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(mPort);
|
MOZ_ASSERT(mPort);
|
||||||
MOZ_ASSERT(mDeviceId.isSome());
|
MOZ_ASSERT(mDeviceId.isSome());
|
||||||
|
MOZ_ASSERT(mDeviceInputTrack);
|
||||||
LOG("Close device %p (InputTrack=%p) for Mic source %p ", *mDeviceId,
|
LOG("Close device %p (InputTrack=%p) for Mic source %p ", *mDeviceId,
|
||||||
mDeviceInputTrack.get(), this);
|
mDeviceInputTrack.get(), this);
|
||||||
mPort->Destroy();
|
mPort->Destroy();
|
||||||
NativeInputTrack::CloseAudio(std::move(mDeviceInputTrack),
|
DeviceInputTrack::CloseAudio(std::move(mDeviceInputTrack),
|
||||||
mInputListener.get());
|
mInputListener.get());
|
||||||
mInputListener = nullptr;
|
mInputListener = nullptr;
|
||||||
mDeviceId = Nothing();
|
mDeviceId = Nothing();
|
||||||
|
|
|
@ -228,7 +228,7 @@ class AudioProcessingTrack : public ProcessedMediaTrack {
|
||||||
|
|
||||||
// Only accessed on the main thread. This is the track producing raw audio
|
// Only accessed on the main thread. This is the track producing raw audio
|
||||||
// input data. Graph thread should MediaInputPort::GetSource() to get this
|
// input data. Graph thread should MediaInputPort::GetSource() to get this
|
||||||
RefPtr<NativeInputTrack> mDeviceInputTrack;
|
RefPtr<DeviceInputTrack> mDeviceInputTrack;
|
||||||
|
|
||||||
// Only accessed on the main thread. Used for bookkeeping on main thread, such
|
// Only accessed on the main thread. Used for bookkeeping on main thread, such
|
||||||
// that DisconnectDeviceInput can be idempotent.
|
// that DisconnectDeviceInput can be idempotent.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче