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