xref: /aosp_15_r20/frameworks/av/media/libaudioprocessing/BufferProviders.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "BufferProvider"
18*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
19*ec779b8eSAndroid Build Coastguard Worker 
20*ec779b8eSAndroid Build Coastguard Worker #include <algorithm>
21*ec779b8eSAndroid Build Coastguard Worker 
22*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/primitives.h>
23*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/format.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/channels.h>
25*ec779b8eSAndroid Build Coastguard Worker #include <sonic.h>
26*ec779b8eSAndroid Build Coastguard Worker #include <media/audiohal/EffectBufferHalInterface.h>
27*ec779b8eSAndroid Build Coastguard Worker #include <media/audiohal/EffectHalInterface.h>
28*ec779b8eSAndroid Build Coastguard Worker #include <media/audiohal/EffectsFactoryHalInterface.h>
29*ec779b8eSAndroid Build Coastguard Worker #include <media/AudioResamplerPublic.h>
30*ec779b8eSAndroid Build Coastguard Worker #include <media/BufferProviders.h>
31*ec779b8eSAndroid Build Coastguard Worker #include <system/audio_effects/effect_downmix.h>
32*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
33*ec779b8eSAndroid Build Coastguard Worker 
34*ec779b8eSAndroid Build Coastguard Worker #ifndef ARRAY_SIZE
35*ec779b8eSAndroid Build Coastguard Worker #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
36*ec779b8eSAndroid Build Coastguard Worker #endif
37*ec779b8eSAndroid Build Coastguard Worker 
38*ec779b8eSAndroid Build Coastguard Worker namespace android {
39*ec779b8eSAndroid Build Coastguard Worker 
40*ec779b8eSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
CopyBufferProvider(size_t inputFrameSize,size_t outputFrameSize,size_t bufferFrameCount)41*ec779b8eSAndroid Build Coastguard Worker CopyBufferProvider::CopyBufferProvider(size_t inputFrameSize,
42*ec779b8eSAndroid Build Coastguard Worker         size_t outputFrameSize, size_t bufferFrameCount) :
43*ec779b8eSAndroid Build Coastguard Worker         mInputFrameSize(inputFrameSize),
44*ec779b8eSAndroid Build Coastguard Worker         mOutputFrameSize(outputFrameSize),
45*ec779b8eSAndroid Build Coastguard Worker         mLocalBufferFrameCount(bufferFrameCount),
46*ec779b8eSAndroid Build Coastguard Worker         mLocalBufferData(NULL),
47*ec779b8eSAndroid Build Coastguard Worker         mConsumed(0)
48*ec779b8eSAndroid Build Coastguard Worker {
49*ec779b8eSAndroid Build Coastguard Worker     ALOGV("CopyBufferProvider(%p)(%zu, %zu, %zu)", this,
50*ec779b8eSAndroid Build Coastguard Worker             inputFrameSize, outputFrameSize, bufferFrameCount);
51*ec779b8eSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(inputFrameSize < outputFrameSize && bufferFrameCount == 0,
52*ec779b8eSAndroid Build Coastguard Worker             "Requires local buffer if inputFrameSize(%zu) < outputFrameSize(%zu)",
53*ec779b8eSAndroid Build Coastguard Worker             inputFrameSize, outputFrameSize);
54*ec779b8eSAndroid Build Coastguard Worker     if (mLocalBufferFrameCount) {
55*ec779b8eSAndroid Build Coastguard Worker         (void)posix_memalign(&mLocalBufferData, 32, mLocalBufferFrameCount * mOutputFrameSize);
56*ec779b8eSAndroid Build Coastguard Worker     }
57*ec779b8eSAndroid Build Coastguard Worker     mBuffer.frameCount = 0;
58*ec779b8eSAndroid Build Coastguard Worker }
59*ec779b8eSAndroid Build Coastguard Worker 
~CopyBufferProvider()60*ec779b8eSAndroid Build Coastguard Worker CopyBufferProvider::~CopyBufferProvider()
61*ec779b8eSAndroid Build Coastguard Worker {
62*ec779b8eSAndroid Build Coastguard Worker     ALOGV("%s(%p) %zu %p %p",
63*ec779b8eSAndroid Build Coastguard Worker            __func__, this, mBuffer.frameCount, mTrackBufferProvider, mLocalBufferData);
64*ec779b8eSAndroid Build Coastguard Worker     if (mBuffer.frameCount != 0) {
65*ec779b8eSAndroid Build Coastguard Worker         mTrackBufferProvider->releaseBuffer(&mBuffer);
66*ec779b8eSAndroid Build Coastguard Worker     }
67*ec779b8eSAndroid Build Coastguard Worker     free(mLocalBufferData);
68*ec779b8eSAndroid Build Coastguard Worker }
69*ec779b8eSAndroid Build Coastguard Worker 
getNextBuffer(AudioBufferProvider::Buffer * pBuffer)70*ec779b8eSAndroid Build Coastguard Worker status_t CopyBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer)
71*ec779b8eSAndroid Build Coastguard Worker {
72*ec779b8eSAndroid Build Coastguard Worker     //ALOGV("CopyBufferProvider(%p)::getNextBuffer(%p (%zu))",
73*ec779b8eSAndroid Build Coastguard Worker     //        this, pBuffer, pBuffer->frameCount);
74*ec779b8eSAndroid Build Coastguard Worker     if (mLocalBufferFrameCount == 0) {
75*ec779b8eSAndroid Build Coastguard Worker         status_t res = mTrackBufferProvider->getNextBuffer(pBuffer);
76*ec779b8eSAndroid Build Coastguard Worker         if (res == OK) {
77*ec779b8eSAndroid Build Coastguard Worker             copyFrames(pBuffer->raw, pBuffer->raw, pBuffer->frameCount);
78*ec779b8eSAndroid Build Coastguard Worker         }
79*ec779b8eSAndroid Build Coastguard Worker         return res;
80*ec779b8eSAndroid Build Coastguard Worker     }
81*ec779b8eSAndroid Build Coastguard Worker     if (mBuffer.frameCount == 0) {
82*ec779b8eSAndroid Build Coastguard Worker         mBuffer.frameCount = pBuffer->frameCount;
83*ec779b8eSAndroid Build Coastguard Worker         status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer);
84*ec779b8eSAndroid Build Coastguard Worker         // At one time an upstream buffer provider had
85*ec779b8eSAndroid Build Coastguard Worker         // res == OK and mBuffer.frameCount == 0, doesn't seem to happen now 7/18/2014.
86*ec779b8eSAndroid Build Coastguard Worker         //
87*ec779b8eSAndroid Build Coastguard Worker         // By API spec, if res != OK, then mBuffer.frameCount == 0.
88*ec779b8eSAndroid Build Coastguard Worker         // but there may be improper implementations.
89*ec779b8eSAndroid Build Coastguard Worker         ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
90*ec779b8eSAndroid Build Coastguard Worker         if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
91*ec779b8eSAndroid Build Coastguard Worker             pBuffer->raw = NULL;
92*ec779b8eSAndroid Build Coastguard Worker             pBuffer->frameCount = 0;
93*ec779b8eSAndroid Build Coastguard Worker             return res;
94*ec779b8eSAndroid Build Coastguard Worker         }
95*ec779b8eSAndroid Build Coastguard Worker         mConsumed = 0;
96*ec779b8eSAndroid Build Coastguard Worker     }
97*ec779b8eSAndroid Build Coastguard Worker     ALOG_ASSERT(mConsumed < mBuffer.frameCount);
98*ec779b8eSAndroid Build Coastguard Worker     size_t count = std::min(mLocalBufferFrameCount, mBuffer.frameCount - mConsumed);
99*ec779b8eSAndroid Build Coastguard Worker     count = std::min(count, pBuffer->frameCount);
100*ec779b8eSAndroid Build Coastguard Worker     pBuffer->raw = mLocalBufferData;
101*ec779b8eSAndroid Build Coastguard Worker     pBuffer->frameCount = count;
102*ec779b8eSAndroid Build Coastguard Worker     copyFrames(pBuffer->raw, (uint8_t*)mBuffer.raw + mConsumed * mInputFrameSize,
103*ec779b8eSAndroid Build Coastguard Worker             pBuffer->frameCount);
104*ec779b8eSAndroid Build Coastguard Worker     return OK;
105*ec779b8eSAndroid Build Coastguard Worker }
106*ec779b8eSAndroid Build Coastguard Worker 
releaseBuffer(AudioBufferProvider::Buffer * pBuffer)107*ec779b8eSAndroid Build Coastguard Worker void CopyBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer)
108*ec779b8eSAndroid Build Coastguard Worker {
109*ec779b8eSAndroid Build Coastguard Worker     //ALOGV("CopyBufferProvider(%p)::releaseBuffer(%p(%zu))",
110*ec779b8eSAndroid Build Coastguard Worker     //        this, pBuffer, pBuffer->frameCount);
111*ec779b8eSAndroid Build Coastguard Worker     if (mLocalBufferFrameCount == 0) {
112*ec779b8eSAndroid Build Coastguard Worker         mTrackBufferProvider->releaseBuffer(pBuffer);
113*ec779b8eSAndroid Build Coastguard Worker         return;
114*ec779b8eSAndroid Build Coastguard Worker     }
115*ec779b8eSAndroid Build Coastguard Worker     // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
116*ec779b8eSAndroid Build Coastguard Worker     mConsumed += pBuffer->frameCount; // TODO: update for efficiency to reuse existing content
117*ec779b8eSAndroid Build Coastguard Worker     if (mConsumed != 0 && mConsumed >= mBuffer.frameCount) {
118*ec779b8eSAndroid Build Coastguard Worker         mTrackBufferProvider->releaseBuffer(&mBuffer);
119*ec779b8eSAndroid Build Coastguard Worker         ALOG_ASSERT(mBuffer.frameCount == 0);
120*ec779b8eSAndroid Build Coastguard Worker     }
121*ec779b8eSAndroid Build Coastguard Worker     pBuffer->raw = NULL;
122*ec779b8eSAndroid Build Coastguard Worker     pBuffer->frameCount = 0;
123*ec779b8eSAndroid Build Coastguard Worker }
124*ec779b8eSAndroid Build Coastguard Worker 
reset()125*ec779b8eSAndroid Build Coastguard Worker void CopyBufferProvider::reset()
126*ec779b8eSAndroid Build Coastguard Worker {
127*ec779b8eSAndroid Build Coastguard Worker     if (mBuffer.frameCount != 0) {
128*ec779b8eSAndroid Build Coastguard Worker         mTrackBufferProvider->releaseBuffer(&mBuffer);
129*ec779b8eSAndroid Build Coastguard Worker     }
130*ec779b8eSAndroid Build Coastguard Worker     mConsumed = 0;
131*ec779b8eSAndroid Build Coastguard Worker }
132*ec779b8eSAndroid Build Coastguard Worker 
setBufferProvider(AudioBufferProvider * p)133*ec779b8eSAndroid Build Coastguard Worker void CopyBufferProvider::setBufferProvider(AudioBufferProvider *p) {
134*ec779b8eSAndroid Build Coastguard Worker     ALOGV("%s(%p): mTrackBufferProvider:%p  mBuffer.frameCount:%zu",
135*ec779b8eSAndroid Build Coastguard Worker             __func__, p, mTrackBufferProvider, mBuffer.frameCount);
136*ec779b8eSAndroid Build Coastguard Worker     if (mTrackBufferProvider == p) {
137*ec779b8eSAndroid Build Coastguard Worker         return;
138*ec779b8eSAndroid Build Coastguard Worker     }
139*ec779b8eSAndroid Build Coastguard Worker     mBuffer.frameCount = 0;
140*ec779b8eSAndroid Build Coastguard Worker     PassthruBufferProvider::setBufferProvider(p);
141*ec779b8eSAndroid Build Coastguard Worker }
142*ec779b8eSAndroid Build Coastguard Worker 
DownmixerBufferProvider(audio_channel_mask_t inputChannelMask,audio_channel_mask_t outputChannelMask,audio_format_t format,uint32_t sampleRate,int32_t sessionId,size_t bufferFrameCount)143*ec779b8eSAndroid Build Coastguard Worker DownmixerBufferProvider::DownmixerBufferProvider(
144*ec779b8eSAndroid Build Coastguard Worker         audio_channel_mask_t inputChannelMask,
145*ec779b8eSAndroid Build Coastguard Worker         audio_channel_mask_t outputChannelMask, audio_format_t format,
146*ec779b8eSAndroid Build Coastguard Worker         uint32_t sampleRate, int32_t sessionId, size_t bufferFrameCount) :
147*ec779b8eSAndroid Build Coastguard Worker         CopyBufferProvider(
148*ec779b8eSAndroid Build Coastguard Worker             audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask),
149*ec779b8eSAndroid Build Coastguard Worker             audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask),
150*ec779b8eSAndroid Build Coastguard Worker             bufferFrameCount)  // set bufferFrameCount to 0 to do in-place
151*ec779b8eSAndroid Build Coastguard Worker {
152*ec779b8eSAndroid Build Coastguard Worker     ALOGV("DownmixerBufferProvider(%p)(%#x, %#x, %#x %u %d %d)",
153*ec779b8eSAndroid Build Coastguard Worker             this, inputChannelMask, outputChannelMask, format,
154*ec779b8eSAndroid Build Coastguard Worker             sampleRate, sessionId, (int)bufferFrameCount);
155*ec779b8eSAndroid Build Coastguard Worker     if (!sIsMultichannelCapable) {
156*ec779b8eSAndroid Build Coastguard Worker         ALOGE("DownmixerBufferProvider() error: not multichannel capable");
157*ec779b8eSAndroid Build Coastguard Worker         return;
158*ec779b8eSAndroid Build Coastguard Worker     }
159*ec779b8eSAndroid Build Coastguard Worker     mEffectsFactory = EffectsFactoryHalInterface::create();
160*ec779b8eSAndroid Build Coastguard Worker     if (mEffectsFactory == 0) {
161*ec779b8eSAndroid Build Coastguard Worker         ALOGE("DownmixerBufferProvider() error: could not obtain the effects factory");
162*ec779b8eSAndroid Build Coastguard Worker         return;
163*ec779b8eSAndroid Build Coastguard Worker     }
164*ec779b8eSAndroid Build Coastguard Worker     if (mEffectsFactory->createEffect(&sDwnmFxDesc.uuid,
165*ec779b8eSAndroid Build Coastguard Worker                                       sessionId,
166*ec779b8eSAndroid Build Coastguard Worker                                       SESSION_ID_INVALID_AND_IGNORED,
167*ec779b8eSAndroid Build Coastguard Worker                                       AUDIO_PORT_HANDLE_NONE,
168*ec779b8eSAndroid Build Coastguard Worker                                       &mDownmixInterface) != 0) {
169*ec779b8eSAndroid Build Coastguard Worker          ALOGE("DownmixerBufferProvider() error creating downmixer effect");
170*ec779b8eSAndroid Build Coastguard Worker          mDownmixInterface.clear();
171*ec779b8eSAndroid Build Coastguard Worker          mEffectsFactory.clear();
172*ec779b8eSAndroid Build Coastguard Worker          return;
173*ec779b8eSAndroid Build Coastguard Worker      }
174*ec779b8eSAndroid Build Coastguard Worker      // channel input configuration will be overridden per-track
175*ec779b8eSAndroid Build Coastguard Worker      mDownmixConfig.inputCfg.channels = inputChannelMask;   // FIXME: Should be bits
176*ec779b8eSAndroid Build Coastguard Worker      mDownmixConfig.outputCfg.channels = outputChannelMask; // FIXME: should be bits
177*ec779b8eSAndroid Build Coastguard Worker      mDownmixConfig.inputCfg.format = format;
178*ec779b8eSAndroid Build Coastguard Worker      mDownmixConfig.outputCfg.format = format;
179*ec779b8eSAndroid Build Coastguard Worker      mDownmixConfig.inputCfg.samplingRate = sampleRate;
180*ec779b8eSAndroid Build Coastguard Worker      mDownmixConfig.outputCfg.samplingRate = sampleRate;
181*ec779b8eSAndroid Build Coastguard Worker      mDownmixConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
182*ec779b8eSAndroid Build Coastguard Worker      mDownmixConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
183*ec779b8eSAndroid Build Coastguard Worker      // input and output buffer provider, and frame count will not be used as the downmix effect
184*ec779b8eSAndroid Build Coastguard Worker      // process() function is called directly (see DownmixerBufferProvider::getNextBuffer())
185*ec779b8eSAndroid Build Coastguard Worker      mDownmixConfig.inputCfg.mask = EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS |
186*ec779b8eSAndroid Build Coastguard Worker              EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE;
187*ec779b8eSAndroid Build Coastguard Worker      mDownmixConfig.outputCfg.mask = mDownmixConfig.inputCfg.mask;
188*ec779b8eSAndroid Build Coastguard Worker      mDownmixConfig.inputCfg.buffer.frameCount = bufferFrameCount;
189*ec779b8eSAndroid Build Coastguard Worker      mDownmixConfig.outputCfg.buffer.frameCount = bufferFrameCount;
190*ec779b8eSAndroid Build Coastguard Worker 
191*ec779b8eSAndroid Build Coastguard Worker      mInFrameSize =
192*ec779b8eSAndroid Build Coastguard Worker              audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask);
193*ec779b8eSAndroid Build Coastguard Worker      mOutFrameSize =
194*ec779b8eSAndroid Build Coastguard Worker              audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask);
195*ec779b8eSAndroid Build Coastguard Worker      status_t status;
196*ec779b8eSAndroid Build Coastguard Worker      status = mEffectsFactory->mirrorBuffer(
197*ec779b8eSAndroid Build Coastguard Worker              nullptr, mInFrameSize * bufferFrameCount, &mInBuffer);
198*ec779b8eSAndroid Build Coastguard Worker      if (status != 0) {
199*ec779b8eSAndroid Build Coastguard Worker          ALOGE("DownmixerBufferProvider() error %d while creating input buffer", status);
200*ec779b8eSAndroid Build Coastguard Worker          mDownmixInterface.clear();
201*ec779b8eSAndroid Build Coastguard Worker          mEffectsFactory.clear();
202*ec779b8eSAndroid Build Coastguard Worker          return;
203*ec779b8eSAndroid Build Coastguard Worker      }
204*ec779b8eSAndroid Build Coastguard Worker      status = mEffectsFactory->mirrorBuffer(
205*ec779b8eSAndroid Build Coastguard Worker              nullptr, mOutFrameSize * bufferFrameCount, &mOutBuffer);
206*ec779b8eSAndroid Build Coastguard Worker      if (status != 0) {
207*ec779b8eSAndroid Build Coastguard Worker          ALOGE("DownmixerBufferProvider() error %d while creating output buffer", status);
208*ec779b8eSAndroid Build Coastguard Worker          mInBuffer.clear();
209*ec779b8eSAndroid Build Coastguard Worker          mDownmixInterface.clear();
210*ec779b8eSAndroid Build Coastguard Worker          mEffectsFactory.clear();
211*ec779b8eSAndroid Build Coastguard Worker          return;
212*ec779b8eSAndroid Build Coastguard Worker      }
213*ec779b8eSAndroid Build Coastguard Worker      mDownmixInterface->setInBuffer(mInBuffer);
214*ec779b8eSAndroid Build Coastguard Worker      mDownmixInterface->setOutBuffer(mOutBuffer);
215*ec779b8eSAndroid Build Coastguard Worker 
216*ec779b8eSAndroid Build Coastguard Worker      int cmdStatus;
217*ec779b8eSAndroid Build Coastguard Worker      uint32_t replySize = sizeof(int);
218*ec779b8eSAndroid Build Coastguard Worker 
219*ec779b8eSAndroid Build Coastguard Worker      // Configure downmixer
220*ec779b8eSAndroid Build Coastguard Worker      status = mDownmixInterface->command(
221*ec779b8eSAndroid Build Coastguard Worker              EFFECT_CMD_SET_CONFIG /*cmdCode*/, sizeof(effect_config_t) /*cmdSize*/,
222*ec779b8eSAndroid Build Coastguard Worker              &mDownmixConfig /*pCmdData*/,
223*ec779b8eSAndroid Build Coastguard Worker              &replySize, &cmdStatus /*pReplyData*/);
224*ec779b8eSAndroid Build Coastguard Worker      if (status != 0 || cmdStatus != 0) {
225*ec779b8eSAndroid Build Coastguard Worker          ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while configuring downmixer",
226*ec779b8eSAndroid Build Coastguard Worker                  status, cmdStatus);
227*ec779b8eSAndroid Build Coastguard Worker          mOutBuffer.clear();
228*ec779b8eSAndroid Build Coastguard Worker          mInBuffer.clear();
229*ec779b8eSAndroid Build Coastguard Worker          mDownmixInterface.clear();
230*ec779b8eSAndroid Build Coastguard Worker          mEffectsFactory.clear();
231*ec779b8eSAndroid Build Coastguard Worker          return;
232*ec779b8eSAndroid Build Coastguard Worker      }
233*ec779b8eSAndroid Build Coastguard Worker 
234*ec779b8eSAndroid Build Coastguard Worker      // Enable downmixer
235*ec779b8eSAndroid Build Coastguard Worker      replySize = sizeof(int);
236*ec779b8eSAndroid Build Coastguard Worker      status = mDownmixInterface->command(
237*ec779b8eSAndroid Build Coastguard Worker              EFFECT_CMD_ENABLE /*cmdCode*/, 0 /*cmdSize*/, NULL /*pCmdData*/,
238*ec779b8eSAndroid Build Coastguard Worker              &replySize, &cmdStatus /*pReplyData*/);
239*ec779b8eSAndroid Build Coastguard Worker      if (status != 0 || cmdStatus != 0) {
240*ec779b8eSAndroid Build Coastguard Worker          ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while enabling downmixer",
241*ec779b8eSAndroid Build Coastguard Worker                  status, cmdStatus);
242*ec779b8eSAndroid Build Coastguard Worker          mOutBuffer.clear();
243*ec779b8eSAndroid Build Coastguard Worker          mInBuffer.clear();
244*ec779b8eSAndroid Build Coastguard Worker          mDownmixInterface.clear();
245*ec779b8eSAndroid Build Coastguard Worker          mEffectsFactory.clear();
246*ec779b8eSAndroid Build Coastguard Worker          return;
247*ec779b8eSAndroid Build Coastguard Worker      }
248*ec779b8eSAndroid Build Coastguard Worker 
249*ec779b8eSAndroid Build Coastguard Worker      // Set downmix type
250*ec779b8eSAndroid Build Coastguard Worker      // parameter size rounded for padding on 32bit boundary
251*ec779b8eSAndroid Build Coastguard Worker      const int psizePadded = ((sizeof(downmix_params_t) - 1)/sizeof(int) + 1) * sizeof(int);
252*ec779b8eSAndroid Build Coastguard Worker      const int downmixParamSize =
253*ec779b8eSAndroid Build Coastguard Worker              sizeof(effect_param_t) + psizePadded + sizeof(downmix_type_t);
254*ec779b8eSAndroid Build Coastguard Worker      effect_param_t * const param = (effect_param_t *) malloc(downmixParamSize);
255*ec779b8eSAndroid Build Coastguard Worker      param->psize = sizeof(downmix_params_t);
256*ec779b8eSAndroid Build Coastguard Worker      const downmix_params_t downmixParam = DOWNMIX_PARAM_TYPE;
257*ec779b8eSAndroid Build Coastguard Worker      memcpy(param->data, &downmixParam, param->psize);
258*ec779b8eSAndroid Build Coastguard Worker      const downmix_type_t downmixType = DOWNMIX_TYPE_FOLD;
259*ec779b8eSAndroid Build Coastguard Worker      param->vsize = sizeof(downmix_type_t);
260*ec779b8eSAndroid Build Coastguard Worker      memcpy(param->data + psizePadded, &downmixType, param->vsize);
261*ec779b8eSAndroid Build Coastguard Worker      replySize = sizeof(int);
262*ec779b8eSAndroid Build Coastguard Worker      status = mDownmixInterface->command(
263*ec779b8eSAndroid Build Coastguard Worker              EFFECT_CMD_SET_PARAM /* cmdCode */, downmixParamSize /* cmdSize */,
264*ec779b8eSAndroid Build Coastguard Worker              param /*pCmdData*/, &replySize, &cmdStatus /*pReplyData*/);
265*ec779b8eSAndroid Build Coastguard Worker      free(param);
266*ec779b8eSAndroid Build Coastguard Worker      if (status != 0 || cmdStatus != 0) {
267*ec779b8eSAndroid Build Coastguard Worker          ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while setting downmix type",
268*ec779b8eSAndroid Build Coastguard Worker                  status, cmdStatus);
269*ec779b8eSAndroid Build Coastguard Worker          mOutBuffer.clear();
270*ec779b8eSAndroid Build Coastguard Worker          mInBuffer.clear();
271*ec779b8eSAndroid Build Coastguard Worker          mDownmixInterface.clear();
272*ec779b8eSAndroid Build Coastguard Worker          mEffectsFactory.clear();
273*ec779b8eSAndroid Build Coastguard Worker          return;
274*ec779b8eSAndroid Build Coastguard Worker      }
275*ec779b8eSAndroid Build Coastguard Worker      ALOGV("DownmixerBufferProvider() downmix type set to %d", (int) downmixType);
276*ec779b8eSAndroid Build Coastguard Worker }
277*ec779b8eSAndroid Build Coastguard Worker 
~DownmixerBufferProvider()278*ec779b8eSAndroid Build Coastguard Worker DownmixerBufferProvider::~DownmixerBufferProvider()
279*ec779b8eSAndroid Build Coastguard Worker {
280*ec779b8eSAndroid Build Coastguard Worker     ALOGV("~DownmixerBufferProvider (%p)", this);
281*ec779b8eSAndroid Build Coastguard Worker     if (mDownmixInterface != 0) {
282*ec779b8eSAndroid Build Coastguard Worker         mDownmixInterface->close();
283*ec779b8eSAndroid Build Coastguard Worker     }
284*ec779b8eSAndroid Build Coastguard Worker }
285*ec779b8eSAndroid Build Coastguard Worker 
copyFrames(void * dst,const void * src,size_t frames)286*ec779b8eSAndroid Build Coastguard Worker void DownmixerBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
287*ec779b8eSAndroid Build Coastguard Worker {
288*ec779b8eSAndroid Build Coastguard Worker     mInBuffer->setExternalData(const_cast<void*>(src));
289*ec779b8eSAndroid Build Coastguard Worker     mInBuffer->setFrameCount(frames);
290*ec779b8eSAndroid Build Coastguard Worker     mInBuffer->update(mInFrameSize * frames);
291*ec779b8eSAndroid Build Coastguard Worker     mOutBuffer->setFrameCount(frames);
292*ec779b8eSAndroid Build Coastguard Worker     mOutBuffer->setExternalData(dst);
293*ec779b8eSAndroid Build Coastguard Worker     if (dst != src) {
294*ec779b8eSAndroid Build Coastguard Worker         // Downmix may be accumulating, need to populate the output buffer
295*ec779b8eSAndroid Build Coastguard Worker         // with the dst data.
296*ec779b8eSAndroid Build Coastguard Worker         mOutBuffer->update(mOutFrameSize * frames);
297*ec779b8eSAndroid Build Coastguard Worker     }
298*ec779b8eSAndroid Build Coastguard Worker     // may be in-place if src == dst.
299*ec779b8eSAndroid Build Coastguard Worker     status_t res = mDownmixInterface->process();
300*ec779b8eSAndroid Build Coastguard Worker     if (res == OK) {
301*ec779b8eSAndroid Build Coastguard Worker         mOutBuffer->commit(mOutFrameSize * frames);
302*ec779b8eSAndroid Build Coastguard Worker     } else {
303*ec779b8eSAndroid Build Coastguard Worker         ALOGE("DownmixBufferProvider error %d", res);
304*ec779b8eSAndroid Build Coastguard Worker     }
305*ec779b8eSAndroid Build Coastguard Worker }
306*ec779b8eSAndroid Build Coastguard Worker 
307*ec779b8eSAndroid Build Coastguard Worker /* call once in a pthread_once handler. */
init()308*ec779b8eSAndroid Build Coastguard Worker /*static*/ status_t DownmixerBufferProvider::init()
309*ec779b8eSAndroid Build Coastguard Worker {
310*ec779b8eSAndroid Build Coastguard Worker     // find multichannel downmix effect if we have to play multichannel content
311*ec779b8eSAndroid Build Coastguard Worker     sp<EffectsFactoryHalInterface> effectsFactory = EffectsFactoryHalInterface::create();
312*ec779b8eSAndroid Build Coastguard Worker     if (effectsFactory == 0) {
313*ec779b8eSAndroid Build Coastguard Worker         ALOGE("AudioMixer() error: could not obtain the effects factory");
314*ec779b8eSAndroid Build Coastguard Worker         return NO_INIT;
315*ec779b8eSAndroid Build Coastguard Worker     }
316*ec779b8eSAndroid Build Coastguard Worker     uint32_t numEffects = 0;
317*ec779b8eSAndroid Build Coastguard Worker     int ret = effectsFactory->queryNumberEffects(&numEffects);
318*ec779b8eSAndroid Build Coastguard Worker     if (ret != 0) {
319*ec779b8eSAndroid Build Coastguard Worker         ALOGE("AudioMixer() error %d querying number of effects", ret);
320*ec779b8eSAndroid Build Coastguard Worker         return NO_INIT;
321*ec779b8eSAndroid Build Coastguard Worker     }
322*ec779b8eSAndroid Build Coastguard Worker     ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
323*ec779b8eSAndroid Build Coastguard Worker 
324*ec779b8eSAndroid Build Coastguard Worker     for (uint32_t i = 0 ; i < numEffects ; i++) {
325*ec779b8eSAndroid Build Coastguard Worker         if (effectsFactory->getDescriptor(i, &sDwnmFxDesc) == 0) {
326*ec779b8eSAndroid Build Coastguard Worker             ALOGV("effect %d is called %s", i, sDwnmFxDesc.name);
327*ec779b8eSAndroid Build Coastguard Worker             if (memcmp(&sDwnmFxDesc.type, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) {
328*ec779b8eSAndroid Build Coastguard Worker                 ALOGI("found effect \"%s\" from %s",
329*ec779b8eSAndroid Build Coastguard Worker                         sDwnmFxDesc.name, sDwnmFxDesc.implementor);
330*ec779b8eSAndroid Build Coastguard Worker                 sIsMultichannelCapable = true;
331*ec779b8eSAndroid Build Coastguard Worker                 break;
332*ec779b8eSAndroid Build Coastguard Worker             }
333*ec779b8eSAndroid Build Coastguard Worker         }
334*ec779b8eSAndroid Build Coastguard Worker     }
335*ec779b8eSAndroid Build Coastguard Worker     ALOGW_IF(!sIsMultichannelCapable, "unable to find downmix effect");
336*ec779b8eSAndroid Build Coastguard Worker     return NO_INIT;
337*ec779b8eSAndroid Build Coastguard Worker }
338*ec779b8eSAndroid Build Coastguard Worker 
339*ec779b8eSAndroid Build Coastguard Worker /*static*/ bool DownmixerBufferProvider::sIsMultichannelCapable = false;
340*ec779b8eSAndroid Build Coastguard Worker /*static*/ effect_descriptor_t DownmixerBufferProvider::sDwnmFxDesc;
341*ec779b8eSAndroid Build Coastguard Worker 
RemixBufferProvider(audio_channel_mask_t inputChannelMask,audio_channel_mask_t outputChannelMask,audio_format_t format,size_t bufferFrameCount)342*ec779b8eSAndroid Build Coastguard Worker RemixBufferProvider::RemixBufferProvider(audio_channel_mask_t inputChannelMask,
343*ec779b8eSAndroid Build Coastguard Worker         audio_channel_mask_t outputChannelMask, audio_format_t format,
344*ec779b8eSAndroid Build Coastguard Worker         size_t bufferFrameCount) :
345*ec779b8eSAndroid Build Coastguard Worker         CopyBufferProvider(
346*ec779b8eSAndroid Build Coastguard Worker                 audio_bytes_per_sample(format)
347*ec779b8eSAndroid Build Coastguard Worker                     * audio_channel_count_from_out_mask(inputChannelMask),
348*ec779b8eSAndroid Build Coastguard Worker                 audio_bytes_per_sample(format)
349*ec779b8eSAndroid Build Coastguard Worker                     * audio_channel_count_from_out_mask(outputChannelMask),
350*ec779b8eSAndroid Build Coastguard Worker                 bufferFrameCount),
351*ec779b8eSAndroid Build Coastguard Worker         mFormat(format),
352*ec779b8eSAndroid Build Coastguard Worker         mSampleSize(audio_bytes_per_sample(format)),
353*ec779b8eSAndroid Build Coastguard Worker         mInputChannels(audio_channel_count_from_out_mask(inputChannelMask)),
354*ec779b8eSAndroid Build Coastguard Worker         mOutputChannels(audio_channel_count_from_out_mask(outputChannelMask))
355*ec779b8eSAndroid Build Coastguard Worker {
356*ec779b8eSAndroid Build Coastguard Worker     ALOGV("RemixBufferProvider(%p)(%#x, %#x, %#x) %zu %zu",
357*ec779b8eSAndroid Build Coastguard Worker             this, format, inputChannelMask, outputChannelMask,
358*ec779b8eSAndroid Build Coastguard Worker             mInputChannels, mOutputChannels);
359*ec779b8eSAndroid Build Coastguard Worker     (void) memcpy_by_index_array_initialization_from_channel_mask(
360*ec779b8eSAndroid Build Coastguard Worker             mIdxAry, ARRAY_SIZE(mIdxAry), outputChannelMask, inputChannelMask);
361*ec779b8eSAndroid Build Coastguard Worker }
362*ec779b8eSAndroid Build Coastguard Worker 
copyFrames(void * dst,const void * src,size_t frames)363*ec779b8eSAndroid Build Coastguard Worker void RemixBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
364*ec779b8eSAndroid Build Coastguard Worker {
365*ec779b8eSAndroid Build Coastguard Worker     memcpy_by_index_array(dst, mOutputChannels,
366*ec779b8eSAndroid Build Coastguard Worker             src, mInputChannels, mIdxAry, mSampleSize, frames);
367*ec779b8eSAndroid Build Coastguard Worker }
368*ec779b8eSAndroid Build Coastguard Worker 
ChannelMixBufferProvider(audio_channel_mask_t inputChannelMask,audio_channel_mask_t outputChannelMask,audio_format_t format,size_t bufferFrameCount)369*ec779b8eSAndroid Build Coastguard Worker ChannelMixBufferProvider::ChannelMixBufferProvider(audio_channel_mask_t inputChannelMask,
370*ec779b8eSAndroid Build Coastguard Worker         audio_channel_mask_t outputChannelMask, audio_format_t format,
371*ec779b8eSAndroid Build Coastguard Worker         size_t bufferFrameCount) :
372*ec779b8eSAndroid Build Coastguard Worker         CopyBufferProvider(
373*ec779b8eSAndroid Build Coastguard Worker                 audio_bytes_per_sample(format)
374*ec779b8eSAndroid Build Coastguard Worker                     * audio_channel_count_from_out_mask(inputChannelMask),
375*ec779b8eSAndroid Build Coastguard Worker                 audio_bytes_per_sample(format)
376*ec779b8eSAndroid Build Coastguard Worker                     * audio_channel_count_from_out_mask(outputChannelMask),
377*ec779b8eSAndroid Build Coastguard Worker                 bufferFrameCount)
378*ec779b8eSAndroid Build Coastguard Worker         , mChannelMix{format == AUDIO_FORMAT_PCM_FLOAT
379*ec779b8eSAndroid Build Coastguard Worker                 ? audio_utils::channels::IChannelMix::create(outputChannelMask) : nullptr}
380*ec779b8eSAndroid Build Coastguard Worker         , mIsValid{mChannelMix && mChannelMix->setInputChannelMask(inputChannelMask)}
381*ec779b8eSAndroid Build Coastguard Worker {
382*ec779b8eSAndroid Build Coastguard Worker     ALOGV("ChannelMixBufferProvider(%p)(%#x, %#x, %#x)",
383*ec779b8eSAndroid Build Coastguard Worker             this, format, inputChannelMask, outputChannelMask);
384*ec779b8eSAndroid Build Coastguard Worker }
385*ec779b8eSAndroid Build Coastguard Worker 
copyFrames(void * dst,const void * src,size_t frames)386*ec779b8eSAndroid Build Coastguard Worker void ChannelMixBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
387*ec779b8eSAndroid Build Coastguard Worker {
388*ec779b8eSAndroid Build Coastguard Worker     if (mIsValid) {
389*ec779b8eSAndroid Build Coastguard Worker         mChannelMix->process(static_cast<const float *>(src), static_cast<float *>(dst),
390*ec779b8eSAndroid Build Coastguard Worker                 frames, false /* accumulate */);
391*ec779b8eSAndroid Build Coastguard Worker     } else {
392*ec779b8eSAndroid Build Coastguard Worker         // Should fall back to a different BufferProvider if not valid.
393*ec779b8eSAndroid Build Coastguard Worker         ALOGE("%s: Use without being valid!", __func__);
394*ec779b8eSAndroid Build Coastguard Worker     }
395*ec779b8eSAndroid Build Coastguard Worker }
396*ec779b8eSAndroid Build Coastguard Worker 
ReformatBufferProvider(int32_t channelCount,audio_format_t inputFormat,audio_format_t outputFormat,size_t bufferFrameCount)397*ec779b8eSAndroid Build Coastguard Worker ReformatBufferProvider::ReformatBufferProvider(int32_t channelCount,
398*ec779b8eSAndroid Build Coastguard Worker         audio_format_t inputFormat, audio_format_t outputFormat,
399*ec779b8eSAndroid Build Coastguard Worker         size_t bufferFrameCount) :
400*ec779b8eSAndroid Build Coastguard Worker         CopyBufferProvider(
401*ec779b8eSAndroid Build Coastguard Worker                 channelCount * audio_bytes_per_sample(inputFormat),
402*ec779b8eSAndroid Build Coastguard Worker                 channelCount * audio_bytes_per_sample(outputFormat),
403*ec779b8eSAndroid Build Coastguard Worker                 bufferFrameCount),
404*ec779b8eSAndroid Build Coastguard Worker         mChannelCount(channelCount),
405*ec779b8eSAndroid Build Coastguard Worker         mInputFormat(inputFormat),
406*ec779b8eSAndroid Build Coastguard Worker         mOutputFormat(outputFormat)
407*ec779b8eSAndroid Build Coastguard Worker {
408*ec779b8eSAndroid Build Coastguard Worker     ALOGV("ReformatBufferProvider(%p)(%u, %#x, %#x)",
409*ec779b8eSAndroid Build Coastguard Worker             this, channelCount, inputFormat, outputFormat);
410*ec779b8eSAndroid Build Coastguard Worker }
411*ec779b8eSAndroid Build Coastguard Worker 
copyFrames(void * dst,const void * src,size_t frames)412*ec779b8eSAndroid Build Coastguard Worker void ReformatBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
413*ec779b8eSAndroid Build Coastguard Worker {
414*ec779b8eSAndroid Build Coastguard Worker     memcpy_by_audio_format(dst, mOutputFormat, src, mInputFormat, frames * mChannelCount);
415*ec779b8eSAndroid Build Coastguard Worker }
416*ec779b8eSAndroid Build Coastguard Worker 
ClampFloatBufferProvider(int32_t channelCount,size_t bufferFrameCount)417*ec779b8eSAndroid Build Coastguard Worker ClampFloatBufferProvider::ClampFloatBufferProvider(int32_t channelCount, size_t bufferFrameCount) :
418*ec779b8eSAndroid Build Coastguard Worker         CopyBufferProvider(
419*ec779b8eSAndroid Build Coastguard Worker                 channelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT),
420*ec779b8eSAndroid Build Coastguard Worker                 channelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT),
421*ec779b8eSAndroid Build Coastguard Worker                 bufferFrameCount),
422*ec779b8eSAndroid Build Coastguard Worker         mChannelCount(channelCount)
423*ec779b8eSAndroid Build Coastguard Worker {
424*ec779b8eSAndroid Build Coastguard Worker     ALOGV("ClampFloatBufferProvider(%p)(%u)", this, channelCount);
425*ec779b8eSAndroid Build Coastguard Worker }
426*ec779b8eSAndroid Build Coastguard Worker 
copyFrames(void * dst,const void * src,size_t frames)427*ec779b8eSAndroid Build Coastguard Worker void ClampFloatBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
428*ec779b8eSAndroid Build Coastguard Worker {
429*ec779b8eSAndroid Build Coastguard Worker     memcpy_to_float_from_float_with_clamping((float*)dst, (const float*)src,
430*ec779b8eSAndroid Build Coastguard Worker                                              frames * mChannelCount,
431*ec779b8eSAndroid Build Coastguard Worker                                              FLOAT_NOMINAL_RANGE_HEADROOM);
432*ec779b8eSAndroid Build Coastguard Worker }
433*ec779b8eSAndroid Build Coastguard Worker 
TimestretchBufferProvider(int32_t channelCount,audio_format_t format,uint32_t sampleRate,const AudioPlaybackRate & playbackRate)434*ec779b8eSAndroid Build Coastguard Worker TimestretchBufferProvider::TimestretchBufferProvider(int32_t channelCount,
435*ec779b8eSAndroid Build Coastguard Worker         audio_format_t format, uint32_t sampleRate, const AudioPlaybackRate &playbackRate) :
436*ec779b8eSAndroid Build Coastguard Worker         mChannelCount(channelCount),
437*ec779b8eSAndroid Build Coastguard Worker         mFormat(format),
438*ec779b8eSAndroid Build Coastguard Worker         mSampleRate(sampleRate),
439*ec779b8eSAndroid Build Coastguard Worker         mFrameSize(channelCount * audio_bytes_per_sample(format)),
440*ec779b8eSAndroid Build Coastguard Worker         mLocalBufferFrameCount(0),
441*ec779b8eSAndroid Build Coastguard Worker         mLocalBufferData(NULL),
442*ec779b8eSAndroid Build Coastguard Worker         mRemaining(0),
443*ec779b8eSAndroid Build Coastguard Worker         mSonicStream(sonicCreateStream(sampleRate, mChannelCount)),
444*ec779b8eSAndroid Build Coastguard Worker         mFallbackFailErrorShown(false),
445*ec779b8eSAndroid Build Coastguard Worker         mAudioPlaybackRateValid(false)
446*ec779b8eSAndroid Build Coastguard Worker {
447*ec779b8eSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(mSonicStream == NULL,
448*ec779b8eSAndroid Build Coastguard Worker             "TimestretchBufferProvider can't allocate Sonic stream");
449*ec779b8eSAndroid Build Coastguard Worker 
450*ec779b8eSAndroid Build Coastguard Worker     setPlaybackRate(playbackRate);
451*ec779b8eSAndroid Build Coastguard Worker     ALOGV("TimestretchBufferProvider(%p)(%u, %#x, %u %f %f %d %d)",
452*ec779b8eSAndroid Build Coastguard Worker             this, channelCount, format, sampleRate, playbackRate.mSpeed,
453*ec779b8eSAndroid Build Coastguard Worker             playbackRate.mPitch, playbackRate.mStretchMode, playbackRate.mFallbackMode);
454*ec779b8eSAndroid Build Coastguard Worker     mBuffer.frameCount = 0;
455*ec779b8eSAndroid Build Coastguard Worker }
456*ec779b8eSAndroid Build Coastguard Worker 
~TimestretchBufferProvider()457*ec779b8eSAndroid Build Coastguard Worker TimestretchBufferProvider::~TimestretchBufferProvider()
458*ec779b8eSAndroid Build Coastguard Worker {
459*ec779b8eSAndroid Build Coastguard Worker     ALOGV("~TimestretchBufferProvider(%p)", this);
460*ec779b8eSAndroid Build Coastguard Worker     sonicDestroyStream(mSonicStream);
461*ec779b8eSAndroid Build Coastguard Worker     if (mBuffer.frameCount != 0) {
462*ec779b8eSAndroid Build Coastguard Worker         mTrackBufferProvider->releaseBuffer(&mBuffer);
463*ec779b8eSAndroid Build Coastguard Worker     }
464*ec779b8eSAndroid Build Coastguard Worker     free(mLocalBufferData);
465*ec779b8eSAndroid Build Coastguard Worker }
466*ec779b8eSAndroid Build Coastguard Worker 
getNextBuffer(AudioBufferProvider::Buffer * pBuffer)467*ec779b8eSAndroid Build Coastguard Worker status_t TimestretchBufferProvider::getNextBuffer(
468*ec779b8eSAndroid Build Coastguard Worker         AudioBufferProvider::Buffer *pBuffer)
469*ec779b8eSAndroid Build Coastguard Worker {
470*ec779b8eSAndroid Build Coastguard Worker     ALOGV("TimestretchBufferProvider(%p)::getNextBuffer(%p (%zu))",
471*ec779b8eSAndroid Build Coastguard Worker             this, pBuffer, pBuffer->frameCount);
472*ec779b8eSAndroid Build Coastguard Worker 
473*ec779b8eSAndroid Build Coastguard Worker     // BYPASS
474*ec779b8eSAndroid Build Coastguard Worker     //return mTrackBufferProvider->getNextBuffer(pBuffer);
475*ec779b8eSAndroid Build Coastguard Worker 
476*ec779b8eSAndroid Build Coastguard Worker     // check if previously processed data is sufficient.
477*ec779b8eSAndroid Build Coastguard Worker     if (pBuffer->frameCount <= mRemaining) {
478*ec779b8eSAndroid Build Coastguard Worker         ALOGV("previous sufficient");
479*ec779b8eSAndroid Build Coastguard Worker         pBuffer->raw = mLocalBufferData;
480*ec779b8eSAndroid Build Coastguard Worker         return OK;
481*ec779b8eSAndroid Build Coastguard Worker     }
482*ec779b8eSAndroid Build Coastguard Worker 
483*ec779b8eSAndroid Build Coastguard Worker     // do we need to resize our buffer?
484*ec779b8eSAndroid Build Coastguard Worker     if (pBuffer->frameCount > mLocalBufferFrameCount) {
485*ec779b8eSAndroid Build Coastguard Worker         void *newmem;
486*ec779b8eSAndroid Build Coastguard Worker         if (posix_memalign(&newmem, 32, pBuffer->frameCount * mFrameSize) == OK) {
487*ec779b8eSAndroid Build Coastguard Worker             if (mRemaining != 0) {
488*ec779b8eSAndroid Build Coastguard Worker                 memcpy(newmem, mLocalBufferData, mRemaining * mFrameSize);
489*ec779b8eSAndroid Build Coastguard Worker             }
490*ec779b8eSAndroid Build Coastguard Worker             free(mLocalBufferData);
491*ec779b8eSAndroid Build Coastguard Worker             mLocalBufferData = newmem;
492*ec779b8eSAndroid Build Coastguard Worker             mLocalBufferFrameCount = pBuffer->frameCount;
493*ec779b8eSAndroid Build Coastguard Worker         }
494*ec779b8eSAndroid Build Coastguard Worker     }
495*ec779b8eSAndroid Build Coastguard Worker 
496*ec779b8eSAndroid Build Coastguard Worker     // need to fetch more data
497*ec779b8eSAndroid Build Coastguard Worker     const size_t outputDesired = pBuffer->frameCount - mRemaining;
498*ec779b8eSAndroid Build Coastguard Worker     size_t dstAvailable;
499*ec779b8eSAndroid Build Coastguard Worker     do {
500*ec779b8eSAndroid Build Coastguard Worker         mBuffer.frameCount = mPlaybackRate.mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL
501*ec779b8eSAndroid Build Coastguard Worker                 ? outputDesired : outputDesired * mPlaybackRate.mSpeed + 1;
502*ec779b8eSAndroid Build Coastguard Worker 
503*ec779b8eSAndroid Build Coastguard Worker         status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer);
504*ec779b8eSAndroid Build Coastguard Worker 
505*ec779b8eSAndroid Build Coastguard Worker         ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
506*ec779b8eSAndroid Build Coastguard Worker         if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
507*ec779b8eSAndroid Build Coastguard Worker             ALOGV("upstream provider cannot provide data");
508*ec779b8eSAndroid Build Coastguard Worker             if (mRemaining == 0) {
509*ec779b8eSAndroid Build Coastguard Worker                 pBuffer->raw = NULL;
510*ec779b8eSAndroid Build Coastguard Worker                 pBuffer->frameCount = 0;
511*ec779b8eSAndroid Build Coastguard Worker                 return res;
512*ec779b8eSAndroid Build Coastguard Worker             } else { // return partial count
513*ec779b8eSAndroid Build Coastguard Worker                 pBuffer->raw = mLocalBufferData;
514*ec779b8eSAndroid Build Coastguard Worker                 pBuffer->frameCount = mRemaining;
515*ec779b8eSAndroid Build Coastguard Worker                 return OK;
516*ec779b8eSAndroid Build Coastguard Worker             }
517*ec779b8eSAndroid Build Coastguard Worker         }
518*ec779b8eSAndroid Build Coastguard Worker 
519*ec779b8eSAndroid Build Coastguard Worker         // time-stretch the data
520*ec779b8eSAndroid Build Coastguard Worker         dstAvailable = std::min(mLocalBufferFrameCount - mRemaining, outputDesired);
521*ec779b8eSAndroid Build Coastguard Worker         size_t srcAvailable = mBuffer.frameCount;
522*ec779b8eSAndroid Build Coastguard Worker         processFrames((uint8_t*)mLocalBufferData + mRemaining * mFrameSize, &dstAvailable,
523*ec779b8eSAndroid Build Coastguard Worker                 mBuffer.raw, &srcAvailable);
524*ec779b8eSAndroid Build Coastguard Worker 
525*ec779b8eSAndroid Build Coastguard Worker         // release all data consumed
526*ec779b8eSAndroid Build Coastguard Worker         mBuffer.frameCount = srcAvailable;
527*ec779b8eSAndroid Build Coastguard Worker         mTrackBufferProvider->releaseBuffer(&mBuffer);
528*ec779b8eSAndroid Build Coastguard Worker     } while (dstAvailable == 0); // try until we get output data or upstream provider fails.
529*ec779b8eSAndroid Build Coastguard Worker 
530*ec779b8eSAndroid Build Coastguard Worker     // update buffer vars with the actual data processed and return with buffer
531*ec779b8eSAndroid Build Coastguard Worker     mRemaining += dstAvailable;
532*ec779b8eSAndroid Build Coastguard Worker 
533*ec779b8eSAndroid Build Coastguard Worker     pBuffer->raw = mLocalBufferData;
534*ec779b8eSAndroid Build Coastguard Worker     pBuffer->frameCount = mRemaining;
535*ec779b8eSAndroid Build Coastguard Worker 
536*ec779b8eSAndroid Build Coastguard Worker     return OK;
537*ec779b8eSAndroid Build Coastguard Worker }
538*ec779b8eSAndroid Build Coastguard Worker 
releaseBuffer(AudioBufferProvider::Buffer * pBuffer)539*ec779b8eSAndroid Build Coastguard Worker void TimestretchBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer)
540*ec779b8eSAndroid Build Coastguard Worker {
541*ec779b8eSAndroid Build Coastguard Worker     ALOGV("TimestretchBufferProvider(%p)::releaseBuffer(%p (%zu))",
542*ec779b8eSAndroid Build Coastguard Worker        this, pBuffer, pBuffer->frameCount);
543*ec779b8eSAndroid Build Coastguard Worker 
544*ec779b8eSAndroid Build Coastguard Worker     // BYPASS
545*ec779b8eSAndroid Build Coastguard Worker     //return mTrackBufferProvider->releaseBuffer(pBuffer);
546*ec779b8eSAndroid Build Coastguard Worker 
547*ec779b8eSAndroid Build Coastguard Worker     // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
548*ec779b8eSAndroid Build Coastguard Worker     if (pBuffer->frameCount < mRemaining) {
549*ec779b8eSAndroid Build Coastguard Worker         memcpy(mLocalBufferData,
550*ec779b8eSAndroid Build Coastguard Worker                 (uint8_t*)mLocalBufferData + pBuffer->frameCount * mFrameSize,
551*ec779b8eSAndroid Build Coastguard Worker                 (mRemaining - pBuffer->frameCount) * mFrameSize);
552*ec779b8eSAndroid Build Coastguard Worker         mRemaining -= pBuffer->frameCount;
553*ec779b8eSAndroid Build Coastguard Worker     } else if (pBuffer->frameCount == mRemaining) {
554*ec779b8eSAndroid Build Coastguard Worker         mRemaining = 0;
555*ec779b8eSAndroid Build Coastguard Worker     } else {
556*ec779b8eSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL("Releasing more frames(%zu) than available(%zu)",
557*ec779b8eSAndroid Build Coastguard Worker                 pBuffer->frameCount, mRemaining);
558*ec779b8eSAndroid Build Coastguard Worker     }
559*ec779b8eSAndroid Build Coastguard Worker 
560*ec779b8eSAndroid Build Coastguard Worker     pBuffer->raw = NULL;
561*ec779b8eSAndroid Build Coastguard Worker     pBuffer->frameCount = 0;
562*ec779b8eSAndroid Build Coastguard Worker }
563*ec779b8eSAndroid Build Coastguard Worker 
reset()564*ec779b8eSAndroid Build Coastguard Worker void TimestretchBufferProvider::reset()
565*ec779b8eSAndroid Build Coastguard Worker {
566*ec779b8eSAndroid Build Coastguard Worker     mRemaining = 0;
567*ec779b8eSAndroid Build Coastguard Worker }
568*ec779b8eSAndroid Build Coastguard Worker 
setBufferProvider(AudioBufferProvider * p)569*ec779b8eSAndroid Build Coastguard Worker void TimestretchBufferProvider::setBufferProvider(AudioBufferProvider *p) {
570*ec779b8eSAndroid Build Coastguard Worker     ALOGV("%s(%p): mTrackBufferProvider:%p  mBuffer.frameCount:%zu",
571*ec779b8eSAndroid Build Coastguard Worker             __func__, p, mTrackBufferProvider, mBuffer.frameCount);
572*ec779b8eSAndroid Build Coastguard Worker     if (mTrackBufferProvider == p) {
573*ec779b8eSAndroid Build Coastguard Worker         return;
574*ec779b8eSAndroid Build Coastguard Worker     }
575*ec779b8eSAndroid Build Coastguard Worker     mBuffer.frameCount = 0;
576*ec779b8eSAndroid Build Coastguard Worker     PassthruBufferProvider::setBufferProvider(p);
577*ec779b8eSAndroid Build Coastguard Worker }
578*ec779b8eSAndroid Build Coastguard Worker 
setPlaybackRate(const AudioPlaybackRate & playbackRate)579*ec779b8eSAndroid Build Coastguard Worker status_t TimestretchBufferProvider::setPlaybackRate(const AudioPlaybackRate &playbackRate)
580*ec779b8eSAndroid Build Coastguard Worker {
581*ec779b8eSAndroid Build Coastguard Worker     mPlaybackRate = playbackRate;
582*ec779b8eSAndroid Build Coastguard Worker     mFallbackFailErrorShown = false;
583*ec779b8eSAndroid Build Coastguard Worker     sonicSetSpeed(mSonicStream, mPlaybackRate.mSpeed);
584*ec779b8eSAndroid Build Coastguard Worker     //TODO: pitch is ignored for now
585*ec779b8eSAndroid Build Coastguard Worker     //TODO: optimize: if parameters are the same, don't do any extra computation.
586*ec779b8eSAndroid Build Coastguard Worker 
587*ec779b8eSAndroid Build Coastguard Worker     mAudioPlaybackRateValid = isAudioPlaybackRateValid(mPlaybackRate);
588*ec779b8eSAndroid Build Coastguard Worker     return OK;
589*ec779b8eSAndroid Build Coastguard Worker }
590*ec779b8eSAndroid Build Coastguard Worker 
processFrames(void * dstBuffer,size_t * dstFrames,const void * srcBuffer,size_t * srcFrames)591*ec779b8eSAndroid Build Coastguard Worker void TimestretchBufferProvider::processFrames(void *dstBuffer, size_t *dstFrames,
592*ec779b8eSAndroid Build Coastguard Worker         const void *srcBuffer, size_t *srcFrames)
593*ec779b8eSAndroid Build Coastguard Worker {
594*ec779b8eSAndroid Build Coastguard Worker     ALOGV("processFrames(%zu %zu)  remaining(%zu)", *dstFrames, *srcFrames, mRemaining);
595*ec779b8eSAndroid Build Coastguard Worker     // Note dstFrames is the required number of frames.
596*ec779b8eSAndroid Build Coastguard Worker 
597*ec779b8eSAndroid Build Coastguard Worker     if (!mAudioPlaybackRateValid) {
598*ec779b8eSAndroid Build Coastguard Worker         //fallback mode
599*ec779b8eSAndroid Build Coastguard Worker         // Ensure consumption from src is as expected.
600*ec779b8eSAndroid Build Coastguard Worker         // TODO: add logic to track "very accurate" consumption related to speed, original sampling
601*ec779b8eSAndroid Build Coastguard Worker         // rate, actual frames processed.
602*ec779b8eSAndroid Build Coastguard Worker 
603*ec779b8eSAndroid Build Coastguard Worker         const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
604*ec779b8eSAndroid Build Coastguard Worker         if (*srcFrames < targetSrc) { // limit dst frames to that possible
605*ec779b8eSAndroid Build Coastguard Worker             *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
606*ec779b8eSAndroid Build Coastguard Worker         } else if (*srcFrames > targetSrc + 1) {
607*ec779b8eSAndroid Build Coastguard Worker             *srcFrames = targetSrc + 1;
608*ec779b8eSAndroid Build Coastguard Worker         }
609*ec779b8eSAndroid Build Coastguard Worker         if (*dstFrames > 0) {
610*ec779b8eSAndroid Build Coastguard Worker             switch(mPlaybackRate.mFallbackMode) {
611*ec779b8eSAndroid Build Coastguard Worker             case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT:
612*ec779b8eSAndroid Build Coastguard Worker                 if (*dstFrames <= *srcFrames) {
613*ec779b8eSAndroid Build Coastguard Worker                       size_t copySize = mFrameSize * *dstFrames;
614*ec779b8eSAndroid Build Coastguard Worker                       memcpy(dstBuffer, srcBuffer, copySize);
615*ec779b8eSAndroid Build Coastguard Worker                   } else {
616*ec779b8eSAndroid Build Coastguard Worker                       // cyclically repeat the source.
617*ec779b8eSAndroid Build Coastguard Worker                       for (size_t count = 0; count < *dstFrames; count += *srcFrames) {
618*ec779b8eSAndroid Build Coastguard Worker                           size_t remaining = std::min(*srcFrames, *dstFrames - count);
619*ec779b8eSAndroid Build Coastguard Worker                           memcpy((uint8_t*)dstBuffer + mFrameSize * count,
620*ec779b8eSAndroid Build Coastguard Worker                                   srcBuffer, mFrameSize * remaining);
621*ec779b8eSAndroid Build Coastguard Worker                       }
622*ec779b8eSAndroid Build Coastguard Worker                   }
623*ec779b8eSAndroid Build Coastguard Worker                 break;
624*ec779b8eSAndroid Build Coastguard Worker             case AUDIO_TIMESTRETCH_FALLBACK_DEFAULT:
625*ec779b8eSAndroid Build Coastguard Worker             case AUDIO_TIMESTRETCH_FALLBACK_MUTE:
626*ec779b8eSAndroid Build Coastguard Worker                 memset(dstBuffer,0, mFrameSize * *dstFrames);
627*ec779b8eSAndroid Build Coastguard Worker                 break;
628*ec779b8eSAndroid Build Coastguard Worker             case AUDIO_TIMESTRETCH_FALLBACK_FAIL:
629*ec779b8eSAndroid Build Coastguard Worker             default:
630*ec779b8eSAndroid Build Coastguard Worker                 if(!mFallbackFailErrorShown) {
631*ec779b8eSAndroid Build Coastguard Worker                     ALOGE("invalid parameters in TimestretchBufferProvider fallbackMode:%d",
632*ec779b8eSAndroid Build Coastguard Worker                             mPlaybackRate.mFallbackMode);
633*ec779b8eSAndroid Build Coastguard Worker                     mFallbackFailErrorShown = true;
634*ec779b8eSAndroid Build Coastguard Worker                 }
635*ec779b8eSAndroid Build Coastguard Worker                 break;
636*ec779b8eSAndroid Build Coastguard Worker             }
637*ec779b8eSAndroid Build Coastguard Worker         }
638*ec779b8eSAndroid Build Coastguard Worker     } else {
639*ec779b8eSAndroid Build Coastguard Worker         switch (mFormat) {
640*ec779b8eSAndroid Build Coastguard Worker         case AUDIO_FORMAT_PCM_FLOAT:
641*ec779b8eSAndroid Build Coastguard Worker             if (sonicWriteFloatToStream(mSonicStream, (float*)srcBuffer, *srcFrames) != 1) {
642*ec779b8eSAndroid Build Coastguard Worker                 ALOGE("sonicWriteFloatToStream cannot realloc");
643*ec779b8eSAndroid Build Coastguard Worker                 *srcFrames = 0; // cannot consume all of srcBuffer
644*ec779b8eSAndroid Build Coastguard Worker             }
645*ec779b8eSAndroid Build Coastguard Worker             *dstFrames = sonicReadFloatFromStream(mSonicStream, (float*)dstBuffer, *dstFrames);
646*ec779b8eSAndroid Build Coastguard Worker             break;
647*ec779b8eSAndroid Build Coastguard Worker         case AUDIO_FORMAT_PCM_16_BIT:
648*ec779b8eSAndroid Build Coastguard Worker             if (sonicWriteShortToStream(mSonicStream, (short*)srcBuffer, *srcFrames) != 1) {
649*ec779b8eSAndroid Build Coastguard Worker                 ALOGE("sonicWriteShortToStream cannot realloc");
650*ec779b8eSAndroid Build Coastguard Worker                 *srcFrames = 0; // cannot consume all of srcBuffer
651*ec779b8eSAndroid Build Coastguard Worker             }
652*ec779b8eSAndroid Build Coastguard Worker             *dstFrames = sonicReadShortFromStream(mSonicStream, (short*)dstBuffer, *dstFrames);
653*ec779b8eSAndroid Build Coastguard Worker             break;
654*ec779b8eSAndroid Build Coastguard Worker         default:
655*ec779b8eSAndroid Build Coastguard Worker             // could also be caught on construction
656*ec779b8eSAndroid Build Coastguard Worker             LOG_ALWAYS_FATAL("invalid format %#x for TimestretchBufferProvider", mFormat);
657*ec779b8eSAndroid Build Coastguard Worker         }
658*ec779b8eSAndroid Build Coastguard Worker     }
659*ec779b8eSAndroid Build Coastguard Worker }
660*ec779b8eSAndroid Build Coastguard Worker 
AdjustChannelsBufferProvider(audio_format_t format,size_t inChannelCount,size_t outChannelCount,size_t frameCount,audio_format_t contractedFormat,void * contractedBuffer,size_t contractedOutChannelCount)661*ec779b8eSAndroid Build Coastguard Worker AdjustChannelsBufferProvider::AdjustChannelsBufferProvider(
662*ec779b8eSAndroid Build Coastguard Worker         audio_format_t format, size_t inChannelCount, size_t outChannelCount,
663*ec779b8eSAndroid Build Coastguard Worker         size_t frameCount, audio_format_t contractedFormat, void* contractedBuffer,
664*ec779b8eSAndroid Build Coastguard Worker         size_t contractedOutChannelCount) :
665*ec779b8eSAndroid Build Coastguard Worker         CopyBufferProvider(
666*ec779b8eSAndroid Build Coastguard Worker                 audio_bytes_per_frame(inChannelCount, format),
667*ec779b8eSAndroid Build Coastguard Worker                 audio_bytes_per_frame(std::max(inChannelCount, outChannelCount), format),
668*ec779b8eSAndroid Build Coastguard Worker                 frameCount),
669*ec779b8eSAndroid Build Coastguard Worker         mFormat(format),
670*ec779b8eSAndroid Build Coastguard Worker         mInChannelCount(inChannelCount),
671*ec779b8eSAndroid Build Coastguard Worker         mOutChannelCount(outChannelCount),
672*ec779b8eSAndroid Build Coastguard Worker         mSampleSizeInBytes(audio_bytes_per_sample(format)),
673*ec779b8eSAndroid Build Coastguard Worker         mFrameCount(frameCount),
674*ec779b8eSAndroid Build Coastguard Worker         mContractedFormat(inChannelCount > outChannelCount
675*ec779b8eSAndroid Build Coastguard Worker                 ? contractedFormat : AUDIO_FORMAT_INVALID),
676*ec779b8eSAndroid Build Coastguard Worker         mContractedInChannelCount(inChannelCount > outChannelCount
677*ec779b8eSAndroid Build Coastguard Worker                 ? inChannelCount - outChannelCount : 0),
678*ec779b8eSAndroid Build Coastguard Worker         mContractedOutChannelCount(contractedOutChannelCount),
679*ec779b8eSAndroid Build Coastguard Worker         mContractedSampleSizeInBytes(audio_bytes_per_sample(contractedFormat)),
680*ec779b8eSAndroid Build Coastguard Worker         mContractedInputFrameSize(mContractedInChannelCount * mContractedSampleSizeInBytes),
681*ec779b8eSAndroid Build Coastguard Worker         mContractedBuffer(contractedBuffer),
682*ec779b8eSAndroid Build Coastguard Worker         mContractedWrittenFrames(0)
683*ec779b8eSAndroid Build Coastguard Worker {
684*ec779b8eSAndroid Build Coastguard Worker     ALOGV("AdjustChannelsBufferProvider(%p)(%#x, %zu, %zu, %zu, %#x, %p, %zu)",
685*ec779b8eSAndroid Build Coastguard Worker           this, format, inChannelCount, outChannelCount, frameCount, contractedFormat,
686*ec779b8eSAndroid Build Coastguard Worker           contractedBuffer, contractedOutChannelCount);
687*ec779b8eSAndroid Build Coastguard Worker     if (mContractedFormat != AUDIO_FORMAT_INVALID && mInChannelCount > mOutChannelCount) {
688*ec779b8eSAndroid Build Coastguard Worker         mContractedOutputFrameSize =
689*ec779b8eSAndroid Build Coastguard Worker                 audio_bytes_per_frame(mContractedOutChannelCount, mContractedFormat);
690*ec779b8eSAndroid Build Coastguard Worker     }
691*ec779b8eSAndroid Build Coastguard Worker }
692*ec779b8eSAndroid Build Coastguard Worker 
getNextBuffer(AudioBufferProvider::Buffer * pBuffer)693*ec779b8eSAndroid Build Coastguard Worker status_t AdjustChannelsBufferProvider::getNextBuffer(AudioBufferProvider::Buffer* pBuffer)
694*ec779b8eSAndroid Build Coastguard Worker {
695*ec779b8eSAndroid Build Coastguard Worker     if (mContractedBuffer != nullptr) {
696*ec779b8eSAndroid Build Coastguard Worker         // Restrict frame count only when it is needed to save contracted frames.
697*ec779b8eSAndroid Build Coastguard Worker         const size_t outFramesLeft = mFrameCount - mContractedWrittenFrames;
698*ec779b8eSAndroid Build Coastguard Worker         if (outFramesLeft < pBuffer->frameCount) {
699*ec779b8eSAndroid Build Coastguard Worker             // Restrict the frame count so that we don't write over the size of the output buffer.
700*ec779b8eSAndroid Build Coastguard Worker             pBuffer->frameCount = outFramesLeft;
701*ec779b8eSAndroid Build Coastguard Worker         }
702*ec779b8eSAndroid Build Coastguard Worker     }
703*ec779b8eSAndroid Build Coastguard Worker     return CopyBufferProvider::getNextBuffer(pBuffer);
704*ec779b8eSAndroid Build Coastguard Worker }
705*ec779b8eSAndroid Build Coastguard Worker 
copyFrames(void * dst,const void * src,size_t frames)706*ec779b8eSAndroid Build Coastguard Worker void AdjustChannelsBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
707*ec779b8eSAndroid Build Coastguard Worker {
708*ec779b8eSAndroid Build Coastguard Worker     // For case multi to mono, adjust_channels has special logic that will mix first two input
709*ec779b8eSAndroid Build Coastguard Worker     // channels into a single output channel. In that case, use adjust_channels_non_destructive
710*ec779b8eSAndroid Build Coastguard Worker     // to keep only one channel data even when contracting to mono.
711*ec779b8eSAndroid Build Coastguard Worker     adjust_channels_non_destructive(src, mInChannelCount, dst, mOutChannelCount,
712*ec779b8eSAndroid Build Coastguard Worker             mSampleSizeInBytes, frames * mInChannelCount * mSampleSizeInBytes);
713*ec779b8eSAndroid Build Coastguard Worker     if (mContractedFormat != AUDIO_FORMAT_INVALID
714*ec779b8eSAndroid Build Coastguard Worker         && mContractedBuffer != nullptr) {
715*ec779b8eSAndroid Build Coastguard Worker         const size_t contractedIdx = frames * mOutChannelCount * mSampleSizeInBytes;
716*ec779b8eSAndroid Build Coastguard Worker         uint8_t* oriBuf = (uint8_t*) dst + contractedIdx;
717*ec779b8eSAndroid Build Coastguard Worker         uint8_t* buf = (uint8_t*) mContractedBuffer
718*ec779b8eSAndroid Build Coastguard Worker                 + mContractedWrittenFrames * mContractedOutputFrameSize;
719*ec779b8eSAndroid Build Coastguard Worker         if (mContractedInChannelCount > mContractedOutChannelCount) {
720*ec779b8eSAndroid Build Coastguard Worker             // Adjust the channels first as the contracted buffer may not have enough
721*ec779b8eSAndroid Build Coastguard Worker             // space for the data.
722*ec779b8eSAndroid Build Coastguard Worker             // Use adjust_channels_non_destructive to avoid mix first two channels into one single
723*ec779b8eSAndroid Build Coastguard Worker             // output channel when it is multi to mono.
724*ec779b8eSAndroid Build Coastguard Worker             adjust_channels_non_destructive(
725*ec779b8eSAndroid Build Coastguard Worker                     oriBuf, mContractedInChannelCount, oriBuf, mContractedOutChannelCount,
726*ec779b8eSAndroid Build Coastguard Worker                     mSampleSizeInBytes, frames * mContractedInChannelCount * mSampleSizeInBytes);
727*ec779b8eSAndroid Build Coastguard Worker             memcpy_by_audio_format(
728*ec779b8eSAndroid Build Coastguard Worker                     buf, mContractedFormat, oriBuf, mFormat, mContractedOutChannelCount * frames);
729*ec779b8eSAndroid Build Coastguard Worker         } else {
730*ec779b8eSAndroid Build Coastguard Worker             // Copy the data first as the dst buffer may not have enough space for extra channel.
731*ec779b8eSAndroid Build Coastguard Worker             memcpy_by_audio_format(
732*ec779b8eSAndroid Build Coastguard Worker                 buf, mContractedFormat, oriBuf, mFormat, mContractedInChannelCount * frames);
733*ec779b8eSAndroid Build Coastguard Worker             // Note that if the contracted data is from MONO to MULTICHANNEL, the first 2 channels
734*ec779b8eSAndroid Build Coastguard Worker             // will be duplicated with the original single input channel and all the other channels
735*ec779b8eSAndroid Build Coastguard Worker             // will be 0-filled.
736*ec779b8eSAndroid Build Coastguard Worker             adjust_channels(
737*ec779b8eSAndroid Build Coastguard Worker                     buf, mContractedInChannelCount, buf, mContractedOutChannelCount,
738*ec779b8eSAndroid Build Coastguard Worker                     mContractedSampleSizeInBytes, mContractedInputFrameSize * frames);
739*ec779b8eSAndroid Build Coastguard Worker         }
740*ec779b8eSAndroid Build Coastguard Worker         mContractedWrittenFrames += frames;
741*ec779b8eSAndroid Build Coastguard Worker     }
742*ec779b8eSAndroid Build Coastguard Worker }
743*ec779b8eSAndroid Build Coastguard Worker 
reset()744*ec779b8eSAndroid Build Coastguard Worker void AdjustChannelsBufferProvider::reset()
745*ec779b8eSAndroid Build Coastguard Worker {
746*ec779b8eSAndroid Build Coastguard Worker     mContractedWrittenFrames = 0;
747*ec779b8eSAndroid Build Coastguard Worker     CopyBufferProvider::reset();
748*ec779b8eSAndroid Build Coastguard Worker }
749*ec779b8eSAndroid Build Coastguard Worker 
copyFrames(void * dst,const void * src,size_t frames)750*ec779b8eSAndroid Build Coastguard Worker void TeeBufferProvider::copyFrames(void *dst, const void *src, size_t frames) {
751*ec779b8eSAndroid Build Coastguard Worker     memcpy(dst, src, frames * mInputFrameSize);
752*ec779b8eSAndroid Build Coastguard Worker     if (int teeBufferFrameLeft = mTeeBufferFrameCount - mFrameCopied; teeBufferFrameLeft < frames) {
753*ec779b8eSAndroid Build Coastguard Worker         ALOGW("Unable to copy all frames to tee buffer, %d frames dropped",
754*ec779b8eSAndroid Build Coastguard Worker               (int)frames - teeBufferFrameLeft);
755*ec779b8eSAndroid Build Coastguard Worker         frames = teeBufferFrameLeft;
756*ec779b8eSAndroid Build Coastguard Worker     }
757*ec779b8eSAndroid Build Coastguard Worker     memcpy(mTeeBuffer + mFrameCopied * mInputFrameSize, src, frames * mInputFrameSize);
758*ec779b8eSAndroid Build Coastguard Worker     mFrameCopied += frames;
759*ec779b8eSAndroid Build Coastguard Worker }
760*ec779b8eSAndroid Build Coastguard Worker 
clearFramesCopied()761*ec779b8eSAndroid Build Coastguard Worker void TeeBufferProvider::clearFramesCopied() {
762*ec779b8eSAndroid Build Coastguard Worker     mFrameCopied = 0;
763*ec779b8eSAndroid Build Coastguard Worker }
764*ec779b8eSAndroid Build Coastguard Worker 
765*ec779b8eSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
766*ec779b8eSAndroid Build Coastguard Worker } // namespace android
767