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 21 matching lines...) Expand all Loading... |
32 | 32 |
33 bool IsSameAudioDevice(const AudioDevice& a, const AudioDevice& b) { | 33 bool IsSameAudioDevice(const AudioDevice& a, const AudioDevice& b) { |
34 return a.id == b.id && a.is_input == b.is_input && a.type == b.type | 34 return a.id == b.id && a.is_input == b.is_input && a.type == b.type |
35 && a.device_name == b.device_name; | 35 && a.device_name == b.device_name; |
36 } | 36 } |
37 | 37 |
38 bool IsInNodeList(uint64 node_id, const CrasAudioHandler::NodeIdList& id_list) { | 38 bool IsInNodeList(uint64 node_id, const CrasAudioHandler::NodeIdList& id_list) { |
39 return std::find(id_list.begin(), id_list.end(), node_id) != id_list.end(); | 39 return std::find(id_list.begin(), id_list.end(), node_id) != id_list.end(); |
40 } | 40 } |
41 | 41 |
| 42 bool IsNodeInTheList(uint64 node_id, const AudioNodeList& node_list) { |
| 43 for (size_t i = 0; i < node_list.size(); ++i) { |
| 44 if (node_id == node_list[i].id) |
| 45 return true; |
| 46 } |
| 47 return false; |
| 48 } |
| 49 |
42 } // namespace | 50 } // namespace |
43 | 51 |
44 CrasAudioHandler::AudioObserver::AudioObserver() { | 52 CrasAudioHandler::AudioObserver::AudioObserver() { |
45 } | 53 } |
46 | 54 |
47 CrasAudioHandler::AudioObserver::~AudioObserver() { | 55 CrasAudioHandler::AudioObserver::~AudioObserver() { |
48 } | 56 } |
49 | 57 |
50 void CrasAudioHandler::AudioObserver::OnOutputVolumeChanged() { | 58 void CrasAudioHandler::AudioObserver::OnOutputVolumeChanged() { |
51 } | 59 } |
(...skipping 669 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
721 SetActiveInputNode(active_input_node_id_, notify); | 729 SetActiveInputNode(active_input_node_id_, notify); |
722 } else { | 730 } else { |
723 if (!ChangeActiveDevice(device, &active_output_node_id_)) | 731 if (!ChangeActiveDevice(device, &active_output_node_id_)) |
724 return; | 732 return; |
725 SetupAudioOutputState(); | 733 SetupAudioOutputState(); |
726 SetActiveOutputNode(active_output_node_id_, notify); | 734 SetActiveOutputNode(active_output_node_id_, notify); |
727 } | 735 } |
728 } | 736 } |
729 | 737 |
730 bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes, | 738 bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes, |
731 bool is_input) { | 739 bool is_input, |
| 740 AudioNodeList* new_discovered) { |
732 size_t num_old_devices = 0; | 741 size_t num_old_devices = 0; |
733 size_t num_new_devices = 0; | 742 size_t num_new_devices = 0; |
734 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); | 743 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
735 it != audio_devices_.end(); ++it) { | 744 it != audio_devices_.end(); ++it) { |
736 if (is_input == it->second.is_input) | 745 if (is_input == it->second.is_input) |
737 ++num_old_devices; | 746 ++num_old_devices; |
738 } | 747 } |
739 | 748 |
| 749 bool new_or_changed_device = false; |
| 750 new_discovered->clear(); |
740 for (AudioNodeList::const_iterator it = new_nodes.begin(); | 751 for (AudioNodeList::const_iterator it = new_nodes.begin(); |
741 it != new_nodes.end(); ++it) { | 752 it != new_nodes.end(); ++it) { |
742 if (is_input == it->is_input) { | 753 if (is_input == it->is_input) { |
743 ++num_new_devices; | 754 ++num_new_devices; |
744 // Look to see if the new device not in the old device list. | 755 // Look to see if the new device not in the old device list. |
745 AudioDevice device(*it); | 756 AudioDevice device(*it); |
746 if (FoundNewOrChangedDevice(device)) | 757 DeviceStatus status = CheckDeviceStatus(device); |
747 return true; | 758 if (status == NEW_DEVICE) |
| 759 new_discovered->push_back(*it); |
| 760 if (status == NEW_DEVICE || status == CHANGED_DEVICE) { |
| 761 new_or_changed_device = true; |
| 762 } |
748 } | 763 } |
749 } | 764 } |
750 return num_old_devices != num_new_devices; | 765 return new_or_changed_device || (num_old_devices != num_new_devices); |
751 } | 766 } |
752 | 767 |
753 bool CrasAudioHandler::FoundNewOrChangedDevice(const AudioDevice& device) { | 768 CrasAudioHandler::DeviceStatus CrasAudioHandler::CheckDeviceStatus( |
| 769 const AudioDevice& device) { |
754 const AudioDevice* device_found = GetDeviceFromId(device.id); | 770 const AudioDevice* device_found = GetDeviceFromId(device.id); |
755 if (!device_found) | 771 if (!device_found) |
756 return true; | 772 return NEW_DEVICE; |
757 | 773 |
758 if (!IsSameAudioDevice(device, *device_found)) { | 774 if (!IsSameAudioDevice(device, *device_found)) { |
759 LOG(WARNING) << "Different Audio devices with same id:" | 775 LOG(WARNING) << "Different Audio devices with same id:" |
760 << " new device: " << device.ToString() | 776 << " new device: " << device.ToString() |
761 << " old device: " << device_found->ToString(); | 777 << " old device: " << device_found->ToString(); |
762 return true; | 778 return CHANGED_DEVICE; |
763 } else if (device.active != device_found->active) { | 779 } else if (device.active != device_found->active) { |
764 return true; | 780 return CHANGED_DEVICE; |
765 } | 781 } |
766 | 782 |
767 return false; | 783 return OLD_DEVICE; |
768 } | 784 } |
769 | 785 |
770 void CrasAudioHandler::NotifyActiveNodeChanged(bool is_input) { | 786 void CrasAudioHandler::NotifyActiveNodeChanged(bool is_input) { |
771 if (is_input) | 787 if (is_input) |
772 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveInputNodeChanged()); | 788 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveInputNodeChanged()); |
773 else | 789 else |
774 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveOutputNodeChanged()); | 790 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveOutputNodeChanged()); |
775 } | 791 } |
776 | 792 |
777 void CrasAudioHandler::UpdateDevicesAndSwitchActive( | 793 void CrasAudioHandler::UpdateDevicesAndSwitchActive( |
778 const AudioNodeList& nodes) { | 794 const AudioNodeList& nodes) { |
779 size_t old_output_device_size = 0; | 795 size_t old_output_device_size = 0; |
780 size_t old_input_device_size = 0; | 796 size_t old_input_device_size = 0; |
781 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); | 797 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
782 it != audio_devices_.end(); ++it) { | 798 it != audio_devices_.end(); ++it) { |
783 if (it->second.is_input) | 799 if (it->second.is_input) |
784 ++old_input_device_size; | 800 ++old_input_device_size; |
785 else | 801 else |
786 ++old_output_device_size; | 802 ++old_output_device_size; |
787 } | 803 } |
788 | 804 |
789 bool output_devices_changed = HasDeviceChange(nodes, false); | 805 AudioNodeList hotplug_output_nodes; |
790 bool input_devices_changed = HasDeviceChange(nodes, true); | 806 AudioNodeList hotplug_input_nodes; |
| 807 bool output_devices_changed = |
| 808 HasDeviceChange(nodes, false, &hotplug_output_nodes); |
| 809 bool input_devices_changed = |
| 810 HasDeviceChange(nodes, true, &hotplug_input_nodes); |
791 audio_devices_.clear(); | 811 audio_devices_.clear(); |
792 has_alternative_input_ = false; | 812 has_alternative_input_ = false; |
793 has_alternative_output_ = false; | 813 has_alternative_output_ = false; |
794 | 814 |
795 while (!input_devices_pq_.empty()) | 815 while (!input_devices_pq_.empty()) |
796 input_devices_pq_.pop(); | 816 input_devices_pq_.pop(); |
797 while (!output_devices_pq_.empty()) | 817 while (!output_devices_pq_.empty()) |
798 output_devices_pq_.pop(); | 818 output_devices_pq_.pop(); |
799 | 819 |
800 size_t new_output_device_size = 0; | 820 size_t new_output_device_size = 0; |
(...skipping 15 matching lines...) Expand all Loading... |
816 | 836 |
817 if (device.is_input) { | 837 if (device.is_input) { |
818 input_devices_pq_.push(device); | 838 input_devices_pq_.push(device); |
819 ++new_input_device_size; | 839 ++new_input_device_size; |
820 } else { | 840 } else { |
821 output_devices_pq_.push(device); | 841 output_devices_pq_.push(device); |
822 ++new_output_device_size; | 842 ++new_output_device_size; |
823 } | 843 } |
824 } | 844 } |
825 | 845 |
| 846 // If the previous active device is removed from the new node list, |
| 847 // reset active_output_node_id_. |
| 848 if (!GetDeviceFromId(active_output_node_id_)) |
| 849 active_output_node_id_ = 0; |
| 850 if (!GetDeviceFromId(active_input_node_id_)) |
| 851 active_input_node_id_ = 0; |
| 852 |
826 // If audio nodes change is caused by unplugging some non-active audio | 853 // If audio nodes change is caused by unplugging some non-active audio |
827 // devices, the previously set active audio device will stay active. | 854 // devices, the previously set active audio device will stay active. |
828 // Otherwise, switch to a new active audio device according to their priority. | 855 // Otherwise, switch to a new active audio device according to their priority. |
829 if (input_devices_changed && | 856 if (input_devices_changed && |
830 !NonActiveDeviceUnplugged(old_input_device_size, | 857 !NonActiveDeviceUnplugged(old_input_device_size, |
831 new_input_device_size, | 858 new_input_device_size, |
832 active_input_node_id_)) { | 859 active_input_node_id_)) { |
833 // Some devices like chromeboxes don't have the internal audio input. In | 860 // Some devices like chromeboxes don't have the internal audio input. In |
834 // that case the active input node id should be reset. | 861 // that case the active input node id should be reset. |
835 if (input_devices_pq_.empty()) { | 862 if (input_devices_pq_.empty()) { |
836 active_input_node_id_ = 0; | 863 active_input_node_id_ = 0; |
837 NotifyActiveNodeChanged(true); | 864 NotifyActiveNodeChanged(true); |
838 } else { | 865 } else { |
839 SwitchToDevice(input_devices_pq_.top(), true); | 866 // If user has hot plugged a new node, we should change to the active |
| 867 // device to the new node if it has the highest priority; otherwise, |
| 868 // we should keep the existing active node chosen by user. |
| 869 // For all other cases, we will choose the node with highest priority. |
| 870 if (!active_input_node_id_ || hotplug_input_nodes.empty() || |
| 871 IsNodeInTheList(input_devices_pq_.top().id, hotplug_input_nodes)) { |
| 872 SwitchToDevice(input_devices_pq_.top(), true); |
| 873 } |
840 } | 874 } |
841 } | 875 } |
842 if (output_devices_changed && | 876 if (output_devices_changed && |
843 !NonActiveDeviceUnplugged(old_output_device_size, | 877 !NonActiveDeviceUnplugged(old_output_device_size, |
844 new_output_device_size, | 878 new_output_device_size, |
845 active_output_node_id_)) { | 879 active_output_node_id_)) { |
846 // This is really unlikely to happen because all ChromeOS devices have the | 880 // This is really unlikely to happen because all ChromeOS devices have the |
847 // internal audio output. | 881 // internal audio output. |
848 if (output_devices_pq_.empty()) { | 882 if (output_devices_pq_.empty()) { |
849 active_output_node_id_ = 0; | 883 active_output_node_id_ = 0; |
850 NotifyActiveNodeChanged(false); | 884 NotifyActiveNodeChanged(false); |
851 } else { | 885 } else { |
852 SwitchToDevice(output_devices_pq_.top(), true); | 886 // ditto input node case. |
| 887 if (!active_output_node_id_ || hotplug_output_nodes.empty() || |
| 888 IsNodeInTheList(output_devices_pq_.top().id, hotplug_output_nodes)) { |
| 889 SwitchToDevice(output_devices_pq_.top(), true); |
| 890 } |
853 } | 891 } |
854 } | 892 } |
855 } | 893 } |
856 | 894 |
857 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list, | 895 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list, |
858 bool success) { | 896 bool success) { |
859 if (!success) { | 897 if (!success) { |
860 LOG_IF(ERROR, log_errors_) << "Failed to retrieve audio nodes data"; | 898 LOG_IF(ERROR, log_errors_) << "Failed to retrieve audio nodes data"; |
861 return; | 899 return; |
862 } | 900 } |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
921 active_output_node_id_ = 0; | 959 active_output_node_id_ = 0; |
922 chromeos::DBusThreadManager::Get() | 960 chromeos::DBusThreadManager::Get() |
923 ->GetCrasAudioClient() | 961 ->GetCrasAudioClient() |
924 ->RemoveActiveOutputNode(node_id); | 962 ->RemoveActiveOutputNode(node_id); |
925 if (notify) | 963 if (notify) |
926 NotifyActiveNodeChanged(false); | 964 NotifyActiveNodeChanged(false); |
927 } | 965 } |
928 } | 966 } |
929 | 967 |
930 } // namespace chromeos | 968 } // namespace chromeos |
OLD | NEW |