Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(561)

Side by Side Diff: media/audio/pulse/pulse_unified.cc

Issue 163343002: Reland 153623004: Remove the unified IO code on the browser (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: fixed the cras bot Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/audio/pulse/pulse_unified.h ('k') | media/audio/sounds/audio_stream_handler.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 "media/audio/pulse/pulse_unified.h"
6
7 #include "base/single_thread_task_runner.h"
8 #include "base/time/time.h"
9 #include "media/audio/audio_manager_base.h"
10 #include "media/audio/audio_parameters.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
19 static const int kFifoSizeInPackets = 10;
20
21 // static, pa_stream_notify_cb
22 void PulseAudioUnifiedStream::StreamNotifyCallback(pa_stream* s,
23 void* user_data) {
24 PulseAudioUnifiedStream* stream =
25 static_cast<PulseAudioUnifiedStream*>(user_data);
26
27 // Forward unexpected failures to the AudioSourceCallback if available. All
28 // these variables are only modified under pa_threaded_mainloop_lock() so this
29 // should be thread safe.
30 if (s && stream->source_callback_ &&
31 pa_stream_get_state(s) == PA_STREAM_FAILED) {
32 stream->source_callback_->OnError(stream);
33 }
34
35 pa_threaded_mainloop_signal(stream->pa_mainloop_, 0);
36 }
37
38 // static, used by pa_stream_set_read_callback.
39 void PulseAudioUnifiedStream::ReadCallback(pa_stream* handle, size_t length,
40 void* user_data) {
41 static_cast<PulseAudioUnifiedStream*>(user_data)->ReadData();
42 }
43
44 PulseAudioUnifiedStream::PulseAudioUnifiedStream(
45 const AudioParameters& params,
46 const std::string& input_device_id,
47 AudioManagerBase* manager)
48 : params_(params),
49 input_device_id_(input_device_id),
50 manager_(manager),
51 pa_context_(NULL),
52 pa_mainloop_(NULL),
53 input_stream_(NULL),
54 output_stream_(NULL),
55 volume_(1.0f),
56 source_callback_(NULL) {
57 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread());
58 CHECK(params_.IsValid());
59 input_bus_ = AudioBus::Create(params_);
60 output_bus_ = AudioBus::Create(params_);
61 }
62
63 PulseAudioUnifiedStream::~PulseAudioUnifiedStream() {
64 // All internal structures should already have been freed in Close(), which
65 // calls AudioManagerBase::ReleaseOutputStream() which deletes this object.
66 DCHECK(!input_stream_);
67 DCHECK(!output_stream_);
68 DCHECK(!pa_context_);
69 DCHECK(!pa_mainloop_);
70 }
71
72 bool PulseAudioUnifiedStream::Open() {
73 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread());
74 // Prepare the recording buffers for the callbacks.
75 fifo_.reset(new media::SeekableBuffer(
76 0, kFifoSizeInPackets * params_.GetBytesPerBuffer()));
77 input_data_buffer_.reset(new uint8[params_.GetBytesPerBuffer()]);
78
79 if (!pulse::CreateOutputStream(&pa_mainloop_, &pa_context_, &output_stream_,
80 params_, &StreamNotifyCallback, NULL, this))
81 return false;
82
83 if (!pulse::CreateInputStream(pa_mainloop_, pa_context_, &input_stream_,
84 params_, input_device_id_,
85 &StreamNotifyCallback, this))
86 return false;
87
88 DCHECK(pa_mainloop_);
89 DCHECK(pa_context_);
90 DCHECK(input_stream_);
91 DCHECK(output_stream_);
92 return true;
93 }
94
95 void PulseAudioUnifiedStream::Reset() {
96 if (!pa_mainloop_) {
97 DCHECK(!input_stream_);
98 DCHECK(!output_stream_);
99 DCHECK(!pa_context_);
100 return;
101 }
102
103 {
104 AutoPulseLock auto_lock(pa_mainloop_);
105
106 // Close the input stream.
107 if (input_stream_) {
108 // Disable all the callbacks before disconnecting.
109 pa_stream_set_state_callback(input_stream_, NULL, NULL);
110 pa_stream_flush(input_stream_, NULL, NULL);
111 pa_stream_disconnect(input_stream_);
112
113 // Release PulseAudio structures.
114 pa_stream_unref(input_stream_);
115 input_stream_ = NULL;
116 }
117
118 // Close the ouput stream.
119 if (output_stream_) {
120 // Release PulseAudio output stream structures.
121 pa_stream_set_state_callback(output_stream_, NULL, NULL);
122 pa_stream_disconnect(output_stream_);
123 pa_stream_unref(output_stream_);
124 output_stream_ = NULL;
125 }
126
127 if (pa_context_) {
128 pa_context_disconnect(pa_context_);
129 pa_context_set_state_callback(pa_context_, NULL, NULL);
130 pa_context_unref(pa_context_);
131 pa_context_ = NULL;
132 }
133 }
134
135 pa_threaded_mainloop_stop(pa_mainloop_);
136 pa_threaded_mainloop_free(pa_mainloop_);
137 pa_mainloop_ = NULL;
138 }
139
140 void PulseAudioUnifiedStream::Close() {
141 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread());
142 Reset();
143
144 // Signal to the manager that we're closed and can be removed.
145 // This should be the last call in the function as it deletes "this".
146 manager_->ReleaseOutputStream(this);
147 }
148
149 void PulseAudioUnifiedStream::WriteData(size_t requested_bytes) {
150 CHECK_EQ(requested_bytes, static_cast<size_t>(params_.GetBytesPerBuffer()));
151
152 void* buffer = NULL;
153 int frames_filled = 0;
154 if (source_callback_) {
155 CHECK_GE(pa_stream_begin_write(
156 output_stream_, &buffer, &requested_bytes), 0);
157 uint32 hardware_delay = pulse::GetHardwareLatencyInBytes(
158 output_stream_, params_.sample_rate(),
159 params_.GetBytesPerFrame());
160 fifo_->Read(input_data_buffer_.get(), requested_bytes);
161 input_bus_->FromInterleaved(
162 input_data_buffer_.get(), params_.frames_per_buffer(), 2);
163
164 frames_filled = source_callback_->OnMoreIOData(
165 input_bus_.get(),
166 output_bus_.get(),
167 AudioBuffersState(0, hardware_delay));
168 }
169
170 // Zero the unfilled data so it plays back as silence.
171 if (frames_filled < output_bus_->frames()) {
172 output_bus_->ZeroFramesPartial(
173 frames_filled, output_bus_->frames() - frames_filled);
174 }
175
176 // Note: If this ever changes to output raw float the data must be clipped
177 // and sanitized since it may come from an untrusted source such as NaCl.
178 output_bus_->Scale(volume_);
179 output_bus_->ToInterleaved(
180 output_bus_->frames(), params_.bits_per_sample() / 8, buffer);
181
182 if (pa_stream_write(output_stream_, buffer, requested_bytes, NULL, 0LL,
183 PA_SEEK_RELATIVE) < 0) {
184 if (source_callback_) {
185 source_callback_->OnError(this);
186 }
187 }
188 }
189
190 void PulseAudioUnifiedStream::ReadData() {
191 do {
192 size_t length = 0;
193 const void* data = NULL;
194 pa_stream_peek(input_stream_, &data, &length);
195 if (!data || length == 0)
196 break;
197
198 fifo_->Append(reinterpret_cast<const uint8*>(data), length);
199
200 // Deliver the recording data to the renderer and drive the playout.
201 int packet_size = params_.GetBytesPerBuffer();
202 while (fifo_->forward_bytes() >= packet_size) {
203 WriteData(packet_size);
204 }
205
206 // Checks if we still have data.
207 pa_stream_drop(input_stream_);
208 } while (pa_stream_readable_size(input_stream_) > 0);
209
210 pa_threaded_mainloop_signal(pa_mainloop_, 0);
211 }
212
213 void PulseAudioUnifiedStream::Start(AudioSourceCallback* callback) {
214 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread());
215 CHECK(callback);
216 CHECK(input_stream_);
217 CHECK(output_stream_);
218 AutoPulseLock auto_lock(pa_mainloop_);
219
220 // Ensure the context and stream are ready.
221 if (pa_context_get_state(pa_context_) != PA_CONTEXT_READY &&
222 pa_stream_get_state(output_stream_) != PA_STREAM_READY &&
223 pa_stream_get_state(input_stream_) != PA_STREAM_READY) {
224 callback->OnError(this);
225 return;
226 }
227
228 source_callback_ = callback;
229
230 fifo_->Clear();
231
232 // Uncork (resume) the input stream.
233 pa_stream_set_read_callback(input_stream_, &ReadCallback, this);
234 pa_stream_readable_size(input_stream_);
235 pa_operation* operation = pa_stream_cork(input_stream_, 0, NULL, NULL);
236 WaitForOperationCompletion(pa_mainloop_, operation);
237
238 // Uncork (resume) the output stream.
239 // We use the recording stream to drive the playback, so we do not need to
240 // register the write callback using pa_stream_set_write_callback().
241 operation = pa_stream_cork(output_stream_, 0,
242 &pulse::StreamSuccessCallback, pa_mainloop_);
243 WaitForOperationCompletion(pa_mainloop_, operation);
244 }
245
246 void PulseAudioUnifiedStream::Stop() {
247 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread());
248
249 // Cork (pause) the stream. Waiting for the main loop lock will ensure
250 // outstanding callbacks have completed.
251 AutoPulseLock auto_lock(pa_mainloop_);
252
253 // Set |source_callback_| to NULL so all FulfillWriteRequest() calls which may
254 // occur while waiting on the flush and cork exit immediately.
255 source_callback_ = NULL;
256
257 // Set the read callback to NULL before flushing the stream, otherwise it
258 // will cause deadlock on the operation.
259 pa_stream_set_read_callback(input_stream_, NULL, NULL);
260 pa_operation* operation = pa_stream_flush(
261 input_stream_, &pulse::StreamSuccessCallback, pa_mainloop_);
262 WaitForOperationCompletion(pa_mainloop_, operation);
263
264 operation = pa_stream_cork(input_stream_, 1, &pulse::StreamSuccessCallback,
265 pa_mainloop_);
266 WaitForOperationCompletion(pa_mainloop_, operation);
267
268 // Flush the stream prior to cork, doing so after will cause hangs. Write
269 // callbacks are suspended while inside pa_threaded_mainloop_lock() so this
270 // is all thread safe.
271 operation = pa_stream_flush(
272 output_stream_, &pulse::StreamSuccessCallback, pa_mainloop_);
273 WaitForOperationCompletion(pa_mainloop_, operation);
274
275 operation = pa_stream_cork(output_stream_, 1, &pulse::StreamSuccessCallback,
276 pa_mainloop_);
277 WaitForOperationCompletion(pa_mainloop_, operation);
278 }
279
280 void PulseAudioUnifiedStream::SetVolume(double volume) {
281 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread());
282
283 volume_ = static_cast<float>(volume);
284 }
285
286 void PulseAudioUnifiedStream::GetVolume(double* volume) {
287 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread());
288
289 *volume = volume_;
290 }
291
292 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/pulse/pulse_unified.h ('k') | media/audio/sounds/audio_stream_handler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698