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/bind_to_current_loop.h" | 24 #include "media/base/bind_to_current_loop.h" |
25 #include "media/base/channel_mixing_matrix.h" | 25 #include "media/base/channel_mixing_matrix.h" |
26 #include "media/base/demuxer_stream.h" | 26 #include "media/base/demuxer_stream.h" |
27 #include "media/base/media_client.h" | |
27 #include "media/base/media_log.h" | 28 #include "media/base/media_log.h" |
28 #include "media/base/media_switches.h" | 29 #include "media/base/media_switches.h" |
29 #include "media/base/renderer_client.h" | 30 #include "media/base/renderer_client.h" |
30 #include "media/base/timestamp_constants.h" | 31 #include "media/base/timestamp_constants.h" |
31 #include "media/filters/audio_clock.h" | 32 #include "media/filters/audio_clock.h" |
32 #include "media/filters/decrypting_demuxer_stream.h" | 33 #include "media/filters/decrypting_demuxer_stream.h" |
33 | 34 |
34 namespace media { | 35 namespace media { |
35 | 36 |
37 static const int kMaxFramesPerCompressedAudioBuffer = 4096; | |
DaleCurtis
2017/06/15 21:46:33
Needs explanation; possibly should be stored in Au
AndyWu
2017/08/02 01:43:41
Done.
| |
38 | |
36 AudioRendererImpl::AudioRendererImpl( | 39 AudioRendererImpl::AudioRendererImpl( |
37 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 40 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
38 media::AudioRendererSink* sink, | 41 media::AudioRendererSink* sink, |
39 const CreateAudioDecodersCB& create_audio_decoders_cb, | 42 const CreateAudioDecodersCB& create_audio_decoders_cb, |
40 MediaLog* media_log) | 43 MediaLog* media_log) |
41 : task_runner_(task_runner), | 44 : task_runner_(task_runner), |
42 expecting_config_changes_(false), | 45 expecting_config_changes_(false), |
43 sink_(sink), | 46 sink_(sink), |
44 media_log_(media_log), | 47 media_log_(media_log), |
45 client_(nullptr), | 48 client_(nullptr), |
46 tick_clock_(new base::DefaultTickClock()), | 49 tick_clock_(new base::DefaultTickClock()), |
47 last_audio_memory_usage_(0), | 50 last_audio_memory_usage_(0), |
48 last_decoded_sample_rate_(0), | 51 last_decoded_sample_rate_(0), |
49 last_decoded_channel_layout_(CHANNEL_LAYOUT_NONE), | 52 last_decoded_channel_layout_(CHANNEL_LAYOUT_NONE), |
50 is_encrypted_(false), | 53 is_encrypted_(false), |
51 last_decoded_channels_(0), | 54 last_decoded_channels_(0), |
52 playback_rate_(0.0), | 55 playback_rate_(0.0), |
53 state_(kUninitialized), | 56 state_(kUninitialized), |
54 create_audio_decoders_cb_(create_audio_decoders_cb), | 57 create_audio_decoders_cb_(create_audio_decoders_cb), |
55 buffering_state_(BUFFERING_HAVE_NOTHING), | 58 buffering_state_(BUFFERING_HAVE_NOTHING), |
56 rendering_(false), | 59 rendering_(false), |
57 sink_playing_(false), | 60 sink_playing_(false), |
58 pending_read_(false), | 61 pending_read_(false), |
59 received_end_of_stream_(false), | 62 received_end_of_stream_(false), |
60 rendered_end_of_stream_(false), | 63 rendered_end_of_stream_(false), |
61 is_suspending_(false), | 64 is_suspending_(false), |
65 is_passthrough_(false), | |
66 last_reported_media_time_(kNoTimestamp), | |
62 weak_factory_(this) { | 67 weak_factory_(this) { |
63 DCHECK(create_audio_decoders_cb_); | 68 DCHECK(create_audio_decoders_cb_); |
64 // Tests may not have a power monitor. | 69 // Tests may not have a power monitor. |
65 base::PowerMonitor* monitor = base::PowerMonitor::Get(); | 70 base::PowerMonitor* monitor = base::PowerMonitor::Get(); |
66 if (!monitor) | 71 if (!monitor) |
67 return; | 72 return; |
68 | 73 |
69 // PowerObserver's must be added and removed from the same thread, but we | 74 // PowerObserver's must be added and removed from the same thread, but we |
70 // won't remove the observer until we're destructed on |task_runner_| so we | 75 // won't remove the observer until we're destructed on |task_runner_| so we |
71 // must post it here if we're on the wrong thread. | 76 // must post it here if we're on the wrong thread. |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
172 | 177 |
173 base::AutoLock auto_lock(lock_); | 178 base::AutoLock auto_lock(lock_); |
174 DCHECK(!rendering_); | 179 DCHECK(!rendering_); |
175 DCHECK_EQ(state_, kFlushed); | 180 DCHECK_EQ(state_, kFlushed); |
176 | 181 |
177 start_timestamp_ = time; | 182 start_timestamp_ = time; |
178 ended_timestamp_ = kInfiniteDuration; | 183 ended_timestamp_ = kInfiniteDuration; |
179 last_render_time_ = stop_rendering_time_ = base::TimeTicks(); | 184 last_render_time_ = stop_rendering_time_ = base::TimeTicks(); |
180 first_packet_timestamp_ = kNoTimestamp; | 185 first_packet_timestamp_ = kNoTimestamp; |
181 audio_clock_.reset(new AudioClock(time, audio_parameters_.sample_rate())); | 186 audio_clock_.reset(new AudioClock(time, audio_parameters_.sample_rate())); |
187 last_reported_media_time_ = kNoTimestamp; | |
182 } | 188 } |
183 | 189 |
184 base::TimeDelta AudioRendererImpl::CurrentMediaTime() { | 190 base::TimeDelta AudioRendererImpl::CurrentMediaTime() { |
185 base::AutoLock auto_lock(lock_); | 191 base::AutoLock auto_lock(lock_); |
186 | 192 |
187 // Return the current time based on the known extents of the rendered audio | 193 // Return the current time based on the known extents of the rendered audio |
188 // data plus an estimate based on the last time those values were calculated. | 194 // data plus an estimate based on the last time those values were calculated. |
189 base::TimeDelta current_media_time = audio_clock_->front_timestamp(); | 195 base::TimeDelta current_media_time = audio_clock_->front_timestamp(); |
190 if (!last_render_time_.is_null()) { | 196 if (!last_render_time_.is_null()) { |
191 current_media_time += | 197 current_media_time += |
192 (tick_clock_->NowTicks() - last_render_time_) * playback_rate_; | 198 (tick_clock_->NowTicks() - last_render_time_) * playback_rate_; |
193 if (current_media_time > audio_clock_->back_timestamp()) | 199 if (current_media_time > audio_clock_->back_timestamp()) |
194 current_media_time = audio_clock_->back_timestamp(); | 200 current_media_time = audio_clock_->back_timestamp(); |
195 } | 201 } |
196 | 202 |
197 return current_media_time; | 203 // Clamp current media time to the last reported value, this prevents higher |
DaleCurtis
2017/06/15 21:46:33
We already do this in PipelineImpl.
AndyWu
2017/08/02 01:43:41
Hi Chris, do you agree to remove this logic?
chcunningham
2017/08/04 19:26:40
Yep, should be fine. It used to live here, but had
AndyWu
2017/08/04 21:45:52
Thanks for your feedback.
| |
204 // level clients from seeing time go backwards. This may happen when seeking | |
205 // a passthrough audio stream, since we are unable to trim a compressed audio | |
206 // buffer. | |
207 if (last_reported_media_time_ < current_media_time) | |
208 last_reported_media_time_ = current_media_time; | |
209 | |
210 return last_reported_media_time_; | |
198 } | 211 } |
199 | 212 |
200 bool AudioRendererImpl::GetWallClockTimes( | 213 bool AudioRendererImpl::GetWallClockTimes( |
201 const std::vector<base::TimeDelta>& media_timestamps, | 214 const std::vector<base::TimeDelta>& media_timestamps, |
202 std::vector<base::TimeTicks>* wall_clock_times) { | 215 std::vector<base::TimeTicks>* wall_clock_times) { |
203 base::AutoLock auto_lock(lock_); | 216 base::AutoLock auto_lock(lock_); |
204 DCHECK(wall_clock_times->empty()); | 217 DCHECK(wall_clock_times->empty()); |
205 | 218 |
206 // When playback is paused (rate is zero), assume a rate of 1.0. | 219 // When playback is paused (rate is zero), assume a rate of 1.0. |
207 const double playback_rate = playback_rate_ ? playback_rate_ : 1.0; | 220 const double playback_rate = playback_rate_ ? playback_rate_ : 1.0; |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
362 | 375 |
363 audio_buffer_stream_->set_config_change_observer(base::Bind( | 376 audio_buffer_stream_->set_config_change_observer(base::Bind( |
364 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr())); | 377 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr())); |
365 | 378 |
366 // Always post |init_cb_| because |this| could be destroyed if initialization | 379 // Always post |init_cb_| because |this| could be destroyed if initialization |
367 // failed. | 380 // failed. |
368 init_cb_ = BindToCurrentLoop(init_cb); | 381 init_cb_ = BindToCurrentLoop(init_cb); |
369 | 382 |
370 auto output_device_info = sink_->GetOutputDeviceInfo(); | 383 auto output_device_info = sink_->GetOutputDeviceInfo(); |
371 const AudioParameters& hw_params = output_device_info.output_params(); | 384 const AudioParameters& hw_params = output_device_info.output_params(); |
385 AudioCodec codec = stream->audio_decoder_config().codec(); | |
386 MediaClient* media_client = GetMediaClient(); | |
DaleCurtis
2017/06/15 21:46:33
if (auto* mc = GetMediaClient())
is_passthrough_
AndyWu
2017/08/02 01:43:41
Done.
| |
387 is_passthrough_ = | |
388 media_client && media_client->IsSupportedBitstreamAudioCodec(codec); | |
372 expecting_config_changes_ = stream->SupportsConfigChanges(); | 389 expecting_config_changes_ = stream->SupportsConfigChanges(); |
373 | 390 |
374 bool use_stream_params = !expecting_config_changes_ || !hw_params.IsValid() || | 391 bool use_stream_params = !expecting_config_changes_ || !hw_params.IsValid() || |
375 hw_params.format() == AudioParameters::AUDIO_FAKE || | 392 hw_params.format() == AudioParameters::AUDIO_FAKE || |
376 !sink_->IsOptimizedForHardwareParameters(); | 393 !sink_->IsOptimizedForHardwareParameters(); |
377 | 394 |
378 if (stream->audio_decoder_config().channel_layout() == | 395 if (stream->audio_decoder_config().channel_layout() == |
379 CHANNEL_LAYOUT_DISCRETE && | 396 CHANNEL_LAYOUT_DISCRETE && |
380 sink_->IsOptimizedForHardwareParameters()) { | 397 sink_->IsOptimizedForHardwareParameters()) { |
381 use_stream_params = false; | 398 use_stream_params = false; |
382 } | 399 } |
383 | 400 |
384 if (use_stream_params) { | 401 if (is_passthrough_) { |
402 AudioParameters::Format format = AudioParameters::AUDIO_FAKE; | |
403 if (codec == kCodecAC3) { | |
404 format = AudioParameters::AUDIO_BITSTREAM_AC3; | |
405 } else if (codec == kCodecEAC3) { | |
406 format = AudioParameters::AUDIO_BITSTREAM_EAC3; | |
407 } else { | |
408 NOTREACHED(); | |
409 } | |
410 | |
411 const int buffer_size = kMaxFramesPerCompressedAudioBuffer * | |
412 stream->audio_decoder_config().bytes_per_frame(); | |
413 | |
414 audio_parameters_.Reset( | |
415 format, stream->audio_decoder_config().channel_layout(), | |
416 stream->audio_decoder_config().samples_per_second(), | |
417 stream->audio_decoder_config().bits_per_channel(), buffer_size); | |
418 buffer_converter_.reset(); | |
419 } else if (use_stream_params) { | |
385 // The actual buffer size is controlled via the size of the AudioBus | 420 // The actual buffer size is controlled via the size of the AudioBus |
386 // provided to Render(), but we should choose a value here based on hardware | 421 // provided to Render(), but we should choose a value here based on hardware |
387 // parameters if possible since it affects the initial buffer size used by | 422 // parameters if possible since it affects the initial buffer size used by |
388 // the algorithm. Too little will cause underflow on Bluetooth devices. | 423 // the algorithm. Too little will cause underflow on Bluetooth devices. |
389 int buffer_size = | 424 int buffer_size = |
390 std::max(stream->audio_decoder_config().samples_per_second() / 100, | 425 std::max(stream->audio_decoder_config().samples_per_second() / 100, |
391 hw_params.IsValid() ? hw_params.frames_per_buffer() : 0); | 426 hw_params.IsValid() ? hw_params.frames_per_buffer() : 0); |
392 audio_parameters_.Reset(AudioParameters::AUDIO_PCM_LOW_LATENCY, | 427 audio_parameters_.Reset(AudioParameters::AUDIO_PCM_LOW_LATENCY, |
393 stream->audio_decoder_config().channel_layout(), | 428 stream->audio_decoder_config().channel_layout(), |
394 stream->audio_decoder_config().samples_per_second(), | 429 stream->audio_decoder_config().samples_per_second(), |
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
662 | 697 |
663 AttemptRead_Locked(); | 698 AttemptRead_Locked(); |
664 } | 699 } |
665 | 700 |
666 bool AudioRendererImpl::HandleDecodedBuffer_Locked( | 701 bool AudioRendererImpl::HandleDecodedBuffer_Locked( |
667 const scoped_refptr<AudioBuffer>& buffer) { | 702 const scoped_refptr<AudioBuffer>& buffer) { |
668 lock_.AssertAcquired(); | 703 lock_.AssertAcquired(); |
669 if (buffer->end_of_stream()) { | 704 if (buffer->end_of_stream()) { |
670 received_end_of_stream_ = true; | 705 received_end_of_stream_ = true; |
671 } else { | 706 } else { |
672 if (state_ == kPlaying) { | 707 if (buffer->IsBitstreamFormat() && state_ == kPlaying) { |
673 if (IsBeforeStartTime(buffer)) | 708 if (IsBeforeStartTime(buffer)) |
674 return true; | 709 return true; |
675 | 710 |
711 // Adjust the start time since we are unable to trim a compressed audio | |
712 // buffer. | |
713 if (buffer->timestamp() < start_timestamp_ && | |
DaleCurtis
2017/06/15 21:46:33
I'd just skip this and seek to the first full buff
AndyWu
2017/08/02 01:43:41
Done.
| |
714 (buffer->timestamp() + buffer->duration()) > start_timestamp_) { | |
715 start_timestamp_ = buffer->timestamp(); | |
716 audio_clock_.reset(new AudioClock(buffer->timestamp(), | |
717 audio_parameters_.sample_rate())); | |
718 } | |
719 } else if (state_ == kPlaying) { | |
720 if (IsBeforeStartTime(buffer)) | |
721 return true; | |
722 | |
676 // Trim off any additional time before the start timestamp. | 723 // Trim off any additional time before the start timestamp. |
677 const base::TimeDelta trim_time = start_timestamp_ - buffer->timestamp(); | 724 const base::TimeDelta trim_time = start_timestamp_ - buffer->timestamp(); |
678 if (trim_time > base::TimeDelta()) { | 725 if (trim_time > base::TimeDelta()) { |
679 buffer->TrimStart(buffer->frame_count() * | 726 buffer->TrimStart(buffer->frame_count() * |
680 (static_cast<double>(trim_time.InMicroseconds()) / | 727 (static_cast<double>(trim_time.InMicroseconds()) / |
681 buffer->duration().InMicroseconds())); | 728 buffer->duration().InMicroseconds())); |
682 buffer->set_timestamp(start_timestamp_); | 729 buffer->set_timestamp(start_timestamp_); |
683 } | 730 } |
684 // If the entire buffer was trimmed, request a new one. | 731 // If the entire buffer was trimmed, request a new one. |
685 if (!buffer->frame_count()) | 732 if (!buffer->frame_count()) |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
761 } | 808 } |
762 | 809 |
763 void AudioRendererImpl::SetPlaybackRate(double playback_rate) { | 810 void AudioRendererImpl::SetPlaybackRate(double playback_rate) { |
764 DVLOG(1) << __func__ << "(" << playback_rate << ")"; | 811 DVLOG(1) << __func__ << "(" << playback_rate << ")"; |
765 DCHECK(task_runner_->BelongsToCurrentThread()); | 812 DCHECK(task_runner_->BelongsToCurrentThread()); |
766 DCHECK_GE(playback_rate, 0); | 813 DCHECK_GE(playback_rate, 0); |
767 DCHECK(sink_.get()); | 814 DCHECK(sink_.get()); |
768 | 815 |
769 base::AutoLock auto_lock(lock_); | 816 base::AutoLock auto_lock(lock_); |
770 | 817 |
818 if (is_passthrough_ && playback_rate != 0 && playback_rate != 1) { | |
819 MEDIA_LOG(ERROR, media_log_) | |
DaleCurtis
2017/06/15 21:46:32
WARNING or INFO, no need for ERROR.
AndyWu
2017/08/02 01:43:41
Done.
| |
820 << "Unsupported playback rate when outputing compressed bitstream." | |
821 << " Playback Rate: " << playback_rate; | |
822 return; | |
823 } | |
824 | |
771 // We have two cases here: | 825 // We have two cases here: |
772 // Play: current_playback_rate == 0 && playback_rate != 0 | 826 // Play: current_playback_rate == 0 && playback_rate != 0 |
773 // Pause: current_playback_rate != 0 && playback_rate == 0 | 827 // Pause: current_playback_rate != 0 && playback_rate == 0 |
774 double current_playback_rate = playback_rate_; | 828 double current_playback_rate = playback_rate_; |
775 playback_rate_ = playback_rate; | 829 playback_rate_ = playback_rate; |
776 | 830 |
777 if (!rendering_) | 831 if (!rendering_) |
778 return; | 832 return; |
779 | 833 |
780 if (current_playback_rate == 0 && playback_rate != 0) { | 834 if (current_playback_rate == 0 && playback_rate != 0) { |
(...skipping 11 matching lines...) Expand all Loading... | |
792 const scoped_refptr<AudioBuffer>& buffer) { | 846 const scoped_refptr<AudioBuffer>& buffer) { |
793 DCHECK_EQ(state_, kPlaying); | 847 DCHECK_EQ(state_, kPlaying); |
794 return buffer.get() && !buffer->end_of_stream() && | 848 return buffer.get() && !buffer->end_of_stream() && |
795 (buffer->timestamp() + buffer->duration()) < start_timestamp_; | 849 (buffer->timestamp() + buffer->duration()) < start_timestamp_; |
796 } | 850 } |
797 | 851 |
798 int AudioRendererImpl::Render(base::TimeDelta delay, | 852 int AudioRendererImpl::Render(base::TimeDelta delay, |
799 base::TimeTicks delay_timestamp, | 853 base::TimeTicks delay_timestamp, |
800 int prior_frames_skipped, | 854 int prior_frames_skipped, |
801 AudioBus* audio_bus) { | 855 AudioBus* audio_bus) { |
802 const int frames_requested = audio_bus->frames(); | 856 int frames_requested = audio_bus->frames(); |
803 DVLOG(4) << __func__ << " delay:" << delay | 857 DVLOG(4) << __func__ << " delay:" << delay |
804 << " prior_frames_skipped:" << prior_frames_skipped | 858 << " prior_frames_skipped:" << prior_frames_skipped |
805 << " frames_requested:" << frames_requested; | 859 << " frames_requested:" << frames_requested; |
806 | 860 |
807 int frames_written = 0; | 861 int frames_written = 0; |
808 { | 862 { |
809 base::AutoLock auto_lock(lock_); | 863 base::AutoLock auto_lock(lock_); |
810 last_render_time_ = tick_clock_->NowTicks(); | 864 last_render_time_ = tick_clock_->NowTicks(); |
811 | 865 |
812 int64_t frames_delayed = AudioTimestampHelper::TimeToFrames( | 866 int64_t frames_delayed = AudioTimestampHelper::TimeToFrames( |
(...skipping 18 matching lines...) Expand all Loading... | |
831 return 0; | 885 return 0; |
832 } | 886 } |
833 | 887 |
834 // Mute audio by returning 0 when not playing. | 888 // Mute audio by returning 0 when not playing. |
835 if (state_ != kPlaying) { | 889 if (state_ != kPlaying) { |
836 audio_clock_->WroteAudio(0, frames_requested, frames_delayed, | 890 audio_clock_->WroteAudio(0, frames_requested, frames_delayed, |
837 playback_rate_); | 891 playback_rate_); |
838 return 0; | 892 return 0; |
839 } | 893 } |
840 | 894 |
841 // Delay playback by writing silence if we haven't reached the first | 895 if (is_passthrough_ && algorithm_->frames_buffered() > 0) { |
842 // timestamp yet; this can occur if the video starts before the audio. | 896 frames_written += algorithm_->FillBuffer(audio_bus, 0, frames_requested, |
chcunningham
2017/06/14 20:03:08
special passthrough logic needs "why" documentatio
DaleCurtis
2017/06/15 21:46:33
FYI, this is going to be wrong in cases where the
AndyWu
2017/08/02 01:43:41
Done.
AndyWu
2017/08/02 01:43:41
Done.
| |
843 if (algorithm_->frames_buffered() > 0) { | 897 playback_rate_); |
898 frames_requested = frames_written; | |
899 } else if (algorithm_->frames_buffered() > 0) { | |
900 // Delay playback by writing silence if we haven't reached the first | |
901 // timestamp yet; this can occur if the video starts before the audio. | |
844 CHECK_NE(first_packet_timestamp_, kNoTimestamp); | 902 CHECK_NE(first_packet_timestamp_, kNoTimestamp); |
845 CHECK_GE(first_packet_timestamp_, base::TimeDelta()); | 903 CHECK_GE(first_packet_timestamp_, base::TimeDelta()); |
846 const base::TimeDelta play_delay = | 904 const base::TimeDelta play_delay = |
847 first_packet_timestamp_ - audio_clock_->back_timestamp(); | 905 first_packet_timestamp_ - audio_clock_->back_timestamp(); |
848 if (play_delay > base::TimeDelta()) { | 906 if (play_delay > base::TimeDelta()) { |
849 DCHECK_EQ(frames_written, 0); | 907 DCHECK_EQ(frames_written, 0); |
850 | 908 |
851 // Don't multiply |play_delay| out since it can be a huge value on | 909 // Don't multiply |play_delay| out since it can be a huge value on |
852 // poorly encoded media and multiplying by the sample rate could cause | 910 // poorly encoded media and multiplying by the sample rate could cause |
853 // the value to overflow. | 911 // the value to overflow. |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1023 // All channels with a zero mix are muted and can be ignored. | 1081 // All channels with a zero mix are muted and can be ignored. |
1024 std::vector<bool> channel_mask(audio_parameters_.channels(), false); | 1082 std::vector<bool> channel_mask(audio_parameters_.channels(), false); |
1025 for (size_t ch = 0; ch < matrix.size(); ++ch) { | 1083 for (size_t ch = 0; ch < matrix.size(); ++ch) { |
1026 channel_mask[ch] = std::any_of(matrix[ch].begin(), matrix[ch].end(), | 1084 channel_mask[ch] = std::any_of(matrix[ch].begin(), matrix[ch].end(), |
1027 [](float mix) { return !!mix; }); | 1085 [](float mix) { return !!mix; }); |
1028 } | 1086 } |
1029 algorithm_->SetChannelMask(std::move(channel_mask)); | 1087 algorithm_->SetChannelMask(std::move(channel_mask)); |
1030 } | 1088 } |
1031 | 1089 |
1032 } // namespace media | 1090 } // namespace media |
OLD | NEW |