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