blob: bbf105688ccfa56f4b062266b83162c83c20b6ec [file] [log] [blame]
Dhananjay Kumar1c978df2015-09-04 13:44:59 +05301/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
2 *
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{
104 int ret = 0, val[2] = {-1, -1};
105 struct mixer_ctl *ctl = NULL;
106 struct mixer *mixer = mixer_open(MIXER_CARD);
107 if (mixer)
108 ctl = mixer_get_ctl_by_name(mixer, ASPHERE_MIXER_NAME);
109 if (!ctl) {
110 ALOGE("%s: could not get ctl for mixer cmd - %s",
111 __func__, ASPHERE_MIXER_NAME);
112 return -EINVAL;
113 }
114 ret = mixer_ctl_get_array(ctl, val, sizeof(val)/sizeof(val[0]));
115 if (!ret) {
116 asphere.enabled = (val[0] == 0) ? false : true;
117 asphere.strength = val[1];
118 }
119 ALOGD("%s: returned %d, enabled:%d, strength:%d",
120 __func__, ret, val[0], val[1]);
121
122 return ret;
123}
124
125static int asphere_set_values_to_mixer(void)
126{
127 int ret = 0, val[2] = {-1, -1};
128 struct mixer_ctl *ctl = NULL;
129 struct mixer *mixer = mixer_open(MIXER_CARD);
130 if (mixer)
131 ctl = mixer_get_ctl_by_name(mixer, ASPHERE_MIXER_NAME);
132 if (!ctl) {
133 ALOGE("%s: could not get ctl for mixer cmd - %s",
134 __func__, ASPHERE_MIXER_NAME);
135 return -EINVAL;
136 }
137 val[0] = ((asphere.status == ASPHERE_ACTIVE) && asphere.enabled) ? 1 : 0;
138 val[1] = asphere.strength;
139
140 ret = mixer_ctl_set_array(ctl, val, sizeof(val)/sizeof(val[0]));
141 ALOGD("%s: returned %d, enabled:%d, strength:%d",
142 __func__, ret, val[0], val[1]);
143
144 return ret;
145}
146
147static void asphere_init_once() {
148 ALOGD("%s", __func__);
149 pthread_mutex_init(&asphere.lock, NULL);
150 asphere.init_status = 1;
151 asphere_get_values_from_mixer();
152 asphere_create_app_notification_node();
153}
154
155static int asphere_init() {
156 pthread_once(&asphere_once, asphere_init_once);
157 return asphere.init_status;
158}
159
160void asphere_set_parameters(struct str_parms *parms)
161{
162 int ret = 0;
163 bool enable = false;
164 int strength = -1;
165 char value[32] = {0};
166 char propValue[PROPERTY_VALUE_MAX] = {0};
167 bool set_enable = false, set_strength = false;
168
169 if (!property_get("audio.pp.asphere.enabled", propValue, "false") ||
170 (strncmp("true", propValue, 4) != 0)) {
171 ALOGV("%s: property not set!!! not doing anything", __func__);
172 return;
173 }
174 if (asphere_init() != 1) {
175 ALOGW("%s: init check failed!!!", __func__);
176 return;
177 }
178
179 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
180 value, sizeof(value));
181 if (ret > 0) {
182 enable = (atoi(value) == 1) ? true : false;
183 set_enable = true;
184 }
185
186 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
187 value, sizeof(value));
188 if (ret > 0) {
189 strength = atoi(value);
190 if (strength >= 0 && strength <= 1000)
191 set_strength = true;
192 }
193
194 if (set_enable || set_strength) {
195 pthread_mutex_lock(&asphere.lock);
196 asphere.enabled = set_enable ? enable : asphere.enabled;
197 asphere.strength = set_strength ? strength : asphere.strength;
198 ret = asphere_set_values_to_mixer();
199 pthread_mutex_unlock(&asphere.lock);
200 ALOGV("%s: exit ret %d", __func__, ret);
201 }
202}
203
204void asphere_get_parameters(struct str_parms *query,
205 struct str_parms *reply)
206{
207 char value[32] = {0};
208 char propValue[PROPERTY_VALUE_MAX] = {0};
209 int get_status, get_enable, get_strength, ret;
210
211 if (!property_get("audio.pp.asphere.enabled", propValue, "false") ||
212 (strncmp("true", propValue, 4) != 0)) {
213 ALOGV("%s: property not set!!! not doing anything", __func__);
214 return;
215 }
216 if (asphere_init() != 1) {
217 ALOGW("%s: init check failed!!!", __func__);
218 return;
219 }
220
221 ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ASPHERE_STATUS,
222 value, sizeof(value));
223 if (ret >= 0) {
224 str_parms_add_int(reply, AUDIO_PARAMETER_KEY_ASPHERE_STATUS,
225 asphere.status);
226 }
227
228 ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
229 value, sizeof(value));
230 if (ret >= 0) {
231 str_parms_add_int(reply, AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
232 asphere.enabled ? 1 : 0);
233 }
234
235 ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
236 value, sizeof(value));
237 if (ret >= 0) {
238 str_parms_add_int(reply, AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
239 asphere.strength);
240 }
241}
242
243static bool effect_needs_asphere_concurrency_handling(effect_context_t *context)
244{
245 if (memcmp(&context->desc->type,
246 &equalizer_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
247 memcmp(&context->desc->type,
248 &bassboost_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
249 memcmp(&context->desc->type,
250 &virtualizer_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
251 memcmp(&context->desc->type,
252 &ins_preset_reverb_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
253 memcmp(&context->desc->type,
254 &ins_env_reverb_descriptor.type, sizeof(effect_uuid_t)) == 0)
255 return true;
256
257 return false;
258}
259
260void handle_asphere_on_effect_enabled(bool enable,
261 effect_context_t *context,
262 struct listnode *created_effects)
263{
264 struct listnode *node;
265 char propValue[PROPERTY_VALUE_MAX] = {0};
266
267 ALOGV("%s: effect %0x", __func__, context->desc->type.timeLow);
268 if (!property_get("audio.pp.asphere.enabled", propValue, "false") ||
269 (strncmp("true", propValue, 4) != 0)) {
270 ALOGV("%s: property not set!!! not doing anything", __func__);
271 return;
272 }
273 if (asphere_init() != 1) {
274 ALOGW("%s: init check failed!!!", __func__);
275 return;
276 }
277
278 if (!effect_needs_asphere_concurrency_handling(context)) {
279 ALOGV("%s: effect %0x, do not need concurrency handling",
280 __func__, context->desc->type.timeLow);
281 return;
282 }
283
284 list_for_each(node, created_effects) {
285 effect_context_t *fx_ctxt = node_to_item(node,
286 effect_context_t,
287 effects_list_node);
288 if (fx_ctxt != NULL &&
289 effect_needs_asphere_concurrency_handling(fx_ctxt) == true &&
290 fx_ctxt != context && effect_is_active(fx_ctxt) == true) {
291 ALOGV("%s: found another effect %0x, skip processing %0x", __func__,
292 fx_ctxt->desc->type.timeLow, context->desc->type.timeLow);
293 return;
294 }
295 }
296 pthread_mutex_lock(&asphere.lock);
297 asphere.status = enable ? ASPHERE_SUSPENDED : ASPHERE_ACTIVE;
298 asphere_set_values_to_mixer();
299 asphere_notify_app();
300 pthread_mutex_unlock(&asphere.lock);
301}