Bug 1839170 - Refactor Snap pulling, Add Firefox Snap Core22 and GNOME 42 SDK symbols...
[gecko.git] / dom / media / DeviceInputTrack.cpp
blob5e67cd9b6c691968f5927126c540a62d63f76487
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
7 #include "DeviceInputTrack.h"
9 #include "MediaTrackGraphImpl.h"
10 #include "Tracing.h"
12 namespace mozilla {
14 #ifdef LOG_INTERNAL
15 # undef LOG_INTERNAL
16 #endif // LOG_INTERNAL
17 #define LOG_INTERNAL(level, msg, ...) \
18 MOZ_LOG(gMediaTrackGraphLog, LogLevel::level, (msg, ##__VA_ARGS__))
20 #ifdef LOG
21 # undef LOG
22 #endif // LOG
23 #define LOG(msg, ...) LOG_INTERNAL(Debug, msg, ##__VA_ARGS__)
25 #ifdef LOGE
26 # undef LOGE
27 #endif // LOGE
28 #define LOGE(msg, ...) LOG_INTERNAL(Error, msg, ##__VA_ARGS__)
30 // This can only be called in graph thread since mGraph->CurrentDriver() is
31 // graph thread only
32 #ifdef TRACK_GRAPH_LOG_INTERNAL
33 # undef TRACK_GRAPH_LOG_INTERNAL
34 #endif // TRACK_GRAPH_LOG_INTERNAL
35 #define TRACK_GRAPH_LOG_INTERNAL(level, msg, ...) \
36 LOG_INTERNAL(level, "(Graph %p, Driver %p) DeviceInputTrack %p, " msg, \
37 this->mGraph, this->mGraph->CurrentDriver(), this, \
38 ##__VA_ARGS__)
40 #ifdef TRACK_GRAPH_LOG
41 # undef TRACK_GRAPH_LOG
42 #endif // TRACK_GRAPH_LOG
43 #define TRACK_GRAPH_LOG(msg, ...) \
44 TRACK_GRAPH_LOG_INTERNAL(Debug, msg, ##__VA_ARGS__)
46 #ifdef TRACK_GRAPH_LOGV
47 # undef TRACK_GRAPH_LOGV
48 #endif // TRACK_GRAPH_LOGV
49 #define TRACK_GRAPH_LOGV(msg, ...) \
50 TRACK_GRAPH_LOG_INTERNAL(Verbose, msg, ##__VA_ARGS__)
52 #ifdef TRACK_GRAPH_LOGE
53 # undef TRACK_GRAPH_LOGE
54 #endif // TRACK_GRAPH_LOGE
55 #define TRACK_GRAPH_LOGE(msg, ...) \
56 TRACK_GRAPH_LOG_INTERNAL(Error, msg, ##__VA_ARGS__)
58 #ifdef CONSUMER_GRAPH_LOG_INTERNAL
59 # undef CONSUMER_GRAPH_LOG_INTERNAL
60 #endif // CONSUMER_GRAPH_LOG_INTERNAL
61 #define CONSUMER_GRAPH_LOG_INTERNAL(level, msg, ...) \
62 LOG_INTERNAL( \
63 level, "(Graph %p, Driver %p) DeviceInputConsumerTrack %p, " msg, \
64 this->mGraph, this->mGraph->CurrentDriver(), this, ##__VA_ARGS__)
66 #ifdef CONSUMER_GRAPH_LOGV
67 # undef CONSUMER_GRAPH_LOGV
68 #endif // CONSUMER_GRAPH_LOGV
69 #define CONSUMER_GRAPH_LOGV(msg, ...) \
70 CONSUMER_GRAPH_LOG_INTERNAL(Verbose, msg, ##__VA_ARGS__)
72 DeviceInputConsumerTrack::DeviceInputConsumerTrack(TrackRate aSampleRate)
73 : ProcessedMediaTrack(aSampleRate, MediaSegment::AUDIO,
74 new AudioSegment()) {}
76 void DeviceInputConsumerTrack::ConnectDeviceInput(
77 CubebUtils::AudioDeviceID aId, AudioDataListener* aListener,
78 const PrincipalHandle& aPrincipal) {
79 MOZ_ASSERT(NS_IsMainThread());
80 MOZ_ASSERT(GraphImpl());
81 MOZ_ASSERT(aListener);
82 MOZ_ASSERT(!mListener);
83 MOZ_ASSERT(!mDeviceInputTrack);
84 MOZ_ASSERT(mDeviceId.isNothing());
85 MOZ_ASSERT(!mDeviceInputTrack,
86 "Must disconnect a device input before connecting a new one");
88 mListener = aListener;
89 mDeviceId.emplace(aId);
91 mDeviceInputTrack =
92 DeviceInputTrack::OpenAudio(GraphImpl(), aId, aPrincipal, this);
93 LOG("Open device %p (DeviceInputTrack %p) for consumer %p", aId,
94 mDeviceInputTrack.get(), this);
95 mPort = AllocateInputPort(mDeviceInputTrack.get());
98 void DeviceInputConsumerTrack::DisconnectDeviceInput() {
99 MOZ_ASSERT(NS_IsMainThread());
100 MOZ_ASSERT(GraphImpl());
102 if (!mListener) {
103 MOZ_ASSERT(mDeviceId.isNothing());
104 MOZ_ASSERT(!mDeviceInputTrack);
105 return;
108 MOZ_ASSERT(mPort);
109 MOZ_ASSERT(mDeviceInputTrack);
110 MOZ_ASSERT(mDeviceId.isSome());
112 LOG("Close device %p (DeviceInputTrack %p) for consumer %p ", *mDeviceId,
113 mDeviceInputTrack.get(), this);
114 mPort->Destroy();
115 DeviceInputTrack::CloseAudio(mDeviceInputTrack.forget(), this);
116 mListener = nullptr;
117 mDeviceId = Nothing();
120 Maybe<CubebUtils::AudioDeviceID> DeviceInputConsumerTrack::DeviceId() const {
121 MOZ_ASSERT(NS_IsMainThread());
122 return mDeviceId;
125 NotNull<AudioDataListener*> DeviceInputConsumerTrack::GetAudioDataListener()
126 const {
127 MOZ_ASSERT(NS_IsMainThread());
128 return WrapNotNull(mListener.get());
131 bool DeviceInputConsumerTrack::ConnectToNativeDevice() const {
132 MOZ_ASSERT(NS_IsMainThread());
133 return mDeviceInputTrack && mDeviceInputTrack->AsNativeInputTrack();
136 bool DeviceInputConsumerTrack::ConnectToNonNativeDevice() const {
137 MOZ_ASSERT(NS_IsMainThread());
138 return mDeviceInputTrack && mDeviceInputTrack->AsNonNativeInputTrack();
141 void DeviceInputConsumerTrack::GetInputSourceData(AudioSegment& aOutput,
142 const MediaInputPort* aPort,
143 GraphTime aFrom,
144 GraphTime aTo) const {
145 MOZ_ASSERT(mGraph->OnGraphThread());
146 MOZ_ASSERT(aOutput.IsEmpty());
148 MediaTrack* source = aPort->GetSource();
149 GraphTime next;
150 for (GraphTime t = aFrom; t < aTo; t = next) {
151 MediaInputPort::InputInterval interval =
152 MediaInputPort::GetNextInputInterval(aPort, t);
153 interval.mEnd = std::min(interval.mEnd, aTo);
155 const bool inputEnded =
156 source->Ended() &&
157 source->GetEnd() <=
158 source->GraphTimeToTrackTimeWithBlocking(interval.mStart);
160 TrackTime ticks = interval.mEnd - interval.mStart;
161 next = interval.mEnd;
163 if (interval.mStart >= interval.mEnd) {
164 break;
167 if (inputEnded) {
168 aOutput.AppendNullData(ticks);
169 CONSUMER_GRAPH_LOGV(
170 "Getting %" PRId64
171 " ticks of null data from input port source (ended input)",
172 ticks);
173 } else if (interval.mInputIsBlocked) {
174 aOutput.AppendNullData(ticks);
175 CONSUMER_GRAPH_LOGV(
176 "Getting %" PRId64
177 " ticks of null data from input port source (blocked input)",
178 ticks);
179 } else if (source->IsSuspended()) {
180 aOutput.AppendNullData(ticks);
181 CONSUMER_GRAPH_LOGV(
182 "Getting %" PRId64
183 " ticks of null data from input port source (source is suspended)",
184 ticks);
185 } else {
186 TrackTime start =
187 source->GraphTimeToTrackTimeWithBlocking(interval.mStart);
188 TrackTime end = source->GraphTimeToTrackTimeWithBlocking(interval.mEnd);
189 MOZ_ASSERT(source->GetData<AudioSegment>()->GetDuration() >= end);
190 aOutput.AppendSlice(*source->GetData<AudioSegment>(), start, end);
191 CONSUMER_GRAPH_LOGV("Getting %" PRId64
192 " ticks of real data from input port source %p",
193 end - start, source);
198 /* static */
199 NotNull<RefPtr<DeviceInputTrack>> DeviceInputTrack::OpenAudio(
200 MediaTrackGraphImpl* aGraph, CubebUtils::AudioDeviceID aDeviceId,
201 const PrincipalHandle& aPrincipalHandle,
202 DeviceInputConsumerTrack* aConsumer) {
203 MOZ_ASSERT(NS_IsMainThread());
204 MOZ_ASSERT(aConsumer);
205 MOZ_ASSERT(aGraph == aConsumer->GraphImpl());
207 RefPtr<DeviceInputTrack> track =
208 aGraph->GetDeviceInputTrackMainThread(aDeviceId);
209 if (track) {
210 MOZ_ASSERT(!track->mConsumerTracks.IsEmpty());
211 track->AddDataListener(aConsumer->GetAudioDataListener());
212 } else {
213 // Create a NativeInputTrack or NonNativeInputTrack, depending on whether
214 // the given graph already has a native device or not.
215 if (aGraph->GetNativeInputTrackMainThread()) {
216 // A native device is already in use. This device will be a non-native
217 // device.
218 track = new NonNativeInputTrack(aGraph->GraphRate(), aDeviceId,
219 aPrincipalHandle);
220 } else {
221 // No native device is in use. This device will be the native device.
222 track = new NativeInputTrack(aGraph->GraphRate(), aDeviceId,
223 aPrincipalHandle);
225 LOG("Create %sNativeInputTrack %p in MTG %p for device %p",
226 (track->AsNativeInputTrack() ? "" : "Non"), track.get(), aGraph,
227 aDeviceId);
228 aGraph->AddTrack(track);
229 // Add the listener before opening the device so the device passed to
230 // OpenAudioInput always has a non-zero input channel count.
231 track->AddDataListener(aConsumer->GetAudioDataListener());
232 aGraph->OpenAudioInput(track);
234 MOZ_ASSERT(track->AsNativeInputTrack() || track->AsNonNativeInputTrack());
235 MOZ_ASSERT(track->mDeviceId == aDeviceId);
237 MOZ_ASSERT(!track->mConsumerTracks.Contains(aConsumer));
238 track->mConsumerTracks.AppendElement(aConsumer);
240 LOG("DeviceInputTrack %p (device %p: %snative) in MTG %p has %zu users now",
241 track.get(), track->mDeviceId,
242 (track->AsNativeInputTrack() ? "" : "non-"), aGraph,
243 track->mConsumerTracks.Length());
244 if (track->mConsumerTracks.Length() > 1) {
245 track->ReevaluateInputDevice();
248 return WrapNotNull(track);
251 /* static */
252 void DeviceInputTrack::CloseAudio(already_AddRefed<DeviceInputTrack> aTrack,
253 DeviceInputConsumerTrack* aConsumer) {
254 MOZ_ASSERT(NS_IsMainThread());
256 RefPtr<DeviceInputTrack> track = aTrack;
257 MOZ_ASSERT(track);
259 track->RemoveDataListener(aConsumer->GetAudioDataListener());
260 DebugOnly<bool> removed = track->mConsumerTracks.RemoveElement(aConsumer);
261 MOZ_ASSERT(removed);
262 LOG("DeviceInputTrack %p (device %p) in MTG %p has %zu users now",
263 track.get(), track->mDeviceId, track->GraphImpl(),
264 track->mConsumerTracks.Length());
265 if (track->mConsumerTracks.IsEmpty()) {
266 track->GraphImpl()->CloseAudioInput(track);
267 track->Destroy();
268 } else {
269 track->ReevaluateInputDevice();
273 const nsTArray<RefPtr<DeviceInputConsumerTrack>>&
274 DeviceInputTrack::GetConsumerTracks() const {
275 MOZ_ASSERT(NS_IsMainThread());
276 return mConsumerTracks;
279 DeviceInputTrack::DeviceInputTrack(TrackRate aSampleRate,
280 CubebUtils::AudioDeviceID aDeviceId,
281 const PrincipalHandle& aPrincipalHandle)
282 : ProcessedMediaTrack(aSampleRate, MediaSegment::AUDIO, new AudioSegment()),
283 mDeviceId(aDeviceId),
284 mPrincipalHandle(aPrincipalHandle) {}
286 uint32_t DeviceInputTrack::MaxRequestedInputChannels() const {
287 MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
288 uint32_t maxInputChannels = 0;
289 for (const auto& listener : mListeners) {
290 maxInputChannels = std::max(maxInputChannels,
291 listener->RequestedInputChannelCount(mGraph));
293 return maxInputChannels;
296 bool DeviceInputTrack::HasVoiceInput() const {
297 MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
298 for (const auto& listener : mListeners) {
299 if (listener->IsVoiceInput(mGraph)) {
300 return true;
303 return false;
306 void DeviceInputTrack::DeviceChanged(MediaTrackGraphImpl* aGraph) const {
307 MOZ_ASSERT(aGraph->OnGraphThreadOrNotRunning());
308 MOZ_ASSERT(aGraph == mGraph,
309 "Receive device changed signal from another graph");
310 TRACK_GRAPH_LOG("DeviceChanged");
311 for (const auto& listener : mListeners) {
312 listener->DeviceChanged(aGraph);
316 void DeviceInputTrack::ReevaluateInputDevice() {
317 MOZ_ASSERT(NS_IsMainThread());
318 class Message : public ControlMessage {
319 public:
320 explicit Message(MediaTrack* aTrack, CubebUtils::AudioDeviceID aDeviceId)
321 : ControlMessage(aTrack), mDeviceId(aDeviceId) {}
322 void Run() override {
323 TRACE("DeviceInputTrack::ReevaluateInputDevice ControlMessage");
324 mTrack->GraphImpl()->ReevaluateInputDevice(mDeviceId);
326 CubebUtils::AudioDeviceID mDeviceId;
328 mGraph->AppendMessage(MakeUnique<Message>(this, mDeviceId));
331 void DeviceInputTrack::AddDataListener(AudioDataListener* aListener) {
332 MOZ_ASSERT(NS_IsMainThread());
334 class Message : public ControlMessage {
335 public:
336 Message(DeviceInputTrack* aInputTrack, AudioDataListener* aListener)
337 : ControlMessage(nullptr),
338 mInputTrack(aInputTrack),
339 mListener(aListener) {}
340 void Run() override {
341 TRACE("DeviceInputTrack::AddDataListener ControlMessage");
342 MOZ_ASSERT(!mInputTrack->mListeners.Contains(mListener.get()),
343 "Don't add a listener twice.");
344 mInputTrack->mListeners.AppendElement(mListener.get());
346 RefPtr<DeviceInputTrack> mInputTrack;
347 RefPtr<AudioDataListener> mListener;
350 mGraph->AppendMessage(MakeUnique<Message>(this, aListener));
353 void DeviceInputTrack::RemoveDataListener(AudioDataListener* aListener) {
354 MOZ_ASSERT(NS_IsMainThread());
356 class Message : public ControlMessage {
357 public:
358 Message(DeviceInputTrack* aInputTrack, AudioDataListener* aListener)
359 : ControlMessage(nullptr),
360 mInputTrack(aInputTrack),
361 mListener(aListener) {}
362 void Run() override {
363 TRACE("DeviceInputTrack::RemoveDataListener ControlMessage");
364 DebugOnly<bool> wasPresent =
365 mInputTrack->mListeners.RemoveElement(mListener.get());
366 MOZ_ASSERT(wasPresent, "Remove an unknown listener");
367 mListener->Disconnect(mInputTrack->GraphImpl());
369 RefPtr<DeviceInputTrack> mInputTrack;
370 RefPtr<AudioDataListener> mListener;
373 mGraph->AppendMessage(MakeUnique<Message>(this, aListener));
376 NativeInputTrack::NativeInputTrack(TrackRate aSampleRate,
377 CubebUtils::AudioDeviceID aDeviceId,
378 const PrincipalHandle& aPrincipalHandle)
379 : DeviceInputTrack(aSampleRate, aDeviceId, aPrincipalHandle),
380 mIsBufferingAppended(false),
381 mInputChannels(0) {}
383 void NativeInputTrack::DestroyImpl() {
384 MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
385 mPendingData.Clear();
386 ProcessedMediaTrack::DestroyImpl();
389 void NativeInputTrack::ProcessInput(GraphTime aFrom, GraphTime aTo,
390 uint32_t aFlags) {
391 MOZ_ASSERT(mGraph->OnGraphThread());
392 TRACE_COMMENT("NativeInputTrack::ProcessInput", "%p", this);
394 TRACK_GRAPH_LOGV("(Native) ProcessInput from %" PRId64 " to %" PRId64
395 ", needs %" PRId64 " frames",
396 aFrom, aTo, aTo - aFrom);
398 TrackTime from = GraphTimeToTrackTime(aFrom);
399 TrackTime to = GraphTimeToTrackTime(aTo);
400 if (from >= to) {
401 return;
404 MOZ_ASSERT_IF(!mIsBufferingAppended, mPendingData.IsEmpty());
406 TrackTime need = to - from;
407 TrackTime dataNeed = std::min(mPendingData.GetDuration(), need);
408 TrackTime silenceNeed = std::max(need - dataNeed, (TrackTime)0);
410 MOZ_ASSERT_IF(dataNeed > 0, silenceNeed == 0);
412 GetData<AudioSegment>()->AppendSlice(mPendingData, 0, dataNeed);
413 mPendingData.RemoveLeading(dataNeed);
414 GetData<AudioSegment>()->AppendNullData(silenceNeed);
417 uint32_t NativeInputTrack::NumberOfChannels() const {
418 MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
419 return mInputChannels;
422 void NativeInputTrack::NotifyInputStopped(MediaTrackGraphImpl* aGraph) {
423 MOZ_ASSERT(aGraph->OnGraphThreadOrNotRunning());
424 MOZ_ASSERT(aGraph == mGraph,
425 "Receive input stopped signal from another graph");
426 TRACK_GRAPH_LOG("(Native) NotifyInputStopped");
427 mInputChannels = 0;
428 mIsBufferingAppended = false;
429 mPendingData.Clear();
432 void NativeInputTrack::NotifyInputData(MediaTrackGraphImpl* aGraph,
433 const AudioDataValue* aBuffer,
434 size_t aFrames, TrackRate aRate,
435 uint32_t aChannels,
436 uint32_t aAlreadyBuffered) {
437 MOZ_ASSERT(aGraph->OnGraphThread());
438 MOZ_ASSERT(aGraph == mGraph, "Receive input data from another graph");
439 TRACK_GRAPH_LOGV(
440 "NotifyInputData: frames=%zu, rate=%d, channel=%u, alreadyBuffered=%u",
441 aFrames, aRate, aChannels, aAlreadyBuffered);
443 if (!mIsBufferingAppended) {
444 // First time we see live frames getting added. Use what's already buffered
445 // in the driver's scratch buffer as a starting point.
446 MOZ_ASSERT(mPendingData.IsEmpty());
447 constexpr TrackTime buffering = WEBAUDIO_BLOCK_SIZE;
448 const TrackTime remaining =
449 buffering - static_cast<TrackTime>(aAlreadyBuffered);
450 mPendingData.AppendNullData(remaining);
451 mIsBufferingAppended = true;
452 TRACK_GRAPH_LOG("Set mIsBufferingAppended by appending %" PRId64 " frames.",
453 remaining);
456 MOZ_ASSERT(aChannels);
457 if (!mInputChannels) {
458 mInputChannels = aChannels;
460 mPendingData.AppendFromInterleavedBuffer(aBuffer, aFrames, aChannels,
461 mPrincipalHandle);
464 NonNativeInputTrack::NonNativeInputTrack(
465 TrackRate aSampleRate, CubebUtils::AudioDeviceID aDeviceId,
466 const PrincipalHandle& aPrincipalHandle)
467 : DeviceInputTrack(aSampleRate, aDeviceId, aPrincipalHandle),
468 mAudioSource(nullptr),
469 mSourceIdNumber(0),
470 mGraphDriverThreadId(std::thread::id()) {}
472 void NonNativeInputTrack::DestroyImpl() {
473 MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
474 if (mAudioSource) {
475 mAudioSource->Stop();
476 mAudioSource = nullptr;
478 ProcessedMediaTrack::DestroyImpl();
481 void NonNativeInputTrack::ProcessInput(GraphTime aFrom, GraphTime aTo,
482 uint32_t aFlags) {
483 MOZ_ASSERT(mGraph->OnGraphThread());
484 TRACE_COMMENT("NonNativeInputTrack::ProcessInput", "%p", this);
486 TRACK_GRAPH_LOGV("(NonNative) ProcessInput from %" PRId64 " to %" PRId64
487 ", needs %" PRId64 " frames",
488 aFrom, aTo, aTo - aFrom);
490 TrackTime from = GraphTimeToTrackTime(aFrom);
491 TrackTime to = GraphTimeToTrackTime(aTo);
492 if (from >= to) {
493 return;
496 TrackTime delta = to - from;
497 if (!mAudioSource) {
498 GetData<AudioSegment>()->AppendNullData(delta);
499 return;
502 // GetAudioSegment only checks the given reader if DEBUG is defined.
503 AudioInputSource::Consumer consumer =
504 #ifdef DEBUG
505 // If we are on GraphRunner, we should always be on the same thread.
506 mGraph->mGraphRunner || !CheckGraphDriverChanged()
507 ? AudioInputSource::Consumer::Same
508 : AudioInputSource::Consumer::Changed;
509 #else
510 AudioInputSource::Consumer::Same;
511 #endif
513 AudioSegment data = mAudioSource->GetAudioSegment(delta, consumer);
514 MOZ_ASSERT(data.GetDuration() == delta);
515 GetData<AudioSegment>()->AppendFrom(&data);
518 uint32_t NonNativeInputTrack::NumberOfChannels() const {
519 MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
520 return mAudioSource ? mAudioSource->mChannelCount : 0;
523 void NonNativeInputTrack::StartAudio(
524 RefPtr<AudioInputSource>&& aAudioInputSource) {
525 MOZ_ASSERT(mGraph->OnGraphThread());
526 MOZ_ASSERT(aAudioInputSource->mPrincipalHandle == mPrincipalHandle);
527 MOZ_ASSERT(aAudioInputSource->mDeviceId == mDeviceId);
529 TRACK_GRAPH_LOG("StartAudio with source %p", aAudioInputSource.get());
530 mAudioSource = std::move(aAudioInputSource);
531 mAudioSource->Start();
534 void NonNativeInputTrack::StopAudio() {
535 MOZ_ASSERT(mGraph->OnGraphThread());
537 TRACK_GRAPH_LOG("StopAudio from source %p", mAudioSource.get());
538 if (!mAudioSource) {
539 return;
541 mAudioSource->Stop();
542 mAudioSource = nullptr;
545 AudioInputType NonNativeInputTrack::DevicePreference() const {
546 MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
547 return mAudioSource && mAudioSource->mIsVoice ? AudioInputType::Voice
548 : AudioInputType::Unknown;
551 void NonNativeInputTrack::NotifyDeviceChanged(uint32_t aSourceId) {
552 MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
554 // No need to forward the notification if the audio input has been stopped or
555 // restarted by it users.
556 if (!mAudioSource || mAudioSource->mId != aSourceId) {
557 TRACK_GRAPH_LOG("(NonNative) NotifyDeviceChanged: No need to forward");
558 return;
561 TRACK_GRAPH_LOG("(NonNative) NotifyDeviceChanged");
562 // Forward the notification.
563 DeviceInputTrack::DeviceChanged(mGraph);
566 void NonNativeInputTrack::NotifyInputStopped(uint32_t aSourceId) {
567 MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
569 // No need to forward the notification if the audio input has been stopped or
570 // restarted by it users.
571 if (!mAudioSource || mAudioSource->mId != aSourceId) {
572 TRACK_GRAPH_LOG("(NonNative) NotifyInputStopped: No need to forward");
573 return;
576 TRACK_GRAPH_LOGE(
577 "(NonNative) NotifyInputStopped: audio unexpectedly stopped");
578 // Destory the underlying audio stream if it's stopped unexpectedly.
579 mAudioSource->Stop();
582 AudioInputSource::Id NonNativeInputTrack::GenerateSourceId() {
583 MOZ_ASSERT(mGraph->OnGraphThread());
584 return mSourceIdNumber++;
587 bool NonNativeInputTrack::CheckGraphDriverChanged() {
588 MOZ_ASSERT(mGraph->CurrentDriver()->OnThread());
590 std::thread::id currentId = std::this_thread::get_id();
591 if (mGraphDriverThreadId == currentId) {
592 return false;
594 mGraphDriverThreadId = currentId;
595 return true;
598 AudioInputSourceListener::AudioInputSourceListener(NonNativeInputTrack* aOwner)
599 : mOwner(aOwner) {}
601 void AudioInputSourceListener::AudioDeviceChanged(
602 AudioInputSource::Id aSourceId) {
603 MOZ_ASSERT(NS_IsMainThread());
604 MOZ_ASSERT(mOwner);
606 if (mOwner->IsDestroyed()) {
607 LOG("NonNativeInputTrack %p has been destroyed. No need to forward the "
608 "audio device-changed notification",
609 mOwner.get());
610 return;
613 class DeviceChangedMessage : public ControlMessage {
614 public:
615 DeviceChangedMessage(NonNativeInputTrack* aInputTrack,
616 AudioInputSource::Id aSourceId)
617 : ControlMessage(nullptr),
618 mInputTrack(aInputTrack),
619 mSourceId(aSourceId) {
620 MOZ_ASSERT(mInputTrack);
622 void Run() override {
623 TRACE("NonNativeInputTrack::AudioDeviceChanged ControlMessage");
624 mInputTrack->NotifyDeviceChanged(mSourceId);
626 RefPtr<NonNativeInputTrack> mInputTrack;
627 AudioInputSource::Id mSourceId;
630 MOZ_DIAGNOSTIC_ASSERT(mOwner->GraphImpl());
631 mOwner->GraphImpl()->AppendMessage(
632 MakeUnique<DeviceChangedMessage>(mOwner.get(), aSourceId));
635 void AudioInputSourceListener::AudioStateCallback(
636 AudioInputSource::Id aSourceId,
637 AudioInputSource::EventListener::State aState) {
638 MOZ_ASSERT(NS_IsMainThread());
639 MOZ_ASSERT(mOwner);
641 const char* state =
642 aState == AudioInputSource::EventListener::State::Started ? "started"
643 : aState == AudioInputSource::EventListener::State::Stopped ? "stopped"
644 : aState == AudioInputSource::EventListener::State::Drained ? "drained"
645 : "error";
647 if (mOwner->IsDestroyed()) {
648 LOG("NonNativeInputTrack %p has been destroyed. No need to forward the "
649 "audio state-changed(%s) notification",
650 mOwner.get(), state);
651 return;
654 if (aState == AudioInputSource::EventListener::State::Started) {
655 LOG("We can ignore %s notification for NonNativeInputTrack %p", state,
656 mOwner.get());
657 return;
660 LOG("Notify audio stopped due to entering %s state", state);
662 class InputStoppedMessage : public ControlMessage {
663 public:
664 InputStoppedMessage(NonNativeInputTrack* aInputTrack,
665 AudioInputSource::Id aSourceId)
666 : ControlMessage(nullptr),
667 mInputTrack(aInputTrack),
668 mSourceId(aSourceId) {
669 MOZ_ASSERT(mInputTrack);
671 void Run() override {
672 TRACE("NonNativeInputTrack::AudioStateCallback ControlMessage");
673 mInputTrack->NotifyInputStopped(mSourceId);
675 RefPtr<NonNativeInputTrack> mInputTrack;
676 AudioInputSource::Id mSourceId;
679 MOZ_DIAGNOSTIC_ASSERT(mOwner->GraphImpl());
680 mOwner->GraphImpl()->AppendMessage(
681 MakeUnique<InputStoppedMessage>(mOwner.get(), aSourceId));
684 #undef LOG_INTERNAL
685 #undef LOG
686 #undef LOGE
687 #undef TRACK_GRAPH_LOG_INTERNAL
688 #undef TRACK_GRAPH_LOG
689 #undef TRACK_GRAPH_LOGV
690 #undef TRACK_GRAPH_LOGE
691 #undef CONSUMER_GRAPH_LOG_INTERNAL
692 #undef CONSUMER_GRAPH_LOGV
694 } // namespace mozilla