- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / media / webrtc_local_audio_source_provider.cc
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 kMaxNumberOfBuffers = 10;
19
20 // Size of the buffer that WebAudio processes each time, it is the same value
21 // as AudioNode::ProcessingSizeInFrames in WebKit.
22 // static
23 const size_t WebRtcLocalAudioSourceProvider::kWebAudioRenderBufferSize = 128;
24
25 WebRtcLocalAudioSourceProvider::WebRtcLocalAudioSourceProvider()
26     : audio_delay_ms_(0),
27       volume_(1),
28       key_pressed_(false),
29       is_enabled_(false) {
30 }
31
32 WebRtcLocalAudioSourceProvider::~WebRtcLocalAudioSourceProvider() {
33   if (audio_converter_.get())
34     audio_converter_->RemoveInput(this);
35 }
36
37 void WebRtcLocalAudioSourceProvider::Initialize(
38     const media::AudioParameters& source_params) {
39   DCHECK(thread_checker_.CalledOnValidThread());
40
41   // Use the native audio output hardware sample-rate for the sink.
42   if (RenderThreadImpl::current()) {
43     media::AudioHardwareConfig* hardware_config =
44         RenderThreadImpl::current()->GetAudioHardwareConfig();
45     int sample_rate = hardware_config->GetOutputSampleRate();
46     sink_params_.Reset(
47         source_params.format(), media::CHANNEL_LAYOUT_STEREO, 2, 0,
48         sample_rate, source_params.bits_per_sample(),
49         kWebAudioRenderBufferSize);
50   } else {
51     // This happens on unittests which does not have a valid RenderThreadImpl,
52     // the unittests should have injected their own |sink_params_| for testing.
53     DCHECK(sink_params_.IsValid());
54   }
55
56   base::AutoLock auto_lock(lock_);
57   source_params_ = source_params;
58   // Create the audio converter with |disable_fifo| as false so that the
59   // converter will request source_params.frames_per_buffer() each time.
60   // This will not increase the complexity as there is only one client to
61   // the converter.
62   audio_converter_.reset(
63       new media::AudioConverter(source_params, sink_params_, false));
64   audio_converter_->AddInput(this);
65   fifo_.reset(new media::AudioFifo(
66       source_params.channels(),
67       kMaxNumberOfBuffers * source_params.frames_per_buffer()));
68 }
69
70 void WebRtcLocalAudioSourceProvider::DeliverData(
71     media::AudioBus* audio_source,
72     int audio_delay_milliseconds,
73     int volume,
74     bool key_pressed) {
75   base::AutoLock auto_lock(lock_);
76   if (!is_enabled_)
77     return;
78
79   DCHECK(fifo_.get());
80
81   if (fifo_->frames() + audio_source->frames() <= fifo_->max_frames()) {
82     fifo_->Push(audio_source);
83   } else {
84     // This can happen if the data in FIFO is too slowed to be consumed or
85     // WebAudio stops consuming data.
86     DLOG(WARNING) << "Local source provicer FIFO is full" << fifo_->frames();
87   }
88
89   // Cache the values for GetAudioProcessingParams().
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 }
108
109 void WebRtcLocalAudioSourceProvider::setClient(
110     WebKit::WebAudioSourceProviderClient* client) {
111   NOTREACHED();
112 }
113
114 void WebRtcLocalAudioSourceProvider::provideInput(
115     const WebVector<float*>& audio_data, size_t number_of_frames) {
116   DCHECK_EQ(number_of_frames, kWebAudioRenderBufferSize);
117   if (!bus_wrapper_ ||
118       static_cast<size_t>(bus_wrapper_->channels()) != audio_data.size()) {
119     bus_wrapper_ = media::AudioBus::CreateWrapper(audio_data.size());
120   }
121
122   bus_wrapper_->set_frames(number_of_frames);
123   for (size_t i = 0; i < audio_data.size(); ++i)
124     bus_wrapper_->SetChannelData(i, audio_data[i]);
125
126   base::AutoLock auto_lock(lock_);
127   DCHECK(audio_converter_.get());
128   DCHECK(fifo_.get());
129   is_enabled_ = true;
130   audio_converter_->Convert(bus_wrapper_.get());
131 }
132
133 double WebRtcLocalAudioSourceProvider::ProvideInput(
134     media::AudioBus* audio_bus, base::TimeDelta buffer_delay) {
135   if (fifo_->frames() >= audio_bus->frames()) {
136     fifo_->Consume(audio_bus, 0, audio_bus->frames());
137   } else {
138     audio_bus->Zero();
139     if (!last_fill_.is_null()) {
140       DLOG(WARNING) << "Underrun, FIFO has data " << fifo_->frames()
141                     << " samples but " << audio_bus->frames()
142                     << " samples are needed";
143     }
144   }
145
146   return 1.0;
147 }
148
149 void WebRtcLocalAudioSourceProvider::SetSinkParamsForTesting(
150     const media::AudioParameters& sink_params) {
151   DCHECK(thread_checker_.CalledOnValidThread());
152   sink_params_ = sink_params;
153 }
154
155 }  // namespace content