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
#endif // TRACK_GRAPH_LOG_INTERNAL
#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, \
##__VA_ARGS__)
@ -50,12 +50,12 @@ namespace mozilla {
TRACK_GRAPH_LOG_INTERNAL(Verbose, msg, ##__VA_ARGS__)
/* static */
Result<RefPtr<NativeInputTrack>, nsresult> NativeInputTrack::OpenAudio(
Result<RefPtr<DeviceInputTrack>, nsresult> DeviceInputTrack::OpenAudio(
MediaTrackGraphImpl* aGraph, CubebUtils::AudioDeviceID aDeviceId,
const PrincipalHandle& aPrincipalHandle, AudioDataListener* aListener) {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<NativeInputTrack> track = aGraph->GetNativeInputTrack();
RefPtr<DeviceInputTrack> track = aGraph->GetNativeInputTrack();
if (!track) {
track =
new NativeInputTrack(aGraph->GraphRate(), aDeviceId, aPrincipalHandle);
@ -77,7 +77,7 @@ Result<RefPtr<NativeInputTrack>, nsresult> NativeInputTrack::OpenAudio(
MOZ_ASSERT(track->mDeviceId == aDeviceId);
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);
if (track->mUserCount > 1) {
track->ReevaluateInputDevice();
@ -87,7 +87,7 @@ Result<RefPtr<NativeInputTrack>, nsresult> NativeInputTrack::OpenAudio(
}
/* static */
void NativeInputTrack::CloseAudio(RefPtr<NativeInputTrack>&& aTrack,
void DeviceInputTrack::CloseAudio(RefPtr<DeviceInputTrack>&& aTrack,
AudioDataListener* aListener) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aTrack);
@ -95,7 +95,7 @@ void NativeInputTrack::CloseAudio(RefPtr<NativeInputTrack>&& aTrack,
aTrack->RemoveDataListener(aListener);
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);
if (aTrack->mUserCount == 0) {
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,
const PrincipalHandle& aPrincipalHandle)
: ProcessedMediaTrack(aSampleRate, MediaSegment::AUDIO, new AudioSegment()),
mDeviceId(aDeviceId),
mPrincipalHandle(aPrincipalHandle),
mIsBufferingAppended(false),
mInputChannels(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() {
MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
mPendingData.Clear();
@ -126,7 +221,7 @@ void NativeInputTrack::ProcessInput(GraphTime aFrom, GraphTime aTo,
MOZ_ASSERT(mGraph->OnGraphThread());
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",
aFrom, aTo, aTo - aFrom);
@ -158,7 +253,7 @@ void NativeInputTrack::NotifyInputStopped(MediaTrackGraphImpl* aGraph) {
MOZ_ASSERT(aGraph->OnGraphThreadOrNotRunning());
MOZ_ASSERT(aGraph == mGraph,
"Receive input stopped signal from another graph");
TRACK_GRAPH_LOG("NotifyInputStopped");
TRACK_GRAPH_LOG("(Native) NotifyInputStopped");
mInputChannels = 0;
mIsBufferingAppended = false;
mPendingData.Clear();
@ -196,96 +291,6 @@ void NativeInputTrack::NotifyInputData(MediaTrackGraphImpl* aGraph,
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
#undef LOGE

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

@ -12,15 +12,18 @@
namespace mozilla {
// MediaTrack subclass storing the raw audio data from microphone.
class NativeInputTrack : public ProcessedMediaTrack {
class NativeInputTrack;
class DeviceInputTrack : public ProcessedMediaTrack {
public:
// Main Thread APIs:
// The following two APIs can create and destroy a NativeInputTrack reference
// on main thread, then open and close the paired audio device accordingly on
// the graph thread. The user who wants to read the audio input from a certain
// device should use these APIs to obtain a NativeInputTrack reference and
// return the reference when the user no longer needs the audio data.
// The following two APIs can create and destroy a DeviceInputTrack reference
// on main thread, then open and close the underlying audio device accordingly
// on the graph thread. The user who wants to read the audio input from a
// certain device should use these APIs to obtain a DeviceInputTrack reference
// 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
// created when the first user who requests the audio data. Once the
@ -35,82 +38,96 @@ class NativeInputTrack : public ProcessedMediaTrack {
//
// Example:
// // On main thread
// RefPtr<NativeInputTrack> track = NativeInputTrack::OpenAudio(...);
// RefPtr<DeviceInputTrack> track = DeviceInputTrack::OpenAudio(...);
// ...
// // On graph thread
// AudioSegmen* data = track->GetData<AudioSegment>();
// ...
// // 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
// 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
// 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.
static Result<RefPtr<NativeInputTrack>, nsresult> OpenAudio(
static Result<RefPtr<DeviceInputTrack>, nsresult> OpenAudio(
MediaTrackGraphImpl* aGraph, CubebUtils::AudioDeviceID aDeviceId,
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.
static void CloseAudio(RefPtr<NativeInputTrack>&& aTrack,
static void CloseAudio(RefPtr<DeviceInputTrack>&& aTrack,
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 ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) override;
uint32_t NumberOfChannels() const override;
// Graph thread APIs: Redirect calls from GraphDriver to mDataUsers
void DeviceChanged(MediaTrackGraphImpl* aGraph);
// Graph thread APIs: Get input audio data and event from graph
// Graph thread APIs: Get input audio data and event from graph.
void NotifyInputStopped(MediaTrackGraphImpl* aGraph);
void NotifyInputData(MediaTrackGraphImpl* aGraph,
const AudioDataValue* aBuffer, size_t aFrames,
TrackRate aRate, uint32_t aChannels,
uint32_t aAlreadyBuffered);
// Graph thread APIs
uint32_t MaxRequestedInputChannels() const;
bool HasVoiceInput() const;
// Any thread
NativeInputTrack* AsNativeInputTrack() override { return this; }
// Any thread
const CubebUtils::AudioDeviceID mDeviceId;
const PrincipalHandle mPrincipalHandle;
private:
NativeInputTrack(TrackRate aSampleRate, CubebUtils::AudioDeviceID aDeviceId,
const PrincipalHandle& aPrincipalHandle);
~NativeInputTrack() = default;
// Main thread APIs
void ReevaluateInputDevice();
void AddDataListener(AudioDataListener* aListener);
void RemoveDataListener(AudioDataListener* aListener);
// Graph thread only members:
// Indicate whether we append extra frames in mPendingData. The extra number
// of frames is in [0, WEBAUDIO_BLOCK_SIZE] range.
bool mIsBufferingAppended;
// Queue the audio input data coming from NotifyInputData. Used in graph
// thread only.
bool mIsBufferingAppended = false;
// Queue the audio input data coming from NotifyInputData.
AudioSegment mPendingData;
// Only accessed on the graph thread.
// The input channel count for the audio data.
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

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

@ -682,11 +682,12 @@ void MediaTrackGraphImpl::OpenAudioInputImpl(NativeInputTrack* aTrack) {
SwitchAtNextIteration(driver);
}
void MediaTrackGraphImpl::OpenAudioInput(NativeInputTrack* aTrack) {
void MediaTrackGraphImpl::OpenAudioInput(DeviceInputTrack* aTrack) {
MOZ_ASSERT(NS_IsMainThread());
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));
class Message : public ControlMessage {
@ -702,10 +703,10 @@ void MediaTrackGraphImpl::OpenAudioInput(NativeInputTrack* aTrack) {
};
MOZ_ASSERT(!mNativeInputTrackOnMain);
mNativeInputTrackOnMain = aTrack;
mNativeInputTrackOnMain = aTrack->AsNativeInputTrack();
// XXX Check not destroyed!
this->AppendMessage(MakeUnique<Message>(this, aTrack));
this->AppendMessage(MakeUnique<Message>(this, aTrack->AsNativeInputTrack()));
}
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(aTrack);
MOZ_ASSERT(aTrack->AsNativeInputTrack());
class Message : public ControlMessage {
public:
Message(MediaTrackGraphImpl* aGraph, CubebUtils::AudioDeviceID aID)

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

@ -97,7 +97,7 @@ class MediaTrack;
class MediaTrackGraph;
class MediaTrackGraphImpl;
class MediaTrackListener;
class NativeInputTrack;
class DeviceInputTrack;
class ProcessedMediaTrack;
class SourceMediaTrack;
@ -359,7 +359,7 @@ class MediaTrack : public mozilla::LinkedListElement<MediaTrack> {
virtual ForwardedInputTrack* AsForwardedInputTrack() { return nullptr; }
virtual CrossGraphTransmitter* AsCrossGraphTransmitter() { 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
// above, on the media graph thread.
@ -1031,8 +1031,8 @@ class MediaTrackGraph {
// Idempotent
void ForceShutDown();
virtual void OpenAudioInput(NativeInputTrack* aTrack) = 0;
virtual void CloseAudioInput(NativeInputTrack* aTrack) = 0;
virtual void OpenAudioInput(DeviceInputTrack* aTrack) = 0;
virtual void CloseAudioInput(DeviceInputTrack* aTrack) = 0;
// Control API.
/**

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

@ -411,7 +411,7 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
void OpenAudioInputImpl(NativeInputTrack* aTrack);
/* Called on the main thread when something requests audio from an input
* 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
* 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
* anymore, for a particular track. It can be that other tracks still need
* 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
* audio output are mixed and written to a single audio output stream. */

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

@ -84,10 +84,12 @@ TEST_F(TestDeviceInputTrack, NativeInputTrackData) {
const PrincipalHandle testPrincipal =
MakePrincipalHandle(nsContentUtils::GetSystemPrincipal());
auto r = NativeInputTrack::OpenAudio(mGraph.get(), deviceId, testPrincipal,
nullptr);
ASSERT_TRUE(r.isOk());
RefPtr<NativeInputTrack> track = r.unwrap();
// Setup: Create a NativeInputTrack and add it to mGraph
RefPtr<NativeInputTrack> track =
new NativeInputTrack(mGraph->GraphRate(), deviceId, testPrincipal);
mGraph->AddTrack(track);
// Main test below:
generator.GenerateInterleaved(buffer.Elements(), nrFrames);
track->NotifyInputData(mGraph.get(), buffer.Elements(), nrFrames, mRate,
@ -123,7 +125,9 @@ TEST_F(TestDeviceInputTrack, NativeInputTrackData) {
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) {
@ -136,7 +140,8 @@ TEST_F(TestDeviceInputTrack, OpenTwiceWithoutCloseFirst) {
auto r1 = NativeInputTrack::OpenAudio(mGraph.get(), deviceId1, testPrincipal,
nullptr);
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,
nullptr);

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

@ -1332,12 +1332,13 @@ nsresult AudioProcessingTrack::ConnectDeviceInput(
mInputListener = aListener;
mDeviceId.emplace(aId);
auto r = NativeInputTrack::OpenAudio(GraphImpl(), aId, aPrincipal,
auto r = DeviceInputTrack::OpenAudio(GraphImpl(), aId, aPrincipal,
mInputListener.get());
if (r.isErr()) {
NS_WARNING("Failed to open audio device.");
return r.unwrapErr();
}
mDeviceInputTrack = r.unwrap();
MOZ_ASSERT(mDeviceInputTrack);
LOG("Open device %p (InputTrack=%p) for Mic source %p", aId,
@ -1354,10 +1355,11 @@ void AudioProcessingTrack::DisconnectDeviceInput() {
}
MOZ_ASSERT(mPort);
MOZ_ASSERT(mDeviceId.isSome());
MOZ_ASSERT(mDeviceInputTrack);
LOG("Close device %p (InputTrack=%p) for Mic source %p ", *mDeviceId,
mDeviceInputTrack.get(), this);
mPort->Destroy();
NativeInputTrack::CloseAudio(std::move(mDeviceInputTrack),
DeviceInputTrack::CloseAudio(std::move(mDeviceInputTrack),
mInputListener.get());
mInputListener = nullptr;
mDeviceId = Nothing();

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

@ -228,7 +228,7 @@ class AudioProcessingTrack : public ProcessedMediaTrack {
// Only accessed on the main thread. This is the track producing raw audio
// 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
// that DisconnectDeviceInput can be idempotent.