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> |
11 #include <cmath> | 11 #include <cmath> |
12 | 12 |
13 #include "base/bind.h" | 13 #include "base/bind.h" |
14 #include "base/bind_helpers.h" | 14 #include "base/bind_helpers.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "chromeos/audio/audio_devices_pref_handler.h" | 16 #include "base/sys_info.h" |
17 #include "chromeos/audio/audio_devices_pref_handler_stub.h" | 17 #include "chromeos/audio/audio_devices_pref_handler_stub.h" |
18 #include "chromeos/dbus/dbus_thread_manager.h" | 18 #include "chromeos/dbus/dbus_thread_manager.h" |
19 | 19 |
20 using std::max; | 20 using std::max; |
21 using std::min; | 21 using std::min; |
22 | 22 |
23 namespace chromeos { | 23 namespace chromeos { |
24 | 24 |
25 namespace { | 25 namespace { |
26 | 26 |
27 // Default value for unmuting, as a percent in the range [0, 100]. | 27 // Default value for unmuting, as a percent in the range [0, 100]. |
28 // Used when sound is unmuted, but volume was less than kMuteThresholdPercent. | 28 // Used when sound is unmuted, but volume was less than kMuteThresholdPercent. |
29 const int kDefaultUnmuteVolumePercent = 4; | 29 const int kDefaultUnmuteVolumePercent = 4; |
30 | 30 |
31 // Volume value which should be considered as muted in range [0, 100]. | 31 // Volume value which should be considered as muted in range [0, 100]. |
32 const int kMuteThresholdPercent = 1; | 32 const int kMuteThresholdPercent = 1; |
33 | 33 |
34 // The duration of HDMI output re-discover grace period in milliseconds. | 34 // The duration of HDMI output re-discover grace period in milliseconds. |
35 const int kHDMIRediscoverGracePeriodDurationInMs = 2000; | 35 const int kHDMIRediscoverGracePeriodDurationInMs = 2000; |
36 | 36 |
37 static CrasAudioHandler* g_cras_audio_handler = NULL; | 37 static CrasAudioHandler* g_cras_audio_handler = NULL; |
38 | 38 |
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.stable_device_id == b.stable_device_id && a.is_input == b.is_input && |
41 && a.device_name == b.device_name; | 41 a.type == b.type && 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 IsDeviceInList(const AudioDevice& device, const AudioNodeList& node_list) { | |
50 for (const AudioNode& node : node_list) { | |
51 if (device.stable_device_id == node.stable_device_id) | |
52 return true; | |
53 } | |
54 return false; | |
55 } | |
56 | |
49 } // namespace | 57 } // namespace |
50 | 58 |
51 CrasAudioHandler::AudioObserver::AudioObserver() { | 59 CrasAudioHandler::AudioObserver::AudioObserver() { |
52 } | 60 } |
53 | 61 |
54 CrasAudioHandler::AudioObserver::~AudioObserver() { | 62 CrasAudioHandler::AudioObserver::~AudioObserver() { |
55 } | 63 } |
56 | 64 |
57 void CrasAudioHandler::AudioObserver::OnOutputNodeVolumeChanged( | 65 void CrasAudioHandler::AudioObserver::OnOutputNodeVolumeChanged( |
58 uint64_t /* node_id */, | 66 uint64_t /* node_id */, |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
226 const AudioDevice* device = GetDeviceFromId(node_id); | 234 const AudioDevice* device = GetDeviceFromId(node_id); |
227 if (!device) { | 235 if (!device) { |
228 VLOG(1) << "AddActiveInputNode: Cannot find device id=" | 236 VLOG(1) << "AddActiveInputNode: Cannot find device id=" |
229 << "0x" << std::hex << node_id; | 237 << "0x" << std::hex << node_id; |
230 return; | 238 return; |
231 } | 239 } |
232 | 240 |
233 // If there is no primary active device, set |node_id| to primary active node. | 241 // If there is no primary active device, set |node_id| to primary active node. |
234 if ((device->is_input && !active_input_node_id_) || | 242 if ((device->is_input && !active_input_node_id_) || |
235 (!device->is_input && !active_output_node_id_)) { | 243 (!device->is_input && !active_output_node_id_)) { |
236 SwitchToDevice(*device, notify); | 244 SwitchToDevice(*device, notify, ACTIVATE_BY_USER); |
237 return; | 245 return; |
238 } | 246 } |
239 | 247 |
240 AddAdditionalActiveNode(node_id, notify); | 248 AddAdditionalActiveNode(node_id, notify); |
241 } | 249 } |
242 | 250 |
243 void CrasAudioHandler::ChangeActiveNodes(const NodeIdList& new_active_ids) { | 251 void CrasAudioHandler::ChangeActiveNodes(const NodeIdList& new_active_ids) { |
244 // Flags for whether there are input or output nodes passed in from | 252 // Flags for whether there are input or output nodes passed in from |
245 // |new_active_ids|. If there are no input nodes passed in, we will not | 253 // |new_active_ids|. If there are no input nodes passed in, we will not |
246 // make any change for input nodes; same for the output nodes. | 254 // make any change for input nodes; same for the output nodes. |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
381 SetOutputVolumePercent(kDefaultUnmuteVolumePercent); | 389 SetOutputVolumePercent(kDefaultUnmuteVolumePercent); |
382 } | 390 } |
383 } | 391 } |
384 | 392 |
385 void CrasAudioHandler::SetInputMute(bool mute_on) { | 393 void CrasAudioHandler::SetInputMute(bool mute_on) { |
386 SetInputMuteInternal(mute_on); | 394 SetInputMuteInternal(mute_on); |
387 FOR_EACH_OBSERVER(AudioObserver, observers_, | 395 FOR_EACH_OBSERVER(AudioObserver, observers_, |
388 OnInputMuteChanged(input_mute_on_)); | 396 OnInputMuteChanged(input_mute_on_)); |
389 } | 397 } |
390 | 398 |
391 void CrasAudioHandler::SetActiveOutputNode(uint64_t node_id, bool notify) { | 399 void CrasAudioHandler::SetActiveDevice(const AudioDevice& active_device, |
392 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> | 400 bool notify, |
393 SetActiveOutputNode(node_id); | 401 DeviceActivateType activate_by) { |
402 if (active_device.is_input) { | |
403 chromeos::DBusThreadManager::Get() | |
404 ->GetCrasAudioClient() | |
405 ->SetActiveInputNode(active_device.id); | |
406 } else { | |
407 chromeos::DBusThreadManager::Get() | |
408 ->GetCrasAudioClient() | |
409 ->SetActiveOutputNode(active_device.id); | |
410 } | |
411 | |
394 if (notify) | 412 if (notify) |
395 NotifyActiveNodeChanged(false); | 413 NotifyActiveNodeChanged(active_device.is_input); |
396 | 414 |
397 // Save state for all output nodes. | 415 // Save active state for the nodes. |
398 for (AudioDeviceMap::iterator it = audio_devices_.begin(); | 416 for (AudioDeviceMap::iterator it = audio_devices_.begin(); |
399 it != audio_devices_.end(); ++it) { | 417 it != audio_devices_.end(); ++it) { |
400 if (it->second.is_input) | 418 const AudioDevice& device = it->second; |
419 if (device.is_input != active_device.is_input) | |
401 continue; | 420 continue; |
402 audio_pref_handler_->SetDeviceState(it->second, it->second.active | 421 SaveDeviceState(device, device.active, activate_by); |
403 ? AUDIO_STATE_ACTIVE | |
404 : AUDIO_STATE_INACTIVE); | |
405 } | 422 } |
406 } | 423 } |
407 | 424 |
408 void CrasAudioHandler::SetActiveInputNode(uint64_t node_id, bool notify) { | 425 void CrasAudioHandler::SaveDeviceState(const AudioDevice& device, |
409 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> | 426 bool active, |
410 SetActiveInputNode(node_id); | 427 DeviceActivateType activate_by) { |
411 if (notify) | 428 if (!active) { |
412 NotifyActiveNodeChanged(true); | 429 audio_pref_handler_->SetDeviceActive(device, false, false); |
413 | 430 } else { |
414 // Save state for all input nodes. | 431 switch (activate_by) { |
415 for (AudioDeviceMap::iterator it = audio_devices_.begin(); | 432 case ACTIVATE_BY_USER: |
416 it != audio_devices_.end(); ++it) { | 433 audio_pref_handler_->SetDeviceActive(device, true, true); |
417 if (!it->second.is_input) | 434 break; |
418 continue; | 435 case ACTIVATE_BY_PRIORITY: |
419 audio_pref_handler_->SetDeviceState(it->second, it->second.active | 436 audio_pref_handler_->SetDeviceActive(device, true, false); |
420 ? AUDIO_STATE_ACTIVE | 437 break; |
421 : AUDIO_STATE_INACTIVE); | 438 default: |
439 // The device is made active due to its previous active state in prefs, | |
440 // don't change its active state settings in prefs. | |
441 break; | |
442 } | |
422 } | 443 } |
423 } | 444 } |
424 | 445 |
425 void CrasAudioHandler::SetVolumeGainPercentForDevice(uint64_t device_id, | 446 void CrasAudioHandler::SetVolumeGainPercentForDevice(uint64_t device_id, |
426 int value) { | 447 int value) { |
427 const AudioDevice* device = GetDeviceFromId(device_id); | 448 const AudioDevice* device = GetDeviceFromId(device_id); |
428 if (!device) | 449 if (!device) |
429 return; | 450 return; |
430 | 451 |
431 if (device->is_input) | 452 if (device->is_input) |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
525 } | 546 } |
526 | 547 |
527 void CrasAudioHandler::AudioClientRestarted() { | 548 void CrasAudioHandler::AudioClientRestarted() { |
528 // Make sure the logging is enabled in case cras server | 549 // Make sure the logging is enabled in case cras server |
529 // restarts after crashing. | 550 // restarts after crashing. |
530 LogErrors(); | 551 LogErrors(); |
531 InitializeAudioState(); | 552 InitializeAudioState(); |
532 } | 553 } |
533 | 554 |
534 void CrasAudioHandler::NodesChanged() { | 555 void CrasAudioHandler::NodesChanged() { |
535 // Refresh audio nodes data. | 556 if (cras_service_available_) |
536 GetNodes(); | 557 GetNodes(); |
537 } | 558 } |
538 | 559 |
539 void CrasAudioHandler::ActiveOutputNodeChanged(uint64_t node_id) { | 560 void CrasAudioHandler::ActiveOutputNodeChanged(uint64_t node_id) { |
540 if (active_output_node_id_ == node_id) | 561 if (active_output_node_id_ == node_id) |
541 return; | 562 return; |
542 | 563 |
543 // Active audio output device should always be changed by chrome. | 564 // Active audio output device should always be changed by chrome. |
544 // During system boot, cras may change active input to unknown device 0x1, | 565 // During system boot, cras may change active input to unknown device 0x1, |
545 // we don't need to log it, since it is not an valid device. | 566 // we don't need to log it, since it is not an valid device. |
546 if (GetDeviceFromId(node_id)) { | 567 if (GetDeviceFromId(node_id)) { |
(...skipping 28 matching lines...) Expand all Loading... | |
575 } | 596 } |
576 | 597 |
577 const AudioDevice* CrasAudioHandler::GetDeviceFromId(uint64_t device_id) const { | 598 const AudioDevice* CrasAudioHandler::GetDeviceFromId(uint64_t device_id) const { |
578 AudioDeviceMap::const_iterator it = audio_devices_.find(device_id); | 599 AudioDeviceMap::const_iterator it = audio_devices_.find(device_id); |
579 if (it == audio_devices_.end()) | 600 if (it == audio_devices_.end()) |
580 return NULL; | 601 return NULL; |
581 | 602 |
582 return &(it->second); | 603 return &(it->second); |
583 } | 604 } |
584 | 605 |
606 const AudioDevice* CrasAudioHandler::GetDeviceFromStableDeviceId( | |
607 uint64_t stable_device_id) const { | |
608 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); | |
609 it != audio_devices_.end(); ++it) { | |
610 if (it->second.stable_device_id == stable_device_id) | |
611 return &(it->second); | |
612 } | |
613 return NULL; | |
614 } | |
615 | |
585 const AudioDevice* CrasAudioHandler::GetKeyboardMic() const { | 616 const AudioDevice* CrasAudioHandler::GetKeyboardMic() const { |
586 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); | 617 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
587 it != audio_devices_.end(); it++) { | 618 it != audio_devices_.end(); it++) { |
588 if (it->second.is_input && it->second.type == AUDIO_TYPE_KEYBOARD_MIC) | 619 if (it->second.is_input && it->second.type == AUDIO_TYPE_KEYBOARD_MIC) |
589 return &(it->second); | 620 return &(it->second); |
590 } | 621 } |
591 return NULL; | 622 return NULL; |
592 } | 623 } |
593 | 624 |
594 void CrasAudioHandler::SetupAudioInputState() { | 625 void CrasAudioHandler::SetupAudioInputState() { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
648 // TODO(jennyz): crbug.com/417418, track the status for the decison if | 679 // TODO(jennyz): crbug.com/417418, track the status for the decison if |
649 // we should persist input gain value in prefs. | 680 // we should persist input gain value in prefs. |
650 if (!device->is_input) { | 681 if (!device->is_input) { |
651 audio_pref_handler_->SetMuteValue(*device, IsOutputMuted()); | 682 audio_pref_handler_->SetMuteValue(*device, IsOutputMuted()); |
652 SetOutputNodeVolumePercent(node_id, GetOutputVolumePercent()); | 683 SetOutputNodeVolumePercent(node_id, GetOutputVolumePercent()); |
653 } | 684 } |
654 } | 685 } |
655 | 686 |
656 void CrasAudioHandler::InitializeAudioState() { | 687 void CrasAudioHandler::InitializeAudioState() { |
657 ApplyAudioPolicy(); | 688 ApplyAudioPolicy(); |
689 | |
690 // Defer querying cras for GetNodes until cras service becomes available. | |
691 cras_service_available_ = false; | |
692 chromeos::DBusThreadManager::Get() | |
693 ->GetCrasAudioClient() | |
694 ->WaitForServiceToBeAvailable(base::Bind( | |
695 &CrasAudioHandler::InitializeAudioAfterCrasServiceAvailable, | |
696 weak_ptr_factory_.GetWeakPtr())); | |
697 } | |
698 | |
699 void CrasAudioHandler::InitializeAudioAfterCrasServiceAvailable( | |
700 bool service_is_available) { | |
701 if (!service_is_available) { | |
702 LOG(ERROR) << "Cras service is not available"; | |
703 cras_service_available_ = false; | |
704 return; | |
705 } | |
706 | |
707 cras_service_available_ = true; | |
658 GetNodes(); | 708 GetNodes(); |
659 } | 709 } |
660 | 710 |
661 void CrasAudioHandler::ApplyAudioPolicy() { | 711 void CrasAudioHandler::ApplyAudioPolicy() { |
662 output_mute_locked_ = false; | 712 output_mute_locked_ = false; |
663 if (!audio_pref_handler_->GetAudioOutputAllowedValue()) { | 713 if (!audio_pref_handler_->GetAudioOutputAllowedValue()) { |
664 // Mute the device, but do not update the preference. | 714 // Mute the device, but do not update the preference. |
665 SetOutputMuteInternal(true); | 715 SetOutputMuteInternal(true); |
666 output_mute_locked_ = true; | 716 output_mute_locked_ = true; |
667 } else { | 717 } else { |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
743 } | 793 } |
744 | 794 |
745 void CrasAudioHandler::GetNodes() { | 795 void CrasAudioHandler::GetNodes() { |
746 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->GetNodes( | 796 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->GetNodes( |
747 base::Bind(&CrasAudioHandler::HandleGetNodes, | 797 base::Bind(&CrasAudioHandler::HandleGetNodes, |
748 weak_ptr_factory_.GetWeakPtr()), | 798 weak_ptr_factory_.GetWeakPtr()), |
749 base::Bind(&CrasAudioHandler::HandleGetNodesError, | 799 base::Bind(&CrasAudioHandler::HandleGetNodesError, |
750 weak_ptr_factory_.GetWeakPtr())); | 800 weak_ptr_factory_.GetWeakPtr())); |
751 } | 801 } |
752 | 802 |
753 bool CrasAudioHandler::ChangeActiveDevice(const AudioDevice& new_active_device, | 803 bool CrasAudioHandler::ChangeActiveDevice( |
754 uint64_t* current_active_node_id) { | 804 const AudioDevice& new_active_device) { |
805 uint64_t& current_active_node_id = new_active_device.is_input | |
806 ? active_input_node_id_ | |
807 : active_output_node_id_; | |
755 // If the device we want to switch to is already the current active device, | 808 // If the device we want to switch to is already the current active device, |
756 // do nothing. | 809 // do nothing. |
757 if (new_active_device.active && | 810 if (new_active_device.active && |
758 new_active_device.id == *current_active_node_id) { | 811 new_active_device.id == current_active_node_id) { |
759 return false; | 812 return false; |
760 } | 813 } |
761 | 814 |
815 bool found_new_active_device = false; | |
762 // Reset all other input or output devices' active status. The active audio | 816 // Reset all other input or output devices' active status. The active audio |
763 // device from the previous user session can be remembered by cras, but not | 817 // device from the previous user session can be remembered by cras, but not |
764 // in chrome. see crbug.com/273271. | 818 // in chrome. see crbug.com/273271. |
765 for (AudioDeviceMap::iterator it = audio_devices_.begin(); | 819 for (AudioDeviceMap::iterator it = audio_devices_.begin(); |
766 it != audio_devices_.end(); ++it) { | 820 it != audio_devices_.end(); ++it) { |
767 if (it->second.is_input == new_active_device.is_input && | 821 if (it->second.is_input == new_active_device.is_input && |
768 it->second.id != new_active_device.id) | 822 it->second.id != new_active_device.id) { |
769 it->second.active = false; | 823 it->second.active = false; |
824 } else if (it->second.is_input == new_active_device.is_input && | |
825 it->second.id == new_active_device.id) { | |
826 found_new_active_device = true; | |
827 } | |
828 } | |
829 | |
830 if (!found_new_active_device) { | |
831 LOG(ERROR) << "Invalid new active device: " << new_active_device.ToString(); | |
832 return false; | |
770 } | 833 } |
771 | 834 |
772 // Set the current active input/output device to the new_active_device. | 835 // Set the current active input/output device to the new_active_device. |
773 *current_active_node_id = new_active_device.id; | 836 current_active_node_id = new_active_device.id; |
774 audio_devices_[*current_active_node_id].active = true; | 837 audio_devices_[current_active_node_id].active = true; |
775 return true; | 838 return true; |
776 } | 839 } |
777 | 840 |
778 bool CrasAudioHandler::NonActiveDeviceUnplugged(size_t old_devices_size, | 841 void CrasAudioHandler::SwitchToDevice(const AudioDevice& device, |
779 size_t new_devices_size, | 842 bool notify, |
780 uint64_t current_active_node) { | 843 DeviceActivateType activate_by) { |
781 return (new_devices_size < old_devices_size && | 844 if (!ChangeActiveDevice(device)) |
782 GetDeviceFromId(current_active_node)); | 845 return; |
846 | |
847 if (device.is_input) | |
848 SetupAudioInputState(); | |
849 else | |
850 SetupAudioOutputState(); | |
851 | |
852 SetActiveDevice(device, notify, activate_by); | |
783 } | 853 } |
784 | 854 |
785 void CrasAudioHandler::SwitchToDevice(const AudioDevice& device, bool notify) { | 855 bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes, |
786 if (device.is_input) { | 856 bool is_input, |
787 if (!ChangeActiveDevice(device, &active_input_node_id_)) | 857 AudioDevicePriorityQueue* new_discovered, |
788 return; | 858 bool* device_removed, |
789 SetupAudioInputState(); | 859 bool* active_device_removed) { |
790 SetActiveInputNode(active_input_node_id_, notify); | 860 *device_removed = false; |
791 } else { | |
792 if (!ChangeActiveDevice(device, &active_output_node_id_)) | |
793 return; | |
794 SetupAudioOutputState(); | |
795 SetActiveOutputNode(active_output_node_id_, notify); | |
796 } | |
797 } | |
798 | |
799 bool CrasAudioHandler::HasDeviceChange( | |
800 const AudioNodeList& new_nodes, | |
801 bool is_input, | |
802 AudioDevicePriorityQueue* new_discovered) { | |
803 size_t num_old_devices = 0; | |
804 size_t num_new_devices = 0; | |
805 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); | 861 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
806 it != audio_devices_.end(); ++it) { | 862 it != audio_devices_.end(); ++it) { |
807 if (is_input == it->second.is_input) | 863 const AudioDevice& device = it->second; |
808 ++num_old_devices; | 864 if (is_input != device.is_input) |
865 continue; | |
866 if (!IsDeviceInList(device, new_nodes)) { | |
867 *device_removed = true; | |
868 if ((is_input && device.id == active_input_node_id_) || | |
869 (!is_input && device.id == active_output_node_id_)) { | |
870 *active_device_removed = true; | |
871 } | |
872 } | |
809 } | 873 } |
810 | 874 |
811 bool new_or_changed_device = false; | 875 bool new_or_changed_device = false; |
812 while (!new_discovered->empty()) | 876 while (!new_discovered->empty()) |
813 new_discovered->pop(); | 877 new_discovered->pop(); |
814 for (AudioNodeList::const_iterator it = new_nodes.begin(); | 878 for (AudioNodeList::const_iterator it = new_nodes.begin(); |
815 it != new_nodes.end(); ++it) { | 879 it != new_nodes.end(); ++it) { |
816 if (is_input == it->is_input) { | 880 if (is_input != it->is_input) |
817 ++num_new_devices; | 881 continue; |
818 // Look to see if the new device not in the old device list. | 882 // Check if the new device is not in the old device list. |
819 AudioDevice device(*it); | 883 AudioDevice device(*it); |
820 DeviceStatus status = CheckDeviceStatus(device); | 884 DeviceStatus status = CheckDeviceStatus(device); |
821 if (status == NEW_DEVICE) | 885 if (status == NEW_DEVICE) |
822 new_discovered->push(device); | 886 new_discovered->push(device); |
823 if (status == NEW_DEVICE || status == CHANGED_DEVICE) { | 887 if (status == NEW_DEVICE || status == CHANGED_DEVICE) { |
824 new_or_changed_device = true; | 888 new_or_changed_device = true; |
825 } | |
826 } | 889 } |
827 } | 890 } |
828 return new_or_changed_device || (num_old_devices != num_new_devices); | 891 return new_or_changed_device || *device_removed; |
829 } | 892 } |
830 | 893 |
831 CrasAudioHandler::DeviceStatus CrasAudioHandler::CheckDeviceStatus( | 894 CrasAudioHandler::DeviceStatus CrasAudioHandler::CheckDeviceStatus( |
832 const AudioDevice& device) { | 895 const AudioDevice& device) { |
833 const AudioDevice* device_found = GetDeviceFromId(device.id); | 896 const AudioDevice* device_found = |
897 GetDeviceFromStableDeviceId(device.stable_device_id); | |
834 if (!device_found) | 898 if (!device_found) |
835 return NEW_DEVICE; | 899 return NEW_DEVICE; |
836 | 900 |
837 if (!IsSameAudioDevice(device, *device_found)) { | 901 if (!IsSameAudioDevice(device, *device_found)) { |
838 LOG(WARNING) << "Different Audio devices with same id:" | 902 LOG(ERROR) << "Different Audio devices with same stable device id:" |
839 << " new device: " << device.ToString() | 903 << " new device: " << device.ToString() |
840 << " old device: " << device_found->ToString(); | 904 << " old device: " << device_found->ToString(); |
841 return CHANGED_DEVICE; | 905 return CHANGED_DEVICE; |
842 } else if (device.active != device_found->active) { | 906 } else if (device.active != device_found->active) { |
843 return CHANGED_DEVICE; | 907 return CHANGED_DEVICE; |
844 } | 908 } |
845 | 909 |
846 return OLD_DEVICE; | 910 return OLD_DEVICE; |
847 } | 911 } |
848 | 912 |
849 void CrasAudioHandler::NotifyActiveNodeChanged(bool is_input) { | 913 void CrasAudioHandler::NotifyActiveNodeChanged(bool is_input) { |
850 if (is_input) | 914 if (is_input) |
851 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveInputNodeChanged()); | 915 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveInputNodeChanged()); |
852 else | 916 else |
853 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveOutputNodeChanged()); | 917 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveOutputNodeChanged()); |
854 } | 918 } |
855 | 919 |
920 bool CrasAudioHandler::GetActiveDeviceFromUserPref(bool is_input, | |
921 AudioDevice* active_device) { | |
922 bool found_active_device = false; | |
923 bool last_active_device_activate_by_user = false; | |
924 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); | |
925 it != audio_devices_.end(); ++it) { | |
926 AudioDevice device = it->second; | |
927 if (device.is_input != is_input) | |
928 continue; | |
929 | |
930 bool active = false; | |
931 bool activate_by_user = false; | |
932 if (!audio_pref_handler_->GetDeviceActive(device, &active, | |
933 &activate_by_user) || | |
934 !active) { | |
935 continue; | |
936 } | |
937 | |
938 if (!found_active_device) { | |
939 found_active_device = true; | |
940 *active_device = device; | |
941 last_active_device_activate_by_user = activate_by_user; | |
942 continue; | |
943 } | |
944 | |
945 // Choose the best one among multiple active devices from prefs. | |
946 if (activate_by_user) { | |
947 if (!last_active_device_activate_by_user) { | |
948 // Device activated by user has higher priority than the one | |
949 // is not activated by user. | |
950 *active_device = device; | |
951 last_active_device_activate_by_user = true; | |
952 } else { | |
953 // If there are more than one active devices activated by user in the | |
954 // prefs, most likely, after the device was shut down, and before it | |
955 // is rebooted, user has plugged in some previously unplugged audio | |
956 // devices. For such case, it does not make sense to honor the active | |
957 // states in the prefs. | |
958 VLOG(1) << "Found more than one user activated devices in the prefs."; | |
959 return false; | |
960 } | |
961 } else if (!last_active_device_activate_by_user) { | |
962 // If there are more than one active devices activated by priority in the | |
963 // prefs, most likely, cras is still enumerating the audio devices | |
964 // progressively. For such case, it does not make sense to honor the | |
965 // active states in the prefs. | |
966 VLOG(1) << "Found more than one active devices by priority in the prefs."; | |
967 return false; | |
968 } | |
969 } | |
970 | |
971 if (found_active_device && !active_device->is_for_simple_usage()) { | |
972 // This is an odd case which is rare but possible to happen during cras | |
973 // initialization depeneding the audio device enumation process. The only | |
974 // audio node coming from cras is an internal audio device not visible | |
975 // to user, such as AUDIO_TYPE_POST_MIX_LOOPBACK. | |
976 return false; | |
977 } | |
978 | |
979 return found_active_device; | |
980 } | |
981 | |
982 void CrasAudioHandler::HandleNonHotplugNodesChange( | |
983 bool is_input, | |
984 const AudioDevicePriorityQueue& hotplug_nodes, | |
985 bool has_device_change, | |
986 bool has_device_removed, | |
987 bool active_device_removed) { | |
988 bool has_current_active_node = | |
989 is_input ? active_input_node_id_ : active_output_node_id_; | |
990 | |
991 // No device change, extra NodesChanged signal received. | |
992 if (!has_device_change && has_current_active_node) | |
993 return; | |
994 | |
995 if (hotplug_nodes.empty()) { | |
996 // Unplugged a non-active device. | |
997 if (has_device_removed) { | |
998 if (!active_device_removed && has_current_active_node) { | |
999 // Removed a non-active device, keep the current active device. | |
1000 return; | |
1001 } | |
1002 | |
1003 if (active_device_removed) { | |
1004 // Unplugged the current active device. | |
1005 SwitchToTopPriorityDevice(is_input); | |
1006 return; | |
1007 } | |
1008 } | |
1009 | |
1010 // Some unexpected error happens on cras side. See crbug.com/586026. | |
1011 // Either cras sent stale nodes to chrome again or cras triggered some | |
1012 // error. Restore the previously selected active. | |
1013 VLOG(1) << "Odd case from cras, the active node is lost unexpectedly. "; | |
1014 SwitchToPreviousActiveDeviceIfAvailable(is_input); | |
1015 } else { | |
1016 // Looks like a new chrome session starts. | |
1017 SwitchToPreviousActiveDeviceIfAvailable(is_input); | |
1018 } | |
1019 } | |
1020 | |
1021 void CrasAudioHandler::HandleHotPlugDevice( | |
1022 const AudioDevice& hotplug_device, | |
1023 const AudioDevicePriorityQueue& device_priority_queue) { | |
1024 bool last_state_active = false; | |
1025 bool last_activate_by_user = false; | |
1026 if (!audio_pref_handler_->GetDeviceActive(hotplug_device, &last_state_active, | |
1027 &last_activate_by_user)) { | |
1028 // |hotplug_device} is plugged in for the first time, activate it if it | |
hychao
2016/03/02 15:34:05
|hotplug_device|
jennyz
2016/03/02 19:33:37
Done.
| |
1029 // is of the highest priority. | |
1030 if (device_priority_queue.top().id == hotplug_device.id) { | |
1031 VLOG(1) << "Hotplug a device for the first time: " | |
1032 << hotplug_device.ToString(); | |
1033 SwitchToDevice(hotplug_device, true, ACTIVATE_BY_PRIORITY); | |
1034 } | |
1035 } else if (last_state_active) { | |
1036 VLOG(1) << "Hotplug a device, restore to active: " | |
1037 << hotplug_device.ToString(); | |
1038 SwitchToDevice(hotplug_device, true, ACTIVATE_BY_RESTORE_PREVIOUS_STATE); | |
1039 } else { | |
1040 // Do not active the device if its previous state is inactive. | |
1041 VLOG(1) << "Hotplug device remains inactive as its previous state:" | |
1042 << hotplug_device.ToString(); | |
1043 } | |
1044 } | |
1045 | |
1046 void CrasAudioHandler::SwitchToTopPriorityDevice(bool is_input) { | |
1047 AudioDevice top_device = | |
1048 is_input ? input_devices_pq_.top() : output_devices_pq_.top(); | |
1049 SwitchToDevice(top_device, true, ACTIVATE_BY_PRIORITY); | |
1050 } | |
1051 | |
1052 void CrasAudioHandler::SwitchToPreviousActiveDeviceIfAvailable(bool is_input) { | |
1053 AudioDevice previous_active_device; | |
1054 if (GetActiveDeviceFromUserPref(is_input, &previous_active_device)) { | |
1055 // Switch to previous active device stored in user prefs. | |
1056 SwitchToDevice(previous_active_device, true, | |
1057 ACTIVATE_BY_RESTORE_PREVIOUS_STATE); | |
1058 } else { | |
1059 // No previous active device, switch to the top priority device. | |
1060 SwitchToTopPriorityDevice(is_input); | |
1061 } | |
1062 } | |
1063 | |
856 void CrasAudioHandler::UpdateDevicesAndSwitchActive( | 1064 void CrasAudioHandler::UpdateDevicesAndSwitchActive( |
857 const AudioNodeList& nodes) { | 1065 const AudioNodeList& nodes) { |
858 size_t old_output_device_size = 0; | 1066 size_t old_output_device_size = 0; |
859 size_t old_input_device_size = 0; | 1067 size_t old_input_device_size = 0; |
860 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); | 1068 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
861 it != audio_devices_.end(); ++it) { | 1069 it != audio_devices_.end(); ++it) { |
862 if (it->second.is_input) | 1070 if (it->second.is_input) |
863 ++old_input_device_size; | 1071 ++old_input_device_size; |
864 else | 1072 else |
865 ++old_output_device_size; | 1073 ++old_output_device_size; |
866 } | 1074 } |
867 | 1075 |
868 AudioDevicePriorityQueue hotplug_output_nodes; | 1076 AudioDevicePriorityQueue hotplug_output_nodes; |
869 AudioDevicePriorityQueue hotplug_input_nodes; | 1077 AudioDevicePriorityQueue hotplug_input_nodes; |
1078 bool has_output_removed = false; | |
1079 bool has_input_removed = false; | |
1080 bool active_output_removed = false; | |
1081 bool active_input_removed = false; | |
870 bool output_devices_changed = | 1082 bool output_devices_changed = |
871 HasDeviceChange(nodes, false, &hotplug_output_nodes); | 1083 HasDeviceChange(nodes, false, &hotplug_output_nodes, &has_output_removed, |
1084 &active_output_removed); | |
872 bool input_devices_changed = | 1085 bool input_devices_changed = |
873 HasDeviceChange(nodes, true, &hotplug_input_nodes); | 1086 HasDeviceChange(nodes, true, &hotplug_input_nodes, &has_input_removed, |
1087 &active_input_removed); | |
874 audio_devices_.clear(); | 1088 audio_devices_.clear(); |
875 has_alternative_input_ = false; | 1089 has_alternative_input_ = false; |
876 has_alternative_output_ = false; | 1090 has_alternative_output_ = false; |
877 | 1091 |
878 while (!input_devices_pq_.empty()) | 1092 while (!input_devices_pq_.empty()) |
879 input_devices_pq_.pop(); | 1093 input_devices_pq_.pop(); |
880 while (!output_devices_pq_.empty()) | 1094 while (!output_devices_pq_.empty()) |
881 output_devices_pq_.pop(); | 1095 output_devices_pq_.pop(); |
882 | 1096 |
883 size_t new_output_device_size = 0; | 1097 size_t new_output_device_size = 0; |
884 size_t new_input_device_size = 0; | 1098 size_t new_input_device_size = 0; |
885 for (size_t i = 0; i < nodes.size(); ++i) { | 1099 for (size_t i = 0; i < nodes.size(); ++i) { |
886 AudioDevice device(nodes[i]); | 1100 AudioDevice device(nodes[i]); |
887 audio_devices_[device.id] = device; | 1101 audio_devices_[device.id] = device; |
888 | |
889 if (!has_alternative_input_ && | 1102 if (!has_alternative_input_ && |
890 device.is_input && | 1103 device.is_input && |
891 device.type != AUDIO_TYPE_INTERNAL_MIC && | 1104 device.type != AUDIO_TYPE_INTERNAL_MIC && |
892 device.type != AUDIO_TYPE_KEYBOARD_MIC) { | 1105 device.type != AUDIO_TYPE_KEYBOARD_MIC) { |
893 has_alternative_input_ = true; | 1106 has_alternative_input_ = true; |
894 } else if (!has_alternative_output_ && | 1107 } else if (!has_alternative_output_ && |
895 !device.is_input && | 1108 !device.is_input && |
896 device.type != AUDIO_TYPE_INTERNAL_SPEAKER) { | 1109 device.type != AUDIO_TYPE_INTERNAL_SPEAKER) { |
897 has_alternative_output_ = true; | 1110 has_alternative_output_ = true; |
898 } | 1111 } |
899 | 1112 |
900 if (device.is_input) { | 1113 if (device.is_input) { |
901 input_devices_pq_.push(device); | 1114 input_devices_pq_.push(device); |
902 ++new_input_device_size; | 1115 ++new_input_device_size; |
903 } else { | 1116 } else { |
904 output_devices_pq_.push(device); | 1117 output_devices_pq_.push(device); |
905 ++new_output_device_size; | 1118 ++new_output_device_size; |
906 } | 1119 } |
907 } | 1120 } |
908 | 1121 |
1122 // Handle output device changes. | |
1123 HandleAudioDeviceChange(false, output_devices_pq_, hotplug_output_nodes, | |
1124 output_devices_changed, has_output_removed, | |
1125 active_output_removed); | |
1126 | |
1127 // Handle input device changes. | |
1128 HandleAudioDeviceChange(true, input_devices_pq_, hotplug_input_nodes, | |
1129 input_devices_changed, has_input_removed, | |
1130 active_input_removed); | |
1131 } | |
1132 | |
1133 void CrasAudioHandler::HandleAudioDeviceChange( | |
1134 bool is_input, | |
1135 const AudioDevicePriorityQueue& devices_pq, | |
1136 const AudioDevicePriorityQueue& hotplug_nodes, | |
1137 bool has_device_change, | |
1138 bool has_device_removed, | |
1139 bool active_device_removed) { | |
1140 uint64_t& active_node_id = | |
1141 is_input ? active_input_node_id_ : active_output_node_id_; | |
1142 | |
1143 // No audio devices found. | |
1144 if (devices_pq.empty()) { | |
1145 VLOG(1) << "No " << (is_input ? "input" : "output") << " devices found"; | |
1146 active_node_id = 0; | |
1147 NotifyActiveNodeChanged(is_input); | |
1148 return; | |
1149 } | |
1150 | |
909 // If the previous active device is removed from the new node list, | 1151 // If the previous active device is removed from the new node list, |
910 // or changed to inactive by cras, reset active_output_node_id_. | 1152 // or changed to inactive by cras, reset active_node_id. |
911 // See crbug.com/478968. | 1153 // See crbug.com/478968. |
912 const AudioDevice* active_output = GetDeviceFromId(active_output_node_id_); | 1154 const AudioDevice* active_device = GetDeviceFromId(active_node_id); |
913 if (!active_output || !active_output->active) | 1155 if (!active_device || !active_device->active) |
914 active_output_node_id_ = 0; | 1156 active_node_id = 0; |
915 const AudioDevice* active_input = GetDeviceFromId(active_input_node_id_); | |
916 if (!active_input || !active_input->active) | |
917 active_input_node_id_ = 0; | |
918 | 1157 |
919 // If audio nodes change is caused by unplugging some non-active audio | 1158 if (!active_node_id || hotplug_nodes.empty() || hotplug_nodes.size() > 1) { |
920 // devices, we wont't change the current active audio devices. | 1159 HandleNonHotplugNodesChange(is_input, hotplug_nodes, has_device_change, |
921 if (input_devices_changed && | 1160 has_device_removed, active_device_removed); |
922 !NonActiveDeviceUnplugged(old_input_device_size, | 1161 } else { |
923 new_input_device_size, | 1162 // Typical user hotplug case. |
924 active_input_node_id_)) { | 1163 HandleHotPlugDevice(hotplug_nodes.top(), devices_pq); |
925 // Some devices like chromeboxes don't have the internal audio input. In | |
926 // that case the active input node id should be reset. | |
927 if (input_devices_pq_.empty()) { | |
928 active_input_node_id_ = 0; | |
929 NotifyActiveNodeChanged(true); | |
930 } else { | |
931 // If there is no current active node, or, no new hot plugged node, select | |
932 // the active node by their priorities. | |
933 if (!active_input_node_id_ || hotplug_input_nodes.empty()) { | |
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 } | |
960 } | |
961 } | |
962 } | |
963 if (output_devices_changed && | |
964 !NonActiveDeviceUnplugged(old_output_device_size, | |
965 new_output_device_size, | |
966 active_output_node_id_)) { | |
967 // ditto input node logic. | |
968 if (output_devices_pq_.empty()) { | |
969 active_output_node_id_ = 0; | |
970 NotifyActiveNodeChanged(false); | |
971 } else { | |
972 if (!active_output_node_id_ || hotplug_output_nodes.empty()) { | |
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 } | |
989 } | |
990 } | |
991 } | 1164 } |
992 } | 1165 } |
993 | 1166 |
994 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list, | 1167 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list, |
995 bool success) { | 1168 bool success) { |
996 if (!success) { | 1169 if (!success) { |
997 LOG_IF(ERROR, log_errors_) << "Failed to retrieve audio nodes data"; | 1170 LOG_IF(ERROR, log_errors_) << "Failed to retrieve audio nodes data"; |
998 return; | 1171 return; |
999 } | 1172 } |
1000 | 1173 |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1093 hdmi_rediscover_grace_period_duration_in_ms_), | 1266 hdmi_rediscover_grace_period_duration_in_ms_), |
1094 this, &CrasAudioHandler::UpdateAudioAfterHDMIRediscoverGracePeriod); | 1267 this, &CrasAudioHandler::UpdateAudioAfterHDMIRediscoverGracePeriod); |
1095 } | 1268 } |
1096 | 1269 |
1097 void CrasAudioHandler::SetHDMIRediscoverGracePeriodForTesting( | 1270 void CrasAudioHandler::SetHDMIRediscoverGracePeriodForTesting( |
1098 int duration_in_ms) { | 1271 int duration_in_ms) { |
1099 hdmi_rediscover_grace_period_duration_in_ms_ = duration_in_ms; | 1272 hdmi_rediscover_grace_period_duration_in_ms_ = duration_in_ms; |
1100 } | 1273 } |
1101 | 1274 |
1102 } // namespace chromeos | 1275 } // namespace chromeos |
OLD | NEW |