1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <assert.h>
17 #include <ctype.h>
18 #include <errno.h>
19 #include <getopt.h>
20 #include <math.h>
21 #include <poll.h>
22 #include <stdarg.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "audio_mixer.h"
29 #include "securec.h"
30 
31 #define AUDIO_MAX_CARDS   32
32 #define SND_CARD_NAME_LEN 64
33 #define INFO_BUF_LEN      128
34 #define CARD_SRV_NAME_LEN (SND_CARD_NAME_LEN)
35 #define DEFAULT_CARD_NAME "hdf_audio_codec_primary_dev0"
36 
37 #define SRV_SND_PRIMARY_MIN 0
38 #define SRV_SND_PRIMARY_MAX 10
39 #define SRV_SND_HDMI_MIN    11
40 #define SRV_SND_HDMI_MAX    20
41 #define SRV_SND_USB_MIN     21
42 #define SRV_SND_USB_MAX     30
43 #define SRV_SND_A2DP_MIN    31
44 #define SRV_SND_A2DP_MAX    40
45 
46 #define SSET_WR 0
47 #define SSET_RO 1
48 #define STRTOL_BASE 10
49 
50 #define L_INACTIV (1 << 1)
51 
52 struct HdfIoService *g_service = NULL;
53 static char g_serviceName[CARD_SRV_NAME_LEN] = DEFAULT_CARD_NAME;
54 static char g_card[SND_CARD_NAME_LEN] = "primary0";
55 static char g_dev[SND_CARD_NAME_LEN] = "default";
56 static AudioPcmType g_pcm = PCM_RENDER;
57 static bool g_debugFlag = false;
58 #ifdef CHANNEL_MAP
59 static bool chnmapFlag = false;
60 #endif
61 
ShowUsage(void)62 static int32_t ShowUsage(void)
63 {
64     printf("Usage: audio_mixer <options> [command]\n");
65     printf("\nAvailable options:\n");
66     printf("  -h, --help        this help\n");
67     printf("  -l, --list-cards  list all soundcards and digital audio devices\n");
68     printf("  -c, --card N      select the card\n");
69     printf("  -D, --device N    select the device, default '%s'\n", g_dev);
70     printf("  -P, --pcm N       select the PCM type(1: reader/2: capture), default 1\n");
71     printf("  -d, --debug       debug mode\n");
72     printf("  -v, --version     print version of this program\n");
73     printf("  -i, --inactive    show also inactive controls. (Reserved)\n");
74     printf("  -S, --service N   select the audio card service default '%s'\n", DEFAULT_CARD_NAME);
75 #ifdef CHANNEL_MAP
76     printf("  -m, --chmap=ch1,ch2,..    Give the channel map to override or follow\n");
77 #endif
78 
79     printf("\nAvailable commands:\n");
80     printf("  info      show all info for mixer\n");
81     printf("  controls  show all controls for given card\n");
82     printf("  contents  show contents of all controls for given card\n");
83     printf("  set ID P  set control contents for one control\n");
84     printf("  get ID    get control contents for one control\n");
85 
86     return 0;
87 }
88 
89 #ifdef LEGECY_STRATEGY
AudioCard2Dev(int32_t card)90 static int32_t AudioCard2Dev(int32_t card)
91 {
92     int32_t ret;
93     SND_TYPE sndType;
94     char ctlDev[CARD_SRV_NAME_LEN] = {0};
95 
96     switch (card) {
97         case SRV_SND_PRIMARY_MIN ... SRV_SND_PRIMARY_MAX:
98             sndType = SND_PRIMARY;
99             ret = sprintf_s(ctlDev, CARD_SRV_NAME_LEN - 1, "%s%d", "primary", card);
100             break;
101         case SRV_SND_HDMI_MIN ... SRV_SND_HDMI_MAX:
102             sndType = SND_HDMI;
103             ret = sprintf_s(ctlDev, CARD_SRV_NAME_LEN - 1, "%s%d", "hdmi", card);
104             break;
105         case SRV_SND_USB_MIN ... SRV_SND_USB_MAX:
106             sndType = SND_USB;
107             ret = sprintf_s(ctlDev, CARD_SRV_NAME_LEN - 1, "%s%d", "usb", card);
108             break;
109         case SRV_SND_A2DP_MIN ... SRV_SND_A2DP_MAX:
110             sndType = SND_A2DP;
111             ret = sprintf_s(ctlDev, CARD_SRV_NAME_LEN - 1, "%s%d", "a2dp", card);
112             break;
113         default:
114             DEBUG_LOG("Unknown sound card type!\n");
115             return U_FAILURE;
116     }
117     if (ret < 0) {
118         DEBUG_LOG("Failed to synthesize the card name!\n");
119         return U_FAILURE;
120     }
121     DEBUG_LOG("The card type: %i\n", sndType);
122     DEBUG_LOG("The card name: %s\n", ctlDev);
123     ret = memcpy_s(g_card, SND_CARD_NAME_LEN, ctlDev, strlen(ctlDev));
124     if (ret != 0) {
125         DEBUG_LOG("memcpy_s fail!\n");
126         return U_FAILURE;
127     }
128 
129     return U_SUCCESS;
130 }
131 
AudioCard2Dev2(const char * string,int32_t * index)132 static int32_t AudioCard2Dev2(const char *string, int32_t *index)
133 {
134     int32_t ret;
135     size_t len, offset;
136     char *name = NULL;
137 
138     name = strrchr(string, '/') + 1;
139     len = strlen(name);
140     if (len == 0) {
141         *index = -1;
142         DEBUG_LOG("name is empty!!!\n");
143         return U_FAILURE;
144     }
145     DEBUG_LOG("name is %s, len = %zu\n", name, len);
146 
147     offset = len - 1;
148     if (isdigit(name[offset]) == 0) {
149         *index = -1;
150         DEBUG_LOG("name is error!!!\n");
151         return U_FAILURE;
152     }
153     name += isdigit(name[offset - 1]) ? offset - 1 : offset;
154 
155     ret = sscanf_s(name, "%i", index);
156     if (ret <= 0) {
157         DEBUG_LOG("%s\n", strerror(errno));
158         printf("%s\n", strerror(errno));
159         return U_FAILURE;
160     }
161 
162     return AudioCard2Dev(*index);
163 }
164 
AudioCardGetIndex(const char * string,int32_t * index)165 static int32_t AudioCardGetIndex(const char *string, int32_t *index)
166 {
167     int32_t ret;
168     int32_t card = -1;
169 
170     if (string == NULL || *string == '\0') {
171         DEBUG_LOG("Invalid parameters!\n");
172         return U_INVALID_PARAM;
173     }
174 
175     if ((isdigit(*string) && *(string + 1) == 0) ||
176         (isdigit(*string) && isdigit(*(string + 1)) && *(string + 2) == 0)) {   // 2 for offset
177         /* An index was found */
178         ret = sscanf_s(string, "%i", &card);
179         if (ret <= 0) {
180             DEBUG_LOG("%s\n", strerror(errno));
181             printf("%s\n", strerror(errno));
182             return U_FAILURE;
183         }
184         if (card < 0 || card >= AUDIO_MAX_CARDS) {
185             DEBUG_LOG("%s\n", strerror(errno));
186             printf("%s\n", strerror(errno));
187             return U_FAILURE;
188         }
189 
190         ret = AudioCard2Dev(card);
191         if (ret != U_SUCCESS) {
192             return ret;
193         }
194         *index = card;
195     } else if (string[0] == '/') {
196         /* Find the device name */
197         return AudioCard2Dev2(string, index);
198     } else {
199         *index = -1;
200         DEBUG_LOG("Sound card name that cannot be converted\n");
201         return U_FAILURE;
202     }
203 
204     return U_SUCCESS;
205 }
206 #endif
207 
UpdateCardName(const char * card)208 static void UpdateCardName(const char *card)
209 {
210     int32_t id;
211 
212     if (card == NULL || *card == '\0') {
213         DEBUG_LOG("Invalid card!\n");
214         return;
215     }
216 
217     if ((isdigit(*card) && *(card + 1) == 0) ||
218         (isdigit(*card) && isdigit(*(card + 1)) && *(card + 2) == 0)) { // 2 for offset
219         id = (int32_t)strtol(card, NULL, STRTOL_BASE);
220         DEBUG_LOG("card %i\n", id);
221         UpdateCardSname(id, g_service, g_serviceName, CARD_SRV_NAME_LEN);
222         DEBUG_LOG("cardServiceName:%s, dev:%s\n", g_serviceName, g_dev);
223     }
224 }
225 
MixerInfo(void)226 static int32_t MixerInfo(void)
227 {
228     printf("card/dev: '%s'/'%s'\n", g_card, g_dev);
229     printf("  Mixer name : '%s'\n", "MIXER");
230     printf("  Components : '%s'\n", "Audio Components");
231     printf("----------------------------------\n");
232     MctlInfo(g_service, g_serviceName);
233 
234     return U_SUCCESS;
235 }
236 
237 #ifdef LEGECY_STRATEGY
CheckCardAndDev(int32_t index)238 static bool CheckCardAndDev(int32_t index)
239 {
240     switch (index) {
241         case SRV_SND_PRIMARY_MIN ... SRV_SND_PRIMARY_MAX:
242             DEBUG_LOG("primary%d\n", index);
243             break;
244         case SRV_SND_HDMI_MIN ... SRV_SND_HDMI_MAX:
245             DEBUG_LOG("hdmi%d\n", index);
246             break;
247         case SRV_SND_USB_MIN ... SRV_SND_USB_MAX:
248             DEBUG_LOG("usb%d\n", index);
249             break;
250         case SRV_SND_A2DP_MIN ... SRV_SND_A2DP_MAX:
251             DEBUG_LOG("a2dp%d\n", index);
252             break;
253         default:
254             DEBUG_LOG("Unknown sound card!!!\n");
255             return false;
256     }
257 
258     return true;
259 }
260 #endif
261 
MixerControls(void)262 static int32_t MixerControls(void)
263 {
264     if (g_service == NULL) {
265         DEBUG_LOG("Invalid service!\n");
266         return U_FAILURE;
267     }
268 
269     return MctlList(g_service, g_serviceName);
270 }
271 
ShowAllCardList(void)272 static void ShowAllCardList(void)
273 {
274     int32_t ret;
275 
276     if (g_service == NULL) {
277         DEBUG_LOG("Invalid service!\n");
278         return;
279     }
280 
281     ret = GetAllCards(g_service);
282     if (ret != U_SUCCESS) {
283         DEBUG_LOG("Couldn't find any sound card equipment!\n");
284     }
285 }
286 
DupCtlName(char * data,int32_t dataLen,char * buf,int32_t bufSize)287 static int32_t DupCtlName(char *data, int32_t dataLen, char *buf, int32_t bufSize)
288 {
289     int32_t ret;
290 
291     if (dataLen <= 0 || bufSize <= 0) {
292         DEBUG_LOG("Unable to copy to control name space!\n");
293         return U_FAILURE;
294     }
295 
296     if (bufSize >= dataLen) {
297         bufSize = dataLen - 1;
298     }
299 
300     ret = strncpy_s(data, dataLen, buf, bufSize);
301     if (ret != 0) {
302         DEBUG_LOG("strncpy_s fail!\n");
303         return U_FAILURE;
304     }
305     data[dataLen - 1] = '\0';
306 
307     return U_SUCCESS;
308 }
309 
ParseName(const char * s,struct AudioHwCtlElemId * eId)310 static int32_t ParseName(const char *s, struct AudioHwCtlElemId *eId)
311 {
312     int32_t c, size, len;
313     char *ptr = NULL;
314     char buf[INFO_BUF_LEN] = {0};
315     char *sbuf = buf;
316 
317     ptr = strstr(s, "=");
318     if (ptr == NULL) {
319         DEBUG_LOG("Cannot find the given element from control default!\n");
320         return U_FAILURE;
321     }
322     ptr++;
323 
324     size = 0;
325     if (*ptr == '\"' || *ptr == '\'') {
326         c = *ptr++;
327         while (*ptr && *ptr != c) {
328             if (size < (int32_t)sizeof(buf)) {
329                 *sbuf++ = *ptr;
330                 size++;
331             }
332             ptr++;
333         }
334         if (*ptr == c) {
335             ptr++;
336         }
337     } else {
338         while (*ptr && *ptr != ',') {
339             if (size < (int32_t)sizeof(buf)) {
340                 *sbuf++ = *ptr;
341                 size++;
342             }
343             ptr++;
344         }
345     }
346     *sbuf = (*ptr == '\0') ? *ptr : '\0';
347     DEBUG_LOG("control name=%s, size=%d\n", buf, size);
348     len = (int32_t)sizeof(eId->name);
349 
350     return DupCtlName((char *)eId->name, len, buf, size);
351 }
352 
ParseNumId(const char * s,uint32_t * idx)353 static int32_t ParseNumId(const char *s, uint32_t *idx)
354 {
355     int32_t numid;
356     char *ptr = NULL;
357 
358     ptr = strstr(s, "=");
359     if (ptr == NULL) {
360         DEBUG_LOG("Cannot find the given element from control default!\n");
361         return U_FAILURE;
362     }
363     ptr++;
364 
365     if (!isdigit(*ptr)) {
366         DEBUG_LOG("Invalid elem index!\n");
367         printf("Invalid elem index!\n");
368         return U_FAILURE;
369     }
370 
371     numid = (int32_t)strtol(ptr, NULL, STRTOL_BASE);
372     if (numid <= 0) {
373         DEBUG_LOG("audio_mixer: Invalid numid %d\n", numid);
374         return U_FAILURE;
375     }
376     *idx = (uint32_t)numid;
377 
378     return U_SUCCESS;
379 }
380 
ParseElemIndex(const char * str,struct AudioHwCtlElemIndex * sid)381 static int32_t ParseElemIndex(const char *str, struct AudioHwCtlElemIndex *sid)
382 {
383     int32_t ret;
384 
385     while (isspace(*str) || *str == '\t') {
386         str++;
387     }
388 
389     if (!(*str)) {
390         DEBUG_LOG("Invalid elem index string!\n");
391         return U_FAILURE;
392     }
393 
394     sid->eId.iface = AUDIO_CTL_ELEM_IFACE_MIXER;
395     if (strncasecmp(str, "name", strlen("name")) == 0) {
396         ret = ParseName(str + strlen("name"), &sid->eId);
397         if (ret != U_SUCCESS) {
398             DEBUG_LOG("Invalid elem index string!\n");
399             printf("Invalid elem index string!\n");
400             return U_FAILURE;
401         }
402         sid->index = 0;
403     } else if (strncasecmp(str, "numid", strlen("numid")) == 0) {
404         ret = ParseNumId(str + strlen("numid"), &sid->index);
405         if (ret != U_SUCCESS) {
406             DEBUG_LOG("Invalid elem index string!\n");
407             printf("Invalid elem index string!\n");
408             return U_FAILURE;
409         }
410         while (!isdigit(*str)) {
411             str++;
412         }
413     } else {
414         DEBUG_LOG("Cannot be resolved at present %s!\n", str);
415         return U_FAILURE;
416     }
417 
418     return U_SUCCESS;
419 }
420 
FillSndCardName(struct MixerCardCtlInfo * ctlInfo)421 static int32_t FillSndCardName(struct MixerCardCtlInfo *ctlInfo)
422 {
423     int32_t ret;
424 
425     if (strlen(g_serviceName) == 0) {
426         DEBUG_LOG("The sound card service name is error!\n");
427         return U_FAILURE;
428     }
429 
430     ret = strncpy_s(ctlInfo->cardSrvName, AUDIO_CARD_SRV_NAME_LEN, g_serviceName, strlen(g_serviceName));
431     if (ret != 0) {
432         DEBUG_LOG("strncpy_s fail!\n");
433         return U_FAILURE;
434     }
435     ctlInfo->cardSrvName[AUDIO_CARD_SRV_NAME_LEN - 1] = '\0';
436 
437     return U_SUCCESS;
438 }
439 
MixerESet(unsigned int argc,char * argv[],int32_t roflag)440 static int32_t MixerESet(unsigned int argc, char *argv[], int32_t roflag)
441 {
442     int32_t ret, slen;
443     struct MixerCardCtlInfo ctlInfo;
444 
445     if (argc < 1) {
446         printf("Specify a full control identifier: "
447                "[[iface=<iface>,][name='name',]"
448                "[index=<index>,]] | [numid=<numid>]\n");
449         return U_FAILURE;
450     }
451 
452     slen = (int32_t)sizeof(struct MixerCardCtlInfo);
453     memset_s(&ctlInfo, slen, 0, slen);
454     ret = ParseElemIndex(argv[0], &ctlInfo.edx);
455     if (ret != U_SUCCESS) {
456         DEBUG_LOG("Wrong scontrol identifier: %s\n", argv[0]);
457         printf("Wrong scontrol identifier: %s\n", argv[0]);
458         return U_FAILURE;
459     }
460     if (g_debugFlag) {
461         printf("index=%u, iface=%s, name='%s'\n", ctlInfo.edx.index, STRING(MIXER), ctlInfo.edx.eId.name);
462     }
463 
464     if (roflag == SSET_WR && argc < 2) {    // 2 for number of argcs
465         DEBUG_LOG("Specify what you want to set...\n");
466         printf("Specify what you want to set...\n");
467         return U_FAILURE;
468     }
469 
470     /* Query whether the control to be set exists. */
471     if (!MixerFindSelem(g_service, g_serviceName, &ctlInfo.edx.eId)) {
472         DEBUG_LOG("Can't find scontrol identifier: %s, %i\n", ctlInfo.edx.eId.name, ctlInfo.edx.index);
473         return U_FAILURE;
474     }
475 
476     ret = FillSndCardName(&ctlInfo);
477     if (ret != U_SUCCESS) {
478         return ret;
479     }
480 
481     if (roflag == SSET_WR) {
482         ret = MctlSetElem(g_service, &ctlInfo, argc, argv);
483         if (ret != U_SUCCESS) {
484             return ret;
485         }
486     }
487 
488     return MctlGetElem(g_service, &ctlInfo);
489 }
490 
ServiceHandleInit(void)491 static int32_t ServiceHandleInit(void)
492 {
493     int32_t ret;
494 
495     ret = GetLibsoHandle(g_pcm);
496     if (ret != U_SUCCESS) {
497         return ret;
498     }
499 
500     if (g_service != NULL) {
501         return U_SUCCESS;
502     }
503 
504     if (strlen(g_serviceName) >= CARD_SRV_NAME_LEN) {
505         g_service = MixerBindCrlSrvDefault();
506     } else {
507         g_service = MixerBindCrlSrv(g_serviceName);
508     }
509     if (g_service == NULL) {
510         DEBUG_LOG("Failed to obtain the service!\n");
511         CloseLibsoHandle();
512         return U_FAILURE;
513     }
514 
515     return U_SUCCESS;
516 }
517 
FreeGlobal(void)518 static void FreeGlobal(void)
519 {
520     ReleaseCtlElemList();
521     MixerRecycleCrlSrv(g_service);
522     CloseLibsoHandle();
523 }
524 
GetPcm(const char * string)525 static void GetPcm(const char *string)
526 {
527     int type;
528 
529     type = (int32_t)strtol(string, NULL, STRTOL_BASE);
530     switch (type) {
531         case PCM_RENDER:
532             g_pcm = PCM_RENDER;
533             break;
534         case PCM_CAPTURE:
535             g_pcm = PCM_CAPTURE;
536             break;
537         default:
538             DEBUG_LOG("Wrong PCM type!\n");
539             break;
540     }
541 }
542 
543 #ifdef CHANNEL_MAP
MixerSetChannels(unsigned int argc,char * str)544 static int32_t MixerSetChannels(unsigned int argc, char *str)
545 {
546     if (argc < 1) {
547         DEBUG_LOG("Channels error!\n");
548         return U_FAILURE;
549     }
550 
551     return SetChannels(g_service, g_serviceName, argc, str);
552 }
553 #endif
554 
main(int argc,char * argv[])555 int main(int argc, char *argv[])
556 {
557     int32_t ret;
558     int32_t c;
559     int32_t optionIndex = -1;
560 #ifdef LEGECY_STRATEGY
561     int index = 0;
562 #else
563     int updateId = 0;
564     char *newCard = NULL;
565 #endif
566     int badOpt = 0;
567     int level = 0;
568 #ifdef CHANNEL_MAP
569     int chnmapId = 0;
570     char *chnmapString = "front,render,2";
571 #endif
572     bool doDeviceList = false;
573     bool doUpdateCardName = false;
574     static const struct option longOpts[] = {
575         {"help",       0, NULL, 'h'},
576         {"list-cards", 0, NULL, 'l'},
577         {"card",       1, NULL, 'c'},
578         {"device",     1, NULL, 'D'},
579         {"pcm",        1, NULL, 'P'},
580         {"inactive",   0, NULL, 'i'},
581         {"debug",      0, NULL, 'd'},
582         {"version",    0, NULL, 'v'},
583         {"service",    1, NULL, 'S'},
584 #ifdef CHANNEL_MAP
585         {"chmap",      1, NULL, 'm'},
586 #endif
587         {NULL,         0, NULL, 0  }
588     };
589 
590     static const char shortOptions[] = "hlc:D:P:idvS:"
591 #ifdef CHANNEL_MAP
592                                        "m:"
593 #endif
594         ;
595 
596     while (1) {
597         c = getopt_long(argc, argv, shortOptions, longOpts, &optionIndex);
598         if (c < 0) {
599             DEBUG_LOG("Parameter parsing completed!\n");
600             break;
601         }
602 
603         switch (c) {
604             case 'h':
605                 ShowUsage();
606                 return 0;
607             case 'l':
608                 doDeviceList = true;
609                 break;
610             case 'c':
611 #ifdef LEGECY_STRATEGY
612                 ret = AudioCardGetIndex(optarg, &index);
613                 if (ret != U_SUCCESS) {
614                     return ret;
615                 }
616                 if (!CheckCardAndDev(index)) {
617                     fprintf(stderr, "Invalid card number '%s'.\n", optarg);
618                     badOpt++;
619                 }
620 #else
621                 /* The new version conversion policy is enabled. */
622                 doUpdateCardName = true;
623                 updateId = optind;
624                 newCard = optarg;
625 #endif
626                 break;
627             case 'D':
628                 ret = strncpy_s(g_dev, SND_CARD_NAME_LEN - 1, optarg, strlen(optarg));
629                 if (ret != 0) {
630                     DEBUG_LOG("strncpy_s fail!\n");
631                     goto FINISH;
632                 }
633                 g_dev[sizeof(g_dev) - 1] = '\0';
634 
635                 break;
636             case 'P':
637                 GetPcm(optarg);
638                 break;
639             case 'i':
640                 level |= L_INACTIV;
641                 printf("Reserved Parameters. [level %i]\n", level);
642                 return 0;
643             case 'd':
644                 g_debugFlag = true;
645                 break;
646             case 'v':
647                 printf("audio_mixer version %s\n", ShowVersion());
648                 return 0;
649             case 'S':
650                 ret = strncpy_s(g_serviceName, CARD_SRV_NAME_LEN - 1, optarg, strlen(optarg));
651                 if (ret != 0) {
652                     DEBUG_LOG("strncpy_s fail!\n");
653                     goto FINISH;
654                 }
655                 g_serviceName[strlen(optarg)] = '\0';
656 
657                 break;
658 #ifdef CHANNEL_MAP
659             case 'm':
660                 chnmapFlag = true;
661                 chnmapId = optind;
662                 chnmapString = optarg;
663 
664                 break;
665 #endif
666             default:
667                 fprintf(stderr, "Invalid switch or option -%c needs an argument.\n", c);
668                 badOpt++;
669         }
670     }
671     if (badOpt) {
672         ERR_LOG("The argument passed in was incorrect!\n");
673         return 1;
674     }
675 
676     DebugLog(g_debugFlag);
677     ret = ServiceHandleInit();
678     if (ret != U_SUCCESS) {
679         goto FINISH;
680     }
681     AudioMixerOpsInit();
682 
683     if (doDeviceList) {
684         ShowAllCardList();
685         goto FINISH;
686     }
687 
688 #ifdef CHANNEL_MAP
689     if (chnmapFlag) {
690         if (chnmapId < 1) {
691             chnmapId = 1;
692         }
693         ret = MixerSetChannels((unsigned int)chnmapId, chnmapString);
694         if (ret != U_SUCCESS) {
695             DEBUG_LOG("Unable to parse channel map string: %s\n", optarg);
696         }
697         goto FINISH;
698     }
699 #endif
700 
701     if (doUpdateCardName) {
702         UpdateCardName(newCard);
703         if (argc - optind <= 0) {
704             ret = 0;
705             goto FINISH;
706         }
707     }
708 
709     if (argc - optind <= 0) {
710         DEBUG_LOG("The parameter passed in is incorrect, argc = %i, optind = %i\n", argc, optind);
711         printf("Use this parameter together with other parameters!\n");
712         ShowUsage();
713         ret = 0;
714         goto FINISH;
715     }
716 
717     if (strcmp(argv[optind], "help") == 0) {
718         ret = ShowUsage() ? 1 : 0;
719     } else if (strcmp(argv[optind], "info") == 0) {
720         ret = MixerInfo() ? 1 : 0;
721     } else if (strcmp(argv[optind], "controls") == 0) {
722         ret = MixerControls() ? 1 : 0;
723     } else if (strcmp(argv[optind], "contents") == 0) {
724         ret = MixerControls() ? 1 : 0;
725     } else if (strcmp(argv[optind], "set") == 0) {
726         ret = MixerESet(argc - optind - 1, (argc - optind > 1) ? (argv + optind + 1) : NULL, SSET_WR) ? 1 : 0;
727     } else if (strcmp(argv[optind], "get") == 0) {
728         ret = MixerESet(argc - optind - 1, (argc - optind > 1) ? (argv + optind + 1) : NULL, SSET_RO) ? 1 : 0;
729     } else {
730         fprintf(stderr, "audio_mixer: Unknown command '%s'...\n", argv[optind]);
731         ret = 0;
732     }
733 
734 FINISH:
735     /* Releasing Global Resources. */
736     FreeGlobal();
737 
738     return ret;
739 }
740