Index: content/renderer/media/webrtc_audio_capturer.cc |
diff --git a/content/renderer/media/webrtc_audio_capturer.cc b/content/renderer/media/webrtc_audio_capturer.cc |
index 976b9edd2ecf3705fc5b2749ed4902b03c9f10bd..db9817ddd259933b47a3de67b9b3291f1ca2d52b 100644 |
--- a/content/renderer/media/webrtc_audio_capturer.cc |
+++ b/content/renderer/media/webrtc_audio_capturer.cc |
@@ -57,12 +57,73 @@ static int GetBufferSizeForSampleRate(int sample_rate) { |
return buffer_size; |
} |
+// This is a temporary audio buffer with parameters used to send data to |
+// callbacks. |
+class WebRtcAudioCapturer::ConfiguredBuffer : |
+ public base::RefCounted<WebRtcAudioCapturer::ConfiguredBuffer> { |
+ public: |
+ ConfiguredBuffer() {} |
+ |
+ bool Initialize(int sample_rate, |
+ media::AudioParameters::Format format, |
+ media::ChannelLayout channel_layout) { |
+ int buffer_size = GetBufferSizeForSampleRate(sample_rate); |
+ if (!buffer_size) { |
+ DLOG(ERROR) << "Unsupported sample-rate: " << sample_rate; |
+ return false; |
+ } |
+ |
+ // bits_per_sample is always 16 for now. |
+ int bits_per_sample = 16; |
+ |
+ params_.Reset(format, channel_layout, 0, sample_rate, bits_per_sample, |
+ buffer_size); |
+ buffer_.reset(new int16[params_.frames_per_buffer() * params_.channels()]); |
+ |
+ return true; |
+ } |
+ |
+ int16* buffer() const { return buffer_.get(); } |
+ const media::AudioParameters& params() const { return params_; } |
+ |
+ private: |
+ ~ConfiguredBuffer() {} |
+ friend class base::RefCounted<WebRtcAudioCapturer::ConfiguredBuffer>; |
+ |
+ scoped_ptr<int16[]> buffer_; |
tommi (sloooow) - chröme
2013/02/08 20:00:39
ah, thanks. I didn't know about the DefaultDeleter
phoglund_chromium
2013/02/11 09:18:57
Done.
|
+ |
+ // Cached values of utilized audio parameters. |
+ media::AudioParameters params_; |
+}; |
+ |
// static |
scoped_refptr<WebRtcAudioCapturer> WebRtcAudioCapturer::CreateCapturer() { |
scoped_refptr<WebRtcAudioCapturer> capturer = new WebRtcAudioCapturer(); |
return capturer; |
} |
+bool WebRtcAudioCapturer::Reconfigure(int sample_rate, |
+ media::AudioParameters::Format format, |
+ media::ChannelLayout channel_layout) { |
+ scoped_refptr<ConfiguredBuffer> new_buffer(new ConfiguredBuffer()); |
+ if (!new_buffer->Initialize(sample_rate, format, channel_layout)) |
+ return false; |
+ |
+ SinkList sinks; |
+ { |
+ base::AutoLock auto_lock(lock_); |
+ |
+ buffer_ = new_buffer; |
+ sinks = sinks_; |
+ } |
+ |
+ // Tell all sinks which format we use. |
+ for (SinkList::const_iterator it = sinks.begin(); it != sinks.end(); ++it) |
tommi (sloooow) - chröme
2013/02/08 20:00:39
No action needed in this CL since I think you've i
phoglund_chromium
2013/02/11 09:18:57
Yeah, the buffer and parameters really need to be
|
+ (*it)->SetCaptureFormat(new_buffer->params()); |
+ |
+ return true; |
+} |
+ |
bool WebRtcAudioCapturer::Initialize(media::ChannelLayout channel_layout, |
int sample_rate) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
@@ -98,18 +159,8 @@ bool WebRtcAudioCapturer::Initialize(media::ChannelLayout channel_layout, |
return false; |
} |
- int buffer_size = GetBufferSizeForSampleRate(sample_rate); |
- |
- // Configure audio parameters for the default source. |
- params_.Reset(format, channel_layout, 0, sample_rate, 16, buffer_size); |
- |
- // Tell all sinks which format we use. |
- for (SinkList::const_iterator it = sinks_.begin(); |
- it != sinks_.end(); ++it) { |
- (*it)->SetCaptureFormat(params_); |
- } |
- |
- buffer_.reset(new int16[params_.frames_per_buffer() * params_.channels()]); |
+ if (!Reconfigure(sample_rate, format, channel_layout)) |
+ return false; |
// Create and configure the default audio capturing source. The |source_| |
// will be overwritten if an external client later calls SetCapturerSource() |
@@ -162,6 +213,7 @@ void WebRtcAudioCapturer::SetCapturerSource( |
DVLOG(1) << "SetCapturerSource(channel_layout=" << channel_layout << "," |
<< "sample_rate=" << sample_rate << ")"; |
scoped_refptr<media::AudioCapturerSource> old_source; |
+ scoped_refptr<ConfiguredBuffer> current_buffer; |
{ |
base::AutoLock auto_lock(lock_); |
if (source_ == source) |
@@ -169,9 +221,10 @@ void WebRtcAudioCapturer::SetCapturerSource( |
source_.swap(old_source); |
source_ = source; |
+ current_buffer = buffer_; |
} |
- const bool no_default_audio_source_exists = !buffer_.get(); |
+ const bool no_default_audio_source_exists = !current_buffer->buffer(); |
// Detach the old source from normal recording or perform first-time |
// initialization if Initialize() has never been called. For the second |
@@ -185,30 +238,20 @@ void WebRtcAudioCapturer::SetCapturerSource( |
// Dispatch the new parameters both to the sink(s) and to the new source. |
// The idea is to get rid of any dependency of the microphone parameters |
// which would normally be used by default. |
- |
- int buffer_size = GetBufferSizeForSampleRate(sample_rate); |
- if (!buffer_size) { |
- DLOG(ERROR) << "Unsupported sample-rate: " << sample_rate; |
+ if (!Reconfigure(sample_rate, current_buffer->params().format(), |
+ channel_layout)) { |
return; |
- } |
- |
- params_.Reset(params_.format(), |
- channel_layout, |
- 0, |
- sample_rate, |
- 16, // ignored since the audio stack uses float32. |
- buffer_size); |
- |
- buffer_.reset(new int16[params_.frames_per_buffer() * params_.channels()]); |
- |
- for (SinkList::const_iterator it = sinks_.begin(); |
- it != sinks_.end(); ++it) { |
- (*it)->SetCaptureFormat(params_); |
+ } else { |
+ // The buffer has been reconfigured. Update |current_buffer|. |
+ base::AutoLock auto_lock(lock_); |
+ current_buffer = buffer_; |
} |
} |
- if (source) |
- source->Initialize(params_, this, this); |
+ if (source) { |
+ // Make sure to grab the new parameters in case they were reconfigured. |
+ source->Initialize(current_buffer->params(), this, this); |
+ } |
} |
void WebRtcAudioCapturer::SetStopCallback( |
@@ -233,8 +276,9 @@ void WebRtcAudioCapturer::PrepareLoopback() { |
// in case since these tests were performed on a 16 core, 64GB Win 7 |
// machine. We could also add some sort of error notifier in this area if |
// the FIFO overflows. |
- loopback_fifo_.reset(new media::AudioFifo(params_.channels(), |
- 10 * params_.frames_per_buffer())); |
+ loopback_fifo_.reset(new media::AudioFifo( |
+ buffer_->params().channels(), |
+ 10 * buffer_->params().frames_per_buffer())); |
buffering_ = true; |
} |
@@ -359,12 +403,16 @@ void WebRtcAudioCapturer::Capture(media::AudioBus* audio_source, |
// |source_| is AudioInputDevice, otherwise it is driven by client's |
// CaptureCallback. |
SinkList sinks; |
+ scoped_refptr<ConfiguredBuffer> buffer_ref_while_calling; |
{ |
base::AutoLock auto_lock(lock_); |
if (!running_) |
return; |
- // Copy the sink list to a local variable. |
+ // Copy the stuff we will need to local variables. In particular, we grab |
+ // a reference to the buffer so we can ensure it stays alive even if the |
+ // buffer is reconfigured while we are calling back. |
+ buffer_ref_while_calling = buffer_; |
sinks = sinks_; |
// Push captured audio to FIFO so it can be read by a local sink. |
@@ -379,17 +427,19 @@ void WebRtcAudioCapturer::Capture(media::AudioBus* audio_source, |
} |
} |
+ int bytes_per_sample = |
+ buffer_ref_while_calling->params().bits_per_sample() / 8; |
+ |
// Interleave, scale, and clip input to int and store result in |
// a local byte buffer. |
- audio_source->ToInterleaved(audio_source->frames(), |
- params_.bits_per_sample() / 8, |
- buffer_.get()); |
+ audio_source->ToInterleaved(audio_source->frames(), bytes_per_sample, |
+ buffer_ref_while_calling->buffer()); |
// Feed the data to the sinks. |
for (SinkList::const_iterator it = sinks.begin(); |
it != sinks.end(); |
++it) { |
- (*it)->CaptureData(reinterpret_cast<const int16*>(buffer_.get()), |
+ (*it)->CaptureData(buffer_ref_while_calling->buffer(), |
audio_source->channels(), audio_source->frames(), |
audio_delay_milliseconds, volume); |
} |
@@ -424,4 +474,10 @@ void WebRtcAudioCapturer::OnDeviceStopped() { |
on_device_stopped_cb_.Run(); |
} |
+media::AudioParameters WebRtcAudioCapturer::audio_parameters() { |
+ base::AutoLock auto_lock(lock_); |
+ DCHECK(buffer_.get() != NULL); |
tommi (sloooow) - chröme
2013/02/08 20:00:39
you can remove this. we avoid having (D)CHECKs fol
phoglund_chromium
2013/02/11 09:18:57
Done.
|
+ return buffer_->params(); |
+} |
+ |
} // namespace content |