blob: 20ca694dcc40683c2508eacbc35ba08e9732f5ed [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
65struct asphere_module {
66 bool enabled;
67 int status;
68 int strength;
69 pthread_mutex_t lock;
70 int init_status;
71};
72
73static struct asphere_module asphere;
74pthread_once_t asphere_once = PTHREAD_ONCE_INIT;
75
76static int asphere_create_app_notification_node(void)
77{
78 int fd;
79 if ((fd = open(AUDIO_ASPHERE_EVENT_NODE, O_CREAT|O_TRUNC|O_WRONLY,
80 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
81 ALOGE("creating notification node failed %d", errno);
82 return -EINVAL;
83 }
84 chmod(AUDIO_ASPHERE_EVENT_NODE, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH);
85 close(fd);
86 ALOGD("%s: successfully created notification node %s",
87 __func__, AUDIO_ASPHERE_EVENT_NODE);
88 return 0;
89}
90
91static int asphere_notify_app(void)
92{
93 int fd;
94 if ((fd = open(AUDIO_ASPHERE_EVENT_NODE, O_TRUNC|O_WRONLY)) < 0) {
95 ALOGE("opening notification node failed %d", errno);
96 return -EINVAL;
97 }
98 close(fd);
99 ALOGD("%s: successfully opened notification node", __func__);
100 return 0;
101}
102
103static int asphere_get_values_from_mixer(void)
104{
Manish Dewangan338c50a2017-09-12 15:22:03 +0530105 int ret = 0;
106 long val[2] = {-1, -1};
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530107 struct mixer_ctl *ctl = NULL;
108 struct mixer *mixer = mixer_open(MIXER_CARD);
109 if (mixer)
110 ctl = mixer_get_ctl_by_name(mixer, ASPHERE_MIXER_NAME);
111 if (!ctl) {
112 ALOGE("%s: could not get ctl for mixer cmd - %s",
113 __func__, ASPHERE_MIXER_NAME);
114 return -EINVAL;
115 }
116 ret = mixer_ctl_get_array(ctl, val, sizeof(val)/sizeof(val[0]));
117 if (!ret) {
118 asphere.enabled = (val[0] == 0) ? false : true;
119 asphere.strength = val[1];
120 }
121 ALOGD("%s: returned %d, enabled:%d, strength:%d",
122 __func__, ret, val[0], val[1]);
123
124 return ret;
125}
126
127static int asphere_set_values_to_mixer(void)
128{
Manish Dewangan338c50a2017-09-12 15:22:03 +0530129 int ret = 0;
130 long val[2] = {-1, -1};
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530131 struct mixer_ctl *ctl = NULL;
132 struct mixer *mixer = mixer_open(MIXER_CARD);
133 if (mixer)
134 ctl = mixer_get_ctl_by_name(mixer, ASPHERE_MIXER_NAME);
135 if (!ctl) {
136 ALOGE("%s: could not get ctl for mixer cmd - %s",
137 __func__, ASPHERE_MIXER_NAME);
138 return -EINVAL;
139 }
140 val[0] = ((asphere.status == ASPHERE_ACTIVE) && asphere.enabled) ? 1 : 0;
141 val[1] = asphere.strength;
142
143 ret = mixer_ctl_set_array(ctl, val, sizeof(val)/sizeof(val[0]));
144 ALOGD("%s: returned %d, enabled:%d, strength:%d",
145 __func__, ret, val[0], val[1]);
146
147 return ret;
148}
149
150static void asphere_init_once() {
151 ALOGD("%s", __func__);
152 pthread_mutex_init(&asphere.lock, NULL);
153 asphere.init_status = 1;
154 asphere_get_values_from_mixer();
155 asphere_create_app_notification_node();
156}
157
158static int asphere_init() {
159 pthread_once(&asphere_once, asphere_init_once);
160 return asphere.init_status;
161}
162
163void asphere_set_parameters(struct str_parms *parms)
164{
165 int ret = 0;
166 bool enable = false;
167 int strength = -1;
168 char value[32] = {0};
169 char propValue[PROPERTY_VALUE_MAX] = {0};
170 bool set_enable = false, set_strength = false;
171
Ramjee Singh63839662017-05-10 15:27:22 +0530172 if (!property_get("vendor.audio.pp.asphere.enabled", propValue, "false") ||
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530173 (strncmp("true", propValue, 4) != 0)) {
174 ALOGV("%s: property not set!!! not doing anything", __func__);
175 return;
176 }
177 if (asphere_init() != 1) {
178 ALOGW("%s: init check failed!!!", __func__);
179 return;
180 }
181
182 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
183 value, sizeof(value));
184 if (ret > 0) {
185 enable = (atoi(value) == 1) ? true : false;
186 set_enable = true;
187 }
188
189 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
190 value, sizeof(value));
191 if (ret > 0) {
192 strength = atoi(value);
193 if (strength >= 0 && strength <= 1000)
194 set_strength = true;
195 }
196
197 if (set_enable || set_strength) {
198 pthread_mutex_lock(&asphere.lock);
199 asphere.enabled = set_enable ? enable : asphere.enabled;
200 asphere.strength = set_strength ? strength : asphere.strength;
201 ret = asphere_set_values_to_mixer();
202 pthread_mutex_unlock(&asphere.lock);
203 ALOGV("%s: exit ret %d", __func__, ret);
204 }
205}
206
207void asphere_get_parameters(struct str_parms *query,
208 struct str_parms *reply)
209{
210 char value[32] = {0};
211 char propValue[PROPERTY_VALUE_MAX] = {0};
212 int get_status, get_enable, get_strength, ret;
213
Ramjee Singh63839662017-05-10 15:27:22 +0530214 if (!property_get("vendor.audio.pp.asphere.enabled", propValue, "false") ||
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530215 (strncmp("true", propValue, 4) != 0)) {
216 ALOGV("%s: property not set!!! not doing anything", __func__);
217 return;
218 }
219 if (asphere_init() != 1) {
220 ALOGW("%s: init check failed!!!", __func__);
221 return;
222 }
223
224 ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ASPHERE_STATUS,
225 value, sizeof(value));
226 if (ret >= 0) {
227 str_parms_add_int(reply, AUDIO_PARAMETER_KEY_ASPHERE_STATUS,
228 asphere.status);
229 }
230
231 ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
232 value, sizeof(value));
233 if (ret >= 0) {
234 str_parms_add_int(reply, AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
235 asphere.enabled ? 1 : 0);
236 }
237
238 ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
239 value, sizeof(value));
240 if (ret >= 0) {
241 str_parms_add_int(reply, AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
242 asphere.strength);
243 }
244}
245
246static bool effect_needs_asphere_concurrency_handling(effect_context_t *context)
247{
248 if (memcmp(&context->desc->type,
249 &equalizer_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
250 memcmp(&context->desc->type,
251 &bassboost_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
252 memcmp(&context->desc->type,
253 &virtualizer_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
254 memcmp(&context->desc->type,
255 &ins_preset_reverb_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
256 memcmp(&context->desc->type,
257 &ins_env_reverb_descriptor.type, sizeof(effect_uuid_t)) == 0)
258 return true;
259
260 return false;
261}
262
263void handle_asphere_on_effect_enabled(bool enable,
264 effect_context_t *context,
265 struct listnode *created_effects)
266{
267 struct listnode *node;
268 char propValue[PROPERTY_VALUE_MAX] = {0};
269
270 ALOGV("%s: effect %0x", __func__, context->desc->type.timeLow);
Ramjee Singh63839662017-05-10 15:27:22 +0530271 if (!property_get("vendor.audio.pp.asphere.enabled", propValue, "false") ||
Dhananjay Kumar1c978df2015-09-04 13:44:59 +0530272 (strncmp("true", propValue, 4) != 0)) {
273 ALOGV("%s: property not set!!! not doing anything", __func__);
274 return;
275 }
276 if (asphere_init() != 1) {
277 ALOGW("%s: init check failed!!!", __func__);
278 return;
279 }
280
281 if (!effect_needs_asphere_concurrency_handling(context)) {
282 ALOGV("%s: effect %0x, do not need concurrency handling",
283 __func__, context->desc->type.timeLow);
284 return;
285 }
286
287 list_for_each(node, created_effects) {
288 effect_context_t *fx_ctxt = node_to_item(node,
289 effect_context_t,
290 effects_list_node);
291 if (fx_ctxt != NULL &&
292 effect_needs_asphere_concurrency_handling(fx_ctxt) == true &&
293 fx_ctxt != context && effect_is_active(fx_ctxt) == true) {
294 ALOGV("%s: found another effect %0x, skip processing %0x", __func__,
295 fx_ctxt->desc->type.timeLow, context->desc->type.timeLow);
296 return;
297 }
298 }
299 pthread_mutex_lock(&asphere.lock);
300 asphere.status = enable ? ASPHERE_SUSPENDED : ASPHERE_ACTIVE;
301 asphere_set_values_to_mixer();
302 asphere_notify_app();
303 pthread_mutex_unlock(&asphere.lock);
304}