1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "BufferProvider" 18 //#define LOG_NDEBUG 0 19 20 #include <audio_utils/primitives.h> 21 #include <audio_utils/format.h> 22 #include <external/sonic/sonic.h> 23 #include <media/audiohal/EffectBufferHalInterface.h> 24 #include <media/audiohal/EffectHalInterface.h> 25 #include <media/audiohal/EffectsFactoryHalInterface.h> 26 #include <media/AudioResamplerPublic.h> 27 #include <media/BufferProviders.h> 28 #include <system/audio_effects/effect_downmix.h> 29 #include <utils/Log.h> 30 31 #ifndef ARRAY_SIZE 32 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) 33 #endif 34 35 namespace android { 36 37 // ---------------------------------------------------------------------------- 38 39 template <typename T> 40 static inline T min(const T& a, const T& b) 41 { 42 return a < b ? a : b; 43 } 44 45 CopyBufferProvider::CopyBufferProvider(size_t inputFrameSize, 46 size_t outputFrameSize, size_t bufferFrameCount) : 47 mInputFrameSize(inputFrameSize), 48 mOutputFrameSize(outputFrameSize), 49 mLocalBufferFrameCount(bufferFrameCount), 50 mLocalBufferData(NULL), 51 mConsumed(0) 52 { 53 ALOGV("CopyBufferProvider(%p)(%zu, %zu, %zu)", this, 54 inputFrameSize, outputFrameSize, bufferFrameCount); 55 LOG_ALWAYS_FATAL_IF(inputFrameSize < outputFrameSize && bufferFrameCount == 0, 56 "Requires local buffer if inputFrameSize(%zu) < outputFrameSize(%zu)", 57 inputFrameSize, outputFrameSize); 58 if (mLocalBufferFrameCount) { 59 (void)posix_memalign(&mLocalBufferData, 32, mLocalBufferFrameCount * mOutputFrameSize); 60 } 61 mBuffer.frameCount = 0; 62 } 63 64 CopyBufferProvider::~CopyBufferProvider() 65 { 66 ALOGV("~CopyBufferProvider(%p)", this); 67 if (mBuffer.frameCount != 0) { 68 mTrackBufferProvider->releaseBuffer(&mBuffer); 69 } 70 free(mLocalBufferData); 71 } 72 73 status_t CopyBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer) 74 { 75 //ALOGV("CopyBufferProvider(%p)::getNextBuffer(%p (%zu))", 76 // this, pBuffer, pBuffer->frameCount); 77 if (mLocalBufferFrameCount == 0) { 78 status_t res = mTrackBufferProvider->getNextBuffer(pBuffer); 79 if (res == OK) { 80 copyFrames(pBuffer->raw, pBuffer->raw, pBuffer->frameCount); 81 } 82 return res; 83 } 84 if (mBuffer.frameCount == 0) { 85 mBuffer.frameCount = pBuffer->frameCount; 86 status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer); 87 // At one time an upstream buffer provider had 88 // res == OK and mBuffer.frameCount == 0, doesn't seem to happen now 7/18/2014. 89 // 90 // By API spec, if res != OK, then mBuffer.frameCount == 0. 91 // but there may be improper implementations. 92 ALOG_ASSERT(res == OK || mBuffer.frameCount == 0); 93 if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe. 94 pBuffer->raw = NULL; 95 pBuffer->frameCount = 0; 96 return res; 97 } 98 mConsumed = 0; 99 } 100 ALOG_ASSERT(mConsumed < mBuffer.frameCount); 101 size_t count = min(mLocalBufferFrameCount, mBuffer.frameCount - mConsumed); 102 count = min(count, pBuffer->frameCount); 103 pBuffer->raw = mLocalBufferData; 104 pBuffer->frameCount = count; 105 copyFrames(pBuffer->raw, (uint8_t*)mBuffer.raw + mConsumed * mInputFrameSize, 106 pBuffer->frameCount); 107 return OK; 108 } 109 110 void CopyBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) 111 { 112 //ALOGV("CopyBufferProvider(%p)::releaseBuffer(%p(%zu))", 113 // this, pBuffer, pBuffer->frameCount); 114 if (mLocalBufferFrameCount == 0) { 115 mTrackBufferProvider->releaseBuffer(pBuffer); 116 return; 117 } 118 // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount"); 119 mConsumed += pBuffer->frameCount; // TODO: update for efficiency to reuse existing content 120 if (mConsumed != 0 && mConsumed >= mBuffer.frameCount) { 121 mTrackBufferProvider->releaseBuffer(&mBuffer); 122 ALOG_ASSERT(mBuffer.frameCount == 0); 123 } 124 pBuffer->raw = NULL; 125 pBuffer->frameCount = 0; 126 } 127 128 void CopyBufferProvider::reset() 129 { 130 if (mBuffer.frameCount != 0) { 131 mTrackBufferProvider->releaseBuffer(&mBuffer); 132 } 133 mConsumed = 0; 134 } 135 136 DownmixerBufferProvider::DownmixerBufferProvider( 137 audio_channel_mask_t inputChannelMask, 138 audio_channel_mask_t outputChannelMask, audio_format_t format, 139 uint32_t sampleRate, int32_t sessionId, size_t bufferFrameCount) : 140 CopyBufferProvider( 141 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask), 142 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask), 143 bufferFrameCount) // set bufferFrameCount to 0 to do in-place 144 { 145 ALOGV("DownmixerBufferProvider(%p)(%#x, %#x, %#x %u %d %d)", 146 this, inputChannelMask, outputChannelMask, format, 147 sampleRate, sessionId, (int)bufferFrameCount); 148 if (!sIsMultichannelCapable) { 149 ALOGE("DownmixerBufferProvider() error: not multichannel capable"); 150 return; 151 } 152 mEffectsFactory = EffectsFactoryHalInterface::create(); 153 if (mEffectsFactory == 0) { 154 ALOGE("DownmixerBufferProvider() error: could not obtain the effects factory"); 155 return; 156 } 157 if (mEffectsFactory->createEffect(&sDwnmFxDesc.uuid, 158 sessionId, 159 SESSION_ID_INVALID_AND_IGNORED, 160 &mDownmixInterface) != 0) { 161 ALOGE("DownmixerBufferProvider() error creating downmixer effect"); 162 mDownmixInterface.clear(); 163 mEffectsFactory.clear(); 164 return; 165 } 166 // channel input configuration will be overridden per-track 167 mDownmixConfig.inputCfg.channels = inputChannelMask; // FIXME: Should be bits 168 mDownmixConfig.outputCfg.channels = outputChannelMask; // FIXME: should be bits 169 mDownmixConfig.inputCfg.format = format; 170 mDownmixConfig.outputCfg.format = format; 171 mDownmixConfig.inputCfg.samplingRate = sampleRate; 172 mDownmixConfig.outputCfg.samplingRate = sampleRate; 173 mDownmixConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; 174 mDownmixConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE; 175 // input and output buffer provider, and frame count will not be used as the downmix effect 176 // process() function is called directly (see DownmixerBufferProvider::getNextBuffer()) 177 mDownmixConfig.inputCfg.mask = EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | 178 EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE; 179 mDownmixConfig.outputCfg.mask = mDownmixConfig.inputCfg.mask; 180 181 mInFrameSize = 182 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask); 183 mOutFrameSize = 184 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask); 185 status_t status; 186 status = EffectBufferHalInterface::mirror( 187 nullptr, mInFrameSize * bufferFrameCount, &mInBuffer); 188 if (status != 0) { 189 ALOGE("DownmixerBufferProvider() error %d while creating input buffer", status); 190 mDownmixInterface.clear(); 191 mEffectsFactory.clear(); 192 return; 193 } 194 status = EffectBufferHalInterface::mirror( 195 nullptr, mOutFrameSize * bufferFrameCount, &mOutBuffer); 196 if (status != 0) { 197 ALOGE("DownmixerBufferProvider() error %d while creating output buffer", status); 198 mInBuffer.clear(); 199 mDownmixInterface.clear(); 200 mEffectsFactory.clear(); 201 return; 202 } 203 mDownmixInterface->setInBuffer(mInBuffer); 204 mDownmixInterface->setOutBuffer(mOutBuffer); 205 206 int cmdStatus; 207 uint32_t replySize = sizeof(int); 208 209 // Configure downmixer 210 status = mDownmixInterface->command( 211 EFFECT_CMD_SET_CONFIG /*cmdCode*/, sizeof(effect_config_t) /*cmdSize*/, 212 &mDownmixConfig /*pCmdData*/, 213 &replySize, &cmdStatus /*pReplyData*/); 214 if (status != 0 || cmdStatus != 0) { 215 ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while configuring downmixer", 216 status, cmdStatus); 217 mOutBuffer.clear(); 218 mInBuffer.clear(); 219 mDownmixInterface.clear(); 220 mEffectsFactory.clear(); 221 return; 222 } 223 224 // Enable downmixer 225 replySize = sizeof(int); 226 status = mDownmixInterface->command( 227 EFFECT_CMD_ENABLE /*cmdCode*/, 0 /*cmdSize*/, NULL /*pCmdData*/, 228 &replySize, &cmdStatus /*pReplyData*/); 229 if (status != 0 || cmdStatus != 0) { 230 ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while enabling downmixer", 231 status, cmdStatus); 232 mOutBuffer.clear(); 233 mInBuffer.clear(); 234 mDownmixInterface.clear(); 235 mEffectsFactory.clear(); 236 return; 237 } 238 239 // Set downmix type 240 // parameter size rounded for padding on 32bit boundary 241 const int psizePadded = ((sizeof(downmix_params_t) - 1)/sizeof(int) + 1) * sizeof(int); 242 const int downmixParamSize = 243 sizeof(effect_param_t) + psizePadded + sizeof(downmix_type_t); 244 effect_param_t * const param = (effect_param_t *) malloc(downmixParamSize); 245 param->psize = sizeof(downmix_params_t); 246 const downmix_params_t downmixParam = DOWNMIX_PARAM_TYPE; 247 memcpy(param->data, &downmixParam, param->psize); 248 const downmix_type_t downmixType = DOWNMIX_TYPE_FOLD; 249 param->vsize = sizeof(downmix_type_t); 250 memcpy(param->data + psizePadded, &downmixType, param->vsize); 251 replySize = sizeof(int); 252 status = mDownmixInterface->command( 253 EFFECT_CMD_SET_PARAM /* cmdCode */, downmixParamSize /* cmdSize */, 254 param /*pCmdData*/, &replySize, &cmdStatus /*pReplyData*/); 255 free(param); 256 if (status != 0 || cmdStatus != 0) { 257 ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while setting downmix type", 258 status, cmdStatus); 259 mOutBuffer.clear(); 260 mInBuffer.clear(); 261 mDownmixInterface.clear(); 262 mEffectsFactory.clear(); 263 return; 264 } 265 ALOGV("DownmixerBufferProvider() downmix type set to %d", (int) downmixType); 266 } 267 268 DownmixerBufferProvider::~DownmixerBufferProvider() 269 { 270 ALOGV("~DownmixerBufferProvider (%p)", this); 271 if (mDownmixInterface != 0) { 272 mDownmixInterface->close(); 273 } 274 } 275 276 void DownmixerBufferProvider::copyFrames(void *dst, const void *src, size_t frames) 277 { 278 mInBuffer->setExternalData(const_cast<void*>(src)); 279 mInBuffer->setFrameCount(frames); 280 mInBuffer->update(mInFrameSize * frames); 281 mOutBuffer->setFrameCount(frames); 282 mOutBuffer->setExternalData(dst); 283 if (dst != src) { 284 // Downmix may be accumulating, need to populate the output buffer 285 // with the dst data. 286 mOutBuffer->update(mOutFrameSize * frames); 287 } 288 // may be in-place if src == dst. 289 status_t res = mDownmixInterface->process(); 290 if (res == OK) { 291 mOutBuffer->commit(mOutFrameSize * frames); 292 } else { 293 ALOGE("DownmixBufferProvider error %d", res); 294 } 295 } 296 297 /* call once in a pthread_once handler. */ 298 /*static*/ status_t DownmixerBufferProvider::init() 299 { 300 // find multichannel downmix effect if we have to play multichannel content 301 sp<EffectsFactoryHalInterface> effectsFactory = EffectsFactoryHalInterface::create(); 302 if (effectsFactory == 0) { 303 ALOGE("AudioMixer() error: could not obtain the effects factory"); 304 return NO_INIT; 305 } 306 uint32_t numEffects = 0; 307 int ret = effectsFactory->queryNumberEffects(&numEffects); 308 if (ret != 0) { 309 ALOGE("AudioMixer() error %d querying number of effects", ret); 310 return NO_INIT; 311 } 312 ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects); 313 314 for (uint32_t i = 0 ; i < numEffects ; i++) { 315 if (effectsFactory->getDescriptor(i, &sDwnmFxDesc) == 0) { 316 ALOGV("effect %d is called %s", i, sDwnmFxDesc.name); 317 if (memcmp(&sDwnmFxDesc.type, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) { 318 ALOGI("found effect \"%s\" from %s", 319 sDwnmFxDesc.name, sDwnmFxDesc.implementor); 320 sIsMultichannelCapable = true; 321 break; 322 } 323 } 324 } 325 ALOGW_IF(!sIsMultichannelCapable, "unable to find downmix effect"); 326 return NO_INIT; 327 } 328 329 /*static*/ bool DownmixerBufferProvider::sIsMultichannelCapable = false; 330 /*static*/ effect_descriptor_t DownmixerBufferProvider::sDwnmFxDesc; 331 332 RemixBufferProvider::RemixBufferProvider(audio_channel_mask_t inputChannelMask, 333 audio_channel_mask_t outputChannelMask, audio_format_t format, 334 size_t bufferFrameCount) : 335 CopyBufferProvider( 336 audio_bytes_per_sample(format) 337 * audio_channel_count_from_out_mask(inputChannelMask), 338 audio_bytes_per_sample(format) 339 * audio_channel_count_from_out_mask(outputChannelMask), 340 bufferFrameCount), 341 mFormat(format), 342 mSampleSize(audio_bytes_per_sample(format)), 343 mInputChannels(audio_channel_count_from_out_mask(inputChannelMask)), 344 mOutputChannels(audio_channel_count_from_out_mask(outputChannelMask)) 345 { 346 ALOGV("RemixBufferProvider(%p)(%#x, %#x, %#x) %zu %zu", 347 this, format, inputChannelMask, outputChannelMask, 348 mInputChannels, mOutputChannels); 349 (void) memcpy_by_index_array_initialization_from_channel_mask( 350 mIdxAry, ARRAY_SIZE(mIdxAry), outputChannelMask, inputChannelMask); 351 } 352 353 void RemixBufferProvider::copyFrames(void *dst, const void *src, size_t frames) 354 { 355 memcpy_by_index_array(dst, mOutputChannels, 356 src, mInputChannels, mIdxAry, mSampleSize, frames); 357 } 358 359 ReformatBufferProvider::ReformatBufferProvider(int32_t channelCount, 360 audio_format_t inputFormat, audio_format_t outputFormat, 361 size_t bufferFrameCount) : 362 CopyBufferProvider( 363 channelCount * audio_bytes_per_sample(inputFormat), 364 channelCount * audio_bytes_per_sample(outputFormat), 365 bufferFrameCount), 366 mChannelCount(channelCount), 367 mInputFormat(inputFormat), 368 mOutputFormat(outputFormat) 369 { 370 ALOGV("ReformatBufferProvider(%p)(%u, %#x, %#x)", 371 this, channelCount, inputFormat, outputFormat); 372 } 373 374 void ReformatBufferProvider::copyFrames(void *dst, const void *src, size_t frames) 375 { 376 memcpy_by_audio_format(dst, mOutputFormat, src, mInputFormat, frames * mChannelCount); 377 } 378 379 TimestretchBufferProvider::TimestretchBufferProvider(int32_t channelCount, 380 audio_format_t format, uint32_t sampleRate, const AudioPlaybackRate &playbackRate) : 381 mChannelCount(channelCount), 382 mFormat(format), 383 mSampleRate(sampleRate), 384 mFrameSize(channelCount * audio_bytes_per_sample(format)), 385 mLocalBufferFrameCount(0), 386 mLocalBufferData(NULL), 387 mRemaining(0), 388 mSonicStream(sonicCreateStream(sampleRate, mChannelCount)), 389 mFallbackFailErrorShown(false), 390 mAudioPlaybackRateValid(false) 391 { 392 LOG_ALWAYS_FATAL_IF(mSonicStream == NULL, 393 "TimestretchBufferProvider can't allocate Sonic stream"); 394 395 setPlaybackRate(playbackRate); 396 ALOGV("TimestretchBufferProvider(%p)(%u, %#x, %u %f %f %d %d)", 397 this, channelCount, format, sampleRate, playbackRate.mSpeed, 398 playbackRate.mPitch, playbackRate.mStretchMode, playbackRate.mFallbackMode); 399 mBuffer.frameCount = 0; 400 } 401 402 TimestretchBufferProvider::~TimestretchBufferProvider() 403 { 404 ALOGV("~TimestretchBufferProvider(%p)", this); 405 sonicDestroyStream(mSonicStream); 406 if (mBuffer.frameCount != 0) { 407 mTrackBufferProvider->releaseBuffer(&mBuffer); 408 } 409 free(mLocalBufferData); 410 } 411 412 status_t TimestretchBufferProvider::getNextBuffer( 413 AudioBufferProvider::Buffer *pBuffer) 414 { 415 ALOGV("TimestretchBufferProvider(%p)::getNextBuffer(%p (%zu))", 416 this, pBuffer, pBuffer->frameCount); 417 418 // BYPASS 419 //return mTrackBufferProvider->getNextBuffer(pBuffer); 420 421 // check if previously processed data is sufficient. 422 if (pBuffer->frameCount <= mRemaining) { 423 ALOGV("previous sufficient"); 424 pBuffer->raw = mLocalBufferData; 425 return OK; 426 } 427 428 // do we need to resize our buffer? 429 if (pBuffer->frameCount > mLocalBufferFrameCount) { 430 void *newmem; 431 if (posix_memalign(&newmem, 32, pBuffer->frameCount * mFrameSize) == OK) { 432 if (mRemaining != 0) { 433 memcpy(newmem, mLocalBufferData, mRemaining * mFrameSize); 434 } 435 free(mLocalBufferData); 436 mLocalBufferData = newmem; 437 mLocalBufferFrameCount = pBuffer->frameCount; 438 } 439 } 440 441 // need to fetch more data 442 const size_t outputDesired = pBuffer->frameCount - mRemaining; 443 size_t dstAvailable; 444 do { 445 mBuffer.frameCount = mPlaybackRate.mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL 446 ? outputDesired : outputDesired * mPlaybackRate.mSpeed + 1; 447 448 status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer); 449 450 ALOG_ASSERT(res == OK || mBuffer.frameCount == 0); 451 if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe. 452 ALOGV("upstream provider cannot provide data"); 453 if (mRemaining == 0) { 454 pBuffer->raw = NULL; 455 pBuffer->frameCount = 0; 456 return res; 457 } else { // return partial count 458 pBuffer->raw = mLocalBufferData; 459 pBuffer->frameCount = mRemaining; 460 return OK; 461 } 462 } 463 464 // time-stretch the data 465 dstAvailable = min(mLocalBufferFrameCount - mRemaining, outputDesired); 466 size_t srcAvailable = mBuffer.frameCount; 467 processFrames((uint8_t*)mLocalBufferData + mRemaining * mFrameSize, &dstAvailable, 468 mBuffer.raw, &srcAvailable); 469 470 // release all data consumed 471 mBuffer.frameCount = srcAvailable; 472 mTrackBufferProvider->releaseBuffer(&mBuffer); 473 } while (dstAvailable == 0); // try until we get output data or upstream provider fails. 474 475 // update buffer vars with the actual data processed and return with buffer 476 mRemaining += dstAvailable; 477 478 pBuffer->raw = mLocalBufferData; 479 pBuffer->frameCount = mRemaining; 480 481 return OK; 482 } 483 484 void TimestretchBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) 485 { 486 ALOGV("TimestretchBufferProvider(%p)::releaseBuffer(%p (%zu))", 487 this, pBuffer, pBuffer->frameCount); 488 489 // BYPASS 490 //return mTrackBufferProvider->releaseBuffer(pBuffer); 491 492 // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount"); 493 if (pBuffer->frameCount < mRemaining) { 494 memcpy(mLocalBufferData, 495 (uint8_t*)mLocalBufferData + pBuffer->frameCount * mFrameSize, 496 (mRemaining - pBuffer->frameCount) * mFrameSize); 497 mRemaining -= pBuffer->frameCount; 498 } else if (pBuffer->frameCount == mRemaining) { 499 mRemaining = 0; 500 } else { 501 LOG_ALWAYS_FATAL("Releasing more frames(%zu) than available(%zu)", 502 pBuffer->frameCount, mRemaining); 503 } 504 505 pBuffer->raw = NULL; 506 pBuffer->frameCount = 0; 507 } 508 509 void TimestretchBufferProvider::reset() 510 { 511 mRemaining = 0; 512 } 513 514 status_t TimestretchBufferProvider::setPlaybackRate(const AudioPlaybackRate &playbackRate) 515 { 516 mPlaybackRate = playbackRate; 517 mFallbackFailErrorShown = false; 518 sonicSetSpeed(mSonicStream, mPlaybackRate.mSpeed); 519 //TODO: pitch is ignored for now 520 //TODO: optimize: if parameters are the same, don't do any extra computation. 521 522 mAudioPlaybackRateValid = isAudioPlaybackRateValid(mPlaybackRate); 523 return OK; 524 } 525 526 void TimestretchBufferProvider::processFrames(void *dstBuffer, size_t *dstFrames, 527 const void *srcBuffer, size_t *srcFrames) 528 { 529 ALOGV("processFrames(%zu %zu) remaining(%zu)", *dstFrames, *srcFrames, mRemaining); 530 // Note dstFrames is the required number of frames. 531 532 if (!mAudioPlaybackRateValid) { 533 //fallback mode 534 // Ensure consumption from src is as expected. 535 // TODO: add logic to track "very accurate" consumption related to speed, original sampling 536 // rate, actual frames processed. 537 538 const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed; 539 if (*srcFrames < targetSrc) { // limit dst frames to that possible 540 *dstFrames = *srcFrames / mPlaybackRate.mSpeed; 541 } else if (*srcFrames > targetSrc + 1) { 542 *srcFrames = targetSrc + 1; 543 } 544 if (*dstFrames > 0) { 545 switch(mPlaybackRate.mFallbackMode) { 546 case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT: 547 if (*dstFrames <= *srcFrames) { 548 size_t copySize = mFrameSize * *dstFrames; 549 memcpy(dstBuffer, srcBuffer, copySize); 550 } else { 551 // cyclically repeat the source. 552 for (size_t count = 0; count < *dstFrames; count += *srcFrames) { 553 size_t remaining = min(*srcFrames, *dstFrames - count); 554 memcpy((uint8_t*)dstBuffer + mFrameSize * count, 555 srcBuffer, mFrameSize * remaining); 556 } 557 } 558 break; 559 case AUDIO_TIMESTRETCH_FALLBACK_DEFAULT: 560 case AUDIO_TIMESTRETCH_FALLBACK_MUTE: 561 memset(dstBuffer,0, mFrameSize * *dstFrames); 562 break; 563 case AUDIO_TIMESTRETCH_FALLBACK_FAIL: 564 default: 565 if(!mFallbackFailErrorShown) { 566 ALOGE("invalid parameters in TimestretchBufferProvider fallbackMode:%d", 567 mPlaybackRate.mFallbackMode); 568 mFallbackFailErrorShown = true; 569 } 570 break; 571 } 572 } 573 } else { 574 switch (mFormat) { 575 case AUDIO_FORMAT_PCM_FLOAT: 576 if (sonicWriteFloatToStream(mSonicStream, (float*)srcBuffer, *srcFrames) != 1) { 577 ALOGE("sonicWriteFloatToStream cannot realloc"); 578 *srcFrames = 0; // cannot consume all of srcBuffer 579 } 580 *dstFrames = sonicReadFloatFromStream(mSonicStream, (float*)dstBuffer, *dstFrames); 581 break; 582 case AUDIO_FORMAT_PCM_16_BIT: 583 if (sonicWriteShortToStream(mSonicStream, (short*)srcBuffer, *srcFrames) != 1) { 584 ALOGE("sonicWriteShortToStream cannot realloc"); 585 *srcFrames = 0; // cannot consume all of srcBuffer 586 } 587 *dstFrames = sonicReadShortFromStream(mSonicStream, (short*)dstBuffer, *dstFrames); 588 break; 589 default: 590 // could also be caught on construction 591 LOG_ALWAYS_FATAL("invalid format %#x for TimestretchBufferProvider", mFormat); 592 } 593 } 594 } 595 // ---------------------------------------------------------------------------- 596 } // namespace android 597