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