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