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>
min(const T & a,const T & b)40 static inline T min(const T& a, const T& b)
41 {
42     return a < b ? a : b;
43 }
44 
CopyBufferProvider(size_t inputFrameSize,size_t outputFrameSize,size_t bufferFrameCount)45 CopyBufferProvider::CopyBufferProvider(size_t inputFrameSize,
46         size_t outputFrameSize, size_t bufferFrameCount) :
47         mInputFrameSize(inputFrameSize),
48         mOutputFrameSize(outputFrameSize),
49         mLocalBufferFrameCount(bufferFrameCount),
50         mLocalBufferData(NULL),
51         mConsumed(0)
52 {
53     ALOGV("CopyBufferProvider(%p)(%zu, %zu, %zu)", this,
54             inputFrameSize, outputFrameSize, bufferFrameCount);
55     LOG_ALWAYS_FATAL_IF(inputFrameSize < outputFrameSize && bufferFrameCount == 0,
56             "Requires local buffer if inputFrameSize(%zu) < outputFrameSize(%zu)",
57             inputFrameSize, outputFrameSize);
58     if (mLocalBufferFrameCount) {
59         (void)posix_memalign(&mLocalBufferData, 32, mLocalBufferFrameCount * mOutputFrameSize);
60     }
61     mBuffer.frameCount = 0;
62 }
63 
~CopyBufferProvider()64 CopyBufferProvider::~CopyBufferProvider()
65 {
66     ALOGV("~CopyBufferProvider(%p)", this);
67     if (mBuffer.frameCount != 0) {
68         mTrackBufferProvider->releaseBuffer(&mBuffer);
69     }
70     free(mLocalBufferData);
71 }
72 
getNextBuffer(AudioBufferProvider::Buffer * pBuffer,int64_t pts)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 
releaseBuffer(AudioBufferProvider::Buffer * pBuffer)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 
reset()129 void CopyBufferProvider::reset()
130 {
131     if (mBuffer.frameCount != 0) {
132         mTrackBufferProvider->releaseBuffer(&mBuffer);
133     }
134     mConsumed = 0;
135 }
136 
DownmixerBufferProvider(audio_channel_mask_t inputChannelMask,audio_channel_mask_t outputChannelMask,audio_format_t format,uint32_t sampleRate,int32_t sessionId,size_t bufferFrameCount)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 
~DownmixerBufferProvider()229 DownmixerBufferProvider::~DownmixerBufferProvider()
230 {
231     ALOGV("~DownmixerBufferProvider (%p)", this);
232     EffectRelease(mDownmixHandle);
233     mDownmixHandle = NULL;
234 }
235 
copyFrames(void * dst,const void * src,size_t frames)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. */
init()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 
RemixBufferProvider(audio_channel_mask_t inputChannelMask,audio_channel_mask_t outputChannelMask,audio_format_t format,size_t bufferFrameCount)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 
copyFrames(void * dst,const void * src,size_t frames)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 
ReformatBufferProvider(int32_t channelCount,audio_format_t inputFormat,audio_format_t outputFormat,size_t bufferFrameCount)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 
copyFrames(void * dst,const void * src,size_t frames)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 
TimestretchBufferProvider(int32_t channelCount,audio_format_t format,uint32_t sampleRate,const AudioPlaybackRate & playbackRate)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 
~TimestretchBufferProvider()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 
getNextBuffer(AudioBufferProvider::Buffer * pBuffer,int64_t pts)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 
releaseBuffer(AudioBufferProvider::Buffer * pBuffer)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 
reset()455 void TimestretchBufferProvider::reset()
456 {
457     mRemaining = 0;
458 }
459 
setPlaybackRate(const AudioPlaybackRate & playbackRate)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 
processFrames(void * dstBuffer,size_t * dstFrames,const void * srcBuffer,size_t * srcFrames)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