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