Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / media / audio / cras / cras_input.cc
blob335417fe5ab9c8f390127d54cad9ff6db008b467
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_(CRAS_STREAM_INPUT),
28 pin_device_(NO_DEVICE),
29 is_loopback_(device_id == AudioManagerBase::kLoopbackInputDeviceId) {
30 DCHECK(audio_manager_);
31 audio_bus_ = AudioBus::Create(params_);
34 CrasInputStream::~CrasInputStream() {
35 DCHECK(!client_);
38 bool CrasInputStream::Open() {
39 if (client_) {
40 NOTREACHED() << "CrasInputStream already open";
41 return false; // Already open.
44 // Sanity check input values.
45 if (params_.sample_rate() <= 0) {
46 DLOG(WARNING) << "Unsupported audio frequency.";
47 return false;
50 if (AudioParameters::AUDIO_PCM_LINEAR != params_.format() &&
51 AudioParameters::AUDIO_PCM_LOW_LATENCY != params_.format()) {
52 DLOG(WARNING) << "Unsupported audio format.";
53 return false;
56 snd_pcm_format_t pcm_format =
57 AudioManagerCras::BitsToFormat(params_.bits_per_sample());
58 if (pcm_format == SND_PCM_FORMAT_UNKNOWN) {
59 DLOG(WARNING) << "Unsupported bits/sample: " << params_.bits_per_sample();
60 return false;
63 // Create the client and connect to the CRAS server.
64 if (cras_client_create(&client_) < 0) {
65 DLOG(WARNING) << "Couldn't create CRAS client.\n";
66 client_ = NULL;
67 return false;
70 if (cras_client_connect(client_)) {
71 DLOG(WARNING) << "Couldn't connect CRAS client.\n";
72 cras_client_destroy(client_);
73 client_ = NULL;
74 return false;
77 // Then start running the client.
78 if (cras_client_run_thread(client_)) {
79 DLOG(WARNING) << "Couldn't run CRAS client.\n";
80 cras_client_destroy(client_);
81 client_ = NULL;
82 return false;
85 if (is_loopback_) {
86 if (cras_client_connected_wait(client_) < 0) {
87 DLOG(WARNING) << "Couldn't synchronize data.";
88 // TODO(chinyue): Add a DestroyClientOnError method to de-duplicate the
89 // cleanup code.
90 cras_client_destroy(client_);
91 client_ = NULL;
92 return false;
94 pin_device_ = cras_client_get_first_dev_type_idx(client_,
95 CRAS_NODE_TYPE_POST_MIX_PRE_DSP, CRAS_STREAM_INPUT);
96 if (pin_device_ < 0) {
97 DLOG(WARNING) << "Couldn't find CRAS loopback device.";
98 cras_client_destroy(client_);
99 client_ = NULL;
100 return false;
104 return true;
107 void CrasInputStream::Close() {
108 Stop();
110 if (client_) {
111 cras_client_stop(client_);
112 cras_client_destroy(client_);
113 client_ = NULL;
116 // Signal to the manager that we're closed and can be removed.
117 // Should be last call in the method as it deletes "this".
118 audio_manager_->ReleaseInputStream(this);
121 void CrasInputStream::Start(AudioInputCallback* callback) {
122 DCHECK(client_);
123 DCHECK(callback);
125 // Channel map to CRAS_CHANNEL, values in the same order of
126 // corresponding source in Chromium defined Channels.
127 static const int kChannelMap[] = {
128 CRAS_CH_FL,
129 CRAS_CH_FR,
130 CRAS_CH_FC,
131 CRAS_CH_LFE,
132 CRAS_CH_RL,
133 CRAS_CH_RR,
134 CRAS_CH_FLC,
135 CRAS_CH_FRC,
136 CRAS_CH_RC,
137 CRAS_CH_SL,
138 CRAS_CH_SR
140 static_assert(arraysize(kChannelMap) == CHANNELS_MAX + 1,
141 "kChannelMap array size should match");
143 // If already playing, stop before re-starting.
144 if (started_)
145 return;
147 StartAgc();
149 callback_ = callback;
151 // Prepare |audio_format| and |stream_params| for the stream we
152 // will create.
153 cras_audio_format* audio_format = cras_audio_format_create(
154 AudioManagerCras::BitsToFormat(params_.bits_per_sample()),
155 params_.sample_rate(),
156 params_.channels());
157 if (!audio_format) {
158 DLOG(WARNING) << "Error setting up audio parameters.";
159 callback_->OnError(this);
160 callback_ = NULL;
161 return;
164 // Initialize channel layout to all -1 to indicate that none of
165 // the channels is set in the layout.
166 int8 layout[CRAS_CH_MAX];
167 for (size_t i = 0; i < arraysize(layout); ++i)
168 layout[i] = -1;
170 // Converts to CRAS defined channels. ChannelOrder will return -1
171 // for channels that are not present in params_.channel_layout().
172 for (size_t i = 0; i < arraysize(kChannelMap); ++i) {
173 layout[kChannelMap[i]] = ChannelOrder(params_.channel_layout(),
174 static_cast<Channels>(i));
176 if (cras_audio_format_set_channel_layout(audio_format, layout) != 0) {
177 DLOG(WARNING) << "Error setting channel layout.";
178 callback->OnError(this);
179 return;
182 uint32_t flags = 0;
183 if (params_.effects() & AudioParameters::PlatformEffectsMask::HOTWORD)
184 flags = HOTWORD_STREAM;
186 unsigned int frames_per_packet = params_.frames_per_buffer();
187 cras_stream_params* stream_params = cras_client_stream_params_create(
188 stream_direction_,
189 frames_per_packet, // Total latency.
190 frames_per_packet, // Call back when this many ready.
191 frames_per_packet, // Minimum Callback level ignored for capture streams.
192 CRAS_STREAM_TYPE_DEFAULT,
193 flags,
194 this,
195 CrasInputStream::SamplesReady,
196 CrasInputStream::StreamError,
197 audio_format);
198 if (!stream_params) {
199 DLOG(WARNING) << "Error setting up stream parameters.";
200 callback_->OnError(this);
201 callback_ = NULL;
202 cras_audio_format_destroy(audio_format);
203 return;
206 // Before starting the stream, save the number of bytes in a frame for use in
207 // the callback.
208 bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format);
210 // Adding the stream will start the audio callbacks.
211 if (cras_client_add_pinned_stream(client_, pin_device_, &stream_id_,
212 stream_params)) {
213 DLOG(WARNING) << "Failed to add the stream.";
214 callback_->OnError(this);
215 callback_ = NULL;
218 // Done with config params.
219 cras_audio_format_destroy(audio_format);
220 cras_client_stream_params_destroy(stream_params);
222 started_ = true;
225 void CrasInputStream::Stop() {
226 DCHECK(client_);
228 if (!callback_ || !started_)
229 return;
231 StopAgc();
233 // Removing the stream from the client stops audio.
234 cras_client_rm_stream(client_, stream_id_);
236 started_ = false;
237 callback_ = NULL;
240 // Static callback asking for samples. Run on high priority thread.
241 int CrasInputStream::SamplesReady(cras_client* client,
242 cras_stream_id_t stream_id,
243 uint8* samples,
244 size_t frames,
245 const timespec* sample_ts,
246 void* arg) {
247 CrasInputStream* me = static_cast<CrasInputStream*>(arg);
248 me->ReadAudio(frames, samples, sample_ts);
249 return frames;
252 // Static callback for stream errors.
253 int CrasInputStream::StreamError(cras_client* client,
254 cras_stream_id_t stream_id,
255 int err,
256 void* arg) {
257 CrasInputStream* me = static_cast<CrasInputStream*>(arg);
258 me->NotifyStreamError(err);
259 return 0;
262 void CrasInputStream::ReadAudio(size_t frames,
263 uint8* buffer,
264 const timespec* sample_ts) {
265 DCHECK(callback_);
267 timespec latency_ts = {0, 0};
269 // Determine latency and pass that on to the sink. sample_ts is the wall time
270 // indicating when the first sample in the buffer was captured. Convert that
271 // to latency in bytes.
272 cras_client_calc_capture_latency(sample_ts, &latency_ts);
273 double latency_usec =
274 latency_ts.tv_sec * base::Time::kMicrosecondsPerSecond +
275 latency_ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond;
276 double frames_latency =
277 latency_usec * params_.sample_rate() / base::Time::kMicrosecondsPerSecond;
278 unsigned int bytes_latency =
279 static_cast<unsigned int>(frames_latency * bytes_per_frame_);
281 // Update the AGC volume level once every second. Note that, |volume| is
282 // also updated each time SetVolume() is called through IPC by the
283 // render-side AGC.
284 double normalized_volume = 0.0;
285 GetAgcVolume(&normalized_volume);
287 audio_bus_->FromInterleaved(
288 buffer, audio_bus_->frames(), params_.bits_per_sample() / 8);
289 callback_->OnData(this, audio_bus_.get(), bytes_latency, normalized_volume);
292 void CrasInputStream::NotifyStreamError(int err) {
293 if (callback_)
294 callback_->OnError(this);
297 double CrasInputStream::GetMaxVolume() {
298 DCHECK(client_);
300 // Capture gain is returned as dB * 100 (150 => 1.5dBFS). Convert the dB
301 // value to a ratio before returning.
302 double dB = cras_client_get_system_max_capture_gain(client_) / 100.0;
303 return GetVolumeRatioFromDecibels(dB);
306 void CrasInputStream::SetVolume(double volume) {
307 DCHECK(client_);
309 // Convert from the passed volume ratio, to dB * 100.
310 double dB = GetDecibelsFromVolumeRatio(volume);
311 cras_client_set_system_capture_gain(client_, static_cast<long>(dB * 100.0));
313 // Update the AGC volume level based on the last setting above. Note that,
314 // the volume-level resolution is not infinite and it is therefore not
315 // possible to assume that the volume provided as input parameter can be
316 // used directly. Instead, a new query to the audio hardware is required.
317 // This method does nothing if AGC is disabled.
318 UpdateAgcVolume();
321 double CrasInputStream::GetVolume() {
322 if (!client_)
323 return 0.0;
325 long dB = cras_client_get_system_capture_gain(client_) / 100.0;
326 return GetVolumeRatioFromDecibels(dB);
329 bool CrasInputStream::IsMuted() {
330 return false;
333 double CrasInputStream::GetVolumeRatioFromDecibels(double dB) const {
334 return pow(10, dB / 20.0);
337 double CrasInputStream::GetDecibelsFromVolumeRatio(double volume_ratio) const {
338 return 20 * log10(volume_ratio);
341 } // namespace media