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