cras_util.cc 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. // Copyright 2020 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 "media/audio/cras/cras_util.h"
  5. #include "base/logging.h"
  6. #include "base/strings/string_number_conversions.h"
  7. #include "base/time/time.h"
  8. #include "media/audio/audio_device_description.h"
  9. #include "media/audio/cras/audio_manager_cras_base.h"
  10. namespace media {
  11. namespace {
  12. constexpr char kInternalInputVirtualDevice[] = "Built-in mic";
  13. constexpr char kInternalOutputVirtualDevice[] = "Built-in speaker";
  14. constexpr char kHeadphoneLineOutVirtualDevice[] = "Headphone/Line Out";
  15. // Names below are from the node_type_to_str function in CRAS server.
  16. // https://chromium.googlesource.com/chromiumos/third_party/adhd/+/refs/heads/main/cras/src/server/cras_iodev_list.c
  17. constexpr char kInternalSpeaker[] = "INTERNAL_SPEAKER";
  18. constexpr char kHeadphone[] = "HEADPHONE";
  19. constexpr char kHDMI[] = "HDMI";
  20. constexpr char kLineout[] = "LINEOUT";
  21. constexpr char kMic[] = "MIC";
  22. constexpr char kInternalMic[] = "INTERNAL_MIC";
  23. constexpr char kFrontMic[] = "FRONT_MIC";
  24. constexpr char kRearMic[] = "REAR_MIC";
  25. constexpr char kBluetoothNBMic[] = "BLUETOOTH_NB_MIC";
  26. constexpr char kUSB[] = "USB";
  27. constexpr char kBluetooth[] = "BLUETOOTH";
  28. constexpr char kAlsaLoopback[] = "ALSA_LOOPBACK";
  29. // Returns if that an input or output audio device is for simple usage like
  30. // playback or recording for user. In contrast, audio device such as loopback,
  31. // always on keyword recognition (HOTWORD), and keyboard mic are not for simple
  32. // usage.
  33. // One special case is ALSA loopback device, which will only exist under
  34. // testing. We want it visible to users for e2e tests.
  35. bool IsForSimpleUsage(std::string type) {
  36. return type == kInternalSpeaker || type == kHeadphone || type == kHDMI ||
  37. type == kLineout || type == kMic || type == kInternalMic ||
  38. type == kFrontMic || type == kRearMic || type == kBluetoothNBMic ||
  39. type == kUSB || type == kBluetooth || type == kAlsaLoopback;
  40. }
  41. bool IsInternalMic(std::string type) {
  42. return type == kInternalMic || type == kFrontMic || type == kRearMic;
  43. }
  44. // Connects to the CRAS server.
  45. libcras_client* CrasConnect() {
  46. libcras_client* client;
  47. client = libcras_client_create();
  48. if (!client) {
  49. LOG(ERROR) << "Couldn't create CRAS client.\n";
  50. return nullptr;
  51. }
  52. if (libcras_client_connect(client)) {
  53. LOG(ERROR) << "Couldn't connect CRAS client.\n";
  54. libcras_client_destroy(client);
  55. return nullptr;
  56. }
  57. return client;
  58. }
  59. // Disconnects from the CRAS server.
  60. void CrasDisconnect(libcras_client** client) {
  61. if (*client) {
  62. libcras_client_stop(*client);
  63. libcras_client_destroy(*client);
  64. *client = nullptr;
  65. }
  66. }
  67. } // namespace
  68. CrasDevice::CrasDevice() = default;
  69. CrasDevice::CrasDevice(struct libcras_node_info* node, DeviceType type)
  70. : type(type) {
  71. int rc;
  72. rc = libcras_node_info_get_id(node, &id);
  73. if (rc) {
  74. LOG(ERROR) << "Failed to get the node id: " << rc;
  75. id = 0;
  76. }
  77. rc = libcras_node_info_get_dev_idx(node, &dev_idx);
  78. if (rc) {
  79. LOG(ERROR) << "Failed to get the dev idx: " << rc;
  80. dev_idx = 0;
  81. }
  82. rc = libcras_node_info_is_plugged(node, &plugged);
  83. if (rc) {
  84. LOG(ERROR) << "Failed to get if the node is plugged: " << rc;
  85. plugged = false;
  86. }
  87. rc = libcras_node_info_is_active(node, &active);
  88. if (rc) {
  89. LOG(ERROR) << "Failed to get if the node is active: " << rc;
  90. active = false;
  91. }
  92. char* type_str;
  93. rc = libcras_node_info_get_type(node, &type_str);
  94. if (rc) {
  95. LOG(ERROR) << "Failed to get the node type: " << rc;
  96. node_type = nullptr;
  97. }
  98. node_type = type_str;
  99. char* node_name;
  100. rc = libcras_node_info_get_node_name(node, &node_name);
  101. if (rc) {
  102. LOG(ERROR) << "Failed to get the node name: " << rc;
  103. node_name = nullptr;
  104. }
  105. char* device_name;
  106. rc = libcras_node_info_get_dev_name(node, &device_name);
  107. if (rc) {
  108. LOG(ERROR) << "Failed to get the dev name: " << rc;
  109. device_name = nullptr;
  110. }
  111. rc = libcras_node_info_get_max_supported_channels(node,
  112. &max_supported_channels);
  113. if (rc) {
  114. LOG(ERROR) << "Failed to get max supported channels: " << rc;
  115. max_supported_channels = 0;
  116. }
  117. name = std::string(node_name);
  118. if (name.empty() || name == "(default)")
  119. name = device_name;
  120. dev_name = device_name;
  121. }
  122. void mergeDevices(CrasDevice& old_dev, CrasDevice& new_dev) {
  123. if (old_dev.node_type == kLineout || new_dev.node_type == kLineout) {
  124. old_dev.name = kHeadphoneLineOutVirtualDevice;
  125. old_dev.node_type = "";
  126. } else if (old_dev.node_type == kInternalSpeaker ||
  127. new_dev.node_type == kInternalSpeaker) {
  128. old_dev.name = kInternalOutputVirtualDevice;
  129. old_dev.node_type = "";
  130. } else if (IsInternalMic(old_dev.node_type) ||
  131. IsInternalMic(new_dev.node_type)) {
  132. old_dev.name = kInternalInputVirtualDevice;
  133. old_dev.node_type = "";
  134. } else {
  135. LOG(WARNING) << "Failed to create virtual device for " << old_dev.name;
  136. }
  137. old_dev.active |= new_dev.active;
  138. }
  139. CrasUtil::CrasUtil() = default;
  140. CrasUtil::~CrasUtil() = default;
  141. std::vector<CrasDevice> CrasUtil::CrasGetAudioDevices(DeviceType type) {
  142. std::vector<CrasDevice> devices;
  143. libcras_client* client = CrasConnect();
  144. if (!client)
  145. return devices;
  146. int rc;
  147. struct libcras_node_info** nodes;
  148. size_t num_nodes;
  149. if (type == DeviceType::kInput) {
  150. rc =
  151. libcras_client_get_nodes(client, CRAS_STREAM_INPUT, &nodes, &num_nodes);
  152. } else {
  153. rc = libcras_client_get_nodes(client, CRAS_STREAM_OUTPUT, &nodes,
  154. &num_nodes);
  155. }
  156. if (rc < 0) {
  157. LOG(ERROR) << "Failed to get devices: " << std::strerror(rc);
  158. CrasDisconnect(&client);
  159. return devices;
  160. }
  161. for (size_t i = 0; i < num_nodes; i++) {
  162. auto new_dev = CrasDevice(nodes[i], type);
  163. if (!new_dev.plugged || !IsForSimpleUsage(new_dev.node_type))
  164. continue;
  165. bool added = false;
  166. for (auto& dev : devices) {
  167. if (dev.dev_idx == new_dev.dev_idx) {
  168. mergeDevices(dev, new_dev);
  169. added = true;
  170. break;
  171. }
  172. }
  173. if (!added)
  174. devices.emplace_back(new_dev);
  175. }
  176. libcras_node_info_array_destroy(nodes, num_nodes);
  177. CrasDisconnect(&client);
  178. return devices;
  179. }
  180. int CrasUtil::CrasGetAecSupported() {
  181. libcras_client* client = CrasConnect();
  182. if (!client)
  183. return 0;
  184. int supported;
  185. libcras_client_get_aec_supported(client, &supported);
  186. CrasDisconnect(&client);
  187. return supported;
  188. }
  189. int CrasUtil::CrasGetAecGroupId() {
  190. libcras_client* client = CrasConnect();
  191. if (!client)
  192. return -1;
  193. int id;
  194. int rc = libcras_client_get_aec_group_id(client, &id);
  195. CrasDisconnect(&client);
  196. return rc < 0 ? rc : id;
  197. }
  198. int CrasUtil::CrasGetDefaultOutputBufferSize() {
  199. libcras_client* client = CrasConnect();
  200. if (!client)
  201. return -1;
  202. int size;
  203. int rc = libcras_client_get_default_output_buffer_size(client, &size);
  204. CrasDisconnect(&client);
  205. return rc < 0 ? rc : size;
  206. }
  207. } // namespace media