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 }