| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/renderers/audio_renderer_impl.h" | 5 #include "media/renderers/audio_renderer_impl.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/callback.h" | 13 #include "base/callback.h" |
| 14 #include "base/callback_helpers.h" | 14 #include "base/callback_helpers.h" |
| 15 #include "base/command_line.h" | 15 #include "base/command_line.h" |
| 16 #include "base/logging.h" | 16 #include "base/logging.h" |
| 17 #include "base/power_monitor/power_monitor.h" | 17 #include "base/power_monitor/power_monitor.h" |
| 18 #include "base/single_thread_task_runner.h" | 18 #include "base/single_thread_task_runner.h" |
| 19 #include "base/time/default_tick_clock.h" | 19 #include "base/time/default_tick_clock.h" |
| 20 #include "build/build_config.h" | 20 #include "build/build_config.h" |
| 21 #include "media/base/audio_buffer.h" | 21 #include "media/base/audio_buffer.h" |
| 22 #include "media/base/audio_buffer_converter.h" | 22 #include "media/base/audio_buffer_converter.h" |
| 23 #include "media/base/audio_latency.h" | 23 #include "media/base/audio_latency.h" |
| 24 #include "media/base/audio_splicer.h" | |
| 25 #include "media/base/bind_to_current_loop.h" | 24 #include "media/base/bind_to_current_loop.h" |
| 26 #include "media/base/demuxer_stream.h" | 25 #include "media/base/demuxer_stream.h" |
| 27 #include "media/base/media_log.h" | 26 #include "media/base/media_log.h" |
| 28 #include "media/base/media_switches.h" | 27 #include "media/base/media_switches.h" |
| 29 #include "media/base/renderer_client.h" | 28 #include "media/base/renderer_client.h" |
| 30 #include "media/base/timestamp_constants.h" | 29 #include "media/base/timestamp_constants.h" |
| 31 #include "media/filters/audio_clock.h" | 30 #include "media/filters/audio_clock.h" |
| 32 #include "media/filters/decrypting_demuxer_stream.h" | 31 #include "media/filters/decrypting_demuxer_stream.h" |
| 33 | 32 |
| 34 namespace media { | 33 namespace media { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 51 playback_rate_(0.0), | 50 playback_rate_(0.0), |
| 52 state_(kUninitialized), | 51 state_(kUninitialized), |
| 53 buffering_state_(BUFFERING_HAVE_NOTHING), | 52 buffering_state_(BUFFERING_HAVE_NOTHING), |
| 54 rendering_(false), | 53 rendering_(false), |
| 55 sink_playing_(false), | 54 sink_playing_(false), |
| 56 pending_read_(false), | 55 pending_read_(false), |
| 57 received_end_of_stream_(false), | 56 received_end_of_stream_(false), |
| 58 rendered_end_of_stream_(false), | 57 rendered_end_of_stream_(false), |
| 59 is_suspending_(false), | 58 is_suspending_(false), |
| 60 weak_factory_(this) { | 59 weak_factory_(this) { |
| 61 audio_buffer_stream_->set_splice_observer(base::Bind( | |
| 62 &AudioRendererImpl::OnNewSpliceBuffer, weak_factory_.GetWeakPtr())); | |
| 63 audio_buffer_stream_->set_config_change_observer(base::Bind( | 60 audio_buffer_stream_->set_config_change_observer(base::Bind( |
| 64 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr())); | 61 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr())); |
| 65 | 62 |
| 66 // Tests may not have a power monitor. | 63 // Tests may not have a power monitor. |
| 67 base::PowerMonitor* monitor = base::PowerMonitor::Get(); | 64 base::PowerMonitor* monitor = base::PowerMonitor::Get(); |
| 68 if (!monitor) | 65 if (!monitor) |
| 69 return; | 66 return; |
| 70 | 67 |
| 71 // PowerObserver's must be added and removed from the same thread, but we | 68 // PowerObserver's must be added and removed from the same thread, but we |
| 72 // won't remove the observer until we're destructed on |task_runner_| so we | 69 // won't remove the observer until we're destructed on |task_runner_| so we |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 294 DCHECK_EQ(state_, kFlushed); | 291 DCHECK_EQ(state_, kFlushed); |
| 295 DCHECK(!flush_cb_.is_null()); | 292 DCHECK(!flush_cb_.is_null()); |
| 296 | 293 |
| 297 received_end_of_stream_ = false; | 294 received_end_of_stream_ = false; |
| 298 rendered_end_of_stream_ = false; | 295 rendered_end_of_stream_ = false; |
| 299 | 296 |
| 300 // Flush() may have been called while underflowed/not fully buffered. | 297 // Flush() may have been called while underflowed/not fully buffered. |
| 301 if (buffering_state_ != BUFFERING_HAVE_NOTHING) | 298 if (buffering_state_ != BUFFERING_HAVE_NOTHING) |
| 302 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); | 299 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); |
| 303 | 300 |
| 304 splicer_->Reset(); | |
| 305 if (buffer_converter_) | 301 if (buffer_converter_) |
| 306 buffer_converter_->Reset(); | 302 buffer_converter_->Reset(); |
| 307 algorithm_->FlushBuffers(); | 303 algorithm_->FlushBuffers(); |
| 308 } | 304 } |
| 309 | 305 |
| 310 // Changes in buffering state are always posted. Flush callback must only be | 306 // Changes in buffering state are always posted. Flush callback must only be |
| 311 // run after buffering state has been set back to nothing. | 307 // run after buffering state has been set back to nothing. |
| 312 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&flush_cb_)); | 308 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&flush_cb_)); |
| 313 } | 309 } |
| 314 | 310 |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 459 if (!audio_parameters_.IsValid()) { | 455 if (!audio_parameters_.IsValid()) { |
| 460 DVLOG(1) << __func__ << ": Invalid audio parameters: " | 456 DVLOG(1) << __func__ << ": Invalid audio parameters: " |
| 461 << audio_parameters_.AsHumanReadableString(); | 457 << audio_parameters_.AsHumanReadableString(); |
| 462 ChangeState_Locked(kUninitialized); | 458 ChangeState_Locked(kUninitialized); |
| 463 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); | 459 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); |
| 464 return; | 460 return; |
| 465 } | 461 } |
| 466 | 462 |
| 467 if (expecting_config_changes_) | 463 if (expecting_config_changes_) |
| 468 buffer_converter_.reset(new AudioBufferConverter(audio_parameters_)); | 464 buffer_converter_.reset(new AudioBufferConverter(audio_parameters_)); |
| 469 splicer_.reset(new AudioSplicer(audio_parameters_.sample_rate(), media_log_)); | |
| 470 | 465 |
| 471 // We're all good! Continue initializing the rest of the audio renderer | 466 // We're all good! Continue initializing the rest of the audio renderer |
| 472 // based on the decoder format. | 467 // based on the decoder format. |
| 473 algorithm_.reset(new AudioRendererAlgorithm()); | 468 algorithm_.reset(new AudioRendererAlgorithm()); |
| 474 algorithm_->Initialize(audio_parameters_); | 469 algorithm_->Initialize(audio_parameters_); |
| 475 | 470 |
| 476 ChangeState_Locked(kFlushed); | 471 ChangeState_Locked(kFlushed); |
| 477 | 472 |
| 478 { | 473 { |
| 479 base::AutoUnlock auto_unlock(lock_); | 474 base::AutoUnlock auto_unlock(lock_); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 554 | 549 |
| 555 DCHECK_EQ(status, AudioBufferStream::OK); | 550 DCHECK_EQ(status, AudioBufferStream::OK); |
| 556 DCHECK(buffer.get()); | 551 DCHECK(buffer.get()); |
| 557 | 552 |
| 558 if (state_ == kFlushing) { | 553 if (state_ == kFlushing) { |
| 559 ChangeState_Locked(kFlushed); | 554 ChangeState_Locked(kFlushed); |
| 560 DoFlush_Locked(); | 555 DoFlush_Locked(); |
| 561 return; | 556 return; |
| 562 } | 557 } |
| 563 | 558 |
| 559 bool need_another_buffer = false; |
| 560 |
| 564 if (expecting_config_changes_) { | 561 if (expecting_config_changes_) { |
| 565 if (last_decoded_sample_rate_ && | 562 if (last_decoded_sample_rate_ && |
| 566 buffer->sample_rate() != last_decoded_sample_rate_) { | 563 buffer->sample_rate() != last_decoded_sample_rate_) { |
| 567 DVLOG(1) << __func__ << " Updating audio sample_rate." | 564 DVLOG(1) << __func__ << " Updating audio sample_rate." |
| 568 << " ts:" << buffer->timestamp().InMicroseconds() | 565 << " ts:" << buffer->timestamp().InMicroseconds() |
| 569 << " old:" << last_decoded_sample_rate_ | 566 << " old:" << last_decoded_sample_rate_ |
| 570 << " new:" << buffer->sample_rate(); | 567 << " new:" << buffer->sample_rate(); |
| 571 OnConfigChange(); | 568 OnConfigChange(); |
| 572 } | 569 } |
| 573 last_decoded_sample_rate_ = buffer->sample_rate(); | 570 last_decoded_sample_rate_ = buffer->sample_rate(); |
| 574 | 571 |
| 575 DCHECK(buffer_converter_); | 572 DCHECK(buffer_converter_); |
| 576 buffer_converter_->AddInput(buffer); | 573 buffer_converter_->AddInput(buffer); |
| 574 |
| 575 if (!buffer_converter_->HasNextBuffer()) { |
| 576 AttemptRead_Locked(); |
| 577 return; |
| 578 } |
| 579 |
| 577 while (buffer_converter_->HasNextBuffer()) { | 580 while (buffer_converter_->HasNextBuffer()) { |
| 578 if (!splicer_->AddInput(buffer_converter_->GetNextBuffer())) { | 581 need_another_buffer = |
| 579 HandleAbortedReadOrDecodeError(AUDIO_RENDERER_ERROR_SPLICE_FAILED); | 582 HandleDecodedBuffer_Locked(buffer_converter_->GetNextBuffer()); |
| 580 return; | |
| 581 } | |
| 582 } | 583 } |
| 583 } else { | 584 } else { |
| 584 // TODO(chcunningham, tguilbert): Figure out if we want to support implicit | 585 // TODO(chcunningham, tguilbert): Figure out if we want to support implicit |
| 585 // config changes during src=. Doing so requires resampling each individual | 586 // config changes during src=. Doing so requires resampling each individual |
| 586 // stream which is inefficient when there are many tags in a page. | 587 // stream which is inefficient when there are many tags in a page. |
| 587 // | 588 // |
| 588 // Check if the buffer we received matches the expected configuration. | 589 // Check if the buffer we received matches the expected configuration. |
| 589 // Note: We explicitly do not check channel layout here to avoid breaking | 590 // Note: We explicitly do not check channel layout here to avoid breaking |
| 590 // weird behavior with multichannel wav files: http://crbug.com/600538. | 591 // weird behavior with multichannel wav files: http://crbug.com/600538. |
| 591 if (!buffer->end_of_stream() && | 592 if (!buffer->end_of_stream() && |
| 592 (buffer->sample_rate() != audio_parameters_.sample_rate() || | 593 (buffer->sample_rate() != audio_parameters_.sample_rate() || |
| 593 buffer->channel_count() != audio_parameters_.channels())) { | 594 buffer->channel_count() != audio_parameters_.channels())) { |
| 594 MEDIA_LOG(ERROR, media_log_) | 595 MEDIA_LOG(ERROR, media_log_) |
| 595 << "Unsupported midstream configuration change!" | 596 << "Unsupported midstream configuration change!" |
| 596 << " Sample Rate: " << buffer->sample_rate() << " vs " | 597 << " Sample Rate: " << buffer->sample_rate() << " vs " |
| 597 << audio_parameters_.sample_rate() | 598 << audio_parameters_.sample_rate() |
| 598 << ", Channels: " << buffer->channel_count() << " vs " | 599 << ", Channels: " << buffer->channel_count() << " vs " |
| 599 << audio_parameters_.channels(); | 600 << audio_parameters_.channels(); |
| 600 HandleAbortedReadOrDecodeError(PIPELINE_ERROR_DECODE); | 601 HandleAbortedReadOrDecodeError(PIPELINE_ERROR_DECODE); |
| 601 return; | 602 return; |
| 602 } | 603 } |
| 603 | 604 |
| 604 if (!splicer_->AddInput(buffer)) { | 605 need_another_buffer = HandleDecodedBuffer_Locked(buffer); |
| 605 HandleAbortedReadOrDecodeError(AUDIO_RENDERER_ERROR_SPLICE_FAILED); | |
| 606 return; | |
| 607 } | |
| 608 } | 606 } |
| 609 | 607 |
| 610 if (!splicer_->HasNextBuffer()) { | |
| 611 AttemptRead_Locked(); | |
| 612 return; | |
| 613 } | |
| 614 | |
| 615 bool need_another_buffer = false; | |
| 616 while (splicer_->HasNextBuffer()) | |
| 617 need_another_buffer = HandleSplicerBuffer_Locked(splicer_->GetNextBuffer()); | |
| 618 | |
| 619 if (!need_another_buffer && !CanRead_Locked()) | 608 if (!need_another_buffer && !CanRead_Locked()) |
| 620 return; | 609 return; |
| 621 | 610 |
| 622 AttemptRead_Locked(); | 611 AttemptRead_Locked(); |
| 623 } | 612 } |
| 624 | 613 |
| 625 bool AudioRendererImpl::HandleSplicerBuffer_Locked( | 614 bool AudioRendererImpl::HandleDecodedBuffer_Locked( |
| 626 const scoped_refptr<AudioBuffer>& buffer) { | 615 const scoped_refptr<AudioBuffer>& buffer) { |
| 627 lock_.AssertAcquired(); | 616 lock_.AssertAcquired(); |
| 628 if (buffer->end_of_stream()) { | 617 if (buffer->end_of_stream()) { |
| 629 received_end_of_stream_ = true; | 618 received_end_of_stream_ = true; |
| 630 } else { | 619 } else { |
| 631 if (state_ == kPlaying) { | 620 if (state_ == kPlaying) { |
| 632 if (IsBeforeStartTime(buffer)) | 621 if (IsBeforeStartTime(buffer)) |
| 633 return true; | 622 return true; |
| 634 | 623 |
| 635 // Trim off any additional time before the start timestamp. | 624 // Trim off any additional time before the start timestamp. |
| (...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 928 return; | 917 return; |
| 929 } | 918 } |
| 930 } | 919 } |
| 931 | 920 |
| 932 void AudioRendererImpl::ChangeState_Locked(State new_state) { | 921 void AudioRendererImpl::ChangeState_Locked(State new_state) { |
| 933 DVLOG(1) << __func__ << " : " << state_ << " -> " << new_state; | 922 DVLOG(1) << __func__ << " : " << state_ << " -> " << new_state; |
| 934 lock_.AssertAcquired(); | 923 lock_.AssertAcquired(); |
| 935 state_ = new_state; | 924 state_ = new_state; |
| 936 } | 925 } |
| 937 | 926 |
| 938 void AudioRendererImpl::OnNewSpliceBuffer(base::TimeDelta splice_timestamp) { | |
| 939 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 940 splicer_->SetSpliceTimestamp(splice_timestamp); | |
| 941 } | |
| 942 | |
| 943 void AudioRendererImpl::OnConfigChange() { | 927 void AudioRendererImpl::OnConfigChange() { |
| 944 DCHECK(task_runner_->BelongsToCurrentThread()); | 928 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 945 DCHECK(expecting_config_changes_); | 929 DCHECK(expecting_config_changes_); |
| 946 buffer_converter_->ResetTimestampState(); | 930 buffer_converter_->ResetTimestampState(); |
| 947 // Drain flushed buffers from the converter so the AudioSplicer receives all | |
| 948 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should | |
| 949 // only appear after config changes, AddInput() should never fail here. | |
| 950 while (buffer_converter_->HasNextBuffer()) | |
| 951 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); | |
| 952 } | 931 } |
| 953 | 932 |
| 954 void AudioRendererImpl::SetBufferingState_Locked( | 933 void AudioRendererImpl::SetBufferingState_Locked( |
| 955 BufferingState buffering_state) { | 934 BufferingState buffering_state) { |
| 956 DVLOG(1) << __func__ << " : " << buffering_state_ << " -> " | 935 DVLOG(1) << __func__ << " : " << buffering_state_ << " -> " |
| 957 << buffering_state; | 936 << buffering_state; |
| 958 DCHECK_NE(buffering_state_, buffering_state); | 937 DCHECK_NE(buffering_state_, buffering_state); |
| 959 lock_.AssertAcquired(); | 938 lock_.AssertAcquired(); |
| 960 buffering_state_ = buffering_state; | 939 buffering_state_ = buffering_state; |
| 961 | 940 |
| 962 task_runner_->PostTask( | 941 task_runner_->PostTask( |
| 963 FROM_HERE, base::Bind(&AudioRendererImpl::OnBufferingStateChange, | 942 FROM_HERE, base::Bind(&AudioRendererImpl::OnBufferingStateChange, |
| 964 weak_factory_.GetWeakPtr(), buffering_state_)); | 943 weak_factory_.GetWeakPtr(), buffering_state_)); |
| 965 } | 944 } |
| 966 | 945 |
| 967 } // namespace media | 946 } // namespace media |
| OLD | NEW |