1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "audio_hw_audiozoom"
18 /*#define LOG_NDEBUG 0*/
19 
20 #include <errno.h>
21 #include <log/log.h>
22 #include <stdlib.h>
23 #include <expat.h>
24 #include <audio_hw.h>
25 #include <system/audio.h>
26 #include <platform_api.h>
27 #include "audio_extn.h"
28 
29 #include "audiozoom.h"
30 
31 #include <resolv.h>
32 
33 #define AUDIOZOOM_PRESET_FILE "/vendor/etc/audiozoom.xml"
34 
35 typedef struct qdsp_audiozoom_cfg {
36     uint32_t             topo_id;
37     uint32_t             module_id;
38     uint32_t             instance_id;
39     uint32_t             zoom_param_id;
40     uint32_t             wide_param_id;
41     uint32_t             dir_param_id;
42     uint32_t             app_type;
43 } qdsp_audiozoom_cfg_t;
44 
45 static qdsp_audiozoom_cfg_t qdsp_audiozoom;
46 
start_tag(void * userdata __unused,const XML_Char * tag_name,const XML_Char ** attr)47 static void start_tag(void *userdata __unused, const XML_Char *tag_name,
48                       const XML_Char **attr)
49 {
50     uint32_t index = 0;
51 
52     if (!attr) {
53         ALOGE("%s: NULL platform/tag_name/attr", __func__);
54         return;
55     }
56 
57     if (strcmp(tag_name, "topo") == 0) {
58         if (strcmp(attr[0], "id") == 0) {
59             if (attr[1])
60                 qdsp_audiozoom.topo_id = atoi(attr[1]);
61         }
62     } else if (strcmp(tag_name, "module") == 0) {
63         if (strcmp(attr[0], "id") == 0) {
64             if (attr[1])
65                 qdsp_audiozoom.module_id = atoi(attr[1]);
66         }
67     } else if (strcmp(tag_name, "param") == 0) {
68         while (attr[index] != NULL) {
69             if (strcmp(attr[index], "zoom_id") == 0) {
70                 index++;
71                 if (attr[index])
72                     qdsp_audiozoom.zoom_param_id = atoi(attr[index]);
73                 else
74                     break;
75             } else if (strcmp(attr[index], "wide_id") == 0) {
76                 index++;
77                 if (attr[index])
78                     qdsp_audiozoom.wide_param_id = atoi(attr[index]);
79                 else
80                     break;
81             } else if (strcmp(attr[index], "dir_id") == 0) {
82                 index++;
83                 if (attr[index])
84                     qdsp_audiozoom.dir_param_id = atoi(attr[index]);
85                 else
86                     break;
87             }
88             index++;
89         }
90     } else if (strcmp(tag_name, "app_type") == 0) {
91         if (strcmp(attr[0], "id") == 0) {
92             if (attr[1])
93                 qdsp_audiozoom.app_type = atoi(attr[1]);
94         }
95     } else if (strcmp(tag_name, "instance") == 0) {
96         if (strcmp(attr[0], "id") == 0) {
97             if (attr[1])
98                 qdsp_audiozoom.instance_id = atoi(attr[1]);
99         }
100     } else {
101         ALOGE("%s: %s is not a supported tag", __func__, tag_name);
102     }
103 
104     return;
105 }
106 
end_tag(void * userdata __unused,const XML_Char * tag_name)107 static void end_tag(void *userdata __unused, const XML_Char *tag_name)
108 {
109     if (strcmp(tag_name, "topo") == 0) {
110     } else if (strcmp(tag_name, "module") == 0) {
111     } else if (strcmp(tag_name, "param") == 0) {
112     } else if (strcmp(tag_name, "app_type") == 0) {
113     } else if (strcmp(tag_name, "instance") == 0) {
114     } else {
115         ALOGE("%s: %s is not a supported tag", __func__, tag_name);
116     }
117 }
118 
audio_extn_audiozoom_parse_info(const char * filename)119 static int audio_extn_audiozoom_parse_info(const char *filename)
120 {
121     XML_Parser      parser;
122     FILE            *file;
123     int             ret = 0;
124     int             bytes_read;
125     void            *buf;
126     static const uint32_t kBufSize = 1024;
127 
128     file = fopen(filename, "r");
129     if (!file) {
130         ALOGE("%s: Failed to open %s", __func__, filename);
131         ret = -ENODEV;
132         goto done;
133     }
134 
135     parser = XML_ParserCreate(NULL);
136     if (!parser) {
137         ALOGE("%s: Failed to create XML parser!", __func__);
138         ret = -ENODEV;
139         goto err_close_file;
140     }
141 
142     XML_SetElementHandler(parser, start_tag, end_tag);
143 
144     while (1) {
145         buf = XML_GetBuffer(parser, kBufSize);
146         if (buf == NULL) {
147             ALOGE("%s: XML_GetBuffer failed", __func__);
148             ret = -ENOMEM;
149             goto err_free_parser;
150         }
151 
152         bytes_read = fread(buf, 1, kBufSize, file);
153         if (bytes_read < 0) {
154             ALOGE("%s: fread failed, bytes read = %d", __func__, bytes_read);
155              ret = bytes_read;
156             goto err_free_parser;
157         }
158 
159         if (XML_ParseBuffer(parser, bytes_read,
160                             bytes_read == 0) == XML_STATUS_ERROR) {
161             ALOGE("%s: XML_ParseBuffer failed, for %s",
162                 __func__, filename);
163             ret = -EINVAL;
164             goto err_free_parser;
165         }
166 
167         if (bytes_read == 0)
168             break;
169     }
170 
171 err_free_parser:
172     XML_ParserFree(parser);
173 err_close_file:
174     fclose(file);
175 done:
176     return ret;
177 }
178 
audio_extn_audiozoom_set_microphone_direction(struct stream_in * in,audio_microphone_direction_t dir)179 int audio_extn_audiozoom_set_microphone_direction(
180     struct stream_in *in, audio_microphone_direction_t dir)
181 {
182     (void)in;
183     (void)dir;
184     return 0;
185 }
186 
audio_extn_audiozoom_set_microphone_field_dimension_zoom(struct stream_in * in,float zoom)187 static int audio_extn_audiozoom_set_microphone_field_dimension_zoom(
188     struct stream_in *in, float zoom)
189 {
190     struct audio_device *adev = in->dev;
191     struct str_parms *parms = str_parms_create();
192     /* The encoding process in b64_ntop represents 24-bit groups of input bits
193        as output strings of 4 encoded characters. */
194     char data[((sizeof(zoom) + 2) / 3) * 4 + 1] = {0};
195     int32_t ret;
196 
197     if (zoom > 1.0 || zoom < 0)
198         return -EINVAL;
199 
200     if (qdsp_audiozoom.topo_id == 0 || qdsp_audiozoom.module_id == 0 ||
201         qdsp_audiozoom.zoom_param_id == 0)
202         return -ENOSYS;
203 
204     str_parms_add_int(parms, "cal_devid", in->device);
205     str_parms_add_int(parms, "cal_apptype", in->app_type_cfg.app_type);
206     str_parms_add_int(parms, "cal_topoid", qdsp_audiozoom.topo_id);
207     str_parms_add_int(parms, "cal_moduleid", qdsp_audiozoom.module_id);
208     str_parms_add_int(parms, "cal_instanceid", qdsp_audiozoom.instance_id);
209     str_parms_add_int(parms, "cal_paramid", qdsp_audiozoom.zoom_param_id);
210 
211     ret = b64_ntop((uint8_t*)&zoom, sizeof(zoom), data, sizeof(data));
212     if (ret > 0) {
213         str_parms_add_str(parms, "cal_data", data);
214 
215         platform_set_parameters(adev->platform, parms);
216     } else {
217         ALOGE("%s: failed to convert data to string, ret %d", __func__, ret);
218     }
219 
220     str_parms_destroy(parms);
221 
222     return 0;
223 }
224 
audio_extn_audiozoom_set_microphone_field_dimension_wide_angle(struct stream_in * in,float zoom)225 static int audio_extn_audiozoom_set_microphone_field_dimension_wide_angle(
226     struct stream_in *in, float zoom)
227 {
228     (void)in;
229     (void)zoom;
230     return 0;
231 }
232 
audio_extn_audiozoom_set_microphone_field_dimension(struct stream_in * in,float zoom)233 int audio_extn_audiozoom_set_microphone_field_dimension(
234     struct stream_in *in, float zoom)
235 {
236     if (zoom > 1.0 || zoom < -1.0)
237         return -EINVAL;
238 
239     if (zoom >= 0 && zoom <= 1.0)
240         return audio_extn_audiozoom_set_microphone_field_dimension_zoom(in, zoom);
241 
242     if (zoom >= -1.0 && zoom <= 0)
243         return audio_extn_audiozoom_set_microphone_field_dimension_wide_angle(in, zoom);
244 
245     return 0;
246 }
247 
audio_extn_audiozoom_init()248 int audio_extn_audiozoom_init()
249 {
250     audio_extn_audiozoom_parse_info(AUDIOZOOM_PRESET_FILE);
251 
252     ALOGV("%s: topo_id=%d, module_id=%d, instance_id=%d, zoom__id=%d, dir_id=%d, app_type=%d",
253         __func__, qdsp_audiozoom.topo_id, qdsp_audiozoom.module_id, qdsp_audiozoom.instance_id,
254         qdsp_audiozoom.zoom_param_id, qdsp_audiozoom.dir_param_id,qdsp_audiozoom.app_type);
255 
256     return 0;
257 }
258