Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 // The audio stream implementation is made difficult because different methods | 5 // The audio stream implementation is made difficult because different methods |
| 6 // are available for calling depending on what state the stream is. Here is the | 6 // are available for calling depending on what state the stream is. Here is the |
| 7 // state transition table for the stream. | 7 // state transition table for the stream. |
| 8 // | 8 // |
| 9 // STATE_CREATED -> Open() -> STATE_OPENED | 9 // STATE_CREATED -> Open() -> STATE_OPENED |
| 10 // STATE_OPENED -> Start() -> STATE_STARTED | 10 // STATE_OPENED -> Start() -> STATE_STARTED |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 48 // class lock, or under a different lock to avoid unecessarily blocking other | 48 // class lock, or under a different lock to avoid unecessarily blocking other |
| 49 // threads. | 49 // threads. |
| 50 | 50 |
| 51 #include "media/audio/linux/alsa_output.h" | 51 #include "media/audio/linux/alsa_output.h" |
| 52 | 52 |
| 53 #include <algorithm> | 53 #include <algorithm> |
| 54 | 54 |
| 55 #include "base/logging.h" | 55 #include "base/logging.h" |
| 56 #include "base/stl_util-inl.h" | 56 #include "base/stl_util-inl.h" |
| 57 #include "base/time.h" | 57 #include "base/time.h" |
| 58 #include "media/audio/audio_util.h" | |
| 58 | 59 |
| 59 // Require 10ms latency from the audio device. Taken from ALSA documentation | 60 // Require 10ms latency from the audio device. Taken from ALSA documentation |
| 60 // example. | 61 // example. |
| 61 // TODO(ajwong): Figure out what this parameter actually does, and what a good | 62 // TODO(ajwong): Figure out what this parameter actually does, and what a good |
| 62 // value would be. | 63 // value would be. |
| 63 static const unsigned int kTargetLatencyMicroseconds = 10000; | 64 static const unsigned int kTargetLatencyMicroseconds = 10000; |
| 64 | 65 |
| 65 // Minimal amount of time to sleep. If any future event is expected to | 66 // Minimal amount of time to sleep. If any future event is expected to |
| 66 // execute within this timeframe, treat it as if it should execute immediately. | 67 // execute within this timeframe, treat it as if it should execute immediately. |
| 67 // | 68 // |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 82 playback_handle_(NULL), | 83 playback_handle_(NULL), |
| 83 source_callback_(NULL), | 84 source_callback_(NULL), |
| 84 playback_thread_("PlaybackThread"), | 85 playback_thread_("PlaybackThread"), |
| 85 channels_(channels), | 86 channels_(channels), |
| 86 sample_rate_(sample_rate), | 87 sample_rate_(sample_rate), |
| 87 bits_per_sample_(bits_per_sample), | 88 bits_per_sample_(bits_per_sample), |
| 88 min_buffer_frames_((min_buffer_ms * sample_rate_) / | 89 min_buffer_frames_((min_buffer_ms * sample_rate_) / |
| 89 base::Time::kMillisecondsPerSecond), | 90 base::Time::kMillisecondsPerSecond), |
| 90 packet_size_(0), | 91 packet_size_(0), |
| 91 device_write_suspended_(true), // Start suspended. | 92 device_write_suspended_(true), // Start suspended. |
| 92 resources_released_(false) { | 93 resources_released_(false), |
| 94 volume_(1.0) { | |
| 93 // Reference self to avoid accidental deletion before the message loop is | 95 // Reference self to avoid accidental deletion before the message loop is |
| 94 // done. | 96 // done. |
| 95 AddRef(); | 97 AddRef(); |
| 96 | 98 |
| 97 // Sanity check input values. | 99 // Sanity check input values. |
| 98 if (channels_ != 2) { | 100 if (channels_ != 2) { |
| 99 LOG(WARNING) << "Only 2-channel audio is supported right now."; | 101 LOG(WARNING) << "Only 2-channel audio is supported right now."; |
| 100 state_ = STATE_ERROR; | 102 state_ = STATE_ERROR; |
| 101 } | 103 } |
| 102 | 104 |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 400 // TODO(ajwong): Move to cpu@'s non-blocking audio source. | 402 // TODO(ajwong): Move to cpu@'s non-blocking audio source. |
| 401 scoped_ptr<Packet> packet; | 403 scoped_ptr<Packet> packet; |
| 402 size_t capacity = packet_size_; // Snag it for non-locked usage. | 404 size_t capacity = packet_size_; // Snag it for non-locked usage. |
| 403 { | 405 { |
| 404 AutoUnlock synchronous_data_fetch(lock_); | 406 AutoUnlock synchronous_data_fetch(lock_); |
| 405 packet.reset(new Packet(capacity)); | 407 packet.reset(new Packet(capacity)); |
| 406 size_t used = source_callback_->OnMoreData(this, packet->buffer.get(), | 408 size_t used = source_callback_->OnMoreData(this, packet->buffer.get(), |
| 407 packet->capacity); | 409 packet->capacity); |
| 408 CHECK(used <= capacity) << "Data source overran buffer. Aborting."; | 410 CHECK(used <= capacity) << "Data source overran buffer. Aborting."; |
| 409 packet->size = used; | 411 packet->size = used; |
| 412 media::AdjustVolume(packet->buffer.get(), packet->size, | |
| 413 channels_, bits_per_sample_ >> 3, | |
| 414 volume_); | |
| 410 // TODO(ajwong): Do more buffer validation here, like checking that the | 415 // TODO(ajwong): Do more buffer validation here, like checking that the |
| 411 // packet is correctly aligned to frames, etc. | 416 // packet is correctly aligned to frames, etc. |
| 412 } | 417 } |
| 413 // After reacquiring the lock, recheck state to make sure it is still | 418 // After reacquiring the lock, recheck state to make sure it is still |
| 414 // STATE_STARTED. | 419 // STATE_STARTED. |
| 415 if (state_ != STATE_STARTED) { | 420 if (state_ != STATE_STARTED) { |
| 416 return; | 421 return; |
| 417 } | 422 } |
| 418 buffered_packets_.push_back(packet.release()); | 423 buffered_packets_.push_back(packet.release()); |
| 419 | 424 |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 514 // If the memory buffer was not underrun, schedule another fill in the future. | 519 // If the memory buffer was not underrun, schedule another fill in the future. |
| 515 if (!device_write_suspended_) { | 520 if (!device_write_suspended_) { |
| 516 playback_thread_.message_loop()->PostDelayedTask( | 521 playback_thread_.message_loop()->PostDelayedTask( |
| 517 FROM_HERE, | 522 FROM_HERE, |
| 518 NewRunnableMethod(this, &AlsaPCMOutputStream::FillAlsaDeviceBuffer), | 523 NewRunnableMethod(this, &AlsaPCMOutputStream::FillAlsaDeviceBuffer), |
| 519 kTargetLatencyMicroseconds / base::Time::kMicrosecondsPerMillisecond); | 524 kTargetLatencyMicroseconds / base::Time::kMicrosecondsPerMillisecond); |
| 520 } | 525 } |
| 521 } | 526 } |
| 522 | 527 |
| 523 void AlsaPCMOutputStream::SetVolume(double left_level, double right_level) { | 528 void AlsaPCMOutputStream::SetVolume(double left_level, double right_level) { |
| 524 NOTIMPLEMENTED(); | 529 AutoLock l(lock_); |
|
fbarchard
2009/07/25 00:57:26
is this necessary for one variable?
| |
| 530 volume_ = static_cast<float>(left_level); | |
| 525 } | 531 } |
| 526 | 532 |
| 527 void AlsaPCMOutputStream::GetVolume(double* left_level, double* right_level) { | 533 void AlsaPCMOutputStream::GetVolume(double* left_level, double* right_level) { |
| 528 NOTIMPLEMENTED(); | 534 AutoLock l(lock_); |
| 535 *left_level = volume_; | |
| 536 *right_level = volume_; | |
|
fbarchard
2009/07/25 00:57:26
nit - we should really get rid of this right_level
| |
| 529 } | 537 } |
| OLD | NEW |