diff options
Diffstat (limited to 'media/audio/linux')
-rw-r--r-- | media/audio/linux/alsa_input.cc | 17 | ||||
-rw-r--r-- | media/audio/linux/alsa_input.h | 2 | ||||
-rw-r--r-- | media/audio/linux/alsa_output.cc | 41 | ||||
-rw-r--r-- | media/audio/linux/alsa_output.h | 14 | ||||
-rw-r--r-- | media/audio/linux/alsa_output_unittest.cc | 55 | ||||
-rw-r--r-- | media/audio/linux/audio_manager_linux.cc | 12 | ||||
-rw-r--r-- | media/audio/linux/audio_manager_linux.h | 3 |
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(); |