blob: e06a1aaaeeaadd69d41af9e36ca993a78174b5cf [file] [log] [blame]
Andy Hung857d5a22015-03-26 18:46:00 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "BufferProvider"
18//#define LOG_NDEBUG 0
19
Andy Hung857d5a22015-03-26 18:46:00 -070020#include <audio_utils/primitives.h>
21#include <audio_utils/format.h>
Andy Hung068561c2017-01-03 17:09:32 -080022#include <external/sonic/sonic.h>
Mikhail Naganov022b9952017-01-04 16:36:51 -080023#include <media/audiohal/EffectBufferHalInterface.h>
Mikhail Naganova0c91332016-09-19 10:01:12 -070024#include <media/audiohal/EffectHalInterface.h>
25#include <media/audiohal/EffectsFactoryHalInterface.h>
Andy Hungc5656cc2015-03-26 19:04:33 -070026#include <media/AudioResamplerPublic.h>
Andy Hung068561c2017-01-03 17:09:32 -080027#include <media/BufferProviders.h>
Mikhail Naganov9fe94012016-10-14 14:57:40 -070028#include <system/audio_effects/effect_downmix.h>
Andy Hung857d5a22015-03-26 18:46:00 -070029#include <utils/Log.h>
30
Andy Hung857d5a22015-03-26 18:46:00 -070031#ifndef ARRAY_SIZE
32#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
33#endif
34
35namespace android {
36
37// ----------------------------------------------------------------------------
38
39template <typename T>
40static inline T min(const T& a, const T& b)
41{
42 return a < b ? a : b;
43}
44
45CopyBufferProvider::CopyBufferProvider(size_t inputFrameSize,
46 size_t outputFrameSize, size_t bufferFrameCount) :
47 mInputFrameSize(inputFrameSize),
48 mOutputFrameSize(outputFrameSize),
49 mLocalBufferFrameCount(bufferFrameCount),
50 mLocalBufferData(NULL),
51 mConsumed(0)
52{
53 ALOGV("CopyBufferProvider(%p)(%zu, %zu, %zu)", this,
54 inputFrameSize, outputFrameSize, bufferFrameCount);
55 LOG_ALWAYS_FATAL_IF(inputFrameSize < outputFrameSize && bufferFrameCount == 0,
56 "Requires local buffer if inputFrameSize(%zu) < outputFrameSize(%zu)",
57 inputFrameSize, outputFrameSize);
58 if (mLocalBufferFrameCount) {
59 (void)posix_memalign(&mLocalBufferData, 32, mLocalBufferFrameCount * mOutputFrameSize);
60 }
61 mBuffer.frameCount = 0;
62}
63
64CopyBufferProvider::~CopyBufferProvider()
65{
Andy Hung930bbf92018-09-11 18:44:27 -070066 ALOGV("%s(%p) %zu %p %p",
67 __func__, this, mBuffer.frameCount, mTrackBufferProvider, mLocalBufferData);
Andy Hung857d5a22015-03-26 18:46:00 -070068 if (mBuffer.frameCount != 0) {
69 mTrackBufferProvider->releaseBuffer(&mBuffer);
70 }
71 free(mLocalBufferData);
72}
73
Glenn Kastend79072e2016-01-06 08:41:20 -080074status_t CopyBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer)
Andy Hung857d5a22015-03-26 18:46:00 -070075{
Glenn Kastend79072e2016-01-06 08:41:20 -080076 //ALOGV("CopyBufferProvider(%p)::getNextBuffer(%p (%zu))",
77 // this, pBuffer, pBuffer->frameCount);
Andy Hung857d5a22015-03-26 18:46:00 -070078 if (mLocalBufferFrameCount == 0) {
Glenn Kastend79072e2016-01-06 08:41:20 -080079 status_t res = mTrackBufferProvider->getNextBuffer(pBuffer);
Andy Hung857d5a22015-03-26 18:46:00 -070080 if (res == OK) {
81 copyFrames(pBuffer->raw, pBuffer->raw, pBuffer->frameCount);
82 }
83 return res;
84 }
85 if (mBuffer.frameCount == 0) {
86 mBuffer.frameCount = pBuffer->frameCount;
Glenn Kastend79072e2016-01-06 08:41:20 -080087 status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer);
Andy Hung857d5a22015-03-26 18:46:00 -070088 // At one time an upstream buffer provider had
89 // res == OK and mBuffer.frameCount == 0, doesn't seem to happen now 7/18/2014.
90 //
91 // By API spec, if res != OK, then mBuffer.frameCount == 0.
92 // but there may be improper implementations.
93 ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
94 if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
95 pBuffer->raw = NULL;
96 pBuffer->frameCount = 0;
97 return res;
98 }
99 mConsumed = 0;
100 }
101 ALOG_ASSERT(mConsumed < mBuffer.frameCount);
102 size_t count = min(mLocalBufferFrameCount, mBuffer.frameCount - mConsumed);
103 count = min(count, pBuffer->frameCount);
104 pBuffer->raw = mLocalBufferData;
105 pBuffer->frameCount = count;
106 copyFrames(pBuffer->raw, (uint8_t*)mBuffer.raw + mConsumed * mInputFrameSize,
107 pBuffer->frameCount);
108 return OK;
109}
110
111void CopyBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer)
112{
113 //ALOGV("CopyBufferProvider(%p)::releaseBuffer(%p(%zu))",
114 // this, pBuffer, pBuffer->frameCount);
115 if (mLocalBufferFrameCount == 0) {
116 mTrackBufferProvider->releaseBuffer(pBuffer);
117 return;
118 }
119 // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
120 mConsumed += pBuffer->frameCount; // TODO: update for efficiency to reuse existing content
121 if (mConsumed != 0 && mConsumed >= mBuffer.frameCount) {
122 mTrackBufferProvider->releaseBuffer(&mBuffer);
123 ALOG_ASSERT(mBuffer.frameCount == 0);
124 }
125 pBuffer->raw = NULL;
126 pBuffer->frameCount = 0;
127}
128
129void CopyBufferProvider::reset()
130{
131 if (mBuffer.frameCount != 0) {
132 mTrackBufferProvider->releaseBuffer(&mBuffer);
133 }
134 mConsumed = 0;
135}
136
Andy Hung930bbf92018-09-11 18:44:27 -0700137void CopyBufferProvider::setBufferProvider(AudioBufferProvider *p) {
138 ALOGV("%s(%p): mTrackBufferProvider:%p mBuffer.frameCount:%zu",
139 __func__, p, mTrackBufferProvider, mBuffer.frameCount);
140 if (mTrackBufferProvider == p) {
141 return;
142 }
143 mBuffer.frameCount = 0;
144 PassthruBufferProvider::setBufferProvider(p);
145}
146
Andy Hung857d5a22015-03-26 18:46:00 -0700147DownmixerBufferProvider::DownmixerBufferProvider(
148 audio_channel_mask_t inputChannelMask,
149 audio_channel_mask_t outputChannelMask, audio_format_t format,
150 uint32_t sampleRate, int32_t sessionId, size_t bufferFrameCount) :
151 CopyBufferProvider(
152 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask),
153 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask),
154 bufferFrameCount) // set bufferFrameCount to 0 to do in-place
155{
Mikhail Naganov66916c22017-01-24 17:46:33 -0800156 ALOGV("DownmixerBufferProvider(%p)(%#x, %#x, %#x %u %d %d)",
Andy Hung857d5a22015-03-26 18:46:00 -0700157 this, inputChannelMask, outputChannelMask, format,
Mikhail Naganov66916c22017-01-24 17:46:33 -0800158 sampleRate, sessionId, (int)bufferFrameCount);
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700159 if (!sIsMultichannelCapable) {
160 ALOGE("DownmixerBufferProvider() error: not multichannel capable");
161 return;
162 }
163 mEffectsFactory = EffectsFactoryHalInterface::create();
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700164 if (mEffectsFactory == 0) {
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700165 ALOGE("DownmixerBufferProvider() error: could not obtain the effects factory");
166 return;
167 }
168 if (mEffectsFactory->createEffect(&sDwnmFxDesc.uuid,
169 sessionId,
170 SESSION_ID_INVALID_AND_IGNORED,
171 &mDownmixInterface) != 0) {
Andy Hung857d5a22015-03-26 18:46:00 -0700172 ALOGE("DownmixerBufferProvider() error creating downmixer effect");
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700173 mDownmixInterface.clear();
174 mEffectsFactory.clear();
Andy Hung857d5a22015-03-26 18:46:00 -0700175 return;
176 }
177 // channel input configuration will be overridden per-track
178 mDownmixConfig.inputCfg.channels = inputChannelMask; // FIXME: Should be bits
179 mDownmixConfig.outputCfg.channels = outputChannelMask; // FIXME: should be bits
180 mDownmixConfig.inputCfg.format = format;
181 mDownmixConfig.outputCfg.format = format;
182 mDownmixConfig.inputCfg.samplingRate = sampleRate;
183 mDownmixConfig.outputCfg.samplingRate = sampleRate;
184 mDownmixConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
185 mDownmixConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
186 // input and output buffer provider, and frame count will not be used as the downmix effect
187 // process() function is called directly (see DownmixerBufferProvider::getNextBuffer())
188 mDownmixConfig.inputCfg.mask = EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS |
189 EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE;
190 mDownmixConfig.outputCfg.mask = mDownmixConfig.inputCfg.mask;
191
Mikhail Naganov66916c22017-01-24 17:46:33 -0800192 mInFrameSize =
193 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask);
194 mOutFrameSize =
195 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800196 status_t status;
Kevin Rocard7588ff42018-01-08 11:11:30 -0800197 status = mEffectsFactory->mirrorBuffer(
Mikhail Naganov66916c22017-01-24 17:46:33 -0800198 nullptr, mInFrameSize * bufferFrameCount, &mInBuffer);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800199 if (status != 0) {
200 ALOGE("DownmixerBufferProvider() error %d while creating input buffer", status);
201 mDownmixInterface.clear();
202 mEffectsFactory.clear();
203 return;
204 }
Kevin Rocard7588ff42018-01-08 11:11:30 -0800205 status = mEffectsFactory->mirrorBuffer(
Mikhail Naganov66916c22017-01-24 17:46:33 -0800206 nullptr, mOutFrameSize * bufferFrameCount, &mOutBuffer);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800207 if (status != 0) {
208 ALOGE("DownmixerBufferProvider() error %d while creating output buffer", status);
209 mInBuffer.clear();
210 mDownmixInterface.clear();
211 mEffectsFactory.clear();
212 return;
213 }
Mikhail Naganov2f607552017-01-11 16:09:03 -0800214 mDownmixInterface->setInBuffer(mInBuffer);
215 mDownmixInterface->setOutBuffer(mOutBuffer);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800216
Andy Hung857d5a22015-03-26 18:46:00 -0700217 int cmdStatus;
218 uint32_t replySize = sizeof(int);
219
220 // Configure downmixer
Mikhail Naganov022b9952017-01-04 16:36:51 -0800221 status = mDownmixInterface->command(
Andy Hung857d5a22015-03-26 18:46:00 -0700222 EFFECT_CMD_SET_CONFIG /*cmdCode*/, sizeof(effect_config_t) /*cmdSize*/,
223 &mDownmixConfig /*pCmdData*/,
224 &replySize, &cmdStatus /*pReplyData*/);
225 if (status != 0 || cmdStatus != 0) {
226 ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while configuring downmixer",
227 status, cmdStatus);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800228 mOutBuffer.clear();
229 mInBuffer.clear();
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700230 mDownmixInterface.clear();
231 mEffectsFactory.clear();
Andy Hung857d5a22015-03-26 18:46:00 -0700232 return;
233 }
234
235 // Enable downmixer
236 replySize = sizeof(int);
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700237 status = mDownmixInterface->command(
Andy Hung857d5a22015-03-26 18:46:00 -0700238 EFFECT_CMD_ENABLE /*cmdCode*/, 0 /*cmdSize*/, NULL /*pCmdData*/,
239 &replySize, &cmdStatus /*pReplyData*/);
240 if (status != 0 || cmdStatus != 0) {
241 ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while enabling downmixer",
242 status, cmdStatus);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800243 mOutBuffer.clear();
244 mInBuffer.clear();
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700245 mDownmixInterface.clear();
246 mEffectsFactory.clear();
Andy Hung857d5a22015-03-26 18:46:00 -0700247 return;
248 }
249
250 // Set downmix type
251 // parameter size rounded for padding on 32bit boundary
252 const int psizePadded = ((sizeof(downmix_params_t) - 1)/sizeof(int) + 1) * sizeof(int);
253 const int downmixParamSize =
254 sizeof(effect_param_t) + psizePadded + sizeof(downmix_type_t);
255 effect_param_t * const param = (effect_param_t *) malloc(downmixParamSize);
256 param->psize = sizeof(downmix_params_t);
257 const downmix_params_t downmixParam = DOWNMIX_PARAM_TYPE;
258 memcpy(param->data, &downmixParam, param->psize);
259 const downmix_type_t downmixType = DOWNMIX_TYPE_FOLD;
260 param->vsize = sizeof(downmix_type_t);
261 memcpy(param->data + psizePadded, &downmixType, param->vsize);
262 replySize = sizeof(int);
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700263 status = mDownmixInterface->command(
Andy Hung857d5a22015-03-26 18:46:00 -0700264 EFFECT_CMD_SET_PARAM /* cmdCode */, downmixParamSize /* cmdSize */,
265 param /*pCmdData*/, &replySize, &cmdStatus /*pReplyData*/);
266 free(param);
267 if (status != 0 || cmdStatus != 0) {
268 ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while setting downmix type",
269 status, cmdStatus);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800270 mOutBuffer.clear();
271 mInBuffer.clear();
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700272 mDownmixInterface.clear();
273 mEffectsFactory.clear();
Andy Hung857d5a22015-03-26 18:46:00 -0700274 return;
275 }
276 ALOGV("DownmixerBufferProvider() downmix type set to %d", (int) downmixType);
277}
278
279DownmixerBufferProvider::~DownmixerBufferProvider()
280{
281 ALOGV("~DownmixerBufferProvider (%p)", this);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800282 if (mDownmixInterface != 0) {
283 mDownmixInterface->close();
284 }
Andy Hung857d5a22015-03-26 18:46:00 -0700285}
286
287void DownmixerBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
288{
Mikhail Naganov022b9952017-01-04 16:36:51 -0800289 mInBuffer->setExternalData(const_cast<void*>(src));
290 mInBuffer->setFrameCount(frames);
Mikhail Naganov66916c22017-01-24 17:46:33 -0800291 mInBuffer->update(mInFrameSize * frames);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800292 mOutBuffer->setFrameCount(frames);
Mikhail Naganov66916c22017-01-24 17:46:33 -0800293 mOutBuffer->setExternalData(dst);
294 if (dst != src) {
295 // Downmix may be accumulating, need to populate the output buffer
296 // with the dst data.
297 mOutBuffer->update(mOutFrameSize * frames);
298 }
Andy Hung857d5a22015-03-26 18:46:00 -0700299 // may be in-place if src == dst.
Mikhail Naganov022b9952017-01-04 16:36:51 -0800300 status_t res = mDownmixInterface->process();
301 if (res == OK) {
Mikhail Naganov66916c22017-01-24 17:46:33 -0800302 mOutBuffer->commit(mOutFrameSize * frames);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800303 } else {
304 ALOGE("DownmixBufferProvider error %d", res);
305 }
Andy Hung857d5a22015-03-26 18:46:00 -0700306}
307
308/* call once in a pthread_once handler. */
309/*static*/ status_t DownmixerBufferProvider::init()
310{
311 // find multichannel downmix effect if we have to play multichannel content
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700312 sp<EffectsFactoryHalInterface> effectsFactory = EffectsFactoryHalInterface::create();
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700313 if (effectsFactory == 0) {
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700314 ALOGE("AudioMixer() error: could not obtain the effects factory");
315 return NO_INIT;
316 }
Andy Hung857d5a22015-03-26 18:46:00 -0700317 uint32_t numEffects = 0;
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700318 int ret = effectsFactory->queryNumberEffects(&numEffects);
Andy Hung857d5a22015-03-26 18:46:00 -0700319 if (ret != 0) {
320 ALOGE("AudioMixer() error %d querying number of effects", ret);
321 return NO_INIT;
322 }
323 ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
324
325 for (uint32_t i = 0 ; i < numEffects ; i++) {
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700326 if (effectsFactory->getDescriptor(i, &sDwnmFxDesc) == 0) {
Andy Hung857d5a22015-03-26 18:46:00 -0700327 ALOGV("effect %d is called %s", i, sDwnmFxDesc.name);
328 if (memcmp(&sDwnmFxDesc.type, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) {
329 ALOGI("found effect \"%s\" from %s",
330 sDwnmFxDesc.name, sDwnmFxDesc.implementor);
331 sIsMultichannelCapable = true;
332 break;
333 }
334 }
335 }
336 ALOGW_IF(!sIsMultichannelCapable, "unable to find downmix effect");
337 return NO_INIT;
338}
339
340/*static*/ bool DownmixerBufferProvider::sIsMultichannelCapable = false;
341/*static*/ effect_descriptor_t DownmixerBufferProvider::sDwnmFxDesc;
342
343RemixBufferProvider::RemixBufferProvider(audio_channel_mask_t inputChannelMask,
344 audio_channel_mask_t outputChannelMask, audio_format_t format,
345 size_t bufferFrameCount) :
346 CopyBufferProvider(
347 audio_bytes_per_sample(format)
348 * audio_channel_count_from_out_mask(inputChannelMask),
349 audio_bytes_per_sample(format)
350 * audio_channel_count_from_out_mask(outputChannelMask),
351 bufferFrameCount),
352 mFormat(format),
353 mSampleSize(audio_bytes_per_sample(format)),
354 mInputChannels(audio_channel_count_from_out_mask(inputChannelMask)),
355 mOutputChannels(audio_channel_count_from_out_mask(outputChannelMask))
356{
357 ALOGV("RemixBufferProvider(%p)(%#x, %#x, %#x) %zu %zu",
358 this, format, inputChannelMask, outputChannelMask,
359 mInputChannels, mOutputChannels);
Andy Hung18aa2702015-05-05 23:48:38 -0700360 (void) memcpy_by_index_array_initialization_from_channel_mask(
361 mIdxAry, ARRAY_SIZE(mIdxAry), outputChannelMask, inputChannelMask);
Andy Hung857d5a22015-03-26 18:46:00 -0700362}
363
364void RemixBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
365{
366 memcpy_by_index_array(dst, mOutputChannels,
367 src, mInputChannels, mIdxAry, mSampleSize, frames);
368}
369
370ReformatBufferProvider::ReformatBufferProvider(int32_t channelCount,
371 audio_format_t inputFormat, audio_format_t outputFormat,
372 size_t bufferFrameCount) :
373 CopyBufferProvider(
374 channelCount * audio_bytes_per_sample(inputFormat),
375 channelCount * audio_bytes_per_sample(outputFormat),
376 bufferFrameCount),
377 mChannelCount(channelCount),
378 mInputFormat(inputFormat),
379 mOutputFormat(outputFormat)
380{
381 ALOGV("ReformatBufferProvider(%p)(%u, %#x, %#x)",
382 this, channelCount, inputFormat, outputFormat);
383}
384
385void ReformatBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
386{
387 memcpy_by_audio_format(dst, mOutputFormat, src, mInputFormat, frames * mChannelCount);
388}
389
Kevin Rocarde053bfa2017-11-09 22:07:34 -0800390ClampFloatBufferProvider::ClampFloatBufferProvider(int32_t channelCount, size_t bufferFrameCount) :
391 CopyBufferProvider(
392 channelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT),
393 channelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT),
394 bufferFrameCount),
395 mChannelCount(channelCount)
396{
397 ALOGV("ClampFloatBufferProvider(%p)(%u)", this, channelCount);
398}
399
400void ClampFloatBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
401{
402 memcpy_to_float_from_float_with_clamping((float*)dst, (const float*)src,
403 frames * mChannelCount,
404 FLOAT_NOMINAL_RANGE_HEADROOM);
405}
406
Andy Hungc5656cc2015-03-26 19:04:33 -0700407TimestretchBufferProvider::TimestretchBufferProvider(int32_t channelCount,
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700408 audio_format_t format, uint32_t sampleRate, const AudioPlaybackRate &playbackRate) :
Andy Hungc5656cc2015-03-26 19:04:33 -0700409 mChannelCount(channelCount),
410 mFormat(format),
411 mSampleRate(sampleRate),
412 mFrameSize(channelCount * audio_bytes_per_sample(format)),
Andy Hungc5656cc2015-03-26 19:04:33 -0700413 mLocalBufferFrameCount(0),
414 mLocalBufferData(NULL),
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700415 mRemaining(0),
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700416 mSonicStream(sonicCreateStream(sampleRate, mChannelCount)),
Ricardo Garcia6c7f0622015-04-30 18:39:16 -0700417 mFallbackFailErrorShown(false),
418 mAudioPlaybackRateValid(false)
Andy Hungc5656cc2015-03-26 19:04:33 -0700419{
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700420 LOG_ALWAYS_FATAL_IF(mSonicStream == NULL,
421 "TimestretchBufferProvider can't allocate Sonic stream");
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700422
423 setPlaybackRate(playbackRate);
424 ALOGV("TimestretchBufferProvider(%p)(%u, %#x, %u %f %f %d %d)",
425 this, channelCount, format, sampleRate, playbackRate.mSpeed,
426 playbackRate.mPitch, playbackRate.mStretchMode, playbackRate.mFallbackMode);
427 mBuffer.frameCount = 0;
Andy Hungc5656cc2015-03-26 19:04:33 -0700428}
429
430TimestretchBufferProvider::~TimestretchBufferProvider()
431{
432 ALOGV("~TimestretchBufferProvider(%p)", this);
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700433 sonicDestroyStream(mSonicStream);
Andy Hungc5656cc2015-03-26 19:04:33 -0700434 if (mBuffer.frameCount != 0) {
435 mTrackBufferProvider->releaseBuffer(&mBuffer);
436 }
437 free(mLocalBufferData);
438}
439
440status_t TimestretchBufferProvider::getNextBuffer(
Glenn Kastend79072e2016-01-06 08:41:20 -0800441 AudioBufferProvider::Buffer *pBuffer)
Andy Hungc5656cc2015-03-26 19:04:33 -0700442{
Glenn Kastend79072e2016-01-06 08:41:20 -0800443 ALOGV("TimestretchBufferProvider(%p)::getNextBuffer(%p (%zu))",
444 this, pBuffer, pBuffer->frameCount);
Andy Hungc5656cc2015-03-26 19:04:33 -0700445
446 // BYPASS
Glenn Kastend79072e2016-01-06 08:41:20 -0800447 //return mTrackBufferProvider->getNextBuffer(pBuffer);
Andy Hungc5656cc2015-03-26 19:04:33 -0700448
449 // check if previously processed data is sufficient.
450 if (pBuffer->frameCount <= mRemaining) {
451 ALOGV("previous sufficient");
452 pBuffer->raw = mLocalBufferData;
453 return OK;
454 }
455
456 // do we need to resize our buffer?
457 if (pBuffer->frameCount > mLocalBufferFrameCount) {
458 void *newmem;
459 if (posix_memalign(&newmem, 32, pBuffer->frameCount * mFrameSize) == OK) {
460 if (mRemaining != 0) {
461 memcpy(newmem, mLocalBufferData, mRemaining * mFrameSize);
462 }
463 free(mLocalBufferData);
464 mLocalBufferData = newmem;
465 mLocalBufferFrameCount = pBuffer->frameCount;
466 }
467 }
468
469 // need to fetch more data
470 const size_t outputDesired = pBuffer->frameCount - mRemaining;
Andy Hung6d626692015-08-21 12:53:46 -0700471 size_t dstAvailable;
472 do {
473 mBuffer.frameCount = mPlaybackRate.mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL
474 ? outputDesired : outputDesired * mPlaybackRate.mSpeed + 1;
Andy Hungc5656cc2015-03-26 19:04:33 -0700475
Glenn Kastend79072e2016-01-06 08:41:20 -0800476 status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer);
Andy Hungc5656cc2015-03-26 19:04:33 -0700477
Andy Hung6d626692015-08-21 12:53:46 -0700478 ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
479 if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
480 ALOGV("upstream provider cannot provide data");
481 if (mRemaining == 0) {
482 pBuffer->raw = NULL;
483 pBuffer->frameCount = 0;
484 return res;
485 } else { // return partial count
486 pBuffer->raw = mLocalBufferData;
487 pBuffer->frameCount = mRemaining;
488 return OK;
489 }
Andy Hungc5656cc2015-03-26 19:04:33 -0700490 }
Andy Hungc5656cc2015-03-26 19:04:33 -0700491
Andy Hung6d626692015-08-21 12:53:46 -0700492 // time-stretch the data
493 dstAvailable = min(mLocalBufferFrameCount - mRemaining, outputDesired);
494 size_t srcAvailable = mBuffer.frameCount;
495 processFrames((uint8_t*)mLocalBufferData + mRemaining * mFrameSize, &dstAvailable,
496 mBuffer.raw, &srcAvailable);
Andy Hungc5656cc2015-03-26 19:04:33 -0700497
Andy Hung6d626692015-08-21 12:53:46 -0700498 // release all data consumed
499 mBuffer.frameCount = srcAvailable;
500 mTrackBufferProvider->releaseBuffer(&mBuffer);
501 } while (dstAvailable == 0); // try until we get output data or upstream provider fails.
Andy Hungc5656cc2015-03-26 19:04:33 -0700502
503 // update buffer vars with the actual data processed and return with buffer
504 mRemaining += dstAvailable;
505
506 pBuffer->raw = mLocalBufferData;
507 pBuffer->frameCount = mRemaining;
508
509 return OK;
510}
511
512void TimestretchBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer)
513{
514 ALOGV("TimestretchBufferProvider(%p)::releaseBuffer(%p (%zu))",
515 this, pBuffer, pBuffer->frameCount);
516
517 // BYPASS
518 //return mTrackBufferProvider->releaseBuffer(pBuffer);
519
520 // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
521 if (pBuffer->frameCount < mRemaining) {
522 memcpy(mLocalBufferData,
523 (uint8_t*)mLocalBufferData + pBuffer->frameCount * mFrameSize,
524 (mRemaining - pBuffer->frameCount) * mFrameSize);
525 mRemaining -= pBuffer->frameCount;
526 } else if (pBuffer->frameCount == mRemaining) {
527 mRemaining = 0;
528 } else {
529 LOG_ALWAYS_FATAL("Releasing more frames(%zu) than available(%zu)",
530 pBuffer->frameCount, mRemaining);
531 }
532
533 pBuffer->raw = NULL;
534 pBuffer->frameCount = 0;
535}
536
537void TimestretchBufferProvider::reset()
538{
539 mRemaining = 0;
540}
541
Andy Hung930bbf92018-09-11 18:44:27 -0700542void TimestretchBufferProvider::setBufferProvider(AudioBufferProvider *p) {
543 ALOGV("%s(%p): mTrackBufferProvider:%p mBuffer.frameCount:%zu",
544 __func__, p, mTrackBufferProvider, mBuffer.frameCount);
545 if (mTrackBufferProvider == p) {
546 return;
547 }
548 mBuffer.frameCount = 0;
549 PassthruBufferProvider::setBufferProvider(p);
550}
551
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700552status_t TimestretchBufferProvider::setPlaybackRate(const AudioPlaybackRate &playbackRate)
Andy Hungc5656cc2015-03-26 19:04:33 -0700553{
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700554 mPlaybackRate = playbackRate;
555 mFallbackFailErrorShown = false;
556 sonicSetSpeed(mSonicStream, mPlaybackRate.mSpeed);
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700557 //TODO: pitch is ignored for now
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700558 //TODO: optimize: if parameters are the same, don't do any extra computation.
Ricardo Garcia6c7f0622015-04-30 18:39:16 -0700559
560 mAudioPlaybackRateValid = isAudioPlaybackRateValid(mPlaybackRate);
Andy Hungc5656cc2015-03-26 19:04:33 -0700561 return OK;
562}
563
564void TimestretchBufferProvider::processFrames(void *dstBuffer, size_t *dstFrames,
565 const void *srcBuffer, size_t *srcFrames)
566{
567 ALOGV("processFrames(%zu %zu) remaining(%zu)", *dstFrames, *srcFrames, mRemaining);
568 // Note dstFrames is the required number of frames.
569
Ricardo Garcia6c7f0622015-04-30 18:39:16 -0700570 if (!mAudioPlaybackRateValid) {
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700571 //fallback mode
Andy Hungcf8d2c82016-08-10 16:02:01 -0700572 // Ensure consumption from src is as expected.
573 // TODO: add logic to track "very accurate" consumption related to speed, original sampling
574 // rate, actual frames processed.
575
576 const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
577 if (*srcFrames < targetSrc) { // limit dst frames to that possible
578 *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
579 } else if (*srcFrames > targetSrc + 1) {
580 *srcFrames = targetSrc + 1;
581 }
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700582 if (*dstFrames > 0) {
583 switch(mPlaybackRate.mFallbackMode) {
584 case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT:
585 if (*dstFrames <= *srcFrames) {
586 size_t copySize = mFrameSize * *dstFrames;
587 memcpy(dstBuffer, srcBuffer, copySize);
588 } else {
589 // cyclically repeat the source.
590 for (size_t count = 0; count < *dstFrames; count += *srcFrames) {
591 size_t remaining = min(*srcFrames, *dstFrames - count);
592 memcpy((uint8_t*)dstBuffer + mFrameSize * count,
593 srcBuffer, mFrameSize * remaining);
594 }
595 }
596 break;
597 case AUDIO_TIMESTRETCH_FALLBACK_DEFAULT:
598 case AUDIO_TIMESTRETCH_FALLBACK_MUTE:
599 memset(dstBuffer,0, mFrameSize * *dstFrames);
600 break;
601 case AUDIO_TIMESTRETCH_FALLBACK_FAIL:
602 default:
603 if(!mFallbackFailErrorShown) {
604 ALOGE("invalid parameters in TimestretchBufferProvider fallbackMode:%d",
605 mPlaybackRate.mFallbackMode);
606 mFallbackFailErrorShown = true;
607 }
608 break;
609 }
Andy Hungc5656cc2015-03-26 19:04:33 -0700610 }
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700611 } else {
612 switch (mFormat) {
613 case AUDIO_FORMAT_PCM_FLOAT:
614 if (sonicWriteFloatToStream(mSonicStream, (float*)srcBuffer, *srcFrames) != 1) {
615 ALOGE("sonicWriteFloatToStream cannot realloc");
616 *srcFrames = 0; // cannot consume all of srcBuffer
617 }
618 *dstFrames = sonicReadFloatFromStream(mSonicStream, (float*)dstBuffer, *dstFrames);
619 break;
620 case AUDIO_FORMAT_PCM_16_BIT:
621 if (sonicWriteShortToStream(mSonicStream, (short*)srcBuffer, *srcFrames) != 1) {
622 ALOGE("sonicWriteShortToStream cannot realloc");
623 *srcFrames = 0; // cannot consume all of srcBuffer
624 }
625 *dstFrames = sonicReadShortFromStream(mSonicStream, (short*)dstBuffer, *dstFrames);
626 break;
627 default:
628 // could also be caught on construction
629 LOG_ALWAYS_FATAL("invalid format %#x for TimestretchBufferProvider", mFormat);
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700630 }
Andy Hungc5656cc2015-03-26 19:04:33 -0700631 }
632}
Andy Hung857d5a22015-03-26 18:46:00 -0700633// ----------------------------------------------------------------------------
634} // namespace android