| // Copyright 2013 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chromeos/ash/components/audio/audio_device.h" |
| |
| #include <stdint.h> |
| |
| #include "ash/constants/ash_features.h" |
| #include "base/containers/contains.h" |
| #include "base/format_macros.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| // Get the priority for a particular device type. The priority returned |
| // will be between 0 to 3, the higher number meaning a higher priority. |
| uint8_t GetDevicePriority(AudioDeviceType type, bool is_input) { |
| switch (type) { |
| case AudioDeviceType::kHeadphone: |
| case AudioDeviceType::kLineout: |
| case AudioDeviceType::kMic: |
| case AudioDeviceType::kUsb: |
| case AudioDeviceType::kBluetooth: |
| return 3; |
| case AudioDeviceType::kHdmi: |
| return 2; |
| case AudioDeviceType::kInternalSpeaker: |
| case AudioDeviceType::kInternalMic: |
| case AudioDeviceType::kFrontMic: |
| return 1; |
| // Lower the priority of bluetooth mic to prevent unexpected bad eperience |
| // to user because of bluetooth audio profile switching. Make priority to |
| // zero so this mic will never be automatically chosen. |
| case AudioDeviceType::kBluetoothNbMic: |
| // Rear mic should have priority lower than front mic to prevent poor |
| // quality input caused by accidental selecting to rear side mic. |
| case AudioDeviceType::kRearMic: |
| case AudioDeviceType::kKeyboardMic: |
| case AudioDeviceType::kHotword: |
| case AudioDeviceType::kPostMixLoopback: |
| case AudioDeviceType::kPostDspLoopback: |
| case AudioDeviceType::kAlsaLoopback: |
| case AudioDeviceType::kOther: |
| default: |
| return 0; |
| } |
| } |
| |
| } // namespace |
| |
| // static |
| std::string AudioDevice::GetTypeString(AudioDeviceType type) { |
| switch (type) { |
| case AudioDeviceType::kHeadphone: |
| return "HEADPHONE"; |
| case AudioDeviceType::kMic: |
| return "MIC"; |
| case AudioDeviceType::kUsb: |
| return "USB"; |
| case AudioDeviceType::kBluetooth: |
| return "BLUETOOTH"; |
| case AudioDeviceType::kBluetoothNbMic: |
| return "BLUETOOTH_NB_MIC"; |
| case AudioDeviceType::kHdmi: |
| return "HDMI"; |
| case AudioDeviceType::kInternalSpeaker: |
| return "INTERNAL_SPEAKER"; |
| case AudioDeviceType::kInternalMic: |
| return "INTERNAL_MIC"; |
| case AudioDeviceType::kFrontMic: |
| return "FRONT_MIC"; |
| case AudioDeviceType::kRearMic: |
| return "REAR_MIC"; |
| case AudioDeviceType::kKeyboardMic: |
| return "KEYBOARD_MIC"; |
| case AudioDeviceType::kHotword: |
| return "HOTWORD"; |
| case AudioDeviceType::kLineout: |
| return "LINEOUT"; |
| case AudioDeviceType::kPostMixLoopback: |
| return "POST_MIX_LOOPBACK"; |
| case AudioDeviceType::kPostDspLoopback: |
| return "POST_DSP_LOOPBACK"; |
| case AudioDeviceType::kAlsaLoopback: |
| return "ALSA_LOOPBACK"; |
| case AudioDeviceType::kOther: |
| default: |
| return "OTHER"; |
| } |
| } |
| |
| // static |
| AudioDeviceType AudioDevice::GetAudioType(const std::string& node_type) { |
| if (base::Contains(node_type, "HEADPHONE")) { |
| return AudioDeviceType::kHeadphone; |
| } else if (base::Contains(node_type, "INTERNAL_MIC")) { |
| return AudioDeviceType::kInternalMic; |
| } else if (base::Contains(node_type, "FRONT_MIC")) { |
| return AudioDeviceType::kFrontMic; |
| } else if (base::Contains(node_type, "REAR_MIC")) { |
| return AudioDeviceType::kRearMic; |
| } else if (base::Contains(node_type, "KEYBOARD_MIC")) { |
| return AudioDeviceType::kKeyboardMic; |
| } else if (base::Contains(node_type, "BLUETOOTH_NB_MIC")) { |
| return AudioDeviceType::kBluetoothNbMic; |
| } else if (base::Contains(node_type, "MIC")) { |
| return AudioDeviceType::kMic; |
| } else if (base::Contains(node_type, "USB")) { |
| return AudioDeviceType::kUsb; |
| } else if (base::Contains(node_type, "BLUETOOTH")) { |
| return AudioDeviceType::kBluetooth; |
| } else if (base::Contains(node_type, "HDMI")) { |
| return AudioDeviceType::kHdmi; |
| } else if (base::Contains(node_type, "INTERNAL_SPEAKER")) { |
| return AudioDeviceType::kInternalSpeaker; |
| } |
| // TODO(hychao): Remove the 'AOKR' matching line after CRAS switches |
| // node type naming to 'HOTWORD'. |
| else if (base::Contains(node_type, "AOKR")) { |
| return AudioDeviceType::kHotword; |
| } else if (base::Contains(node_type, "HOTWORD")) { |
| return AudioDeviceType::kHotword; |
| } else if (base::Contains(node_type, "LINEOUT")) { |
| return AudioDeviceType::kLineout; |
| } else if (base::Contains(node_type, "POST_MIX_LOOPBACK")) { |
| return AudioDeviceType::kPostMixLoopback; |
| } else if (base::Contains(node_type, "POST_DSP_LOOPBACK")) { |
| return AudioDeviceType::kPostDspLoopback; |
| } else if (base::Contains(node_type, "ALSA_LOOPBACK")) { |
| return AudioDeviceType::kAlsaLoopback; |
| } else { |
| return AudioDeviceType::kOther; |
| } |
| } |
| |
| AudioDevice::AudioDevice() = default; |
| |
| AudioDevice::AudioDevice(const AudioNode& node) { |
| is_input = node.is_input; |
| id = node.id; |
| stable_device_id_version = node.StableDeviceIdVersion(); |
| stable_device_id = node.StableDeviceId(); |
| if (stable_device_id_version == 2) { |
| deprecated_stable_device_id = node.stable_device_id_v1; |
| } |
| type = GetAudioType(node.type); |
| if (!node.name.empty() && node.name != "(default)") { |
| display_name = node.name; |
| } else { |
| display_name = node.device_name; |
| } |
| device_name = node.device_name; |
| priority = GetDevicePriority(type, node.is_input); |
| active = node.active; |
| plugged_time = node.plugged_time; |
| max_supported_channels = node.max_supported_channels; |
| audio_effect = node.audio_effect; |
| number_of_volume_steps = node.number_of_volume_steps; |
| } |
| |
| AudioDevice::AudioDevice(const AudioDevice& other) = default; |
| |
| AudioDevice& AudioDevice::operator=(const AudioDevice& other) = default; |
| |
| std::string AudioDevice::ToString() const { |
| if (stable_device_id_version == 0) { |
| return "Null device"; |
| } |
| |
| std::string result; |
| base::StringAppendF(&result, "is_input = %s ", is_input ? "true" : "false"); |
| base::StringAppendF(&result, "id = 0x%" PRIx64 " ", id); |
| base::StringAppendF(&result, "stable_device_id_version = %d", |
| stable_device_id_version); |
| base::StringAppendF(&result, "stable_device_id = 0x%" PRIx64 " ", |
| stable_device_id); |
| base::StringAppendF(&result, "deprecated_stable_device_id = 0x%" PRIx64 " ", |
| deprecated_stable_device_id); |
| base::StringAppendF(&result, "display_name = %s ", display_name.c_str()); |
| base::StringAppendF(&result, "device_name = %s ", device_name.c_str()); |
| base::StringAppendF(&result, "type = %s ", GetTypeString(type).c_str()); |
| base::StringAppendF(&result, "priority = %d ", priority); |
| base::StringAppendF(&result, "user_priority = %d ", user_priority); |
| base::StringAppendF(&result, "active = %s ", active ? "true" : "false"); |
| base::StringAppendF(&result, "plugged_time = %s ", |
| base::NumberToString(plugged_time).c_str()); |
| base::StringAppendF(&result, "max_supported_channels = %s ", |
| base::NumberToString(max_supported_channels).c_str()); |
| base::StringAppendF(&result, "audio_effect = %s ", |
| base::NumberToString(audio_effect).c_str()); |
| base::StringAppendF(&result, "number_of_volume_steps = %s ", |
| base::NumberToString(number_of_volume_steps).c_str()); |
| return result; |
| } |
| |
| bool AudioDevice::IsExternalDevice() const { |
| if (!is_for_simple_usage()) { |
| return false; |
| } |
| |
| return is_input ? !IsInternalMic() : !IsInternalSpeaker(); |
| } |
| |
| bool AudioDevice::IsInternalMic() const { |
| switch (type) { |
| case AudioDeviceType::kInternalMic: |
| case AudioDeviceType::kFrontMic: |
| case AudioDeviceType::kRearMic: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool AudioDevice::IsInternalSpeaker() const { |
| return type == AudioDeviceType::kInternalSpeaker; |
| } |
| |
| bool LessBuiltInPriority(const AudioDevice& a, const AudioDevice& b) { |
| if (a.priority < b.priority) { |
| return true; |
| } else if (b.priority < a.priority) { |
| return false; |
| } else if (a.plugged_time < b.plugged_time) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| bool LessUserPriority(const AudioDevice& a, const AudioDevice& b) { |
| if (a.user_priority < b.user_priority) { |
| return true; |
| } else if (b.user_priority < a.user_priority) { |
| return false; |
| } else { |
| return LessBuiltInPriority(a, b); |
| } |
| } |
| |
| bool AudioDeviceCompare::operator()(const AudioDevice& a, |
| const AudioDevice& b) const { |
| return LessUserPriority(a, b); |
| } |
| |
| } // namespace ash |