Increase safebrowsing download check timeout.
[chromium-blink-merge.git] / media / audio / cras / cras_input.cc
blob0181d88a273490bff9e523178998811086203c49
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_);
32 CrasInputStream::~CrasInputStream() {
33 DCHECK(!client_);
36 bool CrasInputStream::Open() {
37 if (client_) {
38 NOTREACHED() << "CrasInputStream already open";
39 return false; // Already open.
42 // Sanity check input values.
43 if (params_.sample_rate() <= 0) {
44 DLOG(WARNING) << "Unsupported audio frequency.";
45 return false;
48 if (AudioParameters::AUDIO_PCM_LINEAR != params_.format() &&
49 AudioParameters::AUDIO_PCM_LOW_LATENCY != params_.format()) {
50 DLOG(WARNING) << "Unsupported audio format.";
51 return false;
54 snd_pcm_format_t pcm_format =
55 AudioManagerCras::BitsToFormat(params_.bits_per_sample());
56 if (pcm_format == SND_PCM_FORMAT_UNKNOWN) {
57 DLOG(WARNING) << "Unsupported bits/sample: " << params_.bits_per_sample();
58 return false;
61 // Create the client and connect to the CRAS server.
62 if (cras_client_create(&client_) < 0) {
63 DLOG(WARNING) << "Couldn't create CRAS client.\n";
64 client_ = NULL;
65 return false;
68 if (cras_client_connect(client_)) {
69 DLOG(WARNING) << "Couldn't connect CRAS client.\n";
70 cras_client_destroy(client_);
71 client_ = NULL;
72 return false;
75 // Then start running the client.
76 if (cras_client_run_thread(client_)) {
77 DLOG(WARNING) << "Couldn't run CRAS client.\n";
78 cras_client_destroy(client_);
79 client_ = NULL;
80 return false;
83 return true;
86 void CrasInputStream::Close() {
87 Stop();
89 if (client_) {
90 cras_client_stop(client_);
91 cras_client_destroy(client_);
92 client_ = NULL;
95 // Signal to the manager that we're closed and can be removed.
96 // Should be last call in the method as it deletes "this".
97 audio_manager_->ReleaseInputStream(this);
100 void CrasInputStream::Start(AudioInputCallback* callback) {
101 DCHECK(client_);
102 DCHECK(callback);
104 // If already playing, stop before re-starting.
105 if (started_)
106 return;
108 StartAgc();
110 callback_ = callback;
112 // Prepare |audio_format| and |stream_params| for the stream we
113 // will create.
114 cras_audio_format* audio_format = cras_audio_format_create(
115 AudioManagerCras::BitsToFormat(params_.bits_per_sample()),
116 params_.sample_rate(),
117 params_.channels());
118 if (!audio_format) {
119 DLOG(WARNING) << "Error setting up audio parameters.";
120 callback_->OnError(this);
121 callback_ = NULL;
122 return;
125 unsigned int frames_per_packet = params_.frames_per_buffer();
126 cras_stream_params* stream_params = cras_client_stream_params_create(
127 stream_direction_,
128 frames_per_packet, // Total latency.
129 frames_per_packet, // Call back when this many ready.
130 frames_per_packet, // Minimum Callback level ignored for capture streams.
131 CRAS_STREAM_TYPE_DEFAULT,
132 0, // Unused flags.
133 this,
134 CrasInputStream::SamplesReady,
135 CrasInputStream::StreamError,
136 audio_format);
137 if (!stream_params) {
138 DLOG(WARNING) << "Error setting up stream parameters.";
139 callback_->OnError(this);
140 callback_ = NULL;
141 cras_audio_format_destroy(audio_format);
142 return;
145 // Before starting the stream, save the number of bytes in a frame for use in
146 // the callback.
147 bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format);
149 // Adding the stream will start the audio callbacks.
150 if (cras_client_add_stream(client_, &stream_id_, stream_params)) {
151 DLOG(WARNING) << "Failed to add the stream.";
152 callback_->OnError(this);
153 callback_ = NULL;
156 // Done with config params.
157 cras_audio_format_destroy(audio_format);
158 cras_client_stream_params_destroy(stream_params);
160 started_ = true;
163 void CrasInputStream::Stop() {
164 DCHECK(client_);
166 if (!callback_ || !started_)
167 return;
169 StopAgc();
171 // Removing the stream from the client stops audio.
172 cras_client_rm_stream(client_, stream_id_);
174 started_ = false;
175 callback_ = NULL;
178 // Static callback asking for samples. Run on high priority thread.
179 int CrasInputStream::SamplesReady(cras_client* client,
180 cras_stream_id_t stream_id,
181 uint8* samples,
182 size_t frames,
183 const timespec* sample_ts,
184 void* arg) {
185 CrasInputStream* me = static_cast<CrasInputStream*>(arg);
186 me->ReadAudio(frames, samples, sample_ts);
187 return frames;
190 // Static callback for stream errors.
191 int CrasInputStream::StreamError(cras_client* client,
192 cras_stream_id_t stream_id,
193 int err,
194 void* arg) {
195 CrasInputStream* me = static_cast<CrasInputStream*>(arg);
196 me->NotifyStreamError(err);
197 return 0;
200 void CrasInputStream::ReadAudio(size_t frames,
201 uint8* buffer,
202 const timespec* sample_ts) {
203 DCHECK(callback_);
205 timespec latency_ts = {0, 0};
207 // Determine latency and pass that on to the sink. sample_ts is the wall time
208 // indicating when the first sample in the buffer was captured. Convert that
209 // to latency in bytes.
210 cras_client_calc_capture_latency(sample_ts, &latency_ts);
211 double latency_usec =
212 latency_ts.tv_sec * base::Time::kMicrosecondsPerSecond +
213 latency_ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond;
214 double frames_latency =
215 latency_usec * params_.sample_rate() / base::Time::kMicrosecondsPerSecond;
216 unsigned int bytes_latency =
217 static_cast<unsigned int>(frames_latency * bytes_per_frame_);
219 // Update the AGC volume level once every second. Note that, |volume| is
220 // also updated each time SetVolume() is called through IPC by the
221 // render-side AGC.
222 double normalized_volume = 0.0;
223 GetAgcVolume(&normalized_volume);
225 callback_->OnData(this,
226 buffer,
227 frames * bytes_per_frame_,
228 bytes_latency,
229 normalized_volume);
232 void CrasInputStream::NotifyStreamError(int err) {
233 if (callback_)
234 callback_->OnError(this);
237 double CrasInputStream::GetMaxVolume() {
238 DCHECK(client_);
240 // Capture gain is returned as dB * 100 (150 => 1.5dBFS). Convert the dB
241 // value to a ratio before returning.
242 double dB = cras_client_get_system_max_capture_gain(client_) / 100.0;
243 return GetVolumeRatioFromDecibels(dB);
246 void CrasInputStream::SetVolume(double volume) {
247 DCHECK(client_);
249 // Convert from the passed volume ratio, to dB * 100.
250 double dB = GetDecibelsFromVolumeRatio(volume);
251 cras_client_set_system_capture_gain(client_, static_cast<long>(dB * 100.0));
253 // Update the AGC volume level based on the last setting above. Note that,
254 // the volume-level resolution is not infinite and it is therefore not
255 // possible to assume that the volume provided as input parameter can be
256 // used directly. Instead, a new query to the audio hardware is required.
257 // This method does nothing if AGC is disabled.
258 UpdateAgcVolume();
261 double CrasInputStream::GetVolume() {
262 if (!client_)
263 return 0.0;
265 long dB = cras_client_get_system_capture_gain(client_) / 100.0;
266 return GetVolumeRatioFromDecibels(dB);
269 double CrasInputStream::GetVolumeRatioFromDecibels(double dB) const {
270 return pow(10, dB / 20.0);
273 double CrasInputStream::GetDecibelsFromVolumeRatio(double volume_ratio) const {
274 return 20 * log10(volume_ratio);
277 } // namespace media