1857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung/* 2857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung * Copyright (C) 2015 The Android Open Source Project 3857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung * 4857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung * Licensed under the Apache License, Version 2.0 (the "License"); 5857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung * you may not use this file except in compliance with the License. 6857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung * You may obtain a copy of the License at 7857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung * 8857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung * http://www.apache.org/licenses/LICENSE-2.0 9857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung * 10857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung * Unless required by applicable law or agreed to in writing, software 11857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung * distributed under the License is distributed on an "AS IS" BASIS, 12857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung * See the License for the specific language governing permissions and 14857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung * limitations under the License. 15857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung */ 16857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 17857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung#define LOG_TAG "BufferProvider" 18857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung//#define LOG_NDEBUG 0 19857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 20857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung#include <audio_effects/effect_downmix.h> 21857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung#include <audio_utils/primitives.h> 22857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung#include <audio_utils/format.h> 23c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung#include <media/AudioResamplerPublic.h> 24857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung#include <media/EffectsFactoryApi.h> 25c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 26857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung#include <utils/Log.h> 27857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 28857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung#include "Configuration.h" 29857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung#include "BufferProviders.h" 30857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 31857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung#ifndef ARRAY_SIZE 32857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) 33857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung#endif 34857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 35857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hungnamespace android { 36857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 37857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung// ---------------------------------------------------------------------------- 38857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 39857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hungtemplate <typename T> 40857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hungstatic inline T min(const T& a, const T& b) 41857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung{ 42857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung return a < b ? a : b; 43857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung} 44857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 45857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy HungCopyBufferProvider::CopyBufferProvider(size_t inputFrameSize, 46857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung size_t outputFrameSize, size_t bufferFrameCount) : 47857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mInputFrameSize(inputFrameSize), 48857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mOutputFrameSize(outputFrameSize), 49857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mLocalBufferFrameCount(bufferFrameCount), 50857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mLocalBufferData(NULL), 51857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mConsumed(0) 52857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung{ 53857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGV("CopyBufferProvider(%p)(%zu, %zu, %zu)", this, 54857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung inputFrameSize, outputFrameSize, bufferFrameCount); 55857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung LOG_ALWAYS_FATAL_IF(inputFrameSize < outputFrameSize && bufferFrameCount == 0, 56857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung "Requires local buffer if inputFrameSize(%zu) < outputFrameSize(%zu)", 57857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung inputFrameSize, outputFrameSize); 58857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (mLocalBufferFrameCount) { 59857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung (void)posix_memalign(&mLocalBufferData, 32, mLocalBufferFrameCount * mOutputFrameSize); 60857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 61857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mBuffer.frameCount = 0; 62857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung} 63857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 64857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy HungCopyBufferProvider::~CopyBufferProvider() 65857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung{ 66857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGV("~CopyBufferProvider(%p)", this); 67857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (mBuffer.frameCount != 0) { 68857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mTrackBufferProvider->releaseBuffer(&mBuffer); 69857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 70857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung free(mLocalBufferData); 71857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung} 72857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 73d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kastenstatus_t CopyBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer) 74857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung{ 75d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten //ALOGV("CopyBufferProvider(%p)::getNextBuffer(%p (%zu))", 76d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten // this, pBuffer, pBuffer->frameCount); 77857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (mLocalBufferFrameCount == 0) { 78d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten status_t res = mTrackBufferProvider->getNextBuffer(pBuffer); 79857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (res == OK) { 80857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung copyFrames(pBuffer->raw, pBuffer->raw, pBuffer->frameCount); 81857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 82857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung return res; 83857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 84857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (mBuffer.frameCount == 0) { 85857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mBuffer.frameCount = pBuffer->frameCount; 86d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer); 87857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // At one time an upstream buffer provider had 88857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // res == OK and mBuffer.frameCount == 0, doesn't seem to happen now 7/18/2014. 89857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // 90857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // By API spec, if res != OK, then mBuffer.frameCount == 0. 91857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // but there may be improper implementations. 92857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOG_ASSERT(res == OK || mBuffer.frameCount == 0); 93857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe. 94857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung pBuffer->raw = NULL; 95857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung pBuffer->frameCount = 0; 96857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung return res; 97857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 98857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mConsumed = 0; 99857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 100857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOG_ASSERT(mConsumed < mBuffer.frameCount); 101857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung size_t count = min(mLocalBufferFrameCount, mBuffer.frameCount - mConsumed); 102857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung count = min(count, pBuffer->frameCount); 103857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung pBuffer->raw = mLocalBufferData; 104857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung pBuffer->frameCount = count; 105857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung copyFrames(pBuffer->raw, (uint8_t*)mBuffer.raw + mConsumed * mInputFrameSize, 106857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung pBuffer->frameCount); 107857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung return OK; 108857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung} 109857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 110857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hungvoid CopyBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) 111857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung{ 112857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung //ALOGV("CopyBufferProvider(%p)::releaseBuffer(%p(%zu))", 113857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // this, pBuffer, pBuffer->frameCount); 114857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (mLocalBufferFrameCount == 0) { 115857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mTrackBufferProvider->releaseBuffer(pBuffer); 116857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung return; 117857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 118857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount"); 119857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mConsumed += pBuffer->frameCount; // TODO: update for efficiency to reuse existing content 120857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (mConsumed != 0 && mConsumed >= mBuffer.frameCount) { 121857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mTrackBufferProvider->releaseBuffer(&mBuffer); 122857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOG_ASSERT(mBuffer.frameCount == 0); 123857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 124857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung pBuffer->raw = NULL; 125857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung pBuffer->frameCount = 0; 126857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung} 127857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 128857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hungvoid CopyBufferProvider::reset() 129857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung{ 130857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (mBuffer.frameCount != 0) { 131857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mTrackBufferProvider->releaseBuffer(&mBuffer); 132857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 133857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mConsumed = 0; 134857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung} 135857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 136857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy HungDownmixerBufferProvider::DownmixerBufferProvider( 137857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung audio_channel_mask_t inputChannelMask, 138857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung audio_channel_mask_t outputChannelMask, audio_format_t format, 139857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung uint32_t sampleRate, int32_t sessionId, size_t bufferFrameCount) : 140857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung CopyBufferProvider( 141857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask), 142857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask), 143857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung bufferFrameCount) // set bufferFrameCount to 0 to do in-place 144857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung{ 145857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGV("DownmixerBufferProvider(%p)(%#x, %#x, %#x %u %d)", 146857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung this, inputChannelMask, outputChannelMask, format, 147857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung sampleRate, sessionId); 148857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (!sIsMultichannelCapable 149857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung || EffectCreate(&sDwnmFxDesc.uuid, 150857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung sessionId, 151857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung SESSION_ID_INVALID_AND_IGNORED, 152857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung &mDownmixHandle) != 0) { 153857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGE("DownmixerBufferProvider() error creating downmixer effect"); 154857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixHandle = NULL; 155857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung return; 156857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 157857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // channel input configuration will be overridden per-track 158857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixConfig.inputCfg.channels = inputChannelMask; // FIXME: Should be bits 159857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixConfig.outputCfg.channels = outputChannelMask; // FIXME: should be bits 160857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixConfig.inputCfg.format = format; 161857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixConfig.outputCfg.format = format; 162857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixConfig.inputCfg.samplingRate = sampleRate; 163857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixConfig.outputCfg.samplingRate = sampleRate; 164857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; 165857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE; 166857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // input and output buffer provider, and frame count will not be used as the downmix effect 167857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // process() function is called directly (see DownmixerBufferProvider::getNextBuffer()) 168857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixConfig.inputCfg.mask = EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | 169857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE; 170857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixConfig.outputCfg.mask = mDownmixConfig.inputCfg.mask; 171857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 172857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung int cmdStatus; 173857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung uint32_t replySize = sizeof(int); 174857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 175857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // Configure downmixer 176857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung status_t status = (*mDownmixHandle)->command(mDownmixHandle, 177857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung EFFECT_CMD_SET_CONFIG /*cmdCode*/, sizeof(effect_config_t) /*cmdSize*/, 178857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung &mDownmixConfig /*pCmdData*/, 179857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung &replySize, &cmdStatus /*pReplyData*/); 180857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (status != 0 || cmdStatus != 0) { 181857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while configuring downmixer", 182857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung status, cmdStatus); 183857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung EffectRelease(mDownmixHandle); 184857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixHandle = NULL; 185857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung return; 186857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 187857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 188857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // Enable downmixer 189857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung replySize = sizeof(int); 190857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung status = (*mDownmixHandle)->command(mDownmixHandle, 191857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung EFFECT_CMD_ENABLE /*cmdCode*/, 0 /*cmdSize*/, NULL /*pCmdData*/, 192857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung &replySize, &cmdStatus /*pReplyData*/); 193857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (status != 0 || cmdStatus != 0) { 194857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while enabling downmixer", 195857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung status, cmdStatus); 196857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung EffectRelease(mDownmixHandle); 197857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixHandle = NULL; 198857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung return; 199857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 200857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 201857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // Set downmix type 202857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // parameter size rounded for padding on 32bit boundary 203857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung const int psizePadded = ((sizeof(downmix_params_t) - 1)/sizeof(int) + 1) * sizeof(int); 204857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung const int downmixParamSize = 205857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung sizeof(effect_param_t) + psizePadded + sizeof(downmix_type_t); 206857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung effect_param_t * const param = (effect_param_t *) malloc(downmixParamSize); 207857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung param->psize = sizeof(downmix_params_t); 208857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung const downmix_params_t downmixParam = DOWNMIX_PARAM_TYPE; 209857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung memcpy(param->data, &downmixParam, param->psize); 210857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung const downmix_type_t downmixType = DOWNMIX_TYPE_FOLD; 211857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung param->vsize = sizeof(downmix_type_t); 212857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung memcpy(param->data + psizePadded, &downmixType, param->vsize); 213857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung replySize = sizeof(int); 214857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung status = (*mDownmixHandle)->command(mDownmixHandle, 215857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung EFFECT_CMD_SET_PARAM /* cmdCode */, downmixParamSize /* cmdSize */, 216857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung param /*pCmdData*/, &replySize, &cmdStatus /*pReplyData*/); 217857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung free(param); 218857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (status != 0 || cmdStatus != 0) { 219857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while setting downmix type", 220857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung status, cmdStatus); 221857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung EffectRelease(mDownmixHandle); 222857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixHandle = NULL; 223857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung return; 224857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 225857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGV("DownmixerBufferProvider() downmix type set to %d", (int) downmixType); 226857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung} 227857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 228857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy HungDownmixerBufferProvider::~DownmixerBufferProvider() 229857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung{ 230857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGV("~DownmixerBufferProvider (%p)", this); 231857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung EffectRelease(mDownmixHandle); 232857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixHandle = NULL; 233857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung} 234857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 235857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hungvoid DownmixerBufferProvider::copyFrames(void *dst, const void *src, size_t frames) 236857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung{ 237857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixConfig.inputCfg.buffer.frameCount = frames; 238857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixConfig.inputCfg.buffer.raw = const_cast<void *>(src); 239857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixConfig.outputCfg.buffer.frameCount = frames; 240857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mDownmixConfig.outputCfg.buffer.raw = dst; 241857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // may be in-place if src == dst. 242857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung status_t res = (*mDownmixHandle)->process(mDownmixHandle, 243857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung &mDownmixConfig.inputCfg.buffer, &mDownmixConfig.outputCfg.buffer); 244857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGE_IF(res != OK, "DownmixBufferProvider error %d", res); 245857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung} 246857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 247857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung/* call once in a pthread_once handler. */ 248857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung/*static*/ status_t DownmixerBufferProvider::init() 249857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung{ 250857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung // find multichannel downmix effect if we have to play multichannel content 251857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung uint32_t numEffects = 0; 252857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung int ret = EffectQueryNumberEffects(&numEffects); 253857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (ret != 0) { 254857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGE("AudioMixer() error %d querying number of effects", ret); 255857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung return NO_INIT; 256857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 257857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects); 258857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 259857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung for (uint32_t i = 0 ; i < numEffects ; i++) { 260857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (EffectQueryEffect(i, &sDwnmFxDesc) == 0) { 261857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGV("effect %d is called %s", i, sDwnmFxDesc.name); 262857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung if (memcmp(&sDwnmFxDesc.type, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) { 263857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGI("found effect \"%s\" from %s", 264857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung sDwnmFxDesc.name, sDwnmFxDesc.implementor); 265857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung sIsMultichannelCapable = true; 266857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung break; 267857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 268857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 269857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung } 270857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGW_IF(!sIsMultichannelCapable, "unable to find downmix effect"); 271857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung return NO_INIT; 272857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung} 273857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 274857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung/*static*/ bool DownmixerBufferProvider::sIsMultichannelCapable = false; 275857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung/*static*/ effect_descriptor_t DownmixerBufferProvider::sDwnmFxDesc; 276857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 277857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy HungRemixBufferProvider::RemixBufferProvider(audio_channel_mask_t inputChannelMask, 278857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung audio_channel_mask_t outputChannelMask, audio_format_t format, 279857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung size_t bufferFrameCount) : 280857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung CopyBufferProvider( 281857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung audio_bytes_per_sample(format) 282857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung * audio_channel_count_from_out_mask(inputChannelMask), 283857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung audio_bytes_per_sample(format) 284857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung * audio_channel_count_from_out_mask(outputChannelMask), 285857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung bufferFrameCount), 286857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mFormat(format), 287857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mSampleSize(audio_bytes_per_sample(format)), 288857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mInputChannels(audio_channel_count_from_out_mask(inputChannelMask)), 289857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mOutputChannels(audio_channel_count_from_out_mask(outputChannelMask)) 290857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung{ 291857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGV("RemixBufferProvider(%p)(%#x, %#x, %#x) %zu %zu", 292857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung this, format, inputChannelMask, outputChannelMask, 293857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mInputChannels, mOutputChannels); 29418aa27016a94d0fee243637a80fd0741f89e08f2Andy Hung (void) memcpy_by_index_array_initialization_from_channel_mask( 29518aa27016a94d0fee243637a80fd0741f89e08f2Andy Hung mIdxAry, ARRAY_SIZE(mIdxAry), outputChannelMask, inputChannelMask); 296857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung} 297857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 298857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hungvoid RemixBufferProvider::copyFrames(void *dst, const void *src, size_t frames) 299857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung{ 300857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung memcpy_by_index_array(dst, mOutputChannels, 301857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung src, mInputChannels, mIdxAry, mSampleSize, frames); 302857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung} 303857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 304857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy HungReformatBufferProvider::ReformatBufferProvider(int32_t channelCount, 305857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung audio_format_t inputFormat, audio_format_t outputFormat, 306857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung size_t bufferFrameCount) : 307857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung CopyBufferProvider( 308857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung channelCount * audio_bytes_per_sample(inputFormat), 309857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung channelCount * audio_bytes_per_sample(outputFormat), 310857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung bufferFrameCount), 311857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mChannelCount(channelCount), 312857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mInputFormat(inputFormat), 313857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung mOutputFormat(outputFormat) 314857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung{ 315857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung ALOGV("ReformatBufferProvider(%p)(%u, %#x, %#x)", 316857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung this, channelCount, inputFormat, outputFormat); 317857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung} 318857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 319857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hungvoid ReformatBufferProvider::copyFrames(void *dst, const void *src, size_t frames) 320857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung{ 321857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung memcpy_by_audio_format(dst, mOutputFormat, src, mInputFormat, frames * mChannelCount); 322857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung} 323857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung 324c5656cc900aeb4a705e27508dd82c70030a97709Andy HungTimestretchBufferProvider::TimestretchBufferProvider(int32_t channelCount, 3255a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia audio_format_t format, uint32_t sampleRate, const AudioPlaybackRate &playbackRate) : 326c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung mChannelCount(channelCount), 327c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung mFormat(format), 328c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung mSampleRate(sampleRate), 329c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung mFrameSize(channelCount * audio_bytes_per_sample(format)), 330c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung mLocalBufferFrameCount(0), 331c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung mLocalBufferData(NULL), 332f097cae65bfce7200938c5bd89e7e9b61cba78b3Ricardo Garcia mRemaining(0), 3335a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia mSonicStream(sonicCreateStream(sampleRate, mChannelCount)), 3346c7f062d3149d6890daaee64828959ad6f61ea54Ricardo Garcia mFallbackFailErrorShown(false), 3356c7f062d3149d6890daaee64828959ad6f61ea54Ricardo Garcia mAudioPlaybackRateValid(false) 336c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung{ 337f097cae65bfce7200938c5bd89e7e9b61cba78b3Ricardo Garcia LOG_ALWAYS_FATAL_IF(mSonicStream == NULL, 338f097cae65bfce7200938c5bd89e7e9b61cba78b3Ricardo Garcia "TimestretchBufferProvider can't allocate Sonic stream"); 3395a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia 3405a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia setPlaybackRate(playbackRate); 3415a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia ALOGV("TimestretchBufferProvider(%p)(%u, %#x, %u %f %f %d %d)", 3425a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia this, channelCount, format, sampleRate, playbackRate.mSpeed, 3435a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia playbackRate.mPitch, playbackRate.mStretchMode, playbackRate.mFallbackMode); 3445a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia mBuffer.frameCount = 0; 345c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung} 346c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 347c5656cc900aeb4a705e27508dd82c70030a97709Andy HungTimestretchBufferProvider::~TimestretchBufferProvider() 348c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung{ 349c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung ALOGV("~TimestretchBufferProvider(%p)", this); 350f097cae65bfce7200938c5bd89e7e9b61cba78b3Ricardo Garcia sonicDestroyStream(mSonicStream); 351c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung if (mBuffer.frameCount != 0) { 352c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung mTrackBufferProvider->releaseBuffer(&mBuffer); 353c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung } 354c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung free(mLocalBufferData); 355c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung} 356c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 357c5656cc900aeb4a705e27508dd82c70030a97709Andy Hungstatus_t TimestretchBufferProvider::getNextBuffer( 358d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten AudioBufferProvider::Buffer *pBuffer) 359c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung{ 360d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten ALOGV("TimestretchBufferProvider(%p)::getNextBuffer(%p (%zu))", 361d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten this, pBuffer, pBuffer->frameCount); 362c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 363c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung // BYPASS 364d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten //return mTrackBufferProvider->getNextBuffer(pBuffer); 365c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 366c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung // check if previously processed data is sufficient. 367c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung if (pBuffer->frameCount <= mRemaining) { 368c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung ALOGV("previous sufficient"); 369c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung pBuffer->raw = mLocalBufferData; 370c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung return OK; 371c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung } 372c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 373c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung // do we need to resize our buffer? 374c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung if (pBuffer->frameCount > mLocalBufferFrameCount) { 375c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung void *newmem; 376c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung if (posix_memalign(&newmem, 32, pBuffer->frameCount * mFrameSize) == OK) { 377c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung if (mRemaining != 0) { 378c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung memcpy(newmem, mLocalBufferData, mRemaining * mFrameSize); 379c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung } 380c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung free(mLocalBufferData); 381c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung mLocalBufferData = newmem; 382c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung mLocalBufferFrameCount = pBuffer->frameCount; 383c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung } 384c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung } 385c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 386c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung // need to fetch more data 387c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung const size_t outputDesired = pBuffer->frameCount - mRemaining; 3886d62669e2796df93135e58388f75e6780f6a207eAndy Hung size_t dstAvailable; 3896d62669e2796df93135e58388f75e6780f6a207eAndy Hung do { 3906d62669e2796df93135e58388f75e6780f6a207eAndy Hung mBuffer.frameCount = mPlaybackRate.mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL 3916d62669e2796df93135e58388f75e6780f6a207eAndy Hung ? outputDesired : outputDesired * mPlaybackRate.mSpeed + 1; 392c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 393d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer); 394c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 3956d62669e2796df93135e58388f75e6780f6a207eAndy Hung ALOG_ASSERT(res == OK || mBuffer.frameCount == 0); 3966d62669e2796df93135e58388f75e6780f6a207eAndy Hung if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe. 3976d62669e2796df93135e58388f75e6780f6a207eAndy Hung ALOGV("upstream provider cannot provide data"); 3986d62669e2796df93135e58388f75e6780f6a207eAndy Hung if (mRemaining == 0) { 3996d62669e2796df93135e58388f75e6780f6a207eAndy Hung pBuffer->raw = NULL; 4006d62669e2796df93135e58388f75e6780f6a207eAndy Hung pBuffer->frameCount = 0; 4016d62669e2796df93135e58388f75e6780f6a207eAndy Hung return res; 4026d62669e2796df93135e58388f75e6780f6a207eAndy Hung } else { // return partial count 4036d62669e2796df93135e58388f75e6780f6a207eAndy Hung pBuffer->raw = mLocalBufferData; 4046d62669e2796df93135e58388f75e6780f6a207eAndy Hung pBuffer->frameCount = mRemaining; 4056d62669e2796df93135e58388f75e6780f6a207eAndy Hung return OK; 4066d62669e2796df93135e58388f75e6780f6a207eAndy Hung } 407c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung } 408c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 4096d62669e2796df93135e58388f75e6780f6a207eAndy Hung // time-stretch the data 4106d62669e2796df93135e58388f75e6780f6a207eAndy Hung dstAvailable = min(mLocalBufferFrameCount - mRemaining, outputDesired); 4116d62669e2796df93135e58388f75e6780f6a207eAndy Hung size_t srcAvailable = mBuffer.frameCount; 4126d62669e2796df93135e58388f75e6780f6a207eAndy Hung processFrames((uint8_t*)mLocalBufferData + mRemaining * mFrameSize, &dstAvailable, 4136d62669e2796df93135e58388f75e6780f6a207eAndy Hung mBuffer.raw, &srcAvailable); 414c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 4156d62669e2796df93135e58388f75e6780f6a207eAndy Hung // release all data consumed 4166d62669e2796df93135e58388f75e6780f6a207eAndy Hung mBuffer.frameCount = srcAvailable; 4176d62669e2796df93135e58388f75e6780f6a207eAndy Hung mTrackBufferProvider->releaseBuffer(&mBuffer); 4186d62669e2796df93135e58388f75e6780f6a207eAndy Hung } while (dstAvailable == 0); // try until we get output data or upstream provider fails. 419c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 420c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung // update buffer vars with the actual data processed and return with buffer 421c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung mRemaining += dstAvailable; 422c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 423c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung pBuffer->raw = mLocalBufferData; 424c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung pBuffer->frameCount = mRemaining; 425c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 426c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung return OK; 427c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung} 428c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 429c5656cc900aeb4a705e27508dd82c70030a97709Andy Hungvoid TimestretchBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) 430c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung{ 431c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung ALOGV("TimestretchBufferProvider(%p)::releaseBuffer(%p (%zu))", 432c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung this, pBuffer, pBuffer->frameCount); 433c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 434c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung // BYPASS 435c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung //return mTrackBufferProvider->releaseBuffer(pBuffer); 436c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 437c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount"); 438c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung if (pBuffer->frameCount < mRemaining) { 439c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung memcpy(mLocalBufferData, 440c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung (uint8_t*)mLocalBufferData + pBuffer->frameCount * mFrameSize, 441c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung (mRemaining - pBuffer->frameCount) * mFrameSize); 442c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung mRemaining -= pBuffer->frameCount; 443c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung } else if (pBuffer->frameCount == mRemaining) { 444c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung mRemaining = 0; 445c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung } else { 446c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung LOG_ALWAYS_FATAL("Releasing more frames(%zu) than available(%zu)", 447c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung pBuffer->frameCount, mRemaining); 448c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung } 449c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 450c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung pBuffer->raw = NULL; 451c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung pBuffer->frameCount = 0; 452c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung} 453c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 454c5656cc900aeb4a705e27508dd82c70030a97709Andy Hungvoid TimestretchBufferProvider::reset() 455c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung{ 456c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung mRemaining = 0; 457c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung} 458c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 4595a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garciastatus_t TimestretchBufferProvider::setPlaybackRate(const AudioPlaybackRate &playbackRate) 460c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung{ 4615a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia mPlaybackRate = playbackRate; 4625a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia mFallbackFailErrorShown = false; 4635a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia sonicSetSpeed(mSonicStream, mPlaybackRate.mSpeed); 464f097cae65bfce7200938c5bd89e7e9b61cba78b3Ricardo Garcia //TODO: pitch is ignored for now 4655a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia //TODO: optimize: if parameters are the same, don't do any extra computation. 4666c7f062d3149d6890daaee64828959ad6f61ea54Ricardo Garcia 4676c7f062d3149d6890daaee64828959ad6f61ea54Ricardo Garcia mAudioPlaybackRateValid = isAudioPlaybackRateValid(mPlaybackRate); 468c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung return OK; 469c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung} 470c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 471c5656cc900aeb4a705e27508dd82c70030a97709Andy Hungvoid TimestretchBufferProvider::processFrames(void *dstBuffer, size_t *dstFrames, 472c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung const void *srcBuffer, size_t *srcFrames) 473c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung{ 474c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung ALOGV("processFrames(%zu %zu) remaining(%zu)", *dstFrames, *srcFrames, mRemaining); 475c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung // Note dstFrames is the required number of frames. 476c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 477c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung // Ensure consumption from src is as expected. 4785a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia //TODO: add logic to track "very accurate" consumption related to speed, original sampling 4795a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia //rate, actual frames processed. 4805a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed; 481c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung if (*srcFrames < targetSrc) { // limit dst frames to that possible 4825a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia *dstFrames = *srcFrames / mPlaybackRate.mSpeed; 483c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung } else if (*srcFrames > targetSrc + 1) { 484c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung *srcFrames = targetSrc + 1; 485c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung } 486c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung 4876c7f062d3149d6890daaee64828959ad6f61ea54Ricardo Garcia if (!mAudioPlaybackRateValid) { 4885a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia //fallback mode 4895a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia if (*dstFrames > 0) { 4905a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia switch(mPlaybackRate.mFallbackMode) { 4915a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT: 4925a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia if (*dstFrames <= *srcFrames) { 4935a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia size_t copySize = mFrameSize * *dstFrames; 4945a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia memcpy(dstBuffer, srcBuffer, copySize); 4955a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia } else { 4965a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia // cyclically repeat the source. 4975a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia for (size_t count = 0; count < *dstFrames; count += *srcFrames) { 4985a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia size_t remaining = min(*srcFrames, *dstFrames - count); 4995a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia memcpy((uint8_t*)dstBuffer + mFrameSize * count, 5005a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia srcBuffer, mFrameSize * remaining); 5015a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia } 5025a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia } 5035a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia break; 5045a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia case AUDIO_TIMESTRETCH_FALLBACK_DEFAULT: 5055a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia case AUDIO_TIMESTRETCH_FALLBACK_MUTE: 5065a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia memset(dstBuffer,0, mFrameSize * *dstFrames); 5075a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia break; 5085a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia case AUDIO_TIMESTRETCH_FALLBACK_FAIL: 5095a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia default: 5105a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia if(!mFallbackFailErrorShown) { 5115a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia ALOGE("invalid parameters in TimestretchBufferProvider fallbackMode:%d", 5125a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia mPlaybackRate.mFallbackMode); 5135a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia mFallbackFailErrorShown = true; 5145a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia } 5155a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia break; 5165a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia } 517c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung } 5185a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia } else { 5195a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia switch (mFormat) { 5205a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia case AUDIO_FORMAT_PCM_FLOAT: 5215a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia if (sonicWriteFloatToStream(mSonicStream, (float*)srcBuffer, *srcFrames) != 1) { 5225a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia ALOGE("sonicWriteFloatToStream cannot realloc"); 5235a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia *srcFrames = 0; // cannot consume all of srcBuffer 5245a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia } 5255a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia *dstFrames = sonicReadFloatFromStream(mSonicStream, (float*)dstBuffer, *dstFrames); 5265a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia break; 5275a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia case AUDIO_FORMAT_PCM_16_BIT: 5285a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia if (sonicWriteShortToStream(mSonicStream, (short*)srcBuffer, *srcFrames) != 1) { 5295a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia ALOGE("sonicWriteShortToStream cannot realloc"); 5305a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia *srcFrames = 0; // cannot consume all of srcBuffer 5315a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia } 5325a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia *dstFrames = sonicReadShortFromStream(mSonicStream, (short*)dstBuffer, *dstFrames); 5335a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia break; 5345a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia default: 5355a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia // could also be caught on construction 5365a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia LOG_ALWAYS_FATAL("invalid format %#x for TimestretchBufferProvider", mFormat); 537f097cae65bfce7200938c5bd89e7e9b61cba78b3Ricardo Garcia } 538c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung } 539c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung} 540857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung// ---------------------------------------------------------------------------- 541857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung} // namespace android 542