OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/renderer/media/webrtc_local_audio_source_provider.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "content/renderer/render_thread_impl.h" | |
9 #include "media/audio/audio_parameters.h" | |
10 #include "media/base/audio_fifo.h" | |
11 #include "media/base/audio_hardware_config.h" | |
12 #include "third_party/WebKit/public/web/WebAudioSourceProviderClient.h" | |
13 | |
14 using WebKit::WebVector; | |
15 | |
16 namespace content { | |
17 | |
18 static const size_t kMaxNumberOfBuffer = 10; | |
19 static const size_t kWebAudioRenderBufferSize = 128; | |
20 | |
21 WebRtcLocalAudioSourceProvider::WebRtcLocalAudioSourceProvider() | |
22 : audio_delay_ms_(0), | |
23 volume_(1), | |
24 key_pressed_(false), | |
25 is_enabled_(false), | |
26 use_sink_params_for_testing_(false) { | |
tommi (sloooow) - chröme
2013/09/10 16:00:38
I don't like mixing test code and production code
no longer working on chromium
2013/09/11 10:22:07
How about now?
| |
27 } | |
28 | |
29 WebRtcLocalAudioSourceProvider::~WebRtcLocalAudioSourceProvider() { | |
30 if (audio_converter_.get()) | |
31 audio_converter_->RemoveInput(this); | |
32 } | |
33 | |
34 void WebRtcLocalAudioSourceProvider::Initialize( | |
35 const media::AudioParameters& source_params) { | |
36 DCHECK(thread_checker_.CalledOnValidThread()); | |
37 if (!use_sink_params_for_testing_) { | |
38 // Use the native audio output hardware sample-rate for the sink. | |
39 media::AudioHardwareConfig* hardware_config = | |
40 RenderThreadImpl::current()->GetAudioHardwareConfig(); | |
41 int sample_rate = hardware_config->GetOutputSampleRate(); | |
42 sink_params_.Reset( | |
43 source_params.format(), media::CHANNEL_LAYOUT_STEREO, 2, 0, | |
44 sample_rate, source_params.bits_per_sample(), | |
45 kWebAudioRenderBufferSize); | |
46 } | |
47 | |
48 base::AutoLock auto_lock(lock_); | |
49 source_params_ = source_params; | |
50 // Create the audio converter with |disable_fifo| as false so that the | |
51 // converter will request source_params.frames_per_buffer() each time. | |
52 // This will not increase the complexity as there is only one client to | |
53 // the converter. | |
54 audio_converter_.reset( | |
55 new media::AudioConverter(source_params, sink_params_, false)); | |
56 audio_converter_->AddInput(this); | |
57 fifo_.reset(new media::AudioFifo( | |
58 source_params.channels(), | |
59 kMaxNumberOfBuffer * source_params.frames_per_buffer())); | |
60 } | |
61 | |
62 void WebRtcLocalAudioSourceProvider::DeliverData( | |
63 media::AudioBus* audio_source, | |
64 int audio_delay_milliseconds, | |
65 int volume, | |
66 bool key_pressed) { | |
67 base::AutoLock auto_lock(lock_); | |
68 if (!is_enabled_) | |
69 return; | |
70 | |
71 DCHECK(fifo_.get()); | |
72 | |
73 if (fifo_->frames() + audio_source->frames() <= fifo_->max_frames()) { | |
74 fifo_->Push(audio_source); | |
75 } else { | |
76 // This can happen if the data in FIFO is too slowed to be consumed or | |
77 // WebAudio stops consuming data. | |
78 DLOG(WARNING) << "Local source provicer FIFO is full" << fifo_->frames(); | |
79 } | |
80 | |
81 // Cache the values for GetAudioProcessingParams(). | |
82 last_fill_ = base::TimeTicks::Now(); | |
83 audio_delay_ms_ = audio_delay_milliseconds; | |
84 volume_ = volume; | |
85 key_pressed_ = key_pressed; | |
86 } | |
87 | |
88 void WebRtcLocalAudioSourceProvider::GetAudioProcessingParams( | |
89 int* delay_ms, int* volume, bool* key_pressed) { | |
90 int elapsed_ms = 0; | |
91 if (!last_fill_.is_null()) { | |
92 elapsed_ms = static_cast<int>( | |
93 (base::TimeTicks::Now() - last_fill_).InMilliseconds()); | |
94 } | |
95 *delay_ms = audio_delay_ms_ + elapsed_ms + static_cast<int>( | |
96 1000 * fifo_->frames() / source_params_.sample_rate() + 0.5); | |
97 *volume = volume_; | |
98 *key_pressed = key_pressed_; | |
99 } | |
100 | |
101 void WebRtcLocalAudioSourceProvider::setClient( | |
102 WebKit::WebAudioSourceProviderClient* client) { | |
103 NOTIMPLEMENTED(); | |
104 } | |
105 | |
106 void WebRtcLocalAudioSourceProvider::provideInput( | |
107 const WebVector<float*>& audio_data, size_t number_of_frames) { | |
108 DCHECK_EQ(number_of_frames, kWebAudioRenderBufferSize); | |
109 if (!bus_wrapper_ || | |
110 static_cast<size_t>(bus_wrapper_->channels()) != audio_data.size()) { | |
111 bus_wrapper_ = media::AudioBus::CreateWrapper(audio_data.size()); | |
112 } | |
113 | |
114 bus_wrapper_->set_frames(number_of_frames); | |
115 for (size_t i = 0; i < audio_data.size(); ++i) | |
116 bus_wrapper_->SetChannelData(i, audio_data[i]); | |
117 | |
118 base::AutoLock auto_lock(lock_); | |
119 DCHECK(audio_converter_.get()); | |
120 DCHECK(fifo_.get()); | |
121 is_enabled_ = true; | |
122 audio_converter_->Convert(bus_wrapper_.get()); | |
123 } | |
124 | |
125 double WebRtcLocalAudioSourceProvider::ProvideInput( | |
126 media::AudioBus* audio_bus, base::TimeDelta buffer_delay) { | |
127 if (fifo_->frames() >= audio_bus->frames()) { | |
128 fifo_->Consume(audio_bus, 0, audio_bus->frames()); | |
129 } else { | |
130 audio_bus->Zero(); | |
131 if (!last_fill_.is_null()) { | |
132 DLOG(WARNING) << "Underrun, FIFO has data " << fifo_->frames() | |
133 << " samples but " << audio_bus->frames() | |
134 << " samples are needed"; | |
135 } | |
136 } | |
137 | |
138 return 1.0; | |
139 } | |
140 | |
141 void WebRtcLocalAudioSourceProvider::SetSinkParamsForTesting( | |
142 const media::AudioParameters& sink_params) { | |
143 DCHECK(thread_checker_.CalledOnValidThread()); | |
144 sink_params_ = sink_params; | |
145 use_sink_params_for_testing_ = true; | |
146 } | |
147 | |
148 } // namespace content | |
OLD | NEW |