| 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 |