diff options
author | enal@chromium.org <enal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-15 21:51:27 +0000 |
---|---|---|
committer | enal@chromium.org <enal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-15 21:51:27 +0000 |
commit | 06e639cdc5cf9b7d3e97c7d7c57920b56b4b6e17 (patch) | |
tree | 048f6ff41defac63e23924bc88b16a6fb439ed4b /media | |
parent | d466b8a0b44ef89c81fa4ede86de1b488b8ec07d (diff) | |
download | chromium_src-06e639cdc5cf9b7d3e97c7d7c57920b56b4b6e17.zip chromium_src-06e639cdc5cf9b7d3e97c7d7c57920b56b4b6e17.tar.gz chromium_src-06e639cdc5cf9b7d3e97c7d7c57920b56b4b6e17.tar.bz2 |
Fix problem when 'ended' event was fired before stream really ended.
That caused impression that rewind does not work. With that
change small JS program
var a = new Audio("file:///home/enal/temp/click2/click2.wav");
var num_played = 0;
a.addEventListener('canplaythrough', function() {
a.play();
});
a.addEventListener('ended', function() {
num_played ++;
if (num_played < 10) {
a.currentTime = 0;
a.play();
}
});
works correctly, you hear 10 clicks one after another, and it takes
~1.5 seconds to play all 10 sounds (one click is 146ms). Current
Chrome plays only beginnings of the first 9 clicks and then entire
10th click -- 'ended' event fires too early, so rewind stops audio
playback for all clicks but last one.
With that fix you can easily create pool of audio objects -- on 'ended'
event just add audio object to the pool.
Fix consists of 3 parts:
1) For low-latency code path pass entire "audio state" object to the renderer
process. That allows renderer take into account number of pending bytes
in the buffer.
2) When using low-latency code path renderer not only fills the buffer with
data, but also writes length of data into first word of the buffer. That
allows host process to pass correct byte counts to renderer.
3) Renderer now keeps track of the earliest time playback can end based on the
number of rendered bytes, and will not call 'ended' callback till that time.
BUG=http://code.google.com/p/chromium/issues/detail?id=78992
http://codereview.chromium.org/7328030
Review URL: http://codereview.chromium.org/7328030
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@92749 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/audio/audio_buffers_state.cc | 9 | ||||
-rw-r--r-- | media/audio/audio_buffers_state.h | 10 | ||||
-rw-r--r-- | media/audio/audio_output_controller.cc | 16 | ||||
-rw-r--r-- | media/audio/audio_output_controller.h | 10 | ||||
-rw-r--r-- | media/audio/audio_output_controller_unittest.cc | 2 | ||||
-rw-r--r-- | media/audio/audio_util.cc | 33 | ||||
-rw-r--r-- | media/audio/audio_util.h | 16 |
7 files changed, 80 insertions, 16 deletions
diff --git a/media/audio/audio_buffers_state.cc b/media/audio/audio_buffers_state.cc index f31cf1d..2fe1105 100644 --- a/media/audio/audio_buffers_state.cc +++ b/media/audio/audio_buffers_state.cc @@ -1,9 +1,11 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "media/audio/audio_buffers_state.h" +#include "base/sync_socket.h" + AudioBuffersState::AudioBuffersState() : pending_bytes(0), hardware_delay_bytes(0), @@ -20,3 +22,8 @@ AudioBuffersState::AudioBuffersState(int pending_bytes, int AudioBuffersState::total_bytes() { return pending_bytes + hardware_delay_bytes; } + +bool AudioBuffersState::Receive(base::SyncSocket *socket) { + return socket->Receive(this, sizeof(AudioBuffersState)) == + sizeof(AudioBuffersState); +} diff --git a/media/audio/audio_buffers_state.h b/media/audio/audio_buffers_state.h index e3a2faf..a0a037c 100644 --- a/media/audio/audio_buffers_state.h +++ b/media/audio/audio_buffers_state.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,6 +7,10 @@ #include "base/time.h" +namespace base { +class SyncSocket; +} + // AudioBuffersState struct stores current state of audio buffers along with // the timestamp of the moment this state corresponds to. It is used for audio // synchronization. @@ -27,6 +31,10 @@ struct AudioBuffersState { // to account for the time it takes to deliver AudioBuffersState from // the browser process to the renderer. base::Time timestamp; + + // Receives AudioBuffersState from socket. + // Returns true if successfully got it. + bool Receive(base::SyncSocket *socket); }; diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc index ec75cde..30882f4 100644 --- a/media/audio/audio_output_controller.cc +++ b/media/audio/audio_output_controller.cc @@ -5,6 +5,7 @@ #include "media/audio/audio_output_controller.h" #include "base/message_loop.h" +#include "media/audio/audio_buffers_state.h" namespace media { @@ -202,7 +203,7 @@ void AudioOutputController::DoPause() { if (LowLatencyMode()) { // Send a special pause mark to the low-latency audio thread. - sync_reader_->UpdatePendingBytes(kPauseMark); + sync_reader_->UpdateBufferState(AudioBuffersState(kPauseMark, 0)); } handler_->OnPaused(this); @@ -268,13 +269,13 @@ void AudioOutputController::DoReportError(int code) { uint32 AudioOutputController::OnMoreData( AudioOutputStream* stream, uint8* dest, uint32 max_size, AudioBuffersState buffers_state) { - // If regular latency mode is used. - if (!sync_reader_) { - base::AutoLock auto_lock(lock_); + base::AutoLock auto_lock(lock_); - // Save current buffers state. - buffers_state_ = buffers_state; + // Save current buffers state. + buffers_state_ = buffers_state; + // If regular latency mode is used. + if (!sync_reader_) { if (state_ != kPlaying) { // Don't read anything. Save the number of bytes in the hardware buffer. return 0; @@ -288,7 +289,8 @@ uint32 AudioOutputController::OnMoreData( // Low latency mode. uint32 size = sync_reader_->Read(dest, max_size); - sync_reader_->UpdatePendingBytes(buffers_state.total_bytes() + size); + buffers_state_.pending_bytes += size; + sync_reader_->UpdateBufferState(buffers_state_); return size; } diff --git a/media/audio/audio_output_controller.h b/media/audio/audio_output_controller.h index 29fb0a7..65edaa1 100644 --- a/media/audio/audio_output_controller.h +++ b/media/audio/audio_output_controller.h @@ -14,6 +14,7 @@ #include "media/audio/audio_manager.h" #include "media/audio/simple_sources.h" +struct AudioBuffersState; class MessageLoop; class Task; @@ -90,10 +91,9 @@ class AudioOutputController public: virtual ~SyncReader() {} - // Notify the synchronous reader the number of bytes in the - // AudioOutputController not yet played. This is used by SyncReader to - // prepare more data and perform synchronization. - virtual void UpdatePendingBytes(uint32 bytes) = 0; + // Notify the synchronous reader the buffer state. This is used by + // SyncReader to prepare more data and perform synchronization. + virtual void UpdateBufferState(const AudioBuffersState& buffer_state) = 0; // Read certain amount of data into |data|. This method returns if some // data is available. @@ -208,4 +208,4 @@ class AudioOutputController } // namespace media -#endif // MEDIA_AUDIO_AUDIO_OUTPUT_CONTROLLER_H_ +#endif // MEDIA_AUDIO_AUDIO_OUTPUT_CONTROLLER_H_ diff --git a/media/audio/audio_output_controller_unittest.cc b/media/audio/audio_output_controller_unittest.cc index 0f94ae5..b2ad2b0 100644 --- a/media/audio/audio_output_controller_unittest.cc +++ b/media/audio/audio_output_controller_unittest.cc @@ -50,7 +50,7 @@ class MockAudioOutputControllerSyncReader public: MockAudioOutputControllerSyncReader() {} - MOCK_METHOD1(UpdatePendingBytes, void(uint32 bytes)); + MOCK_METHOD1(UpdateBufferState, void(const AudioBuffersState& buffer_state)); MOCK_METHOD2(Read, uint32(void* data, uint32 size)); MOCK_METHOD0(Close, void()); diff --git a/media/audio/audio_util.cc b/media/audio/audio_util.cc index 18e2abb..0d055b9 100644 --- a/media/audio/audio_util.cc +++ b/media/audio/audio_util.cc @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "base/logging.h" +#include "base/shared_memory.h" #include "media/audio/audio_util.h" #if defined(OS_MACOSX) #include "media/audio/mac/audio_low_latency_output_mac.h" @@ -234,4 +235,36 @@ double GetAudioHardwareSampleRate() #endif } +// When transferring data in the shared memory, first word is size of data +// in bytes. Actual data starts immediately after it. + +uint32 TotalSharedMemorySizeInBytes(uint32 packet_size) { + // Need to reserve extra 4 bytes for size of data. + return packet_size + sizeof(uint32); +} + +uint32 GetMaxDataSizeInBytes(uint32 shared_memory_size) { + // We can transfer 4 less bytes of data than shared memory size.. + DCHECK_GT(shared_memory_size, sizeof(uint32)); + return shared_memory_size - sizeof(uint32); +} + +uint32 GetActualDataSizeInBytes(base::SharedMemory* shared_memory) { + // Actual data size stored in the beginning of the buffer. + uint32 actual_data_size = 0; + memcpy(&actual_data_size, shared_memory->memory(), sizeof(uint32)); + return actual_data_size; +} + +void SetActualDataSizeInBytes(base::SharedMemory* shared_memory, + uint32 actual_data_size) { + // Set actual data size in the beginning of the buffer. + memcpy(shared_memory->memory(), &actual_data_size, sizeof(uint32)); +} + +void* GetDataPointer(base::SharedMemory* shared_memory) { + // Data itself is stored after size that occupies 4 bytes. + return static_cast<char*>(shared_memory->memory()) + sizeof(uint32); +} + } // namespace media diff --git a/media/audio/audio_util.h b/media/audio/audio_util.h index 15a0935..a73a613 100644 --- a/media/audio/audio_util.h +++ b/media/audio/audio_util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,6 +9,10 @@ #include "base/basictypes.h" +namespace base { +class SharedMemory; +} + namespace media { // For all audio functions 3 audio formats are supported: @@ -94,6 +98,16 @@ void SwizzleCoreAudioLayout5_1(Format* b, uint32 filled) { // Returns the default audio hardware sample-rate. double GetAudioHardwareSampleRate(); +// Functions that handle data buffer passed between processes in the shared +// memory. Called on both IPC sides. + +uint32 TotalSharedMemorySizeInBytes(uint32 packet_size); +uint32 GetMaxDataSizeInBytes(uint32 shared_memory_size); +uint32 GetActualDataSizeInBytes(base::SharedMemory* shared_memory); +void SetActualDataSizeInBytes(base::SharedMemory* shared_memory, + uint32 actual_data_size); +void* GetDataPointer(base::SharedMemory* shared_memory); + } // namespace media #endif // MEDIA_AUDIO_AUDIO_UTIL_H_ |