Home | History | Annotate | Download | only in libaudioprocessing
      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>
     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 %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 
    268 DownmixerBufferProvider::~DownmixerBufferProvider()
    269 {
    270     ALOGV("~DownmixerBufferProvider (%p)", this);
    271     if (mDownmixInterface != 0) {
    272         mDownmixInterface->close();
    273     }
    274 }
    275 
    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. */
    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 
    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 
    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 
    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 
    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 
    379 TimestretchBufferProvider::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 
    402 TimestretchBufferProvider::~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 
    412 status_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 
    484 void 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 
    509 void TimestretchBufferProvider::reset()
    510 {
    511     mRemaining = 0;
    512 }
    513 
    514 status_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 
    526 void 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