xref: /aosp_15_r20/external/oboe/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1 /*
2  * Copyright 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "common/OboeDebug.h"
18 #include "OboeStreamCallbackProxy.h"
19 
20 bool OboeStreamCallbackProxy::mCallbackReturnStop = false;
21 
onAudioReady(oboe::AudioStream * audioStream,void * audioData,int numFrames)22 oboe::DataCallbackResult OboeStreamCallbackProxy::onAudioReady(
23         oboe::AudioStream *audioStream,
24         void *audioData,
25         int numFrames) {
26     oboe::DataCallbackResult callbackResult = oboe::DataCallbackResult::Stop;
27     int64_t startTimeNanos = getNanoseconds();
28 
29     // Record which CPU this is running on.
30     orCurrentCpuMask(sched_getcpu());
31 
32     // Change affinity if app requested a change.
33     uint32_t mask = mCpuAffinityMask;
34     if (mask != mPreviousMask) {
35         int err = applyCpuAffinityMask(mask);
36         if (err != 0) {
37         }
38         mPreviousMask = mask;
39     }
40 
41     mCallbackCount++;
42     mFramesPerCallback = numFrames;
43 
44     if (mCallbackReturnStop) {
45         return oboe::DataCallbackResult::Stop;
46     }
47 
48     if (mCallback != nullptr) {
49         callbackResult = mCallback->onAudioReady(audioStream, audioData, numFrames);
50     }
51 
52     mSynthWorkload.onCallback(mNumWorkloadVoices);
53     if (mNumWorkloadVoices > 0) {
54         // Render into the buffer or discard the synth voices.
55         float *buffer = (audioStream->getChannelCount() == 2 && mHearWorkload)
56                         ? static_cast<float *>(audioData) : nullptr;
57         mSynthWorkload.renderStereo(buffer, numFrames);
58     }
59 
60     // Measure CPU load.
61     int64_t currentTimeNanos = getNanoseconds();
62     // Sometimes we get a short callback when doing sample rate conversion.
63     // Just ignore those to avoid noise.
64     if (numFrames > (getFramesPerCallback() / 2)) {
65         int64_t calculationTime = currentTimeNanos - startTimeNanos;
66         float currentCpuLoad = calculationTime * 0.000000001f * audioStream->getSampleRate() / numFrames;
67         mCpuLoad = (mCpuLoad * 0.95f) + (currentCpuLoad * 0.05f); // simple low pass filter
68         mMaxCpuLoad = std::max(currentCpuLoad, mMaxCpuLoad.load());
69     }
70 
71     if (mPreviousCallbackTimeNs != 0) {
72         mStatistics.add((currentTimeNanos - mPreviousCallbackTimeNs) * kNsToMsScaler);
73     }
74     mPreviousCallbackTimeNs = currentTimeNanos;
75 
76     return callbackResult;
77 }
78 
applyCpuAffinityMask(uint32_t mask)79 int OboeStreamCallbackProxy::applyCpuAffinityMask(uint32_t mask) {
80     int err = 0;
81     // Capture original CPU set so we can restore it.
82     if (!mIsOriginalCpuSetValid) {
83         err = sched_getaffinity((pid_t) 0,
84                                 sizeof(mOriginalCpuSet),
85                                 &mOriginalCpuSet);
86         if (err) {
87             LOGE("%s(0x%02X) - sched_getaffinity(), errno = %d\n", __func__, mask, errno);
88             return -errno;
89         }
90         mIsOriginalCpuSetValid = true;
91     }
92     if (mask) {
93         cpu_set_t cpu_set;
94         CPU_ZERO(&cpu_set);
95         int cpuCount = sysconf(_SC_NPROCESSORS_CONF);
96         for (int cpuIndex = 0; cpuIndex < cpuCount; cpuIndex++) {
97             if (mask & (1 << cpuIndex)) {
98                 CPU_SET(cpuIndex, &cpu_set);
99             }
100         }
101         err = sched_setaffinity((pid_t) 0, sizeof(cpu_set_t), &cpu_set);
102     } else {
103         // Restore original mask.
104         err = sched_setaffinity((pid_t) 0, sizeof(mOriginalCpuSet), &mOriginalCpuSet);
105     }
106     if (err) {
107         LOGE("%s(0x%02X) - sched_setaffinity(), errno = %d\n", __func__, mask, errno);
108         return -errno;
109     }
110     return 0;
111 }
112