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
35namespace android {
36
37// ----------------------------------------------------------------------------
38
39template <typename T>
40static inline T min(const T& a, const T& b)
41{
42    return a < b ? a : b;
43}
44
45CopyBufferProvider::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
64CopyBufferProvider::~CopyBufferProvider()
65{
66    ALOGV("~CopyBufferProvider(%p)", this);
67    if (mBuffer.frameCount != 0) {
68        mTrackBufferProvider->releaseBuffer(&mBuffer);
69    }
70    free(mLocalBufferData);
71}
72
73status_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
110void 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
128void CopyBufferProvider::reset()
129{
130    if (mBuffer.frameCount != 0) {
131        mTrackBufferProvider->releaseBuffer(&mBuffer);
132    }
133    mConsumed = 0;
134}
135
136DownmixerBufferProvider::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 = EffectBufferHalInterface::mirror(
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 = EffectBufferHalInterface::mirror(
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
268DownmixerBufferProvider::~DownmixerBufferProvider()
269{
270    ALOGV("~DownmixerBufferProvider (%p)", this);
271    if (mDownmixInterface != 0) {
272        mDownmixInterface->close();
273    }
274}
275
276void 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. */
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
332RemixBufferProvider::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
353void 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
359ReformatBufferProvider::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
374void ReformatBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
375{
376    memcpy_by_audio_format(dst, mOutputFormat, src, mInputFormat, frames * mChannelCount);
377}
378
379TimestretchBufferProvider::TimestretchBufferProvider(int32_t channelCount,
380        audio_format_t format, uint32_t sampleRate, const AudioPlaybackRate &playbackRate) :
381        mChannelCount(channelCount),
382        mFormat(format),
383        mSampleRate(sampleRate),
384        mFrameSize(channelCount * audio_bytes_per_sample(format)),
385        mLocalBufferFrameCount(0),
386        mLocalBufferData(NULL),
387        mRemaining(0),
388        mSonicStream(sonicCreateStream(sampleRate, mChannelCount)),
389        mFallbackFailErrorShown(false),
390        mAudioPlaybackRateValid(false)
391{
392    LOG_ALWAYS_FATAL_IF(mSonicStream == NULL,
393            "TimestretchBufferProvider can't allocate Sonic stream");
394
395    setPlaybackRate(playbackRate);
396    ALOGV("TimestretchBufferProvider(%p)(%u, %#x, %u %f %f %d %d)",
397            this, channelCount, format, sampleRate, playbackRate.mSpeed,
398            playbackRate.mPitch, playbackRate.mStretchMode, playbackRate.mFallbackMode);
399    mBuffer.frameCount = 0;
400}
401
402TimestretchBufferProvider::~TimestretchBufferProvider()
403{
404    ALOGV("~TimestretchBufferProvider(%p)", this);
405    sonicDestroyStream(mSonicStream);
406    if (mBuffer.frameCount != 0) {
407        mTrackBufferProvider->releaseBuffer(&mBuffer);
408    }
409    free(mLocalBufferData);
410}
411
412status_t TimestretchBufferProvider::getNextBuffer(
413        AudioBufferProvider::Buffer *pBuffer)
414{
415    ALOGV("TimestretchBufferProvider(%p)::getNextBuffer(%p (%zu))",
416            this, pBuffer, pBuffer->frameCount);
417
418    // BYPASS
419    //return mTrackBufferProvider->getNextBuffer(pBuffer);
420
421    // check if previously processed data is sufficient.
422    if (pBuffer->frameCount <= mRemaining) {
423        ALOGV("previous sufficient");
424        pBuffer->raw = mLocalBufferData;
425        return OK;
426    }
427
428    // do we need to resize our buffer?
429    if (pBuffer->frameCount > mLocalBufferFrameCount) {
430        void *newmem;
431        if (posix_memalign(&newmem, 32, pBuffer->frameCount * mFrameSize) == OK) {
432            if (mRemaining != 0) {
433                memcpy(newmem, mLocalBufferData, mRemaining * mFrameSize);
434            }
435            free(mLocalBufferData);
436            mLocalBufferData = newmem;
437            mLocalBufferFrameCount = pBuffer->frameCount;
438        }
439    }
440
441    // need to fetch more data
442    const size_t outputDesired = pBuffer->frameCount - mRemaining;
443    size_t dstAvailable;
444    do {
445        mBuffer.frameCount = mPlaybackRate.mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL
446                ? outputDesired : outputDesired * mPlaybackRate.mSpeed + 1;
447
448        status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer);
449
450        ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
451        if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
452            ALOGV("upstream provider cannot provide data");
453            if (mRemaining == 0) {
454                pBuffer->raw = NULL;
455                pBuffer->frameCount = 0;
456                return res;
457            } else { // return partial count
458                pBuffer->raw = mLocalBufferData;
459                pBuffer->frameCount = mRemaining;
460                return OK;
461            }
462        }
463
464        // time-stretch the data
465        dstAvailable = min(mLocalBufferFrameCount - mRemaining, outputDesired);
466        size_t srcAvailable = mBuffer.frameCount;
467        processFrames((uint8_t*)mLocalBufferData + mRemaining * mFrameSize, &dstAvailable,
468                mBuffer.raw, &srcAvailable);
469
470        // release all data consumed
471        mBuffer.frameCount = srcAvailable;
472        mTrackBufferProvider->releaseBuffer(&mBuffer);
473    } while (dstAvailable == 0); // try until we get output data or upstream provider fails.
474
475    // update buffer vars with the actual data processed and return with buffer
476    mRemaining += dstAvailable;
477
478    pBuffer->raw = mLocalBufferData;
479    pBuffer->frameCount = mRemaining;
480
481    return OK;
482}
483
484void TimestretchBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer)
485{
486    ALOGV("TimestretchBufferProvider(%p)::releaseBuffer(%p (%zu))",
487       this, pBuffer, pBuffer->frameCount);
488
489    // BYPASS
490    //return mTrackBufferProvider->releaseBuffer(pBuffer);
491
492    // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
493    if (pBuffer->frameCount < mRemaining) {
494        memcpy(mLocalBufferData,
495                (uint8_t*)mLocalBufferData + pBuffer->frameCount * mFrameSize,
496                (mRemaining - pBuffer->frameCount) * mFrameSize);
497        mRemaining -= pBuffer->frameCount;
498    } else if (pBuffer->frameCount == mRemaining) {
499        mRemaining = 0;
500    } else {
501        LOG_ALWAYS_FATAL("Releasing more frames(%zu) than available(%zu)",
502                pBuffer->frameCount, mRemaining);
503    }
504
505    pBuffer->raw = NULL;
506    pBuffer->frameCount = 0;
507}
508
509void TimestretchBufferProvider::reset()
510{
511    mRemaining = 0;
512}
513
514status_t TimestretchBufferProvider::setPlaybackRate(const AudioPlaybackRate &playbackRate)
515{
516    mPlaybackRate = playbackRate;
517    mFallbackFailErrorShown = false;
518    sonicSetSpeed(mSonicStream, mPlaybackRate.mSpeed);
519    //TODO: pitch is ignored for now
520    //TODO: optimize: if parameters are the same, don't do any extra computation.
521
522    mAudioPlaybackRateValid = isAudioPlaybackRateValid(mPlaybackRate);
523    return OK;
524}
525
526void TimestretchBufferProvider::processFrames(void *dstBuffer, size_t *dstFrames,
527        const void *srcBuffer, size_t *srcFrames)
528{
529    ALOGV("processFrames(%zu %zu)  remaining(%zu)", *dstFrames, *srcFrames, mRemaining);
530    // Note dstFrames is the required number of frames.
531
532    if (!mAudioPlaybackRateValid) {
533        //fallback mode
534        // Ensure consumption from src is as expected.
535        // TODO: add logic to track "very accurate" consumption related to speed, original sampling
536        // rate, actual frames processed.
537
538        const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
539        if (*srcFrames < targetSrc) { // limit dst frames to that possible
540            *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
541        } else if (*srcFrames > targetSrc + 1) {
542            *srcFrames = targetSrc + 1;
543        }
544        if (*dstFrames > 0) {
545            switch(mPlaybackRate.mFallbackMode) {
546            case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT:
547                if (*dstFrames <= *srcFrames) {
548                      size_t copySize = mFrameSize * *dstFrames;
549                      memcpy(dstBuffer, srcBuffer, copySize);
550                  } else {
551                      // cyclically repeat the source.
552                      for (size_t count = 0; count < *dstFrames; count += *srcFrames) {
553                          size_t remaining = min(*srcFrames, *dstFrames - count);
554                          memcpy((uint8_t*)dstBuffer + mFrameSize * count,
555                                  srcBuffer, mFrameSize * remaining);
556                      }
557                  }
558                break;
559            case AUDIO_TIMESTRETCH_FALLBACK_DEFAULT:
560            case AUDIO_TIMESTRETCH_FALLBACK_MUTE:
561                memset(dstBuffer,0, mFrameSize * *dstFrames);
562                break;
563            case AUDIO_TIMESTRETCH_FALLBACK_FAIL:
564            default:
565                if(!mFallbackFailErrorShown) {
566                    ALOGE("invalid parameters in TimestretchBufferProvider fallbackMode:%d",
567                            mPlaybackRate.mFallbackMode);
568                    mFallbackFailErrorShown = true;
569                }
570                break;
571            }
572        }
573    } else {
574        switch (mFormat) {
575        case AUDIO_FORMAT_PCM_FLOAT:
576            if (sonicWriteFloatToStream(mSonicStream, (float*)srcBuffer, *srcFrames) != 1) {
577                ALOGE("sonicWriteFloatToStream cannot realloc");
578                *srcFrames = 0; // cannot consume all of srcBuffer
579            }
580            *dstFrames = sonicReadFloatFromStream(mSonicStream, (float*)dstBuffer, *dstFrames);
581            break;
582        case AUDIO_FORMAT_PCM_16_BIT:
583            if (sonicWriteShortToStream(mSonicStream, (short*)srcBuffer, *srcFrames) != 1) {
584                ALOGE("sonicWriteShortToStream cannot realloc");
585                *srcFrames = 0; // cannot consume all of srcBuffer
586            }
587            *dstFrames = sonicReadShortFromStream(mSonicStream, (short*)dstBuffer, *dstFrames);
588            break;
589        default:
590            // could also be caught on construction
591            LOG_ALWAYS_FATAL("invalid format %#x for TimestretchBufferProvider", mFormat);
592        }
593    }
594}
595// ----------------------------------------------------------------------------
596} // namespace android
597