Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1170)

Unified Diff: media/audio/win/audio_low_latency_output_win.cc

Issue 1318933003: Fix audio glitching on Vista due to unreliable OS callbacks. (Closed) Base URL: http://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Typo. Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/audio/win/audio_low_latency_output_win.cc
diff --git a/media/audio/win/audio_low_latency_output_win.cc b/media/audio/win/audio_low_latency_output_win.cc
index c297acc6d54c87c0c6c5e8bf0184484d09fe4c69..829d18fdbabe6ebd50e3a463625303480f8e7c23 100644
--- a/media/audio/win/audio_low_latency_output_win.cc
+++ b/media/audio/win/audio_low_latency_output_win.cc
@@ -472,69 +472,88 @@ bool WASAPIAudioOutputStream::RenderAudioFromSource(UINT64 device_frequency) {
}
// Check if there is enough available space to fit the packet size
- // specified by the client, wait until a future callback.
+ // specified by the client. If not, wait until a future callback.
if (num_available_frames < packet_size_frames_)
return true;
- // Grab all available space in the rendering endpoint buffer
- // into which the client can write a data packet.
- hr = audio_render_client_->GetBuffer(packet_size_frames_,
- &audio_data);
- if (FAILED(hr)) {
- DLOG(ERROR) << "Failed to use rendering audio buffer: "
- << std::hex << hr;
- return false;
- }
+ // Derive the number of packets we need to get from the client to fill up the
+ // available area in the endpoint buffer. Well-behaved (> Vista) clients and
+ // exclusive mode streams should generally have a |num_packets| value of 1.
+ //
+ // Vista clients are not able to maintain reliable callbacks, so the endpoint
+ // buffer may exhaust itself such that back-to-back callbacks are occasionally
+ // necessary to avoid glitches. In such cases we have no choice but to issue
+ // back-to-back reads and pray that the browser side has enough data cached or
+ // that the render can fulfill the read before we glitch anyways.
tommi (sloooow) - chröme 2015/09/03 08:31:28 Can we record some sort of stats to see how often
DaleCurtis 2015/09/03 16:36:31 It's tracked by Media.AudioRendererMissedDeadline
+ //
+ // API documentation does not guarantee that even on Win7+ clients we won't
+ // need to fill more than a period size worth of buffers; but in practice this
+ // appears to be infrequent.
+ //
+ // See http://crbug.com/524947.
+ const size_t num_packets = num_available_frames / packet_size_frames_;
+ for (size_t n = 0; n < num_packets; ++n) {
+ // Grab all available space in the rendering endpoint buffer
+ // into which the client can write a data packet.
+ hr = audio_render_client_->GetBuffer(packet_size_frames_,
+ &audio_data);
+ if (FAILED(hr)) {
+ DLOG(ERROR) << "Failed to use rendering audio buffer: "
+ << std::hex << hr;
+ return false;
+ }
+
+ // Derive the audio delay which corresponds to the delay between
+ // a render event and the time when the first audio sample in a
+ // packet is played out through the speaker. This delay value
+ // can typically be utilized by an acoustic echo-control (AEC)
+ // unit at the render side.
+ UINT64 position = 0;
+ uint32 audio_delay_bytes = 0;
+ hr = audio_clock_->GetPosition(&position, NULL);
+ if (SUCCEEDED(hr)) {
+ // Stream position of the sample that is currently playing
+ // through the speaker.
+ double pos_sample_playing_frames = format_.Format.nSamplesPerSec *
+ (static_cast<double>(position) / device_frequency);
+
+ // Stream position of the last sample written to the endpoint
+ // buffer. Note that, the packet we are about to receive in
+ // the upcoming callback is also included.
+ size_t pos_last_sample_written_frames =
+ num_written_frames_ + packet_size_frames_;
+
+ // Derive the actual delay value which will be fed to the
+ // render client using the OnMoreData() callback.
+ audio_delay_bytes = (pos_last_sample_written_frames -
+ pos_sample_playing_frames) * format_.Format.nBlockAlign;
+ }
- // Derive the audio delay which corresponds to the delay between
- // a render event and the time when the first audio sample in a
- // packet is played out through the speaker. This delay value
- // can typically be utilized by an acoustic echo-control (AEC)
- // unit at the render side.
- UINT64 position = 0;
- uint32 audio_delay_bytes = 0;
- hr = audio_clock_->GetPosition(&position, NULL);
- if (SUCCEEDED(hr)) {
- // Stream position of the sample that is currently playing
- // through the speaker.
- double pos_sample_playing_frames = format_.Format.nSamplesPerSec *
- (static_cast<double>(position) / device_frequency);
-
- // Stream position of the last sample written to the endpoint
- // buffer. Note that, the packet we are about to receive in
- // the upcoming callback is also included.
- size_t pos_last_sample_written_frames =
- num_written_frames_ + packet_size_frames_;
-
- // Derive the actual delay value which will be fed to the
- // render client using the OnMoreData() callback.
- audio_delay_bytes = (pos_last_sample_written_frames -
- pos_sample_playing_frames) * format_.Format.nBlockAlign;
+ // 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);
+ uint32 num_filled_bytes = frames_filled * format_.Format.nBlockAlign;
+ DCHECK_LE(num_filled_bytes, packet_size_bytes_);
+
+ // 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.
+ const int bytes_per_sample = format_.Format.wBitsPerSample >> 3;
+ audio_bus_->Scale(volume_);
+ audio_bus_->ToInterleaved(
+ frames_filled, bytes_per_sample, audio_data);
+
+ // Release the buffer space acquired in the GetBuffer() call.
+ // Render silence if we were not able to fill up the buffer totally.
+ DWORD flags = (num_filled_bytes < packet_size_bytes_) ?
+ AUDCLNT_BUFFERFLAGS_SILENT : 0;
+ audio_render_client_->ReleaseBuffer(packet_size_frames_, flags);
+
+ num_written_frames_ += packet_size_frames_;
}
- // 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);
- uint32 num_filled_bytes = frames_filled * format_.Format.nBlockAlign;
- DCHECK_LE(num_filled_bytes, packet_size_bytes_);
-
- // 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.
- const int bytes_per_sample = format_.Format.wBitsPerSample >> 3;
- audio_bus_->Scale(volume_);
- audio_bus_->ToInterleaved(
- frames_filled, bytes_per_sample, audio_data);
-
- // Release the buffer space acquired in the GetBuffer() call.
- // Render silence if we were not able to fill up the buffer totally.
- DWORD flags = (num_filled_bytes < packet_size_bytes_) ?
- AUDCLNT_BUFFERFLAGS_SILENT : 0;
- audio_render_client_->ReleaseBuffer(packet_size_frames_, flags);
-
- num_written_frames_ += packet_size_frames_;
return true;
}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698