blob: 82bb49622aedcbb30639de99ff19eb06758da9c4 [file] [log] [blame]
Ramjee Singh63839662017-05-10 15:27:22 +05301/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
Dhananjay Kumar1c978df2015-09-04 13:44:59 +05302 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29#define LOG_TAG "audio_pp_asphere"
30/*#define LOG_NDEBUG 0*/
31
32#include <errno.h>
33#include <fcntl.h>
34#include <stdlib.h>
35#include <unistd.h>
36#include <stdbool.h>
37#include <sys/stat.h>
38#include <cutils/log.h>
39#include <cutils/list.h>
40#include <cutils/str_parms.h>
41#include <cutils/properties.h>
42#include <hardware/audio_effect.h>
Vinay Vermaaddfa4a2018-04-29 14:03:38 +053043#include <pthread.h>
Dhananjay Kumar1c978df2015-09-04 13:44:59 +053044#include "bundle.h"
45#include "equalizer.h"
46#include "bass_boost.h"
47#include "virtualizer.h"
48#include "reverb.h"
49#include "asphere.h"
50
51#define ASPHERE_MIXER_NAME "MSM ASphere Set Param"
52
53#define AUDIO_PARAMETER_KEY_ASPHERE_STATUS "asphere_status"
54#define AUDIO_PARAMETER_KEY_ASPHERE_ENABLE "asphere_enable"
55#define AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH "asphere_strength"
56
57#define AUDIO_ASPHERE_EVENT_NODE "/data/misc/audio_pp/event_node"
58
59enum {
60 ASPHERE_ACTIVE = 0,
61 ASPHERE_SUSPENDED,
62 ASPHERE_ERROR
63};
64
Vatsal Buchaa1358992018-11-14 13:25:08 +053065#ifdef AUDIO_FEATURE_ENABLED_GCOV
66extern void __gcov_flush();
67static void enable_gcov()
68{
69 __gcov_flush();
70}
71#else
72static void enable_gcov()
73{
74}
75#endif
76
Dhananjay Kumar1c978df2015-09-04 13:44:59 +053077struct asphere_module {
78 bool enabled;
79 int status;
80 int strength;
81 pthread_mutex_t lock;
82 int init_status;
83};
84
85static struct asphere_module asphere;
86pthread_once_t asphere_once = PTHREAD_ONCE_INIT;
87
88static int asphere_create_app_notification_node(void)
89{
90 int fd;
91 if ((fd = open(AUDIO_ASPHERE_EVENT_NODE, O_CREAT|O_TRUNC|O_WRONLY,
92 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
93 ALOGE("creating notification node failed %d", errno);
94 return -EINVAL;
95 }
96 chmod(AUDIO_ASPHERE_EVENT_NODE, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH);
97 close(fd);
98 ALOGD("%s: successfully created notification node %s",
99 __func__, AUDIO_ASPHERE_EVENT_NODE);
100 return 0;
101}
102
103static int asphere_notify_app(void)
104{
105 int fd;
106 if ((fd = open(AUDIO_ASPHERE_EVENT_NODE, O_TRUNC|O_WRONLY)) < 0) {
107 ALOGE("opening notification node failed %d", errno);
108 return -EINVAL;
109 }
110 close(fd);
111 ALOGD("%s: successfully opened notification node", __func__);
112 return 0;
113}
114
115static int asphere_get_values_from_mixer(void)
116{
Manish Dewangan338c50a2017-09-12 15:22:03 +0530117 int ret = 0;
118 long val[2] = {-1, -1};
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530119 struct mixer_ctl *ctl = NULL;
120 struct mixer *mixer = mixer_open(MIXER_CARD);
121 if (mixer)
122 ctl = mixer_get_ctl_by_name(mixer, ASPHERE_MIXER_NAME);
123 if (!ctl) {
124 ALOGE("%s: could not get ctl for mixer cmd - %s",
125 __func__, ASPHERE_MIXER_NAME);
126 return -EINVAL;
127 }
128 ret = mixer_ctl_get_array(ctl, val, sizeof(val)/sizeof(val[0]));
129 if (!ret) {
130 asphere.enabled = (val[0] == 0) ? false : true;
131 asphere.strength = val[1];
132 }
133 ALOGD("%s: returned %d, enabled:%d, strength:%d",
134 __func__, ret, val[0], val[1]);
135
136 return ret;
137}
138
139static int asphere_set_values_to_mixer(void)
140{
Manish Dewangan338c50a2017-09-12 15:22:03 +0530141 int ret = 0;
142 long val[2] = {-1, -1};
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530143 struct mixer_ctl *ctl = NULL;
144 struct mixer *mixer = mixer_open(MIXER_CARD);
145 if (mixer)
146 ctl = mixer_get_ctl_by_name(mixer, ASPHERE_MIXER_NAME);
147 if (!ctl) {
148 ALOGE("%s: could not get ctl for mixer cmd - %s",
149 __func__, ASPHERE_MIXER_NAME);
150 return -EINVAL;
151 }
152 val[0] = ((asphere.status == ASPHERE_ACTIVE) && asphere.enabled) ? 1 : 0;
153 val[1] = asphere.strength;
154
155 ret = mixer_ctl_set_array(ctl, val, sizeof(val)/sizeof(val[0]));
156 ALOGD("%s: returned %d, enabled:%d, strength:%d",
157 __func__, ret, val[0], val[1]);
158
159 return ret;
160}
161
162static void asphere_init_once() {
163 ALOGD("%s", __func__);
164 pthread_mutex_init(&asphere.lock, NULL);
165 asphere.init_status = 1;
166 asphere_get_values_from_mixer();
167 asphere_create_app_notification_node();
168}
169
170static int asphere_init() {
171 pthread_once(&asphere_once, asphere_init_once);
Vatsal Buchaa1358992018-11-14 13:25:08 +0530172 enable_gcov();
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530173 return asphere.init_status;
174}
175
176void asphere_set_parameters(struct str_parms *parms)
177{
178 int ret = 0;
179 bool enable = false;
180 int strength = -1;
181 char value[32] = {0};
182 char propValue[PROPERTY_VALUE_MAX] = {0};
183 bool set_enable = false, set_strength = false;
184
Ramjee Singh63839662017-05-10 15:27:22 +0530185 if (!property_get("vendor.audio.pp.asphere.enabled", propValue, "false") ||
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530186 (strncmp("true", propValue, 4) != 0)) {
187 ALOGV("%s: property not set!!! not doing anything", __func__);
188 return;
189 }
190 if (asphere_init() != 1) {
191 ALOGW("%s: init check failed!!!", __func__);
192 return;
193 }
194
195 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
196 value, sizeof(value));
197 if (ret > 0) {
198 enable = (atoi(value) == 1) ? true : false;
199 set_enable = true;
200 }
201
202 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
203 value, sizeof(value));
204 if (ret > 0) {
205 strength = atoi(value);
206 if (strength >= 0 && strength <= 1000)
207 set_strength = true;
208 }
209
210 if (set_enable || set_strength) {
211 pthread_mutex_lock(&asphere.lock);
212 asphere.enabled = set_enable ? enable : asphere.enabled;
213 asphere.strength = set_strength ? strength : asphere.strength;
214 ret = asphere_set_values_to_mixer();
215 pthread_mutex_unlock(&asphere.lock);
216 ALOGV("%s: exit ret %d", __func__, ret);
217 }
218}
219
220void asphere_get_parameters(struct str_parms *query,
221 struct str_parms *reply)
222{
223 char value[32] = {0};
224 char propValue[PROPERTY_VALUE_MAX] = {0};
225 int get_status, get_enable, get_strength, ret;
226
Ramjee Singh63839662017-05-10 15:27:22 +0530227 if (!property_get("vendor.audio.pp.asphere.enabled", propValue, "false") ||
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530228 (strncmp("true", propValue, 4) != 0)) {
229 ALOGV("%s: property not set!!! not doing anything", __func__);
230 return;
231 }
232 if (asphere_init() != 1) {
233 ALOGW("%s: init check failed!!!", __func__);
234 return;
235 }
236
237 ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ASPHERE_STATUS,
238 value, sizeof(value));
239 if (ret >= 0) {
240 str_parms_add_int(reply, AUDIO_PARAMETER_KEY_ASPHERE_STATUS,
241 asphere.status);
242 }
243
244 ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
245 value, sizeof(value));
246 if (ret >= 0) {
247 str_parms_add_int(reply, AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
248 asphere.enabled ? 1 : 0);
249 }
250
251 ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
252 value, sizeof(value));
253 if (ret >= 0) {
254 str_parms_add_int(reply, AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
255 asphere.strength);
256 }
257}
258
259static bool effect_needs_asphere_concurrency_handling(effect_context_t *context)
260{
261 if (memcmp(&context->desc->type,
262 &equalizer_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
263 memcmp(&context->desc->type,
264 &bassboost_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
265 memcmp(&context->desc->type,
266 &virtualizer_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
267 memcmp(&context->desc->type,
268 &ins_preset_reverb_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
269 memcmp(&context->desc->type,
270 &ins_env_reverb_descriptor.type, sizeof(effect_uuid_t)) == 0)
271 return true;
272
273 return false;
274}
275
276void handle_asphere_on_effect_enabled(bool enable,
277 effect_context_t *context,
278 struct listnode *created_effects)
279{
280 struct listnode *node;
281 char propValue[PROPERTY_VALUE_MAX] = {0};
282
283 ALOGV("%s: effect %0x", __func__, context->desc->type.timeLow);
Ramjee Singh63839662017-05-10 15:27:22 +0530284 if (!property_get("vendor.audio.pp.asphere.enabled", propValue, "false") ||
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530285 (strncmp("true", propValue, 4) != 0)) {
286 ALOGV("%s: property not set!!! not doing anything", __func__);
287 return;
288 }
289 if (asphere_init() != 1) {
290 ALOGW("%s: init check failed!!!", __func__);
291 return;
292 }
293
294 if (!effect_needs_asphere_concurrency_handling(context)) {
295 ALOGV("%s: effect %0x, do not need concurrency handling",
296 __func__, context->desc->type.timeLow);
297 return;
298 }
299
300 list_for_each(node, created_effects) {
301 effect_context_t *fx_ctxt = node_to_item(node,
302 effect_context_t,
303 effects_list_node);
304 if (fx_ctxt != NULL &&
305 effect_needs_asphere_concurrency_handling(fx_ctxt) == true &&
306 fx_ctxt != context && effect_is_active(fx_ctxt) == true) {
307 ALOGV("%s: found another effect %0x, skip processing %0x", __func__,
308 fx_ctxt->desc->type.timeLow, context->desc->type.timeLow);
309 return;
310 }
311 }
312 pthread_mutex_lock(&asphere.lock);
313 asphere.status = enable ? ASPHERE_SUSPENDED : ASPHERE_ACTIVE;
314 asphere_set_values_to_mixer();
315 asphere_notify_app();
316 pthread_mutex_unlock(&asphere.lock);
317}