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