AudioHardware: Dispatch setParameters to input and output
[tinyalsa-audio.git] / Mixer.cpp
1 /*
2  * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
3  *
4  * This is based on TinyHardware:
5  * Copyright 2011 Wolfson Microelectronics plc
6  *
7  * This is based on Nexus S AudioHardware implementation:
8  * Copyright 2010, The Android Open-Source Project
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *     http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  */
22
23 #define LOG_TAG "AudioHardware"
24
25 #include <cutils/log.h>
26 #include <media/AudioSystem.h>
27 #include <expat.h>
28
29 #include "Mixer.h"
30
31 /*
32  * Missing:
33  * - "write" element handling (as well as ctl), for type MIXER_DATA_TYPE_WRITE
34  */
35
36 namespace android {
37
38 struct tinyalsa_mixer_device_name mixer_output_devices_names[] = {
39         { AudioSystem::DEVICE_OUT_EARPIECE, "earpiece" },
40         { AudioSystem::DEVICE_OUT_SPEAKER, "speaker" },
41         { AudioSystem::DEVICE_OUT_WIRED_HEADSET, "headset" },
42         { AudioSystem::DEVICE_OUT_WIRED_HEADPHONE, "headphone" },
43         { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO, "bluetooth-sco" },
44         { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET, "bluetooth-sco-headset" },
45         { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT, "bluetooth-sco-carkit" },
46         { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, "bluetooth-a2dp" },
47         { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, "bluetooth-a2dp-headphones" },
48         { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, "bluetooth-a2dp-speaker" },
49         { AudioSystem::DEVICE_OUT_AUX_DIGITAL, "aux-digital" },
50         { AudioSystem::DEVICE_OUT_HDMI, "hdmi" }
51 };
52
53 struct tinyalsa_mixer_device_name mixer_input_devices_names[] = {
54         { AudioSystem::DEVICE_IN_COMMUNICATION, "communication" },
55         { AudioSystem::DEVICE_IN_AMBIENT, "ambient" },
56         { AudioSystem::DEVICE_IN_BUILTIN_MIC, "builtin-mic" },
57         { AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET, "bluetooth-sco-headset" },
58         { AudioSystem::DEVICE_IN_WIRED_HEADSET, "headset" },
59         { AudioSystem::DEVICE_IN_AUX_DIGITAL, "aux-digital" },
60         { AudioSystem::DEVICE_IN_VOICE_CALL, "voice-call" },
61         { AudioSystem::DEVICE_IN_BACK_MIC, "back-mic" }
62 };
63
64 struct tinyalsa_mixer_mode_name mixer_modes_names[] = {
65         { AudioSystem::MODE_NORMAL, "normal" },
66         { AudioSystem::MODE_RINGTONE, "ringtone" },
67         { AudioSystem::MODE_IN_CALL, "in-call" },
68         { AudioSystem::MODE_IN_COMMUNICATION, "in-communication" }
69 };
70
71 struct tinyalsa_mixer_device mixer_init_device;
72
73 struct tinyalsa_mixer_device *mixer_output_devices = NULL;
74 struct tinyalsa_mixer_device *mixer_current_output_device = NULL;
75
76 struct tinyalsa_mixer_device *mixer_input_devices = NULL;
77 struct tinyalsa_mixer_device *mixer_current_input_device = NULL;
78
79 int tinyalsa_mixer_started = 0;
80
81 status_t tinyalsa_mixer_devices_alloc(void)
82 {
83         int devices_names_count, modes_names_count;
84         int i, j, c;
85
86         modes_names_count = sizeof(mixer_modes_names) /
87                 sizeof(mixer_modes_names[0]);
88
89         if(mixer_output_devices != NULL) {
90                 LOGE("Error: mixer_output_devices are already allocated");
91                 return BAD_VALUE;
92         }
93
94         devices_names_count = sizeof(mixer_output_devices_names) /
95                 sizeof(mixer_output_devices_names[0]);
96         c = devices_names_count * modes_names_count;
97
98         mixer_output_devices = (struct tinyalsa_mixer_device *)
99                 calloc(c, sizeof(*mixer_output_devices));
100
101         LOGD("Alloc %d elements (%d bytes) to mixer_output_devices", c,
102                 (sizeof(*mixer_output_devices) * c));
103
104         for(i=0 ; i < devices_names_count ; i++) {
105                 for(j=0 ; j < modes_names_count ; j++) {
106                         c = i * modes_names_count + j;
107                         mixer_output_devices[c].type =
108                                 mixer_output_devices_names[i].type;
109                         mixer_output_devices[c].mode =
110                                 mixer_modes_names[j].mode;
111                         mixer_output_devices[c].enabled = 0;
112                 }
113         }
114
115         if(mixer_input_devices != NULL) {
116                 LOGE("Error: mixer_input_devices are already allocated");
117                 return BAD_VALUE;
118         }
119
120         c = sizeof(mixer_input_devices_names) /
121                 sizeof(mixer_input_devices_names[0]);
122
123         mixer_input_devices = (struct tinyalsa_mixer_device *)
124                 calloc(c, sizeof(*mixer_input_devices));
125
126         LOGD("Alloc %d elements (%d bytes) to mixer_input_devices", c,
127                 (sizeof(*mixer_input_devices) * c));
128
129         for(i=0 ; i < c ; i++) {
130                 mixer_input_devices[i].type =
131                         mixer_input_devices_names[i].type;
132                 mixer_input_devices[i].mode = AudioSystem::MODE_NORMAL;
133         }
134
135         memset(&mixer_init_device, 0, sizeof(mixer_init_device));
136         mixer_current_output_device = NULL;
137         mixer_current_input_device = NULL;
138
139         return NO_ERROR;
140 }
141
142 void tinyalsa_mixer_devices_free(void)
143 {
144         if(mixer_output_devices != NULL)
145                 free(mixer_output_devices);
146         if(mixer_input_devices != NULL)
147                 free(mixer_input_devices);
148
149         mixer_current_output_device = NULL;
150         mixer_current_input_device = NULL;
151 }
152
153 void list_head_dump(struct list_head *list_p)
154 {
155         struct tinyalsa_mixer_data *mixer_data;
156         struct list_head *list = list_p;
157
158         LOGD("Dump from top to bottom");
159
160         while(list) {
161                 mixer_data = (struct tinyalsa_mixer_data *) list->data;
162                 LOGD("* %s:%s", mixer_data->name, mixer_data->value);
163
164                 if(list->next != NULL)
165                         list = list->next;
166                 else
167                         break;
168         }
169
170         LOGD("Dump from bottom to top");
171
172         while(list) {
173                 mixer_data = (struct tinyalsa_mixer_data *) list->data;
174                 LOGD("* %s:%s", mixer_data->name, mixer_data->value);
175
176                 if(list->prev != NULL)
177                         list = list->prev;
178                 else
179                         break;
180         }
181
182 }
183
184 struct list_head *list_head_alloc(void)
185 {
186         struct list_head *list = (struct list_head *)
187                 calloc(1, sizeof(struct list_head));
188
189
190         return list;
191 }
192
193 struct tinyalsa_mixer_data *tinyalsa_mixer_data_alloc(void)
194 {
195         struct tinyalsa_mixer_data *mixer_data = (struct tinyalsa_mixer_data *)
196                 calloc(1, sizeof(struct tinyalsa_mixer_data));
197
198         return mixer_data;
199 }
200
201 void tinyalsa_mixer_device_list_free(struct list_head *list)
202 {
203         struct tinyalsa_mixer_data *mixer_data;
204
205         while(list) {
206                 mixer_data = (struct tinyalsa_mixer_data *) list->data;
207                 if(mixer_data->name)
208                         free(mixer_data->name);
209                 if(mixer_data->attr)
210                         free(mixer_data->attr);
211                 if(mixer_data->value)
212                         free(mixer_data->value);
213
214                 if(list->next != NULL)
215                         list = list->next;
216                 else
217                         break;
218         }
219 }
220
221 void tinyalsa_mixer_device_free(struct tinyalsa_mixer_device *device)
222 {
223         if(device->enable != NULL)
224                 tinyalsa_mixer_device_list_free(device->enable);
225         if(device->disable != NULL)
226                 tinyalsa_mixer_device_list_free(device->disable);
227 }
228
229 struct tinyalsa_mixer_device *tinyalsa_mixer_device_get(int type, int mode,
230         int enabled, struct tinyalsa_mixer_device *devices, int devices_count)
231 {
232         int i;
233
234         if(type < 0 || mode < 0 || devices == NULL || devices_count <= 0) {
235                 return NULL;
236         }
237
238         for(i=0 ; i < devices_count ; i++) {
239                 if(devices[i].type == type && devices[i].mode == mode) {
240                         if(enabled && devices[i].enabled)
241                                 return &devices[i];
242                         else if(!enabled)
243                                 return &devices[i];
244                 }
245         }
246
247         return NULL;
248 }
249
250 int tinyalsa_mixer_type_get_from_string(char *device_name,
251         struct tinyalsa_mixer_device_name *devices_names, int devices_names_count)
252 {
253         int i;
254
255         if(device_name == NULL || devices_names == NULL || devices_names_count <= 0) {
256                 return -1;
257         }
258
259         for(i=0 ; i < devices_names_count ; i++) {
260                 if(strcmp(devices_names[i].name, device_name) == 0) {
261                         return devices_names[i].type;
262                 }
263         }
264
265         return -1;
266 }
267
268 int tinyalsa_mixer_mode_get_from_string(char *device_mode)
269 {
270         int modes_names_count;
271         int i;
272
273         // Fallback
274         if(device_mode == NULL)
275                 return AudioSystem::MODE_NORMAL;
276
277         modes_names_count = sizeof(mixer_modes_names) /
278                 sizeof(mixer_modes_names[0]);
279
280         for(i=0 ; i < modes_names_count ; i++) {
281                 if(strcmp(mixer_modes_names[i].name, device_mode) == 0) {
282                         return mixer_modes_names[i].mode;
283                 }
284         }
285
286         // Fallback
287         return AudioSystem::MODE_NORMAL;
288 }
289
290 struct tinyalsa_mixer_device *tinyalsa_mixer_device_get_from_strings(
291         char *device_name, char *device_type, char *device_mode)
292 {
293         int devices_names_count, modes_names_count;
294         int mode, type;
295         int c;
296
297         if(device_name == NULL || device_type == NULL)
298                 return NULL;
299
300         if(strcmp(device_type, "output") == 0) {
301                 modes_names_count = sizeof(mixer_modes_names) /
302                         sizeof(mixer_modes_names[0]);
303
304                 mode = tinyalsa_mixer_mode_get_from_string(device_mode);
305
306                 devices_names_count = sizeof(mixer_output_devices_names) /
307                         sizeof(mixer_output_devices_names[0]);
308
309                 type = tinyalsa_mixer_type_get_from_string(device_name,
310                         mixer_output_devices_names, devices_names_count);
311
312                 c = devices_names_count * modes_names_count;
313
314                 return tinyalsa_mixer_device_get(type, mode, 0,
315                         mixer_output_devices, c);
316         } else if(strcmp(device_type, "input") == 0) {
317                 modes_names_count = sizeof(mixer_modes_names) /
318                         sizeof(mixer_modes_names[0]);
319
320                 mode = tinyalsa_mixer_mode_get_from_string(device_mode);
321
322                 devices_names_count = sizeof(mixer_input_devices_names) /
323                         sizeof(mixer_input_devices_names[0]);
324
325                 type = tinyalsa_mixer_type_get_from_string(device_name,
326                         mixer_input_devices_names, devices_names_count);
327
328                 c = devices_names_count * modes_names_count;
329
330                 return tinyalsa_mixer_device_get(type, mode, 0,
331                         mixer_input_devices, c);
332         } else {
333                 LOGE("Unknown device type: %s", device_type);
334                 return NULL;
335         }
336 }
337
338 struct tinyalsa_mixer_data *tinyalsa_mixer_data_get_from_attr(
339         struct list_head *list, char *data_attr)
340 {
341         struct tinyalsa_mixer_data *mixer_data = NULL;
342
343         if(list == NULL || data_attr == NULL)
344                 return NULL;
345
346         while(list) {
347                 mixer_data = (struct tinyalsa_mixer_data *) list->data;
348
349                 if(mixer_data != NULL && mixer_data->attr != NULL) {
350                         if(strcmp(mixer_data->attr, data_attr) == 0) {
351                                 return mixer_data;
352                         }
353                 }
354
355                 if(list->next != NULL)
356                         list = list->next;
357                 else
358                         break;
359         }
360
361         return NULL;
362 }
363
364 status_t tinyalsa_mixer_route_set(struct mixer *mixer,
365         struct tinyalsa_mixer_data *mixer_data)
366 {
367         struct mixer_ctl *ctl;
368         status_t status = BAD_VALUE;
369         int value;
370         int type;
371         int rc;
372         int i;
373
374         ctl = mixer_get_ctl_by_name(mixer, mixer_data->name);
375         type = mixer_ctl_get_type(ctl);
376
377         switch(type) {
378                 case MIXER_CTL_TYPE_BOOL:
379                         value = strcmp(mixer_data->value, "on") == 0 ?
380                                 1 : 0;
381                         break;
382                 case MIXER_CTL_TYPE_INT:
383                         value = atoi(mixer_data->value);
384                         break;
385                 case MIXER_CTL_TYPE_BYTE:
386                         value = atoi(mixer_data->value) & 0xff;
387                         break;
388                 case MIXER_CTL_TYPE_ENUM:
389                 case MIXER_CTL_TYPE_UNKNOWN:
390                         rc = mixer_ctl_set_enum_by_string(ctl, mixer_data->value);
391                         if(!rc)
392                                 status = NO_ERROR;
393         }
394
395         if(type == MIXER_CTL_TYPE_BOOL || type == MIXER_CTL_TYPE_INT ||
396                 type == MIXER_CTL_TYPE_BYTE) {
397                         for(i=0 ; i < mixer_ctl_get_num_values(ctl) ; i++) {
398                                 rc = mixer_ctl_set_value(ctl, i, value);
399                                 if(!rc)
400                                         status = NO_ERROR;
401                         }
402         }
403
404         LOGD("Setting %s to %s", mixer_data->name, mixer_data->value);
405
406         return status;
407 }
408
409 status_t tinyalsa_mixer_route_set_list(struct mixer *mixer, struct list_head *list)
410 {
411         struct tinyalsa_mixer_data *mixer_data = NULL;
412         status_t status;
413
414         while(list) {
415                 mixer_data = (struct tinyalsa_mixer_data *) list->data;
416
417                 if(mixer_data->attr && strcmp(mixer_data->attr, "voice-volume") == 0) {
418                         LOGD("Skipping voice volume control");
419                 } else {
420                         status = tinyalsa_mixer_route_set(mixer, mixer_data);
421                 }
422
423                 if(list->next != NULL)
424                         list = list->next;
425                 else
426                         break;
427         }
428
429         return status;
430 }
431
432 status_t tinyalsa_mixer_route_init(struct mixer *mixer)
433 {
434         status_t status;
435
436         status = tinyalsa_mixer_route_set_list(mixer, mixer_init_device.enable);
437         if(status != NO_ERROR) {
438                 LOGE("Failed to set init route!");
439                 goto error;
440         }
441
442 error:
443         return BAD_VALUE;
444 }
445
446 status_t tinyalsa_mixer_route(struct mixer *mixer, int type, int mode) {
447         int devices_names_count, modes_names_count;
448         struct tinyalsa_mixer_device *device;
449         status_t status;
450         int c;
451
452         if(AudioSystem::isOutputDevice((AudioSystem::audio_devices) type)) {
453                 modes_names_count = sizeof(mixer_modes_names) /
454                         sizeof(mixer_modes_names[0]);
455
456                 devices_names_count = sizeof(mixer_output_devices_names) /
457                         sizeof(mixer_output_devices_names[0]);
458
459                 c = devices_names_count * modes_names_count;
460
461                 device = tinyalsa_mixer_device_get(type, mode, 1,
462                         mixer_output_devices, c);
463
464                 // Try normal mode
465                 if(!device) {
466                         LOGE("Fallback to normal mode");
467                         device = tinyalsa_mixer_device_get(type, AudioSystem::MODE_NORMAL, 1,
468                         mixer_output_devices, c);
469
470                         if(!device)
471                                 goto error_device;
472                 }
473
474                 if(mixer_current_output_device != NULL) {
475                         status = tinyalsa_mixer_route_set_list(mixer,
476                                 mixer_current_output_device->disable);
477                         mixer_current_output_device = NULL;
478                         if(status != NO_ERROR) {
479                                 LOGE("Failed to set disable route for current device!");
480                                 goto error;
481                         }
482                 }
483
484                 status = tinyalsa_mixer_route_set_list(mixer, device->enable);
485                 if(status != NO_ERROR) {
486                         LOGE("Failed to set enable route for device: %d/%d!", type, mode);
487                         goto error;
488                 }
489
490                 mixer_current_output_device = device;
491         } else if(AudioSystem::isInputDevice((AudioSystem::audio_devices) type)) {
492                 c = sizeof(mixer_input_devices_names) /
493                         sizeof(mixer_input_devices_names[0]);
494
495                 // There are no modes for input
496                 device = tinyalsa_mixer_device_get(type, AudioSystem::MODE_NORMAL, 1,
497                         mixer_input_devices, c);
498
499                 if(!device)
500                         goto error_device;
501
502                 if(mixer_current_input_device != NULL) {
503                         status = tinyalsa_mixer_route_set_list(mixer,
504                                 mixer_current_input_device->disable);
505                         mixer_current_input_device = NULL;
506                         if(status != NO_ERROR) {
507                                 LOGE("Failed to set disable route for current device!");
508                                 goto error;
509                         }
510                 }
511
512                 status = tinyalsa_mixer_route_set_list(mixer, device->enable);
513                 if(status != NO_ERROR) {
514                         LOGE("Failed to set enable route for device: %d!", type);
515                         goto error;
516                 }
517
518                 mixer_current_input_device = device;
519         } else {
520                 goto error_device;
521         }
522
523         return NO_ERROR;
524
525 error_device:
526         LOGE("Error: device of type %d not found!", type);
527 error:
528         return BAD_VALUE;
529 }
530
531 status_t tinyalsa_mixer_set_voice_volume(struct mixer *mixer, float volume)
532 {
533         struct tinyalsa_mixer_data *mixer_data = NULL;
534         int value, value_min, value_max, values_count;
535         char *value_string;
536         status_t status;
537
538         if(mixer_current_output_device == NULL) {
539                 LOGE("Failed to set voice volume: no output device!");
540                 return BAD_VALUE;
541         }
542
543         mixer_data = tinyalsa_mixer_data_get_from_attr(
544                 mixer_current_output_device->enable, "voice-volume");
545
546         if(mixer_data == NULL || mixer_data->value == NULL) {
547                 LOGE("Failed to set voice volume: no valid data!");
548                 return BAD_VALUE;
549         }
550
551         values_count = sscanf(mixer_data->value, "%d-%d", &value_min, &value_max);
552         if(values_count != 2) {
553                 LOGE("Failed to set voice volume: wrong value!");
554                 return BAD_VALUE;
555         }
556
557         value = (value_max - value_min) * volume + value_min;
558
559         // Ugly workaround because string value is needed
560         value_string = mixer_data->value;
561         asprintf(&mixer_data->value, "%d", value);
562
563         status = tinyalsa_mixer_route_set(mixer, mixer_data);
564
565         free(mixer_data->value);
566         mixer_data->value = value_string;
567
568         return status;
569 }
570
571 status_t tinyalsa_mixer_set_mic_mute(struct mixer *mixer, int state)
572 {
573         struct tinyalsa_mixer_data *mixer_data = NULL;
574         status_t status;
575
576         if(mixer_current_output_device == NULL) {
577                 LOGE("Failed to set mic mute: no output device!");
578                 return BAD_VALUE;
579         }
580
581         if(state) {
582                 mixer_data = tinyalsa_mixer_data_get_from_attr(
583                         mixer_current_output_device->enable, "mic");
584         } else {
585                 mixer_data = tinyalsa_mixer_data_get_from_attr(
586                         mixer_current_output_device->disable, "mic");
587         }
588
589         if(mixer_data == NULL || mixer_data->value == NULL) {
590                 LOGE("Failed to set mic mute: no valid data!");
591                 return BAD_VALUE;
592         }
593
594         return tinyalsa_mixer_route_set(mixer, mixer_data);
595 }
596
597 void tinyalsa_mixer_config_free(void)
598 {
599         int devices_names_count, modes_names_count;
600         int c;
601         int i;
602
603         modes_names_count = sizeof(mixer_modes_names) /
604                 sizeof(mixer_modes_names[0]);
605
606         // free init device
607         tinyalsa_mixer_device_free(&mixer_init_device);
608
609         devices_names_count = sizeof(mixer_output_devices_names) /
610                 sizeof(mixer_output_devices_names[0]);
611
612         // free output devices
613         c = devices_names_count * modes_names_count;
614
615         for(i=0 ; i < c ; i++) {
616                 tinyalsa_mixer_device_free(&mixer_output_devices[i]);
617         }
618
619         devices_names_count = sizeof(mixer_input_devices_names) /
620                 sizeof(mixer_input_devices_names[0]);
621
622         // free input devices
623         c = devices_names_count;
624
625         for(i=0 ; i < c ; i++) {
626                 tinyalsa_mixer_device_free(&mixer_input_devices[i]);
627         }
628 }
629
630 void tinyalsa_mixer_config_start(void *data, const XML_Char *elem,
631         const XML_Char **attr)
632 {
633         struct tinyalsa_mixer_config_data *config_data;
634         struct tinyalsa_mixer_data *mixer_data;
635         struct list_head *list_prev;
636         struct list_head *list;
637
638         const XML_Char *device_name = NULL;
639         const XML_Char *device_type = NULL;
640         const XML_Char *device_mode = NULL;
641         const XML_Char *data_name = NULL;
642         const XML_Char *data_attr = NULL;
643         const XML_Char *data_value = NULL;
644         int i;
645
646         config_data = (struct tinyalsa_mixer_config_data *) data;
647
648         if(strcmp(elem, "tinyalsa-audio") == 0) {
649                 for(i=0 ; attr[i] && attr[i+1] ; i++) {
650                         if(strcmp(attr[i], "device") == 0) {
651                                 i++;
652                                 LOGD("Parsing config for device: %s", attr[i]);
653                         }
654                 }
655         } else if(strcmp(elem, "device") == 0) {
656                 for(i=0 ; attr[i] && attr[i+1] ; i++) {
657                         if(strcmp(attr[i], "type") == 0) {
658                                 i++;
659                                 device_type = attr[i];
660                         } else if(strcmp(attr[i], "mode") == 0) {
661                                 i++;
662                                 device_mode = attr[i];
663                         } else if(strcmp(attr[i], "name") == 0) {
664                                 i++;
665                                 device_name = attr[i];
666                         }
667                 }
668
669                 if(device_type == NULL) {
670                         LOGE("Missing device type!");
671                         return;
672                 }
673
674                 if(strcmp(device_type, "init") == 0) {
675                         config_data->device = &mixer_init_device;
676                 } else if(device_name != NULL) {
677                         config_data->device =
678                                 tinyalsa_mixer_device_get_from_strings((char *) device_name, (char *) device_type, (char *) device_mode);
679                         if(config_data->device != NULL)
680                                 config_data->device->enabled = 1;
681                 } else {
682                         LOGE("Missing device name!");
683                         return;
684                 }
685         } else if(strcmp(elem, "path") == 0 && config_data->device != NULL) {
686                 for(i=0 ; attr[i] && attr[i+1] ; i++) {
687                         if(strcmp(attr[i], "name") == 0) {
688                                 i++;
689                                 if(strcmp(attr[i], "enable") == 0) {
690                                         config_data->list_start =
691                                                 &config_data->device->enable;
692                                 } else if(strcmp(attr[i], "disable") == 0) {
693                                         config_data->list_start =
694                                                 &config_data->device->disable;
695                                 }
696                         }
697                 }
698         } else if(strcmp(elem, "ctl") == 0 && config_data->device != NULL) {
699                 for(i=0 ; attr[i] && attr[i+1] ; i++) {
700                         if(strcmp(attr[i], "name") == 0) {
701                                 i++;
702                                 data_name = attr[i];
703                         } else if(strcmp(attr[i], "attr") == 0) {
704                                 i++;
705                                 data_attr = attr[i];
706                         } else if(strcmp(attr[i], "value") == 0) {
707                                 i++;
708                                 data_value = attr[i];
709                         }
710                 }
711
712                 if(data_name && data_value) {
713                         list = list_head_alloc();
714
715                         if(config_data->list_start != NULL) {
716                                 *config_data->list_start = list;
717                                 config_data->list_start = NULL;
718                         } else {
719                                 config_data->list->next = list;
720                                 list->prev = config_data->list;
721                         }
722
723                         mixer_data = tinyalsa_mixer_data_alloc();
724                         list->data = (void *) mixer_data;
725
726                         mixer_data->name = strdup((char *) data_name);
727                         mixer_data->value = strdup((char *) data_value);
728                         mixer_data->type = MIXER_DATA_TYPE_CTL;
729
730                         if(data_attr)
731                                 mixer_data->attr = strdup((char *) data_attr);
732
733                         config_data->list = list;
734                 }
735         }
736 }
737
738 void tinyalsa_mixer_config_end(void *data, const XML_Char *name)
739 {
740         struct tinyalsa_mixer_config_data *config_data;
741
742         config_data = (struct tinyalsa_mixer_config_data *) data;
743
744         if(strcmp(name, "tinyalsa-audio") == 0) {
745                 LOGI("Config parsing done");
746         } else if(strcmp(name, "device") == 0) {
747                 config_data->device = NULL;
748         } else if(strcmp(name, "path") == 0) {
749                 config_data->list_start = NULL;
750                 config_data->list = NULL;
751         }
752 }
753
754 status_t tinyalsa_mixer_config_parse(void)
755 {
756         struct tinyalsa_mixer_config_data config_data;
757
758         char buf[80];
759         XML_Parser p;
760         FILE *f;
761
762         int eof = 0;
763         int len = 0;
764
765         f = fopen(TINYALSA_MIXER_CONFIG_FILE, "r");
766         if(!f) {
767                 LOGE("Failed to open tinyalsa-audio config file!");
768                 return BAD_VALUE;
769         }
770
771         p = XML_ParserCreate(NULL);
772         if(!p) {
773                 LOGE("Failed to create XML parser!");
774                 goto error_file;
775         }
776
777         memset(&config_data, 0, sizeof(config_data));
778
779         XML_SetUserData(p, &config_data);
780         XML_SetElementHandler(p, tinyalsa_mixer_config_start, tinyalsa_mixer_config_end);
781
782         while(!eof) {
783                 len = fread(buf, 1, sizeof(buf), f);
784                 if(ferror(f)) {
785                         LOGE("Failed to read config file!");
786                         goto error_xml_parser;
787                 }
788
789                 eof = feof(f);
790
791                 if(XML_Parse(p, buf, len, eof) == XML_STATUS_ERROR) {
792                         LOGE("Failed to parse line %d: %s",
793                                 XML_GetCurrentLineNumber(p),
794                                 XML_ErrorString(XML_GetErrorCode(p)));
795                         goto error_xml_parser;
796                 }
797         }
798
799         return NO_ERROR;
800
801 error_xml_parser:
802         XML_ParserFree(p);
803
804 error_file:
805         fclose(f);
806
807         return BAD_VALUE;
808 }
809
810 int tinyalsa_mixer_is_started(void)
811 {
812         return tinyalsa_mixer_started;
813 }
814
815 void tinyalsa_mixer_start(void)
816 {
817         tinyalsa_mixer_started = 1;
818 }
819
820 void tinyalsa_mixer_stop(void)
821 {
822         tinyalsa_mixer_started = 0;
823 }
824
825 TinyALSAMixer::TinyALSAMixer() :
826         mMixer(NULL), mMainInstance(0)
827 {
828         LOGD("Mixer()");
829
830         mMixer = mixer_open(0);
831
832         if(!tinyalsa_mixer_is_started()) {
833                 tinyalsa_mixer_start();
834                 mMainInstance = 1;
835
836                 tinyalsa_mixer_devices_alloc();
837                 tinyalsa_mixer_config_parse();
838
839                 tinyalsa_mixer_route_init(mMixer);
840         }
841 }
842
843 TinyALSAMixer::~TinyALSAMixer()
844 {
845         LOGD("~Mixer()");
846
847         if(mMainInstance) {
848                 tinyalsa_mixer_config_free();
849                 tinyalsa_mixer_devices_free();
850         }
851
852         if(mMixer)
853                 mixer_close(mMixer);
854 }
855
856 status_t TinyALSAMixer::route(int type)
857 {
858         return tinyalsa_mixer_route(mMixer, type, AudioSystem::MODE_NORMAL);
859 }
860
861 status_t TinyALSAMixer::route(int type, int mode)
862 {
863         return tinyalsa_mixer_route(mMixer, type, mode);
864 }
865
866 status_t TinyALSAMixer::setVoiceVolume(float volume)
867 {
868         return tinyalsa_mixer_set_voice_volume(mMixer, volume);
869 }
870
871 status_t TinyALSAMixer::setMicMute(bool state)
872 {
873         return tinyalsa_mixer_set_mic_mute(mMixer, state ? 1 : 0);
874 }
875
876 }; // namespace android