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