Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(122)

Side by Side Diff: media/audio/linux/alsa_output.cc

Issue 2008010: Fixes in AlsaPcmOutputStream. (Closed)
Patch Set: - Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 // THREAD SAFETY 5 // THREAD SAFETY
6 // 6 //
7 // The AlsaPcmOutputStream object's internal state is accessed by two threads: 7 // The AlsaPcmOutputStream object's internal state is accessed by two threads:
8 // 8 //
9 // client thread - creates the object and calls the public APIs. 9 // client thread - creates the object and calls the public APIs.
10 // message loop thread - executes all the internal tasks including querying 10 // message loop thread - executes all the internal tasks including querying
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
77 77
78 #include <algorithm> 78 #include <algorithm>
79 79
80 #include "base/logging.h" 80 #include "base/logging.h"
81 #include "base/message_loop.h" 81 #include "base/message_loop.h"
82 #include "base/stl_util-inl.h" 82 #include "base/stl_util-inl.h"
83 #include "base/time.h" 83 #include "base/time.h"
84 #include "media/audio/audio_util.h" 84 #include "media/audio/audio_util.h"
85 #include "media/audio/linux/alsa_wrapper.h" 85 #include "media/audio/linux/alsa_wrapper.h"
86 #include "media/audio/linux/audio_manager_linux.h" 86 #include "media/audio/linux/audio_manager_linux.h"
87 #include "media/base/data_buffer.h"
88 #include "media/base/seekable_buffer.h"
87 89
88 // Amount of time to wait if we've exhausted the data source. This is to avoid 90 // Amount of time to wait if we've exhausted the data source. This is to avoid
89 // busy looping. 91 // busy looping.
90 static const uint32 kNoDataSleepMilliseconds = 10; 92 static const uint32 kNoDataSleepMilliseconds = 10;
91 93
92 // According to the linux nanosleep manpage, nanosleep on linux can miss the 94 // According to the linux nanosleep manpage, nanosleep on linux can miss the
93 // deadline by up to 10ms because the kernel timeslice is 10ms. Give a 2x 95 // deadline by up to 10ms because the kernel timeslice is 10ms. Give a 2x
94 // buffer to compensate for the timeslice, and any additional slowdowns. 96 // buffer to compensate for the timeslice, and any additional slowdowns.
95 static const uint32 kSleepErrorMilliseconds = 20; 97 static const uint32 kSleepErrorMilliseconds = 20;
96 98
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 void AlsaPcmOutputStream::GetVolume(double* volume) { 371 void AlsaPcmOutputStream::GetVolume(double* volume) {
370 DCHECK_EQ(MessageLoop::current(), client_thread_loop_); 372 DCHECK_EQ(MessageLoop::current(), client_thread_loop_);
371 373
372 *volume = shared_data_.volume(); 374 *volume = shared_data_.volume();
373 } 375 }
374 376
375 void AlsaPcmOutputStream::OpenTask(uint32 packet_size) { 377 void AlsaPcmOutputStream::OpenTask(uint32 packet_size) {
376 DCHECK_EQ(MessageLoop::current(), message_loop_); 378 DCHECK_EQ(MessageLoop::current(), message_loop_);
377 379
378 // Initialize the configuration variables. 380 // Initialize the configuration variables.
379 frames_per_packet_ = packet_size / bytes_per_frame_; 381 packet_size_ = packet_size;
382 frames_per_packet_ = packet_size_ / bytes_per_frame_;
380 383
381 // Try to open the device. 384 // Try to open the device.
382 micros_per_packet_ = 385 micros_per_packet_ =
383 FramesToMicros(packet_size / bytes_per_frame_, sample_rate_); 386 FramesToMicros(packet_size / bytes_per_frame_, sample_rate_);
384 latency_micros_ = std::max(AlsaPcmOutputStream::kMinLatencyMicros, 387 latency_micros_ = std::max(AlsaPcmOutputStream::kMinLatencyMicros,
385 micros_per_packet_ * 2); 388 micros_per_packet_ * 2);
386 if (requested_device_name_ == kAutoSelectDevice) { 389 if (requested_device_name_ == kAutoSelectDevice) {
387 playback_handle_ = AutoSelectDevice(latency_micros_); 390 playback_handle_ = AutoSelectDevice(latency_micros_);
388 if (playback_handle_) { 391 if (playback_handle_) {
389 LOG(INFO) << "Auto-selected device: " << device_name_; 392 LOG(INFO) << "Auto-selected device: " << device_name_;
390 } 393 }
391 } else { 394 } else {
392 device_name_ = requested_device_name_; 395 device_name_ = requested_device_name_;
393 playback_handle_ = OpenDevice(device_name_, channels_, latency_micros_); 396 playback_handle_ = OpenDevice(device_name_, channels_, latency_micros_);
394 } 397 }
395 398
396 // Finish initializing the stream if the device was opened successfully. 399 // Finish initializing the stream if the device was opened successfully.
397 if (playback_handle_ == NULL) { 400 if (playback_handle_ == NULL) {
398 stop_stream_ = true; 401 stop_stream_ = true;
399 } else { 402 } else {
400 packet_.reset(new Packet(packet_size)); 403 bytes_per_output_frame_ = should_downmix_ ? 2 * bytes_per_sample_ :
401 if (should_downmix_) { 404 bytes_per_frame_;
402 bytes_per_output_frame_ = 2 * bytes_per_sample_; 405 uint32 output_packet_size = frames_per_packet_ * bytes_per_output_frame_;
406 buffer_.reset(new media::SeekableBuffer(0, output_packet_size));
407
408 // Get alsa buffer size.
409 snd_pcm_uframes_t buffer_size;
410 snd_pcm_uframes_t period_size;
411 int error = wrapper_->PcmGetParams(playback_handle_, &buffer_size,
412 &period_size);
413 if (error < 0) {
414 LOG(ERROR) << "Failed to get playback buffer size from ALSA: "
415 << wrapper_->StrError(error);
416 alsa_buffer_frames_ = frames_per_packet_;
417 } else {
418 alsa_buffer_frames_ = buffer_size;
403 } 419 }
404 } 420 }
405 } 421 }
406 422
407 void AlsaPcmOutputStream::StartTask() { 423 void AlsaPcmOutputStream::StartTask() {
408 DCHECK_EQ(MessageLoop::current(), message_loop_); 424 DCHECK_EQ(MessageLoop::current(), message_loop_);
409 425
410 if (stop_stream_) { 426 if (stop_stream_) {
411 return; 427 return;
412 } 428 }
(...skipping 11 matching lines...) Expand all
424 440
425 error = wrapper_->PcmPrepare(playback_handle_); 441 error = wrapper_->PcmPrepare(playback_handle_);
426 if (error < 0 && error != -EAGAIN) { 442 if (error < 0 && error != -EAGAIN) {
427 LOG(ERROR) << "Failure preparing stream (" 443 LOG(ERROR) << "Failure preparing stream ("
428 << wrapper_->PcmName(playback_handle_) << "): " 444 << wrapper_->PcmName(playback_handle_) << "): "
429 << wrapper_->StrError(error); 445 << wrapper_->StrError(error);
430 stop_stream_ = true; 446 stop_stream_ = true;
431 return; 447 return;
432 } 448 }
433 449
434 // Do a best-effort pre-roll to fill the buffer. Use integer rounding to find 450 ScheduleNextWrite();
435 // the maximum number of full packets that can fit into the buffer.
436 //
437 // TODO(ajwong): Handle EAGAIN.
438 const uint32 num_preroll = latency_micros_ / micros_per_packet_;
439 for (uint32 i = 0; i < num_preroll; ++i) {
440 BufferPacket(packet_.get());
441 WritePacket(packet_.get());
442 }
443
444 ScheduleNextWrite(packet_.get());
445 } 451 }
446 452
447 void AlsaPcmOutputStream::CloseTask() { 453 void AlsaPcmOutputStream::CloseTask() {
448 // NOTE: Keep this function idempotent to handle errors that might cause 454 // NOTE: Keep this function idempotent to handle errors that might cause
449 // multiple CloseTasks to be posted. 455 // multiple CloseTasks to be posted.
450 DCHECK_EQ(MessageLoop::current(), message_loop_); 456 DCHECK_EQ(MessageLoop::current(), message_loop_);
451 457
452 // Shutdown the audio device. 458 // Shutdown the audio device.
453 if (playback_handle_ && !CloseDevice(playback_handle_)) { 459 if (playback_handle_ && !CloseDevice(playback_handle_)) {
454 LOG(WARNING) << "Unable to close audio device. Leaking handle."; 460 LOG(WARNING) << "Unable to close audio device. Leaking handle.";
455 } 461 }
456 playback_handle_ = NULL; 462 playback_handle_ = NULL;
457 463
458 // Release the buffer. 464 // Release the buffer.
459 packet_.reset(); 465 buffer_.reset();
460 466
461 // Signal anything that might already be scheduled to stop. 467 // Signal anything that might already be scheduled to stop.
462 stop_stream_ = true; 468 stop_stream_ = true;
463 } 469 }
464 470
465 void AlsaPcmOutputStream::BufferPacket(Packet* packet) { 471 void AlsaPcmOutputStream::BufferPacket() {
466 DCHECK_EQ(MessageLoop::current(), message_loop_); 472 DCHECK_EQ(MessageLoop::current(), message_loop_);
467 473
468 // If stopped, simulate a 0-lengthed packet. 474 // If stopped, simulate a 0-lengthed packet.
469 if (stop_stream_) { 475 if (stop_stream_) {
470 packet->used = packet->size = 0; 476 buffer_->Clear();
471 return; 477 return;
472 } 478 }
473 479
474 // Request more data if we don't have any cached. 480 // Request more data if we have capacity.
475 if (packet->used >= packet->size) { 481 if (buffer_->forward_capacity() > buffer_->forward_bytes()) {
476 // Before making a request to source for data. We need to determine the 482 // Before making a request to source for data. We need to determine the
477 // delay (in bytes) for the requested data to be played. 483 // delay (in bytes) for the requested data to be played.
478 snd_pcm_sframes_t delay = 0; 484 snd_pcm_sframes_t delay = buffer_->forward_bytes() * bytes_per_frame_ /
485 bytes_per_output_frame_ + GetCurrentDelay() * bytes_per_output_frame_;
479 486
480 // Don't query ALSA's delay if we have underrun since it'll be jammed at 487 media::DataBuffer* packet = new media::DataBuffer(packet_size_);
481 // some non-zero value and potentially even negative! 488 size_t packet_size =
482 if (wrapper_->PcmState(playback_handle_) != SND_PCM_STATE_XRUN) { 489 shared_data_.OnMoreData(this, packet->GetWritableData(),
483 int error = wrapper_->PcmDelay(playback_handle_, &delay); 490 packet->GetBufferSize(), delay);
484 if (error >= 0) { 491 CHECK(packet_size <= packet->GetBufferSize()) <<
485 // Convert frames to bytes, but watch out for those negatives! 492 "Data source overran buffer.";
486 delay = (delay < 0 ? 0 : delay) * bytes_per_output_frame_;
487 } else {
488 // Assume a delay of zero and attempt to recover the device.
489 delay = 0;
490 error = wrapper_->PcmRecover(playback_handle_,
491 error,
492 kPcmRecoverIsSilent);
493 if (error < 0) {
494 LOG(ERROR) << "Failed querying delay: " << wrapper_->StrError(error);
495 }
496 }
497 }
498
499 packet->used = 0;
500 packet->size = shared_data_.OnMoreData(this, packet->buffer.get(),
501 packet->capacity, delay);
502 CHECK(packet->size <= packet->capacity) << "Data source overran buffer.";
503 493
504 // This should not happen, but incase it does, drop any trailing bytes 494 // This should not happen, but incase it does, drop any trailing bytes
505 // that aren't large enough to make a frame. Without this, packet writing 495 // that aren't large enough to make a frame. Without this, packet writing
506 // may stall because the last few bytes in the packet may never get used by 496 // may stall because the last few bytes in the packet may never get used by
507 // WritePacket. 497 // WritePacket.
508 DCHECK(packet->size % bytes_per_frame_ == 0); 498 DCHECK(packet_size % bytes_per_frame_ == 0);
509 packet->size = (packet->size / bytes_per_frame_) * bytes_per_frame_; 499 packet_size = (packet_size / bytes_per_frame_) * bytes_per_frame_;
510 500
511 if (should_downmix_) { 501 if (should_downmix_) {
512 if (media::FoldChannels(packet->buffer.get(), 502 if (media::FoldChannels(packet->GetWritableData(),
513 packet->size, 503 packet_size,
514 channels_, 504 channels_,
515 bytes_per_sample_, 505 bytes_per_sample_,
516 shared_data_.volume())) { 506 shared_data_.volume())) {
517 // Adjust packet size for downmix. 507 // Adjust packet size for downmix.
518 packet->size = 508 packet_size =
519 packet->size / bytes_per_frame_ * bytes_per_output_frame_; 509 packet_size / bytes_per_frame_ * bytes_per_output_frame_;
520 } else { 510 } else {
521 LOG(ERROR) << "Folding failed"; 511 LOG(ERROR) << "Folding failed";
522 } 512 }
523 } else { 513 } else {
524 // TODO(ajwong): Handle other channel orderings. 514 // TODO(ajwong): Handle other channel orderings.
525 515
526 // Handle channel order for 5.0 audio. 516 // Handle channel order for 5.0 audio.
527 if (channels_ == 5) { 517 if (channels_ == 5) {
528 if (bytes_per_sample_ == 1) { 518 if (bytes_per_sample_ == 1) {
529 Swizzle50Layout(reinterpret_cast<uint8*>(packet->buffer.get()), 519 Swizzle50Layout(packet->GetWritableData(), packet_size);
530 packet->size);
531 } else if (bytes_per_sample_ == 2) { 520 } else if (bytes_per_sample_ == 2) {
532 Swizzle50Layout(reinterpret_cast<int16*>(packet->buffer.get()), 521 Swizzle50Layout(packet->GetWritableData(), packet_size);
533 packet->size);
534 } else if (bytes_per_sample_ == 4) { 522 } else if (bytes_per_sample_ == 4) {
535 Swizzle50Layout(reinterpret_cast<int32*>(packet->buffer.get()), 523 Swizzle50Layout(packet->GetWritableData(), packet_size);
536 packet->size);
537 } 524 }
538 } 525 }
539 526
540 // Handle channel order for 5.1 audio. 527 // Handle channel order for 5.1 audio.
541 if (channels_ == 6) { 528 if (channels_ == 6) {
542 if (bytes_per_sample_ == 1) { 529 if (bytes_per_sample_ == 1) {
543 Swizzle51Layout(reinterpret_cast<uint8*>(packet->buffer.get()), 530 Swizzle51Layout(packet->GetWritableData(), packet_size);
544 packet->size);
545 } else if (bytes_per_sample_ == 2) { 531 } else if (bytes_per_sample_ == 2) {
546 Swizzle51Layout(reinterpret_cast<int16*>(packet->buffer.get()), 532 Swizzle51Layout(packet->GetWritableData(), packet_size);
547 packet->size);
548 } else if (bytes_per_sample_ == 4) { 533 } else if (bytes_per_sample_ == 4) {
549 Swizzle51Layout(reinterpret_cast<int32*>(packet->buffer.get()), 534 Swizzle51Layout(packet->GetWritableData(), packet_size);
550 packet->size);
551 } 535 }
552 } 536 }
553 537
554 media::AdjustVolume(packet->buffer.get(), 538 media::AdjustVolume(packet->GetWritableData(),
555 packet->size, 539 packet_size,
556 channels_, 540 channels_,
557 bytes_per_sample_, 541 bytes_per_sample_,
558 shared_data_.volume()); 542 shared_data_.volume());
543
544 packet->SetDataSize(packet_size);
545
546 // Add the packet to the buffer.
547 buffer_->Append(packet);
559 } 548 }
560 } 549 }
561 } 550 }
562 551
563 void AlsaPcmOutputStream::WritePacket(Packet* packet) { 552 void AlsaPcmOutputStream::WritePacket() {
564 DCHECK_EQ(MessageLoop::current(), message_loop_); 553 DCHECK_EQ(MessageLoop::current(), message_loop_);
565 554
566 CHECK(packet->size % bytes_per_output_frame_ == 0);
567
568 // If the device is in error, just eat the bytes. 555 // If the device is in error, just eat the bytes.
569 if (stop_stream_) { 556 if (stop_stream_) {
570 packet->used = packet->size; 557 buffer_->Clear();
571 return; 558 return;
572 } 559 }
573 560
574 if (packet->used < packet->size) { 561 CHECK_EQ(buffer_->forward_bytes() % bytes_per_output_frame_, 0u);
575 char* buffer_pos = packet->buffer.get() + packet->used; 562
576 snd_pcm_sframes_t frames = FramesInPacket(*packet, bytes_per_output_frame_); 563 const uint8* buffer_data;
564 size_t buffer_size;
565 if (buffer_->GetCurrentChunk(&buffer_data, &buffer_size)) {
566 buffer_size = buffer_size - (buffer_size % bytes_per_output_frame_);
567 snd_pcm_sframes_t frames = buffer_size / bytes_per_output_frame_;
577 568
578 DCHECK_GT(frames, 0); 569 DCHECK_GT(frames, 0);
579 570
580 snd_pcm_sframes_t frames_written = 571 snd_pcm_sframes_t frames_written =
581 wrapper_->PcmWritei(playback_handle_, buffer_pos, frames); 572 wrapper_->PcmWritei(playback_handle_, buffer_data, frames);
582 if (frames_written < 0) { 573 if (frames_written < 0) {
583 // Attempt once to immediately recover from EINTR, 574 // Attempt once to immediately recover from EINTR,
584 // EPIPE (overrun/underrun), ESTRPIPE (stream suspended). WritePacket 575 // EPIPE (overrun/underrun), ESTRPIPE (stream suspended). WritePacket
585 // will eventually be called again, so eventual recovery will happen if 576 // will eventually be called again, so eventual recovery will happen if
586 // muliple retries are required. 577 // muliple retries are required.
587 frames_written = wrapper_->PcmRecover(playback_handle_, 578 frames_written = wrapper_->PcmRecover(playback_handle_,
588 frames_written, 579 frames_written,
589 kPcmRecoverIsSilent); 580 kPcmRecoverIsSilent);
590 } 581 }
591 582
592 if (frames_written < 0) { 583 if (frames_written < 0) {
593 // TODO(ajwong): Is EAGAIN the only error we want to except from stopping 584 // TODO(ajwong): Is EAGAIN the only error we want to except from stopping
594 // the pcm playback? 585 // the pcm playback?
595 if (frames_written != -EAGAIN) { 586 if (frames_written != -EAGAIN) {
596 LOG(ERROR) << "Failed to write to pcm device: " 587 LOG(ERROR) << "Failed to write to pcm device: "
597 << wrapper_->StrError(frames_written); 588 << wrapper_->StrError(frames_written);
598 shared_data_.OnError(this, frames_written); 589 shared_data_.OnError(this, frames_written);
599 stop_stream_ = true; 590 stop_stream_ = true;
600 } 591 }
601 } else { 592 } else {
602 packet->used += frames_written * bytes_per_output_frame_; 593 if (frames_written > frames) {
594 LOG(WARNING)
595 << "snd_pcm_writei() has written more frame that we asked.";
596 frames_written = frames;
597 }
598
599 // Seek forward in the buffer after we've written some data to ALSA.
600 buffer_->Seek(frames_written * bytes_per_output_frame_);
603 } 601 }
604 } 602 }
605 } 603 }
606 604
607 void AlsaPcmOutputStream::WriteTask() { 605 void AlsaPcmOutputStream::WriteTask() {
608 DCHECK_EQ(MessageLoop::current(), message_loop_); 606 DCHECK_EQ(MessageLoop::current(), message_loop_);
609 607
610 if (stop_stream_) { 608 if (stop_stream_) {
611 return; 609 return;
612 } 610 }
613 611
614 BufferPacket(packet_.get()); 612 BufferPacket();
615 WritePacket(packet_.get()); 613 WritePacket();
616 614
617 ScheduleNextWrite(packet_.get()); 615 ScheduleNextWrite();
618 } 616 }
619 617
620 void AlsaPcmOutputStream::ScheduleNextWrite(Packet* current_packet) { 618 void AlsaPcmOutputStream::ScheduleNextWrite() {
621 DCHECK_EQ(MessageLoop::current(), message_loop_); 619 DCHECK_EQ(MessageLoop::current(), message_loop_);
622 620
623 if (stop_stream_) { 621 if (stop_stream_) {
624 return; 622 return;
625 } 623 }
626 624
627 // Calculate when we should have enough buffer for another packet of data. 625 // Next write is scheduled for the moment when half of the buffer is
628 // Make sure to take into consideration down-mixing. 626 // available.
629 uint32 frames_leftover = 627 uint32 frames_avail_wanted = alsa_buffer_frames_ / 2;
630 FramesInPacket(*current_packet, bytes_per_output_frame_);
631 uint32 frames_avail_wanted =
632 (frames_leftover > 0) ? frames_leftover : frames_per_packet_;
633 uint32 available_frames = GetAvailableFrames(); 628 uint32 available_frames = GetAvailableFrames();
634 uint32 next_fill_time_ms = 0; 629 uint32 next_fill_time_ms = 0;
635 630
636 // It's possible to have more frames available than what we want, in which 631 // It's possible to have more frames available than what we want, in which
637 // case we'll leave our |next_fill_time_ms| at 0ms. 632 // case we'll leave our |next_fill_time_ms| at 0ms.
638 if (available_frames < frames_avail_wanted) { 633 if (available_frames < frames_avail_wanted) {
639 uint32 frames_until_empty_enough = frames_avail_wanted - available_frames; 634 uint32 frames_until_empty_enough = frames_avail_wanted - available_frames;
640 next_fill_time_ms = 635 next_fill_time_ms =
641 FramesToMillis(frames_until_empty_enough, sample_rate_); 636 FramesToMillis(frames_until_empty_enough, sample_rate_);
642 } 637 }
643 638
644 // Adjust for timer resolution issues. 639 // Adjust for timer resolution issues.
645 if (next_fill_time_ms < kSleepErrorMilliseconds) { 640 if (next_fill_time_ms < kSleepErrorMilliseconds) {
646 next_fill_time_ms = 0; 641 next_fill_time_ms = 0;
647 } else { 642 } else {
648 next_fill_time_ms -= kSleepErrorMilliseconds; 643 next_fill_time_ms -= kSleepErrorMilliseconds;
649 } 644 }
650 645
651 // Avoid busy looping if the data source is exhausted. 646 // Avoid busy looping if the data source is exhausted.
652 if (current_packet->size == 0) { 647 if (buffer_->forward_bytes() == 0) {
653 next_fill_time_ms = std::max(next_fill_time_ms, kNoDataSleepMilliseconds); 648 next_fill_time_ms = std::max(next_fill_time_ms, kNoDataSleepMilliseconds);
654 } 649 }
655 650
656 // Wake up sooner than should be necessary to avoid stutter.
657 next_fill_time_ms /= 2; // TODO(fbarchard): Remove this hack.
658
659 // Only schedule more reads/writes if we are still in the playing state. 651 // Only schedule more reads/writes if we are still in the playing state.
660 if (shared_data_.state() == kIsPlaying) { 652 if (shared_data_.state() == kIsPlaying) {
661 if (next_fill_time_ms == 0) { 653 if (next_fill_time_ms == 0) {
662 message_loop_->PostTask( 654 message_loop_->PostTask(
663 FROM_HERE, 655 FROM_HERE,
664 NewRunnableMethod(this, &AlsaPcmOutputStream::WriteTask)); 656 NewRunnableMethod(this, &AlsaPcmOutputStream::WriteTask));
665 } else { 657 } else {
666 // TODO(ajwong): Measure the reliability of the delay interval. Use 658 // TODO(ajwong): Measure the reliability of the delay interval. Use
667 // base/histogram.h. 659 // base/histogram.h.
668 message_loop_->PostDelayedTask( 660 message_loop_->PostDelayedTask(
669 FROM_HERE, 661 FROM_HERE,
670 NewRunnableMethod(this, &AlsaPcmOutputStream::WriteTask), 662 NewRunnableMethod(this, &AlsaPcmOutputStream::WriteTask),
671 next_fill_time_ms); 663 next_fill_time_ms);
672 } 664 }
673 } 665 }
674 } 666 }
675 667
676 uint32 AlsaPcmOutputStream::FramesInPacket(const Packet& packet,
677 uint32 bytes_per_frame) {
678 return (packet.size - packet.used) / bytes_per_frame;
679 }
680
681 uint32 AlsaPcmOutputStream::FramesToMicros(uint32 frames, uint32 sample_rate) { 668 uint32 AlsaPcmOutputStream::FramesToMicros(uint32 frames, uint32 sample_rate) {
682 return frames * base::Time::kMicrosecondsPerSecond / sample_rate; 669 return frames * base::Time::kMicrosecondsPerSecond / sample_rate;
683 } 670 }
684 671
685 uint32 AlsaPcmOutputStream::FramesToMillis(uint32 frames, uint32 sample_rate) { 672 uint32 AlsaPcmOutputStream::FramesToMillis(uint32 frames, uint32 sample_rate) {
686 return frames * base::Time::kMillisecondsPerSecond / sample_rate; 673 return frames * base::Time::kMillisecondsPerSecond / sample_rate;
687 } 674 }
688 675
689 std::string AlsaPcmOutputStream::FindDeviceForChannels(uint32 channels) { 676 std::string AlsaPcmOutputStream::FindDeviceForChannels(uint32 channels) {
690 // Constants specified by the ALSA API for device hints. 677 // Constants specified by the ALSA API for device hints.
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
798 } 785 }
799 if (available_frames < 0) { 786 if (available_frames < 0) {
800 LOG(ERROR) << "Failed querying available frames. Assuming 0: " 787 LOG(ERROR) << "Failed querying available frames. Assuming 0: "
801 << wrapper_->StrError(available_frames); 788 << wrapper_->StrError(available_frames);
802 return 0; 789 return 0;
803 } 790 }
804 791
805 return available_frames; 792 return available_frames;
806 } 793 }
807 794
795 snd_pcm_sframes_t AlsaPcmOutputStream::GetCurrentDelay() {
796 snd_pcm_sframes_t delay = 0;
797
798 // Don't query ALSA's delay if we have underrun since it'll be jammed at
799 // some non-zero value and potentially even negative!
800 if (wrapper_->PcmState(playback_handle_) != SND_PCM_STATE_XRUN) {
801 int error = wrapper_->PcmDelay(playback_handle_, &delay);
802 if (error < 0) {
803 // Assume a delay of zero and attempt to recover the device.
804 delay = 0;
805 error = wrapper_->PcmRecover(playback_handle_,
806 error,
807 kPcmRecoverIsSilent);
808 if (error < 0) {
809 LOG(ERROR) << "Failed querying delay: " << wrapper_->StrError(error);
810 }
811 }
812 if (delay < 0)
813 delay = 0;
814 }
815 return delay;
816 }
817
808 snd_pcm_t* AlsaPcmOutputStream::AutoSelectDevice(unsigned int latency) { 818 snd_pcm_t* AlsaPcmOutputStream::AutoSelectDevice(unsigned int latency) {
809 // For auto-selection: 819 // For auto-selection:
810 // 1) Attempt to open a device that best matches the number of channels 820 // 1) Attempt to open a device that best matches the number of channels
811 // requested. 821 // requested.
812 // 2) If that fails, attempt the "plug:" version of it incase ALSA can 822 // 2) If that fails, attempt the "plug:" version of it incase ALSA can
813 // remap do some software conversion to make it work. 823 // remap do some software conversion to make it work.
814 // 3) Fallback to kDefaultDevice. 824 // 3) Fallback to kDefaultDevice.
815 // 4) If that fails too, try the "plug:" version of kDefaultDevice. 825 // 4) If that fails too, try the "plug:" version of kDefaultDevice.
816 // 5) Give up. 826 // 5) Give up.
817 snd_pcm_t* handle = NULL; 827 snd_pcm_t* handle = NULL;
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
963 } 973 }
964 974
965 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to 975 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to
966 // release ownership of the currently registered callback. 976 // release ownership of the currently registered callback.
967 void AlsaPcmOutputStream::SharedData::set_source_callback( 977 void AlsaPcmOutputStream::SharedData::set_source_callback(
968 AudioSourceCallback* callback) { 978 AudioSourceCallback* callback) {
969 DCHECK_EQ(MessageLoop::current(), state_transition_loop_); 979 DCHECK_EQ(MessageLoop::current(), state_transition_loop_);
970 AutoLock l(lock_); 980 AutoLock l(lock_);
971 source_callback_ = callback; 981 source_callback_ = callback;
972 } 982 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698