tor-browser

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

GraphDriver.cpp (56769B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=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 file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "GraphDriver.h"
      8 
      9 #include "AudioNodeEngine.h"
     10 #include "CallbackThreadRegistry.h"
     11 #include "CubebDeviceEnumerator.h"
     12 #include "MediaTrackGraphImpl.h"
     13 #include "Tracing.h"
     14 #include "cubeb/cubeb.h"
     15 #include "mozilla/ClearOnShutdown.h"
     16 #include "mozilla/MathAlgorithms.h"
     17 #include "mozilla/SchedulerGroup.h"
     18 #include "mozilla/SharedThreadPool.h"
     19 #include "mozilla/StaticPrefs_media.h"
     20 #include "mozilla/dom/AudioContext.h"
     21 #include "mozilla/dom/AudioDeviceInfo.h"
     22 #include "mozilla/dom/BaseAudioContextBinding.h"
     23 
     24 #ifdef MOZ_WEBRTC
     25 #  include "webrtc/MediaEngineWebRTC.h"
     26 #endif
     27 
     28 #ifdef XP_MACOSX
     29 #  include <sys/sysctl.h>
     30 
     31 #  include "nsCocoaFeatures.h"
     32 #endif
     33 
     34 extern mozilla::LazyLogModule gMediaTrackGraphLog;
     35 #ifdef LOG
     36 #  undef LOG
     37 #endif  // LOG
     38 #define LOG(type, msg) MOZ_LOG(gMediaTrackGraphLog, type, msg)
     39 
     40 namespace mozilla {
     41 
     42 GraphDriver::GraphDriver(GraphInterface* aGraphInterface,
     43                         GraphDriver* aPreviousDriver, uint32_t aSampleRate)
     44    : mGraphInterface(aGraphInterface),
     45      mSampleRate(aSampleRate),
     46      mPreviousDriver(aPreviousDriver) {}
     47 
     48 void GraphDriver::SetStreamName(const nsACString& aStreamName) {
     49  MOZ_ASSERT(InIteration() || (!ThreadRunning() && NS_IsMainThread()));
     50  mStreamName = aStreamName;
     51  LOG(LogLevel::Debug, ("%p: GraphDriver::SetStreamName driver=%p %s", Graph(),
     52                        this, mStreamName.get()));
     53 }
     54 
     55 void GraphDriver::SetState(const nsACString& aStreamName,
     56                           GraphTime aStateComputedTime,
     57                           TimeStamp aIterationTimeStamp) {
     58  MOZ_ASSERT(InIteration() || !ThreadRunning());
     59 
     60  mStreamName = aStreamName;
     61  mStateComputedTime = aStateComputedTime;
     62  mTargetIterationTimeStamp = aIterationTimeStamp;
     63 }
     64 
     65 #ifdef DEBUG
     66 bool GraphDriver::InIteration() const {
     67  return OnThread() || Graph()->InDriverIteration(this);
     68 }
     69 #endif
     70 
     71 GraphDriver* GraphDriver::PreviousDriver() {
     72  MOZ_ASSERT(InIteration() || !ThreadRunning());
     73  return mPreviousDriver;
     74 }
     75 
     76 void GraphDriver::SetPreviousDriver(GraphDriver* aPreviousDriver) {
     77  MOZ_ASSERT(InIteration() || !ThreadRunning());
     78  mPreviousDriver = aPreviousDriver;
     79 }
     80 
     81 ThreadedDriver::ThreadedDriver(GraphInterface* aGraphInterface,
     82                               GraphDriver* aPreviousDriver,
     83                               uint32_t aSampleRate)
     84    : GraphDriver(aGraphInterface, aPreviousDriver, aSampleRate),
     85      mThreadRunning(false) {}
     86 
     87 class MediaTrackGraphShutdownThreadRunnable : public Runnable {
     88 public:
     89  explicit MediaTrackGraphShutdownThreadRunnable(
     90      already_AddRefed<nsIThread> aThread)
     91      : Runnable("MediaTrackGraphShutdownThreadRunnable"), mThread(aThread) {}
     92  NS_IMETHOD Run() override {
     93    TRACE("MediaTrackGraphShutdownThreadRunnable");
     94    MOZ_ASSERT(NS_IsMainThread());
     95    MOZ_ASSERT(mThread);
     96 
     97    mThread->AsyncShutdown();
     98    mThread = nullptr;
     99    return NS_OK;
    100  }
    101 
    102 private:
    103  nsCOMPtr<nsIThread> mThread;
    104 };
    105 
    106 ThreadedDriver::~ThreadedDriver() {
    107  if (mThread) {
    108    nsCOMPtr<nsIRunnable> event =
    109        new MediaTrackGraphShutdownThreadRunnable(mThread.forget());
    110    SchedulerGroup::Dispatch(event.forget());
    111  }
    112 }
    113 
    114 class MediaTrackGraphInitThreadRunnable : public Runnable {
    115 public:
    116  explicit MediaTrackGraphInitThreadRunnable(ThreadedDriver* aDriver)
    117      : Runnable("MediaTrackGraphInitThreadRunnable"), mDriver(aDriver) {}
    118  NS_IMETHOD Run() override {
    119    TRACE("MediaTrackGraphInitThreadRunnable");
    120    MOZ_ASSERT(!mDriver->ThreadRunning());
    121    LOG(LogLevel::Debug, ("Starting a new system driver for graph %p",
    122                          mDriver->mGraphInterface.get()));
    123 
    124    if (GraphDriver* previousDriver = mDriver->PreviousDriver()) {
    125      LOG(LogLevel::Debug,
    126          ("%p releasing an AudioCallbackDriver(%p), for graph %p",
    127           mDriver.get(), previousDriver, mDriver->Graph()));
    128      MOZ_ASSERT(!mDriver->AsAudioCallbackDriver());
    129      AudioCallbackDriver* audioCallbackDriver =
    130          previousDriver->AsAudioCallbackDriver();
    131      MOZ_ALWAYS_SUCCEEDS(audioCallbackDriver->mCubebOperationThread->Dispatch(
    132          NS_NewRunnableFunction(
    133              "ThreadedDriver previousDriver::Stop()",
    134              [audioCallbackDriver = RefPtr{audioCallbackDriver}] {
    135                audioCallbackDriver->Stop();
    136              })));
    137      mDriver->SetPreviousDriver(nullptr);
    138    }
    139 
    140    mDriver->RunThread();
    141    return NS_OK;
    142  }
    143 
    144 private:
    145  RefPtr<ThreadedDriver> mDriver;
    146 };
    147 
    148 void ThreadedDriver::Start() {
    149  MOZ_ASSERT(!ThreadRunning());
    150  LOG(LogLevel::Debug,
    151      ("Starting thread for a SystemClockDriver  %p", mGraphInterface.get()));
    152  (void)NS_WARN_IF(mThread);
    153  MOZ_ASSERT(!mThread);  // Ensure we haven't already started it
    154 
    155  nsCOMPtr<nsIRunnable> event = new MediaTrackGraphInitThreadRunnable(this);
    156  // Note: mThread may be null during event->Run() if we pass to NewNamedThread!
    157  // See AudioInitTask
    158  nsresult rv = NS_NewNamedThread("MediaTrackGrph", getter_AddRefs(mThread));
    159  if (NS_SUCCEEDED(rv)) {
    160    mThread->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
    161  }
    162 }
    163 
    164 void ThreadedDriver::Shutdown() {
    165  NS_ASSERTION(NS_IsMainThread(), "Must be called on main thread");
    166  // mGraph's thread is not running so it's OK to do whatever here
    167  LOG(LogLevel::Debug, ("Stopping threads for MediaTrackGraph %p", this));
    168 
    169  if (mThread) {
    170    LOG(LogLevel::Debug,
    171        ("%p: Stopping ThreadedDriver's %p thread", Graph(), this));
    172    mThread->AsyncShutdown();
    173    mThread = nullptr;
    174  }
    175 }
    176 
    177 SystemClockDriver::SystemClockDriver(GraphInterface* aGraphInterface,
    178                                     GraphDriver* aPreviousDriver,
    179                                     uint32_t aSampleRate)
    180    : ThreadedDriver(aGraphInterface, aPreviousDriver, aSampleRate),
    181      mInitialTimeStamp(TimeStamp::Now()) {}
    182 
    183 SystemClockDriver::~SystemClockDriver() = default;
    184 
    185 void ThreadedDriver::RunThread() {
    186  mThreadRunning = true;
    187  while (true) {
    188    WaitForNextIteration();
    189 
    190    MediaTime interval = GetIntervalForIteration();
    191    GraphTime nextStateComputedTime = mStateComputedTime + interval;
    192    LOG(LogLevel::Verbose,
    193        ("%p: interval[%ld; %ld]", Graph(), (long)mStateComputedTime,
    194         (long)nextStateComputedTime));
    195 
    196    mStateComputedTime = nextStateComputedTime;
    197    IterationResult result = Graph()->OneIteration(mStateComputedTime, nullptr);
    198 
    199    if (result.IsStop()) {
    200      // Signal that we're done stopping.
    201      result.Stopped();
    202      break;
    203    }
    204    if (GraphDriver* nextDriver = result.NextDriver()) {
    205      LOG(LogLevel::Debug, ("%p: Switching to AudioCallbackDriver", Graph()));
    206      result.Switched();
    207      nextDriver->SetState(mStreamName, mStateComputedTime,
    208                           mTargetIterationTimeStamp);
    209      nextDriver->Start();
    210      break;
    211    }
    212    MOZ_ASSERT(result.IsStillProcessing());
    213  }
    214  mThreadRunning = false;
    215 }
    216 
    217 MediaTime SystemClockDriver::GetIntervalForIteration() {
    218  return MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(
    219      MillisecondsToMediaTime(MEDIA_GRAPH_TARGET_PERIOD_MS));
    220 }
    221 
    222 void ThreadedDriver::EnsureNextIteration() {
    223  mWaitHelper.EnsureNextIteration();
    224 }
    225 
    226 void ThreadedDriver::WaitForNextIteration() {
    227  MOZ_ASSERT(mThread);
    228  MOZ_ASSERT(OnThread());
    229  mWaitHelper.WaitForNextIterationAtLeast(NextIterationWaitDuration());
    230 }
    231 
    232 TimeDuration ThreadedDriver::IterationDuration() {
    233  return MediaTimeToTimeDuration(GetIntervalForIteration());
    234 }
    235 
    236 TimeDuration SystemClockDriver::NextIterationWaitDuration() {
    237  MOZ_ASSERT(mThread);
    238  MOZ_ASSERT(OnThread());
    239  TimeStamp now = TimeStamp::Now();
    240  if (mTargetIterationTimeStamp.IsNull()) {
    241    // No previous driver with which to synchronize rendering.
    242    // Start rendering now.
    243    mTargetIterationTimeStamp = now;
    244  } else {
    245    mTargetIterationTimeStamp += IterationDuration();
    246  }
    247  TimeDuration timeout = mTargetIterationTimeStamp - now;
    248  if (timeout <
    249      TimeDuration::FromMilliseconds(-SYSTEM_CLOCK_BANKRUPTCY_THRESHOLD_MS)) {
    250    // Don't try to catch up because rendering has fallen so far behind.
    251    // Instead try to render at consistent time intervals from now.
    252    LOG(LogLevel::Warning, ("%p: Global underrun detected", Graph()));
    253    mTargetIterationTimeStamp = now;
    254  }
    255 
    256  LOG(LogLevel::Verbose,
    257      ("%p: Waiting for next iteration; at %f (real %f), timeout=%f", Graph(),
    258       MediaTimeToSeconds(mStateComputedTime),
    259       (now - mInitialTimeStamp).ToSeconds(), timeout.ToSeconds()));
    260  return timeout;
    261 }
    262 
    263 OfflineClockDriver::OfflineClockDriver(GraphInterface* aGraphInterface,
    264                                       uint32_t aSampleRate)
    265    : ThreadedDriver(aGraphInterface, nullptr, aSampleRate) {}
    266 
    267 OfflineClockDriver::~OfflineClockDriver() = default;
    268 
    269 void OfflineClockDriver::RunThread() {
    270  nsCOMPtr<nsIThreadInternal> threadInternal = do_QueryInterface(mThread);
    271  nsCOMPtr<nsIThreadObserver> observer = do_QueryInterface(Graph());
    272  threadInternal->SetObserver(observer);
    273 
    274  ThreadedDriver::RunThread();
    275 }
    276 
    277 MediaTime OfflineClockDriver::GetIntervalForIteration() {
    278  return MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(std::clamp<MediaTime>(
    279      mEndTime - mStateComputedTime, 0,
    280      MillisecondsToMediaTime(MEDIA_GRAPH_TARGET_PERIOD_MS)));
    281 }
    282 
    283 /* Helper to proxy the GraphInterface methods used by a running
    284 * mFallbackDriver. */
    285 class AudioCallbackDriver::FallbackWrapper : public GraphInterface {
    286 public:
    287  FallbackWrapper(RefPtr<GraphInterface> aGraph,
    288                  RefPtr<AudioCallbackDriver> aOwner, uint32_t aSampleRate,
    289                  const nsACString& aStreamName, GraphTime aStateComputedTime,
    290                  TimeStamp aIterationTimeStamp)
    291      : mGraph(std::move(aGraph)),
    292        mOwner(std::move(aOwner)),
    293        mFallbackDriver(
    294            MakeRefPtr<SystemClockDriver>(this, nullptr, aSampleRate)) {
    295    mFallbackDriver->SetState(aStreamName, aStateComputedTime,
    296                              aIterationTimeStamp);
    297  }
    298 
    299  NS_DECL_THREADSAFE_ISUPPORTS
    300 
    301  /* Proxied SystemClockDriver methods */
    302  void Start() { mFallbackDriver->Start(); }
    303  MOZ_CAN_RUN_SCRIPT void Shutdown() {
    304    RefPtr<SystemClockDriver> driver = mFallbackDriver;
    305    driver->Shutdown();
    306  }
    307  void SetStreamName(const nsACString& aStreamName) {
    308    mFallbackDriver->SetStreamName(aStreamName);
    309  }
    310  void EnsureNextIteration() { mFallbackDriver->EnsureNextIteration(); }
    311 #ifdef DEBUG
    312  bool InIteration() { return mFallbackDriver->InIteration(); }
    313 #endif
    314  bool OnThread() { return mFallbackDriver->OnThread(); }
    315 
    316  /* GraphInterface methods */
    317  void NotifyInputStopped() override {
    318    MOZ_CRASH("Unexpected NotifyInputStopped from fallback SystemClockDriver");
    319  }
    320  void NotifyInputData(const AudioDataValue* aBuffer, size_t aFrames,
    321                       TrackRate aRate, uint32_t aChannels,
    322                       uint32_t aAlreadyBuffered) override {
    323    MOZ_CRASH("Unexpected NotifyInputData from fallback SystemClockDriver");
    324  }
    325  void NotifySetRequestedInputProcessingParamsResult(
    326      AudioCallbackDriver* aDriver, int aGeneration,
    327      Result<cubeb_input_processing_params, int>&& aResult) override {
    328    MOZ_CRASH(
    329        "Unexpected processing params result from fallback SystemClockDriver");
    330  }
    331  void DeviceChanged() override {
    332    MOZ_CRASH("Unexpected DeviceChanged from fallback SystemClockDriver");
    333  }
    334 #ifdef DEBUG
    335  bool InDriverIteration(const GraphDriver* aDriver) const override {
    336    return mGraph->InDriverIteration(mOwner) && mOwner->OnFallback();
    337  }
    338 #endif
    339  IterationResult OneIteration(GraphTime aStateComputedEnd,
    340                               MixerCallbackReceiver* aMixerReceiver) override {
    341    MOZ_ASSERT(!aMixerReceiver);
    342 
    343 #ifdef DEBUG
    344    AutoInCallback aic(mOwner);
    345 #endif
    346 
    347    IterationResult result =
    348        mGraph->OneIteration(aStateComputedEnd, aMixerReceiver);
    349 
    350    AudioStreamState audioState = mOwner->mAudioStreamState;
    351 
    352    MOZ_ASSERT(audioState != AudioStreamState::Stopping,
    353               "The audio driver can only enter stopping if it iterated the "
    354               "graph, which it can only do if there's no fallback driver");
    355 
    356    // After a devicechange event from the audio driver, wait for a five
    357    // millisecond grace period before handing control to the audio driver. We
    358    // do this because cubeb leaves no guarantee on audio callbacks coming in
    359    // after a device change event.
    360    if (audioState == AudioStreamState::ChangingDevice &&
    361        mOwner->mChangingDeviceStartTime + TimeDuration::FromMilliseconds(5) <
    362            TimeStamp::Now()) {
    363      mOwner->mChangingDeviceStartTime = TimeStamp();
    364      if (mOwner->mAudioStreamState.compareExchange(
    365              AudioStreamState::ChangingDevice, AudioStreamState::Starting)) {
    366        audioState = AudioStreamState::Starting;
    367        LOG(LogLevel::Debug, ("%p: Fallback driver has started. Waiting for "
    368                              "audio driver to start.",
    369                              mOwner.get()));
    370      }
    371    }
    372 
    373    if (audioState != AudioStreamState::Running && result.IsStillProcessing()) {
    374      mOwner->MaybeStartAudioStream();
    375      return result;
    376    }
    377 
    378    MOZ_ASSERT(result.IsStillProcessing() || result.IsStop() ||
    379               result.IsSwitchDriver());
    380 
    381    IterationResult stopFallback =
    382        IterationResult::CreateStop(NS_NewRunnableFunction(
    383            "AudioCallbackDriver::FallbackDriverStopped",
    384            [self = RefPtr<FallbackWrapper>(this), this, aStateComputedEnd,
    385             result = std::move(result)]() mutable {
    386              FallbackDriverState fallbackState =
    387                  result.IsStillProcessing() ? FallbackDriverState::None
    388                                             : FallbackDriverState::Stopped;
    389              mOwner->FallbackDriverStopped(
    390                  aStateComputedEnd, mFallbackDriver->IterationTimeStamp(),
    391                  fallbackState);
    392 
    393              if (fallbackState == FallbackDriverState::Stopped) {
    394 #ifdef DEBUG
    395                // The AudioCallbackDriver may not iterate the graph, but we'll
    396                // call into it so we need to be regarded as "in iteration".
    397                AutoInCallback aic(mOwner);
    398 #endif
    399                if (GraphDriver* nextDriver = result.NextDriver()) {
    400                  LOG(LogLevel::Debug,
    401                      ("%p: Switching from fallback to other driver.",
    402                       mOwner.get()));
    403                  result.Switched();
    404                  nextDriver->SetState(mOwner->mStreamName, aStateComputedEnd,
    405                                       mFallbackDriver->IterationTimeStamp());
    406                  nextDriver->Start();
    407                } else if (result.IsStop()) {
    408                  LOG(LogLevel::Debug,
    409                      ("%p: Stopping fallback driver.", mOwner.get()));
    410                  result.Stopped();
    411                }
    412              }
    413              mOwner = nullptr;
    414              // Proxy the release of the fallback driver to a background
    415              // thread, so it doesn't perform unexpected suicide.
    416              NS_DispatchBackgroundTask(NS_NewRunnableFunction(
    417                  "AudioCallbackDriver::FallbackDriverStopped::Release",
    418                  [fallback = std::move(self->mFallbackDriver)] {}));
    419            }));
    420 
    421    return stopFallback;
    422  }
    423 
    424 private:
    425  virtual ~FallbackWrapper() = default;
    426 
    427  const RefPtr<GraphInterface> mGraph;
    428  // Valid until mFallbackDriver has finished its last iteration.
    429  RefPtr<AudioCallbackDriver> mOwner;
    430  RefPtr<SystemClockDriver> mFallbackDriver;
    431 };
    432 
    433 NS_IMPL_ISUPPORTS0(AudioCallbackDriver::FallbackWrapper)
    434 
    435 /* static */
    436 already_AddRefed<TaskQueue> AudioCallbackDriver::CreateTaskQueue() {
    437  return TaskQueue::Create(CubebUtils::GetCubebOperationThread(),
    438                           "AudioCallbackDriver cubeb task queue")
    439      .forget();
    440 }
    441 
    442 AudioCallbackDriver::AudioCallbackDriver(
    443    GraphInterface* aGraphInterface, GraphDriver* aPreviousDriver,
    444    uint32_t aSampleRate, uint32_t aOutputChannelCount,
    445    uint32_t aInputChannelCount, CubebUtils::AudioDeviceID aOutputDeviceID,
    446    CubebUtils::AudioDeviceID aInputDeviceID, AudioInputType aAudioInputType,
    447    Maybe<AudioInputProcessingParamsRequest> aRequestedInputProcessingParams)
    448    : GraphDriver(aGraphInterface, aPreviousDriver, aSampleRate),
    449      mOutputChannelCount(aOutputChannelCount),
    450      mInputChannelCount(aInputChannelCount),
    451      mOutputDeviceID(aOutputDeviceID),
    452      mInputDeviceID(aInputDeviceID),
    453      mIterationDurationMS(MEDIA_GRAPH_TARGET_PERIOD_MS),
    454      mCubebOperationThread(CreateTaskQueue()),
    455      mInputProcessingRequest(aRequestedInputProcessingParams.valueOr(
    456          AudioInputProcessingParamsRequest{})),
    457      mAudioThreadId(ProfilerThreadId{}),
    458      mAudioThreadIdInCb(std::thread::id()),
    459      mFallback("AudioCallbackDriver::mFallback"),
    460      mSandboxed(CubebUtils::SandboxEnabled()) {
    461  LOG(LogLevel::Debug, ("%p: AudioCallbackDriver %p ctor - input: device %p, "
    462                        "channel %d, output: device %p, channel %d",
    463                        Graph(), this, mInputDeviceID, mInputChannelCount,
    464                        mOutputDeviceID, mOutputChannelCount));
    465 
    466  NS_WARNING_ASSERTION(mOutputChannelCount != 0,
    467                       "Invalid output channel count");
    468 
    469  if (aAudioInputType == AudioInputType::Voice &&
    470      StaticPrefs::
    471          media_getusermedia_microphone_prefer_voice_stream_with_processing_enabled()) {
    472    LOG(LogLevel::Debug,
    473        ("%p: AudioCallbackDriver %p ctor - using VOICE and requesting input "
    474         "processing params %s (Gen %d).",
    475         Graph(), this,
    476         CubebUtils::ProcessingParamsToString(mInputProcessingRequest.mParams)
    477             .get(),
    478         mInputProcessingRequest.mGeneration));
    479    mInputDevicePreference = CUBEB_DEVICE_PREF_VOICE;
    480    CubebUtils::SetInCommunication(true);
    481  } else {
    482    mInputDevicePreference = CUBEB_DEVICE_PREF_ALL;
    483  }
    484 }
    485 
    486 AudioCallbackDriver::~AudioCallbackDriver() {
    487  if (mInputDevicePreference == CUBEB_DEVICE_PREF_VOICE) {
    488    CubebUtils::SetInCommunication(false);
    489  }
    490 }
    491 
    492 bool IsMacbookOrMacbookAir() {
    493 #ifdef XP_MACOSX
    494  size_t len = 0;
    495  sysctlbyname("hw.model", NULL, &len, NULL, 0);
    496  if (len) {
    497    UniquePtr<char[]> model(new char[len]);
    498    // This string can be
    499    // MacBook%d,%d for a normal MacBook
    500    // MacBookAir%d,%d for a Macbook Air
    501    sysctlbyname("hw.model", model.get(), &len, NULL, 0);
    502    char* substring = strstr(model.get(), "MacBook");
    503    if (substring) {
    504      const size_t offset = strlen("MacBook");
    505      if (!strncmp(model.get() + offset, "Air", 3) ||
    506          isdigit(model[offset + 1])) {
    507        return true;
    508      }
    509    }
    510  }
    511 #endif
    512  return false;
    513 }
    514 
    515 void AudioCallbackDriver::Init(const nsCString& aStreamName) {
    516  LOG(LogLevel::Debug,
    517      ("%p: AudioCallbackDriver::Init driver=%p", Graph(), this));
    518  TRACE("AudioCallbackDriver::Init");
    519  MOZ_ASSERT(OnCubebOperationThread());
    520  MOZ_ASSERT(mAudioStreamState == AudioStreamState::Pending);
    521  if (mFallbackDriverState == FallbackDriverState::Stopped) {
    522    // The graph has already stopped us.
    523    return;
    524  }
    525  RefPtr<CubebUtils::CubebHandle> handle = CubebUtils::GetCubeb();
    526  if (!handle) {
    527    NS_WARNING("Could not get cubeb context.");
    528    LOG(LogLevel::Warning, ("%s: Could not get cubeb context", __func__));
    529    mAudioStreamState = AudioStreamState::None;
    530    if (TryStartingFallbackDriver().isOk()) {
    531      CubebUtils::ReportCubebStreamInitFailure(true);
    532    }
    533    return;
    534  }
    535 
    536  cubeb_stream_params output;
    537  cubeb_stream_params input;
    538  bool firstStream = CubebUtils::GetFirstStream();
    539 
    540  MOZ_ASSERT(!NS_IsMainThread(),
    541             "This is blocking and should never run on the main thread.");
    542 
    543  output.rate = mSampleRate;
    544  output.format = CUBEB_SAMPLE_FLOAT32NE;
    545 
    546  if (!mOutputChannelCount) {
    547    LOG(LogLevel::Warning, ("Output number of channels is 0."));
    548    mAudioStreamState = AudioStreamState::None;
    549    if (TryStartingFallbackDriver().isOk()) {
    550      CubebUtils::ReportCubebStreamInitFailure(firstStream);
    551    }
    552    return;
    553  }
    554 
    555  CubebUtils::AudioDeviceID forcedOutputDeviceId = nullptr;
    556 
    557  char* forcedOutputDeviceName = CubebUtils::GetForcedOutputDevice();
    558  if (forcedOutputDeviceName) {
    559    RefPtr<CubebDeviceEnumerator> enumerator = Enumerator::GetInstance();
    560    RefPtr<AudioDeviceInfo> device = enumerator->DeviceInfoFromName(
    561        NS_ConvertUTF8toUTF16(forcedOutputDeviceName), EnumeratorSide::OUTPUT);
    562    if (device && device->DeviceID()) {
    563      forcedOutputDeviceId = device->DeviceID();
    564    }
    565  }
    566 
    567  mBuffer = AudioCallbackBufferWrapper<AudioDataValue>(mOutputChannelCount);
    568  mScratchBuffer =
    569      SpillBuffer<AudioDataValue, WEBAUDIO_BLOCK_SIZE * 2>(mOutputChannelCount);
    570 
    571  output.channels = mOutputChannelCount;
    572  AudioConfig::ChannelLayout::ChannelMap channelMap =
    573      AudioConfig::ChannelLayout(mOutputChannelCount).Map();
    574 
    575  output.layout = static_cast<uint32_t>(channelMap);
    576  output.prefs = CubebUtils::GetDefaultStreamPrefs(CUBEB_DEVICE_TYPE_OUTPUT);
    577  if (mInputDevicePreference == CUBEB_DEVICE_PREF_VOICE &&
    578      CubebUtils::RouteOutputAsVoice()) {
    579    output.prefs |= static_cast<cubeb_stream_prefs>(CUBEB_STREAM_PREF_VOICE);
    580  }
    581  output.input_params = CUBEB_INPUT_PROCESSING_PARAM_NONE;
    582 
    583  uint32_t latencyFrames = CubebUtils::GetCubebMTGLatencyInFrames(&output);
    584 
    585  LOG(LogLevel::Debug, ("Minimum latency in frames: %d", latencyFrames));
    586 
    587  // Macbook and MacBook air don't have enough CPU to run very low latency
    588  // MediaTrackGraphs, cap the minimal latency to 512 frames int this case.
    589  if (IsMacbookOrMacbookAir()) {
    590    latencyFrames = std::max((uint32_t)512, latencyFrames);
    591    LOG(LogLevel::Debug,
    592        ("Macbook or macbook air, new latency: %d", latencyFrames));
    593  }
    594 
    595  // Buffer sizes lower than 10ms are nowadays common. It's not very useful
    596  // when doing voice, because all the WebRTC code that does audio input
    597  // processing deals in 10ms chunks of audio. Take the first power of two
    598  // above 10ms at the current rate in this case. It's probably 512, for common
    599  // rates.
    600  if (mInputDevicePreference == CUBEB_DEVICE_PREF_VOICE) {
    601    if (latencyFrames < mSampleRate / 100) {
    602      latencyFrames = mozilla::RoundUpPow2(mSampleRate / 100);
    603      LOG(LogLevel::Debug,
    604          ("AudioProcessing enabled, new latency %d", latencyFrames));
    605    }
    606  }
    607 
    608  // It's not useful for the graph to run with a block size lower than the Web
    609  // Audio API block size, but increasingly devices report that they can do
    610  // audio latencies lower than that.
    611  if (latencyFrames < WEBAUDIO_BLOCK_SIZE) {
    612    LOG(LogLevel::Debug,
    613        ("Latency clamped to %d from %d", WEBAUDIO_BLOCK_SIZE, latencyFrames));
    614    latencyFrames = WEBAUDIO_BLOCK_SIZE;
    615  }
    616  LOG(LogLevel::Debug, ("Effective latency in frames: %d", latencyFrames));
    617 
    618  input = output;
    619  input.channels = mInputChannelCount;
    620  input.layout = CUBEB_LAYOUT_UNDEFINED;
    621  input.prefs = CubebUtils::GetDefaultStreamPrefs(CUBEB_DEVICE_TYPE_INPUT);
    622  if (mInputDevicePreference == CUBEB_DEVICE_PREF_VOICE) {
    623    input.prefs |= static_cast<cubeb_stream_prefs>(CUBEB_STREAM_PREF_VOICE);
    624  }
    625  input.input_params = CUBEB_INPUT_PROCESSING_PARAM_NONE;
    626 
    627  cubeb_stream* stream = nullptr;
    628  const char* streamName =
    629      aStreamName.IsEmpty() ? "AudioCallbackDriver" : aStreamName.get();
    630  bool inputWanted = mInputChannelCount > 0;
    631  CubebUtils::AudioDeviceID outputId = mOutputDeviceID;
    632  CubebUtils::AudioDeviceID inputId = mInputDeviceID;
    633 
    634  if (CubebUtils::CubebStreamInit(
    635          handle->Context(), &stream, streamName, inputId,
    636          inputWanted ? &input : nullptr,
    637          forcedOutputDeviceId ? forcedOutputDeviceId : outputId, &output,
    638          latencyFrames, DataCallback_s, StateCallback_s, this) == CUBEB_OK) {
    639    mCubeb = handle;
    640    mAudioStream.own(stream);
    641    DebugOnly<int> rv =
    642        cubeb_stream_set_volume(mAudioStream, CubebUtils::GetVolumeScale());
    643    NS_WARNING_ASSERTION(
    644        rv == CUBEB_OK,
    645        "Could not set the audio stream volume in GraphDriver.cpp");
    646    CubebUtils::ReportCubebBackendUsed();
    647  } else {
    648    NS_WARNING(
    649        "Could not create a cubeb stream for MediaTrackGraph, falling "
    650        "back to a SystemClockDriver");
    651    mAudioStreamState = AudioStreamState::None;
    652    // Only report failures when we're not coming from a driver that was
    653    // created itself as a fallback driver because of a previous audio driver
    654    // failure.
    655    if (TryStartingFallbackDriver().isOk()) {
    656      CubebUtils::ReportCubebStreamInitFailure(firstStream);
    657    }
    658    return;
    659  }
    660 
    661 #ifdef XP_MACOSX
    662  PanOutputIfNeeded(inputWanted);
    663 #endif
    664 
    665  if (inputWanted && InputDevicePreference() == AudioInputType::Voice) {
    666    SetInputProcessingParams(mInputProcessingRequest);
    667  }
    668 
    669  cubeb_stream_register_device_changed_callback(
    670      mAudioStream, AudioCallbackDriver::DeviceChangedCallback_s);
    671 
    672  // No-op if MOZ_DUMP_AUDIO is not defined as an environment variable. This
    673  // is intended for diagnosing issues, and only works if the content sandbox is
    674  // disabled.
    675  mInputStreamFile.Open("GraphDriverInput", input.channels, input.rate);
    676  mOutputStreamFile.Open("GraphDriverOutput", output.channels, output.rate);
    677 
    678  if (NS_WARN_IF(!StartStream())) {
    679    LOG(LogLevel::Warning,
    680        ("%p: AudioCallbackDriver couldn't start a cubeb stream.", Graph()));
    681    return;
    682  }
    683 
    684  LOG(LogLevel::Debug, ("%p: AudioCallbackDriver started.", Graph()));
    685 }
    686 
    687 void AudioCallbackDriver::SetCubebStreamName(const nsCString& aStreamName) {
    688  MOZ_ASSERT(OnCubebOperationThread());
    689  MOZ_ASSERT(mAudioStream);
    690  cubeb_stream_set_name(mAudioStream, aStreamName.get());
    691 }
    692 
    693 void AudioCallbackDriver::Start() {
    694  MOZ_ASSERT(!IsStarted());
    695  MOZ_ASSERT(mAudioStreamState == AudioStreamState::None);
    696  MOZ_ASSERT_IF(PreviousDriver(), PreviousDriver()->InIteration());
    697  mAudioStreamState = AudioStreamState::Pending;
    698 
    699  // Starting an audio driver could take a while. We start a system driver in
    700  // the meantime so that the graph is kept running.
    701  (void)TryStartingFallbackDriver();
    702 
    703  if (mPreviousDriver) {
    704    if (AudioCallbackDriver* previousAudioCallback =
    705            mPreviousDriver->AsAudioCallbackDriver()) {
    706      LOG(LogLevel::Debug, ("Releasing audio driver off main thread."));
    707      MOZ_ALWAYS_SUCCEEDS(
    708          previousAudioCallback->mCubebOperationThread->Dispatch(
    709              NS_NewRunnableFunction(
    710                  "AudioCallbackDriver previousDriver::Stop()",
    711                  [previousDriver = RefPtr{previousAudioCallback}] {
    712                    previousDriver->Stop();
    713                  })));
    714    } else {
    715      LOG(LogLevel::Debug,
    716          ("Dropping driver reference for SystemClockDriver."));
    717      MOZ_ASSERT(mPreviousDriver->AsSystemClockDriver());
    718    }
    719    mPreviousDriver = nullptr;
    720  }
    721 
    722  LOG(LogLevel::Debug, ("Starting new audio driver off main thread, "
    723                        "to ensure it runs after previous shutdown."));
    724  MOZ_ALWAYS_SUCCEEDS(mCubebOperationThread->Dispatch(
    725      NS_NewRunnableFunction("AudioCallbackDriver Init()",
    726                             [self = RefPtr{this}, streamName = mStreamName] {
    727                               self->Init(streamName);
    728                             })));
    729 }
    730 
    731 bool AudioCallbackDriver::StartStream() {
    732  TRACE("AudioCallbackDriver::StartStream");
    733  MOZ_ASSERT(!IsStarted() && OnCubebOperationThread());
    734  // Set STARTING before cubeb_stream_start, since starting the cubeb stream
    735  // can result in a callback (that may read mAudioStreamState) before
    736  // mAudioStreamState would otherwise be set.
    737  mAudioStreamState = AudioStreamState::Starting;
    738  if (cubeb_stream_start(mAudioStream) != CUBEB_OK) {
    739    NS_WARNING("Could not start cubeb stream for MTG.");
    740    return false;
    741  }
    742 
    743  return true;
    744 }
    745 
    746 void AudioCallbackDriver::Stop() {
    747  LOG(LogLevel::Debug,
    748      ("%p: AudioCallbackDriver::Stop driver=%p", Graph(), this));
    749  TRACE("AudioCallbackDriver::Stop");
    750  MOZ_ASSERT(OnCubebOperationThread());
    751  cubeb_stream_register_device_changed_callback(mAudioStream, nullptr);
    752  if (cubeb_stream_stop(mAudioStream) != CUBEB_OK) {
    753    NS_WARNING("Could not stop cubeb stream for MTG.");
    754  } else {
    755    mAudioStreamState = AudioStreamState::None;
    756  }
    757 }
    758 
    759 void AudioCallbackDriver::Shutdown() {
    760  MOZ_ASSERT(NS_IsMainThread());
    761  RefPtr<FallbackWrapper> fallback;
    762  {
    763    auto fallbackLock = mFallback.Lock();
    764    fallback = fallbackLock.ref();
    765    fallbackLock.ref() = nullptr;
    766  }
    767  if (fallback) {
    768    LOG(LogLevel::Debug,
    769        ("%p: Releasing fallback driver %p.", Graph(), fallback.get()));
    770    fallback->Shutdown();
    771  }
    772 
    773  LOG(LogLevel::Debug,
    774      ("%p: Releasing audio driver off main thread (GraphDriver::Shutdown).",
    775       Graph()));
    776 
    777  nsLiteralCString reason("AudioCallbackDriver::Shutdown");
    778  NS_DispatchAndSpinEventLoopUntilComplete(
    779      reason, mCubebOperationThread,
    780      NS_NewRunnableFunction(reason.get(),
    781                             [self = RefPtr{this}] { self->Stop(); }));
    782 }
    783 
    784 void AudioCallbackDriver::SetStreamName(const nsACString& aStreamName) {
    785  MOZ_ASSERT(InIteration() || !ThreadRunning());
    786  if (aStreamName == mStreamName) {
    787    return;
    788  }
    789  // Record the stream name, which will be passed onto the next driver, if
    790  // any, either from this driver or the fallback driver.
    791  GraphDriver::SetStreamName(aStreamName);
    792  {
    793    auto fallbackLock = mFallback.Lock();
    794    FallbackWrapper* fallback = fallbackLock.ref().get();
    795    if (fallback) {
    796      MOZ_ASSERT(fallback->InIteration());
    797      fallback->SetStreamName(aStreamName);
    798    }
    799  }
    800  AudioStreamState streamState = mAudioStreamState;
    801  if (streamState != AudioStreamState::None &&
    802      streamState != AudioStreamState::Stopping) {
    803    MOZ_ALWAYS_SUCCEEDS(mCubebOperationThread->Dispatch(
    804        NS_NewRunnableFunction("AudioCallbackDriver SetStreamName()",
    805                               [self = RefPtr{this}, streamName = mStreamName] {
    806                                 self->SetCubebStreamName(streamName);
    807                               })));
    808  }
    809 }
    810 
    811 /* static */
    812 long AudioCallbackDriver::DataCallback_s(cubeb_stream* aStream, void* aUser,
    813                                         const void* aInputBuffer,
    814                                         void* aOutputBuffer, long aFrames) {
    815  AudioCallbackDriver* driver = reinterpret_cast<AudioCallbackDriver*>(aUser);
    816  return driver->DataCallback(static_cast<const AudioDataValue*>(aInputBuffer),
    817                              static_cast<AudioDataValue*>(aOutputBuffer),
    818                              aFrames);
    819 }
    820 
    821 /* static */
    822 void AudioCallbackDriver::StateCallback_s(cubeb_stream* aStream, void* aUser,
    823                                          cubeb_state aState) {
    824  AudioCallbackDriver* driver = reinterpret_cast<AudioCallbackDriver*>(aUser);
    825  driver->StateCallback(aState);
    826 }
    827 
    828 /* static */
    829 void AudioCallbackDriver::DeviceChangedCallback_s(void* aUser) {
    830  AudioCallbackDriver* driver = reinterpret_cast<AudioCallbackDriver*>(aUser);
    831  driver->DeviceChangedCallback();
    832 }
    833 
    834 AudioCallbackDriver::AutoInCallback::AutoInCallback(
    835    AudioCallbackDriver* aDriver)
    836    : mDriver(aDriver) {
    837  MOZ_ASSERT(mDriver->mAudioThreadIdInCb == std::thread::id());
    838  mDriver->mAudioThreadIdInCb = std::this_thread::get_id();
    839 }
    840 
    841 AudioCallbackDriver::AutoInCallback::~AutoInCallback() {
    842  MOZ_ASSERT(mDriver->mAudioThreadIdInCb == std::this_thread::get_id());
    843  mDriver->mAudioThreadIdInCb = std::thread::id();
    844 }
    845 
    846 bool AudioCallbackDriver::CheckThreadIdChanged() {
    847  ProfilerThreadId id = profiler_current_thread_id();
    848  if (id != mAudioThreadId) {
    849    mAudioThreadId = id;
    850    return true;
    851  }
    852  return false;
    853 }
    854 
    855 long AudioCallbackDriver::DataCallback(const AudioDataValue* aInputBuffer,
    856                                       AudioDataValue* aOutputBuffer,
    857                                       long aFrames) {
    858  TimeStamp iterationStartTimeStamp = TimeStamp::Now();
    859 
    860  if (!mSandboxed && CheckThreadIdChanged()) {
    861    CallbackThreadRegistry::Get()->Register(mAudioThreadId,
    862                                            "NativeAudioCallback");
    863  }
    864 
    865  if (mAudioStreamState.compareExchange(AudioStreamState::Starting,
    866                                        AudioStreamState::Running)) {
    867    MOZ_ASSERT(mScratchBuffer.IsEmpty());
    868    mFirstCallbackIteration = true;
    869    LOG(LogLevel::Verbose, ("%p: AudioCallbackDriver %p First audio callback "
    870                            "close the Fallback driver",
    871                            Graph(), this));
    872  }
    873 
    874  FallbackDriverState fallbackState = mFallbackDriverState;
    875  if (MOZ_UNLIKELY(fallbackState == FallbackDriverState::Stopped)) {
    876    // We're supposed to stop.
    877    PodZero(aOutputBuffer, aFrames * mOutputChannelCount);
    878    if (!mSandboxed) {
    879      CallbackThreadRegistry::Get()->Unregister(mAudioThreadId);
    880    }
    881    return aFrames - 1;
    882  }
    883 
    884  AudioStreamState audioStreamState = mAudioStreamState;
    885  if (MOZ_UNLIKELY(audioStreamState == AudioStreamState::ChangingDevice ||
    886                   fallbackState == FallbackDriverState::Running)) {
    887    // Wait for the fallback driver to stop. Wake it up so it can stop if it's
    888    // sleeping.
    889    LOG(LogLevel::Verbose,
    890        ("%p: AudioCallbackDriver %p Waiting for the Fallback driver to stop",
    891         Graph(), this));
    892    EnsureNextIteration();
    893    PodZero(aOutputBuffer, aFrames * mOutputChannelCount);
    894    return aFrames;
    895  }
    896 
    897  MOZ_ASSERT(audioStreamState == AudioStreamState::Running);
    898  TRACE_AUDIO_CALLBACK_FRAME_COUNT("AudioCallbackDriver real-time budget",
    899                                   aFrames, mSampleRate);
    900  TRACE("AudioCallbackDriver::DataCallback");
    901 
    902 #ifdef DEBUG
    903  AutoInCallback aic(this);
    904 #endif
    905 
    906  uint32_t durationMS = aFrames * 1000 / mSampleRate;
    907 
    908  // For now, simply average the duration with the previous
    909  // duration so there is some damping against sudden changes.
    910  if (!mIterationDurationMS) {
    911    mIterationDurationMS = durationMS;
    912  } else {
    913    mIterationDurationMS = (mIterationDurationMS * 3) + durationMS;
    914    mIterationDurationMS /= 4;
    915  }
    916 
    917  mBuffer.SetBuffer(aOutputBuffer, aFrames);
    918  // fill part or all with leftover data from last iteration (since we
    919  // align to Audio blocks)
    920  uint32_t prefilledFrameCount = mScratchBuffer.Empty(mBuffer);
    921 
    922  if (mFirstCallbackIteration && !mTargetIterationTimeStamp.IsNull()) {
    923    MediaTime renderingTime =
    924        MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(SecondsToMediaTime(
    925            (iterationStartTimeStamp - mTargetIterationTimeStamp).ToSeconds()));
    926    // There is no previous iteration from which to carry over mScratchBuffer.
    927    MOZ_ASSERT(prefilledFrameCount == 0);
    928    if (renderingTime < aFrames) {
    929      // The audio data callback has occurred soon after the previous driver's
    930      // rendering time.  Synchronize the rendering times of graph frames
    931      // under the audio callback with the rendering times under the previous
    932      // driver by padding the start of the provided buffer with silence.
    933      prefilledFrameCount = AssertedCast<uint32_t>(aFrames - renderingTime);
    934      mBuffer.WriteSilence(prefilledFrameCount);
    935    }
    936  }
    937  mFirstCallbackIteration = false;
    938 
    939  // State computed time is decided by the audio callback's buffer length.
    940  GraphTime bufferEndGraphTime = mStateComputedTime + mBuffer.Available();
    941  GraphTime nextStateComputedTime =
    942      MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(bufferEndGraphTime);
    943  LOG(LogLevel::Verbose,
    944      ("%p: interval[%ld; %ld] (frames: %ld) (durationMS: %u) "
    945       "(duration ticks: %ld)",
    946       Graph(), (long)mStateComputedTime, (long)nextStateComputedTime,
    947       (long)aFrames, (uint32_t)durationMS,
    948       (long)(nextStateComputedTime - mStateComputedTime)));
    949 
    950  // mTargetIterationTimeStamp is used to synchronize the timing of rendering
    951  // when switching to a different driver.  iterationStartTimeStamp, which
    952  // corresponds to bufferEndGraphTime, is adjusted for the extra rendering by
    953  // the graph due to rounding to block boundaries, so that
    954  // mTargetIterationTimeStamp corresponds to nextStateComputedTime.
    955  // This is calculated for all iterations, not just when the IterationResult
    956  // indicates a switch, because DeviceChangedCallback() might start a
    957  // fallback driver for the next iteration.
    958  mTargetIterationTimeStamp =
    959      iterationStartTimeStamp +
    960      MediaTimeToTimeDuration(nextStateComputedTime - bufferEndGraphTime);
    961 
    962  // Process mic data if any/needed
    963  if (aInputBuffer && mInputChannelCount > 0) {
    964    Graph()->NotifyInputData(aInputBuffer, static_cast<size_t>(aFrames),
    965                             mSampleRate, mInputChannelCount,
    966                             prefilledFrameCount);
    967  }
    968 
    969  IterationResult result = Graph()->OneIteration(nextStateComputedTime, this);
    970 
    971  mStateComputedTime = nextStateComputedTime;
    972 
    973  MOZ_ASSERT(mBuffer.Available() == 0,
    974             "The graph should have filled the buffer");
    975 
    976  mBuffer.BufferFilled();
    977 
    978 #ifdef MOZ_SAMPLE_TYPE_FLOAT32
    979  // Prevent returning NaN to the OS mixer, and propagating NaN into the reverse
    980  // stream of the AEC.
    981  NaNToZeroInPlace(aOutputBuffer, aFrames * mOutputChannelCount);
    982 #endif
    983 
    984 #ifdef XP_MACOSX
    985  // This only happens when the output is on a macbookpro's external speaker,
    986  // that are stereo, but let's just be safe.
    987  if (mNeedsPanning && mOutputChannelCount == 2) {
    988    // hard pan to the right
    989    for (uint32_t i = 0; i < aFrames * 2; i += 2) {
    990      aOutputBuffer[i + 1] += aOutputBuffer[i];
    991      aOutputBuffer[i] = 0.0;
    992    }
    993  }
    994 #endif
    995 
    996  // No-op if MOZ_DUMP_AUDIO is not defined as an environment variable
    997  if (aInputBuffer) {
    998    mInputStreamFile.Write(static_cast<const AudioDataValue*>(aInputBuffer),
    999                           aFrames * mInputChannelCount);
   1000  }
   1001  mOutputStreamFile.Write(static_cast<const AudioDataValue*>(aOutputBuffer),
   1002                          aFrames * mOutputChannelCount);
   1003 
   1004  if (result.IsStop()) {
   1005    if (mInputDeviceID) {
   1006      mGraphInterface->NotifyInputStopped();
   1007    }
   1008    // Signal that we have stopped.
   1009    result.Stopped();
   1010    // Update the flag before handing over the graph and going to drain.
   1011    mAudioStreamState = AudioStreamState::Stopping;
   1012    if (!mSandboxed) {
   1013      CallbackThreadRegistry::Get()->Unregister(mAudioThreadId);
   1014    }
   1015    return aFrames - 1;
   1016  }
   1017 
   1018  if (GraphDriver* nextDriver = result.NextDriver()) {
   1019    LOG(LogLevel::Debug,
   1020        ("%p: Switching to %s driver.", Graph(),
   1021         nextDriver->AsAudioCallbackDriver() ? "audio" : "system"));
   1022    if (mInputDeviceID) {
   1023      mGraphInterface->NotifyInputStopped();
   1024    }
   1025    result.Switched();
   1026    mAudioStreamState = AudioStreamState::Stopping;
   1027    nextDriver->SetState(mStreamName, mStateComputedTime,
   1028                         iterationStartTimeStamp);
   1029    nextDriver->Start();
   1030    if (!mSandboxed) {
   1031      CallbackThreadRegistry::Get()->Unregister(mAudioThreadId);
   1032    }
   1033    // Returning less than aFrames starts the draining and eventually stops the
   1034    // audio thread. This function will never get called again.
   1035    return aFrames - 1;
   1036  }
   1037 
   1038  MOZ_ASSERT(result.IsStillProcessing());
   1039  return aFrames;
   1040 }
   1041 
   1042 static const char* StateToString(cubeb_state aState) {
   1043  switch (aState) {
   1044    case CUBEB_STATE_STARTED:
   1045      return "STARTED";
   1046    case CUBEB_STATE_STOPPED:
   1047      return "STOPPED";
   1048    case CUBEB_STATE_DRAINED:
   1049      return "DRAINED";
   1050    case CUBEB_STATE_ERROR:
   1051      return "ERROR";
   1052    default:
   1053      MOZ_CRASH("Unexpected state!");
   1054  }
   1055 }
   1056 
   1057 void AudioCallbackDriver::StateCallback(cubeb_state aState) {
   1058  MOZ_ASSERT(!InIteration());
   1059  LOG(LogLevel::Debug,
   1060      ("AudioCallbackDriver(%p) State: %s", this, StateToString(aState)));
   1061 
   1062  if (aState == CUBEB_STATE_STARTED || aState == CUBEB_STATE_STOPPED) {
   1063    // Nothing to do for STARTED.
   1064    //
   1065    // For STOPPED, don't reset mAudioStreamState until after
   1066    // cubeb_stream_stop() returns, as wasapi_stream_stop() dispatches
   1067    // CUBEB_STATE_STOPPED before ensuring that data callbacks have finished.
   1068    // https://searchfox.org/mozilla-central/rev/f9beb753a84aa297713d1565dcd0c5e3c66e4174/media/libcubeb/src/cubeb_wasapi.cpp#3009,3012
   1069    return;
   1070  }
   1071 
   1072  AudioStreamState streamState = mAudioStreamState;
   1073  if (streamState < AudioStreamState::Starting) {
   1074    // mAudioStream has already entered STOPPED, DRAINED, or ERROR.
   1075    // Don't reset a Pending state indicating that a task to destroy
   1076    // mAudioStream and init a new cubeb_stream has already been triggered.
   1077    return;
   1078  }
   1079 
   1080  // Reset for DRAINED or ERROR.
   1081  streamState = mAudioStreamState.exchange(AudioStreamState::None);
   1082 
   1083  if (aState == CUBEB_STATE_ERROR) {
   1084    // About to hand over control of the graph.  Do not start a new driver if
   1085    // StateCallback() receives an error for this stream while the main thread
   1086    // or another driver has control of the graph.
   1087    if (streamState == AudioStreamState::Starting ||
   1088        streamState == AudioStreamState::ChangingDevice ||
   1089        streamState == AudioStreamState::Running) {
   1090      if (mFallbackDriverState.compareExchange(FallbackDriverState::None,
   1091                                               FallbackDriverState::Running)) {
   1092        // Only switch to fallback if it's not already running. It could be
   1093        // running with the callback driver having started but not seen a single
   1094        // callback yet. I.e., handover from fallback to callback is not done.
   1095        if (mInputDeviceID) {
   1096 #ifdef DEBUG
   1097          // No audio callback after an error. We're calling into the graph here
   1098          // so we need to be regarded as "in iteration".
   1099          AutoInCallback aic(this);
   1100 #endif
   1101          mGraphInterface->NotifyInputStopped();
   1102        }
   1103        FallbackToSystemClockDriver();
   1104      }
   1105    }
   1106  }
   1107 }
   1108 
   1109 void AudioCallbackDriver::MixerCallback(AudioChunk* aMixedBuffer,
   1110                                        uint32_t aSampleRate) {
   1111  MOZ_ASSERT(InIteration());
   1112  uint32_t toWrite = mBuffer.Available();
   1113 
   1114  TrackTime frameCount = aMixedBuffer->mDuration;
   1115  if (!mBuffer.Available() && frameCount > 0) {
   1116    NS_WARNING("DataCallback buffer full, expect frame drops.");
   1117  }
   1118 
   1119  MOZ_ASSERT(mBuffer.Available() <= frameCount);
   1120 
   1121  mBuffer.WriteFrames(*aMixedBuffer, mBuffer.Available());
   1122  MOZ_ASSERT(mBuffer.Available() == 0,
   1123             "Missing frames to fill audio callback's buffer.");
   1124  if (toWrite == frameCount) {
   1125    return;
   1126  }
   1127 
   1128  aMixedBuffer->SliceTo(toWrite, frameCount);
   1129  DebugOnly<uint32_t> written = mScratchBuffer.Fill(*aMixedBuffer);
   1130  NS_WARNING_ASSERTION(written == frameCount - toWrite, "Dropping frames.");
   1131 };
   1132 
   1133 void AudioCallbackDriver::PanOutputIfNeeded(bool aMicrophoneActive) {
   1134 #ifdef XP_MACOSX
   1135  TRACE("AudioCallbackDriver::PanOutputIfNeeded");
   1136  cubeb_device* out = nullptr;
   1137  int rv;
   1138  char name[128];
   1139  size_t length = sizeof(name);
   1140 
   1141  rv = sysctlbyname("hw.model", name, &length, NULL, 0);
   1142  if (rv) {
   1143    return;
   1144  }
   1145 
   1146  int major, minor;
   1147  for (uint32_t i = 0; i < length; i++) {
   1148    // skip the model name
   1149    if (isalpha(name[i])) {
   1150      continue;
   1151    }
   1152    sscanf(name + i, "%d,%d", &major, &minor);
   1153    break;
   1154  }
   1155 
   1156  enum MacbookModel { MacBook, MacBookPro, MacBookAir, NotAMacbook };
   1157 
   1158  MacbookModel model;
   1159 
   1160  if (!strncmp(name, "MacBookPro", length)) {
   1161    model = MacBookPro;
   1162  } else if (strncmp(name, "MacBookAir", length)) {
   1163    model = MacBookAir;
   1164  } else if (strncmp(name, "MacBook", length)) {
   1165    model = MacBook;
   1166  } else {
   1167    model = NotAMacbook;
   1168  }
   1169  // For macbook pro before 2016 model (change of chassis), hard pan the audio
   1170  // to the right if the speakers are in use to avoid feedback.
   1171  if (model == MacBookPro && major <= 12) {
   1172    if (cubeb_stream_get_current_device(mAudioStream, &out) == CUBEB_OK) {
   1173      MOZ_ASSERT(out);
   1174      // Check if we are currently outputing sound on external speakers.
   1175      if (out->output_name && !strcmp(out->output_name, "ispk")) {
   1176        // Pan everything to the right speaker.
   1177        LOG(LogLevel::Debug, ("Using the built-in speakers, with%s audio input",
   1178                              aMicrophoneActive ? "" : "out"));
   1179        mNeedsPanning = aMicrophoneActive;
   1180      } else {
   1181        LOG(LogLevel::Debug, ("Using an external output device"));
   1182        mNeedsPanning = false;
   1183      }
   1184      cubeb_stream_device_destroy(mAudioStream, out);
   1185    }
   1186  }
   1187 #endif
   1188 }
   1189 
   1190 void AudioCallbackDriver::DeviceChangedCallback() {
   1191  MOZ_ASSERT(!InIteration());
   1192  // Set this before the atomic write.
   1193  mChangingDeviceStartTime = TimeStamp::Now();
   1194 
   1195  if (mAudioStreamState.compareExchange(AudioStreamState::Running,
   1196                                        AudioStreamState::ChangingDevice)) {
   1197    // Change to ChangingDevice only if we're running, i.e. there has been a
   1198    // data callback and no state callback saying otherwise.
   1199    // - If the audio stream is not running, it has either been stopped or it is
   1200    //   starting. In the latter case we assume there will be no data callback
   1201    //   coming until after the device change is done.
   1202    // - If the audio stream is running here, there is no guarantee from the
   1203    //   cubeb mac backend that no more data callback will occur before the
   1204    //   device change takes place. They will however stop *soon*, and we hope
   1205    //   they stop before the first callback from the fallback driver. If the
   1206    //   fallback driver callback occurs before the last data callback before
   1207    //   the device switch, the worst case is that a long period of time
   1208    //   (seconds) may pass without the graph getting iterated at all.
   1209    Result<bool, FallbackDriverState> res = TryStartingFallbackDriver();
   1210 
   1211    LOG(LogLevel::Info,
   1212        ("%p: AudioCallbackDriver %p underlying default device is changing. "
   1213         "Fallback %s.",
   1214         Graph(), this,
   1215         res.isOk() ? "started"
   1216                    : (res.inspectErr() == FallbackDriverState::Running
   1217                           ? "already running"
   1218                           : "has been stopped")));
   1219 
   1220    if (res.isErr() && res.inspectErr() == FallbackDriverState::Stopped) {
   1221      mChangingDeviceStartTime = TimeStamp();
   1222    }
   1223  }
   1224 
   1225  // Tell the audio engine the device has changed, it might want to reset some
   1226  // state.
   1227  Graph()->DeviceChanged();
   1228 #ifdef XP_MACOSX
   1229  RefPtr<AudioCallbackDriver> self(this);
   1230  bool hasInput = mInputChannelCount;
   1231  NS_DispatchBackgroundTask(NS_NewRunnableFunction(
   1232      "PanOutputIfNeeded", [self{std::move(self)}, hasInput]() {
   1233        self->PanOutputIfNeeded(hasInput);
   1234      }));
   1235 #endif
   1236 }
   1237 
   1238 TimeDuration AudioCallbackDriver::IterationDuration() {
   1239  MOZ_ASSERT(InIteration());
   1240  // The real fix would be to have an API in cubeb to give us the number. Short
   1241  // of that, we approximate it here. bug 1019507
   1242  return TimeDuration::FromMilliseconds(mIterationDurationMS);
   1243 }
   1244 
   1245 void AudioCallbackDriver::EnsureNextIteration() {
   1246  if (mFallbackDriverState == FallbackDriverState::Running) {
   1247    auto fallback = mFallback.Lock();
   1248    if (fallback.ref()) {
   1249      fallback.ref()->EnsureNextIteration();
   1250    }
   1251  }
   1252 }
   1253 
   1254 TimeDuration AudioCallbackDriver::AudioOutputLatency() {
   1255  TRACE("AudioCallbackDriver::AudioOutputLatency");
   1256  uint32_t latencyFrames;
   1257  int rv = cubeb_stream_get_latency(mAudioStream, &latencyFrames);
   1258  if (rv || mSampleRate == 0) {
   1259    return TimeDuration::FromSeconds(0.0);
   1260  }
   1261 
   1262  return TimeDuration::FromSeconds(static_cast<double>(latencyFrames) /
   1263                                   mSampleRate);
   1264 }
   1265 
   1266 bool AudioCallbackDriver::HasFallback() const {
   1267  MOZ_ASSERT(InIteration());
   1268  return mFallbackDriverState != FallbackDriverState::None;
   1269 }
   1270 
   1271 bool AudioCallbackDriver::OnFallback() const {
   1272  MOZ_ASSERT(InIteration());
   1273  return mFallbackDriverState == FallbackDriverState::Running;
   1274 }
   1275 
   1276 Result<bool, AudioCallbackDriver::FallbackDriverState>
   1277 AudioCallbackDriver::TryStartingFallbackDriver() {
   1278  FallbackDriverState oldState =
   1279      mFallbackDriverState.exchange(FallbackDriverState::Running);
   1280  switch (oldState) {
   1281    case FallbackDriverState::None:
   1282      // None -> Running: we can start the fallback.
   1283      FallbackToSystemClockDriver();
   1284      return true;
   1285    case FallbackDriverState::Stopped:
   1286      // Stopped -> Running: Invalid edge, the graph has told us to stop.
   1287      // Restore the state.
   1288      mFallbackDriverState = oldState;
   1289      [[fallthrough]];
   1290    case FallbackDriverState::Running:
   1291      // Nothing to do, return the state.
   1292      return Err(oldState);
   1293  }
   1294  MOZ_CRASH("Unexpected fallback state");
   1295 }
   1296 
   1297 void AudioCallbackDriver::FallbackToSystemClockDriver() {
   1298  MOZ_ASSERT(mFallbackDriverState == FallbackDriverState::Running);
   1299  DebugOnly<AudioStreamState> audioStreamState =
   1300      static_cast<AudioStreamState>(mAudioStreamState);
   1301  MOZ_ASSERT(audioStreamState == AudioStreamState::None ||
   1302             audioStreamState == AudioStreamState::Pending ||
   1303             audioStreamState == AudioStreamState::ChangingDevice);
   1304  LOG(LogLevel::Debug,
   1305      ("%p: AudioCallbackDriver %p Falling back to SystemClockDriver.", Graph(),
   1306       this));
   1307  // On DeviceChangedCallback() or StateChangeCallback(), mScratchBuffer might
   1308  // not be empty, but switching to a fallback driver is giving up on
   1309  // outputting mScratchBuffer contiguously.
   1310  // Clear the buffer so that it is not output later when an audio callback
   1311  // arrives for a new discontiguous output stream.
   1312  mScratchBuffer.Empty();
   1313 
   1314  mNextReInitBackoffStep =
   1315      TimeDuration::FromMilliseconds(AUDIO_INITIAL_FALLBACK_BACKOFF_STEP_MS);
   1316  mNextReInitAttempt = TimeStamp::Now() + mNextReInitBackoffStep;
   1317  auto fallback = MakeRefPtr<FallbackWrapper>(Graph(), this, mSampleRate,
   1318                                              mStreamName, mStateComputedTime,
   1319                                              mTargetIterationTimeStamp);
   1320  {
   1321    auto driver = mFallback.Lock();
   1322    MOZ_RELEASE_ASSERT(!driver.ref());
   1323    driver.ref() = fallback;
   1324  }
   1325  fallback->Start();
   1326 }
   1327 
   1328 void AudioCallbackDriver::FallbackDriverStopped(GraphTime aStateComputedTime,
   1329                                                TimeStamp aIterationTimeStamp,
   1330                                                FallbackDriverState aState) {
   1331  LOG(LogLevel::Debug,
   1332      ("%p: AudioCallbackDriver %p Fallback driver has stopped.", Graph(),
   1333       this));
   1334  mStateComputedTime = aStateComputedTime;
   1335  mTargetIterationTimeStamp = aIterationTimeStamp;
   1336  mNextReInitAttempt = TimeStamp();
   1337  mNextReInitBackoffStep = TimeDuration();
   1338  {
   1339    auto fallback = mFallback.Lock();
   1340    MOZ_ASSERT(fallback.ref()->OnThread());
   1341    fallback.ref() = nullptr;
   1342  }
   1343 
   1344  MOZ_ASSERT(aState == FallbackDriverState::None ||
   1345             aState == FallbackDriverState::Stopped);
   1346  mFallbackDriverState = aState;
   1347  AudioStreamState audioState = mAudioStreamState;
   1348  LOG(LogLevel::Debug,
   1349      ("%p: AudioCallbackDriver %p Fallback driver stopped.%s%s", Graph(), this,
   1350       aState == FallbackDriverState::Stopped ? " Draining." : "",
   1351       aState == FallbackDriverState::None &&
   1352               audioState == AudioStreamState::ChangingDevice
   1353           ? " Starting another due to device change."
   1354           : ""));
   1355 
   1356  if (aState == FallbackDriverState::None) {
   1357    MOZ_ASSERT(audioState == AudioStreamState::Running ||
   1358               audioState == AudioStreamState::ChangingDevice);
   1359    if (audioState == AudioStreamState::ChangingDevice) {
   1360      MOZ_ALWAYS_OK(TryStartingFallbackDriver());
   1361    }
   1362  }
   1363 }
   1364 
   1365 void AudioCallbackDriver::MaybeStartAudioStream() {
   1366  AudioStreamState streamState = mAudioStreamState;
   1367  if (streamState != AudioStreamState::None) {
   1368    LOG(LogLevel::Verbose,
   1369        ("%p: AudioCallbackDriver %p Cannot re-init.", Graph(), this));
   1370    return;
   1371  }
   1372 
   1373  TimeStamp now = TimeStamp::Now();
   1374  if (now < mNextReInitAttempt) {
   1375    LOG(LogLevel::Verbose,
   1376        ("%p: AudioCallbackDriver %p Not time to re-init yet. %.3fs left.",
   1377         Graph(), this, (mNextReInitAttempt - now).ToSeconds()));
   1378    return;
   1379  }
   1380 
   1381  LOG(LogLevel::Debug, ("%p: AudioCallbackDriver %p Attempting to re-init "
   1382                        "audio stream from fallback driver.",
   1383                        Graph(), this));
   1384  mNextReInitBackoffStep =
   1385      std::min(mNextReInitBackoffStep * 2,
   1386               TimeDuration::FromMilliseconds(
   1387                   StaticPrefs::media_audio_device_retry_ms()));
   1388  mNextReInitAttempt = now + mNextReInitBackoffStep;
   1389  Start();
   1390 }
   1391 
   1392 const AudioInputProcessingParamsRequest&
   1393 AudioCallbackDriver::RequestedInputProcessingParams() const {
   1394  MOZ_ASSERT(InIteration());
   1395  return mInputProcessingRequest;
   1396 }
   1397 
   1398 void AudioCallbackDriver::RequestInputProcessingParams(
   1399    AudioInputProcessingParamsRequest aRequest) {
   1400  MOZ_ASSERT(InIteration());
   1401  MOZ_ASSERT(aRequest.mGeneration > mInputProcessingRequest.mGeneration);
   1402  MOZ_ASSERT(aRequest.mParams != mInputProcessingRequest.mParams);
   1403  LOG(LogLevel::Info,
   1404      ("AudioCallbackDriver %p, Input processing params %s (Gen %d) requested.",
   1405       this, CubebUtils::ProcessingParamsToString(aRequest.mParams).get(),
   1406       aRequest.mGeneration));
   1407  mInputProcessingRequest = aRequest;
   1408  MOZ_ALWAYS_SUCCEEDS(mCubebOperationThread->Dispatch(
   1409      NS_NewRunnableFunction(__func__, [this, self = RefPtr(this), aRequest] {
   1410        SetInputProcessingParams(aRequest);
   1411      })));
   1412 }
   1413 
   1414 void AudioCallbackDriver::SetInputProcessingParams(
   1415    AudioInputProcessingParamsRequest aRequest) {
   1416  MOZ_ASSERT(OnCubebOperationThread());
   1417  const auto requested = aRequest.mParams;
   1418  auto params = aRequest.mParams;
   1419  const auto generation = aRequest.mGeneration;
   1420  auto result = ([&]() -> Maybe<Result<cubeb_input_processing_params, int>> {
   1421    // This function decides how to handle the request.
   1422    // Returning Nothing() does nothing, because either
   1423    //   1) there is no update since the previous state, or
   1424    //   2) handling is deferred to a later time.
   1425    // Returning Some() result will forward that result to
   1426    // AudioDataListener::OnInputProcessingParamsResult on the callback
   1427    // thread.
   1428    if (!mAudioStream) {
   1429      // No Init yet.
   1430      LOG(LogLevel::Debug, ("AudioCallbackDriver %p, has no cubeb stream to "
   1431                            "set processing params on!",
   1432                            this));
   1433      return Nothing();
   1434    }
   1435    if (mAudioStreamState == AudioStreamState::None) {
   1436      // Driver (and cubeb stream) was stopped.
   1437      return Nothing();
   1438    }
   1439    cubeb_input_processing_params supported;
   1440    auto handle = CubebUtils::GetCubeb();
   1441    int r = cubeb_get_supported_input_processing_params(handle->Context(),
   1442                                                        &supported);
   1443    if (r != CUBEB_OK) {
   1444      LOG(LogLevel::Debug,
   1445          ("AudioCallbackDriver %p, no supported processing params", this));
   1446      return Some(Err(CUBEB_ERROR_NOT_SUPPORTED));
   1447    }
   1448    params &= supported;
   1449    LOG(LogLevel::Debug,
   1450        ("AudioCallbackDriver %p, requested processing params %s (gen %d) "
   1451         "reduced to %s by supported params %s",
   1452         this, CubebUtils::ProcessingParamsToString(requested).get(),
   1453         generation, CubebUtils::ProcessingParamsToString(params).get(),
   1454         CubebUtils::ProcessingParamsToString(supported).get()));
   1455    if (params == mConfiguredInputProcessingParams) {
   1456      LOG(LogLevel::Debug,
   1457          ("AudioCallbackDriver %p, no change in processing params %s. Not "
   1458           "attempting reconfiguration.",
   1459           this, CubebUtils::ProcessingParamsToString(params).get()));
   1460      return Some(params);
   1461    }
   1462    mConfiguredInputProcessingParams = params;
   1463    r = cubeb_stream_set_input_processing_params(mAudioStream, params);
   1464    if (r == CUBEB_OK) {
   1465      LOG(LogLevel::Info,
   1466          ("AudioCallbackDriver %p, input processing params set to %s", this,
   1467           CubebUtils::ProcessingParamsToString(params).get()));
   1468      return Some(params);
   1469    }
   1470    LOG(LogLevel::Info,
   1471        ("AudioCallbackDriver %p, failed setting input processing params to "
   1472         "%s. r=%d",
   1473         this, CubebUtils::ProcessingParamsToString(params).get(), r));
   1474    return Some(Err(r));
   1475  })();
   1476  if (!result) {
   1477    return;
   1478  }
   1479  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
   1480      NS_NewRunnableFunction(__func__, [this, self = RefPtr(this), generation,
   1481                                        result = result.extract()]() mutable {
   1482        LOG(LogLevel::Debug,
   1483            ("AudioCallbackDriver %p, Notifying of input processing params %s "
   1484             "(Gen %d). r=%d",
   1485             this,
   1486             CubebUtils::ProcessingParamsToString(
   1487                 result.unwrapOr(CUBEB_INPUT_PROCESSING_PARAM_NONE))
   1488                 .get(),
   1489             generation, result.isErr() ? result.inspectErr() : CUBEB_OK));
   1490        mGraphInterface->NotifySetRequestedInputProcessingParamsResult(
   1491            this, generation, std::move(result));
   1492      })));
   1493 }
   1494 
   1495 }  // namespace mozilla
   1496 
   1497 // avoid redefined macro in unified build
   1498 #undef LOG