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

Side by Side Diff: media/renderers/audio_renderer_impl.cc

Issue 2466463005: Support (E)AC3 passthrough
Patch Set: Add unit tests Created 3 years, 6 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) 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
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
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
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
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
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
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
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
OLDNEW
« media/filters/audio_renderer_algorithm.cc ('K') | « media/renderers/audio_renderer_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698