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 15namespace media { 16 17CrasInputStream::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 33CrasInputStream::~CrasInputStream() { 34 DCHECK(!client_); 35} 36 37bool 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 87void 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 101void CrasInputStream::Start(AudioInputCallback* callback) { 102 DCHECK(client_); 103 DCHECK(callback); 104 105 // Channel map to CRAS_CHANNEL, values in the same order of 106 // corresponding source in Chromium defined Channels. 107 static const int kChannelMap[] = { 108 CRAS_CH_FL, 109 CRAS_CH_FR, 110 CRAS_CH_FC, 111 CRAS_CH_LFE, 112 CRAS_CH_RL, 113 CRAS_CH_RR, 114 CRAS_CH_FLC, 115 CRAS_CH_FRC, 116 CRAS_CH_RC, 117 CRAS_CH_SL, 118 CRAS_CH_SR 119 }; 120 COMPILE_ASSERT(arraysize(kChannelMap) == CHANNELS_MAX + 1, 121 channel_map_size_do_not_match); 122 123 // If already playing, stop before re-starting. 124 if (started_) 125 return; 126 127 StartAgc(); 128 129 callback_ = callback; 130 131 // Prepare |audio_format| and |stream_params| for the stream we 132 // will create. 133 cras_audio_format* audio_format = cras_audio_format_create( 134 AudioManagerCras::BitsToFormat(params_.bits_per_sample()), 135 params_.sample_rate(), 136 params_.channels()); 137 if (!audio_format) { 138 DLOG(WARNING) << "Error setting up audio parameters."; 139 callback_->OnError(this); 140 callback_ = NULL; 141 return; 142 } 143 144 // Initialize channel layout to all -1 to indicate that none of 145 // the channels is set in the layout. 146 int8 layout[CRAS_CH_MAX]; 147 for (size_t i = 0; i < arraysize(layout); ++i) 148 layout[i] = -1; 149 150 // Converts to CRAS defined channels. ChannelOrder will return -1 151 // for channels that are not present in params_.channel_layout(). 152 for (size_t i = 0; i < arraysize(kChannelMap); ++i) { 153 layout[kChannelMap[i]] = ChannelOrder(params_.channel_layout(), 154 static_cast<Channels>(i)); 155 } 156 if (cras_audio_format_set_channel_layout(audio_format, layout) != 0) { 157 DLOG(WARNING) << "Error setting channel layout."; 158 callback->OnError(this); 159 return; 160 } 161 162 unsigned int frames_per_packet = params_.frames_per_buffer(); 163 cras_stream_params* stream_params = cras_client_stream_params_create( 164 stream_direction_, 165 frames_per_packet, // Total latency. 166 frames_per_packet, // Call back when this many ready. 167 frames_per_packet, // Minimum Callback level ignored for capture streams. 168 CRAS_STREAM_TYPE_DEFAULT, 169 0, // Unused flags. 170 this, 171 CrasInputStream::SamplesReady, 172 CrasInputStream::StreamError, 173 audio_format); 174 if (!stream_params) { 175 DLOG(WARNING) << "Error setting up stream parameters."; 176 callback_->OnError(this); 177 callback_ = NULL; 178 cras_audio_format_destroy(audio_format); 179 return; 180 } 181 182 // Before starting the stream, save the number of bytes in a frame for use in 183 // the callback. 184 bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format); 185 186 // Adding the stream will start the audio callbacks. 187 if (cras_client_add_stream(client_, &stream_id_, stream_params)) { 188 DLOG(WARNING) << "Failed to add the stream."; 189 callback_->OnError(this); 190 callback_ = NULL; 191 } 192 193 // Done with config params. 194 cras_audio_format_destroy(audio_format); 195 cras_client_stream_params_destroy(stream_params); 196 197 started_ = true; 198} 199 200void CrasInputStream::Stop() { 201 DCHECK(client_); 202 203 if (!callback_ || !started_) 204 return; 205 206 StopAgc(); 207 208 // Removing the stream from the client stops audio. 209 cras_client_rm_stream(client_, stream_id_); 210 211 started_ = false; 212 callback_ = NULL; 213} 214 215// Static callback asking for samples. Run on high priority thread. 216int CrasInputStream::SamplesReady(cras_client* client, 217 cras_stream_id_t stream_id, 218 uint8* samples, 219 size_t frames, 220 const timespec* sample_ts, 221 void* arg) { 222 CrasInputStream* me = static_cast<CrasInputStream*>(arg); 223 me->ReadAudio(frames, samples, sample_ts); 224 return frames; 225} 226 227// Static callback for stream errors. 228int CrasInputStream::StreamError(cras_client* client, 229 cras_stream_id_t stream_id, 230 int err, 231 void* arg) { 232 CrasInputStream* me = static_cast<CrasInputStream*>(arg); 233 me->NotifyStreamError(err); 234 return 0; 235} 236 237void CrasInputStream::ReadAudio(size_t frames, 238 uint8* buffer, 239 const timespec* sample_ts) { 240 DCHECK(callback_); 241 242 timespec latency_ts = {0, 0}; 243 244 // Determine latency and pass that on to the sink. sample_ts is the wall time 245 // indicating when the first sample in the buffer was captured. Convert that 246 // to latency in bytes. 247 cras_client_calc_capture_latency(sample_ts, &latency_ts); 248 double latency_usec = 249 latency_ts.tv_sec * base::Time::kMicrosecondsPerSecond + 250 latency_ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond; 251 double frames_latency = 252 latency_usec * params_.sample_rate() / base::Time::kMicrosecondsPerSecond; 253 unsigned int bytes_latency = 254 static_cast<unsigned int>(frames_latency * bytes_per_frame_); 255 256 // Update the AGC volume level once every second. Note that, |volume| is 257 // also updated each time SetVolume() is called through IPC by the 258 // render-side AGC. 259 double normalized_volume = 0.0; 260 GetAgcVolume(&normalized_volume); 261 262 audio_bus_->FromInterleaved( 263 buffer, audio_bus_->frames(), params_.bits_per_sample() / 8); 264 callback_->OnData(this, audio_bus_.get(), bytes_latency, normalized_volume); 265} 266 267void CrasInputStream::NotifyStreamError(int err) { 268 if (callback_) 269 callback_->OnError(this); 270} 271 272double CrasInputStream::GetMaxVolume() { 273 DCHECK(client_); 274 275 // Capture gain is returned as dB * 100 (150 => 1.5dBFS). Convert the dB 276 // value to a ratio before returning. 277 double dB = cras_client_get_system_max_capture_gain(client_) / 100.0; 278 return GetVolumeRatioFromDecibels(dB); 279} 280 281void CrasInputStream::SetVolume(double volume) { 282 DCHECK(client_); 283 284 // Convert from the passed volume ratio, to dB * 100. 285 double dB = GetDecibelsFromVolumeRatio(volume); 286 cras_client_set_system_capture_gain(client_, static_cast<long>(dB * 100.0)); 287 288 // Update the AGC volume level based on the last setting above. Note that, 289 // the volume-level resolution is not infinite and it is therefore not 290 // possible to assume that the volume provided as input parameter can be 291 // used directly. Instead, a new query to the audio hardware is required. 292 // This method does nothing if AGC is disabled. 293 UpdateAgcVolume(); 294} 295 296double CrasInputStream::GetVolume() { 297 if (!client_) 298 return 0.0; 299 300 long dB = cras_client_get_system_capture_gain(client_) / 100.0; 301 return GetVolumeRatioFromDecibels(dB); 302} 303 304bool CrasInputStream::IsMuted() { 305 return false; 306} 307 308double CrasInputStream::GetVolumeRatioFromDecibels(double dB) const { 309 return pow(10, dB / 20.0); 310} 311 312double CrasInputStream::GetDecibelsFromVolumeRatio(double volume_ratio) const { 313 return 20 * log10(volume_ratio); 314} 315 316} // namespace media 317