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