Index: chromeos/audio/cras_audio_handler.cc |
diff --git a/chromeos/audio/cras_audio_handler.cc b/chromeos/audio/cras_audio_handler.cc |
index 444eab643cbb4ab81cc8aef0975e9c0b7199c49c..2e40388d783f5118e1fc98554c3696b51c6cae57 100644 |
--- a/chromeos/audio/cras_audio_handler.cc |
+++ b/chromeos/audio/cras_audio_handler.cc |
@@ -41,7 +41,7 @@ const std::vector<double> kStereoToMono = {0.5, 0.5, 0.5, 0.5}; |
// Mixer matrix, [1, 0; 0, 1] |
const std::vector<double> kStereoToStereo = {1, 0, 0, 1}; |
-static CrasAudioHandler* g_cras_audio_handler = NULL; |
+static CrasAudioHandler* g_cras_audio_handler = nullptr; |
bool IsSameAudioDevice(const AudioDevice& a, const AudioDevice& b) { |
return a.stable_device_id == b.stable_device_id && a.is_input == b.is_input && |
@@ -111,12 +111,12 @@ void CrasAudioHandler::InitializeForTesting() { |
void CrasAudioHandler::Shutdown() { |
CHECK(g_cras_audio_handler); |
delete g_cras_audio_handler; |
- g_cras_audio_handler = NULL; |
+ g_cras_audio_handler = nullptr; |
} |
// static |
bool CrasAudioHandler::IsInitialized() { |
- return g_cras_audio_handler != NULL; |
+ return g_cras_audio_handler != nullptr; |
} |
// static |
@@ -127,11 +127,80 @@ CrasAudioHandler* CrasAudioHandler::Get() { |
} |
void CrasAudioHandler::OnVideoCaptureStarted(media::VideoFacingMode facing) { |
- // TODO(jennyz): Switch active audio device according to video facing. |
+ // Do nothing if the device doesn't have both front and rear microphones. |
+ if (!HasDualInternalMic()) |
+ return; |
+ |
+ bool camera_is_already_on = IsCameraOn(); |
+ switch (facing) { |
+ case media::MEDIA_VIDEO_FACING_USER: |
+ front_camera_on_ = true; |
+ break; |
+ case media::MEDIA_VIDEO_FACING_ENVIRONMENT: |
+ rear_camera_on_ = true; |
+ break; |
+ default: |
+ LOG_IF(WARNING, facing == media::NUM_MEDIA_VIDEO_FACING_MODES) |
+ << "On the device with dual microphone, got video capture " |
+ << "notification with invalid camera facing mode value"; |
+ return; |
+ } |
+ |
+ // If the camera is already on before this notification, don't change active |
+ // input. In the case that both cameras are turned on at the same time, we |
+ // won't change the active input after the first camera is turned on. We only |
+ // support the use case of one camera on at a time. The third party |
+ // developer can turn on/off both microphones with extension api if they like |
+ // to. |
+ if (camera_is_already_on) |
+ return; |
+ |
+ // If the current active input is an external device, keep it. |
+ const AudioDevice* active_input = GetDeviceFromId(active_input_node_id_); |
+ if (active_input && active_input->IsExternalDevice()) |
+ return; |
+ |
+ // Activate the correct mic for the current active camera. |
+ ActivateMicForCamera(facing); |
} |
void CrasAudioHandler::OnVideoCaptureStopped(media::VideoFacingMode facing) { |
- // TODO(jennyz): Switch active audio device according to video facing. |
+ // Do nothing if the device doesn't have both front and rear microphones. |
+ if (!HasDualInternalMic()) |
+ return; |
+ |
+ switch (facing) { |
+ case media::MEDIA_VIDEO_FACING_USER: |
+ front_camera_on_ = false; |
+ break; |
+ case media::MEDIA_VIDEO_FACING_ENVIRONMENT: |
+ rear_camera_on_ = false; |
+ break; |
+ default: |
+ LOG_IF(WARNING, facing == media::NUM_MEDIA_VIDEO_FACING_MODES) |
+ << "On the device with dual microphone, got video capture " |
+ << "notification with invalid camera facing mode value"; |
+ return; |
+ } |
+ |
+ // If not all cameras are turned off, don't change active input. In the case |
+ // that both cameras are turned on at the same time before one of them is |
+ // stopped, we won't change active input until all of them are stopped. |
+ // We only support the use case of one camera on at a time. The third party |
+ // developer can turn on/off both microphones with extension api if they like |
+ // to. |
+ if (IsCameraOn()) |
+ return; |
+ |
+ // If the current active input is an external device, keep it. |
+ const AudioDevice* active_input = GetDeviceFromId(active_input_node_id_); |
+ if (active_input && active_input->IsExternalDevice()) |
+ return; |
+ |
+ // Switch to front mic properly. |
+ DeviceActivateType activated_by = |
+ HasExternalDevice(true) ? ACTIVATE_BY_USER : ACTIVATE_BY_PRIORITY; |
+ SwitchToDevice(*GetDeviceByType(AUDIO_TYPE_FRONT_MIC), true, activated_by); |
} |
void CrasAudioHandler::AddAudioObserver(AudioObserver* observer) { |
@@ -143,7 +212,7 @@ void CrasAudioHandler::RemoveAudioObserver(AudioObserver* observer) { |
} |
bool CrasAudioHandler::HasKeyboardMic() { |
- return GetKeyboardMic() != NULL; |
+ return GetKeyboardMic() != nullptr; |
} |
bool CrasAudioHandler::IsOutputMuted() { |
@@ -218,9 +287,10 @@ uint64_t CrasAudioHandler::GetPrimaryActiveInputNode() const { |
void CrasAudioHandler::GetAudioDevices(AudioDeviceList* device_list) const { |
device_list->clear(); |
- for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
- it != audio_devices_.end(); ++it) |
- device_list->push_back(it->second); |
+ for (const auto& item : audio_devices_) { |
+ const AudioDevice& device = item.second; |
+ device_list->push_back(device); |
+ } |
} |
bool CrasAudioHandler::GetPrimaryActiveOutputDevice(AudioDevice* device) const { |
@@ -347,10 +417,8 @@ void CrasAudioHandler::SetActiveDevices(const AudioDeviceList& devices, |
} |
void CrasAudioHandler::SwapInternalSpeakerLeftRightChannel(bool swap) { |
- for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
- it != audio_devices_.end(); |
- ++it) { |
- const AudioDevice& device = it->second; |
+ for (const auto& item : audio_devices_) { |
+ const AudioDevice& device = item.second; |
if (!device.is_input && device.type == AUDIO_TYPE_INTERNAL_SPEAKER) { |
chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->SwapLeftRight( |
device.id, swap); |
@@ -387,10 +455,8 @@ bool CrasAudioHandler::has_alternative_output() const { |
void CrasAudioHandler::SetOutputVolumePercent(int volume_percent) { |
// Set all active devices to the same volume. |
- for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
- it != audio_devices_.end(); |
- it++) { |
- const AudioDevice& device = it->second; |
+ for (const auto& item : audio_devices_) { |
+ const AudioDevice& device = item.second; |
if (!device.is_input && device.active) |
SetOutputNodeVolumePercent(device.id, volume_percent); |
} |
@@ -406,10 +472,8 @@ void CrasAudioHandler::SetOutputVolumePercentWithoutNotifyingObservers( |
// TODO: Rename the 'Percent' to something more meaningful. |
void CrasAudioHandler::SetInputGainPercent(int gain_percent) { |
// TODO(jennyz): Should we set all input devices' gain to the same level? |
- for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
- it != audio_devices_.end(); |
- it++) { |
- const AudioDevice& device = it->second; |
+ for (const auto& item : audio_devices_) { |
+ const AudioDevice& device = item.second; |
if (device.is_input && device.active) |
SetInputNodeGainPercent(active_input_node_id_, gain_percent); |
} |
@@ -424,10 +488,8 @@ void CrasAudioHandler::SetOutputMute(bool mute_on) { |
return; |
// Save the mute state for all active output audio devices. |
- for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
- it != audio_devices_.end(); |
- it++) { |
- const AudioDevice& device = it->second; |
+ for (const auto& item : audio_devices_) { |
+ const AudioDevice& device = item.second; |
if (!device.is_input && device.active) { |
audio_pref_handler_->SetMuteValue(device, output_mute_on_); |
} |
@@ -468,9 +530,8 @@ void CrasAudioHandler::SetActiveDevice(const AudioDevice& active_device, |
NotifyActiveNodeChanged(active_device.is_input); |
// Save active state for the nodes. |
- for (AudioDeviceMap::iterator it = audio_devices_.begin(); |
- it != audio_devices_.end(); ++it) { |
- const AudioDevice& device = it->second; |
+ for (const auto& item : audio_devices_) { |
+ const AudioDevice& device = item.second; |
if (device.is_input != active_device.is_input) |
continue; |
SaveDeviceState(device, device.active, activate_by); |
@@ -604,7 +665,7 @@ CrasAudioHandler::~CrasAudioHandler() { |
RemoveObserver(this); |
if (audio_pref_handler_.get()) |
audio_pref_handler_->RemoveAudioPrefObserver(this); |
- audio_pref_handler_ = NULL; |
+ audio_pref_handler_ = nullptr; |
} |
void CrasAudioHandler::AudioClientRestarted() { |
@@ -712,28 +773,28 @@ void CrasAudioHandler::EmitLoginPromptVisibleCalled() { |
const AudioDevice* CrasAudioHandler::GetDeviceFromId(uint64_t device_id) const { |
AudioDeviceMap::const_iterator it = audio_devices_.find(device_id); |
if (it == audio_devices_.end()) |
- return NULL; |
+ return nullptr; |
return &(it->second); |
} |
const AudioDevice* CrasAudioHandler::GetDeviceFromStableDeviceId( |
uint64_t stable_device_id) const { |
- for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
- it != audio_devices_.end(); ++it) { |
- if (it->second.stable_device_id == stable_device_id) |
- return &(it->second); |
+ for (const auto& item : audio_devices_) { |
+ const AudioDevice& device = item.second; |
+ if (device.stable_device_id == stable_device_id) |
+ return &device; |
} |
- return NULL; |
+ return nullptr; |
} |
const AudioDevice* CrasAudioHandler::GetKeyboardMic() const { |
- for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
- it != audio_devices_.end(); it++) { |
- if (it->second.is_input && it->second.type == AUDIO_TYPE_KEYBOARD_MIC) |
- return &(it->second); |
+ for (const auto& item : audio_devices_) { |
+ const AudioDevice& device = item.second; |
+ if (device.is_input && device.type == AUDIO_TYPE_KEYBOARD_MIC) |
+ return &device; |
} |
- return NULL; |
+ return nullptr; |
} |
void CrasAudioHandler::SetupAudioInputState() { |
@@ -940,13 +1001,13 @@ bool CrasAudioHandler::ChangeActiveDevice( |
// Reset all other input or output devices' active status. The active audio |
// device from the previous user session can be remembered by cras, but not |
// in chrome. see crbug.com/273271. |
- for (AudioDeviceMap::iterator it = audio_devices_.begin(); |
- it != audio_devices_.end(); ++it) { |
- if (it->second.is_input == new_active_device.is_input && |
- it->second.id != new_active_device.id) { |
- it->second.active = false; |
- } else if (it->second.is_input == new_active_device.is_input && |
- it->second.id == new_active_device.id) { |
+ for (auto& item : audio_devices_) { |
+ AudioDevice& device = item.second; |
+ if (device.is_input == new_active_device.is_input && |
+ device.id != new_active_device.id) { |
+ device.active = false; |
+ } else if (device.is_input == new_active_device.is_input && |
+ device.id == new_active_device.id) { |
found_new_active_device = true; |
} |
} |
@@ -982,9 +1043,8 @@ bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes, |
bool* device_removed, |
bool* active_device_removed) { |
*device_removed = false; |
- for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
- it != audio_devices_.end(); ++it) { |
- const AudioDevice& device = it->second; |
+ for (const auto& item : audio_devices_) { |
+ const AudioDevice& device = item.second; |
if (is_input != device.is_input) |
continue; |
if (!IsDeviceInList(device, new_nodes)) { |
@@ -999,12 +1059,12 @@ bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes, |
bool new_or_changed_device = false; |
while (!new_discovered->empty()) |
new_discovered->pop(); |
- for (AudioNodeList::const_iterator it = new_nodes.begin(); |
- it != new_nodes.end(); ++it) { |
- if (is_input != it->is_input) |
+ |
+ for (const AudioNode& node : new_nodes) { |
+ if (is_input != node.is_input) |
continue; |
// Check if the new device is not in the old device list. |
- AudioDevice device(*it); |
+ AudioDevice device(node); |
DeviceStatus status = CheckDeviceStatus(device); |
if (status == NEW_DEVICE) |
new_discovered->push(device); |
@@ -1047,9 +1107,8 @@ bool CrasAudioHandler::GetActiveDeviceFromUserPref(bool is_input, |
AudioDevice* active_device) { |
bool found_active_device = false; |
bool last_active_device_activate_by_user = false; |
- for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
- it != audio_devices_.end(); ++it) { |
- AudioDevice device = it->second; |
+ for (const auto& item : audio_devices_) { |
+ const AudioDevice& device = item.second; |
if (device.is_input != is_input || !device.is_for_simple_usage()) |
continue; |
@@ -1183,8 +1242,17 @@ void CrasAudioHandler::HandleHotPlugDevice( |
void CrasAudioHandler::SwitchToTopPriorityDevice(bool is_input) { |
AudioDevice top_device = |
is_input ? input_devices_pq_.top() : output_devices_pq_.top(); |
- if (top_device.is_for_simple_usage()) |
- SwitchToDevice(top_device, true, ACTIVATE_BY_PRIORITY); |
+ if (!top_device.is_for_simple_usage()) |
+ return; |
+ |
+ // For the dual camera and dual microphone case, choose microphone |
+ // that is consistent to the active camera. |
+ if (IsFrontOrRearMic(top_device) && HasDualInternalMic() && IsCameraOn()) { |
+ ActivateInternalMicForActiveCamera(); |
+ return; |
+ } |
+ |
+ SwitchToDevice(top_device, true, ACTIVATE_BY_PRIORITY); |
} |
void CrasAudioHandler::SwitchToPreviousActiveDeviceIfAvailable(bool is_input) { |
@@ -1204,9 +1272,9 @@ void CrasAudioHandler::UpdateDevicesAndSwitchActive( |
const AudioNodeList& nodes) { |
size_t old_output_device_size = 0; |
size_t old_input_device_size = 0; |
- for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); |
- it != audio_devices_.end(); ++it) { |
- if (it->second.is_input) |
+ for (const auto& item : audio_devices_) { |
+ const AudioDevice& device = item.second; |
+ if (device.is_input) |
++old_input_device_size; |
else |
++old_output_device_size; |
@@ -1423,4 +1491,94 @@ void CrasAudioHandler::SetHDMIRediscoverGracePeriodForTesting( |
hdmi_rediscover_grace_period_duration_in_ms_ = duration_in_ms; |
} |
+void CrasAudioHandler::ActivateMicForCamera( |
+ media::VideoFacingMode camera_facing) { |
+ const AudioDevice* mic = GetMicForCamera(camera_facing); |
+ if (!mic || mic->active) |
+ return; |
+ |
+ SwitchToDevice(*mic, true, ACTIVATE_BY_CAMERA); |
+} |
+ |
+void CrasAudioHandler::ActivateInternalMicForActiveCamera() { |
+ DCHECK(IsCameraOn()); |
+ if (HasDualInternalMic()) { |
+ media::VideoFacingMode facing = front_camera_on_ |
+ ? media::MEDIA_VIDEO_FACING_USER |
+ : media::MEDIA_VIDEO_FACING_ENVIRONMENT; |
+ ActivateMicForCamera(facing); |
+ } |
+} |
+ |
+// For the dual microphone case, from user point of view, they only see internal |
+// microphone in UI. Chrome will make the best decision on which one to pick. |
+// If the camera is off, the front microphone should be picked as the default |
+// active microphone. Otherwise, it will switch to the microphone that |
+// matches the active camera, i.e. front microphone for front camera and |
+// rear microphone for rear camera. |
+void CrasAudioHandler::SwitchToFrontOrRearMic() { |
+ DCHECK(HasDualInternalMic()); |
+ if (IsCameraOn()) { |
+ ActivateInternalMicForActiveCamera(); |
+ } else { |
+ SwitchToDevice(*GetDeviceByType(AUDIO_TYPE_FRONT_MIC), true, |
+ ACTIVATE_BY_USER); |
+ } |
+} |
+ |
+const AudioDevice* CrasAudioHandler::GetMicForCamera( |
+ media::VideoFacingMode camera_facing) { |
+ switch (camera_facing) { |
+ case media::MEDIA_VIDEO_FACING_USER: |
+ return GetDeviceByType(AUDIO_TYPE_FRONT_MIC); |
+ case media::MEDIA_VIDEO_FACING_ENVIRONMENT: |
+ return GetDeviceByType(AUDIO_TYPE_REAR_MIC); |
+ default: |
+ NOTREACHED(); |
+ } |
+ return nullptr; |
+} |
+ |
+const AudioDevice* CrasAudioHandler::GetDeviceByType(AudioDeviceType type) { |
+ for (const auto& item : audio_devices_) { |
+ const AudioDevice& device = item.second; |
+ if (device.type == type) |
+ return &device; |
+ } |
+ return nullptr; |
+} |
+ |
+bool CrasAudioHandler::HasDualInternalMic() const { |
+ bool has_front_mic = false; |
+ bool has_rear_mic = false; |
+ for (const auto& item : audio_devices_) { |
+ const AudioDevice& device = item.second; |
+ if (device.type == AUDIO_TYPE_FRONT_MIC) |
+ has_front_mic = true; |
+ else if (device.type == AUDIO_TYPE_REAR_MIC) |
+ has_rear_mic = true; |
+ if (has_front_mic && has_rear_mic) |
+ break; |
+ } |
+ return has_front_mic && has_rear_mic; |
+} |
+ |
+bool CrasAudioHandler::IsFrontOrRearMic(const AudioDevice& device) const { |
+ return device.is_input && (device.type == AUDIO_TYPE_FRONT_MIC || |
+ device.type == AUDIO_TYPE_REAR_MIC); |
+} |
+ |
+bool CrasAudioHandler::IsCameraOn() const { |
+ return front_camera_on_ || rear_camera_on_; |
+} |
+ |
+bool CrasAudioHandler::HasExternalDevice(bool is_input) const { |
+ for (const auto& item : audio_devices_) { |
+ const AudioDevice& device = item.second; |
+ if (is_input == device.is_input && device.IsExternalDevice()) |
+ return true; |
+ } |
+ return false; |
+} |
+ |
} // namespace chromeos |