output_stream.cc 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. // Copyright 2018 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_stream.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/callback_helpers.h"
  8. #include "base/strings/string_piece.h"
  9. #include "base/strings/stringprintf.h"
  10. #include "base/threading/sequenced_task_runner_handle.h"
  11. #include "base/trace_event/trace_event.h"
  12. #include "third_party/abseil-cpp/absl/utility/utility.h"
  13. namespace audio {
  14. const float kSilenceThresholdDBFS = -72.24719896f;
  15. // Desired polling frequency. Note: If this is set too low, short-duration
  16. // "blip" sounds won't be detected. http://crbug.com/339133#c4
  17. const int kPowerMeasurementsPerSecond = 15;
  18. std::string GetCtorLogString(media::AudioManager* audio_manager,
  19. const std::string& device_id,
  20. const media::AudioParameters& params) {
  21. return base::StringPrintf(
  22. "Ctor({audio_manager_name=%s}, {device_id=%s}, {params=[%s]})",
  23. audio_manager->GetName(), device_id.c_str(),
  24. params.AsHumanReadableString().c_str());
  25. }
  26. OutputStream::OutputStream(
  27. CreatedCallback created_callback,
  28. DeleteCallback delete_callback,
  29. ManagedDeviceOutputStreamCreateCallback
  30. managed_device_output_stream_create_callback,
  31. mojo::PendingReceiver<media::mojom::AudioOutputStream> stream_receiver,
  32. mojo::PendingAssociatedRemote<media::mojom::AudioOutputStreamObserver>
  33. observer,
  34. mojo::PendingRemote<media::mojom::AudioLog> log,
  35. media::AudioManager* audio_manager,
  36. OutputStreamActivityMonitor* activity_monitor,
  37. const std::string& output_device_id,
  38. const media::AudioParameters& params,
  39. LoopbackCoordinator* coordinator,
  40. const base::UnguessableToken& loopback_group_id)
  41. : foreign_socket_(),
  42. delete_callback_(std::move(delete_callback)),
  43. receiver_(this, std::move(stream_receiver)),
  44. observer_(std::move(observer)),
  45. log_(std::move(log)),
  46. coordinator_(coordinator),
  47. // Unretained is safe since we own |reader_|
  48. reader_(log_ ? base::BindRepeating(&media::mojom::AudioLog::OnLogMessage,
  49. base::Unretained(log_.get()))
  50. : base::DoNothing(),
  51. params,
  52. &foreign_socket_),
  53. controller_(audio_manager,
  54. this,
  55. activity_monitor,
  56. params,
  57. output_device_id,
  58. &reader_,
  59. std::move(managed_device_output_stream_create_callback)),
  60. loopback_group_id_(loopback_group_id) {
  61. DCHECK(receiver_.is_bound());
  62. DCHECK(created_callback);
  63. DCHECK(delete_callback_);
  64. DCHECK(coordinator_);
  65. TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("audio", "audio::OutputStream", this);
  66. TRACE_EVENT_NESTABLE_ASYNC_BEGIN2("audio", "OutputStream", this, "device id",
  67. output_device_id, "params",
  68. params.AsHumanReadableString());
  69. SendLogMessage(
  70. "%s", GetCtorLogString(audio_manager, output_device_id, params).c_str());
  71. // |this| owns these objects, so unretained is safe.
  72. base::RepeatingClosure error_handler =
  73. base::BindRepeating(&OutputStream::OnError, base::Unretained(this));
  74. receiver_.set_disconnect_handler(error_handler);
  75. // We allow the observer to terminate the stream by closing the message pipe.
  76. if (observer_)
  77. observer_.set_disconnect_handler(std::move(error_handler));
  78. if (log_)
  79. log_->OnCreated(params, output_device_id);
  80. coordinator_->RegisterMember(loopback_group_id_, &controller_);
  81. if (!reader_.IsValid() || !controller_.CreateStream()) {
  82. // Either SyncReader initialization failed or the controller failed to
  83. // create the stream. In the latter case, the controller will have called
  84. // OnControllerError().
  85. std::move(created_callback).Run(nullptr);
  86. return;
  87. }
  88. CreateAudioPipe(std::move(created_callback));
  89. }
  90. OutputStream::~OutputStream() {
  91. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  92. if (log_)
  93. log_->OnClosed();
  94. if (observer_) {
  95. observer_.ResetWithReason(
  96. static_cast<uint32_t>(media::mojom::AudioOutputStreamObserver::
  97. DisconnectReason::kTerminatedByClient),
  98. std::string());
  99. }
  100. controller_.Close();
  101. coordinator_->UnregisterMember(loopback_group_id_, &controller_);
  102. if (is_audible_)
  103. TRACE_EVENT_NESTABLE_ASYNC_END0("audio", "Audible", this);
  104. if (playing_)
  105. TRACE_EVENT_NESTABLE_ASYNC_END0("audio", "Playing", this);
  106. TRACE_EVENT_NESTABLE_ASYNC_END0("audio", "OutputStream", this);
  107. TRACE_EVENT_NESTABLE_ASYNC_END0("audio", "audio::OutputStream", this);
  108. }
  109. void OutputStream::Play() {
  110. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  111. SendLogMessage("%s()", __func__);
  112. controller_.Play();
  113. if (log_)
  114. log_->OnStarted();
  115. }
  116. void OutputStream::Pause() {
  117. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  118. SendLogMessage("%s()", __func__);
  119. controller_.Pause();
  120. if (log_)
  121. log_->OnStopped();
  122. }
  123. void OutputStream::Flush() {
  124. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  125. SendLogMessage("%s()", __func__);
  126. controller_.Flush();
  127. }
  128. void OutputStream::SetVolume(double volume) {
  129. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  130. TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("audio", "SetVolume", this, "volume",
  131. volume);
  132. if (volume < 0 || volume > 1) {
  133. receiver_.ReportBadMessage("Invalid volume");
  134. OnControllerError();
  135. return;
  136. }
  137. controller_.SetVolume(volume);
  138. if (log_)
  139. log_->OnSetVolume(volume);
  140. }
  141. void OutputStream::CreateAudioPipe(CreatedCallback created_callback) {
  142. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  143. DCHECK(reader_.IsValid());
  144. TRACE_EVENT_NESTABLE_ASYNC_INSTANT0("audio", "CreateAudioPipe", this);
  145. SendLogMessage("%s()", __func__);
  146. base::UnsafeSharedMemoryRegion shared_memory_region =
  147. reader_.TakeSharedMemoryRegion();
  148. mojo::PlatformHandle socket_handle(foreign_socket_.Take());
  149. if (!shared_memory_region.IsValid() || !socket_handle.is_valid()) {
  150. std::move(created_callback).Run(nullptr);
  151. OnError();
  152. return;
  153. }
  154. std::move(created_callback)
  155. .Run({absl::in_place, std::move(shared_memory_region),
  156. std::move(socket_handle)});
  157. }
  158. void OutputStream::OnControllerPlaying() {
  159. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  160. if (playing_)
  161. return;
  162. TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("audio", "Playing", this);
  163. playing_ = true;
  164. if (observer_)
  165. observer_->DidStartPlaying();
  166. if (OutputController::will_monitor_audio_levels()) {
  167. DCHECK(!poll_timer_.IsRunning());
  168. // base::Unretained is safe because |this| owns |poll_timer_|.
  169. poll_timer_.Start(FROM_HERE, base::Seconds(1) / kPowerMeasurementsPerSecond,
  170. base::BindRepeating(&OutputStream::PollAudioLevel,
  171. base::Unretained(this)));
  172. return;
  173. }
  174. // In case we don't monitor audio levels, we assume a stream is audible when
  175. // it's playing.
  176. if (observer_)
  177. observer_->DidChangeAudibleState(true);
  178. }
  179. void OutputStream::OnControllerPaused() {
  180. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  181. if (!playing_)
  182. return;
  183. playing_ = false;
  184. if (OutputController::will_monitor_audio_levels()) {
  185. DCHECK(poll_timer_.IsRunning());
  186. poll_timer_.Stop();
  187. }
  188. if (observer_)
  189. observer_->DidStopPlaying();
  190. TRACE_EVENT_NESTABLE_ASYNC_END0("audio", "Playing", this);
  191. }
  192. void OutputStream::OnControllerError() {
  193. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  194. TRACE_EVENT_NESTABLE_ASYNC_INSTANT0("audio", "OnControllerError", this);
  195. SendLogMessage("%s()", __func__);
  196. // Stop checking the audio level to avoid using this object while it's being
  197. // torn down.
  198. poll_timer_.Stop();
  199. if (log_)
  200. log_->OnError();
  201. if (observer_) {
  202. observer_.ResetWithReason(
  203. static_cast<uint32_t>(media::mojom::AudioOutputStreamObserver::
  204. DisconnectReason::kPlatformError),
  205. std::string());
  206. }
  207. OnError();
  208. }
  209. void OutputStream::OnLog(base::StringPiece message) {
  210. // No sequence check: |log_| is thread-safe.
  211. if (log_) {
  212. log_->OnLogMessage(base::StringPrintf("%s", std::string(message).c_str()));
  213. }
  214. }
  215. void OutputStream::OnError() {
  216. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  217. TRACE_EVENT_NESTABLE_ASYNC_INSTANT0("audio", "OnError", this);
  218. // Defer callback so we're not destructed while in the constructor.
  219. base::SequencedTaskRunnerHandle::Get()->PostTask(
  220. FROM_HERE,
  221. base::BindOnce(&OutputStream::CallDeleter, weak_factory_.GetWeakPtr()));
  222. // Ignore any incoming calls.
  223. receiver_.reset();
  224. }
  225. void OutputStream::CallDeleter() {
  226. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  227. std::move(delete_callback_).Run(this);
  228. }
  229. // TODO(crbug.com/1017219): it might be useful to track these transitions with
  230. // logs as well but note that the method is called at a rather high rate.
  231. void OutputStream::PollAudioLevel() {
  232. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  233. bool was_audible = is_audible_;
  234. is_audible_ = IsAudible();
  235. if (is_audible_ && !was_audible) {
  236. TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("audio", "Audible", this);
  237. if (observer_)
  238. observer_->DidChangeAudibleState(is_audible_);
  239. } else if (!is_audible_ && was_audible) {
  240. TRACE_EVENT_NESTABLE_ASYNC_END0("audio", "Audible", this);
  241. if (observer_)
  242. observer_->DidChangeAudibleState(is_audible_);
  243. }
  244. }
  245. bool OutputStream::IsAudible() {
  246. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  247. float power_dbfs = controller_.ReadCurrentPowerAndClip().first;
  248. return power_dbfs >= kSilenceThresholdDBFS;
  249. }
  250. void OutputStream::SendLogMessage(const char* format, ...) {
  251. if (!log_)
  252. return;
  253. va_list args;
  254. va_start(args, format);
  255. log_->OnLogMessage(
  256. "audio::OS::" + base::StringPrintV(format, args) +
  257. base::StringPrintf(" [controller=0x%" PRIXPTR "]",
  258. reinterpret_cast<uintptr_t>(&controller_)));
  259. va_end(args);
  260. }
  261. } // namespace audio