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