Commit 18359a3a authored by xians@chromium.org's avatar xians@chromium.org

Switch the input code to use AudioBlockFifo.

It saves two memcpy and quite some intermedia AudioBus code.

Also, this CL corrects a mistake in https://codereview.chromium.org/389623002/ by using FromInterleavedPartial() instead of FromInterleaved().

BUG=393199
TEST=bots and webrtc loopback test: https://apprtc.appspot.com

Review URL: https://codereview.chromium.org/396263004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284477 0039d316-1c4b-4281-b951-d872f2087c98
parent c2693b64
......@@ -14,8 +14,8 @@
#include "content/renderer/media/webrtc_audio_capturer.h"
#include "content/renderer/render_frame_impl.h"
#include "media/audio/audio_output_device.h"
#include "media/base/audio_block_fifo.h"
#include "media/base/audio_bus.h"
#include "media/base/audio_fifo.h"
namespace content {
......@@ -42,8 +42,10 @@ int WebRtcLocalAudioRenderer::Render(
// Provide data by reading from the FIFO if the FIFO contains enough
// to fulfill the request.
if (loopback_fifo_->frames() >= audio_bus->frames()) {
loopback_fifo_->Consume(audio_bus, 0, audio_bus->frames());
if (loopback_fifo_->available_blocks()) {
const media::AudioBus* audio_data = loopback_fifo_->Consume();
DCHECK_EQ(audio_data->frames(), audio_bus->frames());
audio_data->CopyTo(audio_bus);
} else {
audio_bus->Zero();
// This warning is perfectly safe if it happens for the first audio
......@@ -70,14 +72,8 @@ void WebRtcLocalAudioRenderer::OnData(const int16* audio_data,
return;
// Push captured audio to FIFO so it can be read by a local sink.
if (loopback_fifo_->frames() + number_of_frames <=
loopback_fifo_->max_frames()) {
scoped_ptr<media::AudioBus> audio_source = media::AudioBus::Create(
number_of_channels, number_of_frames);
audio_source->FromInterleaved(audio_data,
audio_source->frames(),
sizeof(audio_data[0]));
loopback_fifo_->Push(audio_source.get());
if (loopback_fifo_->GetUnfilledFrames() >= number_of_frames) {
loopback_fifo_->Push(audio_data, number_of_frames, sizeof(audio_data[0]));
const base::TimeTicks now = base::TimeTicks::Now();
total_render_time_ += now - last_render_time_;
......@@ -311,8 +307,10 @@ void WebRtcLocalAudioRenderer::ReconfigureSink(
// in case since these tests were performed on a 16 core, 64GB Win 7
// machine. We could also add some sort of error notifier in this area if
// the FIFO overflows.
media::AudioFifo* new_fifo = new media::AudioFifo(
params.channels(), 10 * params.frames_per_buffer());
const int blocks_of_buffers =
10 * params.frames_per_buffer() / sink_params_.frames_per_buffer() + 1;
media::AudioBlockFifo* new_fifo = new media::AudioBlockFifo(
params.channels(), sink_params_.frames_per_buffer(), blocks_of_buffers);
base::AutoLock auto_lock(thread_lock_);
loopback_fifo_.reset(new_fifo);
......
......@@ -21,7 +21,7 @@
namespace media {
class AudioBus;
class AudioFifo;
class AudioBlockFifo;
class AudioOutputDevice;
class AudioParameters;
}
......@@ -124,7 +124,7 @@ class CONTENT_EXPORT WebRtcLocalAudioRenderer
scoped_refptr<media::AudioOutputDevice> sink_;
// Contains copies of captured audio frames.
scoped_ptr<media::AudioFifo> loopback_fifo_;
scoped_ptr<media::AudioBlockFifo> loopback_fifo_;
// Stores last time a render callback was received. The time difference
// between a new time stamp and this value can be used to derive the
......
......@@ -11,11 +11,13 @@
#include "base/mac/mac_logging.h"
#include "media/audio/mac/audio_manager_mac.h"
#include "media/base/audio_bus.h"
#include "media/base/audio_fifo.h"
#include "media/base/data_buffer.h"
namespace media {
// Number of blocks of buffers used in the |fifo_|.
const int kNumberOfBlocksBufferInFifo = 2;
static std::ostream& operator<<(std::ostream& os,
const AudioStreamBasicDescription& format) {
os << "sample rate : " << format.mSampleRate << std::endl
......@@ -44,8 +46,9 @@ AUAudioInputStream::AUAudioInputStream(AudioManagerMac* manager,
started_(false),
hardware_latency_frames_(0),
number_of_channels_in_frame_(0),
audio_bus_(media::AudioBus::Create(input_params)),
audio_wrapper_(media::AudioBus::Create(input_params)) {
fifo_(input_params.channels(),
number_of_frames_,
kNumberOfBlocksBufferInFifo) {
DCHECK(manager_);
// Set up the desired (output) format specified by the client.
......@@ -494,43 +497,17 @@ OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames,
if (!audio_data)
return kAudioUnitErr_InvalidElement;
if (number_of_frames != number_of_frames_) {
// Create a FIFO on the fly to handle any discrepancies in callback rates.
if (!fifo_) {
VLOG(1) << "Audio frame size changed from " << number_of_frames_ << " to "
<< number_of_frames << "; adding FIFO to compensate.";
fifo_.reset(new AudioFifo(
format_.mChannelsPerFrame, number_of_frames_ + number_of_frames));
}
if (audio_wrapper_->frames() != static_cast<int>(number_of_frames)) {
audio_wrapper_ = media::AudioBus::Create(format_.mChannelsPerFrame,
number_of_frames);
}
}
// Copy captured (and interleaved) data into deinterleaved audio bus.
audio_wrapper_->FromInterleaved(
audio_data, audio_wrapper_->frames(), format_.mBitsPerChannel / 8);
// When FIFO does not kick in, data will be directly passed to the callback.
if (!fifo_) {
CHECK_EQ(audio_wrapper_->frames(), static_cast<int>(number_of_frames_));
sink_->OnData(
this, audio_wrapper_.get(), capture_delay_bytes, normalized_volume);
return noErr;
}
// Copy captured (and interleaved) data into FIFO.
fifo_.Push(audio_data, number_of_frames, format_.mBitsPerChannel / 8);
// Compensate the audio delay caused by the FIFO.
capture_delay_bytes += fifo_->frames() * format_.mBytesPerFrame;
fifo_->Push(audio_wrapper_.get());
if (fifo_->frames() >= static_cast<int>(number_of_frames_)) {
// Consume the audio from the FIFO.
fifo_->Consume(audio_bus_.get(), 0, audio_bus_->frames());
DCHECK(fifo_->frames() < static_cast<int>(number_of_frames_));
// Consume and deliver the data when the FIFO has a block of available data.
while (fifo_.available_blocks()) {
const AudioBus* audio_bus = fifo_.Consume();
DCHECK_EQ(audio_bus->frames(), static_cast<int>(number_of_frames_));
sink_->OnData(
this, audio_bus_.get(), capture_delay_bytes, normalized_volume);
// Compensate the audio delay caused by the FIFO.
capture_delay_bytes += fifo_.GetAvailableFrames() * format_.mBytesPerFrame;
sink_->OnData(this, audio_bus, capture_delay_bytes, normalized_volume);
}
return noErr;
......
......@@ -45,11 +45,11 @@
#include "media/audio/agc_audio_stream.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_parameters.h"
#include "media/base/audio_block_fifo.h"
namespace media {
class AudioBus;
class AudioFifo;
class AudioManagerMac;
class DataBuffer;
......@@ -148,20 +148,12 @@ class AUAudioInputStream : public AgcAudioStream<AudioInputStream> {
// when querying the volume of each channel.
int number_of_channels_in_frame_;
// Dynamically allocated FIFO used to accumulates recorded data when
// CoreAudio delivers non-requested frame size of data.
scoped_ptr<media::AudioFifo> fifo_;
// FIFO used to accumulates recorded data.
media::AudioBlockFifo fifo_;
// Used to defer Start() to workaround http://crbug.com/160920.
base::CancelableClosure deferred_start_cb_;
// Audio bus used for storage of deinterleaved data for the OnData callback.
scoped_ptr<media::AudioBus> audio_bus_;
// Audio bus used to convert interleaved data to deinterleaved data before
// storing data to FIFO or delivering data via OnData callback.
scoped_ptr<media::AudioBus> audio_wrapper_;
DISALLOW_COPY_AND_ASSIGN(AUAudioInputStream);
};
......
......@@ -9,13 +9,15 @@
#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,
......@@ -28,6 +30,9 @@ PulseAudioInputStream::PulseAudioInputStream(AudioManagerPulse* audio_manager,
channels_(0),
volume_(0.0),
stream_started_(false),
fifo_(params.channels(),
params.frames_per_buffer(),
kNumberOfBlocksBufferInFifo),
pa_mainloop_(mainloop),
pa_context_(context),
handle_(NULL),
......@@ -35,7 +40,6 @@ PulseAudioInputStream::PulseAudioInputStream(AudioManagerPulse* audio_manager,
DCHECK(mainloop);
DCHECK(context);
CHECK(params_.IsValid());
audio_bus_ = AudioBus::Create(params_);
}
PulseAudioInputStream::~PulseAudioInputStream() {
......@@ -54,8 +58,6 @@ bool PulseAudioInputStream::Open() {
DCHECK(handle_);
buffer_.reset(new media::SeekableBuffer(0, 2 * params_.GetBytesPerBuffer()));
audio_data_buffer_.reset(new uint8[params_.GetBytesPerBuffer()]);
return true;
}
......@@ -74,7 +76,7 @@ void PulseAudioInputStream::Start(AudioInputCallback* callback) {
// Clean up the old buffer.
pa_stream_drop(handle_);
buffer_->Clear();
fifo_.Clear();
// Start the streaming.
callback_ = callback;
......@@ -265,23 +267,19 @@ void PulseAudioInputStream::ReadData() {
if (!data || length == 0)
break;
buffer_->Append(reinterpret_cast<const uint8*>(data), length);
const int number_of_frames = length / params_.GetBytesPerFrame();
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);
audio_bus_->FromInterleaved(audio_data_buffer_.get(),
audio_bus_->frames(),
params_.bits_per_sample() / 8);
callback_->OnData(
this, audio_bus_.get(), 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 "
......
......@@ -12,6 +12,7 @@
#include "media/audio/audio_device_name.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_parameters.h"
#include "media/base/audio_block_fifo.h"
struct pa_context;
struct pa_source_info;
......@@ -21,7 +22,6 @@ struct pa_threaded_mainloop;
namespace media {
class AudioManagerPulse;
class SeekableBuffer;
class PulseAudioInputStream : public AgcAudioStream<AudioInputStream> {
public:
......@@ -61,11 +61,7 @@ class PulseAudioInputStream : public AgcAudioStream<AudioInputStream> {
bool stream_started_;
// Holds the data from the OS.
scoped_ptr<media::SeekableBuffer> buffer_;
// Temporary storage for recorded data. It gets a packet of data from
// |buffer_| and deliver the data to OnData() callback.
scoped_ptr<uint8[]> audio_data_buffer_;
AudioBlockFifo fifo_;
// PulseAudio API structs.
pa_threaded_mainloop* pa_mainloop_; // Weak.
......@@ -75,8 +71,6 @@ class PulseAudioInputStream : public AgcAudioStream<AudioInputStream> {
// Flag indicating the state of the context has been changed.
bool context_state_changed_;
scoped_ptr<AudioBus> audio_bus_;
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(PulseAudioInputStream);
......
......@@ -44,7 +44,8 @@ void AudioBlockFifo::Push(const void* source,
std::min(block_frames_ - write_pos_, frames_to_push);
// Deinterleave the content to the FIFO and update the |write_pos_|.
current_block->FromInterleaved(source_ptr, push_frames, bytes_per_sample);
current_block->FromInterleavedPartial(
source_ptr, write_pos_, push_frames, bytes_per_sample);
write_pos_ = (write_pos_ + push_frames) % block_frames_;
if (!write_pos_) {
// The current block is completely filled, increment |write_block_| and
......@@ -55,6 +56,7 @@ void AudioBlockFifo::Push(const void* source,
source_ptr += push_frames * bytes_per_sample * current_block->channels();
frames_to_push -= push_frames;
DCHECK_GE(frames_to_push, 0);
}
}
......@@ -73,6 +75,10 @@ void AudioBlockFifo::Clear() {
available_blocks_ = 0;
}
int AudioBlockFifo::GetAvailableFrames() const {
return available_blocks_ * block_frames_ + write_pos_;
}
int AudioBlockFifo::GetUnfilledFrames() const {
const int unfilled_frames =
(audio_blocks_.size() - available_blocks_) * block_frames_ - write_pos_;
......
......@@ -39,6 +39,9 @@ class MEDIA_EXPORT AudioBlockFifo {
// Number of available block of memory ready to be consumed in the FIFO.
int available_blocks() const { return available_blocks_; }
// Number of available frames of data in the FIFO.
int GetAvailableFrames() const;
// Number of unfilled frames in the whole FIFO.
int GetUnfilledFrames() const;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment