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)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 
releaseBuffer(AudioBufferProvider::Buffer * pBuffer)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 
reset()128 void CopyBufferProvider::reset()
129 {
130     if (mBuffer.frameCount != 0) {
131         mTrackBufferProvider->releaseBuffer(&mBuffer);
132     }
133     mConsumed = 0;
134 }
135 
DownmixerBufferProvider(audio_channel_mask_t inputChannelMask,audio_channel_mask_t outputChannelMask,audio_format_t format,uint32_t sampleRate,int32_t sessionId,size_t bufferFrameCount)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 
~DownmixerBufferProvider()228 DownmixerBufferProvider::~DownmixerBufferProvider()
229 {
230     ALOGV("~DownmixerBufferProvider (%p)", this);
231     EffectRelease(mDownmixHandle);
232     mDownmixHandle = NULL;
233 }
234 
copyFrames(void * dst,const void * src,size_t frames)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. */
init()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 
RemixBufferProvider(audio_channel_mask_t inputChannelMask,audio_channel_mask_t outputChannelMask,audio_format_t format,size_t bufferFrameCount)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 
copyFrames(void * dst,const void * src,size_t frames)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 
ReformatBufferProvider(int32_t channelCount,audio_format_t inputFormat,audio_format_t outputFormat,size_t bufferFrameCount)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 
copyFrames(void * dst,const void * src,size_t frames)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 
TimestretchBufferProvider(int32_t channelCount,audio_format_t format,uint32_t sampleRate,const AudioPlaybackRate & playbackRate)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 
~TimestretchBufferProvider()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 
getNextBuffer(AudioBufferProvider::Buffer * pBuffer)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 
releaseBuffer(AudioBufferProvider::Buffer * pBuffer)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 
reset()454 void TimestretchBufferProvider::reset()
455 {
456     mRemaining = 0;
457 }
458 
setPlaybackRate(const AudioPlaybackRate & playbackRate)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 
processFrames(void * dstBuffer,size_t * dstFrames,const void * srcBuffer,size_t * srcFrames)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