blob: 8b9ee0b0ab49b32b7eb4cec1793a602d659bcf27 [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>
jiabindce8f8c2018-12-10 17:49:31 -080022#include <audio_utils/channels.h>
Andy Hung068561c2017-01-03 17:09:32 -080023#include <external/sonic/sonic.h>
Mikhail Naganov022b9952017-01-04 16:36:51 -080024#include <media/audiohal/EffectBufferHalInterface.h>
Mikhail Naganova0c91332016-09-19 10:01:12 -070025#include <media/audiohal/EffectHalInterface.h>
26#include <media/audiohal/EffectsFactoryHalInterface.h>
Andy Hungc5656cc2015-03-26 19:04:33 -070027#include <media/AudioResamplerPublic.h>
Andy Hung068561c2017-01-03 17:09:32 -080028#include <media/BufferProviders.h>
Mikhail Naganov9fe94012016-10-14 14:57:40 -070029#include <system/audio_effects/effect_downmix.h>
Andy Hung857d5a22015-03-26 18:46:00 -070030#include <utils/Log.h>
31
Andy Hung857d5a22015-03-26 18:46:00 -070032#ifndef ARRAY_SIZE
33#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
34#endif
35
36namespace android {
37
38// ----------------------------------------------------------------------------
39
40template <typename T>
41static inline T min(const T& a, const T& b)
42{
43 return a < b ? a : b;
44}
45
46CopyBufferProvider::CopyBufferProvider(size_t inputFrameSize,
47 size_t outputFrameSize, size_t bufferFrameCount) :
48 mInputFrameSize(inputFrameSize),
49 mOutputFrameSize(outputFrameSize),
50 mLocalBufferFrameCount(bufferFrameCount),
51 mLocalBufferData(NULL),
52 mConsumed(0)
53{
54 ALOGV("CopyBufferProvider(%p)(%zu, %zu, %zu)", this,
55 inputFrameSize, outputFrameSize, bufferFrameCount);
56 LOG_ALWAYS_FATAL_IF(inputFrameSize < outputFrameSize && bufferFrameCount == 0,
57 "Requires local buffer if inputFrameSize(%zu) < outputFrameSize(%zu)",
58 inputFrameSize, outputFrameSize);
59 if (mLocalBufferFrameCount) {
60 (void)posix_memalign(&mLocalBufferData, 32, mLocalBufferFrameCount * mOutputFrameSize);
61 }
62 mBuffer.frameCount = 0;
63}
64
65CopyBufferProvider::~CopyBufferProvider()
66{
67 ALOGV("~CopyBufferProvider(%p)", this);
68 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
137DownmixerBufferProvider::DownmixerBufferProvider(
138 audio_channel_mask_t inputChannelMask,
139 audio_channel_mask_t outputChannelMask, audio_format_t format,
140 uint32_t sampleRate, int32_t sessionId, size_t bufferFrameCount) :
141 CopyBufferProvider(
142 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask),
143 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask),
144 bufferFrameCount) // set bufferFrameCount to 0 to do in-place
145{
Mikhail Naganov66916c22017-01-24 17:46:33 -0800146 ALOGV("DownmixerBufferProvider(%p)(%#x, %#x, %#x %u %d %d)",
Andy Hung857d5a22015-03-26 18:46:00 -0700147 this, inputChannelMask, outputChannelMask, format,
Mikhail Naganov66916c22017-01-24 17:46:33 -0800148 sampleRate, sessionId, (int)bufferFrameCount);
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700149 if (!sIsMultichannelCapable) {
150 ALOGE("DownmixerBufferProvider() error: not multichannel capable");
151 return;
152 }
153 mEffectsFactory = EffectsFactoryHalInterface::create();
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700154 if (mEffectsFactory == 0) {
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700155 ALOGE("DownmixerBufferProvider() error: could not obtain the effects factory");
156 return;
157 }
158 if (mEffectsFactory->createEffect(&sDwnmFxDesc.uuid,
159 sessionId,
160 SESSION_ID_INVALID_AND_IGNORED,
161 &mDownmixInterface) != 0) {
Andy Hung857d5a22015-03-26 18:46:00 -0700162 ALOGE("DownmixerBufferProvider() error creating downmixer effect");
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700163 mDownmixInterface.clear();
164 mEffectsFactory.clear();
Andy Hung857d5a22015-03-26 18:46:00 -0700165 return;
166 }
167 // channel input configuration will be overridden per-track
168 mDownmixConfig.inputCfg.channels = inputChannelMask; // FIXME: Should be bits
169 mDownmixConfig.outputCfg.channels = outputChannelMask; // FIXME: should be bits
170 mDownmixConfig.inputCfg.format = format;
171 mDownmixConfig.outputCfg.format = format;
172 mDownmixConfig.inputCfg.samplingRate = sampleRate;
173 mDownmixConfig.outputCfg.samplingRate = sampleRate;
174 mDownmixConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
175 mDownmixConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
176 // input and output buffer provider, and frame count will not be used as the downmix effect
177 // process() function is called directly (see DownmixerBufferProvider::getNextBuffer())
178 mDownmixConfig.inputCfg.mask = EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS |
179 EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE;
180 mDownmixConfig.outputCfg.mask = mDownmixConfig.inputCfg.mask;
181
Mikhail Naganov66916c22017-01-24 17:46:33 -0800182 mInFrameSize =
183 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask);
184 mOutFrameSize =
185 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800186 status_t status;
Kevin Rocard7588ff42018-01-08 11:11:30 -0800187 status = mEffectsFactory->mirrorBuffer(
Mikhail Naganov66916c22017-01-24 17:46:33 -0800188 nullptr, mInFrameSize * bufferFrameCount, &mInBuffer);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800189 if (status != 0) {
190 ALOGE("DownmixerBufferProvider() error %d while creating input buffer", status);
191 mDownmixInterface.clear();
192 mEffectsFactory.clear();
193 return;
194 }
Kevin Rocard7588ff42018-01-08 11:11:30 -0800195 status = mEffectsFactory->mirrorBuffer(
Mikhail Naganov66916c22017-01-24 17:46:33 -0800196 nullptr, mOutFrameSize * bufferFrameCount, &mOutBuffer);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800197 if (status != 0) {
198 ALOGE("DownmixerBufferProvider() error %d while creating output buffer", status);
199 mInBuffer.clear();
200 mDownmixInterface.clear();
201 mEffectsFactory.clear();
202 return;
203 }
Mikhail Naganov2f607552017-01-11 16:09:03 -0800204 mDownmixInterface->setInBuffer(mInBuffer);
205 mDownmixInterface->setOutBuffer(mOutBuffer);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800206
Andy Hung857d5a22015-03-26 18:46:00 -0700207 int cmdStatus;
208 uint32_t replySize = sizeof(int);
209
210 // Configure downmixer
Mikhail Naganov022b9952017-01-04 16:36:51 -0800211 status = mDownmixInterface->command(
Andy Hung857d5a22015-03-26 18:46:00 -0700212 EFFECT_CMD_SET_CONFIG /*cmdCode*/, sizeof(effect_config_t) /*cmdSize*/,
213 &mDownmixConfig /*pCmdData*/,
214 &replySize, &cmdStatus /*pReplyData*/);
215 if (status != 0 || cmdStatus != 0) {
216 ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while configuring downmixer",
217 status, cmdStatus);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800218 mOutBuffer.clear();
219 mInBuffer.clear();
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700220 mDownmixInterface.clear();
221 mEffectsFactory.clear();
Andy Hung857d5a22015-03-26 18:46:00 -0700222 return;
223 }
224
225 // Enable downmixer
226 replySize = sizeof(int);
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700227 status = mDownmixInterface->command(
Andy Hung857d5a22015-03-26 18:46:00 -0700228 EFFECT_CMD_ENABLE /*cmdCode*/, 0 /*cmdSize*/, NULL /*pCmdData*/,
229 &replySize, &cmdStatus /*pReplyData*/);
230 if (status != 0 || cmdStatus != 0) {
231 ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while enabling downmixer",
232 status, cmdStatus);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800233 mOutBuffer.clear();
234 mInBuffer.clear();
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700235 mDownmixInterface.clear();
236 mEffectsFactory.clear();
Andy Hung857d5a22015-03-26 18:46:00 -0700237 return;
238 }
239
240 // Set downmix type
241 // parameter size rounded for padding on 32bit boundary
242 const int psizePadded = ((sizeof(downmix_params_t) - 1)/sizeof(int) + 1) * sizeof(int);
243 const int downmixParamSize =
244 sizeof(effect_param_t) + psizePadded + sizeof(downmix_type_t);
245 effect_param_t * const param = (effect_param_t *) malloc(downmixParamSize);
246 param->psize = sizeof(downmix_params_t);
247 const downmix_params_t downmixParam = DOWNMIX_PARAM_TYPE;
248 memcpy(param->data, &downmixParam, param->psize);
249 const downmix_type_t downmixType = DOWNMIX_TYPE_FOLD;
250 param->vsize = sizeof(downmix_type_t);
251 memcpy(param->data + psizePadded, &downmixType, param->vsize);
252 replySize = sizeof(int);
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700253 status = mDownmixInterface->command(
Andy Hung857d5a22015-03-26 18:46:00 -0700254 EFFECT_CMD_SET_PARAM /* cmdCode */, downmixParamSize /* cmdSize */,
255 param /*pCmdData*/, &replySize, &cmdStatus /*pReplyData*/);
256 free(param);
257 if (status != 0 || cmdStatus != 0) {
258 ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while setting downmix type",
259 status, cmdStatus);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800260 mOutBuffer.clear();
261 mInBuffer.clear();
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700262 mDownmixInterface.clear();
263 mEffectsFactory.clear();
Andy Hung857d5a22015-03-26 18:46:00 -0700264 return;
265 }
266 ALOGV("DownmixerBufferProvider() downmix type set to %d", (int) downmixType);
267}
268
269DownmixerBufferProvider::~DownmixerBufferProvider()
270{
271 ALOGV("~DownmixerBufferProvider (%p)", this);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800272 if (mDownmixInterface != 0) {
273 mDownmixInterface->close();
274 }
Andy Hung857d5a22015-03-26 18:46:00 -0700275}
276
277void DownmixerBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
278{
Mikhail Naganov022b9952017-01-04 16:36:51 -0800279 mInBuffer->setExternalData(const_cast<void*>(src));
280 mInBuffer->setFrameCount(frames);
Mikhail Naganov66916c22017-01-24 17:46:33 -0800281 mInBuffer->update(mInFrameSize * frames);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800282 mOutBuffer->setFrameCount(frames);
Mikhail Naganov66916c22017-01-24 17:46:33 -0800283 mOutBuffer->setExternalData(dst);
284 if (dst != src) {
285 // Downmix may be accumulating, need to populate the output buffer
286 // with the dst data.
287 mOutBuffer->update(mOutFrameSize * frames);
288 }
Andy Hung857d5a22015-03-26 18:46:00 -0700289 // may be in-place if src == dst.
Mikhail Naganov022b9952017-01-04 16:36:51 -0800290 status_t res = mDownmixInterface->process();
291 if (res == OK) {
Mikhail Naganov66916c22017-01-24 17:46:33 -0800292 mOutBuffer->commit(mOutFrameSize * frames);
Mikhail Naganov022b9952017-01-04 16:36:51 -0800293 } else {
294 ALOGE("DownmixBufferProvider error %d", res);
295 }
Andy Hung857d5a22015-03-26 18:46:00 -0700296}
297
298/* call once in a pthread_once handler. */
299/*static*/ status_t DownmixerBufferProvider::init()
300{
301 // find multichannel downmix effect if we have to play multichannel content
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700302 sp<EffectsFactoryHalInterface> effectsFactory = EffectsFactoryHalInterface::create();
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700303 if (effectsFactory == 0) {
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700304 ALOGE("AudioMixer() error: could not obtain the effects factory");
305 return NO_INIT;
306 }
Andy Hung857d5a22015-03-26 18:46:00 -0700307 uint32_t numEffects = 0;
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700308 int ret = effectsFactory->queryNumberEffects(&numEffects);
Andy Hung857d5a22015-03-26 18:46:00 -0700309 if (ret != 0) {
310 ALOGE("AudioMixer() error %d querying number of effects", ret);
311 return NO_INIT;
312 }
313 ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
314
315 for (uint32_t i = 0 ; i < numEffects ; i++) {
Mikhail Naganov4a3d5c22016-08-15 13:47:42 -0700316 if (effectsFactory->getDescriptor(i, &sDwnmFxDesc) == 0) {
Andy Hung857d5a22015-03-26 18:46:00 -0700317 ALOGV("effect %d is called %s", i, sDwnmFxDesc.name);
318 if (memcmp(&sDwnmFxDesc.type, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) {
319 ALOGI("found effect \"%s\" from %s",
320 sDwnmFxDesc.name, sDwnmFxDesc.implementor);
321 sIsMultichannelCapable = true;
322 break;
323 }
324 }
325 }
326 ALOGW_IF(!sIsMultichannelCapable, "unable to find downmix effect");
327 return NO_INIT;
328}
329
330/*static*/ bool DownmixerBufferProvider::sIsMultichannelCapable = false;
331/*static*/ effect_descriptor_t DownmixerBufferProvider::sDwnmFxDesc;
332
333RemixBufferProvider::RemixBufferProvider(audio_channel_mask_t inputChannelMask,
334 audio_channel_mask_t outputChannelMask, audio_format_t format,
335 size_t bufferFrameCount) :
336 CopyBufferProvider(
337 audio_bytes_per_sample(format)
338 * audio_channel_count_from_out_mask(inputChannelMask),
339 audio_bytes_per_sample(format)
340 * audio_channel_count_from_out_mask(outputChannelMask),
341 bufferFrameCount),
342 mFormat(format),
343 mSampleSize(audio_bytes_per_sample(format)),
344 mInputChannels(audio_channel_count_from_out_mask(inputChannelMask)),
345 mOutputChannels(audio_channel_count_from_out_mask(outputChannelMask))
346{
347 ALOGV("RemixBufferProvider(%p)(%#x, %#x, %#x) %zu %zu",
348 this, format, inputChannelMask, outputChannelMask,
349 mInputChannels, mOutputChannels);
Andy Hung18aa2702015-05-05 23:48:38 -0700350 (void) memcpy_by_index_array_initialization_from_channel_mask(
351 mIdxAry, ARRAY_SIZE(mIdxAry), outputChannelMask, inputChannelMask);
Andy Hung857d5a22015-03-26 18:46:00 -0700352}
353
354void RemixBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
355{
356 memcpy_by_index_array(dst, mOutputChannels,
357 src, mInputChannels, mIdxAry, mSampleSize, frames);
358}
359
360ReformatBufferProvider::ReformatBufferProvider(int32_t channelCount,
361 audio_format_t inputFormat, audio_format_t outputFormat,
362 size_t bufferFrameCount) :
363 CopyBufferProvider(
364 channelCount * audio_bytes_per_sample(inputFormat),
365 channelCount * audio_bytes_per_sample(outputFormat),
366 bufferFrameCount),
367 mChannelCount(channelCount),
368 mInputFormat(inputFormat),
369 mOutputFormat(outputFormat)
370{
371 ALOGV("ReformatBufferProvider(%p)(%u, %#x, %#x)",
372 this, channelCount, inputFormat, outputFormat);
373}
374
375void ReformatBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
376{
377 memcpy_by_audio_format(dst, mOutputFormat, src, mInputFormat, frames * mChannelCount);
378}
379
Kevin Rocarde053bfa2017-11-09 22:07:34 -0800380ClampFloatBufferProvider::ClampFloatBufferProvider(int32_t channelCount, size_t bufferFrameCount) :
381 CopyBufferProvider(
382 channelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT),
383 channelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT),
384 bufferFrameCount),
385 mChannelCount(channelCount)
386{
387 ALOGV("ClampFloatBufferProvider(%p)(%u)", this, channelCount);
388}
389
390void ClampFloatBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
391{
392 memcpy_to_float_from_float_with_clamping((float*)dst, (const float*)src,
393 frames * mChannelCount,
394 FLOAT_NOMINAL_RANGE_HEADROOM);
395}
396
Andy Hungc5656cc2015-03-26 19:04:33 -0700397TimestretchBufferProvider::TimestretchBufferProvider(int32_t channelCount,
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700398 audio_format_t format, uint32_t sampleRate, const AudioPlaybackRate &playbackRate) :
Andy Hungc5656cc2015-03-26 19:04:33 -0700399 mChannelCount(channelCount),
400 mFormat(format),
401 mSampleRate(sampleRate),
402 mFrameSize(channelCount * audio_bytes_per_sample(format)),
Andy Hungc5656cc2015-03-26 19:04:33 -0700403 mLocalBufferFrameCount(0),
404 mLocalBufferData(NULL),
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700405 mRemaining(0),
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700406 mSonicStream(sonicCreateStream(sampleRate, mChannelCount)),
Ricardo Garcia6c7f0622015-04-30 18:39:16 -0700407 mFallbackFailErrorShown(false),
408 mAudioPlaybackRateValid(false)
Andy Hungc5656cc2015-03-26 19:04:33 -0700409{
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700410 LOG_ALWAYS_FATAL_IF(mSonicStream == NULL,
411 "TimestretchBufferProvider can't allocate Sonic stream");
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700412
413 setPlaybackRate(playbackRate);
414 ALOGV("TimestretchBufferProvider(%p)(%u, %#x, %u %f %f %d %d)",
415 this, channelCount, format, sampleRate, playbackRate.mSpeed,
416 playbackRate.mPitch, playbackRate.mStretchMode, playbackRate.mFallbackMode);
417 mBuffer.frameCount = 0;
Andy Hungc5656cc2015-03-26 19:04:33 -0700418}
419
420TimestretchBufferProvider::~TimestretchBufferProvider()
421{
422 ALOGV("~TimestretchBufferProvider(%p)", this);
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700423 sonicDestroyStream(mSonicStream);
Andy Hungc5656cc2015-03-26 19:04:33 -0700424 if (mBuffer.frameCount != 0) {
425 mTrackBufferProvider->releaseBuffer(&mBuffer);
426 }
427 free(mLocalBufferData);
428}
429
430status_t TimestretchBufferProvider::getNextBuffer(
Glenn Kastend79072e2016-01-06 08:41:20 -0800431 AudioBufferProvider::Buffer *pBuffer)
Andy Hungc5656cc2015-03-26 19:04:33 -0700432{
Glenn Kastend79072e2016-01-06 08:41:20 -0800433 ALOGV("TimestretchBufferProvider(%p)::getNextBuffer(%p (%zu))",
434 this, pBuffer, pBuffer->frameCount);
Andy Hungc5656cc2015-03-26 19:04:33 -0700435
436 // BYPASS
Glenn Kastend79072e2016-01-06 08:41:20 -0800437 //return mTrackBufferProvider->getNextBuffer(pBuffer);
Andy Hungc5656cc2015-03-26 19:04:33 -0700438
439 // check if previously processed data is sufficient.
440 if (pBuffer->frameCount <= mRemaining) {
441 ALOGV("previous sufficient");
442 pBuffer->raw = mLocalBufferData;
443 return OK;
444 }
445
446 // do we need to resize our buffer?
447 if (pBuffer->frameCount > mLocalBufferFrameCount) {
448 void *newmem;
449 if (posix_memalign(&newmem, 32, pBuffer->frameCount * mFrameSize) == OK) {
450 if (mRemaining != 0) {
451 memcpy(newmem, mLocalBufferData, mRemaining * mFrameSize);
452 }
453 free(mLocalBufferData);
454 mLocalBufferData = newmem;
455 mLocalBufferFrameCount = pBuffer->frameCount;
456 }
457 }
458
459 // need to fetch more data
460 const size_t outputDesired = pBuffer->frameCount - mRemaining;
Andy Hung6d626692015-08-21 12:53:46 -0700461 size_t dstAvailable;
462 do {
463 mBuffer.frameCount = mPlaybackRate.mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL
464 ? outputDesired : outputDesired * mPlaybackRate.mSpeed + 1;
Andy Hungc5656cc2015-03-26 19:04:33 -0700465
Glenn Kastend79072e2016-01-06 08:41:20 -0800466 status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer);
Andy Hungc5656cc2015-03-26 19:04:33 -0700467
Andy Hung6d626692015-08-21 12:53:46 -0700468 ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
469 if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
470 ALOGV("upstream provider cannot provide data");
471 if (mRemaining == 0) {
472 pBuffer->raw = NULL;
473 pBuffer->frameCount = 0;
474 return res;
475 } else { // return partial count
476 pBuffer->raw = mLocalBufferData;
477 pBuffer->frameCount = mRemaining;
478 return OK;
479 }
Andy Hungc5656cc2015-03-26 19:04:33 -0700480 }
Andy Hungc5656cc2015-03-26 19:04:33 -0700481
Andy Hung6d626692015-08-21 12:53:46 -0700482 // time-stretch the data
483 dstAvailable = min(mLocalBufferFrameCount - mRemaining, outputDesired);
484 size_t srcAvailable = mBuffer.frameCount;
485 processFrames((uint8_t*)mLocalBufferData + mRemaining * mFrameSize, &dstAvailable,
486 mBuffer.raw, &srcAvailable);
Andy Hungc5656cc2015-03-26 19:04:33 -0700487
Andy Hung6d626692015-08-21 12:53:46 -0700488 // release all data consumed
489 mBuffer.frameCount = srcAvailable;
490 mTrackBufferProvider->releaseBuffer(&mBuffer);
491 } while (dstAvailable == 0); // try until we get output data or upstream provider fails.
Andy Hungc5656cc2015-03-26 19:04:33 -0700492
493 // update buffer vars with the actual data processed and return with buffer
494 mRemaining += dstAvailable;
495
496 pBuffer->raw = mLocalBufferData;
497 pBuffer->frameCount = mRemaining;
498
499 return OK;
500}
501
502void TimestretchBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer)
503{
504 ALOGV("TimestretchBufferProvider(%p)::releaseBuffer(%p (%zu))",
505 this, pBuffer, pBuffer->frameCount);
506
507 // BYPASS
508 //return mTrackBufferProvider->releaseBuffer(pBuffer);
509
510 // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
511 if (pBuffer->frameCount < mRemaining) {
512 memcpy(mLocalBufferData,
513 (uint8_t*)mLocalBufferData + pBuffer->frameCount * mFrameSize,
514 (mRemaining - pBuffer->frameCount) * mFrameSize);
515 mRemaining -= pBuffer->frameCount;
516 } else if (pBuffer->frameCount == mRemaining) {
517 mRemaining = 0;
518 } else {
519 LOG_ALWAYS_FATAL("Releasing more frames(%zu) than available(%zu)",
520 pBuffer->frameCount, mRemaining);
521 }
522
523 pBuffer->raw = NULL;
524 pBuffer->frameCount = 0;
525}
526
527void TimestretchBufferProvider::reset()
528{
529 mRemaining = 0;
530}
531
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700532status_t TimestretchBufferProvider::setPlaybackRate(const AudioPlaybackRate &playbackRate)
Andy Hungc5656cc2015-03-26 19:04:33 -0700533{
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700534 mPlaybackRate = playbackRate;
535 mFallbackFailErrorShown = false;
536 sonicSetSpeed(mSonicStream, mPlaybackRate.mSpeed);
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700537 //TODO: pitch is ignored for now
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700538 //TODO: optimize: if parameters are the same, don't do any extra computation.
Ricardo Garcia6c7f0622015-04-30 18:39:16 -0700539
540 mAudioPlaybackRateValid = isAudioPlaybackRateValid(mPlaybackRate);
Andy Hungc5656cc2015-03-26 19:04:33 -0700541 return OK;
542}
543
544void TimestretchBufferProvider::processFrames(void *dstBuffer, size_t *dstFrames,
545 const void *srcBuffer, size_t *srcFrames)
546{
547 ALOGV("processFrames(%zu %zu) remaining(%zu)", *dstFrames, *srcFrames, mRemaining);
548 // Note dstFrames is the required number of frames.
549
Ricardo Garcia6c7f0622015-04-30 18:39:16 -0700550 if (!mAudioPlaybackRateValid) {
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700551 //fallback mode
Andy Hungcf8d2c82016-08-10 16:02:01 -0700552 // Ensure consumption from src is as expected.
553 // TODO: add logic to track "very accurate" consumption related to speed, original sampling
554 // rate, actual frames processed.
555
556 const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
557 if (*srcFrames < targetSrc) { // limit dst frames to that possible
558 *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
559 } else if (*srcFrames > targetSrc + 1) {
560 *srcFrames = targetSrc + 1;
561 }
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700562 if (*dstFrames > 0) {
563 switch(mPlaybackRate.mFallbackMode) {
564 case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT:
565 if (*dstFrames <= *srcFrames) {
566 size_t copySize = mFrameSize * *dstFrames;
567 memcpy(dstBuffer, srcBuffer, copySize);
568 } else {
569 // cyclically repeat the source.
570 for (size_t count = 0; count < *dstFrames; count += *srcFrames) {
571 size_t remaining = min(*srcFrames, *dstFrames - count);
572 memcpy((uint8_t*)dstBuffer + mFrameSize * count,
573 srcBuffer, mFrameSize * remaining);
574 }
575 }
576 break;
577 case AUDIO_TIMESTRETCH_FALLBACK_DEFAULT:
578 case AUDIO_TIMESTRETCH_FALLBACK_MUTE:
579 memset(dstBuffer,0, mFrameSize * *dstFrames);
580 break;
581 case AUDIO_TIMESTRETCH_FALLBACK_FAIL:
582 default:
583 if(!mFallbackFailErrorShown) {
584 ALOGE("invalid parameters in TimestretchBufferProvider fallbackMode:%d",
585 mPlaybackRate.mFallbackMode);
586 mFallbackFailErrorShown = true;
587 }
588 break;
589 }
Andy Hungc5656cc2015-03-26 19:04:33 -0700590 }
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700591 } else {
592 switch (mFormat) {
593 case AUDIO_FORMAT_PCM_FLOAT:
594 if (sonicWriteFloatToStream(mSonicStream, (float*)srcBuffer, *srcFrames) != 1) {
595 ALOGE("sonicWriteFloatToStream cannot realloc");
596 *srcFrames = 0; // cannot consume all of srcBuffer
597 }
598 *dstFrames = sonicReadFloatFromStream(mSonicStream, (float*)dstBuffer, *dstFrames);
599 break;
600 case AUDIO_FORMAT_PCM_16_BIT:
601 if (sonicWriteShortToStream(mSonicStream, (short*)srcBuffer, *srcFrames) != 1) {
602 ALOGE("sonicWriteShortToStream cannot realloc");
603 *srcFrames = 0; // cannot consume all of srcBuffer
604 }
605 *dstFrames = sonicReadShortFromStream(mSonicStream, (short*)dstBuffer, *dstFrames);
606 break;
607 default:
608 // could also be caught on construction
609 LOG_ALWAYS_FATAL("invalid format %#x for TimestretchBufferProvider", mFormat);
Ricardo Garciaf097cae2015-04-13 12:17:21 -0700610 }
Andy Hungc5656cc2015-03-26 19:04:33 -0700611 }
612}
jiabindce8f8c2018-12-10 17:49:31 -0800613
614AdjustChannelsBufferProvider::AdjustChannelsBufferProvider(audio_format_t format,
615 size_t inChannelCount, size_t outChannelCount, size_t frameCount) :
616 CopyBufferProvider(
617 audio_bytes_per_frame(inChannelCount, format),
618 audio_bytes_per_frame(outChannelCount, format),
619 frameCount),
620 mFormat(format),
621 mInChannelCount(inChannelCount),
622 mOutChannelCount(outChannelCount),
623 mSampleSizeInBytes(audio_bytes_per_sample(format))
624{
625 ALOGV("AdjustBufferProvider(%p)(%#x, %zu, %zu, %zu)",
626 this, format, inChannelCount, outChannelCount, frameCount);
627}
628
629void AdjustChannelsBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
630{
631 adjust_channels(src, mInChannelCount, dst, mOutChannelCount, mSampleSizeInBytes,
632 frames * mInChannelCount * mSampleSizeInBytes);
633}
634
635AdjustChannelsNonDestructiveBufferProvider::AdjustChannelsNonDestructiveBufferProvider(
636 audio_format_t format, size_t inChannelCount, size_t outChannelCount,
637 audio_format_t contractedFormat, size_t contractedFrameCount, void* contractedBuffer) :
638 CopyBufferProvider(
639 audio_bytes_per_frame(inChannelCount, format),
640 audio_bytes_per_frame(outChannelCount, format),
641 0 /*bufferFrameCount*/),
642 mFormat(format),
643 mInChannelCount(inChannelCount),
644 mOutChannelCount(outChannelCount),
645 mSampleSizeInBytes(audio_bytes_per_sample(format)),
646 mContractedChannelCount(inChannelCount - outChannelCount),
647 mContractedFormat(contractedFormat),
648 mContractedFrameCount(contractedFrameCount),
649 mContractedBuffer(contractedBuffer),
650 mContractedWrittenFrames(0)
651{
652 ALOGV("AdjustChannelsNonDestructiveBufferProvider(%p)(%#x, %zu, %zu, %#x, %p)",
653 this, format, inChannelCount, outChannelCount, contractedFormat, contractedBuffer);
654 if (mContractedFormat != AUDIO_FORMAT_INVALID && mInChannelCount > mOutChannelCount) {
655 mContractedFrameSize = audio_bytes_per_frame(mContractedChannelCount, mContractedFormat);
656 }
657}
658
659status_t AdjustChannelsNonDestructiveBufferProvider::getNextBuffer(
660 AudioBufferProvider::Buffer* pBuffer)
661{
662 const size_t outFramesLeft = mContractedFrameCount - mContractedWrittenFrames;
663 if (outFramesLeft < pBuffer->frameCount) {
664 // Restrict the frame count so that we don't write over the size of the output buffer.
665 pBuffer->frameCount = outFramesLeft;
666 }
667 return CopyBufferProvider::getNextBuffer(pBuffer);
668}
669
670void AdjustChannelsNonDestructiveBufferProvider::copyFrames(
671 void *dst, const void *src, size_t frames)
672{
673 adjust_channels_non_destructive(src, mInChannelCount, dst, mOutChannelCount, mSampleSizeInBytes,
674 frames * mInChannelCount * mSampleSizeInBytes);
675 if (mContractedFormat != AUDIO_FORMAT_INVALID && mContractedBuffer != NULL
676 && mInChannelCount > mOutChannelCount) {
677 const size_t contractedIdx = frames * mOutChannelCount * mSampleSizeInBytes;
678 memcpy_by_audio_format(
679 (uint8_t*)mContractedBuffer + mContractedWrittenFrames * mContractedFrameSize,
680 mContractedFormat, (uint8_t*)dst + contractedIdx, mFormat,
681 mContractedChannelCount * frames);
682 mContractedWrittenFrames += frames;
683 }
684}
685
686void AdjustChannelsNonDestructiveBufferProvider::reset()
687{
688 mContractedWrittenFrames = 0;
689 CopyBufferProvider::reset();
690}
Andy Hung857d5a22015-03-26 18:46:00 -0700691// ----------------------------------------------------------------------------
692} // namespace android