chromium/chromeos/ash/services/assistant/platform/audio_devices.h

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

#ifndef CHROMEOS_ASH_SERVICES_ASSISTANT_PLATFORM_AUDIO_DEVICES_H_
#define CHROMEOS_ASH_SERVICES_ASSISTANT_PLATFORM_AUDIO_DEVICES_H_

#include <cstdint>
#include <optional>

#include "base/component_export.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/scoped_observation_traits.h"
#include "chromeos/ash/components/audio/audio_device.h"

namespace ash {

class CrasAudioHandler;

namespace assistant {

// This class will monitor the available audio devices (through
// |CrasAudioHandler|), and select the devices to use for audio input (both
// regular input and hotword detection).
// When the selected devices change, this class will:
//     - Inform the observers.
//     - Find the hotword model to use, and send it to
//       CrasAudioHandler::SetHotwordModel().
class COMPONENT_EXPORT(ASSISTANT_SERVICE) AudioDevices {
 public:
  class Observer : public base::CheckedObserver {
   public:
    ~Observer() override = default;

    // Set the input device to use for audio capture.
    virtual void SetDeviceId(const std::optional<std::string>& device_id) = 0;
    // Set the input device to use for hardware based hotword detection.
    virtual void SetHotwordDeviceId(
        const std::optional<std::string>& device_id) = 0;
  };

  AudioDevices(CrasAudioHandler* cras_audio_handler, const std::string& locale);
  AudioDevices(const AudioDevices&) = delete;
  AudioDevices& operator=(const AudioDevices&) = delete;
  ~AudioDevices();

  void AddAndFireObserver(Observer*);
  void RemoveObserver(Observer*);

  void SetLocale(const std::string& locale);

  // Used during unittests to simulate an update to the list of available audio
  // devices.
  void SetAudioDevicesForTest(const AudioDeviceList& audio_devices);

 private:
  class ScopedCrasAudioHandlerObserver;
  class HotwordModelUpdater;

  void SetAudioDevices(const AudioDeviceList& audio_devices);
  void UpdateHotwordDeviceId(const AudioDeviceList& devices);
  void UpdateDeviceId(const AudioDeviceList& devices);
  void UpdateHotwordModel();

  // Handles the asynchronous nature of sending a new hotword model to
  // |cras_audio_handler_|.
  std::unique_ptr<HotwordModelUpdater> hotword_model_updater_;

  base::ObserverList<Observer> observers_;

  // Owned by |AssistantManagerServiceImpl|.
  const raw_ptr<CrasAudioHandler> cras_audio_handler_;

  std::string locale_;
  std::optional<uint64_t> hotword_device_id_;
  std::optional<uint64_t> device_id_;

  // Observes changes to the available audio devices, and sends the list of
  // devices to SetAudioDevices().
  std::unique_ptr<ScopedCrasAudioHandlerObserver>
      scoped_cras_audio_handler_observer_;
};

}  // namespace assistant
}  // namespace ash

namespace base {

template <>
struct ScopedObservationTraits<ash::assistant::AudioDevices,
                               ash::assistant::AudioDevices::Observer> {
  static void AddObserver(ash::assistant::AudioDevices* source,
                          ash::assistant::AudioDevices::Observer* observer) {
    source->AddAndFireObserver(observer);
  }
  static void RemoveObserver(ash::assistant::AudioDevices* source,
                             ash::assistant::AudioDevices::Observer* observer) {
    source->RemoveObserver(observer);
  }
};

}  // namespace base

#endif  // CHROMEOS_ASH_SERVICES_ASSISTANT_PLATFORM_AUDIO_DEVICES_H_