- add sources.
[platform/framework/web/crosswalk.git] / src / media / audio / cras / cras_input.cc
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/bind.h"
11 #include "base/logging.h"
12 #include "base/time/time.h"
13 #include "media/audio/audio_manager.h"
14 #include "media/audio/cras/audio_manager_cras.h"
15 #include "media/audio/linux/alsa_util.h"
16
17 namespace media {
18
19 CrasInputStream::CrasInputStream(const AudioParameters& params,
20                                  AudioManagerCras* manager,
21                                  const std::string& device_id)
22     : audio_manager_(manager),
23       bytes_per_frame_(0),
24       callback_(NULL),
25       client_(NULL),
26       params_(params),
27       started_(false),
28       stream_id_(0),
29       stream_direction_(device_id == AudioManagerBase::kLoopbackInputDeviceId ?
30                             CRAS_STREAM_POST_MIX_PRE_DSP : CRAS_STREAM_INPUT) {
31   DCHECK(audio_manager_);
32 }
33
34 CrasInputStream::~CrasInputStream() {
35   DCHECK(!client_);
36 }
37
38 bool CrasInputStream::Open() {
39   if (client_) {
40     NOTREACHED() << "CrasInputStream already open";
41     return false;  // Already open.
42   }
43
44   // Sanity check input values.
45   if (params_.sample_rate() <= 0) {
46     DLOG(WARNING) << "Unsupported audio frequency.";
47     return false;
48   }
49
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;
54   }
55
56   snd_pcm_format_t pcm_format =
57       alsa_util::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;
61   }
62
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;
68   }
69
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;
75   }
76
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;
83   }
84
85   return true;
86 }
87
88 void CrasInputStream::Close() {
89   if (client_) {
90     cras_client_stop(client_);
91     cras_client_destroy(client_);
92     client_ = NULL;
93   }
94
95   if (callback_) {
96     callback_->OnClose(this);
97     callback_ = NULL;
98   }
99
100   // Signal to the manager that we're closed and can be removed.
101   // Should be last call in the method as it deletes "this".
102   audio_manager_->ReleaseInputStream(this);
103 }
104
105 void CrasInputStream::Start(AudioInputCallback* callback) {
106   DCHECK(client_);
107   DCHECK(callback);
108
109   // If already playing, stop before re-starting.
110   if (started_)
111     return;
112
113   StartAgc();
114
115   callback_ = callback;
116
117   // Prepare |audio_format| and |stream_params| for the stream we
118   // will create.
119   cras_audio_format* audio_format = cras_audio_format_create(
120       alsa_util::BitsToFormat(params_.bits_per_sample()),
121       params_.sample_rate(),
122       params_.channels());
123   if (!audio_format) {
124     DLOG(WARNING) << "Error setting up audio parameters.";
125     callback_->OnError(this);
126     callback_ = NULL;
127     return;
128   }
129
130   unsigned int frames_per_packet = params_.frames_per_buffer();
131   cras_stream_params* stream_params = cras_client_stream_params_create(
132       stream_direction_,
133       frames_per_packet,  // Total latency.
134       frames_per_packet,  // Call back when this many ready.
135       frames_per_packet,  // Minimum Callback level ignored for capture streams.
136       CRAS_STREAM_TYPE_DEFAULT,
137       0,  // Unused flags.
138       this,
139       CrasInputStream::SamplesReady,
140       CrasInputStream::StreamError,
141       audio_format);
142   if (!stream_params) {
143     DLOG(WARNING) << "Error setting up stream parameters.";
144     callback_->OnError(this);
145     callback_ = NULL;
146     cras_audio_format_destroy(audio_format);
147     return;
148   }
149
150   // Before starting the stream, save the number of bytes in a frame for use in
151   // the callback.
152   bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format);
153
154   // Adding the stream will start the audio callbacks.
155   if (cras_client_add_stream(client_, &stream_id_, stream_params)) {
156     DLOG(WARNING) << "Failed to add the stream.";
157     callback_->OnError(this);
158     callback_ = NULL;
159   }
160
161   // Done with config params.
162   cras_audio_format_destroy(audio_format);
163   cras_client_stream_params_destroy(stream_params);
164
165   started_ = true;
166 }
167
168 void CrasInputStream::Stop() {
169   DCHECK(client_);
170
171   if (!callback_ || !started_)
172     return;
173
174   StopAgc();
175
176   // Removing the stream from the client stops audio.
177   cras_client_rm_stream(client_, stream_id_);
178
179   started_ = false;
180 }
181
182 // Static callback asking for samples.  Run on high priority thread.
183 int CrasInputStream::SamplesReady(cras_client* client,
184                                   cras_stream_id_t stream_id,
185                                   uint8* samples,
186                                   size_t frames,
187                                   const timespec* sample_ts,
188                                   void* arg) {
189   CrasInputStream* me = static_cast<CrasInputStream*>(arg);
190   me->ReadAudio(frames, samples, sample_ts);
191   return frames;
192 }
193
194 // Static callback for stream errors.
195 int CrasInputStream::StreamError(cras_client* client,
196                                  cras_stream_id_t stream_id,
197                                  int err,
198                                  void* arg) {
199   CrasInputStream* me = static_cast<CrasInputStream*>(arg);
200   me->NotifyStreamError(err);
201   return 0;
202 }
203
204 void CrasInputStream::ReadAudio(size_t frames,
205                                 uint8* buffer,
206                                 const timespec* sample_ts) {
207   DCHECK(callback_);
208
209   timespec latency_ts = {0, 0};
210
211   // Determine latency and pass that on to the sink.  sample_ts is the wall time
212   // indicating when the first sample in the buffer was captured.  Convert that
213   // to latency in bytes.
214   cras_client_calc_capture_latency(sample_ts, &latency_ts);
215   double latency_usec =
216       latency_ts.tv_sec * base::Time::kMicrosecondsPerSecond +
217       latency_ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond;
218   double frames_latency =
219       latency_usec * params_.sample_rate() / base::Time::kMicrosecondsPerSecond;
220   unsigned int bytes_latency =
221       static_cast<unsigned int>(frames_latency * bytes_per_frame_);
222
223   // Update the AGC volume level once every second. Note that, |volume| is
224   // also updated each time SetVolume() is called through IPC by the
225   // render-side AGC.
226   double normalized_volume = 0.0;
227   GetAgcVolume(&normalized_volume);
228
229   callback_->OnData(this,
230                     buffer,
231                     frames * bytes_per_frame_,
232                     bytes_latency,
233                     normalized_volume);
234 }
235
236 void CrasInputStream::NotifyStreamError(int err) {
237   if (callback_)
238     callback_->OnError(this);
239 }
240
241 double CrasInputStream::GetMaxVolume() {
242   DCHECK(client_);
243
244   // Capture gain is returned as dB * 100 (150 => 1.5dBFS).  Convert the dB
245   // value to a ratio before returning.
246   double dB = cras_client_get_system_max_capture_gain(client_) / 100.0;
247   return GetVolumeRatioFromDecibels(dB);
248 }
249
250 void CrasInputStream::SetVolume(double volume) {
251   DCHECK(client_);
252
253   // Convert from the passed volume ratio, to dB * 100.
254   double dB = GetDecibelsFromVolumeRatio(volume);
255   cras_client_set_system_capture_gain(client_, static_cast<long>(dB * 100.0));
256
257   // Update the AGC volume level based on the last setting above. Note that,
258   // the volume-level resolution is not infinite and it is therefore not
259   // possible to assume that the volume provided as input parameter can be
260   // used directly. Instead, a new query to the audio hardware is required.
261   // This method does nothing if AGC is disabled.
262   UpdateAgcVolume();
263 }
264
265 double CrasInputStream::GetVolume() {
266   if (!client_)
267     return 0.0;
268
269   long dB = cras_client_get_system_capture_gain(client_) / 100.0;
270   return GetVolumeRatioFromDecibels(dB);
271 }
272
273 double CrasInputStream::GetVolumeRatioFromDecibels(double dB) const {
274   return pow(10, dB / 20.0);
275 }
276
277 double CrasInputStream::GetDecibelsFromVolumeRatio(double volume_ratio) const {
278   return 20 * log10(volume_ratio);
279 }
280
281 }  // namespace media