#include "base/logging.h"
#include "media/audio/pulse/audio_manager_pulse.h"
#include "media/audio/pulse/pulse_util.h"
-#include "media/base/seekable_buffer.h"
namespace media {
using pulse::AutoPulseLock;
using pulse::WaitForOperationCompletion;
+// Number of blocks of buffers used in the |fifo_|.
+const int kNumberOfBlocksBufferInFifo = 2;
+
PulseAudioInputStream::PulseAudioInputStream(AudioManagerPulse* audio_manager,
const std::string& device_name,
const AudioParameters& params,
channels_(0),
volume_(0.0),
stream_started_(false),
+ fifo_(params.channels(),
+ params.frames_per_buffer(),
+ kNumberOfBlocksBufferInFifo),
pa_mainloop_(mainloop),
pa_context_(context),
handle_(NULL),
context_state_changed_(false) {
DCHECK(mainloop);
DCHECK(context);
+ CHECK(params_.IsValid());
}
PulseAudioInputStream::~PulseAudioInputStream() {
DCHECK(handle_);
- buffer_.reset(new media::SeekableBuffer(0, 2 * params_.GetBytesPerBuffer()));
- audio_data_buffer_.reset(new uint8[params_.GetBytesPerBuffer()]);
return true;
}
// Clean up the old buffer.
pa_stream_drop(handle_);
- buffer_->Clear();
+ fifo_.Clear();
// Start the streaming.
callback_ = callback;
operation = pa_stream_cork(handle_, 1, &pulse::StreamSuccessCallback,
pa_mainloop_);
WaitForOperationCompletion(pa_mainloop_, operation);
+ callback_ = NULL;
}
void PulseAudioInputStream::Close() {
if (handle_) {
// Disable all the callbacks before disconnecting.
pa_stream_set_state_callback(handle_, NULL, NULL);
- pa_stream_flush(handle_, NULL, NULL);
+ pa_operation* operation = pa_stream_flush(
+ handle_, &pulse::StreamSuccessCallback, pa_mainloop_);
+ WaitForOperationCompletion(pa_mainloop_, operation);
if (pa_stream_get_state(handle_) != PA_STREAM_UNCONNECTED)
pa_stream_disconnect(handle_);
}
}
- if (callback_)
- callback_->OnClose(this);
-
// Signal to the manager that we're closed and can be removed.
// This should be the last call in the function as it deletes "this".
audio_manager_->ReleaseInputStream(this);
if (!data || length == 0)
break;
- buffer_->Append(reinterpret_cast<const uint8*>(data), length);
+ const int number_of_frames = length / params_.GetBytesPerFrame();
+ if (number_of_frames > fifo_.GetUnfilledFrames()) {
+ // Dynamically increase capacity to the FIFO to handle larger buffer got
+ // from Pulse.
+ const int increase_blocks_of_buffer = static_cast<int>(
+ (number_of_frames - fifo_.GetUnfilledFrames()) /
+ params_.frames_per_buffer()) + 1;
+ fifo_.IncreaseCapacity(increase_blocks_of_buffer);
+ }
+
+ fifo_.Push(data, number_of_frames, params_.bits_per_sample() / 8);
// Checks if we still have data.
pa_stream_drop(handle_);
} while (pa_stream_readable_size(handle_) > 0);
- int packet_size = params_.GetBytesPerBuffer();
- while (buffer_->forward_bytes() >= packet_size) {
- buffer_->Read(audio_data_buffer_.get(), packet_size);
- callback_->OnData(this, audio_data_buffer_.get(), packet_size,
- hardware_delay, normalized_volume);
+ while (fifo_.available_blocks()) {
+ const AudioBus* audio_bus = fifo_.Consume();
- if (buffer_->forward_bytes() < packet_size)
- break;
+ // Compensate the audio delay caused by the FIFO.
+ hardware_delay += fifo_.GetAvailableFrames() * params_.GetBytesPerFrame();
+ callback_->OnData(this, audio_bus, hardware_delay, normalized_volume);
- // TODO(xians): Remove once PPAPI is using circular buffers.
- DVLOG(1) << "OnData is being called consecutively, sleep 5ms to "
- << "wait until render consumes the data";
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5));
+ // Sleep 5ms to wait until render consumes the data in order to avoid
+ // back to back OnData() method.
+ if (fifo_.available_blocks())
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5));
}
pa_threaded_mainloop_signal(pa_mainloop_, 0);