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

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

Powered by Google App Engine
This is Rietveld 408576698