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 "audio_mixer.h"
17 
18 #include <assert.h>
19 #include <ctype.h>
20 #include <dlfcn.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include <string.h>
24 #include <strings.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 
29 #include "hdf_base.h"
30 #include "securec.h"
31 
32 #define AUDIO_UTIL_VERSION_STR "V1.0.0"
33 
34 #define AUDIO_DEV_FILE_PATH    "/dev/"
35 #define CTL_SRV_NAME_PRE       "hdf_audio_control"
36 #define CTL_SRV_DEFAULT        CTL_SRV_NAME_PRE
37 #define MIXER_SRV_NAME_PRE     "hdf_audio_codec_"
38 #define MIXER_SRV_NAME         MIXER_SRV_NAME_PRE "%s_dev%i"
39 #define MIXER_SRV_NAME_DEFAULT MIXER_SRV_NAME_PRE "primary_dev0"
40 #define SERVICE_NAME_LEN       64
41 #define BUF_SIZE_T             256
42 #define CHN_MONO               (1 << 0)
43 #define CHN_STEREO             (1 << 1)
44 #define OUTPUT_ALIGN           16
45 #define BIT_VALULE_OFFSET      31
46 #define STRTOL_BASE            10
47 
48 #define IFACE(v) [AUDIO_CTL_ELEM_IFACE_##v] = #v
49 #define TYPE(v)  [AUDIO_CTL_ELEM_TYPE_##v] = #v
50 
51 static struct AudioMixer g_audioMixer;
52 static struct AudioMixerContents g_mixerCts;
53 
54 static const char *g_capLibPath = HDF_LIBRARY_FULL_PATH("libaudio_capture_adapter");
55 static const char *g_renLibPath = HDF_LIBRARY_FULL_PATH("libaudio_render_adapter");
56 static void *g_soHandle = NULL;
57 static AudioPcmType g_pcmT = PCM_RENDER;
58 static bool g_debugFlag = false;
59 
60 static const char * const ctlEIfNames[] = {
61     IFACE(CARD),
62     IFACE(PCM),
63     IFACE(MIXER),
64 };
65 
66 static const char * const ctlElemTypeNames[] = {
67     TYPE(NONE),
68     TYPE(BOOLEAN),
69     TYPE(INTEGER),
70     TYPE(ENUMERATED),
71     TYPE(BYTES),
72 };
73 
DebugLog(bool flag)74 void DebugLog(bool flag)
75 {
76     g_debugFlag = flag;
77 }
78 
CallLibFunction(const char * funcName)79 static void *CallLibFunction(const char *funcName)
80 {
81     void *func = NULL;
82     char *error = NULL;
83 
84     if (g_soHandle == NULL) {
85         DEBUG_LOG("Invalid dynamic library handle!\n");
86         return NULL;
87     }
88 
89     (void)dlerror(); /* Clear any existing error */
90     func = dlsym(g_soHandle, funcName);
91     error = dlerror();
92     if (error != NULL) {
93         DEBUG_LOG("%s\n", error);
94         printf("%s\n", error);
95         return NULL;
96     }
97 
98     return func;
99 }
100 
AudioMixerList(const struct HdfIoService * service,struct AudioMixerContents * mixerCts)101 static int32_t AudioMixerList(const struct HdfIoService *service, struct AudioMixerContents *mixerCts)
102 {
103     int32_t (*AmixerCtlElemList)(AudioPcmType, const struct HdfIoService *, struct AudioMixerContents *);
104 
105     AmixerCtlElemList = CallLibFunction("AudioMixerCtlElem");
106     if (AmixerCtlElemList == NULL) {
107         return U_FAILURE;
108     }
109 
110     return AmixerCtlElemList(g_pcmT, service, mixerCts);
111 }
112 
AudioMixerGet(const struct HdfIoService * service,struct AudioMixerCtlElemInfo * infoData)113 static int32_t AudioMixerGet(const struct HdfIoService *service, struct AudioMixerCtlElemInfo *infoData)
114 {
115     int32_t (*AmixerGetCtlElem)(AudioPcmType, const struct HdfIoService *, struct AudioMixerCtlElemInfo *);
116 
117     AmixerGetCtlElem = CallLibFunction("AudioMixerCtlGetElem");
118     if (AmixerGetCtlElem == NULL) {
119         return U_FAILURE;
120     }
121 
122     return AmixerGetCtlElem(g_pcmT, service, infoData);
123 }
124 
AudioMixerSet(const struct HdfIoService * service,struct AudioMixerCtlElemInfo * infoData)125 static int32_t AudioMixerSet(const struct HdfIoService *service, struct AudioMixerCtlElemInfo *infoData)
126 {
127     int32_t (*AmixerSetCtlElem)(AudioPcmType, const struct HdfIoService *, struct AudioMixerCtlElemInfo *);
128 
129     AmixerSetCtlElem = CallLibFunction("AudioMixerCtlSetElem");
130     if (AmixerSetCtlElem == NULL) {
131         return U_FAILURE;
132     }
133 
134     return AmixerSetCtlElem(g_pcmT, service, infoData);
135 }
136 
GetSoHandle(const char * filename)137 static int32_t GetSoHandle(const char *filename)
138 {
139     char buf[PATH_MAX] = {0};
140 
141     if (realpath(filename, buf) == NULL) {
142         return U_FAILURE;
143     }
144 
145     if (g_soHandle != NULL) {
146         DEBUG_LOG("It's been initialized!\n");
147         return U_SUCCESS;
148     }
149 
150     g_soHandle = dlopen(buf, RTLD_LAZY);
151     if (g_soHandle == NULL) {
152         DEBUG_LOG("%s\n", dlerror());
153         printf("%s\n", dlerror());
154         return U_FAILURE;
155     }
156 
157     return U_SUCCESS;
158 }
159 
GetLibsoHandle(AudioPcmType pcm)160 int32_t GetLibsoHandle(AudioPcmType pcm)
161 {
162     int32_t ret;
163 
164     g_pcmT = pcm;
165     switch (pcm) {
166         default:
167             DEBUG_LOG("Wrong PCM type!\n");
168             /* fall through */
169             __attribute__((fallthrough));
170         case PCM_RENDER:
171             ret = GetSoHandle(g_renLibPath);
172             if (ret != U_SUCCESS) {
173                 DEBUG_LOG("Failed to open the render dynamic library!\n");
174             }
175             break;
176         case PCM_CAPTURE:
177             ret = GetSoHandle(g_capLibPath);
178             if (ret != U_SUCCESS) {
179                 DEBUG_LOG("Failed to open the capture dynamic library!\n");
180             }
181             break;
182     }
183 
184     return ret;
185 }
186 
CloseLibsoHandle(void)187 void CloseLibsoHandle(void)
188 {
189     if (g_soHandle != NULL) {
190         (void)dlclose(g_soHandle);
191         g_soHandle = NULL;
192     }
193 }
194 
AudioMixerOpsInit(void)195 void AudioMixerOpsInit(void)
196 {
197     g_audioMixer.GetElemList = AudioMixerList;
198     g_audioMixer.GetElemProp = AudioMixerGet;
199     g_audioMixer.SetElemProp = AudioMixerSet;
200 
201     g_mixerCts.data = NULL;
202     g_mixerCts.elemNum = 0;
203     (void)memset_s(g_mixerCts.cardServiceName, AUDIO_CARD_SRV_NAME_LEN, 0x0, AUDIO_CARD_SRV_NAME_LEN);
204 }
205 
ShowVersion(void)206 const char *ShowVersion(void)
207 {
208     return AUDIO_UTIL_VERSION_STR;
209 }
210 
CheckMixerDevFile(const char * file)211 static bool CheckMixerDevFile(const char *file)
212 {
213     char buf[PATH_MAX] = {0};
214 
215     if (realpath(file, buf) == NULL) {
216         DEBUG_LOG("%s\n", strerror(errno));
217         return false;
218     }
219 
220     if (access(file, F_OK)) {
221         DEBUG_LOG("%s\n", strerror(errno));
222         return false;
223     }
224 
225     return true;
226 }
227 
MixerBindCrlSrvDefault(void)228 struct HdfIoService *MixerBindCrlSrvDefault(void)
229 {
230     int ret;
231     char buf[BUF_SIZE_T + 1] = {0};
232     struct HdfIoService *(*SrvBindDef)(const char *);
233 
234     ret = snprintf_s(buf, BUF_SIZE_T, BUF_SIZE_T, "%s%s", AUDIO_DEV_FILE_PATH, MIXER_SRV_NAME_DEFAULT);
235     if (ret < 0) {
236         DEBUG_LOG("Failed to synthesize the service path!\n");
237         return NULL;
238     }
239 
240     if (!CheckMixerDevFile(buf)) {
241         /* The sound card service file does not exist */
242         return NULL;
243     }
244 
245     SrvBindDef = CallLibFunction("HdfIoServiceBindName");
246     if (SrvBindDef == NULL) {
247         return NULL;
248     }
249 
250     return SrvBindDef(CTL_SRV_DEFAULT);
251 }
252 
MixerBindCrlSrv(const char * serviceName)253 struct HdfIoService *MixerBindCrlSrv(const char *serviceName)
254 {
255     int ret;
256     char path[BUF_SIZE_T + 1] = {0};
257     struct HdfIoService *(*SrvBind)(const char *);
258 
259     if (serviceName == NULL) {
260         DEBUG_LOG("Invalid parameters!\n");
261         return NULL;
262     }
263 
264     if (strncmp(serviceName, MIXER_SRV_NAME_PRE, strlen(MIXER_SRV_NAME_PRE))) {
265         DEBUG_LOG("The service name does not match!\n");
266         return NULL;
267     }
268 
269     ret = snprintf_s(path, BUF_SIZE_T, BUF_SIZE_T, "%s%s", AUDIO_DEV_FILE_PATH, serviceName);
270     if (ret < 0) {
271         DEBUG_LOG("Failed to synthesize the service path!\n");
272         return NULL;
273     }
274     if (!CheckMixerDevFile(path)) {
275         /* The sound card service file does not exist */
276         return NULL;
277     }
278 
279     SrvBind = CallLibFunction("HdfIoServiceBindName");
280     if (SrvBind == NULL) {
281         return NULL;
282     }
283 
284     return SrvBind(CTL_SRV_DEFAULT);
285 }
286 
MixerRecycleCrlSrv(struct HdfIoService * srv)287 void MixerRecycleCrlSrv(struct HdfIoService *srv)
288 {
289     void (*SrvRecycle)(struct HdfIoService *);
290 
291     if (srv != NULL) {
292         SrvRecycle = CallLibFunction("AudioCloseServiceSub");
293         if (SrvRecycle != NULL) {
294             SrvRecycle(srv);
295         }
296     }
297 }
298 
CtlElemIfaceName(AudioCtlElemIfaceType iface)299 static const char *CtlElemIfaceName(AudioCtlElemIfaceType iface)
300 {
301     return ctlEIfNames[iface];
302 }
303 
CtlElemName(struct AudioHwCtlElemIndex * id)304 static const char *CtlElemName(struct AudioHwCtlElemIndex *id)
305 {
306     return (const char *)id->eId.name;
307 }
308 
PrintCtlElemInfo(struct AudioHwCtlElemId * id)309 static void PrintCtlElemInfo(struct AudioHwCtlElemId *id)
310 {
311     printf("iface=%s, name='%s'\n", CtlElemIfaceName(id->iface), id->name);
312 }
313 
PrintCtlElemInfoidx(struct MixerCtsElemIdx * eidx)314 static void PrintCtlElemInfoidx(struct MixerCtsElemIdx *eidx)
315 {
316     printf("index=%u, numid=%u, ", eidx->index, eidx->index + 1);
317     PrintCtlElemInfo(eidx->id);
318 }
319 
PrintCtlElemList(struct AudioMixerContents * contents)320 static void PrintCtlElemList(struct AudioMixerContents *contents)
321 {
322     uint32_t num, idx;
323     struct MixerCtsElemIdx eidx;
324     struct AudioHwCtlElemId *id = NULL;
325 
326     num = contents->elemNum;
327     id = (struct AudioHwCtlElemId *)contents->data;
328     for (idx = 0; idx < num; idx++) {
329         eidx.id = id++;
330         eidx.index = idx;
331         PrintCtlElemInfoidx(&eidx);
332     }
333 }
334 
ReleaseCtlElemList(void)335 void ReleaseCtlElemList(void)
336 {
337     if (g_mixerCts.data != NULL) {
338         free(g_mixerCts.data);
339         g_mixerCts.data = NULL;
340     }
341     g_mixerCts.elemNum = 0;
342     (void)memset_s(g_mixerCts.cardServiceName, AUDIO_CARD_SRV_NAME_LEN, 0x0, AUDIO_CARD_SRV_NAME_LEN);
343 }
344 
MctlListSub(const struct HdfIoService * service,const char * cardSrv)345 static int32_t MctlListSub(const struct HdfIoService *service, const char *cardSrv)
346 {
347     int32_t ret;
348 
349     ret = strncpy_s(g_mixerCts.cardServiceName, AUDIO_CARD_SRV_NAME_LEN - 1, cardSrv, AUDIO_CARD_SRV_NAME_LEN - 1);
350     if (ret != 0) {
351         DEBUG_LOG("strncpy_s fail!\n");
352         return U_FAILURE;
353     }
354     g_mixerCts.cardServiceName[AUDIO_CARD_SRV_NAME_LEN - 1] = '\0';
355     if (g_audioMixer.GetElemList == NULL) {
356         DEBUG_LOG("The callback function is NULL!\n");
357         return U_FAILURE;
358     }
359 
360     if (g_mixerCts.data != NULL && g_mixerCts.elemNum > 0) {
361         /* The list of control elements has been obtained */
362         return U_SUCCESS;
363     }
364 
365     if (g_mixerCts.data != NULL) {
366         free(g_mixerCts.data);
367         g_mixerCts.data = NULL;
368     }
369     g_mixerCts.elemNum = 0;
370 
371     ret = g_audioMixer.GetElemList(service, &g_mixerCts);
372     if (ret != U_SUCCESS) {
373         return ret;
374     }
375     if (g_mixerCts.data == NULL) {
376         g_mixerCts.elemNum = 0;
377         (void)memset_s(g_mixerCts.cardServiceName, AUDIO_CARD_SRV_NAME_LEN, 0x0, AUDIO_CARD_SRV_NAME_LEN);
378         DEBUG_LOG("Failed to obtain data!\n");
379         return U_FAILURE;
380     }
381     if (g_mixerCts.elemNum == 0) {
382         free(g_mixerCts.data);
383         g_mixerCts.data = NULL;
384         (void)memset_s(g_mixerCts.cardServiceName, AUDIO_CARD_SRV_NAME_LEN, 0x0, AUDIO_CARD_SRV_NAME_LEN);
385         DEBUG_LOG("Description Failed to obtain the number of data!\n");
386         return U_FAILURE;
387     }
388 
389     return U_SUCCESS;
390 }
391 
MctlList(const struct HdfIoService * service,const char * cardSrv)392 int32_t MctlList(const struct HdfIoService *service, const char *cardSrv)
393 {
394     int32_t ret;
395 
396     if (service == NULL || cardSrv == NULL) {
397         DEBUG_LOG("Invalid parameters!\n");
398         return U_INVALID_PARAM;
399     }
400 
401     ret = MctlListSub(service, cardSrv);
402     if (ret != U_SUCCESS) {
403         return ret;
404     }
405     PrintCtlElemList(&g_mixerCts);
406 
407     return U_SUCCESS;
408 }
409 
MctlInfo(const struct HdfIoService * service,const char * cardSrv)410 int32_t MctlInfo(const struct HdfIoService *service, const char *cardSrv)
411 {
412     int32_t ret;
413     uint32_t num;
414     struct AudioHwCtlElemId *id;
415 
416     if (g_mixerCts.data == NULL || g_mixerCts.elemNum == 0) {
417         ReleaseCtlElemList();
418         ret = MctlListSub(service, cardSrv);
419         if (ret != U_SUCCESS) {
420             DEBUG_LOG("No reference data\n");
421             return ret;
422         }
423     }
424 
425     /* The list of control elements has been obtained */
426     num = g_mixerCts.elemNum;
427     id = (struct AudioHwCtlElemId *)g_mixerCts.data;
428     while (num--) {
429         PrintCtlElemInfo(id++);
430     }
431     ReleaseCtlElemList();
432 
433     return U_SUCCESS;
434 }
435 
MixerFindSelem(const struct HdfIoService * srv,const char * cardSrv,const struct AudioHwCtlElemId * eId)436 bool MixerFindSelem(const struct HdfIoService *srv, const char *cardSrv, const struct AudioHwCtlElemId *eId)
437 {
438     int32_t ret;
439     uint32_t index;
440     struct AudioHwCtlElemId *findElem;
441 
442     if (eId == NULL) {
443         DEBUG_LOG("Invalid parameters\n");
444         return false;
445     }
446 
447     if (g_mixerCts.elemNum == 0 || g_mixerCts.data == NULL) {
448         ReleaseCtlElemList();
449         ret = MctlListSub(srv, cardSrv);
450         if (ret != U_SUCCESS) {
451             DEBUG_LOG("No reference data\n");
452             return false;
453         }
454     }
455 
456     findElem = g_mixerCts.data;
457     for (index = 0; index < g_mixerCts.elemNum; index++) {
458         if (strcmp(eId->name, findElem[index].name) == 0) {
459             break;
460         }
461     }
462     if (index == g_mixerCts.elemNum) {
463         DEBUG_LOG("The corresponding control does not match!\n");
464         ReleaseCtlElemList();
465         return false;
466     }
467     ReleaseCtlElemList();
468 
469     return true;
470 }
471 
GetCtlElemIface(struct AudioHwCtlElemIndex * id)472 static AudioCtlElemIfaceType GetCtlElemIface(struct AudioHwCtlElemIndex *id)
473 {
474     return id->eId.iface;
475 }
476 
CtlElemGetIdx(struct AudioHwCtlElemIndex * id)477 static unsigned int CtlElemGetIdx(struct AudioHwCtlElemIndex *id)
478 {
479     return id->index;
480 }
481 
CtlElemInfoCnt(struct AudioMixerCtlElemInfo * info)482 static unsigned int CtlElemInfoCnt(struct AudioMixerCtlElemInfo *info)
483 {
484     return info->count;
485 }
486 
CtlElemGetInfoType(struct AudioMixerCtlElemInfo * info)487 static AudioCtlElemType CtlElemGetInfoType(struct AudioMixerCtlElemInfo *info)
488 {
489     return info->type;
490 }
491 
CtlElemTypeName(AudioCtlElemType type)492 static const char *CtlElemTypeName(AudioCtlElemType type)
493 {
494     return ctlElemTypeNames[type];
495 }
496 
MixerCtlType(struct AudioMixerCtlElemInfo * info)497 static const char *MixerCtlType(struct AudioMixerCtlElemInfo *info)
498 {
499     return CtlElemTypeName(CtlElemGetInfoType(info));
500 }
501 
CtlElemInfoGetMin(struct AudioMixerCtlElemInfo * info)502 static int32_t CtlElemInfoGetMin(struct AudioMixerCtlElemInfo *info)
503 {
504     return info->value.intVal.min;
505 }
506 
CtlElemInfoGetMax(struct AudioMixerCtlElemInfo * info)507 static int32_t CtlElemInfoGetMax(struct AudioMixerCtlElemInfo *info)
508 {
509     return info->value.intVal.max;
510 }
511 
CtlElemInfoGetStep(struct AudioMixerCtlElemInfo * info)512 static int32_t CtlElemInfoGetStep(struct AudioMixerCtlElemInfo *info)
513 {
514     return info->value.intVal.step;
515 }
516 
CtlElemInfoGetVals(struct AudioMixerCtlElemInfo * info)517 static long *CtlElemInfoGetVals(struct AudioMixerCtlElemInfo *info)
518 {
519     return info->value.intVal.vals;
520 }
521 
CtlElemInfoSetItem(struct AudioMixerCtlElemInfo * info,uint32_t val)522 static void CtlElemInfoSetItem(struct AudioMixerCtlElemInfo *info, uint32_t val)
523 {
524     info->value.enumVal.item = val;
525 }
526 
CtlElemInfoGetItems(struct AudioMixerCtlElemInfo * info)527 static uint32_t CtlElemInfoGetItems(struct AudioMixerCtlElemInfo *info)
528 {
529     return info->value.enumVal.items;
530 }
531 
CtlElemInfoGetItem(struct AudioMixerCtlElemInfo * info)532 static uint32_t CtlElemInfoGetItem(struct AudioMixerCtlElemInfo *info)
533 {
534     return info->value.enumVal.item;
535 }
536 
CtlElemInfoGetItemName(struct AudioMixerCtlElemInfo * info)537 static char *CtlElemInfoGetItemName(struct AudioMixerCtlElemInfo *info)
538 {
539     return info->value.enumVal.name;
540 }
541 
CtlElemValueGetBoolean(struct AudioMixerCtlElemInfo * info,uint32_t idx)542 static int32_t CtlElemValueGetBoolean(struct AudioMixerCtlElemInfo *info, uint32_t idx)
543 {
544     if (idx > BIT_VALULE_OFFSET - 1) {
545         return 0;
546     }
547 
548     return ((info->value.intVal.max >> idx) & 0x1);
549 }
550 
CtlElemValueGetInt(struct AudioMixerCtlElemInfo * info,uint32_t idx)551 static int32_t CtlElemValueGetInt(struct AudioMixerCtlElemInfo *info, uint32_t idx)
552 {
553     return CtlElemValueGetBoolean(info, idx);
554 }
555 
CtlElemValueGetByte(struct AudioMixerCtlElemInfo * info,uint32_t idx)556 static char CtlElemValueGetByte(struct AudioMixerCtlElemInfo *info, uint32_t idx)
557 {
558     if (idx >= RESERVED_BUF_LEN) {
559         return '?';
560     }
561 
562     return info->value.reserved[idx];
563 }
564 
CtlElemValueGetBytes(struct AudioMixerCtlElemInfo * info)565 static unsigned char *CtlElemValueGetBytes(struct AudioMixerCtlElemInfo *info)
566 {
567     return info->value.reserved;
568 }
569 
CtlElemValueGetEnum(struct AudioMixerCtlElemInfo * info,uint32_t idx)570 static uint32_t CtlElemValueGetEnum(struct AudioMixerCtlElemInfo *info, uint32_t idx)
571 {
572     if (idx > BIT_VALULE_OFFSET) {
573         return 0;
574     }
575 
576     return ((info->value.enumVal.item >> idx) & 0x1);
577 }
578 
PrintOtherVal(struct AudioMixerCtlElemInfo * info)579 static void PrintOtherVal(struct AudioMixerCtlElemInfo *info)
580 {
581     uint32_t idx;
582     unsigned int count;
583     AudioCtlElemType type;
584 
585     type = CtlElemGetInfoType(info);
586     count = CtlElemInfoCnt(info);
587     for (idx = 0; idx < count; idx++) {
588         if (idx > 0) {
589             printf(", ");
590         }
591 
592         switch (type) {
593             case AUDIO_CTL_ELEM_TYPE_BOOLEAN:
594                 printf("%s", CtlElemValueGetBoolean(info, idx) ? "on" : "off");
595                 break;
596             case AUDIO_CTL_ELEM_TYPE_BYTES:
597                 printf("0x%02x", CtlElemValueGetByte(info, idx));
598                 break;
599             case AUDIO_CTL_ELEM_TYPE_INTEGER:
600                 printf("%i", CtlElemValueGetInt(info, idx));
601                 break;
602             case AUDIO_CTL_ELEM_TYPE_ENUMERATED:
603                 printf("%u", CtlElemValueGetEnum(info, idx));
604                 break;
605             default:
606                 printf("?");
607                 break;
608         }
609     }
610     printf("\n");
611 }
612 
PrintValue(struct AudioMixerCtlElemInfo * info)613 static void PrintValue(struct AudioMixerCtlElemInfo *info)
614 {
615     long *ptr;
616     uint32_t idx, items;
617     AudioCtlElemType type;
618 
619     type = CtlElemGetInfoType(info);
620     switch (type) {
621         case AUDIO_CTL_ELEM_TYPE_INTEGER:
622             printf(", min=%i, max=%i, step=%i\n",
623                 CtlElemInfoGetMin(info),
624                 CtlElemInfoGetMax(info),
625                 CtlElemInfoGetStep(info));
626             ptr = CtlElemInfoGetVals(info);
627             printf("  : values=");
628             for (idx = 0; idx < info->count; idx++) {
629                 if (idx > 0) {
630                     printf(", ");
631                 }
632                 printf("%i", (int)ptr[idx]);
633             }
634             printf("\n");
635             break;
636         case AUDIO_CTL_ELEM_TYPE_ENUMERATED:
637             {
638                 items = CtlElemInfoGetItems(info);
639                 printf(", items=%u\n", items);
640                 for (idx = 0; idx < items; idx++) {
641                     CtlElemInfoSetItem(info, idx);
642                     printf("%s; Item #%u '%s'\n", "  ", idx, CtlElemInfoGetItemName(info));
643                 }
644                 printf("  : values=%u\n", CtlElemInfoGetItem(info));
645             }
646             break;
647         case AUDIO_CTL_ELEM_TYPE_BOOLEAN:
648             printf("\n  : values=");
649             PrintOtherVal(info);
650             break;
651         case AUDIO_CTL_ELEM_TYPE_BYTES:
652             printf("  : values=%s\n", CtlElemValueGetBytes(info));
653             break;
654         default:
655             DEBUG_LOG("Mismatched control value type!\n");
656             break;
657     }
658 }
659 
ShowIntVal(struct AudioMixerCtlElemInfo * info)660 static void ShowIntVal(struct AudioMixerCtlElemInfo *info)
661 {
662     int32_t ret;
663     uint32_t index;
664     unsigned int count;
665     const char *iface;
666     const char *space = "  ";
667     char buf[BUF_SIZE_T + 1] = {0};
668 
669     index = CtlElemGetIdx(&info->eIndexId);
670     iface = CtlElemIfaceName(GetCtlElemIface(&info->eIndexId));
671     if (index > 0) {
672         ret = snprintf_s(buf, BUF_SIZE_T, BUF_SIZE_T, "index=%u, iface=%s, name=%s",
673             index, iface, CtlElemName(&info->eIndexId));
674     } else {
675         ret = snprintf_s(buf, BUF_SIZE_T, BUF_SIZE_T, "iface=%s, name=%s",
676             iface, CtlElemName(&info->eIndexId));
677     }
678     if (ret < 0) {
679         DEBUG_LOG("Failed to snprintf_s!\n");
680         return;
681     }
682 
683     buf[BUF_SIZE_T] = '\0';
684     printf("%s\n", buf);
685 
686     count = CtlElemInfoCnt(info);
687     printf("%s; type=%s, values=%u", space, MixerCtlType(info), count);
688     PrintValue(info);
689 }
690 
ShowEnumVal(struct AudioMixerCtlElemInfo * info)691 static void ShowEnumVal(struct AudioMixerCtlElemInfo *info)
692 {
693     printf("  : values=%u\n", CtlElemInfoGetItem(info));
694 }
695 
ShowBytesVal(const unsigned char * data)696 static void ShowBytesVal(const unsigned char *data)
697 {
698     int i;
699     const unsigned char *p = data;
700 
701     printf("\ndata:\t");
702     for (i = 0; i < RESERVED_BUF_LEN; i++) {
703         if (*p == '\0') {
704             break;
705         }
706 
707         if ((i % OUTPUT_ALIGN) == 0) {
708             printf("\n");
709         }
710         printf("0x%02x \n", *p++);
711     }
712     printf("\n");
713     printf("string: %s\n", data);
714 }
715 
ShowElemInfo(struct AudioMixerCtlElemInfo * info)716 static void ShowElemInfo(struct AudioMixerCtlElemInfo *info)
717 {
718     switch (info->type) {
719         case AUDIO_CTL_ELEM_TYPE_INTEGER:
720         case AUDIO_CTL_ELEM_TYPE_BOOLEAN:
721             ShowIntVal(info);
722             break;
723         case AUDIO_CTL_ELEM_TYPE_ENUMERATED:
724             ShowEnumVal(info);
725             break;
726         case AUDIO_CTL_ELEM_TYPE_BYTES:
727             ShowBytesVal(info->value.reserved);
728             break;
729         default:
730             DEBUG_LOG("Mismatched control value type!\n");
731             break;
732     }
733 }
734 
MctlGetElem(const struct HdfIoService * service,struct MixerCardCtlInfo * ctlInfo)735 int32_t MctlGetElem(const struct HdfIoService *service, struct MixerCardCtlInfo *ctlInfo)
736 {
737     int32_t ret;
738     struct AudioMixerCtlElemInfo info;
739 
740     if (service == NULL || ctlInfo == NULL) {
741         DEBUG_LOG("Invalid parameters!\n");
742         return U_INVALID_PARAM;
743     }
744 
745     ret = strncpy_s(info.cardSrvName, AUDIO_CARD_SRV_NAME_LEN - 1, ctlInfo->cardSrvName, AUDIO_CARD_SRV_NAME_LEN - 1);
746     if (ret != 0) {
747         DEBUG_LOG("strncpy_s cardSrvName fail!\n");
748         return U_FAILURE;
749     }
750     info.cardSrvName[AUDIO_CARD_SRV_NAME_LEN - 1] = '\0';
751     ret = strncpy_s(info.eIndexId.eId.name, AUDIO_ELEM_NAME_LEN - 1, ctlInfo->edx.eId.name, AUDIO_ELEM_NAME_LEN - 1);
752     if (ret != 0) {
753         DEBUG_LOG("strncpy_s element name fail!\n");
754         return U_FAILURE;
755     }
756     info.eIndexId.eId.name[AUDIO_ELEM_NAME_LEN - 1] = '\0';
757     info.eIndexId.eId.iface = ctlInfo->edx.eId.iface;
758     // need info.type
759     info.type = AUDIO_CTL_ELEM_TYPE_INTEGER;
760 
761     if (g_audioMixer.GetElemProp == NULL) {
762         DEBUG_LOG("The callback function is NULL!\n");
763         return U_FAILURE;
764     }
765     ret = g_audioMixer.GetElemProp(service, &info);
766     if (ret != U_SUCCESS) {
767         DEBUG_LOG("Failed to get control!\n");
768         return U_FAILURE;
769     }
770     ShowElemInfo(&info);
771 
772     return U_SUCCESS;
773 }
774 
775 static const struct ChannelMask g_chnMask[] = {
776     {"frontleft",   1 << AMIXER_CHN_FRONT_LEFT                                    },
777     {"frontright",  1 << AMIXER_CHN_FRONT_RIGHT                                   },
778     {"frontcenter", 1 << AMIXER_CHN_FRONT_CENTER                                  },
779     {"front",       ((1 << AMIXER_CHN_FRONT_LEFT) | (1 << AMIXER_CHN_FRONT_RIGHT))},
780     {"center",      1 << AMIXER_CHN_FRONT_CENTER                                  },
781     {"rearleft",    1 << AMIXER_CHN_REAR_LEFT                                     },
782     {"rearright",   1 << AMIXER_CHN_REAR_RIGHT                                    },
783     {"rear",        ((1 << AMIXER_CHN_REAR_LEFT) | (1 << AMIXER_CHN_REAR_RIGHT))  },
784     {"woofer",      1 << AMIXER_CHN_WOOFER                                        },
785     {NULL,          0                                                             }
786 };
787 
ChannelsMask(char ** ptr,unsigned int chns)788 static uint32_t ChannelsMask(char **ptr, unsigned int chns)
789 {
790     const struct ChannelMask *msk;
791 
792     for (msk = g_chnMask; msk->name != NULL; msk++) {
793         if (strncasecmp(*ptr, msk->name, strlen(msk->name)) == 0) {
794             /* Stop loop at specified character. */
795             while (**ptr != '\0' && **ptr != ',' && **ptr != ' ' && **ptr != '\t') {
796                 (*ptr)++;
797             }
798             /* Skip the specified character. */
799             if (**ptr == ',' || **ptr == ' ' || **ptr == '\t') {
800                 (*ptr)++;
801             }
802 
803             return msk->mask;
804         }
805     }
806 
807     return chns;
808 }
809 
DirMask(char ** ptr,unsigned int dir)810 static uint32_t DirMask(char **ptr, unsigned int dir)
811 {
812     int find = 0;
813 
814     /* Stop loop at specified character. */
815     while (**ptr != '\0' && **ptr != ',' && **ptr != ' ' && **ptr != '\t') {
816         (*ptr)++;
817     }
818 
819     /* Skip the specified character. */
820     if (**ptr == ',' || **ptr == ' ' || **ptr == '\t') {
821         (*ptr)++;
822     }
823 
824     if (strncasecmp(*ptr, "render", strlen("render")) == 0) {
825         dir = find = PCM_RENDER + 1;
826     } else if (strncasecmp(*ptr, "capture", strlen("capture")) == 0) {
827         dir = find = PCM_CAPTURE + 1;
828     }
829 
830     if (find) {
831         /* Stop loop at specified character. */
832         while (**ptr != '\0' && **ptr != ',' && **ptr != ' ' && **ptr != '\t') {
833             (*ptr)++;
834         }
835 
836         /* Skip the specified character. */
837         if (**ptr == ',' || **ptr == ' ' || **ptr == '\t') {
838             (*ptr)++;
839         }
840     }
841 
842     return dir;
843 }
844 
IsRenderChannel(AudioMixerChannelIdType chn)845 static bool IsRenderChannel(AudioMixerChannelIdType chn)
846 {
847     return !!(chn);
848 }
849 
IsCaptureChannel(AudioMixerChannelIdType chn)850 static bool IsCaptureChannel(AudioMixerChannelIdType chn)
851 {
852     return !(chn);
853 }
854 
FillChnmap(struct AudioMixerCtlElemInfo * info,uint32_t chns,uint32_t dir,char ** ptr)855 static int32_t FillChnmap(struct AudioMixerCtlElemInfo *info, uint32_t chns, uint32_t dir, char **ptr)
856 {
857     char *sp;
858     AudioMixerChannelIdType chn;
859 
860     /* Matches the specified channel. */
861     for (chn = AMIXER_CHN_FRONT_LEFT; chn < AMIXER_CHN_LAST; chn++) {
862         sp = NULL;
863         if (!(chns & (1 << (uint32_t)chn))) {
864             continue;
865         }
866 
867         if (!((dir & PCM_RENDER) && IsRenderChannel(chn)) && !((dir & PCM_CAPTURE) && IsCaptureChannel(chn))) {
868             DEBUG_LOG("Unable to set channel!\n");
869             return U_FAILURE;
870         }
871 
872         info->value.enumVal.item |= (chns & (1 << chn));
873         /* Search for the next channel. */
874         while (**ptr != '\0' && **ptr != ',') {
875             (*ptr)++;
876         }
877         if (**ptr == '\0') {
878             break;
879         }
880         (*ptr)++; // skip ','
881         DEBUG_LOG("skip, = %s\n", *ptr);
882     }
883 
884     if (info->value.enumVal.item > CHN_STEREO) {
885         info->value.enumVal.item = CHN_STEREO;
886     } else {
887         info->value.enumVal.item = CHN_MONO;
888     }
889     DEBUG_LOG("chns = %i\n", info->value.enumVal.item);
890 
891     return U_SUCCESS;
892 }
893 
FillChnlsIntVal(struct AudioMixerCtlElemInfo * info,unsigned int argc,char * argv)894 static int32_t FillChnlsIntVal(struct AudioMixerCtlElemInfo *info, unsigned int argc, char *argv)
895 {
896     bool mchns;
897     int32_t ret;
898     char *ptr = NULL;
899     uint32_t dir = 3;
900     uint32_t chns = ~0U;
901 
902     ptr = argv;
903     chns = ChannelsMask(&ptr, chns);
904     if (*ptr == '\0') {
905         DEBUG_LOG("Channels Mask = %u\n", chns);
906         return U_FAILURE;
907     }
908 
909     dir = DirMask(&ptr, dir);
910     if (*ptr == '\0') {
911         DEBUG_LOG("Direct Mask = %u\n", chns);
912         return U_FAILURE;
913     }
914 
915     mchns = (strchr(ptr, ',') != NULL);
916     if (!mchns) {
917         info->value.enumVal.item = CHN_MONO;
918         return U_SUCCESS;
919     }
920 
921     ret = FillChnmap(info, chns, dir, &ptr);
922     if (ret != U_SUCCESS) {
923         return ret;
924     }
925 
926     return U_SUCCESS;
927 }
928 
SetChannels(const struct HdfIoService * srv,const char * cardSrv,unsigned int argc,char * argv)929 int32_t SetChannels(const struct HdfIoService *srv, const char *cardSrv, unsigned int argc, char *argv)
930 {
931     int32_t ret;
932     struct AudioMixerCtlElemInfo infoData;
933 
934     if (srv == NULL || cardSrv == NULL || argc == 0) {
935         DEBUG_LOG("Invalid parameters!\n");
936         return U_INVALID_PARAM;
937     }
938 
939     DEBUG_LOG("argc = %u, argv = %s\n", argc, argv);
940     (void)memset_s(infoData.cardSrvName, AUDIO_CARD_SRV_NAME_LEN, 0, AUDIO_CARD_SRV_NAME_LEN);
941     ret = strncpy_s(infoData.cardSrvName, AUDIO_CARD_SRV_NAME_LEN, cardSrv, strlen(cardSrv) + 1);
942     if (ret != 0) {
943         DEBUG_LOG("strncpy_s card service name is faild!\n");
944         return U_FAILURE;
945     }
946     infoData.cardSrvName[AUDIO_CARD_SRV_NAME_LEN - 1] = '\0';
947 
948     (void)memset_s(infoData.eIndexId.eId.name, AUDIO_ELEM_NAME_LEN, 0, AUDIO_ELEM_NAME_LEN);
949     ret = strncpy_s(
950         infoData.eIndexId.eId.name, AUDIO_ELEM_NAME_LEN, "Captrue Channel Mode", strlen("Captrue Channel Mode") + 1);
951     if (ret != 0) {
952         DEBUG_LOG("strncpy_s element name is failed!\n");
953         return U_FAILURE;
954     }
955     infoData.eIndexId.eId.iface = AUDIO_CTL_ELEM_IFACE_MIXER;
956     infoData.type = AUDIO_CTL_ELEM_TYPE_INTEGER;
957     ret = FillChnlsIntVal(&infoData, argc, argv);
958     if (ret != U_SUCCESS) {
959         return ret;
960     }
961 
962     if (g_audioMixer.SetElemProp == NULL) {
963         DEBUG_LOG("The callback function is NULL!\n");
964         return U_FAILURE;
965     }
966     ret = g_audioMixer.SetElemProp(srv, &infoData);
967     if (ret != U_SUCCESS) {
968         return ret;
969     }
970 
971     ret = strncpy_s(
972         infoData.eIndexId.eId.name, AUDIO_ELEM_NAME_LEN, "Render Channel Mode", strlen("Render Channel Mode") + 1);
973     if (ret != 0) {
974         DEBUG_LOG("strncpy_s element name is failed!\n");
975         return U_FAILURE;
976     }
977 
978     return g_audioMixer.SetElemProp(srv, &infoData);
979 }
980 
FillIntVal(struct AudioMixerCtlElemInfo * info,unsigned int argc,char * argv[])981 static int32_t FillIntVal(struct AudioMixerCtlElemInfo *info, unsigned int argc, char *argv[])
982 {
983     char *vals, *minPtr, *maxPtr, *stepPtr;
984     char *ptr = NULL;
985     char *outPtr = NULL;
986 
987     if (argc != 2) {    // 2 for numbers of argc
988         DEBUG_LOG("Unable to set too much value!\n");
989         return U_FAILURE;
990     }
991 
992     ptr = argv[argc - 1];
993     DEBUG_LOG("argv[%u] = %s\n", argc - 1, ptr);
994     vals = strtok_r(ptr, ",", &outPtr);
995     if (outPtr == NULL) {
996         info->value.intVal.vals[0] = strtol(ptr, NULL, STRTOL_BASE);
997         info->value.intVal.min = 0;
998         info->value.intVal.step = 0;
999 
1000         return U_SUCCESS;
1001     }
1002 
1003     info->value.intVal.vals[0] = strtol(vals, NULL, STRTOL_BASE);
1004     maxPtr = strtok_r(NULL, ",", &outPtr);
1005     if (outPtr == NULL) {
1006         info->value.intVal.max = (int32_t)strtol(maxPtr, NULL, STRTOL_BASE);
1007         info->value.intVal.min = 0;
1008         info->value.intVal.step = 0;
1009 
1010         return U_SUCCESS;
1011     }
1012 
1013     info->value.intVal.max = (int32_t)strtol(maxPtr, NULL, STRTOL_BASE);
1014     minPtr = strtok_r(NULL, ",", &outPtr);
1015     if (outPtr != NULL) {
1016         info->value.intVal.min = (int32_t)strtol(minPtr, NULL, STRTOL_BASE);
1017         stepPtr = strtok_r(NULL, ",", &outPtr);
1018         info->value.intVal.step = outPtr != NULL ? (int32_t)strtol(stepPtr, NULL, STRTOL_BASE) : 0;
1019     } else {
1020         info->value.intVal.min = (int32_t)strtol(minPtr, NULL, STRTOL_BASE);
1021         info->value.intVal.step = 0;
1022     }
1023 
1024     return U_SUCCESS;
1025 }
1026 
FillEnumVal(struct AudioMixerCtlElemInfo * info,unsigned int argc,char * argv[])1027 static int32_t FillEnumVal(struct AudioMixerCtlElemInfo *info, unsigned int argc, char *argv[])
1028 {
1029     int32_t ret;
1030     unsigned int idx;
1031     char *ptr = NULL;
1032 
1033     printf("\n");
1034     /* Multiple enumerated values are output line by line. */
1035     for (idx = 1; idx < argc; idx++) {
1036         ptr = argv[idx];
1037         // Control Settings with enumerated values.
1038         ret = strcpy_s(info->value.enumVal.name, AUDIO_ELEM_NAME_LEN - 1, ptr);
1039         if (ret != EOK) {
1040             printf("strcpy_s failed: argv = %s\n", ptr);
1041         } else {
1042             printf("%s\n", ptr);
1043         }
1044     }
1045 
1046     return U_SUCCESS;
1047 }
1048 
FillBytesVal(unsigned char * buf,unsigned int argc,char * argv[])1049 static int32_t FillBytesVal(unsigned char *buf, unsigned int argc, char *argv[])
1050 {
1051     int32_t ret;
1052     size_t len;
1053     unsigned int idx;
1054     unsigned char *ptr = buf;
1055     char *sptr = NULL;
1056     size_t size = RESERVED_BUF_LEN;
1057 
1058     /* Multiple input parameters are separated and combined with a ",". */
1059     for (idx = 1; idx < argc; idx++) {
1060         sptr = argv[idx];
1061         len = strlen(argv[idx]);
1062         if (size <= len) {
1063             DEBUG_LOG("The callback function is NULL!\n");
1064             break;
1065         }
1066         ret = strncpy_s((char *)ptr, RESERVED_BUF_LEN - 1, sptr, len);
1067         if (ret != 0) {
1068             DEBUG_LOG("strncpy_s faild!\n");
1069             return U_FAILURE;
1070         }
1071         ptr += len;
1072         *ptr++ = ',';
1073         size -= len + 1;
1074     }
1075     if (idx < argc) {
1076         DEBUG_LOG("Unable to set too much data!\n");
1077         return U_FAILURE;
1078     }
1079     printf("data buf = %s\n", buf);
1080 
1081     return U_SUCCESS;
1082 }
1083 
1084 
MctlSetElem(const struct HdfIoService * srv,struct MixerCardCtlInfo * ctlInfo,unsigned int argc,char * argv[])1085 int32_t MctlSetElem(const struct HdfIoService *srv,
1086                     struct MixerCardCtlInfo *ctlInfo,
1087                     unsigned int argc, char *argv[])
1088 {
1089     int32_t ret;
1090     struct AudioMixerCtlElemInfo infoData;
1091 
1092     if (srv == NULL || ctlInfo == NULL || argc == 0) {
1093         DEBUG_LOG("Invalid parameters!\n");
1094         return U_INVALID_PARAM;
1095     }
1096 
1097     ret = strncpy_s(infoData.cardSrvName, AUDIO_CARD_SRV_NAME_LEN, ctlInfo->cardSrvName, AUDIO_CARD_SRV_NAME_LEN);
1098     if (ret != 0) {
1099         DEBUG_LOG("strncpy_s card service name is faild!\n");
1100         return U_FAILURE;
1101     }
1102     infoData.cardSrvName[AUDIO_CARD_SRV_NAME_LEN - 1] = '\0';
1103 
1104     ret = strncpy_s(infoData.eIndexId.eId.name, AUDIO_ELEM_NAME_LEN, ctlInfo->edx.eId.name, AUDIO_ELEM_NAME_LEN);
1105     if (ret != 0) {
1106         DEBUG_LOG("strncpy_s element name is failed!\n");
1107         return U_FAILURE;
1108     }
1109     infoData.eIndexId.eId.name[AUDIO_ELEM_NAME_LEN - 1] = '\0';
1110     infoData.eIndexId.eId.iface = AUDIO_CTL_ELEM_IFACE_MIXER;
1111 
1112     // First, read the value type.(infoData.type)
1113     infoData.type = AUDIO_CTL_ELEM_TYPE_INTEGER;
1114     switch (infoData.type) {
1115         case AUDIO_CTL_ELEM_TYPE_INTEGER:
1116         case AUDIO_CTL_ELEM_TYPE_BOOLEAN:
1117             ret = FillIntVal(&infoData, argc, argv);
1118             break;
1119         case AUDIO_CTL_ELEM_TYPE_ENUMERATED:
1120             ret = FillEnumVal(&infoData, argc, argv);
1121             break;
1122         case AUDIO_CTL_ELEM_TYPE_BYTES:
1123             ret = FillBytesVal(infoData.value.reserved, argc, argv);
1124             break;
1125         default:
1126             ret = U_FAILURE;
1127             break;
1128     }
1129     if (ret != U_SUCCESS) {
1130         DEBUG_LOG("The value type does not match!\n");
1131         return U_FAILURE;
1132     }
1133 
1134     if (g_audioMixer.SetElemProp == NULL) {
1135         DEBUG_LOG("The callback function is NULL!\n");
1136         return U_FAILURE;
1137     }
1138 
1139     return g_audioMixer.SetElemProp(srv, &infoData);
1140 }
1141 
SkipSpecifyStr(const char * src,const char * needle)1142 static char *SkipSpecifyStr(const char *src, const char *needle)
1143 {
1144     char *p = NULL;
1145 
1146     p = strstr(src, needle);
1147     if (p != NULL) {
1148         p += strlen(needle);
1149     }
1150 
1151     return p;
1152 }
1153 
GetSndCardType(const char * name,char * buf,uint32_t len)1154 static int32_t GetSndCardType(const char *name, char *buf, uint32_t len)
1155 {
1156     int32_t ret;
1157     char *ptr = NULL;
1158     char *out = NULL;
1159 
1160     if (name == NULL || buf == NULL || len == 0) {
1161         DEBUG_LOG("Invalid parameters!\n");
1162         return U_INVALID_PARAM;
1163     }
1164 
1165     ptr = SkipSpecifyStr(name, MIXER_SRV_NAME_PRE);
1166     if (ptr == NULL) {
1167         DEBUG_LOG("No found card type!\n");
1168         return U_FAILURE;
1169     }
1170 
1171     ret = memcpy_s(buf, len, ptr, strlen(ptr) + 1);
1172     if (ret != EOK) {
1173         DEBUG_LOG("memcpy_s fail!\n");
1174         return U_FAILURE;
1175     }
1176     ptr = strtok_r(buf, "_", &out);
1177     ret = memcpy_s(buf, len, ptr, strlen(ptr) + 1);
1178     if (ret != EOK) {
1179         DEBUG_LOG("memcpy_s fail!\n");
1180         return U_FAILURE;
1181     }
1182 
1183     return U_SUCCESS;
1184 }
1185 
ShowAllAdapters(struct SndCardsList * sndList)1186 static void ShowAllAdapters(struct SndCardsList *sndList)
1187 {
1188     int32_t i, ret;
1189     uint32_t cnums;
1190     char ctype[AUDIO_BASE_LEN] = {0};
1191     struct AudioCardId *clist = NULL;
1192 
1193     if (sndList->cardNums == 0 || sndList->cardsList == NULL) {
1194         DEBUG_LOG("No sound cards found...!\n");
1195         goto end;
1196     }
1197 
1198     cnums = sndList->cardNums;
1199     clist = sndList->cardsList;
1200     printf("****** List of Audio Hardware Devices ******\n");
1201     /* To keep the primary sound card always in front of the total,
1202      * output it in the following order.
1203      */
1204     for (i = (int32_t)cnums - 1; i >= 0; i--) {
1205         (void)memset_s(ctype, AUDIO_BASE_LEN, 0, AUDIO_BASE_LEN);
1206         ret = GetSndCardType(clist[i].cardName, ctype, AUDIO_BASE_LEN);
1207         if (ret != U_SUCCESS) {
1208             goto end;
1209         }
1210         printf("card %i: %s [%s], device 0\n", clist[i].index, ctype, clist[i].cardName);
1211         printf("  Subdevices: 1/1\n");
1212         printf("  Subdevice #0: subdevice #0\n");
1213     }
1214 
1215 end:
1216     if (sndList->cardsList != NULL) {
1217         free(sndList->cardsList);
1218         sndList->cardsList = NULL;
1219     }
1220 }
1221 
GetAllCards(const struct HdfIoService * service)1222 int32_t GetAllCards(const struct HdfIoService *service)
1223 {
1224     int32_t ret;
1225     struct SndCardsList sndcards;
1226     int32_t (*GetAllAdapters)(const struct HdfIoService *, struct SndCardsList *);
1227 
1228     if (service == NULL) {
1229         DEBUG_LOG("Invalid parameter!\n");
1230         return U_INVALID_PARAM;
1231     }
1232 
1233     GetAllAdapters = CallLibFunction("AudioMixerGetAllAdapters");
1234     if (GetAllAdapters == NULL) {
1235         return U_FAILURE;
1236     }
1237 
1238     (void)memset_s(&sndcards, sizeof(struct SndCardsList), 0, sizeof(struct SndCardsList));
1239     ret = GetAllAdapters(service, &sndcards);
1240     if (ret != U_SUCCESS) {
1241         DEBUG_LOG("Description Failed to obtain the sound card list!\n");
1242         return U_FAILURE;
1243     }
1244     ShowAllAdapters(&sndcards);
1245 
1246     return U_SUCCESS;
1247 }
1248 
FindSpecificCardName(int card,struct SndCardsList * cardList)1249 static char *FindSpecificCardName(int card, struct SndCardsList *cardList)
1250 {
1251     int32_t i;
1252     uint32_t cnums;
1253     struct AudioCardId *clist = NULL;
1254 
1255     if (cardList->cardNums == 0 || cardList->cardsList == NULL) {
1256         DEBUG_LOG("No sound cards found...!\n");
1257         goto end;
1258     }
1259 
1260     cnums = cardList->cardNums;
1261     clist = cardList->cardsList;
1262     for (i = 0; i < (int32_t)cnums; i++) {
1263         if (card == clist[i].index) {
1264             DEBUG_LOG("I found this sound card. [card%i: %s]\n", card, clist[i].cardName);
1265             return clist[i].cardName;
1266         }
1267     }
1268 
1269 end:
1270     if (cardList->cardsList != NULL) {
1271         free(cardList->cardsList);
1272         cardList->cardsList = NULL;
1273     }
1274     cardList->cardNums = 0;
1275 
1276     return NULL;
1277 }
1278 
UpdateCardSname(int card,const struct HdfIoService * srv,char * const sname,size_t snameLen)1279 void UpdateCardSname(int card, const struct HdfIoService *srv, char * const sname, size_t snameLen)
1280 {
1281     int32_t ret;
1282     struct SndCardsList cardList;
1283     int32_t (*GetAllCardsFunc)(const struct HdfIoService *, struct SndCardsList *);
1284     char *cname = NULL;
1285 
1286     if (card < 0 || srv == NULL || sname == NULL || snameLen == 0) {
1287         DEBUG_LOG("Invalid parameter!\n");
1288         return;
1289     }
1290 
1291     GetAllCardsFunc = CallLibFunction("AudioMixerGetAllAdapters");
1292     if (GetAllCardsFunc == NULL) {
1293         DEBUG_LOG("Description Failed to obtain the current sound card list of the system!\n");
1294         return;
1295     }
1296 
1297     (void)memset_s(&cardList, sizeof(struct SndCardsList), 0, sizeof(struct SndCardsList));
1298     ret = GetAllCardsFunc(srv, &cardList);
1299     if (ret != U_SUCCESS) {
1300         DEBUG_LOG("Update failed: Description Failed to obtain the sound card list!\n");
1301         return;
1302     }
1303 
1304     cname = FindSpecificCardName(card, &cardList);
1305     if (cname == NULL) {
1306         DEBUG_LOG("Update failed: The corresponding sound card cannot be matched!\n");
1307         return;
1308     }
1309 
1310     ret = memcpy_s(sname, snameLen, cname, strlen(cname) + 1);
1311     if (ret != EOK) {
1312         DEBUG_LOG("Update failed: memcpy_s fail!\n");
1313     }
1314     sname[snameLen - 1] = '\0';
1315     if (g_debugFlag) {
1316         printf("|--> [%s]\n", sname);
1317     }
1318 
1319     if (cardList.cardsList != NULL) {
1320         free(cardList.cardsList);
1321         cardList.cardsList = NULL;
1322     }
1323     cardList.cardNums = 0;
1324 }
1325