Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1275)

Side by Side Diff: chromeos/audio/cras_audio_handler.cc

Issue 1380103003: Store audio device's active state in preference (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix string format Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chromeos/audio/cras_audio_handler.h ('k') | chromeos/audio/cras_audio_handler_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « chromeos/audio/cras_audio_handler.h ('k') | chromeos/audio/cras_audio_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698