blob: e11cfc78d86b450303d6caa48238138d7ec28bd8 [file] [log] [blame]
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -07001/*
Dhananjay Kumar16ac9e52015-07-20 16:56:45 +05302 * Copyright (c) 2014-15, The Linux Foundation. All rights reserved.
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -07003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
28 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#define LOG_TAG "EffectsHwAcc"
32//#define LOG_NDEBUG 0
33
34#include <utils/Log.h>
35#include <media/EffectsFactoryApi.h>
36#include <audio_effects/effect_hwaccelerator.h>
37#include "EffectsHwAcc.h"
38
39namespace android {
40
41#define FRAME_SIZE(format) ((format == AUDIO_FORMAT_PCM_24_BIT_PACKED) ? \
42 3 /* bytes for 24 bit */ : \
43 (format == AUDIO_FORMAT_PCM_16_BIT) ? \
44 sizeof(uint16_t) : sizeof(uint8_t))
45// ----------------------------------------------------------------------------
46EffectsHwAcc::EffectsBufferProvider::EffectsBufferProvider()
47 : AudioBufferProvider(), mEffectsHandle(NULL),
48 mInputBuffer(NULL), mOutputBuffer(NULL),
49 mInputBufferFrameCountOffset(0)
50{
51}
52
53EffectsHwAcc::EffectsBufferProvider::~EffectsBufferProvider()
54{
55 ALOGV(" deleting HwAccEffBufferProvider");
56
57 if (mEffectsHandle)
58 EffectRelease(mEffectsHandle);
59 if (mInputBuffer)
60 free(mInputBuffer);
61 if (mOutputBuffer)
62 free(mOutputBuffer);
63}
64
65status_t EffectsHwAcc::EffectsBufferProvider::getNextBuffer(
66 AudioBufferProvider::Buffer *pBuffer,
67 int64_t pts)
68{
69 ALOGV("EffectsBufferProvider::getNextBuffer");
70
71 size_t reqInputFrameCount, frameCount, offset;
72 size_t reqOutputFrameCount = pBuffer->frameCount;
73 int ret = 0;
74
Dhananjay Kumar16ac9e52015-07-20 16:56:45 +053075 if (mTrackInputBufferProvider != NULL) {
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070076 while (1) {
77 reqInputFrameCount = ((reqOutputFrameCount *
78 mEffectsConfig.inputCfg.samplingRate)/
79 mEffectsConfig.outputCfg.samplingRate) +
80 (((reqOutputFrameCount *
81 mEffectsConfig.inputCfg.samplingRate)%
82 mEffectsConfig.outputCfg.samplingRate) ? 1 : 0);
83 ALOGV("InputFrameCount: %d, OutputFrameCount: %d, InputBufferFrameCountOffset: %d",
84 reqInputFrameCount, reqOutputFrameCount,
85 mInputBufferFrameCountOffset);
86 frameCount = reqInputFrameCount - mInputBufferFrameCountOffset;
87 offset = mInputBufferFrameCountOffset *
88 FRAME_SIZE(mEffectsConfig.inputCfg.format) *
89 popcount(mEffectsConfig.inputCfg.channels);
90 while (frameCount) {
91 pBuffer->frameCount = frameCount;
Dhananjay Kumar16ac9e52015-07-20 16:56:45 +053092 ret = mTrackInputBufferProvider->getNextBuffer(pBuffer, pts);
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -070093 if (ret == OK) {
94 int bytesInBuffer = pBuffer->frameCount *
95 FRAME_SIZE(mEffectsConfig.inputCfg.format) *
96 popcount(mEffectsConfig.inputCfg.channels);
97 memcpy((char *)mInputBuffer+offset, pBuffer->i8, bytesInBuffer);
98 frameCount -= pBuffer->frameCount;
99 mInputBufferFrameCountOffset += pBuffer->frameCount;
100 offset += bytesInBuffer;
Dhananjay Kumar16ac9e52015-07-20 16:56:45 +0530101 mTrackInputBufferProvider->releaseBuffer(pBuffer);
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700102 } else
103 break;
104 }
105 if (ret == OK) {
106 mEffectsConfig.inputCfg.buffer.frameCount = reqInputFrameCount;
107 mEffectsConfig.inputCfg.buffer.raw = (void *)mInputBuffer;
108 mEffectsConfig.outputCfg.buffer.frameCount = reqOutputFrameCount;
109 mEffectsConfig.outputCfg.buffer.raw = (void *)mOutputBuffer;
110
111 ret = (*mEffectsHandle)->process(mEffectsHandle,
112 &mEffectsConfig.inputCfg.buffer,
113 &mEffectsConfig.outputCfg.buffer);
114 if (ret == -ENODATA) {
115 ALOGV("Continue to provide more data for initial buffering");
116 mInputBufferFrameCountOffset -= reqInputFrameCount;
117 continue;
118 }
119 if (ret > 0)
120 mInputBufferFrameCountOffset -= reqInputFrameCount;
121 pBuffer->raw = (void *)mOutputBuffer;
122 pBuffer->frameCount = reqOutputFrameCount;
123 }
124 return ret;
125 }
126 } else {
127 ALOGE("EffBufferProvider::getNextBuffer() error: NULL track buffer provider");
128 return NO_INIT;
129 }
130}
131
132void EffectsHwAcc::EffectsBufferProvider::releaseBuffer(
133 AudioBufferProvider::Buffer *pBuffer)
134{
135 ALOGV("EffBufferProvider::releaseBuffer()");
Dhananjay Kumar16ac9e52015-07-20 16:56:45 +0530136 if (this->mTrackInputBufferProvider != NULL) {
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700137 pBuffer->frameCount = 0;
138 pBuffer->raw = NULL;
139 } else {
140 ALOGE("HwAccEffectsBufferProvider::releaseBuffer() error: NULL track buffer provider");
141 }
142}
143
144EffectsHwAcc::EffectsHwAcc(uint32_t sampleRate)
145 : mEnabled(false), mFd(-1), mBufferProvider(NULL),
146 mInputSampleRate(sampleRate), mOutputSampleRate(sampleRate)
147{
148}
149
150EffectsHwAcc::~EffectsHwAcc()
151{
152 ALOGV("deleting EffectsHwAcc");
153
154 if (mBufferProvider)
155 delete mBufferProvider;
156}
157
158void EffectsHwAcc::setSampleRate(uint32_t inpSR, uint32_t outSR)
159{
160 mInputSampleRate = inpSR;
161 mOutputSampleRate = outSR;
162}
163
164void EffectsHwAcc::unprepareEffects(AudioBufferProvider **bufferProvider)
165{
166 ALOGV("EffectsHwAcc::unprepareEffects");
167
168 EffectsBufferProvider *pHwAccbp = mBufferProvider;
169 if (mBufferProvider != NULL) {
170 ALOGV(" deleting h/w accelerator EffectsBufferProvider");
171 int cmdStatus, status;
172 uint32_t replySize = sizeof(int);
173
174 replySize = sizeof(int);
175 status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
176 EFFECT_CMD_DISABLE,
177 0 /*cmdSize*/, NULL /*pCmdData*/,
178 &replySize, &cmdStatus /*pReplyData*/);
179 if ((status != 0) || (cmdStatus != 0))
180 ALOGE("error %d while enabling hw acc effects", status);
181
182 *bufferProvider = pHwAccbp->mTrackBufferProvider;
183 delete mBufferProvider;
184
185 mBufferProvider = NULL;
186 } else {
187 ALOGV(" nothing to do, no h/w accelerator effects to delete");
188 }
189 mEnabled = false;
190}
191
Dhananjay Kumar16ac9e52015-07-20 16:56:45 +0530192status_t EffectsHwAcc::prepareEffects(AudioBufferProvider **inputBufferProvider,
193 AudioBufferProvider **bufferProvider,
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700194 int sessionId,
195 audio_channel_mask_t channelMask,
196 int frameCount)
197{
198 ALOGV("EffectsHwAcc::prepareAccEffects");
199
200 // discard the previous hw acc effects if there was one
201 unprepareEffects(bufferProvider);
202
203 EffectsBufferProvider* pHwAccbp = new EffectsBufferProvider();
204 int32_t status;
205 int cmdStatus;
206 uint32_t replySize;
207 uint32_t size = (sizeof(effect_param_t) + 2 * sizeof(int32_t) - 1) /
208 (sizeof(uint32_t) + 1);
209 uint32_t buf32[size];
210 effect_param_t *param = (effect_param_t *)buf32;
211
212 uint32_t i, numEffects = 0;
213 effect_descriptor_t hwAccFxDesc;
214 int ret = EffectQueryNumberEffects(&numEffects);
215 if (ret != 0) {
216 ALOGE("AudioMixer() error %d querying number of effects", ret);
217 goto noEffectsForActiveTrack;
218 }
219 ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
220
221 for (i = 0 ; i < numEffects ; i++) {
222 if (EffectQueryEffect(i, &hwAccFxDesc) == 0) {
223 if (memcmp(&hwAccFxDesc.type, EFFECT_UIID_HWACCELERATOR,
224 sizeof(effect_uuid_t)) == 0) {
225 ALOGI("found effect \"%s\" from %s",
226 hwAccFxDesc.name, hwAccFxDesc.implementor);
227 break;
228 }
229 }
230 }
231 if (i == numEffects) {
232 ALOGW("H/W accelerated effects library not found");
233 goto noEffectsForActiveTrack;
234 }
235 if (EffectCreate(&hwAccFxDesc.uuid, sessionId, -1 /*ioId not relevant here*/,
236 &pHwAccbp->mEffectsHandle) != 0) {
237 ALOGE("prepareEffects fails: error creating effect");
238 goto noEffectsForActiveTrack;
239 }
240
241 // channel input configuration will be overridden per-track
242 pHwAccbp->mEffectsConfig.inputCfg.channels = channelMask;
243 pHwAccbp->mEffectsConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
244 pHwAccbp->mEffectsConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
245 pHwAccbp->mEffectsConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
246 pHwAccbp->mEffectsConfig.inputCfg.samplingRate = mInputSampleRate;
247 pHwAccbp->mEffectsConfig.outputCfg.samplingRate = mOutputSampleRate;
248 pHwAccbp->mEffectsConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
249 pHwAccbp->mEffectsConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
250 pHwAccbp->mEffectsConfig.outputCfg.buffer.frameCount = frameCount;
251 pHwAccbp->mEffectsConfig.inputCfg.mask = EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS |
252 EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE;
253 pHwAccbp->mEffectsConfig.outputCfg.mask = pHwAccbp->mEffectsConfig.inputCfg.mask;
254
255 // Configure hw acc effects
256 replySize = sizeof(int);
257 status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
258 EFFECT_CMD_SET_CONFIG,
259 sizeof(effect_config_t) /*cmdSize*/,
260 &pHwAccbp->mEffectsConfig /*pCmdData*/,
261 &replySize, &cmdStatus /*pReplyData*/);
262 if ((status != 0) || (cmdStatus != 0)) {
263 ALOGE("error %d while configuring h/w acc effects", status);
264 goto noEffectsForActiveTrack;
265 }
266 replySize = sizeof(int);
267 status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
268 EFFECT_CMD_HW_ACC,
269 sizeof(frameCount) /*cmdSize*/,
270 &frameCount /*pCmdData*/,
271 &replySize,
272 &cmdStatus /*pReplyData*/);
273 if ((status != 0) || (cmdStatus != 0)) {
274 ALOGE("error %d while enabling h/w acc effects", status);
275 goto noEffectsForActiveTrack;
276 }
277 replySize = sizeof(int);
278 status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
279 EFFECT_CMD_ENABLE,
280 0 /*cmdSize*/, NULL /*pCmdData*/,
281 &replySize, &cmdStatus /*pReplyData*/);
282 if ((status != 0) || (cmdStatus != 0)) {
283 ALOGE("error %d while enabling h/w acc effects", status);
284 goto noEffectsForActiveTrack;
285 }
286
287 param->psize = sizeof(int32_t);
288 *(int32_t *)param->data = HW_ACCELERATOR_FD;
289 param->vsize = sizeof(int32_t);
290 replySize = sizeof(effect_param_t) +
291 ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) +
292 param->vsize;
293 status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
294 EFFECT_CMD_GET_PARAM,
295 sizeof(effect_param_t) + param->psize,
296 param, &replySize, param);
297 if ((param->status != 0) || (*(int32_t *)(param->data + sizeof(int32_t)) <= 0)) {
298 ALOGE("error %d while enabling h/w acc effects", status);
299 goto noEffectsForActiveTrack;
300 }
301 mFd = *(int32_t *)(param->data + sizeof(int32_t));
302
303 pHwAccbp->mInputBuffer = calloc(6*frameCount,
304 /* 6 times buffering to account for an input of
305 192kHz to an output of 32kHz - may be a least
306 sampling rate of rendering device */
307 FRAME_SIZE(pHwAccbp->mEffectsConfig.inputCfg.format) *
308 popcount(channelMask));
309 if (!pHwAccbp->mInputBuffer)
310 goto noEffectsForActiveTrack;
311
312 pHwAccbp->mOutputBuffer = calloc(frameCount,
313 FRAME_SIZE(pHwAccbp->mEffectsConfig.outputCfg.format) *
314 popcount(AUDIO_CHANNEL_OUT_STEREO));
315 if (!pHwAccbp->mOutputBuffer) {
316 free(pHwAccbp->mInputBuffer);
317 goto noEffectsForActiveTrack;
318 }
319 // initialization successful:
Dhananjay Kumar16ac9e52015-07-20 16:56:45 +0530320 // - keep backup of track's buffer provider
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700321 pHwAccbp->mTrackBufferProvider = *bufferProvider;
Dhananjay Kumar16ac9e52015-07-20 16:56:45 +0530322 pHwAccbp->mTrackInputBufferProvider = *inputBufferProvider;
323 // - we'll use the hw acc effect integrated inside this track's buffer provider,
324 // and we'll use it as the track's buffer provider
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700325 mBufferProvider = pHwAccbp;
326 *bufferProvider = pHwAccbp;
327
328 mEnabled = true;
329 return NO_ERROR;
330
331noEffectsForActiveTrack:
332 delete pHwAccbp;
333 mBufferProvider = NULL;
334 return NO_INIT;
335}
336
Dhananjay Kumar16ac9e52015-07-20 16:56:45 +0530337void EffectsHwAcc::setBufferProvider(AudioBufferProvider **trackInputBufferProvider,
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700338 AudioBufferProvider **trackBufferProvider)
339{
340 ALOGV("setBufferProvider");
341 if (mBufferProvider &&
Dhananjay Kumar16ac9e52015-07-20 16:56:45 +0530342 (mBufferProvider->mTrackInputBufferProvider != *trackInputBufferProvider)) {
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700343 *trackBufferProvider = mBufferProvider;
Dhananjay Kumar16ac9e52015-07-20 16:56:45 +0530344 mBufferProvider->mTrackInputBufferProvider = *trackInputBufferProvider;
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700345 }
346}
347
Alexy Josephd464f3b2014-11-18 16:14:41 -0800348#ifdef HW_ACC_HPX
349void EffectsHwAcc::updateHPXState(uint32_t state)
350{
351 EffectsBufferProvider *pHwAccbp = mBufferProvider;
352 if (pHwAccbp) {
353 ALOGV("updateHPXState: %d", state);
354 int cmdStatus, status;
355 uint32_t replySize = sizeof(int);
356 uint32_t data = state;
357 uint32_t size = (sizeof(effect_param_t) + 2 * sizeof(int32_t));
358 uint32_t buf32[size];
359 effect_param_t *param = (effect_param_t *)buf32;
360
361 param->psize = sizeof(int32_t);
362 *(int32_t *)param->data = HW_ACCELERATOR_HPX_STATE;
363 param->vsize = sizeof(int32_t);
364 memcpy((param->data + param->psize), &data, param->vsize);
365 status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
366 EFFECT_CMD_SET_PARAM,
367 sizeof(effect_param_t) + param->psize +
368 param->vsize,
369 param, &replySize, &cmdStatus);
370
371 if ((status != 0) || (cmdStatus != 0))
372 ALOGE("error %d while updating HW ACC HPX BYPASS state", status);
373 }
374}
375#endif
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700376// ----------------------------------------------------------------------------
377}; // namespace android