1 // Copyright (c) 2013 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
5 #include "chromeos/audio/audio_device.h"
6
7 #include <stdint.h>
8
9 #include "base/format_macros.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13
14 namespace chromeos {
15
16 namespace {
17
18 // Get the priority for a particular device type. The priority returned
19 // will be between 0 to 3, the higher number meaning a higher priority.
GetDevicePriority(AudioDeviceType type,bool is_input)20 uint8_t GetDevicePriority(AudioDeviceType type, bool is_input) {
21 switch (type) {
22 case AUDIO_TYPE_HEADPHONE:
23 case AUDIO_TYPE_LINEOUT:
24 case AUDIO_TYPE_MIC:
25 case AUDIO_TYPE_USB:
26 case AUDIO_TYPE_BLUETOOTH:
27 return 3;
28 case AUDIO_TYPE_HDMI:
29 return 2;
30 case AUDIO_TYPE_INTERNAL_SPEAKER:
31 case AUDIO_TYPE_INTERNAL_MIC:
32 case AUDIO_TYPE_FRONT_MIC:
33 return 1;
34 // Lower the priority of bluetooth mic to prevent unexpected bad eperience
35 // to user because of bluetooth audio profile switching. Make priority to
36 // zero so this mic will never be automatically chosen.
37 case AUDIO_TYPE_BLUETOOTH_NB_MIC:
38 // Rear mic should have priority lower than front mic to prevent poor
39 // quality input caused by accidental selecting to rear side mic.
40 case AUDIO_TYPE_REAR_MIC:
41 case AUDIO_TYPE_KEYBOARD_MIC:
42 case AUDIO_TYPE_HOTWORD:
43 case AUDIO_TYPE_POST_MIX_LOOPBACK:
44 case AUDIO_TYPE_POST_DSP_LOOPBACK:
45 case AUDIO_TYPE_ALSA_LOOPBACK:
46 case AUDIO_TYPE_OTHER:
47 default:
48 return 0;
49 }
50 }
51
52 } // namespace
53
54 // static
GetTypeString(AudioDeviceType type)55 std::string AudioDevice::GetTypeString(AudioDeviceType type) {
56 switch (type) {
57 case AUDIO_TYPE_HEADPHONE:
58 return "HEADPHONE";
59 case AUDIO_TYPE_MIC:
60 return "MIC";
61 case AUDIO_TYPE_USB:
62 return "USB";
63 case AUDIO_TYPE_BLUETOOTH:
64 return "BLUETOOTH";
65 case AUDIO_TYPE_BLUETOOTH_NB_MIC:
66 return "BLUETOOTH_NB_MIC";
67 case AUDIO_TYPE_HDMI:
68 return "HDMI";
69 case AUDIO_TYPE_INTERNAL_SPEAKER:
70 return "INTERNAL_SPEAKER";
71 case AUDIO_TYPE_INTERNAL_MIC:
72 return "INTERNAL_MIC";
73 case AUDIO_TYPE_FRONT_MIC:
74 return "FRONT_MIC";
75 case AUDIO_TYPE_REAR_MIC:
76 return "REAR_MIC";
77 case AUDIO_TYPE_KEYBOARD_MIC:
78 return "KEYBOARD_MIC";
79 case AUDIO_TYPE_HOTWORD:
80 return "HOTWORD";
81 case AUDIO_TYPE_LINEOUT:
82 return "LINEOUT";
83 case AUDIO_TYPE_POST_MIX_LOOPBACK:
84 return "POST_MIX_LOOPBACK";
85 case AUDIO_TYPE_POST_DSP_LOOPBACK:
86 return "POST_DSP_LOOPBACK";
87 case AUDIO_TYPE_ALSA_LOOPBACK:
88 return "ALSA_LOOPBACK";
89 case AUDIO_TYPE_OTHER:
90 default:
91 return "OTHER";
92 }
93 }
94
95 // static
GetAudioType(const std::string & node_type)96 AudioDeviceType AudioDevice::GetAudioType(
97 const std::string& node_type) {
98 if (node_type.find("HEADPHONE") != std::string::npos)
99 return AUDIO_TYPE_HEADPHONE;
100 else if (node_type.find("INTERNAL_MIC") != std::string::npos)
101 return AUDIO_TYPE_INTERNAL_MIC;
102 else if (node_type.find("FRONT_MIC") != std::string::npos)
103 return AUDIO_TYPE_FRONT_MIC;
104 else if (node_type.find("REAR_MIC") != std::string::npos)
105 return AUDIO_TYPE_REAR_MIC;
106 else if (node_type.find("KEYBOARD_MIC") != std::string::npos)
107 return AUDIO_TYPE_KEYBOARD_MIC;
108 else if (node_type.find("BLUETOOTH_NB_MIC") != std::string::npos)
109 return AUDIO_TYPE_BLUETOOTH_NB_MIC;
110 else if (node_type.find("MIC") != std::string::npos)
111 return AUDIO_TYPE_MIC;
112 else if (node_type.find("USB") != std::string::npos)
113 return AUDIO_TYPE_USB;
114 else if (node_type.find("BLUETOOTH") != std::string::npos)
115 return AUDIO_TYPE_BLUETOOTH;
116 else if (node_type.find("HDMI") != std::string::npos)
117 return AUDIO_TYPE_HDMI;
118 else if (node_type.find("INTERNAL_SPEAKER") != std::string::npos)
119 return AUDIO_TYPE_INTERNAL_SPEAKER;
120 // TODO(hychao): Remove the 'AOKR' matching line after CRAS switches
121 // node type naming to 'HOTWORD'.
122 else if (node_type.find("AOKR") != std::string::npos)
123 return AUDIO_TYPE_HOTWORD;
124 else if (node_type.find("HOTWORD") != std::string::npos)
125 return AUDIO_TYPE_HOTWORD;
126 else if (node_type.find("LINEOUT") != std::string::npos)
127 return AUDIO_TYPE_LINEOUT;
128 else if (node_type.find("POST_MIX_LOOPBACK") != std::string::npos)
129 return AUDIO_TYPE_POST_MIX_LOOPBACK;
130 else if (node_type.find("POST_DSP_LOOPBACK") != std::string::npos)
131 return AUDIO_TYPE_POST_DSP_LOOPBACK;
132 else if (node_type.find("ALSA_LOOPBACK") != std::string::npos)
133 return AUDIO_TYPE_ALSA_LOOPBACK;
134 else
135 return AUDIO_TYPE_OTHER;
136 }
137
138 AudioDevice::AudioDevice() = default;
139
AudioDevice(const AudioNode & node)140 AudioDevice::AudioDevice(const AudioNode& node) {
141 is_input = node.is_input;
142 id = node.id;
143 stable_device_id_version = node.StableDeviceIdVersion();
144 stable_device_id = node.StableDeviceId();
145 if (stable_device_id_version == 2)
146 deprecated_stable_device_id = node.stable_device_id_v1;
147 type = GetAudioType(node.type);
148 if (!node.name.empty() && node.name != "(default)")
149 display_name = node.name;
150 else
151 display_name = node.device_name;
152 device_name = node.device_name;
153 priority = GetDevicePriority(type, node.is_input);
154 active = node.active;
155 plugged_time = node.plugged_time;
156 max_supported_channels = node.max_supported_channels;
157 }
158
159 AudioDevice::AudioDevice(const AudioDevice& other) = default;
160
ToString() const161 std::string AudioDevice::ToString() const {
162 if (stable_device_id_version == 0) {
163 return "Null device";
164 }
165
166 std::string result;
167 base::StringAppendF(&result,
168 "is_input = %s ",
169 is_input ? "true" : "false");
170 base::StringAppendF(&result,
171 "id = 0x%" PRIx64 " ",
172 id);
173 base::StringAppendF(&result, "stable_device_id_version = %d",
174 stable_device_id_version);
175 base::StringAppendF(&result, "stable_device_id = 0x%" PRIx64 " ",
176 stable_device_id);
177 base::StringAppendF(&result, "deprecated_stable_device_id = 0x%" PRIx64 " ",
178 deprecated_stable_device_id);
179 base::StringAppendF(&result, "display_name = %s ", display_name.c_str());
180 base::StringAppendF(&result,
181 "device_name = %s ",
182 device_name.c_str());
183 base::StringAppendF(&result,
184 "type = %s ",
185 GetTypeString(type).c_str());
186 base::StringAppendF(&result,
187 "active = %s ",
188 active ? "true" : "false");
189 base::StringAppendF(&result, "plugged_time= %s ",
190 base::NumberToString(plugged_time).c_str());
191
192 return result;
193 }
194
IsExternalDevice() const195 bool AudioDevice::IsExternalDevice() const {
196 if (!is_for_simple_usage())
197 return false;
198
199 if (is_input) {
200 return !IsInternalMic();
201 } else {
202 return (type != AUDIO_TYPE_INTERNAL_SPEAKER);
203 }
204 }
205
IsInternalMic() const206 bool AudioDevice::IsInternalMic() const {
207 switch (type) {
208 case AUDIO_TYPE_INTERNAL_MIC:
209 case AUDIO_TYPE_FRONT_MIC:
210 case AUDIO_TYPE_REAR_MIC:
211 return true;
212 default:
213 return false;
214 }
215 }
216
217 } // namespace chromeos
218