Home | History | Annotate | Download | only in media
      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 
     17 using media::AudioBus;
     18 
     19 namespace content {
     20 
     21 AudioSyncReader::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 
     45 AudioSyncReader::~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 
     57 bool AudioSyncReader::DataReady() {
     58   return !media::IsUnknownDataSize(shared_memory_, packet_size_);
     59 }
     60 
     61 // media::AudioOutputController::SyncReader implementations.
     62 void 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 
     74 int 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 
    140 void AudioSyncReader::Close() {
    141   if (socket_) {
    142     socket_->Close();
    143   }
    144 }
    145 
    146 bool 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)
    154 bool 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
    165 bool 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 
    176 void 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