chromium/chromeos/ash/components/audio/audio_devices_pref_handler_impl.cc

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/ash/components/audio/audio_devices_pref_handler_impl.h"

#include <stdint.h>

#include <algorithm>
#include <optional>
#include <unordered_set>

#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chromeos/ash/components/audio/audio_device.h"
#include "chromeos/ash/components/audio/audio_device_id.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"

namespace ash {
namespace {

// Values used for muted preference.
const int kPrefMuteOff = 0;
const int kPrefMuteOn = 1;

// Prefs keys.
const char kActiveKey[] = "active";
const char kActivateByUserKey[] = "activate_by_user";

// Migrates an entry associated with |device|'s v1 stable device ID in
// |settings| to the key derived from |device|'s v2 stable device ID
// (which is expected to be equal to |intended_key|), if the entry can
// be found.
// Returns whether the migration occurred.
bool MigrateDeviceIdInSettings(base::Value::Dict* settings,
                               const std::string& intended_key,
                               const AudioDevice& device) {
  if (device.stable_device_id_version == 1)
    return false;

  DCHECK_EQ(2, device.stable_device_id_version);

  std::string old_device_id = GetVersionedDeviceIdString(device, 1);
  std::optional<base::Value> value = settings->Extract(old_device_id);
  if (!value)
    return false;

  DCHECK_EQ(intended_key, GetDeviceIdString(device));
  settings->SetByDottedPath(intended_key, std::move(*value));
  return true;
}

}  // namespace

double AudioDevicesPrefHandlerImpl::GetOutputVolumeValue(
    const AudioDevice* device) {
  if (!device)
    return kDefaultOutputVolumePercent;
  else
    return GetOutputVolumePrefValue(*device);
}

double AudioDevicesPrefHandlerImpl::GetInputGainValue(
    const AudioDevice* device) {
  DCHECK(device);
  return GetInputGainPrefValue(*device);
}

void AudioDevicesPrefHandlerImpl::SetVolumeGainValue(const AudioDevice& device,
                                                     double value) {
  // TODO(baileyberro): Refactor public interface to use two explicit methods.
  device.is_input ? SetInputGainPrefValue(device, value)
                  : SetOutputVolumePrefValue(device, value);
}

void AudioDevicesPrefHandlerImpl::SetOutputVolumePrefValue(
    const AudioDevice& device,
    double value) {
  DCHECK(!device.is_input);
  // Use this opportunity to remove device record under deprecated device ID,
  // if one exists.
  if (device.stable_device_id_version == 2) {
    std::string old_device_id = GetVersionedDeviceIdString(device, 1);
    device_volume_settings_.Remove(old_device_id);
  }
  device_volume_settings_.Set(GetDeviceIdString(device), value);

  SaveDevicesVolumePref();
}

void AudioDevicesPrefHandlerImpl::SetInputGainPrefValue(
    const AudioDevice& device,
    double value) {
  DCHECK(device.is_input);

  const std::string device_id = GetDeviceIdString(device);

  // Use this opportunity to remove input device record from
  // |device_volume_settings_|.
  // TODO(baileyberro): Remove this check in M94.
  if (device_volume_settings_.Find(device_id)) {
    device_volume_settings_.Remove(device_id);
    SaveDevicesVolumePref();
  }

  device_gain_settings_.Set(device_id, value);
  SaveDevicesGainPref();
}

bool AudioDevicesPrefHandlerImpl::GetMuteValue(const AudioDevice& device) {
  std::string device_id_str = GetDeviceIdString(device);
  if (!device_mute_settings_.Find(device_id_str))
    MigrateDeviceMuteSettings(device_id_str, device);

  int mute =
      device_mute_settings_.FindInt(device_id_str).value_or(kPrefMuteOff);
  return (mute == kPrefMuteOn);
}

void AudioDevicesPrefHandlerImpl::SetMuteValue(const AudioDevice& device,
                                               bool mute) {
  // Use this opportunity to remove device record under deprecated device ID,
  // if one exists.
  if (device.stable_device_id_version == 2) {
    std::string old_device_id = GetVersionedDeviceIdString(device, 1);
    device_mute_settings_.Remove(old_device_id);
  }
  device_mute_settings_.Set(GetDeviceIdString(device),
                            mute ? kPrefMuteOn : kPrefMuteOff);
  SaveDevicesMutePref();
}

void AudioDevicesPrefHandlerImpl::SetDeviceActive(const AudioDevice& device,
                                                  bool active,
                                                  bool activate_by_user) {
  base::Value::Dict dict;
  dict.Set(kActiveKey, active);
  if (active)
    dict.Set(kActivateByUserKey, activate_by_user);

  // Use this opportunity to remove device record under deprecated device ID,
  // if one exists.
  if (device.stable_device_id_version == 2) {
    std::string old_device_id = GetVersionedDeviceIdString(device, 1);
    device_state_settings_.Remove(old_device_id);
  }
  device_state_settings_.SetByDottedPath(GetDeviceIdString(device),
                                         std::move(dict));
  SaveDevicesStatePref();
}

bool AudioDevicesPrefHandlerImpl::GetDeviceActive(const AudioDevice& device,
                                                  bool* active,
                                                  bool* activate_by_user) {
  const std::string device_id_str = GetDeviceIdString(device);
  if (!device_state_settings_.Find(device_id_str) &&
      !MigrateDevicesStatePref(device_id_str, device)) {
    return false;
  }

  base::Value::Dict* dict =
      device_state_settings_.FindDictByDottedPath(device_id_str);
  if (!dict) {
    LOG(ERROR) << "Could not get device state for device:" << device.ToString();
    return false;
  }

  std::optional<bool> active_opt = dict->FindBool(kActiveKey);
  if (!active_opt.has_value()) {
    LOG(ERROR) << "Could not get active value for device:" << device.ToString();
    return false;
  }

  *active = active_opt.value();
  if (!*active)
    return true;

  std::optional<bool> activate_by_user_opt = dict->FindBool(kActivateByUserKey);
  if (!activate_by_user_opt.has_value()) {
    LOG(ERROR) << "Could not get activate_by_user value for previously "
                  "active device:"
               << device.ToString();
    return false;
  }

  *activate_by_user = activate_by_user_opt.value();
  return true;
}

void AudioDevicesPrefHandlerImpl::SetUserPriorityHigherThan(
    const AudioDevice& target,
    const AudioDevice* base) {
  int t = GetUserPriority(target);
  int b = 0;
  if (base) {
    b = GetUserPriority(*base);
  }

  // Don't need to update the user priority of `target` if it's already has
  // higher priority than base.
  if (t > b)
    return;

  auto target_id = GetDeviceIdString(target);
  base::Value::Dict& priority_prefs =
      target.is_input ? input_device_user_priority_settings_
                      : output_device_user_priority_settings_;

  if (t != kUserPriorityNone) {
    // before: [. . . t - - - b . . .]
    // after:  [. . . - - - b t . . .]
    for (auto it : priority_prefs) {
      if (it.second.GetInt() > t && it.second.GetInt() <= b)
        it.second = base::Value(it.second.GetInt() - 1);
    }
    priority_prefs.Set(target_id, b);
  } else {
    // before: [. . . b + + +]
    // after : [. . . b t + + +]
    for (auto it : priority_prefs) {
      if (it.second.GetInt() > b)
        it.second = base::Value(it.second.GetInt() + 1);
    }
    priority_prefs.Set(target_id, b + 1);
  }

  if (target.is_input) {
    SaveInputDevicesUserPriorityPref();
  } else {
    SaveOutputDevicesUserPriorityPref();
  }
}

int AudioDevicesPrefHandlerImpl::GetUserPriority(const AudioDevice& device) {
  if (device.is_input) {
    return input_device_user_priority_settings_
        .FindInt(GetDeviceIdString(device))
        .value_or(kUserPriorityNone);
    ;
  } else {
    return output_device_user_priority_settings_
        .FindInt(GetDeviceIdString(device))
        .value_or(kUserPriorityNone);
    ;
  }
}

const std::optional<uint64_t>
AudioDevicesPrefHandlerImpl::GetPreferredDeviceFromPreferenceSet(
    bool is_input,
    const AudioDeviceList& devices) {
  const base::Value::Dict& device_pref_set =
      is_input ? input_device_preference_set_settings_
               : output_device_preference_set_settings_;
  const std::string ids = GetDeviceSetIdString(devices);
  const std::string* id_string = device_pref_set.FindString(ids);
  return id_string ? ParseDeviceId(*id_string) : std::nullopt;
}

void AudioDevicesPrefHandlerImpl::UpdateDevicePreferenceSet(
    const AudioDeviceList& devices,
    const AudioDevice& preferred_device) {
  // Double check that |preferred_device| exists in |devices|.
  auto it = std::find_if(
      devices.begin(), devices.end(), [&](const AudioDevice& device) {
        return device.stable_device_id == preferred_device.stable_device_id;
      });

  if (it == devices.end()) {
    LOG(ERROR)
        << "The preferred_device does not exist in the given device list. "
        << preferred_device.ToString();
    return;
  }

  bool is_input = preferred_device.is_input;
  base::Value::Dict& device_pref_set =
      is_input ? input_device_preference_set_settings_
               : output_device_preference_set_settings_;
  device_pref_set.Set(GetDeviceSetIdString(devices),
                      GetDeviceIdString(preferred_device));

  if (is_input) {
    SaveInputDevicePreferenceSetPref();
  } else {
    SaveOutputDevicePreferenceSetPref();
  }
}

const base::Value::List&
AudioDevicesPrefHandlerImpl::GetMostRecentActivatedDeviceIdList(bool is_input) {
  return is_input ? most_recent_activated_input_device_ids_
                  : most_recent_activated_output_device_ids_;
}

void AudioDevicesPrefHandlerImpl::UpdateMostRecentActivatedDeviceIdList(
    const AudioDevice& device) {
  base::Value::List& ids = device.is_input
                               ? most_recent_activated_input_device_ids_
                               : most_recent_activated_output_device_ids_;
  std::string target_device_id = GetDeviceIdString(device);
  // Find if this device is already in the list, remove it if so.
  for (auto it = ids.begin(); it != ids.end(); it++) {
    if (target_device_id == *it) {
      ids.erase(it);
      break;
    }
  }

  // Add this device to the end of the list.
  ids.Append(target_device_id);

  if (device.is_input) {
    SaveMostRecentActivatedInputDeviceIdsPref();
  } else {
    SaveMostRecentActivatedOutputDeviceIdsPref();
  }
}

void AudioDevicesPrefHandlerImpl::DropLeastRecentlySeenDevices(
    const std::vector<AudioDevice>& connected_devices,
    size_t keep_devices) {
  ScopedDictPrefUpdate last_seen_update(local_state_,
                                        prefs::kAudioDevicesLastSeen);
  base::Value::Dict& last_seen = last_seen_update.Get();

  // Set timestamp of connected devices.
  double time = base::Time::Now().InSecondsFSinceUnixEpoch();
  for (AudioDevice device : connected_devices) {
    last_seen.Set(GetDeviceIdString(device), time);
  }

  // Order devices by last seen timestamp.
  std::vector<std::string> recently_seen_ids;
  for (auto device : last_seen) {
    recently_seen_ids.push_back(device.first);
  }
  std::sort(recently_seen_ids.begin(), recently_seen_ids.end(),
            [&](const std::string& i, const std::string& j) {
              // More recent device first.
              return last_seen.FindDouble(i).value_or(0) >
                     last_seen.FindDouble(j).value_or(0);
            });

  // Keep `keep_devices` recently seen devices.
  while (recently_seen_ids.size() > keep_devices &&
         last_seen.FindDouble(recently_seen_ids.back()).value_or(0) != time) {
    last_seen.Remove(recently_seen_ids.back());
    recently_seen_ids.pop_back();
  }

  // Remove preferences if not seen recently, keeping the most recent
  // `keep_devices` devices.
  // TODO(aaronyu): Consider also remove volume/mute/gain preferences.
  for (base::Value::Dict& settings :
       std::initializer_list<std::reference_wrapper<base::Value::Dict>>{
           input_device_user_priority_settings_,
           output_device_user_priority_settings_}) {
    std::vector<std::string> to_remove;
    for (auto entry : settings) {
      const std::string& id = entry.first;
      if (last_seen.Find(id) == nullptr) {
        to_remove.push_back(id);
      }
    }
    for (const std::string& id : to_remove) {
      settings.Remove(id);
    }
  }
  SaveInputDevicesUserPriorityPref();
  SaveOutputDevicesUserPriorityPref();
}

bool AudioDevicesPrefHandlerImpl::GetAudioOutputAllowedValue() const {
  return local_state_->GetBoolean(prefs::kAudioOutputAllowed);
}

void AudioDevicesPrefHandlerImpl::AddAudioPrefObserver(
    AudioPrefObserver* observer) {
  observers_.AddObserver(observer);
}

void AudioDevicesPrefHandlerImpl::RemoveAudioPrefObserver(
    AudioPrefObserver* observer) {
  observers_.RemoveObserver(observer);
}

double AudioDevicesPrefHandlerImpl::GetOutputVolumePrefValue(
    const AudioDevice& device) {
  DCHECK(!device.is_input);
  std::string device_id_str = GetDeviceIdString(device);
  if (!device_volume_settings_.Find(device_id_str))
    MigrateDeviceVolumeGainSettings(device_id_str, device);
  return *device_volume_settings_.FindDouble(device_id_str);
}

double AudioDevicesPrefHandlerImpl::GetInputGainPrefValue(
    const AudioDevice& device) {
  DCHECK(device.is_input);
  std::string device_id_str = GetDeviceIdString(device);
  if (!device_gain_settings_.Find(device_id_str))
    SetInputGainPrefValue(device, kDefaultInputGainPercent);
  return *device_gain_settings_.FindDouble(device_id_str);
}

double AudioDevicesPrefHandlerImpl::GetDeviceDefaultOutputVolume(
    const AudioDevice& device) {
  switch (device.type) {
    case AudioDeviceType::kBluetooth:
      return kDefaultBluetoothOutputVolumePercent;
    case AudioDeviceType::kUsb:
      return kDefaultUsbOutputVolumePercent;
    case AudioDeviceType::kHdmi:
      return kDefaultHdmiOutputVolumePercent;
    default:
      return kDefaultOutputVolumePercent;
  }
}

bool AudioDevicesPrefHandlerImpl::GetNoiseCancellationState() {
  return local_state_->GetBoolean(prefs::kInputNoiseCancellationEnabled);
}

void AudioDevicesPrefHandlerImpl::SetNoiseCancellationState(
    bool noise_cancellation_state) {
  local_state_->SetBoolean(prefs::kInputNoiseCancellationEnabled,
                           noise_cancellation_state);
}

bool AudioDevicesPrefHandlerImpl::GetStyleTransferState() const {
  return local_state_->GetBoolean(prefs::kInputStyleTransferEnabled);
}

void AudioDevicesPrefHandlerImpl::SetStyleTransferState(
    bool style_transfer_state) {
  local_state_->SetBoolean(prefs::kInputStyleTransferEnabled,
                           style_transfer_state);
}

bool AudioDevicesPrefHandlerImpl::GetForceRespectUiGainsState() {
  return local_state_->GetBoolean(prefs::kInputForceRespectUiGainsEnabled);
}

void AudioDevicesPrefHandlerImpl::SetForceRespectUiGainsState(
    bool force_respect_ui_gains_state) {
  local_state_->SetBoolean(prefs::kInputForceRespectUiGainsEnabled,
                           force_respect_ui_gains_state);
}

bool AudioDevicesPrefHandlerImpl::GetHfpMicSrState() {
  return local_state_->GetBoolean(prefs::kHandsFreeProfileInputSuperResolution);
}

void AudioDevicesPrefHandlerImpl::SetHfpMicSrState(bool hfp_mic_sr_state) {
  local_state_->SetBoolean(prefs::kHandsFreeProfileInputSuperResolution,
                           hfp_mic_sr_state);
}

AudioDevicesPrefHandlerImpl::AudioDevicesPrefHandlerImpl(
    PrefService* local_state)
    : local_state_(local_state) {
  InitializePrefObservers();

  LoadDevicesMutePref();
  LoadDevicesVolumePref();
  LoadDevicesGainPref();
  LoadInputDevicesUserPriorityPref();
  LoadOutputDevicesUserPriorityPref();

  // Reset set-based audio selection preference pref for testing purpose.
  if (features::IsResetAudioSelectionImprovementPrefEnabled()) {
    SaveDevicesStatePref();
    SaveInputDevicePreferenceSetPref();
    SaveOutputDevicePreferenceSetPref();
    SaveMostRecentActivatedInputDeviceIdsPref();
    SaveMostRecentActivatedOutputDeviceIdsPref();
  } else {
    LoadDevicesStatePref();
    LoadInputDevicePreferenceSetPref();
    LoadOutputDevicePreferenceSetPref();
    LoadMostRecentActivatedInputDeviceIdsPref();
    LoadMostRecentActivatedOutputDeviceIdsPref();
  }
}

AudioDevicesPrefHandlerImpl::~AudioDevicesPrefHandlerImpl() = default;

void AudioDevicesPrefHandlerImpl::InitializePrefObservers() {
  pref_change_registrar_.Init(local_state_);
  base::RepeatingClosure callback =
      base::BindRepeating(&AudioDevicesPrefHandlerImpl::NotifyAudioPolicyChange,
                          base::Unretained(this));
  pref_change_registrar_.Add(prefs::kAudioOutputAllowed, callback);
}

void AudioDevicesPrefHandlerImpl::LoadDevicesMutePref() {
  const base::Value::Dict& mute_prefs =
      local_state_->GetDict(prefs::kAudioDevicesMute);
  device_mute_settings_ = mute_prefs.Clone();
}

void AudioDevicesPrefHandlerImpl::SaveDevicesMutePref() {
  local_state_->SetDict(prefs::kAudioDevicesMute,
                        device_mute_settings_.Clone());
}

void AudioDevicesPrefHandlerImpl::LoadDevicesVolumePref() {
  const base::Value::Dict& volume_prefs =
      local_state_->GetDict(prefs::kAudioDevicesVolumePercent);
  device_volume_settings_ = volume_prefs.Clone();
}

void AudioDevicesPrefHandlerImpl::SaveDevicesVolumePref() {
  local_state_->SetDict(prefs::kAudioDevicesVolumePercent,
                        device_volume_settings_.Clone());
}

void AudioDevicesPrefHandlerImpl::LoadDevicesGainPref() {
  const base::Value::Dict& gain_prefs =
      local_state_->GetDict(prefs::kAudioDevicesGainPercent);
  device_gain_settings_ = gain_prefs.Clone();
}

void AudioDevicesPrefHandlerImpl::SaveDevicesGainPref() {
  local_state_->SetDict(prefs::kAudioDevicesGainPercent,
                        device_gain_settings_.Clone());
}

void AudioDevicesPrefHandlerImpl::LoadDevicesStatePref() {
  const base::Value::Dict& state_prefs =
      local_state_->GetDict(prefs::kAudioDevicesState);
  device_state_settings_ = state_prefs.Clone();
}

void AudioDevicesPrefHandlerImpl::SaveDevicesStatePref() {
  local_state_->SetDict(prefs::kAudioDevicesState,
                        device_state_settings_.Clone());
}

void AudioDevicesPrefHandlerImpl::LoadInputDevicesUserPriorityPref() {
  const base::Value::Dict& priority_prefs =
      local_state_->GetDict(prefs::kAudioInputDevicesUserPriority);
  input_device_user_priority_settings_ = priority_prefs.Clone();
}

void AudioDevicesPrefHandlerImpl::SaveInputDevicesUserPriorityPref() {
  local_state_->SetDict(prefs::kAudioInputDevicesUserPriority,
                        input_device_user_priority_settings_.Clone());
}

void AudioDevicesPrefHandlerImpl::LoadOutputDevicesUserPriorityPref() {
  const base::Value::Dict& priority_prefs =
      local_state_->GetDict(prefs::kAudioOutputDevicesUserPriority);
  output_device_user_priority_settings_ = priority_prefs.Clone();
}

void AudioDevicesPrefHandlerImpl::SaveOutputDevicesUserPriorityPref() {
  local_state_->SetDict(prefs::kAudioOutputDevicesUserPriority,
                        output_device_user_priority_settings_.Clone());
}

void AudioDevicesPrefHandlerImpl::LoadInputDevicePreferenceSetPref() {
  const base::Value::Dict& preference_set_prefs =
      local_state_->GetDict(prefs::kAudioInputDevicePreferenceSet);
  input_device_preference_set_settings_ = preference_set_prefs.Clone();
}

void AudioDevicesPrefHandlerImpl::SaveInputDevicePreferenceSetPref() {
  local_state_->SetDict(prefs::kAudioInputDevicePreferenceSet,
                        input_device_preference_set_settings_.Clone());
}

void AudioDevicesPrefHandlerImpl::LoadOutputDevicePreferenceSetPref() {
  const base::Value::Dict& preference_set_prefs =
      local_state_->GetDict(prefs::kAudioOutputDevicePreferenceSet);
  output_device_preference_set_settings_ = preference_set_prefs.Clone();
}

void AudioDevicesPrefHandlerImpl::SaveMostRecentActivatedInputDeviceIdsPref() {
  local_state_->SetList(prefs::kAudioMostRecentActivatedInputDeviceIds,
                        most_recent_activated_input_device_ids_.Clone());
}

void AudioDevicesPrefHandlerImpl::LoadMostRecentActivatedInputDeviceIdsPref() {
  const base::Value::List& id_list_pref =
      local_state_->GetList(prefs::kAudioMostRecentActivatedInputDeviceIds);
  most_recent_activated_input_device_ids_ = id_list_pref.Clone();
}

void AudioDevicesPrefHandlerImpl::SaveMostRecentActivatedOutputDeviceIdsPref() {
  local_state_->SetList(prefs::kAudioMostRecentActivatedOutputDeviceIds,
                        most_recent_activated_output_device_ids_.Clone());
}

void AudioDevicesPrefHandlerImpl::LoadMostRecentActivatedOutputDeviceIdsPref() {
  const base::Value::List& id_list_pref =
      local_state_->GetList(prefs::kAudioMostRecentActivatedOutputDeviceIds);
  most_recent_activated_output_device_ids_ = id_list_pref.Clone();
}

void AudioDevicesPrefHandlerImpl::SaveOutputDevicePreferenceSetPref() {
  local_state_->SetDict(prefs::kAudioOutputDevicePreferenceSet,
                        output_device_preference_set_settings_.Clone());
}

bool AudioDevicesPrefHandlerImpl::MigrateDevicesStatePref(
    const std::string& device_key,
    const AudioDevice& device) {
  if (!MigrateDeviceIdInSettings(&device_state_settings_, device_key, device)) {
    return false;
  }

  SaveDevicesStatePref();
  return true;
}

void AudioDevicesPrefHandlerImpl::MigrateDeviceMuteSettings(
    const std::string& device_key,
    const AudioDevice& device) {
  if (!MigrateDeviceIdInSettings(&device_mute_settings_, device_key, device)) {
    // If there was no recorded value for deprecated device ID, use value from
    // global mute pref.
    int old_mute = local_state_->GetInteger(prefs::kAudioMute);
    device_mute_settings_.Set(device_key, old_mute);
  }
  SaveDevicesMutePref();
}

void AudioDevicesPrefHandlerImpl::MigrateDeviceVolumeGainSettings(
    const std::string& device_key,
    const AudioDevice& device) {
  DCHECK(!device.is_input);
  if (!MigrateDeviceIdInSettings(&device_volume_settings_, device_key,
                                 device)) {
    // If there was no recorded value for deprecated device ID, use value from
    // default volume associated to device type.
    double default_volume = GetDeviceDefaultOutputVolume(device);
    device_volume_settings_.Set(device_key, default_volume);
  }
  SaveDevicesVolumePref();
}

void AudioDevicesPrefHandlerImpl::NotifyAudioPolicyChange() {
  for (auto& observer : observers_)
    observer.OnAudioPolicyPrefChanged();
}

// static
void AudioDevicesPrefHandlerImpl::RegisterPrefs(PrefRegistrySimple* registry) {
  registry->RegisterDictionaryPref(prefs::kAudioDevicesVolumePercent);
  registry->RegisterDictionaryPref(prefs::kAudioDevicesGainPercent);
  registry->RegisterDictionaryPref(prefs::kAudioDevicesMute);
  registry->RegisterDictionaryPref(prefs::kAudioDevicesState);
  registry->RegisterBooleanPref(prefs::kInputNoiseCancellationEnabled, false);
  registry->RegisterBooleanPref(prefs::kInputStyleTransferEnabled, false);
  registry->RegisterBooleanPref(prefs::kHandsFreeProfileInputSuperResolution,
                                false);

  // Register the prefs backing the audio muting policies.
  // Policy for audio input is handled by kAudioCaptureAllowed in the Chrome
  // media system.
  registry->RegisterBooleanPref(prefs::kAudioOutputAllowed, true);

  registry->RegisterIntegerPref(prefs::kAudioMute, kPrefMuteOff);

  registry->RegisterDictionaryPref(prefs::kAudioInputDevicesUserPriority);
  registry->RegisterDictionaryPref(prefs::kAudioOutputDevicesUserPriority);

  registry->RegisterDictionaryPref(prefs::kAudioInputDevicePreferenceSet);
  registry->RegisterDictionaryPref(prefs::kAudioOutputDevicePreferenceSet);

  registry->RegisterListPref(prefs::kAudioMostRecentActivatedInputDeviceIds);
  registry->RegisterListPref(prefs::kAudioMostRecentActivatedOutputDeviceIds);

  registry->RegisterDictionaryPref(prefs::kAudioDevicesLastSeen);

  registry->RegisterBooleanPref(prefs::kInputForceRespectUiGainsEnabled, false);
}

}  // namespace ash