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