blob: 3566ee2ef80f1b05889a02afaa3d71cc70fef447 [file] [log] [blame]
Andy Hung857d5a22015-03-26 18:46:00 -07001/*
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>
Andy Hungc5656cc2015-03-26 19:04:33 -070023#include <media/AudioResamplerPublic.h>
Andy Hung857d5a22015-03-26 18:46:00 -070024#include <media/EffectsFactoryApi.h>
Andy Hungc5656cc2015-03-26 19:04:33 -070025
Andy Hung857d5a22015-03-26 18:46:00 -070026#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
35namespace android {
36
37// ----------------------------------------------------------------------------
38
39template <typename T>
40static inline T min(const T& a, const T& b)
41{
42 return a < b ? a : b;
43}
44
45CopyBufferProvider::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
64CopyBufferProvider::~CopyBufferProvider()
65{
66 ALOGV("~CopyBufferProvider(%p)", this);
67 if (mBuffer.frameCount != 0) {
68 mTrackBufferProvider->releaseBuffer(&mBuffer);
69 }
70 free(mLocalBufferData);
71}
72
73status_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
111void 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
129void CopyBufferProvider::reset()
130{
131 if (mBuffer.frameCount != 0) {
132 mTrackBufferProvider->releaseBuffer(&mBuffer);
133 }
134 mConsumed = 0;
135}
136
137DownmixerBufferProvider::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
229DownmixerBufferProvider::~DownmixerBufferProvider()
230{
231 ALOGV("~DownmixerBufferProvider (%p)", this);
232 EffectRelease(mDownmixHandle);
233 mDownmixHandle = NULL;
234}
235
236void 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. */
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
278RemixBufferProvider::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);
Andy Hung18aa2702015-05-05 23:48:38 -0700295 (void) memcpy_by_index_array_initialization_from_channel_mask(
296 mIdxAry, ARRAY_SIZE(mIdxAry), outputChannelMask, inputChannelMask);
Andy Hung857d5a22015-03-26 18:46:00 -0700297}
298
299void 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
305ReformatBufferProvider::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
320void ReformatBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
321{
322 memcpy_by_audio_format(dst, mOutputFormat, src, mInputFormat, frames * mChannelCount);
323}
324
Andy Hungc5656cc2015-03-26 19:04:33 -0700325TimestretchBufferProvider::TimestretchBufferProvider(int32_t channelCount,
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700326 audio_format_t format, uint32_t sampleRate, const AudioPlaybackRate &playbackRate) :
Andy Hungc5656cc2015-03-26 19:04:33 -0700327 mChannelCount(channelCount),
328 mFormat(format),
329 mSampleRate(sampleRate),
330 mFrameSize(channelCount * audio_bytes_per_sample(format)),
Andy Hungc5656cc2015-03-26 19:04:33 -0700331 mLocalBufferFrameCount(0),
332 mLocalBufferData(NULL),
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700333 mRemaining(0),
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700334 mSonicStream(sonicCreateStream(sampleRate, mChannelCount)),
Ricardo Garcia6c7f0622015-04-30 18:39:16 -0700335 mFallbackFailErrorShown(false),
336 mAudioPlaybackRateValid(false)
Andy Hungc5656cc2015-03-26 19:04:33 -0700337{
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700338 LOG_ALWAYS_FATAL_IF(mSonicStream == NULL,
339 "TimestretchBufferProvider can't allocate Sonic stream");
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700340
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;
Andy Hungc5656cc2015-03-26 19:04:33 -0700346}
347
348TimestretchBufferProvider::~TimestretchBufferProvider()
349{
350 ALOGV("~TimestretchBufferProvider(%p)", this);
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700351 sonicDestroyStream(mSonicStream);
Andy Hungc5656cc2015-03-26 19:04:33 -0700352 if (mBuffer.frameCount != 0) {
353 mTrackBufferProvider->releaseBuffer(&mBuffer);
354 }
355 free(mLocalBufferData);
356}
357
358status_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;
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700389 mBuffer.frameCount = mPlaybackRate.mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL
390 ? outputDesired : outputDesired * mPlaybackRate.mSpeed + 1;
Andy Hungc5656cc2015-03-26 19:04:33 -0700391
392 status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
393
394 ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
395 if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
396 ALOGD("buffer error");
397 if (mRemaining == 0) {
398 pBuffer->raw = NULL;
399 pBuffer->frameCount = 0;
400 return res;
401 } else { // return partial count
402 pBuffer->raw = mLocalBufferData;
403 pBuffer->frameCount = mRemaining;
404 return OK;
405 }
406 }
407
408 // time-stretch the data
409 size_t dstAvailable = min(mLocalBufferFrameCount - mRemaining, outputDesired);
410 size_t srcAvailable = mBuffer.frameCount;
411 processFrames((uint8_t*)mLocalBufferData + mRemaining * mFrameSize, &dstAvailable,
412 mBuffer.raw, &srcAvailable);
413
414 // release all data consumed
415 mBuffer.frameCount = srcAvailable;
416 mTrackBufferProvider->releaseBuffer(&mBuffer);
417
418 // update buffer vars with the actual data processed and return with buffer
419 mRemaining += dstAvailable;
420
421 pBuffer->raw = mLocalBufferData;
422 pBuffer->frameCount = mRemaining;
423
424 return OK;
425}
426
427void TimestretchBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer)
428{
429 ALOGV("TimestretchBufferProvider(%p)::releaseBuffer(%p (%zu))",
430 this, pBuffer, pBuffer->frameCount);
431
432 // BYPASS
433 //return mTrackBufferProvider->releaseBuffer(pBuffer);
434
435 // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
436 if (pBuffer->frameCount < mRemaining) {
437 memcpy(mLocalBufferData,
438 (uint8_t*)mLocalBufferData + pBuffer->frameCount * mFrameSize,
439 (mRemaining - pBuffer->frameCount) * mFrameSize);
440 mRemaining -= pBuffer->frameCount;
441 } else if (pBuffer->frameCount == mRemaining) {
442 mRemaining = 0;
443 } else {
444 LOG_ALWAYS_FATAL("Releasing more frames(%zu) than available(%zu)",
445 pBuffer->frameCount, mRemaining);
446 }
447
448 pBuffer->raw = NULL;
449 pBuffer->frameCount = 0;
450}
451
452void TimestretchBufferProvider::reset()
453{
454 mRemaining = 0;
455}
456
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700457status_t TimestretchBufferProvider::setPlaybackRate(const AudioPlaybackRate &playbackRate)
Andy Hungc5656cc2015-03-26 19:04:33 -0700458{
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700459 mPlaybackRate = playbackRate;
460 mFallbackFailErrorShown = false;
461 sonicSetSpeed(mSonicStream, mPlaybackRate.mSpeed);
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700462 //TODO: pitch is ignored for now
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700463 //TODO: optimize: if parameters are the same, don't do any extra computation.
Ricardo Garcia6c7f0622015-04-30 18:39:16 -0700464
465 mAudioPlaybackRateValid = isAudioPlaybackRateValid(mPlaybackRate);
Andy Hungc5656cc2015-03-26 19:04:33 -0700466 return OK;
467}
468
469void TimestretchBufferProvider::processFrames(void *dstBuffer, size_t *dstFrames,
470 const void *srcBuffer, size_t *srcFrames)
471{
472 ALOGV("processFrames(%zu %zu) remaining(%zu)", *dstFrames, *srcFrames, mRemaining);
473 // Note dstFrames is the required number of frames.
474
475 // Ensure consumption from src is as expected.
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700476 //TODO: add logic to track "very accurate" consumption related to speed, original sampling
477 //rate, actual frames processed.
478 const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
Andy Hungc5656cc2015-03-26 19:04:33 -0700479 if (*srcFrames < targetSrc) { // limit dst frames to that possible
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700480 *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
Andy Hungc5656cc2015-03-26 19:04:33 -0700481 } else if (*srcFrames > targetSrc + 1) {
482 *srcFrames = targetSrc + 1;
483 }
484
Ricardo Garcia6c7f0622015-04-30 18:39:16 -0700485 if (!mAudioPlaybackRateValid) {
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700486 //fallback mode
487 if (*dstFrames > 0) {
488 switch(mPlaybackRate.mFallbackMode) {
489 case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT:
490 if (*dstFrames <= *srcFrames) {
491 size_t copySize = mFrameSize * *dstFrames;
492 memcpy(dstBuffer, srcBuffer, copySize);
493 } else {
494 // cyclically repeat the source.
495 for (size_t count = 0; count < *dstFrames; count += *srcFrames) {
496 size_t remaining = min(*srcFrames, *dstFrames - count);
497 memcpy((uint8_t*)dstBuffer + mFrameSize * count,
498 srcBuffer, mFrameSize * remaining);
499 }
500 }
501 break;
502 case AUDIO_TIMESTRETCH_FALLBACK_DEFAULT:
503 case AUDIO_TIMESTRETCH_FALLBACK_MUTE:
504 memset(dstBuffer,0, mFrameSize * *dstFrames);
505 break;
506 case AUDIO_TIMESTRETCH_FALLBACK_FAIL:
507 default:
508 if(!mFallbackFailErrorShown) {
509 ALOGE("invalid parameters in TimestretchBufferProvider fallbackMode:%d",
510 mPlaybackRate.mFallbackMode);
511 mFallbackFailErrorShown = true;
512 }
513 break;
514 }
Andy Hungc5656cc2015-03-26 19:04:33 -0700515 }
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700516 } else {
517 switch (mFormat) {
518 case AUDIO_FORMAT_PCM_FLOAT:
519 if (sonicWriteFloatToStream(mSonicStream, (float*)srcBuffer, *srcFrames) != 1) {
520 ALOGE("sonicWriteFloatToStream cannot realloc");
521 *srcFrames = 0; // cannot consume all of srcBuffer
522 }
523 *dstFrames = sonicReadFloatFromStream(mSonicStream, (float*)dstBuffer, *dstFrames);
524 break;
525 case AUDIO_FORMAT_PCM_16_BIT:
526 if (sonicWriteShortToStream(mSonicStream, (short*)srcBuffer, *srcFrames) != 1) {
527 ALOGE("sonicWriteShortToStream cannot realloc");
528 *srcFrames = 0; // cannot consume all of srcBuffer
529 }
530 *dstFrames = sonicReadShortFromStream(mSonicStream, (short*)dstBuffer, *dstFrames);
531 break;
532 default:
533 // could also be caught on construction
534 LOG_ALWAYS_FATAL("invalid format %#x for TimestretchBufferProvider", mFormat);
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700535 }
Andy Hungc5656cc2015-03-26 19:04:33 -0700536 }
537}
Andy Hung857d5a22015-03-26 18:46:00 -0700538// ----------------------------------------------------------------------------
539} // namespace android