| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/audio/cras/cras_unified.h" | 5 #include "media/audio/cras/cras_unified.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "media/audio/cras/audio_manager_cras.h" | 8 #include "media/audio/cras/audio_manager_cras.h" |
| 9 | 9 |
| 10 namespace media { | 10 namespace media { |
| 11 | 11 |
| 12 // Overview of operation: | 12 // Overview of operation: |
| 13 // 1) An object of CrasUnifiedStream is created by the AudioManager | 13 // 1) An object of CrasUnifiedStream is created by the AudioManager |
| 14 // factory: audio_man->MakeAudioStream(). | 14 // factory: audio_man->MakeAudioStream(). |
| 15 // 2) Next some thread will call Open(), at that point a client is created and | 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. | 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 | 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 | 18 // which will create its own thread that periodically calls the source for more |
| 19 // data as buffers are being consumed. | 19 // data as buffers are being consumed. |
| 20 // 4) When finished Stop() is called, which is handled by stopping the stream. | 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, | 21 // 5) Finally Close() is called. It cleans up and notifies the audio manager, |
| 22 // which likely will destroy this object. | 22 // which likely will destroy this object. |
| 23 // | 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: | 24 // Simplified data flow for output only streams: |
| 49 // | 25 // |
| 50 // +-------------+ +------------------+ | 26 // +-------------+ +------------------+ |
| 51 // | CRAS Server | | Chrome Client | | 27 // | CRAS Server | | Chrome Client | |
| 52 // +------+------+ Add Stream +---------+--------+ | 28 // +------+------+ Add Stream +---------+--------+ |
| 53 // |<----------------------------------| | 29 // |<----------------------------------| |
| 54 // | | | 30 // | | |
| 55 // | Near out of samples, request more | | 31 // | Near out of samples, request more | |
| 56 // |---------------------------------->| | 32 // |---------------------------------->| |
| 57 // | | UnifiedCallback() | 33 // | | UnifiedCallback() |
| (...skipping 21 matching lines...) Expand all Loading... |
| 79 params_(params), | 55 params_(params), |
| 80 bytes_per_frame_(0), | 56 bytes_per_frame_(0), |
| 81 is_playing_(false), | 57 is_playing_(false), |
| 82 volume_(1.0), | 58 volume_(1.0), |
| 83 manager_(manager), | 59 manager_(manager), |
| 84 source_callback_(NULL), | 60 source_callback_(NULL), |
| 85 stream_direction_(CRAS_STREAM_OUTPUT) { | 61 stream_direction_(CRAS_STREAM_OUTPUT) { |
| 86 DCHECK(manager_); | 62 DCHECK(manager_); |
| 87 DCHECK(params_.channels() > 0); | 63 DCHECK(params_.channels() > 0); |
| 88 | 64 |
| 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); | 65 output_bus_ = AudioBus::Create(params); |
| 102 } | 66 } |
| 103 | 67 |
| 104 CrasUnifiedStream::~CrasUnifiedStream() { | 68 CrasUnifiedStream::~CrasUnifiedStream() { |
| 105 DCHECK(!is_playing_); | 69 DCHECK(!is_playing_); |
| 106 } | 70 } |
| 107 | 71 |
| 108 bool CrasUnifiedStream::Open() { | 72 bool CrasUnifiedStream::Open() { |
| 109 // Sanity check input values. | 73 // Sanity check input values. |
| 110 if (params_.sample_rate() <= 0) { | 74 if (params_.sample_rate() <= 0) { |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 uint8* input_samples, | 282 uint8* input_samples, |
| 319 uint8* output_samples, | 283 uint8* output_samples, |
| 320 const timespec* input_ts, | 284 const timespec* input_ts, |
| 321 const timespec* output_ts) { | 285 const timespec* output_ts) { |
| 322 switch (stream_direction_) { | 286 switch (stream_direction_) { |
| 323 case CRAS_STREAM_OUTPUT: | 287 case CRAS_STREAM_OUTPUT: |
| 324 return WriteAudio(frames, output_samples, output_ts); | 288 return WriteAudio(frames, output_samples, output_ts); |
| 325 case CRAS_STREAM_INPUT: | 289 case CRAS_STREAM_INPUT: |
| 326 NOTREACHED() << "CrasUnifiedStream doesn't support input streams."; | 290 NOTREACHED() << "CrasUnifiedStream doesn't support input streams."; |
| 327 return 0; | 291 return 0; |
| 328 case CRAS_STREAM_UNIFIED: | |
| 329 return ReadWriteAudio(frames, input_samples, output_samples, | |
| 330 input_ts, output_ts); | |
| 331 default: | 292 default: |
| 332 break; | 293 break; |
| 333 } | 294 } |
| 334 | 295 |
| 335 return 0; | 296 return 0; |
| 336 } | 297 } |
| 337 | 298 |
| 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, | 299 uint32 CrasUnifiedStream::WriteAudio(size_t frames, |
| 370 uint8* buffer, | 300 uint8* buffer, |
| 371 const timespec* sample_ts) { | 301 const timespec* sample_ts) { |
| 372 DCHECK_EQ(frames, static_cast<size_t>(output_bus_->frames())); | 302 DCHECK_EQ(frames, static_cast<size_t>(output_bus_->frames())); |
| 373 | 303 |
| 374 // Determine latency and pass that on to the source. | 304 // Determine latency and pass that on to the source. |
| 375 timespec latency_ts = {0, 0}; | 305 timespec latency_ts = {0, 0}; |
| 376 cras_client_calc_playback_latency(sample_ts, &latency_ts); | 306 cras_client_calc_playback_latency(sample_ts, &latency_ts); |
| 377 | 307 |
| 378 int frames_filled = source_callback_->OnMoreData( | 308 int frames_filled = source_callback_->OnMoreData( |
| 379 output_bus_.get(), AudioBuffersState(0, GetBytesLatency(latency_ts))); | 309 output_bus_.get(), AudioBuffersState(0, GetBytesLatency(latency_ts))); |
| 380 | 310 |
| 381 // Note: If this ever changes to output raw float the data must be clipped and | 311 // 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. | 312 // sanitized since it may come from an untrusted source such as NaCl. |
| 383 output_bus_->ToInterleaved( | 313 output_bus_->ToInterleaved( |
| 384 frames_filled, bytes_per_frame_ / params_.channels(), buffer); | 314 frames_filled, bytes_per_frame_ / params_.channels(), buffer); |
| 385 | 315 |
| 386 return frames_filled; | 316 return frames_filled; |
| 387 } | 317 } |
| 388 | 318 |
| 389 void CrasUnifiedStream::NotifyStreamError(int err) { | 319 void CrasUnifiedStream::NotifyStreamError(int err) { |
| 390 // This will remove the stream from the client. | 320 // This will remove the stream from the client. |
| 391 if (source_callback_) | 321 if (source_callback_) |
| 392 source_callback_->OnError(this); | 322 source_callback_->OnError(this); |
| 393 } | 323 } |
| 394 | 324 |
| 395 } // namespace media | 325 } // namespace media |
| OLD | NEW |