4a56d3a6b1407321484b8c00c85b2cbe81f4cf6a
[platform/framework/web/crosswalk.git] / src / media / audio / pulse / pulse_input.cc
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
3 // found in the LICENSE file.
4
5 #include "media/audio/pulse/pulse_input.h"
6
7 #include <pulse/pulseaudio.h>
8
9 #include "base/logging.h"
10 #include "media/audio/pulse/audio_manager_pulse.h"
11 #include "media/audio/pulse/pulse_util.h"
12
13 namespace media {
14
15 using pulse::AutoPulseLock;
16 using pulse::WaitForOperationCompletion;
17
18 // Number of blocks of buffers used in the |fifo_|.
19 const int kNumberOfBlocksBufferInFifo = 2;
20
21 PulseAudioInputStream::PulseAudioInputStream(AudioManagerPulse* audio_manager,
22                                              const std::string& device_name,
23                                              const AudioParameters& params,
24                                              pa_threaded_mainloop* mainloop,
25                                              pa_context* context)
26     : audio_manager_(audio_manager),
27       callback_(NULL),
28       device_name_(device_name),
29       params_(params),
30       channels_(0),
31       volume_(0.0),
32       stream_started_(false),
33       fifo_(params.channels(),
34             params.frames_per_buffer(),
35             kNumberOfBlocksBufferInFifo),
36       pa_mainloop_(mainloop),
37       pa_context_(context),
38       handle_(NULL),
39       context_state_changed_(false) {
40   DCHECK(mainloop);
41   DCHECK(context);
42   CHECK(params_.IsValid());
43 }
44
45 PulseAudioInputStream::~PulseAudioInputStream() {
46   // All internal structures should already have been freed in Close(),
47   // which calls AudioManagerPulse::Release which deletes this object.
48   DCHECK(!handle_);
49 }
50
51 bool PulseAudioInputStream::Open() {
52   DCHECK(thread_checker_.CalledOnValidThread());
53   AutoPulseLock auto_lock(pa_mainloop_);
54   if (!pulse::CreateInputStream(pa_mainloop_, pa_context_, &handle_, params_,
55                                 device_name_, &StreamNotifyCallback, this)) {
56     return false;
57   }
58
59   DCHECK(handle_);
60
61   return true;
62 }
63
64 void PulseAudioInputStream::Start(AudioInputCallback* callback) {
65   DCHECK(thread_checker_.CalledOnValidThread());
66   DCHECK(callback);
67   DCHECK(handle_);
68
69   // AGC needs to be started out of the lock.
70   StartAgc();
71
72   AutoPulseLock auto_lock(pa_mainloop_);
73
74   if (stream_started_)
75     return;
76
77   // Clean up the old buffer.
78   pa_stream_drop(handle_);
79   fifo_.Clear();
80
81   // Start the streaming.
82   callback_ = callback;
83   pa_stream_set_read_callback(handle_, &ReadCallback, this);
84   pa_stream_readable_size(handle_);
85   stream_started_ = true;
86
87   pa_operation* operation = pa_stream_cork(handle_, 0, NULL, NULL);
88   WaitForOperationCompletion(pa_mainloop_, operation);
89 }
90
91 void PulseAudioInputStream::Stop() {
92   DCHECK(thread_checker_.CalledOnValidThread());
93   AutoPulseLock auto_lock(pa_mainloop_);
94   if (!stream_started_)
95     return;
96
97   StopAgc();
98
99   // Set the flag to false to stop filling new data to soundcard.
100   stream_started_ = false;
101
102   pa_operation* operation = pa_stream_flush(handle_,
103                                             &pulse::StreamSuccessCallback,
104                                             pa_mainloop_);
105   WaitForOperationCompletion(pa_mainloop_, operation);
106
107   // Stop the stream.
108   pa_stream_set_read_callback(handle_, NULL, NULL);
109   operation = pa_stream_cork(handle_, 1, &pulse::StreamSuccessCallback,
110                              pa_mainloop_);
111   WaitForOperationCompletion(pa_mainloop_, operation);
112   callback_ = NULL;
113 }
114
115 void PulseAudioInputStream::Close() {
116   DCHECK(thread_checker_.CalledOnValidThread());
117   {
118     AutoPulseLock auto_lock(pa_mainloop_);
119     if (handle_) {
120       // Disable all the callbacks before disconnecting.
121       pa_stream_set_state_callback(handle_, NULL, NULL);
122       pa_operation* operation = pa_stream_flush(
123           handle_, &pulse::StreamSuccessCallback, pa_mainloop_);
124       WaitForOperationCompletion(pa_mainloop_, operation);
125
126       if (pa_stream_get_state(handle_) != PA_STREAM_UNCONNECTED)
127         pa_stream_disconnect(handle_);
128
129       // Release PulseAudio structures.
130       pa_stream_unref(handle_);
131       handle_ = NULL;
132     }
133   }
134
135   // Signal to the manager that we're closed and can be removed.
136   // This should be the last call in the function as it deletes "this".
137   audio_manager_->ReleaseInputStream(this);
138 }
139
140 double PulseAudioInputStream::GetMaxVolume() {
141   return static_cast<double>(PA_VOLUME_NORM);
142 }
143
144 void PulseAudioInputStream::SetVolume(double volume) {
145   AutoPulseLock auto_lock(pa_mainloop_);
146   if (!handle_)
147     return;
148
149   size_t index = pa_stream_get_device_index(handle_);
150   pa_operation* operation = NULL;
151   if (!channels_) {
152     // Get the number of channels for the source only when the |channels_| is 0.
153     // We are assuming the stream source is not changed on the fly here.
154     operation = pa_context_get_source_info_by_index(
155         pa_context_, index, &VolumeCallback, this);
156     WaitForOperationCompletion(pa_mainloop_, operation);
157     if (!channels_) {
158       DLOG(WARNING) << "Failed to get the number of channels for the source";
159       return;
160     }
161   }
162
163   pa_cvolume pa_volume;
164   pa_cvolume_set(&pa_volume, channels_, volume);
165   operation = pa_context_set_source_volume_by_index(
166       pa_context_, index, &pa_volume, NULL, NULL);
167
168   // Don't need to wait for this task to complete.
169   pa_operation_unref(operation);
170 }
171
172 double PulseAudioInputStream::GetVolume() {
173   if (pa_threaded_mainloop_in_thread(pa_mainloop_)) {
174     // When being called by the pulse thread, GetVolume() is asynchronous and
175     // called under AutoPulseLock.
176     if (!handle_)
177       return 0.0;
178
179     size_t index = pa_stream_get_device_index(handle_);
180     pa_operation* operation = pa_context_get_source_info_by_index(
181         pa_context_, index, &VolumeCallback, this);
182     // Do not wait for the operation since we can't block the pulse thread.
183     pa_operation_unref(operation);
184
185     // Return zero and the callback will asynchronously update the |volume_|.
186     return 0.0;
187   } else {
188     // Called by other thread, put an AutoPulseLock and wait for the operation.
189     AutoPulseLock auto_lock(pa_mainloop_);
190     if (!handle_)
191       return 0.0;
192
193     size_t index = pa_stream_get_device_index(handle_);
194     pa_operation* operation = pa_context_get_source_info_by_index(
195         pa_context_, index, &VolumeCallback, this);
196     WaitForOperationCompletion(pa_mainloop_, operation);
197
198     return volume_;
199   }
200 }
201
202 // static, used by pa_stream_set_read_callback.
203 void PulseAudioInputStream::ReadCallback(pa_stream* handle,
204                                          size_t length,
205                                          void* user_data) {
206   PulseAudioInputStream* stream =
207       reinterpret_cast<PulseAudioInputStream*>(user_data);
208
209   stream->ReadData();
210 }
211
212 // static, used by pa_context_get_source_info_by_index.
213 void PulseAudioInputStream::VolumeCallback(pa_context* context,
214                                            const pa_source_info* info,
215                                            int error, void* user_data) {
216   PulseAudioInputStream* stream =
217       reinterpret_cast<PulseAudioInputStream*>(user_data);
218
219   if (error) {
220     pa_threaded_mainloop_signal(stream->pa_mainloop_, 0);
221     return;
222   }
223
224   if (stream->channels_ != info->channel_map.channels)
225     stream->channels_ = info->channel_map.channels;
226
227   pa_volume_t volume = PA_VOLUME_MUTED;  // Minimum possible value.
228   // Use the max volume of any channel as the volume.
229   for (int i = 0; i < stream->channels_; ++i) {
230     if (volume < info->volume.values[i])
231       volume = info->volume.values[i];
232   }
233
234   // It is safe to access |volume_| here since VolumeCallback() is running
235   // under PulseLock.
236   stream->volume_ = static_cast<double>(volume);
237 }
238
239 // static, used by pa_stream_set_state_callback.
240 void PulseAudioInputStream::StreamNotifyCallback(pa_stream* s,
241                                                  void* user_data) {
242   PulseAudioInputStream* stream =
243       reinterpret_cast<PulseAudioInputStream*>(user_data);
244   if (s && stream->callback_ &&
245       pa_stream_get_state(s) == PA_STREAM_FAILED) {
246     stream->callback_->OnError(stream);
247   }
248
249   pa_threaded_mainloop_signal(stream->pa_mainloop_, 0);
250 }
251
252 void PulseAudioInputStream::ReadData() {
253   uint32 hardware_delay = pulse::GetHardwareLatencyInBytes(
254       handle_, params_.sample_rate(), params_.GetBytesPerFrame());
255
256   // Update the AGC volume level once every second. Note that,
257   // |volume| is also updated each time SetVolume() is called
258   // through IPC by the render-side AGC.
259   // We disregard the |normalized_volume| from GetAgcVolume()
260   // and use the value calculated by |volume_|.
261   double normalized_volume = 0.0;
262   GetAgcVolume(&normalized_volume);
263   normalized_volume = volume_ / GetMaxVolume();
264
265   do {
266     size_t length = 0;
267     const void* data = NULL;
268     pa_stream_peek(handle_, &data, &length);
269     if (!data || length == 0)
270       break;
271
272     const int number_of_frames = length / params_.GetBytesPerFrame();
273     if (number_of_frames > fifo_.GetUnfilledFrames()) {
274       // Dynamically increase capacity to the FIFO to handle larger buffer got
275       // from Pulse.
276       const int increase_blocks_of_buffer = static_cast<int>(
277           (number_of_frames - fifo_.GetUnfilledFrames()) /
278               params_.frames_per_buffer()) + 1;
279       fifo_.IncreaseCapacity(increase_blocks_of_buffer);
280     }
281
282     fifo_.Push(data, number_of_frames, params_.bits_per_sample() / 8);
283
284     // Checks if we still have data.
285     pa_stream_drop(handle_);
286   } while (pa_stream_readable_size(handle_) > 0);
287
288   while (fifo_.available_blocks()) {
289     const AudioBus* audio_bus = fifo_.Consume();
290
291     // Compensate the audio delay caused by the FIFO.
292     hardware_delay += fifo_.GetAvailableFrames() * params_.GetBytesPerFrame();
293     callback_->OnData(this, audio_bus, hardware_delay, normalized_volume);
294
295     // Sleep 5ms to wait until render consumes the data in order to avoid
296     // back to back OnData() method.
297     if (fifo_.available_blocks())
298       base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5));
299   }
300
301   pa_threaded_mainloop_signal(pa_mainloop_, 0);
302 }
303
304 }  // namespace media