Commit ebae1d3f authored by xians's avatar xians Committed by Commit bot

Used native deinterleaved and float point format for the input streams.

If we call GetProperty of kAudioUnitProperty_StreamFormat before setting the format, the device will report kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved as the native format of the device, which is the same as the output.

This patch changes the format to use kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved to open the device, so that we will avoid format flipping back and forth. Hope this optimization will help increase the stability of the input audio on Mac.

TBR=DaleCurtis@chromium.org

BUG=404884
TEST=media_unittests && https://webrtc.googlecode.com/svn-history/r5497/trunk/samples/js/demos/html/pc1.html, https://www.google.com/intl/en/chrome/demos/speech.html

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

Cr-Commit-Position: refs/heads/master@{#292636}
parent 22aa58e6
......@@ -45,10 +45,10 @@
#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 AudioBlockFifo;
class AudioBus;
class AudioManagerMac;
class DataBuffer;
......@@ -78,7 +78,7 @@ class AUAudioInputStream : public AgcAudioStream<AudioInputStream> {
bool started() const { return started_; }
AudioUnit audio_unit() { return audio_unit_; }
AudioBufferList* audio_buffer_list() { return &audio_buffer_list_; }
AudioBufferList* audio_buffer_list() { return audio_buffer_list_.get(); }
private:
// AudioOutputUnit callback.
......@@ -90,7 +90,8 @@ class AUAudioInputStream : public AgcAudioStream<AudioInputStream> {
AudioBufferList* io_data);
// Pushes recorded data to consumer of the input audio stream.
OSStatus Provide(UInt32 number_of_frames, AudioBufferList* io_data,
OSStatus Provide(UInt32 number_of_frames,
AudioBufferList* io_data,
const AudioTimeStamp* time_stamp);
// Gets the fixed capture hardware latency and store it during initialization.
......@@ -132,11 +133,11 @@ class AUAudioInputStream : public AgcAudioStream<AudioInputStream> {
AudioDeviceID input_device_id_;
// Provides a mechanism for encapsulating one or more buffers of audio data.
AudioBufferList audio_buffer_list_;
scoped_ptr<AudioBufferList, base::FreeDeleter> audio_buffer_list_;
// Temporary storage for recorded data. The InputProc() renders into this
// array as soon as a frame of the desired buffer size has been recorded.
scoped_ptr<uint8[]> audio_data_buffer_;
scoped_ptr<float, base::AlignedFreeDeleter> audio_data_buffer_;
// True after successfull Start(), false after successful Stop().
bool started_;
......@@ -148,8 +149,12 @@ class AUAudioInputStream : public AgcAudioStream<AudioInputStream> {
// when querying the volume of each channel.
int number_of_channels_in_frame_;
// FIFO used to accumulates recorded data.
media::AudioBlockFifo fifo_;
// Dynamically allocated FIFO used when CoreAudio asks for unexpected frame
// sizes.
scoped_ptr<AudioBlockFifo> fifo_;
// AudioBus wrapper for delievering data via AudioSourceCallback::OnData().
scoped_ptr<AudioBus> audio_wrapper_;
// Used to defer Start() to workaround http://crbug.com/160920.
base::CancelableClosure deferred_start_cb_;
......
......@@ -22,7 +22,8 @@ AudioBlockFifo::AudioBlockFifo(int channels, int frames, int blocks)
}
}
AudioBlockFifo::~AudioBlockFifo() {}
AudioBlockFifo::~AudioBlockFifo() {
}
void AudioBlockFifo::Push(const void* source,
int frames,
......@@ -46,20 +47,39 @@ void AudioBlockFifo::Push(const void* source,
// Deinterleave the content to the FIFO and update the |write_pos_|.
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
// |available_blocks_|.
write_block_ = (write_block_ + 1) % audio_blocks_.size();
++available_blocks_;
}
UpdatePosition(push_frames);
source_ptr += push_frames * bytes_per_sample * current_block->channels();
frames_to_push -= push_frames;
DCHECK_GE(frames_to_push, 0);
}
}
void AudioBlockFifo::Push(const AudioBus* source) {
DCHECK(source);
DCHECK_LT(available_blocks_, static_cast<int>(audio_blocks_.size()));
int source_start_frame = 0;
while (source_start_frame < source->frames()) {
// Get the current write block.
AudioBus* current_block = audio_blocks_[write_block_];
DCHECK_EQ(source->channels(), current_block->channels());
// Figure out what segment sizes we need when adding the new content to
// the FIFO.
const int push_frames = std::min(block_frames_ - write_pos_,
source->frames() - source_start_frame);
// Copy the data to FIFO.
source->CopyPartialFramesTo(
source_start_frame, push_frames, write_pos_, current_block);
UpdatePosition(push_frames);
source_start_frame += push_frames;
DCHECK_LE(source_start_frame, source->frames());
}
}
const AudioBus* AudioBlockFifo::Consume() {
DCHECK(available_blocks_);
AudioBus* audio_bus = audio_blocks_[read_block_];
......@@ -86,4 +106,14 @@ int AudioBlockFifo::GetUnfilledFrames() const {
return unfilled_frames;
}
void AudioBlockFifo::UpdatePosition(int push_frames) {
write_pos_ = (write_pos_ + push_frames) % block_frames_;
if (!write_pos_) {
// The current block is completely filled, increment |write_block_| and
// |available_blocks_|.
write_block_ = (write_block_ + 1) % audio_blocks_.size();
++available_blocks_;
}
}
} // namespace media
......@@ -28,6 +28,10 @@ class MEDIA_EXPORT AudioBlockFifo {
// Push() will crash if the allocated space is insufficient.
void Push(const void* source, int frames, int bytes_per_sample);
// Pushes the audio data from |source| to the FIFO.
// Push() will crash if the allocated space is insufficient.
void Push(const AudioBus* source);
// Consumes a block of audio from the FIFO. Returns an AudioBus which
// contains the consumed audio data to avoid copying.
// Consume() will crash if the FIFO does not contain a block of data.
......@@ -46,6 +50,9 @@ class MEDIA_EXPORT AudioBlockFifo {
int GetUnfilledFrames() const;
private:
// Helper method to update the indexes in Push methods.
void UpdatePosition(int push_frames);
// The actual FIFO is a vector of audio buses.
ScopedVector<AudioBus> audio_blocks_;
......
......@@ -8,17 +8,38 @@
namespace media {
class AudioBlockFifoTest : public testing::Test {
public:
protected:
AudioBlockFifoTest() {}
virtual ~AudioBlockFifoTest() {}
void PushAndVerify(AudioBlockFifo* fifo, int frames_to_push,
int channels, int block_frames, int max_frames) {
private:
DISALLOW_COPY_AND_ASSIGN(AudioBlockFifoTest);
};
class AudioBlockFifoFormatTest : public AudioBlockFifoTest,
public testing::WithParamInterface<bool> {
protected:
void PushAndVerify(AudioBlockFifo* fifo,
int frames_to_push,
int channels,
int block_frames,
int max_frames) {
const int bytes_per_sample = 2;
const int data_byte_size = bytes_per_sample * channels * frames_to_push;
if (GetParam()) {
scoped_ptr<media::AudioBus> data =
AudioBus::Create(channels, frames_to_push);
for (int filled_frames = max_frames - fifo->GetUnfilledFrames();
filled_frames + frames_to_push <= max_frames;) {
fifo->Push(data.get());
filled_frames += frames_to_push;
EXPECT_EQ(max_frames - filled_frames, fifo->GetUnfilledFrames());
EXPECT_EQ(static_cast<int>(filled_frames / block_frames),
fifo->available_blocks());
}
} else {
scoped_ptr<uint8[]> data(new uint8[data_byte_size]);
memset(data.get(), 0, data_byte_size);
for (int filled_frames = max_frames - fifo->GetUnfilledFrames();
filled_frames + frames_to_push <= max_frames;) {
fifo->Push(data.get(), frames_to_push, bytes_per_sample);
......@@ -28,9 +49,7 @@ class AudioBlockFifoTest : public testing::Test {
fifo->available_blocks());
}
}
private:
DISALLOW_COPY_AND_ASSIGN(AudioBlockFifoTest);
}
};
// Verify that construction works as intended.
......@@ -44,7 +63,7 @@ TEST_F(AudioBlockFifoTest, Construct) {
}
// Pushes audio bus objects to/from a FIFO up to different degrees.
TEST_F(AudioBlockFifoTest, Push) {
TEST_P(AudioBlockFifoFormatTest, Push) {
const int channels = 2;
const int frames = 128;
const int blocks = 2;
......@@ -65,7 +84,7 @@ TEST_F(AudioBlockFifoTest, Push) {
// Perform a sequence of Push/Consume calls to different degrees, and verify
// things are correct.
TEST_F(AudioBlockFifoTest, PushAndConsume) {
TEST_P(AudioBlockFifoFormatTest, PushAndConsume) {
const int channels = 2;
const int frames = 441;
const int blocks = 4;
......@@ -100,10 +119,9 @@ TEST_F(AudioBlockFifoTest, PushAndConsume) {
fifo.Clear();
int new_push_frames = 128;
// Change the input frame and try to fill up the FIFO.
PushAndVerify(&fifo, new_push_frames, channels, frames,
frames * blocks);
PushAndVerify(&fifo, new_push_frames, channels, frames, frames * blocks);
EXPECT_TRUE(fifo.GetUnfilledFrames() != 0);
EXPECT_TRUE(fifo.available_blocks() == blocks -1);
EXPECT_TRUE(fifo.available_blocks() == blocks - 1);
// Consume all the existing filled blocks of data.
while (fifo.available_blocks()) {
......@@ -122,14 +140,13 @@ TEST_F(AudioBlockFifoTest, PushAndConsume) {
// Completely fill up the buffer again.
new_push_frames = frames * blocks - remain_frames;
PushAndVerify(&fifo, new_push_frames, channels, frames,
frames * blocks);
PushAndVerify(&fifo, new_push_frames, channels, frames, frames * blocks);
EXPECT_TRUE(fifo.GetUnfilledFrames() == 0);
EXPECT_TRUE(fifo.available_blocks() == blocks);
}
// Perform a sequence of Push/Consume calls to a 1 block FIFO.
TEST_F(AudioBlockFifoTest, PushAndConsumeOneBlockFifo) {
TEST_P(AudioBlockFifoFormatTest, PushAndConsumeOneBlockFifo) {
static const int channels = 2;
static const int frames = 441;
static const int blocks = 1;
......@@ -146,4 +163,8 @@ TEST_F(AudioBlockFifoTest, PushAndConsumeOneBlockFifo) {
EXPECT_TRUE(fifo.GetUnfilledFrames() == frames);
}
INSTANTIATE_TEST_CASE_P(AudioBlockFifoTests,
AudioBlockFifoFormatTest,
::testing::Values(false, true));
} // namespace media
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