1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ppapi/shared_impl/ppb_audio_config_shared.h"
#include <algorithm>
#include "build/build_config.h"
#include "ppapi/thunk/enter.h"
#include "ppapi/thunk/ppb_instance_api.h"
namespace ppapi {
// Rounds up requested_size to the nearest multiple of minimum_size.
static uint32_t CalculateMultipleOfSampleFrameCount(uint32_t minimum_size,
uint32_t requested_size) {
const uint32_t multiple = (requested_size + minimum_size - 1) / minimum_size;
return std::min(minimum_size * multiple,
static_cast<uint32_t>(PP_AUDIOMAXSAMPLEFRAMECOUNT));
}
PPB_AudioConfig_Shared::PPB_AudioConfig_Shared(ResourceObjectType type,
PP_Instance instance)
: Resource(type, instance),
sample_rate_(PP_AUDIOSAMPLERATE_NONE),
sample_frame_count_(0) {}
PPB_AudioConfig_Shared::~PPB_AudioConfig_Shared() {}
PP_Resource PPB_AudioConfig_Shared::Create(ResourceObjectType type,
PP_Instance instance,
PP_AudioSampleRate sample_rate,
uint32_t sample_frame_count) {
scoped_refptr<PPB_AudioConfig_Shared> object(
new PPB_AudioConfig_Shared(type, instance));
if (!object->Init(sample_rate, sample_frame_count))
return 0;
return object->GetReference();
}
// static
uint32_t PPB_AudioConfig_Shared::RecommendSampleFrameCount_1_0(
PP_AudioSampleRate sample_rate,
uint32_t requested_sample_frame_count) {
// Version 1.0: Don't actually query to get a value from the
// hardware; instead return the input for in-range values.
if (requested_sample_frame_count < PP_AUDIOMINSAMPLEFRAMECOUNT)
return PP_AUDIOMINSAMPLEFRAMECOUNT;
if (requested_sample_frame_count > PP_AUDIOMAXSAMPLEFRAMECOUNT)
return PP_AUDIOMAXSAMPLEFRAMECOUNT;
return requested_sample_frame_count;
}
// static
uint32_t PPB_AudioConfig_Shared::RecommendSampleFrameCount_1_1(
PP_Instance instance,
PP_AudioSampleRate sample_rate,
uint32_t sample_frame_count) {
// Version 1.1: Query the back-end hardware for sample rate and buffer size,
// and recommend a best fit based on request.
thunk::EnterInstanceNoLock enter(instance);
if (enter.failed())
return 0;
// Get the hardware config.
PP_AudioSampleRate hardware_sample_rate = static_cast<PP_AudioSampleRate>(
enter.functions()->GetAudioHardwareOutputSampleRate(instance));
uint32_t hardware_sample_frame_count =
enter.functions()->GetAudioHardwareOutputBufferSize(instance);
if (sample_frame_count < PP_AUDIOMINSAMPLEFRAMECOUNT)
sample_frame_count = PP_AUDIOMINSAMPLEFRAMECOUNT;
// If hardware information isn't available we're connected to a fake audio
// output stream on the browser side, so we can use whatever sample count the
// client wants.
if (!hardware_sample_frame_count || !hardware_sample_rate)
return sample_frame_count;
// Note: All the values below were determined through experimentation to
// minimize jitter and back-to-back callbacks from the browser. Please take
// care when modifying these values as they impact a large number of users.
// TODO(dalecurtis): Land jitter test and add documentation for updating this.
// Should track the value reported by XP and ALSA backends.
const uint32_t kHighLatencySampleFrameCount = 2048;
#if BUILDFLAG(IS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
// TODO(ihf): Remove this once ARM Chromebooks support low latency audio. For
// now we classify them as high latency. See crbug.com/289770. Note that
// Adobe Flash is affected but not HTML5, WebRTC and WebAudio (they are using
// real time threads).
const bool kHighLatencyDevice = true;
#else
const bool kHighLatencyDevice = false;
#endif
// If client is using same sample rate as audio hardware, then recommend a
// multiple of the audio hardware's sample frame count.
if (!kHighLatencyDevice && hardware_sample_rate == sample_rate) {
return CalculateMultipleOfSampleFrameCount(hardware_sample_frame_count,
sample_frame_count);
}
// If the hardware requires a high latency buffer or we're at a low sample
// rate w/ a buffer that's larger than 10ms, choose the nearest multiple of
// the high latency sample frame count. An example of too low and too large
// is 16kHz and a sample frame count greater than 160 frames.
if (kHighLatencyDevice ||
hardware_sample_frame_count >= kHighLatencySampleFrameCount ||
(hardware_sample_rate < 44100 &&
hardware_sample_frame_count > hardware_sample_rate / 100u)) {
return CalculateMultipleOfSampleFrameCount(
sample_frame_count,
std::max(kHighLatencySampleFrameCount, hardware_sample_frame_count));
}
// All low latency clients should be able to handle a 512 frame buffer with
// resampling from 44.1kHz and 48kHz to higher sample rates.
// TODO(dalecurtis): We may need to investigate making the callback thread
// high priority to handle buffers at the absolute minimum w/o glitching.
const uint32_t kLowLatencySampleFrameCount = 512;
// Special case for 48kHz -> 44.1kHz and buffer sizes greater than 10ms. In
// testing most buffer sizes > 10ms led to glitching, so we choose a size we
// know won't cause jitter.
int min_sample_frame_count = kLowLatencySampleFrameCount;
if (hardware_sample_rate == 44100 && sample_rate == 48000 &&
hardware_sample_frame_count > hardware_sample_rate / 100u) {
min_sample_frame_count =
std::max(2 * kLowLatencySampleFrameCount, hardware_sample_frame_count);
}
return CalculateMultipleOfSampleFrameCount(min_sample_frame_count,
sample_frame_count);
}
// static
PP_AudioSampleRate PPB_AudioConfig_Shared::RecommendSampleRate(
PP_Instance instance) {
thunk::EnterInstanceNoLock enter(instance);
if (enter.failed())
return PP_AUDIOSAMPLERATE_NONE;
PP_AudioSampleRate hardware_sample_rate = static_cast<PP_AudioSampleRate>(
enter.functions()->GetAudioHardwareOutputSampleRate(instance));
return hardware_sample_rate;
}
thunk::PPB_AudioConfig_API* PPB_AudioConfig_Shared::AsPPB_AudioConfig_API() {
return this;
}
PP_AudioSampleRate PPB_AudioConfig_Shared::GetSampleRate() {
return sample_rate_;
}
uint32_t PPB_AudioConfig_Shared::GetSampleFrameCount() {
return sample_frame_count_;
}
bool PPB_AudioConfig_Shared::Init(PP_AudioSampleRate sample_rate,
uint32_t sample_frame_count) {
// TODO(brettw): Currently we don't actually check what the hardware
// supports, so just allow sample rates of the "guaranteed working" ones.
// TODO(dalecurtis): If sample rates are added RecommendSampleFrameCount_1_1()
// must be updated to account for the new rates.
if (sample_rate != PP_AUDIOSAMPLERATE_44100 &&
sample_rate != PP_AUDIOSAMPLERATE_48000)
return false;
// TODO(brettw): Currently we don't actually query to get a value from the
// hardware, so just validate the range.
if (sample_frame_count > PP_AUDIOMAXSAMPLEFRAMECOUNT ||
sample_frame_count < PP_AUDIOMINSAMPLEFRAMECOUNT)
return false;
sample_rate_ = sample_rate;
sample_frame_count_ = sample_frame_count;
return true;
}
} // namespace ppapi
|