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"
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"
19 CrasInputStream::CrasInputStream(const AudioParameters& params,
20 AudioManagerCras* manager,
21 const std::string& device_id)
22 : audio_manager_(manager),
29 stream_direction_(device_id == AudioManagerBase::kLoopbackInputDeviceId ?
30 CRAS_STREAM_POST_MIX_PRE_DSP : CRAS_STREAM_INPUT) {
31 DCHECK(audio_manager_);
34 CrasInputStream::~CrasInputStream() {
38 bool CrasInputStream::Open() {
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.";
50 if (AudioParameters::AUDIO_PCM_LINEAR != params_.format() &&
51 AudioParameters::AUDIO_PCM_LOW_LATENCY != params_.format()) {
52 DLOG(WARNING) << "Unsupported audio format.";
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();
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";
70 if (cras_client_connect(client_)) {
71 DLOG(WARNING) << "Couldn't connect CRAS client.\n";
72 cras_client_destroy(client_);
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_);
88 void CrasInputStream::Close() {
90 cras_client_stop(client_);
91 cras_client_destroy(client_);
96 callback_->OnClose(this);
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);
105 void CrasInputStream::Start(AudioInputCallback* callback) {
109 // If already playing, stop before re-starting.
115 callback_ = callback;
117 // Prepare |audio_format| and |stream_params| for the stream we
119 cras_audio_format* audio_format = cras_audio_format_create(
120 alsa_util::BitsToFormat(params_.bits_per_sample()),
121 params_.sample_rate(),
124 DLOG(WARNING) << "Error setting up audio parameters.";
125 callback_->OnError(this);
130 unsigned int frames_per_packet = params_.frames_per_buffer();
131 cras_stream_params* stream_params = cras_client_stream_params_create(
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,
139 CrasInputStream::SamplesReady,
140 CrasInputStream::StreamError,
142 if (!stream_params) {
143 DLOG(WARNING) << "Error setting up stream parameters.";
144 callback_->OnError(this);
146 cras_audio_format_destroy(audio_format);
150 // Before starting the stream, save the number of bytes in a frame for use in
152 bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format);
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);
161 // Done with config params.
162 cras_audio_format_destroy(audio_format);
163 cras_client_stream_params_destroy(stream_params);
168 void CrasInputStream::Stop() {
171 if (!callback_ || !started_)
176 // Removing the stream from the client stops audio.
177 cras_client_rm_stream(client_, stream_id_);
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,
187 const timespec* sample_ts,
189 CrasInputStream* me = static_cast<CrasInputStream*>(arg);
190 me->ReadAudio(frames, samples, sample_ts);
194 // Static callback for stream errors.
195 int CrasInputStream::StreamError(cras_client* client,
196 cras_stream_id_t stream_id,
199 CrasInputStream* me = static_cast<CrasInputStream*>(arg);
200 me->NotifyStreamError(err);
204 void CrasInputStream::ReadAudio(size_t frames,
206 const timespec* sample_ts) {
209 timespec latency_ts = {0, 0};
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_);
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
226 double normalized_volume = 0.0;
227 GetAgcVolume(&normalized_volume);
229 callback_->OnData(this,
231 frames * bytes_per_frame_,
236 void CrasInputStream::NotifyStreamError(int err) {
238 callback_->OnError(this);
241 double CrasInputStream::GetMaxVolume() {
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);
250 void CrasInputStream::SetVolume(double volume) {
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));
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.
265 double CrasInputStream::GetVolume() {
269 long dB = cras_client_get_system_capture_gain(client_) / 100.0;
270 return GetVolumeRatioFromDecibels(dB);
273 double CrasInputStream::GetVolumeRatioFromDecibels(double dB) const {
274 return pow(10, dB / 20.0);
277 double CrasInputStream::GetDecibelsFromVolumeRatio(double volume_ratio) const {
278 return 20 * log10(volume_ratio);