summaryrefslogtreecommitdiff
path: root/chromium/media/audio/audio_system_helper.cc
blob: f30c71720731e584dc4dec8f8e15b6e2f8d6733f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2017 The Chromium Authors. All rights reserved.
// 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_helper.h"

#include "base/task/single_thread_task_runner.h"
#include "media/audio/audio_manager.h"
#include "media/base/limits.h"

namespace media {

namespace {

absl::optional<AudioParameters> TryToFixChannels(
    const AudioParameters& params) {
  DCHECK(!params.IsValid());
  AudioParameters params_copy(params);

  // If the number of output channels is greater than the maximum, use the
  // maximum allowed value. Hardware channels are ignored upstream, so it is
  // better to report a valid value if this is the only problem.
  if (params.channels() > limits::kMaxChannels) {
    DCHECK(params.channel_layout() == CHANNEL_LAYOUT_DISCRETE);
    params_copy.set_channels_for_discrete(limits::kMaxChannels);
  }

  return params_copy.IsValid() ? params_copy
                               : absl::optional<AudioParameters>();
}

}  // namespace

AudioSystemHelper::AudioSystemHelper(AudioManager* audio_manager)
    : audio_manager_(audio_manager) {
  DCHECK(audio_manager_);
}

AudioSystemHelper::~AudioSystemHelper() = default;

void AudioSystemHelper::GetInputStreamParameters(
    const std::string& device_id,
    AudioSystem::OnAudioParamsCallback on_params_cb) {
  DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
  std::move(on_params_cb).Run(ComputeInputParameters(device_id));
}

void AudioSystemHelper::GetOutputStreamParameters(
    const std::string& device_id,
    AudioSystem::OnAudioParamsCallback on_params_cb) {
  DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
  std::move(on_params_cb).Run(ComputeOutputParameters(device_id));
}

void AudioSystemHelper::HasInputDevices(
    AudioSystem::OnBoolCallback on_has_devices_cb) {
  DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
  std::move(on_has_devices_cb).Run(audio_manager_->HasAudioInputDevices());
}

void AudioSystemHelper::HasOutputDevices(
    AudioSystem::OnBoolCallback on_has_devices_cb) {
  DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
  std::move(on_has_devices_cb).Run(audio_manager_->HasAudioOutputDevices());
}

void AudioSystemHelper::GetDeviceDescriptions(
    bool for_input,
    AudioSystem::OnDeviceDescriptionsCallback on_descriptions_cb) {
  DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
  AudioDeviceDescriptions descriptions;
  if (for_input)
    audio_manager_->GetAudioInputDeviceDescriptions(&descriptions);
  else
    audio_manager_->GetAudioOutputDeviceDescriptions(&descriptions);
  std::move(on_descriptions_cb).Run(std::move(descriptions));
}

void AudioSystemHelper::GetAssociatedOutputDeviceID(
    const std::string& input_device_id,
    AudioSystem::OnDeviceIdCallback on_device_id_cb) {
  DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
  const std::string associated_output_device_id =
      audio_manager_->GetAssociatedOutputDeviceID(input_device_id);
  std::move(on_device_id_cb)
      .Run(associated_output_device_id.empty() ? absl::optional<std::string>()
                                               : associated_output_device_id);
}

void AudioSystemHelper::GetInputDeviceInfo(
    const std::string& input_device_id,
    AudioSystem::OnInputDeviceInfoCallback on_input_device_info_cb) {
  DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
  const std::string associated_output_device_id =
      audio_manager_->GetAssociatedOutputDeviceID(input_device_id);
  std::move(on_input_device_info_cb)
      .Run(ComputeInputParameters(input_device_id),
           associated_output_device_id.empty() ? absl::optional<std::string>()
                                               : associated_output_device_id);
}

absl::optional<AudioParameters> AudioSystemHelper::ComputeInputParameters(
    const std::string& device_id) {
  DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());

  // TODO(olka): remove this when AudioManager::GetInputStreamParameters()
  // returns invalid parameters if the device is not found.
  if (AudioDeviceDescription::IsLoopbackDevice(device_id)) {
    // For system audio capture, we need an output device (namely speaker)
    // instead of an input device (namely microphone) to work.
    // AudioManager::GetInputStreamParameters will check |device_id| and
    // query the correct device for audio parameters by itself.
    if (!audio_manager_->HasAudioOutputDevices())
      return absl::optional<AudioParameters>();
  } else {
    if (!audio_manager_->HasAudioInputDevices())
      return absl::optional<AudioParameters>();
  }

  AudioParameters params = audio_manager_->GetInputStreamParameters(device_id);
  return params.IsValid() ? params : TryToFixChannels(params);
}

absl::optional<AudioParameters> AudioSystemHelper::ComputeOutputParameters(
    const std::string& device_id) {
  DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());

  // TODO(olka): remove this when
  // AudioManager::Get[Default]OutputStreamParameters() returns invalid
  // parameters if the device is not found.
  if (!audio_manager_->HasAudioOutputDevices())
    return absl::optional<AudioParameters>();

  AudioParameters params =
      AudioDeviceDescription::IsDefaultDevice(device_id)
          ? audio_manager_->GetDefaultOutputStreamParameters()
          : audio_manager_->GetOutputStreamParameters(device_id);

  if (params.IsValid())
    return params;

  return TryToFixChannels(params);
}

}  // namespace media