Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / media / audio / cras / cras_input.cc
blob31bba72b4a7ab4dd0ee0b2f8652d19a73412008d
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/audio/cras/cras_input.h"
7 #include <math.h>
9 #include "base/basictypes.h"
10 #include "base/logging.h"
11 #include "base/time/time.h"
12 #include "media/audio/audio_manager.h"
13 #include "media/audio/cras/audio_manager_cras.h"
15 namespace media {
17 CrasInputStream::CrasInputStream(const AudioParameters& params,
18 AudioManagerCras* manager,
19 const std::string& device_id)
20 : audio_manager_(manager),
21 bytes_per_frame_(0),
22 callback_(NULL),
23 client_(NULL),
24 params_(params),
25 started_(false),
26 stream_id_(0),
27 stream_direction_(device_id == AudioManagerBase::kLoopbackInputDeviceId ?
28 CRAS_STREAM_POST_MIX_PRE_DSP : CRAS_STREAM_INPUT) {
29 DCHECK(audio_manager_);
30 audio_bus_ = AudioBus::Create(params_);
33 CrasInputStream::~CrasInputStream() {
34 DCHECK(!client_);
37 bool CrasInputStream::Open() {
38 if (client_) {
39 NOTREACHED() << "CrasInputStream already open";
40 return false; // Already open.
43 // Sanity check input values.
44 if (params_.sample_rate() <= 0) {
45 DLOG(WARNING) << "Unsupported audio frequency.";
46 return false;
49 if (AudioParameters::AUDIO_PCM_LINEAR != params_.format() &&
50 AudioParameters::AUDIO_PCM_LOW_LATENCY != params_.format()) {
51 DLOG(WARNING) << "Unsupported audio format.";
52 return false;
55 snd_pcm_format_t pcm_format =
56 AudioManagerCras::BitsToFormat(params_.bits_per_sample());
57 if (pcm_format == SND_PCM_FORMAT_UNKNOWN) {
58 DLOG(WARNING) << "Unsupported bits/sample: " << params_.bits_per_sample();
59 return false;
62 // Create the client and connect to the CRAS server.
63 if (cras_client_create(&client_) < 0) {
64 DLOG(WARNING) << "Couldn't create CRAS client.\n";
65 client_ = NULL;
66 return false;
69 if (cras_client_connect(client_)) {
70 DLOG(WARNING) << "Couldn't connect CRAS client.\n";
71 cras_client_destroy(client_);
72 client_ = NULL;
73 return false;
76 // Then start running the client.
77 if (cras_client_run_thread(client_)) {
78 DLOG(WARNING) << "Couldn't run CRAS client.\n";
79 cras_client_destroy(client_);
80 client_ = NULL;
81 return false;
84 return true;
87 void CrasInputStream::Close() {
88 Stop();
90 if (client_) {
91 cras_client_stop(client_);
92 cras_client_destroy(client_);
93 client_ = NULL;
96 // Signal to the manager that we're closed and can be removed.
97 // Should be last call in the method as it deletes "this".
98 audio_manager_->ReleaseInputStream(this);
101 void CrasInputStream::Start(AudioInputCallback* callback) {
102 DCHECK(client_);
103 DCHECK(callback);
105 // Channel map to CRAS_CHANNEL, values in the same order of
106 // corresponding source in Chromium defined Channels.
107 static const int kChannelMap[] = {
108 CRAS_CH_FL,
109 CRAS_CH_FR,
110 CRAS_CH_FC,
111 CRAS_CH_LFE,
112 CRAS_CH_RL,
113 CRAS_CH_RR,
114 CRAS_CH_FLC,
115 CRAS_CH_FRC,
116 CRAS_CH_RC,
117 CRAS_CH_SL,
118 CRAS_CH_SR
120 static_assert(arraysize(kChannelMap) == CHANNELS_MAX + 1,
121 "kChannelMap array size should match");
123 // If already playing, stop before re-starting.
124 if (started_)
125 return;
127 StartAgc();
129 callback_ = callback;
131 // Prepare |audio_format| and |stream_params| for the stream we
132 // will create.
133 cras_audio_format* audio_format = cras_audio_format_create(
134 AudioManagerCras::BitsToFormat(params_.bits_per_sample()),
135 params_.sample_rate(),
136 params_.channels());
137 if (!audio_format) {
138 DLOG(WARNING) << "Error setting up audio parameters.";
139 callback_->OnError(this);
140 callback_ = NULL;
141 return;
144 // Initialize channel layout to all -1 to indicate that none of
145 // the channels is set in the layout.
146 int8 layout[CRAS_CH_MAX];
147 for (size_t i = 0; i < arraysize(layout); ++i)
148 layout[i] = -1;
150 // Converts to CRAS defined channels. ChannelOrder will return -1
151 // for channels that are not present in params_.channel_layout().
152 for (size_t i = 0; i < arraysize(kChannelMap); ++i) {
153 layout[kChannelMap[i]] = ChannelOrder(params_.channel_layout(),
154 static_cast<Channels>(i));
156 if (cras_audio_format_set_channel_layout(audio_format, layout) != 0) {
157 DLOG(WARNING) << "Error setting channel layout.";
158 callback->OnError(this);
159 return;
162 uint32_t flags = 0;
163 if (params_.effects() & AudioParameters::PlatformEffectsMask::HOTWORD)
164 flags = HOTWORD_STREAM;
166 unsigned int frames_per_packet = params_.frames_per_buffer();
167 cras_stream_params* stream_params = cras_client_stream_params_create(
168 stream_direction_,
169 frames_per_packet, // Total latency.
170 frames_per_packet, // Call back when this many ready.
171 frames_per_packet, // Minimum Callback level ignored for capture streams.
172 CRAS_STREAM_TYPE_DEFAULT,
173 flags,
174 this,
175 CrasInputStream::SamplesReady,
176 CrasInputStream::StreamError,
177 audio_format);
178 if (!stream_params) {
179 DLOG(WARNING) << "Error setting up stream parameters.";
180 callback_->OnError(this);
181 callback_ = NULL;
182 cras_audio_format_destroy(audio_format);
183 return;
186 // Before starting the stream, save the number of bytes in a frame for use in
187 // the callback.
188 bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format);
190 // Adding the stream will start the audio callbacks.
191 if (cras_client_add_stream(client_, &stream_id_, stream_params)) {
192 DLOG(WARNING) << "Failed to add the stream.";
193 callback_->OnError(this);
194 callback_ = NULL;
197 // Done with config params.
198 cras_audio_format_destroy(audio_format);
199 cras_client_stream_params_destroy(stream_params);
201 started_ = true;
204 void CrasInputStream::Stop() {
205 DCHECK(client_);
207 if (!callback_ || !started_)
208 return;
210 StopAgc();
212 // Removing the stream from the client stops audio.
213 cras_client_rm_stream(client_, stream_id_);
215 started_ = false;
216 callback_ = NULL;
219 // Static callback asking for samples. Run on high priority thread.
220 int CrasInputStream::SamplesReady(cras_client* client,
221 cras_stream_id_t stream_id,
222 uint8* samples,
223 size_t frames,
224 const timespec* sample_ts,
225 void* arg) {
226 CrasInputStream* me = static_cast<CrasInputStream*>(arg);
227 me->ReadAudio(frames, samples, sample_ts);
228 return frames;
231 // Static callback for stream errors.
232 int CrasInputStream::StreamError(cras_client* client,
233 cras_stream_id_t stream_id,
234 int err,
235 void* arg) {
236 CrasInputStream* me = static_cast<CrasInputStream*>(arg);
237 me->NotifyStreamError(err);
238 return 0;
241 void CrasInputStream::ReadAudio(size_t frames,
242 uint8* buffer,
243 const timespec* sample_ts) {
244 DCHECK(callback_);
246 timespec latency_ts = {0, 0};
248 // Determine latency and pass that on to the sink. sample_ts is the wall time
249 // indicating when the first sample in the buffer was captured. Convert that
250 // to latency in bytes.
251 cras_client_calc_capture_latency(sample_ts, &latency_ts);
252 double latency_usec =
253 latency_ts.tv_sec * base::Time::kMicrosecondsPerSecond +
254 latency_ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond;
255 double frames_latency =
256 latency_usec * params_.sample_rate() / base::Time::kMicrosecondsPerSecond;
257 unsigned int bytes_latency =
258 static_cast<unsigned int>(frames_latency * bytes_per_frame_);
260 // Update the AGC volume level once every second. Note that, |volume| is
261 // also updated each time SetVolume() is called through IPC by the
262 // render-side AGC.
263 double normalized_volume = 0.0;
264 GetAgcVolume(&normalized_volume);
266 audio_bus_->FromInterleaved(
267 buffer, audio_bus_->frames(), params_.bits_per_sample() / 8);
268 callback_->OnData(this, audio_bus_.get(), bytes_latency, normalized_volume);
271 void CrasInputStream::NotifyStreamError(int err) {
272 if (callback_)
273 callback_->OnError(this);
276 double CrasInputStream::GetMaxVolume() {
277 DCHECK(client_);
279 // Capture gain is returned as dB * 100 (150 => 1.5dBFS). Convert the dB
280 // value to a ratio before returning.
281 double dB = cras_client_get_system_max_capture_gain(client_) / 100.0;
282 return GetVolumeRatioFromDecibels(dB);
285 void CrasInputStream::SetVolume(double volume) {
286 DCHECK(client_);
288 // Convert from the passed volume ratio, to dB * 100.
289 double dB = GetDecibelsFromVolumeRatio(volume);
290 cras_client_set_system_capture_gain(client_, static_cast<long>(dB * 100.0));
292 // Update the AGC volume level based on the last setting above. Note that,
293 // the volume-level resolution is not infinite and it is therefore not
294 // possible to assume that the volume provided as input parameter can be
295 // used directly. Instead, a new query to the audio hardware is required.
296 // This method does nothing if AGC is disabled.
297 UpdateAgcVolume();
300 double CrasInputStream::GetVolume() {
301 if (!client_)
302 return 0.0;
304 long dB = cras_client_get_system_capture_gain(client_) / 100.0;
305 return GetVolumeRatioFromDecibels(dB);
308 bool CrasInputStream::IsMuted() {
309 return false;
312 double CrasInputStream::GetVolumeRatioFromDecibels(double dB) const {
313 return pow(10, dB / 20.0);
316 double CrasInputStream::GetDecibelsFromVolumeRatio(double volume_ratio) const {
317 return 20 * log10(volume_ratio);
320 } // namespace media