blob: 3b846b7a6aef1403970403b2e961bfd2b74771d6 [file] [log] [blame]
wei.wang1e45cfd32023-07-10 08:33:46 +00001/*
2 * Copyright (C) 2023 Amlogic Corporation.
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#define LOG_TAG "AML_Audio_Setting"
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <stdint.h>
21#include <string.h>
22#include <unistd.h>
23#include <fcntl.h>
24#include <errno.h>
25#include <ctype.h>
26#include <poll.h>
27#include <sys/ioctl.h>
28#include <pthread.h>
29#include <linux/ioctl.h>
30#define __force
31#define __bitwise
32#define __user
33#include <sound/asound.h>
34#include "AML_Audio_Setting.h"
35#include <cutils/log.h>
36
37#ifndef SNDRV_CTL_ELEM_ID_NAME_MAXLEN
38#define SNDRV_CTL_ELEM_ID_NAME_MAXLEN 44
39#endif
haiyang.ren1882f702024-09-02 09:12:20 +000040#define DEFAULT_AML_SOUND_CARD 0
wei.wang1e45cfd32023-07-10 08:33:46 +000041/* TLV header size*/
haiyang.ren1882f702024-09-02 09:12:20 +000042#define TLV_HEADER_SIZE (2 * sizeof(unsigned int))
wei.wang1e45cfd32023-07-10 08:33:46 +000043
haiyang.ren1882f702024-09-02 09:12:20 +000044#define TDMC_GAIN "TDMOUT_C Software Gain"
45#define TDMB_GAIN "TDMOUT_B Software Gain"
46#define TDMA_GAIN "TDMOUT_A Software Gain"
47#define AML_CHIP_ID "AML chip id"
48#define AML_CHIP_ID_S1A 69
49#define AML_CHIP_ID_S4D 58
50
51#define HDMI_OUT_MUTE "Audio hdmi-out mute"
52#define DAC_DIGITAL_VOLUME "DAC Digital Playback Volume"
53#define DIGITAL_MODE "Audio Digital Mode"
54#define DRC_CONTROL "Audio DRC Control"
55#define HDMI_CON "Audio Output Select"
56#define SPDIF_FORMAT "Audio spdif format"
57
wei.wang1e45cfd32023-07-10 08:33:46 +000058#define DAC_DIGITAl_DEFAULT_VOLUME (251)
haiyang.ren1882f702024-09-02 09:12:20 +000059#define HEADPHONE_DAC_CHANNEL_NUM (2)
wei.wang1e45cfd32023-07-10 08:33:46 +000060
haiyang.ren1882f702024-09-02 09:12:20 +000061#define DRC_MODE_LINE 2
62#define DRC_MODE_RF 3
63#define DRC_MODE_BIT 0
64#define DRC_HIGH_CUT_BIT 3
65#define DRC_LOW_BST_BIT 16
haiyang.ren936bfc52023-09-18 05:46:24 +000066
wei.wang1e45cfd32023-07-10 08:33:46 +000067extern "C" {
68
69struct mixer_ctl {
70 struct mixer *mixer;
71 struct snd_ctl_elem_info *info;
72 char **ename;
73 bool info_retrieved;
74};
75
76struct mixer {
77 int fd;
78 struct snd_ctl_card_info card_info;
79 struct snd_ctl_elem_info *elem_info;
80 struct mixer_ctl *ctl;
81 unsigned int count;
82};
83
84/* Mixer control types */
85enum mixer_ctl_type {
86 MIXER_CTL_TYPE_BOOL,
87 MIXER_CTL_TYPE_INT,
88 MIXER_CTL_TYPE_ENUM,
89 MIXER_CTL_TYPE_BYTE,
90 MIXER_CTL_TYPE_IEC958,
91 MIXER_CTL_TYPE_INT64,
92 MIXER_CTL_TYPE_UNKNOWN,
93
94 MIXER_CTL_TYPE_MAX,
95};
96
97static pthread_mutex_t g_volume_lock = PTHREAD_MUTEX_INITIALIZER;
98static pthread_mutex_t g_mute_lock = PTHREAD_MUTEX_INITIALIZER;
haiyang.ren49ae2c82023-11-02 09:31:41 +000099static int reserved_volume = 30;
haiyang.ren260660b2024-08-20 07:00:28 +0000100static bool mute_status = false;
wei.wang158743372023-08-07 08:07:05 +0000101static int chip_id = 0;
wei.wang1e45cfd32023-07-10 08:33:46 +0000102
103static void _mixer_close(struct mixer *mixer)
104{
105 unsigned int n,m;
106
107 if (!mixer)
108 return;
109
110 if (mixer->fd >= 0)
111 close(mixer->fd);
112
113 if (mixer->ctl) {
114 for (n = 0; n < mixer->count; n++) {
115 if (mixer->ctl[n].ename) {
116 unsigned int max = mixer->ctl[n].info->value.enumerated.items;
117 for (m = 0; m < max; m++)
118 free(mixer->ctl[n].ename[m]);
119 free(mixer->ctl[n].ename);
120 }
121 }
122 free(mixer->ctl);
123 }
124
125 if (mixer->elem_info)
126 free(mixer->elem_info);
127
128 free(mixer);
129
130 /* TODO: verify frees */
131}
132
133static struct mixer *_mixer_open(unsigned int card)
134{
135 struct snd_ctl_elem_list elist;
136 struct snd_ctl_elem_id *eid = NULL;
137 struct mixer *mixer = NULL;
138 unsigned int n;
139 int fd;
140 char fn[256];
141
142 snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card);
143 fd = open(fn, O_RDWR);
144 if (fd < 0)
145 return 0;
146
147 memset(&elist, 0, sizeof(elist));
148 if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
149 goto fail;
150
151 mixer = (struct mixer *)calloc(1, sizeof(*mixer));
152 if (!mixer)
153 goto fail;
154
155 mixer->ctl = (struct mixer_ctl *)calloc(elist.count, sizeof(struct mixer_ctl));
156 mixer->elem_info = (struct snd_ctl_elem_info *)calloc(elist.count, sizeof(struct snd_ctl_elem_info));
157 if (!mixer->ctl || !mixer->elem_info)
158 goto fail;
159
160 if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0)
161 goto fail;
162
163 eid = (struct snd_ctl_elem_id *)calloc(elist.count, sizeof(struct snd_ctl_elem_id));
164 if (!eid)
165 goto fail;
166
167 mixer->count = elist.count;
168 mixer->fd = fd;
169 elist.space = mixer->count;
170 elist.pids = eid;
171 if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
172 goto fail;
173
174 for (n = 0; n < mixer->count; n++) {
175 struct mixer_ctl *ctl = mixer->ctl + n;
176
177 ctl->mixer = mixer;
178 ctl->info = mixer->elem_info + n;
179 ctl->info->id.numid = eid[n].numid;
180 strncpy((char *)ctl->info->id.name, (char *)eid[n].name,
181 SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
182 ctl->info->id.name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1] = 0;
183 }
184
185 free(eid);
186 return mixer;
187
188fail:
189 /* TODO: verify frees in failure case */
190 if (eid)
191 free(eid);
192 if (mixer)
193 _mixer_close(mixer);
194 else if (fd >= 0)
195 close(fd);
196 return 0;
197}
198
199static bool _mixer_ctl_get_elem_info(struct mixer_ctl* ctl)
200{
201 if (!ctl->info_retrieved) {
202 if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info) < 0)
203 return false;
204 ctl->info_retrieved = true;
205 }
206
207 if (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED || ctl->ename)
208 return true;
209
210 struct snd_ctl_elem_info tmp;
211 char** enames = (char**)calloc(ctl->info->value.enumerated.items, sizeof(char*));
212 if (!enames)
213 return false;
214
215 for (unsigned int i = 0; i < ctl->info->value.enumerated.items; i++) {
216 memset(&tmp, 0, sizeof(tmp));
217 tmp.id.numid = ctl->info->id.numid;
218 tmp.value.enumerated.item = i;
219 if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0)
220 goto fail;
221 enames[i] = strdup(tmp.value.enumerated.name);
222 if (!enames[i])
223 goto fail;
224 }
225 ctl->ename = enames;
226 return true;
227
228fail:
229 free(enames);
230 return false;
231}
232
233static const char *_mixer_get_name(struct mixer *mixer)
234{
235 return (const char *)mixer->card_info.name;
236}
237
238static unsigned int _mixer_get_num_ctls(struct mixer *mixer)
239{
240 if (!mixer)
241 return 0;
242
243 return mixer->count;
244}
245
246static struct mixer_ctl *_mixer_get_ctl(struct mixer *mixer, unsigned int id)
247{
248 struct mixer_ctl *ctl;
249
250 if (!mixer || (id >= mixer->count))
251 return NULL;
252
253 ctl = mixer->ctl + id;
254 if (!_mixer_ctl_get_elem_info(ctl))
255 return NULL;
256
257 return ctl;
258}
259
260static struct mixer_ctl *_mixer_get_ctl_by_name(struct mixer *mixer, const char *name)
261{
262 unsigned int n;
263
264 if (!mixer)
265 return NULL;
266
267 for (n = 0; n < mixer->count; n++)
268 if (!strcmp(name, (char*) mixer->elem_info[n].id.name))
269 return _mixer_get_ctl(mixer, n);
270
271 return NULL;
272}
273
274static void _mixer_ctl_update(struct mixer_ctl *ctl)
275{
276 ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info);
277}
278
279static const char *_mixer_ctl_get_name(struct mixer_ctl *ctl)
280{
281 if (!ctl)
282 return NULL;
283
284 return (const char *)ctl->info->id.name;
285}
286
287static enum mixer_ctl_type _mixer_ctl_get_type(struct mixer_ctl *ctl)
288{
289 if (!ctl)
290 return MIXER_CTL_TYPE_UNKNOWN;
291
292 switch (ctl->info->type) {
293 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return MIXER_CTL_TYPE_BOOL;
294 case SNDRV_CTL_ELEM_TYPE_INTEGER: return MIXER_CTL_TYPE_INT;
295 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return MIXER_CTL_TYPE_ENUM;
296 case SNDRV_CTL_ELEM_TYPE_BYTES: return MIXER_CTL_TYPE_BYTE;
297 case SNDRV_CTL_ELEM_TYPE_IEC958: return MIXER_CTL_TYPE_IEC958;
298 case SNDRV_CTL_ELEM_TYPE_INTEGER64: return MIXER_CTL_TYPE_INT64;
299 default: return MIXER_CTL_TYPE_UNKNOWN;
300 };
301}
302
303static const char *_mixer_ctl_get_type_string(struct mixer_ctl *ctl)
304{
305 if (!ctl)
306 return "";
307
308 switch (ctl->info->type) {
309 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL";
310 case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT";
311 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM";
312 case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTE";
313 case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958";
314 case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64";
315 default: return "Unknown";
316 };
317}
318
319static unsigned int _mixer_ctl_get_num_values(struct mixer_ctl *ctl)
320{
321 if (!ctl)
322 return 0;
323
324 return ctl->info->count;
325}
326
327static int percent_to_int(struct snd_ctl_elem_info *ei, int percent)
328{
329 int range;
330
331 if (percent > 100)
332 percent = 100;
333 else if (percent < 0)
334 percent = 0;
335
336 range = (ei->value.integer.max - ei->value.integer.min);
337
338 return ei->value.integer.min + (range * percent) / 100;
339}
340
341static int int_to_percent(struct snd_ctl_elem_info *ei, int value)
342{
343 int range = (ei->value.integer.max - ei->value.integer.min);
344
345 if (range == 0)
346 return 0;
347
348 return ((value - ei->value.integer.min) / range) * 100;
349}
350
351static int _mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value)
352{
353 struct snd_ctl_elem_value ev;
354 int ret;
355
356 if (!ctl || (id >= ctl->info->count))
357 return -EINVAL;
358
359 memset(&ev, 0, sizeof(ev));
360 ev.id.numid = ctl->info->id.numid;
361 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
362 if (ret < 0)
363 return ret;
364
365 switch (ctl->info->type) {
366 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
367 ev.value.integer.value[id] = !!value;
368 break;
369
370 case SNDRV_CTL_ELEM_TYPE_INTEGER:
371 ev.value.integer.value[id] = value;
372 break;
373
374 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
375 ev.value.enumerated.item[id] = value;
376 break;
377
378 case SNDRV_CTL_ELEM_TYPE_BYTES:
379 ev.value.bytes.data[id] = value;
380 break;
381
382 default:
383 return -EINVAL;
384 }
385
386 return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
387}
388
389static int _mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id)
390{
391 struct snd_ctl_elem_value ev;
392 int ret;
393
394 if (!ctl || (id >= ctl->info->count))
395 return -EINVAL;
396
397 memset(&ev, 0, sizeof(ev));
398 ev.id.numid = ctl->info->id.numid;
399 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
400 if (ret < 0)
401 return ret;
402
403 switch (ctl->info->type) {
404 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
405 return !!ev.value.integer.value[id];
406
407 case SNDRV_CTL_ELEM_TYPE_INTEGER:
408 return ev.value.integer.value[id];
409
410 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
411 return ev.value.enumerated.item[id];
412
413 case SNDRV_CTL_ELEM_TYPE_BYTES:
414 return ev.value.bytes.data[id];
415
416 default:
417 return -EINVAL;
418 }
419
420 return 0;
421}
422
423static int _mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id)
424{
425 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
426 return -EINVAL;
427
428 return int_to_percent(ctl->info, _mixer_ctl_get_value(ctl, id));
429}
430
431static int _mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent)
432{
433 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
434 return -EINVAL;
435
436 return _mixer_ctl_set_value(ctl, id, percent_to_int(ctl->info, percent));
437}
438
439static int _mixer_ctl_is_access_tlv_rw(struct mixer_ctl *ctl)
440{
441 return (ctl->info->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE);
442}
443
444static int _mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count)
445{
446 struct snd_ctl_elem_value ev;
447 int ret = 0;
448 size_t size;
449 void *source;
450 size_t total_count;
451
452 if ((!ctl) || !count || !array)
453 return -EINVAL;
454
455 total_count = ctl->info->count;
456
457 if ((ctl->info->type == SNDRV_CTL_ELEM_TYPE_BYTES) &&
458 _mixer_ctl_is_access_tlv_rw(ctl)) {
459 /* Additional two words is for the TLV header */
460 total_count += TLV_HEADER_SIZE;
461 }
462
463 if (count > total_count)
464 return -EINVAL;
465
466 memset(&ev, 0, sizeof(ev));
467 ev.id.numid = ctl->info->id.numid;
468
469 switch (ctl->info->type) {
470 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
471 case SNDRV_CTL_ELEM_TYPE_INTEGER:
472 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
473 if (ret < 0)
474 return ret;
475 size = sizeof(ev.value.integer.value[0]);
476 source = ev.value.integer.value;
477 break;
478
479 case SNDRV_CTL_ELEM_TYPE_BYTES:
480 /* check if this is new bytes TLV */
481 if (_mixer_ctl_is_access_tlv_rw(ctl)) {
482 struct snd_ctl_tlv *tlv;
483 int ret;
484
485 if (count > SIZE_MAX - sizeof(*tlv))
486 return -EINVAL;
487 tlv = (struct snd_ctl_tlv *)calloc(1, sizeof(*tlv) + count);
488 if (!tlv)
489 return -ENOMEM;
490 tlv->numid = ctl->info->id.numid;
491 tlv->length = count;
492 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_TLV_READ, tlv);
493
494 source = tlv->tlv;
495 memcpy(array, source, count);
496
497 free(tlv);
498
499 return ret;
500 } else {
501 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
502 if (ret < 0)
503 return ret;
504 size = sizeof(ev.value.bytes.data[0]);
505 source = ev.value.bytes.data;
506 break;
507 }
508
509 case SNDRV_CTL_ELEM_TYPE_IEC958:
510 size = sizeof(ev.value.iec958);
511 source = &ev.value.iec958;
512 break;
513
514 default:
515 return -EINVAL;
516 }
517
518 memcpy(array, source, size * count);
519
520 return 0;
521}
522
523static int _mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count)
524{
525 struct snd_ctl_elem_value ev;
526 size_t size;
527 void *dest;
528 size_t total_count;
529
530 if ((!ctl) || !count || !array)
531 return -EINVAL;
532
533 total_count = ctl->info->count;
534
535 if ((ctl->info->type == SNDRV_CTL_ELEM_TYPE_BYTES) &&
536 _mixer_ctl_is_access_tlv_rw(ctl)) {
537 /* Additional two words is for the TLV header */
538 total_count += TLV_HEADER_SIZE;
539 }
540
541 if (count > total_count)
542 return -EINVAL;
543
544 memset(&ev, 0, sizeof(ev));
545 ev.id.numid = ctl->info->id.numid;
546
547 switch (ctl->info->type) {
548 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
549 case SNDRV_CTL_ELEM_TYPE_INTEGER:
550 size = sizeof(ev.value.integer.value[0]);
551 dest = ev.value.integer.value;
552 break;
553
554 case SNDRV_CTL_ELEM_TYPE_BYTES:
555 /* check if this is new bytes TLV */
556 if (_mixer_ctl_is_access_tlv_rw(ctl)) {
557 struct snd_ctl_tlv *tlv;
558 int ret = 0;
559 if (count > SIZE_MAX - sizeof(*tlv))
560 return -EINVAL;
561 tlv = (struct snd_ctl_tlv *)calloc(1, sizeof(*tlv) + count);
562 if (!tlv)
563 return -ENOMEM;
564 tlv->numid = ctl->info->id.numid;
565 tlv->length = count;
566 memcpy(tlv->tlv, array, count);
567
568 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_TLV_WRITE, tlv);
569 free(tlv);
570
571 return ret;
572 } else {
573 size = sizeof(ev.value.bytes.data[0]);
574 dest = ev.value.bytes.data;
575 }
576 break;
577
578 case SNDRV_CTL_ELEM_TYPE_IEC958:
579 size = sizeof(ev.value.iec958);
580 dest = &ev.value.iec958;
581 break;
582
583 default:
584 return -EINVAL;
585 }
586
587 memcpy(dest, array, size * count);
588
589 return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
590}
591
592static int _mixer_ctl_get_range_min(struct mixer_ctl *ctl)
593{
594 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
595 return -EINVAL;
596
597 return ctl->info->value.integer.min;
598}
599
600static int _mixer_ctl_get_range_max(struct mixer_ctl *ctl)
601{
602 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
603 return -EINVAL;
604
605 return ctl->info->value.integer.max;
606}
607
608static unsigned int _mixer_ctl_get_num_enums(struct mixer_ctl *ctl)
609{
610 if (!ctl)
611 return 0;
612
613 return ctl->info->value.enumerated.items;
614}
615
616static const char *_mixer_ctl_get_enum_string(struct mixer_ctl *ctl,
617 unsigned int enum_id)
618{
619 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) ||
620 (enum_id >= ctl->info->value.enumerated.items))
621 return NULL;
622
623 return (const char *)ctl->ename[enum_id];
624}
625
626static int _mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string)
627{
628 unsigned int i, num_enums;
629 struct snd_ctl_elem_value ev;
630 int ret;
631
632 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED))
633 return -EINVAL;
634
635 num_enums = ctl->info->value.enumerated.items;
636 for (i = 0; i < num_enums; i++) {
637 if (!strcmp(string, ctl->ename[i])) {
638 memset(&ev, 0, sizeof(ev));
639 ev.value.enumerated.item[0] = i;
640 ev.id.numid = ctl->info->id.numid;
641 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
642 if (ret < 0)
643 return ret;
644 return 0;
645 }
646 }
647
648 return -EINVAL;
649}
650
651static int aml_audio_mixer_int(const char *control, int value, bool set)
652{
653 int ret = -1;
654 struct mixer_ctl *pCtrl = NULL;
655 struct mixer *mixer = NULL;
656 if (control == NULL) {
657 ALOGE("[%s:%d] control is invalid!\n", __FUNCTION__, __LINE__);
658 return ret;
659 }
660 mixer = _mixer_open(DEFAULT_AML_SOUND_CARD);
661
662 if (mixer == NULL) {
663 ALOGE("[%s:%d] mixer is invalid!\n", __FUNCTION__, __LINE__);
664 return ret;
665 }
666
667 pCtrl = _mixer_get_ctl_by_name(mixer, control);
668 if (pCtrl == NULL) {
669 ALOGE("[%s:%d] Failed to find control: %s\n", __FUNCTION__, __LINE__, control);
670 _mixer_close(mixer);
671 return ret;
672 }
673 if (set) {
674 ret = _mixer_ctl_set_value(pCtrl, 0, value);
675 ALOGV("[%s:%d] set %s: %d, ret %d", __FUNCTION__, __LINE__, control, value, ret);
676 } else {
677 ret = _mixer_ctl_get_value(pCtrl, 0);
678 }
679 _mixer_close(mixer);
680
681 return ret;
682}
683
684static int aml_audio_mixer_array(const char *control, void *array, size_t count, bool set)
685{
686 int ret = -1;
687 struct mixer_ctl *pCtrl = NULL;
688 struct mixer *mixer = NULL;
689 if (control == NULL) {
690 ALOGE("[%s:%d] control is invalid!\n", __FUNCTION__, __LINE__);
691 return ret;
692 }
693 mixer = _mixer_open(DEFAULT_AML_SOUND_CARD);
694
695 if (mixer == NULL) {
696 ALOGE("[%s:%d] mixer is invalid!\n", __FUNCTION__, __LINE__);
697 return ret;
698 }
699
700 pCtrl = _mixer_get_ctl_by_name(mixer, control);
701 if (pCtrl == NULL) {
702 ALOGE("[%s:%d] Failed to find control: %s\n", __FUNCTION__, __LINE__, control);
703 _mixer_close(mixer);
704 return ret;
705 }
706 if (set) {
707 ret = _mixer_ctl_set_array(pCtrl, array, count);
708 ALOGV("[%s:%d] set %s, ret %d", __FUNCTION__, __LINE__, control, ret);
709 } else {
710 ret = _mixer_ctl_get_array(pCtrl, array, count);
711 }
712 _mixer_close(mixer);
713
714 return ret;
715}
716
717/* Headphone mute */
718static int set_dac_digital_mute(bool mute)
719{
720 int ret = 0;
721 static bool last_mute_state = false;
722 static int dac_digital_volume = DAC_DIGITAl_DEFAULT_VOLUME; // volume range: 0 ~ 255
723 int headphone_dac_gain[HEADPHONE_DAC_CHANNEL_NUM] = {dac_digital_volume, dac_digital_volume};
724
725 if (last_mute_state == mute) {
726 return ret;
727 }
728 if (mute) {
729 dac_digital_volume = aml_audio_mixer_int(DAC_DIGITAL_VOLUME, 0, false);//get current hp vol
730 headphone_dac_gain[0] = headphone_dac_gain[1] = 0;
731 ret = aml_audio_mixer_array(DAC_DIGITAL_VOLUME, headphone_dac_gain, HEADPHONE_DAC_CHANNEL_NUM, true);
732 } else {
733 //headphone_dac_gain[0] = headphone_dac_gain[1] = dac_digital_volume;
734 ret = aml_audio_mixer_array(DAC_DIGITAL_VOLUME, headphone_dac_gain, HEADPHONE_DAC_CHANNEL_NUM, true);
735 }
736 last_mute_state = mute;
737 ALOGD("[%s:%d] DAC Digital %smute, dac_digital_volume is %d", __func__, __LINE__, mute?" ":"un", dac_digital_volume);
738 return ret;
739}
740
yuliang.huf4792d52023-09-19 10:14:14 +0000741int aml_audio_set_hdmi_param(bool isconnect)
742{
743 int ret = 0;
744 pthread_mutex_lock(&g_volume_lock);
745 chip_id = aml_audio_mixer_int(AML_CHIP_ID, 0, false);
746 /*s1a use this way to set hdmi status*/
haiyang.ren1882f702024-09-02 09:12:20 +0000747 if (AML_CHIP_ID_S1A == chip_id || AML_CHIP_ID_S4D == chip_id) {
yuliang.huf4792d52023-09-19 10:14:14 +0000748 ret = aml_audio_mixer_int(HDMI_CON, isconnect, true);
749 ALOGD("[%s:%d] isconnect: %d, ret: %d", __func__, __LINE__, isconnect, ret);
750 }
751 pthread_mutex_unlock(&g_volume_lock);
752 return ret;
753}
754
wei.wang1e45cfd32023-07-10 08:33:46 +0000755int aml_audio_set_volume(int value)
756{
757 int ret = 0;
758 if (value < 0 || value > 100) {
759 ALOGE("[%s:%d]bad volume: %d", __func__, __LINE__, value);
760 return -1;
761 }
762
763 pthread_mutex_lock(&g_volume_lock);
wei.wang158743372023-08-07 08:07:05 +0000764 chip_id = aml_audio_mixer_int(AML_CHIP_ID, 0, false);
765 /*s1a use TDM-A as cvbs/hdmi_tx samesource*/
haiyang.ren1882f702024-09-02 09:12:20 +0000766 if (AML_CHIP_ID_S1A == chip_id) {
wei.wang158743372023-08-07 08:07:05 +0000767 ret = aml_audio_mixer_int(TDMA_GAIN, value, true);
haiyang.ren1882f702024-09-02 09:12:20 +0000768 } else if (AML_CHIP_ID_S4D == chip_id) {
769 ret = aml_audio_mixer_int(TDMC_GAIN, value, true);
770 } else {
wei.wang158743372023-08-07 08:07:05 +0000771 ret = aml_audio_mixer_int(TDMB_GAIN, value, true);
haiyang.ren1882f702024-09-02 09:12:20 +0000772 }
wei.wang158743372023-08-07 08:07:05 +0000773 ALOGD("[%s:%d] chip_id: %d, volume: %d, ret: %d", __func__, __LINE__, chip_id, value, ret);
wei.wang1e45cfd32023-07-10 08:33:46 +0000774 pthread_mutex_unlock(&g_volume_lock);
775
776 return ret;
777}
778
779int aml_audio_get_volume()
780{
781 pthread_mutex_lock(&g_volume_lock);
782 int ret = 0;
haiyang.renf9cfa202024-04-07 09:26:30 +0000783 chip_id = aml_audio_mixer_int(AML_CHIP_ID, 0, false);
haiyang.ren1882f702024-09-02 09:12:20 +0000784 if (AML_CHIP_ID_S1A == chip_id) {
wei.wang158743372023-08-07 08:07:05 +0000785 ret = aml_audio_mixer_int(TDMA_GAIN, 0, false);
haiyang.ren1882f702024-09-02 09:12:20 +0000786 } else if (AML_CHIP_ID_S4D == chip_id) {
787 ret = aml_audio_mixer_int(TDMC_GAIN, 0, false);
788 } else {
wei.wang158743372023-08-07 08:07:05 +0000789 ret = aml_audio_mixer_int(TDMB_GAIN, 0, false);
haiyang.ren1882f702024-09-02 09:12:20 +0000790 }
wei.wang158743372023-08-07 08:07:05 +0000791 ALOGD("[%s:%d] chip_id: %d, volume: %d", __func__, __LINE__, chip_id, ret);
wei.wang1e45cfd32023-07-10 08:33:46 +0000792 pthread_mutex_unlock(&g_volume_lock);
793
794 return ret;
795}
796
797int aml_audio_set_mute(int port, bool mute)
798{
799 pthread_mutex_lock(&g_mute_lock);
800 int ret = -1;
801 if (port <= AUDIO_PORT_MIN || port >= AUDIO_PORT_MAX) {
802 ALOGE("[%s:%d]bad port: %d", __func__, __LINE__, port);
803 } else if (port == AUDIO_PORT_HDMI) {
haiyang.ren85627e82024-02-26 11:16:42 +0000804 if (aml_audio_get_spdif_format() == AUD_CODEC_TYPE_STEREO_PCM) {
haiyang.ren260660b2024-08-20 07:00:28 +0000805 if (mute_status != mute) {
806 if (mute) {
807 reserved_volume = aml_audio_get_volume();
808 ret = aml_audio_set_volume(0);
809 } else {
810 ret = aml_audio_set_volume(reserved_volume);
811 }
812 mute_status = mute;
813 } else {
814 ALOGE("[%s:%d] Invalid mute setting.", __func__, __LINE__);
haiyang.ren85627e82024-02-26 11:16:42 +0000815 }
816 } else {
817 ret = aml_audio_mixer_int(HDMI_OUT_MUTE, mute ? 1 : 0, true);
haiyang.ren49ae2c82023-11-02 09:31:41 +0000818 }
wei.wang1e45cfd32023-07-10 08:33:46 +0000819 } else if (port == AUDIO_PORT_HEADPHONE) {
820 ret = set_dac_digital_mute(mute);
821 }
haiyang.ren260660b2024-08-20 07:00:28 +0000822 ALOGD("[%s:%d] port: %d, mute_status: %d, mute: %d, ret: %d",
823 __func__, __LINE__, port, mute_status, mute, ret);
wei.wang1e45cfd32023-07-10 08:33:46 +0000824 pthread_mutex_unlock(&g_mute_lock);
825 return ret;
826}
827
828bool aml_audio_get_mute(int port)
829{
830 pthread_mutex_lock(&g_mute_lock);
831 bool ret = false;
832 if (port <= AUDIO_PORT_MIN || port >= AUDIO_PORT_MAX) {
833 ALOGE("[%s:%d]bad port: %d", __func__, __LINE__, port);
834 } else if (port == AUDIO_PORT_HDMI) {
haiyang.ren85627e82024-02-26 11:16:42 +0000835 if (aml_audio_get_spdif_format() == AUD_CODEC_TYPE_STEREO_PCM) {
haiyang.ren260660b2024-08-20 07:00:28 +0000836 ret = mute_status;
haiyang.ren85627e82024-02-26 11:16:42 +0000837 } else {
838 ret = aml_audio_mixer_int(HDMI_OUT_MUTE, 0, false) ? true : false;
839 }
wei.wang1e45cfd32023-07-10 08:33:46 +0000840 } else if (port == AUDIO_PORT_HEADPHONE) {
841 ret = aml_audio_mixer_int(DAC_DIGITAL_VOLUME, 0, false) ? false : true;
842 }
843 ALOGD("[%s:%d] port: %d, mute: %d", __func__, __LINE__, port, ret);
844 pthread_mutex_unlock(&g_mute_lock);
845 return ret;
846}
847
haiyang.ren936bfc52023-09-18 05:46:24 +0000848int aml_audio_set_digital_mode(enum audio_digital_mode mode)
849{
850 int ret = 0;
851 if ((mode != AML_HAL_PCM) && (mode != AML_HAL_DDP) &&
852 (mode != AML_HAL_AUTO) && (mode != AML_HAL_BYPASS) &&
853 (mode != AML_HAL_DD)) {
854 printf("Invalid mode\n");
855 return false;
haiyang.renfdc144e2023-09-01 02:55:50 +0000856 }
857
haiyang.ren936bfc52023-09-18 05:46:24 +0000858 pthread_mutex_lock(&g_volume_lock);
859 ret = aml_audio_mixer_int(DIGITAL_MODE, mode, true);
860 ALOGD("[%s:%d] mode: %d, ret: %d", __func__, __LINE__, mode, ret);
861 pthread_mutex_unlock(&g_volume_lock);
haiyang.renfdc144e2023-09-01 02:55:50 +0000862
haiyang.ren936bfc52023-09-18 05:46:24 +0000863 return ret;
864}
865
866int aml_audio_get_digital_mode()
867{
868 pthread_mutex_lock(&g_volume_lock);
869 int ret = 0;
870 ret = aml_audio_mixer_int(DIGITAL_MODE, 0, false);
871 ALOGD("[%s:%d] mod: %d", __func__, __LINE__, ret);
872 pthread_mutex_unlock(&g_volume_lock);
873
874 return ret;
875}
876
877int aml_audio_set_drc_mode(enum audio_drc_mode mode)
878{
879 int ret = 0;
880 int drc_control = DRC_MODE_LINE;
881 if ((mode != DRC_RF) && (mode != DRC_LINE) && (mode != DRC_OFF)) {
882 printf("Invalid mode!\n");
883 return false;
haiyang.renfdc144e2023-09-01 02:55:50 +0000884 }
885
haiyang.ren936bfc52023-09-18 05:46:24 +0000886 pthread_mutex_lock(&g_volume_lock);
887 if (mode == DRC_LINE) {
888 drc_control = (DRC_MODE_LINE<<DRC_MODE_BIT)|(100<<DRC_HIGH_CUT_BIT)|(100<<DRC_LOW_BST_BIT);
889 } else if (mode == DRC_RF) {
890 drc_control = (DRC_MODE_RF<<DRC_MODE_BIT)|(100<<DRC_HIGH_CUT_BIT)|(100<<DRC_LOW_BST_BIT);
891 }
892 ret = aml_audio_mixer_int(DRC_CONTROL, drc_control, true);
893 ALOGD("[%s:%d] mode: %d, drc_control: %#x, ret: %d.", __func__, __LINE__, mode, drc_control, ret);
894 pthread_mutex_unlock(&g_volume_lock);
895
896 return ret;
897}
898
899int aml_audio_get_drc_mode()
900{
901 pthread_mutex_lock(&g_volume_lock);
902 int ret = 0, drc_control;
903 drc_control = aml_audio_mixer_int(DRC_CONTROL, 0, false);
904
905 if (drc_control == DRC_MODE_LINE)
906 ret = DRC_OFF;
907 else
908 ret = (drc_control&3 == DRC_MODE_LINE) ? DRC_LINE : DRC_RF;
909 ALOGD("[%s:%d] mode: %d", __func__, __LINE__, ret);
910 pthread_mutex_unlock(&g_volume_lock);
911
912 return ret;
913}
haiyang.ren85627e82024-02-26 11:16:42 +0000914
915int aml_audio_get_spdif_format()
916{
917 pthread_mutex_lock(&g_volume_lock);
918 int ret = 0;
919 ret = aml_audio_mixer_int(SPDIF_FORMAT, 0, false);
920 ALOGD("[%s:%d] ret: %x.", __func__, __LINE__, ret);
921 pthread_mutex_unlock(&g_volume_lock);
922
923 return ret;
924}
wei.wang1e45cfd32023-07-10 08:33:46 +0000925}//extern c