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

Side by Side Diff: content/renderer/media/webrtc_audio_renderer.cc

Issue 139303016: Feed the render data to MediaStreamAudioProcessor and used AudioBus in render callback (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed the unittests, ready for review now. Created 6 years, 11 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 "content/renderer/media/webrtc_audio_renderer.h" 5 #include "content/renderer/media/webrtc_audio_renderer.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/metrics/histogram.h" 8 #include "base/metrics/histogram.h"
9 #include "base/strings/string_util.h" 9 #include "base/strings/string_util.h"
10 #include "base/strings/stringprintf.h" 10 #include "base/strings/stringprintf.h"
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 int frames_per_buffer) 170 int frames_per_buffer)
171 : state_(UNINITIALIZED), 171 : state_(UNINITIALIZED),
172 source_render_view_id_(source_render_view_id), 172 source_render_view_id_(source_render_view_id),
173 session_id_(session_id), 173 session_id_(session_id),
174 source_(NULL), 174 source_(NULL),
175 play_ref_count_(0), 175 play_ref_count_(0),
176 start_ref_count_(0), 176 start_ref_count_(0),
177 audio_delay_milliseconds_(0), 177 audio_delay_milliseconds_(0),
178 fifo_delay_milliseconds_(0), 178 fifo_delay_milliseconds_(0),
179 sample_rate_(sample_rate), 179 sample_rate_(sample_rate),
180 number_of_channels_(0),
180 frames_per_buffer_(frames_per_buffer) { 181 frames_per_buffer_(frames_per_buffer) {
181 WebRtcLogMessage(base::StringPrintf( 182 WebRtcLogMessage(base::StringPrintf(
182 "WAR::WAR. source_render_view_id=%d" 183 "WAR::WAR. source_render_view_id=%d"
183 ", session_id=%d, sample_rate=%d, frames_per_buffer=%d", 184 ", session_id=%d, sample_rate=%d, frames_per_buffer=%d",
184 source_render_view_id, 185 source_render_view_id,
185 session_id, 186 session_id,
186 sample_rate, 187 sample_rate,
187 frames_per_buffer)); 188 frames_per_buffer));
188 } 189 }
189 190
190 WebRtcAudioRenderer::~WebRtcAudioRenderer() { 191 WebRtcAudioRenderer::~WebRtcAudioRenderer() {
191 DCHECK(thread_checker_.CalledOnValidThread()); 192 DCHECK(thread_checker_.CalledOnValidThread());
192 DCHECK_EQ(state_, UNINITIALIZED); 193 DCHECK_EQ(state_, UNINITIALIZED);
193 buffer_.reset();
194 } 194 }
195 195
196 bool WebRtcAudioRenderer::Initialize(WebRtcAudioRendererSource* source) { 196 bool WebRtcAudioRenderer::Initialize(WebRtcAudioRendererSource* source) {
197 DVLOG(1) << "WebRtcAudioRenderer::Initialize()"; 197 DVLOG(1) << "WebRtcAudioRenderer::Initialize()";
198 DCHECK(thread_checker_.CalledOnValidThread()); 198 DCHECK(thread_checker_.CalledOnValidThread());
199 base::AutoLock auto_lock(lock_); 199 base::AutoLock auto_lock(lock_);
200 DCHECK_EQ(state_, UNINITIALIZED); 200 DCHECK_EQ(state_, UNINITIALIZED);
201 DCHECK(source); 201 DCHECK(source);
202 DCHECK(!sink_.get()); 202 DCHECK(!sink_.get());
203 DCHECK(!source_); 203 DCHECK(!source_);
204 204
205 // Use stereo output on all platforms. 205 // Use stereo output on all platforms.
206 media::ChannelLayout channel_layout = media::CHANNEL_LAYOUT_STEREO; 206 media::ChannelLayout channel_layout = media::CHANNEL_LAYOUT_STEREO;
207 207
208 // TODO(tommi,henrika): Maybe we should just change |sample_rate_| to be 208 DVLOG(1) << "Audio output hardware sample rate: " << sample_rate_;
209 // immutable and change its value instead of using a temporary?
210 int sample_rate = sample_rate_;
211 DVLOG(1) << "Audio output hardware sample rate: " << sample_rate;
212 209
213 // WebRTC does not yet support higher rates than 96000 on the client side 210 // WebRTC does not yet support higher rates than 96000 on the client side
214 // and 48000 is the preferred sample rate. Therefore, if 192000 is detected, 211 // and 48000 is the preferred sample rate. Therefore, if 192000 is detected,
215 // we change the rate to 48000 instead. The consequence is that the native 212 // we change the rate to 48000 instead. The consequence is that the native
216 // layer will be opened up at 192kHz but WebRTC will provide data at 48kHz 213 // layer will be opened up at 192kHz but WebRTC will provide data at 48kHz
217 // which will then be resampled by the audio converted on the browser side 214 // which will then be resampled by the audio converted on the browser side
218 // to match the native audio layer. 215 // to match the native audio layer.
219 if (sample_rate == 192000) { 216 if (sample_rate_ == 192000) {
220 DVLOG(1) << "Resampling from 48000 to 192000 is required"; 217 DVLOG(1) << "Resampling from 48000 to 192000 is required";
221 sample_rate = 48000; 218 sample_rate_ = 48000;
222 } 219 }
223 media::AudioSampleRate asr = media::AsAudioSampleRate(sample_rate); 220 media::AudioSampleRate asr = media::AsAudioSampleRate(sample_rate_);
224 if (asr != media::kUnexpectedAudioSampleRate) { 221 if (asr != media::kUnexpectedAudioSampleRate) {
225 UMA_HISTOGRAM_ENUMERATION( 222 UMA_HISTOGRAM_ENUMERATION(
226 "WebRTC.AudioOutputSampleRate", asr, media::kUnexpectedAudioSampleRate); 223 "WebRTC.AudioOutputSampleRate", asr, media::kUnexpectedAudioSampleRate);
227 } else { 224 } else {
228 UMA_HISTOGRAM_COUNTS("WebRTC.AudioOutputSampleRateUnexpected", sample_rate); 225 UMA_HISTOGRAM_COUNTS("WebRTC.AudioOutputSampleRateUnexpected",
226 sample_rate_);
229 } 227 }
230 228
231 // Verify that the reported output hardware sample rate is supported 229 // Verify that the reported output hardware sample rate is supported
232 // on the current platform. 230 // on the current platform.
233 if (std::find(&kValidOutputRates[0], 231 if (std::find(&kValidOutputRates[0],
234 &kValidOutputRates[0] + arraysize(kValidOutputRates), 232 &kValidOutputRates[0] + arraysize(kValidOutputRates),
235 sample_rate) == 233 sample_rate_) ==
236 &kValidOutputRates[arraysize(kValidOutputRates)]) { 234 &kValidOutputRates[arraysize(kValidOutputRates)]) {
237 DLOG(ERROR) << sample_rate << " is not a supported output rate."; 235 DLOG(ERROR) << sample_rate_ << " is not a supported output rate.";
238 return false; 236 return false;
239 } 237 }
240 238
241 // Set up audio parameters for the source, i.e., the WebRTC client. 239 // Set up audio parameters for the source, i.e., the WebRTC client.
242 240
243 // The WebRTC client only supports multiples of 10ms as buffer size where 241 // The WebRTC client only supports multiples of 10ms as buffer size where
244 // 10ms is preferred for lowest possible delay. 242 // 10ms is preferred for lowest possible delay.
245 media::AudioParameters source_params; 243 media::AudioParameters source_params;
246 int buffer_size = (sample_rate / 100); 244 const int frames_per_10ms = (sample_rate_ / 100);
247 DVLOG(1) << "Using WebRTC output buffer size: " << buffer_size; 245 DVLOG(1) << "Using WebRTC output buffer size: " << frames_per_10ms;
248 246
249 int channels = ChannelLayoutToChannelCount(channel_layout); 247 number_of_channels_ = ChannelLayoutToChannelCount(channel_layout);
250 source_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, 248 source_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
251 channel_layout, channels, 0, 249 channel_layout, number_of_channels_, 0,
252 sample_rate, 16, buffer_size); 250 sample_rate_, 16, frames_per_10ms);
253 251
254 // Set up audio parameters for the sink, i.e., the native audio output stream. 252 // Set up audio parameters for the sink, i.e., the native audio output stream.
255 // We strive to open up using native parameters to achieve best possible 253 // We strive to open up using native parameters to achieve best possible
256 // performance and to ensure that no FIFO is needed on the browser side to 254 // performance and to ensure that no FIFO is needed on the browser side to
257 // match the client request. Any mismatch between the source and the sink is 255 // match the client request. Any mismatch between the source and the sink is
258 // taken care of in this class instead using a pull FIFO. 256 // taken care of in this class instead using a pull FIFO.
259 257
260 media::AudioParameters sink_params; 258 media::AudioParameters sink_params;
261 259
262 // Use native output siz as default. 260 // Use native output size as default.
263 buffer_size = frames_per_buffer_;
264 #if defined(OS_ANDROID) 261 #if defined(OS_ANDROID)
265 // TODO(henrika): Keep tuning this scheme and espcicially for low-latency 262 // TODO(henrika): Keep tuning this scheme and espcicially for low-latency
266 // cases. Might not be possible to come up with the perfect solution using 263 // cases. Might not be possible to come up with the perfect solution using
267 // the render side only. 264 // the render side only.
268 const int frames_per_10ms = (sample_rate / 100); 265 if (frames_per_buffer_ < 2 * frames_per_10ms) {
269 if (buffer_size < 2 * frames_per_10ms) {
270 // Examples of low-latency frame sizes and the resulting |buffer_size|: 266 // Examples of low-latency frame sizes and the resulting |buffer_size|:
271 // Nexus 7 : 240 audio frames => 2*480 = 960 267 // Nexus 7 : 240 audio frames => 2*480 = 960
272 // Nexus 10 : 256 => 2*441 = 882 268 // Nexus 10 : 256 => 2*441 = 882
273 // Galaxy Nexus: 144 => 2*441 = 882 269 // Galaxy Nexus: 144 => 2*441 = 882
274 buffer_size = 2 * frames_per_10ms; 270 frames_per_buffer_ = 2 * frames_per_10ms;
275 DVLOG(1) << "Low-latency output detected on Android"; 271 DVLOG(1) << "Low-latency output detected on Android";
276 } 272 }
277 #endif 273 #endif
278 DVLOG(1) << "Using sink output buffer size: " << buffer_size; 274 DVLOG(1) << "Using sink output buffer size: " << frames_per_buffer_;
279 275
280 sink_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, 276 sink_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
281 channel_layout, channels, 0, sample_rate, 16, buffer_size); 277 channel_layout, number_of_channels_, 0, sample_rate_, 16,
278 frames_per_buffer_);
282 279
283 // Create a FIFO if re-buffering is required to match the source input with 280 // Create a FIFO if re-buffering is required to match the source input with
284 // the sink request. The source acts as provider here and the sink as 281 // the sink request. The source acts as provider here and the sink as
285 // consumer. 282 // consumer.
286 fifo_delay_milliseconds_ = 0; 283 fifo_delay_milliseconds_ = 0;
287 if (source_params.frames_per_buffer() != sink_params.frames_per_buffer()) { 284 if (source_params.frames_per_buffer() != sink_params.frames_per_buffer()) {
288 DVLOG(1) << "Rebuffering from " << source_params.frames_per_buffer() 285 DVLOG(1) << "Rebuffering from " << source_params.frames_per_buffer()
289 << " to " << sink_params.frames_per_buffer(); 286 << " to " << sink_params.frames_per_buffer();
290 audio_fifo_.reset(new media::AudioPullFifo( 287 audio_fifo_.reset(new media::AudioPullFifo(
291 source_params.channels(), 288 source_params.channels(),
292 source_params.frames_per_buffer(), 289 source_params.frames_per_buffer(),
293 base::Bind( 290 base::Bind(
294 &WebRtcAudioRenderer::SourceCallback, 291 &WebRtcAudioRenderer::SourceCallback,
295 base::Unretained(this)))); 292 base::Unretained(this))));
296 293
297 if (sink_params.frames_per_buffer() > source_params.frames_per_buffer()) { 294 if (sink_params.frames_per_buffer() > source_params.frames_per_buffer()) {
298 int frame_duration_milliseconds = base::Time::kMillisecondsPerSecond / 295 int frame_duration_milliseconds = base::Time::kMillisecondsPerSecond /
299 static_cast<double>(source_params.sample_rate()); 296 static_cast<double>(source_params.sample_rate());
300 fifo_delay_milliseconds_ = (sink_params.frames_per_buffer() - 297 fifo_delay_milliseconds_ = (sink_params.frames_per_buffer() -
301 source_params.frames_per_buffer()) * frame_duration_milliseconds; 298 source_params.frames_per_buffer()) * frame_duration_milliseconds;
302 } 299 }
303 } 300 }
304 301
305 // Allocate local audio buffers based on the parameters above.
306 // It is assumed that each audio sample contains 16 bits and each
307 // audio frame contains one or two audio samples depending on the
308 // number of channels.
309 buffer_.reset(
310 new int16[source_params.frames_per_buffer() * source_params.channels()]);
311
312 source_ = source; 302 source_ = source;
313 source->SetRenderFormat(source_params);
314 303
315 // Configure the audio rendering client and start rendering. 304 // Configure the audio rendering client and start rendering.
316 sink_ = AudioDeviceFactory::NewOutputDevice(source_render_view_id_); 305 sink_ = AudioDeviceFactory::NewOutputDevice(source_render_view_id_);
317 306
318 // TODO(tommi): Rename InitializeUnifiedStream to rather reflect association 307 // TODO(tommi): Rename InitializeUnifiedStream to rather reflect association
319 // with a session. 308 // with a session.
320 DCHECK_GE(session_id_, 0); 309 DCHECK_GE(session_id_, 0);
321 sink_->InitializeUnifiedStream(sink_params, this, session_id_); 310 sink_->InitializeUnifiedStream(sink_params, this, session_id_);
322 311
323 sink_->Start(); 312 sink_->Start();
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 DVLOG(2) << "WebRtcAudioRenderer::SourceCallback(" 447 DVLOG(2) << "WebRtcAudioRenderer::SourceCallback("
459 << fifo_frame_delay << ", " 448 << fifo_frame_delay << ", "
460 << audio_bus->frames() << ")"; 449 << audio_bus->frames() << ")";
461 450
462 int output_delay_milliseconds = audio_delay_milliseconds_; 451 int output_delay_milliseconds = audio_delay_milliseconds_;
463 output_delay_milliseconds += fifo_delay_milliseconds_; 452 output_delay_milliseconds += fifo_delay_milliseconds_;
464 DVLOG(2) << "output_delay_milliseconds: " << output_delay_milliseconds; 453 DVLOG(2) << "output_delay_milliseconds: " << output_delay_milliseconds;
465 454
466 // We need to keep render data for the |source_| regardless of |state_|, 455 // We need to keep render data for the |source_| regardless of |state_|,
467 // otherwise the data will be buffered up inside |source_|. 456 // otherwise the data will be buffered up inside |source_|.
468 source_->RenderData(reinterpret_cast<uint8*>(buffer_.get()), 457 source_->RenderData(audio_bus, sample_rate_, output_delay_milliseconds);
469 audio_bus->channels(), audio_bus->frames(),
470 output_delay_milliseconds);
471 458
472 // Avoid filling up the audio bus if we are not playing; instead 459 // Avoid filling up the audio bus if we are not playing; instead
473 // return here and ensure that the returned value in Render() is 0. 460 // return here and ensure that the returned value in Render() is 0.
474 if (state_ != PLAYING) { 461 if (state_ != PLAYING) {
475 audio_bus->Zero(); 462 audio_bus->Zero();
476 return; 463 return;
477 } 464 }
478
479 // De-interleave each channel and convert to 32-bit floating-point
480 // with nominal range -1.0 -> +1.0 to match the callback format.
481 audio_bus->FromInterleaved(buffer_.get(),
482 audio_bus->frames(),
483 sizeof(buffer_[0]));
484 } 465 }
485 466
486 } // namespace content 467 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698