1 // Copyright 2013 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_unified.h" 6 7 #include "base/logging.h" 8 #include "media/audio/cras/audio_manager_cras.h" 9 10 namespace media { 11 12 // Overview of operation: 13 // 1) An object of CrasUnifiedStream is created by the AudioManager 14 // factory: audio_man->MakeAudioStream(). 15 // 2) Next some thread will call Open(), at that point a client is created and 16 // configured for the correct format and sample rate. 17 // 3) Then Start(source) is called and a stream is added to the CRAS client 18 // which will create its own thread that periodically calls the source for more 19 // data as buffers are being consumed. 20 // 4) When finished Stop() is called, which is handled by stopping the stream. 21 // 5) Finally Close() is called. It cleans up and notifies the audio manager, 22 // which likely will destroy this object. 23 // 24 // For output-only streams, a unified stream is created with 0 input channels. 25 // 26 // Simplified data flow for unified streams: 27 // 28 // +-------------+ +------------------+ 29 // | CRAS Server | | Chrome Client | 30 // +------+------+ Add Stream +---------+--------+ 31 // |<----------------------------------| 32 // | | 33 // | buffer_frames captured to shm | 34 // |---------------------------------->| 35 // | | UnifiedCallback() 36 // | | ReadWriteAudio() 37 // | | 38 // | buffer_frames written to shm | 39 // |<----------------------------------| 40 // | | 41 // ... Repeats for each block. ... 42 // | | 43 // | | 44 // | Remove stream | 45 // |<----------------------------------| 46 // | | 47 // 48 // Simplified data flow for output only streams: 49 // 50 // +-------------+ +------------------+ 51 // | CRAS Server | | Chrome Client | 52 // +------+------+ Add Stream +---------+--------+ 53 // |<----------------------------------| 54 // | | 55 // | Near out of samples, request more | 56 // |---------------------------------->| 57 // | | UnifiedCallback() 58 // | | WriteAudio() 59 // | | 60 // | buffer_frames written to shm | 61 // |<----------------------------------| 62 // | | 63 // ... Repeats for each block. ... 64 // | | 65 // | | 66 // | Remove stream | 67 // |<----------------------------------| 68 // | | 69 // 70 // For Unified streams the Chrome client is notified whenever buffer_frames have 71 // been captured. For Output streams the client is notified a few milliseconds 72 // before the hardware buffer underruns and fills the buffer with another block 73 // of audio. 74 75 CrasUnifiedStream::CrasUnifiedStream(const AudioParameters& params, 76 AudioManagerCras* manager) 77 : client_(NULL), 78 stream_id_(0), 79 params_(params), 80 bytes_per_frame_(0), 81 is_playing_(false), 82 volume_(1.0), 83 manager_(manager), 84 source_callback_(NULL), 85 stream_direction_(CRAS_STREAM_OUTPUT) { 86 DCHECK(manager_); 87 DCHECK(params_.channels() > 0); 88 89 // Must have at least one input or output. If there are both they must be the 90 // same. 91 int input_channels = params_.input_channels(); 92 93 if (input_channels) { 94 // A unified stream for input and output. 95 DCHECK(params_.channels() == input_channels); 96 stream_direction_ = CRAS_STREAM_UNIFIED; 97 input_bus_ = AudioBus::Create(input_channels, 98 params_.frames_per_buffer()); 99 } 100 101 output_bus_ = AudioBus::Create(params); 102 } 103 104 CrasUnifiedStream::~CrasUnifiedStream() { 105 DCHECK(!is_playing_); 106 } 107 108 bool CrasUnifiedStream::Open() { 109 // Sanity check input values. 110 if (params_.sample_rate() <= 0) { 111 LOG(WARNING) << "Unsupported audio frequency."; 112 return false; 113 } 114 115 if (AudioManagerCras::BitsToFormat(params_.bits_per_sample()) == 116 SND_PCM_FORMAT_UNKNOWN) { 117 LOG(WARNING) << "Unsupported pcm format"; 118 return false; 119 } 120 121 // Create the client and connect to the CRAS server. 122 if (cras_client_create(&client_)) { 123 LOG(WARNING) << "Couldn't create CRAS client.\n"; 124 client_ = NULL; 125 return false; 126 } 127 128 if (cras_client_connect(client_)) { 129 LOG(WARNING) << "Couldn't connect CRAS client.\n"; 130 cras_client_destroy(client_); 131 client_ = NULL; 132 return false; 133 } 134 135 // Then start running the client. 136 if (cras_client_run_thread(client_)) { 137 LOG(WARNING) << "Couldn't run CRAS client.\n"; 138 cras_client_destroy(client_); 139 client_ = NULL; 140 return false; 141 } 142 143 return true; 144 } 145 146 void CrasUnifiedStream::Close() { 147 if (client_) { 148 cras_client_stop(client_); 149 cras_client_destroy(client_); 150 client_ = NULL; 151 } 152 153 // Signal to the manager that we're closed and can be removed. 154 // Should be last call in the method as it deletes "this". 155 manager_->ReleaseOutputStream(this); 156 } 157 158 void CrasUnifiedStream::Start(AudioSourceCallback* callback) { 159 CHECK(callback); 160 161 // Channel map to CRAS_CHANNEL, values in the same order of 162 // corresponding source in Chromium defined Channels. 163 static const int kChannelMap[] = { 164 CRAS_CH_FL, 165 CRAS_CH_FR, 166 CRAS_CH_FC, 167 CRAS_CH_LFE, 168 CRAS_CH_RL, 169 CRAS_CH_RR, 170 CRAS_CH_FLC, 171 CRAS_CH_FRC, 172 CRAS_CH_RC, 173 CRAS_CH_SL, 174 CRAS_CH_SR 175 }; 176 177 source_callback_ = callback; 178 179 // Only start if we can enter the playing state. 180 if (is_playing_) 181 return; 182 183 // Prepare |audio_format| and |stream_params| for the stream we 184 // will create. 185 cras_audio_format* audio_format = cras_audio_format_create( 186 AudioManagerCras::BitsToFormat(params_.bits_per_sample()), 187 params_.sample_rate(), 188 params_.channels()); 189 if (!audio_format) { 190 LOG(WARNING) << "Error setting up audio parameters."; 191 callback->OnError(this); 192 return; 193 } 194 195 // Initialize channel layout to all -1 to indicate that none of 196 // the channels is set in the layout. 197 int8 layout[CRAS_CH_MAX] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; 198 199 // Converts to CRAS defined channels. ChannelOrder will return -1 200 // for channels that does not present in params_.channel_layout(). 201 for (size_t i = 0; i < arraysize(kChannelMap); ++i) 202 layout[kChannelMap[i]] = ChannelOrder(params_.channel_layout(), 203 static_cast<Channels>(i)); 204 205 if (cras_audio_format_set_channel_layout(audio_format, layout)) { 206 LOG(WARNING) << "Error setting channel layout."; 207 callback->OnError(this); 208 return; 209 } 210 211 cras_stream_params* stream_params = cras_client_unified_params_create( 212 stream_direction_, 213 params_.frames_per_buffer(), 214 CRAS_STREAM_TYPE_DEFAULT, 215 0, 216 this, 217 CrasUnifiedStream::UnifiedCallback, 218 CrasUnifiedStream::StreamError, 219 audio_format); 220 if (!stream_params) { 221 LOG(WARNING) << "Error setting up stream parameters."; 222 callback->OnError(this); 223 cras_audio_format_destroy(audio_format); 224 return; 225 } 226 227 // Before starting the stream, save the number of bytes in a frame for use in 228 // the callback. 229 bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format); 230 231 // Adding the stream will start the audio callbacks requesting data. 232 if (cras_client_add_stream(client_, &stream_id_, stream_params) < 0) { 233 LOG(WARNING) << "Failed to add the stream"; 234 callback->OnError(this); 235 cras_audio_format_destroy(audio_format); 236 cras_client_stream_params_destroy(stream_params); 237 return; 238 } 239 240 // Set initial volume. 241 cras_client_set_stream_volume(client_, stream_id_, volume_); 242 243 // Done with config params. 244 cras_audio_format_destroy(audio_format); 245 cras_client_stream_params_destroy(stream_params); 246 247 is_playing_ = true; 248 } 249 250 void CrasUnifiedStream::Stop() { 251 if (!client_) 252 return; 253 254 // Removing the stream from the client stops audio. 255 cras_client_rm_stream(client_, stream_id_); 256 257 is_playing_ = false; 258 } 259 260 void CrasUnifiedStream::SetVolume(double volume) { 261 if (!client_) 262 return; 263 volume_ = static_cast<float>(volume); 264 cras_client_set_stream_volume(client_, stream_id_, volume_); 265 } 266 267 void CrasUnifiedStream::GetVolume(double* volume) { 268 *volume = volume_; 269 } 270 271 uint32 CrasUnifiedStream::GetBytesLatency( 272 const struct timespec& latency_ts) { 273 uint32 latency_usec; 274 275 // Treat negative latency (if we are too slow to render) as 0. 276 if (latency_ts.tv_sec < 0 || latency_ts.tv_nsec < 0) { 277 latency_usec = 0; 278 } else { 279 latency_usec = (latency_ts.tv_sec * base::Time::kMicrosecondsPerSecond) + 280 latency_ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond; 281 } 282 283 double frames_latency = 284 latency_usec * params_.sample_rate() / base::Time::kMicrosecondsPerSecond; 285 286 return static_cast<unsigned int>(frames_latency * bytes_per_frame_); 287 } 288 289 // Static callback asking for samples. 290 int CrasUnifiedStream::UnifiedCallback(cras_client* client, 291 cras_stream_id_t stream_id, 292 uint8* input_samples, 293 uint8* output_samples, 294 unsigned int frames, 295 const timespec* input_ts, 296 const timespec* output_ts, 297 void* arg) { 298 CrasUnifiedStream* me = static_cast<CrasUnifiedStream*>(arg); 299 return me->DispatchCallback(frames, 300 input_samples, 301 output_samples, 302 input_ts, 303 output_ts); 304 } 305 306 // Static callback for stream errors. 307 int CrasUnifiedStream::StreamError(cras_client* client, 308 cras_stream_id_t stream_id, 309 int err, 310 void* arg) { 311 CrasUnifiedStream* me = static_cast<CrasUnifiedStream*>(arg); 312 me->NotifyStreamError(err); 313 return 0; 314 } 315 316 // Calls the appropriate rendering function for this type of stream. 317 uint32 CrasUnifiedStream::DispatchCallback(size_t frames, 318 uint8* input_samples, 319 uint8* output_samples, 320 const timespec* input_ts, 321 const timespec* output_ts) { 322 switch (stream_direction_) { 323 case CRAS_STREAM_OUTPUT: 324 return WriteAudio(frames, output_samples, output_ts); 325 case CRAS_STREAM_INPUT: 326 NOTREACHED() << "CrasUnifiedStream doesn't support input streams."; 327 return 0; 328 case CRAS_STREAM_UNIFIED: 329 return ReadWriteAudio(frames, input_samples, output_samples, 330 input_ts, output_ts); 331 default: 332 break; 333 } 334 335 return 0; 336 } 337 338 // Note these are run from a real time thread, so don't waste cycles here. 339 uint32 CrasUnifiedStream::ReadWriteAudio(size_t frames, 340 uint8* input_samples, 341 uint8* output_samples, 342 const timespec* input_ts, 343 const timespec* output_ts) { 344 DCHECK_EQ(frames, static_cast<size_t>(output_bus_->frames())); 345 DCHECK(source_callback_); 346 347 uint32 bytes_per_sample = bytes_per_frame_ / params_.channels(); 348 input_bus_->FromInterleaved(input_samples, frames, bytes_per_sample); 349 350 // Determine latency and pass that on to the source. We have the capture time 351 // of the first input sample and the playback time of the next audio sample 352 // passed from the audio server, add them together for total latency. 353 uint32 total_delay_bytes; 354 timespec latency_ts = {0, 0}; 355 cras_client_calc_capture_latency(input_ts, &latency_ts); 356 total_delay_bytes = GetBytesLatency(latency_ts); 357 cras_client_calc_playback_latency(output_ts, &latency_ts); 358 total_delay_bytes += GetBytesLatency(latency_ts); 359 360 int frames_filled = source_callback_->OnMoreData( 361 output_bus_.get(), 362 AudioBuffersState(0, total_delay_bytes)); 363 364 output_bus_->ToInterleaved(frames_filled, bytes_per_sample, output_samples); 365 366 return frames_filled; 367 } 368 369 uint32 CrasUnifiedStream::WriteAudio(size_t frames, 370 uint8* buffer, 371 const timespec* sample_ts) { 372 DCHECK_EQ(frames, static_cast<size_t>(output_bus_->frames())); 373 374 // Determine latency and pass that on to the source. 375 timespec latency_ts = {0, 0}; 376 cras_client_calc_playback_latency(sample_ts, &latency_ts); 377 378 int frames_filled = source_callback_->OnMoreData( 379 output_bus_.get(), AudioBuffersState(0, GetBytesLatency(latency_ts))); 380 381 // Note: If this ever changes to output raw float the data must be clipped and 382 // sanitized since it may come from an untrusted source such as NaCl. 383 output_bus_->ToInterleaved( 384 frames_filled, bytes_per_frame_ / params_.channels(), buffer); 385 386 return frames_filled; 387 } 388 389 void CrasUnifiedStream::NotifyStreamError(int err) { 390 // This will remove the stream from the client. 391 if (source_callback_) 392 source_callback_->OnError(this); 393 } 394 395 } // namespace media 396