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 51static struct AudioMixer g_audioMixer; 52static struct AudioMixerContents g_mixerCts; 53 54static const char *g_capLibPath = HDF_LIBRARY_FULL_PATH("libaudio_capture_adapter"); 55static const char *g_renLibPath = HDF_LIBRARY_FULL_PATH("libaudio_render_adapter"); 56static void *g_soHandle = NULL; 57static AudioPcmType g_pcmT = PCM_RENDER; 58static bool g_debugFlag = false; 59 60static const char * const ctlEIfNames[] = { 61 IFACE(CARD), 62 IFACE(PCM), 63 IFACE(MIXER), 64}; 65 66static const char * const ctlElemTypeNames[] = { 67 TYPE(NONE), 68 TYPE(BOOLEAN), 69 TYPE(INTEGER), 70 TYPE(ENUMERATED), 71 TYPE(BYTES), 72}; 73 74void DebugLog(bool flag) 75{ 76 g_debugFlag = flag; 77} 78 79static 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 101static 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 113static 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 125static 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 137static 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 160int32_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 187void CloseLibsoHandle(void) 188{ 189 if (g_soHandle != NULL) { 190 (void)dlclose(g_soHandle); 191 g_soHandle = NULL; 192 } 193} 194 195void 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 206const char *ShowVersion(void) 207{ 208 return AUDIO_UTIL_VERSION_STR; 209} 210 211static 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 228struct 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 253struct 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 287void 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 299static const char *CtlElemIfaceName(AudioCtlElemIfaceType iface) 300{ 301 return ctlEIfNames[iface]; 302} 303 304static const char *CtlElemName(struct AudioHwCtlElemIndex *id) 305{ 306 return (const char *)id->eId.name; 307} 308 309static void PrintCtlElemInfo(struct AudioHwCtlElemId *id) 310{ 311 printf("iface=%s, name='%s'\n", CtlElemIfaceName(id->iface), id->name); 312} 313 314static void PrintCtlElemInfoidx(struct MixerCtsElemIdx *eidx) 315{ 316 printf("index=%u, numid=%u, ", eidx->index, eidx->index + 1); 317 PrintCtlElemInfo(eidx->id); 318} 319 320static 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 335void 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 345static 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 392int32_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 410int32_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 436bool 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 472static AudioCtlElemIfaceType GetCtlElemIface(struct AudioHwCtlElemIndex *id) 473{ 474 return id->eId.iface; 475} 476 477static unsigned int CtlElemGetIdx(struct AudioHwCtlElemIndex *id) 478{ 479 return id->index; 480} 481 482static unsigned int CtlElemInfoCnt(struct AudioMixerCtlElemInfo *info) 483{ 484 return info->count; 485} 486 487static AudioCtlElemType CtlElemGetInfoType(struct AudioMixerCtlElemInfo *info) 488{ 489 return info->type; 490} 491 492static const char *CtlElemTypeName(AudioCtlElemType type) 493{ 494 return ctlElemTypeNames[type]; 495} 496 497static const char *MixerCtlType(struct AudioMixerCtlElemInfo *info) 498{ 499 return CtlElemTypeName(CtlElemGetInfoType(info)); 500} 501 502static int32_t CtlElemInfoGetMin(struct AudioMixerCtlElemInfo *info) 503{ 504 return info->value.intVal.min; 505} 506 507static int32_t CtlElemInfoGetMax(struct AudioMixerCtlElemInfo *info) 508{ 509 return info->value.intVal.max; 510} 511 512static int32_t CtlElemInfoGetStep(struct AudioMixerCtlElemInfo *info) 513{ 514 return info->value.intVal.step; 515} 516 517static long *CtlElemInfoGetVals(struct AudioMixerCtlElemInfo *info) 518{ 519 return info->value.intVal.vals; 520} 521 522static void CtlElemInfoSetItem(struct AudioMixerCtlElemInfo *info, uint32_t val) 523{ 524 info->value.enumVal.item = val; 525} 526 527static uint32_t CtlElemInfoGetItems(struct AudioMixerCtlElemInfo *info) 528{ 529 return info->value.enumVal.items; 530} 531 532static uint32_t CtlElemInfoGetItem(struct AudioMixerCtlElemInfo *info) 533{ 534 return info->value.enumVal.item; 535} 536 537static char *CtlElemInfoGetItemName(struct AudioMixerCtlElemInfo *info) 538{ 539 return info->value.enumVal.name; 540} 541 542static 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 551static int32_t CtlElemValueGetInt(struct AudioMixerCtlElemInfo *info, uint32_t idx) 552{ 553 return CtlElemValueGetBoolean(info, idx); 554} 555 556static 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 565static unsigned char *CtlElemValueGetBytes(struct AudioMixerCtlElemInfo *info) 566{ 567 return info->value.reserved; 568} 569 570static 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 579static 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 613static 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 660static 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 691static void ShowEnumVal(struct AudioMixerCtlElemInfo *info) 692{ 693 printf(" : values=%u\n", CtlElemInfoGetItem(info)); 694} 695 696static 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 716static 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 735int32_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 775static 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 788static 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 810static 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 845static bool IsRenderChannel(AudioMixerChannelIdType chn) 846{ 847 return !!(chn); 848} 849 850static bool IsCaptureChannel(AudioMixerChannelIdType chn) 851{ 852 return !(chn); 853} 854 855static 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 894static 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 929int32_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 981static 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 1027static 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 1049static 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 1085int32_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 1142static 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 1154static 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 1186static 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 1215end: 1216 if (sndList->cardsList != NULL) { 1217 free(sndList->cardsList); 1218 sndList->cardsList = NULL; 1219 } 1220} 1221 1222int32_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 1249static 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 1269end: 1270 if (cardList->cardsList != NULL) { 1271 free(cardList->cardsList); 1272 cardList->cardsList = NULL; 1273 } 1274 cardList->cardNums = 0; 1275 1276 return NULL; 1277} 1278 1279void 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