summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorfbarchard@chromium.org <fbarchard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-23 22:56:35 +0000
committerfbarchard@chromium.org <fbarchard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-23 22:56:35 +0000
commit32a61d0268edcef77e2d4300c9287414ecc52fe6 (patch)
treefcae08e54b86ecf58686150a6b0a60a2368ef766 /media
parent1ed60a369d47c7fce9a92d52513486960f63506d (diff)
downloadchromium_src-32a61d0268edcef77e2d4300c9287414ecc52fe6.zip
chromium_src-32a61d0268edcef77e2d4300c9287414ecc52fe6.tar.gz
chromium_src-32a61d0268edcef77e2d4300c9287414ecc52fe6.tar.bz2
Prototype audio time shift.
Review URL: http://codereview.chromium.org/92007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14366 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/audio/win/waveout_output_win.cc5
-rw-r--r--media/base/filter_host_impl.cc2
-rw-r--r--media/filters/audio_renderer_base.cc100
-rw-r--r--media/filters/audio_renderer_base.h2
-rw-r--r--media/filters/audio_renderer_impl.cc22
-rw-r--r--media/filters/audio_renderer_impl.h5
-rw-r--r--media/filters/null_audio_renderer.cc2
7 files changed, 82 insertions, 56 deletions
diff --git a/media/audio/win/waveout_output_win.cc b/media/audio/win/waveout_output_win.cc
index 9a3f581..2f5d8ab 100644
--- a/media/audio/win/waveout_output_win.cc
+++ b/media/audio/win/waveout_output_win.cc
@@ -218,8 +218,8 @@ void PCMWaveOutAudioOutputStream::GetVolume(double* left_level,
HandleError(res);
return;
}
- *left_level = double(LOWORD(volume_packed)) / kMaxVolumeLevel;
- *right_level = double(HIWORD(volume_packed)) / kMaxVolumeLevel;
+ *left_level = static_cast<double>(LOWORD(volume_packed)) / kMaxVolumeLevel;
+ *right_level = static_cast<double>(HIWORD(volume_packed)) / kMaxVolumeLevel;
}
size_t PCMWaveOutAudioOutputStream::GetNumBuffers() {
@@ -234,6 +234,7 @@ void PCMWaveOutAudioOutputStream::HandleError(MMRESULT error) {
void PCMWaveOutAudioOutputStream::QueueNextPacket(WAVEHDR *buffer) {
// Call the source which will fill our buffer with pleasant sounds and
// return to us how many bytes were used.
+ // TODO(fbarchard): Handle used 0 by queueing more.
size_t used = callback_->OnMoreData(this, buffer->lpData, buffer_size_);
if (used <= buffer_size_) {
buffer->dwBufferLength = used;
diff --git a/media/base/filter_host_impl.cc b/media/base/filter_host_impl.cc
index cba2eb1..6cf39cd 100644
--- a/media/base/filter_host_impl.cc
+++ b/media/base/filter_host_impl.cc
@@ -45,7 +45,7 @@ void FilterHostImpl::ScheduleTimeUpdateCallback(base::TimeDelta time) {
time -= pipeline()->GetInterpolatedTime();
int delay = static_cast<int>(time.InMilliseconds());
float rate = pipeline()->GetPlaybackRate();
- if (rate != 1.0f && rate != 0.0f) {
+ if (rate > 0.0f) {
delay = static_cast<int>(delay / rate);
}
if (delay > 0) {
diff --git a/media/filters/audio_renderer_base.cc b/media/filters/audio_renderer_base.cc
index 01a8737..28acd82 100644
--- a/media/filters/audio_renderer_base.cc
+++ b/media/filters/audio_renderer_base.cc
@@ -79,54 +79,71 @@ void AudioRendererBase::OnReadComplete(Buffer* buffer_in) {
}
}
-size_t AudioRendererBase::FillBuffer(uint8* dest, size_t len) {
+size_t AudioRendererBase::FillBuffer(uint8* dest, size_t dest_len,
+ float rate) {
// Update the pipeline's time.
host_->SetTime(last_fill_buffer_time_);
- size_t result = 0;
size_t buffers_released = 0;
- {
- AutoLock auto_lock(lock_);
- // Loop until the buffer has been filled.
- while (len > 0 && !queue_.empty()) {
- Buffer* buffer = queue_.front();
+ size_t dest_written = 0;
- // Determine how much to copy.
- const uint8* data = buffer->GetData() + data_offset_;
- size_t data_len = buffer->GetDataSize() - data_offset_;
- data_len = std::min(len, data_len);
+ AutoLock auto_lock(lock_);
+ // Loop until the buffer has been filled.
+ while (dest_len > 0 && !queue_.empty()) {
+ Buffer* buffer = queue_.front();
+
+ // Determine how much to copy.
+ const uint8* data = buffer->GetData() + data_offset_;
+ size_t data_len = buffer->GetDataSize() - data_offset_;
+
+ // New scaled packet size aligned to 16 to ensure its on a
+ // channel/sample boundary. Only guaranteed to works for power of 2
+ // number of channels and sample size.
+ size_t scaled_data_len = (rate <= 0.0f) ? 0 :
+ static_cast<size_t>(data_len / rate) & ~15;
+ if (scaled_data_len > dest_len) {
+ data_len = (data_len * dest_len / scaled_data_len) & ~15;
+ scaled_data_len = dest_len;
+ }
- // Copy into buffer.
+ if (rate >= 1.0f) { // Speed up.
+ memcpy(dest, data, scaled_data_len);
+ } else if (rate >= 0.5) { // Slow down.
memcpy(dest, data, data_len);
- len -= data_len;
- dest += data_len;
- data_offset_ += data_len;
- result += data_len;
-
+ memcpy(dest + data_len, data, scaled_data_len - data_len);
+ } else { // Pause.
+ memset(dest, 0, data_len);
+ }
+ dest += scaled_data_len;
+ dest_len -= scaled_data_len;
+ dest_written += scaled_data_len;
+
+ data_offset_ += data_len;
+
+ if (rate == 0.0f)
+ return 0;
+
+ // Check to see if we're finished with the front buffer.
+ if (buffer->GetDataSize() - data_offset_ < 16) {
+ // Update the time. If this is the last buffer in the queue, we'll
+ // drop out of the loop before len == 0, so we need to always update
+ // the time here.
+ last_fill_buffer_time_ = buffer->GetTimestamp() + buffer->GetDuration();
+
+ // Dequeue the buffer.
+ queue_.pop_front();
+ buffer->Release();
+ ++buffers_released;
+
+ // Reset our offset into the front buffer.
+ data_offset_ = 0;
+ } else {
// If we're done with the read, compute the time.
- if (len == 0) {
- // Integer divide so multiply before divide to work properly.
- int64 us_written = (buffer->GetDuration().InMicroseconds() *
- data_offset_) / buffer->GetDataSize();
- last_fill_buffer_time_ = buffer->GetTimestamp() +
- base::TimeDelta::FromMicroseconds(us_written);
- }
-
- // Check to see if we're finished with the front buffer.
- if (data_offset_ == buffer->GetDataSize()) {
- // Update the time. If this is the last buffer in the queue, we'll
- // drop out of the loop before len == 0, so we need to always update
- // the time here.
- last_fill_buffer_time_ = buffer->GetTimestamp() + buffer->GetDuration();
-
- // Dequeue the buffer.
- queue_.pop_front();
- buffer->Release();
- ++buffers_released;
-
- // Reset our offset into the front buffer.
- data_offset_ = 0;
- }
+ // Integer divide so multiply before divide to work properly.
+ int64 us_written = (buffer->GetDuration().InMicroseconds() *
+ data_offset_) / buffer->GetDataSize();
+ last_fill_buffer_time_ = buffer->GetTimestamp() +
+ base::TimeDelta::FromMicroseconds(us_written);
}
}
@@ -134,8 +151,7 @@ size_t AudioRendererBase::FillBuffer(uint8* dest, size_t len) {
for (size_t i = 0; i < buffers_released; ++i) {
ScheduleRead();
}
-
- return result;
+ return dest_written;
}
void AudioRendererBase::ScheduleRead() {
diff --git a/media/filters/audio_renderer_base.h b/media/filters/audio_renderer_base.h
index 6659fa1..5536a5d 100644
--- a/media/filters/audio_renderer_base.h
+++ b/media/filters/audio_renderer_base.h
@@ -66,7 +66,7 @@ class AudioRendererBase : public AudioRenderer {
// of their buffer to playback silence.
//
// Safe to call on any thread.
- size_t FillBuffer(uint8* dest, size_t len);
+ size_t FillBuffer(uint8* dest, size_t len, float rate);
// Helper to parse a media format and return whether we were successful
// retrieving all the information we care about.
diff --git a/media/filters/audio_renderer_impl.cc b/media/filters/audio_renderer_impl.cc
index 55a1096..95e1401 100644
--- a/media/filters/audio_renderer_impl.cc
+++ b/media/filters/audio_renderer_impl.cc
@@ -9,10 +9,11 @@ namespace media {
// We'll try to fill 4096 samples per buffer, which is roughly ~92ms of audio
// data for a 44.1kHz audio source.
-static const size_t kSamplesPerBuffer = 4096;
+static const size_t kSamplesPerBuffer = 8*1024;
AudioRendererImpl::AudioRendererImpl()
: AudioRendererBase(kDefaultMaxQueueSize),
+ playback_rate_(0.0f),
stream_(NULL) {
}
@@ -33,14 +34,15 @@ bool AudioRendererImpl::IsMediaFormatSupported(
ParseMediaFormat(media_format, &channels, &sample_rate, &sample_bits);
}
-void AudioRendererImpl::SetPlaybackRate(float playback_rate) {
+void AudioRendererImpl::SetPlaybackRate(float rate) {
DCHECK(stream_);
- // TODO(scherkus): handle playback rates not equal to 1.0.
- if (playback_rate == 1.0f) {
+
+ // TODO(fbarchard): limit rate to reasonable values
+ playback_rate_ = rate;
+
+ static bool started = false;
+ if (rate > 0.0f && !started)
stream_->Start(this);
- } else {
- NOTIMPLEMENTED();
- }
}
void AudioRendererImpl::SetVolume(float volume) {
@@ -52,8 +54,10 @@ size_t AudioRendererImpl::OnMoreData(AudioOutputStream* stream, void* dest_void,
// TODO(scherkus): handle end of stream.
DCHECK(stream_ == stream);
- // TODO(scherkus): maybe change OnMoreData to pass in char/uint8 or similar.
- return FillBuffer(reinterpret_cast<uint8*>(dest_void), len);
+ // TODO(scherkus): Maybe change OnMoreData to pass in char/uint8 or similar.
+ // TODO(fbarchard): Waveout_output_win.h should handle zero length buffers
+ // without clicking.
+ return FillBuffer(static_cast<uint8*>(dest_void), len, playback_rate_);
}
void AudioRendererImpl::OnClose(AudioOutputStream* stream) {
diff --git a/media/filters/audio_renderer_impl.h b/media/filters/audio_renderer_impl.h
index b7e551b..e0804ce 100644
--- a/media/filters/audio_renderer_impl.h
+++ b/media/filters/audio_renderer_impl.h
@@ -53,6 +53,11 @@ class AudioRendererImpl : public AudioRendererBase,
virtual void OnStop();
private:
+ // Playback rate
+ // 0.0f is paused, 0.5f is half speed, 1.0f is normal, 2.0f is double speed.
+ // Rate should normally be any value between 0.5 and 3.0.
+ float playback_rate_;
+
// Audio output stream device.
AudioOutputStream* stream_;
diff --git a/media/filters/null_audio_renderer.cc b/media/filters/null_audio_renderer.cc
index 1d50e69..74604f8 100644
--- a/media/filters/null_audio_renderer.cc
+++ b/media/filters/null_audio_renderer.cc
@@ -51,7 +51,7 @@ void NullAudioRenderer::ThreadMain() {
// Only consume buffers when actually playing.
if (playback_rate_ > 0.0f) {
- size_t bytes = FillBuffer(buffer_.get(), buffer_size_);
+ size_t bytes = FillBuffer(buffer_.get(), buffer_size_, playback_rate_);
// Calculate our sleep duration, taking playback rate into consideration.
sleep_in_milliseconds =