summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/audio/audio_output_controller_unittest.cc2
-rw-r--r--media/audio/audio_output_mixer.cc50
-rw-r--r--media/audio/audio_util.cc15
-rw-r--r--media/audio/audio_util.h3
-rw-r--r--media/audio/win/audio_manager_win.cc5
-rw-r--r--media/audio/win/audio_output_win_unittest.cc53
6 files changed, 70 insertions, 58 deletions
diff --git a/media/audio/audio_output_controller_unittest.cc b/media/audio/audio_output_controller_unittest.cc
index f40a9ae..6fe2499 100644
--- a/media/audio/audio_output_controller_unittest.cc
+++ b/media/audio/audio_output_controller_unittest.cc
@@ -196,7 +196,7 @@ TEST_F(AudioOutputControllerTest, PlayPausePlayClose) {
MockAudioOutputControllerSyncReader sync_reader;
EXPECT_CALL(sync_reader, UpdatePendingBytes(_))
- .Times(AtLeast(2));
+ .Times(AtLeast(1));
EXPECT_CALL(sync_reader, Read(_, kHardwareBufferSize))
.WillRepeatedly(DoAll(SignalEvent(&event), Return(4)));
EXPECT_CALL(sync_reader, DataReady())
diff --git a/media/audio/audio_output_mixer.cc b/media/audio/audio_output_mixer.cc
index edce4ea..542db78 100644
--- a/media/audio/audio_output_mixer.cc
+++ b/media/audio/audio_output_mixer.cc
@@ -47,6 +47,8 @@ bool AudioOutputMixer::OpenStream() {
}
pending_bytes_ = 0; // Just in case.
physical_stream_.reset(stream);
+ physical_stream_->SetVolume(1.0);
+ physical_stream_->Start(this);
close_timer_.Reset();
return true;
}
@@ -64,46 +66,24 @@ bool AudioOutputMixer::StartStream(
double volume = 0.0;
stream_proxy->GetVolume(&volume);
- bool should_start = proxies_.empty();
- {
- base::AutoLock lock(lock_);
- ProxyData* proxy_data = &proxies_[stream_proxy];
- proxy_data->audio_source_callback = callback;
- proxy_data->volume = volume;
- proxy_data->pending_bytes = 0;
- }
- // We cannot start physical stream under the lock,
- // OnMoreData() would try acquiring it...
- if (should_start) {
- physical_stream_->SetVolume(1.0);
- physical_stream_->Start(this);
- }
+
+ base::AutoLock lock(lock_);
+ ProxyData* proxy_data = &proxies_[stream_proxy];
+ proxy_data->audio_source_callback = callback;
+ proxy_data->volume = volume;
+ proxy_data->pending_bytes = 0;
return true;
}
void AudioOutputMixer::StopStream(AudioOutputProxy* stream_proxy) {
DCHECK_EQ(MessageLoop::current(), message_loop_);
- // Because of possible deadlock we cannot stop physical stream under the lock
- // (physical_stream_->Stop() can call OnError(), and it acquires the lock to
- // iterate through proxies), so acquire the lock, update proxy list, release
- // the lock, and only then stop physical stream if necessary.
- bool stop_physical_stream = false;
- {
- base::AutoLock lock(lock_);
- ProxyMap::iterator it = proxies_.find(stream_proxy);
- if (it != proxies_.end()) {
- proxies_.erase(it);
- stop_physical_stream = proxies_.empty();
- }
- }
- if (physical_stream_.get()) {
- if (stop_physical_stream) {
- physical_stream_->Stop();
- pending_bytes_ = 0; // Just in case.
- }
+ base::AutoLock lock(lock_);
+ ProxyMap::iterator it = proxies_.find(stream_proxy);
+ if (it != proxies_.end())
+ proxies_.erase(it);
+ if (physical_stream_.get())
close_timer_.Reset();
- }
}
void AudioOutputMixer::StreamVolumeSet(AudioOutputProxy* stream_proxy,
@@ -144,8 +124,10 @@ void AudioOutputMixer::Shutdown() {
void AudioOutputMixer::ClosePhysicalStream() {
DCHECK_EQ(MessageLoop::current(), message_loop_);
- if (proxies_.empty() && physical_stream_.get() != NULL)
+ if (proxies_.empty() && physical_stream_.get() != NULL) {
+ physical_stream_->Stop();
physical_stream_.release()->Close();
+ }
}
// AudioSourceCallback implementation.
diff --git a/media/audio/audio_util.cc b/media/audio/audio_util.cc
index 23aad0f..4035d28 100644
--- a/media/audio/audio_util.cc
+++ b/media/audio/audio_util.cc
@@ -21,6 +21,7 @@
#include "base/shared_memory.h"
#include "base/time.h"
#if defined(OS_WIN)
+#include "base/sys_info.h"
#include "base/win/windows_version.h"
#include "media/audio/audio_manager_base.h"
#endif
@@ -519,6 +520,20 @@ bool IsWASAPISupported() {
return base::win::GetVersion() >= base::win::VERSION_VISTA;
}
+int NumberOfWaveOutBuffers() {
+ // Simple heuristic: use 3 buffers on single-core system or on Vista,
+ // 2 otherwise.
+ // Entire Windows audio stack was rewritten for Windows Vista, and wave out
+ // API is simulated on top of new API, so there is noticeable performance
+ // degradation compared to Windows XP. Part of regression was fixed in
+ // Windows 7. Maybe it is fixed in Vista Serice Pack, but let's be cautious.
+ if ((base::SysInfo::NumberOfProcessors() < 2) ||
+ (base::win::GetVersion() == base::win::VERSION_VISTA)) {
+ return 3;
+ }
+ return 2;
+}
+
#endif
} // namespace media
diff --git a/media/audio/audio_util.h b/media/audio/audio_util.h
index df5683f..4ac0ef6 100644
--- a/media/audio/audio_util.h
+++ b/media/audio/audio_util.h
@@ -132,6 +132,9 @@ MEDIA_EXPORT bool IsUnknownDataSize(base::SharedMemory* shared_memory,
// sometimes check was written incorrectly, so move into separate function.
MEDIA_EXPORT bool IsWASAPISupported();
+// Returns number of buffers to be used by wave out.
+MEDIA_EXPORT int NumberOfWaveOutBuffers();
+
#endif // defined(OS_WIN)
} // namespace media
diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc
index 93dcf2f..38c4615 100644
--- a/media/audio/win/audio_manager_win.cc
+++ b/media/audio/win/audio_manager_win.cc
@@ -244,7 +244,10 @@ AudioOutputStream* AudioManagerWin::MakeLinearOutputStream(
if (params.channels() > kWinMaxChannels)
return NULL;
- return new PCMWaveOutAudioOutputStream(this, params, 3, WAVE_MAPPER);
+ return new PCMWaveOutAudioOutputStream(this,
+ params,
+ media::NumberOfWaveOutBuffers(),
+ WAVE_MAPPER);
}
// Factory for the implementations of AudioOutputStream for
diff --git a/media/audio/win/audio_output_win_unittest.cc b/media/audio/win/audio_output_win_unittest.cc
index 4066643..d954093 100644
--- a/media/audio/win/audio_output_win_unittest.cc
+++ b/media/audio/win/audio_output_win_unittest.cc
@@ -76,7 +76,7 @@ class TestSourceBasic : public AudioOutputStream::AudioSourceCallback {
int had_error_;
};
-const int kNumBuffers = 3;
+const int kMaxNumBuffers = 3;
// Specializes TestSourceBasic to detect that the AudioStream is using
// triple buffering correctly.
class TestSourceTripleBuffer : public TestSourceBasic {
@@ -92,14 +92,14 @@ class TestSourceTripleBuffer : public TestSourceBasic {
AudioBuffersState buffers_state) {
// Call the base, which increments the callback_count_.
TestSourceBasic::OnMoreData(dest, max_size, buffers_state);
- if (callback_count() % kNumBuffers == 2) {
+ if (callback_count() % NumberOfWaveOutBuffers() == 2) {
set_error(!CompareExistingIfNotNULL(2, dest));
- } else if (callback_count() % kNumBuffers == 1) {
+ } else if (callback_count() % NumberOfWaveOutBuffers() == 1) {
set_error(!CompareExistingIfNotNULL(1, dest));
} else {
set_error(!CompareExistingIfNotNULL(0, dest));
}
- if (callback_count() > kNumBuffers) {
+ if (callback_count() > kMaxNumBuffers) {
set_error(buffer_address_[0] == buffer_address_[1]);
set_error(buffer_address_[1] == buffer_address_[2]);
}
@@ -114,7 +114,7 @@ class TestSourceTripleBuffer : public TestSourceBasic {
return (entry == address);
}
- void* buffer_address_[kNumBuffers];
+ void* buffer_address_[kMaxNumBuffers];
};
// Specializes TestSourceBasic to simulate a source that blocks for some time
@@ -129,7 +129,7 @@ class TestSourceLaggy : public TestSourceBasic {
AudioBuffersState buffers_state) {
// Call the base, which increments the callback_count_.
TestSourceBasic::OnMoreData(dest, max_size, buffers_state);
- if (callback_count() > kNumBuffers) {
+ if (callback_count() > kMaxNumBuffers) {
::Sleep(lag_in_ms_);
}
return max_size;
@@ -312,7 +312,7 @@ TEST(WinAudioTest, PCMWaveStreamTripleBuffer) {
EXPECT_TRUE(oas->Open());
oas->Start(&test_triple_buffer);
::Sleep(300);
- EXPECT_GT(test_triple_buffer.callback_count(), kNumBuffers);
+ EXPECT_GT(test_triple_buffer.callback_count(), kMaxNumBuffers);
EXPECT_FALSE(test_triple_buffer.had_error());
oas->Stop();
::Sleep(500);
@@ -600,28 +600,37 @@ TEST(WinAudioTest, PCMWaveStreamPendingBytes) {
uint32 bytes_100_ms = samples_100_ms * 2;
- // We expect the amount of pending bytes will reaching 2 times of
- // |bytes_100_ms| because the audio output stream has a triple buffer scheme.
+ // Audio output stream has either a double or triple buffer scheme.
+ // We expect the amount of pending bytes will reaching up to 2 times of
+ // |bytes_100_ms| depending on number of buffers used.
// From that it would decrease as we are playing the data but not providing
// new one. And then we will try to provide zero data so the amount of
// pending bytes will go down and eventually read zero.
InSequence s;
+
EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms,
Field(&AudioBuffersState::pending_bytes, 0)))
.WillOnce(Return(bytes_100_ms));
- EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms,
- Field(&AudioBuffersState::pending_bytes,
- bytes_100_ms)))
- .WillOnce(Return(bytes_100_ms));
- EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms,
- Field(&AudioBuffersState::pending_bytes,
- 2 * bytes_100_ms)))
- .WillOnce(Return(bytes_100_ms));
- EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms,
- Field(&AudioBuffersState::pending_bytes,
- 2 * bytes_100_ms)))
- .Times(AnyNumber())
- .WillRepeatedly(Return(0));
+ switch (NumberOfWaveOutBuffers()) {
+ case 2:
+ break; // Calls are the same as at end of 3-buffer scheme.
+ case 3:
+ EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms,
+ Field(&AudioBuffersState::pending_bytes,
+ bytes_100_ms)))
+ .WillOnce(Return(bytes_100_ms));
+ EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms,
+ Field(&AudioBuffersState::pending_bytes,
+ 2 * bytes_100_ms)))
+ .WillOnce(Return(bytes_100_ms));
+ EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms,
+ Field(&AudioBuffersState::pending_bytes,
+ 2 * bytes_100_ms)))
+ .Times(AnyNumber())
+ .WillRepeatedly(Return(0));
+ default:
+ ASSERT_TRUE(false) << "Unexpected number of buffers";
+ }
EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms,
Field(&AudioBuffersState::pending_bytes,
bytes_100_ms)))