Home | History | Annotate | Download | only in audioflinger
      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_effects/effect_downmix.h>
     21 #include <audio_utils/primitives.h>
     22 #include <audio_utils/format.h>
     23 #include <media/AudioResamplerPublic.h>
     24 #include <media/EffectsFactoryApi.h>
     25 
     26 #include <utils/Log.h>
     27 
     28 #include "Configuration.h"
     29 #include "BufferProviders.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>
     40 static inline T min(const T& a, const T& b)
     41 {
     42     return a < b ? a : b;
     43 }
     44 
     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 
     64 CopyBufferProvider::~CopyBufferProvider()
     65 {
     66     ALOGV("~CopyBufferProvider(%p)", this);
     67     if (mBuffer.frameCount != 0) {
     68         mTrackBufferProvider->releaseBuffer(&mBuffer);
     69     }
     70     free(mLocalBufferData);
     71 }
     72 
     73 status_t CopyBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer,
     74         int64_t pts)
     75 {
     76     //ALOGV("CopyBufferProvider(%p)::getNextBuffer(%p (%zu), %lld)",
     77     //        this, pBuffer, pBuffer->frameCount, pts);
     78     if (mLocalBufferFrameCount == 0) {
     79         status_t res = mTrackBufferProvider->getNextBuffer(pBuffer, pts);
     80         if (res == OK) {
     81             copyFrames(pBuffer->raw, pBuffer->raw, pBuffer->frameCount);
     82         }
     83         return res;
     84     }
     85     if (mBuffer.frameCount == 0) {
     86         mBuffer.frameCount = pBuffer->frameCount;
     87         status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
     88         // At one time an upstream buffer provider had
     89         // res == OK and mBuffer.frameCount == 0, doesn't seem to happen now 7/18/2014.
     90         //
     91         // By API spec, if res != OK, then mBuffer.frameCount == 0.
     92         // but there may be improper implementations.
     93         ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
     94         if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
     95             pBuffer->raw = NULL;
     96             pBuffer->frameCount = 0;
     97             return res;
     98         }
     99         mConsumed = 0;
    100     }
    101     ALOG_ASSERT(mConsumed < mBuffer.frameCount);
    102     size_t count = min(mLocalBufferFrameCount, mBuffer.frameCount - mConsumed);
    103     count = min(count, pBuffer->frameCount);
    104     pBuffer->raw = mLocalBufferData;
    105     pBuffer->frameCount = count;
    106     copyFrames(pBuffer->raw, (uint8_t*)mBuffer.raw + mConsumed * mInputFrameSize,
    107             pBuffer->frameCount);
    108     return OK;
    109 }
    110 
    111 void CopyBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer)
    112 {
    113     //ALOGV("CopyBufferProvider(%p)::releaseBuffer(%p(%zu))",
    114     //        this, pBuffer, pBuffer->frameCount);
    115     if (mLocalBufferFrameCount == 0) {
    116         mTrackBufferProvider->releaseBuffer(pBuffer);
    117         return;
    118     }
    119     // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
    120     mConsumed += pBuffer->frameCount; // TODO: update for efficiency to reuse existing content
    121     if (mConsumed != 0 && mConsumed >= mBuffer.frameCount) {
    122         mTrackBufferProvider->releaseBuffer(&mBuffer);
    123         ALOG_ASSERT(mBuffer.frameCount == 0);
    124     }
    125     pBuffer->raw = NULL;
    126     pBuffer->frameCount = 0;
    127 }
    128 
    129 void CopyBufferProvider::reset()
    130 {
    131     if (mBuffer.frameCount != 0) {
    132         mTrackBufferProvider->releaseBuffer(&mBuffer);
    133     }
    134     mConsumed = 0;
    135 }
    136 
    137 DownmixerBufferProvider::DownmixerBufferProvider(
    138         audio_channel_mask_t inputChannelMask,
    139         audio_channel_mask_t outputChannelMask, audio_format_t format,
    140         uint32_t sampleRate, int32_t sessionId, size_t bufferFrameCount) :
    141         CopyBufferProvider(
    142             audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask),
    143             audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask),
    144             bufferFrameCount)  // set bufferFrameCount to 0 to do in-place
    145 {
    146     ALOGV("DownmixerBufferProvider(%p)(%#x, %#x, %#x %u %d)",
    147             this, inputChannelMask, outputChannelMask, format,
    148             sampleRate, sessionId);
    149     if (!sIsMultichannelCapable
    150             || EffectCreate(&sDwnmFxDesc.uuid,
    151                     sessionId,
    152                     SESSION_ID_INVALID_AND_IGNORED,
    153                     &mDownmixHandle) != 0) {
    154          ALOGE("DownmixerBufferProvider() error creating downmixer effect");
    155          mDownmixHandle = NULL;
    156          return;
    157      }
    158      // channel input configuration will be overridden per-track
    159      mDownmixConfig.inputCfg.channels = inputChannelMask;   // FIXME: Should be bits
    160      mDownmixConfig.outputCfg.channels = outputChannelMask; // FIXME: should be bits
    161      mDownmixConfig.inputCfg.format = format;
    162      mDownmixConfig.outputCfg.format = format;
    163      mDownmixConfig.inputCfg.samplingRate = sampleRate;
    164      mDownmixConfig.outputCfg.samplingRate = sampleRate;
    165      mDownmixConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
    166      mDownmixConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
    167      // input and output buffer provider, and frame count will not be used as the downmix effect
    168      // process() function is called directly (see DownmixerBufferProvider::getNextBuffer())
    169      mDownmixConfig.inputCfg.mask = EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS |
    170              EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE;
    171      mDownmixConfig.outputCfg.mask = mDownmixConfig.inputCfg.mask;
    172 
    173      int cmdStatus;
    174      uint32_t replySize = sizeof(int);
    175 
    176      // Configure downmixer
    177      status_t status = (*mDownmixHandle)->command(mDownmixHandle,
    178              EFFECT_CMD_SET_CONFIG /*cmdCode*/, sizeof(effect_config_t) /*cmdSize*/,
    179              &mDownmixConfig /*pCmdData*/,
    180              &replySize, &cmdStatus /*pReplyData*/);
    181      if (status != 0 || cmdStatus != 0) {
    182          ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while configuring downmixer",
    183                  status, cmdStatus);
    184          EffectRelease(mDownmixHandle);
    185          mDownmixHandle = NULL;
    186          return;
    187      }
    188 
    189      // Enable downmixer
    190      replySize = sizeof(int);
    191      status = (*mDownmixHandle)->command(mDownmixHandle,
    192              EFFECT_CMD_ENABLE /*cmdCode*/, 0 /*cmdSize*/, NULL /*pCmdData*/,
    193              &replySize, &cmdStatus /*pReplyData*/);
    194      if (status != 0 || cmdStatus != 0) {
    195          ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while enabling downmixer",
    196                  status, cmdStatus);
    197          EffectRelease(mDownmixHandle);
    198          mDownmixHandle = NULL;
    199          return;
    200      }
    201 
    202      // Set downmix type
    203      // parameter size rounded for padding on 32bit boundary
    204      const int psizePadded = ((sizeof(downmix_params_t) - 1)/sizeof(int) + 1) * sizeof(int);
    205      const int downmixParamSize =
    206              sizeof(effect_param_t) + psizePadded + sizeof(downmix_type_t);
    207      effect_param_t * const param = (effect_param_t *) malloc(downmixParamSize);
    208      param->psize = sizeof(downmix_params_t);
    209      const downmix_params_t downmixParam = DOWNMIX_PARAM_TYPE;
    210      memcpy(param->data, &downmixParam, param->psize);
    211      const downmix_type_t downmixType = DOWNMIX_TYPE_FOLD;
    212      param->vsize = sizeof(downmix_type_t);
    213      memcpy(param->data + psizePadded, &downmixType, param->vsize);
    214      replySize = sizeof(int);
    215      status = (*mDownmixHandle)->command(mDownmixHandle,
    216              EFFECT_CMD_SET_PARAM /* cmdCode */, downmixParamSize /* cmdSize */,
    217              param /*pCmdData*/, &replySize, &cmdStatus /*pReplyData*/);
    218      free(param);
    219      if (status != 0 || cmdStatus != 0) {
    220          ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while setting downmix type",
    221                  status, cmdStatus);
    222          EffectRelease(mDownmixHandle);
    223          mDownmixHandle = NULL;
    224          return;
    225      }
    226      ALOGV("DownmixerBufferProvider() downmix type set to %d", (int) downmixType);
    227 }
    228 
    229 DownmixerBufferProvider::~DownmixerBufferProvider()
    230 {
    231     ALOGV("~DownmixerBufferProvider (%p)", this);
    232     EffectRelease(mDownmixHandle);
    233     mDownmixHandle = NULL;
    234 }
    235 
    236 void DownmixerBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
    237 {
    238     mDownmixConfig.inputCfg.buffer.frameCount = frames;
    239     mDownmixConfig.inputCfg.buffer.raw = const_cast<void *>(src);
    240     mDownmixConfig.outputCfg.buffer.frameCount = frames;
    241     mDownmixConfig.outputCfg.buffer.raw = dst;
    242     // may be in-place if src == dst.
    243     status_t res = (*mDownmixHandle)->process(mDownmixHandle,
    244             &mDownmixConfig.inputCfg.buffer, &mDownmixConfig.outputCfg.buffer);
    245     ALOGE_IF(res != OK, "DownmixBufferProvider error %d", res);
    246 }
    247 
    248 /* call once in a pthread_once handler. */
    249 /*static*/ status_t DownmixerBufferProvider::init()
    250 {
    251     // find multichannel downmix effect if we have to play multichannel content
    252     uint32_t numEffects = 0;
    253     int ret = EffectQueryNumberEffects(&numEffects);
    254     if (ret != 0) {
    255         ALOGE("AudioMixer() error %d querying number of effects", ret);
    256         return NO_INIT;
    257     }
    258     ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
    259 
    260     for (uint32_t i = 0 ; i < numEffects ; i++) {
    261         if (EffectQueryEffect(i, &sDwnmFxDesc) == 0) {
    262             ALOGV("effect %d is called %s", i, sDwnmFxDesc.name);
    263             if (memcmp(&sDwnmFxDesc.type, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) {
    264                 ALOGI("found effect \"%s\" from %s",
    265                         sDwnmFxDesc.name, sDwnmFxDesc.implementor);
    266                 sIsMultichannelCapable = true;
    267                 break;
    268             }
    269         }
    270     }
    271     ALOGW_IF(!sIsMultichannelCapable, "unable to find downmix effect");
    272     return NO_INIT;
    273 }
    274 
    275 /*static*/ bool DownmixerBufferProvider::sIsMultichannelCapable = false;
    276 /*static*/ effect_descriptor_t DownmixerBufferProvider::sDwnmFxDesc;
    277 
    278 RemixBufferProvider::RemixBufferProvider(audio_channel_mask_t inputChannelMask,
    279         audio_channel_mask_t outputChannelMask, audio_format_t format,
    280         size_t bufferFrameCount) :
    281         CopyBufferProvider(
    282                 audio_bytes_per_sample(format)
    283                     * audio_channel_count_from_out_mask(inputChannelMask),
    284                 audio_bytes_per_sample(format)
    285                     * audio_channel_count_from_out_mask(outputChannelMask),
    286                 bufferFrameCount),
    287         mFormat(format),
    288         mSampleSize(audio_bytes_per_sample(format)),
    289         mInputChannels(audio_channel_count_from_out_mask(inputChannelMask)),
    290         mOutputChannels(audio_channel_count_from_out_mask(outputChannelMask))
    291 {
    292     ALOGV("RemixBufferProvider(%p)(%#x, %#x, %#x) %zu %zu",
    293             this, format, inputChannelMask, outputChannelMask,
    294             mInputChannels, mOutputChannels);
    295     (void) memcpy_by_index_array_initialization_from_channel_mask(
    296             mIdxAry, ARRAY_SIZE(mIdxAry), outputChannelMask, inputChannelMask);
    297 }
    298 
    299 void RemixBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
    300 {
    301     memcpy_by_index_array(dst, mOutputChannels,
    302             src, mInputChannels, mIdxAry, mSampleSize, frames);
    303 }
    304 
    305 ReformatBufferProvider::ReformatBufferProvider(int32_t channelCount,
    306         audio_format_t inputFormat, audio_format_t outputFormat,
    307         size_t bufferFrameCount) :
    308         CopyBufferProvider(
    309                 channelCount * audio_bytes_per_sample(inputFormat),
    310                 channelCount * audio_bytes_per_sample(outputFormat),
    311                 bufferFrameCount),
    312         mChannelCount(channelCount),
    313         mInputFormat(inputFormat),
    314         mOutputFormat(outputFormat)
    315 {
    316     ALOGV("ReformatBufferProvider(%p)(%u, %#x, %#x)",
    317             this, channelCount, inputFormat, outputFormat);
    318 }
    319 
    320 void ReformatBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
    321 {
    322     memcpy_by_audio_format(dst, mOutputFormat, src, mInputFormat, frames * mChannelCount);
    323 }
    324 
    325 TimestretchBufferProvider::TimestretchBufferProvider(int32_t channelCount,
    326         audio_format_t format, uint32_t sampleRate, const AudioPlaybackRate &playbackRate) :
    327         mChannelCount(channelCount),
    328         mFormat(format),
    329         mSampleRate(sampleRate),
    330         mFrameSize(channelCount * audio_bytes_per_sample(format)),
    331         mLocalBufferFrameCount(0),
    332         mLocalBufferData(NULL),
    333         mRemaining(0),
    334         mSonicStream(sonicCreateStream(sampleRate, mChannelCount)),
    335         mFallbackFailErrorShown(false),
    336         mAudioPlaybackRateValid(false)
    337 {
    338     LOG_ALWAYS_FATAL_IF(mSonicStream == NULL,
    339             "TimestretchBufferProvider can't allocate Sonic stream");
    340 
    341     setPlaybackRate(playbackRate);
    342     ALOGV("TimestretchBufferProvider(%p)(%u, %#x, %u %f %f %d %d)",
    343             this, channelCount, format, sampleRate, playbackRate.mSpeed,
    344             playbackRate.mPitch, playbackRate.mStretchMode, playbackRate.mFallbackMode);
    345     mBuffer.frameCount = 0;
    346 }
    347 
    348 TimestretchBufferProvider::~TimestretchBufferProvider()
    349 {
    350     ALOGV("~TimestretchBufferProvider(%p)", this);
    351     sonicDestroyStream(mSonicStream);
    352     if (mBuffer.frameCount != 0) {
    353         mTrackBufferProvider->releaseBuffer(&mBuffer);
    354     }
    355     free(mLocalBufferData);
    356 }
    357 
    358 status_t TimestretchBufferProvider::getNextBuffer(
    359         AudioBufferProvider::Buffer *pBuffer, int64_t pts)
    360 {
    361     ALOGV("TimestretchBufferProvider(%p)::getNextBuffer(%p (%zu), %lld)",
    362             this, pBuffer, pBuffer->frameCount, pts);
    363 
    364     // BYPASS
    365     //return mTrackBufferProvider->getNextBuffer(pBuffer, pts);
    366 
    367     // check if previously processed data is sufficient.
    368     if (pBuffer->frameCount <= mRemaining) {
    369         ALOGV("previous sufficient");
    370         pBuffer->raw = mLocalBufferData;
    371         return OK;
    372     }
    373 
    374     // do we need to resize our buffer?
    375     if (pBuffer->frameCount > mLocalBufferFrameCount) {
    376         void *newmem;
    377         if (posix_memalign(&newmem, 32, pBuffer->frameCount * mFrameSize) == OK) {
    378             if (mRemaining != 0) {
    379                 memcpy(newmem, mLocalBufferData, mRemaining * mFrameSize);
    380             }
    381             free(mLocalBufferData);
    382             mLocalBufferData = newmem;
    383             mLocalBufferFrameCount = pBuffer->frameCount;
    384         }
    385     }
    386 
    387     // need to fetch more data
    388     const size_t outputDesired = pBuffer->frameCount - mRemaining;
    389     size_t dstAvailable;
    390     do {
    391         mBuffer.frameCount = mPlaybackRate.mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL
    392                 ? outputDesired : outputDesired * mPlaybackRate.mSpeed + 1;
    393 
    394         status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
    395 
    396         ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
    397         if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
    398             ALOGV("upstream provider cannot provide data");
    399             if (mRemaining == 0) {
    400                 pBuffer->raw = NULL;
    401                 pBuffer->frameCount = 0;
    402                 return res;
    403             } else { // return partial count
    404                 pBuffer->raw = mLocalBufferData;
    405                 pBuffer->frameCount = mRemaining;
    406                 return OK;
    407             }
    408         }
    409 
    410         // time-stretch the data
    411         dstAvailable = min(mLocalBufferFrameCount - mRemaining, outputDesired);
    412         size_t srcAvailable = mBuffer.frameCount;
    413         processFrames((uint8_t*)mLocalBufferData + mRemaining * mFrameSize, &dstAvailable,
    414                 mBuffer.raw, &srcAvailable);
    415 
    416         // release all data consumed
    417         mBuffer.frameCount = srcAvailable;
    418         mTrackBufferProvider->releaseBuffer(&mBuffer);
    419     } while (dstAvailable == 0); // try until we get output data or upstream provider fails.
    420 
    421     // update buffer vars with the actual data processed and return with buffer
    422     mRemaining += dstAvailable;
    423 
    424     pBuffer->raw = mLocalBufferData;
    425     pBuffer->frameCount = mRemaining;
    426 
    427     return OK;
    428 }
    429 
    430 void TimestretchBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer)
    431 {
    432     ALOGV("TimestretchBufferProvider(%p)::releaseBuffer(%p (%zu))",
    433        this, pBuffer, pBuffer->frameCount);
    434 
    435     // BYPASS
    436     //return mTrackBufferProvider->releaseBuffer(pBuffer);
    437 
    438     // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
    439     if (pBuffer->frameCount < mRemaining) {
    440         memcpy(mLocalBufferData,
    441                 (uint8_t*)mLocalBufferData + pBuffer->frameCount * mFrameSize,
    442                 (mRemaining - pBuffer->frameCount) * mFrameSize);
    443         mRemaining -= pBuffer->frameCount;
    444     } else if (pBuffer->frameCount == mRemaining) {
    445         mRemaining = 0;
    446     } else {
    447         LOG_ALWAYS_FATAL("Releasing more frames(%zu) than available(%zu)",
    448                 pBuffer->frameCount, mRemaining);
    449     }
    450 
    451     pBuffer->raw = NULL;
    452     pBuffer->frameCount = 0;
    453 }
    454 
    455 void TimestretchBufferProvider::reset()
    456 {
    457     mRemaining = 0;
    458 }
    459 
    460 status_t TimestretchBufferProvider::setPlaybackRate(const AudioPlaybackRate &playbackRate)
    461 {
    462     mPlaybackRate = playbackRate;
    463     mFallbackFailErrorShown = false;
    464     sonicSetSpeed(mSonicStream, mPlaybackRate.mSpeed);
    465     //TODO: pitch is ignored for now
    466     //TODO: optimize: if parameters are the same, don't do any extra computation.
    467 
    468     mAudioPlaybackRateValid = isAudioPlaybackRateValid(mPlaybackRate);
    469     return OK;
    470 }
    471 
    472 void TimestretchBufferProvider::processFrames(void *dstBuffer, size_t *dstFrames,
    473         const void *srcBuffer, size_t *srcFrames)
    474 {
    475     ALOGV("processFrames(%zu %zu)  remaining(%zu)", *dstFrames, *srcFrames, mRemaining);
    476     // Note dstFrames is the required number of frames.
    477 
    478     // Ensure consumption from src is as expected.
    479     //TODO: add logic to track "very accurate" consumption related to speed, original sampling
    480     //rate, actual frames processed.
    481     const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
    482     if (*srcFrames < targetSrc) { // limit dst frames to that possible
    483         *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
    484     } else if (*srcFrames > targetSrc + 1) {
    485         *srcFrames = targetSrc + 1;
    486     }
    487 
    488     if (!mAudioPlaybackRateValid) {
    489         //fallback mode
    490         if (*dstFrames > 0) {
    491             switch(mPlaybackRate.mFallbackMode) {
    492             case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT:
    493                 if (*dstFrames <= *srcFrames) {
    494                       size_t copySize = mFrameSize * *dstFrames;
    495                       memcpy(dstBuffer, srcBuffer, copySize);
    496                   } else {
    497                       // cyclically repeat the source.
    498                       for (size_t count = 0; count < *dstFrames; count += *srcFrames) {
    499                           size_t remaining = min(*srcFrames, *dstFrames - count);
    500                           memcpy((uint8_t*)dstBuffer + mFrameSize * count,
    501                                   srcBuffer, mFrameSize * remaining);
    502                       }
    503                   }
    504                 break;
    505             case AUDIO_TIMESTRETCH_FALLBACK_DEFAULT:
    506             case AUDIO_TIMESTRETCH_FALLBACK_MUTE:
    507                 memset(dstBuffer,0, mFrameSize * *dstFrames);
    508                 break;
    509             case AUDIO_TIMESTRETCH_FALLBACK_FAIL:
    510             default:
    511                 if(!mFallbackFailErrorShown) {
    512                     ALOGE("invalid parameters in TimestretchBufferProvider fallbackMode:%d",
    513                             mPlaybackRate.mFallbackMode);
    514                     mFallbackFailErrorShown = true;
    515                 }
    516                 break;
    517             }
    518         }
    519     } else {
    520         switch (mFormat) {
    521         case AUDIO_FORMAT_PCM_FLOAT:
    522             if (sonicWriteFloatToStream(mSonicStream, (float*)srcBuffer, *srcFrames) != 1) {
    523                 ALOGE("sonicWriteFloatToStream cannot realloc");
    524                 *srcFrames = 0; // cannot consume all of srcBuffer
    525             }
    526             *dstFrames = sonicReadFloatFromStream(mSonicStream, (float*)dstBuffer, *dstFrames);
    527             break;
    528         case AUDIO_FORMAT_PCM_16_BIT:
    529             if (sonicWriteShortToStream(mSonicStream, (short*)srcBuffer, *srcFrames) != 1) {
    530                 ALOGE("sonicWriteShortToStream cannot realloc");
    531                 *srcFrames = 0; // cannot consume all of srcBuffer
    532             }
    533             *dstFrames = sonicReadShortFromStream(mSonicStream, (short*)dstBuffer, *dstFrames);
    534             break;
    535         default:
    536             // could also be caught on construction
    537             LOG_ALWAYS_FATAL("invalid format %#x for TimestretchBufferProvider", mFormat);
    538         }
    539     }
    540 }
    541 // ----------------------------------------------------------------------------
    542 } // namespace android
    543