1 /*
2  * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3  */
4 #include "sound_mixer.h"
5 #include "ulog/ulog.h"
6 
7 #define LOG_TAG  "[sound_mixer]"
8 #define MIXER_RETURN_ERR      -1
9 #define MIXER_RETURN_SUCCESS  0
10 
11 #define AOS_MASTER_VOLUME_TX_STRING    "Master Volume TX"
12 #define AOS_MASTER_MUTE_STATE_STRING   "Master Mute State"
13 
aos_mixer_common_set_int_value(char * name,int value)14 static int aos_mixer_common_set_int_value(char *name, int value)
15 {
16     int card = 0;
17     aos_mixer_t *mixer = NULL;
18     if(!name) {
19         return MIXER_RETURN_ERR;
20     }
21     for(card = 0; card < AOS_SNDCARD_NUM_MAX; card++) {
22         if(MIXER_RETURN_SUCCESS == aos_mixer_open(&mixer, card)) {
23             aos_mixer_print_info(mixer);
24             if(MIXER_RETURN_SUCCESS == aos_mixer_set_int_value(mixer, name, value)) {
25                 aos_mixer_close(mixer);
26                 mixer = NULL;
27                 return MIXER_RETURN_SUCCESS;
28             }
29         }
30         aos_mixer_close(mixer);
31         mixer = NULL;
32     }
33     return MIXER_RETURN_ERR;
34 }
35 
aos_mixer_common_get_int_value(char * name,int * value)36 int aos_mixer_common_get_int_value(char *name, int *value)
37 {
38     int card = 0;
39     aos_mixer_t *mixer = NULL;
40     if(!name) {
41         return MIXER_RETURN_ERR;
42     }
43     for(card = 0; card < AOS_SNDCARD_NUM_MAX; card++) {
44         if(MIXER_RETURN_SUCCESS == aos_mixer_open(&mixer, card)) {
45             aos_mixer_print_info(mixer);
46             if(MIXER_RETURN_SUCCESS == aos_mixer_get_int_value(mixer, name, value)) {
47                 aos_mixer_close(mixer);
48                 mixer = NULL;
49                 return MIXER_RETURN_SUCCESS;
50             }
51         }
52         aos_mixer_close(mixer);
53         mixer = NULL;
54     }
55     return MIXER_RETURN_ERR;
56 }
57 
aos_mixer_open(aos_mixer_t ** mixer,int card)58 int aos_mixer_open(aos_mixer_t **mixer, int card)
59 {
60     struct audio_ctl_elem_list elist;
61     struct audio_ctl_elem_id *eid = NULL;
62     struct audio_ctl_elem_info *ei = NULL;
63     int fd;
64     unsigned int n;
65     char fn[256];
66 
67     /* 1. open fd */
68     snprintf(fn, sizeof(fn), "/dev/controlC%u", card);
69     fd = open(fn, O_RDWR);
70     if (fd < 0) {
71         LOGE(LOG_TAG, "%s:%d, open %s failed", __func__, __LINE__, fn);
72         return MIXER_RETURN_ERR;
73     }
74     LOGD(LOG_TAG, "%s:%d, open %s successfully", __func__, __LINE__, fn);
75 
76     /* 2. new aos_mixer_t object */
77     *mixer = (aos_mixer_t *)calloc(1, sizeof(aos_mixer_t));
78     memset(*mixer, 0, sizeof(aos_mixer_t));
79     (*mixer)->fd = fd;
80     (*mixer)->name = strdup(fn);
81     (*mixer)->card = card;
82 
83     /* 3. get elem_list count number */
84     memset(&elist, 0, sizeof(elist));
85     if (ioctl(fd, AUDIO_CTL_IOCTL_ELEM_LIST, &elist) < 0) {
86         return MIXER_RETURN_ERR;
87     }
88     (*mixer)->count = elist.count;
89     elist.space = elist.count;
90 
91     /* 4. get card info */
92     if(ioctl(fd, AUDIO_CTL_IOCTL_CARD_INFO, &((*mixer)->card_info)) < 0) {
93         return MIXER_RETURN_ERR;
94     }
95 
96     /* 5. get audio_ctl_elem_list */
97     eid = calloc(elist.count, sizeof(struct audio_ctl_elem_id));
98     if(!eid) {
99         return MIXER_RETURN_ERR;
100     }
101     elist.pids = eid;
102     if (ioctl(fd, AUDIO_CTL_IOCTL_ELEM_LIST, &elist) < 0) {
103         return MIXER_RETURN_ERR;
104     }
105 
106     /* 6. get audio_ctl_elem_info */
107     (*mixer)->elem_info = calloc(elist.count, sizeof(struct audio_ctl_elem_info));
108     if(!(*mixer)->elem_info) {
109         return MIXER_RETURN_ERR;
110     }
111     for (n = 0; n < (*mixer)->count; n++) {
112         ei = (*mixer)->elem_info + n;
113         ei->id.id = eid[n].id;
114         if (ioctl(fd, AUDIO_CTL_IOCTL_ELEM_INFO, ei) < 0) {
115             LOGE(LOG_TAG, "%s:%d, ioctl AUDIO_CTL_IOCTL_ELEM_INFO failed", __func__, __LINE__);
116         }
117     }
118     if(eid) {
119         free(eid);
120     }
121     return MIXER_RETURN_SUCCESS;
122 }
123 
aos_mixer_print_info(aos_mixer_t * mixer)124 int aos_mixer_print_info(aos_mixer_t *mixer)
125 {
126     const char *type;
127     unsigned int info_cnt;
128     unsigned int i;
129     struct audio_ctl_elem_info * elem_info = NULL;
130 
131     if(!mixer) {
132         return MIXER_RETURN_ERR;
133     }
134     info_cnt = mixer->count;
135     LOGD(LOG_TAG, "%s:%d, element_info count %d", __func__, __LINE__, info_cnt);
136     for (i = 0; i < info_cnt; i++) {
137         elem_info = mixer->elem_info + i;
138         switch (elem_info->type) {
139             case AOS_CTL_ELEM_TYPE_BOOLEAN:
140                 type = "BOOL";
141                 break;
142             case AOS_CTL_ELEM_TYPE_INTEGER:
143                 type = "INT";
144                 break;
145             case AOS_CTL_ELEM_TYPE_ENUMERATED:
146                 type = "ENUM";
147                 break;
148             case AOS_CTL_ELEM_TYPE_BYTES:
149                 type = "BYTE";
150                 break;
151             case AOS_CTL_ELEM_TYPE_IEC958:
152                 type = "IEC958";
153                 break;
154             case AOS_CTL_ELEM_TYPE_INTEGER64:
155                 type = "INT64";
156                 break;
157             default:
158                 type = "Unknown";
159                 break;
160         }
161 
162         LOGD(LOG_TAG, "%s:%d, element_info[%d].id.id = %d", __func__, __LINE__, i, elem_info->id.id);
163         LOGD(LOG_TAG, "%s:%d, element_info[%d].id.name = %s", __func__, __LINE__, i, elem_info->id.name);
164         LOGD(LOG_TAG, "%s:%d, element_info[%d].count = %d", __func__, __LINE__, i, elem_info->count);
165         LOGD(LOG_TAG, "%s:%d, element_info[%d].type = %d (%s)", __func__, __LINE__, i, elem_info->type, type);
166     }
167     return MIXER_RETURN_SUCCESS;
168 }
169 
aos_mixer_set_int_value(aos_mixer_t * mixer,char * name,int value)170 int aos_mixer_set_int_value(aos_mixer_t *mixer, char *name, int value)
171 {
172     int i = 0;
173     struct audio_ctl_elem_info * elem_info = NULL;
174     struct audio_ctl_elem_value ev;
175     if(!mixer || !name) {
176         return MIXER_RETURN_ERR;
177     }
178     for(i = 0; i < mixer->count; i++) {
179         elem_info = mixer->elem_info + i;
180         if(!strcmp(elem_info->id.name, name)) {
181             break;
182         }
183     }
184     if(i >= mixer->count) {
185         return MIXER_RETURN_ERR;
186     }
187     if(AOS_CTL_ELEM_TYPE_INTEGER != elem_info->type) {
188         return MIXER_RETURN_ERR;
189     }
190     ev.id.id = elem_info->id.id;
191     ev.value.integer.value[0] = value;
192     if(ioctl(mixer->fd, AUDIO_CTL_IOCTL_ELEM_WRITE, &ev) < 0) {
193         return MIXER_RETURN_ERR;
194     }
195     LOGD(LOG_TAG, "%s:%d, set [%s, %d] successfully", __func__, __LINE__, name, value);
196     return MIXER_RETURN_SUCCESS;
197 }
198 
aos_mixer_get_int_value(aos_mixer_t * mixer,char * name,int * value)199 int aos_mixer_get_int_value(aos_mixer_t *mixer, char *name, int *value)
200 {
201     int i = 0;
202     struct audio_ctl_elem_info * elem_info = NULL;
203     struct audio_ctl_elem_value ev;
204     if(!mixer || !name) {
205         return MIXER_RETURN_ERR;
206     }
207     for(i = 0; i < mixer->count; i++) {
208         elem_info = mixer->elem_info + i;
209         if(!strcmp(elem_info->id.name, name)) {
210             break;
211         }
212     }
213     if(i >= mixer->count) {
214         return MIXER_RETURN_ERR;
215     }
216     if(AOS_CTL_ELEM_TYPE_INTEGER != elem_info->type) {
217         return MIXER_RETURN_ERR;
218     }
219     ev.id.id = elem_info->id.id;
220     if(ioctl(mixer->fd, AUDIO_CTL_IOCTL_ELEM_READ, &ev) < 0) {
221         return MIXER_RETURN_ERR;
222     }
223     *value = ev.value.integer.value[0];
224     LOGD(LOG_TAG, "%s:%d, get [%s, %d] successfully", __func__, __LINE__, name, *value);
225     return MIXER_RETURN_SUCCESS;
226 }
227 
aos_mixer_close(aos_mixer_t * mixer)228 int aos_mixer_close(aos_mixer_t *mixer)
229 {
230     if(!mixer) {
231         LOGE(LOG_TAG, "%s:%d, invalid mixer", __func__, __LINE__);
232         return MIXER_RETURN_ERR;
233     }
234     if(mixer->fd >= 0) {
235         close(mixer->fd);
236         mixer->fd = -1;
237     }
238     if(mixer->name) {
239         free(mixer->name);
240         mixer->name = NULL;
241     }
242     if(mixer->elem_info) {
243         free(mixer->elem_info);
244         mixer->elem_info = NULL;
245     }
246     free(mixer);
247     mixer = NULL;
248     LOGD(LOG_TAG, "%s:%d, close mixer successfully", __func__, __LINE__);
249     return MIXER_RETURN_SUCCESS;
250 }
251 
aos_set_master_volume(int volume)252 int aos_set_master_volume(int volume)
253 {
254     return aos_mixer_common_set_int_value(AOS_MASTER_VOLUME_TX_STRING, volume);
255 }
256 
aos_get_master_volume(int * volume)257 int aos_get_master_volume(int *volume)
258 {
259     return aos_mixer_common_get_int_value(AOS_MASTER_VOLUME_TX_STRING, volume);
260 }
261 
aos_set_mute_state(int mute)262 int aos_set_mute_state(int mute)
263 {
264     return aos_mixer_common_set_int_value(AOS_MASTER_MUTE_STATE_STRING, mute);
265 }
266 
aos_get_mute_state(int * mute)267 int aos_get_mute_state(int *mute)
268 {
269     return aos_mixer_common_get_int_value(AOS_MASTER_MUTE_STATE_STRING, mute);
270 }
271 
aos_mixer_test(char * pbuffer,int outlen,int argc,char ** argv)272 void aos_mixer_test(char *pbuffer, int outlen, int argc, char **argv)
273 {
274     int volume = -1;
275     if (argc < 1) {
276         LOGE(LOG_TAG, "%s:%d: Usage: %s", __func__, __LINE__, argv[0]);
277         return;
278     }
279     aos_set_master_volume(55);
280     aos_get_master_volume(&volume);
281     aos_set_mute_state(1);
282 }