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, | |
403 it->second.active ? AUDIO_STATE_ACTIVE : AUDIO_STATE_INACTIVE); | |
404 } | |
401 } | 405 } |
402 | 406 |
403 void CrasAudioHandler::SetActiveInputNode(uint64_t node_id, bool notify) { | 407 void CrasAudioHandler::SetActiveInputNode(uint64_t node_id, bool notify) { |
404 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> | 408 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> |
405 SetActiveInputNode(node_id); | 409 SetActiveInputNode(node_id); |
406 if (notify) | 410 if (notify) |
407 NotifyActiveNodeChanged(true); | 411 NotifyActiveNodeChanged(true); |
412 | |
413 // Save state for all input nodes. | |
414 for (AudioDeviceMap::iterator it = audio_devices_.begin(); | |
415 it != audio_devices_.end(); ++it) { | |
416 if (!it->second.is_input) | |
417 continue; | |
418 audio_pref_handler_->SetDeviceState(it->second, | |
419 it->second.active ? AUDIO_STATE_ACTIVE : AUDIO_STATE_INACTIVE); | |
420 } | |
408 } | 421 } |
409 | 422 |
410 void CrasAudioHandler::SetVolumeGainPercentForDevice(uint64_t device_id, | 423 void CrasAudioHandler::SetVolumeGainPercentForDevice(uint64_t device_id, |
411 int value) { | 424 int value) { |
412 const AudioDevice* device = GetDeviceFromId(device_id); | 425 const AudioDevice* device = GetDeviceFromId(device_id); |
413 if (!device) | 426 if (!device) |
414 return; | 427 return; |
415 | 428 |
416 if (device->is_input) | 429 if (device->is_input) |
417 SetInputNodeGainPercent(device_id, value); | 430 SetInputNodeGainPercent(device_id, value); |
(...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
775 SetActiveInputNode(active_input_node_id_, notify); | 788 SetActiveInputNode(active_input_node_id_, notify); |
776 } else { | 789 } else { |
777 if (!ChangeActiveDevice(device, &active_output_node_id_)) | 790 if (!ChangeActiveDevice(device, &active_output_node_id_)) |
778 return; | 791 return; |
779 SetupAudioOutputState(); | 792 SetupAudioOutputState(); |
780 SetActiveOutputNode(active_output_node_id_, notify); | 793 SetActiveOutputNode(active_output_node_id_, notify); |
781 } | 794 } |
782 } | 795 } |
783 | 796 |
784 bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes, | 797 bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes, |
785 bool is_input, | 798 bool is_input, |
786 AudioNodeList* new_discovered) { | 799 AudioDevicePriorityQueue* new_discovered) { |
787 size_t num_old_devices = 0; | 800 size_t num_old_devices = 0; |
788 size_t num_new_devices = 0; | 801 size_t num_new_devices = 0; |
789 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); | 802 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
790 it != audio_devices_.end(); ++it) { | 803 it != audio_devices_.end(); ++it) { |
791 if (is_input == it->second.is_input) | 804 if (is_input == it->second.is_input) |
792 ++num_old_devices; | 805 ++num_old_devices; |
793 } | 806 } |
794 | 807 |
795 bool new_or_changed_device = false; | 808 bool new_or_changed_device = false; |
796 new_discovered->clear(); | 809 while (!new_discovered->empty()) |
810 new_discovered->pop(); | |
797 for (AudioNodeList::const_iterator it = new_nodes.begin(); | 811 for (AudioNodeList::const_iterator it = new_nodes.begin(); |
798 it != new_nodes.end(); ++it) { | 812 it != new_nodes.end(); ++it) { |
799 if (is_input == it->is_input) { | 813 if (is_input == it->is_input) { |
800 ++num_new_devices; | 814 ++num_new_devices; |
801 // Look to see if the new device not in the old device list. | 815 // Look to see if the new device not in the old device list. |
802 AudioDevice device(*it); | 816 AudioDevice device(*it); |
803 DeviceStatus status = CheckDeviceStatus(device); | 817 DeviceStatus status = CheckDeviceStatus(device); |
804 if (status == NEW_DEVICE) | 818 if (status == NEW_DEVICE) |
805 new_discovered->push_back(*it); | 819 new_discovered->push(device); |
806 if (status == NEW_DEVICE || status == CHANGED_DEVICE) { | 820 if (status == NEW_DEVICE || status == CHANGED_DEVICE) { |
807 new_or_changed_device = true; | 821 new_or_changed_device = true; |
808 } | 822 } |
809 } | 823 } |
810 } | 824 } |
811 return new_or_changed_device || (num_old_devices != num_new_devices); | 825 return new_or_changed_device || (num_old_devices != num_new_devices); |
812 } | 826 } |
813 | 827 |
814 CrasAudioHandler::DeviceStatus CrasAudioHandler::CheckDeviceStatus( | 828 CrasAudioHandler::DeviceStatus CrasAudioHandler::CheckDeviceStatus( |
815 const AudioDevice& device) { | 829 const AudioDevice& device) { |
(...skipping 25 matching lines...) Expand all Loading... | |
841 size_t old_output_device_size = 0; | 855 size_t old_output_device_size = 0; |
842 size_t old_input_device_size = 0; | 856 size_t old_input_device_size = 0; |
843 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); | 857 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
844 it != audio_devices_.end(); ++it) { | 858 it != audio_devices_.end(); ++it) { |
845 if (it->second.is_input) | 859 if (it->second.is_input) |
846 ++old_input_device_size; | 860 ++old_input_device_size; |
847 else | 861 else |
848 ++old_output_device_size; | 862 ++old_output_device_size; |
849 } | 863 } |
850 | 864 |
851 AudioNodeList hotplug_output_nodes; | 865 AudioDevicePriorityQueue hotplug_output_nodes; |
852 AudioNodeList hotplug_input_nodes; | 866 AudioDevicePriorityQueue hotplug_input_nodes; |
853 bool output_devices_changed = | 867 bool output_devices_changed = |
854 HasDeviceChange(nodes, false, &hotplug_output_nodes); | 868 HasDeviceChange(nodes, false, &hotplug_output_nodes); |
855 bool input_devices_changed = | 869 bool input_devices_changed = |
856 HasDeviceChange(nodes, true, &hotplug_input_nodes); | 870 HasDeviceChange(nodes, true, &hotplug_input_nodes); |
857 audio_devices_.clear(); | 871 audio_devices_.clear(); |
858 has_alternative_input_ = false; | 872 has_alternative_input_ = false; |
859 has_alternative_output_ = false; | 873 has_alternative_output_ = false; |
860 | 874 |
861 while (!input_devices_pq_.empty()) | 875 while (!input_devices_pq_.empty()) |
862 input_devices_pq_.pop(); | 876 input_devices_pq_.pop(); |
(...skipping 30 matching lines...) Expand all Loading... | |
893 // or changed to inactive by cras, reset active_output_node_id_. | 907 // or changed to inactive by cras, reset active_output_node_id_. |
894 // See crbug.com/478968. | 908 // See crbug.com/478968. |
895 const AudioDevice* active_output = GetDeviceFromId(active_output_node_id_); | 909 const AudioDevice* active_output = GetDeviceFromId(active_output_node_id_); |
896 if (!active_output || !active_output->active) | 910 if (!active_output || !active_output->active) |
897 active_output_node_id_ = 0; | 911 active_output_node_id_ = 0; |
898 const AudioDevice* active_input = GetDeviceFromId(active_input_node_id_); | 912 const AudioDevice* active_input = GetDeviceFromId(active_input_node_id_); |
899 if (!active_input || !active_input->active) | 913 if (!active_input || !active_input->active) |
900 active_input_node_id_ = 0; | 914 active_input_node_id_ = 0; |
901 | 915 |
902 // If audio nodes change is caused by unplugging some non-active audio | 916 // If audio nodes change is caused by unplugging some non-active audio |
903 // devices, the previously set active audio device will stay active. | 917 // 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 && | 918 if (input_devices_changed && |
906 !NonActiveDeviceUnplugged(old_input_device_size, | 919 !NonActiveDeviceUnplugged(old_input_device_size, |
907 new_input_device_size, | 920 new_input_device_size, |
908 active_input_node_id_)) { | 921 active_input_node_id_)) { |
909 // Some devices like chromeboxes don't have the internal audio input. In | 922 // Some devices like chromeboxes don't have the internal audio input. In |
910 // that case the active input node id should be reset. | 923 // that case the active input node id should be reset. |
911 if (input_devices_pq_.empty()) { | 924 if (input_devices_pq_.empty()) { |
912 active_input_node_id_ = 0; | 925 active_input_node_id_ = 0; |
913 NotifyActiveNodeChanged(true); | 926 NotifyActiveNodeChanged(true); |
914 } else { | 927 } else { |
915 // If user has hot plugged a new node, we should change to the active | 928 // 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, | 929 // the active node by their priorities. |
917 // we should keep the existing active node chosen by user. | 930 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); | 931 SwitchToDevice(input_devices_pq_.top(), true); |
932 } else { | |
933 // If user has hot plugged any input nodes, look at the one with highest | |
934 // priority (normally, there is only one hot plugged input node), and | |
935 // consider switch to it depend on its last state stored in preference. | |
936 AudioDeviceState last_state = | |
937 audio_pref_handler_->GetDeviceState(hotplug_input_nodes.top()); | |
938 switch (last_state) { | |
939 case AUDIO_STATE_ACTIVE: | |
Daniel Erat
2016/01/07 17:31:12
this should be indented two spaces beyond the prev
hychao
2016/01/11 07:02:32
Done.
| |
940 // This node was plugged in before and was selected as the active one | |
941 // before it was unplugged last time, switch to this device. | |
942 SwitchToDevice(hotplug_input_nodes.top(), true); | |
943 break; | |
944 case AUDIO_STATE_NOT_AVAILABLE: | |
945 // This is a new node, not plugged in before, with the highest | |
946 // priority. Switch to this device. | |
947 if (input_devices_pq_.top().id == hotplug_input_nodes.top().id) | |
948 SwitchToDevice(hotplug_input_nodes.top(), true); | |
949 break; | |
950 case AUDIO_STATE_INACTIVE: | |
951 // This node was NOT selected as the active one last time before it | |
952 // got unplugged, so don't switch to it. | |
953 default: | |
954 break; | |
955 } | |
922 } | 956 } |
923 } | 957 } |
924 } | 958 } |
925 if (output_devices_changed && | 959 if (output_devices_changed && |
926 !NonActiveDeviceUnplugged(old_output_device_size, | 960 !NonActiveDeviceUnplugged(old_output_device_size, |
927 new_output_device_size, | 961 new_output_device_size, |
928 active_output_node_id_)) { | 962 active_output_node_id_)) { |
929 // This is really unlikely to happen because all ChromeOS devices have the | 963 // ditto input node logic. |
930 // internal audio output. | |
931 if (output_devices_pq_.empty()) { | 964 if (output_devices_pq_.empty()) { |
932 active_output_node_id_ = 0; | 965 active_output_node_id_ = 0; |
933 NotifyActiveNodeChanged(false); | 966 NotifyActiveNodeChanged(false); |
934 } else { | 967 } else { |
935 // ditto input node case. | 968 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); | 969 SwitchToDevice(output_devices_pq_.top(), true); |
970 } else { | |
971 AudioDeviceState last_state = | |
972 audio_pref_handler_->GetDeviceState(hotplug_output_nodes.top()); | |
973 switch (last_state) { | |
974 case AUDIO_STATE_ACTIVE: | |
Daniel Erat
2016/01/07 17:31:12
same here
hychao
2016/01/11 07:02:32
Done.
| |
975 SwitchToDevice(hotplug_output_nodes.top(), true); | |
976 break; | |
977 case AUDIO_STATE_NOT_AVAILABLE: | |
978 if (output_devices_pq_.top().id == hotplug_output_nodes.top().id) | |
979 SwitchToDevice(hotplug_output_nodes.top(), true); | |
980 break; | |
981 case AUDIO_STATE_INACTIVE: | |
982 default: | |
983 break; | |
984 } | |
939 } | 985 } |
940 } | 986 } |
941 } | 987 } |
942 } | 988 } |
943 | 989 |
944 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list, | 990 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list, |
945 bool success) { | 991 bool success) { |
946 if (!success) { | 992 if (!success) { |
947 LOG_IF(ERROR, log_errors_) << "Failed to retrieve audio nodes data"; | 993 LOG_IF(ERROR, log_errors_) << "Failed to retrieve audio nodes data"; |
948 return; | 994 return; |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1043 hdmi_rediscover_grace_period_duration_in_ms_), | 1089 hdmi_rediscover_grace_period_duration_in_ms_), |
1044 this, &CrasAudioHandler::UpdateAudioAfterHDMIRediscoverGracePeriod); | 1090 this, &CrasAudioHandler::UpdateAudioAfterHDMIRediscoverGracePeriod); |
1045 } | 1091 } |
1046 | 1092 |
1047 void CrasAudioHandler::SetHDMIRediscoverGracePeriodForTesting( | 1093 void CrasAudioHandler::SetHDMIRediscoverGracePeriodForTesting( |
1048 int duration_in_ms) { | 1094 int duration_in_ms) { |
1049 hdmi_rediscover_grace_period_duration_in_ms_ = duration_in_ms; | 1095 hdmi_rediscover_grace_period_duration_in_ms_ = duration_in_ms; |
1050 } | 1096 } |
1051 | 1097 |
1052 } // namespace chromeos | 1098 } // namespace chromeos |
OLD | NEW |