tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DeviceInputTrack.cpp (25307B)


      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/. */
      6 
      7 #include "DeviceInputTrack.h"
      8 
      9 #include "Tracing.h"
     10 
     11 namespace mozilla {
     12 
     13 #ifdef LOG_INTERNAL
     14 #  undef LOG_INTERNAL
     15 #endif  // LOG_INTERNAL
     16 #define LOG_INTERNAL(level, msg, ...) \
     17  MOZ_LOG(gMediaTrackGraphLog, LogLevel::level, (msg, ##__VA_ARGS__))
     18 
     19 #ifdef LOG
     20 #  undef LOG
     21 #endif  // LOG
     22 #define LOG(msg, ...) LOG_INTERNAL(Debug, msg, ##__VA_ARGS__)
     23 
     24 #ifdef LOGE
     25 #  undef LOGE
     26 #endif  // LOGE
     27 #define LOGE(msg, ...) LOG_INTERNAL(Error, msg, ##__VA_ARGS__)
     28 
     29 // This can only be called in graph thread since mGraph->CurrentDriver() is
     30 // graph thread only
     31 #ifdef TRACK_GRAPH_LOG_INTERNAL
     32 #  undef TRACK_GRAPH_LOG_INTERNAL
     33 #endif  // TRACK_GRAPH_LOG_INTERNAL
     34 #define TRACK_GRAPH_LOG_INTERNAL(level, msg, ...)                        \
     35  LOG_INTERNAL(level, "(Graph %p, Driver %p) DeviceInputTrack %p, " msg, \
     36               this->mGraph, this->mGraph->CurrentDriver(), this,        \
     37               ##__VA_ARGS__)
     38 
     39 #ifdef TRACK_GRAPH_LOG
     40 #  undef TRACK_GRAPH_LOG
     41 #endif  // TRACK_GRAPH_LOG
     42 #define TRACK_GRAPH_LOG(msg, ...) \
     43  TRACK_GRAPH_LOG_INTERNAL(Debug, msg, ##__VA_ARGS__)
     44 
     45 #ifdef TRACK_GRAPH_LOGV
     46 #  undef TRACK_GRAPH_LOGV
     47 #endif  // TRACK_GRAPH_LOGV
     48 #define TRACK_GRAPH_LOGV(msg, ...) \
     49  TRACK_GRAPH_LOG_INTERNAL(Verbose, msg, ##__VA_ARGS__)
     50 
     51 #ifdef TRACK_GRAPH_LOGE
     52 #  undef TRACK_GRAPH_LOGE
     53 #endif  // TRACK_GRAPH_LOGE
     54 #define TRACK_GRAPH_LOGE(msg, ...) \
     55  TRACK_GRAPH_LOG_INTERNAL(Error, msg, ##__VA_ARGS__)
     56 
     57 #ifdef CONSUMER_GRAPH_LOG_INTERNAL
     58 #  undef CONSUMER_GRAPH_LOG_INTERNAL
     59 #endif  // CONSUMER_GRAPH_LOG_INTERNAL
     60 #define CONSUMER_GRAPH_LOG_INTERNAL(level, msg, ...)                    \
     61  LOG_INTERNAL(                                                         \
     62      level, "(Graph %p, Driver %p) DeviceInputConsumerTrack %p, " msg, \
     63      this->mGraph, this->mGraph->CurrentDriver(), this, ##__VA_ARGS__)
     64 
     65 #ifdef CONSUMER_GRAPH_LOGV
     66 #  undef CONSUMER_GRAPH_LOGV
     67 #endif  // CONSUMER_GRAPH_LOGV
     68 #define CONSUMER_GRAPH_LOGV(msg, ...) \
     69  CONSUMER_GRAPH_LOG_INTERNAL(Verbose, msg, ##__VA_ARGS__)
     70 
     71 DeviceInputConsumerTrack::DeviceInputConsumerTrack(TrackRate aSampleRate)
     72    : ProcessedMediaTrack(aSampleRate, MediaSegment::AUDIO,
     73                          new AudioSegment()) {}
     74 
     75 void DeviceInputConsumerTrack::ConnectDeviceInput(
     76    CubebUtils::AudioDeviceID aId, AudioDataListener* aListener,
     77    const PrincipalHandle& aPrincipal) {
     78  MOZ_ASSERT(NS_IsMainThread());
     79  MOZ_ASSERT(Graph());
     80  MOZ_ASSERT(aListener);
     81  MOZ_ASSERT(!mListener);
     82  MOZ_ASSERT(!mDeviceInputTrack);
     83  MOZ_ASSERT(mDeviceId.isNothing());
     84  MOZ_ASSERT(!mDeviceInputTrack,
     85             "Must disconnect a device input before connecting a new one");
     86 
     87  mListener = aListener;
     88  mDeviceId.emplace(aId);
     89 
     90  mDeviceInputTrack =
     91      DeviceInputTrack::OpenAudio(Graph(), aId, aPrincipal, this);
     92  LOG("Open device %p (DeviceInputTrack %p) for consumer %p", aId,
     93      mDeviceInputTrack.get(), this);
     94  mPort = AllocateInputPort(mDeviceInputTrack.get());
     95 }
     96 
     97 void DeviceInputConsumerTrack::DisconnectDeviceInput() {
     98  MOZ_ASSERT(NS_IsMainThread());
     99  MOZ_ASSERT(Graph());
    100 
    101  if (!mListener) {
    102    MOZ_ASSERT(mDeviceId.isNothing());
    103    MOZ_ASSERT(!mDeviceInputTrack);
    104    return;
    105  }
    106 
    107  MOZ_ASSERT(mPort);
    108  MOZ_ASSERT(mDeviceInputTrack);
    109  MOZ_ASSERT(mDeviceId.isSome());
    110 
    111  LOG("Close device %p (DeviceInputTrack %p) for consumer %p ", *mDeviceId,
    112      mDeviceInputTrack.get(), this);
    113  mPort->Destroy();
    114  DeviceInputTrack::CloseAudio(mDeviceInputTrack.forget(), this);
    115  mListener = nullptr;
    116  mDeviceId = Nothing();
    117 }
    118 
    119 Maybe<CubebUtils::AudioDeviceID> DeviceInputConsumerTrack::DeviceId() const {
    120  MOZ_ASSERT(NS_IsMainThread());
    121  return mDeviceId;
    122 }
    123 
    124 NotNull<AudioDataListener*> DeviceInputConsumerTrack::GetAudioDataListener()
    125    const {
    126  MOZ_ASSERT(NS_IsMainThread());
    127  return WrapNotNull(mListener.get());
    128 }
    129 
    130 bool DeviceInputConsumerTrack::ConnectedToNativeDevice() const {
    131  MOZ_ASSERT(NS_IsMainThread());
    132  return mDeviceInputTrack && mDeviceInputTrack->AsNativeInputTrack();
    133 }
    134 
    135 bool DeviceInputConsumerTrack::ConnectedToNonNativeDevice() const {
    136  MOZ_ASSERT(NS_IsMainThread());
    137  return mDeviceInputTrack && mDeviceInputTrack->AsNonNativeInputTrack();
    138 }
    139 
    140 DeviceInputTrack* DeviceInputConsumerTrack::GetDeviceInputTrackGraphThread()
    141    const {
    142  AssertOnGraphThread();
    143 
    144  if (mInputs.IsEmpty()) {
    145    return nullptr;
    146  }
    147  MOZ_ASSERT(mInputs.Length() == 1);
    148  MediaTrack* track = mInputs[0]->GetSource();
    149  MOZ_ASSERT(track->AsDeviceInputTrack());
    150  return static_cast<DeviceInputTrack*>(track);
    151 }
    152 
    153 void DeviceInputConsumerTrack::GetInputSourceData(AudioSegment& aOutput,
    154                                                  GraphTime aFrom,
    155                                                  GraphTime aTo) const {
    156  AssertOnGraphThread();
    157  MOZ_ASSERT(aOutput.IsEmpty());
    158  MOZ_ASSERT(mInputs.Length() == 1);
    159 
    160  MediaInputPort* port = mInputs[0];
    161  MediaTrack* source = port->GetSource();
    162  GraphTime next;
    163  for (GraphTime t = aFrom; t < aTo; t = next) {
    164    MediaInputPort::InputInterval interval =
    165        MediaInputPort::GetNextInputInterval(port, t);
    166    interval.mEnd = std::min(interval.mEnd, aTo);
    167 
    168    const bool inputEnded =
    169        source->Ended() &&
    170        source->GetEnd() <=
    171            source->GraphTimeToTrackTimeWithBlocking(interval.mStart);
    172 
    173    TrackTime ticks = interval.mEnd - interval.mStart;
    174    next = interval.mEnd;
    175 
    176    if (interval.mStart >= interval.mEnd) {
    177      break;
    178    }
    179 
    180    if (inputEnded) {
    181      aOutput.AppendNullData(ticks);
    182      CONSUMER_GRAPH_LOGV(
    183          "Getting %" PRId64
    184          " ticks of null data from input port source (ended input)",
    185          ticks);
    186    } else if (interval.mInputIsBlocked) {
    187      aOutput.AppendNullData(ticks);
    188      CONSUMER_GRAPH_LOGV(
    189          "Getting %" PRId64
    190          " ticks of null data from input port source (blocked input)",
    191          ticks);
    192    } else if (source->IsSuspended()) {
    193      aOutput.AppendNullData(ticks);
    194      CONSUMER_GRAPH_LOGV(
    195          "Getting %" PRId64
    196          " ticks of null data from input port source (source is suspended)",
    197          ticks);
    198    } else {
    199      TrackTime start =
    200          source->GraphTimeToTrackTimeWithBlocking(interval.mStart);
    201      TrackTime end = source->GraphTimeToTrackTimeWithBlocking(interval.mEnd);
    202      MOZ_ASSERT(source->GetData<AudioSegment>()->GetDuration() >= end);
    203      aOutput.AppendSlice(*source->GetData<AudioSegment>(), start, end);
    204      CONSUMER_GRAPH_LOGV("Getting %" PRId64
    205                          " ticks of real data from input port source %p",
    206                          end - start, source);
    207    }
    208  }
    209 }
    210 
    211 /* static */
    212 NotNull<RefPtr<DeviceInputTrack>> DeviceInputTrack::OpenAudio(
    213    MediaTrackGraph* aGraph, CubebUtils::AudioDeviceID aDeviceId,
    214    const PrincipalHandle& aPrincipalHandle,
    215    DeviceInputConsumerTrack* aConsumer) {
    216  MOZ_ASSERT(NS_IsMainThread());
    217  MOZ_ASSERT(aConsumer);
    218  MOZ_ASSERT(aGraph == aConsumer->Graph());
    219 
    220  RefPtr<DeviceInputTrack> track =
    221      aGraph->GetDeviceInputTrackMainThread(aDeviceId);
    222  if (track) {
    223    MOZ_ASSERT(!track->mConsumerTracks.IsEmpty());
    224    track->AddDataListener(aConsumer->GetAudioDataListener());
    225  } else {
    226    // Create a NativeInputTrack or NonNativeInputTrack, depending on whether
    227    // the given graph already has a native device or not.
    228    if (aGraph->GetNativeInputTrackMainThread()) {
    229      // A native device is already in use. This device will be a non-native
    230      // device.
    231      track = new NonNativeInputTrack(aGraph->GraphRate(), aDeviceId,
    232                                      aPrincipalHandle);
    233    } else {
    234      // No native device is in use. This device will be the native device.
    235      track = new NativeInputTrack(aGraph->GraphRate(), aDeviceId,
    236                                   aPrincipalHandle);
    237    }
    238    LOG("Create %sNativeInputTrack %p in MTG %p for device %p",
    239        (track->AsNativeInputTrack() ? "" : "Non"), track.get(), aGraph,
    240        aDeviceId);
    241    aGraph->AddTrack(track);
    242    // Add the listener before opening the device so the device passed to
    243    // OpenAudioInput always has a non-zero input channel count.
    244    track->AddDataListener(aConsumer->GetAudioDataListener());
    245    aGraph->OpenAudioInput(track);
    246  }
    247  MOZ_ASSERT(track->AsNativeInputTrack() || track->AsNonNativeInputTrack());
    248  MOZ_ASSERT(track->mDeviceId == aDeviceId);
    249 
    250  MOZ_ASSERT(!track->mConsumerTracks.Contains(aConsumer));
    251  track->mConsumerTracks.AppendElement(aConsumer);
    252 
    253  LOG("DeviceInputTrack %p (device %p: %snative) in MTG %p has %zu users now",
    254      track.get(), track->mDeviceId,
    255      (track->AsNativeInputTrack() ? "" : "non-"), aGraph,
    256      track->mConsumerTracks.Length());
    257  if (track->mConsumerTracks.Length() > 1) {
    258    track->ReevaluateInputDevice();
    259  }
    260 
    261  return WrapNotNull(track);
    262 }
    263 
    264 /* static */
    265 void DeviceInputTrack::CloseAudio(already_AddRefed<DeviceInputTrack> aTrack,
    266                                  DeviceInputConsumerTrack* aConsumer) {
    267  MOZ_ASSERT(NS_IsMainThread());
    268 
    269  RefPtr<DeviceInputTrack> track = aTrack;
    270  MOZ_ASSERT(track);
    271 
    272  track->RemoveDataListener(aConsumer->GetAudioDataListener());
    273  DebugOnly<bool> removed = track->mConsumerTracks.RemoveElement(aConsumer);
    274  MOZ_ASSERT(removed);
    275  LOG("DeviceInputTrack %p (device %p) in MTG %p has %zu users now",
    276      track.get(), track->mDeviceId, track->Graph(),
    277      track->mConsumerTracks.Length());
    278  if (track->mConsumerTracks.IsEmpty()) {
    279    track->Graph()->CloseAudioInput(track);
    280    track->Destroy();
    281  } else {
    282    track->ReevaluateInputDevice();
    283  }
    284 }
    285 
    286 const nsTArray<RefPtr<DeviceInputConsumerTrack>>&
    287 DeviceInputTrack::GetConsumerTracks() const {
    288  MOZ_ASSERT(NS_IsMainThread());
    289  return mConsumerTracks;
    290 }
    291 
    292 DeviceInputTrack::DeviceInputTrack(TrackRate aSampleRate,
    293                                   CubebUtils::AudioDeviceID aDeviceId,
    294                                   const PrincipalHandle& aPrincipalHandle)
    295    : ProcessedMediaTrack(aSampleRate, MediaSegment::AUDIO, new AudioSegment()),
    296      mDeviceId(aDeviceId),
    297      mPrincipalHandle(aPrincipalHandle) {}
    298 
    299 uint32_t DeviceInputTrack::MaxRequestedInputChannels() const {
    300  AssertOnGraphThreadOrNotRunning();
    301  uint32_t maxInputChannels = 0;
    302  for (const auto& listener : mListeners) {
    303    maxInputChannels = std::max(maxInputChannels,
    304                                listener->RequestedInputChannelCount(mGraph));
    305  }
    306  return maxInputChannels;
    307 }
    308 
    309 bool DeviceInputTrack::HasVoiceInput() const {
    310  AssertOnGraphThreadOrNotRunning();
    311  for (const auto& listener : mListeners) {
    312    if (listener->IsVoiceInput(mGraph)) {
    313      return true;
    314    }
    315  }
    316  return false;
    317 }
    318 
    319 AudioInputProcessingParamsRequest
    320 DeviceInputTrack::UpdateRequestedProcessingParams() {
    321  AssertOnGraphThreadOrNotRunning();
    322  Maybe<cubeb_input_processing_params> params;
    323  for (const auto& listener : mListeners) {
    324    if (params) {
    325      *params &= listener->RequestedInputProcessingParams(mGraph);
    326    } else {
    327      params = Some(listener->RequestedInputProcessingParams(mGraph));
    328    }
    329  }
    330 
    331  if (auto p = params.valueOr(CUBEB_INPUT_PROCESSING_PARAM_NONE);
    332      p != mProcessingParamsRequest.mParams) {
    333    mProcessingParamsRequest.mParams = p;
    334    mProcessingParamsRequest.mGeneration =
    335        Graph()->ProcessingParamsGeneration();
    336 
    337    TRACK_GRAPH_LOG(
    338        "%sNativeInputTrack notifying of setting requested processing params "
    339        "%s (Gen %d)",
    340        (AsNonNativeInputTrack() ? "Non" : ""),
    341        CubebUtils::ProcessingParamsToString(mProcessingParamsRequest.mParams)
    342            .get(),
    343        mProcessingParamsRequest.mGeneration);
    344 
    345    NotifySetRequestedProcessingParams(Graph(),
    346                                       mProcessingParamsRequest.mGeneration,
    347                                       mProcessingParamsRequest.mParams);
    348  }
    349 
    350  return mProcessingParamsRequest;
    351 }
    352 
    353 void DeviceInputTrack::DeviceChanged(MediaTrackGraph* aGraph) const {
    354  AssertOnGraphThreadOrNotRunning();
    355  MOZ_ASSERT(aGraph == mGraph,
    356             "Receive device changed signal from another graph");
    357  TRACK_GRAPH_LOG("DeviceChanged");
    358  for (const auto& listener : mListeners) {
    359    listener->DeviceChanged(aGraph);
    360  }
    361 }
    362 
    363 void DeviceInputTrack::NotifySetRequestedProcessingParams(
    364    MediaTrackGraph* aGraph, int aGeneration,
    365    cubeb_input_processing_params aRequestedParams) {
    366  AssertOnGraphThread();
    367  for (const auto& listener : mListeners) {
    368    listener->NotifySetRequestedInputProcessingParams(mGraph, aGeneration,
    369                                                      aRequestedParams);
    370  }
    371 }
    372 
    373 void DeviceInputTrack::NotifySetRequestedProcessingParamsResult(
    374    MediaTrackGraph* aGraph, int aGeneration,
    375    const Result<cubeb_input_processing_params, int>& aResult) {
    376  AssertOnGraphThread();
    377  for (const auto& listener : mListeners) {
    378    listener->NotifySetRequestedInputProcessingParamsResult(mGraph, aGeneration,
    379                                                            aResult);
    380  }
    381 }
    382 
    383 void DeviceInputTrack::ReevaluateInputDevice() {
    384  MOZ_ASSERT(NS_IsMainThread());
    385  QueueControlMessageWithNoShutdown([self = RefPtr{this}, this] {
    386    TRACE("DeviceInputTrack::ReevaluateInputDevice ControlMessage");
    387    Graph()->ReevaluateInputDevice(mDeviceId);
    388  });
    389 }
    390 
    391 void DeviceInputTrack::AddDataListener(AudioDataListener* aListener) {
    392  MOZ_ASSERT(NS_IsMainThread());
    393  QueueControlMessageWithNoShutdown(
    394      [self = RefPtr{this}, this, listener = RefPtr{aListener}] {
    395        TRACE("DeviceInputTrack::AddDataListener ControlMessage");
    396        MOZ_ASSERT(!mListeners.Contains(listener.get()),
    397                   "Don't add a listener twice.");
    398        mListeners.AppendElement(listener.get());
    399      });
    400 }
    401 
    402 void DeviceInputTrack::RemoveDataListener(AudioDataListener* aListener) {
    403  MOZ_ASSERT(NS_IsMainThread());
    404  QueueControlMessageWithNoShutdown(
    405      [self = RefPtr{this}, this, listener = RefPtr{aListener}] {
    406        TRACE("DeviceInputTrack::RemoveDataListener ControlMessage");
    407        DebugOnly<bool> wasPresent = mListeners.RemoveElement(listener.get());
    408        MOZ_ASSERT(wasPresent, "Remove an unknown listener");
    409        listener->Disconnect(Graph());
    410      });
    411 }
    412 
    413 NativeInputTrack::NativeInputTrack(TrackRate aSampleRate,
    414                                   CubebUtils::AudioDeviceID aDeviceId,
    415                                   const PrincipalHandle& aPrincipalHandle)
    416    : DeviceInputTrack(aSampleRate, aDeviceId, aPrincipalHandle),
    417      mIsBufferingAppended(false),
    418      mInputChannels(0) {}
    419 
    420 void NativeInputTrack::DestroyImpl() {
    421  AssertOnGraphThreadOrNotRunning();
    422  mPendingData.Clear();
    423  ProcessedMediaTrack::DestroyImpl();
    424 }
    425 
    426 void NativeInputTrack::ProcessInput(GraphTime aFrom, GraphTime aTo,
    427                                    uint32_t aFlags) {
    428  AssertOnGraphThread();
    429  TRACE_COMMENT("NativeInputTrack::ProcessInput", "%p", this);
    430 
    431  TRACK_GRAPH_LOGV("(Native) ProcessInput from %" PRId64 " to %" PRId64
    432                   ", needs %" PRId64 " frames",
    433                   aFrom, aTo, aTo - aFrom);
    434 
    435  TrackTime from = GraphTimeToTrackTime(aFrom);
    436  TrackTime to = GraphTimeToTrackTime(aTo);
    437  MOZ_ASSERT(from < to);
    438 
    439  MOZ_ASSERT_IF(!mIsBufferingAppended, mPendingData.IsEmpty());
    440 
    441  TrackTime need = to - from;
    442  TrackTime dataNeed = std::min(mPendingData.GetDuration(), need);
    443  TrackTime silenceNeed = std::max(need - dataNeed, (TrackTime)0);
    444 
    445  // TODO (bug 1879353): Reenable assertion.
    446  // MOZ_ASSERT_IF(dataNeed > 0, silenceNeed == 0);
    447 
    448  GetData<AudioSegment>()->AppendSlice(mPendingData, 0, dataNeed);
    449  mPendingData.RemoveLeading(dataNeed);
    450  GetData<AudioSegment>()->AppendNullData(silenceNeed);
    451 
    452  // TODO (bug 1879353): Remove as assertion above will hold.
    453  if (dataNeed > 0 && silenceNeed > 0) {
    454    NotifyInputStopped(mGraph);
    455  }
    456 }
    457 
    458 uint32_t NativeInputTrack::NumberOfChannels() const {
    459  AssertOnGraphThreadOrNotRunning();
    460  return mInputChannels;
    461 }
    462 
    463 void NativeInputTrack::NotifyInputStopped(MediaTrackGraph* aGraph) {
    464  AssertOnGraphThreadOrNotRunning();
    465  MOZ_ASSERT(aGraph == mGraph,
    466             "Receive input stopped signal from another graph");
    467  TRACK_GRAPH_LOG("(Native) NotifyInputStopped");
    468  mInputChannels = 0;
    469  mIsBufferingAppended = false;
    470  mPendingData.Clear();
    471 }
    472 
    473 void NativeInputTrack::NotifyInputData(MediaTrackGraph* aGraph,
    474                                       const AudioDataValue* aBuffer,
    475                                       size_t aFrames, TrackRate aRate,
    476                                       uint32_t aChannels,
    477                                       uint32_t aAlreadyBuffered) {
    478  AssertOnGraphThread();
    479  MOZ_ASSERT(aGraph == mGraph, "Receive input data from another graph");
    480  TRACK_GRAPH_LOGV(
    481      "NotifyInputData: frames=%zu, rate=%d, channel=%u, alreadyBuffered=%u",
    482      aFrames, aRate, aChannels, aAlreadyBuffered);
    483 
    484  if (!mIsBufferingAppended) {
    485    // First time we see live frames getting added. Use what's already buffered
    486    // in the driver's scratch buffer as a starting point.
    487    MOZ_ASSERT(mPendingData.IsEmpty());
    488    constexpr TrackTime buffering = WEBAUDIO_BLOCK_SIZE;
    489    const TrackTime remaining =
    490        buffering - static_cast<TrackTime>(aAlreadyBuffered);
    491    mPendingData.AppendNullData(remaining);
    492    mIsBufferingAppended = true;
    493    TRACK_GRAPH_LOG("Set mIsBufferingAppended by appending %" PRId64 " frames.",
    494                    remaining);
    495  }
    496 
    497  MOZ_ASSERT(aChannels);
    498  if (!mInputChannels) {
    499    mInputChannels = aChannels;
    500  }
    501  mPendingData.AppendFromInterleavedBuffer(aBuffer, aFrames, aChannels,
    502                                           mPrincipalHandle);
    503 }
    504 
    505 NonNativeInputTrack::NonNativeInputTrack(
    506    TrackRate aSampleRate, CubebUtils::AudioDeviceID aDeviceId,
    507    const PrincipalHandle& aPrincipalHandle)
    508    : DeviceInputTrack(aSampleRate, aDeviceId, aPrincipalHandle),
    509      mAudioSource(nullptr),
    510      mSourceIdNumber(0) {}
    511 
    512 void NonNativeInputTrack::DestroyImpl() {
    513  AssertOnGraphThreadOrNotRunning();
    514  if (mAudioSource) {
    515    mAudioSource->Stop();
    516    mAudioSource = nullptr;
    517  }
    518  ProcessedMediaTrack::DestroyImpl();
    519 }
    520 
    521 void NonNativeInputTrack::ProcessInput(GraphTime aFrom, GraphTime aTo,
    522                                       uint32_t aFlags) {
    523  AssertOnGraphThread();
    524  TRACE_COMMENT("NonNativeInputTrack::ProcessInput", "%p", this);
    525 
    526  TRACK_GRAPH_LOGV("(NonNative) ProcessInput from %" PRId64 " to %" PRId64
    527                   ", needs %" PRId64 " frames",
    528                   aFrom, aTo, aTo - aFrom);
    529 
    530  TrackTime from = GraphTimeToTrackTime(aFrom);
    531  TrackTime to = GraphTimeToTrackTime(aTo);
    532  MOZ_ASSERT(from < to);
    533 
    534  TrackTime delta = to - from;
    535  if (!mAudioSource) {
    536    GetData<AudioSegment>()->AppendNullData(delta);
    537    return;
    538  }
    539 
    540  AudioInputSource::Consumer consumer = AudioInputSource::Consumer::Same;
    541  // GraphRunner keeps the same thread.
    542  MOZ_ASSERT(!HasGraphThreadChanged());
    543 
    544  ReevaluateProcessingParams();
    545 
    546  AudioSegment data = mAudioSource->GetAudioSegment(delta, consumer);
    547  MOZ_ASSERT(data.GetDuration() == delta);
    548  GetData<AudioSegment>()->AppendFrom(&data);
    549 }
    550 
    551 uint32_t NonNativeInputTrack::NumberOfChannels() const {
    552  AssertOnGraphThreadOrNotRunning();
    553  return mAudioSource ? mAudioSource->mChannelCount : 0;
    554 }
    555 
    556 void NonNativeInputTrack::StartAudio(
    557    RefPtr<AudioInputSource>&& aAudioInputSource) {
    558  AssertOnGraphThread();
    559  MOZ_ASSERT(aAudioInputSource->mPrincipalHandle == mPrincipalHandle);
    560  MOZ_ASSERT(aAudioInputSource->mDeviceId == mDeviceId);
    561 
    562  TRACK_GRAPH_LOG("StartAudio with source %p", aAudioInputSource.get());
    563 #ifdef DEBUG
    564  mGraphThreadId = std::this_thread::get_id();
    565 #endif
    566  mAudioSource = std::move(aAudioInputSource);
    567  mAudioSource->Init();
    568  ReevaluateProcessingParams();
    569  mAudioSource->Start();
    570 }
    571 
    572 void NonNativeInputTrack::StopAudio() {
    573  AssertOnGraphThread();
    574 
    575  TRACK_GRAPH_LOG("StopAudio from source %p", mAudioSource.get());
    576  if (!mAudioSource) {
    577    return;
    578  }
    579  mAudioSource->Stop();
    580  mAudioSource = nullptr;
    581 #ifdef DEBUG
    582  mGraphThreadId = std::thread::id();
    583 #endif
    584 }
    585 
    586 AudioInputType NonNativeInputTrack::DevicePreference() const {
    587  AssertOnGraphThreadOrNotRunning();
    588  return mAudioSource && mAudioSource->mIsVoice ? AudioInputType::Voice
    589                                                : AudioInputType::Unknown;
    590 }
    591 
    592 void NonNativeInputTrack::NotifyDeviceChanged(uint32_t aSourceId) {
    593  AssertOnGraphThreadOrNotRunning();
    594 
    595  // No need to forward the notification if the audio input has been stopped or
    596  // restarted by it users.
    597  if (!mAudioSource || mAudioSource->mId != aSourceId) {
    598    TRACK_GRAPH_LOG("(NonNative) NotifyDeviceChanged: No need to forward");
    599    return;
    600  }
    601 
    602  TRACK_GRAPH_LOG("(NonNative) NotifyDeviceChanged");
    603  // Forward the notification.
    604  DeviceInputTrack::DeviceChanged(mGraph);
    605 }
    606 
    607 void NonNativeInputTrack::NotifyInputStopped(uint32_t aSourceId) {
    608  AssertOnGraphThreadOrNotRunning();
    609 
    610  // No need to forward the notification if the audio input has been stopped or
    611  // restarted by it users.
    612  if (!mAudioSource || mAudioSource->mId != aSourceId) {
    613    TRACK_GRAPH_LOG("(NonNative) NotifyInputStopped: No need to forward");
    614    return;
    615  }
    616 
    617  TRACK_GRAPH_LOGE(
    618      "(NonNative) NotifyInputStopped: audio unexpectedly stopped");
    619  // Destory the underlying audio stream if it's stopped unexpectedly.
    620  mAudioSource->Stop();
    621 }
    622 
    623 AudioInputSource::Id NonNativeInputTrack::GenerateSourceId() {
    624  AssertOnGraphThread();
    625  return mSourceIdNumber++;
    626 }
    627 
    628 void NonNativeInputTrack::ReevaluateProcessingParams() {
    629  AssertOnGraphThread();
    630  MOZ_ASSERT(mAudioSource);
    631  auto request = UpdateRequestedProcessingParams();
    632  if (mRequestedProcessingParamsGeneration == request.mGeneration) {
    633    return;
    634  }
    635  auto generation = mRequestedProcessingParamsGeneration = request.mGeneration;
    636  auto params = request.mParams;
    637  using Promise = AudioInputSource::SetRequestedProcessingParamsPromise;
    638  mAudioSource->SetRequestedProcessingParams(params)->Then(
    639      GetMainThreadSerialEventTarget(), __func__,
    640      [this, self = RefPtr(this),
    641       generation](Promise::ResolveOrRejectValue&& aValue) {
    642        if (IsDestroyed()) {
    643          return;
    644        }
    645        auto result = ([&]() -> Result<cubeb_input_processing_params, int> {
    646          if (aValue.IsResolve()) {
    647            return aValue.ResolveValue();
    648          }
    649          return Err(aValue.RejectValue());
    650        })();
    651        QueueControlMessageWithNoShutdown([this, self = RefPtr(this),
    652                                           generation,
    653                                           result = std::move(result)] {
    654          NotifySetRequestedProcessingParamsResult(Graph(), generation, result);
    655        });
    656      });
    657 }
    658 
    659 #ifdef DEBUG
    660 bool NonNativeInputTrack::HasGraphThreadChanged() {
    661  AssertOnGraphThread();
    662 
    663  std::thread::id currentId = std::this_thread::get_id();
    664  if (mGraphThreadId == currentId) {
    665    return false;
    666  }
    667  mGraphThreadId = currentId;
    668  return true;
    669 }
    670 #endif  // DEBUG
    671 
    672 AudioInputSourceListener::AudioInputSourceListener(NonNativeInputTrack* aOwner)
    673    : mOwner(aOwner) {}
    674 
    675 void AudioInputSourceListener::AudioDeviceChanged(
    676    AudioInputSource::Id aSourceId) {
    677  MOZ_ASSERT(NS_IsMainThread());
    678  MOZ_ASSERT(mOwner);
    679 
    680  if (mOwner->IsDestroyed()) {
    681    LOG("NonNativeInputTrack %p has been destroyed. No need to forward the "
    682        "audio device-changed notification",
    683        mOwner.get());
    684    return;
    685  }
    686 
    687  MOZ_DIAGNOSTIC_ASSERT(mOwner->Graph());
    688  mOwner->QueueControlMessageWithNoShutdown([inputTrack = mOwner, aSourceId] {
    689    TRACE("NonNativeInputTrack::AudioDeviceChanged ControlMessage");
    690    inputTrack->NotifyDeviceChanged(aSourceId);
    691  });
    692 }
    693 
    694 void AudioInputSourceListener::AudioStateCallback(
    695    AudioInputSource::Id aSourceId,
    696    AudioInputSource::EventListener::State aState) {
    697  MOZ_ASSERT(NS_IsMainThread());
    698  MOZ_ASSERT(mOwner);
    699 
    700  const char* state =
    701      aState == AudioInputSource::EventListener::State::Started   ? "started"
    702      : aState == AudioInputSource::EventListener::State::Stopped ? "stopped"
    703      : aState == AudioInputSource::EventListener::State::Drained ? "drained"
    704                                                                  : "error";
    705 
    706  if (mOwner->IsDestroyed()) {
    707    LOG("NonNativeInputTrack %p has been destroyed. No need to forward the "
    708        "audio state-changed(%s) notification",
    709        mOwner.get(), state);
    710    return;
    711  }
    712 
    713  if (aState == AudioInputSource::EventListener::State::Started) {
    714    LOG("We can ignore %s notification for NonNativeInputTrack %p", state,
    715        mOwner.get());
    716    return;
    717  }
    718 
    719  LOG("Notify audio stopped due to entering %s state", state);
    720 
    721  MOZ_DIAGNOSTIC_ASSERT(mOwner->Graph());
    722  mOwner->QueueControlMessageWithNoShutdown([inputTrack = mOwner, aSourceId] {
    723    TRACE("NonNativeInputTrack::AudioStateCallback ControlMessage");
    724    inputTrack->NotifyInputStopped(aSourceId);
    725  });
    726 }
    727 
    728 #undef LOG_INTERNAL
    729 #undef LOG
    730 #undef LOGE
    731 #undef TRACK_GRAPH_LOG_INTERNAL
    732 #undef TRACK_GRAPH_LOG
    733 #undef TRACK_GRAPH_LOGV
    734 #undef TRACK_GRAPH_LOGE
    735 #undef CONSUMER_GRAPH_LOG_INTERNAL
    736 #undef CONSUMER_GRAPH_LOGV
    737 
    738 }  // namespace mozilla