Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_sync_reader.cc
blob3daacca566ea499a15e294cd3ffffd3ef3a06917
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/media/audio_sync_reader.h"
7 #include <algorithm>
9 #include "base/command_line.h"
10 #include "base/memory/shared_memory.h"
11 #include "base/metrics/histogram.h"
12 #include "content/public/common/content_switches.h"
13 #include "media/audio/audio_buffers_state.h"
14 #include "media/audio/audio_parameters.h"
16 using media::AudioBus;
18 namespace content {
20 AudioSyncReader::AudioSyncReader(base::SharedMemory* shared_memory,
21 const media::AudioParameters& params)
22 : shared_memory_(shared_memory),
23 mute_audio_(CommandLine::ForCurrentProcess()->HasSwitch(
24 switches::kMuteAudio)),
25 packet_size_(shared_memory_->requested_size()),
26 renderer_callback_count_(0),
27 renderer_missed_callback_count_(0),
28 #if defined(OS_MACOSX)
29 maximum_wait_time_(params.GetBufferDuration() / 2),
30 #else
31 // TODO(dalecurtis): Investigate if we can reduce this on all platforms.
32 maximum_wait_time_(base::TimeDelta::FromMilliseconds(20)),
33 #endif
34 buffer_index_(0) {
35 DCHECK_EQ(packet_size_, AudioBus::CalculateMemorySize(params));
36 output_bus_ = AudioBus::WrapMemory(params, shared_memory->memory());
37 output_bus_->Zero();
40 AudioSyncReader::~AudioSyncReader() {
41 if (!renderer_callback_count_)
42 return;
44 // Recording the percentage of deadline misses gives us a rough overview of
45 // how many users might be running into audio glitches.
46 int percentage_missed =
47 100.0 * renderer_missed_callback_count_ / renderer_callback_count_;
48 UMA_HISTOGRAM_PERCENTAGE(
49 "Media.AudioRendererMissedDeadline", percentage_missed);
52 // media::AudioOutputController::SyncReader implementations.
53 void AudioSyncReader::UpdatePendingBytes(uint32 bytes) {
54 // Zero out the entire output buffer to avoid stuttering/repeating-buffers
55 // in the anomalous case if the renderer is unable to keep up with real-time.
56 output_bus_->Zero();
57 socket_->Send(&bytes, sizeof(bytes));
58 ++buffer_index_;
61 void AudioSyncReader::Read(AudioBus* dest) {
62 ++renderer_callback_count_;
63 if (!WaitUntilDataIsReady()) {
64 ++renderer_missed_callback_count_;
65 dest->Zero();
66 return;
69 if (mute_audio_)
70 dest->Zero();
71 else
72 output_bus_->CopyTo(dest);
75 void AudioSyncReader::Close() {
76 socket_->Close();
79 bool AudioSyncReader::Init() {
80 socket_.reset(new base::CancelableSyncSocket());
81 foreign_socket_.reset(new base::CancelableSyncSocket());
82 return base::CancelableSyncSocket::CreatePair(socket_.get(),
83 foreign_socket_.get());
86 #if defined(OS_WIN)
87 bool AudioSyncReader::PrepareForeignSocketHandle(
88 base::ProcessHandle process_handle,
89 base::SyncSocket::Handle* foreign_handle) {
90 ::DuplicateHandle(GetCurrentProcess(), foreign_socket_->handle(),
91 process_handle, foreign_handle,
92 0, FALSE, DUPLICATE_SAME_ACCESS);
93 return (*foreign_handle != 0);
95 #else
96 bool AudioSyncReader::PrepareForeignSocketHandle(
97 base::ProcessHandle process_handle,
98 base::FileDescriptor* foreign_handle) {
99 foreign_handle->fd = foreign_socket_->handle();
100 foreign_handle->auto_close = false;
101 return (foreign_handle->fd != -1);
103 #endif
105 bool AudioSyncReader::WaitUntilDataIsReady() {
106 base::TimeDelta timeout = maximum_wait_time_;
107 const base::TimeTicks start_time = base::TimeTicks::Now();
108 const base::TimeTicks finish_time = start_time + timeout;
110 // Check if data is ready and if not, wait a reasonable amount of time for it.
112 // Data readiness is achieved via parallel counters, one on the renderer side
113 // and one here. Every time a buffer is requested via UpdatePendingBytes(),
114 // |buffer_index_| is incremented. Subsequently every time the renderer has a
115 // buffer ready it increments its counter and sends the counter value over the
116 // SyncSocket. Data is ready when |buffer_index_| matches the counter value
117 // received from the renderer.
119 // The counter values may temporarily become out of sync if the renderer is
120 // unable to deliver audio fast enough. It's assumed that the renderer will
121 // catch up at some point, which means discarding counter values read from the
122 // SyncSocket which don't match our current buffer index.
123 size_t bytes_received = 0;
124 uint32 renderer_buffer_index = 0;
125 while (timeout.InMicroseconds() > 0) {
126 bytes_received = socket_->ReceiveWithTimeout(
127 &renderer_buffer_index, sizeof(renderer_buffer_index), timeout);
128 if (!bytes_received)
129 break;
131 DCHECK_EQ(bytes_received, sizeof(renderer_buffer_index));
132 if (renderer_buffer_index == buffer_index_)
133 break;
135 // Reduce the timeout value as receives succeed, but aren't the right index.
136 timeout = finish_time - base::TimeTicks::Now();
139 // Receive timed out or another error occurred. Receive can timeout if the
140 // renderer is unable to deliver audio data within the allotted time.
141 if (!bytes_received || renderer_buffer_index != buffer_index_) {
142 DVLOG(2) << "AudioSyncReader::WaitUntilDataIsReady() timed out.";
144 base::TimeDelta time_since_start = base::TimeTicks::Now() - start_time;
145 UMA_HISTOGRAM_CUSTOM_TIMES("Media.AudioOutputControllerDataNotReady",
146 time_since_start,
147 base::TimeDelta::FromMilliseconds(1),
148 base::TimeDelta::FromMilliseconds(1000),
149 50);
150 return false;
153 return true;
156 } // namespace content