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/alsa/alsa_util.h" 14#include "media/audio/audio_manager.h" 15#include "media/audio/cras/audio_manager_cras.h" 16 17namespace media { 18 19CrasInputStream::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 34CrasInputStream::~CrasInputStream() { 35 DCHECK(!client_); 36} 37 38bool 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 88void 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 105void 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 168void 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. 183int 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. 195int 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 204void 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 236void CrasInputStream::NotifyStreamError(int err) { 237 if (callback_) 238 callback_->OnError(this); 239} 240 241double 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 250void 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 265double 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 273double CrasInputStream::GetVolumeRatioFromDecibels(double dB) const { 274 return pow(10, dB / 20.0); 275} 276 277double CrasInputStream::GetDecibelsFromVolumeRatio(double volume_ratio) const { 278 return 20 * log10(volume_ratio); 279} 280 281} // namespace media 282