OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/audio/pulse/pulse_output.h" | 5 #include "media/audio/pulse/pulse_output.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "media/audio/audio_parameters.h" | 9 #include "media/audio/audio_parameters.h" |
10 #include "media/audio/audio_util.h" | 10 #include "media/audio/audio_util.h" |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 *state = pa_context_get_state(context); | 121 *state = pa_context_get_state(context); |
122 } | 122 } |
123 | 123 |
124 // static | 124 // static |
125 void PulseAudioOutputStream::WriteRequestCallback(pa_stream* playback_handle, | 125 void PulseAudioOutputStream::WriteRequestCallback(pa_stream* playback_handle, |
126 size_t length, | 126 size_t length, |
127 void* stream_addr) { | 127 void* stream_addr) { |
128 PulseAudioOutputStream* stream = | 128 PulseAudioOutputStream* stream = |
129 reinterpret_cast<PulseAudioOutputStream*>(stream_addr); | 129 reinterpret_cast<PulseAudioOutputStream*>(stream_addr); |
130 | 130 |
131 DCHECK_EQ(stream->manager_->GetMessageLoop(), MessageLoop::current()); | 131 DCHECK(stream->manager_->GetMessageLoop()->BelongsToCurrentThread()); |
132 | 132 |
133 stream->write_callback_handled_ = true; | 133 stream->write_callback_handled_ = true; |
134 | 134 |
135 // Fulfill write request. | 135 // Fulfill write request. |
136 stream->FulfillWriteRequest(length); | 136 stream->FulfillWriteRequest(length); |
137 } | 137 } |
138 | 138 |
139 PulseAudioOutputStream::PulseAudioOutputStream(const AudioParameters& params, | 139 PulseAudioOutputStream::PulseAudioOutputStream(const AudioParameters& params, |
140 AudioManagerPulse* manager) | 140 AudioManagerPulse* manager) |
141 : channel_layout_(params.channel_layout), | 141 : channel_layout_(params.channel_layout()), |
142 channel_count_(ChannelLayoutToChannelCount(channel_layout_)), | 142 channel_count_(ChannelLayoutToChannelCount(channel_layout_)), |
143 sample_format_(BitsToPASampleFormat(params.bits_per_sample)), | 143 sample_format_(BitsToPASampleFormat(params.bits_per_sample())), |
144 sample_rate_(params.sample_rate), | 144 sample_rate_(params.sample_rate()), |
145 bytes_per_frame_(params.channels * params.bits_per_sample / 8), | 145 bytes_per_frame_(params.GetBytesPerFrame()), |
146 manager_(manager), | 146 manager_(manager), |
147 pa_context_(NULL), | 147 pa_context_(NULL), |
148 pa_mainloop_(NULL), | 148 pa_mainloop_(NULL), |
149 playback_handle_(NULL), | 149 playback_handle_(NULL), |
150 packet_size_(params.GetPacketSize()), | 150 packet_size_(params.GetBytesPerBuffer()), |
151 frames_per_packet_(packet_size_ / bytes_per_frame_), | 151 frames_per_packet_(packet_size_ / bytes_per_frame_), |
152 client_buffer_(NULL), | 152 client_buffer_(NULL), |
153 volume_(1.0f), | 153 volume_(1.0f), |
154 stream_stopped_(true), | 154 stream_stopped_(true), |
155 write_callback_handled_(false), | 155 write_callback_handled_(false), |
156 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | 156 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), |
157 source_callback_(NULL) { | 157 source_callback_(NULL) { |
158 DCHECK_EQ(manager_->GetMessageLoop(), MessageLoop::current()); | 158 DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); |
159 | 159 |
160 // TODO(slock): Sanity check input values. | 160 // TODO(slock): Sanity check input values. |
161 } | 161 } |
162 | 162 |
163 PulseAudioOutputStream::~PulseAudioOutputStream() { | 163 PulseAudioOutputStream::~PulseAudioOutputStream() { |
164 // All internal structures should already have been freed in Close(), | 164 // All internal structures should already have been freed in Close(), |
165 // which calls AudioManagerPulse::Release which deletes this object. | 165 // which calls AudioManagerPulse::Release which deletes this object. |
166 DCHECK(!playback_handle_); | 166 DCHECK(!playback_handle_); |
167 DCHECK(!pa_context_); | 167 DCHECK(!pa_context_); |
168 DCHECK(!pa_mainloop_); | 168 DCHECK(!pa_mainloop_); |
169 } | 169 } |
170 | 170 |
171 bool PulseAudioOutputStream::Open() { | 171 bool PulseAudioOutputStream::Open() { |
172 DCHECK_EQ(manager_->GetMessageLoop(), MessageLoop::current()); | 172 DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); |
173 | 173 |
174 // TODO(slock): Possibly move most of this to an OpenPlaybackDevice function | 174 // TODO(slock): Possibly move most of this to an OpenPlaybackDevice function |
175 // in a new class 'pulse_util', like alsa_util. | 175 // in a new class 'pulse_util', like alsa_util. |
176 | 176 |
177 // Create a mainloop API and connect to the default server. | 177 // Create a mainloop API and connect to the default server. |
178 pa_mainloop_ = pa_mainloop_new(); | 178 pa_mainloop_ = pa_mainloop_new(); |
179 pa_mainloop_api* pa_mainloop_api = pa_mainloop_get_api(pa_mainloop_); | 179 pa_mainloop_api* pa_mainloop_api = pa_mainloop_get_api(pa_mainloop_); |
180 pa_context_ = pa_context_new(pa_mainloop_api, "Chromium"); | 180 pa_context_ = pa_context_new(pa_mainloop_api, "Chromium"); |
181 pa_context_state_t pa_context_state = PA_CONTEXT_UNCONNECTED; | 181 pa_context_state_t pa_context_state = PA_CONTEXT_UNCONNECTED; |
182 pa_context_connect(pa_context_, NULL, PA_CONTEXT_NOFLAGS, NULL); | 182 pa_context_connect(pa_context_, NULL, PA_CONTEXT_NOFLAGS, NULL); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 if (pa_mainloop_) { | 265 if (pa_mainloop_) { |
266 pa_mainloop_free(pa_mainloop_); | 266 pa_mainloop_free(pa_mainloop_); |
267 pa_mainloop_ = NULL; | 267 pa_mainloop_ = NULL; |
268 } | 268 } |
269 | 269 |
270 // Release internal buffer. | 270 // Release internal buffer. |
271 client_buffer_.reset(); | 271 client_buffer_.reset(); |
272 } | 272 } |
273 | 273 |
274 void PulseAudioOutputStream::Close() { | 274 void PulseAudioOutputStream::Close() { |
275 DCHECK_EQ(manager_->GetMessageLoop(), MessageLoop::current()); | 275 DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); |
276 | 276 |
277 Reset(); | 277 Reset(); |
278 | 278 |
279 // Signal to the manager that we're closed and can be removed. | 279 // Signal to the manager that we're closed and can be removed. |
280 // This should be the last call in the function as it deletes "this". | 280 // This should be the last call in the function as it deletes "this". |
281 manager_->ReleaseOutputStream(this); | 281 manager_->ReleaseOutputStream(this); |
282 } | 282 } |
283 | 283 |
284 void PulseAudioOutputStream::WaitForWriteRequest() { | 284 void PulseAudioOutputStream::WaitForWriteRequest() { |
285 DCHECK_EQ(manager_->GetMessageLoop(), MessageLoop::current()); | 285 DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); |
286 | 286 |
287 if (stream_stopped_) | 287 if (stream_stopped_) |
288 return; | 288 return; |
289 | 289 |
290 // Iterate the PulseAudio mainloop. If PulseAudio doesn't request a write, | 290 // Iterate the PulseAudio mainloop. If PulseAudio doesn't request a write, |
291 // post a task to iterate the mainloop again. | 291 // post a task to iterate the mainloop again. |
292 write_callback_handled_ = false; | 292 write_callback_handled_ = false; |
293 pa_mainloop_iterate(pa_mainloop_, 1, NULL); | 293 pa_mainloop_iterate(pa_mainloop_, 1, NULL); |
294 if (!write_callback_handled_) { | 294 if (!write_callback_handled_) { |
295 manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind( | 295 manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind( |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 } | 330 } |
331 | 331 |
332 void PulseAudioOutputStream::FulfillWriteRequest(size_t requested_bytes) { | 332 void PulseAudioOutputStream::FulfillWriteRequest(size_t requested_bytes) { |
333 // If we have enough data to fulfill the request, we can finish the write. | 333 // If we have enough data to fulfill the request, we can finish the write. |
334 if (stream_stopped_) | 334 if (stream_stopped_) |
335 return; | 335 return; |
336 | 336 |
337 // Request more data from the source until we can fulfill the request or | 337 // Request more data from the source until we can fulfill the request or |
338 // fail to receive anymore data. | 338 // fail to receive anymore data. |
339 bool buffering_successful = true; | 339 bool buffering_successful = true; |
340 while (client_buffer_->forward_bytes() < requested_bytes && | 340 size_t forward_bytes = static_cast<size_t>(client_buffer_->forward_bytes()); |
341 buffering_successful) { | 341 while (forward_bytes < requested_bytes && buffering_successful) { |
342 buffering_successful = BufferPacketFromSource(); | 342 buffering_successful = BufferPacketFromSource(); |
343 } | 343 } |
344 | 344 |
345 size_t bytes_written = 0; | 345 size_t bytes_written = 0; |
346 if (client_buffer_->forward_bytes() > 0) { | 346 if (client_buffer_->forward_bytes() > 0) { |
347 // Try to fulfill the request by writing as many of the requested bytes to | 347 // Try to fulfill the request by writing as many of the requested bytes to |
348 // the stream as we can. | 348 // the stream as we can. |
349 WriteToStream(requested_bytes, &bytes_written); | 349 WriteToStream(requested_bytes, &bytes_written); |
350 } | 350 } |
351 | 351 |
(...skipping 10 matching lines...) Expand all Loading... |
362 &PulseAudioOutputStream::WaitForWriteRequest, | 362 &PulseAudioOutputStream::WaitForWriteRequest, |
363 weak_factory_.GetWeakPtr())); | 363 weak_factory_.GetWeakPtr())); |
364 } | 364 } |
365 } | 365 } |
366 | 366 |
367 void PulseAudioOutputStream::WriteToStream(size_t bytes_to_write, | 367 void PulseAudioOutputStream::WriteToStream(size_t bytes_to_write, |
368 size_t* bytes_written) { | 368 size_t* bytes_written) { |
369 *bytes_written = 0; | 369 *bytes_written = 0; |
370 while (*bytes_written < bytes_to_write) { | 370 while (*bytes_written < bytes_to_write) { |
371 const uint8* chunk; | 371 const uint8* chunk; |
372 size_t chunk_size; | 372 int chunk_size; |
373 | 373 |
374 // Stop writing if there is no more data available. | 374 // Stop writing if there is no more data available. |
375 if (!client_buffer_->GetCurrentChunk(&chunk, &chunk_size)) | 375 if (!client_buffer_->GetCurrentChunk(&chunk, &chunk_size)) |
376 break; | 376 break; |
377 | 377 |
378 // Write data to stream. | 378 // Write data to stream. |
379 pa_stream_write(playback_handle_, chunk, chunk_size, | 379 pa_stream_write(playback_handle_, chunk, chunk_size, |
380 NULL, 0LL, PA_SEEK_RELATIVE); | 380 NULL, 0LL, PA_SEEK_RELATIVE); |
381 client_buffer_->Seek(chunk_size); | 381 client_buffer_->Seek(chunk_size); |
382 *bytes_written += chunk_size; | 382 *bytes_written += chunk_size; |
383 } | 383 } |
384 } | 384 } |
385 | 385 |
386 void PulseAudioOutputStream::Start(AudioSourceCallback* callback) { | 386 void PulseAudioOutputStream::Start(AudioSourceCallback* callback) { |
387 DCHECK_EQ(manager_->GetMessageLoop(), MessageLoop::current()); | 387 DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); |
388 CHECK(callback); | 388 CHECK(callback); |
389 DLOG_IF(ERROR, !playback_handle_) | 389 DLOG_IF(ERROR, !playback_handle_) |
390 << "Open() has not been called successfully"; | 390 << "Open() has not been called successfully"; |
391 if (!playback_handle_) | 391 if (!playback_handle_) |
392 return; | 392 return; |
393 | 393 |
394 source_callback_ = callback; | 394 source_callback_ = callback; |
395 | 395 |
396 // Clear buffer, it might still have data in it. | 396 // Clear buffer, it might still have data in it. |
397 client_buffer_->Clear(); | 397 client_buffer_->Clear(); |
398 stream_stopped_ = false; | 398 stream_stopped_ = false; |
399 | 399 |
400 // Start playback. | 400 // Start playback. |
401 manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind( | 401 manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind( |
402 &PulseAudioOutputStream::WaitForWriteRequest, | 402 &PulseAudioOutputStream::WaitForWriteRequest, |
403 weak_factory_.GetWeakPtr())); | 403 weak_factory_.GetWeakPtr())); |
404 } | 404 } |
405 | 405 |
406 void PulseAudioOutputStream::Stop() { | 406 void PulseAudioOutputStream::Stop() { |
407 DCHECK_EQ(manager_->GetMessageLoop(), MessageLoop::current()); | 407 DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); |
408 | 408 |
409 stream_stopped_ = true; | 409 stream_stopped_ = true; |
410 } | 410 } |
411 | 411 |
412 void PulseAudioOutputStream::SetVolume(double volume) { | 412 void PulseAudioOutputStream::SetVolume(double volume) { |
413 DCHECK_EQ(manager_->GetMessageLoop(), MessageLoop::current()); | 413 DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); |
414 | 414 |
415 volume_ = static_cast<float>(volume); | 415 volume_ = static_cast<float>(volume); |
416 } | 416 } |
417 | 417 |
418 void PulseAudioOutputStream::GetVolume(double* volume) { | 418 void PulseAudioOutputStream::GetVolume(double* volume) { |
419 DCHECK_EQ(manager_->GetMessageLoop(), MessageLoop::current()); | 419 DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); |
420 | 420 |
421 *volume = volume_; | 421 *volume = volume_; |
422 } | 422 } |
423 | 423 |
424 uint32 PulseAudioOutputStream::RunDataCallback( | 424 uint32 PulseAudioOutputStream::RunDataCallback( |
425 uint8* dest, uint32 max_size, AudioBuffersState buffers_state) { | 425 uint8* dest, uint32 max_size, AudioBuffersState buffers_state) { |
426 if (source_callback_) | 426 if (source_callback_) |
427 return source_callback_->OnMoreData(dest, max_size, buffers_state); | 427 return source_callback_->OnMoreData(dest, max_size, buffers_state); |
428 | 428 |
429 return 0; | 429 return 0; |
430 } | 430 } |
431 | 431 |
432 } // namespace media | 432 } // namespace media |
OLD | NEW |