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:
Chun-Min Chang 2022-04-18 18:45:33 +00:00
Родитель e24a32d029
Коммит 086c0af18e
8 изменённых файлов: 201 добавлений и 168 удалений

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

@ -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.