OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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_local_audio_source_provider.h" | 5 #include "content/renderer/media/webrtc_local_audio_source_provider.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "content/renderer/render_thread_impl.h" | 8 #include "content/renderer/render_thread_impl.h" |
9 #include "media/audio/audio_parameters.h" | 9 #include "media/audio/audio_parameters.h" |
10 #include "media/base/audio_fifo.h" | 10 #include "media/base/audio_fifo.h" |
11 #include "media/base/audio_hardware_config.h" | 11 #include "media/base/audio_hardware_config.h" |
12 #include "third_party/WebKit/public/web/WebAudioSourceProviderClient.h" | 12 #include "third_party/WebKit/public/web/WebAudioSourceProviderClient.h" |
13 | 13 |
14 using WebKit::WebVector; | 14 using WebKit::WebVector; |
15 | 15 |
16 namespace content { | 16 namespace content { |
17 | 17 |
18 static const size_t kMaxNumberOfBuffers = 10; | 18 static const size_t kMaxNumberOfBuffers = 10; |
19 | 19 |
20 // Size of the buffer that WebAudio processes each time, it is the same value | 20 // Size of the buffer that WebAudio processes each time, it is the same value |
21 // as AudioNode::ProcessingSizeInFrames in WebKit. | 21 // as AudioNode::ProcessingSizeInFrames in WebKit. |
22 // static | 22 // static |
23 const size_t WebRtcLocalAudioSourceProvider::kWebAudioRenderBufferSize = 128; | 23 const size_t WebRtcLocalAudioSourceProvider::kWebAudioRenderBufferSize = 128; |
24 | 24 |
25 WebRtcLocalAudioSourceProvider::WebRtcLocalAudioSourceProvider() | 25 WebRtcLocalAudioSourceProvider::WebRtcLocalAudioSourceProvider() |
26 : audio_delay_ms_(0), | 26 : is_enabled_(false) { |
27 volume_(1), | |
28 key_pressed_(false), | |
29 is_enabled_(false) { | |
30 } | 27 } |
31 | 28 |
32 WebRtcLocalAudioSourceProvider::~WebRtcLocalAudioSourceProvider() { | 29 WebRtcLocalAudioSourceProvider::~WebRtcLocalAudioSourceProvider() { |
33 if (audio_converter_.get()) | 30 if (audio_converter_.get()) |
34 audio_converter_->RemoveInput(this); | 31 audio_converter_->RemoveInput(this); |
35 } | 32 } |
36 | 33 |
37 void WebRtcLocalAudioSourceProvider::Initialize( | 34 void WebRtcLocalAudioSourceProvider::SetCaptureFormat( |
38 const media::AudioParameters& source_params) { | 35 const media::AudioParameters& params) { |
39 DCHECK(thread_checker_.CalledOnValidThread()); | 36 DCHECK(thread_checker_.CalledOnValidThread()); |
| 37 DCHECK(params.IsValid()); |
40 | 38 |
41 // Use the native audio output hardware sample-rate for the sink. | 39 // Use the native audio output hardware sample-rate for the sink. |
42 if (RenderThreadImpl::current()) { | 40 if (RenderThreadImpl::current()) { |
43 media::AudioHardwareConfig* hardware_config = | 41 media::AudioHardwareConfig* hardware_config = |
44 RenderThreadImpl::current()->GetAudioHardwareConfig(); | 42 RenderThreadImpl::current()->GetAudioHardwareConfig(); |
45 int sample_rate = hardware_config->GetOutputSampleRate(); | 43 int sample_rate = hardware_config->GetOutputSampleRate(); |
46 sink_params_.Reset( | 44 sink_params_.Reset( |
47 source_params.format(), media::CHANNEL_LAYOUT_STEREO, 2, 0, | 45 params.format(), media::CHANNEL_LAYOUT_STEREO, 2, 0, |
48 sample_rate, source_params.bits_per_sample(), | 46 sample_rate, params.bits_per_sample(), |
49 kWebAudioRenderBufferSize); | 47 kWebAudioRenderBufferSize); |
50 } else { | 48 } else { |
51 // This happens on unittests which does not have a valid RenderThreadImpl, | 49 // This happens on unittests which does not have a valid RenderThreadImpl, |
52 // the unittests should have injected their own |sink_params_| for testing. | 50 // the unittests should have injected their own |sink_params_| for testing. |
53 DCHECK(sink_params_.IsValid()); | 51 DCHECK(sink_params_.IsValid()); |
54 } | 52 } |
55 | 53 |
56 base::AutoLock auto_lock(lock_); | 54 base::AutoLock auto_lock(lock_); |
57 source_params_ = source_params; | 55 source_params_ = params; |
58 // Create the audio converter with |disable_fifo| as false so that the | 56 // Create the audio converter with |disable_fifo| as false so that the |
59 // converter will request source_params.frames_per_buffer() each time. | 57 // converter will request source_params.frames_per_buffer() each time. |
60 // This will not increase the complexity as there is only one client to | 58 // This will not increase the complexity as there is only one client to |
61 // the converter. | 59 // the converter. |
62 audio_converter_.reset( | 60 audio_converter_.reset( |
63 new media::AudioConverter(source_params, sink_params_, false)); | 61 new media::AudioConverter(params, sink_params_, false)); |
64 audio_converter_->AddInput(this); | 62 audio_converter_->AddInput(this); |
65 fifo_.reset(new media::AudioFifo( | 63 fifo_.reset(new media::AudioFifo( |
66 source_params.channels(), | 64 params.channels(), |
67 kMaxNumberOfBuffers * source_params.frames_per_buffer())); | 65 kMaxNumberOfBuffers * params.frames_per_buffer())); |
| 66 input_wrapper_ = media::AudioBus::Create(source_params_.channels(), |
| 67 source_params_.frames_per_buffer()); |
68 } | 68 } |
69 | 69 |
70 void WebRtcLocalAudioSourceProvider::DeliverData( | 70 int WebRtcLocalAudioSourceProvider::CaptureData( |
71 media::AudioBus* audio_source, | 71 const std::vector<int>& channels, |
| 72 const int16* audio_data, |
| 73 int sample_rate, |
| 74 int number_of_channels, |
| 75 int number_of_frames, |
72 int audio_delay_milliseconds, | 76 int audio_delay_milliseconds, |
73 int volume, | 77 int current_volume, |
| 78 bool need_audio_processing, |
74 bool key_pressed) { | 79 bool key_pressed) { |
75 base::AutoLock auto_lock(lock_); | 80 base::AutoLock auto_lock(lock_); |
76 if (!is_enabled_) | 81 if (!is_enabled_) |
77 return; | 82 return 0; |
78 | 83 |
79 DCHECK(fifo_.get()); | 84 DCHECK(fifo_.get()); |
| 85 // TODO(xians): A better way to handle the interleaved and deinterleaved |
| 86 // format switching. |
| 87 DCHECK(input_wrapper_->frames() == number_of_frames); |
| 88 CHECK(input_wrapper_->channels() == number_of_channels); |
| 89 input_wrapper_->FromInterleaved(audio_data, number_of_frames, 2); |
80 | 90 |
81 if (fifo_->frames() + audio_source->frames() <= fifo_->max_frames()) { | 91 if (fifo_->frames() + number_of_frames <= fifo_->max_frames()) { |
82 fifo_->Push(audio_source); | 92 fifo_->Push(input_wrapper_.get()); |
83 } else { | 93 } else { |
84 // This can happen if the data in FIFO is too slowed to be consumed or | 94 // This can happen if the data in FIFO is too slowed to be consumed or |
85 // WebAudio stops consuming data. | 95 // WebAudio stops consuming data. |
86 DLOG(WARNING) << "Local source provicer FIFO is full" << fifo_->frames(); | 96 DLOG(WARNING) << "Local source provicer FIFO is full" << fifo_->frames(); |
87 } | 97 } |
88 | 98 |
89 // Cache the values for GetAudioProcessingParams(). | 99 return 0; |
90 last_fill_ = base::TimeTicks::Now(); | |
91 audio_delay_ms_ = audio_delay_milliseconds; | |
92 volume_ = volume; | |
93 key_pressed_ = key_pressed; | |
94 } | |
95 | |
96 void WebRtcLocalAudioSourceProvider::GetAudioProcessingParams( | |
97 int* delay_ms, int* volume, bool* key_pressed) { | |
98 int elapsed_ms = 0; | |
99 if (!last_fill_.is_null()) { | |
100 elapsed_ms = static_cast<int>( | |
101 (base::TimeTicks::Now() - last_fill_).InMilliseconds()); | |
102 } | |
103 *delay_ms = audio_delay_ms_ + elapsed_ms + static_cast<int>( | |
104 1000 * fifo_->frames() / source_params_.sample_rate() + 0.5); | |
105 *volume = volume_; | |
106 *key_pressed = key_pressed_; | |
107 } | 100 } |
108 | 101 |
109 void WebRtcLocalAudioSourceProvider::setClient( | 102 void WebRtcLocalAudioSourceProvider::setClient( |
110 WebKit::WebAudioSourceProviderClient* client) { | 103 WebKit::WebAudioSourceProviderClient* client) { |
111 NOTREACHED(); | 104 NOTREACHED(); |
112 } | 105 } |
113 | 106 |
114 void WebRtcLocalAudioSourceProvider::provideInput( | 107 void WebRtcLocalAudioSourceProvider::provideInput( |
115 const WebVector<float*>& audio_data, size_t number_of_frames) { | 108 const WebVector<float*>& audio_data, size_t number_of_frames) { |
116 DCHECK_EQ(number_of_frames, kWebAudioRenderBufferSize); | 109 DCHECK_EQ(number_of_frames, kWebAudioRenderBufferSize); |
117 if (!bus_wrapper_ || | 110 if (!output_wrapper_ || |
118 static_cast<size_t>(bus_wrapper_->channels()) != audio_data.size()) { | 111 static_cast<size_t>(output_wrapper_->channels()) != audio_data.size()) { |
119 bus_wrapper_ = media::AudioBus::CreateWrapper(audio_data.size()); | 112 output_wrapper_ = media::AudioBus::CreateWrapper(audio_data.size()); |
120 } | 113 } |
121 | 114 |
122 bus_wrapper_->set_frames(number_of_frames); | 115 output_wrapper_->set_frames(number_of_frames); |
123 for (size_t i = 0; i < audio_data.size(); ++i) | 116 for (size_t i = 0; i < audio_data.size(); ++i) |
124 bus_wrapper_->SetChannelData(i, audio_data[i]); | 117 output_wrapper_->SetChannelData(i, audio_data[i]); |
125 | 118 |
126 base::AutoLock auto_lock(lock_); | 119 base::AutoLock auto_lock(lock_); |
127 DCHECK(audio_converter_.get()); | 120 DCHECK(audio_converter_.get()); |
128 DCHECK(fifo_.get()); | 121 DCHECK(fifo_.get()); |
129 is_enabled_ = true; | 122 is_enabled_ = true; |
130 audio_converter_->Convert(bus_wrapper_.get()); | 123 audio_converter_->Convert(output_wrapper_.get()); |
131 } | 124 } |
132 | 125 |
133 double WebRtcLocalAudioSourceProvider::ProvideInput( | 126 double WebRtcLocalAudioSourceProvider::ProvideInput( |
134 media::AudioBus* audio_bus, base::TimeDelta buffer_delay) { | 127 media::AudioBus* audio_bus, base::TimeDelta buffer_delay) { |
135 if (fifo_->frames() >= audio_bus->frames()) { | 128 if (fifo_->frames() >= audio_bus->frames()) { |
136 fifo_->Consume(audio_bus, 0, audio_bus->frames()); | 129 fifo_->Consume(audio_bus, 0, audio_bus->frames()); |
137 } else { | 130 } else { |
138 audio_bus->Zero(); | 131 audio_bus->Zero(); |
139 if (!last_fill_.is_null()) { | 132 DVLOG(1) << "WARNING: Underrun, FIFO has data " << fifo_->frames() |
140 DLOG(WARNING) << "Underrun, FIFO has data " << fifo_->frames() | 133 << " samples but " << audio_bus->frames() |
141 << " samples but " << audio_bus->frames() | 134 << " samples are needed"; |
142 << " samples are needed"; | |
143 } | |
144 } | 135 } |
145 | 136 |
146 return 1.0; | 137 return 1.0; |
147 } | 138 } |
148 | 139 |
149 void WebRtcLocalAudioSourceProvider::SetSinkParamsForTesting( | 140 void WebRtcLocalAudioSourceProvider::SetSinkParamsForTesting( |
150 const media::AudioParameters& sink_params) { | 141 const media::AudioParameters& sink_params) { |
151 DCHECK(thread_checker_.CalledOnValidThread()); | 142 DCHECK(thread_checker_.CalledOnValidThread()); |
152 sink_params_ = sink_params; | 143 sink_params_ = sink_params; |
153 } | 144 } |
154 | 145 |
155 } // namespace content | 146 } // namespace content |
OLD | NEW |