| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chromeos/audio/cras_audio_handler.h" | 5 #include "chromeos/audio/cras_audio_handler.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 bool IsSameAudioDevice(const AudioDevice& a, const AudioDevice& b) { | 39 bool IsSameAudioDevice(const AudioDevice& a, const AudioDevice& b) { |
| 40 return a.id == b.id && a.is_input == b.is_input && a.type == b.type | 40 return a.id == b.id && a.is_input == b.is_input && a.type == b.type |
| 41 && a.device_name == b.device_name; | 41 && a.device_name == b.device_name; |
| 42 } | 42 } |
| 43 | 43 |
| 44 bool IsInNodeList(uint64_t node_id, | 44 bool IsInNodeList(uint64_t node_id, |
| 45 const CrasAudioHandler::NodeIdList& id_list) { | 45 const CrasAudioHandler::NodeIdList& id_list) { |
| 46 return std::find(id_list.begin(), id_list.end(), node_id) != id_list.end(); | 46 return std::find(id_list.begin(), id_list.end(), node_id) != id_list.end(); |
| 47 } | 47 } |
| 48 | 48 |
| 49 bool IsNodeInTheList(uint64_t node_id, const AudioNodeList& node_list) { | |
| 50 for (size_t i = 0; i < node_list.size(); ++i) { | |
| 51 if (node_id == node_list[i].id) | |
| 52 return true; | |
| 53 } | |
| 54 return false; | |
| 55 } | |
| 56 | |
| 57 } // namespace | 49 } // namespace |
| 58 | 50 |
| 59 CrasAudioHandler::AudioObserver::AudioObserver() { | 51 CrasAudioHandler::AudioObserver::AudioObserver() { |
| 60 } | 52 } |
| 61 | 53 |
| 62 CrasAudioHandler::AudioObserver::~AudioObserver() { | 54 CrasAudioHandler::AudioObserver::~AudioObserver() { |
| 63 } | 55 } |
| 64 | 56 |
| 65 void CrasAudioHandler::AudioObserver::OnOutputNodeVolumeChanged( | 57 void CrasAudioHandler::AudioObserver::OnOutputNodeVolumeChanged( |
| 66 uint64_t /* node_id */, | 58 uint64_t /* node_id */, |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 294 make_input_change = true; | 286 make_input_change = true; |
| 295 RemoveActiveNodeInternal(device.id, false); // no notification. | 287 RemoveActiveNodeInternal(device.id, false); // no notification. |
| 296 } else if (!device.is_input && request_output_change && | 288 } else if (!device.is_input && request_output_change && |
| 297 !IsInNodeList(device.id, new_active_ids)) { | 289 !IsInNodeList(device.id, new_active_ids)) { |
| 298 make_output_change = true; | 290 make_output_change = true; |
| 299 RemoveActiveNodeInternal(device.id, false); // no notification. | 291 RemoveActiveNodeInternal(device.id, false); // no notification. |
| 300 } | 292 } |
| 301 } | 293 } |
| 302 } | 294 } |
| 303 | 295 |
| 304 // Adds the new active devices. | 296 // Adds the new active devices. Note that this function is used by audio |
| 297 // extension to manage multiple active nodes, in which case the devices |
| 298 // selection preference is controlled by the app, we intentionally exclude |
| 299 // the additional nodes from saving their device states as a result. |
| 305 for (size_t i = 0; i < nodes_to_activate.size(); ++i) | 300 for (size_t i = 0; i < nodes_to_activate.size(); ++i) |
| 306 AddActiveNode(nodes_to_activate[i], false); // no notification. | 301 AddActiveNode(nodes_to_activate[i], false); // no notification. |
| 307 | 302 |
| 308 // Notify the active nodes change now. | 303 // Notify the active nodes change now. |
| 309 if (make_input_change) | 304 if (make_input_change) |
| 310 NotifyActiveNodeChanged(true); | 305 NotifyActiveNodeChanged(true); |
| 311 if (make_output_change) | 306 if (make_output_change) |
| 312 NotifyActiveNodeChanged(false); | 307 NotifyActiveNodeChanged(false); |
| 313 } | 308 } |
| 314 | 309 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 SetInputMuteInternal(mute_on); | 386 SetInputMuteInternal(mute_on); |
| 392 FOR_EACH_OBSERVER(AudioObserver, observers_, | 387 FOR_EACH_OBSERVER(AudioObserver, observers_, |
| 393 OnInputMuteChanged(input_mute_on_)); | 388 OnInputMuteChanged(input_mute_on_)); |
| 394 } | 389 } |
| 395 | 390 |
| 396 void CrasAudioHandler::SetActiveOutputNode(uint64_t node_id, bool notify) { | 391 void CrasAudioHandler::SetActiveOutputNode(uint64_t node_id, bool notify) { |
| 397 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> | 392 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> |
| 398 SetActiveOutputNode(node_id); | 393 SetActiveOutputNode(node_id); |
| 399 if (notify) | 394 if (notify) |
| 400 NotifyActiveNodeChanged(false); | 395 NotifyActiveNodeChanged(false); |
| 396 |
| 397 // Save state for all output nodes. |
| 398 for (AudioDeviceMap::iterator it = audio_devices_.begin(); |
| 399 it != audio_devices_.end(); ++it) { |
| 400 if (it->second.is_input) |
| 401 continue; |
| 402 audio_pref_handler_->SetDeviceState(it->second, it->second.active |
| 403 ? AUDIO_STATE_ACTIVE |
| 404 : AUDIO_STATE_INACTIVE); |
| 405 } |
| 401 } | 406 } |
| 402 | 407 |
| 403 void CrasAudioHandler::SetActiveInputNode(uint64_t node_id, bool notify) { | 408 void CrasAudioHandler::SetActiveInputNode(uint64_t node_id, bool notify) { |
| 404 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> | 409 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> |
| 405 SetActiveInputNode(node_id); | 410 SetActiveInputNode(node_id); |
| 406 if (notify) | 411 if (notify) |
| 407 NotifyActiveNodeChanged(true); | 412 NotifyActiveNodeChanged(true); |
| 413 |
| 414 // Save state for all input nodes. |
| 415 for (AudioDeviceMap::iterator it = audio_devices_.begin(); |
| 416 it != audio_devices_.end(); ++it) { |
| 417 if (!it->second.is_input) |
| 418 continue; |
| 419 audio_pref_handler_->SetDeviceState(it->second, it->second.active |
| 420 ? AUDIO_STATE_ACTIVE |
| 421 : AUDIO_STATE_INACTIVE); |
| 422 } |
| 408 } | 423 } |
| 409 | 424 |
| 410 void CrasAudioHandler::SetVolumeGainPercentForDevice(uint64_t device_id, | 425 void CrasAudioHandler::SetVolumeGainPercentForDevice(uint64_t device_id, |
| 411 int value) { | 426 int value) { |
| 412 const AudioDevice* device = GetDeviceFromId(device_id); | 427 const AudioDevice* device = GetDeviceFromId(device_id); |
| 413 if (!device) | 428 if (!device) |
| 414 return; | 429 return; |
| 415 | 430 |
| 416 if (device->is_input) | 431 if (device->is_input) |
| 417 SetInputNodeGainPercent(device_id, value); | 432 SetInputNodeGainPercent(device_id, value); |
| (...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 774 SetupAudioInputState(); | 789 SetupAudioInputState(); |
| 775 SetActiveInputNode(active_input_node_id_, notify); | 790 SetActiveInputNode(active_input_node_id_, notify); |
| 776 } else { | 791 } else { |
| 777 if (!ChangeActiveDevice(device, &active_output_node_id_)) | 792 if (!ChangeActiveDevice(device, &active_output_node_id_)) |
| 778 return; | 793 return; |
| 779 SetupAudioOutputState(); | 794 SetupAudioOutputState(); |
| 780 SetActiveOutputNode(active_output_node_id_, notify); | 795 SetActiveOutputNode(active_output_node_id_, notify); |
| 781 } | 796 } |
| 782 } | 797 } |
| 783 | 798 |
| 784 bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes, | 799 bool CrasAudioHandler::HasDeviceChange( |
| 785 bool is_input, | 800 const AudioNodeList& new_nodes, |
| 786 AudioNodeList* new_discovered) { | 801 bool is_input, |
| 802 AudioDevicePriorityQueue* new_discovered) { |
| 787 size_t num_old_devices = 0; | 803 size_t num_old_devices = 0; |
| 788 size_t num_new_devices = 0; | 804 size_t num_new_devices = 0; |
| 789 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); | 805 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
| 790 it != audio_devices_.end(); ++it) { | 806 it != audio_devices_.end(); ++it) { |
| 791 if (is_input == it->second.is_input) | 807 if (is_input == it->second.is_input) |
| 792 ++num_old_devices; | 808 ++num_old_devices; |
| 793 } | 809 } |
| 794 | 810 |
| 795 bool new_or_changed_device = false; | 811 bool new_or_changed_device = false; |
| 796 new_discovered->clear(); | 812 while (!new_discovered->empty()) |
| 813 new_discovered->pop(); |
| 797 for (AudioNodeList::const_iterator it = new_nodes.begin(); | 814 for (AudioNodeList::const_iterator it = new_nodes.begin(); |
| 798 it != new_nodes.end(); ++it) { | 815 it != new_nodes.end(); ++it) { |
| 799 if (is_input == it->is_input) { | 816 if (is_input == it->is_input) { |
| 800 ++num_new_devices; | 817 ++num_new_devices; |
| 801 // Look to see if the new device not in the old device list. | 818 // Look to see if the new device not in the old device list. |
| 802 AudioDevice device(*it); | 819 AudioDevice device(*it); |
| 803 DeviceStatus status = CheckDeviceStatus(device); | 820 DeviceStatus status = CheckDeviceStatus(device); |
| 804 if (status == NEW_DEVICE) | 821 if (status == NEW_DEVICE) |
| 805 new_discovered->push_back(*it); | 822 new_discovered->push(device); |
| 806 if (status == NEW_DEVICE || status == CHANGED_DEVICE) { | 823 if (status == NEW_DEVICE || status == CHANGED_DEVICE) { |
| 807 new_or_changed_device = true; | 824 new_or_changed_device = true; |
| 808 } | 825 } |
| 809 } | 826 } |
| 810 } | 827 } |
| 811 return new_or_changed_device || (num_old_devices != num_new_devices); | 828 return new_or_changed_device || (num_old_devices != num_new_devices); |
| 812 } | 829 } |
| 813 | 830 |
| 814 CrasAudioHandler::DeviceStatus CrasAudioHandler::CheckDeviceStatus( | 831 CrasAudioHandler::DeviceStatus CrasAudioHandler::CheckDeviceStatus( |
| 815 const AudioDevice& device) { | 832 const AudioDevice& device) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 841 size_t old_output_device_size = 0; | 858 size_t old_output_device_size = 0; |
| 842 size_t old_input_device_size = 0; | 859 size_t old_input_device_size = 0; |
| 843 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); | 860 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
| 844 it != audio_devices_.end(); ++it) { | 861 it != audio_devices_.end(); ++it) { |
| 845 if (it->second.is_input) | 862 if (it->second.is_input) |
| 846 ++old_input_device_size; | 863 ++old_input_device_size; |
| 847 else | 864 else |
| 848 ++old_output_device_size; | 865 ++old_output_device_size; |
| 849 } | 866 } |
| 850 | 867 |
| 851 AudioNodeList hotplug_output_nodes; | 868 AudioDevicePriorityQueue hotplug_output_nodes; |
| 852 AudioNodeList hotplug_input_nodes; | 869 AudioDevicePriorityQueue hotplug_input_nodes; |
| 853 bool output_devices_changed = | 870 bool output_devices_changed = |
| 854 HasDeviceChange(nodes, false, &hotplug_output_nodes); | 871 HasDeviceChange(nodes, false, &hotplug_output_nodes); |
| 855 bool input_devices_changed = | 872 bool input_devices_changed = |
| 856 HasDeviceChange(nodes, true, &hotplug_input_nodes); | 873 HasDeviceChange(nodes, true, &hotplug_input_nodes); |
| 857 audio_devices_.clear(); | 874 audio_devices_.clear(); |
| 858 has_alternative_input_ = false; | 875 has_alternative_input_ = false; |
| 859 has_alternative_output_ = false; | 876 has_alternative_output_ = false; |
| 860 | 877 |
| 861 while (!input_devices_pq_.empty()) | 878 while (!input_devices_pq_.empty()) |
| 862 input_devices_pq_.pop(); | 879 input_devices_pq_.pop(); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 893 // or changed to inactive by cras, reset active_output_node_id_. | 910 // or changed to inactive by cras, reset active_output_node_id_. |
| 894 // See crbug.com/478968. | 911 // See crbug.com/478968. |
| 895 const AudioDevice* active_output = GetDeviceFromId(active_output_node_id_); | 912 const AudioDevice* active_output = GetDeviceFromId(active_output_node_id_); |
| 896 if (!active_output || !active_output->active) | 913 if (!active_output || !active_output->active) |
| 897 active_output_node_id_ = 0; | 914 active_output_node_id_ = 0; |
| 898 const AudioDevice* active_input = GetDeviceFromId(active_input_node_id_); | 915 const AudioDevice* active_input = GetDeviceFromId(active_input_node_id_); |
| 899 if (!active_input || !active_input->active) | 916 if (!active_input || !active_input->active) |
| 900 active_input_node_id_ = 0; | 917 active_input_node_id_ = 0; |
| 901 | 918 |
| 902 // If audio nodes change is caused by unplugging some non-active audio | 919 // If audio nodes change is caused by unplugging some non-active audio |
| 903 // devices, the previously set active audio device will stay active. | 920 // devices, we wont't change the current active audio devices. |
| 904 // Otherwise, switch to a new active audio device according to their priority. | |
| 905 if (input_devices_changed && | 921 if (input_devices_changed && |
| 906 !NonActiveDeviceUnplugged(old_input_device_size, | 922 !NonActiveDeviceUnplugged(old_input_device_size, |
| 907 new_input_device_size, | 923 new_input_device_size, |
| 908 active_input_node_id_)) { | 924 active_input_node_id_)) { |
| 909 // Some devices like chromeboxes don't have the internal audio input. In | 925 // Some devices like chromeboxes don't have the internal audio input. In |
| 910 // that case the active input node id should be reset. | 926 // that case the active input node id should be reset. |
| 911 if (input_devices_pq_.empty()) { | 927 if (input_devices_pq_.empty()) { |
| 912 active_input_node_id_ = 0; | 928 active_input_node_id_ = 0; |
| 913 NotifyActiveNodeChanged(true); | 929 NotifyActiveNodeChanged(true); |
| 914 } else { | 930 } else { |
| 915 // If user has hot plugged a new node, we should change to the active | 931 // If there is no current active node, or, no new hot plugged node, select |
| 916 // device to the new node if it has the highest priority; otherwise, | 932 // the active node by their priorities. |
| 917 // we should keep the existing active node chosen by user. | 933 if (!active_input_node_id_ || hotplug_input_nodes.empty()) { |
| 918 // For all other cases, we will choose the node with highest priority. | |
| 919 if (!active_input_node_id_ || hotplug_input_nodes.empty() || | |
| 920 IsNodeInTheList(input_devices_pq_.top().id, hotplug_input_nodes)) { | |
| 921 SwitchToDevice(input_devices_pq_.top(), true); | 934 SwitchToDevice(input_devices_pq_.top(), true); |
| 935 } else { |
| 936 // If user has hot plugged any input nodes, look at the one with highest |
| 937 // priority (normally, there is only one hot plugged input node), and |
| 938 // consider switch to it depend on its last state stored in preference. |
| 939 AudioDeviceState last_state = |
| 940 audio_pref_handler_->GetDeviceState(hotplug_input_nodes.top()); |
| 941 switch (last_state) { |
| 942 case AUDIO_STATE_ACTIVE: |
| 943 // This node was plugged in before and was selected as the active |
| 944 // one |
| 945 // before it was unplugged last time, switch to this device. |
| 946 SwitchToDevice(hotplug_input_nodes.top(), true); |
| 947 break; |
| 948 case AUDIO_STATE_NOT_AVAILABLE: |
| 949 // This is a new node, not plugged in before, with the highest |
| 950 // priority. Switch to this device. |
| 951 if (input_devices_pq_.top().id == hotplug_input_nodes.top().id) |
| 952 SwitchToDevice(hotplug_input_nodes.top(), true); |
| 953 break; |
| 954 case AUDIO_STATE_INACTIVE: |
| 955 // This node was NOT selected as the active one last time before it |
| 956 // got unplugged, so don't switch to it. |
| 957 default: |
| 958 break; |
| 959 } |
| 922 } | 960 } |
| 923 } | 961 } |
| 924 } | 962 } |
| 925 if (output_devices_changed && | 963 if (output_devices_changed && |
| 926 !NonActiveDeviceUnplugged(old_output_device_size, | 964 !NonActiveDeviceUnplugged(old_output_device_size, |
| 927 new_output_device_size, | 965 new_output_device_size, |
| 928 active_output_node_id_)) { | 966 active_output_node_id_)) { |
| 929 // This is really unlikely to happen because all ChromeOS devices have the | 967 // ditto input node logic. |
| 930 // internal audio output. | |
| 931 if (output_devices_pq_.empty()) { | 968 if (output_devices_pq_.empty()) { |
| 932 active_output_node_id_ = 0; | 969 active_output_node_id_ = 0; |
| 933 NotifyActiveNodeChanged(false); | 970 NotifyActiveNodeChanged(false); |
| 934 } else { | 971 } else { |
| 935 // ditto input node case. | 972 if (!active_output_node_id_ || hotplug_output_nodes.empty()) { |
| 936 if (!active_output_node_id_ || hotplug_output_nodes.empty() || | |
| 937 IsNodeInTheList(output_devices_pq_.top().id, hotplug_output_nodes)) { | |
| 938 SwitchToDevice(output_devices_pq_.top(), true); | 973 SwitchToDevice(output_devices_pq_.top(), true); |
| 974 } else { |
| 975 AudioDeviceState last_state = |
| 976 audio_pref_handler_->GetDeviceState(hotplug_output_nodes.top()); |
| 977 switch (last_state) { |
| 978 case AUDIO_STATE_ACTIVE: |
| 979 SwitchToDevice(hotplug_output_nodes.top(), true); |
| 980 break; |
| 981 case AUDIO_STATE_NOT_AVAILABLE: |
| 982 if (output_devices_pq_.top().id == hotplug_output_nodes.top().id) |
| 983 SwitchToDevice(hotplug_output_nodes.top(), true); |
| 984 break; |
| 985 case AUDIO_STATE_INACTIVE: |
| 986 default: |
| 987 break; |
| 988 } |
| 939 } | 989 } |
| 940 } | 990 } |
| 941 } | 991 } |
| 942 } | 992 } |
| 943 | 993 |
| 944 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list, | 994 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list, |
| 945 bool success) { | 995 bool success) { |
| 946 if (!success) { | 996 if (!success) { |
| 947 LOG_IF(ERROR, log_errors_) << "Failed to retrieve audio nodes data"; | 997 LOG_IF(ERROR, log_errors_) << "Failed to retrieve audio nodes data"; |
| 948 return; | 998 return; |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1043 hdmi_rediscover_grace_period_duration_in_ms_), | 1093 hdmi_rediscover_grace_period_duration_in_ms_), |
| 1044 this, &CrasAudioHandler::UpdateAudioAfterHDMIRediscoverGracePeriod); | 1094 this, &CrasAudioHandler::UpdateAudioAfterHDMIRediscoverGracePeriod); |
| 1045 } | 1095 } |
| 1046 | 1096 |
| 1047 void CrasAudioHandler::SetHDMIRediscoverGracePeriodForTesting( | 1097 void CrasAudioHandler::SetHDMIRediscoverGracePeriodForTesting( |
| 1048 int duration_in_ms) { | 1098 int duration_in_ms) { |
| 1049 hdmi_rediscover_grace_period_duration_in_ms_ = duration_in_ms; | 1099 hdmi_rediscover_grace_period_duration_in_ms_ = duration_in_ms; |
| 1050 } | 1100 } |
| 1051 | 1101 |
| 1052 } // namespace chromeos | 1102 } // namespace chromeos |
| OLD | NEW |