blob: e14380537b809c306a870125e9c3cb13cac4feb3 [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
20#include <audio_effects/effect_downmix.h>
21#include <audio_utils/primitives.h>
22#include <audio_utils/format.h>
23#include <media/EffectsFactoryApi.h>
24#include <utils/Log.h>
25
26#include "Configuration.h"
27#include "BufferProviders.h"
28
29#ifndef ARRAY_SIZE
30#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
31#endif
32
33namespace android {
34
35// ----------------------------------------------------------------------------
36
37template <typename T>
38static inline T min(const T& a, const T& b)
39{
40 return a < b ? a : b;
41}
42
43CopyBufferProvider::CopyBufferProvider(size_t inputFrameSize,
44 size_t outputFrameSize, size_t bufferFrameCount) :
45 mInputFrameSize(inputFrameSize),
46 mOutputFrameSize(outputFrameSize),
47 mLocalBufferFrameCount(bufferFrameCount),
48 mLocalBufferData(NULL),
49 mConsumed(0)
50{
51 ALOGV("CopyBufferProvider(%p)(%zu, %zu, %zu)", this,
52 inputFrameSize, outputFrameSize, bufferFrameCount);
53 LOG_ALWAYS_FATAL_IF(inputFrameSize < outputFrameSize && bufferFrameCount == 0,
54 "Requires local buffer if inputFrameSize(%zu) < outputFrameSize(%zu)",
55 inputFrameSize, outputFrameSize);
56 if (mLocalBufferFrameCount) {
57 (void)posix_memalign(&mLocalBufferData, 32, mLocalBufferFrameCount * mOutputFrameSize);
58 }
59 mBuffer.frameCount = 0;
60}
61
62CopyBufferProvider::~CopyBufferProvider()
63{
64 ALOGV("~CopyBufferProvider(%p)", this);
65 if (mBuffer.frameCount != 0) {
66 mTrackBufferProvider->releaseBuffer(&mBuffer);
67 }
68 free(mLocalBufferData);
69}
70
71status_t CopyBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer,
72 int64_t pts)
73{
74 //ALOGV("CopyBufferProvider(%p)::getNextBuffer(%p (%zu), %lld)",
75 // this, pBuffer, pBuffer->frameCount, pts);
76 if (mLocalBufferFrameCount == 0) {
77 status_t res = mTrackBufferProvider->getNextBuffer(pBuffer, pts);
78 if (res == OK) {
79 copyFrames(pBuffer->raw, pBuffer->raw, pBuffer->frameCount);
80 }
81 return res;
82 }
83 if (mBuffer.frameCount == 0) {
84 mBuffer.frameCount = pBuffer->frameCount;
85 status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
86 // At one time an upstream buffer provider had
87 // res == OK and mBuffer.frameCount == 0, doesn't seem to happen now 7/18/2014.
88 //
89 // By API spec, if res != OK, then mBuffer.frameCount == 0.
90 // but there may be improper implementations.
91 ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
92 if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
93 pBuffer->raw = NULL;
94 pBuffer->frameCount = 0;
95 return res;
96 }
97 mConsumed = 0;
98 }
99 ALOG_ASSERT(mConsumed < mBuffer.frameCount);
100 size_t count = min(mLocalBufferFrameCount, mBuffer.frameCount - mConsumed);
101 count = min(count, pBuffer->frameCount);
102 pBuffer->raw = mLocalBufferData;
103 pBuffer->frameCount = count;
104 copyFrames(pBuffer->raw, (uint8_t*)mBuffer.raw + mConsumed * mInputFrameSize,
105 pBuffer->frameCount);
106 return OK;
107}
108
109void CopyBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer)
110{
111 //ALOGV("CopyBufferProvider(%p)::releaseBuffer(%p(%zu))",
112 // this, pBuffer, pBuffer->frameCount);
113 if (mLocalBufferFrameCount == 0) {
114 mTrackBufferProvider->releaseBuffer(pBuffer);
115 return;
116 }
117 // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
118 mConsumed += pBuffer->frameCount; // TODO: update for efficiency to reuse existing content
119 if (mConsumed != 0 && mConsumed >= mBuffer.frameCount) {
120 mTrackBufferProvider->releaseBuffer(&mBuffer);
121 ALOG_ASSERT(mBuffer.frameCount == 0);
122 }
123 pBuffer->raw = NULL;
124 pBuffer->frameCount = 0;
125}
126
127void CopyBufferProvider::reset()
128{
129 if (mBuffer.frameCount != 0) {
130 mTrackBufferProvider->releaseBuffer(&mBuffer);
131 }
132 mConsumed = 0;
133}
134
135DownmixerBufferProvider::DownmixerBufferProvider(
136 audio_channel_mask_t inputChannelMask,
137 audio_channel_mask_t outputChannelMask, audio_format_t format,
138 uint32_t sampleRate, int32_t sessionId, size_t bufferFrameCount) :
139 CopyBufferProvider(
140 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask),
141 audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask),
142 bufferFrameCount) // set bufferFrameCount to 0 to do in-place
143{
144 ALOGV("DownmixerBufferProvider(%p)(%#x, %#x, %#x %u %d)",
145 this, inputChannelMask, outputChannelMask, format,
146 sampleRate, sessionId);
147 if (!sIsMultichannelCapable
148 || EffectCreate(&sDwnmFxDesc.uuid,
149 sessionId,
150 SESSION_ID_INVALID_AND_IGNORED,
151 &mDownmixHandle) != 0) {
152 ALOGE("DownmixerBufferProvider() error creating downmixer effect");
153 mDownmixHandle = NULL;
154 return;
155 }
156 // channel input configuration will be overridden per-track
157 mDownmixConfig.inputCfg.channels = inputChannelMask; // FIXME: Should be bits
158 mDownmixConfig.outputCfg.channels = outputChannelMask; // FIXME: should be bits
159 mDownmixConfig.inputCfg.format = format;
160 mDownmixConfig.outputCfg.format = format;
161 mDownmixConfig.inputCfg.samplingRate = sampleRate;
162 mDownmixConfig.outputCfg.samplingRate = sampleRate;
163 mDownmixConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
164 mDownmixConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
165 // input and output buffer provider, and frame count will not be used as the downmix effect
166 // process() function is called directly (see DownmixerBufferProvider::getNextBuffer())
167 mDownmixConfig.inputCfg.mask = EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS |
168 EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE;
169 mDownmixConfig.outputCfg.mask = mDownmixConfig.inputCfg.mask;
170
171 int cmdStatus;
172 uint32_t replySize = sizeof(int);
173
174 // Configure downmixer
175 status_t status = (*mDownmixHandle)->command(mDownmixHandle,
176 EFFECT_CMD_SET_CONFIG /*cmdCode*/, sizeof(effect_config_t) /*cmdSize*/,
177 &mDownmixConfig /*pCmdData*/,
178 &replySize, &cmdStatus /*pReplyData*/);
179 if (status != 0 || cmdStatus != 0) {
180 ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while configuring downmixer",
181 status, cmdStatus);
182 EffectRelease(mDownmixHandle);
183 mDownmixHandle = NULL;
184 return;
185 }
186
187 // Enable downmixer
188 replySize = sizeof(int);
189 status = (*mDownmixHandle)->command(mDownmixHandle,
190 EFFECT_CMD_ENABLE /*cmdCode*/, 0 /*cmdSize*/, NULL /*pCmdData*/,
191 &replySize, &cmdStatus /*pReplyData*/);
192 if (status != 0 || cmdStatus != 0) {
193 ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while enabling downmixer",
194 status, cmdStatus);
195 EffectRelease(mDownmixHandle);
196 mDownmixHandle = NULL;
197 return;
198 }
199
200 // Set downmix type
201 // parameter size rounded for padding on 32bit boundary
202 const int psizePadded = ((sizeof(downmix_params_t) - 1)/sizeof(int) + 1) * sizeof(int);
203 const int downmixParamSize =
204 sizeof(effect_param_t) + psizePadded + sizeof(downmix_type_t);
205 effect_param_t * const param = (effect_param_t *) malloc(downmixParamSize);
206 param->psize = sizeof(downmix_params_t);
207 const downmix_params_t downmixParam = DOWNMIX_PARAM_TYPE;
208 memcpy(param->data, &downmixParam, param->psize);
209 const downmix_type_t downmixType = DOWNMIX_TYPE_FOLD;
210 param->vsize = sizeof(downmix_type_t);
211 memcpy(param->data + psizePadded, &downmixType, param->vsize);
212 replySize = sizeof(int);
213 status = (*mDownmixHandle)->command(mDownmixHandle,
214 EFFECT_CMD_SET_PARAM /* cmdCode */, downmixParamSize /* cmdSize */,
215 param /*pCmdData*/, &replySize, &cmdStatus /*pReplyData*/);
216 free(param);
217 if (status != 0 || cmdStatus != 0) {
218 ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while setting downmix type",
219 status, cmdStatus);
220 EffectRelease(mDownmixHandle);
221 mDownmixHandle = NULL;
222 return;
223 }
224 ALOGV("DownmixerBufferProvider() downmix type set to %d", (int) downmixType);
225}
226
227DownmixerBufferProvider::~DownmixerBufferProvider()
228{
229 ALOGV("~DownmixerBufferProvider (%p)", this);
230 EffectRelease(mDownmixHandle);
231 mDownmixHandle = NULL;
232}
233
234void DownmixerBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
235{
236 mDownmixConfig.inputCfg.buffer.frameCount = frames;
237 mDownmixConfig.inputCfg.buffer.raw = const_cast<void *>(src);
238 mDownmixConfig.outputCfg.buffer.frameCount = frames;
239 mDownmixConfig.outputCfg.buffer.raw = dst;
240 // may be in-place if src == dst.
241 status_t res = (*mDownmixHandle)->process(mDownmixHandle,
242 &mDownmixConfig.inputCfg.buffer, &mDownmixConfig.outputCfg.buffer);
243 ALOGE_IF(res != OK, "DownmixBufferProvider error %d", res);
244}
245
246/* call once in a pthread_once handler. */
247/*static*/ status_t DownmixerBufferProvider::init()
248{
249 // find multichannel downmix effect if we have to play multichannel content
250 uint32_t numEffects = 0;
251 int ret = EffectQueryNumberEffects(&numEffects);
252 if (ret != 0) {
253 ALOGE("AudioMixer() error %d querying number of effects", ret);
254 return NO_INIT;
255 }
256 ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
257
258 for (uint32_t i = 0 ; i < numEffects ; i++) {
259 if (EffectQueryEffect(i, &sDwnmFxDesc) == 0) {
260 ALOGV("effect %d is called %s", i, sDwnmFxDesc.name);
261 if (memcmp(&sDwnmFxDesc.type, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) {
262 ALOGI("found effect \"%s\" from %s",
263 sDwnmFxDesc.name, sDwnmFxDesc.implementor);
264 sIsMultichannelCapable = true;
265 break;
266 }
267 }
268 }
269 ALOGW_IF(!sIsMultichannelCapable, "unable to find downmix effect");
270 return NO_INIT;
271}
272
273/*static*/ bool DownmixerBufferProvider::sIsMultichannelCapable = false;
274/*static*/ effect_descriptor_t DownmixerBufferProvider::sDwnmFxDesc;
275
276RemixBufferProvider::RemixBufferProvider(audio_channel_mask_t inputChannelMask,
277 audio_channel_mask_t outputChannelMask, audio_format_t format,
278 size_t bufferFrameCount) :
279 CopyBufferProvider(
280 audio_bytes_per_sample(format)
281 * audio_channel_count_from_out_mask(inputChannelMask),
282 audio_bytes_per_sample(format)
283 * audio_channel_count_from_out_mask(outputChannelMask),
284 bufferFrameCount),
285 mFormat(format),
286 mSampleSize(audio_bytes_per_sample(format)),
287 mInputChannels(audio_channel_count_from_out_mask(inputChannelMask)),
288 mOutputChannels(audio_channel_count_from_out_mask(outputChannelMask))
289{
290 ALOGV("RemixBufferProvider(%p)(%#x, %#x, %#x) %zu %zu",
291 this, format, inputChannelMask, outputChannelMask,
292 mInputChannels, mOutputChannels);
293
294 const audio_channel_representation_t inputRepresentation =
295 audio_channel_mask_get_representation(inputChannelMask);
296 const audio_channel_representation_t outputRepresentation =
297 audio_channel_mask_get_representation(outputChannelMask);
298 const uint32_t inputBits = audio_channel_mask_get_bits(inputChannelMask);
299 const uint32_t outputBits = audio_channel_mask_get_bits(outputChannelMask);
300
301 switch (inputRepresentation) {
302 case AUDIO_CHANNEL_REPRESENTATION_POSITION:
303 switch (outputRepresentation) {
304 case AUDIO_CHANNEL_REPRESENTATION_POSITION:
305 memcpy_by_index_array_initialization(mIdxAry, ARRAY_SIZE(mIdxAry),
306 outputBits, inputBits);
307 return;
308 case AUDIO_CHANNEL_REPRESENTATION_INDEX:
309 // TODO: output channel index mask not currently allowed
310 // fall through
311 default:
312 break;
313 }
314 break;
315 case AUDIO_CHANNEL_REPRESENTATION_INDEX:
316 switch (outputRepresentation) {
317 case AUDIO_CHANNEL_REPRESENTATION_POSITION:
318 memcpy_by_index_array_initialization_src_index(mIdxAry, ARRAY_SIZE(mIdxAry),
319 outputBits, inputBits);
320 return;
321 case AUDIO_CHANNEL_REPRESENTATION_INDEX:
322 // TODO: output channel index mask not currently allowed
323 // fall through
324 default:
325 break;
326 }
327 break;
328 default:
329 break;
330 }
331 LOG_ALWAYS_FATAL("invalid channel mask conversion from %#x to %#x",
332 inputChannelMask, outputChannelMask);
333}
334
335void RemixBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
336{
337 memcpy_by_index_array(dst, mOutputChannels,
338 src, mInputChannels, mIdxAry, mSampleSize, frames);
339}
340
341ReformatBufferProvider::ReformatBufferProvider(int32_t channelCount,
342 audio_format_t inputFormat, audio_format_t outputFormat,
343 size_t bufferFrameCount) :
344 CopyBufferProvider(
345 channelCount * audio_bytes_per_sample(inputFormat),
346 channelCount * audio_bytes_per_sample(outputFormat),
347 bufferFrameCount),
348 mChannelCount(channelCount),
349 mInputFormat(inputFormat),
350 mOutputFormat(outputFormat)
351{
352 ALOGV("ReformatBufferProvider(%p)(%u, %#x, %#x)",
353 this, channelCount, inputFormat, outputFormat);
354}
355
356void ReformatBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
357{
358 memcpy_by_audio_format(dst, mOutputFormat, src, mInputFormat, frames * mChannelCount);
359}
360
361// ----------------------------------------------------------------------------
362} // namespace android