GraphDriver.cpp 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  4. * You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include <MediaStreamGraphImpl.h>
  6. #include "mozilla/dom/AudioContext.h"
  7. #include "mozilla/SharedThreadPool.h"
  8. #include "mozilla/ClearOnShutdown.h"
  9. #include "mozilla/Unused.h"
  10. #include "CubebUtils.h"
  11. #ifdef MOZ_WEBRTC
  12. #include "webrtc/MediaEngineWebRTC.h"
  13. #endif
  14. extern mozilla::LazyLogModule gMediaStreamGraphLog;
  15. #define STREAM_LOG(type, msg) MOZ_LOG(gMediaStreamGraphLog, type, msg)
  16. // XXX: We didn't use NSPR log here because we wanted this interleaved with
  17. // adb logcat on Android/B2G. This is no longer a concern; use NSPR?
  18. // #define ENABLE_LIFECYCLE_LOG
  19. #ifdef ENABLE_LIFECYCLE_LOG
  20. #define LIFECYCLE_LOG(...) printf(__VA_ARGS__);printf("\n");
  21. #else
  22. #define LIFECYCLE_LOG(...)
  23. #endif
  24. namespace mozilla {
  25. StaticRefPtr<nsIThreadPool> AsyncCubebTask::sThreadPool;
  26. struct AutoProfilerUnregisterThread
  27. {
  28. // The empty ctor is used to silence a pre-4.8.0 GCC unused variable warning.
  29. AutoProfilerUnregisterThread()
  30. {
  31. }
  32. ~AutoProfilerUnregisterThread()
  33. {
  34. profiler_unregister_thread();
  35. }
  36. };
  37. GraphDriver::GraphDriver(MediaStreamGraphImpl* aGraphImpl)
  38. : mIterationStart(0),
  39. mIterationEnd(0),
  40. mGraphImpl(aGraphImpl),
  41. mWaitState(WAITSTATE_RUNNING),
  42. mCurrentTimeStamp(TimeStamp::Now()),
  43. mPreviousDriver(nullptr),
  44. mNextDriver(nullptr)
  45. { }
  46. void GraphDriver::SetGraphTime(GraphDriver* aPreviousDriver,
  47. GraphTime aLastSwitchNextIterationStart,
  48. GraphTime aLastSwitchNextIterationEnd)
  49. {
  50. GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
  51. // We set mIterationEnd here, because the first thing a driver do when it
  52. // does an iteration is to update graph times, so we are in fact setting
  53. // mIterationStart of the next iteration by setting the end of the previous
  54. // iteration.
  55. mIterationStart = aLastSwitchNextIterationStart;
  56. mIterationEnd = aLastSwitchNextIterationEnd;
  57. MOZ_ASSERT(!PreviousDriver());
  58. MOZ_ASSERT(aPreviousDriver);
  59. STREAM_LOG(LogLevel::Debug, ("Setting previous driver: %p (%s)",
  60. aPreviousDriver,
  61. aPreviousDriver->AsAudioCallbackDriver()
  62. ? "AudioCallbackDriver"
  63. : "SystemClockDriver"));
  64. SetPreviousDriver(aPreviousDriver);
  65. }
  66. void GraphDriver::SwitchAtNextIteration(GraphDriver* aNextDriver)
  67. {
  68. GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
  69. LIFECYCLE_LOG("Switching to new driver: %p (%s)",
  70. aNextDriver, aNextDriver->AsAudioCallbackDriver() ?
  71. "AudioCallbackDriver" : "SystemClockDriver");
  72. if (mNextDriver &&
  73. mNextDriver != GraphImpl()->CurrentDriver()) {
  74. LIFECYCLE_LOG("Discarding previous next driver: %p (%s)",
  75. mNextDriver.get(), mNextDriver->AsAudioCallbackDriver() ?
  76. "AudioCallbackDriver" : "SystemClockDriver");
  77. }
  78. SetNextDriver(aNextDriver);
  79. }
  80. GraphTime
  81. GraphDriver::StateComputedTime() const
  82. {
  83. return mGraphImpl->mStateComputedTime;
  84. }
  85. void GraphDriver::EnsureNextIteration()
  86. {
  87. mGraphImpl->EnsureNextIteration();
  88. }
  89. void GraphDriver::Shutdown()
  90. {
  91. if (AsAudioCallbackDriver()) {
  92. LIFECYCLE_LOG("Releasing audio driver off main thread (GraphDriver::Shutdown).\n");
  93. RefPtr<AsyncCubebTask> releaseEvent =
  94. new AsyncCubebTask(AsAudioCallbackDriver(), AsyncCubebOperation::SHUTDOWN);
  95. releaseEvent->Dispatch(NS_DISPATCH_SYNC);
  96. } else {
  97. Stop();
  98. }
  99. }
  100. bool GraphDriver::Switching()
  101. {
  102. GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
  103. return mNextDriver || mPreviousDriver;
  104. }
  105. GraphDriver* GraphDriver::NextDriver()
  106. {
  107. GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
  108. return mNextDriver;
  109. }
  110. GraphDriver* GraphDriver::PreviousDriver()
  111. {
  112. GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
  113. return mPreviousDriver;
  114. }
  115. void GraphDriver::SetNextDriver(GraphDriver* aNextDriver)
  116. {
  117. GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
  118. mNextDriver = aNextDriver;
  119. }
  120. void GraphDriver::SetPreviousDriver(GraphDriver* aPreviousDriver)
  121. {
  122. GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
  123. mPreviousDriver = aPreviousDriver;
  124. }
  125. ThreadedDriver::ThreadedDriver(MediaStreamGraphImpl* aGraphImpl)
  126. : GraphDriver(aGraphImpl)
  127. { }
  128. class MediaStreamGraphShutdownThreadRunnable : public Runnable {
  129. public:
  130. explicit MediaStreamGraphShutdownThreadRunnable(already_AddRefed<nsIThread> aThread)
  131. : mThread(aThread)
  132. {
  133. }
  134. NS_IMETHOD Run() override
  135. {
  136. MOZ_ASSERT(NS_IsMainThread());
  137. MOZ_ASSERT(mThread);
  138. mThread->Shutdown();
  139. mThread = nullptr;
  140. return NS_OK;
  141. }
  142. private:
  143. nsCOMPtr<nsIThread> mThread;
  144. };
  145. ThreadedDriver::~ThreadedDriver()
  146. {
  147. if (mThread) {
  148. if (NS_IsMainThread()) {
  149. mThread->Shutdown();
  150. } else {
  151. nsCOMPtr<nsIRunnable> event =
  152. new MediaStreamGraphShutdownThreadRunnable(mThread.forget());
  153. NS_DispatchToMainThread(event);
  154. }
  155. }
  156. }
  157. class MediaStreamGraphInitThreadRunnable : public Runnable {
  158. public:
  159. explicit MediaStreamGraphInitThreadRunnable(ThreadedDriver* aDriver)
  160. : mDriver(aDriver)
  161. {
  162. }
  163. NS_IMETHOD Run() override
  164. {
  165. char aLocal;
  166. STREAM_LOG(LogLevel::Debug, ("Starting system thread"));
  167. profiler_register_thread("MediaStreamGraph", &aLocal);
  168. LIFECYCLE_LOG("Starting a new system driver for graph %p\n",
  169. mDriver->mGraphImpl.get());
  170. RefPtr<GraphDriver> previousDriver;
  171. {
  172. MonitorAutoLock mon(mDriver->mGraphImpl->GetMonitor());
  173. previousDriver = mDriver->PreviousDriver();
  174. }
  175. if (previousDriver) {
  176. LIFECYCLE_LOG("%p releasing an AudioCallbackDriver(%p), for graph %p\n",
  177. mDriver,
  178. previousDriver,
  179. mDriver->GraphImpl());
  180. MOZ_ASSERT(!mDriver->AsAudioCallbackDriver());
  181. RefPtr<AsyncCubebTask> releaseEvent =
  182. new AsyncCubebTask(previousDriver->AsAudioCallbackDriver(), AsyncCubebOperation::SHUTDOWN);
  183. releaseEvent->Dispatch();
  184. MonitorAutoLock mon(mDriver->mGraphImpl->GetMonitor());
  185. mDriver->SetPreviousDriver(nullptr);
  186. } else {
  187. MonitorAutoLock mon(mDriver->mGraphImpl->GetMonitor());
  188. MOZ_ASSERT(mDriver->mGraphImpl->MessagesQueued() ||
  189. mDriver->mGraphImpl->mForceShutDown, "Don't start a graph without messages queued.");
  190. mDriver->mGraphImpl->SwapMessageQueues();
  191. }
  192. mDriver->RunThread();
  193. return NS_OK;
  194. }
  195. private:
  196. RefPtr<ThreadedDriver> mDriver;
  197. };
  198. void
  199. ThreadedDriver::Start()
  200. {
  201. LIFECYCLE_LOG("Starting thread for a SystemClockDriver %p\n", mGraphImpl.get());
  202. Unused << NS_WARN_IF(mThread);
  203. if (!mThread) { // Ensure we haven't already started it
  204. nsCOMPtr<nsIRunnable> event = new MediaStreamGraphInitThreadRunnable(this);
  205. // Note: mThread may be null during event->Run() if we pass to NewNamedThread! See AudioInitTask
  206. nsresult rv = NS_NewNamedThread("MediaStreamGrph", getter_AddRefs(mThread));
  207. if (NS_SUCCEEDED(rv)) {
  208. mThread->Dispatch(event, NS_DISPATCH_NORMAL);
  209. }
  210. }
  211. }
  212. void
  213. ThreadedDriver::Resume()
  214. {
  215. Start();
  216. }
  217. void
  218. ThreadedDriver::Revive()
  219. {
  220. // Note: only called on MainThread, without monitor
  221. // We know were weren't in a running state
  222. STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver reviving."));
  223. // If we were switching, switch now. Otherwise, tell thread to run the main
  224. // loop again.
  225. MonitorAutoLock mon(mGraphImpl->GetMonitor());
  226. if (NextDriver()) {
  227. NextDriver()->SetGraphTime(this, mIterationStart, mIterationEnd);
  228. mGraphImpl->SetCurrentDriver(NextDriver());
  229. NextDriver()->Start();
  230. } else {
  231. nsCOMPtr<nsIRunnable> event = new MediaStreamGraphInitThreadRunnable(this);
  232. mThread->Dispatch(event, NS_DISPATCH_NORMAL);
  233. }
  234. }
  235. void
  236. ThreadedDriver::RemoveCallback()
  237. {
  238. }
  239. void
  240. ThreadedDriver::Stop()
  241. {
  242. NS_ASSERTION(NS_IsMainThread(), "Must be called on main thread");
  243. // mGraph's thread is not running so it's OK to do whatever here
  244. STREAM_LOG(LogLevel::Debug, ("Stopping threads for MediaStreamGraph %p", this));
  245. if (mThread) {
  246. mThread->Shutdown();
  247. mThread = nullptr;
  248. }
  249. }
  250. SystemClockDriver::SystemClockDriver(MediaStreamGraphImpl* aGraphImpl)
  251. : ThreadedDriver(aGraphImpl),
  252. mInitialTimeStamp(TimeStamp::Now()),
  253. mLastTimeStamp(TimeStamp::Now()),
  254. mIsFallback(false)
  255. {}
  256. SystemClockDriver::~SystemClockDriver()
  257. { }
  258. void
  259. SystemClockDriver::MarkAsFallback()
  260. {
  261. mIsFallback = true;
  262. }
  263. bool
  264. SystemClockDriver::IsFallback()
  265. {
  266. return mIsFallback;
  267. }
  268. void
  269. ThreadedDriver::RunThread()
  270. {
  271. AutoProfilerUnregisterThread autoUnregister;
  272. while (true) {
  273. mIterationStart = IterationEnd();
  274. mIterationEnd += GetIntervalForIteration();
  275. GraphTime stateComputedTime = StateComputedTime();
  276. if (stateComputedTime < mIterationEnd) {
  277. STREAM_LOG(LogLevel::Warning, ("Media graph global underrun detected"));
  278. mIterationEnd = stateComputedTime;
  279. }
  280. if (mIterationStart >= mIterationEnd) {
  281. NS_ASSERTION(mIterationStart == mIterationEnd ,
  282. "Time can't go backwards!");
  283. // This could happen due to low clock resolution, maybe?
  284. STREAM_LOG(LogLevel::Debug, ("Time did not advance"));
  285. }
  286. GraphTime nextStateComputedTime =
  287. mGraphImpl->RoundUpToNextAudioBlock(
  288. mIterationEnd + mGraphImpl->MillisecondsToMediaTime(AUDIO_TARGET_MS));
  289. if (nextStateComputedTime < stateComputedTime) {
  290. // A previous driver may have been processing further ahead of
  291. // iterationEnd.
  292. STREAM_LOG(LogLevel::Warning,
  293. ("Prevent state from going backwards. interval[%ld; %ld] state[%ld; %ld]",
  294. (long)mIterationStart, (long)mIterationEnd,
  295. (long)stateComputedTime, (long)nextStateComputedTime));
  296. nextStateComputedTime = stateComputedTime;
  297. }
  298. STREAM_LOG(LogLevel::Verbose,
  299. ("interval[%ld; %ld] state[%ld; %ld]",
  300. (long)mIterationStart, (long)mIterationEnd,
  301. (long)stateComputedTime, (long)nextStateComputedTime));
  302. bool stillProcessing = mGraphImpl->OneIteration(nextStateComputedTime);
  303. if (!stillProcessing) {
  304. // Enter shutdown mode. The stable-state handler will detect this
  305. // and complete shutdown if the graph does not get restarted.
  306. mGraphImpl->SignalMainThreadCleanup();
  307. return;
  308. }
  309. MonitorAutoLock lock(GraphImpl()->GetMonitor());
  310. if (NextDriver()) {
  311. STREAM_LOG(LogLevel::Debug, ("Switching to AudioCallbackDriver"));
  312. RemoveCallback();
  313. NextDriver()->SetGraphTime(this, mIterationStart, mIterationEnd);
  314. mGraphImpl->SetCurrentDriver(NextDriver());
  315. NextDriver()->Start();
  316. return;
  317. }
  318. }
  319. }
  320. MediaTime
  321. SystemClockDriver::GetIntervalForIteration()
  322. {
  323. TimeStamp now = TimeStamp::Now();
  324. MediaTime interval =
  325. mGraphImpl->SecondsToMediaTime((now - mCurrentTimeStamp).ToSeconds());
  326. mCurrentTimeStamp = now;
  327. MOZ_LOG(gMediaStreamGraphLog, LogLevel::Verbose,
  328. ("Updating current time to %f (real %f, StateComputedTime() %f)",
  329. mGraphImpl->MediaTimeToSeconds(IterationEnd() + interval),
  330. (now - mInitialTimeStamp).ToSeconds(),
  331. mGraphImpl->MediaTimeToSeconds(StateComputedTime())));
  332. return interval;
  333. }
  334. TimeStamp
  335. OfflineClockDriver::GetCurrentTimeStamp()
  336. {
  337. MOZ_CRASH("This driver does not support getting the current timestamp.");
  338. return TimeStamp();
  339. }
  340. void
  341. SystemClockDriver::WaitForNextIteration()
  342. {
  343. mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
  344. PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
  345. TimeStamp now = TimeStamp::Now();
  346. // This lets us avoid hitting the Atomic twice when we know we won't sleep
  347. bool another = mGraphImpl->mNeedAnotherIteration; // atomic
  348. if (!another) {
  349. mGraphImpl->mGraphDriverAsleep = true; // atomic
  350. mWaitState = WAITSTATE_WAITING_INDEFINITELY;
  351. }
  352. // NOTE: mNeedAnotherIteration while also atomic may have changed before
  353. // we could set mGraphDriverAsleep, so we must re-test it.
  354. // (EnsureNextIteration sets mNeedAnotherIteration, then tests
  355. // mGraphDriverAsleep
  356. if (another || mGraphImpl->mNeedAnotherIteration) { // atomic
  357. int64_t timeoutMS = MEDIA_GRAPH_TARGET_PERIOD_MS -
  358. int64_t((now - mCurrentTimeStamp).ToMilliseconds());
  359. // Make sure timeoutMS doesn't overflow 32 bits by waking up at
  360. // least once a minute, if we need to wake up at all
  361. timeoutMS = std::max<int64_t>(0, std::min<int64_t>(timeoutMS, 60*1000));
  362. timeout = PR_MillisecondsToInterval(uint32_t(timeoutMS));
  363. STREAM_LOG(LogLevel::Verbose,
  364. ("Waiting for next iteration; at %f, timeout=%f",
  365. (now - mInitialTimeStamp).ToSeconds(), timeoutMS/1000.0));
  366. if (mWaitState == WAITSTATE_WAITING_INDEFINITELY) {
  367. mGraphImpl->mGraphDriverAsleep = false; // atomic
  368. }
  369. mWaitState = WAITSTATE_WAITING_FOR_NEXT_ITERATION;
  370. }
  371. if (timeout > 0) {
  372. mGraphImpl->GetMonitor().Wait(timeout);
  373. STREAM_LOG(LogLevel::Verbose, ("Resuming after timeout; at %f, elapsed=%f",
  374. (TimeStamp::Now() - mInitialTimeStamp).ToSeconds(),
  375. (TimeStamp::Now() - now).ToSeconds()));
  376. }
  377. if (mWaitState == WAITSTATE_WAITING_INDEFINITELY) {
  378. mGraphImpl->mGraphDriverAsleep = false; // atomic
  379. }
  380. // Note: this can race against the EnsureNextIteration setting
  381. // WAITSTATE_RUNNING and setting mGraphDriverAsleep to false, so you can
  382. // have an iteration with WAITSTATE_WAKING_UP instead of RUNNING.
  383. mWaitState = WAITSTATE_RUNNING;
  384. mGraphImpl->mNeedAnotherIteration = false; // atomic
  385. }
  386. void SystemClockDriver::WakeUp()
  387. {
  388. mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
  389. // Note: this can race against the thread setting WAITSTATE_RUNNING and
  390. // setting mGraphDriverAsleep to false, so you can have an iteration
  391. // with WAITSTATE_WAKING_UP instead of RUNNING.
  392. mWaitState = WAITSTATE_WAKING_UP;
  393. mGraphImpl->mGraphDriverAsleep = false; // atomic
  394. mGraphImpl->GetMonitor().Notify();
  395. }
  396. OfflineClockDriver::OfflineClockDriver(MediaStreamGraphImpl* aGraphImpl, GraphTime aSlice)
  397. : ThreadedDriver(aGraphImpl),
  398. mSlice(aSlice)
  399. {
  400. }
  401. OfflineClockDriver::~OfflineClockDriver()
  402. {
  403. }
  404. MediaTime
  405. OfflineClockDriver::GetIntervalForIteration()
  406. {
  407. return mGraphImpl->MillisecondsToMediaTime(mSlice);
  408. }
  409. void
  410. OfflineClockDriver::WaitForNextIteration()
  411. {
  412. // No op: we want to go as fast as possible when we are offline
  413. }
  414. void
  415. OfflineClockDriver::WakeUp()
  416. {
  417. MOZ_ASSERT(false, "An offline graph should not have to wake up.");
  418. }
  419. AsyncCubebTask::AsyncCubebTask(AudioCallbackDriver* aDriver, AsyncCubebOperation aOperation)
  420. : mDriver(aDriver),
  421. mOperation(aOperation),
  422. mShutdownGrip(aDriver->GraphImpl())
  423. {
  424. NS_WARNING_ASSERTION(mDriver->mAudioStream || aOperation == INIT,
  425. "No audio stream!");
  426. }
  427. AsyncCubebTask::~AsyncCubebTask()
  428. {
  429. }
  430. /* static */
  431. nsresult
  432. AsyncCubebTask::EnsureThread()
  433. {
  434. if (!sThreadPool) {
  435. nsCOMPtr<nsIThreadPool> threadPool =
  436. SharedThreadPool::Get(NS_LITERAL_CSTRING("CubebOperation"), 1);
  437. sThreadPool = threadPool;
  438. // Need to null this out before xpcom-shutdown-threads Observers run
  439. // since we don't know the order that the shutdown-threads observers
  440. // will run. ClearOnShutdown guarantees it runs first.
  441. if (!NS_IsMainThread()) {
  442. NS_DispatchToMainThread(NS_NewRunnableFunction([]() -> void {
  443. ClearOnShutdown(&sThreadPool, ShutdownPhase::ShutdownThreads);
  444. }));
  445. } else {
  446. ClearOnShutdown(&sThreadPool, ShutdownPhase::ShutdownThreads);
  447. }
  448. const uint32_t kIdleThreadTimeoutMs = 2000;
  449. nsresult rv = sThreadPool->SetIdleThreadTimeout(PR_MillisecondsToInterval(kIdleThreadTimeoutMs));
  450. if (NS_WARN_IF(NS_FAILED(rv))) {
  451. return rv;
  452. }
  453. }
  454. return NS_OK;
  455. }
  456. NS_IMETHODIMP
  457. AsyncCubebTask::Run()
  458. {
  459. MOZ_ASSERT(mDriver);
  460. switch(mOperation) {
  461. case AsyncCubebOperation::INIT: {
  462. LIFECYCLE_LOG("AsyncCubebOperation::INIT driver=%p\n", mDriver.get());
  463. mDriver->Init();
  464. mDriver->CompleteAudioContextOperations(mOperation);
  465. break;
  466. }
  467. case AsyncCubebOperation::SHUTDOWN: {
  468. LIFECYCLE_LOG("AsyncCubebOperation::SHUTDOWN driver=%p\n", mDriver.get());
  469. mDriver->Stop();
  470. mDriver->CompleteAudioContextOperations(mOperation);
  471. mDriver = nullptr;
  472. mShutdownGrip = nullptr;
  473. break;
  474. }
  475. default:
  476. MOZ_CRASH("Operation not implemented.");
  477. }
  478. // The thread will kill itself after a bit
  479. return NS_OK;
  480. }
  481. StreamAndPromiseForOperation::StreamAndPromiseForOperation(MediaStream* aStream,
  482. void* aPromise,
  483. dom::AudioContextOperation aOperation)
  484. : mStream(aStream)
  485. , mPromise(aPromise)
  486. , mOperation(aOperation)
  487. {
  488. // MOZ_ASSERT(aPromise);
  489. }
  490. AudioCallbackDriver::AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl)
  491. : GraphDriver(aGraphImpl)
  492. , mSampleRate(0)
  493. , mInputChannels(1)
  494. , mIterationDurationMS(MEDIA_GRAPH_TARGET_PERIOD_MS)
  495. , mStarted(false)
  496. , mAudioInput(nullptr)
  497. , mAudioChannel(aGraphImpl->AudioChannel())
  498. , mAddedMixer(false)
  499. , mInCallback(false)
  500. , mMicrophoneActive(false)
  501. , mShouldFallbackIfError(false)
  502. , mFromFallback(false)
  503. {
  504. STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver ctor for graph %p", aGraphImpl));
  505. }
  506. AudioCallbackDriver::~AudioCallbackDriver()
  507. {
  508. MOZ_ASSERT(mPromisesForOperation.IsEmpty());
  509. }
  510. void
  511. AudioCallbackDriver::Init()
  512. {
  513. cubeb* cubebContext = CubebUtils::GetCubebContext();
  514. if (!cubebContext) {
  515. NS_WARNING("Could not get cubeb context.");
  516. return;
  517. }
  518. cubeb_stream_params output;
  519. cubeb_stream_params input;
  520. uint32_t latency_frames;
  521. MOZ_ASSERT(!NS_IsMainThread(),
  522. "This is blocking and should never run on the main thread.");
  523. mSampleRate = output.rate = CubebUtils::PreferredSampleRate();
  524. (void)mAudioChannel;
  525. output.channels = mGraphImpl->AudioChannelCount();
  526. if (AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_S16) {
  527. output.format = CUBEB_SAMPLE_S16NE;
  528. } else {
  529. output.format = CUBEB_SAMPLE_FLOAT32NE;
  530. }
  531. Maybe<uint32_t> latencyPref = CubebUtils::GetCubebMSGLatencyInFrames();
  532. if (latencyPref) {
  533. latency_frames = latencyPref.value();
  534. } else {
  535. if (cubeb_get_min_latency(cubebContext, output, &latency_frames) != CUBEB_OK) {
  536. NS_WARNING("Could not get minimal latency from cubeb.");
  537. }
  538. }
  539. input = output;
  540. input.channels = mInputChannels; // change to support optional stereo capture
  541. cubeb_stream* stream = nullptr;
  542. CubebUtils::AudioDeviceID input_id = nullptr, output_id = nullptr;
  543. // We have to translate the deviceID values to cubeb devid's since those can be
  544. // freed whenever enumerate is called.
  545. {
  546. #ifdef MOZ_WEBRTC
  547. StaticMutexAutoLock lock(AudioInputCubeb::Mutex());
  548. #endif
  549. if ((!mGraphImpl->mInputWanted
  550. #ifdef MOZ_WEBRTC
  551. || AudioInputCubeb::GetDeviceID(mGraphImpl->mInputDeviceID, input_id)
  552. #endif
  553. ) &&
  554. (mGraphImpl->mOutputDeviceID == -1 // pass nullptr for ID for default output
  555. #ifdef MOZ_WEBRTC
  556. // XXX we should figure out how we would use a deviceID for output without webrtc.
  557. // Currently we don't set this though, so it's ok
  558. || AudioInputCubeb::GetDeviceID(mGraphImpl->mOutputDeviceID, output_id)
  559. #endif
  560. ) &&
  561. // XXX Only pass input input if we have an input listener. Always
  562. // set up output because it's easier, and it will just get silence.
  563. // XXX Add support for adding/removing an input listener later.
  564. cubeb_stream_init(cubebContext, &stream,
  565. "AudioCallbackDriver",
  566. input_id,
  567. mGraphImpl->mInputWanted ? &input : nullptr,
  568. output_id,
  569. mGraphImpl->mOutputWanted ? &output : nullptr, latency_frames,
  570. DataCallback_s, StateCallback_s, this) == CUBEB_OK) {
  571. mAudioStream.own(stream);
  572. DebugOnly<int> rv = cubeb_stream_set_volume(mAudioStream, CubebUtils::GetVolumeScale());
  573. NS_WARNING_ASSERTION(
  574. rv == CUBEB_OK,
  575. "Could not set the audio stream volume in GraphDriver.cpp");
  576. } else {
  577. #ifdef MOZ_WEBRTC
  578. StaticMutexAutoUnlock unlock(AudioInputCubeb::Mutex());
  579. #endif
  580. NS_WARNING("Could not create a cubeb stream for MediaStreamGraph, falling back to a SystemClockDriver");
  581. // Fall back to a driver using a normal thread. If needed,
  582. // the graph will try to re-open an audio stream later.
  583. MonitorAutoLock lock(GraphImpl()->GetMonitor());
  584. SystemClockDriver* nextDriver = new SystemClockDriver(GraphImpl());
  585. SetNextDriver(nextDriver);
  586. nextDriver->MarkAsFallback();
  587. nextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
  588. // We're not using SwitchAtNextIteration here, because there
  589. // won't be a next iteration if we don't restart things manually:
  590. // the audio stream just signaled that it's in error state.
  591. mGraphImpl->SetCurrentDriver(nextDriver);
  592. nextDriver->Start();
  593. return;
  594. }
  595. }
  596. bool aec;
  597. Unused << mGraphImpl->AudioTrackPresent(aec);
  598. SetMicrophoneActive(aec);
  599. cubeb_stream_register_device_changed_callback(mAudioStream,
  600. AudioCallbackDriver::DeviceChangedCallback_s);
  601. StartStream();
  602. STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver started."));
  603. }
  604. void
  605. AudioCallbackDriver::Destroy()
  606. {
  607. STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver destroyed."));
  608. mAudioInput = nullptr;
  609. mAudioStream.reset();
  610. }
  611. void
  612. AudioCallbackDriver::Resume()
  613. {
  614. STREAM_LOG(LogLevel::Debug, ("Resuming audio threads for MediaStreamGraph %p", mGraphImpl.get()));
  615. if (cubeb_stream_start(mAudioStream) != CUBEB_OK) {
  616. NS_WARNING("Could not start cubeb stream for MSG.");
  617. }
  618. }
  619. void
  620. AudioCallbackDriver::Start()
  621. {
  622. if (mPreviousDriver) {
  623. if (mPreviousDriver->AsAudioCallbackDriver()) {
  624. LIFECYCLE_LOG("Releasing audio driver off main thread.");
  625. RefPtr<AsyncCubebTask> releaseEvent =
  626. new AsyncCubebTask(mPreviousDriver->AsAudioCallbackDriver(),
  627. AsyncCubebOperation::SHUTDOWN);
  628. releaseEvent->Dispatch();
  629. mPreviousDriver = nullptr;
  630. } else {
  631. LIFECYCLE_LOG("Dropping driver reference for SystemClockDriver.");
  632. MOZ_ASSERT(mPreviousDriver->AsSystemClockDriver());
  633. mFromFallback = mPreviousDriver->AsSystemClockDriver()->IsFallback();
  634. mPreviousDriver = nullptr;
  635. }
  636. }
  637. LIFECYCLE_LOG("Starting new audio driver off main thread, "
  638. "to ensure it runs after previous shutdown.");
  639. RefPtr<AsyncCubebTask> initEvent =
  640. new AsyncCubebTask(AsAudioCallbackDriver(), AsyncCubebOperation::INIT);
  641. initEvent->Dispatch();
  642. }
  643. void
  644. AudioCallbackDriver::StartStream()
  645. {
  646. mShouldFallbackIfError = true;
  647. if (cubeb_stream_start(mAudioStream) != CUBEB_OK) {
  648. MOZ_CRASH("Could not start cubeb stream for MSG.");
  649. }
  650. {
  651. MonitorAutoLock mon(mGraphImpl->GetMonitor());
  652. mStarted = true;
  653. mWaitState = WAITSTATE_RUNNING;
  654. }
  655. }
  656. void
  657. AudioCallbackDriver::Stop()
  658. {
  659. if (cubeb_stream_stop(mAudioStream) != CUBEB_OK) {
  660. NS_WARNING("Could not stop cubeb stream for MSG.");
  661. }
  662. }
  663. void
  664. AudioCallbackDriver::Revive()
  665. {
  666. // Note: only called on MainThread, without monitor
  667. // We know were weren't in a running state
  668. STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver reviving."));
  669. // If we were switching, switch now. Otherwise, start the audio thread again.
  670. MonitorAutoLock mon(mGraphImpl->GetMonitor());
  671. if (NextDriver()) {
  672. RemoveCallback();
  673. NextDriver()->SetGraphTime(this, mIterationStart, mIterationEnd);
  674. mGraphImpl->SetCurrentDriver(NextDriver());
  675. NextDriver()->Start();
  676. } else {
  677. STREAM_LOG(LogLevel::Debug,
  678. ("Starting audio threads for MediaStreamGraph %p from a new thread.",
  679. mGraphImpl.get()));
  680. RefPtr<AsyncCubebTask> initEvent =
  681. new AsyncCubebTask(this, AsyncCubebOperation::INIT);
  682. initEvent->Dispatch();
  683. }
  684. }
  685. void
  686. AudioCallbackDriver::RemoveCallback()
  687. {
  688. if (mAddedMixer) {
  689. mGraphImpl->mMixer.RemoveCallback(this);
  690. mAddedMixer = false;
  691. }
  692. }
  693. void
  694. AudioCallbackDriver::WaitForNextIteration()
  695. {
  696. }
  697. void
  698. AudioCallbackDriver::WakeUp()
  699. {
  700. mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
  701. mGraphImpl->GetMonitor().Notify();
  702. }
  703. /* static */ long
  704. AudioCallbackDriver::DataCallback_s(cubeb_stream* aStream,
  705. void* aUser,
  706. const void* aInputBuffer,
  707. void* aOutputBuffer,
  708. long aFrames)
  709. {
  710. AudioCallbackDriver* driver = reinterpret_cast<AudioCallbackDriver*>(aUser);
  711. return driver->DataCallback(static_cast<const AudioDataValue*>(aInputBuffer),
  712. static_cast<AudioDataValue*>(aOutputBuffer), aFrames);
  713. }
  714. /* static */ void
  715. AudioCallbackDriver::StateCallback_s(cubeb_stream* aStream, void * aUser,
  716. cubeb_state aState)
  717. {
  718. AudioCallbackDriver* driver = reinterpret_cast<AudioCallbackDriver*>(aUser);
  719. driver->StateCallback(aState);
  720. }
  721. /* static */ void
  722. AudioCallbackDriver::DeviceChangedCallback_s(void* aUser)
  723. {
  724. AudioCallbackDriver* driver = reinterpret_cast<AudioCallbackDriver*>(aUser);
  725. driver->DeviceChangedCallback();
  726. }
  727. bool AudioCallbackDriver::InCallback() {
  728. return mInCallback;
  729. }
  730. AudioCallbackDriver::AutoInCallback::AutoInCallback(AudioCallbackDriver* aDriver)
  731. : mDriver(aDriver)
  732. {
  733. mDriver->mInCallback = true;
  734. }
  735. AudioCallbackDriver::AutoInCallback::~AutoInCallback() {
  736. mDriver->mInCallback = false;
  737. }
  738. long
  739. AudioCallbackDriver::DataCallback(const AudioDataValue* aInputBuffer,
  740. AudioDataValue* aOutputBuffer, long aFrames)
  741. {
  742. bool stillProcessing;
  743. // Don't add the callback until we're inited and ready
  744. if (!mAddedMixer) {
  745. mGraphImpl->mMixer.AddCallback(this);
  746. mAddedMixer = true;
  747. }
  748. #ifdef DEBUG
  749. // DebugOnly<> doesn't work here... it forces an initialization that will cause
  750. // mInCallback to be set back to false before we exit the statement. Do it by
  751. // hand instead.
  752. AutoInCallback aic(this);
  753. #endif
  754. GraphTime stateComputedTime = StateComputedTime();
  755. if (stateComputedTime == 0) {
  756. MonitorAutoLock mon(mGraphImpl->GetMonitor());
  757. // Because this function is called during cubeb_stream_init (to prefill the
  758. // audio buffers), it can be that we don't have a message here (because this
  759. // driver is the first one for this graph), and the graph would exit. Simply
  760. // return here until we have messages.
  761. if (!mGraphImpl->MessagesQueued()) {
  762. PodZero(aOutputBuffer, aFrames * mGraphImpl->AudioChannelCount());
  763. return aFrames;
  764. }
  765. mGraphImpl->SwapMessageQueues();
  766. }
  767. uint32_t durationMS = aFrames * 1000 / mSampleRate;
  768. // For now, simply average the duration with the previous
  769. // duration so there is some damping against sudden changes.
  770. if (!mIterationDurationMS) {
  771. mIterationDurationMS = durationMS;
  772. } else {
  773. mIterationDurationMS = (mIterationDurationMS*3) + durationMS;
  774. mIterationDurationMS /= 4;
  775. }
  776. // Process mic data if any/needed
  777. if (aInputBuffer) {
  778. if (mAudioInput) { // for this specific input-only or full-duplex stream
  779. mAudioInput->NotifyInputData(mGraphImpl, aInputBuffer,
  780. static_cast<size_t>(aFrames),
  781. mSampleRate, mInputChannels);
  782. }
  783. }
  784. mBuffer.SetBuffer(aOutputBuffer, aFrames);
  785. // fill part or all with leftover data from last iteration (since we
  786. // align to Audio blocks)
  787. mScratchBuffer.Empty(mBuffer);
  788. // if we totally filled the buffer (and mScratchBuffer isn't empty),
  789. // we don't need to run an iteration and if we do so we may overflow.
  790. if (mBuffer.Available()) {
  791. // State computed time is decided by the audio callback's buffer length. We
  792. // compute the iteration start and end from there, trying to keep the amount
  793. // of buffering in the graph constant.
  794. GraphTime nextStateComputedTime =
  795. mGraphImpl->RoundUpToNextAudioBlock(stateComputedTime + mBuffer.Available());
  796. mIterationStart = mIterationEnd;
  797. // inGraph is the number of audio frames there is between the state time and
  798. // the current time, i.e. the maximum theoretical length of the interval we
  799. // could use as [mIterationStart; mIterationEnd].
  800. GraphTime inGraph = stateComputedTime - mIterationStart;
  801. // We want the interval [mIterationStart; mIterationEnd] to be before the
  802. // interval [stateComputedTime; nextStateComputedTime]. We also want
  803. // the distance between these intervals to be roughly equivalent each time, to
  804. // ensure there is no clock drift between current time and state time. Since
  805. // we can't act on the state time because we have to fill the audio buffer, we
  806. // reclock the current time against the state time, here.
  807. mIterationEnd = mIterationStart + 0.8 * inGraph;
  808. STREAM_LOG(LogLevel::Verbose, ("interval[%ld; %ld] state[%ld; %ld] (frames: %ld) (durationMS: %u) (duration ticks: %ld)\n",
  809. (long)mIterationStart, (long)mIterationEnd,
  810. (long)stateComputedTime, (long)nextStateComputedTime,
  811. (long)aFrames, (uint32_t)durationMS,
  812. (long)(nextStateComputedTime - stateComputedTime)));
  813. mCurrentTimeStamp = TimeStamp::Now();
  814. if (stateComputedTime < mIterationEnd) {
  815. STREAM_LOG(LogLevel::Warning, ("Media graph global underrun detected"));
  816. mIterationEnd = stateComputedTime;
  817. }
  818. stillProcessing = mGraphImpl->OneIteration(nextStateComputedTime);
  819. } else {
  820. STREAM_LOG(LogLevel::Verbose, ("DataCallback buffer filled entirely from scratch buffer, skipping iteration."));
  821. stillProcessing = true;
  822. }
  823. mBuffer.BufferFilled();
  824. // Callback any observers for the AEC speaker data. Note that one
  825. // (maybe) of these will be full-duplex, the others will get their input
  826. // data off separate cubeb callbacks. Take care with how stuff is
  827. // removed/added to this list and TSAN issues, but input and output will
  828. // use separate callback methods.
  829. mGraphImpl->NotifyOutputData(aOutputBuffer, static_cast<size_t>(aFrames),
  830. mSampleRate, ChannelCount);
  831. if (!stillProcessing) {
  832. // About to hand over control of the graph. Do not start a new driver if
  833. // StateCallback() receives an error for this stream while the main thread
  834. // or another driver has control of the graph.
  835. mShouldFallbackIfError = false;
  836. // Enter shutdown mode. The stable-state handler will detect this
  837. // and complete shutdown if the graph does not get restarted.
  838. mGraphImpl->SignalMainThreadCleanup();
  839. return aFrames - 1;
  840. }
  841. bool switching = false;
  842. {
  843. MonitorAutoLock mon(mGraphImpl->GetMonitor());
  844. switching = !!NextDriver();
  845. }
  846. if (switching) {
  847. mShouldFallbackIfError = false;
  848. // If the audio stream has not been started by the previous driver or
  849. // the graph itself, keep it alive.
  850. MonitorAutoLock mon(mGraphImpl->GetMonitor());
  851. if (!IsStarted()) {
  852. return aFrames;
  853. }
  854. STREAM_LOG(LogLevel::Debug, ("Switching to system driver."));
  855. RemoveCallback();
  856. NextDriver()->SetGraphTime(this, mIterationStart, mIterationEnd);
  857. mGraphImpl->SetCurrentDriver(NextDriver());
  858. NextDriver()->Start();
  859. // Returning less than aFrames starts the draining and eventually stops the
  860. // audio thread. This function will never get called again.
  861. return aFrames - 1;
  862. }
  863. return aFrames;
  864. }
  865. void
  866. AudioCallbackDriver::StateCallback(cubeb_state aState)
  867. {
  868. STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver State: %d", aState));
  869. if (aState == CUBEB_STATE_ERROR && mShouldFallbackIfError) {
  870. mShouldFallbackIfError = false;
  871. MonitorAutoLock lock(GraphImpl()->GetMonitor());
  872. // Fall back to a driver using a normal thread. If needed,
  873. // the graph will try to re-open an audio stream later.
  874. SystemClockDriver* nextDriver = new SystemClockDriver(GraphImpl());
  875. SetNextDriver(nextDriver);
  876. RemoveCallback();
  877. nextDriver->MarkAsFallback();
  878. nextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
  879. // We're not using SwitchAtNextIteration here, because there
  880. // won't be a next iteration if we don't restart things manually:
  881. // the audio stream just signaled that it's in error state.
  882. mGraphImpl->SetCurrentDriver(nextDriver);
  883. nextDriver->Start();
  884. }
  885. }
  886. void
  887. AudioCallbackDriver::MixerCallback(AudioDataValue* aMixedBuffer,
  888. AudioSampleFormat aFormat,
  889. uint32_t aChannels,
  890. uint32_t aFrames,
  891. uint32_t aSampleRate)
  892. {
  893. uint32_t toWrite = mBuffer.Available();
  894. if (!mBuffer.Available()) {
  895. NS_WARNING("DataCallback buffer full, expect frame drops.");
  896. }
  897. MOZ_ASSERT(mBuffer.Available() <= aFrames);
  898. mBuffer.WriteFrames(aMixedBuffer, mBuffer.Available());
  899. MOZ_ASSERT(mBuffer.Available() == 0, "Missing frames to fill audio callback's buffer.");
  900. DebugOnly<uint32_t> written = mScratchBuffer.Fill(aMixedBuffer + toWrite * aChannels, aFrames - toWrite);
  901. NS_WARNING_ASSERTION(written == aFrames - toWrite, "Dropping frames.");
  902. };
  903. void
  904. AudioCallbackDriver::DeviceChangedCallback() {
  905. // Tell the audio engine the device has changed, it might want to reset some
  906. // state.
  907. MonitorAutoLock mon(mGraphImpl->GetMonitor());
  908. if (mAudioInput) {
  909. mAudioInput->DeviceChanged();
  910. }
  911. }
  912. void
  913. AudioCallbackDriver::SetMicrophoneActive(bool aActive)
  914. {
  915. MonitorAutoLock mon(mGraphImpl->GetMonitor());
  916. mMicrophoneActive = aActive;
  917. }
  918. uint32_t
  919. AudioCallbackDriver::IterationDuration()
  920. {
  921. // The real fix would be to have an API in cubeb to give us the number. Short
  922. // of that, we approximate it here. bug 1019507
  923. return mIterationDurationMS;
  924. }
  925. bool
  926. AudioCallbackDriver::IsStarted() {
  927. mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
  928. return mStarted;
  929. }
  930. void
  931. AudioCallbackDriver::EnqueueStreamAndPromiseForOperation(MediaStream* aStream,
  932. void* aPromise,
  933. dom::AudioContextOperation aOperation)
  934. {
  935. MonitorAutoLock mon(mGraphImpl->GetMonitor());
  936. mPromisesForOperation.AppendElement(StreamAndPromiseForOperation(aStream,
  937. aPromise,
  938. aOperation));
  939. }
  940. void AudioCallbackDriver::CompleteAudioContextOperations(AsyncCubebOperation aOperation)
  941. {
  942. AutoTArray<StreamAndPromiseForOperation, 1> array;
  943. // We can't lock for the whole function because AudioContextOperationCompleted
  944. // will grab the monitor
  945. {
  946. MonitorAutoLock mon(GraphImpl()->GetMonitor());
  947. array.SwapElements(mPromisesForOperation);
  948. }
  949. for (uint32_t i = 0; i < array.Length(); i++) {
  950. StreamAndPromiseForOperation& s = array[i];
  951. if ((aOperation == AsyncCubebOperation::INIT &&
  952. s.mOperation == dom::AudioContextOperation::Resume) ||
  953. (aOperation == AsyncCubebOperation::SHUTDOWN &&
  954. s.mOperation != dom::AudioContextOperation::Resume)) {
  955. GraphImpl()->AudioContextOperationCompleted(s.mStream,
  956. s.mPromise,
  957. s.mOperation);
  958. array.RemoveElementAt(i);
  959. i--;
  960. }
  961. }
  962. if (!array.IsEmpty()) {
  963. MonitorAutoLock mon(GraphImpl()->GetMonitor());
  964. mPromisesForOperation.AppendElements(array);
  965. }
  966. }
  967. } // namespace mozilla