input_stream.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  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/input_stream.h"
  5. #include <string>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/callback_helpers.h"
  9. #include "base/strings/strcat.h"
  10. #include "base/strings/string_piece.h"
  11. #include "base/strings/stringprintf.h"
  12. #include "base/trace_event/trace_event.h"
  13. #include "media/audio/audio_manager.h"
  14. #include "media/base/audio_parameters.h"
  15. #include "media/base/user_input_monitor.h"
  16. #include "media/mojo/mojom/audio_processing.mojom.h"
  17. #include "mojo/public/cpp/system/buffer.h"
  18. #include "mojo/public/cpp/system/handle.h"
  19. #include "mojo/public/cpp/system/platform_handle.h"
  20. #include "services/audio/input_sync_writer.h"
  21. #include "services/audio/user_input_monitor.h"
  22. #include "third_party/abseil-cpp/absl/utility/utility.h"
  23. namespace audio {
  24. namespace {
  25. const int kMaxInputChannels = 3;
  26. using InputStreamErrorCode = media::mojom::InputStreamErrorCode;
  27. using DisconnectReason =
  28. media::mojom::AudioInputStreamObserver::DisconnectReason;
  29. const char* ErrorCodeToString(InputController::ErrorCode error) {
  30. switch (error) {
  31. case (InputController::STREAM_CREATE_ERROR):
  32. return "STREAM_CREATE_ERROR";
  33. case (InputController::STREAM_OPEN_ERROR):
  34. return "STREAM_OPEN_ERROR";
  35. case (InputController::STREAM_ERROR):
  36. return "STREAM_ERROR";
  37. case (InputController::STREAM_OPEN_SYSTEM_PERMISSIONS_ERROR):
  38. return "STREAM_OPEN_SYSTEM_PERMISSIONS_ERROR";
  39. case (InputController::STREAM_OPEN_DEVICE_IN_USE_ERROR):
  40. return "STREAM_OPEN_DEVICE_IN_USE_ERROR";
  41. default:
  42. NOTREACHED();
  43. }
  44. return "UNKNOWN_ERROR";
  45. }
  46. std::string GetCtorLogString(const std::string& device_id,
  47. const media::AudioParameters& params,
  48. bool enable_agc) {
  49. std::string str = base::StringPrintf("Ctor(");
  50. base::StringAppendF(&str, "{device_id=%s}, ", device_id.c_str());
  51. base::StringAppendF(&str, "{params=[%s]}, ",
  52. params.AsHumanReadableString().c_str());
  53. base::StringAppendF(&str, "{enable_agc=%d})", enable_agc);
  54. return str;
  55. }
  56. } // namespace
  57. InputStream::InputStream(
  58. CreatedCallback created_callback,
  59. DeleteCallback delete_callback,
  60. mojo::PendingReceiver<media::mojom::AudioInputStream> receiver,
  61. mojo::PendingRemote<media::mojom::AudioInputStreamClient> client,
  62. mojo::PendingRemote<media::mojom::AudioInputStreamObserver> observer,
  63. mojo::PendingRemote<media::mojom::AudioLog> log,
  64. media::AudioManager* audio_manager,
  65. AecdumpRecordingManager* aecdump_recording_manager,
  66. std::unique_ptr<UserInputMonitor> user_input_monitor,
  67. InputStreamActivityMonitor* activity_monitor,
  68. DeviceOutputListener* device_output_listener,
  69. media::mojom::AudioProcessingConfigPtr processing_config,
  70. const std::string& device_id,
  71. const media::AudioParameters& params,
  72. uint32_t shared_memory_count,
  73. bool enable_agc)
  74. : id_(base::UnguessableToken::Create()),
  75. receiver_(this, std::move(receiver)),
  76. client_(std::move(client)),
  77. observer_(std::move(observer)),
  78. log_(std::move(log)),
  79. created_callback_(std::move(created_callback)),
  80. delete_callback_(std::move(delete_callback)),
  81. foreign_socket_(),
  82. writer_(InputSyncWriter::Create(
  83. log_ ? base::BindRepeating(&media::mojom::AudioLog::OnLogMessage,
  84. base::Unretained(log_.get()))
  85. : base::DoNothing(),
  86. shared_memory_count,
  87. params,
  88. &foreign_socket_)),
  89. user_input_monitor_(std::move(user_input_monitor)) {
  90. DCHECK(audio_manager);
  91. DCHECK(activity_monitor);
  92. DCHECK(receiver_.is_bound());
  93. DCHECK(client_);
  94. DCHECK(created_callback_);
  95. DCHECK(delete_callback_);
  96. DCHECK(params.IsValid());
  97. TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("audio", "audio::InputStream", this);
  98. TRACE_EVENT_NESTABLE_ASYNC_BEGIN2("audio", "InputStream", this, "device id",
  99. device_id, "params",
  100. params.AsHumanReadableString());
  101. SendLogMessage("%s", GetCtorLogString(device_id, params, enable_agc).c_str());
  102. // |this| owns these objects, so unretained is safe.
  103. base::RepeatingClosure error_handler =
  104. base::BindRepeating(&InputStream::OnStreamError, base::Unretained(this),
  105. absl::optional<DisconnectReason>());
  106. receiver_.set_disconnect_handler(error_handler);
  107. client_.set_disconnect_handler(error_handler);
  108. if (observer_)
  109. observer_.set_disconnect_handler(std::move(error_handler));
  110. if (log_)
  111. log_->OnCreated(params, device_id);
  112. // Only MONO, STEREO and STEREO_AND_KEYBOARD_MIC channel layouts are expected,
  113. // see AudioManagerBase::MakeAudioInputStream().
  114. if (params.channels() > kMaxInputChannels) {
  115. OnStreamPlatformError();
  116. return;
  117. }
  118. if (!writer_) {
  119. OnStreamPlatformError();
  120. return;
  121. }
  122. controller_ = InputController::Create(
  123. audio_manager, this, writer_.get(), user_input_monitor_.get(),
  124. activity_monitor, device_output_listener, aecdump_recording_manager,
  125. std::move(processing_config), params, device_id, enable_agc);
  126. }
  127. InputStream::~InputStream() {
  128. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  129. SendLogMessage("Dtor()");
  130. if (log_)
  131. log_->OnClosed();
  132. if (observer_) {
  133. observer_.ResetWithReason(
  134. static_cast<uint32_t>(DisconnectReason::kTerminatedByClient),
  135. std::string());
  136. }
  137. if (created_callback_) {
  138. // Didn't manage to create the stream. Call the callback anyways as mandated
  139. // by mojo.
  140. std::move(created_callback_).Run(nullptr, false, absl::nullopt);
  141. }
  142. if (!controller_) {
  143. // Didn't initialize properly, nothing to clean up.
  144. return;
  145. }
  146. // TODO(https://crbug.com/803102): remove InputController::Close() after
  147. // content/ streams are removed, destructor should suffice.
  148. controller_->Close();
  149. TRACE_EVENT_NESTABLE_ASYNC_END0("audio", "InputStream", this);
  150. TRACE_EVENT_NESTABLE_ASYNC_END0("audio", "audio::InputStream", this);
  151. }
  152. void InputStream::SetOutputDeviceForAec(const std::string& output_device_id) {
  153. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  154. DCHECK(controller_);
  155. controller_->SetOutputDeviceForAec(output_device_id);
  156. SendLogMessage("%s({output_device_id=%s})", __func__,
  157. output_device_id.c_str());
  158. }
  159. void InputStream::Record() {
  160. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  161. DCHECK(controller_);
  162. TRACE_EVENT_NESTABLE_ASYNC_INSTANT0("audio", "Record", this);
  163. SendLogMessage("%s()", __func__);
  164. controller_->Record();
  165. if (observer_)
  166. observer_->DidStartRecording();
  167. if (log_)
  168. log_->OnStarted();
  169. }
  170. void InputStream::SetVolume(double volume) {
  171. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  172. DCHECK(controller_);
  173. TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("audio", "SetVolume", this, "volume",
  174. volume);
  175. if (volume < 0 || volume > 1) {
  176. receiver_.ReportBadMessage("Invalid volume");
  177. OnStreamPlatformError();
  178. return;
  179. }
  180. controller_->SetVolume(volume);
  181. if (log_)
  182. log_->OnSetVolume(volume);
  183. }
  184. void InputStream::OnCreated(bool initially_muted) {
  185. TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("audio", "Created", this,
  186. "initially muted", initially_muted);
  187. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  188. SendLogMessage("%s({muted=%s})", __func__,
  189. initially_muted ? "true" : "false");
  190. base::ReadOnlySharedMemoryRegion shared_memory_region =
  191. writer_->TakeSharedMemoryRegion();
  192. if (!shared_memory_region.IsValid()) {
  193. OnStreamPlatformError();
  194. return;
  195. }
  196. mojo::PlatformHandle socket_handle(foreign_socket_.Take());
  197. DCHECK(socket_handle.is_valid());
  198. std::move(created_callback_)
  199. .Run({absl::in_place, std::move(shared_memory_region),
  200. std::move(socket_handle)},
  201. initially_muted, id_);
  202. }
  203. DisconnectReason InputErrorToDisconnectReason(InputController::ErrorCode code) {
  204. switch (code) {
  205. case InputController::STREAM_OPEN_SYSTEM_PERMISSIONS_ERROR:
  206. return DisconnectReason::kSystemPermissions;
  207. case InputController::STREAM_OPEN_DEVICE_IN_USE_ERROR:
  208. return DisconnectReason::kDeviceInUse;
  209. default:
  210. break;
  211. }
  212. return DisconnectReason::kPlatformError;
  213. }
  214. InputStreamErrorCode InputControllerErrorToStreamError(
  215. InputController::ErrorCode code) {
  216. switch (code) {
  217. case InputController::STREAM_OPEN_SYSTEM_PERMISSIONS_ERROR:
  218. return InputStreamErrorCode::kSystemPermissions;
  219. case InputController::STREAM_OPEN_DEVICE_IN_USE_ERROR:
  220. return InputStreamErrorCode::kDeviceInUse;
  221. default:
  222. break;
  223. }
  224. return InputStreamErrorCode::kUnknown;
  225. }
  226. void InputStream::OnError(InputController::ErrorCode error_code) {
  227. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  228. TRACE_EVENT_NESTABLE_ASYNC_INSTANT0("audio", "Error", this);
  229. client_->OnError(InputControllerErrorToStreamError(error_code));
  230. if (log_)
  231. log_->OnError();
  232. SendLogMessage("%s({error_code=%s})", __func__,
  233. ErrorCodeToString(error_code));
  234. OnStreamError(InputErrorToDisconnectReason(error_code));
  235. }
  236. void InputStream::OnLog(base::StringPiece message) {
  237. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  238. if (log_)
  239. log_->OnLogMessage(std::string(message) + " [id=" + id_.ToString() + "]");
  240. }
  241. void InputStream::OnMuted(bool is_muted) {
  242. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  243. client_->OnMutedStateChanged(is_muted);
  244. }
  245. void InputStream::OnStreamPlatformError() {
  246. OnStreamError(DisconnectReason::kPlatformError);
  247. }
  248. void InputStream::OnStreamError(
  249. absl::optional<DisconnectReason> reason_to_report) {
  250. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  251. TRACE_EVENT_NESTABLE_ASYNC_INSTANT0("audio", "OnStreamError", this);
  252. if (reason_to_report.has_value()) {
  253. if (observer_) {
  254. observer_.ResetWithReason(static_cast<uint32_t>(reason_to_report.value()),
  255. std::string());
  256. }
  257. SendLogMessage("%s()", __func__);
  258. }
  259. // Defer callback so we're not destructed while in the constructor.
  260. base::SequencedTaskRunnerHandle::Get()->PostTask(
  261. FROM_HERE,
  262. base::BindOnce(&InputStream::CallDeleter, weak_factory_.GetWeakPtr()));
  263. receiver_.reset();
  264. }
  265. void InputStream::CallDeleter() {
  266. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  267. std::move(delete_callback_).Run(this);
  268. }
  269. void InputStream::SendLogMessage(const char* format, ...) {
  270. DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
  271. if (!log_)
  272. return;
  273. va_list args;
  274. va_start(args, format);
  275. log_->OnLogMessage("audio::IS::" + base::StringPrintV(format, args) +
  276. base::StringPrintf(" [id=%s]", id_.ToString().c_str()));
  277. va_end(args);
  278. }
  279. } // namespace audio