blob: 2d9e1cb16b87d227635b6a232d5c466b88b36cbc [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{
66 ALOGV("~CopyBufferProvider(%p)", this);
67 if (mBuffer.frameCount != 0) {
68 mTrackBufferProvider->releaseBuffer(&mBuffer);
69 }
70 free(mLocalBufferData);
71}
72
Glenn Kastend79072e2016-01-06 08:41:20 -080073status_t CopyBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer)
Andy Hung857d5a22015-03-26 18:46:00 -070074{
Glenn Kastend79072e2016-01-06 08:41:20 -080075 //ALOGV("CopyBufferProvider(%p)::getNextBuffer(%p (%zu))",
76 // this, pBuffer, pBuffer->frameCount);
Andy Hung857d5a22015-03-26 18:46:00 -070077 if (mLocalBufferFrameCount == 0) {
Glenn Kastend79072e2016-01-06 08:41:20 -080078 status_t res = mTrackBufferProvider->getNextBuffer(pBuffer);
Andy Hung857d5a22015-03-26 18:46:00 -070079 if (res == OK) {
80 copyFrames(pBuffer->raw, pBuffer->raw, pBuffer->frameCount);
81 }
82 return res;
83 }
84 if (mBuffer.frameCount == 0) {
85 mBuffer.frameCount = pBuffer->frameCount;
Glenn Kastend79072e2016-01-06 08:41:20 -080086 status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer);
Andy Hung857d5a22015-03-26 18:46:00 -070087 // At one time an upstream buffer provider had
88 // res == OK and mBuffer.frameCount == 0, doesn't seem to happen now 7/18/2014.
89 //
90 // By API spec, if res != OK, then mBuffer.frameCount == 0.
91 // but there may be improper implementations.
92 ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
93 if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
94 pBuffer->raw = NULL;
95 pBuffer->frameCount = 0;
96 return res;
97 }
98 mConsumed = 0;
99 }
100 ALOG_ASSERT(mConsumed < mBuffer.frameCount);
101 size_t count = min(mLocalBufferFrameCount, mBuffer.frameCount - mConsumed);
102 count = min(count, pBuffer->frameCount);
103 pBuffer->raw = mLocalBufferData;
104 pBuffer->frameCount = count;
105 copyFrames(pBuffer->raw, (uint8_t*)mBuffer.raw + mConsumed * mInputFrameSize,
106 pBuffer->frameCount);
107 return OK;
108}
109
110void CopyBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer)
111{
112 //ALOGV("CopyBufferProvider(%p)::releaseBuffer(%p(%zu))",
113 // this, pBuffer, pBuffer->frameCount);
114 if (mLocalBufferFrameCount == 0) {
115 mTrackBufferProvider->releaseBuffer(pBuffer);
116 return;
117 }
118 // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
119 mConsumed += pBuffer->frameCount; // TODO: update for efficiency to reuse existing content
120 if (mConsumed != 0 && mConsumed >= mBuffer.frameCount) {
121 mTrackBufferProvider->releaseBuffer(&mBuffer);
122 ALOG_ASSERT(mBuffer.frameCount == 0);
123 }
124 pBuffer->raw = NULL;
125 pBuffer->frameCount = 0;
126}
127
128void CopyBufferProvider::reset()
129{
130 if (mBuffer.frameCount != 0) {
131 mTrackBufferProvider->releaseBuffer(&mBuffer);
132 }
133 mConsumed = 0;
134}
135
136DownmixerBufferProvider::DownmixerBufferProvider(
137 audio_channel_mask_t inputChannelMask,
138 audio_channel_mask_t outputChannelMask, audio_format_t format,
139 uint32_t sampleRate, int32_t sessionId, size_t bufferFrameCount) :
140 CopyBufferProvider(
141 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask),
142 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask),
143 bufferFrameCount) // set bufferFrameCount to 0 to do in-place
144{
Mikhail Naganov66916c22017-01-24 17:46:33 -0800145 ALOGV("DownmixerBufferProvider(%p)(%#x, %#x, %#x %u %d %d)",
Andy Hung857d5a22015-03-26 18:46:00 -0700146 this, inputChannelMask, outputChannelMask, format,
Mikhail Naganov66916c22017-01-24 17:46:33 -0800147 sampleRate, sessionId, (int)bufferFrameCount);
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700148 if (!sIsMultichannelCapable) {
149 ALOGE("DownmixerBufferProvider() error: not multichannel capable");
150 return;
151 }
152 mEffectsFactory = EffectsFactoryHalInterface::create();
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700153 if (mEffectsFactory == 0) {
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700154 ALOGE("DownmixerBufferProvider() error: could not obtain the effects factory");
155 return;
156 }
157 if (mEffectsFactory->createEffect(&sDwnmFxDesc.uuid,
158 sessionId,
159 SESSION_ID_INVALID_AND_IGNORED,
160 &mDownmixInterface) != 0) {
Andy Hung857d5a22015-03-26 18:46:00 -0700161 ALOGE("DownmixerBufferProvider() error creating downmixer effect");
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700162 mDownmixInterface.clear();
163 mEffectsFactory.clear();
Andy Hung857d5a22015-03-26 18:46:00 -0700164 return;
165 }
166 // channel input configuration will be overridden per-track
167 mDownmixConfig.inputCfg.channels = inputChannelMask; // FIXME: Should be bits
168 mDownmixConfig.outputCfg.channels = outputChannelMask; // FIXME: should be bits
169 mDownmixConfig.inputCfg.format = format;
170 mDownmixConfig.outputCfg.format = format;
171 mDownmixConfig.inputCfg.samplingRate = sampleRate;
172 mDownmixConfig.outputCfg.samplingRate = sampleRate;
173 mDownmixConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
174 mDownmixConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
175 // input and output buffer provider, and frame count will not be used as the downmix effect
176 // process() function is called directly (see DownmixerBufferProvider::getNextBuffer())
177 mDownmixConfig.inputCfg.mask = EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS |
178 EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE;
179 mDownmixConfig.outputCfg.mask = mDownmixConfig.inputCfg.mask;
180
Mikhail Naganov66916c22017-01-24 17:46:33 -0800181 mInFrameSize =
182 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask);
183 mOutFrameSize =
184 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800185 status_t status;
Kevin Rocard7588ff42018-01-08 11:11:30 -0800186 status = mEffectsFactory->mirrorBuffer(
Mikhail Naganov66916c22017-01-24 17:46:33 -0800187 nullptr, mInFrameSize * bufferFrameCount, &mInBuffer);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800188 if (status != 0) {
189 ALOGE("DownmixerBufferProvider() error %d while creating input buffer", status);
190 mDownmixInterface.clear();
191 mEffectsFactory.clear();
192 return;
193 }
Kevin Rocard7588ff42018-01-08 11:11:30 -0800194 status = mEffectsFactory->mirrorBuffer(
Mikhail Naganov66916c22017-01-24 17:46:33 -0800195 nullptr, mOutFrameSize * bufferFrameCount, &mOutBuffer);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800196 if (status != 0) {
197 ALOGE("DownmixerBufferProvider() error %d while creating output buffer", status);
198 mInBuffer.clear();
199 mDownmixInterface.clear();
200 mEffectsFactory.clear();
201 return;
202 }
Mikhail Naganov2f607552017-01-11 16:09:03 -0800203 mDownmixInterface->setInBuffer(mInBuffer);
204 mDownmixInterface->setOutBuffer(mOutBuffer);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800205
Andy Hung857d5a22015-03-26 18:46:00 -0700206 int cmdStatus;
207 uint32_t replySize = sizeof(int);
208
209 // Configure downmixer
Mikhail Naganov022b9952017-01-04 16:36:51 -0800210 status = mDownmixInterface->command(
Andy Hung857d5a22015-03-26 18:46:00 -0700211 EFFECT_CMD_SET_CONFIG /*cmdCode*/, sizeof(effect_config_t) /*cmdSize*/,
212 &mDownmixConfig /*pCmdData*/,
213 &replySize, &cmdStatus /*pReplyData*/);
214 if (status != 0 || cmdStatus != 0) {
215 ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while configuring downmixer",
216 status, cmdStatus);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800217 mOutBuffer.clear();
218 mInBuffer.clear();
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700219 mDownmixInterface.clear();
220 mEffectsFactory.clear();
Andy Hung857d5a22015-03-26 18:46:00 -0700221 return;
222 }
223
224 // Enable downmixer
225 replySize = sizeof(int);
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700226 status = mDownmixInterface->command(
Andy Hung857d5a22015-03-26 18:46:00 -0700227 EFFECT_CMD_ENABLE /*cmdCode*/, 0 /*cmdSize*/, NULL /*pCmdData*/,
228 &replySize, &cmdStatus /*pReplyData*/);
229 if (status != 0 || cmdStatus != 0) {
230 ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while enabling downmixer",
231 status, cmdStatus);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800232 mOutBuffer.clear();
233 mInBuffer.clear();
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700234 mDownmixInterface.clear();
235 mEffectsFactory.clear();
Andy Hung857d5a22015-03-26 18:46:00 -0700236 return;
237 }
238
239 // Set downmix type
240 // parameter size rounded for padding on 32bit boundary
241 const int psizePadded = ((sizeof(downmix_params_t) - 1)/sizeof(int) + 1) * sizeof(int);
242 const int downmixParamSize =
243 sizeof(effect_param_t) + psizePadded + sizeof(downmix_type_t);
244 effect_param_t * const param = (effect_param_t *) malloc(downmixParamSize);
245 param->psize = sizeof(downmix_params_t);
246 const downmix_params_t downmixParam = DOWNMIX_PARAM_TYPE;
247 memcpy(param->data, &downmixParam, param->psize);
248 const downmix_type_t downmixType = DOWNMIX_TYPE_FOLD;
249 param->vsize = sizeof(downmix_type_t);
250 memcpy(param->data + psizePadded, &downmixType, param->vsize);
251 replySize = sizeof(int);
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700252 status = mDownmixInterface->command(
Andy Hung857d5a22015-03-26 18:46:00 -0700253 EFFECT_CMD_SET_PARAM /* cmdCode */, downmixParamSize /* cmdSize */,
254 param /*pCmdData*/, &replySize, &cmdStatus /*pReplyData*/);
255 free(param);
256 if (status != 0 || cmdStatus != 0) {
257 ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while setting downmix type",
258 status, cmdStatus);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800259 mOutBuffer.clear();
260 mInBuffer.clear();
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700261 mDownmixInterface.clear();
262 mEffectsFactory.clear();
Andy Hung857d5a22015-03-26 18:46:00 -0700263 return;
264 }
265 ALOGV("DownmixerBufferProvider() downmix type set to %d", (int) downmixType);
266}
267
268DownmixerBufferProvider::~DownmixerBufferProvider()
269{
270 ALOGV("~DownmixerBufferProvider (%p)", this);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800271 if (mDownmixInterface != 0) {
272 mDownmixInterface->close();
273 }
Andy Hung857d5a22015-03-26 18:46:00 -0700274}
275
276void DownmixerBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
277{
Mikhail Naganov022b9952017-01-04 16:36:51 -0800278 mInBuffer->setExternalData(const_cast<void*>(src));
279 mInBuffer->setFrameCount(frames);
Mikhail Naganov66916c22017-01-24 17:46:33 -0800280 mInBuffer->update(mInFrameSize * frames);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800281 mOutBuffer->setFrameCount(frames);
Mikhail Naganov66916c22017-01-24 17:46:33 -0800282 mOutBuffer->setExternalData(dst);
283 if (dst != src) {
284 // Downmix may be accumulating, need to populate the output buffer
285 // with the dst data.
286 mOutBuffer->update(mOutFrameSize * frames);
287 }
Andy Hung857d5a22015-03-26 18:46:00 -0700288 // may be in-place if src == dst.
Mikhail Naganov022b9952017-01-04 16:36:51 -0800289 status_t res = mDownmixInterface->process();
290 if (res == OK) {
Mikhail Naganov66916c22017-01-24 17:46:33 -0800291 mOutBuffer->commit(mOutFrameSize * frames);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800292 } else {
293 ALOGE("DownmixBufferProvider error %d", res);
294 }
Andy Hung857d5a22015-03-26 18:46:00 -0700295}
296
297/* call once in a pthread_once handler. */
298/*static*/ status_t DownmixerBufferProvider::init()
299{
300 // find multichannel downmix effect if we have to play multichannel content
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700301 sp<EffectsFactoryHalInterface> effectsFactory = EffectsFactoryHalInterface::create();
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700302 if (effectsFactory == 0) {
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700303 ALOGE("AudioMixer() error: could not obtain the effects factory");
304 return NO_INIT;
305 }
Andy Hung857d5a22015-03-26 18:46:00 -0700306 uint32_t numEffects = 0;
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700307 int ret = effectsFactory->queryNumberEffects(&numEffects);
Andy Hung857d5a22015-03-26 18:46:00 -0700308 if (ret != 0) {
309 ALOGE("AudioMixer() error %d querying number of effects", ret);
310 return NO_INIT;
311 }
312 ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
313
314 for (uint32_t i = 0 ; i < numEffects ; i++) {
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700315 if (effectsFactory->getDescriptor(i, &sDwnmFxDesc) == 0) {
Andy Hung857d5a22015-03-26 18:46:00 -0700316 ALOGV("effect %d is called %s", i, sDwnmFxDesc.name);
317 if (memcmp(&sDwnmFxDesc.type, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) {
318 ALOGI("found effect \"%s\" from %s",
319 sDwnmFxDesc.name, sDwnmFxDesc.implementor);
320 sIsMultichannelCapable = true;
321 break;
322 }
323 }
324 }
325 ALOGW_IF(!sIsMultichannelCapable, "unable to find downmix effect");
326 return NO_INIT;
327}
328
329/*static*/ bool DownmixerBufferProvider::sIsMultichannelCapable = false;
330/*static*/ effect_descriptor_t DownmixerBufferProvider::sDwnmFxDesc;
331
332RemixBufferProvider::RemixBufferProvider(audio_channel_mask_t inputChannelMask,
333 audio_channel_mask_t outputChannelMask, audio_format_t format,
334 size_t bufferFrameCount) :
335 CopyBufferProvider(
336 audio_bytes_per_sample(format)
337 * audio_channel_count_from_out_mask(inputChannelMask),
338 audio_bytes_per_sample(format)
339 * audio_channel_count_from_out_mask(outputChannelMask),
340 bufferFrameCount),
341 mFormat(format),
342 mSampleSize(audio_bytes_per_sample(format)),
343 mInputChannels(audio_channel_count_from_out_mask(inputChannelMask)),
344 mOutputChannels(audio_channel_count_from_out_mask(outputChannelMask))
345{
346 ALOGV("RemixBufferProvider(%p)(%#x, %#x, %#x) %zu %zu",
347 this, format, inputChannelMask, outputChannelMask,
348 mInputChannels, mOutputChannels);
Andy Hung18aa2702015-05-05 23:48:38 -0700349 (void) memcpy_by_index_array_initialization_from_channel_mask(
350 mIdxAry, ARRAY_SIZE(mIdxAry), outputChannelMask, inputChannelMask);
Andy Hung857d5a22015-03-26 18:46:00 -0700351}
352
353void RemixBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
354{
355 memcpy_by_index_array(dst, mOutputChannels,
356 src, mInputChannels, mIdxAry, mSampleSize, frames);
357}
358
359ReformatBufferProvider::ReformatBufferProvider(int32_t channelCount,
360 audio_format_t inputFormat, audio_format_t outputFormat,
361 size_t bufferFrameCount) :
362 CopyBufferProvider(
363 channelCount * audio_bytes_per_sample(inputFormat),
364 channelCount * audio_bytes_per_sample(outputFormat),
365 bufferFrameCount),
366 mChannelCount(channelCount),
367 mInputFormat(inputFormat),
368 mOutputFormat(outputFormat)
369{
370 ALOGV("ReformatBufferProvider(%p)(%u, %#x, %#x)",
371 this, channelCount, inputFormat, outputFormat);
372}
373
374void ReformatBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
375{
376 memcpy_by_audio_format(dst, mOutputFormat, src, mInputFormat, frames * mChannelCount);
377}
378
Kevin Rocarde053bfa2017-11-09 22:07:34 -0800379ClampFloatBufferProvider::ClampFloatBufferProvider(int32_t channelCount, size_t bufferFrameCount) :
380 CopyBufferProvider(
381 channelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT),
382 channelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT),
383 bufferFrameCount),
384 mChannelCount(channelCount)
385{
386 ALOGV("ClampFloatBufferProvider(%p)(%u)", this, channelCount);
387}
388
389void ClampFloatBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
390{
391 memcpy_to_float_from_float_with_clamping((float*)dst, (const float*)src,
392 frames * mChannelCount,
393 FLOAT_NOMINAL_RANGE_HEADROOM);
394}
395
Andy Hungc5656cc2015-03-26 19:04:33 -0700396TimestretchBufferProvider::TimestretchBufferProvider(int32_t channelCount,
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700397 audio_format_t format, uint32_t sampleRate, const AudioPlaybackRate &playbackRate) :
Andy Hungc5656cc2015-03-26 19:04:33 -0700398 mChannelCount(channelCount),
399 mFormat(format),
400 mSampleRate(sampleRate),
401 mFrameSize(channelCount * audio_bytes_per_sample(format)),
Andy Hungc5656cc2015-03-26 19:04:33 -0700402 mLocalBufferFrameCount(0),
403 mLocalBufferData(NULL),
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700404 mRemaining(0),
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700405 mSonicStream(sonicCreateStream(sampleRate, mChannelCount)),
Ricardo Garcia6c7f0622015-04-30 18:39:16 -0700406 mFallbackFailErrorShown(false),
407 mAudioPlaybackRateValid(false)
Andy Hungc5656cc2015-03-26 19:04:33 -0700408{
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700409 LOG_ALWAYS_FATAL_IF(mSonicStream == NULL,
410 "TimestretchBufferProvider can't allocate Sonic stream");
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700411
412 setPlaybackRate(playbackRate);
413 ALOGV("TimestretchBufferProvider(%p)(%u, %#x, %u %f %f %d %d)",
414 this, channelCount, format, sampleRate, playbackRate.mSpeed,
415 playbackRate.mPitch, playbackRate.mStretchMode, playbackRate.mFallbackMode);
416 mBuffer.frameCount = 0;
Andy Hungc5656cc2015-03-26 19:04:33 -0700417}
418
419TimestretchBufferProvider::~TimestretchBufferProvider()
420{
421 ALOGV("~TimestretchBufferProvider(%p)", this);
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700422 sonicDestroyStream(mSonicStream);
Andy Hungc5656cc2015-03-26 19:04:33 -0700423 if (mBuffer.frameCount != 0) {
424 mTrackBufferProvider->releaseBuffer(&mBuffer);
425 }
426 free(mLocalBufferData);
427}
428
429status_t TimestretchBufferProvider::getNextBuffer(
Glenn Kastend79072e2016-01-06 08:41:20 -0800430 AudioBufferProvider::Buffer *pBuffer)
Andy Hungc5656cc2015-03-26 19:04:33 -0700431{
Glenn Kastend79072e2016-01-06 08:41:20 -0800432 ALOGV("TimestretchBufferProvider(%p)::getNextBuffer(%p (%zu))",
433 this, pBuffer, pBuffer->frameCount);
Andy Hungc5656cc2015-03-26 19:04:33 -0700434
435 // BYPASS
Glenn Kastend79072e2016-01-06 08:41:20 -0800436 //return mTrackBufferProvider->getNextBuffer(pBuffer);
Andy Hungc5656cc2015-03-26 19:04:33 -0700437
438 // check if previously processed data is sufficient.
439 if (pBuffer->frameCount <= mRemaining) {
440 ALOGV("previous sufficient");
441 pBuffer->raw = mLocalBufferData;
442 return OK;
443 }
444
445 // do we need to resize our buffer?
446 if (pBuffer->frameCount > mLocalBufferFrameCount) {
447 void *newmem;
448 if (posix_memalign(&newmem, 32, pBuffer->frameCount * mFrameSize) == OK) {
449 if (mRemaining != 0) {
450 memcpy(newmem, mLocalBufferData, mRemaining * mFrameSize);
451 }
452 free(mLocalBufferData);
453 mLocalBufferData = newmem;
454 mLocalBufferFrameCount = pBuffer->frameCount;
455 }
456 }
457
458 // need to fetch more data
459 const size_t outputDesired = pBuffer->frameCount - mRemaining;
Andy Hung6d626692015-08-21 12:53:46 -0700460 size_t dstAvailable;
461 do {
462 mBuffer.frameCount = mPlaybackRate.mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL
463 ? outputDesired : outputDesired * mPlaybackRate.mSpeed + 1;
Andy Hungc5656cc2015-03-26 19:04:33 -0700464
Glenn Kastend79072e2016-01-06 08:41:20 -0800465 status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer);
Andy Hungc5656cc2015-03-26 19:04:33 -0700466
Andy Hung6d626692015-08-21 12:53:46 -0700467 ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
468 if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
469 ALOGV("upstream provider cannot provide data");
470 if (mRemaining == 0) {
471 pBuffer->raw = NULL;
472 pBuffer->frameCount = 0;
473 return res;
474 } else { // return partial count
475 pBuffer->raw = mLocalBufferData;
476 pBuffer->frameCount = mRemaining;
477 return OK;
478 }
Andy Hungc5656cc2015-03-26 19:04:33 -0700479 }
Andy Hungc5656cc2015-03-26 19:04:33 -0700480
Andy Hung6d626692015-08-21 12:53:46 -0700481 // time-stretch the data
482 dstAvailable = min(mLocalBufferFrameCount - mRemaining, outputDesired);
483 size_t srcAvailable = mBuffer.frameCount;
484 processFrames((uint8_t*)mLocalBufferData + mRemaining * mFrameSize, &dstAvailable,
485 mBuffer.raw, &srcAvailable);
Andy Hungc5656cc2015-03-26 19:04:33 -0700486
Andy Hung6d626692015-08-21 12:53:46 -0700487 // release all data consumed
488 mBuffer.frameCount = srcAvailable;
489 mTrackBufferProvider->releaseBuffer(&mBuffer);
490 } while (dstAvailable == 0); // try until we get output data or upstream provider fails.
Andy Hungc5656cc2015-03-26 19:04:33 -0700491
492 // update buffer vars with the actual data processed and return with buffer
493 mRemaining += dstAvailable;
494
495 pBuffer->raw = mLocalBufferData;
496 pBuffer->frameCount = mRemaining;
497
498 return OK;
499}
500
501void TimestretchBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer)
502{
503 ALOGV("TimestretchBufferProvider(%p)::releaseBuffer(%p (%zu))",
504 this, pBuffer, pBuffer->frameCount);
505
506 // BYPASS
507 //return mTrackBufferProvider->releaseBuffer(pBuffer);
508
509 // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
510 if (pBuffer->frameCount < mRemaining) {
511 memcpy(mLocalBufferData,
512 (uint8_t*)mLocalBufferData + pBuffer->frameCount * mFrameSize,
513 (mRemaining - pBuffer->frameCount) * mFrameSize);
514 mRemaining -= pBuffer->frameCount;
515 } else if (pBuffer->frameCount == mRemaining) {
516 mRemaining = 0;
517 } else {
518 LOG_ALWAYS_FATAL("Releasing more frames(%zu) than available(%zu)",
519 pBuffer->frameCount, mRemaining);
520 }
521
522 pBuffer->raw = NULL;
523 pBuffer->frameCount = 0;
524}
525
526void TimestretchBufferProvider::reset()
527{
528 mRemaining = 0;
529}
530
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700531status_t TimestretchBufferProvider::setPlaybackRate(const AudioPlaybackRate &playbackRate)
Andy Hungc5656cc2015-03-26 19:04:33 -0700532{
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700533 mPlaybackRate = playbackRate;
534 mFallbackFailErrorShown = false;
535 sonicSetSpeed(mSonicStream, mPlaybackRate.mSpeed);
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700536 //TODO: pitch is ignored for now
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700537 //TODO: optimize: if parameters are the same, don't do any extra computation.
Ricardo Garcia6c7f0622015-04-30 18:39:16 -0700538
539 mAudioPlaybackRateValid = isAudioPlaybackRateValid(mPlaybackRate);
Andy Hungc5656cc2015-03-26 19:04:33 -0700540 return OK;
541}
542
543void TimestretchBufferProvider::processFrames(void *dstBuffer, size_t *dstFrames,
544 const void *srcBuffer, size_t *srcFrames)
545{
546 ALOGV("processFrames(%zu %zu) remaining(%zu)", *dstFrames, *srcFrames, mRemaining);
547 // Note dstFrames is the required number of frames.
548
Ricardo Garcia6c7f0622015-04-30 18:39:16 -0700549 if (!mAudioPlaybackRateValid) {
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700550 //fallback mode
Andy Hungcf8d2c82016-08-10 16:02:01 -0700551 // Ensure consumption from src is as expected.
552 // TODO: add logic to track "very accurate" consumption related to speed, original sampling
553 // rate, actual frames processed.
554
555 const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
556 if (*srcFrames < targetSrc) { // limit dst frames to that possible
557 *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
558 } else if (*srcFrames > targetSrc + 1) {
559 *srcFrames = targetSrc + 1;
560 }
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700561 if (*dstFrames > 0) {
562 switch(mPlaybackRate.mFallbackMode) {
563 case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT:
564 if (*dstFrames <= *srcFrames) {
565 size_t copySize = mFrameSize * *dstFrames;
566 memcpy(dstBuffer, srcBuffer, copySize);
567 } else {
568 // cyclically repeat the source.
569 for (size_t count = 0; count < *dstFrames; count += *srcFrames) {
570 size_t remaining = min(*srcFrames, *dstFrames - count);
571 memcpy((uint8_t*)dstBuffer + mFrameSize * count,
572 srcBuffer, mFrameSize * remaining);
573 }
574 }
575 break;
576 case AUDIO_TIMESTRETCH_FALLBACK_DEFAULT:
577 case AUDIO_TIMESTRETCH_FALLBACK_MUTE:
578 memset(dstBuffer,0, mFrameSize * *dstFrames);
579 break;
580 case AUDIO_TIMESTRETCH_FALLBACK_FAIL:
581 default:
582 if(!mFallbackFailErrorShown) {
583 ALOGE("invalid parameters in TimestretchBufferProvider fallbackMode:%d",
584 mPlaybackRate.mFallbackMode);
585 mFallbackFailErrorShown = true;
586 }
587 break;
588 }
Andy Hungc5656cc2015-03-26 19:04:33 -0700589 }
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700590 } else {
591 switch (mFormat) {
592 case AUDIO_FORMAT_PCM_FLOAT:
593 if (sonicWriteFloatToStream(mSonicStream, (float*)srcBuffer, *srcFrames) != 1) {
594 ALOGE("sonicWriteFloatToStream cannot realloc");
595 *srcFrames = 0; // cannot consume all of srcBuffer
596 }
597 *dstFrames = sonicReadFloatFromStream(mSonicStream, (float*)dstBuffer, *dstFrames);
598 break;
599 case AUDIO_FORMAT_PCM_16_BIT:
600 if (sonicWriteShortToStream(mSonicStream, (short*)srcBuffer, *srcFrames) != 1) {
601 ALOGE("sonicWriteShortToStream cannot realloc");
602 *srcFrames = 0; // cannot consume all of srcBuffer
603 }
604 *dstFrames = sonicReadShortFromStream(mSonicStream, (short*)dstBuffer, *dstFrames);
605 break;
606 default:
607 // could also be caught on construction
608 LOG_ALWAYS_FATAL("invalid format %#x for TimestretchBufferProvider", mFormat);
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700609 }
Andy Hungc5656cc2015-03-26 19:04:33 -0700610 }
611}
Andy Hung857d5a22015-03-26 18:46:00 -0700612// ----------------------------------------------------------------------------
613} // namespace android