output_device_mixer_impl.cc 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "services/audio/output_device_mixer_impl.h"
  5. #include "base/check.h"
  6. #include "base/containers/contains.h"
  7. #include "base/dcheck_is_on.h"
  8. #include "base/logging.h"
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/metrics/histogram_functions.h"
  11. #include "base/strings/strcat.h"
  12. #include "base/time/time.h"
  13. #include "base/trace_event/trace_event.h"
  14. #include "media/audio/audio_device_description.h"
  15. #include "media/audio/audio_io.h"
  16. namespace audio {
  17. constexpr base::TimeDelta OutputDeviceMixerImpl::kSwitchToUnmixedPlaybackDelay;
  18. constexpr double OutputDeviceMixerImpl::kDefaultVolume;
  19. namespace {
  20. const char* LatencyToUmaSuffix(media::AudioLatency::LatencyType latency) {
  21. switch (latency) {
  22. case media::AudioLatency::LATENCY_EXACT_MS:
  23. return "LatencyExactMs";
  24. case media::AudioLatency::LATENCY_INTERACTIVE:
  25. return "LatencyInteractive";
  26. case media::AudioLatency::LATENCY_RTC:
  27. return "LatencyRtc";
  28. case media::AudioLatency::LATENCY_PLAYBACK:
  29. return "LatencyPlayback";
  30. default:
  31. return "LatencyUnknown";
  32. }
  33. }
  34. const char* DeviceIdToUmaSuffix(const std::string& device_id) {
  35. if (device_id == "")
  36. return ".Default";
  37. return ".NonDefault";
  38. }
  39. // Do not change: used for UMA reporting, matches
  40. // AudioOutputDeviceMixerStreamStatus from enums.xml.
  41. enum class TrackError {
  42. kNone = 0,
  43. kIndependentOpenFailed,
  44. kIndependentPlaybackFailed,
  45. kMixedOpenFailed,
  46. kMixedPlaybackFailed,
  47. kMaxValue = kMixedPlaybackFailed
  48. };
  49. const char* TrackErrorToString(TrackError error) {
  50. switch (error) {
  51. case TrackError::kIndependentOpenFailed:
  52. return "Failed to open independent rendering stream";
  53. case TrackError::kIndependentPlaybackFailed:
  54. return "Error during independent playback";
  55. case TrackError::kMixedOpenFailed:
  56. return "Failed to open mixing rendering stream";
  57. case TrackError::kMixedPlaybackFailed:
  58. return "Error during mixed playback";
  59. default:
  60. NOTREACHED();
  61. return "No error";
  62. }
  63. }
  64. } // namespace
  65. // Audio data flow though the mixer:
  66. //
  67. // * Independent (ummixed) audio stream playback:
  68. // MixTrack::|audio_source_callback_|
  69. // -> MixTrack::|rendering_stream_|.
  70. //
  71. // * Mixed playback:
  72. // MixTrack::|audio_source_callback_|
  73. // -> MixTrack::|graph_input_|
  74. // --> OutputDeviceMixerImpl::|mixing_graph_|
  75. // ---> OutputDeviceMixerImpl::|mixing_graph_rendering_stream_|
  76. // Helper class which stores all the data associated with a specific audio
  77. // output managed by the mixer. To the clients such an audio output is
  78. // represented as MixableOutputStream (below).
  79. class OutputDeviceMixerImpl::MixTrack final
  80. : public media::AudioOutputStream::AudioSourceCallback {
  81. public:
  82. MixTrack(OutputDeviceMixerImpl* mixer,
  83. std::unique_ptr<MixingGraph::Input> graph_input,
  84. base::OnceClosure on_device_change_callback)
  85. : mixer_(mixer),
  86. on_device_change_callback_(std::move(on_device_change_callback)),
  87. graph_input_(std::move(graph_input)) {}
  88. ~MixTrack() final {
  89. DCHECK(!audio_source_callback_);
  90. base::UmaHistogramEnumeration(
  91. "Media.Audio.OutputDeviceMixer.StreamPlaybackStatus", error_);
  92. }
  93. void SetSource(
  94. media::AudioOutputStream::AudioSourceCallback* audio_source_callback) {
  95. DCHECK(!audio_source_callback_ || !audio_source_callback);
  96. audio_source_callback_ = audio_source_callback;
  97. }
  98. void SetVolume(double volume) {
  99. volume_ = volume;
  100. graph_input_->SetVolume(volume);
  101. if (rendering_stream_)
  102. rendering_stream_->SetVolume(volume);
  103. }
  104. double GetVolume() const { return volume_; }
  105. void StartProvidingAudioToMixingGraph() {
  106. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("audio"),
  107. "MixTrack::StartProvidingAudioToMixingGraph", "this",
  108. static_cast<void*>(this));
  109. DCHECK(audio_source_callback_);
  110. RegisterPlaybackStarted();
  111. graph_input_->Start(audio_source_callback_);
  112. }
  113. void StopProvidingAudioToMixingGraph() {
  114. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("audio"),
  115. "MixTrack::StopProvidingAudioToMixingGraph", "this",
  116. static_cast<void*>(this));
  117. DCHECK(audio_source_callback_);
  118. graph_input_->Stop();
  119. RegisterPlaybackStopped(PlaybackType::kMixed);
  120. }
  121. bool OpenIndependentRenderingStream() {
  122. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("audio"),
  123. "MixTrack::OpenIndependentRenderingStream", "this",
  124. static_cast<void*>(this));
  125. DCHECK(!rendering_stream_);
  126. rendering_stream_.reset(
  127. mixer_->CreateAndOpenDeviceStream(graph_input_->GetParams()));
  128. if (rendering_stream_) {
  129. rendering_stream_->SetVolume(volume_);
  130. } else {
  131. LOG(ERROR) << "Failed to open individual rendering stream";
  132. }
  133. return !!rendering_stream_;
  134. }
  135. void StartIndependentRenderingStream() {
  136. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("audio"),
  137. "MixTrack::StartIndependentRenderingStream", "this",
  138. static_cast<void*>(this));
  139. DCHECK(audio_source_callback_);
  140. if (!rendering_stream_) {
  141. // Open the rendering stream if it's not open yet. It will be closed in
  142. // CloseIndependentRenderingStream() or during destruction.
  143. if (!OpenIndependentRenderingStream()) {
  144. ReportError(TrackError::kIndependentOpenFailed);
  145. return;
  146. }
  147. }
  148. RegisterPlaybackStarted();
  149. rendering_stream_->Start(this);
  150. }
  151. void StopIndependentRenderingStream() {
  152. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("audio"),
  153. "MixTrack::StopIndependentRenderingStream", "this",
  154. static_cast<void*>(this));
  155. DCHECK(audio_source_callback_);
  156. if (rendering_stream_) {
  157. rendering_stream_->Stop();
  158. RegisterPlaybackStopped(PlaybackType::kIndependent);
  159. }
  160. }
  161. void CloseIndependentRenderingStream() {
  162. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("audio"),
  163. "MixTrack::CloseIndependentRenderingStream", "this",
  164. static_cast<void*>(this));
  165. DCHECK(!audio_source_callback_);
  166. // Closes the stream.
  167. rendering_stream_.reset();
  168. }
  169. void ReportError(TrackError error) {
  170. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("audio"), "MixTrack::ReportError",
  171. "this", static_cast<void*>(this));
  172. DCHECK(audio_source_callback_);
  173. DCHECK_NE(error, TrackError::kNone);
  174. LOG(ERROR) << "MixableOutputStream: " << TrackErrorToString(error);
  175. error_ = error;
  176. audio_source_callback_->OnError(ErrorType::kUnknown);
  177. }
  178. void OnDeviceChange() {
  179. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("audio"), "MixTrack::OnDeviceChange",
  180. "this", static_cast<void*>(this));
  181. DCHECK(!on_device_change_callback_.is_null());
  182. std::move(on_device_change_callback_).Run();
  183. }
  184. private:
  185. enum class PlaybackType { kMixed, kIndependent };
  186. void RegisterPlaybackStarted() {
  187. DCHECK(playback_activation_time_for_uma_.is_null());
  188. playback_activation_time_for_uma_ = base::TimeTicks::Now();
  189. }
  190. void RegisterPlaybackStopped(PlaybackType playback_type) {
  191. if (playback_type == PlaybackType::kIndependent &&
  192. playback_activation_time_for_uma_.is_null()) {
  193. return; // Stop() for an independent stream can be called multiple times.
  194. }
  195. DCHECK(!playback_activation_time_for_uma_.is_null());
  196. base::UmaHistogramLongTimes(
  197. base::StrCat(
  198. {"Media.Audio.OutputDeviceMixer.StreamDuration.",
  199. ((playback_type == PlaybackType::kMixed) ? "Mixed." : "Unmixed."),
  200. LatencyToUmaSuffix(graph_input_->GetParams().latency_tag())}),
  201. base::TimeTicks::Now() - playback_activation_time_for_uma_);
  202. playback_activation_time_for_uma_ = base::TimeTicks();
  203. }
  204. // media::AudioOutputStream::AudioSourceCallback implementation to intercept
  205. // error reporting during independent playback.
  206. int OnMoreData(base::TimeDelta delay,
  207. base::TimeTicks delay_timestamp,
  208. int prior_frames_skipped,
  209. media::AudioBus* dest) final {
  210. DCHECK(audio_source_callback_);
  211. return audio_source_callback_->OnMoreData(delay, delay_timestamp,
  212. prior_frames_skipped, dest);
  213. }
  214. void OnError(ErrorType type) final {
  215. // Device change events are intercepted by the underlying physical streams.
  216. DCHECK_EQ(type, ErrorType::kUnknown);
  217. ReportError(TrackError::kIndependentPlaybackFailed);
  218. }
  219. double volume_ = kDefaultVolume;
  220. const raw_ptr<OutputDeviceMixerImpl> mixer_;
  221. // Callback to notify the audio output client of the device change. Note that
  222. // all the device change events are initially routed to MixerManager which
  223. // does the centralized processing and notifies each mixer via
  224. // OutputDeviceMixer::ProcessDeviceChange(). There OutputDeviceMixerImpl does
  225. // the cleanup and then dispatches the device change event to all its clients
  226. // via |on_device_change_callback_| of its MixTracks.
  227. base::OnceClosure on_device_change_callback_;
  228. // Callback to request the audio output data from the client.
  229. raw_ptr<media::AudioOutputStream::AudioSourceCallback>
  230. audio_source_callback_ = nullptr;
  231. // Delivers the audio output into MixingGraph, to be mixed for the reference
  232. // signal playback.
  233. const std::unique_ptr<MixingGraph::Input> graph_input_;
  234. // When non-nullptr, points to an open physical output stream used to render
  235. // the audio output independently when mixing is not required.
  236. std::unique_ptr<media::AudioOutputStream, StreamAutoClose> rendering_stream_ =
  237. nullptr;
  238. base::TimeTicks playback_activation_time_for_uma_;
  239. TrackError error_ = TrackError::kNone;
  240. };
  241. // A proxy which represents MixTrack as media::AudioOutputStream.
  242. class OutputDeviceMixerImpl::MixableOutputStream final
  243. : public media::AudioOutputStream {
  244. public:
  245. MixableOutputStream(base::WeakPtr<OutputDeviceMixerImpl> mixer,
  246. MixTrack* mix_track)
  247. : mixer_(std::move(mixer)), mix_track_(mix_track) {}
  248. MixableOutputStream(const MixableOutputStream&) = delete;
  249. MixableOutputStream& operator=(const MixableOutputStream&) = delete;
  250. ~MixableOutputStream() final {
  251. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  252. }
  253. // AudioOutputStream interface.
  254. bool Open() final {
  255. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  256. if (!mixer_) {
  257. LOG(ERROR) << "Stream start failed: device changed";
  258. return false;
  259. }
  260. return mixer_->OpenStream(mix_track_);
  261. }
  262. void Start(AudioSourceCallback* callback) final {
  263. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  264. DCHECK(callback);
  265. TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
  266. TRACE_DISABLED_BY_DEFAULT("audio"), "MixableOutputStream::IsPlaying",
  267. this, "device_id", mixer_ ? mixer_->device_id() : "device changed");
  268. if (!mixer_) {
  269. LOG(ERROR) << "Stream start failed: device changed";
  270. callback->OnError(ErrorType::kDeviceChange);
  271. return;
  272. }
  273. mixer_->StartStream(mix_track_, callback);
  274. }
  275. void Stop() final {
  276. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  277. TRACE_EVENT_NESTABLE_ASYNC_END0(TRACE_DISABLED_BY_DEFAULT("audio"),
  278. "MixableOutputStream::IsPlaying", this);
  279. if (!mixer_)
  280. return;
  281. mixer_->StopStream(mix_track_);
  282. }
  283. void SetVolume(double volume) final {
  284. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  285. if (!mixer_)
  286. return;
  287. mix_track_->SetVolume(volume);
  288. }
  289. void GetVolume(double* volume) final {
  290. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  291. DCHECK(volume);
  292. if (!mixer_)
  293. return;
  294. *volume = mix_track_->GetVolume();
  295. }
  296. void Close() final {
  297. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  298. if (mixer_) {
  299. // `CloseStream` destroys `mix_track_`. Use `ExtractAsDangling` to clear
  300. // the underlying pointer and return another raw_ptr instance that is
  301. // allowed to dangle.
  302. mixer_->CloseStream(mix_track_.ExtractAsDangling());
  303. }
  304. // To match the typical usage pattern of AudioOutputStream.
  305. delete this;
  306. }
  307. void Flush() final {}
  308. private:
  309. SEQUENCE_CHECKER(owning_sequence_);
  310. // OutputDeviceMixerImpl will release all the resources and invalidate its
  311. // weak pointers in OutputDeviceMixer::ProcessDeviceChange(). After that
  312. // MixableOutputStream becomes a no-op.
  313. base::WeakPtr<OutputDeviceMixerImpl> const mixer_
  314. GUARDED_BY_CONTEXT(owning_sequence_);
  315. raw_ptr<MixTrack> mix_track_; // Valid only when |mixer_| is valid.
  316. };
  317. // Logs mixing statistics upon the destruction. Should be created when mixing
  318. // playback starts, and destroyed when it ends.
  319. class OutputDeviceMixerImpl::MixingStats {
  320. public:
  321. MixingStats(const std::string& device_id,
  322. int active_track_count,
  323. int listener_count)
  324. : suffix_(DeviceIdToUmaSuffix(device_id)),
  325. active_track_count_(active_track_count),
  326. listener_count_(listener_count),
  327. start_(base::TimeTicks::Now()) {
  328. DCHECK_GT(active_track_count, 0);
  329. DCHECK_GT(listener_count, 0);
  330. }
  331. ~MixingStats() {
  332. if (!noop_mixing_start_.is_null()) {
  333. LogNoopMixingDuration();
  334. }
  335. DCHECK(!start_.is_null());
  336. base::TimeDelta duration = base::TimeTicks::Now() - start_;
  337. LogPerDeviceUma(duration, suffix_);
  338. LogPerDeviceUma(duration, ""); // Combined.
  339. }
  340. void AddListener() { listener_count_.Increment(); }
  341. void RemoveListener() { listener_count_.Decrement(); }
  342. void AddActiveTrack() {
  343. active_track_count_.Increment();
  344. if (!noop_mixing_start_.is_null()) {
  345. // First track after a period of feeding silence to the listeners.
  346. DCHECK_EQ(active_track_count_.GetCurrent(), 1);
  347. DCHECK(listener_count_.GetCurrent());
  348. LogNoopMixingDuration();
  349. }
  350. }
  351. void RemoveActiveTrack() {
  352. active_track_count_.Decrement();
  353. if (listener_count_.GetCurrent() && !active_track_count_.GetCurrent()) {
  354. // No more tracks, so we start feeding silence to listeners.
  355. DCHECK(noop_mixing_start_.is_null());
  356. noop_mixing_start_ = base::TimeTicks::Now();
  357. }
  358. }
  359. private:
  360. // A helper to track the max value.
  361. class MaxTracker {
  362. public:
  363. explicit MaxTracker(int value) : value_(value), max_value_(value) {}
  364. int GetCurrent() { return value_; }
  365. int GetMax() { return max_value_; }
  366. void Increment() {
  367. if (++value_ > max_value_)
  368. max_value_ = value_;
  369. }
  370. void Decrement() {
  371. DCHECK(value_ > 0);
  372. value_--;
  373. }
  374. private:
  375. int value_;
  376. int max_value_;
  377. };
  378. void LogNoopMixingDuration() {
  379. DCHECK(!noop_mixing_start_.is_null());
  380. base::UmaHistogramLongTimes(
  381. "Media.Audio.OutputDeviceMixer.NoopMixingDuration",
  382. base::TimeTicks::Now() - noop_mixing_start_);
  383. noop_mixing_start_ = base::TimeTicks();
  384. }
  385. void LogPerDeviceUma(base::TimeDelta duration, const char* suffix) {
  386. constexpr int kMaxActiveStreamCount = 50;
  387. constexpr int kMaxListeners = 20;
  388. base::UmaHistogramLongTimes(
  389. base::StrCat({"Media.Audio.OutputDeviceMixer.MixingDuration", suffix}),
  390. duration);
  391. base::UmaHistogramExactLinear(
  392. base::StrCat(
  393. {"Media.Audio.OutputDeviceMixer.MaxMixedStreamCount", suffix}),
  394. active_track_count_.GetMax(), kMaxActiveStreamCount);
  395. base::UmaHistogramExactLinear(
  396. base::StrCat(
  397. {"Media.Audio.OutputDeviceMixer.MaxListenerCount", suffix}),
  398. listener_count_.GetMax(), kMaxListeners);
  399. }
  400. const char* const suffix_;
  401. MaxTracker active_track_count_;
  402. MaxTracker listener_count_;
  403. const base::TimeTicks start_;
  404. // Start of the period when there are no active tracks and we play and feed
  405. // silence to the listeners.
  406. base::TimeTicks noop_mixing_start_;
  407. };
  408. OutputDeviceMixerImpl::OutputDeviceMixerImpl(
  409. const std::string& device_id,
  410. const media::AudioParameters& output_params,
  411. MixingGraph::CreateCallback create_mixing_graph_callback,
  412. CreateStreamCallback create_stream_callback)
  413. : OutputDeviceMixer(device_id),
  414. create_stream_callback_(std::move(create_stream_callback)),
  415. mixing_graph_output_params_(output_params),
  416. mixing_graph_(std::move(create_mixing_graph_callback)
  417. .Run(output_params,
  418. base::BindRepeating(
  419. &OutputDeviceMixerImpl::BroadcastToListeners,
  420. base::Unretained(this)),
  421. base::BindRepeating(
  422. &OutputDeviceMixerImpl::OnMixingGraphError,
  423. base::Unretained(this)))) {
  424. DCHECK(mixing_graph_output_params_.IsValid());
  425. DCHECK_EQ(mixing_graph_output_params_.format(),
  426. media::AudioParameters::AUDIO_PCM_LOW_LATENCY);
  427. TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACE_DISABLED_BY_DEFAULT("audio"),
  428. "OutputDeviceMixerImpl", this, "device_id",
  429. device_id);
  430. }
  431. OutputDeviceMixerImpl::~OutputDeviceMixerImpl() {
  432. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  433. DCHECK(active_tracks_.empty());
  434. DCHECK(!HasListeners());
  435. DCHECK(!MixingInProgress());
  436. DCHECK(!mixing_graph_output_stream_);
  437. TRACE_EVENT_NESTABLE_ASYNC_END0(TRACE_DISABLED_BY_DEFAULT("audio"),
  438. "OutputDeviceMixerImpl", this);
  439. }
  440. media::AudioOutputStream* OutputDeviceMixerImpl::MakeMixableStream(
  441. const media::AudioParameters& params,
  442. base::OnceClosure on_device_change_callback) {
  443. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  444. NON_REENTRANT_SCOPE(reentrancy_checker_);
  445. if (!(params.IsValid() &&
  446. params.format() == media::AudioParameters::AUDIO_PCM_LOW_LATENCY)) {
  447. LOG(ERROR) << "Invalid output stream patameters for device [" << device_id()
  448. << "], parameters: " << params.AsHumanReadableString();
  449. return nullptr;
  450. }
  451. auto mix_track =
  452. std::make_unique<MixTrack>(this, mixing_graph_->CreateInput(params),
  453. std::move(on_device_change_callback));
  454. media::AudioOutputStream* mixable_stream =
  455. new MixableOutputStream(weak_factory_.GetWeakPtr(), mix_track.get());
  456. mix_tracks_.insert(std::move(mix_track));
  457. return mixable_stream;
  458. }
  459. void OutputDeviceMixerImpl::ProcessDeviceChange() {
  460. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  461. NON_REENTRANT_SCOPE(reentrancy_checker_);
  462. #if DCHECK_IS_ON()
  463. DCHECK(!device_changed_);
  464. device_changed_ = true;
  465. #endif
  466. // Make all MixableOutputStream instances no-op.
  467. weak_factory_.InvalidateWeakPtrs();
  468. // Stop and close all audio playback.
  469. if (MixingInProgress()) {
  470. StopMixingGraphPlayback(MixingError::kNone);
  471. } else {
  472. for (MixTrack* mix_track : active_tracks_) {
  473. mix_track->StopIndependentRenderingStream();
  474. }
  475. // In case it was opened when listeners came:
  476. mixing_graph_output_stream_.reset();
  477. }
  478. // For consistency.
  479. for (MixTrack* mix_track : active_tracks_)
  480. mix_track->SetSource(nullptr);
  481. active_tracks_.clear();
  482. // Close independent rendering streams: the clients will want to restore
  483. // active playback in mix_track->OnDeviceChange() calls below; we don't want
  484. // to exceed the limit of simultaneously open output streams when they do so.
  485. for (auto&& mix_track : mix_tracks_)
  486. mix_track->CloseIndependentRenderingStream();
  487. {
  488. base::AutoLock scoped_lock(listener_lock_);
  489. listeners_.clear();
  490. }
  491. // Notify MixableOutputStream users of the device change. Normally they should
  492. // close the current stream they are holding to, create/open a new one and
  493. // resume the playback. We already released all the resources; closing a
  494. // MixableOutputStream will be a no-op since weak pointers to |this| have just
  495. // been invalidated.
  496. for (auto&& mix_track : mix_tracks_)
  497. mix_track->OnDeviceChange();
  498. }
  499. void OutputDeviceMixerImpl::StartListening(Listener* listener) {
  500. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  501. NON_REENTRANT_SCOPE(reentrancy_checker_);
  502. #if DCHECK_IS_ON()
  503. DCHECK(!device_changed_);
  504. #endif
  505. DVLOG(1) << "Reference output listener added for device [" << device_id()
  506. << "]";
  507. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("audio"),
  508. "OutputDeviceMixerImpl::StartListening", "device_id",
  509. device_id());
  510. // A new listener came: cancel scheduled switch to independent playback.
  511. switch_to_unmixed_playback_delay_timer_.Stop();
  512. {
  513. base::AutoLock scoped_lock(listener_lock_);
  514. DCHECK(listeners_.find(listener) == listeners_.end());
  515. listeners_.insert(listener);
  516. if (MixingInProgress()) {
  517. DCHECK(mixing_graph_output_stream_); // We are mixing.
  518. mixing_session_stats_->AddListener();
  519. return;
  520. }
  521. }
  522. // Since we now have listeners, warm-up |mixing_graph_output_stream_|.
  523. EnsureMixingGraphOutputStreamOpen();
  524. // Start reference playback only if at least one audio stream is playing.
  525. if (active_tracks_.empty())
  526. return;
  527. for (MixTrack* mix_track : active_tracks_)
  528. mix_track->StopIndependentRenderingStream();
  529. StartMixingGraphPlayback();
  530. // Note that if StartMixingGraphPlayback() failed, no audio will be playing
  531. // and each client of a playing MixableOutputStream will receive OnError()
  532. // callback call.
  533. }
  534. void OutputDeviceMixerImpl::StopListening(Listener* listener) {
  535. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  536. #if DCHECK_IS_ON()
  537. DCHECK(!device_changed_);
  538. #endif
  539. DVLOG(1) << "Reference output listener removed for device [" << device_id()
  540. << "]";
  541. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("audio"),
  542. "OutputDeviceMixerImpl::StopListening", "device_id",
  543. device_id());
  544. {
  545. base::AutoLock scoped_lock(listener_lock_);
  546. auto iter = listeners_.find(listener);
  547. DCHECK(iter != listeners_.end());
  548. listeners_.erase(iter);
  549. }
  550. if (HasListeners()) {
  551. // We still have some listeners left, so no need to do anything.
  552. return;
  553. }
  554. if (!MixingInProgress()) {
  555. // There is no mixing in progress and no more listeners left: closing
  556. // the warmed up stream.
  557. mixing_graph_output_stream_.reset();
  558. return;
  559. }
  560. mixing_session_stats_->RemoveListener();
  561. DCHECK(mixing_graph_output_stream_); // We are mixing.
  562. if (active_tracks_.empty()) {
  563. // There is no actual playback: we were just sending silence to the
  564. // listener as a reference.
  565. StopMixingGraphPlayback(MixingError::kNone);
  566. } else {
  567. // No listeners left, and we are playing via the mixing graph. Schedule
  568. // switching to independent playback.
  569. switch_to_unmixed_playback_delay_timer_.Start(
  570. FROM_HERE, kSwitchToUnmixedPlaybackDelay, this,
  571. &OutputDeviceMixerImpl::SwitchToUnmixedPlaybackTimerHelper);
  572. }
  573. }
  574. bool OutputDeviceMixerImpl::OpenStream(MixTrack* mix_track) {
  575. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  576. #if DCHECK_IS_ON()
  577. DCHECK(!device_changed_);
  578. #endif
  579. DCHECK(mix_track);
  580. // Defer opening the physical output stream, as the audio mix is requested.
  581. // The physical stream will be open on start if needed.
  582. if (HasListeners())
  583. return true;
  584. return mix_track->OpenIndependentRenderingStream();
  585. }
  586. void OutputDeviceMixerImpl::StartStream(
  587. MixTrack* mix_track,
  588. media::AudioOutputStream::AudioSourceCallback* callback) {
  589. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  590. NON_REENTRANT_SCOPE(reentrancy_checker_);
  591. #if DCHECK_IS_ON()
  592. DCHECK(!device_changed_);
  593. #endif
  594. DCHECK(mix_track);
  595. DCHECK(callback);
  596. DCHECK(!base::Contains(active_tracks_, mix_track));
  597. TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("audio"),
  598. "OutputDeviceMixerImpl::StartStream", "device_id", device_id(),
  599. "mix_track", static_cast<void*>(mix_track));
  600. mix_track->SetSource(callback);
  601. active_tracks_.emplace(mix_track);
  602. if (MixingInProgress()) {
  603. // We are playing all audio as a |mixing_graph_| output.
  604. mix_track->StartProvidingAudioToMixingGraph();
  605. mixing_session_stats_->AddActiveTrack();
  606. } else if (HasListeners()) {
  607. // Either we are starting the first active stream, or the previous switch to
  608. // playing via the mixing graph failed because the its output stream failed
  609. // to open. In any case, none of the active streams are playing individually
  610. // at this point.
  611. EnsureMixingGraphOutputStreamOpen();
  612. StartMixingGraphPlayback();
  613. } else {
  614. // No reference signal is requested.
  615. mix_track->StartIndependentRenderingStream();
  616. }
  617. }
  618. void OutputDeviceMixerImpl::StopStream(MixTrack* mix_track) {
  619. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  620. NON_REENTRANT_SCOPE(reentrancy_checker_);
  621. #if DCHECK_IS_ON()
  622. DCHECK(!device_changed_);
  623. #endif
  624. DCHECK(mix_track);
  625. if (!base::Contains(active_tracks_, mix_track)) {
  626. // MixableOutputStream::Stop() can be called multiple times, even if the
  627. // stream has not been started. See media::AudioOutputStream documentation.
  628. return;
  629. }
  630. TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("audio"),
  631. "OutputDeviceMixerImpl::StopStream", "device_id", device_id(),
  632. "mix_track", static_cast<void*>(mix_track));
  633. active_tracks_.erase(mix_track);
  634. if (MixingInProgress()) {
  635. // We are playing all audio as a |mixing_graph_| output.
  636. mix_track->StopProvidingAudioToMixingGraph();
  637. mixing_session_stats_->RemoveActiveTrack();
  638. if (!HasListeners() && active_tracks_.empty()) {
  639. // All listeners are gone, which means a switch to an independent playback
  640. // is scheduled. But since we have no active tracks, we can stop mixing
  641. // immediately.
  642. DCHECK(switch_to_unmixed_playback_delay_timer_.IsRunning());
  643. StopMixingGraphPlayback(MixingError::kNone);
  644. }
  645. // Note: if there are listeners, we do not stop the reference playback even
  646. // if there are no active mix members. This way the echo canceller will be
  647. // in a consistent state when the playback is activated again. Drawback: we
  648. // keep playing silent audio. An example would be some occasional
  649. // notification sounds and no other audio output: we start the mixing
  650. // playback at the first notification, and stop it only when the echo
  651. // cancellation session is finished (i.e. all the listeners are gone).
  652. } else {
  653. mix_track->StopIndependentRenderingStream();
  654. }
  655. mix_track->SetSource(nullptr);
  656. }
  657. void OutputDeviceMixerImpl::CloseStream(MixTrack* mix_track) {
  658. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  659. NON_REENTRANT_SCOPE(reentrancy_checker_);
  660. #if DCHECK_IS_ON()
  661. DCHECK(!device_changed_);
  662. #endif
  663. DCHECK(mix_track);
  664. DCHECK(!base::Contains(active_tracks_, mix_track));
  665. auto iter = mix_tracks_.find(mix_track);
  666. DCHECK(iter != mix_tracks_.end());
  667. mix_tracks_.erase(iter);
  668. }
  669. media::AudioOutputStream* OutputDeviceMixerImpl::CreateAndOpenDeviceStream(
  670. const media::AudioParameters& params) {
  671. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  672. DCHECK(params.IsValid());
  673. DCHECK_EQ(params.format(), media::AudioParameters::AUDIO_PCM_LOW_LATENCY);
  674. media::AudioOutputStream* stream =
  675. create_stream_callback_.Run(device_id(), params);
  676. if (!stream)
  677. return nullptr;
  678. if (!stream->Open()) {
  679. LOG(ERROR) << "Failed to open stream";
  680. stream->Close();
  681. return nullptr;
  682. }
  683. return stream;
  684. }
  685. void OutputDeviceMixerImpl::BroadcastToListeners(
  686. const media::AudioBus& audio_bus,
  687. base::TimeDelta delay) {
  688. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("audio"),
  689. "OutputDeviceMixerImpl::BroadcastToListeners", "delay ms",
  690. delay.InMilliseconds());
  691. base::AutoLock scoped_lock(listener_lock_);
  692. for (Listener* listener : listeners_) {
  693. listener->OnPlayoutData(audio_bus,
  694. mixing_graph_output_params_.sample_rate(), delay);
  695. }
  696. }
  697. // Processes errors coming from |mixing_graph_| during mixed playback.
  698. void OutputDeviceMixerImpl::OnMixingGraphError(ErrorType error) {
  699. // |mixing_graph_output_stream_| guarantees this.
  700. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  701. // Device change events are intercepted by the underlying physical stream.
  702. DCHECK_EQ(error, ErrorType::kUnknown);
  703. // This call is expected only during mixed playback.
  704. DCHECK(mixing_graph_output_stream_);
  705. StopMixingGraphPlayback(MixingError::kPlaybackFailed);
  706. }
  707. bool OutputDeviceMixerImpl::HasListeners() const {
  708. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  709. return TS_UNCHECKED_READ(listeners_).size();
  710. }
  711. void OutputDeviceMixerImpl::EnsureMixingGraphOutputStreamOpen() {
  712. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  713. DCHECK(HasListeners());
  714. if (mixing_graph_output_stream_)
  715. return;
  716. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("audio"),
  717. "OutputDeviceMixerImpl::EnsureMixingGraphOutputStreamOpen",
  718. "device_id", device_id());
  719. mixing_graph_output_stream_.reset(
  720. CreateAndOpenDeviceStream(mixing_graph_output_params_));
  721. }
  722. // Expects |mixing_graph_output_stream_| to be already open; if not - this is
  723. // interpreted as a failure.
  724. void OutputDeviceMixerImpl::StartMixingGraphPlayback() {
  725. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  726. TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACE_DISABLED_BY_DEFAULT("audio"),
  727. "OutputDeviceMixerImpl mixing", this,
  728. "device_id", device_id());
  729. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("audio"),
  730. "OutputDeviceMixerImpl::StartMixingGraphPlayback", "device_id",
  731. device_id());
  732. if (!mixing_graph_output_stream_) {
  733. StopMixingGraphPlayback(MixingError::kOpenFailed);
  734. return;
  735. }
  736. DCHECK(!mixing_session_stats_);
  737. mixing_session_stats_ = std::make_unique<MixingStats>(
  738. device_id(), active_tracks_.size(), TS_UNCHECKED_READ(listeners_).size());
  739. for (MixTrack* mix_track : active_tracks_)
  740. mix_track->StartProvidingAudioToMixingGraph();
  741. mixing_graph_output_stream_->Start(mixing_graph_.get());
  742. DVLOG(1) << " Mixing started for device [" << device_id() << "]";
  743. }
  744. void OutputDeviceMixerImpl::StopMixingGraphPlayback(MixingError error) {
  745. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  746. if (MixingInProgress()) {
  747. // Mixing was in progress, we should stop it.
  748. DCHECK(mixing_graph_output_stream_);
  749. DCHECK_NE(error, MixingError::kOpenFailed);
  750. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("audio"),
  751. "OutputDeviceMixerImpl::StopMixingGraphPlayback", "device_id",
  752. device_id());
  753. switch_to_unmixed_playback_delay_timer_.Stop();
  754. mixing_graph_output_stream_->Stop();
  755. mixing_graph_output_stream_.reset(); // Auto-close the stream.
  756. mixing_session_stats_.reset();
  757. DVLOG(1) << " Mixing stopped for device [" << device_id() << "]";
  758. for (MixTrack* mix_track : active_tracks_)
  759. mix_track->StopProvidingAudioToMixingGraph();
  760. TRACE_EVENT_NESTABLE_ASYNC_END0(TRACE_DISABLED_BY_DEFAULT("audio"),
  761. "OutputDeviceMixerImpl mixing", this);
  762. }
  763. DCHECK(!mixing_graph_output_stream_);
  764. if (error != MixingError::kNone) {
  765. LOG(ERROR) << ErrorToString(error) << " for device [" << device_id() << "]";
  766. TrackError track_error = (error == MixingError::kOpenFailed)
  767. ? TrackError::kMixedOpenFailed
  768. : TrackError::kMixedPlaybackFailed;
  769. for (MixTrack* mix_track : active_tracks_)
  770. mix_track->ReportError(track_error);
  771. }
  772. base::UmaHistogramEnumeration(
  773. "Media.Audio.OutputDeviceMixer.MixedPlaybackStatus", error);
  774. }
  775. void OutputDeviceMixerImpl::SwitchToUnmixedPlaybackTimerHelper() {
  776. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  777. NON_REENTRANT_SCOPE(reentrancy_checker_);
  778. DCHECK(MixingInProgress());
  779. #if DCHECK_IS_ON()
  780. DCHECK(!device_changed_);
  781. #endif
  782. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("audio"),
  783. "OutputDeviceMixerImpl::SwitchToUnmixedPlaybackTimerHelper",
  784. "device_id", device_id());
  785. StopMixingGraphPlayback(MixingError::kNone);
  786. for (MixTrack* mix_track : active_tracks_)
  787. mix_track->StartIndependentRenderingStream();
  788. }
  789. // static
  790. const char* OutputDeviceMixerImpl::ErrorToString(MixingError error) {
  791. switch (error) {
  792. case MixingError::kOpenFailed:
  793. return "Failed to open mixing rendering stream";
  794. case MixingError::kPlaybackFailed:
  795. return "Error during mixed playback";
  796. default:
  797. NOTREACHED();
  798. return "No error";
  799. }
  800. }
  801. } // namespace audio