blob: 0e4c55a762ed9e14cdda4c76eb0f78fabb6789af [file] [log] [blame]
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -07001/*
2 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
3 *
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
75 if (mTrackBufferProvider != NULL) {
76 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;
92 ret = mTrackBufferProvider->getNextBuffer(pBuffer, pts);
93 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;
101 mTrackBufferProvider->releaseBuffer(pBuffer);
102 } 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()");
136 if (this->mTrackBufferProvider != NULL) {
137 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
192status_t EffectsHwAcc::prepareEffects(AudioBufferProvider **bufferProvider,
193 int sessionId,
194 audio_channel_mask_t channelMask,
195 int frameCount)
196{
197 ALOGV("EffectsHwAcc::prepareAccEffects");
198
199 // discard the previous hw acc effects if there was one
200 unprepareEffects(bufferProvider);
201
202 EffectsBufferProvider* pHwAccbp = new EffectsBufferProvider();
203 int32_t status;
204 int cmdStatus;
205 uint32_t replySize;
206 uint32_t size = (sizeof(effect_param_t) + 2 * sizeof(int32_t) - 1) /
207 (sizeof(uint32_t) + 1);
208 uint32_t buf32[size];
209 effect_param_t *param = (effect_param_t *)buf32;
210
211 uint32_t i, numEffects = 0;
212 effect_descriptor_t hwAccFxDesc;
213 int ret = EffectQueryNumberEffects(&numEffects);
214 if (ret != 0) {
215 ALOGE("AudioMixer() error %d querying number of effects", ret);
216 goto noEffectsForActiveTrack;
217 }
218 ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
219
220 for (i = 0 ; i < numEffects ; i++) {
221 if (EffectQueryEffect(i, &hwAccFxDesc) == 0) {
222 if (memcmp(&hwAccFxDesc.type, EFFECT_UIID_HWACCELERATOR,
223 sizeof(effect_uuid_t)) == 0) {
224 ALOGI("found effect \"%s\" from %s",
225 hwAccFxDesc.name, hwAccFxDesc.implementor);
226 break;
227 }
228 }
229 }
230 if (i == numEffects) {
231 ALOGW("H/W accelerated effects library not found");
232 goto noEffectsForActiveTrack;
233 }
234 if (EffectCreate(&hwAccFxDesc.uuid, sessionId, -1 /*ioId not relevant here*/,
235 &pHwAccbp->mEffectsHandle) != 0) {
236 ALOGE("prepareEffects fails: error creating effect");
237 goto noEffectsForActiveTrack;
238 }
239
240 // channel input configuration will be overridden per-track
241 pHwAccbp->mEffectsConfig.inputCfg.channels = channelMask;
242 pHwAccbp->mEffectsConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
243 pHwAccbp->mEffectsConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
244 pHwAccbp->mEffectsConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
245 pHwAccbp->mEffectsConfig.inputCfg.samplingRate = mInputSampleRate;
246 pHwAccbp->mEffectsConfig.outputCfg.samplingRate = mOutputSampleRate;
247 pHwAccbp->mEffectsConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
248 pHwAccbp->mEffectsConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
249 pHwAccbp->mEffectsConfig.outputCfg.buffer.frameCount = frameCount;
250 pHwAccbp->mEffectsConfig.inputCfg.mask = EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS |
251 EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE;
252 pHwAccbp->mEffectsConfig.outputCfg.mask = pHwAccbp->mEffectsConfig.inputCfg.mask;
253
254 // Configure hw acc effects
255 replySize = sizeof(int);
256 status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
257 EFFECT_CMD_SET_CONFIG,
258 sizeof(effect_config_t) /*cmdSize*/,
259 &pHwAccbp->mEffectsConfig /*pCmdData*/,
260 &replySize, &cmdStatus /*pReplyData*/);
261 if ((status != 0) || (cmdStatus != 0)) {
262 ALOGE("error %d while configuring h/w acc effects", status);
263 goto noEffectsForActiveTrack;
264 }
265 replySize = sizeof(int);
266 status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
267 EFFECT_CMD_HW_ACC,
268 sizeof(frameCount) /*cmdSize*/,
269 &frameCount /*pCmdData*/,
270 &replySize,
271 &cmdStatus /*pReplyData*/);
272 if ((status != 0) || (cmdStatus != 0)) {
273 ALOGE("error %d while enabling h/w acc effects", status);
274 goto noEffectsForActiveTrack;
275 }
276 replySize = sizeof(int);
277 status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
278 EFFECT_CMD_ENABLE,
279 0 /*cmdSize*/, NULL /*pCmdData*/,
280 &replySize, &cmdStatus /*pReplyData*/);
281 if ((status != 0) || (cmdStatus != 0)) {
282 ALOGE("error %d while enabling h/w acc effects", status);
283 goto noEffectsForActiveTrack;
284 }
285
286 param->psize = sizeof(int32_t);
287 *(int32_t *)param->data = HW_ACCELERATOR_FD;
288 param->vsize = sizeof(int32_t);
289 replySize = sizeof(effect_param_t) +
290 ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) +
291 param->vsize;
292 status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
293 EFFECT_CMD_GET_PARAM,
294 sizeof(effect_param_t) + param->psize,
295 param, &replySize, param);
296 if ((param->status != 0) || (*(int32_t *)(param->data + sizeof(int32_t)) <= 0)) {
297 ALOGE("error %d while enabling h/w acc effects", status);
298 goto noEffectsForActiveTrack;
299 }
300 mFd = *(int32_t *)(param->data + sizeof(int32_t));
301
302 pHwAccbp->mInputBuffer = calloc(6*frameCount,
303 /* 6 times buffering to account for an input of
304 192kHz to an output of 32kHz - may be a least
305 sampling rate of rendering device */
306 FRAME_SIZE(pHwAccbp->mEffectsConfig.inputCfg.format) *
307 popcount(channelMask));
308 if (!pHwAccbp->mInputBuffer)
309 goto noEffectsForActiveTrack;
310
311 pHwAccbp->mOutputBuffer = calloc(frameCount,
312 FRAME_SIZE(pHwAccbp->mEffectsConfig.outputCfg.format) *
313 popcount(AUDIO_CHANNEL_OUT_STEREO));
314 if (!pHwAccbp->mOutputBuffer) {
315 free(pHwAccbp->mInputBuffer);
316 goto noEffectsForActiveTrack;
317 }
318 // initialization successful:
319 // - keep track of the real buffer provider in case it was set before
320 pHwAccbp->mTrackBufferProvider = *bufferProvider;
321 // - we'll use the hw acc effect integrated inside this
322 // track's buffer provider, and we'll use it as the track's buffer provider
323 mBufferProvider = pHwAccbp;
324 *bufferProvider = pHwAccbp;
325
326 mEnabled = true;
327 return NO_ERROR;
328
329noEffectsForActiveTrack:
330 delete pHwAccbp;
331 mBufferProvider = NULL;
332 return NO_INIT;
333}
334
335void EffectsHwAcc::setBufferProvider(AudioBufferProvider **bufferProvider,
336 AudioBufferProvider **trackBufferProvider)
337{
338 ALOGV("setBufferProvider");
339 if (mBufferProvider &&
340 (mBufferProvider->mTrackBufferProvider != *bufferProvider)) {
341 *trackBufferProvider = mBufferProvider;
342 mBufferProvider->mTrackBufferProvider = *bufferProvider;
343 }
344}
345
Alexy Josephd464f3b2014-11-18 16:14:41 -0800346#ifdef HW_ACC_HPX
347void EffectsHwAcc::updateHPXState(uint32_t state)
348{
349 EffectsBufferProvider *pHwAccbp = mBufferProvider;
350 if (pHwAccbp) {
351 ALOGV("updateHPXState: %d", state);
352 int cmdStatus, status;
353 uint32_t replySize = sizeof(int);
354 uint32_t data = state;
355 uint32_t size = (sizeof(effect_param_t) + 2 * sizeof(int32_t));
356 uint32_t buf32[size];
357 effect_param_t *param = (effect_param_t *)buf32;
358
359 param->psize = sizeof(int32_t);
360 *(int32_t *)param->data = HW_ACCELERATOR_HPX_STATE;
361 param->vsize = sizeof(int32_t);
362 memcpy((param->data + param->psize), &data, param->vsize);
363 status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
364 EFFECT_CMD_SET_PARAM,
365 sizeof(effect_param_t) + param->psize +
366 param->vsize,
367 param, &replySize, &cmdStatus);
368
369 if ((status != 0) || (cmdStatus != 0))
370 ALOGE("error %d while updating HW ACC HPX BYPASS state", status);
371 }
372}
373#endif
Subhash Chandra Bose Naripeddye40a7cd2014-06-03 19:42:41 -0700374// ----------------------------------------------------------------------------
375}; // namespace android