1 /*
2 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
3 * Not a Contribution.
4 *
5 * Copyright (C) 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #define LOG_TAG "audio_hw_utils"
21 /* #define LOG_NDEBUG 0 */
22
23 #include <errno.h>
24 #include <cutils/properties.h>
25 #include <cutils/config_utils.h>
26 #include <stdlib.h>
27 #include <dlfcn.h>
28 #include <cutils/str_parms.h>
29 #include <cutils/log.h>
30 #include <cutils/misc.h>
31
32 #include "audio_hw.h"
33 #include "platform.h"
34 #include "platform_api.h"
35 #include "audio_extn.h"
36
37 #define AUDIO_OUTPUT_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_output_policy.conf"
38
39 #define OUTPUTS_TAG "outputs"
40
41 #define DYNAMIC_VALUE_TAG "dynamic"
42 #define FLAGS_TAG "flags"
43 #define FORMATS_TAG "formats"
44 #define SAMPLING_RATES_TAG "sampling_rates"
45 #define BIT_WIDTH_TAG "bit_width"
46 #define APP_TYPE_TAG "app_type"
47
48 #define STRING_TO_ENUM(string) { #string, string }
49 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
50
51 struct string_to_enum {
52 const char *name;
53 uint32_t value;
54 };
55
56 const struct string_to_enum s_flag_name_to_enum_table[] = {
57 STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
58 STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
59 STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST),
60 STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
61 STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
62 STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
63 #ifdef INCALL_MUSIC_ENABLED
64 STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_INCALL_MUSIC),
65 #endif
66 #ifdef COMPRESS_VOIP_ENABLED
67 STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_VOIP_RX),
68 #endif
69 };
70
71 const struct string_to_enum s_format_name_to_enum_table[] = {
72 STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
73 STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
74 STRING_TO_ENUM(AUDIO_FORMAT_MP3),
75 STRING_TO_ENUM(AUDIO_FORMAT_AAC),
76 STRING_TO_ENUM(AUDIO_FORMAT_VORBIS),
77 STRING_TO_ENUM(AUDIO_FORMAT_AMR_NB),
78 STRING_TO_ENUM(AUDIO_FORMAT_AMR_WB),
79 STRING_TO_ENUM(AUDIO_FORMAT_AC3),
80 STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
81 #ifdef FORMATS_ENABLED
82 STRING_TO_ENUM(AUDIO_FORMAT_DTS),
83 STRING_TO_ENUM(AUDIO_FORMAT_DTS_LBR),
84 STRING_TO_ENUM(AUDIO_FORMAT_WMA),
85 STRING_TO_ENUM(AUDIO_FORMAT_WMA_PRO),
86 STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADIF),
87 STRING_TO_ENUM(AUDIO_FORMAT_AMR_WB_PLUS),
88 STRING_TO_ENUM(AUDIO_FORMAT_EVRC),
89 STRING_TO_ENUM(AUDIO_FORMAT_EVRCB),
90 STRING_TO_ENUM(AUDIO_FORMAT_EVRCWB),
91 STRING_TO_ENUM(AUDIO_FORMAT_QCELP),
92 STRING_TO_ENUM(AUDIO_FORMAT_MP2),
93 STRING_TO_ENUM(AUDIO_FORMAT_EVRCNW),
94 STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT_OFFLOAD),
95 STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_OFFLOAD),
96 STRING_TO_ENUM(AUDIO_FORMAT_FLAC),
97 STRING_TO_ENUM(AUDIO_FORMAT_ALAC),
98 STRING_TO_ENUM(AUDIO_FORMAT_APE),
99 #endif
100 };
101
string_to_enum(const struct string_to_enum * table,size_t size,const char * name)102 static uint32_t string_to_enum(const struct string_to_enum *table, size_t size,
103 const char *name)
104 {
105 size_t i;
106 for (i = 0; i < size; i++) {
107 if (strcmp(table[i].name, name) == 0) {
108 ALOGV("%s found %s", __func__, table[i].name);
109 return table[i].value;
110 }
111 }
112 return 0;
113 }
114
parse_flag_names(char * name)115 static audio_output_flags_t parse_flag_names(char *name)
116 {
117 uint32_t flag = 0;
118 char *flag_name = strtok(name, "|");
119 while (flag_name != NULL) {
120 if (strlen(flag_name) != 0) {
121 flag |= string_to_enum(s_flag_name_to_enum_table,
122 ARRAY_SIZE(s_flag_name_to_enum_table),
123 flag_name);
124 }
125 flag_name = strtok(NULL, "|");
126 }
127
128 ALOGV("parse_flag_names: flag - %d", flag);
129 return (audio_output_flags_t)flag;
130 }
131
parse_format_names(char * name,struct streams_output_cfg * so_info)132 static void parse_format_names(char *name, struct streams_output_cfg *so_info)
133 {
134 struct stream_format *sf_info = NULL;
135 char *str = strtok(name, "|");
136
137 if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0)
138 return;
139
140 list_init(&so_info->format_list);
141 while (str != NULL) {
142 audio_format_t format = (audio_format_t)string_to_enum(s_format_name_to_enum_table,
143 ARRAY_SIZE(s_format_name_to_enum_table), str);
144 ALOGV("%s: format - %d", __func__, format);
145 if (format != 0) {
146 sf_info = (struct stream_format *)calloc(1, sizeof(struct stream_format));
147 if (sf_info == NULL)
148 break; /* return whatever was parsed */
149
150 sf_info->format = format;
151 list_add_tail(&so_info->format_list, &sf_info->list);
152 }
153 str = strtok(NULL, "|");
154 }
155 }
156
parse_sample_rate_names(char * name,struct streams_output_cfg * so_info)157 static void parse_sample_rate_names(char *name, struct streams_output_cfg *so_info)
158 {
159 struct stream_sample_rate *ss_info = NULL;
160 uint32_t sample_rate = 48000;
161 char *str = strtok(name, "|");
162
163 if (str != NULL && 0 == strcmp(str, DYNAMIC_VALUE_TAG))
164 return;
165
166 list_init(&so_info->sample_rate_list);
167 while (str != NULL) {
168 sample_rate = (uint32_t)strtol(str, (char **)NULL, 10);
169 ALOGV("%s: sample_rate - %d", __func__, sample_rate);
170 if (0 != sample_rate) {
171 ss_info = (struct stream_sample_rate *)calloc(1, sizeof(struct stream_sample_rate));
172 if (ss_info == NULL)
173 break; /* return whatever was parsed */
174
175 ss_info->sample_rate = sample_rate;
176 list_add_tail(&so_info->sample_rate_list, &ss_info->list);
177 }
178 str = strtok(NULL, "|");
179 }
180 }
181
parse_bit_width_names(char * name)182 static int parse_bit_width_names(char *name)
183 {
184 int bit_width = 16;
185 char *str = strtok(name, "|");
186
187 if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG))
188 bit_width = (int)strtol(str, (char **)NULL, 10);
189
190 ALOGV("%s: bit_width - %d", __func__, bit_width);
191 return bit_width;
192 }
193
parse_app_type_names(void * platform,char * name)194 static int parse_app_type_names(void *platform, char *name)
195 {
196 int app_type = platform_get_default_app_type(platform);
197 char *str = strtok(name, "|");
198
199 if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG))
200 app_type = (int)strtol(str, (char **)NULL, 10);
201
202 ALOGV("%s: app_type - %d", __func__, app_type);
203 return app_type;
204 }
205
update_streams_output_cfg_list(cnode * root,void * platform,struct listnode * streams_output_cfg_list)206 static void update_streams_output_cfg_list(cnode *root, void *platform,
207 struct listnode *streams_output_cfg_list)
208 {
209 cnode *node = root->first_child;
210 struct streams_output_cfg *so_info;
211
212 ALOGV("%s", __func__);
213 so_info = (struct streams_output_cfg *)calloc(1, sizeof(struct streams_output_cfg));
214
215 if (!so_info) {
216 ALOGE("failed to allocate mem for so_info list element");
217 return;
218 }
219
220 while (node) {
221 if (strcmp(node->name, FLAGS_TAG) == 0) {
222 so_info->flags = parse_flag_names((char *)node->value);
223 } else if (strcmp(node->name, FORMATS_TAG) == 0) {
224 parse_format_names((char *)node->value, so_info);
225 } else if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
226 so_info->app_type_cfg.sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
227 parse_sample_rate_names((char *)node->value, so_info);
228 } else if (strcmp(node->name, BIT_WIDTH_TAG) == 0) {
229 so_info->app_type_cfg.bit_width = parse_bit_width_names((char *)node->value);
230 } else if (strcmp(node->name, APP_TYPE_TAG) == 0) {
231 so_info->app_type_cfg.app_type = parse_app_type_names(platform, (char *)node->value);
232 }
233 node = node->next;
234 }
235 list_add_tail(streams_output_cfg_list, &so_info->list);
236 }
237
load_output(cnode * root,void * platform,struct listnode * streams_output_cfg_list)238 static void load_output(cnode *root, void *platform,
239 struct listnode *streams_output_cfg_list)
240 {
241 cnode *node = config_find(root, OUTPUTS_TAG);
242 if (node == NULL) {
243 ALOGE("%s: could not load output, node is NULL", __func__);
244 return;
245 }
246
247 node = node->first_child;
248 while (node) {
249 ALOGV("%s: loading output %s", __func__, node->name);
250 update_streams_output_cfg_list(node, platform, streams_output_cfg_list);
251 node = node->next;
252 }
253 }
254
send_app_type_cfg(void * platform,struct mixer * mixer,struct listnode * streams_output_cfg_list)255 static void send_app_type_cfg(void *platform, struct mixer *mixer,
256 struct listnode *streams_output_cfg_list)
257 {
258 int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {-1};
259 int length = 0, i, num_app_types = 0;
260 struct listnode *node;
261 bool update;
262 struct mixer_ctl *ctl = NULL;
263 const char *mixer_ctl_name = "App Type Config";
264 struct streams_output_cfg *so_info;
265
266 if (!mixer) {
267 ALOGE("%s: mixer is null",__func__);
268 return;
269 }
270 ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
271 if (!ctl) {
272 ALOGE("%s: Could not get ctl for mixer cmd - %s",__func__, mixer_ctl_name);
273 return;
274 }
275 if (streams_output_cfg_list == NULL) {
276 app_type_cfg[length++] = 1;
277 app_type_cfg[length++] = platform_get_default_app_type(platform);
278 app_type_cfg[length++] = 48000;
279 app_type_cfg[length++] = 16;
280 mixer_ctl_set_array(ctl, app_type_cfg, length);
281 return;
282 }
283
284 app_type_cfg[length++] = num_app_types;
285 list_for_each(node, streams_output_cfg_list) {
286 so_info = node_to_item(node, struct streams_output_cfg, list);
287 update = true;
288 for (i=0; i<length; i=i+3) {
289 if (app_type_cfg[i+1] == -1)
290 break;
291 else if (app_type_cfg[i+1] == so_info->app_type_cfg.app_type) {
292 update = false;
293 break;
294 }
295 }
296 if (update && ((length + 3) <= MAX_LENGTH_MIXER_CONTROL_IN_INT)) {
297 num_app_types += 1 ;
298 app_type_cfg[length++] = so_info->app_type_cfg.app_type;
299 app_type_cfg[length++] = so_info->app_type_cfg.sample_rate;
300 app_type_cfg[length++] = so_info->app_type_cfg.bit_width;
301 }
302 }
303 ALOGV("%s: num_app_types: %d", __func__, num_app_types);
304 if (num_app_types) {
305 app_type_cfg[0] = num_app_types;
306 mixer_ctl_set_array(ctl, app_type_cfg, length);
307 }
308 }
309
audio_extn_utils_update_streams_output_cfg_list(void * platform,struct mixer * mixer,struct listnode * streams_output_cfg_list)310 void audio_extn_utils_update_streams_output_cfg_list(void *platform,
311 struct mixer *mixer,
312 struct listnode *streams_output_cfg_list)
313 {
314 cnode *root;
315 char *data;
316
317 ALOGV("%s", __func__);
318 list_init(streams_output_cfg_list);
319 data = (char *)load_file(AUDIO_OUTPUT_POLICY_VENDOR_CONFIG_FILE, NULL);
320 if (data == NULL) {
321 send_app_type_cfg(platform, mixer, NULL);
322 ALOGE("%s: could not load output policy config file", __func__);
323 return;
324 }
325
326 root = config_node("", "");
327 if (root == NULL) {
328 ALOGE("cfg_list, NULL config root");
329 return;
330 }
331
332 config_load(root, data);
333 load_output(root, platform, streams_output_cfg_list);
334
335 send_app_type_cfg(platform, mixer, streams_output_cfg_list);
336 }
337
audio_extn_utils_dump_streams_output_cfg_list(struct listnode * streams_output_cfg_list)338 void audio_extn_utils_dump_streams_output_cfg_list(
339 struct listnode *streams_output_cfg_list)
340 {
341 int i=0;
342 struct listnode *node_i, *node_j;
343 struct streams_output_cfg *so_info;
344 struct stream_format *sf_info;
345 struct stream_sample_rate *ss_info;
346 ALOGV("%s", __func__);
347 list_for_each(node_i, streams_output_cfg_list) {
348 so_info = node_to_item(node_i, struct streams_output_cfg, list);
349 ALOGV("%s: flags-%d, output_sample_rate-%d, output_bit_width-%d, app_type-%d",
350 __func__, so_info->flags, so_info->app_type_cfg.sample_rate,
351 so_info->app_type_cfg.bit_width, so_info->app_type_cfg.app_type);
352 list_for_each(node_j, &so_info->format_list) {
353 sf_info = node_to_item(node_j, struct stream_format, list);
354 ALOGV("format-%x", sf_info->format);
355 }
356 list_for_each(node_j, &so_info->sample_rate_list) {
357 ss_info = node_to_item(node_j, struct stream_sample_rate, list);
358 ALOGV("sample rate-%d", ss_info->sample_rate);
359 }
360 }
361 }
362
audio_extn_utils_release_streams_output_cfg_list(struct listnode * streams_output_cfg_list)363 void audio_extn_utils_release_streams_output_cfg_list(
364 struct listnode *streams_output_cfg_list)
365 {
366 struct listnode *node_i, *node_j;
367 struct streams_output_cfg *so_info;
368 struct stream_format *sf_info;
369
370 ALOGV("%s", __func__);
371 while (!list_empty(streams_output_cfg_list)) {
372 node_i = list_head(streams_output_cfg_list);
373 so_info = node_to_item(node_i, struct streams_output_cfg, list);
374 while (!list_empty(&so_info->format_list)) {
375 node_j = list_head(&so_info->format_list);
376 list_remove(node_j);
377 free(node_to_item(node_j, struct stream_format, list));
378 }
379 while (!list_empty(&so_info->sample_rate_list)) {
380 node_j = list_head(&so_info->sample_rate_list);
381 list_remove(node_j);
382 free(node_to_item(node_j, struct stream_sample_rate, list));
383 }
384 list_remove(node_i);
385 free(node_to_item(node_i, struct streams_output_cfg, list));
386 }
387 }
388
set_output_cfg(struct streams_output_cfg * so_info,struct stream_app_type_cfg * app_type_cfg,uint32_t sample_rate,uint32_t bit_width)389 static bool set_output_cfg(struct streams_output_cfg *so_info,
390 struct stream_app_type_cfg *app_type_cfg,
391 uint32_t sample_rate, uint32_t bit_width)
392 {
393 struct listnode *node_i;
394 struct stream_sample_rate *ss_info;
395 list_for_each(node_i, &so_info->sample_rate_list) {
396 ss_info = node_to_item(node_i, struct stream_sample_rate, list);
397 if ((sample_rate <= ss_info->sample_rate) &&
398 (bit_width == so_info->app_type_cfg.bit_width)) {
399 app_type_cfg->app_type = so_info->app_type_cfg.app_type;
400 app_type_cfg->sample_rate = ss_info->sample_rate;
401 app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
402 ALOGV("%s app_type_cfg->app_type %d, app_type_cfg->sample_rate %d, app_type_cfg->bit_width %d",
403 __func__, app_type_cfg->app_type, app_type_cfg->sample_rate, app_type_cfg->bit_width);
404 return true;
405 }
406 }
407 /*
408 * Reiterate through the list assuming dafault sample rate.
409 * Handles scenario where input sample rate is higher
410 * than all sample rates in list for the input bit width.
411 */
412 sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
413 list_for_each(node_i, &so_info->sample_rate_list) {
414 ss_info = node_to_item(node_i, struct stream_sample_rate, list);
415 if ((sample_rate <= ss_info->sample_rate) &&
416 (bit_width == so_info->app_type_cfg.bit_width)) {
417 app_type_cfg->app_type = so_info->app_type_cfg.app_type;
418 app_type_cfg->sample_rate = sample_rate;
419 app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
420 ALOGV("%s Assuming default sample rate. app_type_cfg->app_type %d, app_type_cfg->sample_rate %d, app_type_cfg->bit_width %d",
421 __func__, app_type_cfg->app_type, app_type_cfg->sample_rate, app_type_cfg->bit_width);
422 return true;
423 }
424 }
425 return false;
426 }
427
audio_extn_utils_update_stream_app_type_cfg(void * platform,struct listnode * streams_output_cfg_list,audio_devices_t devices,audio_output_flags_t flags,audio_format_t format,uint32_t sample_rate,uint32_t bit_width,struct stream_app_type_cfg * app_type_cfg)428 void audio_extn_utils_update_stream_app_type_cfg(void *platform,
429 struct listnode *streams_output_cfg_list,
430 audio_devices_t devices,
431 audio_output_flags_t flags,
432 audio_format_t format,
433 uint32_t sample_rate,
434 uint32_t bit_width,
435 struct stream_app_type_cfg *app_type_cfg)
436 {
437 struct listnode *node_i, *node_j, *node_k;
438 struct streams_output_cfg *so_info;
439 struct stream_format *sf_info;
440 struct stream_sample_rate *ss_info;
441
442 if ((24 == bit_width) &&
443 (devices & AUDIO_DEVICE_OUT_SPEAKER)) {
444 int32_t bw = platform_get_snd_device_bit_width(SND_DEVICE_OUT_SPEAKER);
445 if (-ENOSYS != bw)
446 bit_width = (uint32_t)bw;
447 sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
448 ALOGI("%s Allowing 24-bit playback on speaker ONLY at default sampling rate", __func__);
449 }
450
451 ALOGV("%s: flags: %x, format: %x sample_rate %d",
452 __func__, flags, format, sample_rate);
453 list_for_each(node_i, streams_output_cfg_list) {
454 so_info = node_to_item(node_i, struct streams_output_cfg, list);
455 if (so_info->flags == flags) {
456 list_for_each(node_j, &so_info->format_list) {
457 sf_info = node_to_item(node_j, struct stream_format, list);
458 if (sf_info->format == format) {
459 if (set_output_cfg(so_info, app_type_cfg, sample_rate, bit_width))
460 return;
461 }
462 }
463 }
464 }
465 list_for_each(node_i, streams_output_cfg_list) {
466 so_info = node_to_item(node_i, struct streams_output_cfg, list);
467 if (so_info->flags == AUDIO_OUTPUT_FLAG_PRIMARY) {
468 ALOGV("Compatible output profile not found.");
469 app_type_cfg->app_type = so_info->app_type_cfg.app_type;
470 app_type_cfg->sample_rate = so_info->app_type_cfg.sample_rate;
471 app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
472 ALOGV("%s Default to primary output: App type: %d sample_rate %d",
473 __func__, so_info->app_type_cfg.app_type, app_type_cfg->sample_rate);
474 return;
475 }
476 }
477 ALOGW("%s: App type could not be selected. Falling back to default", __func__);
478 app_type_cfg->app_type = platform_get_default_app_type(platform);
479 app_type_cfg->sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
480 app_type_cfg->bit_width = 16;
481 }
482
audio_extn_utils_send_app_type_cfg(struct audio_usecase * usecase)483 int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase)
484 {
485 char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT];
486 int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT], len = 0, rc;
487 struct stream_out *out;
488 struct audio_device *adev;
489 struct mixer_ctl *ctl;
490 int pcm_device_id, acdb_dev_id, snd_device = usecase->out_snd_device;
491 int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
492
493 ALOGV("%s", __func__);
494
495 if (usecase->type != PCM_PLAYBACK) {
496 ALOGV("%s: not a playback path, no need to cfg app type", __func__);
497 rc = 0;
498 goto exit_send_app_type_cfg;
499 }
500 if ((usecase->id != USECASE_AUDIO_PLAYBACK_DEEP_BUFFER) &&
501 (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY) &&
502 (usecase->id != USECASE_AUDIO_PLAYBACK_MULTI_CH) &&
503 (usecase->id != USECASE_AUDIO_PLAYBACK_OFFLOAD)) {
504 ALOGV("%s: a playback path where app type cfg is not required", __func__);
505 rc = 0;
506 goto exit_send_app_type_cfg;
507 }
508 out = usecase->stream.out;
509 adev = out->dev;
510
511 snd_device = usecase->out_snd_device;
512
513 pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
514
515 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
516 "Audio Stream %d App Type Cfg", pcm_device_id);
517
518 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
519 if (!ctl) {
520 ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
521 mixer_ctl_name);
522 rc = -EINVAL;
523 goto exit_send_app_type_cfg;
524 }
525 snd_device = (snd_device == SND_DEVICE_OUT_SPEAKER) ?
526 audio_extn_get_spkr_prot_snd_device(snd_device) : snd_device;
527 acdb_dev_id = platform_get_snd_device_acdb_id(snd_device);
528 if (acdb_dev_id < 0) {
529 ALOGE("%s: Couldn't get the acdb dev id", __func__);
530 rc = -EINVAL;
531 goto exit_send_app_type_cfg;
532 }
533
534 if ((24 == usecase->stream.out->bit_width) &&
535 (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER)) {
536 sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
537 } else {
538 sample_rate = out->app_type_cfg.sample_rate;
539 }
540
541 app_type_cfg[len++] = out->app_type_cfg.app_type;
542 app_type_cfg[len++] = acdb_dev_id;
543 app_type_cfg[len++] = sample_rate;
544
545 mixer_ctl_set_array(ctl, app_type_cfg, len);
546 ALOGI("%s app_type %d, acdb_dev_id %d, sample_rate %d",
547 __func__, out->app_type_cfg.app_type, acdb_dev_id, sample_rate);
548 rc = 0;
549 exit_send_app_type_cfg:
550 return rc;
551 }
552
read_line_from_file(const char * path,char * buf,size_t count)553 int read_line_from_file(const char *path, char *buf, size_t count)
554 {
555 char * fgets_ret;
556 FILE * fd;
557 int rv;
558
559 fd = fopen(path, "r");
560 if (fd == NULL)
561 return -1;
562
563 fgets_ret = fgets(buf, (int)count, fd);
564 if (NULL != fgets_ret) {
565 rv = (int)strlen(buf);
566 } else {
567 rv = ferror(fd);
568 }
569 fclose(fd);
570
571 return rv;
572 }
573
audio_extn_utils_send_audio_calibration(struct audio_device * adev,struct audio_usecase * usecase)574 void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
575 struct audio_usecase *usecase)
576 {
577 int type = usecase->type;
578
579 if (type == PCM_PLAYBACK) {
580 struct stream_out *out = usecase->stream.out;
581 int snd_device = usecase->out_snd_device;
582 snd_device = (snd_device == SND_DEVICE_OUT_SPEAKER) ?
583 audio_extn_get_spkr_prot_snd_device(snd_device) : snd_device;
584 platform_send_audio_calibration(adev->platform, usecase,
585 out->app_type_cfg.app_type,
586 out->app_type_cfg.sample_rate);
587 }
588 if ((type == PCM_HFP_CALL) || (type == PCM_CAPTURE)) {
589 /* when app type is default. the sample rate is not used to send cal */
590 platform_send_audio_calibration(adev->platform, usecase,
591 platform_get_default_app_type(adev->platform),
592 48000);
593 }
594 }
595
596