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