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.
4
5#include "media/audio/cras/cras_input.h"
6
7#include <math.h>
8
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"
14
15namespace media {
16
17CrasInputStream::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_);
31}
32
33CrasInputStream::~CrasInputStream() {
34  DCHECK(!client_);
35}
36
37bool CrasInputStream::Open() {
38  if (client_) {
39    NOTREACHED() << "CrasInputStream already open";
40    return false;  // Already open.
41  }
42
43  // Sanity check input values.
44  if (params_.sample_rate() <= 0) {
45    DLOG(WARNING) << "Unsupported audio frequency.";
46    return false;
47  }
48
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;
53  }
54
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;
60  }
61
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;
67  }
68
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;
74  }
75
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;
82  }
83
84  return true;
85}
86
87void CrasInputStream::Close() {
88  Stop();
89
90  if (client_) {
91    cras_client_stop(client_);
92    cras_client_destroy(client_);
93    client_ = NULL;
94  }
95
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);
99}
100
101void CrasInputStream::Start(AudioInputCallback* callback) {
102  DCHECK(client_);
103  DCHECK(callback);
104
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
119  };
120  COMPILE_ASSERT(arraysize(kChannelMap) == CHANNELS_MAX + 1,
121                 channel_map_size_do_not_match);
122
123  // If already playing, stop before re-starting.
124  if (started_)
125    return;
126
127  StartAgc();
128
129  callback_ = callback;
130
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;
142  }
143
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;
149
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));
155  }
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;
160  }
161
162  unsigned int frames_per_packet = params_.frames_per_buffer();
163  cras_stream_params* stream_params = cras_client_stream_params_create(
164      stream_direction_,
165      frames_per_packet,  // Total latency.
166      frames_per_packet,  // Call back when this many ready.
167      frames_per_packet,  // Minimum Callback level ignored for capture streams.
168      CRAS_STREAM_TYPE_DEFAULT,
169      0,  // Unused flags.
170      this,
171      CrasInputStream::SamplesReady,
172      CrasInputStream::StreamError,
173      audio_format);
174  if (!stream_params) {
175    DLOG(WARNING) << "Error setting up stream parameters.";
176    callback_->OnError(this);
177    callback_ = NULL;
178    cras_audio_format_destroy(audio_format);
179    return;
180  }
181
182  // Before starting the stream, save the number of bytes in a frame for use in
183  // the callback.
184  bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format);
185
186  // Adding the stream will start the audio callbacks.
187  if (cras_client_add_stream(client_, &stream_id_, stream_params)) {
188    DLOG(WARNING) << "Failed to add the stream.";
189    callback_->OnError(this);
190    callback_ = NULL;
191  }
192
193  // Done with config params.
194  cras_audio_format_destroy(audio_format);
195  cras_client_stream_params_destroy(stream_params);
196
197  started_ = true;
198}
199
200void CrasInputStream::Stop() {
201  DCHECK(client_);
202
203  if (!callback_ || !started_)
204    return;
205
206  StopAgc();
207
208  // Removing the stream from the client stops audio.
209  cras_client_rm_stream(client_, stream_id_);
210
211  started_ = false;
212  callback_ = NULL;
213}
214
215// Static callback asking for samples.  Run on high priority thread.
216int CrasInputStream::SamplesReady(cras_client* client,
217                                  cras_stream_id_t stream_id,
218                                  uint8* samples,
219                                  size_t frames,
220                                  const timespec* sample_ts,
221                                  void* arg) {
222  CrasInputStream* me = static_cast<CrasInputStream*>(arg);
223  me->ReadAudio(frames, samples, sample_ts);
224  return frames;
225}
226
227// Static callback for stream errors.
228int CrasInputStream::StreamError(cras_client* client,
229                                 cras_stream_id_t stream_id,
230                                 int err,
231                                 void* arg) {
232  CrasInputStream* me = static_cast<CrasInputStream*>(arg);
233  me->NotifyStreamError(err);
234  return 0;
235}
236
237void CrasInputStream::ReadAudio(size_t frames,
238                                uint8* buffer,
239                                const timespec* sample_ts) {
240  DCHECK(callback_);
241
242  timespec latency_ts = {0, 0};
243
244  // Determine latency and pass that on to the sink.  sample_ts is the wall time
245  // indicating when the first sample in the buffer was captured.  Convert that
246  // to latency in bytes.
247  cras_client_calc_capture_latency(sample_ts, &latency_ts);
248  double latency_usec =
249      latency_ts.tv_sec * base::Time::kMicrosecondsPerSecond +
250      latency_ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond;
251  double frames_latency =
252      latency_usec * params_.sample_rate() / base::Time::kMicrosecondsPerSecond;
253  unsigned int bytes_latency =
254      static_cast<unsigned int>(frames_latency * bytes_per_frame_);
255
256  // Update the AGC volume level once every second. Note that, |volume| is
257  // also updated each time SetVolume() is called through IPC by the
258  // render-side AGC.
259  double normalized_volume = 0.0;
260  GetAgcVolume(&normalized_volume);
261
262  audio_bus_->FromInterleaved(
263      buffer, audio_bus_->frames(), params_.bits_per_sample() / 8);
264  callback_->OnData(this, audio_bus_.get(), bytes_latency, normalized_volume);
265}
266
267void CrasInputStream::NotifyStreamError(int err) {
268  if (callback_)
269    callback_->OnError(this);
270}
271
272double CrasInputStream::GetMaxVolume() {
273  DCHECK(client_);
274
275  // Capture gain is returned as dB * 100 (150 => 1.5dBFS).  Convert the dB
276  // value to a ratio before returning.
277  double dB = cras_client_get_system_max_capture_gain(client_) / 100.0;
278  return GetVolumeRatioFromDecibels(dB);
279}
280
281void CrasInputStream::SetVolume(double volume) {
282  DCHECK(client_);
283
284  // Convert from the passed volume ratio, to dB * 100.
285  double dB = GetDecibelsFromVolumeRatio(volume);
286  cras_client_set_system_capture_gain(client_, static_cast<long>(dB * 100.0));
287
288  // Update the AGC volume level based on the last setting above. Note that,
289  // the volume-level resolution is not infinite and it is therefore not
290  // possible to assume that the volume provided as input parameter can be
291  // used directly. Instead, a new query to the audio hardware is required.
292  // This method does nothing if AGC is disabled.
293  UpdateAgcVolume();
294}
295
296double CrasInputStream::GetVolume() {
297  if (!client_)
298    return 0.0;
299
300  long dB = cras_client_get_system_capture_gain(client_) / 100.0;
301  return GetVolumeRatioFromDecibels(dB);
302}
303
304bool CrasInputStream::IsMuted() {
305  return false;
306}
307
308double CrasInputStream::GetVolumeRatioFromDecibels(double dB) const {
309  return pow(10, dB / 20.0);
310}
311
312double CrasInputStream::GetDecibelsFromVolumeRatio(double volume_ratio) const {
313  return 20 * log10(volume_ratio);
314}
315
316}  // namespace media
317