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"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/strings/stringprintf.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/browser/renderer_host/media/media_stream_manager.h"
143240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "content/public/common/content_switches.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/audio_buffers_state.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/audio_parameters.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using media::AudioBus;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace {
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Used to log if any audio glitches have been detected during an audio session.
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Elements in this enum should not be added, deleted or rearranged.
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccienum AudioGlitchResult {
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AUDIO_RENDERER_NO_AUDIO_GLITCHES = 0,
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AUDIO_RENDERER_AUDIO_GLITCHES = 1,
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AUDIO_RENDERER_AUDIO_GLITCHES_MAX = AUDIO_RENDERER_AUDIO_GLITCHES
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid LogAudioGlitchResult(AudioGlitchResult result) {
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  UMA_HISTOGRAM_ENUMERATION("Media.AudioRendererAudioGlitches",
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            result,
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            AUDIO_RENDERER_AUDIO_GLITCHES_MAX + 1);
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioSyncReader::AudioSyncReader(base::SharedMemory* shared_memory,
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 const media::AudioParameters& params)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : shared_memory_(shared_memory),
433240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      mute_audio_(CommandLine::ForCurrentProcess()->HasSwitch(
443240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch          switches::kMuteAudio)),
451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      packet_size_(shared_memory_->requested_size()),
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      renderer_callback_count_(0),
471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      renderer_missed_callback_count_(0),
481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#if defined(OS_MACOSX)
491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      maximum_wait_time_(params.GetBufferDuration() / 2),
501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#else
511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      // TODO(dalecurtis): Investigate if we can reduce this on all platforms.
521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      maximum_wait_time_(base::TimeDelta::FromMilliseconds(20)),
531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#endif
541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      buffer_index_(0) {
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(packet_size_, AudioBus::CalculateMemorySize(params));
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output_bus_ = AudioBus::WrapMemory(params, shared_memory->memory());
571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  output_bus_->Zero();
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioSyncReader::~AudioSyncReader() {
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!renderer_callback_count_)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Recording the percentage of deadline misses gives us a rough overview of
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // how many users might be running into audio glitches.
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int percentage_missed =
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      100.0 * renderer_missed_callback_count_ / renderer_callback_count_;
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UMA_HISTOGRAM_PERCENTAGE(
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "Media.AudioRendererMissedDeadline", percentage_missed);
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Add more detailed information regarding detected audio glitches where
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // a non-zero value of |renderer_missed_callback_count_| is added to the
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // AUDIO_RENDERER_AUDIO_GLITCHES bin.
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  renderer_missed_callback_count_ > 0 ?
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      LogAudioGlitchResult(AUDIO_RENDERER_AUDIO_GLITCHES) :
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      LogAudioGlitchResult(AUDIO_RENDERER_NO_AUDIO_GLITCHES);
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string log_string =
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::StringPrintf("ASR: number of detected audio glitches=%d",
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                         static_cast<int>(renderer_missed_callback_count_));
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  MediaStreamManager::SendMessageToNativeLog(log_string);
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DVLOG(1) << log_string;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// media::AudioOutputController::SyncReader implementations.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioSyncReader::UpdatePendingBytes(uint32 bytes) {
861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Zero out the entire output buffer to avoid stuttering/repeating-buffers
871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // in the anomalous case if the renderer is unable to keep up with real-time.
881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  output_bus_->Zero();
891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  socket_->Send(&bytes, sizeof(bytes));
901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ++buffer_index_;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void AudioSyncReader::Read(AudioBus* dest) {
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++renderer_callback_count_;
951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!WaitUntilDataIsReady()) {
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ++renderer_missed_callback_count_;
971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    dest->Zero();
981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return;
99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (mute_audio_)
1023240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    dest->Zero();
1031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  else
1043240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    output_bus_->CopyTo(dest);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioSyncReader::Close() {
1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  socket_->Close();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioSyncReader::Init() {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_.reset(new base::CancelableSyncSocket());
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  foreign_socket_.reset(new base::CancelableSyncSocket());
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::CancelableSyncSocket::CreatePair(socket_.get(),
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                foreign_socket_.get());
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool AudioSyncReader::PrepareForeignSocket(
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ProcessHandle process_handle,
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::SyncSocket::TransitDescriptor* descriptor) {
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return foreign_socket_->PrepareTransitDescriptor(process_handle, descriptor);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool AudioSyncReader::WaitUntilDataIsReady() {
1251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::TimeDelta timeout = maximum_wait_time_;
1261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  const base::TimeTicks start_time = base::TimeTicks::Now();
1271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  const base::TimeTicks finish_time = start_time + timeout;
1281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Check if data is ready and if not, wait a reasonable amount of time for it.
1301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  //
1311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Data readiness is achieved via parallel counters, one on the renderer side
1321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // and one here.  Every time a buffer is requested via UpdatePendingBytes(),
1331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // |buffer_index_| is incremented.  Subsequently every time the renderer has a
1341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // buffer ready it increments its counter and sends the counter value over the
1351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // SyncSocket.  Data is ready when |buffer_index_| matches the counter value
1361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // received from the renderer.
1371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  //
1381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // The counter values may temporarily become out of sync if the renderer is
1391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // unable to deliver audio fast enough.  It's assumed that the renderer will
1401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // catch up at some point, which means discarding counter values read from the
1411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // SyncSocket which don't match our current buffer index.
1421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  size_t bytes_received = 0;
1431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  uint32 renderer_buffer_index = 0;
1441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  while (timeout.InMicroseconds() > 0) {
1451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    bytes_received = socket_->ReceiveWithTimeout(
1461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        &renderer_buffer_index, sizeof(renderer_buffer_index), timeout);
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (bytes_received != sizeof(renderer_buffer_index)) {
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      bytes_received = 0;
1491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      break;
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (renderer_buffer_index == buffer_index_)
1531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      break;
1541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Reduce the timeout value as receives succeed, but aren't the right index.
1561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    timeout = finish_time - base::TimeTicks::Now();
1571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
1581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Receive timed out or another error occurred.  Receive can timeout if the
1601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // renderer is unable to deliver audio data within the allotted time.
1611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!bytes_received || renderer_buffer_index != buffer_index_) {
1621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    DVLOG(2) << "AudioSyncReader::WaitUntilDataIsReady() timed out.";
1631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    base::TimeDelta time_since_start = base::TimeTicks::Now() - start_time;
1651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    UMA_HISTOGRAM_CUSTOM_TIMES("Media.AudioOutputControllerDataNotReady",
1661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                               time_since_start,
1671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                               base::TimeDelta::FromMilliseconds(1),
1681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                               base::TimeDelta::FromMilliseconds(1000),
1691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                               50);
1701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return false;
1711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
1721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return true;
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
177