diff options
Diffstat (limited to 'media')
57 files changed, 251 insertions, 148 deletions
diff --git a/media/audio/alsa/alsa_output.cc b/media/audio/alsa/alsa_output.cc index 554aa5f..046c9bc 100644 --- a/media/audio/alsa/alsa_output.cc +++ b/media/audio/alsa/alsa_output.cc @@ -781,7 +781,7 @@ int AlsaPcmOutputStream::RunDataCallback(AudioBus* audio_bus, TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback"); if (source_callback_) - return source_callback_->OnMoreData(audio_bus, total_bytes_delay); + return source_callback_->OnMoreData(audio_bus, total_bytes_delay, 0); return 0; } diff --git a/media/audio/alsa/alsa_output_unittest.cc b/media/audio/alsa/alsa_output_unittest.cc index 8996dbc..af2c46a 100644 --- a/media/audio/alsa/alsa_output_unittest.cc +++ b/media/audio/alsa/alsa_output_unittest.cc @@ -422,7 +422,7 @@ TEST_F(AlsaPcmOutputStreamTest, StartStop) { .WillRepeatedly(Return(SND_PCM_STATE_RUNNING)); EXPECT_CALL(mock_alsa_wrapper_, PcmDelay(kFakeHandle, _)) .WillRepeatedly(DoAll(SetArgumentPointee<1>(0), Return(0))); - EXPECT_CALL(mock_callback, OnMoreData(_, _)) + EXPECT_CALL(mock_callback, OnMoreData(_, _, 0)) .WillRepeatedly(DoAll(ClearBuffer(), Return(kTestFramesPerPacket))); EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(kFakeHandle, _, _)) .WillRepeatedly(Return(kTestFramesPerPacket)); @@ -585,7 +585,7 @@ TEST_F(AlsaPcmOutputStreamTest, BufferPacket) { .WillRepeatedly(Return(0)); // Buffer is full. // Return a partially filled packet. - EXPECT_CALL(mock_callback, OnMoreData(_, _)) + EXPECT_CALL(mock_callback, OnMoreData(_, _, 0)) .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket / 2))); bool source_exhausted; @@ -611,7 +611,7 @@ TEST_F(AlsaPcmOutputStreamTest, BufferPacket_Negative) { .WillOnce(DoAll(SetArgumentPointee<1>(-1), Return(0))); EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_)) .WillRepeatedly(Return(0)); // Buffer is full. - EXPECT_CALL(mock_callback, OnMoreData(_, _)) + EXPECT_CALL(mock_callback, OnMoreData(_, _, 0)) .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket / 2))); bool source_exhausted; @@ -635,7 +635,7 @@ TEST_F(AlsaPcmOutputStreamTest, BufferPacket_Underrun) { .WillOnce(Return(SND_PCM_STATE_XRUN)); EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_)) .WillRepeatedly(Return(0)); // Buffer is full. - EXPECT_CALL(mock_callback, OnMoreData(_, 0)) + EXPECT_CALL(mock_callback, OnMoreData(_, 0, 0)) .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket / 2))); bool source_exhausted; diff --git a/media/audio/android/audio_android_unittest.cc b/media/audio/android/audio_android_unittest.cc index 9140f22..68b53ed 100644 --- a/media/audio/android/audio_android_unittest.cc +++ b/media/audio/android/audio_android_unittest.cc @@ -121,7 +121,9 @@ void CheckDeviceNames(const AudioDeviceNames& device_names) { } // We clear the data bus to ensure that the test does not cause noise. -int RealOnMoreData(AudioBus* dest, uint32 total_bytes_delay) { +int RealOnMoreData(AudioBus* dest, + uint32_t total_bytes_delay, + uint32_t frames_skipped) { dest->Zero(); return dest->frames(); } @@ -177,7 +179,9 @@ class FileAudioSource : public AudioOutputStream::AudioSourceCallback { // Use samples read from a data file and fill up the audio buffer // provided to us in the callback. - int OnMoreData(AudioBus* audio_bus, uint32 total_bytes_delay) override { + int OnMoreData(AudioBus* audio_bus, + uint32_t total_bytes_delay, + uint32_t frames_skipped) override { bool stop_playing = false; int max_size = audio_bus->frames() * audio_bus->channels() * kBytesPerSample; @@ -352,7 +356,9 @@ class FullDuplexAudioSinkSource void OnError(AudioInputStream* stream) override {} // AudioOutputStream::AudioSourceCallback implementation - int OnMoreData(AudioBus* dest, uint32 total_bytes_delay) override { + int OnMoreData(AudioBus* dest, + uint32_t total_bytes_delay, + uint32_t frames_skipped) override { const int size_in_bytes = (params_.bits_per_sample() / 8) * dest->frames() * dest->channels(); EXPECT_EQ(size_in_bytes, params_.GetBytesPerBuffer()); @@ -491,11 +497,11 @@ class AudioAndroidOutputTest : public testing::Test { int count = 0; MockAudioSourceCallback source; - EXPECT_CALL(source, OnMoreData(NotNull(), _)) + EXPECT_CALL(source, OnMoreData(NotNull(), _, 0)) .Times(AtLeast(num_callbacks)) .WillRepeatedly( - DoAll(CheckCountAndPostQuitTask(&count, num_callbacks, loop()), - Invoke(RealOnMoreData))); + DoAll(CheckCountAndPostQuitTask(&count, num_callbacks, loop()), + Invoke(RealOnMoreData))); EXPECT_CALL(source, OnError(audio_output_stream_)).Times(0); OpenAndStartAudioOutputStreamOnAudioThread(&source); @@ -895,7 +901,7 @@ TEST_P(AudioAndroidInputTest, DISABLED_RunDuplexInputStreamWithFileAsSink) { FileAudioSink sink(&event, in_params, file_name); MockAudioSourceCallback source; - EXPECT_CALL(source, OnMoreData(NotNull(), _)) + EXPECT_CALL(source, OnMoreData(NotNull(), _, 0)) .WillRepeatedly(Invoke(RealOnMoreData)); EXPECT_CALL(source, OnError(audio_output_stream_)).Times(0); diff --git a/media/audio/android/opensles_output.cc b/media/audio/android/opensles_output.cc index 2974e14..7fffe3b 100644 --- a/media/audio/android/opensles_output.cc +++ b/media/audio/android/opensles_output.cc @@ -331,8 +331,8 @@ void OpenSLESOutputStream::FillBufferQueueNoLock() { // TODO(henrika): Investigate if it is possible to get a more accurate // delay estimation. const uint32 hardware_delay = buffer_size_bytes_; - int frames_filled = callback_->OnMoreData( - audio_bus_.get(), hardware_delay); + int frames_filled = + callback_->OnMoreData(audio_bus_.get(), hardware_delay, 0); if (frames_filled <= 0) { // Audio source is shutting down, or halted on error. return; diff --git a/media/audio/audio_device_thread.h b/media/audio/audio_device_thread.h index 7e8e2bf..b910c71 100644 --- a/media/audio/audio_device_thread.h +++ b/media/audio/audio_device_thread.h @@ -50,8 +50,8 @@ class MEDIA_EXPORT AudioDeviceThread { // before Process can be called. virtual void MapSharedMemory() = 0; - // Called whenever we receive notifications about pending data. - virtual void Process(uint32 pending_data) = 0; + // Called whenever we receive notifications about pending input data. + virtual void Process(uint32_t pending_data) = 0; protected: // Protected so that derived classes can access directly. diff --git a/media/audio/audio_input_device.cc b/media/audio/audio_input_device.cc index 02fa7a7..074291f 100644 --- a/media/audio/audio_input_device.cc +++ b/media/audio/audio_input_device.cc @@ -36,7 +36,7 @@ class AudioInputDevice::AudioThreadCallback void MapSharedMemory() override; // Called whenever we receive notifications about pending data. - void Process(uint32 pending_data) override; + void Process(uint32_t pending_data) override; private: int current_segment_id_; @@ -297,7 +297,7 @@ void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { } } -void AudioInputDevice::AudioThreadCallback::Process(uint32 pending_data) { +void AudioInputDevice::AudioThreadCallback::Process(uint32_t pending_data) { // The shared memory represents parameters, size of the data buffer and the // actual data buffer containing audio data. Map the memory into this // structure and parse out parameters and the data area. diff --git a/media/audio/audio_io.h b/media/audio/audio_io.h index 5639215..45af3d2 100644 --- a/media/audio/audio_io.h +++ b/media/audio/audio_io.h @@ -61,7 +61,10 @@ class MEDIA_EXPORT AudioOutputStream { // Provide more data by fully filling |dest|. The source will return // the number of frames it filled. |total_bytes_delay| contains current // number of bytes of delay buffered by the AudioOutputStream. - virtual int OnMoreData(AudioBus* dest, uint32 total_bytes_delay) = 0; + // |frames_skipped| contains the number of frames skipped by the consumer. + virtual int OnMoreData(AudioBus* dest, + uint32_t total_bytes_delay, + uint32_t frames_skipped) = 0; // There was an error while playing a buffer. Audio source cannot be // destroyed yet. No direct action needed by the AudioStream, but it is diff --git a/media/audio/audio_low_latency_input_output_unittest.cc b/media/audio/audio_low_latency_input_output_unittest.cc index b24f501..b47c785 100644 --- a/media/audio/audio_low_latency_input_output_unittest.cc +++ b/media/audio/audio_low_latency_input_output_unittest.cc @@ -216,7 +216,9 @@ class FullDuplexAudioSinkSource void OnError(AudioInputStream* stream) override {} // AudioOutputStream::AudioSourceCallback. - int OnMoreData(AudioBus* audio_bus, uint32 total_bytes_delay) override { + int OnMoreData(AudioBus* audio_bus, + uint32_t total_bytes_delay, + uint32_t frames_skipped) override { base::AutoLock lock(lock_); // Update one component in the AudioDelayState for the packet diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc index f092496..d780687 100644 --- a/media/audio/audio_output_controller.cc +++ b/media/audio/audio_output_controller.cc @@ -164,7 +164,7 @@ void AudioOutputController::DoPlay() { return; // Ask for first packet. - sync_reader_->UpdatePendingBytes(0); + sync_reader_->UpdatePendingBytes(0, 0); state_ = kPlaying; @@ -217,7 +217,7 @@ void AudioOutputController::DoPause() { // Let the renderer know we've stopped. Necessary to let PPAPI clients know // audio has been shutdown. TODO(dalecurtis): This stinks. PPAPI should have // a better way to know when it should exit PPB_Audio_Shared::Run(). - sync_reader_->UpdatePendingBytes(std::numeric_limits<uint32_t>::max()); + sync_reader_->UpdatePendingBytes(std::numeric_limits<uint32_t>::max(), 0); handler_->OnPaused(); } @@ -284,7 +284,8 @@ void AudioOutputController::DoReportError() { } int AudioOutputController::OnMoreData(AudioBus* dest, - uint32_t total_bytes_delay) { + uint32_t total_bytes_delay, + uint32_t frames_skipped) { TRACE_EVENT0("audio", "AudioOutputController::OnMoreData"); // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck() @@ -297,8 +298,8 @@ int AudioOutputController::OnMoreData(AudioBus* dest, sync_reader_->Read(dest); const int frames = dest->frames(); - sync_reader_->UpdatePendingBytes(base::saturated_cast<uint32_t>( - total_bytes_delay + frames * params_.GetBytesPerFrame())); + sync_reader_->UpdatePendingBytes( + total_bytes_delay + frames * params_.GetBytesPerFrame(), frames_skipped); if (will_monitor_audio_levels()) power_monitor_.Scan(*dest, frames); diff --git a/media/audio/audio_output_controller.h b/media/audio/audio_output_controller.h index 7820665..95be9f4 100644 --- a/media/audio/audio_output_controller.h +++ b/media/audio/audio_output_controller.h @@ -8,6 +8,7 @@ #include "base/atomic_ref_count.h" #include "base/callback.h" #include "base/memory/ref_counted.h" +#include "base/threading/thread_checker.h" #include "base/timer/timer.h" #include "build/build_config.h" #include "media/audio/audio_io.h" @@ -82,8 +83,12 @@ class MEDIA_EXPORT AudioOutputController // 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; + // prepare more data and perform synchronization. Also inform about if any + // frames has been skipped by the renderer (typically the OS). The renderer + // source can handle this appropriately depending on the type of source. An + // ordinary file playout would ignore this. + virtual void UpdatePendingBytes(uint32_t bytes, + uint32_t frames_skipped) = 0; // Attempts to completely fill |dest|, zeroing |dest| if the request can not // be fulfilled (due to timeout). @@ -153,7 +158,9 @@ class MEDIA_EXPORT AudioOutputController const base::Closure& callback); // AudioSourceCallback implementation. - int OnMoreData(AudioBus* dest, uint32 total_bytes_delay) override; + int OnMoreData(AudioBus* dest, + uint32_t total_bytes_delay, + uint32_t frames_skipped) override; void OnError(AudioOutputStream* stream) override; // AudioDeviceListener implementation. When called AudioOutputController will diff --git a/media/audio/audio_output_controller_unittest.cc b/media/audio/audio_output_controller_unittest.cc index b68dea2..9addca8 100644 --- a/media/audio/audio_output_controller_unittest.cc +++ b/media/audio/audio_output_controller_unittest.cc @@ -51,7 +51,8 @@ class MockAudioOutputControllerSyncReader public: MockAudioOutputControllerSyncReader() {} - MOCK_METHOD1(UpdatePendingBytes, void(uint32 bytes)); + MOCK_METHOD2(UpdatePendingBytes, + void(uint32_t bytes, uint32_t frames_skipped)); MOCK_METHOD1(Read, void(AudioBus* dest)); MOCK_METHOD0(Close, void()); @@ -132,8 +133,7 @@ class AudioOutputControllerTest : public testing::Test { // During playback, the mock pretends to provide audio data rendered and // sent from the render process. - EXPECT_CALL(mock_sync_reader_, UpdatePendingBytes(_)) - .Times(AtLeast(1)); + EXPECT_CALL(mock_sync_reader_, UpdatePendingBytes(_, _)).Times(AtLeast(1)); EXPECT_CALL(mock_sync_reader_, Read(_)) .WillRepeatedly(DoAll(PopulateBuffer(), SignalEvent(&read_event_))); @@ -190,7 +190,7 @@ class AudioOutputControllerTest : public testing::Test { scoped_ptr<AudioBus> dest = AudioBus::Create(params_); ASSERT_TRUE(mock_stream_.callback()); const int frames_read = - mock_stream_.callback()->OnMoreData(dest.get(), 0); + mock_stream_.callback()->OnMoreData(dest.get(), 0, 0); EXPECT_LT(0, frames_read); EXPECT_EQ(kBufferNonZeroData, dest->channel(0)[0]); } diff --git a/media/audio/audio_output_device.cc b/media/audio/audio_output_device.cc index 9924f76..cc0804b 100644 --- a/media/audio/audio_output_device.cc +++ b/media/audio/audio_output_device.cc @@ -28,12 +28,13 @@ class AudioOutputDevice::AudioThreadCallback void MapSharedMemory() override; // Called whenever we receive notifications about pending data. - void Process(uint32 pending_data) override; + void Process(uint32_t pending_data) override; private: AudioRendererSink::RenderCallback* render_callback_; scoped_ptr<AudioBus> output_bus_; uint64 callback_num_; + DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); }; @@ -395,16 +396,19 @@ AudioOutputDevice::AudioThreadCallback::~AudioThreadCallback() { void AudioOutputDevice::AudioThreadCallback::MapSharedMemory() { CHECK_EQ(total_segments_, 1); CHECK(shared_memory_.Map(memory_length_)); - DCHECK_EQ(memory_length_, AudioBus::CalculateMemorySize(audio_parameters_)); + DCHECK_EQ(static_cast<size_t>(memory_length_), + sizeof(AudioOutputBufferParameters) + + AudioBus::CalculateMemorySize(audio_parameters_)); - output_bus_ = - AudioBus::WrapMemory(audio_parameters_, shared_memory_.memory()); + AudioOutputBuffer* buffer = + reinterpret_cast<AudioOutputBuffer*>(shared_memory_.memory()); + output_bus_ = AudioBus::WrapMemory(audio_parameters_, buffer->audio); } // Called whenever we receive notifications about pending data. -void AudioOutputDevice::AudioThreadCallback::Process(uint32 pending_data) { +void AudioOutputDevice::AudioThreadCallback::Process(uint32_t pending_data) { // Convert the number of pending bytes in the render buffer into milliseconds. - int audio_delay_milliseconds = pending_data / bytes_per_ms_; + uint32_t audio_delay_milliseconds = pending_data / bytes_per_ms_; callback_num_++; TRACE_EVENT1("audio", "AudioOutputDevice::FireRenderCallback", @@ -417,10 +421,18 @@ void AudioOutputDevice::AudioThreadCallback::Process(uint32 pending_data) { TRACE_EVENT_ASYNC_END0("audio", "StartingPlayback", this); } - // Update the audio-delay measurement then ask client to render audio. Since - // |output_bus_| is wrapping the shared memory the Render() call is writing - // directly into the shared memory. - render_callback_->Render(output_bus_.get(), audio_delay_milliseconds); + // Read and reset the number of frames skipped. + AudioOutputBuffer* buffer = + reinterpret_cast<AudioOutputBuffer*>(shared_memory_.memory()); + uint32_t frames_skipped = buffer->params.frames_skipped; + buffer->params.frames_skipped = 0; + + // Update the audio-delay measurement, inform about the number of skipped + // frames, and ask client to render audio. Since |output_bus_| is wrapping + // the shared memory the Render() call is writing directly into the shared + // memory. + render_callback_->Render(output_bus_.get(), audio_delay_milliseconds, + frames_skipped); } -} // namespace media. +} // namespace media diff --git a/media/audio/audio_output_device_unittest.cc b/media/audio/audio_output_device_unittest.cc index 5faa119..aa7e649 100644 --- a/media/audio/audio_output_device_unittest.cc +++ b/media/audio/audio_output_device_unittest.cc @@ -44,7 +44,10 @@ class MockRenderCallback : public AudioRendererSink::RenderCallback { MockRenderCallback() {} virtual ~MockRenderCallback() {} - MOCK_METHOD2(Render, int(AudioBus* dest, int audio_delay_milliseconds)); + MOCK_METHOD3(Render, + int(AudioBus* dest, + uint32_t audio_delay_milliseconds, + uint32_t frames_skipped)); MOCK_METHOD0(OnRenderError, void()); }; @@ -117,7 +120,8 @@ class AudioOutputDeviceTest int AudioOutputDeviceTest::CalculateMemorySize() { // Calculate output memory size. - return AudioBus::CalculateMemorySize(default_audio_parameters_); + return sizeof(AudioOutputBufferParameters) + + AudioBus::CalculateMemorySize(default_audio_parameters_); } AudioOutputDeviceTest::AudioOutputDeviceTest() @@ -214,10 +218,9 @@ void AudioOutputDeviceTest::ExpectRenderCallback() { // So, for the sake of this test, we consider the call to Render a sign // of success and quit the loop. const int kNumberOfFramesToProcess = 0; - EXPECT_CALL(callback_, Render(_, _)) - .WillOnce(DoAll( - QuitLoop(io_loop_.task_runner()), - Return(kNumberOfFramesToProcess))); + EXPECT_CALL(callback_, Render(_, _, _)) + .WillOnce(DoAll(QuitLoop(io_loop_.task_runner()), + Return(kNumberOfFramesToProcess))); } void AudioOutputDeviceTest::WaitUntilRenderCallback() { diff --git a/media/audio/audio_output_proxy_unittest.cc b/media/audio/audio_output_proxy_unittest.cc index 6f8befb..71c2ad9 100644 --- a/media/audio/audio_output_proxy_unittest.cc +++ b/media/audio/audio_output_proxy_unittest.cc @@ -124,7 +124,9 @@ class MockAudioManager : public AudioManagerBase { class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback { public: - int OnMoreData(AudioBus* audio_bus, uint32 total_bytes_delay) { + int OnMoreData(AudioBus* audio_bus, + uint32_t total_bytes_delay, + uint32_t frames_skipped) { audio_bus->Zero(); return audio_bus->frames(); } diff --git a/media/audio/audio_output_resampler.cc b/media/audio/audio_output_resampler.cc index 29f6d26..ba33835 100644 --- a/media/audio/audio_output_resampler.cc +++ b/media/audio/audio_output_resampler.cc @@ -28,7 +28,9 @@ class OnMoreDataConverter ~OnMoreDataConverter() override; // AudioSourceCallback interface. - int OnMoreData(AudioBus* dest, uint32 total_bytes_delay) override; + int OnMoreData(AudioBus* dest, + uint32_t total_bytes_delay, + uint32_t frames_skipped) override; void OnError(AudioOutputStream* stream) override; // Sets |source_callback_|. If this is not a new object, then Stop() must be @@ -370,7 +372,8 @@ void OnMoreDataConverter::Stop() { } int OnMoreDataConverter::OnMoreData(AudioBus* dest, - uint32 total_bytes_delay) { + uint32_t total_bytes_delay, + uint32_t frames_skipped) { current_total_bytes_delay_ = total_bytes_delay; audio_converter_.Convert(dest); @@ -389,7 +392,8 @@ double OnMoreDataConverter::ProvideInput(AudioBus* dest, buffer_delay.InSecondsF() * input_bytes_per_second_)); // Retrieve data from the original callback. - const int frames = source_callback_->OnMoreData(dest, new_total_bytes_delay); + const int frames = + source_callback_->OnMoreData(dest, new_total_bytes_delay, 0); // Zero any unfilled frames if anything was filled, otherwise we'll just // return a volume of zero and let AudioConverter drop the output. diff --git a/media/audio/audio_output_stream_sink.cc b/media/audio/audio_output_stream_sink.cc index ceb943f..92739b3 100644 --- a/media/audio/audio_output_stream_sink.cc +++ b/media/audio/audio_output_stream_sink.cc @@ -76,14 +76,15 @@ OutputDevice* AudioOutputStreamSink::GetOutputDevice() { } int AudioOutputStreamSink::OnMoreData(AudioBus* dest, - uint32 total_bytes_delay) { + uint32_t total_bytes_delay, + uint32_t frames_skipped) { // Note: Runs on the audio thread created by the OS. base::AutoLock al(callback_lock_); if (!active_render_callback_) return 0; return active_render_callback_->Render( - dest, total_bytes_delay * 1000.0 / active_params_.GetBytesPerSecond()); + dest, total_bytes_delay * 1000.0 / active_params_.GetBytesPerSecond(), 0); } void AudioOutputStreamSink::OnError(AudioOutputStream* stream) { diff --git a/media/audio/audio_output_stream_sink.h b/media/audio/audio_output_stream_sink.h index 1a5701b..b8eed26 100644 --- a/media/audio/audio_output_stream_sink.h +++ b/media/audio/audio_output_stream_sink.h @@ -39,7 +39,9 @@ class MEDIA_EXPORT AudioOutputStreamSink OutputDevice* GetOutputDevice() override; // AudioSourceCallback implementation. - int OnMoreData(AudioBus* dest, uint32 total_bytes_delay) override; + int OnMoreData(AudioBus* dest, + uint32_t total_bytes_delay, + uint32_t frames_skipped) override; void OnError(AudioOutputStream* stream) override; private: diff --git a/media/audio/audio_parameters.h b/media/audio/audio_parameters.h index c59dd30..f936881 100644 --- a/media/audio/audio_parameters.h +++ b/media/audio/audio_parameters.h @@ -19,25 +19,28 @@ namespace media { // Use a struct-in-struct approach to ensure that we can calculate the required -// size as sizeof(AudioInputBufferParameters) + #(bytes in audio buffer) without -// using packing. Also align AudioInputBufferParameters instead of in -// AudioInputBuffer to be able to calculate size like so. Use a macro for the -// alignment value that's the same as AudioBus::kChannelAlignment, since MSVC -// doesn't accept the latter to be used. +// size as sizeof(Audio{Input,Output}BufferParameters) + #(bytes in audio +// buffer) without using packing. Also align Audio{Input,Output}BufferParameters +// instead of in Audio{Input,Output}Buffer to be able to calculate size like so. +// Use a macro for the alignment value that's the same as +// AudioBus::kChannelAlignment, since MSVC doesn't accept the latter to be used. #if defined(OS_WIN) #pragma warning(push) #pragma warning(disable: 4324) // Disable warning for added padding. #endif #define PARAMETERS_ALIGNMENT 16 static_assert(AudioBus::kChannelAlignment == PARAMETERS_ALIGNMENT, - "AudioInputBufferParameters alignment not same as AudioBus"); + "Audio buffer parameters struct alignment not same as AudioBus"); struct MEDIA_EXPORT ALIGNAS(PARAMETERS_ALIGNMENT) AudioInputBufferParameters { double volume; - uint32 size; + uint32_t size; uint32_t hardware_delay_bytes; uint32_t id; bool key_pressed; }; +struct MEDIA_EXPORT ALIGNAS(PARAMETERS_ALIGNMENT) AudioOutputBufferParameters { + uint32_t frames_skipped; +}; #undef PARAMETERS_ALIGNMENT #if defined(OS_WIN) #pragma warning(pop) @@ -47,11 +50,19 @@ static_assert(sizeof(AudioInputBufferParameters) % AudioBus::kChannelAlignment == 0, "AudioInputBufferParameters not aligned"); +static_assert(sizeof(AudioOutputBufferParameters) % + AudioBus::kChannelAlignment == + 0, + "AudioOutputBufferParameters not aligned"); struct MEDIA_EXPORT AudioInputBuffer { AudioInputBufferParameters params; int8 audio[1]; }; +struct MEDIA_EXPORT AudioOutputBuffer { + AudioOutputBufferParameters params; + int8 audio[1]; +}; class MEDIA_EXPORT AudioParameters { public: diff --git a/media/audio/clockless_audio_sink.cc b/media/audio/clockless_audio_sink.cc index 940ab2e..33d6aff 100644 --- a/media/audio/clockless_audio_sink.cc +++ b/media/audio/clockless_audio_sink.cc @@ -49,7 +49,7 @@ class ClocklessAudioSinkThread : public base::DelegateSimpleThread::Delegate { void Run() override { base::TimeTicks start; while (!stop_event_->IsSignaled()) { - const int frames_received = callback_->Render(audio_bus_.get(), 0); + const int frames_received = callback_->Render(audio_bus_.get(), 0, 0); DCHECK_GE(frames_received, 0); if (audio_hash_) audio_hash_->Update(audio_bus_.get(), frames_received); diff --git a/media/audio/cras/cras_unified.cc b/media/audio/cras/cras_unified.cc index 1656624..180cfc1 100644 --- a/media/audio/cras/cras_unified.cc +++ b/media/audio/cras/cras_unified.cc @@ -306,7 +306,7 @@ uint32 CrasUnifiedStream::WriteAudio(size_t frames, cras_client_calc_playback_latency(sample_ts, &latency_ts); int frames_filled = source_callback_->OnMoreData( - output_bus_.get(), GetBytesLatency(latency_ts)); + output_bus_.get(), GetBytesLatency(latency_ts), 0); // Note: If this ever changes to output raw float the data must be clipped and // sanitized since it may come from an untrusted source such as NaCl. diff --git a/media/audio/cras/cras_unified_unittest.cc b/media/audio/cras/cras_unified_unittest.cc index 2f29bfa..64014c6 100644 --- a/media/audio/cras/cras_unified_unittest.cc +++ b/media/audio/cras/cras_unified_unittest.cc @@ -142,10 +142,10 @@ TEST_F(CrasUnifiedStreamTest, RenderFrames) { base::WaitableEvent event(false, false); - EXPECT_CALL(mock_callback, OnMoreData(_, _)) - .WillRepeatedly(DoAll( - InvokeWithoutArgs(&event, &base::WaitableEvent::Signal), - Return(kTestFramesPerPacket))); + EXPECT_CALL(mock_callback, OnMoreData(_, _, 0)) + .WillRepeatedly( + DoAll(InvokeWithoutArgs(&event, &base::WaitableEvent::Signal), + Return(kTestFramesPerPacket))); test_stream->Start(&mock_callback); diff --git a/media/audio/fake_audio_input_stream.cc b/media/audio/fake_audio_input_stream.cc index 458118da..d437d29 100644 --- a/media/audio/fake_audio_input_stream.cc +++ b/media/audio/fake_audio_input_stream.cc @@ -98,7 +98,7 @@ void FakeAudioInputStream::ReadAudioFromSource() { audio_source_ = ChooseSource(); const int kNoDelay = 0; - audio_source_->OnMoreData(audio_bus_.get(), kNoDelay); + audio_source_->OnMoreData(audio_bus_.get(), kNoDelay, 0); callback_->OnData(this, audio_bus_.get(), 0, 1.0); } diff --git a/media/audio/fake_audio_output_stream.cc b/media/audio/fake_audio_output_stream.cc index b919b84..d91d525 100644 --- a/media/audio/fake_audio_output_stream.cc +++ b/media/audio/fake_audio_output_stream.cc @@ -63,7 +63,7 @@ void FakeAudioOutputStream::GetVolume(double* volume) { void FakeAudioOutputStream::CallOnMoreData() { DCHECK(audio_manager_->GetWorkerTaskRunner()->BelongsToCurrentThread()); - callback_->OnMoreData(audio_bus_.get(), 0); + callback_->OnMoreData(audio_bus_.get(), 0, 0); } } // namespace media diff --git a/media/audio/mac/audio_auhal_mac.cc b/media/audio/mac/audio_auhal_mac.cc index 39c4610..4092a44 100644 --- a/media/audio/mac/audio_auhal_mac.cc +++ b/media/audio/mac/audio_auhal_mac.cc @@ -53,6 +53,7 @@ AUHALStream::AUHALStream(AudioManagerMac* manager, hardware_latency_frames_(0), stopped_(true), current_hardware_pending_bytes_(0), + current_lost_frames_(0), last_sample_time_(0.0), last_number_of_frames_(0), total_lost_frames_(0), @@ -248,11 +249,11 @@ void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) { } // Supply the input data and render the output data. - source_->OnMoreData( - dest, - current_hardware_pending_bytes_ + - frame_delay * params_.GetBytesPerFrame()); + source_->OnMoreData(dest, current_hardware_pending_bytes_ + + frame_delay * params_.GetBytesPerFrame(), + current_lost_frames_); dest->Scale(volume_); + current_lost_frames_ = 0; } // AUHAL callback. @@ -360,6 +361,7 @@ void AUHALStream::UpdatePlayoutTimestamp(const AudioTimeStamp* timestamp) { // glitch count etc and keep a record of the largest glitch. auto lost_frames = diff - last_number_of_frames_; total_lost_frames_ += lost_frames; + current_lost_frames_ += lost_frames; if (lost_frames > largest_glitch_frames_) largest_glitch_frames_ = lost_frames; ++glitches_detected_; diff --git a/media/audio/mac/audio_auhal_mac.h b/media/audio/mac/audio_auhal_mac.h index 0cd648a..351c662 100644 --- a/media/audio/mac/audio_auhal_mac.h +++ b/media/audio/mac/audio_auhal_mac.h @@ -126,6 +126,8 @@ class AUHALStream : public AudioOutputStream { // Gets the current playout latency value. double GetPlayoutLatency(const AudioTimeStamp* output_time_stamp); + // Updates playout timestamp, current lost frames, and total lost frames and + // glitches. void UpdatePlayoutTimestamp(const AudioTimeStamp* timestamp); // Called from the dtor and when the stream is reset. @@ -182,6 +184,11 @@ class AUHALStream : public AudioOutputStream { // Current buffer delay. Set by Render(). uint32 current_hardware_pending_bytes_; + // Lost frames not yet reported to the provider. Increased in + // UpdatePlayoutTimestamp() if any lost frame since last time. Forwarded to + // the provider and reset in ProvideInput(). + uint32_t current_lost_frames_; + // Stores the timestamp of the previous audio buffer requested by the OS. // We use this in combination with |last_number_of_frames_| to detect when // the OS has decided to skip rendering frames (i.e. a glitch). diff --git a/media/audio/mac/audio_auhal_mac_unittest.cc b/media/audio/mac/audio_auhal_mac_unittest.cc index b9c857d..14499b7 100644 --- a/media/audio/mac/audio_auhal_mac_unittest.cc +++ b/media/audio/mac/audio_auhal_mac_unittest.cc @@ -88,7 +88,7 @@ TEST_F(AUHALStreamTest, CreateOpenStartStopClose) { // Wait for the first data callback from the OS. base::WaitableEvent event(false, false); - EXPECT_CALL(source_, OnMoreData(_, _)) + EXPECT_CALL(source_, OnMoreData(_, _, _)) .WillOnce(DoAll(ZeroBuffer(), SignalEvent(&event), Return(0))); EXPECT_CALL(source_, OnError(_)).Times(0); stream->Start(&source_); diff --git a/media/audio/mock_audio_source_callback.h b/media/audio/mock_audio_source_callback.h index 9284d0bf..df661fc 100644 --- a/media/audio/mock_audio_source_callback.h +++ b/media/audio/mock_audio_source_callback.h @@ -15,8 +15,10 @@ class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback { MockAudioSourceCallback(); virtual ~MockAudioSourceCallback(); - MOCK_METHOD2(OnMoreData, int(AudioBus* audio_bus, - uint32 total_bytes_delay)); + MOCK_METHOD3(OnMoreData, + int(AudioBus* audio_bus, + uint32_t total_bytes_delay, + uint32_t frames_skipped)); MOCK_METHOD1(OnError, void(AudioOutputStream* stream)); private: diff --git a/media/audio/null_audio_sink.cc b/media/audio/null_audio_sink.cc index 5b043a0..e9f65fd4 100644 --- a/media/audio/null_audio_sink.cc +++ b/media/audio/null_audio_sink.cc @@ -82,7 +82,7 @@ OutputDevice* NullAudioSink::GetOutputDevice() { void NullAudioSink::CallRender() { DCHECK(task_runner_->BelongsToCurrentThread()); - int frames_received = callback_->Render(audio_bus_.get(), 0); + int frames_received = callback_->Render(audio_bus_.get(), 0, 0); if (!audio_hash_ || frames_received <= 0) return; diff --git a/media/audio/pulse/pulse_output.cc b/media/audio/pulse/pulse_output.cc index 0ba728d..1077e25 100644 --- a/media/audio/pulse/pulse_output.cc +++ b/media/audio/pulse/pulse_output.cc @@ -132,8 +132,8 @@ void PulseAudioOutputStream::FulfillWriteRequest(size_t requested_bytes) { if (source_callback_) { const uint32 hardware_delay = pulse::GetHardwareLatencyInBytes( pa_stream_, params_.sample_rate(), params_.GetBytesPerFrame()); - frames_filled = source_callback_->OnMoreData( - audio_bus_.get(), hardware_delay); + frames_filled = + source_callback_->OnMoreData(audio_bus_.get(), hardware_delay, 0); // Zero any unfilled data so it plays back as silence. if (frames_filled < audio_bus_->frames()) { diff --git a/media/audio/simple_sources.cc b/media/audio/simple_sources.cc index 4ded6bd..b75b96d 100644 --- a/media/audio/simple_sources.cc +++ b/media/audio/simple_sources.cc @@ -110,7 +110,8 @@ SineWaveAudioSource::~SineWaveAudioSource() { // The implementation could be more efficient if a lookup table is constructed // but it is efficient enough for our simple needs. int SineWaveAudioSource::OnMoreData(AudioBus* audio_bus, - uint32 total_bytes_delay) { + uint32_t total_bytes_delay, + uint32_t frames_skipped) { base::AutoLock auto_lock(time_lock_); callbacks_++; @@ -193,7 +194,9 @@ void FileSource::LoadWavFile(const base::FilePath& path_to_wav_file) { file_audio_converter_->AddInput(this); } -int FileSource::OnMoreData(AudioBus* audio_bus, uint32 total_bytes_delay) { +int FileSource::OnMoreData(AudioBus* audio_bus, + uint32_t total_bytes_delay, + uint32_t frames_skipped) { // Load the file if we haven't already. This load needs to happen on the // audio thread, otherwise we'll run on the UI thread on Mac for instance. // This will massively delay the first OnMoreData, but we'll catch up. @@ -242,7 +245,9 @@ BeepingSource::BeepingSource(const AudioParameters& params) BeepingSource::~BeepingSource() { } -int BeepingSource::OnMoreData(AudioBus* audio_bus, uint32 total_bytes_delay) { +int BeepingSource::OnMoreData(AudioBus* audio_bus, + uint32_t total_bytes_delay, + uint32_t frames_skipped) { // Accumulate the time from the last beep. interval_from_last_beep_ += base::TimeTicks::Now() - last_callback_time_; diff --git a/media/audio/simple_sources.h b/media/audio/simple_sources.h index 7a10a34..075b4a7 100644 --- a/media/audio/simple_sources.h +++ b/media/audio/simple_sources.h @@ -31,7 +31,9 @@ class MEDIA_EXPORT SineWaveAudioSource void Reset(); // Implementation of AudioSourceCallback. - int OnMoreData(AudioBus* audio_bus, uint32 total_bytes_delay) override; + int OnMoreData(AudioBus* audio_bus, + uint32_t total_bytes_delay, + uint32_t frames_skipped) override; void OnError(AudioOutputStream* stream) override; // The number of OnMoreData() and OnError() calls respectively. @@ -56,7 +58,9 @@ class MEDIA_EXPORT FileSource : public AudioOutputStream::AudioSourceCallback, ~FileSource() override; // Implementation of AudioSourceCallback. - int OnMoreData(AudioBus* audio_bus, uint32 total_bytes_delay) override; + int OnMoreData(AudioBus* audio_bus, + uint32_t total_bytes_delay, + uint32_t frames_skipped) override; void OnError(AudioOutputStream* stream) override; private: @@ -87,7 +91,9 @@ class BeepingSource : public AudioOutputStream::AudioSourceCallback { ~BeepingSource() override; // Implementation of AudioSourceCallback. - int OnMoreData(AudioBus* audio_bus, uint32 total_bytes_delay) override; + int OnMoreData(AudioBus* audio_bus, + uint32_t total_bytes_delay, + uint32_t frames_skipped) override; void OnError(AudioOutputStream* stream) override; static void BeepOnce(); diff --git a/media/audio/simple_sources_unittest.cc b/media/audio/simple_sources_unittest.cc index 8702af5..86963bc 100644 --- a/media/audio/simple_sources_unittest.cc +++ b/media/audio/simple_sources_unittest.cc @@ -28,7 +28,7 @@ TEST(SimpleSources, SineWaveAudioSource) { SineWaveAudioSource source(1, freq, params.sample_rate()); scoped_ptr<AudioBus> audio_bus = AudioBus::Create(params); - source.OnMoreData(audio_bus.get(), 0); + source.OnMoreData(audio_bus.get(), 0, 0); EXPECT_EQ(1, source.callbacks()); EXPECT_EQ(0, source.errors()); @@ -57,14 +57,12 @@ TEST(SimpleSources, SineWaveAudioCapped) { source.CapSamples(kSampleCap); scoped_ptr<AudioBus> audio_bus = AudioBus::Create(1, 2 * kSampleCap); - EXPECT_EQ(source.OnMoreData( - audio_bus.get(), 0), kSampleCap); + EXPECT_EQ(source.OnMoreData(audio_bus.get(), 0, 0), kSampleCap); EXPECT_EQ(1, source.callbacks()); - EXPECT_EQ(source.OnMoreData(audio_bus.get(), 0), 0); + EXPECT_EQ(source.OnMoreData(audio_bus.get(), 0, 0), 0); EXPECT_EQ(2, source.callbacks()); source.Reset(); - EXPECT_EQ(source.OnMoreData( - audio_bus.get(), 0), kSampleCap); + EXPECT_EQ(source.OnMoreData(audio_bus.get(), 0, 0), kSampleCap); EXPECT_EQ(3, source.callbacks()); EXPECT_EQ(0, source.errors()); } @@ -97,7 +95,7 @@ TEST(SimpleSources, FileSourceTestData) { // Create a FileSource that reads this file. FileSource source(params, temp_path); - EXPECT_EQ(kNumFrames, source.OnMoreData(audio_bus.get(), 0)); + EXPECT_EQ(kNumFrames, source.OnMoreData(audio_bus.get(), 0, 0)); // Convert the test data (little-endian) into floats and compare. const int kFirstSampleIndex = 12 + 8 + 16 + 8; @@ -133,7 +131,7 @@ TEST(SimpleSources, BadFilePathFails) { .Append(FILE_PATH_LITERAL("not")) .Append(FILE_PATH_LITERAL("exist")); FileSource source(params, path); - EXPECT_EQ(0, source.OnMoreData(audio_bus.get(), 0)); + EXPECT_EQ(0, source.OnMoreData(audio_bus.get(), 0, 0)); // Confirm all frames are zero-padded. for (int channel = 0; channel < audio_bus->channels(); ++channel) { @@ -167,7 +165,7 @@ TEST(SimpleSources, FileSourceCorruptTestDataFails) { // Create a FileSource that reads this file. FileSource source(params, temp_path); - EXPECT_EQ(0, source.OnMoreData(audio_bus.get(), 0)); + EXPECT_EQ(0, source.OnMoreData(audio_bus.get(), 0, 0)); // Confirm all frames are zero-padded. for (int channel = 0; channel < audio_bus->channels(); ++channel) { diff --git a/media/audio/sounds/audio_stream_handler.cc b/media/audio/sounds/audio_stream_handler.cc index ee27312..85ee6533 100644 --- a/media/audio/sounds/audio_stream_handler.cc +++ b/media/audio/sounds/audio_stream_handler.cc @@ -106,7 +106,9 @@ class AudioStreamHandler::AudioStreamContainer private: // AudioOutputStream::AudioSourceCallback overrides: // Following methods could be called from *ANY* thread. - int OnMoreData(AudioBus* dest, uint32 /* total_bytes_delay */) override { + int OnMoreData(AudioBus* dest, + uint32_t /* total_bytes_delay */, + uint32_t /* frames_skipped */) override { base::AutoLock al(state_lock_); size_t bytes_written = 0; diff --git a/media/audio/virtual_audio_input_stream_unittest.cc b/media/audio/virtual_audio_input_stream_unittest.cc index 06b3011..48a8e61 100644 --- a/media/audio/virtual_audio_input_stream_unittest.cc +++ b/media/audio/virtual_audio_input_stream_unittest.cc @@ -66,9 +66,11 @@ class TestAudioSource : public SineWaveAudioSource { ~TestAudioSource() override {} - int OnMoreData(AudioBus* audio_bus, uint32 total_bytes_delay) override { - const int ret = SineWaveAudioSource::OnMoreData(audio_bus, - total_bytes_delay); + int OnMoreData(AudioBus* audio_bus, + uint32_t total_bytes_delay, + uint32_t frames_skipped) override { + const int ret = SineWaveAudioSource::OnMoreData( + audio_bus, total_bytes_delay, frames_skipped); data_pulled_.Signal(); return ret; } diff --git a/media/audio/virtual_audio_output_stream.cc b/media/audio/virtual_audio_output_stream.cc index 29e3804..149f3cc 100644 --- a/media/audio/virtual_audio_output_stream.cc +++ b/media/audio/virtual_audio_output_stream.cc @@ -82,7 +82,7 @@ double VirtualAudioOutputStream::ProvideInput(AudioBus* audio_bus, params_.GetBytesPerSecond() * buffer_delay / base::TimeDelta::FromSeconds(1); const int frames = callback_->OnMoreData( - audio_bus, static_cast<uint32>(upstream_delay_in_bytes)); + audio_bus, static_cast<uint32>(upstream_delay_in_bytes), 0); if (frames < audio_bus->frames()) audio_bus->ZeroFramesPartial(frames, audio_bus->frames() - frames); diff --git a/media/audio/win/audio_low_latency_output_win.cc b/media/audio/win/audio_low_latency_output_win.cc index 829d18f..9ead48a 100644 --- a/media/audio/win/audio_low_latency_output_win.cc +++ b/media/audio/win/audio_low_latency_output_win.cc @@ -532,8 +532,8 @@ bool WASAPIAudioOutputStream::RenderAudioFromSource(UINT64 device_frequency) { // Read a data packet from the registered client source and // deliver a delay estimate in the same callback to the client. - int frames_filled = source_->OnMoreData( - audio_bus_.get(), audio_delay_bytes); + int frames_filled = + source_->OnMoreData(audio_bus_.get(), audio_delay_bytes, 0); uint32 num_filled_bytes = frames_filled * format_.Format.nBlockAlign; DCHECK_LE(num_filled_bytes, packet_size_bytes_); diff --git a/media/audio/win/audio_low_latency_output_win_unittest.cc b/media/audio/win/audio_low_latency_output_win_unittest.cc index 5c2d457..8f30411 100644 --- a/media/audio/win/audio_low_latency_output_win_unittest.cc +++ b/media/audio/win/audio_low_latency_output_win_unittest.cc @@ -103,7 +103,9 @@ class ReadFromFileAudioSource : public AudioOutputStream::AudioSourceCallback { } // AudioOutputStream::AudioSourceCallback implementation. - int OnMoreData(AudioBus* audio_bus, uint32 total_bytes_delay) override { + int OnMoreData(AudioBus* audio_bus, + uint32_t total_bytes_delay, + uint32_t frames_skipped) override { // Store time difference between two successive callbacks in an array. // These values will be written to a file in the destructor. const base::TimeTicks now_time = base::TimeTicks::Now(); @@ -382,7 +384,7 @@ TEST(WASAPIAudioOutputStreamTest, ValidPacketSize) { // Wait for the first callback and verify its parameters. Ignore any // subsequent callbacks that might arrive. - EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(bytes_per_packet))) + EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(bytes_per_packet), 0)) .WillOnce(DoAll(QuitLoop(loop.task_runner()), Return(aosw.samples_per_packet()))) .WillRepeatedly(Return(0)); @@ -576,7 +578,7 @@ TEST(WASAPIAudioOutputStreamTest, DISABLED_ExclusiveModeMinBufferSizeAt48kHz) { (aosw.bits_per_sample() / 8); // Wait for the first callback and verify its parameters. - EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(bytes_per_packet))) + EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(bytes_per_packet), 0)) .WillOnce(DoAll(QuitLoop(loop.task_runner()), Return(aosw.samples_per_packet()))) .WillRepeatedly(Return(aosw.samples_per_packet())); @@ -610,7 +612,7 @@ TEST(WASAPIAudioOutputStreamTest, DISABLED_ExclusiveModeMinBufferSizeAt44kHz) { (aosw.bits_per_sample() / 8); // Wait for the first callback and verify its parameters. - EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(bytes_per_packet))) + EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(bytes_per_packet), 0)) .WillOnce(DoAll(QuitLoop(loop.task_runner()), Return(aosw.samples_per_packet()))) .WillRepeatedly(Return(aosw.samples_per_packet())); diff --git a/media/audio/win/audio_output_win_unittest.cc b/media/audio/win/audio_output_win_unittest.cc index 68f61ea..1028488 100644 --- a/media/audio/win/audio_output_win_unittest.cc +++ b/media/audio/win/audio_output_win_unittest.cc @@ -32,7 +32,9 @@ using ::testing::Return; namespace media { -static int ClearData(AudioBus* audio_bus, uint32 total_bytes_delay) { +static int ClearData(AudioBus* audio_bus, + uint32_t total_bytes_delay, + uint32_t frames_skipped) { audio_bus->Zero(); return audio_bus->frames(); } @@ -46,7 +48,9 @@ class TestSourceBasic : public AudioOutputStream::AudioSourceCallback { had_error_(0) { } // AudioSourceCallback::OnMoreData implementation: - int OnMoreData(AudioBus* audio_bus, uint32 total_bytes_delay) override { + int OnMoreData(AudioBus* audio_bus, + uint32_t total_bytes_delay, + uint32_t frames_skipped) override { ++callback_count_; // Touch the channel memory value to make sure memory is good. audio_bus->Zero(); @@ -80,9 +84,11 @@ class TestSourceLaggy : public TestSourceBasic { explicit TestSourceLaggy(int lag_in_ms) : lag_in_ms_(lag_in_ms) { } - int OnMoreData(AudioBus* audio_bus, uint32 total_bytes_delay) override { + int OnMoreData(AudioBus* audio_bus, + uint32_t total_bytes_delay, + uint32_t frames_skipped) override { // Call the base, which increments the callback_count_. - TestSourceBasic::OnMoreData(audio_bus, total_bytes_delay); + TestSourceBasic::OnMoreData(audio_bus, total_bytes_delay, frames_skipped); if (callback_count() > kMaxNumBuffers) { ::Sleep(lag_in_ms_); } @@ -474,22 +480,21 @@ TEST(WinAudioTest, PCMWaveStreamPendingBytes) { // pending bytes will go down and eventually read zero. InSequence s; - EXPECT_CALL(source, OnMoreData(NotNull(), 0)) - .WillOnce(Invoke(ClearData)); + EXPECT_CALL(source, OnMoreData(NotNull(), 0, 0)).WillOnce(Invoke(ClearData)); // Note: If AudioManagerWin::NumberOfWaveOutBuffers() ever changes, or if this // test is run on Vista, these expectations will fail. - EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms)) + EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms, 0)) .WillOnce(Invoke(ClearData)); - EXPECT_CALL(source, OnMoreData(NotNull(), 2 * bytes_100_ms)) + EXPECT_CALL(source, OnMoreData(NotNull(), 2 * bytes_100_ms, 0)) .WillOnce(Invoke(ClearData)); - EXPECT_CALL(source, OnMoreData(NotNull(), 2 * bytes_100_ms)) + EXPECT_CALL(source, OnMoreData(NotNull(), 2 * bytes_100_ms, 0)) .Times(AnyNumber()) .WillRepeatedly(Return(0)); - EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms)) + EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms, 0)) .Times(AnyNumber()) .WillRepeatedly(Return(0)); - EXPECT_CALL(source, OnMoreData(NotNull(), 0)) + EXPECT_CALL(source, OnMoreData(NotNull(), 0, 0)) .Times(AnyNumber()) .WillRepeatedly(Return(0)); @@ -514,7 +519,9 @@ class SyncSocketSource : public AudioOutputStream::AudioSourceCallback { ~SyncSocketSource() override {} // AudioSourceCallback::OnMoreData implementation: - int OnMoreData(AudioBus* audio_bus, uint32 total_bytes_delay) override { + int OnMoreData(AudioBus* audio_bus, + uint32_t total_bytes_delay, + uint32_t frames_skipped) override { socket_->Send(&total_bytes_delay, sizeof(total_bytes_delay)); uint32 size = socket_->Receive(data_.get(), data_size_); DCHECK_EQ(static_cast<size_t>(size) % sizeof(*audio_bus_->channel(0)), 0U); @@ -565,7 +572,7 @@ DWORD __stdcall SyncSocketThread(void* context) { if (ctx.socket->Receive(&total_bytes_delay, sizeof(total_bytes_delay)) == 0) break; if ((times > 0) && (total_bytes_delay < 1000)) __debugbreak(); - sine.OnMoreData(audio_bus.get(), total_bytes_delay); + sine.OnMoreData(audio_bus.get(), total_bytes_delay, 0); ctx.socket->Send(data.get(), ctx.packet_size_bytes); ++times; } diff --git a/media/audio/win/waveout_output_win.cc b/media/audio/win/waveout_output_win.cc index 5be9e0a..456124d 100644 --- a/media/audio/win/waveout_output_win.cc +++ b/media/audio/win/waveout_output_win.cc @@ -327,8 +327,8 @@ void PCMWaveOutAudioOutputStream::QueueNextPacket(WAVEHDR *buffer) { // TODO(sergeyu): Specify correct hardware delay for |total_delay_bytes|. uint32 total_delay_bytes = pending_bytes_; - int frames_filled = callback_->OnMoreData( - audio_bus_.get(), total_delay_bytes); + int frames_filled = + callback_->OnMoreData(audio_bus_.get(), total_delay_bytes, 0); uint32 used = frames_filled * audio_bus_->channels() * format_.Format.wBitsPerSample / 8; diff --git a/media/base/audio_bus_perftest.cc b/media/base/audio_bus_perftest.cc index 71e8132..c126d99 100644 --- a/media/base/audio_bus_perftest.cc +++ b/media/base/audio_bus_perftest.cc @@ -43,7 +43,7 @@ void RunInterleaveBench(AudioBus* bus, const std::string& trace_name) { TEST(AudioBusPerfTest, Interleave) { scoped_ptr<AudioBus> bus = AudioBus::Create(2, 48000 * 120); FakeAudioRenderCallback callback(0.2); - callback.Render(bus.get(), 0); + callback.Render(bus.get(), 0, 0); RunInterleaveBench<int8>(bus.get(), "int8"); RunInterleaveBench<int16>(bus.get(), "int16"); diff --git a/media/base/audio_converter_unittest.cc b/media/base/audio_converter_unittest.cc index 741027f..d427923 100644 --- a/media/base/audio_converter_unittest.cc +++ b/media/base/audio_converter_unittest.cc @@ -111,7 +111,7 @@ class AudioConverterTest converter_->Convert(audio_bus_.get()); // Render expected audio data. - expected_callback_->Render(expected_audio_bus_.get(), 0); + expected_callback_->Render(expected_audio_bus_.get(), 0, 0); // Zero out unused channels in the expected AudioBus just as AudioConverter // would during channel mixing. diff --git a/media/base/audio_hash_unittest.cc b/media/base/audio_hash_unittest.cc index 1adf5bc..742deed 100644 --- a/media/base/audio_hash_unittest.cc +++ b/media/base/audio_hash_unittest.cc @@ -34,7 +34,7 @@ class AudioHashTest : public testing::Test { // audio data, we need to fill each channel manually. for (int ch = 0; ch < audio_bus->channels(); ++ch) { wrapped_bus->SetChannelData(0, audio_bus->channel(ch)); - fake_callback_.Render(wrapped_bus.get(), 0); + fake_callback_.Render(wrapped_bus.get(), 0, 0); } } diff --git a/media/base/audio_renderer_mixer.cc b/media/base/audio_renderer_mixer.cc index 26171f9..218bb9e 100644 --- a/media/base/audio_renderer_mixer.cc +++ b/media/base/audio_renderer_mixer.cc @@ -117,7 +117,8 @@ OutputDevice* AudioRendererMixer::GetOutputDevice() { } int AudioRendererMixer::Render(AudioBus* audio_bus, - int audio_delay_milliseconds) { + uint32_t audio_delay_milliseconds, + uint32_t frames_skipped) { base::AutoLock auto_lock(lock_); // If there are no mixer inputs and we haven't seen one for a while, pause the diff --git a/media/base/audio_renderer_mixer.h b/media/base/audio_renderer_mixer.h index e8a0f8d..80e9d9b 100644 --- a/media/base/audio_renderer_mixer.h +++ b/media/base/audio_renderer_mixer.h @@ -54,7 +54,9 @@ class MEDIA_EXPORT AudioRendererMixer typedef std::map<int, scoped_ptr<LoopbackAudioConverter>> AudioConvertersMap; // AudioRendererSink::RenderCallback implementation. - int Render(AudioBus* audio_bus, int audio_delay_milliseconds) override; + int Render(AudioBus* audio_bus, + uint32_t audio_delay_milliseconds, + uint32_t frames_skipped) override; void OnRenderError() override; bool is_master_sample_rate(int sample_rate) { diff --git a/media/base/audio_renderer_mixer_input.cc b/media/base/audio_renderer_mixer_input.cc index 539cdf3..d0d38d3 100644 --- a/media/base/audio_renderer_mixer_input.cc +++ b/media/base/audio_renderer_mixer_input.cc @@ -166,7 +166,7 @@ OutputDeviceStatus AudioRendererMixerInput::GetDeviceStatus() { double AudioRendererMixerInput::ProvideInput(AudioBus* audio_bus, base::TimeDelta buffer_delay) { int frames_filled = callback_->Render( - audio_bus, static_cast<int>(buffer_delay.InMillisecondsF() + 0.5)); + audio_bus, static_cast<int>(buffer_delay.InMillisecondsF() + 0.5), 0); // AudioConverter expects unfilled frames to be zeroed. if (frames_filled < audio_bus->frames()) { diff --git a/media/base/audio_renderer_mixer_unittest.cc b/media/base/audio_renderer_mixer_unittest.cc index bae2ebb..8f45c2b 100644 --- a/media/base/audio_renderer_mixer_unittest.cc +++ b/media/base/audio_renderer_mixer_unittest.cc @@ -156,12 +156,12 @@ class AudioRendererMixerTest } // Render actual audio data. - int frames = mixer_callback_->Render(audio_bus_.get(), 0); + int frames = mixer_callback_->Render(audio_bus_.get(), 0, 0); if (frames != audio_bus_->frames()) return false; // Render expected audio data (without scaling). - expected_callback_->Render(expected_audio_bus_.get(), 0); + expected_callback_->Render(expected_audio_bus_.get(), 0, 0); if (half_fill_) { // In this case, just verify that every frame was initialized, this will @@ -486,7 +486,7 @@ TEST_P(AudioRendererMixerBehavioralTest, MixerPausesStream) { const base::TimeDelta kSleepTime = base::TimeDelta::FromMilliseconds(100); base::TimeTicks start_time = base::TimeTicks::Now(); while (!pause_event.IsSignaled()) { - mixer_callback_->Render(audio_bus_.get(), 0); + mixer_callback_->Render(audio_bus_.get(), 0, 0); base::PlatformThread::Sleep(kSleepTime); ASSERT_TRUE(base::TimeTicks::Now() - start_time < kTestTimeout); } @@ -501,7 +501,7 @@ TEST_P(AudioRendererMixerBehavioralTest, MixerPausesStream) { // Ensure once the input is paused the sink eventually pauses. start_time = base::TimeTicks::Now(); while (!pause_event.IsSignaled()) { - mixer_callback_->Render(audio_bus_.get(), 0); + mixer_callback_->Render(audio_bus_.get(), 0, 0); base::PlatformThread::Sleep(kSleepTime); ASSERT_TRUE(base::TimeTicks::Now() - start_time < kTestTimeout); } diff --git a/media/base/audio_renderer_sink.h b/media/base/audio_renderer_sink.h index 30cbfef..b45c0fc 100644 --- a/media/base/audio_renderer_sink.h +++ b/media/base/audio_renderer_sink.h @@ -35,8 +35,11 @@ class AudioRendererSink class RenderCallback { public: // Attempts to completely fill all channels of |dest|, returns actual - // number of frames filled. - virtual int Render(AudioBus* dest, int audio_delay_milliseconds) = 0; + // number of frames filled. |frames_skipped| contains the number of frames + // the consumer has skipped, if any. + virtual int Render(AudioBus* dest, + uint32_t audio_delay_milliseconds, + uint32_t frames_skipped) = 0; // Signals an error has occurred. virtual void OnRenderError() = 0; diff --git a/media/base/fake_audio_render_callback.cc b/media/base/fake_audio_render_callback.cc index 73d606e..8d7ef20 100644 --- a/media/base/fake_audio_render_callback.cc +++ b/media/base/fake_audio_render_callback.cc @@ -23,7 +23,8 @@ FakeAudioRenderCallback::FakeAudioRenderCallback(double step) FakeAudioRenderCallback::~FakeAudioRenderCallback() {} int FakeAudioRenderCallback::Render(AudioBus* audio_bus, - int audio_delay_milliseconds) { + uint32_t audio_delay_milliseconds, + uint32_t frames_skipped) { last_audio_delay_milliseconds_ = audio_delay_milliseconds; last_channel_count_ = audio_bus->channels(); @@ -46,7 +47,7 @@ int FakeAudioRenderCallback::Render(AudioBus* audio_bus, double FakeAudioRenderCallback::ProvideInput(AudioBus* audio_bus, base::TimeDelta buffer_delay) { - Render(audio_bus, buffer_delay.InMillisecondsF() + 0.5); + Render(audio_bus, buffer_delay.InMillisecondsF() + 0.5, 0); return volume_; } diff --git a/media/base/fake_audio_render_callback.h b/media/base/fake_audio_render_callback.h index 65d7df2..49d64ba 100644 --- a/media/base/fake_audio_render_callback.h +++ b/media/base/fake_audio_render_callback.h @@ -26,7 +26,9 @@ class FakeAudioRenderCallback // Renders a sine wave into the provided audio data buffer. If |half_fill_| // is set, will only fill half the buffer. - int Render(AudioBus* audio_bus, int audio_delay_milliseconds) override; + int Render(AudioBus* audio_bus, + uint32_t audio_delay_milliseconds, + uint32_t frames_skipped) override; MOCK_METHOD0(OnRenderError, void()); // AudioTransform::ProvideAudioTransformInput implementation. diff --git a/media/base/fake_audio_renderer_sink.cc b/media/base/fake_audio_renderer_sink.cc index d8a7262..5ce6074 100644 --- a/media/base/fake_audio_renderer_sink.cc +++ b/media/base/fake_audio_renderer_sink.cc @@ -60,12 +60,13 @@ OutputDevice* FakeAudioRendererSink::GetOutputDevice() { return output_device_.get(); } -bool FakeAudioRendererSink::Render(AudioBus* dest, int audio_delay_milliseconds, +bool FakeAudioRendererSink::Render(AudioBus* dest, + uint32_t audio_delay_milliseconds, int* frames_written) { if (state_ != kPlaying) return false; - *frames_written = callback_->Render(dest, audio_delay_milliseconds); + *frames_written = callback_->Render(dest, audio_delay_milliseconds, 0); return true; } diff --git a/media/base/fake_audio_renderer_sink.h b/media/base/fake_audio_renderer_sink.h index 0a9bd93..765257d 100644 --- a/media/base/fake_audio_renderer_sink.h +++ b/media/base/fake_audio_renderer_sink.h @@ -43,7 +43,8 @@ class FakeAudioRendererSink : public AudioRendererSink { // Returns false if this object is in a state where calling Render() // should not occur. (i.e., in the kPaused or kStopped state.) The // value of |frames_written| is undefined if false is returned. - bool Render(AudioBus* dest, int audio_delay_milliseconds, + bool Render(AudioBus* dest, + uint32_t audio_delay_milliseconds, int* frames_written); void OnRenderError(); diff --git a/media/blink/webaudiosourceprovider_impl.cc b/media/blink/webaudiosourceprovider_impl.cc index ddc79fe..0276a7b 100644 --- a/media/blink/webaudiosourceprovider_impl.cc +++ b/media/blink/webaudiosourceprovider_impl.cc @@ -114,7 +114,7 @@ void WebAudioSourceProviderImpl::provideInput( DCHECK(renderer_); DCHECK(client_); DCHECK_EQ(channels_, bus_wrapper_->channels()); - const int frames = renderer_->Render(bus_wrapper_.get(), 0); + const int frames = renderer_->Render(bus_wrapper_.get(), 0, 0); if (frames < static_cast<int>(number_of_frames)) { bus_wrapper_->ZeroFramesPartial( frames, diff --git a/media/blink/webaudiosourceprovider_impl_unittest.cc b/media/blink/webaudiosourceprovider_impl_unittest.cc index c0d6070..fddabbc 100644 --- a/media/blink/webaudiosourceprovider_impl_unittest.cc +++ b/media/blink/webaudiosourceprovider_impl_unittest.cc @@ -197,7 +197,7 @@ TEST_F(WebAudioSourceProviderImplTest, ProvideInput) { // Ensure volume adjustment is working. fake_callback_.reset(); - fake_callback_.Render(bus2.get(), 0); + fake_callback_.Render(bus2.get(), 0, 0); bus2->Scale(kTestVolume); fake_callback_.reset(); @@ -216,9 +216,9 @@ TEST_F(WebAudioSourceProviderImplTest, ProvideInput) { // configuring the fake callback to return half the data. After these calls // bus1 is full of junk data, and bus2 is partially filled. wasp_impl_->SetVolume(1); - fake_callback_.Render(bus1.get(), 0); + fake_callback_.Render(bus1.get(), 0, 0); fake_callback_.reset(); - fake_callback_.Render(bus2.get(), 0); + fake_callback_.Render(bus2.get(), 0, 0); bus2->ZeroFramesPartial(bus2->frames() / 2, bus2->frames() - bus2->frames() / 2); fake_callback_.reset(); diff --git a/media/cast/test/receiver.cc b/media/cast/test/receiver.cc index 6c07e37..ed069b6 100644 --- a/media/cast/test/receiver.cc +++ b/media/cast/test/receiver.cc @@ -316,7 +316,9 @@ class NaivePlayer : public InProcessReceiver, //////////////////////////////////////////////////////////////////// // AudioSourceCallback implementation. - int OnMoreData(AudioBus* dest, uint32 total_bytes_delay) final { + int OnMoreData(AudioBus* dest, + uint32_t total_bytes_delay, + uint32_t frames_skipped) final { // Note: This method is being invoked by a separate thread unknown to us // (i.e., outside of CastEnvironment). diff --git a/media/cast/test/utility/audio_utility.cc b/media/cast/test/utility/audio_utility.cc index 094f141..41ecd15 100644 --- a/media/cast/test/utility/audio_utility.cc +++ b/media/cast/test/utility/audio_utility.cc @@ -36,7 +36,7 @@ scoped_ptr<AudioBus> TestAudioBusFactory::NextAudioBus( const int num_samples = static_cast<int>((sample_rate_ * duration) / base::TimeDelta::FromSeconds(1)); scoped_ptr<AudioBus> bus(AudioBus::Create(num_channels_, num_samples)); - source_.OnMoreData(bus.get(), 0); + source_.OnMoreData(bus.get(), 0, 0); bus->Scale(volume_); return bus.Pass(); } diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc index db1948e..424b2d3 100644 --- a/media/renderers/audio_renderer_impl.cc +++ b/media/renderers/audio_renderer_impl.cc @@ -626,7 +626,8 @@ bool AudioRendererImpl::IsBeforeStartTime( } int AudioRendererImpl::Render(AudioBus* audio_bus, - int audio_delay_milliseconds) { + uint32_t audio_delay_milliseconds, + uint32_t frames_skipped) { const int requested_frames = audio_bus->frames(); base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( audio_delay_milliseconds); diff --git a/media/renderers/audio_renderer_impl.h b/media/renderers/audio_renderer_impl.h index de0cbda..7674851 100644 --- a/media/renderers/audio_renderer_impl.h +++ b/media/renderers/audio_renderer_impl.h @@ -151,7 +151,9 @@ class MEDIA_EXPORT AudioRendererImpl // timestamp in the pipeline will be ahead of the actual audio playback. In // this case |audio_delay_milliseconds| should be used to indicate when in the // future should the filled buffer be played. - int Render(AudioBus* audio_bus, int audio_delay_milliseconds) override; + int Render(AudioBus* audio_bus, + uint32_t audio_delay_milliseconds, + uint32_t frames_skipped) override; void OnRenderError() override; // Helper methods that schedule an asynchronous read from the decoder as long |