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

Side by Side Diff: media/base/audio_renderer_mixer.cc

Issue 10698066: Switch to pcm_low_latency and enable resampling. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Review fixes. Created 8 years, 5 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 | Annotate | Revision Log
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/base/audio_renderer_mixer.h" 5 #include "media/base/audio_renderer_mixer.h"
6 6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
7 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "media/audio/audio_util.h"
11 #include "media/base/limits.h"
8 12
9 namespace media { 13 namespace media {
10 14
11 AudioRendererMixer::AudioRendererMixer( 15 AudioRendererMixer::AudioRendererMixer(
16 const AudioParameters& input_params, const AudioParameters& output_params,
17 const scoped_refptr<AudioRendererSink>& sink)
18 : audio_sink_(sink),
19 current_audio_delay_milliseconds_(0) {
20 // Sanity check sample rates.
21 DCHECK_LE(input_params.sample_rate(), limits::kMaxSampleRate);
22 DCHECK_GE(input_params.sample_rate(), limits::kMinSampleRate);
23 DCHECK_LE(output_params.sample_rate(), limits::kMaxSampleRate);
24 DCHECK_GE(output_params.sample_rate(), limits::kMinSampleRate);
25
26 Initialize(input_params, output_params);
27 }
28
29 AudioRendererMixer::AudioRendererMixer(
12 const AudioParameters& params, const scoped_refptr<AudioRendererSink>& sink) 30 const AudioParameters& params, const scoped_refptr<AudioRendererSink>& sink)
13 : audio_parameters_(params), 31 : audio_sink_(sink),
14 audio_sink_(sink) { 32 current_audio_delay_milliseconds_(0) {
15 // TODO(dalecurtis): Once we have resampling we'll need to pass on a different 33 // Create output parameters for passing on to the output sink.
16 // set of AudioParameters than the ones we're given. 34 // TODO(dalecurtis): Set format and buffer size in AudioRendererImpl.
17 audio_sink_->Initialize(audio_parameters_, this); 35 Initialize(params, AudioParameters(
scherkus (not reviewing) 2012/07/12 23:02:52 should the test-only ARM(in, out, sink) ctor be "t
DaleCurtis 2012/07/12 23:16:29 We could bake it into AudioRenderMixerManager (nex
DaleCurtis 2012/07/13 00:01:25 Next patch set does this.
36 AudioParameters::AUDIO_PCM_LOW_LATENCY, params.channel_layout(),
37 GetAudioHardwareSampleRate(), 16, GetAudioHardwareBufferSize()));
38 }
39
40 void AudioRendererMixer::Initialize(const AudioParameters& input_params,
41 const AudioParameters& output_params) {
42 // Only resample if necessary since it's expensive.
43 if (input_params.sample_rate() != output_params.sample_rate()) {
44 resampler_.reset(new MultiChannelResampler(
45 output_params.channels(),
46 input_params.sample_rate() / static_cast<double>(
47 output_params.sample_rate()),
48 base::Bind(&AudioRendererMixer::ProvideInput, base::Unretained(this))));
49 }
50
51 audio_sink_->Initialize(output_params, this);
18 audio_sink_->Start(); 52 audio_sink_->Start();
19 } 53 }
20 54
21 AudioRendererMixer::~AudioRendererMixer() { 55 AudioRendererMixer::~AudioRendererMixer() {
22 // AudioRendererSinks must be stopped before being destructed. 56 // AudioRendererSinks must be stopped before being destructed.
23 audio_sink_->Stop(); 57 audio_sink_->Stop();
24 58
59 // Clean up |mixer_input_audio_data_|.
60 for (size_t i = 0; i < mixer_input_audio_data_.size(); ++i)
61 delete [] mixer_input_audio_data_[i];
62 mixer_input_audio_data_.clear();
63
25 // Ensures that all mixer inputs have stopped themselves prior to destruction 64 // Ensures that all mixer inputs have stopped themselves prior to destruction
26 // and have called RemoveMixerInput(). 65 // and have called RemoveMixerInput().
27 DCHECK_EQ(mixer_inputs_.size(), 0U); 66 DCHECK_EQ(mixer_inputs_.size(), 0U);
28 } 67 }
29 68
30 void AudioRendererMixer::AddMixerInput( 69 void AudioRendererMixer::AddMixerInput(
31 const scoped_refptr<AudioRendererMixerInput>& input) { 70 const scoped_refptr<AudioRendererMixerInput>& input) {
32 base::AutoLock auto_lock(mixer_inputs_lock_); 71 base::AutoLock auto_lock(mixer_inputs_lock_);
33 mixer_inputs_.insert(input); 72 mixer_inputs_.insert(input);
34 } 73 }
35 74
36 void AudioRendererMixer::RemoveMixerInput( 75 void AudioRendererMixer::RemoveMixerInput(
37 const scoped_refptr<AudioRendererMixerInput>& input) { 76 const scoped_refptr<AudioRendererMixerInput>& input) {
38 base::AutoLock auto_lock(mixer_inputs_lock_); 77 base::AutoLock auto_lock(mixer_inputs_lock_);
39 mixer_inputs_.erase(input); 78 mixer_inputs_.erase(input);
40 } 79 }
41 80
42 int AudioRendererMixer::Render(const std::vector<float*>& audio_data, 81 int AudioRendererMixer::Render(const std::vector<float*>& audio_data,
43 int number_of_frames, 82 int number_of_frames,
44 int audio_delay_milliseconds) { 83 int audio_delay_milliseconds) {
84 current_audio_delay_milliseconds_ = audio_delay_milliseconds;
scherkus (not reviewing) 2012/07/12 23:02:52 quick check: are we still planning on removing del
DaleCurtis 2012/07/12 23:16:29 Yes, as far as I know. We can't do that until the
scherkus (not reviewing) 2012/07/14 01:45:02 SGTM
85
86 if (resampler_ != NULL)
scherkus (not reviewing) 2012/07/12 23:02:52 s/resampler_ != NULL/resampler_.get()/
DaleCurtis 2012/07/13 00:01:25 Done.
87 resampler_->Resample(audio_data, number_of_frames);
88 else
89 ProvideInput(audio_data, number_of_frames);
90
91 // Always return the full number of frames requested, ProvideInput() will pad
92 // with silence if it wasn't able to acquire enough data.
93 return number_of_frames;
94 }
95
96 void AudioRendererMixer::ProvideInput(const std::vector<float*>& audio_data,
97 int number_of_frames) {
45 base::AutoLock auto_lock(mixer_inputs_lock_); 98 base::AutoLock auto_lock(mixer_inputs_lock_);
46 99
100 // Allocate staging area for each mixer input's audio data on first call. We
101 // won't know how much to allocate until here because of resampling.
102 if (mixer_input_audio_data_.size() == 0) {
103 // TODO(dalecurtis): If we switch to AVX/SSE optimization, we'll need to
104 // allocate these on 32-byte boundaries and ensure they're sized % 32 bytes.
105 mixer_input_audio_data_.reserve(audio_data.size());
106 for (size_t i = 0; i < audio_data.size(); ++i)
107 mixer_input_audio_data_.push_back(new float[number_of_frames]);
108 mixer_input_audio_data_size_ = number_of_frames;
109 }
110
111 // Sanity check our inputs.
112 DCHECK_LE(number_of_frames, mixer_input_audio_data_size_);
113 DCHECK_EQ(audio_data.size(), mixer_input_audio_data_.size());
114
47 // Zero |audio_data| so we're mixing into a clean buffer and return silence if 115 // Zero |audio_data| so we're mixing into a clean buffer and return silence if
48 // we couldn't get enough data from our inputs. 116 // we couldn't get enough data from our inputs.
49 for (int i = 0; i < audio_parameters_.channels(); ++i) 117 for (size_t i = 0; i < audio_data.size(); ++i)
50 memset(audio_data[i], 0, number_of_frames * sizeof(*audio_data[i])); 118 memset(audio_data[i], 0, number_of_frames * sizeof(*audio_data[i]));
51 119
52 // Have each mixer render its data into an output buffer then mix the result. 120 // Have each mixer render its data into an output buffer then mix the result.
53 for (AudioRendererMixerInputSet::iterator it = mixer_inputs_.begin(); 121 for (AudioRendererMixerInputSet::iterator it = mixer_inputs_.begin();
54 it != mixer_inputs_.end(); ++it) { 122 it != mixer_inputs_.end(); ++it) {
55 const scoped_refptr<AudioRendererMixerInput>& input = *it; 123 const scoped_refptr<AudioRendererMixerInput>& input = *it;
56 124
57 double volume; 125 double volume;
58 input->GetVolume(&volume); 126 input->GetVolume(&volume);
59 127
60 // Nothing to do if the input isn't playing or the volume is zero. 128 // Nothing to do if the input isn't playing.
61 if (!input->playing() || volume == 0.0f) 129 if (!input->playing())
62 continue; 130 continue;
63 131
64 const std::vector<float*>& mixer_input_audio_data = input->audio_data();
65
66 int frames_filled = input->callback()->Render( 132 int frames_filled = input->callback()->Render(
67 mixer_input_audio_data, number_of_frames, audio_delay_milliseconds); 133 mixer_input_audio_data_, number_of_frames,
134 current_audio_delay_milliseconds_);
68 if (frames_filled == 0) 135 if (frames_filled == 0)
69 continue; 136 continue;
70 137
71 // TODO(dalecurtis): Resample audio data.
72
73 // Volume adjust and mix each mixer input into |audio_data| after rendering. 138 // Volume adjust and mix each mixer input into |audio_data| after rendering.
74 // TODO(dalecurtis): Optimize with NEON/SSE/AVX vector_fmac from FFmpeg. 139 // TODO(dalecurtis): Optimize with NEON/SSE/AVX vector_fmac from FFmpeg.
75 for (int j = 0; j < audio_parameters_.channels(); ++j) { 140 for (size_t j = 0; j < audio_data.size(); ++j) {
76 float* dest = audio_data[j]; 141 float* dest = audio_data[j];
77 float* source = mixer_input_audio_data[j]; 142 float* source = mixer_input_audio_data_[j];
78 for (int k = 0; k < frames_filled; ++k) 143 for (int k = 0; k < frames_filled; ++k)
79 dest[k] += source[k] * static_cast<float>(volume); 144 dest[k] += source[k] * static_cast<float>(volume);
80 } 145 }
81 146
82 // No need to clamp values as InterleaveFloatToInt() will take care of this 147 // No need to clamp values as InterleaveFloatToInt() will take care of this
83 // for us later when data is transferred to the browser process. 148 // for us later when data is transferred to the browser process.
84 } 149 }
85
86 // Always return the full number of frames requested, padded with silence if
87 // we couldn't get enough data.
88 return number_of_frames;
89 } 150 }
90 151
91 void AudioRendererMixer::OnRenderError() { 152 void AudioRendererMixer::OnRenderError() {
92 base::AutoLock auto_lock(mixer_inputs_lock_); 153 base::AutoLock auto_lock(mixer_inputs_lock_);
93 154
94 // Call each mixer input and signal an error. 155 // Call each mixer input and signal an error.
95 for (AudioRendererMixerInputSet::iterator it = mixer_inputs_.begin(); 156 for (AudioRendererMixerInputSet::iterator it = mixer_inputs_.begin();
96 it != mixer_inputs_.end(); ++it) { 157 it != mixer_inputs_.end(); ++it) {
97 (*it)->callback()->OnRenderError(); 158 (*it)->callback()->OnRenderError();
98 } 159 }
99 } 160 }
100 161
101 } // namespace media 162 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698