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
|
/*
* Copyright 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "common/OboeDebug.h"
#include "OboeStreamCallbackProxy.h"
bool OboeStreamCallbackProxy::mCallbackReturnStop = false;
oboe::DataCallbackResult OboeStreamCallbackProxy::onAudioReady(
oboe::AudioStream *audioStream,
void *audioData,
int numFrames) {
oboe::DataCallbackResult callbackResult = oboe::DataCallbackResult::Stop;
int64_t startTimeNanos = getNanoseconds();
int32_t numWorkloadVoices = mNumWorkloadVoices;
// Record which CPU this is running on.
orCurrentCpuMask(sched_getcpu());
// Tell ADPF in advance what our workload will be.
if (mWorkloadReportingEnabled) {
audioStream->reportWorkload(numWorkloadVoices);
}
// Change affinity if app requested a change.
uint32_t mask = mCpuAffinityMask;
if (mask != mPreviousMask) {
int err = applyCpuAffinityMask(mask);
if (err != 0) {
}
mPreviousMask = mask;
}
mCallbackCount++;
mFramesPerCallback = numFrames;
if (mCallbackReturnStop) {
return oboe::DataCallbackResult::Stop;
}
if (mCallback != nullptr) {
callbackResult = mCallback->onAudioReady(audioStream, audioData, numFrames);
}
mSynthWorkload.onCallback(numWorkloadVoices);
if (numWorkloadVoices > 0) {
// Render into the buffer or discard the synth voices.
float *buffer = (audioStream->getChannelCount() == 2 && mHearWorkload)
? static_cast<float *>(audioData) : nullptr;
mSynthWorkload.renderStereo(buffer, numFrames);
}
// Measure CPU load.
int64_t currentTimeNanos = getNanoseconds();
// Sometimes we get a short callback when doing sample rate conversion.
// Just ignore those to avoid noise.
if (numFrames > (getFramesPerCallback() / 2)) {
int64_t calculationTime = currentTimeNanos - startTimeNanos;
float currentCpuLoad = calculationTime * 0.000000001f * audioStream->getSampleRate() / numFrames;
mCpuLoad = (mCpuLoad * 0.95f) + (currentCpuLoad * 0.05f); // simple low pass filter
mMaxCpuLoad = std::max(currentCpuLoad, mMaxCpuLoad.load());
}
if (mPreviousCallbackTimeNs != 0) {
mStatistics.add((currentTimeNanos - mPreviousCallbackTimeNs) * kNsToMsScaler);
}
mPreviousCallbackTimeNs = currentTimeNanos;
return callbackResult;
}
int OboeStreamCallbackProxy::applyCpuAffinityMask(uint32_t mask) {
int err = 0;
// Capture original CPU set so we can restore it.
if (!mIsOriginalCpuSetValid) {
err = sched_getaffinity((pid_t) 0,
sizeof(mOriginalCpuSet),
&mOriginalCpuSet);
if (err) {
LOGE("%s(0x%02X) - sched_getaffinity(), errno = %d\n", __func__, mask, errno);
return -errno;
}
mIsOriginalCpuSetValid = true;
}
if (mask) {
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
int cpuCount = sysconf(_SC_NPROCESSORS_CONF);
for (int cpuIndex = 0; cpuIndex < cpuCount; cpuIndex++) {
if (mask & (1 << cpuIndex)) {
CPU_SET(cpuIndex, &cpu_set);
}
}
err = sched_setaffinity((pid_t) 0, sizeof(cpu_set_t), &cpu_set);
} else {
// Restore original mask.
err = sched_setaffinity((pid_t) 0, sizeof(mOriginalCpuSet), &mOriginalCpuSet);
}
if (err) {
LOGE("%s(0x%02X) - sched_setaffinity(), errno = %d\n", __func__, mask, errno);
return -errno;
}
return 0;
}
|