910e62b5创建于 1月15日历史提交
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/audio/audio_system_impl.h"

#include <utility>

#include "base/functional/bind.h"
#include "base/memory/ptr_util.h"
#include "base/task/bind_post_task.h"
#include "base/task/single_thread_task_runner.h"
#include "media/audio/audio_device_description.h"
#include "media/audio/audio_manager.h"

// Using base::Unretained for |audio_manager_| is safe since AudioManager is
// deleted after audio thread is stopped.

// No need to bind the callback to the current loop if we are on the audio
// thread. However, the client still expects to receive the reply
// asynchronously, so we always post the helper function, which will
// synchronously call the (bound to current loop or not) callback. Thus the
// client always receives the callback on the thread it accesses AudioSystem on.

namespace media {

namespace {

void GetInputStreamParametersOnAudioThread(
    AudioManager* audio_manager,
    const std::string& device_id,
    AudioSystem::OnAudioParamsCallback on_params_cb) {
  AudioSystemHelper(audio_manager)
      .GetInputStreamParameters(device_id, std::move(on_params_cb));
}

void GetOutputStreamParametersOnAudioThread(
    AudioManager* audio_manager,
    const std::string& device_id,
    AudioSystem::OnAudioParamsCallback on_params_cb) {
  AudioSystemHelper(audio_manager)
      .GetOutputStreamParameters(device_id, std::move(on_params_cb));
}

void HasInputDevicesOnAudioThread(
    AudioManager* audio_manager,
    AudioSystem::OnBoolCallback on_has_devices_cb) {
  AudioSystemHelper(audio_manager)
      .HasInputDevices(std::move(on_has_devices_cb));
}

void HasOutputDevicesOnAudioThread(
    AudioManager* audio_manager,
    AudioSystem::OnBoolCallback on_has_devices_cb) {
  AudioSystemHelper(audio_manager)
      .HasOutputDevices(std::move(on_has_devices_cb));
}

void GetDeviceDescriptionsOnAudioThread(
    AudioManager* audio_manager,
    bool for_input,
    AudioSystem::OnDeviceDescriptionsCallback on_descriptions_cb) {
  AudioSystemHelper(audio_manager)
      .GetDeviceDescriptions(for_input, std::move(on_descriptions_cb));
}

void GetAssociatedOutputDeviceIDOnAudioThread(
    AudioManager* audio_manager,
    const std::string& input_device_id,
    AudioSystem::OnDeviceIdCallback on_device_id_cb) {
  AudioSystemHelper(audio_manager)
      .GetAssociatedOutputDeviceID(input_device_id, std::move(on_device_id_cb));
}

void GetInputDeviceInfoOnAudioThread(
    AudioManager* audio_manager,
    const std::string& input_device_id,
    AudioSystem::OnInputDeviceInfoCallback on_input_device_info_cb) {
  AudioSystemHelper(audio_manager)
      .GetInputDeviceInfo(input_device_id, std::move(on_input_device_info_cb));
}

}  // namespace

template <typename... Args>
inline base::OnceCallback<void(Args...)>
AudioSystemImpl::MaybeBindToCurrentLoop(
    base::OnceCallback<void(Args...)> callback) {
  return audio_manager_->GetTaskRunner()->BelongsToCurrentThread()
             ? std::move(callback)
             : base::BindPostTaskToCurrentDefault(std::move(callback));
}

// static
std::unique_ptr<AudioSystem> AudioSystemImpl::CreateInstance() {
  DCHECK(AudioManager::Get()) << "AudioManager instance is not created";
  return std::make_unique<AudioSystemImpl>(AudioManager::Get());
}

AudioSystemImpl::AudioSystemImpl(AudioManager* audio_manager)
    : audio_manager_(audio_manager) {
  DETACH_FROM_THREAD(thread_checker_);
}

void AudioSystemImpl::GetInputStreamParameters(
    const std::string& device_id,
    OnAudioParamsCallback on_params_cb) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  audio_manager_->GetTaskRunner()->PostTask(
      FROM_HERE,
      base::BindOnce(&GetInputStreamParametersOnAudioThread,
                     base::Unretained(audio_manager_), device_id,
                     MaybeBindToCurrentLoop(std::move(on_params_cb))));
}

void AudioSystemImpl::GetOutputStreamParameters(
    const std::string& device_id,
    OnAudioParamsCallback on_params_cb) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  audio_manager_->GetTaskRunner()->PostTask(
      FROM_HERE,
      base::BindOnce(&GetOutputStreamParametersOnAudioThread,
                     base::Unretained(audio_manager_), device_id,
                     MaybeBindToCurrentLoop(std::move(on_params_cb))));
}

void AudioSystemImpl::HasInputDevices(OnBoolCallback on_has_devices_cb) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  audio_manager_->GetTaskRunner()->PostTask(
      FROM_HERE,
      base::BindOnce(&HasInputDevicesOnAudioThread,
                     base::Unretained(audio_manager_),
                     MaybeBindToCurrentLoop(std::move(on_has_devices_cb))));
}

void AudioSystemImpl::HasOutputDevices(OnBoolCallback on_has_devices_cb) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  audio_manager_->GetTaskRunner()->PostTask(
      FROM_HERE,
      base::BindOnce(&HasOutputDevicesOnAudioThread,
                     base::Unretained(audio_manager_),
                     MaybeBindToCurrentLoop(std::move(on_has_devices_cb))));
}

void AudioSystemImpl::GetDeviceDescriptions(
    bool for_input,
    OnDeviceDescriptionsCallback on_descriptions_cb) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  audio_manager_->GetTaskRunner()->PostTask(
      FROM_HERE, base::BindOnce(&GetDeviceDescriptionsOnAudioThread,
                                base::Unretained(audio_manager_), for_input,
                                MaybeBindToCurrentLoop(
                                    WrapCallbackWithDeviceNameLocalization(
                                        std::move(on_descriptions_cb)))));
}

void AudioSystemImpl::GetAssociatedOutputDeviceID(
    const std::string& input_device_id,
    OnDeviceIdCallback on_device_id_cb) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  audio_manager_->GetTaskRunner()->PostTask(
      FROM_HERE,
      base::BindOnce(&GetAssociatedOutputDeviceIDOnAudioThread,
                     base::Unretained(audio_manager_), input_device_id,
                     MaybeBindToCurrentLoop(std::move(on_device_id_cb))));
}

void AudioSystemImpl::GetInputDeviceInfo(
    const std::string& input_device_id,
    OnInputDeviceInfoCallback on_input_device_info_cb) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  audio_manager_->GetTaskRunner()->PostTask(
      FROM_HERE,
      base::BindOnce(
          &GetInputDeviceInfoOnAudioThread, base::Unretained(audio_manager_),
          input_device_id,
          MaybeBindToCurrentLoop(std::move(on_input_device_info_cb))));
}

}  // namespace media