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 <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 25 matching lines...) Expand all Loading... | |
36 bool IsSameAudioDevice(const AudioDevice& a, const AudioDevice& b) { | 36 bool IsSameAudioDevice(const AudioDevice& a, const AudioDevice& b) { |
37 return a.id == b.id && a.is_input == b.is_input && a.type == b.type | 37 return a.id == b.id && a.is_input == b.is_input && a.type == b.type |
38 && a.device_name == b.device_name; | 38 && a.device_name == b.device_name; |
39 } | 39 } |
40 | 40 |
41 bool IsInNodeList(uint64_t node_id, | 41 bool IsInNodeList(uint64_t node_id, |
42 const CrasAudioHandler::NodeIdList& id_list) { | 42 const CrasAudioHandler::NodeIdList& id_list) { |
43 return std::find(id_list.begin(), id_list.end(), node_id) != id_list.end(); | 43 return std::find(id_list.begin(), id_list.end(), node_id) != id_list.end(); |
44 } | 44 } |
45 | 45 |
46 bool IsNodeInTheList(uint64_t node_id, const AudioNodeList& node_list) { | |
47 for (size_t i = 0; i < node_list.size(); ++i) { | |
48 if (node_id == node_list[i].id) | |
49 return true; | |
50 } | |
51 return false; | |
52 } | |
53 | |
54 } // namespace | 46 } // namespace |
55 | 47 |
56 CrasAudioHandler::AudioObserver::AudioObserver() { | 48 CrasAudioHandler::AudioObserver::AudioObserver() { |
57 } | 49 } |
58 | 50 |
59 CrasAudioHandler::AudioObserver::~AudioObserver() { | 51 CrasAudioHandler::AudioObserver::~AudioObserver() { |
60 } | 52 } |
61 | 53 |
62 void CrasAudioHandler::AudioObserver::OnOutputNodeVolumeChanged( | 54 void CrasAudioHandler::AudioObserver::OnOutputNodeVolumeChanged( |
63 uint64_t /* node_id */, | 55 uint64_t /* node_id */, |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
238 // If there is no primary active device, set |node_id| to primary active node. | 230 // If there is no primary active device, set |node_id| to primary active node. |
239 if ((device->is_input && !active_input_node_id_) || | 231 if ((device->is_input && !active_input_node_id_) || |
240 (!device->is_input && !active_output_node_id_)) { | 232 (!device->is_input && !active_output_node_id_)) { |
241 SwitchToDevice(*device, notify); | 233 SwitchToDevice(*device, notify); |
242 return; | 234 return; |
243 } | 235 } |
244 | 236 |
245 AddAdditionalActiveNode(node_id, notify); | 237 AddAdditionalActiveNode(node_id, notify); |
246 } | 238 } |
247 | 239 |
248 void CrasAudioHandler::ChangeActiveNodes(const NodeIdList& new_active_ids) { | 240 void CrasAudioHandler::ChangeActiveNodes(const NodeIdList& new_active_ids) { |
jennyz
2015/12/17 22:50:21
What about multiple active audio nodes case?
hychao
2015/12/29 10:57:25
actually I forgot about the multiple active node p
jennyz
2016/01/05 23:46:55
Yes, it makes sense to exclude the new active node
hychao
2016/01/06 06:34:12
Done.
| |
249 // Flags for whether there are input or output nodes passed in from | 241 // Flags for whether there are input or output nodes passed in from |
250 // |new_active_ids|. If there are no input nodes passed in, we will not | 242 // |new_active_ids|. If there are no input nodes passed in, we will not |
251 // make any change for input nodes; same for the output nodes. | 243 // make any change for input nodes; same for the output nodes. |
252 bool request_input_change = false; | 244 bool request_input_change = false; |
253 bool request_output_change = false; | 245 bool request_output_change = false; |
254 | 246 |
255 // Flags for whether we will actually change active status of input | 247 // Flags for whether we will actually change active status of input |
256 // or output nodes. | 248 // or output nodes. |
257 bool make_input_change = false; | 249 bool make_input_change = false; |
258 bool make_output_change = false; | 250 bool make_output_change = false; |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
388 SetInputMuteInternal(mute_on); | 380 SetInputMuteInternal(mute_on); |
389 FOR_EACH_OBSERVER(AudioObserver, observers_, | 381 FOR_EACH_OBSERVER(AudioObserver, observers_, |
390 OnInputMuteChanged(input_mute_on_)); | 382 OnInputMuteChanged(input_mute_on_)); |
391 } | 383 } |
392 | 384 |
393 void CrasAudioHandler::SetActiveOutputNode(uint64_t node_id, bool notify) { | 385 void CrasAudioHandler::SetActiveOutputNode(uint64_t node_id, bool notify) { |
394 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> | 386 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> |
395 SetActiveOutputNode(node_id); | 387 SetActiveOutputNode(node_id); |
396 if (notify) | 388 if (notify) |
397 NotifyActiveNodeChanged(false); | 389 NotifyActiveNodeChanged(false); |
390 | |
391 // Save state for all output nodes. | |
392 for (AudioDeviceMap::iterator it = audio_devices_.begin(); | |
393 it != audio_devices_.end(); ++it) { | |
394 if (it->second.is_input) | |
395 continue; | |
396 audio_pref_handler_->SetDeviceState(it->second, | |
397 it->second.active ? AUDIO_STATE_ACTIVE : AUDIO_STATE_INACTIVE); | |
398 } | |
398 } | 399 } |
399 | 400 |
400 void CrasAudioHandler::SetActiveInputNode(uint64_t node_id, bool notify) { | 401 void CrasAudioHandler::SetActiveInputNode(uint64_t node_id, bool notify) { |
401 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> | 402 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> |
402 SetActiveInputNode(node_id); | 403 SetActiveInputNode(node_id); |
403 if (notify) | 404 if (notify) |
404 NotifyActiveNodeChanged(true); | 405 NotifyActiveNodeChanged(true); |
406 | |
407 // Save state for all input nodes. | |
408 for (AudioDeviceMap::iterator it = audio_devices_.begin(); | |
409 it != audio_devices_.end(); ++it) { | |
410 if (!it->second.is_input) | |
411 continue; | |
412 audio_pref_handler_->SetDeviceState(it->second, | |
413 it->second.active ? AUDIO_STATE_ACTIVE : AUDIO_STATE_INACTIVE); | |
414 } | |
405 } | 415 } |
406 | 416 |
407 void CrasAudioHandler::SetVolumeGainPercentForDevice(uint64_t device_id, | 417 void CrasAudioHandler::SetVolumeGainPercentForDevice(uint64_t device_id, |
408 int value) { | 418 int value) { |
409 const AudioDevice* device = GetDeviceFromId(device_id); | 419 const AudioDevice* device = GetDeviceFromId(device_id); |
410 if (!device) | 420 if (!device) |
411 return; | 421 return; |
412 | 422 |
413 if (device->is_input) | 423 if (device->is_input) |
414 SetInputNodeGainPercent(device_id, value); | 424 SetInputNodeGainPercent(device_id, value); |
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
773 } else { | 783 } else { |
774 if (!ChangeActiveDevice(device, &active_output_node_id_)) | 784 if (!ChangeActiveDevice(device, &active_output_node_id_)) |
775 return; | 785 return; |
776 SetupAudioOutputState(); | 786 SetupAudioOutputState(); |
777 SetActiveOutputNode(active_output_node_id_, notify); | 787 SetActiveOutputNode(active_output_node_id_, notify); |
778 } | 788 } |
779 } | 789 } |
780 | 790 |
781 bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes, | 791 bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes, |
782 bool is_input, | 792 bool is_input, |
783 AudioNodeList* new_discovered) { | 793 AudioDevicePriorityQueue* new_discovered) { |
784 size_t num_old_devices = 0; | 794 size_t num_old_devices = 0; |
785 size_t num_new_devices = 0; | 795 size_t num_new_devices = 0; |
786 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); | 796 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
787 it != audio_devices_.end(); ++it) { | 797 it != audio_devices_.end(); ++it) { |
788 if (is_input == it->second.is_input) | 798 if (is_input == it->second.is_input) |
789 ++num_old_devices; | 799 ++num_old_devices; |
790 } | 800 } |
791 | 801 |
792 bool new_or_changed_device = false; | 802 bool new_or_changed_device = false; |
793 new_discovered->clear(); | 803 while (!new_discovered->empty()) |
804 new_discovered->pop(); | |
794 for (AudioNodeList::const_iterator it = new_nodes.begin(); | 805 for (AudioNodeList::const_iterator it = new_nodes.begin(); |
795 it != new_nodes.end(); ++it) { | 806 it != new_nodes.end(); ++it) { |
796 if (is_input == it->is_input) { | 807 if (is_input == it->is_input) { |
797 ++num_new_devices; | 808 ++num_new_devices; |
798 // Look to see if the new device not in the old device list. | 809 // Look to see if the new device not in the old device list. |
799 AudioDevice device(*it); | 810 AudioDevice device(*it); |
800 DeviceStatus status = CheckDeviceStatus(device); | 811 DeviceStatus status = CheckDeviceStatus(device); |
801 if (status == NEW_DEVICE) | 812 if (status == NEW_DEVICE) |
802 new_discovered->push_back(*it); | 813 new_discovered->push(device); |
803 if (status == NEW_DEVICE || status == CHANGED_DEVICE) { | 814 if (status == NEW_DEVICE || status == CHANGED_DEVICE) { |
804 new_or_changed_device = true; | 815 new_or_changed_device = true; |
805 } | 816 } |
806 } | 817 } |
807 } | 818 } |
808 return new_or_changed_device || (num_old_devices != num_new_devices); | 819 return new_or_changed_device || (num_old_devices != num_new_devices); |
809 } | 820 } |
810 | 821 |
811 CrasAudioHandler::DeviceStatus CrasAudioHandler::CheckDeviceStatus( | 822 CrasAudioHandler::DeviceStatus CrasAudioHandler::CheckDeviceStatus( |
812 const AudioDevice& device) { | 823 const AudioDevice& device) { |
(...skipping 25 matching lines...) Expand all Loading... | |
838 size_t old_output_device_size = 0; | 849 size_t old_output_device_size = 0; |
839 size_t old_input_device_size = 0; | 850 size_t old_input_device_size = 0; |
840 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); | 851 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
841 it != audio_devices_.end(); ++it) { | 852 it != audio_devices_.end(); ++it) { |
842 if (it->second.is_input) | 853 if (it->second.is_input) |
843 ++old_input_device_size; | 854 ++old_input_device_size; |
844 else | 855 else |
845 ++old_output_device_size; | 856 ++old_output_device_size; |
846 } | 857 } |
847 | 858 |
848 AudioNodeList hotplug_output_nodes; | 859 AudioDevicePriorityQueue hotplug_output_nodes; |
849 AudioNodeList hotplug_input_nodes; | 860 AudioDevicePriorityQueue hotplug_input_nodes; |
850 bool output_devices_changed = | 861 bool output_devices_changed = |
851 HasDeviceChange(nodes, false, &hotplug_output_nodes); | 862 HasDeviceChange(nodes, false, &hotplug_output_nodes); |
852 bool input_devices_changed = | 863 bool input_devices_changed = |
853 HasDeviceChange(nodes, true, &hotplug_input_nodes); | 864 HasDeviceChange(nodes, true, &hotplug_input_nodes); |
854 audio_devices_.clear(); | 865 audio_devices_.clear(); |
855 has_alternative_input_ = false; | 866 has_alternative_input_ = false; |
856 has_alternative_output_ = false; | 867 has_alternative_output_ = false; |
857 | 868 |
858 while (!input_devices_pq_.empty()) | 869 while (!input_devices_pq_.empty()) |
859 input_devices_pq_.pop(); | 870 input_devices_pq_.pop(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
891 // See crbug.com/478968. | 902 // See crbug.com/478968. |
892 const AudioDevice* active_output = GetDeviceFromId(active_output_node_id_); | 903 const AudioDevice* active_output = GetDeviceFromId(active_output_node_id_); |
893 if (!active_output || !active_output->active) | 904 if (!active_output || !active_output->active) |
894 active_output_node_id_ = 0; | 905 active_output_node_id_ = 0; |
895 const AudioDevice* active_input = GetDeviceFromId(active_input_node_id_); | 906 const AudioDevice* active_input = GetDeviceFromId(active_input_node_id_); |
896 if (!active_input || !active_input->active) | 907 if (!active_input || !active_input->active) |
897 active_input_node_id_ = 0; | 908 active_input_node_id_ = 0; |
898 | 909 |
899 // If audio nodes change is caused by unplugging some non-active audio | 910 // If audio nodes change is caused by unplugging some non-active audio |
900 // devices, the previously set active audio device will stay active. | 911 // devices, the previously set active audio device will stay active. |
901 // Otherwise, switch to a new active audio device according to their priority. | 912 // Otherwise, switch to a new active audio device according to their priority. |
jennyz
2015/12/17 22:50:21
The comments for how the active audio device is se
hychao
2015/12/29 10:57:25
Done.
| |
902 if (input_devices_changed && | 913 if (input_devices_changed && |
903 !NonActiveDeviceUnplugged(old_input_device_size, | 914 !NonActiveDeviceUnplugged(old_input_device_size, |
904 new_input_device_size, | 915 new_input_device_size, |
905 active_input_node_id_)) { | 916 active_input_node_id_)) { |
906 // Some devices like chromeboxes don't have the internal audio input. In | 917 // Some devices like chromeboxes don't have the internal audio input. In |
907 // that case the active input node id should be reset. | 918 // that case the active input node id should be reset. |
908 if (input_devices_pq_.empty()) { | 919 if (input_devices_pq_.empty()) { |
909 active_input_node_id_ = 0; | 920 active_input_node_id_ = 0; |
910 NotifyActiveNodeChanged(true); | 921 NotifyActiveNodeChanged(true); |
911 } else { | 922 } else { |
912 // If user has hot plugged a new node, we should change to the active | 923 // If user has hot plugged a new node, we should change to the active |
913 // device to the new node if it has the highest priority; otherwise, | 924 // device to the new node if (1) it has the highest priority; or (2) |
914 // we should keep the existing active node chosen by user. | 925 // the last state before it hot plugged was active; otherwise, we should |
926 // keep the existing active node chosen by user. | |
915 // For all other cases, we will choose the node with highest priority. | 927 // For all other cases, we will choose the node with highest priority. |
jennyz
2015/12/17 22:50:21
How about change this as:
If there is no current a
hychao
2015/12/29 10:57:25
Done.
| |
916 if (!active_input_node_id_ || hotplug_input_nodes.empty() || | 928 if (!active_input_node_id_ || hotplug_input_nodes.empty()) { |
917 IsNodeInTheList(input_devices_pq_.top().id, hotplug_input_nodes)) { | |
918 SwitchToDevice(input_devices_pq_.top(), true); | 929 SwitchToDevice(input_devices_pq_.top(), true); |
930 } else { | |
jennyz
2015/12/17 22:50:21
How about comment like this:
If user has hot plugg
hychao
2015/12/29 10:57:25
Thanks for the suggestion. I broke down and moved
| |
931 AudioDeviceState last_state = | |
932 audio_pref_handler_->GetDeviceState(hotplug_input_nodes.top()); | |
933 switch (last_state) { | |
934 case AUDIO_STATE_ACTIVE: | |
935 SwitchToDevice(hotplug_input_nodes.top(), true); | |
936 break; | |
937 case AUDIO_STATE_NOT_AVAILABLE: | |
jennyz
2015/12/17 22:50:21
This is the case if the device is new, not plugged
hychao
2015/12/29 10:57:25
Done.
| |
938 if (input_devices_pq_.top().id == hotplug_input_nodes.top().id) | |
939 SwitchToDevice(hotplug_input_nodes.top(), true); | |
940 break; | |
941 case AUDIO_STATE_INACTIVE: | |
jennyz
2015/12/17 22:50:21
No need to add this line, it should fall into defa
hychao
2015/12/29 10:57:25
Thanks for reminding. I think its useful to keep t
| |
942 default: | |
943 break; | |
944 } | |
919 } | 945 } |
920 } | 946 } |
921 } | 947 } |
922 if (output_devices_changed && | 948 if (output_devices_changed && |
923 !NonActiveDeviceUnplugged(old_output_device_size, | 949 !NonActiveDeviceUnplugged(old_output_device_size, |
924 new_output_device_size, | 950 new_output_device_size, |
925 active_output_node_id_)) { | 951 active_output_node_id_)) { |
926 // This is really unlikely to happen because all ChromeOS devices have the | 952 // This is really unlikely to happen because all ChromeOS devices have the |
927 // internal audio output. | 953 // internal audio output. |
jennyz
2015/12/17 22:50:21
gitto input nodes logic.
hychao
2015/12/29 10:57:25
Done.
| |
928 if (output_devices_pq_.empty()) { | 954 if (output_devices_pq_.empty()) { |
929 active_output_node_id_ = 0; | 955 active_output_node_id_ = 0; |
930 NotifyActiveNodeChanged(false); | 956 NotifyActiveNodeChanged(false); |
931 } else { | 957 } else { |
932 // ditto input node case. | 958 // ditto input node case. |
933 if (!active_output_node_id_ || hotplug_output_nodes.empty() || | 959 if (!active_output_node_id_ || hotplug_output_nodes.empty()) { |
934 IsNodeInTheList(output_devices_pq_.top().id, hotplug_output_nodes)) { | |
935 SwitchToDevice(output_devices_pq_.top(), true); | 960 SwitchToDevice(output_devices_pq_.top(), true); |
961 } else { | |
962 AudioDeviceState last_state = | |
963 audio_pref_handler_->GetDeviceState(hotplug_output_nodes.top()); | |
964 switch (last_state) { | |
965 case AUDIO_STATE_ACTIVE: | |
966 SwitchToDevice(hotplug_output_nodes.top(), true); | |
967 break; | |
968 case AUDIO_STATE_NOT_AVAILABLE: | |
969 if (output_devices_pq_.top().id == hotplug_output_nodes.top().id) | |
970 SwitchToDevice(hotplug_output_nodes.top(), true); | |
971 break; | |
972 case AUDIO_STATE_INACTIVE: | |
jennyz
2015/12/17 22:50:21
ditto
hychao
2015/12/29 10:57:25
Although the comments are not copied over, I keep
| |
973 default: | |
974 break; | |
975 } | |
936 } | 976 } |
937 } | 977 } |
938 } | 978 } |
939 } | 979 } |
940 | 980 |
941 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list, | 981 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list, |
942 bool success) { | 982 bool success) { |
943 if (!success) { | 983 if (!success) { |
944 LOG_IF(ERROR, log_errors_) << "Failed to retrieve audio nodes data"; | 984 LOG_IF(ERROR, log_errors_) << "Failed to retrieve audio nodes data"; |
945 return; | 985 return; |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1040 hdmi_rediscover_grace_period_duration_in_ms_), | 1080 hdmi_rediscover_grace_period_duration_in_ms_), |
1041 this, &CrasAudioHandler::UpdateAudioAfterHDMIRediscoverGracePeriod); | 1081 this, &CrasAudioHandler::UpdateAudioAfterHDMIRediscoverGracePeriod); |
1042 } | 1082 } |
1043 | 1083 |
1044 void CrasAudioHandler::SetHDMIRediscoverGracePeriodForTesting( | 1084 void CrasAudioHandler::SetHDMIRediscoverGracePeriodForTesting( |
1045 int duration_in_ms) { | 1085 int duration_in_ms) { |
1046 hdmi_rediscover_grace_period_duration_in_ms_ = duration_in_ms; | 1086 hdmi_rediscover_grace_period_duration_in_ms_ = duration_in_ms; |
1047 } | 1087 } |
1048 | 1088 |
1049 } // namespace chromeos | 1089 } // namespace chromeos |
OLD | NEW |