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

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

Issue 2721733003: Handle the dual microphones and dual cameras cases. Activate the proper microphone when user activa… (Closed)
Patch Set: Fix test issue. Created 3 years, 9 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
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 23 matching lines...) Expand all
34 const int kMuteThresholdPercent = 1; 34 const int kMuteThresholdPercent = 1;
35 35
36 // The duration of HDMI output re-discover grace period in milliseconds. 36 // The duration of HDMI output re-discover grace period in milliseconds.
37 const int kHDMIRediscoverGracePeriodDurationInMs = 2000; 37 const int kHDMIRediscoverGracePeriodDurationInMs = 2000;
38 38
39 // Mixer matrix, [0.5, 0.5; 0.5, 0.5] 39 // Mixer matrix, [0.5, 0.5; 0.5, 0.5]
40 const std::vector<double> kStereoToMono = {0.5, 0.5, 0.5, 0.5}; 40 const std::vector<double> kStereoToMono = {0.5, 0.5, 0.5, 0.5};
41 // Mixer matrix, [1, 0; 0, 1] 41 // Mixer matrix, [1, 0; 0, 1]
42 const std::vector<double> kStereoToStereo = {1, 0, 0, 1}; 42 const std::vector<double> kStereoToStereo = {1, 0, 0, 1};
43 43
44 static CrasAudioHandler* g_cras_audio_handler = NULL; 44 static CrasAudioHandler* g_cras_audio_handler = nullptr;
45 45
46 bool IsSameAudioDevice(const AudioDevice& a, const AudioDevice& b) { 46 bool IsSameAudioDevice(const AudioDevice& a, const AudioDevice& b) {
47 return a.stable_device_id == b.stable_device_id && a.is_input == b.is_input && 47 return a.stable_device_id == b.stable_device_id && a.is_input == b.is_input &&
48 a.type == b.type && a.device_name == b.device_name; 48 a.type == b.type && a.device_name == b.device_name;
49 } 49 }
50 50
51 bool IsDeviceInList(const AudioDevice& device, const AudioNodeList& node_list) { 51 bool IsDeviceInList(const AudioDevice& device, const AudioNodeList& node_list) {
52 for (const AudioNode& node : node_list) { 52 for (const AudioNode& node : node_list) {
53 if (device.stable_device_id == node.StableDeviceId()) 53 if (device.stable_device_id == node.StableDeviceId())
54 return true; 54 return true;
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 // static 104 // static
105 void CrasAudioHandler::InitializeForTesting() { 105 void CrasAudioHandler::InitializeForTesting() {
106 CHECK(!g_cras_audio_handler); 106 CHECK(!g_cras_audio_handler);
107 CrasAudioHandler::Initialize(new AudioDevicesPrefHandlerStub()); 107 CrasAudioHandler::Initialize(new AudioDevicesPrefHandlerStub());
108 } 108 }
109 109
110 // static 110 // static
111 void CrasAudioHandler::Shutdown() { 111 void CrasAudioHandler::Shutdown() {
112 CHECK(g_cras_audio_handler); 112 CHECK(g_cras_audio_handler);
113 delete g_cras_audio_handler; 113 delete g_cras_audio_handler;
114 g_cras_audio_handler = NULL; 114 g_cras_audio_handler = nullptr;
115 } 115 }
116 116
117 // static 117 // static
118 bool CrasAudioHandler::IsInitialized() { 118 bool CrasAudioHandler::IsInitialized() {
119 return g_cras_audio_handler != NULL; 119 return g_cras_audio_handler != nullptr;
120 } 120 }
121 121
122 // static 122 // static
123 CrasAudioHandler* CrasAudioHandler::Get() { 123 CrasAudioHandler* CrasAudioHandler::Get() {
124 CHECK(g_cras_audio_handler) 124 CHECK(g_cras_audio_handler)
125 << "CrasAudioHandler::Get() called before Initialize()."; 125 << "CrasAudioHandler::Get() called before Initialize().";
126 return g_cras_audio_handler; 126 return g_cras_audio_handler;
127 } 127 }
128 128
129 void CrasAudioHandler::OnVideoCaptureStarted(media::VideoFacingMode facing) { 129 void CrasAudioHandler::OnVideoCaptureStarted(media::VideoFacingMode facing) {
130 // TODO(jennyz): Switch active audio device according to video facing. 130 // Do nothing if the device doesn't have both front and rear microphones.
131 if (!HasDualInternalMic())
132 return;
133 switch (facing) {
134 case media::MEDIA_VIDEO_FACING_USER:
135 front_camera_on_ = true;
136 break;
137 case media::MEDIA_VIDEO_FACING_ENVIRONMENT:
138 rear_camera_on_ = true;
139 break;
140 default:
141 NOTREACHED();
shenghao 2017/03/01 11:25:55 I am not 100% sure but I think it's possible to re
jennyz 2017/03/02 17:31:40 I need to know in which scenario it will pass MEDI
shenghao 2017/03/03 03:45:21 Since external camera has MEDIA_VIDEO_FACING_NONE,
jennyz 2017/03/03 19:35:15 Done.
142 }
143
144 // If the current active input is an external device, keep it.
145 const AudioDevice* active_input = GetDeviceFromId(active_input_node_id_);
146 if (active_input && active_input->IsExternalDevice())
147 return;
148
149 // Activate the correct mic for the current active camera.
150 ActivateMicForCamera(facing);
131 } 151 }
132 152
133 void CrasAudioHandler::OnVideoCaptureStopped(media::VideoFacingMode facing) { 153 void CrasAudioHandler::OnVideoCaptureStopped(media::VideoFacingMode facing) {
134 // TODO(jennyz): Switch active audio device according to video facing. 154 // Do nothing if the device doesn't have both front and rear microphones.
155 if (!HasDualInternalMic())
156 return;
157
158 switch (facing) {
159 case media::MEDIA_VIDEO_FACING_USER:
160 front_camera_on_ = false;
161 break;
162 case media::MEDIA_VIDEO_FACING_ENVIRONMENT:
163 rear_camera_on_ = false;
164 break;
165 default:
166 NOTREACHED();
167 }
168
169 // If the current active input is an external device, keep it.
170 const AudioDevice* active_input = GetDeviceFromId(active_input_node_id_);
171 if (active_input && active_input->IsExternalDevice())
172 return;
173
174 // Switch to front mic properly.
shenghao 2017/03/01 11:25:55 Why is it "front mic"? Do you mean "correct mic"?
jennyz 2017/03/02 17:31:41 In R58, chrome code will only handle the dual came
175 DeviceActivateType activate_by =
shenghao 2017/03/01 11:25:55 s/activate_by/activated_by/
jennyz 2017/03/02 17:31:41 Done.
176 HasExternalDevice(true) ? ACTIVATE_BY_USER : ACTIVATE_BY_PRIORITY;
177 SwitchToDevice(*GetDeviceByType(AUDIO_TYPE_FRONT_MIC), true, activate_by);
shenghao 2017/03/01 11:25:55 Why do we also switch to AUDIO_TYPE_FRONT_MIC? Is
shenghao 2017/03/01 11:27:54 typo: also => always
jennyz 2017/03/02 17:31:40 Acknowledged.
jennyz 2017/03/02 17:31:41 See comments above.
135 } 178 }
136 179
137 void CrasAudioHandler::AddAudioObserver(AudioObserver* observer) { 180 void CrasAudioHandler::AddAudioObserver(AudioObserver* observer) {
138 observers_.AddObserver(observer); 181 observers_.AddObserver(observer);
139 } 182 }
140 183
141 void CrasAudioHandler::RemoveAudioObserver(AudioObserver* observer) { 184 void CrasAudioHandler::RemoveAudioObserver(AudioObserver* observer) {
142 observers_.RemoveObserver(observer); 185 observers_.RemoveObserver(observer);
143 } 186 }
144 187
145 bool CrasAudioHandler::HasKeyboardMic() { 188 bool CrasAudioHandler::HasKeyboardMic() {
146 return GetKeyboardMic() != NULL; 189 return GetKeyboardMic() != nullptr;
147 } 190 }
148 191
149 bool CrasAudioHandler::IsOutputMuted() { 192 bool CrasAudioHandler::IsOutputMuted() {
150 return output_mute_on_; 193 return output_mute_on_;
151 } 194 }
152 195
153 bool CrasAudioHandler::IsOutputMutedForDevice(uint64_t device_id) { 196 bool CrasAudioHandler::IsOutputMutedForDevice(uint64_t device_id) {
154 const AudioDevice* device = GetDeviceFromId(device_id); 197 const AudioDevice* device = GetDeviceFromId(device_id);
155 if (!device) 198 if (!device)
156 return false; 199 return false;
(...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 if (!chromeos::DBusThreadManager::IsInitialized() || 640 if (!chromeos::DBusThreadManager::IsInitialized() ||
598 !chromeos::DBusThreadManager::Get() || 641 !chromeos::DBusThreadManager::Get() ||
599 !chromeos::DBusThreadManager::Get()->GetCrasAudioClient()) 642 !chromeos::DBusThreadManager::Get()->GetCrasAudioClient())
600 return; 643 return;
601 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> 644 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
602 RemoveObserver(this); 645 RemoveObserver(this);
603 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()-> 646 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->
604 RemoveObserver(this); 647 RemoveObserver(this);
605 if (audio_pref_handler_.get()) 648 if (audio_pref_handler_.get())
606 audio_pref_handler_->RemoveAudioPrefObserver(this); 649 audio_pref_handler_->RemoveAudioPrefObserver(this);
607 audio_pref_handler_ = NULL; 650 audio_pref_handler_ = nullptr;
608 } 651 }
609 652
610 void CrasAudioHandler::AudioClientRestarted() { 653 void CrasAudioHandler::AudioClientRestarted() {
611 // Make sure the logging is enabled in case cras server 654 // Make sure the logging is enabled in case cras server
612 // restarts after crashing. 655 // restarts after crashing.
613 LogErrors(); 656 LogErrors();
614 InitializeAudioState(); 657 InitializeAudioState();
615 } 658 }
616 659
617 void CrasAudioHandler::NodesChanged() { 660 void CrasAudioHandler::NodesChanged() {
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
705 748
706 void CrasAudioHandler::EmitLoginPromptVisibleCalled() { 749 void CrasAudioHandler::EmitLoginPromptVisibleCalled() {
707 // Enable logging after cras server is started, which will be after 750 // Enable logging after cras server is started, which will be after
708 // EmitLoginPromptVisible. 751 // EmitLoginPromptVisible.
709 LogErrors(); 752 LogErrors();
710 } 753 }
711 754
712 const AudioDevice* CrasAudioHandler::GetDeviceFromId(uint64_t device_id) const { 755 const AudioDevice* CrasAudioHandler::GetDeviceFromId(uint64_t device_id) const {
713 AudioDeviceMap::const_iterator it = audio_devices_.find(device_id); 756 AudioDeviceMap::const_iterator it = audio_devices_.find(device_id);
714 if (it == audio_devices_.end()) 757 if (it == audio_devices_.end())
715 return NULL; 758 return nullptr;
716 759
717 return &(it->second); 760 return &(it->second);
718 } 761 }
719 762
720 const AudioDevice* CrasAudioHandler::GetDeviceFromStableDeviceId( 763 const AudioDevice* CrasAudioHandler::GetDeviceFromStableDeviceId(
721 uint64_t stable_device_id) const { 764 uint64_t stable_device_id) const {
722 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); 765 for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
723 it != audio_devices_.end(); ++it) { 766 it != audio_devices_.end(); ++it) {
724 if (it->second.stable_device_id == stable_device_id) 767 if (it->second.stable_device_id == stable_device_id)
725 return &(it->second); 768 return &(it->second);
726 } 769 }
727 return NULL; 770 return nullptr;
728 } 771 }
729 772
730 const AudioDevice* CrasAudioHandler::GetKeyboardMic() const { 773 const AudioDevice* CrasAudioHandler::GetKeyboardMic() const {
731 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); 774 for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
732 it != audio_devices_.end(); it++) { 775 it != audio_devices_.end(); it++) {
733 if (it->second.is_input && it->second.type == AUDIO_TYPE_KEYBOARD_MIC) 776 if (it->second.is_input && it->second.type == AUDIO_TYPE_KEYBOARD_MIC)
734 return &(it->second); 777 return &(it->second);
735 } 778 }
736 return NULL; 779 return nullptr;
737 } 780 }
738 781
739 void CrasAudioHandler::SetupAudioInputState() { 782 void CrasAudioHandler::SetupAudioInputState() {
740 // Set the initial audio state to the ones read from audio prefs. 783 // Set the initial audio state to the ones read from audio prefs.
741 const AudioDevice* device = GetDeviceFromId(active_input_node_id_); 784 const AudioDevice* device = GetDeviceFromId(active_input_node_id_);
742 if (!device) { 785 if (!device) {
743 LOG_IF(ERROR, log_errors_) 786 LOG_IF(ERROR, log_errors_)
744 << "Can't set up audio state for unknown input device id =" 787 << "Can't set up audio state for unknown input device id ="
745 << "0x" << std::hex << active_input_node_id_; 788 << "0x" << std::hex << active_input_node_id_;
746 return; 789 return;
(...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after
1176 } else { 1219 } else {
1177 // Do not active the device if its previous state is inactive. 1220 // Do not active the device if its previous state is inactive.
1178 VLOG(1) << "Hotplug device remains inactive as its previous state:" 1221 VLOG(1) << "Hotplug device remains inactive as its previous state:"
1179 << hotplug_device.ToString(); 1222 << hotplug_device.ToString();
1180 } 1223 }
1181 } 1224 }
1182 1225
1183 void CrasAudioHandler::SwitchToTopPriorityDevice(bool is_input) { 1226 void CrasAudioHandler::SwitchToTopPriorityDevice(bool is_input) {
1184 AudioDevice top_device = 1227 AudioDevice top_device =
1185 is_input ? input_devices_pq_.top() : output_devices_pq_.top(); 1228 is_input ? input_devices_pq_.top() : output_devices_pq_.top();
1186 if (top_device.is_for_simple_usage()) 1229 if (!top_device.is_for_simple_usage())
1187 SwitchToDevice(top_device, true, ACTIVATE_BY_PRIORITY); 1230 return;
1231
1232 // For the dual camera and dual microphone case, choose microphone
1233 // that is consistent to the active camera.
1234 if (IsFrontOrRearMic(top_device) && HasDualInternalMic() && IsCameraOn()) {
shenghao 2017/03/01 11:25:55 I think you can write: if (IsFrontOrRearMic(top_d
jennyz 2017/03/02 17:31:40 The above code is not equivalent to the original l
1235 media::VideoFacingMode facing = front_camera_on_
1236 ? media::MEDIA_VIDEO_FACING_USER
1237 : media::MEDIA_VIDEO_FACING_ENVIRONMENT;
1238 ActivateMicForCamera(facing);
1239 return;
1240 }
1241
1242 SwitchToDevice(top_device, true, ACTIVATE_BY_PRIORITY);
1188 } 1243 }
1189 1244
1190 void CrasAudioHandler::SwitchToPreviousActiveDeviceIfAvailable(bool is_input) { 1245 void CrasAudioHandler::SwitchToPreviousActiveDeviceIfAvailable(bool is_input) {
1191 AudioDevice previous_active_device; 1246 AudioDevice previous_active_device;
1192 if (GetActiveDeviceFromUserPref(is_input, &previous_active_device)) { 1247 if (GetActiveDeviceFromUserPref(is_input, &previous_active_device)) {
1193 DCHECK(previous_active_device.is_for_simple_usage()); 1248 DCHECK(previous_active_device.is_for_simple_usage());
1194 // Switch to previous active device stored in user prefs. 1249 // Switch to previous active device stored in user prefs.
1195 SwitchToDevice(previous_active_device, true, 1250 SwitchToDevice(previous_active_device, true,
1196 ACTIVATE_BY_RESTORE_PREVIOUS_STATE); 1251 ACTIVATE_BY_RESTORE_PREVIOUS_STATE);
1197 } else { 1252 } else {
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after
1416 FROM_HERE, base::TimeDelta::FromMilliseconds( 1471 FROM_HERE, base::TimeDelta::FromMilliseconds(
1417 hdmi_rediscover_grace_period_duration_in_ms_), 1472 hdmi_rediscover_grace_period_duration_in_ms_),
1418 this, &CrasAudioHandler::UpdateAudioAfterHDMIRediscoverGracePeriod); 1473 this, &CrasAudioHandler::UpdateAudioAfterHDMIRediscoverGracePeriod);
1419 } 1474 }
1420 1475
1421 void CrasAudioHandler::SetHDMIRediscoverGracePeriodForTesting( 1476 void CrasAudioHandler::SetHDMIRediscoverGracePeriodForTesting(
1422 int duration_in_ms) { 1477 int duration_in_ms) {
1423 hdmi_rediscover_grace_period_duration_in_ms_ = duration_in_ms; 1478 hdmi_rediscover_grace_period_duration_in_ms_ = duration_in_ms;
1424 } 1479 }
1425 1480
1481 void CrasAudioHandler::ActivateMicForCamera(
1482 media::VideoFacingMode camera_facing) {
1483 const AudioDevice* mic = GetMicForCamera(camera_facing);
1484 if (!mic || mic->active)
1485 return;
1486
1487 SwitchToDevice(*mic, true, ACTIVATE_BY_CAMERA);
1488 }
1489
1490 void CrasAudioHandler::ActivateInternalMicForActiveCamera() {
1491 if (HasDualInternalMic() && IsCameraOn()) {
1492 media::VideoFacingMode facing = front_camera_on_
1493 ? media::MEDIA_VIDEO_FACING_USER
1494 : media::MEDIA_VIDEO_FACING_ENVIRONMENT;
1495 ActivateMicForCamera(facing);
1496 }
1497 }
1498
1499 // For the dual microphone case, from user point of view, they only see internal
1500 // microphone in UI. Chrome will make the best decision on which one to pick.
1501 // If the camera is off, the front microphone should be picked as the default
1502 // active microphone. Otherwise, it will switch to the microphone that
1503 // matches the active camera, i.e. front microphone for front camera and
1504 // reaa microphone for rear camera.
shenghao 2017/03/01 11:25:55 s/reaa/rear/
jennyz 2017/03/02 17:31:41 Done.
1505 void CrasAudioHandler::SwitchToFrontOrRearMic() {
1506 DCHECK(HasDualInternalMic());
1507 if (IsCameraOn()) {
shenghao 2017/03/01 11:25:55 Why do we need to check IsCameraOn() twice here an
jennyz 2017/03/02 17:31:40 Removed IsCameraOn() from 1491.
1508 ActivateInternalMicForActiveCamera();
1509 } else {
1510 SwitchToDevice(*GetDeviceByType(AUDIO_TYPE_FRONT_MIC), true,
1511 ACTIVATE_BY_USER);
1512 }
1513 }
1514
1515 const AudioDevice* CrasAudioHandler::GetMicForCamera(
1516 media::VideoFacingMode camera_facing) {
1517 switch (camera_facing) {
1518 case media::MEDIA_VIDEO_FACING_USER:
1519 return GetDeviceByType(AUDIO_TYPE_FRONT_MIC);
1520 case media::MEDIA_VIDEO_FACING_ENVIRONMENT:
1521 return GetDeviceByType(AUDIO_TYPE_REAR_MIC);
1522 break;
shenghao 2017/03/01 11:25:55 You don't need "break" here because of the return
jennyz 2017/03/02 17:31:40 Done.
1523 default:
1524 NOTREACHED();
shenghao 2017/03/01 11:25:55 Same as line 141
jennyz 2017/03/02 17:31:41 This code path is not reachable, the code path to
1525 }
1526 return nullptr;
1527 }
1528
1529 const AudioDevice* CrasAudioHandler::GetDeviceByType(AudioDeviceType type) {
1530 for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
shenghao 2017/03/01 11:25:55 For all the "AudioDeviceMap::const_iterator", can
jennyz 2017/03/02 17:31:40 Done.
1531 it != audio_devices_.end(); ++it) {
1532 if (it->second.type == type)
1533 return &(it->second);
1534 }
1535 return nullptr;
1536 }
1537
1538 bool CrasAudioHandler::HasDualInternalMic() const {
1539 bool has_front_mic = false;
1540 bool has_rear_mic = false;
1541 for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
1542 it != audio_devices_.end(); ++it) {
1543 if (it->second.type == AUDIO_TYPE_FRONT_MIC)
1544 has_front_mic = true;
1545 else if (it->second.type == AUDIO_TYPE_REAR_MIC)
1546 has_rear_mic = true;
1547 if (has_front_mic && has_rear_mic)
1548 break;
1549 }
1550 return has_front_mic && has_rear_mic;
1551 }
1552
1553 bool CrasAudioHandler::IsFrontOrRearMic(const AudioDevice& device) const {
1554 return device.is_input && (device.type == AUDIO_TYPE_FRONT_MIC ||
1555 device.type == AUDIO_TYPE_REAR_MIC);
1556 }
1557
1558 bool CrasAudioHandler::IsCameraOn() const {
1559 return front_camera_on_ || rear_camera_on_;
1560 }
1561
1562 bool CrasAudioHandler::HasExternalDevice(bool is_input) const {
shenghao 2017/03/01 11:25:55 It seems that this method is only called in one pl
jennyz 2017/03/02 17:31:40 I would rather keep it just in case it could be us
1563 for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
1564 it != audio_devices_.end(); ++it) {
1565 if (is_input == it->second.is_input && it->second.IsExternalDevice())
1566 return true;
1567 }
1568 return false;
1569 }
1570
1426 } // namespace chromeos 1571 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698