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
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "build/build_config.h"
#include "ppapi/shared_impl/ppb_audio_config_shared.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 defined(OS_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
|