audio_sync_reader.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/audio_sync_reader.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
93240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "base/command_line.h"
107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/memory/shared_memory.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/metrics/histogram.h"
123240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "content/public/common/content_switches.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/audio_buffers_state.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/audio_parameters.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using media::AudioBus;
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioSyncReader::AudioSyncReader(base::SharedMemory* shared_memory,
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 const media::AudioParameters& params)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : shared_memory_(shared_memory),
233240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      mute_audio_(CommandLine::ForCurrentProcess()->HasSwitch(
243240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch          switches::kMuteAudio)),
251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      packet_size_(shared_memory_->requested_size()),
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      renderer_callback_count_(0),
271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      renderer_missed_callback_count_(0),
281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#if defined(OS_MACOSX)
291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      maximum_wait_time_(params.GetBufferDuration() / 2),
301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#else
311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      // TODO(dalecurtis): Investigate if we can reduce this on all platforms.
321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      maximum_wait_time_(base::TimeDelta::FromMilliseconds(20)),
331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#endif
341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      buffer_index_(0) {
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(packet_size_, AudioBus::CalculateMemorySize(params));
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output_bus_ = AudioBus::WrapMemory(params, shared_memory->memory());
371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  output_bus_->Zero();
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioSyncReader::~AudioSyncReader() {
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!renderer_callback_count_)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Recording the percentage of deadline misses gives us a rough overview of
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // how many users might be running into audio glitches.
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int percentage_missed =
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      100.0 * renderer_missed_callback_count_ / renderer_callback_count_;
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UMA_HISTOGRAM_PERCENTAGE(
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "Media.AudioRendererMissedDeadline", percentage_missed);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// media::AudioOutputController::SyncReader implementations.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioSyncReader::UpdatePendingBytes(uint32 bytes) {
541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Zero out the entire output buffer to avoid stuttering/repeating-buffers
551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // in the anomalous case if the renderer is unable to keep up with real-time.
561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  output_bus_->Zero();
571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  socket_->Send(&bytes, sizeof(bytes));
581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ++buffer_index_;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void AudioSyncReader::Read(AudioBus* dest) {
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++renderer_callback_count_;
631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!WaitUntilDataIsReady()) {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ++renderer_missed_callback_count_;
651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    dest->Zero();
661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return;
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (mute_audio_)
703240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    dest->Zero();
711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  else
723240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    output_bus_->CopyTo(dest);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioSyncReader::Close() {
761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  socket_->Close();
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioSyncReader::Init() {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_.reset(new base::CancelableSyncSocket());
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  foreign_socket_.reset(new base::CancelableSyncSocket());
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::CancelableSyncSocket::CreatePair(socket_.get(),
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                foreign_socket_.get());
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioSyncReader::PrepareForeignSocketHandle(
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ProcessHandle process_handle,
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SyncSocket::Handle* foreign_handle) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ::DuplicateHandle(GetCurrentProcess(), foreign_socket_->handle(),
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    process_handle, foreign_handle,
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    0, FALSE, DUPLICATE_SAME_ACCESS);
931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return (*foreign_handle != 0);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioSyncReader::PrepareForeignSocketHandle(
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ProcessHandle process_handle,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::FileDescriptor* foreign_handle) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  foreign_handle->fd = foreign_socket_->handle();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  foreign_handle->auto_close = false;
1011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return (foreign_handle->fd != -1);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool AudioSyncReader::WaitUntilDataIsReady() {
1061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::TimeDelta timeout = maximum_wait_time_;
1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  const base::TimeTicks start_time = base::TimeTicks::Now();
1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  const base::TimeTicks finish_time = start_time + timeout;
1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Check if data is ready and if not, wait a reasonable amount of time for it.
1111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  //
1121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Data readiness is achieved via parallel counters, one on the renderer side
1131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // and one here.  Every time a buffer is requested via UpdatePendingBytes(),
1141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // |buffer_index_| is incremented.  Subsequently every time the renderer has a
1151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // buffer ready it increments its counter and sends the counter value over the
1161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // SyncSocket.  Data is ready when |buffer_index_| matches the counter value
1171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // received from the renderer.
1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  //
1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // The counter values may temporarily become out of sync if the renderer is
1201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // unable to deliver audio fast enough.  It's assumed that the renderer will
1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // catch up at some point, which means discarding counter values read from the
1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // SyncSocket which don't match our current buffer index.
1231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  size_t bytes_received = 0;
1241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  uint32 renderer_buffer_index = 0;
1251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  while (timeout.InMicroseconds() > 0) {
1261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    bytes_received = socket_->ReceiveWithTimeout(
1271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        &renderer_buffer_index, sizeof(renderer_buffer_index), timeout);
1281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (!bytes_received)
1291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      break;
1301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    DCHECK_EQ(bytes_received, sizeof(renderer_buffer_index));
1321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (renderer_buffer_index == buffer_index_)
1331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      break;
1341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Reduce the timeout value as receives succeed, but aren't the right index.
1361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    timeout = finish_time - base::TimeTicks::Now();
1371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
1381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Receive timed out or another error occurred.  Receive can timeout if the
1401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // renderer is unable to deliver audio data within the allotted time.
1411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!bytes_received || renderer_buffer_index != buffer_index_) {
1421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    DVLOG(2) << "AudioSyncReader::WaitUntilDataIsReady() timed out.";
1431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    base::TimeDelta time_since_start = base::TimeTicks::Now() - start_time;
1451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    UMA_HISTOGRAM_CUSTOM_TIMES("Media.AudioOutputControllerDataNotReady",
1461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                               time_since_start,
1471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                               base::TimeDelta::FromMilliseconds(1),
1481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                               base::TimeDelta::FromMilliseconds(1000),
1491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                               50);
1501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return false;
1511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
1521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return true;
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
157