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 // THREAD SAFETY 6 // 7 // AlsaPcmOutputStream object is *not* thread-safe and should only be used 8 // from the audio thread. We DCHECK on this assumption whenever we can. 9 // 10 // SEMANTICS OF Close() 11 // 12 // Close() is responsible for cleaning up any resources that were acquired after 13 // a successful Open(). Close() will nullify any scheduled outstanding runnable 14 // methods. 15 // 16 // 17 // SEMANTICS OF ERROR STATES 18 // 19 // The object has two distinct error states: |state_| == kInError 20 // and |stop_stream_|. The |stop_stream_| variable is used to indicate 21 // that the playback_handle should no longer be used either because of a 22 // hardware/low-level event. 23 // 24 // When |state_| == kInError, all public API functions will fail with an error 25 // (Start() will call the OnError() function on the callback immediately), or 26 // no-op themselves with the exception of Close(). Even if an error state has 27 // been entered, if Open() has previously returned successfully, Close() must be 28 // called to cleanup the ALSA devices and release resources. 29 // 30 // When |stop_stream_| is set, no more commands will be made against the 31 // ALSA device, and playback will effectively stop. From the client's point of 32 // view, it will seem that the device has just clogged and stopped requesting 33 // data. 34 35 #include "media/audio/alsa/alsa_output.h" 36 37 #include <algorithm> 38 39 #include "base/bind.h" 40 #include "base/debug/trace_event.h" 41 #include "base/logging.h" 42 #include "base/stl_util.h" 43 #include "base/time/time.h" 44 #include "media/audio/alsa/alsa_util.h" 45 #include "media/audio/alsa/alsa_wrapper.h" 46 #include "media/audio/alsa/audio_manager_alsa.h" 47 #include "media/base/channel_mixer.h" 48 #include "media/base/data_buffer.h" 49 #include "media/base/seekable_buffer.h" 50 51 namespace media { 52 53 // Set to 0 during debugging if you want error messages due to underrun 54 // events or other recoverable errors. 55 #if defined(NDEBUG) 56 static const int kPcmRecoverIsSilent = 1; 57 #else 58 static const int kPcmRecoverIsSilent = 0; 59 #endif 60 61 // While the "default" device may support multi-channel audio, in Alsa, only 62 // the device names surround40, surround41, surround50, etc, have a defined 63 // channel mapping according to Lennart: 64 // 65 // http://0pointer.de/blog/projects/guide-to-sound-apis.html 66 // 67 // This function makes a best guess at the specific > 2 channel device name 68 // based on the number of channels requested. NULL is returned if no device 69 // can be found to match the channel numbers. In this case, using 70 // kDefaultDevice is probably the best bet. 71 // 72 // A five channel source is assumed to be surround50 instead of surround41 73 // (which is also 5 channels). 74 // 75 // TODO(ajwong): The source data should have enough info to tell us if we want 76 // surround41 versus surround51, etc., instead of needing us to guess based on 77 // channel number. Fix API to pass that data down. 78 static const char* GuessSpecificDeviceName(uint32 channels) { 79 switch (channels) { 80 case 8: 81 return "surround71"; 82 83 case 7: 84 return "surround70"; 85 86 case 6: 87 return "surround51"; 88 89 case 5: 90 return "surround50"; 91 92 case 4: 93 return "surround40"; 94 95 default: 96 return NULL; 97 } 98 } 99 100 std::ostream& operator<<(std::ostream& os, 101 AlsaPcmOutputStream::InternalState state) { 102 switch (state) { 103 case AlsaPcmOutputStream::kInError: 104 os << "kInError"; 105 break; 106 case AlsaPcmOutputStream::kCreated: 107 os << "kCreated"; 108 break; 109 case AlsaPcmOutputStream::kIsOpened: 110 os << "kIsOpened"; 111 break; 112 case AlsaPcmOutputStream::kIsPlaying: 113 os << "kIsPlaying"; 114 break; 115 case AlsaPcmOutputStream::kIsStopped: 116 os << "kIsStopped"; 117 break; 118 case AlsaPcmOutputStream::kIsClosed: 119 os << "kIsClosed"; 120 break; 121 }; 122 return os; 123 } 124 125 const char AlsaPcmOutputStream::kDefaultDevice[] = "default"; 126 const char AlsaPcmOutputStream::kAutoSelectDevice[] = ""; 127 const char AlsaPcmOutputStream::kPlugPrefix[] = "plug:"; 128 129 // We use 40ms as our minimum required latency. If it is needed, we may be able 130 // to get it down to 20ms. 131 const uint32 AlsaPcmOutputStream::kMinLatencyMicros = 40 * 1000; 132 133 AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name, 134 const AudioParameters& params, 135 AlsaWrapper* wrapper, 136 AudioManagerBase* manager) 137 : requested_device_name_(device_name), 138 pcm_format_(alsa_util::BitsToFormat(params.bits_per_sample())), 139 channels_(params.channels()), 140 channel_layout_(params.channel_layout()), 141 sample_rate_(params.sample_rate()), 142 bytes_per_sample_(params.bits_per_sample() / 8), 143 bytes_per_frame_(params.GetBytesPerFrame()), 144 packet_size_(params.GetBytesPerBuffer()), 145 latency_(std::max( 146 base::TimeDelta::FromMicroseconds(kMinLatencyMicros), 147 FramesToTimeDelta(params.frames_per_buffer() * 2, sample_rate_))), 148 bytes_per_output_frame_(bytes_per_frame_), 149 alsa_buffer_frames_(0), 150 stop_stream_(false), 151 wrapper_(wrapper), 152 manager_(manager), 153 message_loop_(base::MessageLoop::current()), 154 playback_handle_(NULL), 155 frames_per_packet_(packet_size_ / bytes_per_frame_), 156 state_(kCreated), 157 volume_(1.0f), 158 source_callback_(NULL), 159 audio_bus_(AudioBus::Create(params)), 160 weak_factory_(this) { 161 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); 162 DCHECK_EQ(audio_bus_->frames() * bytes_per_frame_, packet_size_); 163 164 // Sanity check input values. 165 if (!params.IsValid()) { 166 LOG(WARNING) << "Unsupported audio parameters."; 167 TransitionTo(kInError); 168 } 169 170 if (pcm_format_ == SND_PCM_FORMAT_UNKNOWN) { 171 LOG(WARNING) << "Unsupported bits per sample: " << params.bits_per_sample(); 172 TransitionTo(kInError); 173 } 174 } 175 176 AlsaPcmOutputStream::~AlsaPcmOutputStream() { 177 InternalState current_state = state(); 178 DCHECK(current_state == kCreated || 179 current_state == kIsClosed || 180 current_state == kInError); 181 DCHECK(!playback_handle_); 182 } 183 184 bool AlsaPcmOutputStream::Open() { 185 DCHECK(IsOnAudioThread()); 186 187 if (state() == kInError) 188 return false; 189 190 if (!CanTransitionTo(kIsOpened)) { 191 NOTREACHED() << "Invalid state: " << state(); 192 return false; 193 } 194 195 // We do not need to check if the transition was successful because 196 // CanTransitionTo() was checked above, and it is assumed that this 197 // object's public API is only called on one thread so the state cannot 198 // transition out from under us. 199 TransitionTo(kIsOpened); 200 201 // Try to open the device. 202 if (requested_device_name_ == kAutoSelectDevice) { 203 playback_handle_ = AutoSelectDevice(latency_.InMicroseconds()); 204 if (playback_handle_) 205 DVLOG(1) << "Auto-selected device: " << device_name_; 206 } else { 207 device_name_ = requested_device_name_; 208 playback_handle_ = alsa_util::OpenPlaybackDevice( 209 wrapper_, device_name_.c_str(), channels_, sample_rate_, 210 pcm_format_, latency_.InMicroseconds()); 211 } 212 213 // Finish initializing the stream if the device was opened successfully. 214 if (playback_handle_ == NULL) { 215 stop_stream_ = true; 216 TransitionTo(kInError); 217 return false; 218 } else { 219 bytes_per_output_frame_ = channel_mixer_ ? 220 mixed_audio_bus_->channels() * bytes_per_sample_ : bytes_per_frame_; 221 uint32 output_packet_size = frames_per_packet_ * bytes_per_output_frame_; 222 buffer_.reset(new media::SeekableBuffer(0, output_packet_size)); 223 224 // Get alsa buffer size. 225 snd_pcm_uframes_t buffer_size; 226 snd_pcm_uframes_t period_size; 227 int error = wrapper_->PcmGetParams(playback_handle_, &buffer_size, 228 &period_size); 229 if (error < 0) { 230 LOG(ERROR) << "Failed to get playback buffer size from ALSA: " 231 << wrapper_->StrError(error); 232 // Buffer size is at least twice of packet size. 233 alsa_buffer_frames_ = frames_per_packet_ * 2; 234 } else { 235 alsa_buffer_frames_ = buffer_size; 236 } 237 } 238 239 return true; 240 } 241 242 void AlsaPcmOutputStream::Close() { 243 DCHECK(IsOnAudioThread()); 244 245 if (state() != kIsClosed) 246 TransitionTo(kIsClosed); 247 248 // Shutdown the audio device. 249 if (playback_handle_) { 250 if (alsa_util::CloseDevice(wrapper_, playback_handle_) < 0) { 251 LOG(WARNING) << "Unable to close audio device. Leaking handle."; 252 } 253 playback_handle_ = NULL; 254 255 // Release the buffer. 256 buffer_.reset(); 257 258 // Signal anything that might already be scheduled to stop. 259 stop_stream_ = true; // Not necessary in production, but unit tests 260 // uses the flag to verify that stream was closed. 261 } 262 263 weak_factory_.InvalidateWeakPtrs(); 264 265 // Signal to the manager that we're closed and can be removed. 266 // Should be last call in the method as it deletes "this". 267 manager_->ReleaseOutputStream(this); 268 } 269 270 void AlsaPcmOutputStream::Start(AudioSourceCallback* callback) { 271 DCHECK(IsOnAudioThread()); 272 273 CHECK(callback); 274 275 if (stop_stream_) 276 return; 277 278 // Only post the task if we can enter the playing state. 279 if (TransitionTo(kIsPlaying) != kIsPlaying) 280 return; 281 282 // Before starting, the buffer might have audio from previous user of this 283 // device. 284 buffer_->Clear(); 285 286 // When starting again, drop all packets in the device and prepare it again 287 // in case we are restarting from a pause state and need to flush old data. 288 int error = wrapper_->PcmDrop(playback_handle_); 289 if (error < 0 && error != -EAGAIN) { 290 LOG(ERROR) << "Failure clearing playback device (" 291 << wrapper_->PcmName(playback_handle_) << "): " 292 << wrapper_->StrError(error); 293 stop_stream_ = true; 294 return; 295 } 296 297 error = wrapper_->PcmPrepare(playback_handle_); 298 if (error < 0 && error != -EAGAIN) { 299 LOG(ERROR) << "Failure preparing stream (" 300 << wrapper_->PcmName(playback_handle_) << "): " 301 << wrapper_->StrError(error); 302 stop_stream_ = true; 303 return; 304 } 305 306 // Ensure the first buffer is silence to avoid startup glitches. 307 int buffer_size = GetAvailableFrames() * bytes_per_output_frame_; 308 scoped_refptr<DataBuffer> silent_packet = new DataBuffer(buffer_size); 309 silent_packet->set_data_size(buffer_size); 310 memset(silent_packet->writable_data(), 0, silent_packet->data_size()); 311 buffer_->Append(silent_packet); 312 WritePacket(); 313 314 // Start the callback chain. 315 set_source_callback(callback); 316 WriteTask(); 317 } 318 319 void AlsaPcmOutputStream::Stop() { 320 DCHECK(IsOnAudioThread()); 321 322 // Reset the callback, so that it is not called anymore. 323 set_source_callback(NULL); 324 weak_factory_.InvalidateWeakPtrs(); 325 326 TransitionTo(kIsStopped); 327 } 328 329 void AlsaPcmOutputStream::SetVolume(double volume) { 330 DCHECK(IsOnAudioThread()); 331 332 volume_ = static_cast<float>(volume); 333 } 334 335 void AlsaPcmOutputStream::GetVolume(double* volume) { 336 DCHECK(IsOnAudioThread()); 337 338 *volume = volume_; 339 } 340 341 void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) { 342 DCHECK(IsOnAudioThread()); 343 344 // If stopped, simulate a 0-length packet. 345 if (stop_stream_) { 346 buffer_->Clear(); 347 *source_exhausted = true; 348 return; 349 } 350 351 *source_exhausted = false; 352 353 // Request more data only when we run out of data in the buffer, because 354 // WritePacket() comsumes only the current chunk of data. 355 if (!buffer_->forward_bytes()) { 356 // Before making a request to source for data we need to determine the 357 // delay (in bytes) for the requested data to be played. 358 const uint32 hardware_delay = GetCurrentDelay() * bytes_per_frame_; 359 360 scoped_refptr<media::DataBuffer> packet = 361 new media::DataBuffer(packet_size_); 362 int frames_filled = RunDataCallback( 363 audio_bus_.get(), AudioBuffersState(0, hardware_delay)); 364 365 size_t packet_size = frames_filled * bytes_per_frame_; 366 DCHECK_LE(packet_size, packet_size_); 367 368 // TODO(dalecurtis): Channel downmixing, upmixing, should be done in mixer; 369 // volume adjust should use SSE optimized vector_fmul() prior to interleave. 370 AudioBus* output_bus = audio_bus_.get(); 371 if (channel_mixer_) { 372 output_bus = mixed_audio_bus_.get(); 373 channel_mixer_->Transform(audio_bus_.get(), output_bus); 374 // Adjust packet size for downmix. 375 packet_size = packet_size / bytes_per_frame_ * bytes_per_output_frame_; 376 } 377 378 // Note: If this ever changes to output raw float the data must be clipped 379 // and sanitized since it may come from an untrusted source such as NaCl. 380 output_bus->Scale(volume_); 381 output_bus->ToInterleaved( 382 frames_filled, bytes_per_sample_, packet->writable_data()); 383 384 if (packet_size > 0) { 385 packet->set_data_size(packet_size); 386 // Add the packet to the buffer. 387 buffer_->Append(packet); 388 } else { 389 *source_exhausted = true; 390 } 391 } 392 } 393 394 void AlsaPcmOutputStream::WritePacket() { 395 DCHECK(IsOnAudioThread()); 396 397 // If the device is in error, just eat the bytes. 398 if (stop_stream_) { 399 buffer_->Clear(); 400 return; 401 } 402 403 if (state() != kIsPlaying) 404 return; 405 406 CHECK_EQ(buffer_->forward_bytes() % bytes_per_output_frame_, 0u); 407 408 const uint8* buffer_data; 409 int buffer_size; 410 if (buffer_->GetCurrentChunk(&buffer_data, &buffer_size)) { 411 buffer_size = buffer_size - (buffer_size % bytes_per_output_frame_); 412 snd_pcm_sframes_t frames = std::min( 413 static_cast<snd_pcm_sframes_t>(buffer_size / bytes_per_output_frame_), 414 GetAvailableFrames()); 415 416 if (!frames) 417 return; 418 419 snd_pcm_sframes_t frames_written = 420 wrapper_->PcmWritei(playback_handle_, buffer_data, frames); 421 if (frames_written < 0) { 422 // Attempt once to immediately recover from EINTR, 423 // EPIPE (overrun/underrun), ESTRPIPE (stream suspended). WritePacket 424 // will eventually be called again, so eventual recovery will happen if 425 // muliple retries are required. 426 frames_written = wrapper_->PcmRecover(playback_handle_, 427 frames_written, 428 kPcmRecoverIsSilent); 429 if (frames_written < 0) { 430 if (frames_written != -EAGAIN) { 431 LOG(ERROR) << "Failed to write to pcm device: " 432 << wrapper_->StrError(frames_written); 433 RunErrorCallback(frames_written); 434 stop_stream_ = true; 435 } 436 } 437 } else { 438 DCHECK_EQ(frames_written, frames); 439 440 // Seek forward in the buffer after we've written some data to ALSA. 441 buffer_->Seek(frames_written * bytes_per_output_frame_); 442 } 443 } else { 444 // If nothing left to write and playback hasn't started yet, start it now. 445 // This ensures that shorter sounds will still play. 446 if (playback_handle_ && 447 (wrapper_->PcmState(playback_handle_) == SND_PCM_STATE_PREPARED) && 448 GetCurrentDelay() > 0) { 449 wrapper_->PcmStart(playback_handle_); 450 } 451 } 452 } 453 454 void AlsaPcmOutputStream::WriteTask() { 455 DCHECK(IsOnAudioThread()); 456 457 if (stop_stream_) 458 return; 459 460 if (state() == kIsStopped) 461 return; 462 463 bool source_exhausted; 464 BufferPacket(&source_exhausted); 465 WritePacket(); 466 467 ScheduleNextWrite(source_exhausted); 468 } 469 470 void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) { 471 DCHECK(IsOnAudioThread()); 472 473 if (stop_stream_ || state() != kIsPlaying) 474 return; 475 476 const uint32 kTargetFramesAvailable = alsa_buffer_frames_ / 2; 477 uint32 available_frames = GetAvailableFrames(); 478 479 base::TimeDelta next_fill_time; 480 if (buffer_->forward_bytes() && available_frames) { 481 // If we've got data available and ALSA has room, deliver it immediately. 482 next_fill_time = base::TimeDelta(); 483 } else if (buffer_->forward_bytes()) { 484 // If we've got data available and no room, poll until room is available. 485 // Polling in this manner allows us to ensure a more consistent callback 486 // schedule. In testing this yields a variance of +/- 5ms versus the non- 487 // polling strategy which is around +/- 30ms and bimodal. 488 next_fill_time = base::TimeDelta::FromMilliseconds(5); 489 } else if (available_frames < kTargetFramesAvailable) { 490 // Schedule the next write for the moment when the available buffer of the 491 // sound card hits |kTargetFramesAvailable|. 492 next_fill_time = FramesToTimeDelta( 493 kTargetFramesAvailable - available_frames, sample_rate_); 494 } else if (!source_exhausted) { 495 // The sound card has |kTargetFramesAvailable| or more frames available. 496 // Invoke the next write immediately to avoid underrun. 497 next_fill_time = base::TimeDelta(); 498 } else { 499 // The sound card has frames available, but our source is exhausted, so 500 // avoid busy looping by delaying a bit. 501 next_fill_time = base::TimeDelta::FromMilliseconds(10); 502 } 503 504 message_loop_->PostDelayedTask(FROM_HERE, base::Bind( 505 &AlsaPcmOutputStream::WriteTask, weak_factory_.GetWeakPtr()), 506 next_fill_time); 507 } 508 509 // static 510 base::TimeDelta AlsaPcmOutputStream::FramesToTimeDelta(int frames, 511 double sample_rate) { 512 return base::TimeDelta::FromMicroseconds( 513 frames * base::Time::kMicrosecondsPerSecond / sample_rate); 514 } 515 516 std::string AlsaPcmOutputStream::FindDeviceForChannels(uint32 channels) { 517 // Constants specified by the ALSA API for device hints. 518 static const int kGetAllDevices = -1; 519 static const char kPcmInterfaceName[] = "pcm"; 520 static const char kIoHintName[] = "IOID"; 521 static const char kNameHintName[] = "NAME"; 522 523 const char* wanted_device = GuessSpecificDeviceName(channels); 524 if (!wanted_device) 525 return std::string(); 526 527 std::string guessed_device; 528 void** hints = NULL; 529 int error = wrapper_->DeviceNameHint(kGetAllDevices, 530 kPcmInterfaceName, 531 &hints); 532 if (error == 0) { 533 // NOTE: Do not early return from inside this if statement. The 534 // hints above need to be freed. 535 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) { 536 // Only examine devices that are output capable.. Valid values are 537 // "Input", "Output", and NULL which means both input and output. 538 scoped_ptr<char, base::FreeDeleter> io( 539 wrapper_->DeviceNameGetHint(*hint_iter, kIoHintName)); 540 if (io != NULL && strcmp(io.get(), "Input") == 0) 541 continue; 542 543 // Attempt to select the closest device for number of channels. 544 scoped_ptr<char, base::FreeDeleter> name( 545 wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName)); 546 if (strncmp(wanted_device, name.get(), strlen(wanted_device)) == 0) { 547 guessed_device = name.get(); 548 break; 549 } 550 } 551 552 // Destroy the hint now that we're done with it. 553 wrapper_->DeviceNameFreeHint(hints); 554 hints = NULL; 555 } else { 556 LOG(ERROR) << "Unable to get hints for devices: " 557 << wrapper_->StrError(error); 558 } 559 560 return guessed_device; 561 } 562 563 snd_pcm_sframes_t AlsaPcmOutputStream::GetCurrentDelay() { 564 snd_pcm_sframes_t delay = -1; 565 // Don't query ALSA's delay if we have underrun since it'll be jammed at some 566 // non-zero value and potentially even negative! 567 // 568 // Also, if we're in the prepared state, don't query because that seems to 569 // cause an I/O error when we do query the delay. 570 snd_pcm_state_t pcm_state = wrapper_->PcmState(playback_handle_); 571 if (pcm_state != SND_PCM_STATE_XRUN && 572 pcm_state != SND_PCM_STATE_PREPARED) { 573 int error = wrapper_->PcmDelay(playback_handle_, &delay); 574 if (error < 0) { 575 // Assume a delay of zero and attempt to recover the device. 576 delay = -1; 577 error = wrapper_->PcmRecover(playback_handle_, 578 error, 579 kPcmRecoverIsSilent); 580 if (error < 0) { 581 LOG(ERROR) << "Failed querying delay: " << wrapper_->StrError(error); 582 } 583 } 584 } 585 586 // snd_pcm_delay() sometimes returns crazy values. In this case return delay 587 // of data we know currently is in ALSA's buffer. Note: When the underlying 588 // driver is PulseAudio based, certain configuration settings (e.g., tsched=1) 589 // will generate much larger delay values than |alsa_buffer_frames_|, so only 590 // clip if delay is truly crazy (> 10x expected). 591 if (static_cast<snd_pcm_uframes_t>(delay) > alsa_buffer_frames_ * 10) { 592 delay = alsa_buffer_frames_ - GetAvailableFrames(); 593 } 594 595 if (delay < 0) { 596 delay = 0; 597 } 598 599 return delay; 600 } 601 602 snd_pcm_sframes_t AlsaPcmOutputStream::GetAvailableFrames() { 603 DCHECK(IsOnAudioThread()); 604 605 if (stop_stream_) 606 return 0; 607 608 // Find the number of frames queued in the sound device. 609 snd_pcm_sframes_t available_frames = 610 wrapper_->PcmAvailUpdate(playback_handle_); 611 if (available_frames < 0) { 612 available_frames = wrapper_->PcmRecover(playback_handle_, 613 available_frames, 614 kPcmRecoverIsSilent); 615 } 616 if (available_frames < 0) { 617 LOG(ERROR) << "Failed querying available frames. Assuming 0: " 618 << wrapper_->StrError(available_frames); 619 return 0; 620 } 621 if (static_cast<uint32>(available_frames) > alsa_buffer_frames_ * 2) { 622 LOG(ERROR) << "ALSA returned " << available_frames << " of " 623 << alsa_buffer_frames_ << " frames available."; 624 return alsa_buffer_frames_; 625 } 626 627 return available_frames; 628 } 629 630 snd_pcm_t* AlsaPcmOutputStream::AutoSelectDevice(unsigned int latency) { 631 // For auto-selection: 632 // 1) Attempt to open a device that best matches the number of channels 633 // requested. 634 // 2) If that fails, attempt the "plug:" version of it in case ALSA can 635 // remap do some software conversion to make it work. 636 // 3) Fallback to kDefaultDevice. 637 // 4) If that fails too, try the "plug:" version of kDefaultDevice. 638 // 5) Give up. 639 snd_pcm_t* handle = NULL; 640 device_name_ = FindDeviceForChannels(channels_); 641 642 // Step 1. 643 if (!device_name_.empty()) { 644 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(), 645 channels_, sample_rate_, 646 pcm_format_, 647 latency)) != NULL) { 648 return handle; 649 } 650 651 // Step 2. 652 device_name_ = kPlugPrefix + device_name_; 653 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(), 654 channels_, sample_rate_, 655 pcm_format_, 656 latency)) != NULL) { 657 return handle; 658 } 659 } 660 661 // For the kDefaultDevice device, we can only reliably depend on 2-channel 662 // output to have the correct ordering according to Lennart. For the channel 663 // formats that we know how to downmix from (3 channel to 8 channel), setup 664 // downmixing. 665 uint32 default_channels = channels_; 666 if (default_channels > 2) { 667 channel_mixer_.reset(new ChannelMixer( 668 channel_layout_, CHANNEL_LAYOUT_STEREO)); 669 default_channels = 2; 670 mixed_audio_bus_ = AudioBus::Create( 671 default_channels, audio_bus_->frames()); 672 } 673 674 // Step 3. 675 device_name_ = kDefaultDevice; 676 if ((handle = alsa_util::OpenPlaybackDevice( 677 wrapper_, device_name_.c_str(), default_channels, sample_rate_, 678 pcm_format_, latency)) != NULL) { 679 return handle; 680 } 681 682 // Step 4. 683 device_name_ = kPlugPrefix + device_name_; 684 if ((handle = alsa_util::OpenPlaybackDevice( 685 wrapper_, device_name_.c_str(), default_channels, sample_rate_, 686 pcm_format_, latency)) != NULL) { 687 return handle; 688 } 689 690 // Unable to open any device. 691 device_name_.clear(); 692 return NULL; 693 } 694 695 bool AlsaPcmOutputStream::CanTransitionTo(InternalState to) { 696 switch (state_) { 697 case kCreated: 698 return to == kIsOpened || to == kIsClosed || to == kInError; 699 700 case kIsOpened: 701 return to == kIsPlaying || to == kIsStopped || 702 to == kIsClosed || to == kInError; 703 704 case kIsPlaying: 705 return to == kIsPlaying || to == kIsStopped || 706 to == kIsClosed || to == kInError; 707 708 case kIsStopped: 709 return to == kIsPlaying || to == kIsStopped || 710 to == kIsClosed || to == kInError; 711 712 case kInError: 713 return to == kIsClosed || to == kInError; 714 715 case kIsClosed: 716 default: 717 return false; 718 } 719 } 720 721 AlsaPcmOutputStream::InternalState 722 AlsaPcmOutputStream::TransitionTo(InternalState to) { 723 DCHECK(IsOnAudioThread()); 724 725 if (!CanTransitionTo(to)) { 726 NOTREACHED() << "Cannot transition from: " << state_ << " to: " << to; 727 state_ = kInError; 728 } else { 729 state_ = to; 730 } 731 return state_; 732 } 733 734 AlsaPcmOutputStream::InternalState AlsaPcmOutputStream::state() { 735 return state_; 736 } 737 738 bool AlsaPcmOutputStream::IsOnAudioThread() const { 739 return message_loop_ && message_loop_ == base::MessageLoop::current(); 740 } 741 742 int AlsaPcmOutputStream::RunDataCallback(AudioBus* audio_bus, 743 AudioBuffersState buffers_state) { 744 TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback"); 745 746 if (source_callback_) 747 return source_callback_->OnMoreData(audio_bus, buffers_state); 748 749 return 0; 750 } 751 752 void AlsaPcmOutputStream::RunErrorCallback(int code) { 753 if (source_callback_) 754 source_callback_->OnError(this); 755 } 756 757 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to 758 // release ownership of the currently registered callback. 759 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { 760 DCHECK(IsOnAudioThread()); 761 source_callback_ = callback; 762 } 763 764 } // namespace media 765