#include "ash/system/audio/audio_effects_controller.h"
#include <memory>
#include "ash/accessibility/accessibility_controller_impl.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/video_conference/effects/video_conference_tray_effects_manager.h"
#include "ash/system/video_conference/effects/video_conference_tray_effects_manager_types.h"
#include "ash/system/video_conference/video_conference_tray_controller.h"
#include "base/notreached.h"
#include "chromeos/ash/components/audio/cras_audio_handler.h"
#include "components/live_caption/caption_util.h"
#include "ui/base/l10n/l10n_util.h"
namespace ash {
AudioEffectsController::AudioEffectsController() {
auto* session_controller = Shell::Get()->session_controller();
DCHECK(session_controller);
session_observation_.Observe(session_controller);
CrasAudioHandler::Get()->AddAudioObserver(this);
}
AudioEffectsController::~AudioEffectsController() {
CrasAudioHandler::Get()->RemoveAudioObserver(this);
VideoConferenceTrayEffectsManager& effects_manager =
VideoConferenceTrayController::Get()->effects_manager();
if (effects_manager.IsDelegateRegistered(this)) {
effects_manager.UnregisterDelegate(this);
}
}
bool IsNoiseCancellationSupported() {
auto* cras_audio_handler = CrasAudioHandler::Get();
return cras_audio_handler->IsNoiseCancellationSupportedForDevice(
cras_audio_handler->GetPrimaryActiveInputNode());
}
bool AudioEffectsController::IsEffectSupported(VcEffectId effect_id) {
switch (effect_id) {
case VcEffectId::kNoiseCancellation:
return IsNoiseCancellationSupported();
case VcEffectId::kLiveCaption:
return captions::IsLiveCaptionFeatureSupported();
case VcEffectId::kBackgroundBlur:
case VcEffectId::kPortraitRelighting:
case VcEffectId::kTestEffect:
NOTREACHED();
return false;
}
}
absl::optional<int> AudioEffectsController::GetEffectState(
VcEffectId effect_id) {
switch (effect_id) {
case VcEffectId::kNoiseCancellation:
return CrasAudioHandler::Get()->GetNoiseCancellationState() ? 1 : 0;
case VcEffectId::kLiveCaption:
return Shell::Get()->accessibility_controller()->live_caption().enabled()
? 1
: 0;
case VcEffectId::kBackgroundBlur:
case VcEffectId::kPortraitRelighting:
case VcEffectId::kTestEffect:
NOTREACHED();
return absl::nullopt;
}
}
void AudioEffectsController::OnEffectControlActivated(
VcEffectId effect_id,
absl::optional<int> value) {
switch (effect_id) {
case VcEffectId::kNoiseCancellation: {
CrasAudioHandler* audio_handler = CrasAudioHandler::Get();
bool new_state = !audio_handler->GetNoiseCancellationState();
audio_handler->SetNoiseCancellationState(
new_state,
CrasAudioHandler::AudioSettingsChangeSource::kVideoConferenceTray);
return;
}
case VcEffectId::kLiveCaption: {
AccessibilityControllerImpl* controller =
Shell::Get()->accessibility_controller();
controller->live_caption().SetEnabled(
!controller->live_caption().enabled());
return;
}
case VcEffectId::kBackgroundBlur:
case VcEffectId::kPortraitRelighting:
case VcEffectId::kTestEffect:
NOTREACHED();
return;
}
}
void AudioEffectsController::OnActiveUserPrefServiceChanged(
PrefService* pref_service) {
VideoConferenceTrayEffectsManager& effects_manager =
VideoConferenceTrayController::Get()->effects_manager();
if (effects_manager.IsDelegateRegistered(this)) {
return;
}
noise_cancellation_supported_ =
IsEffectSupported(VcEffectId::kNoiseCancellation);
const bool live_caption_supported =
IsEffectSupported(VcEffectId::kLiveCaption);
if (noise_cancellation_supported_) {
AddNoiseCancellationEffect();
}
if (live_caption_supported) {
AddLiveCaptionEffect();
}
if (noise_cancellation_supported_ || live_caption_supported) {
effects_manager.RegisterDelegate(this);
}
}
void AudioEffectsController::OnActiveInputNodeChanged() {
const bool noise_cancellation_supported = IsNoiseCancellationSupported();
if (noise_cancellation_supported_ == noise_cancellation_supported) {
return;
}
noise_cancellation_supported_ = noise_cancellation_supported;
const bool effect_added = GetEffectById(VcEffectId::kNoiseCancellation);
if (noise_cancellation_supported_ && !effect_added) {
AddNoiseCancellationEffect();
} else if (!noise_cancellation_supported_ && effect_added) {
RemoveEffect(VcEffectId::kNoiseCancellation);
}
VideoConferenceTrayController::Get()
->effects_manager()
.NotifyEffectSupportStateChanged(VcEffectId::kNoiseCancellation,
noise_cancellation_supported_);
}
void AudioEffectsController::AddNoiseCancellationEffect() {
std::unique_ptr<VcHostedEffect> effect = std::make_unique<VcHostedEffect>(
VcEffectType::kToggle,
base::BindRepeating(&AudioEffectsController::GetEffectState,
base::Unretained(this),
VcEffectId::kNoiseCancellation),
VcEffectId::kNoiseCancellation);
auto effect_state = std::make_unique<VcEffectState>(
&kVideoConferenceNoiseCancellationOnIcon,
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_AUDIO_INPUT_NOISE_CANCELLATION),
IDS_ASH_STATUS_TRAY_AUDIO_INPUT_NOISE_CANCELLATION,
base::BindRepeating(&AudioEffectsController::OnEffectControlActivated,
weak_factory_.GetWeakPtr(),
VcEffectId::kNoiseCancellation,
0));
effect_state->set_disabled_icon(&kVideoConferenceNoiseCancellationOffIcon);
effect->AddState(std::move(effect_state));
effect->set_dependency_flags(VcHostedEffect::ResourceDependency::kMicrophone);
AddEffect(std::move(effect));
}
void AudioEffectsController::AddLiveCaptionEffect() {
std::unique_ptr<VcHostedEffect> effect = std::make_unique<VcHostedEffect>(
VcEffectType::kToggle,
base::BindRepeating(&AudioEffectsController::GetEffectState,
base::Unretained(this), VcEffectId::kLiveCaption),
VcEffectId::kLiveCaption);
auto effect_state = std::make_unique<VcEffectState>(
&kVideoConferenceLiveCaptionOnIcon,
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_LIVE_CAPTION),
IDS_ASH_STATUS_TRAY_LIVE_CAPTION,
base::BindRepeating(&AudioEffectsController::OnEffectControlActivated,
weak_factory_.GetWeakPtr(),
VcEffectId::kLiveCaption,
0));
effect_state->set_disabled_icon(&kVideoConferenceLiveCaptionOffIcon);
effect->AddState(std::move(effect_state));
AddEffect(std::move(effect));
}
}