summaryrefslogtreecommitdiffstats
path: root/media/audio/linux
diff options
context:
space:
mode:
Diffstat (limited to 'media/audio/linux')
-rw-r--r--media/audio/linux/alsa_input.cc17
-rw-r--r--media/audio/linux/alsa_input.h2
-rw-r--r--media/audio/linux/alsa_output.cc41
-rw-r--r--media/audio/linux/alsa_output.h14
-rw-r--r--media/audio/linux/alsa_output_unittest.cc55
-rw-r--r--media/audio/linux/audio_manager_linux.cc12
-rw-r--r--media/audio/linux/audio_manager_linux.h3
7 files changed, 61 insertions, 83 deletions
diff --git a/media/audio/linux/alsa_input.cc b/media/audio/linux/alsa_input.cc
index 800be6f..13aea5b4 100644
--- a/media/audio/linux/alsa_input.cc
+++ b/media/audio/linux/alsa_input.cc
@@ -28,16 +28,14 @@ const char* AlsaPcmInputStream::kAutoSelectDevice = "";
AlsaPcmInputStream::AlsaPcmInputStream(const std::string& device_name,
const AudioParameters& params,
- int samples_per_packet,
AlsaWrapper* wrapper)
: device_name_(device_name),
params_(params),
- samples_per_packet_(samples_per_packet),
- bytes_per_packet_(samples_per_packet_ *
+ bytes_per_packet_(params.samples_per_packet *
(params.channels * params.bits_per_sample) / 8),
wrapper_(wrapper),
packet_duration_ms_(
- (samples_per_packet_ * base::Time::kMillisecondsPerSecond) /
+ (params.samples_per_packet * base::Time::kMillisecondsPerSecond) /
params.sample_rate),
callback_(NULL),
device_handle_(NULL),
@@ -147,7 +145,7 @@ void AlsaPcmInputStream::ReadAudio() {
Recover(frames);
}
- if (frames < samples_per_packet_) {
+ if (frames < params_.samples_per_packet) {
// Not enough data yet or error happened. In both cases wait for a very
// small duration before checking again.
MessageLoop::current()->PostDelayedTask(
@@ -157,15 +155,15 @@ void AlsaPcmInputStream::ReadAudio() {
return;
}
- int num_packets = frames / samples_per_packet_;
+ int num_packets = frames / params_.samples_per_packet;
while (num_packets--) {
int frames_read = wrapper_->PcmReadi(device_handle_, audio_packet_.get(),
- samples_per_packet_);
- if (frames_read == samples_per_packet_) {
+ params_.samples_per_packet);
+ if (frames_read == params_.samples_per_packet) {
callback_->OnData(this, audio_packet_.get(), bytes_per_packet_);
} else {
LOG(WARNING) << "PcmReadi returning less than expected frames: "
- << frames_read << " vs. " << samples_per_packet_
+ << frames_read << " vs. " << params_.samples_per_packet
<< ". Dropping this packet.";
}
}
@@ -213,4 +211,3 @@ void AlsaPcmInputStream::HandleError(const char* method, int error) {
LOG(WARNING) << method << ": " << wrapper_->StrError(error);
callback_->OnError(this, error);
}
-
diff --git a/media/audio/linux/alsa_input.h b/media/audio/linux/alsa_input.h
index d0ed07d..94af7df 100644
--- a/media/audio/linux/alsa_input.h
+++ b/media/audio/linux/alsa_input.h
@@ -30,7 +30,6 @@ class AlsaPcmInputStream : public AudioInputStream {
// |kAutoSelectDevice|.
AlsaPcmInputStream(const std::string& device_name,
const AudioParameters& params,
- int samples_per_packet,
AlsaWrapper* wrapper);
virtual ~AlsaPcmInputStream();
@@ -53,7 +52,6 @@ class AlsaPcmInputStream : public AudioInputStream {
std::string device_name_;
AudioParameters params_;
- int samples_per_packet_;
int bytes_per_packet_;
AlsaWrapper* wrapper_;
int packet_duration_ms_; // Length of each recorded packet in milliseconds.
diff --git a/media/audio/linux/alsa_output.cc b/media/audio/linux/alsa_output.cc
index 410ed15f..6df30b4 100644
--- a/media/audio/linux/alsa_output.cc
+++ b/media/audio/linux/alsa_output.cc
@@ -232,15 +232,18 @@ AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name,
bytes_per_sample_(params.bits_per_sample / 8),
bytes_per_frame_(channels_ * params.bits_per_sample / 8),
should_downmix_(false),
- latency_micros_(0),
- micros_per_packet_(0),
+ packet_size_(params.GetPacketSize()),
+ micros_per_packet_(FramesToMicros(
+ params.samples_per_packet, sample_rate_)),
+ latency_micros_(std::max(AlsaPcmOutputStream::kMinLatencyMicros,
+ micros_per_packet_ * 2)),
bytes_per_output_frame_(bytes_per_frame_),
alsa_buffer_frames_(0),
stop_stream_(false),
wrapper_(wrapper),
manager_(manager),
playback_handle_(NULL),
- frames_per_packet_(0),
+ frames_per_packet_(packet_size_ / bytes_per_frame_),
client_thread_loop_(MessageLoop::current()),
message_loop_(message_loop) {
@@ -271,13 +274,9 @@ AlsaPcmOutputStream::~AlsaPcmOutputStream() {
// where the stream is not always stopped and closed, causing this to fail.
}
-bool AlsaPcmOutputStream::Open(uint32 packet_size) {
+bool AlsaPcmOutputStream::Open() {
DCHECK_EQ(MessageLoop::current(), client_thread_loop_);
- DCHECK_EQ(0U, packet_size % bytes_per_frame_)
- << "Buffers should end on a frame boundary. Frame size: "
- << bytes_per_frame_;
-
if (shared_data_.state() == kInError) {
return false;
}
@@ -294,7 +293,7 @@ bool AlsaPcmOutputStream::Open(uint32 packet_size) {
shared_data_.TransitionTo(kIsOpened);
message_loop_->PostTask(
FROM_HERE,
- NewRunnableMethod(this, &AlsaPcmOutputStream::OpenTask, packet_size));
+ NewRunnableMethod(this, &AlsaPcmOutputStream::OpenTask));
return true;
}
@@ -308,10 +307,6 @@ void AlsaPcmOutputStream::Close() {
NOTREACHED() << "Unable to transition Closed.";
}
- // Signal our successful close, and disassociate the source callback.
- shared_data_.OnClose(this);
- shared_data_.set_source_callback(NULL);
-
message_loop_->PostTask(
FROM_HERE,
NewRunnableMethod(this, &AlsaPcmOutputStream::CloseTask));
@@ -340,6 +335,9 @@ void AlsaPcmOutputStream::Start(AudioSourceCallback* callback) {
void AlsaPcmOutputStream::Stop() {
DCHECK_EQ(MessageLoop::current(), client_thread_loop_);
+ // Reset the callback, so that it is not called anymore.
+ shared_data_.set_source_callback(NULL);
+
shared_data_.TransitionTo(kIsStopped);
}
@@ -355,18 +353,10 @@ void AlsaPcmOutputStream::GetVolume(double* volume) {
*volume = shared_data_.volume();
}
-void AlsaPcmOutputStream::OpenTask(uint32 packet_size) {
+void AlsaPcmOutputStream::OpenTask() {
DCHECK_EQ(message_loop_, MessageLoop::current());
- // Initialize the configuration variables.
- packet_size_ = packet_size;
- frames_per_packet_ = packet_size_ / bytes_per_frame_;
-
// Try to open the device.
- micros_per_packet_ =
- FramesToMicros(packet_size / bytes_per_frame_, sample_rate_);
- latency_micros_ = std::max(AlsaPcmOutputStream::kMinLatencyMicros,
- micros_per_packet_ * 2);
if (requested_device_name_ == kAutoSelectDevice) {
playback_handle_ = AutoSelectDevice(latency_micros_);
if (playback_handle_)
@@ -920,13 +910,6 @@ uint32 AlsaPcmOutputStream::SharedData::OnMoreData(
return 0;
}
-void AlsaPcmOutputStream::SharedData::OnClose(AudioOutputStream* stream) {
- AutoLock l(lock_);
- if (source_callback_) {
- source_callback_->OnClose(stream);
- }
-}
-
void AlsaPcmOutputStream::SharedData::OnError(AudioOutputStream* stream,
int code) {
AutoLock l(lock_);
diff --git a/media/audio/linux/alsa_output.h b/media/audio/linux/alsa_output.h
index bd1ecb9..25ff055 100644
--- a/media/audio/linux/alsa_output.h
+++ b/media/audio/linux/alsa_output.h
@@ -24,6 +24,13 @@
// threading assumptions at the top of the implementation file to avoid
// introducing race conditions between tasks posted to the internal
// message_loop, and the thread calling the public APIs.
+//
+// TODO(sergeyu): AlsaPcmOutputStream is always created and used from the
+// audio thread (i.e. |client_thread_loop_| and |message_loop_| always point
+// to the same thread), so it doesn't need to be thread-safe anymore.
+//
+// TODO(sergeyu): Remove refcounter from AlsaPcmOutputStream and use
+// ScopedRunnableMethodFactory to create tasks.
#ifndef MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_
#define MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_
@@ -79,7 +86,7 @@ class AlsaPcmOutputStream :
MessageLoop* message_loop);
// Implementation of AudioOutputStream.
- virtual bool Open(uint32 packet_size);
+ virtual bool Open();
virtual void Close();
virtual void Start(AudioSourceCallback* callback);
virtual void Stop();
@@ -127,7 +134,7 @@ class AlsaPcmOutputStream :
friend std::ostream& operator<<(std::ostream& os, InternalState);
// Various tasks that complete actions started in the public API.
- void OpenTask(uint32 packet_size);
+ void OpenTask();
void StartTask();
void CloseTask();
@@ -179,7 +186,6 @@ class AlsaPcmOutputStream :
// using a deleted callback.
uint32 OnMoreData(AudioOutputStream* stream, uint8* dest,
uint32 max_size, AudioBuffersState buffers_state);
- void OnClose(AudioOutputStream* stream);
void OnError(AudioOutputStream* stream, int code);
// Changes the AudioSourceCallback to proxy calls to. Pass in NULL to
@@ -211,9 +217,9 @@ class AlsaPcmOutputStream :
// Device configuration data. Populated after OpenTask() completes.
std::string device_name_;
bool should_downmix_;
- uint32 latency_micros_;
uint32 packet_size_;
uint32 micros_per_packet_;
+ uint32 latency_micros_;
uint32 bytes_per_output_frame_;
uint32 alsa_buffer_frames_;
diff --git a/media/audio/linux/alsa_output_unittest.cc b/media/audio/linux/alsa_output_unittest.cc
index cd50919..83c0eff 100644
--- a/media/audio/linux/alsa_output_unittest.cc
+++ b/media/audio/linux/alsa_output_unittest.cc
@@ -70,7 +70,6 @@ class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback {
MOCK_METHOD4(OnMoreData, uint32(AudioOutputStream* stream,
uint8* dest, uint32 max_size,
AudioBuffersState buffers_state));
- MOCK_METHOD1(OnClose, void(AudioOutputStream* stream));
MOCK_METHOD2(OnError, void(AudioOutputStream* stream, int code));
};
@@ -96,16 +95,20 @@ class MockAudioManagerLinux : public AudioManagerLinux {
class AlsaPcmOutputStreamTest : public testing::Test {
protected:
AlsaPcmOutputStreamTest() {
- test_stream_ = CreateStreamWithChannels(kTestChannels);
+ test_stream_ = CreateStream(kTestChannels);
}
virtual ~AlsaPcmOutputStreamTest() {
test_stream_ = NULL;
}
- AlsaPcmOutputStream* CreateStreamWithChannels(int channels) {
+ AlsaPcmOutputStream* CreateStream(int channels) {
+ return CreateStream(channels, kTestFramesPerPacket);
+ }
+
+ AlsaPcmOutputStream* CreateStream(int channels, int32 samples_per_packet) {
AudioParameters params(kTestFormat, channels, kTestSampleRate,
- kTestBitsPerSample);
+ kTestBitsPerSample, samples_per_packet);
return new AlsaPcmOutputStream(kTestDeviceName,
params,
&mock_alsa_wrapper_,
@@ -197,18 +200,19 @@ TEST_F(AlsaPcmOutputStreamTest, ConstructedState) {
test_stream_->shared_data_.state());
// Should support mono.
- test_stream_ = CreateStreamWithChannels(1);
+ test_stream_ = CreateStream(1);
EXPECT_EQ(AlsaPcmOutputStream::kCreated,
test_stream_->shared_data_.state());
// Should support multi-channel.
- test_stream_ = CreateStreamWithChannels(3);
+ test_stream_ = CreateStream(3);
EXPECT_EQ(AlsaPcmOutputStream::kCreated,
test_stream_->shared_data_.state());
// Bad bits per sample.
AudioParameters bad_bps_params(kTestFormat, kTestChannels,
- kTestSampleRate, kTestBitsPerSample - 1);
+ kTestSampleRate, kTestBitsPerSample - 1,
+ kTestFramesPerPacket);
test_stream_ = new AlsaPcmOutputStream(kTestDeviceName,
bad_bps_params,
&mock_alsa_wrapper_,
@@ -220,7 +224,7 @@ TEST_F(AlsaPcmOutputStreamTest, ConstructedState) {
// Bad format.
AudioParameters bad_format_params(
AudioParameters::AUDIO_LAST_FORMAT, kTestChannels,
- kTestSampleRate, kTestBitsPerSample);
+ kTestSampleRate, kTestBitsPerSample, kTestFramesPerPacket);
test_stream_ = new AlsaPcmOutputStream(kTestDeviceName,
bad_format_params,
&mock_alsa_wrapper_,
@@ -235,8 +239,6 @@ TEST_F(AlsaPcmOutputStreamTest, LatencyFloor) {
static_cast<double>(1000000) / kTestSampleRate;
const double kPacketFramesInMinLatency =
AlsaPcmOutputStream::kMinLatencyMicros / kMicrosPerFrame / 2.0;
- const int kMinLatencyPacketSize =
- static_cast<int>(kPacketFramesInMinLatency * kTestBytesPerFrame);
// Test that packets which would cause a latency under less than
// AlsaPcmOutputStream::kMinLatencyMicros will get clipped to
@@ -253,7 +255,8 @@ TEST_F(AlsaPcmOutputStreamTest, LatencyFloor) {
SetArgumentPointee<2>(kTestFramesPerPacket / 2),
Return(0)));
- ASSERT_TRUE(test_stream_->Open(kMinLatencyPacketSize));
+ test_stream_ = CreateStream(kTestChannels, kPacketFramesInMinLatency);
+ ASSERT_TRUE(test_stream_->Open());
message_loop_.RunAllPending();
// Now close it and test that everything was released.
@@ -268,15 +271,9 @@ TEST_F(AlsaPcmOutputStreamTest, LatencyFloor) {
Mock::VerifyAndClear(&mock_manager_);
// Test that having more packets ends up with a latency based on packet size.
- const int kOverMinLatencyPacketSize =
- (kPacketFramesInMinLatency + 1) * kTestBytesPerFrame;
- int64 expected_micros = 2 *
- AlsaPcmOutputStream::FramesToMicros(
- kOverMinLatencyPacketSize / kTestBytesPerFrame,
- kTestSampleRate);
-
- // Recreate the stream to reset the state.
- test_stream_ = CreateStreamWithChannels(kTestChannels);
+ const int kOverMinLatencyPacketSize = kPacketFramesInMinLatency + 1;
+ int64 expected_micros = 2 * AlsaPcmOutputStream::FramesToMicros(
+ kOverMinLatencyPacketSize, kTestSampleRate);
EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
.WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), Return(0)));
@@ -288,7 +285,8 @@ TEST_F(AlsaPcmOutputStreamTest, LatencyFloor) {
SetArgumentPointee<2>(kTestFramesPerPacket / 2),
Return(0)));
- ASSERT_TRUE(test_stream_->Open(kOverMinLatencyPacketSize));
+ test_stream_ = CreateStream(kTestChannels, kOverMinLatencyPacketSize);
+ ASSERT_TRUE(test_stream_->Open());
message_loop_.RunAllPending();
// Now close it and test that everything was released.
@@ -332,7 +330,7 @@ TEST_F(AlsaPcmOutputStreamTest, OpenClose) {
Return(0)));
// Open the stream.
- ASSERT_TRUE(test_stream_->Open(kTestPacketSize));
+ ASSERT_TRUE(test_stream_->Open());
message_loop_.RunAllPending();
EXPECT_EQ(AlsaPcmOutputStream::kIsOpened,
@@ -363,7 +361,7 @@ TEST_F(AlsaPcmOutputStreamTest, PcmOpenFailed) {
.WillOnce(Return(kDummyMessage));
// Open still succeeds since PcmOpen is delegated to another thread.
- ASSERT_TRUE(test_stream_->Open(kTestPacketSize));
+ ASSERT_TRUE(test_stream_->Open());
ASSERT_EQ(AlsaPcmOutputStream::kIsOpened,
test_stream_->shared_data_.state());
ASSERT_FALSE(test_stream_->stop_stream_);
@@ -397,7 +395,7 @@ TEST_F(AlsaPcmOutputStreamTest, PcmSetParamsFailed) {
// If open fails, the stream stays in kCreated because it has effectively had
// no changes.
- ASSERT_TRUE(test_stream_->Open(kTestPacketSize));
+ ASSERT_TRUE(test_stream_->Open());
EXPECT_EQ(AlsaPcmOutputStream::kIsOpened,
test_stream_->shared_data_.state());
ASSERT_FALSE(test_stream_->stop_stream_);
@@ -431,7 +429,7 @@ TEST_F(AlsaPcmOutputStreamTest, StartStop) {
Return(0)));
// Open the stream.
- ASSERT_TRUE(test_stream_->Open(kTestPacketSize));
+ ASSERT_TRUE(test_stream_->Open());
message_loop_.RunAllPending();
// Expect Device setup.
@@ -469,7 +467,6 @@ TEST_F(AlsaPcmOutputStreamTest, StartStop) {
message_loop_.RunAllPending();
EXPECT_CALL(mock_manager_, ReleaseOutputStream(test_stream_.get()));
- EXPECT_CALL(mock_callback, OnClose(test_stream_.get()));
EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
.WillOnce(Return(0));
EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle))
@@ -684,7 +681,7 @@ TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_DeviceSelect) {
.WillRepeatedly(Invoke(EchoHint));
- test_stream_ = CreateStreamWithChannels(i);
+ test_stream_ = CreateStream(i);
EXPECT_TRUE(test_stream_->AutoSelectDevice(i));
EXPECT_EQ(kExpectedDownmix[i], test_stream_->should_downmix_);
@@ -734,7 +731,7 @@ TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_FallbackDevices) {
EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(fourth_try.c_str()), _, _))
.WillOnce(Return(kTestFailedErrno));
- test_stream_ = CreateStreamWithChannels(5);
+ test_stream_ = CreateStream(5);
EXPECT_FALSE(test_stream_->AutoSelectDevice(5));
}
@@ -752,7 +749,7 @@ TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_HintFail) {
EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno))
.WillOnce(Return(kDummyMessage));
- test_stream_ = CreateStreamWithChannels(5);
+ test_stream_ = CreateStream(5);
EXPECT_TRUE(test_stream_->AutoSelectDevice(5));
EXPECT_TRUE(test_stream_->should_downmix_);
}
diff --git a/media/audio/linux/audio_manager_linux.cc b/media/audio/linux/audio_manager_linux.cc
index b22ec44..fdf8044 100644
--- a/media/audio/linux/audio_manager_linux.cc
+++ b/media/audio/linux/audio_manager_linux.cc
@@ -17,7 +17,6 @@
namespace {
const int kMaxInputChannels = 2;
-const int kMaxSamplesPerPacket = media::Limits::kMaxSampleRate;
} // namespace
@@ -37,7 +36,7 @@ AudioOutputStream* AudioManagerLinux::MakeAudioOutputStream(
// Early return for testing hook. Do this before checking for
// |initialized_|.
if (params.format == AudioParameters::AUDIO_MOCK) {
- return FakeAudioOutputStream::MakeFakeStream();
+ return FakeAudioOutputStream::MakeFakeStream(params);
}
if (!initialized()) {
@@ -60,13 +59,12 @@ AudioOutputStream* AudioManagerLinux::MakeAudioOutputStream(
}
AudioInputStream* AudioManagerLinux::MakeAudioInputStream(
- AudioParameters params, int samples_per_packet) {
- if (!params.IsValid() || params.channels > kMaxInputChannels ||
- samples_per_packet < 0 || samples_per_packet > kMaxSamplesPerPacket)
+ AudioParameters params) {
+ if (!params.IsValid() || params.channels > kMaxInputChannels)
return NULL;
if (params.format == AudioParameters::AUDIO_MOCK) {
- return FakeAudioInputStream::MakeFakeStream(params, samples_per_packet);
+ return FakeAudioInputStream::MakeFakeStream(params);
} else if (params.format != AudioParameters::AUDIO_PCM_LINEAR) {
return NULL;
}
@@ -81,7 +79,7 @@ AudioInputStream* AudioManagerLinux::MakeAudioInputStream(
}
AlsaPcmInputStream* stream = new AlsaPcmInputStream(
- device_name, params, samples_per_packet, wrapper_.get());
+ device_name, params, wrapper_.get());
return stream;
}
diff --git a/media/audio/linux/audio_manager_linux.h b/media/audio/linux/audio_manager_linux.h
index afa60af..a5ba17cf 100644
--- a/media/audio/linux/audio_manager_linux.h
+++ b/media/audio/linux/audio_manager_linux.h
@@ -27,8 +27,7 @@ class AudioManagerLinux : public AudioManagerBase {
virtual bool HasAudioOutputDevices();
virtual bool HasAudioInputDevices();
virtual AudioOutputStream* MakeAudioOutputStream(AudioParameters params);
- virtual AudioInputStream* MakeAudioInputStream(
- AudioParameters params, int samples_per_packet);
+ virtual AudioInputStream* MakeAudioInputStream(AudioParameters params);
virtual void MuteAll();
virtual void UnMuteAll();