chromium/extensions/browser/api/audio/audio_service_lacros.cc

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

#include "extensions/browser/api/audio/audio_service_lacros.h"

#include "base/ranges/algorithm.h"
#include "chromeos/lacros/lacros_service.h"
#include "extensions/browser/api/audio/audio_service_utils.h"
#include "mojo/public/cpp/bindings/remote.h"

namespace {

const char* const kServiceNotAvailableErrorMsg =
    "Audio devices crosapi interface is not available";

bool IsAudioCrosapiAvailable() {
  chromeos::LacrosService* service = chromeos::LacrosService::Get();
  DCHECK(service);
  return service->IsAvailable<crosapi::mojom::AudioService>();
}

crosapi::mojom::AudioService& GetAudioCrosapi() {
  chromeos::LacrosService* service = chromeos::LacrosService::Get();
  DCHECK(service);
  return *(service->GetRemote<crosapi::mojom::AudioService>());
}

}  // namespace

namespace extensions {

AudioServiceLacros::CrosapiObserver::CrosapiObserver() = default;
AudioServiceLacros::CrosapiObserver::~CrosapiObserver() = default;

void AudioServiceLacros::CrosapiObserver::OnDeviceListChanged(
    std::vector<crosapi::mojom::AudioDeviceInfoPtr> devices) {
  DeviceInfoList result;
  base::ranges::transform(devices, std::back_inserter(result),
                          extensions::ConvertAudioDeviceInfoFromMojom);
  for (auto& observer : observer_list_) {
    observer.OnDevicesChanged(result);
  }
}

void AudioServiceLacros::CrosapiObserver::OnLevelChanged(const std::string& id,
                                                         int32_t level) {
  for (auto& observer : observer_list_) {
    observer.OnLevelChanged(id, level);
  }
}

void AudioServiceLacros::CrosapiObserver::OnMuteChanged(bool is_input,
                                                        bool is_muted) {
  for (auto& observer : observer_list_) {
    observer.OnMuteChanged(is_input, is_muted);
  }
}

void AudioServiceLacros::CrosapiObserver::AddObserver(Observer* observer) {
  observer_list_.AddObserver(observer);
}

void AudioServiceLacros::CrosapiObserver::RemoveObserver(Observer* observer) {
  observer_list_.RemoveObserver(observer);
}

void AudioServiceLacros::AddObserver(Observer* observer) {
  crosapi_observer_.AddObserver(observer);
}

void AudioServiceLacros::RemoveObserver(Observer* observer) {
  crosapi_observer_.RemoveObserver(observer);
}

AudioServiceLacros::AudioServiceLacros() {
  if (IsAudioCrosapiAvailable()) {
    GetAudioCrosapi().AddAudioChangeObserver(
        receiver_.BindNewPipeAndPassRemote());
  } else {
    LOG(ERROR) << "Failed to add audio crosapi observer. "
               << kServiceNotAvailableErrorMsg;
  }
}

AudioServiceLacros::~AudioServiceLacros() = default;

void AudioServiceLacros::GetDevices(
    const api::audio::DeviceFilter* filter,
    base::OnceCallback<void(bool, DeviceInfoList)> extapi_callback) {
  if (!IsAudioCrosapiAvailable()) {
    LOG(ERROR) << "GetDevices. " << kServiceNotAvailableErrorMsg;
    DeviceInfoList devices_empty;
    std::move(extapi_callback).Run(false, std::move(devices_empty));
    return;
  }

  auto crosapi_callback = base::BindOnce(
      [](base::OnceCallback<void(bool, DeviceInfoList)> extapi_callback,
         std::optional<std::vector<crosapi::mojom::AudioDeviceInfoPtr>>
             crosapi_devices) {
        bool result_out = false;
        DeviceInfoList devices_out;

        if (crosapi_devices) {
          result_out = true;
          base::ranges::transform(*crosapi_devices,
                                  std::back_inserter(devices_out),
                                  extensions::ConvertAudioDeviceInfoFromMojom);
        }

        std::move(extapi_callback).Run(result_out, std::move(devices_out));
      },
      std::move(extapi_callback));

  auto crosapi_filter = ConvertDeviceFilterToMojom(filter);

  GetAudioCrosapi().GetDevices(std::move(crosapi_filter),
                               std::move(crosapi_callback));
}

void AudioServiceLacros::SetActiveDeviceLists(
    const DeviceIdList* input_devices,
    const DeviceIdList* output_devives,
    base::OnceCallback<void(bool)> callback) {
  if (!IsAudioCrosapiAvailable()) {
    LOG(ERROR) << "SetActiveDevices. " << kServiceNotAvailableErrorMsg;
    std::move(callback).Run(false);
    return;
  }

  auto ids = ConvertDeviceIdListsToMojom(input_devices, output_devives);
  GetAudioCrosapi().SetActiveDeviceLists(std::move(ids), std::move(callback));
}

void AudioServiceLacros::SetDeviceSoundLevel(
    const std::string& device_id,
    int level_value,
    base::OnceCallback<void(bool)> callback) {
  if (!IsAudioCrosapiAvailable()) {
    LOG(ERROR) << "SetDeviceSoundLevel. " << kServiceNotAvailableErrorMsg;
    std::move(callback).Run(false);
    return;
  }

  auto properties = crosapi::mojom::AudioDeviceProperties::New(level_value);
  GetAudioCrosapi().SetProperties(device_id, std::move(properties),
                                  std::move(callback));
}

void AudioServiceLacros::SetMute(bool is_input,
                                 bool value,
                                 base::OnceCallback<void(bool)> callback) {
  if (!IsAudioCrosapiAvailable()) {
    LOG(ERROR) << "SetMute. " << kServiceNotAvailableErrorMsg;
    std::move(callback).Run(false);
    return;
  }

  crosapi::mojom::StreamType stream_type =
      is_input ? crosapi::mojom::StreamType::kInput
               : crosapi::mojom::StreamType::kOutput;
  GetAudioCrosapi().SetMute(stream_type, value, std::move(callback));
}

void AudioServiceLacros::GetMute(
    bool is_input,
    base::OnceCallback<void(bool, bool)> callback) {
  if (!IsAudioCrosapiAvailable()) {
    LOG(ERROR) << "GetMute. " << kServiceNotAvailableErrorMsg;
    std::move(callback).Run(false, false);
    return;
  }

  crosapi::mojom::StreamType stream_type =
      is_input ? crosapi::mojom::StreamType::kInput
               : crosapi::mojom::StreamType::kOutput;
  GetAudioCrosapi().GetMute(stream_type, std::move(callback));
}

AudioService::Ptr AudioService::CreateInstance(
    AudioDeviceIdCalculator* id_calculator) {
  return std::make_unique<AudioServiceLacros>();
}

}  // namespace extensions