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