blob: a2c2294435f543355aea993001d77405bfe019c3 [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
40#define DEFAULT_AML_SOUND_CARD 0
41/* TLV header size*/
42#define TLV_HEADER_SIZE (2 * sizeof(unsigned int))
43
44#define TDMB_GAIN "TDMOUT_B Software Gain"
45#define HDMI_OUT_MUTE "Audio hdmi-out mute"
46#define DAC_DIGITAL_VOLUME "DAC Digital Playback Volume"
47#define DAC_DIGITAl_DEFAULT_VOLUME (251)
48#define HEADPHONE_DAC_CHANNEL_NUM (2)
49
50extern "C" {
51
52struct mixer_ctl {
53 struct mixer *mixer;
54 struct snd_ctl_elem_info *info;
55 char **ename;
56 bool info_retrieved;
57};
58
59struct mixer {
60 int fd;
61 struct snd_ctl_card_info card_info;
62 struct snd_ctl_elem_info *elem_info;
63 struct mixer_ctl *ctl;
64 unsigned int count;
65};
66
67/* Mixer control types */
68enum mixer_ctl_type {
69 MIXER_CTL_TYPE_BOOL,
70 MIXER_CTL_TYPE_INT,
71 MIXER_CTL_TYPE_ENUM,
72 MIXER_CTL_TYPE_BYTE,
73 MIXER_CTL_TYPE_IEC958,
74 MIXER_CTL_TYPE_INT64,
75 MIXER_CTL_TYPE_UNKNOWN,
76
77 MIXER_CTL_TYPE_MAX,
78};
79
80static pthread_mutex_t g_volume_lock = PTHREAD_MUTEX_INITIALIZER;
81static pthread_mutex_t g_mute_lock = PTHREAD_MUTEX_INITIALIZER;
82
83static void _mixer_close(struct mixer *mixer)
84{
85 unsigned int n,m;
86
87 if (!mixer)
88 return;
89
90 if (mixer->fd >= 0)
91 close(mixer->fd);
92
93 if (mixer->ctl) {
94 for (n = 0; n < mixer->count; n++) {
95 if (mixer->ctl[n].ename) {
96 unsigned int max = mixer->ctl[n].info->value.enumerated.items;
97 for (m = 0; m < max; m++)
98 free(mixer->ctl[n].ename[m]);
99 free(mixer->ctl[n].ename);
100 }
101 }
102 free(mixer->ctl);
103 }
104
105 if (mixer->elem_info)
106 free(mixer->elem_info);
107
108 free(mixer);
109
110 /* TODO: verify frees */
111}
112
113static struct mixer *_mixer_open(unsigned int card)
114{
115 struct snd_ctl_elem_list elist;
116 struct snd_ctl_elem_id *eid = NULL;
117 struct mixer *mixer = NULL;
118 unsigned int n;
119 int fd;
120 char fn[256];
121
122 snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card);
123 fd = open(fn, O_RDWR);
124 if (fd < 0)
125 return 0;
126
127 memset(&elist, 0, sizeof(elist));
128 if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
129 goto fail;
130
131 mixer = (struct mixer *)calloc(1, sizeof(*mixer));
132 if (!mixer)
133 goto fail;
134
135 mixer->ctl = (struct mixer_ctl *)calloc(elist.count, sizeof(struct mixer_ctl));
136 mixer->elem_info = (struct snd_ctl_elem_info *)calloc(elist.count, sizeof(struct snd_ctl_elem_info));
137 if (!mixer->ctl || !mixer->elem_info)
138 goto fail;
139
140 if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0)
141 goto fail;
142
143 eid = (struct snd_ctl_elem_id *)calloc(elist.count, sizeof(struct snd_ctl_elem_id));
144 if (!eid)
145 goto fail;
146
147 mixer->count = elist.count;
148 mixer->fd = fd;
149 elist.space = mixer->count;
150 elist.pids = eid;
151 if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
152 goto fail;
153
154 for (n = 0; n < mixer->count; n++) {
155 struct mixer_ctl *ctl = mixer->ctl + n;
156
157 ctl->mixer = mixer;
158 ctl->info = mixer->elem_info + n;
159 ctl->info->id.numid = eid[n].numid;
160 strncpy((char *)ctl->info->id.name, (char *)eid[n].name,
161 SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
162 ctl->info->id.name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1] = 0;
163 }
164
165 free(eid);
166 return mixer;
167
168fail:
169 /* TODO: verify frees in failure case */
170 if (eid)
171 free(eid);
172 if (mixer)
173 _mixer_close(mixer);
174 else if (fd >= 0)
175 close(fd);
176 return 0;
177}
178
179static bool _mixer_ctl_get_elem_info(struct mixer_ctl* ctl)
180{
181 if (!ctl->info_retrieved) {
182 if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info) < 0)
183 return false;
184 ctl->info_retrieved = true;
185 }
186
187 if (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED || ctl->ename)
188 return true;
189
190 struct snd_ctl_elem_info tmp;
191 char** enames = (char**)calloc(ctl->info->value.enumerated.items, sizeof(char*));
192 if (!enames)
193 return false;
194
195 for (unsigned int i = 0; i < ctl->info->value.enumerated.items; i++) {
196 memset(&tmp, 0, sizeof(tmp));
197 tmp.id.numid = ctl->info->id.numid;
198 tmp.value.enumerated.item = i;
199 if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0)
200 goto fail;
201 enames[i] = strdup(tmp.value.enumerated.name);
202 if (!enames[i])
203 goto fail;
204 }
205 ctl->ename = enames;
206 return true;
207
208fail:
209 free(enames);
210 return false;
211}
212
213static const char *_mixer_get_name(struct mixer *mixer)
214{
215 return (const char *)mixer->card_info.name;
216}
217
218static unsigned int _mixer_get_num_ctls(struct mixer *mixer)
219{
220 if (!mixer)
221 return 0;
222
223 return mixer->count;
224}
225
226static struct mixer_ctl *_mixer_get_ctl(struct mixer *mixer, unsigned int id)
227{
228 struct mixer_ctl *ctl;
229
230 if (!mixer || (id >= mixer->count))
231 return NULL;
232
233 ctl = mixer->ctl + id;
234 if (!_mixer_ctl_get_elem_info(ctl))
235 return NULL;
236
237 return ctl;
238}
239
240static struct mixer_ctl *_mixer_get_ctl_by_name(struct mixer *mixer, const char *name)
241{
242 unsigned int n;
243
244 if (!mixer)
245 return NULL;
246
247 for (n = 0; n < mixer->count; n++)
248 if (!strcmp(name, (char*) mixer->elem_info[n].id.name))
249 return _mixer_get_ctl(mixer, n);
250
251 return NULL;
252}
253
254static void _mixer_ctl_update(struct mixer_ctl *ctl)
255{
256 ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info);
257}
258
259static const char *_mixer_ctl_get_name(struct mixer_ctl *ctl)
260{
261 if (!ctl)
262 return NULL;
263
264 return (const char *)ctl->info->id.name;
265}
266
267static enum mixer_ctl_type _mixer_ctl_get_type(struct mixer_ctl *ctl)
268{
269 if (!ctl)
270 return MIXER_CTL_TYPE_UNKNOWN;
271
272 switch (ctl->info->type) {
273 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return MIXER_CTL_TYPE_BOOL;
274 case SNDRV_CTL_ELEM_TYPE_INTEGER: return MIXER_CTL_TYPE_INT;
275 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return MIXER_CTL_TYPE_ENUM;
276 case SNDRV_CTL_ELEM_TYPE_BYTES: return MIXER_CTL_TYPE_BYTE;
277 case SNDRV_CTL_ELEM_TYPE_IEC958: return MIXER_CTL_TYPE_IEC958;
278 case SNDRV_CTL_ELEM_TYPE_INTEGER64: return MIXER_CTL_TYPE_INT64;
279 default: return MIXER_CTL_TYPE_UNKNOWN;
280 };
281}
282
283static const char *_mixer_ctl_get_type_string(struct mixer_ctl *ctl)
284{
285 if (!ctl)
286 return "";
287
288 switch (ctl->info->type) {
289 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL";
290 case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT";
291 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM";
292 case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTE";
293 case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958";
294 case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64";
295 default: return "Unknown";
296 };
297}
298
299static unsigned int _mixer_ctl_get_num_values(struct mixer_ctl *ctl)
300{
301 if (!ctl)
302 return 0;
303
304 return ctl->info->count;
305}
306
307static int percent_to_int(struct snd_ctl_elem_info *ei, int percent)
308{
309 int range;
310
311 if (percent > 100)
312 percent = 100;
313 else if (percent < 0)
314 percent = 0;
315
316 range = (ei->value.integer.max - ei->value.integer.min);
317
318 return ei->value.integer.min + (range * percent) / 100;
319}
320
321static int int_to_percent(struct snd_ctl_elem_info *ei, int value)
322{
323 int range = (ei->value.integer.max - ei->value.integer.min);
324
325 if (range == 0)
326 return 0;
327
328 return ((value - ei->value.integer.min) / range) * 100;
329}
330
331static int _mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value)
332{
333 struct snd_ctl_elem_value ev;
334 int ret;
335
336 if (!ctl || (id >= ctl->info->count))
337 return -EINVAL;
338
339 memset(&ev, 0, sizeof(ev));
340 ev.id.numid = ctl->info->id.numid;
341 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
342 if (ret < 0)
343 return ret;
344
345 switch (ctl->info->type) {
346 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
347 ev.value.integer.value[id] = !!value;
348 break;
349
350 case SNDRV_CTL_ELEM_TYPE_INTEGER:
351 ev.value.integer.value[id] = value;
352 break;
353
354 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
355 ev.value.enumerated.item[id] = value;
356 break;
357
358 case SNDRV_CTL_ELEM_TYPE_BYTES:
359 ev.value.bytes.data[id] = value;
360 break;
361
362 default:
363 return -EINVAL;
364 }
365
366 return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
367}
368
369static int _mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id)
370{
371 struct snd_ctl_elem_value ev;
372 int ret;
373
374 if (!ctl || (id >= ctl->info->count))
375 return -EINVAL;
376
377 memset(&ev, 0, sizeof(ev));
378 ev.id.numid = ctl->info->id.numid;
379 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
380 if (ret < 0)
381 return ret;
382
383 switch (ctl->info->type) {
384 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
385 return !!ev.value.integer.value[id];
386
387 case SNDRV_CTL_ELEM_TYPE_INTEGER:
388 return ev.value.integer.value[id];
389
390 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
391 return ev.value.enumerated.item[id];
392
393 case SNDRV_CTL_ELEM_TYPE_BYTES:
394 return ev.value.bytes.data[id];
395
396 default:
397 return -EINVAL;
398 }
399
400 return 0;
401}
402
403static int _mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id)
404{
405 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
406 return -EINVAL;
407
408 return int_to_percent(ctl->info, _mixer_ctl_get_value(ctl, id));
409}
410
411static int _mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent)
412{
413 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
414 return -EINVAL;
415
416 return _mixer_ctl_set_value(ctl, id, percent_to_int(ctl->info, percent));
417}
418
419static int _mixer_ctl_is_access_tlv_rw(struct mixer_ctl *ctl)
420{
421 return (ctl->info->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE);
422}
423
424static int _mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count)
425{
426 struct snd_ctl_elem_value ev;
427 int ret = 0;
428 size_t size;
429 void *source;
430 size_t total_count;
431
432 if ((!ctl) || !count || !array)
433 return -EINVAL;
434
435 total_count = ctl->info->count;
436
437 if ((ctl->info->type == SNDRV_CTL_ELEM_TYPE_BYTES) &&
438 _mixer_ctl_is_access_tlv_rw(ctl)) {
439 /* Additional two words is for the TLV header */
440 total_count += TLV_HEADER_SIZE;
441 }
442
443 if (count > total_count)
444 return -EINVAL;
445
446 memset(&ev, 0, sizeof(ev));
447 ev.id.numid = ctl->info->id.numid;
448
449 switch (ctl->info->type) {
450 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
451 case SNDRV_CTL_ELEM_TYPE_INTEGER:
452 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
453 if (ret < 0)
454 return ret;
455 size = sizeof(ev.value.integer.value[0]);
456 source = ev.value.integer.value;
457 break;
458
459 case SNDRV_CTL_ELEM_TYPE_BYTES:
460 /* check if this is new bytes TLV */
461 if (_mixer_ctl_is_access_tlv_rw(ctl)) {
462 struct snd_ctl_tlv *tlv;
463 int ret;
464
465 if (count > SIZE_MAX - sizeof(*tlv))
466 return -EINVAL;
467 tlv = (struct snd_ctl_tlv *)calloc(1, sizeof(*tlv) + count);
468 if (!tlv)
469 return -ENOMEM;
470 tlv->numid = ctl->info->id.numid;
471 tlv->length = count;
472 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_TLV_READ, tlv);
473
474 source = tlv->tlv;
475 memcpy(array, source, count);
476
477 free(tlv);
478
479 return ret;
480 } else {
481 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
482 if (ret < 0)
483 return ret;
484 size = sizeof(ev.value.bytes.data[0]);
485 source = ev.value.bytes.data;
486 break;
487 }
488
489 case SNDRV_CTL_ELEM_TYPE_IEC958:
490 size = sizeof(ev.value.iec958);
491 source = &ev.value.iec958;
492 break;
493
494 default:
495 return -EINVAL;
496 }
497
498 memcpy(array, source, size * count);
499
500 return 0;
501}
502
503static int _mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count)
504{
505 struct snd_ctl_elem_value ev;
506 size_t size;
507 void *dest;
508 size_t total_count;
509
510 if ((!ctl) || !count || !array)
511 return -EINVAL;
512
513 total_count = ctl->info->count;
514
515 if ((ctl->info->type == SNDRV_CTL_ELEM_TYPE_BYTES) &&
516 _mixer_ctl_is_access_tlv_rw(ctl)) {
517 /* Additional two words is for the TLV header */
518 total_count += TLV_HEADER_SIZE;
519 }
520
521 if (count > total_count)
522 return -EINVAL;
523
524 memset(&ev, 0, sizeof(ev));
525 ev.id.numid = ctl->info->id.numid;
526
527 switch (ctl->info->type) {
528 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
529 case SNDRV_CTL_ELEM_TYPE_INTEGER:
530 size = sizeof(ev.value.integer.value[0]);
531 dest = ev.value.integer.value;
532 break;
533
534 case SNDRV_CTL_ELEM_TYPE_BYTES:
535 /* check if this is new bytes TLV */
536 if (_mixer_ctl_is_access_tlv_rw(ctl)) {
537 struct snd_ctl_tlv *tlv;
538 int ret = 0;
539 if (count > SIZE_MAX - sizeof(*tlv))
540 return -EINVAL;
541 tlv = (struct snd_ctl_tlv *)calloc(1, sizeof(*tlv) + count);
542 if (!tlv)
543 return -ENOMEM;
544 tlv->numid = ctl->info->id.numid;
545 tlv->length = count;
546 memcpy(tlv->tlv, array, count);
547
548 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_TLV_WRITE, tlv);
549 free(tlv);
550
551 return ret;
552 } else {
553 size = sizeof(ev.value.bytes.data[0]);
554 dest = ev.value.bytes.data;
555 }
556 break;
557
558 case SNDRV_CTL_ELEM_TYPE_IEC958:
559 size = sizeof(ev.value.iec958);
560 dest = &ev.value.iec958;
561 break;
562
563 default:
564 return -EINVAL;
565 }
566
567 memcpy(dest, array, size * count);
568
569 return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
570}
571
572static int _mixer_ctl_get_range_min(struct mixer_ctl *ctl)
573{
574 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
575 return -EINVAL;
576
577 return ctl->info->value.integer.min;
578}
579
580static int _mixer_ctl_get_range_max(struct mixer_ctl *ctl)
581{
582 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
583 return -EINVAL;
584
585 return ctl->info->value.integer.max;
586}
587
588static unsigned int _mixer_ctl_get_num_enums(struct mixer_ctl *ctl)
589{
590 if (!ctl)
591 return 0;
592
593 return ctl->info->value.enumerated.items;
594}
595
596static const char *_mixer_ctl_get_enum_string(struct mixer_ctl *ctl,
597 unsigned int enum_id)
598{
599 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) ||
600 (enum_id >= ctl->info->value.enumerated.items))
601 return NULL;
602
603 return (const char *)ctl->ename[enum_id];
604}
605
606static int _mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string)
607{
608 unsigned int i, num_enums;
609 struct snd_ctl_elem_value ev;
610 int ret;
611
612 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED))
613 return -EINVAL;
614
615 num_enums = ctl->info->value.enumerated.items;
616 for (i = 0; i < num_enums; i++) {
617 if (!strcmp(string, ctl->ename[i])) {
618 memset(&ev, 0, sizeof(ev));
619 ev.value.enumerated.item[0] = i;
620 ev.id.numid = ctl->info->id.numid;
621 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
622 if (ret < 0)
623 return ret;
624 return 0;
625 }
626 }
627
628 return -EINVAL;
629}
630
631static int aml_audio_mixer_int(const char *control, int value, bool set)
632{
633 int ret = -1;
634 struct mixer_ctl *pCtrl = NULL;
635 struct mixer *mixer = NULL;
636 if (control == NULL) {
637 ALOGE("[%s:%d] control is invalid!\n", __FUNCTION__, __LINE__);
638 return ret;
639 }
640 mixer = _mixer_open(DEFAULT_AML_SOUND_CARD);
641
642 if (mixer == NULL) {
643 ALOGE("[%s:%d] mixer is invalid!\n", __FUNCTION__, __LINE__);
644 return ret;
645 }
646
647 pCtrl = _mixer_get_ctl_by_name(mixer, control);
648 if (pCtrl == NULL) {
649 ALOGE("[%s:%d] Failed to find control: %s\n", __FUNCTION__, __LINE__, control);
650 _mixer_close(mixer);
651 return ret;
652 }
653 if (set) {
654 ret = _mixer_ctl_set_value(pCtrl, 0, value);
655 ALOGV("[%s:%d] set %s: %d, ret %d", __FUNCTION__, __LINE__, control, value, ret);
656 } else {
657 ret = _mixer_ctl_get_value(pCtrl, 0);
658 }
659 _mixer_close(mixer);
660
661 return ret;
662}
663
664static int aml_audio_mixer_array(const char *control, void *array, size_t count, bool set)
665{
666 int ret = -1;
667 struct mixer_ctl *pCtrl = NULL;
668 struct mixer *mixer = NULL;
669 if (control == NULL) {
670 ALOGE("[%s:%d] control is invalid!\n", __FUNCTION__, __LINE__);
671 return ret;
672 }
673 mixer = _mixer_open(DEFAULT_AML_SOUND_CARD);
674
675 if (mixer == NULL) {
676 ALOGE("[%s:%d] mixer is invalid!\n", __FUNCTION__, __LINE__);
677 return ret;
678 }
679
680 pCtrl = _mixer_get_ctl_by_name(mixer, control);
681 if (pCtrl == NULL) {
682 ALOGE("[%s:%d] Failed to find control: %s\n", __FUNCTION__, __LINE__, control);
683 _mixer_close(mixer);
684 return ret;
685 }
686 if (set) {
687 ret = _mixer_ctl_set_array(pCtrl, array, count);
688 ALOGV("[%s:%d] set %s, ret %d", __FUNCTION__, __LINE__, control, ret);
689 } else {
690 ret = _mixer_ctl_get_array(pCtrl, array, count);
691 }
692 _mixer_close(mixer);
693
694 return ret;
695}
696
697/* Headphone mute */
698static int set_dac_digital_mute(bool mute)
699{
700 int ret = 0;
701 static bool last_mute_state = false;
702 static int dac_digital_volume = DAC_DIGITAl_DEFAULT_VOLUME; // volume range: 0 ~ 255
703 int headphone_dac_gain[HEADPHONE_DAC_CHANNEL_NUM] = {dac_digital_volume, dac_digital_volume};
704
705 if (last_mute_state == mute) {
706 return ret;
707 }
708 if (mute) {
709 dac_digital_volume = aml_audio_mixer_int(DAC_DIGITAL_VOLUME, 0, false);//get current hp vol
710 headphone_dac_gain[0] = headphone_dac_gain[1] = 0;
711 ret = aml_audio_mixer_array(DAC_DIGITAL_VOLUME, headphone_dac_gain, HEADPHONE_DAC_CHANNEL_NUM, true);
712 } else {
713 //headphone_dac_gain[0] = headphone_dac_gain[1] = dac_digital_volume;
714 ret = aml_audio_mixer_array(DAC_DIGITAL_VOLUME, headphone_dac_gain, HEADPHONE_DAC_CHANNEL_NUM, true);
715 }
716 last_mute_state = mute;
717 ALOGD("[%s:%d] DAC Digital %smute, dac_digital_volume is %d", __func__, __LINE__, mute?" ":"un", dac_digital_volume);
718 return ret;
719}
720
721int aml_audio_set_volume(int value)
722{
723 int ret = 0;
724 if (value < 0 || value > 100) {
725 ALOGE("[%s:%d]bad volume: %d", __func__, __LINE__, value);
726 return -1;
727 }
728
729 pthread_mutex_lock(&g_volume_lock);
730 ret = aml_audio_mixer_int(TDMB_GAIN, value, true);
731 ALOGD("[%s:%d] volume: %d, ret: %d", __func__, __LINE__, value, ret);
732 pthread_mutex_unlock(&g_volume_lock);
733
734 return ret;
735}
736
737int aml_audio_get_volume()
738{
739 pthread_mutex_lock(&g_volume_lock);
740 int ret = 0;
741 ret = aml_audio_mixer_int(TDMB_GAIN, 0, false);
742 ALOGD("[%s:%d] volume: %d", __func__, __LINE__, ret);
743 pthread_mutex_unlock(&g_volume_lock);
744
745 return ret;
746}
747
748int aml_audio_set_mute(int port, bool mute)
749{
750 pthread_mutex_lock(&g_mute_lock);
751 int ret = -1;
752 if (port <= AUDIO_PORT_MIN || port >= AUDIO_PORT_MAX) {
753 ALOGE("[%s:%d]bad port: %d", __func__, __LINE__, port);
754 } else if (port == AUDIO_PORT_HDMI) {
755 ret = aml_audio_mixer_int(HDMI_OUT_MUTE, mute ? 1 : 0, true);
756 } else if (port == AUDIO_PORT_HEADPHONE) {
757 ret = set_dac_digital_mute(mute);
758 }
759 ALOGD("[%s:%d] port: %d, mute: %d, ret: %d", __func__, __LINE__, port, mute, ret);
760 pthread_mutex_unlock(&g_mute_lock);
761 return ret;
762}
763
764bool aml_audio_get_mute(int port)
765{
766 pthread_mutex_lock(&g_mute_lock);
767 bool ret = false;
768 if (port <= AUDIO_PORT_MIN || port >= AUDIO_PORT_MAX) {
769 ALOGE("[%s:%d]bad port: %d", __func__, __LINE__, port);
770 } else if (port == AUDIO_PORT_HDMI) {
771 ret = aml_audio_mixer_int(HDMI_OUT_MUTE, 0, false) ? true : false;
772 } else if (port == AUDIO_PORT_HEADPHONE) {
773 ret = aml_audio_mixer_int(DAC_DIGITAL_VOLUME, 0, false) ? false : true;
774 }
775 ALOGD("[%s:%d] port: %d, mute: %d", __func__, __LINE__, port, ret);
776 pthread_mutex_unlock(&g_mute_lock);
777 return ret;
778}
779
780}//extern c