Ignore non-active fullscreen windows for shelf state.
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_sync_reader.cc
bloba51d3d1e35702432f55ca927de219593fcf4239b
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 int input_channels)
23 : shared_memory_(shared_memory),
24 input_channels_(input_channels),
25 mute_audio_(CommandLine::ForCurrentProcess()->HasSwitch(
26 switches::kMuteAudio)),
27 packet_size_(shared_memory_->requested_size()),
28 renderer_callback_count_(0),
29 renderer_missed_callback_count_(0),
30 #if defined(OS_MACOSX)
31 maximum_wait_time_(params.GetBufferDuration() / 2),
32 #else
33 // TODO(dalecurtis): Investigate if we can reduce this on all platforms.
34 maximum_wait_time_(base::TimeDelta::FromMilliseconds(20)),
35 #endif
36 buffer_index_(0) {
37 int input_memory_size = 0;
38 int output_memory_size = AudioBus::CalculateMemorySize(params);
39 if (input_channels_ > 0) {
40 // The input storage is after the output storage.
41 int frames = params.frames_per_buffer();
42 input_memory_size = AudioBus::CalculateMemorySize(input_channels_, frames);
43 char* input_data =
44 static_cast<char*>(shared_memory_->memory()) + output_memory_size;
45 input_bus_ = AudioBus::WrapMemory(input_channels_, frames, input_data);
46 input_bus_->Zero();
48 DCHECK_EQ(packet_size_, output_memory_size + input_memory_size);
49 output_bus_ = AudioBus::WrapMemory(params, shared_memory->memory());
50 output_bus_->Zero();
53 AudioSyncReader::~AudioSyncReader() {
54 if (!renderer_callback_count_)
55 return;
57 // Recording the percentage of deadline misses gives us a rough overview of
58 // how many users might be running into audio glitches.
59 int percentage_missed =
60 100.0 * renderer_missed_callback_count_ / renderer_callback_count_;
61 UMA_HISTOGRAM_PERCENTAGE(
62 "Media.AudioRendererMissedDeadline", percentage_missed);
65 // media::AudioOutputController::SyncReader implementations.
66 void AudioSyncReader::UpdatePendingBytes(uint32 bytes) {
67 // Zero out the entire output buffer to avoid stuttering/repeating-buffers
68 // in the anomalous case if the renderer is unable to keep up with real-time.
69 output_bus_->Zero();
70 socket_->Send(&bytes, sizeof(bytes));
71 ++buffer_index_;
74 void AudioSyncReader::Read(const AudioBus* source, AudioBus* dest) {
75 ++renderer_callback_count_;
76 if (!WaitUntilDataIsReady()) {
77 ++renderer_missed_callback_count_;
78 dest->Zero();
79 return;
82 // Copy optional synchronized live audio input for consumption by renderer
83 // process.
84 if (input_bus_) {
85 if (source)
86 source->CopyTo(input_bus_.get());
87 else
88 input_bus_->Zero();
91 if (mute_audio_)
92 dest->Zero();
93 else
94 output_bus_->CopyTo(dest);
97 void AudioSyncReader::Close() {
98 socket_->Close();
101 bool AudioSyncReader::Init() {
102 socket_.reset(new base::CancelableSyncSocket());
103 foreign_socket_.reset(new base::CancelableSyncSocket());
104 return base::CancelableSyncSocket::CreatePair(socket_.get(),
105 foreign_socket_.get());
108 #if defined(OS_WIN)
109 bool AudioSyncReader::PrepareForeignSocketHandle(
110 base::ProcessHandle process_handle,
111 base::SyncSocket::Handle* foreign_handle) {
112 ::DuplicateHandle(GetCurrentProcess(), foreign_socket_->handle(),
113 process_handle, foreign_handle,
114 0, FALSE, DUPLICATE_SAME_ACCESS);
115 return (*foreign_handle != 0);
117 #else
118 bool AudioSyncReader::PrepareForeignSocketHandle(
119 base::ProcessHandle process_handle,
120 base::FileDescriptor* foreign_handle) {
121 foreign_handle->fd = foreign_socket_->handle();
122 foreign_handle->auto_close = false;
123 return (foreign_handle->fd != -1);
125 #endif
127 bool AudioSyncReader::WaitUntilDataIsReady() {
128 base::TimeDelta timeout = maximum_wait_time_;
129 const base::TimeTicks start_time = base::TimeTicks::Now();
130 const base::TimeTicks finish_time = start_time + timeout;
132 // Check if data is ready and if not, wait a reasonable amount of time for it.
134 // Data readiness is achieved via parallel counters, one on the renderer side
135 // and one here. Every time a buffer is requested via UpdatePendingBytes(),
136 // |buffer_index_| is incremented. Subsequently every time the renderer has a
137 // buffer ready it increments its counter and sends the counter value over the
138 // SyncSocket. Data is ready when |buffer_index_| matches the counter value
139 // received from the renderer.
141 // The counter values may temporarily become out of sync if the renderer is
142 // unable to deliver audio fast enough. It's assumed that the renderer will
143 // catch up at some point, which means discarding counter values read from the
144 // SyncSocket which don't match our current buffer index.
145 size_t bytes_received = 0;
146 uint32 renderer_buffer_index = 0;
147 while (timeout.InMicroseconds() > 0) {
148 bytes_received = socket_->ReceiveWithTimeout(
149 &renderer_buffer_index, sizeof(renderer_buffer_index), timeout);
150 if (!bytes_received)
151 break;
153 DCHECK_EQ(bytes_received, sizeof(renderer_buffer_index));
154 if (renderer_buffer_index == buffer_index_)
155 break;
157 // Reduce the timeout value as receives succeed, but aren't the right index.
158 timeout = finish_time - base::TimeTicks::Now();
161 // Receive timed out or another error occurred. Receive can timeout if the
162 // renderer is unable to deliver audio data within the allotted time.
163 if (!bytes_received || renderer_buffer_index != buffer_index_) {
164 DVLOG(2) << "AudioSyncReader::WaitUntilDataIsReady() timed out.";
166 base::TimeDelta time_since_start = base::TimeTicks::Now() - start_time;
167 UMA_HISTOGRAM_CUSTOM_TIMES("Media.AudioOutputControllerDataNotReady",
168 time_since_start,
169 base::TimeDelta::FromMilliseconds(1),
170 base::TimeDelta::FromMilliseconds(1000),
171 50);
172 return false;
175 return true;
178 } // namespace content