audio_sync_reader.cc revision 3240926e260ce088908e02ac07a6cf7b0c0cbf44
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. 4 5#include "content/browser/renderer_host/media/audio_sync_reader.h" 6 7#include <algorithm> 8 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" 15#include "media/audio/shared_memory_util.h" 16 17using media::AudioBus; 18 19namespace content { 20 21AudioSyncReader::AudioSyncReader(base::SharedMemory* shared_memory, 22 const media::AudioParameters& params, 23 int input_channels) 24 : shared_memory_(shared_memory), 25 input_channels_(input_channels), 26 mute_audio_(CommandLine::ForCurrentProcess()->HasSwitch( 27 switches::kMuteAudio)), 28 renderer_callback_count_(0), 29 renderer_missed_callback_count_(0) { 30 packet_size_ = media::PacketSizeInBytes(shared_memory_->requested_size()); 31 int input_memory_size = 0; 32 int output_memory_size = AudioBus::CalculateMemorySize(params); 33 if (input_channels_ > 0) { 34 // The input storage is after the output storage. 35 int frames = params.frames_per_buffer(); 36 input_memory_size = AudioBus::CalculateMemorySize(input_channels_, frames); 37 char* input_data = 38 static_cast<char*>(shared_memory_->memory()) + output_memory_size; 39 input_bus_ = AudioBus::WrapMemory(input_channels_, frames, input_data); 40 } 41 DCHECK_EQ(packet_size_, output_memory_size + input_memory_size); 42 output_bus_ = AudioBus::WrapMemory(params, shared_memory->memory()); 43} 44 45AudioSyncReader::~AudioSyncReader() { 46 if (!renderer_callback_count_) 47 return; 48 49 // Recording the percentage of deadline misses gives us a rough overview of 50 // how many users might be running into audio glitches. 51 int percentage_missed = 52 100.0 * renderer_missed_callback_count_ / renderer_callback_count_; 53 UMA_HISTOGRAM_PERCENTAGE( 54 "Media.AudioRendererMissedDeadline", percentage_missed); 55} 56 57bool AudioSyncReader::DataReady() { 58 return !media::IsUnknownDataSize(shared_memory_, packet_size_); 59} 60 61// media::AudioOutputController::SyncReader implementations. 62void AudioSyncReader::UpdatePendingBytes(uint32 bytes) { 63 if (bytes != static_cast<uint32>(media::kPauseMark)) { 64 // Store unknown length of data into buffer, so we later 65 // can find out if data became available. 66 media::SetUnknownDataSize(shared_memory_, packet_size_); 67 } 68 69 if (socket_) { 70 socket_->Send(&bytes, sizeof(bytes)); 71 } 72} 73 74int AudioSyncReader::Read(bool block, const AudioBus* source, AudioBus* dest) { 75 ++renderer_callback_count_; 76 if (!DataReady()) { 77 ++renderer_missed_callback_count_; 78 79 if (block) 80 WaitTillDataReady(); 81 } 82 83 // Copy optional synchronized live audio input for consumption by renderer 84 // process. 85 if (source && input_bus_) { 86 DCHECK_EQ(source->channels(), input_bus_->channels()); 87 // TODO(crogers): In some cases with device and sample-rate changes 88 // it's possible for an AOR to insert a resampler in the path. 89 // Because this is used with the Web Audio API, it'd be better 90 // to bypass the device change handling in AOR and instead let 91 // the renderer-side Web Audio code deal with this. 92 if (source->frames() == input_bus_->frames() && 93 source->channels() == input_bus_->channels()) 94 source->CopyTo(input_bus_.get()); 95 else 96 input_bus_->Zero(); 97 } 98 99 // Retrieve the actual number of bytes available from the shared memory. If 100 // the renderer has not completed rendering this value will be invalid (still 101 // the marker stored in UpdatePendingBytes() above) and must be sanitized. 102 // TODO(dalecurtis): Technically this is not the exact size. Due to channel 103 // padding for alignment, there may be more data available than this; AudioBus 104 // will automatically do the right thing during CopyTo(). Rename this method 105 // to GetActualFrameCount(). 106 uint32 size = media::GetActualDataSizeInBytes(shared_memory_, packet_size_); 107 108 // Compute the actual number of frames read. It's important to sanitize this 109 // value for a couple reasons. One, it might still be the unknown data size 110 // marker. Two, shared memory comes from a potentially untrusted source. 111 int frames = 112 size / (sizeof(*output_bus_->channel(0)) * output_bus_->channels()); 113 if (frames < 0) 114 frames = 0; 115 else if (frames > output_bus_->frames()) 116 frames = output_bus_->frames(); 117 118 if (mute_audio_) { 119 dest->Zero(); 120 } else { 121 // Copy data from the shared memory into the caller's AudioBus. 122 output_bus_->CopyTo(dest); 123 124 // Zero out any unfilled frames in the destination bus. 125 dest->ZeroFramesPartial(frames, dest->frames() - frames); 126 } 127 128 // Zero out the entire output buffer to avoid stuttering/repeating-buffers 129 // in the anomalous case if the renderer is unable to keep up with real-time. 130 output_bus_->Zero(); 131 132 // Store unknown length of data into buffer, in case renderer does not store 133 // the length itself. It also helps in decision if we need to yield. 134 media::SetUnknownDataSize(shared_memory_, packet_size_); 135 136 // Return the actual number of frames read. 137 return frames; 138} 139 140void AudioSyncReader::Close() { 141 if (socket_) { 142 socket_->Close(); 143 } 144} 145 146bool AudioSyncReader::Init() { 147 socket_.reset(new base::CancelableSyncSocket()); 148 foreign_socket_.reset(new base::CancelableSyncSocket()); 149 return base::CancelableSyncSocket::CreatePair(socket_.get(), 150 foreign_socket_.get()); 151} 152 153#if defined(OS_WIN) 154bool AudioSyncReader::PrepareForeignSocketHandle( 155 base::ProcessHandle process_handle, 156 base::SyncSocket::Handle* foreign_handle) { 157 ::DuplicateHandle(GetCurrentProcess(), foreign_socket_->handle(), 158 process_handle, foreign_handle, 159 0, FALSE, DUPLICATE_SAME_ACCESS); 160 if (*foreign_handle != 0) 161 return true; 162 return false; 163} 164#else 165bool AudioSyncReader::PrepareForeignSocketHandle( 166 base::ProcessHandle process_handle, 167 base::FileDescriptor* foreign_handle) { 168 foreign_handle->fd = foreign_socket_->handle(); 169 foreign_handle->auto_close = false; 170 if (foreign_handle->fd != -1) 171 return true; 172 return false; 173} 174#endif 175 176void AudioSyncReader::WaitTillDataReady() { 177 base::TimeTicks start = base::TimeTicks::Now(); 178 const base::TimeDelta kMaxWait = base::TimeDelta::FromMilliseconds(20); 179#if defined(OS_WIN) 180 // Sleep(0) on Windows lets the other threads run. 181 const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(0); 182#else 183 // We want to sleep for a bit here, as otherwise a backgrounded renderer won't 184 // get enough cpu to send the data and the high priority thread in the browser 185 // will use up a core causing even more skips. 186 const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(2); 187#endif 188 base::TimeDelta time_since_start; 189 do { 190 base::PlatformThread::Sleep(kSleep); 191 time_since_start = base::TimeTicks::Now() - start; 192 } while (!DataReady() && time_since_start < kMaxWait); 193 UMA_HISTOGRAM_CUSTOM_TIMES("Media.AudioOutputControllerDataNotReady", 194 time_since_start, 195 base::TimeDelta::FromMilliseconds(1), 196 base::TimeDelta::FromMilliseconds(1000), 197 50); 198} 199 200} // namespace content 201