xref: /aosp_15_r20/system/media/audio_utils/MelProcessor.cpp (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
1*b9df5ad1SAndroid Build Coastguard Worker /*
2*b9df5ad1SAndroid Build Coastguard Worker  * Copyright 2022 The Android Open Source Project
3*b9df5ad1SAndroid Build Coastguard Worker  *
4*b9df5ad1SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*b9df5ad1SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*b9df5ad1SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*b9df5ad1SAndroid Build Coastguard Worker  *
8*b9df5ad1SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*b9df5ad1SAndroid Build Coastguard Worker  *
10*b9df5ad1SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*b9df5ad1SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*b9df5ad1SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b9df5ad1SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*b9df5ad1SAndroid Build Coastguard Worker  * limitations under the License.
15*b9df5ad1SAndroid Build Coastguard Worker  */
16*b9df5ad1SAndroid Build Coastguard Worker 
17*b9df5ad1SAndroid Build Coastguard Worker // #define LOG_NDEBUG 0
18*b9df5ad1SAndroid Build Coastguard Worker #define LOG_TAG "audio_utils_MelProcessor"
19*b9df5ad1SAndroid Build Coastguard Worker // #define VERY_VERY_VERBOSE_LOGGING
20*b9df5ad1SAndroid Build Coastguard Worker #ifdef VERY_VERY_VERBOSE_LOGGING
21*b9df5ad1SAndroid Build Coastguard Worker #define ALOGVV ALOGV
22*b9df5ad1SAndroid Build Coastguard Worker #else
23*b9df5ad1SAndroid Build Coastguard Worker #define ALOGVV(a...) do { } while(0)
24*b9df5ad1SAndroid Build Coastguard Worker #endif
25*b9df5ad1SAndroid Build Coastguard Worker 
26*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/MelProcessor.h>
27*b9df5ad1SAndroid Build Coastguard Worker 
28*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/format.h>
29*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/mutex.h>
30*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/power.h>
31*b9df5ad1SAndroid Build Coastguard Worker #include <chrono>
32*b9df5ad1SAndroid Build Coastguard Worker #include <log/log.h>
33*b9df5ad1SAndroid Build Coastguard Worker #include <sstream>
34*b9df5ad1SAndroid Build Coastguard Worker #include <unordered_map>
35*b9df5ad1SAndroid Build Coastguard Worker #include <utils/threads.h>
36*b9df5ad1SAndroid Build Coastguard Worker 
37*b9df5ad1SAndroid Build Coastguard Worker namespace android::audio_utils {
38*b9df5ad1SAndroid Build Coastguard Worker 
39*b9df5ad1SAndroid Build Coastguard Worker constexpr int32_t kSecondsPerMelValue = 1;
40*b9df5ad1SAndroid Build Coastguard Worker constexpr float kMelAdjustmentDb = -3.f;
41*b9df5ad1SAndroid Build Coastguard Worker 
42*b9df5ad1SAndroid Build Coastguard Worker // Estimated offset defined in Table39 of IEC62368-1 3rd edition
43*b9df5ad1SAndroid Build Coastguard Worker // -30dBFS, -10dBFS should correspond to 80dBSPL, 100dBSPL
44*b9df5ad1SAndroid Build Coastguard Worker constexpr float kMeldBFSTodBSPLOffset = 110.f;
45*b9df5ad1SAndroid Build Coastguard Worker 
46*b9df5ad1SAndroid Build Coastguard Worker constexpr float kRs1OutputdBFS = 80.f;  // dBA
47*b9df5ad1SAndroid Build Coastguard Worker 
48*b9df5ad1SAndroid Build Coastguard Worker constexpr float kRs2LowerBound = 80.f;  // dBA
49*b9df5ad1SAndroid Build Coastguard Worker constexpr float kRs2UpperBound = 100.f;  // dBA
50*b9df5ad1SAndroid Build Coastguard Worker 
51*b9df5ad1SAndroid Build Coastguard Worker // The following arrays contain the IIR biquad filter coefficients for performing A-weighting as
52*b9df5ad1SAndroid Build Coastguard Worker // described in IEC 61672:2003 for multiple sample rates. The format is b0, b1, b2, a1, a2
53*b9df5ad1SAndroid Build Coastguard Worker constexpr std::array<std::array<float, kBiquadNumCoefs>, MelProcessor::kCascadeBiquadNumber>
54*b9df5ad1SAndroid Build Coastguard Worker     kBqCoeffs8000 = {{{0.630301, 0.000000, -0.630301, 0.103818, -0.360417},
55*b9df5ad1SAndroid Build Coastguard Worker                       {1.000000, 0.000000, -1.000000, -0.264382, -0.601403},
56*b9df5ad1SAndroid Build Coastguard Worker                       {1.000000, -2.000000, 1.000000, -1.967903, 0.968160}}};
57*b9df5ad1SAndroid Build Coastguard Worker constexpr std::array<std::array<float, kBiquadNumCoefs>, MelProcessor::kCascadeBiquadNumber>
58*b9df5ad1SAndroid Build Coastguard Worker     kBqCoeffs11025 = {{{0.601164, 1.202327, 0.601164, 1.106098, 0.305863},
59*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.593019, 0.613701},
60*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.976658, 0.976794}}};
61*b9df5ad1SAndroid Build Coastguard Worker constexpr std::array<std::array<float, kBiquadNumCoefs>, MelProcessor::kCascadeBiquadNumber>
62*b9df5ad1SAndroid Build Coastguard Worker     kBqCoeffs12000 = {{{0.588344, 1.176688, 0.588344, 1.045901, 0.273477},
63*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.621383, 0.639134},
64*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.978544, 0.978660}}};
65*b9df5ad1SAndroid Build Coastguard Worker constexpr std::array<std::array<float, kBiquadNumCoefs>, MelProcessor::kCascadeBiquadNumber>
66*b9df5ad1SAndroid Build Coastguard Worker     kBqCoeffs16000 = {{{0.531220, 1.062441, 0.531220, 0.821564, 0.168742},
67*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.705510, 0.715988},
68*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.983887, 0.983952}}};
69*b9df5ad1SAndroid Build Coastguard Worker constexpr std::array<std::array<float, kBiquadNumCoefs>, MelProcessor::kCascadeBiquadNumber>
70*b9df5ad1SAndroid Build Coastguard Worker     kBqCoeffs22050 = {{{0.449072, 0.898144, 0.449072, 0.538750, 0.072563},
71*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.779533, 0.785281},
72*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.988295, 0.988329}}};
73*b9df5ad1SAndroid Build Coastguard Worker constexpr std::array<std::array<float, kBiquadNumCoefs>, MelProcessor::kCascadeBiquadNumber>
74*b9df5ad1SAndroid Build Coastguard Worker     kBqCoeffs24000 = {{{0.425411, 0.850821, 0.425411, 0.459298, 0.052739},
75*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.796051, 0.800946},
76*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.989243, 0.989272}}};
77*b9df5ad1SAndroid Build Coastguard Worker constexpr std::array<std::array<float, kBiquadNumCoefs>, MelProcessor::kCascadeBiquadNumber>
78*b9df5ad1SAndroid Build Coastguard Worker     kBqCoeffs32000 = {{{0.343284, 0.686569, 0.343284, 0.179472, 0.008053},
79*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.843991, 0.846816},
80*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.991927, 0.991943}}};
81*b9df5ad1SAndroid Build Coastguard Worker constexpr std::array<std::array<float, kBiquadNumCoefs>, MelProcessor::kCascadeBiquadNumber>
82*b9df5ad1SAndroid Build Coastguard Worker     kBqCoeffs44100 = {{{0.255612, 0.511223, 0.255612, -0.140536, 0.004938},
83*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.884901, 0.886421},
84*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.994139, 0.994147}}};
85*b9df5ad1SAndroid Build Coastguard Worker constexpr std::array<std::array<float, kBiquadNumCoefs>, MelProcessor::kCascadeBiquadNumber>
86*b9df5ad1SAndroid Build Coastguard Worker     kBqCoeffs48000 = {{{0.234183, 0.468366, 0.234183, -0.224558, 0.012607},
87*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.893870, 0.895160},
88*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.994614, 0.994622}}};
89*b9df5ad1SAndroid Build Coastguard Worker constexpr std::array<std::array<float, kBiquadNumCoefs>, MelProcessor::kCascadeBiquadNumber>
90*b9df5ad1SAndroid Build Coastguard Worker     kBqCoeffs64000 = {{{0.169014, 0.338029, 0.169014, -0.502217, 0.063056},
91*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.919579, 0.920314},
92*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.995959, 0.995964}}};
93*b9df5ad1SAndroid Build Coastguard Worker constexpr std::array<std::array<float, kBiquadNumCoefs>, MelProcessor::kCascadeBiquadNumber>
94*b9df5ad1SAndroid Build Coastguard Worker     kBqCoeffs88200 = {{{0.111831, 0.223662, 0.111831, -0.788729, 0.155523},
95*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.941143, 0.941534},
96*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.997067, 0.997069}}};
97*b9df5ad1SAndroid Build Coastguard Worker constexpr std::array<std::array<float, kBiquadNumCoefs>, MelProcessor::kCascadeBiquadNumber>
98*b9df5ad1SAndroid Build Coastguard Worker     kBqCoeffs96000 = {{{0.099469, 0.198937, 0.099469, -0.859073, 0.184502},
99*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.945825, 0.946156},
100*b9df5ad1SAndroid Build Coastguard Worker                        {1.000000, -2.000000, 1.000000, -1.997305, 0.997307}}};
101*b9df5ad1SAndroid Build Coastguard Worker constexpr std::array<std::array<float, kBiquadNumCoefs>, MelProcessor::kCascadeBiquadNumber>
102*b9df5ad1SAndroid Build Coastguard Worker     kBqCoeffs128000 = {{{0.065337, 0.130674, 0.065337, -1.078602, 0.290845},
103*b9df5ad1SAndroid Build Coastguard Worker                         {1.000000, -2.000000, 1.000000, -1.959154, 0.959342},
104*b9df5ad1SAndroid Build Coastguard Worker                         {1.000000, -2.000000, 1.000000, -1.997979, 0.997980}}};
105*b9df5ad1SAndroid Build Coastguard Worker constexpr std::array<std::array<float, kBiquadNumCoefs>, MelProcessor::kCascadeBiquadNumber>
106*b9df5ad1SAndroid Build Coastguard Worker     kBqCoeffs176400 = {{{0.039432, 0.078864, 0.039432, -1.286304, 0.413645},
107*b9df5ad1SAndroid Build Coastguard Worker                         {1.000000, -2.000000, 1.000000, -1.970232, 0.970331},
108*b9df5ad1SAndroid Build Coastguard Worker                         {1.000000, -2.000000, 1.000000, -1.998533, 0.998534}}};
109*b9df5ad1SAndroid Build Coastguard Worker constexpr std::array<std::array<float, kBiquadNumCoefs>, MelProcessor::kCascadeBiquadNumber>
110*b9df5ad1SAndroid Build Coastguard Worker     kBqCoeffs192000 = {{{0.034315, 0.068629, 0.034315, -1.334647, 0.445320},
111*b9df5ad1SAndroid Build Coastguard Worker                         {1.000000, -2.000000, 1.000000, -1.972625, 0.972709},
112*b9df5ad1SAndroid Build Coastguard Worker                         {1.000000, -2.000000, 1.000000, -1.998652, 0.998653}}};
113*b9df5ad1SAndroid Build Coastguard Worker 
MelProcessor(uint32_t sampleRate,uint32_t channelCount,audio_format_t format,const sp<MelCallback> & callback,audio_port_handle_t deviceId,float rs2Value,size_t maxMelsCallback)114*b9df5ad1SAndroid Build Coastguard Worker MelProcessor::MelProcessor(uint32_t sampleRate,
115*b9df5ad1SAndroid Build Coastguard Worker         uint32_t channelCount,
116*b9df5ad1SAndroid Build Coastguard Worker         audio_format_t format,
117*b9df5ad1SAndroid Build Coastguard Worker         const sp<MelCallback>& callback,
118*b9df5ad1SAndroid Build Coastguard Worker         audio_port_handle_t deviceId,
119*b9df5ad1SAndroid Build Coastguard Worker         float rs2Value,
120*b9df5ad1SAndroid Build Coastguard Worker         size_t maxMelsCallback)
121*b9df5ad1SAndroid Build Coastguard Worker     : mCallback(callback),
122*b9df5ad1SAndroid Build Coastguard Worker       mMelWorker("MelWorker#" + pointerString(), mCallback),
123*b9df5ad1SAndroid Build Coastguard Worker       mSampleRate(sampleRate),
124*b9df5ad1SAndroid Build Coastguard Worker       mFramesPerMelValue(sampleRate * kSecondsPerMelValue),
125*b9df5ad1SAndroid Build Coastguard Worker       mChannelCount(channelCount),
126*b9df5ad1SAndroid Build Coastguard Worker       mFormat(format),
127*b9df5ad1SAndroid Build Coastguard Worker       mAWeightSamples(mFramesPerMelValue * mChannelCount),
128*b9df5ad1SAndroid Build Coastguard Worker       mFloatSamples(mFramesPerMelValue * mChannelCount),
129*b9df5ad1SAndroid Build Coastguard Worker       mCurrentChannelEnergy(channelCount, 0.0f),
130*b9df5ad1SAndroid Build Coastguard Worker       mMelValues(maxMelsCallback),
131*b9df5ad1SAndroid Build Coastguard Worker       mDeviceId(deviceId),
132*b9df5ad1SAndroid Build Coastguard Worker       mRs2UpperBound(rs2Value)
133*b9df5ad1SAndroid Build Coastguard Worker {
134*b9df5ad1SAndroid Build Coastguard Worker     createBiquads_l();
135*b9df5ad1SAndroid Build Coastguard Worker 
136*b9df5ad1SAndroid Build Coastguard Worker     mMelWorker.run();
137*b9df5ad1SAndroid Build Coastguard Worker }
138*b9df5ad1SAndroid Build Coastguard Worker 
139*b9df5ad1SAndroid Build Coastguard Worker static const std::unordered_map<uint32_t, const std::array<std::array<float, kBiquadNumCoefs>,
getSampleRateBiquadCoeffs()140*b9df5ad1SAndroid Build Coastguard Worker         MelProcessor::kCascadeBiquadNumber>*>& getSampleRateBiquadCoeffs() {
141*b9df5ad1SAndroid Build Coastguard Worker     static const std::unordered_map<uint32_t, const std::array<std::array<float, kBiquadNumCoefs>,
142*b9df5ad1SAndroid Build Coastguard Worker                              MelProcessor::kCascadeBiquadNumber>*> sampleRateBiquadCoeffs = {
143*b9df5ad1SAndroid Build Coastguard Worker             {8000, &kBqCoeffs8000},
144*b9df5ad1SAndroid Build Coastguard Worker             {11025, &kBqCoeffs11025},
145*b9df5ad1SAndroid Build Coastguard Worker             {12000, &kBqCoeffs12000},
146*b9df5ad1SAndroid Build Coastguard Worker             {16000, &kBqCoeffs16000},
147*b9df5ad1SAndroid Build Coastguard Worker             {22050, &kBqCoeffs22050},
148*b9df5ad1SAndroid Build Coastguard Worker             {24000, &kBqCoeffs24000},
149*b9df5ad1SAndroid Build Coastguard Worker             {32000, &kBqCoeffs32000},
150*b9df5ad1SAndroid Build Coastguard Worker             {44100, &kBqCoeffs44100},
151*b9df5ad1SAndroid Build Coastguard Worker             {48000, &kBqCoeffs48000},
152*b9df5ad1SAndroid Build Coastguard Worker             {64000, &kBqCoeffs64000},
153*b9df5ad1SAndroid Build Coastguard Worker             {88200, &kBqCoeffs88200},
154*b9df5ad1SAndroid Build Coastguard Worker             {96000, &kBqCoeffs96000},
155*b9df5ad1SAndroid Build Coastguard Worker             {128000, &kBqCoeffs128000},
156*b9df5ad1SAndroid Build Coastguard Worker             {176400, &kBqCoeffs176400},
157*b9df5ad1SAndroid Build Coastguard Worker             {192000, &kBqCoeffs192000},
158*b9df5ad1SAndroid Build Coastguard Worker         };
159*b9df5ad1SAndroid Build Coastguard Worker     return sampleRateBiquadCoeffs;
160*b9df5ad1SAndroid Build Coastguard Worker }
161*b9df5ad1SAndroid Build Coastguard Worker 
isSampleRateSupported_l() const162*b9df5ad1SAndroid Build Coastguard Worker bool MelProcessor::isSampleRateSupported_l() const {
163*b9df5ad1SAndroid Build Coastguard Worker     return getSampleRateBiquadCoeffs().count(mSampleRate) != 0;
164*b9df5ad1SAndroid Build Coastguard Worker }
165*b9df5ad1SAndroid Build Coastguard Worker 
createBiquads_l()166*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::createBiquads_l() {
167*b9df5ad1SAndroid Build Coastguard Worker     if (!isSampleRateSupported_l()) {
168*b9df5ad1SAndroid Build Coastguard Worker         return;
169*b9df5ad1SAndroid Build Coastguard Worker     }
170*b9df5ad1SAndroid Build Coastguard Worker 
171*b9df5ad1SAndroid Build Coastguard Worker     const auto& biquadCoeffs = getSampleRateBiquadCoeffs().at(mSampleRate); // checked above
172*b9df5ad1SAndroid Build Coastguard Worker     mCascadedBiquads =
173*b9df5ad1SAndroid Build Coastguard Worker               {std::make_unique<DefaultBiquadFilter>(mChannelCount, biquadCoeffs->at(0)),
174*b9df5ad1SAndroid Build Coastguard Worker                std::make_unique<DefaultBiquadFilter>(mChannelCount, biquadCoeffs->at(1)),
175*b9df5ad1SAndroid Build Coastguard Worker                std::make_unique<DefaultBiquadFilter>(mChannelCount, biquadCoeffs->at(2))};
176*b9df5ad1SAndroid Build Coastguard Worker }
177*b9df5ad1SAndroid Build Coastguard Worker 
setOutputRs2UpperBound(float rs2Value)178*b9df5ad1SAndroid Build Coastguard Worker status_t MelProcessor::setOutputRs2UpperBound(float rs2Value)
179*b9df5ad1SAndroid Build Coastguard Worker {
180*b9df5ad1SAndroid Build Coastguard Worker     if (rs2Value < kRs2LowerBound || rs2Value > kRs2UpperBound) {
181*b9df5ad1SAndroid Build Coastguard Worker         return BAD_VALUE;
182*b9df5ad1SAndroid Build Coastguard Worker     }
183*b9df5ad1SAndroid Build Coastguard Worker 
184*b9df5ad1SAndroid Build Coastguard Worker     mRs2UpperBound = rs2Value;
185*b9df5ad1SAndroid Build Coastguard Worker 
186*b9df5ad1SAndroid Build Coastguard Worker     return NO_ERROR;
187*b9df5ad1SAndroid Build Coastguard Worker }
188*b9df5ad1SAndroid Build Coastguard Worker 
getOutputRs2UpperBound() const189*b9df5ad1SAndroid Build Coastguard Worker float MelProcessor::getOutputRs2UpperBound() const
190*b9df5ad1SAndroid Build Coastguard Worker {
191*b9df5ad1SAndroid Build Coastguard Worker     return mRs2UpperBound;
192*b9df5ad1SAndroid Build Coastguard Worker }
193*b9df5ad1SAndroid Build Coastguard Worker 
setDeviceId(audio_port_handle_t deviceId)194*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::setDeviceId(audio_port_handle_t deviceId)
195*b9df5ad1SAndroid Build Coastguard Worker {
196*b9df5ad1SAndroid Build Coastguard Worker     mDeviceId = deviceId;
197*b9df5ad1SAndroid Build Coastguard Worker }
198*b9df5ad1SAndroid Build Coastguard Worker 
getDeviceId()199*b9df5ad1SAndroid Build Coastguard Worker audio_port_handle_t MelProcessor::getDeviceId() {
200*b9df5ad1SAndroid Build Coastguard Worker     return mDeviceId;
201*b9df5ad1SAndroid Build Coastguard Worker }
202*b9df5ad1SAndroid Build Coastguard Worker 
pause()203*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::pause()
204*b9df5ad1SAndroid Build Coastguard Worker {
205*b9df5ad1SAndroid Build Coastguard Worker     ALOGV("%s", __func__);
206*b9df5ad1SAndroid Build Coastguard Worker     mPaused = true;
207*b9df5ad1SAndroid Build Coastguard Worker }
208*b9df5ad1SAndroid Build Coastguard Worker 
resume()209*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::resume()
210*b9df5ad1SAndroid Build Coastguard Worker {
211*b9df5ad1SAndroid Build Coastguard Worker     ALOGV("%s", __func__);
212*b9df5ad1SAndroid Build Coastguard Worker     mPaused = false;
213*b9df5ad1SAndroid Build Coastguard Worker }
214*b9df5ad1SAndroid Build Coastguard Worker 
drain()215*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::drain()
216*b9df5ad1SAndroid Build Coastguard Worker {
217*b9df5ad1SAndroid Build Coastguard Worker     ALOGV("%s", __func__);
218*b9df5ad1SAndroid Build Coastguard Worker     mMelWorker.drain();
219*b9df5ad1SAndroid Build Coastguard Worker }
220*b9df5ad1SAndroid Build Coastguard Worker 
drainAndWait()221*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::drainAndWait() {
222*b9df5ad1SAndroid Build Coastguard Worker     constexpr size_t kPollMs = 8;
223*b9df5ad1SAndroid Build Coastguard Worker     while (!mMelWorker.ringBufferIsEmpty()) {
224*b9df5ad1SAndroid Build Coastguard Worker         drain();
225*b9df5ad1SAndroid Build Coastguard Worker         std::this_thread::sleep_for(std::chrono::milliseconds(kPollMs));
226*b9df5ad1SAndroid Build Coastguard Worker     }
227*b9df5ad1SAndroid Build Coastguard Worker }
228*b9df5ad1SAndroid Build Coastguard Worker 
updateAudioFormat(uint32_t sampleRate,uint32_t channelCount,audio_format_t format)229*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::updateAudioFormat(uint32_t sampleRate,
230*b9df5ad1SAndroid Build Coastguard Worker                                      uint32_t channelCount,
231*b9df5ad1SAndroid Build Coastguard Worker                                      audio_format_t format) {
232*b9df5ad1SAndroid Build Coastguard Worker     ALOGV("%s: update audio format %u, %u, %d", __func__, sampleRate, channelCount, format);
233*b9df5ad1SAndroid Build Coastguard Worker 
234*b9df5ad1SAndroid Build Coastguard Worker     std::lock_guard l(mLock);
235*b9df5ad1SAndroid Build Coastguard Worker 
236*b9df5ad1SAndroid Build Coastguard Worker     bool differentSampleRate = (mSampleRate != sampleRate);
237*b9df5ad1SAndroid Build Coastguard Worker     bool differentChannelCount = (mChannelCount != channelCount);
238*b9df5ad1SAndroid Build Coastguard Worker 
239*b9df5ad1SAndroid Build Coastguard Worker     mSampleRate = sampleRate;
240*b9df5ad1SAndroid Build Coastguard Worker     mFramesPerMelValue = sampleRate * kSecondsPerMelValue;
241*b9df5ad1SAndroid Build Coastguard Worker     mChannelCount = channelCount;
242*b9df5ad1SAndroid Build Coastguard Worker     mFormat = format;
243*b9df5ad1SAndroid Build Coastguard Worker 
244*b9df5ad1SAndroid Build Coastguard Worker     if (differentSampleRate || differentChannelCount) {
245*b9df5ad1SAndroid Build Coastguard Worker         mAWeightSamples.resize(mFramesPerMelValue * mChannelCount);
246*b9df5ad1SAndroid Build Coastguard Worker         mFloatSamples.resize(mFramesPerMelValue * mChannelCount);
247*b9df5ad1SAndroid Build Coastguard Worker     }
248*b9df5ad1SAndroid Build Coastguard Worker     if (differentChannelCount) {
249*b9df5ad1SAndroid Build Coastguard Worker         mCurrentChannelEnergy.resize(channelCount);
250*b9df5ad1SAndroid Build Coastguard Worker     }
251*b9df5ad1SAndroid Build Coastguard Worker 
252*b9df5ad1SAndroid Build Coastguard Worker     createBiquads_l();
253*b9df5ad1SAndroid Build Coastguard Worker }
254*b9df5ad1SAndroid Build Coastguard Worker 
applyAWeight_l(const void * buffer,size_t samples)255*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::applyAWeight_l(const void* buffer, size_t samples)
256*b9df5ad1SAndroid Build Coastguard Worker {
257*b9df5ad1SAndroid Build Coastguard Worker     memcpy_by_audio_format(mFloatSamples.data(), AUDIO_FORMAT_PCM_FLOAT, buffer, mFormat, samples);
258*b9df5ad1SAndroid Build Coastguard Worker 
259*b9df5ad1SAndroid Build Coastguard Worker     float* tempFloat[2] = { mFloatSamples.data(), mAWeightSamples.data() };
260*b9df5ad1SAndroid Build Coastguard Worker     int inIdx = 1, outIdx = 0;
261*b9df5ad1SAndroid Build Coastguard Worker     const size_t frames = samples / mChannelCount;
262*b9df5ad1SAndroid Build Coastguard Worker     for (const auto& biquad : mCascadedBiquads) {
263*b9df5ad1SAndroid Build Coastguard Worker         outIdx ^= 1;
264*b9df5ad1SAndroid Build Coastguard Worker         inIdx ^= 1;
265*b9df5ad1SAndroid Build Coastguard Worker         biquad->process(tempFloat[outIdx], tempFloat[inIdx], frames);
266*b9df5ad1SAndroid Build Coastguard Worker     }
267*b9df5ad1SAndroid Build Coastguard Worker 
268*b9df5ad1SAndroid Build Coastguard Worker     // should not be the case since the size is odd
269*b9df5ad1SAndroid Build Coastguard Worker     if (!(mCascadedBiquads.size() & 1)) {
270*b9df5ad1SAndroid Build Coastguard Worker         std::swap(mFloatSamples, mAWeightSamples);
271*b9df5ad1SAndroid Build Coastguard Worker     }
272*b9df5ad1SAndroid Build Coastguard Worker }
273*b9df5ad1SAndroid Build Coastguard Worker 
getCombinedChannelEnergy_l()274*b9df5ad1SAndroid Build Coastguard Worker float MelProcessor::getCombinedChannelEnergy_l() {
275*b9df5ad1SAndroid Build Coastguard Worker     float combinedEnergy = 0.0f;
276*b9df5ad1SAndroid Build Coastguard Worker     for (auto& energy: mCurrentChannelEnergy) {
277*b9df5ad1SAndroid Build Coastguard Worker         combinedEnergy += energy;
278*b9df5ad1SAndroid Build Coastguard Worker         energy = 0;
279*b9df5ad1SAndroid Build Coastguard Worker     }
280*b9df5ad1SAndroid Build Coastguard Worker 
281*b9df5ad1SAndroid Build Coastguard Worker     combinedEnergy /= (float) mFramesPerMelValue;
282*b9df5ad1SAndroid Build Coastguard Worker     return combinedEnergy;
283*b9df5ad1SAndroid Build Coastguard Worker }
284*b9df5ad1SAndroid Build Coastguard Worker 
addMelValue_l(float mel)285*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::addMelValue_l(float mel) {
286*b9df5ad1SAndroid Build Coastguard Worker     mMelValues[mCurrentIndex] = mel;
287*b9df5ad1SAndroid Build Coastguard Worker     ALOGV("%s: writing MEL %f at index %d for device %d",
288*b9df5ad1SAndroid Build Coastguard Worker           __func__,
289*b9df5ad1SAndroid Build Coastguard Worker           mel,
290*b9df5ad1SAndroid Build Coastguard Worker           mCurrentIndex,
291*b9df5ad1SAndroid Build Coastguard Worker           mDeviceId.load());
292*b9df5ad1SAndroid Build Coastguard Worker 
293*b9df5ad1SAndroid Build Coastguard Worker     bool notifyWorker = false;
294*b9df5ad1SAndroid Build Coastguard Worker 
295*b9df5ad1SAndroid Build Coastguard Worker     if (mel > mRs2UpperBound) {
296*b9df5ad1SAndroid Build Coastguard Worker         mMelWorker.momentaryExposure(mel, mDeviceId);
297*b9df5ad1SAndroid Build Coastguard Worker         notifyWorker = true;
298*b9df5ad1SAndroid Build Coastguard Worker     }
299*b9df5ad1SAndroid Build Coastguard Worker 
300*b9df5ad1SAndroid Build Coastguard Worker     bool reportContinuousValues = false;
301*b9df5ad1SAndroid Build Coastguard Worker     if ((mMelValues[mCurrentIndex] < kRs1OutputdBFS && mCurrentIndex > 0)) {
302*b9df5ad1SAndroid Build Coastguard Worker         reportContinuousValues = true;
303*b9df5ad1SAndroid Build Coastguard Worker     } else if (mMelValues[mCurrentIndex] >= kRs1OutputdBFS) {
304*b9df5ad1SAndroid Build Coastguard Worker         // only store MEL that are above RS1
305*b9df5ad1SAndroid Build Coastguard Worker         ++mCurrentIndex;
306*b9df5ad1SAndroid Build Coastguard Worker     }
307*b9df5ad1SAndroid Build Coastguard Worker 
308*b9df5ad1SAndroid Build Coastguard Worker     if (reportContinuousValues || (mCurrentIndex > mMelValues.size() - 1)) {
309*b9df5ad1SAndroid Build Coastguard Worker         mMelWorker.newMelValues(mMelValues, mCurrentIndex, mDeviceId);
310*b9df5ad1SAndroid Build Coastguard Worker         notifyWorker = true;
311*b9df5ad1SAndroid Build Coastguard Worker         mCurrentIndex = 0;
312*b9df5ad1SAndroid Build Coastguard Worker     }
313*b9df5ad1SAndroid Build Coastguard Worker 
314*b9df5ad1SAndroid Build Coastguard Worker     if (notifyWorker) {
315*b9df5ad1SAndroid Build Coastguard Worker         mMelWorker.notify();
316*b9df5ad1SAndroid Build Coastguard Worker     }
317*b9df5ad1SAndroid Build Coastguard Worker }
318*b9df5ad1SAndroid Build Coastguard Worker 
process(const void * buffer,size_t bytes)319*b9df5ad1SAndroid Build Coastguard Worker int32_t MelProcessor::process(const void* buffer, size_t bytes) {
320*b9df5ad1SAndroid Build Coastguard Worker     if (mPaused) {
321*b9df5ad1SAndroid Build Coastguard Worker         return 0;
322*b9df5ad1SAndroid Build Coastguard Worker     }
323*b9df5ad1SAndroid Build Coastguard Worker 
324*b9df5ad1SAndroid Build Coastguard Worker     // should be uncontested and not block if process method is called from a single thread
325*b9df5ad1SAndroid Build Coastguard Worker     std::lock_guard<std::mutex> guard(mLock);
326*b9df5ad1SAndroid Build Coastguard Worker 
327*b9df5ad1SAndroid Build Coastguard Worker     if (!isSampleRateSupported_l()) {
328*b9df5ad1SAndroid Build Coastguard Worker         return 0;
329*b9df5ad1SAndroid Build Coastguard Worker     }
330*b9df5ad1SAndroid Build Coastguard Worker 
331*b9df5ad1SAndroid Build Coastguard Worker     const size_t bytes_per_sample = audio_bytes_per_sample(mFormat);
332*b9df5ad1SAndroid Build Coastguard Worker     size_t samples = bytes_per_sample > 0 ? bytes / bytes_per_sample : 0;
333*b9df5ad1SAndroid Build Coastguard Worker     while (samples > 0) {
334*b9df5ad1SAndroid Build Coastguard Worker         const size_t requiredSamples =
335*b9df5ad1SAndroid Build Coastguard Worker             mFramesPerMelValue * mChannelCount - mCurrentSamples;
336*b9df5ad1SAndroid Build Coastguard Worker         size_t processSamples = std::min(requiredSamples, samples);
337*b9df5ad1SAndroid Build Coastguard Worker         processSamples -= processSamples % mChannelCount;
338*b9df5ad1SAndroid Build Coastguard Worker 
339*b9df5ad1SAndroid Build Coastguard Worker         applyAWeight_l(buffer, processSamples);
340*b9df5ad1SAndroid Build Coastguard Worker 
341*b9df5ad1SAndroid Build Coastguard Worker         audio_utils_accumulate_energy(mAWeightSamples.data(),
342*b9df5ad1SAndroid Build Coastguard Worker                                       AUDIO_FORMAT_PCM_FLOAT,
343*b9df5ad1SAndroid Build Coastguard Worker                                       processSamples,
344*b9df5ad1SAndroid Build Coastguard Worker                                       mChannelCount,
345*b9df5ad1SAndroid Build Coastguard Worker                                       mCurrentChannelEnergy.data());
346*b9df5ad1SAndroid Build Coastguard Worker         mCurrentSamples += processSamples;
347*b9df5ad1SAndroid Build Coastguard Worker 
348*b9df5ad1SAndroid Build Coastguard Worker         ALOGVV(
349*b9df5ad1SAndroid Build Coastguard Worker             "required:%zu, process:%zu, mCurrentChannelEnergy[0]:%f, mCurrentSamples:%zu",
350*b9df5ad1SAndroid Build Coastguard Worker             requiredSamples,
351*b9df5ad1SAndroid Build Coastguard Worker             processSamples,
352*b9df5ad1SAndroid Build Coastguard Worker             mCurrentChannelEnergy[0],
353*b9df5ad1SAndroid Build Coastguard Worker             mCurrentSamples.load());
354*b9df5ad1SAndroid Build Coastguard Worker         if (processSamples < requiredSamples) {
355*b9df5ad1SAndroid Build Coastguard Worker             return static_cast<int32_t>(bytes);
356*b9df5ad1SAndroid Build Coastguard Worker         }
357*b9df5ad1SAndroid Build Coastguard Worker 
358*b9df5ad1SAndroid Build Coastguard Worker         addMelValue_l(fmaxf(
359*b9df5ad1SAndroid Build Coastguard Worker             audio_utils_power_from_energy(getCombinedChannelEnergy_l())
360*b9df5ad1SAndroid Build Coastguard Worker                 + kMelAdjustmentDb
361*b9df5ad1SAndroid Build Coastguard Worker                 + kMeldBFSTodBSPLOffset
362*b9df5ad1SAndroid Build Coastguard Worker                 - mAttenuationDB, 0.0f));
363*b9df5ad1SAndroid Build Coastguard Worker 
364*b9df5ad1SAndroid Build Coastguard Worker         samples -= processSamples;
365*b9df5ad1SAndroid Build Coastguard Worker         buffer =
366*b9df5ad1SAndroid Build Coastguard Worker             (const uint8_t*) buffer + processSamples * bytes_per_sample;
367*b9df5ad1SAndroid Build Coastguard Worker         mCurrentSamples = 0;
368*b9df5ad1SAndroid Build Coastguard Worker     }
369*b9df5ad1SAndroid Build Coastguard Worker 
370*b9df5ad1SAndroid Build Coastguard Worker     return static_cast<int32_t>(bytes);
371*b9df5ad1SAndroid Build Coastguard Worker }
372*b9df5ad1SAndroid Build Coastguard Worker 
setAttenuation(float attenuationDB)373*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::setAttenuation(float attenuationDB) {
374*b9df5ad1SAndroid Build Coastguard Worker     ALOGV("%s: setting the attenuation %f", __func__, attenuationDB);
375*b9df5ad1SAndroid Build Coastguard Worker     mAttenuationDB = attenuationDB;
376*b9df5ad1SAndroid Build Coastguard Worker }
377*b9df5ad1SAndroid Build Coastguard Worker 
onLastStrongRef(const void * id)378*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::onLastStrongRef(const void* id __attribute__((unused))) {
379*b9df5ad1SAndroid Build Coastguard Worker    mMelWorker.stop();
380*b9df5ad1SAndroid Build Coastguard Worker    ALOGV("%s: Stopped thread: %s for device %d", __func__, mMelWorker.getThreadName().c_str(),
381*b9df5ad1SAndroid Build Coastguard Worker          mDeviceId.load());
382*b9df5ad1SAndroid Build Coastguard Worker }
383*b9df5ad1SAndroid Build Coastguard Worker 
pointerString() const384*b9df5ad1SAndroid Build Coastguard Worker std::string MelProcessor::pointerString() const {
385*b9df5ad1SAndroid Build Coastguard Worker     const void * address = static_cast<const void*>(this);
386*b9df5ad1SAndroid Build Coastguard Worker     std::stringstream aStream;
387*b9df5ad1SAndroid Build Coastguard Worker     aStream << address;
388*b9df5ad1SAndroid Build Coastguard Worker     return aStream.str();
389*b9df5ad1SAndroid Build Coastguard Worker }
390*b9df5ad1SAndroid Build Coastguard Worker 
run()391*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::MelWorker::run() {
392*b9df5ad1SAndroid Build Coastguard Worker     mThread = std::thread([&]{
393*b9df5ad1SAndroid Build Coastguard Worker         // name the thread to help identification
394*b9df5ad1SAndroid Build Coastguard Worker         androidSetThreadName(mThreadName.c_str());
395*b9df5ad1SAndroid Build Coastguard Worker         ALOGV("%s::run(): Started thread", mThreadName.c_str());
396*b9df5ad1SAndroid Build Coastguard Worker 
397*b9df5ad1SAndroid Build Coastguard Worker         audio_utils::unique_lock l(mCondVarMutex);
398*b9df5ad1SAndroid Build Coastguard Worker         while (true) {
399*b9df5ad1SAndroid Build Coastguard Worker             if (mStopRequested) {
400*b9df5ad1SAndroid Build Coastguard Worker                 return;
401*b9df5ad1SAndroid Build Coastguard Worker             }
402*b9df5ad1SAndroid Build Coastguard Worker             mCondVar.wait(l);
403*b9df5ad1SAndroid Build Coastguard Worker             while (mRbReadPtr != mRbWritePtr && !mStopRequested) { // load-acquire mRbWritePtr
404*b9df5ad1SAndroid Build Coastguard Worker                 ALOGV("%s::run(): new callbacks, rb idx read=%zu, write=%zu",
405*b9df5ad1SAndroid Build Coastguard Worker                       mThreadName.c_str(),
406*b9df5ad1SAndroid Build Coastguard Worker                       mRbReadPtr.load(),
407*b9df5ad1SAndroid Build Coastguard Worker                       mRbWritePtr.load());
408*b9df5ad1SAndroid Build Coastguard Worker                 const auto callback = mCallback.promote();
409*b9df5ad1SAndroid Build Coastguard Worker                 if (callback == nullptr) {
410*b9df5ad1SAndroid Build Coastguard Worker                     ALOGW("%s::run(): MelCallback is null, quitting MelWorker",
411*b9df5ad1SAndroid Build Coastguard Worker                           mThreadName.c_str());
412*b9df5ad1SAndroid Build Coastguard Worker                     return;
413*b9df5ad1SAndroid Build Coastguard Worker                 }
414*b9df5ad1SAndroid Build Coastguard Worker 
415*b9df5ad1SAndroid Build Coastguard Worker                 const MelCallbackData& data = mCallbackRingBuffer[mRbReadPtr];
416*b9df5ad1SAndroid Build Coastguard Worker                 if (data.mMel != 0.f) {
417*b9df5ad1SAndroid Build Coastguard Worker                     l.unlock();
418*b9df5ad1SAndroid Build Coastguard Worker                     callback->onMomentaryExposure(data.mMel, data.mPort);
419*b9df5ad1SAndroid Build Coastguard Worker                     l.lock();
420*b9df5ad1SAndroid Build Coastguard Worker                 } else if (data.mMelsSize != 0) {
421*b9df5ad1SAndroid Build Coastguard Worker                     l.unlock();
422*b9df5ad1SAndroid Build Coastguard Worker                     callback->onNewMelValues(data.mMels, 0, data.mMelsSize,
423*b9df5ad1SAndroid Build Coastguard Worker                                              data.mPort, /*attenuated=*/true);
424*b9df5ad1SAndroid Build Coastguard Worker                     l.lock();
425*b9df5ad1SAndroid Build Coastguard Worker                 } else {
426*b9df5ad1SAndroid Build Coastguard Worker                     ALOGE("%s::run(): Invalid MEL data. Skipping callback", mThreadName.c_str());
427*b9df5ad1SAndroid Build Coastguard Worker                 }
428*b9df5ad1SAndroid Build Coastguard Worker                 mRbReadPtr = nextRingBufferIndex(mRbReadPtr);  // single reader updates this.
429*b9df5ad1SAndroid Build Coastguard Worker             }
430*b9df5ad1SAndroid Build Coastguard Worker         }
431*b9df5ad1SAndroid Build Coastguard Worker     });
432*b9df5ad1SAndroid Build Coastguard Worker }
433*b9df5ad1SAndroid Build Coastguard Worker 
stop()434*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::MelWorker::stop() {
435*b9df5ad1SAndroid Build Coastguard Worker     bool oldValue;
436*b9df5ad1SAndroid Build Coastguard Worker     {
437*b9df5ad1SAndroid Build Coastguard Worker         std::lock_guard l(mCondVarMutex);
438*b9df5ad1SAndroid Build Coastguard Worker         oldValue = mStopRequested;
439*b9df5ad1SAndroid Build Coastguard Worker         mStopRequested = true;
440*b9df5ad1SAndroid Build Coastguard Worker     }
441*b9df5ad1SAndroid Build Coastguard Worker     if (!oldValue) {
442*b9df5ad1SAndroid Build Coastguard Worker         mCondVar.notify_one();
443*b9df5ad1SAndroid Build Coastguard Worker         mThread.join();
444*b9df5ad1SAndroid Build Coastguard Worker     }
445*b9df5ad1SAndroid Build Coastguard Worker }
446*b9df5ad1SAndroid Build Coastguard Worker 
drain()447*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::MelWorker::drain() {
448*b9df5ad1SAndroid Build Coastguard Worker     std::lock_guard l(mCondVarMutex);
449*b9df5ad1SAndroid Build Coastguard Worker     mCondVar.notify_one();
450*b9df5ad1SAndroid Build Coastguard Worker }
451*b9df5ad1SAndroid Build Coastguard Worker 
momentaryExposure(float mel,audio_port_handle_t port)452*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::MelWorker::momentaryExposure(float mel, audio_port_handle_t port) {
453*b9df5ad1SAndroid Build Coastguard Worker     ALOGV("%s", __func__);
454*b9df5ad1SAndroid Build Coastguard Worker 
455*b9df5ad1SAndroid Build Coastguard Worker     if (ringBufferIsFull()) {
456*b9df5ad1SAndroid Build Coastguard Worker         ALOGW("%s: cannot add momentary exposure for port %d, MelWorker buffer is full", __func__,
457*b9df5ad1SAndroid Build Coastguard Worker               port);
458*b9df5ad1SAndroid Build Coastguard Worker         return;
459*b9df5ad1SAndroid Build Coastguard Worker     }
460*b9df5ad1SAndroid Build Coastguard Worker 
461*b9df5ad1SAndroid Build Coastguard Worker     // worker is thread-safe, no lock since there is only one writer and we take into account
462*b9df5ad1SAndroid Build Coastguard Worker     // spurious wake-ups
463*b9df5ad1SAndroid Build Coastguard Worker     mCallbackRingBuffer[mRbWritePtr].mMel = mel;
464*b9df5ad1SAndroid Build Coastguard Worker     mCallbackRingBuffer[mRbWritePtr].mMelsSize = 0;
465*b9df5ad1SAndroid Build Coastguard Worker     mCallbackRingBuffer[mRbWritePtr].mPort = port;
466*b9df5ad1SAndroid Build Coastguard Worker 
467*b9df5ad1SAndroid Build Coastguard Worker     mRbWritePtr = nextRingBufferIndex(mRbWritePtr);  // single writer, store-release.
468*b9df5ad1SAndroid Build Coastguard Worker }
469*b9df5ad1SAndroid Build Coastguard Worker 
newMelValues(const std::vector<float> & mels,size_t melsSize,audio_port_handle_t port)470*b9df5ad1SAndroid Build Coastguard Worker void MelProcessor::MelWorker::newMelValues(const std::vector<float>& mels,
471*b9df5ad1SAndroid Build Coastguard Worker                                            size_t melsSize,
472*b9df5ad1SAndroid Build Coastguard Worker                                            audio_port_handle_t port) {
473*b9df5ad1SAndroid Build Coastguard Worker     ALOGV("%s", __func__);
474*b9df5ad1SAndroid Build Coastguard Worker 
475*b9df5ad1SAndroid Build Coastguard Worker     if (ringBufferIsFull()) {
476*b9df5ad1SAndroid Build Coastguard Worker         ALOGW("%s: cannot add %zu mel values for port %d, MelWorker buffer is full", __func__,
477*b9df5ad1SAndroid Build Coastguard Worker               melsSize, port);
478*b9df5ad1SAndroid Build Coastguard Worker         return;
479*b9df5ad1SAndroid Build Coastguard Worker     }
480*b9df5ad1SAndroid Build Coastguard Worker 
481*b9df5ad1SAndroid Build Coastguard Worker     // worker is thread-safe, no lock since there is only one writer and we take into account
482*b9df5ad1SAndroid Build Coastguard Worker     // spurious wake-ups
483*b9df5ad1SAndroid Build Coastguard Worker     std::copy_n(std::begin(mels), melsSize, mCallbackRingBuffer[mRbWritePtr].mMels.begin());
484*b9df5ad1SAndroid Build Coastguard Worker     mCallbackRingBuffer[mRbWritePtr].mMelsSize = melsSize;
485*b9df5ad1SAndroid Build Coastguard Worker     mCallbackRingBuffer[mRbWritePtr].mMel = 0.f;
486*b9df5ad1SAndroid Build Coastguard Worker     mCallbackRingBuffer[mRbWritePtr].mPort = port;
487*b9df5ad1SAndroid Build Coastguard Worker 
488*b9df5ad1SAndroid Build Coastguard Worker     mRbWritePtr = nextRingBufferIndex(mRbWritePtr);  // single writer, store-release.
489*b9df5ad1SAndroid Build Coastguard Worker }
490*b9df5ad1SAndroid Build Coastguard Worker 
ringBufferIsFull() const491*b9df5ad1SAndroid Build Coastguard Worker bool MelProcessor::MelWorker::ringBufferIsFull() const {
492*b9df5ad1SAndroid Build Coastguard Worker     return nextRingBufferIndex(mRbWritePtr) == mRbReadPtr;
493*b9df5ad1SAndroid Build Coastguard Worker }
494*b9df5ad1SAndroid Build Coastguard Worker 
495*b9df5ad1SAndroid Build Coastguard Worker }   // namespace android
496