blob: 796c30773949faefb0eb9df74b7020af75d38f5d [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001#include "AudioParamParserPriv.h"
2
3#include <assert.h>
4#include <stdio.h>
5#include <string.h>
6#include <sys/stat.h>
7
8#ifdef __linux__
9#include <dirent.h>
10#include <unistd.h>
11#else
12#include <windows.h>
13#pragma warning( disable : 4996 )
14#endif
15
16static AppHandle appHandleInst;
17static int appHandleInited = 0;
18
19#ifdef FORCE_DEBUG_LEVEL
20int appDebugLevel = DEBUG_LEVEL; /* Global debug level setting */
21#else
22int appDebugLevel = INFO_LEVEL; /* Global debug level setting */
23#endif
24
25FILE *appLogFp = NULL;
26int outputLogToStdout = 0;
27
28#ifndef WIN32
29static pthread_rwlock_t appHandleInstLock = PTHREAD_RWLOCK_INITIALIZER;
30static const char *appHandleInstLockCallerFun = NULL; /* Used to cache the lock holder */
31#else
32int __stdcall DllMain(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved)
33{
34 return TRUE;
35}
36#endif
37
38EXPORT APP_STATUS appHandleInit(AppHandle *appHandle)
39{
40#ifdef _DEBUG
41 /* Alwasy show the output console for debug build */
42 appHandleRedirectIOToConsole();
43#endif
44
45 INFO_LOG("appHandle = 0x%p\n", appHandle);
46
47 if (appHandle)
48 {
49 appHandle->xmlDir = NULL;
50 appHandle->xmlCusDir = NULL;
51 appHandle->audioTypeHash = NULL;
52 appHandle->featureOptionsHash = NULL;
53 appHandle->featureOptionsDoc = NULL;
54 appHandle->noficyCbList = NULL;
55#ifndef WIN32
56 appHandle->lockCallerFun = NULL;
57 appHandle->appThreadExit = 0;
58 appHandle->inotifyFd = 0;
59
60 pthread_rwlock_init(&appHandle->lock, NULL);
61#endif
62 appHandleShowAudioTypeSupportedVerInfo(appHandle);
63 return APP_NO_ERROR;
64 }
65 else
66 {
67 WARN_LOG("AppHandle is NULL!\n");
68 return APP_ERROR;
69 }
70}
71
72EXPORT APP_STATUS appHandleUninit(AppHandle *appHandle)
73{
74 INFO_LOG("appHandle = 0x%p\n", appHandle);
75
76 if (!appHandle)
77 {
78 WARN_LOG("AppHandle is NULL!\n");
79 return APP_ERROR;
80 }
81 else
82 {
83 NotifyCb *notifyCb, *tmp;
84
85 /* Lock */
86 appHandleWriteLock(appHandle, __FUNCTION__);
87
88 if (appHandle->xmlDir)
89 {
90 free(appHandle->xmlDir);
91 }
92 appHandle->xmlDir = NULL;
93
94 if (appHandle->xmlCusDir)
95 {
96 free(appHandle->xmlCusDir);
97 }
98 appHandle->xmlCusDir = NULL;
99
100 if (appHandle->featureOptionsDoc)
101 {
102 xmlFreeDoc(appHandle->featureOptionsDoc);
103 }
104 appHandle->featureOptionsDoc = NULL;
105
106#ifndef WIN32
107 if (appHandle->appThreadExit == 0)
108 {
109 void *status;
110 appHandle->appThreadExit = 1;
111 INFO_LOG("Send signal to appThread\n");
112 pthread_kill(appHandle->appThread, SIGUSR1);
113
114 /* TODO: Don't join the inotify thread, since the read function is block waiting */
115 INFO_LOG("Waiting inotify thread join...\n");
116 pthread_join(appHandle->appThread, &status);
117 INFO_LOG("inotify thread joined\n");
118 appHandle->inotifyFd = 0;
119 }
120#endif
121
122 // release notify callback list
123 LL_FOREACH_SAFE(appHandle->noficyCbList, notifyCb, tmp)
124 {
125 LL_DELETE(appHandle->noficyCbList, notifyCb);
126 free(notifyCb);
127 }
128 appHandle->noficyCbList = NULL;
129
130 /* If appHandle is singleton instance, reset the init info */
131 if (appHandle == &appHandleInst)
132 {
133 appHandleInited = 0;
134 }
135
136 appHandleReleaseAudioTypeHash(appHandle);
137
138 appHandleReleaseFeatureOptionsHash(appHandle);
139
140 xmlCleanupParser();
141
142 /* Flush app log */
143 if (appLogFp)
144 {
145 fflush(appLogFp);
146 }
147
148 /* Unlock */
149 appHandleUnlock(appHandle);
150
151 return APP_NO_ERROR;
152 }
153}
154
155EXPORT const char *appHandleGetBuildTimeStamp()
156{
157 return __DATE__" "__TIME__;
158}
159
160EXPORT int appHandleWriteLock(AppHandle *appHandle, const char *callerFun)
161{
162 int res = 0;
163
164 if (!appHandle)
165 {
166 WARN_LOG("appHandle is NULL\n");
167 return res;
168 }
169
170#ifndef WIN32
171 while (1)
172 {
173 if (pthread_rwlock_trywrlock(&appHandle->lock) == 0)
174 {
175 appHandle->lockCallerFun = callerFun;
176 DEBUG_LOG("AppHandle lock is locked by %s()\n", appHandle->lockCallerFun);
177 break;
178 }
179 else
180 {
181 DEBUG_LOG("Cannot lock the AppHandle lock, delay some time. (the locker is %s())\n", appHandle->lockCallerFun);
182 utilUsleep(1);
183 }
184 }
185#else
186 //DEBUG_LOG("Not support this function yet!\n");
187#endif
188 return res;
189}
190
191EXPORT int appHandleReadLock(AppHandle *appHandle, const char *callerFun)
192{
193 int res = 0;
194
195 if (!appHandle)
196 {
197 WARN_LOG("appHandle is NULL\n");
198 return res;
199 }
200
201#ifndef WIN32
202 while (1)
203 {
204 if (pthread_rwlock_tryrdlock(&appHandle->lock) == 0)
205 {
206 appHandle->lockCallerFun = callerFun;
207 DEBUG_LOG("AppHandle lock is locked by %s()\n", appHandle->lockCallerFun);
208 break;
209 }
210 else
211 {
212 DEBUG_LOG("Cannot lock the AppHandle lock, delay some time. (the locker is %s())\n", appHandle->lockCallerFun);
213 utilUsleep(1);
214 }
215 }
216#else
217 //DEBUG_LOG("Not support this function yet!\n");
218#endif
219 return res;
220}
221
222EXPORT int appHandleUnlock(AppHandle *appHandle)
223{
224 int res = 0;
225
226 if (!appHandle)
227 {
228 WARN_LOG("appHandle is NULL\n");
229 return res;
230 }
231
232#ifndef WIN32
233 DEBUG_LOG("Unlock appHandle lock\n");
234 res = pthread_rwlock_unlock(&appHandle->lock);
235#endif
236 return res;
237}
238
239EXPORT int appHandleInstWriteLock(const char *callerFun)
240{
241 int res = 0;
242
243#ifndef WIN32
244 while (1)
245 {
246 if (pthread_rwlock_trywrlock(&appHandleInstLock) == 0)
247 {
248 appHandleInstLockCallerFun = callerFun;
249 DEBUG_LOG("%s acquired the appHandleInstLock\n", callerFun);
250 break;
251 }
252 else
253 {
254 DEBUG_LOG("Cannot lock the appHandleInstLock, delay some time. (the locker is %s)\n", callerFun);
255 utilUsleep(1);
256 }
257 }
258#else
259 //DEBUG_LOG("Not support this function yet!\n");
260#endif
261 return res;
262}
263
264EXPORT int appHandleInstUnlock()
265{
266 int res = 0;
267#ifndef WIN32
268 DEBUG_LOG("Unlock appHandleInst lock\n");
269 res = pthread_rwlock_unlock(&appHandleInstLock);
270#endif
271 return res;
272}
273
274EXPORT FeatureOption *featureOptionCreate(const char *name, const char *value)
275{
276 FeatureOption *featureOption = malloc(sizeof(FeatureOption));
277 featureOption->name = strdup(name);
278 featureOption->value = strdup(value);
279 return featureOption;
280}
281
282EXPORT void featureOptionRelease(FeatureOption *featureOption)
283{
284 free(featureOption->name);
285 free(featureOption->value);
286 free(featureOption);
287}
288
289EXPORT void appHandleReleaseFeatureOptionsHash(AppHandle *appHandle)
290{
291 if (appHandle->featureOptionsHash)
292 {
293 FeatureOption *tmp, *item;
294 HASH_ITER(hh, appHandle->featureOptionsHash, item, tmp)
295 {
296 HASH_DEL(appHandle->featureOptionsHash, item);
297 featureOptionRelease(item);
298 }
299 }
300 appHandle->featureOptionsHash = NULL;
301}
302
303EXPORT AppHandle *appHandleGetInstance()
304{
305 appHandleInstWriteLock(__FUNCTION__);
306
307 INFO_LOG("");
308
309 if (!appHandleInited)
310 {
311 appHandleInit(&appHandleInst);
312#ifdef WIN32
313 appHandleParseXml(&appHandleInst, XML_FOLDER_ON_TUNING_TOOL, XML_CUS_FOLDER_ON_TUNING_TOOL);
314#else
315 appHandleParseXml(&appHandleInst, XML_FOLDER_ON_DEVICE, XML_CUS_FOLDER_ON_DEVICE);
316#endif
317 appHandleInited = 1;
318 }
319
320 appHandleInstUnlock();
321
322 return &appHandleInst;
323}
324
325EXPORT APP_STATUS appHandleParseXml(AppHandle *appHandle, const char *dir, const char *cusDir)
326{
327 INFO_LOG("appHandle = 0x%p, dir = %s, cusDir = %s\n", appHandle, dir, cusDir);
328
329 if (!appHandle)
330 {
331 ERR_LOG("appHandle is NULL!\n");
332 return APP_ERROR;
333 }
334
335 if (!dir)
336 {
337 ERR_LOG("dir is NULL\n");
338 return APP_ERROR;
339 }
340
341 if (appHandle->xmlDir || appHandle->xmlCusDir)
342 {
343 ERR_LOG("XML already parsed, don't call the appHandleParseXml twice!\n");
344 return APP_ERROR;
345 }
346
347 appHandleWriteLock(appHandle, __FUNCTION__);
348
349 appHandle->xmlDir = strdup(dir);
350#if defined(APP_FORCE_ENABLE_CUS_XML) || defined(WIN32) || defined(CONFIG_MT_ENG_BUILD)
351 appHandle->xmlCusDir = strdup(cusDir);
352#else
353#if !defined(WIN32)
354 if (isCustXmlEnable())
355 {
356 appHandle->xmlCusDir = strdup(cusDir);
357 }
358 else
359 {
360 INFO_LOG("Cust XML folder not enabled");
361 }
362#endif
363#endif
364 INFO_LOG("XmlDir = %s, XmlCusDir = %s\n", appHandle->xmlDir, appHandle->xmlCusDir);
365
366 /* Load feature options information */
367 appHandleLoadDirFeatureOptionsInfo(appHandle);
368
369 /* Load audio type information */
370 appHandleLoadDirAudioTypeInfo(appHandle);
371
372 appHandleUnlock(appHandle);
373
374#ifndef WIN32
375 /* Setup file system monitor thread */
376 if (appHandle->xmlCusDir)
377 {
378 if (pthread_create(&appHandle->appThread, NULL, appHandleThreadLoop, (void *)appHandle))
379 {
380 ERR_LOG("Create app thread fail!\n");
381 return APP_ERROR;
382 }
383 else
384 {
385 INFO_LOG("Create app thread successfully\n");
386 }
387 }
388 else
389 {
390 WARN_LOG("Cus folder is NULL, don't create FS monitor thread\n");
391 }
392#endif
393 return APP_NO_ERROR;
394}
395
396EXPORT APP_STATUS appHandleLoadDirFeatureOptionsInfo(AppHandle *appHandle)
397{
398 struct stat fileStat;
399 int strLen;
400 char *featureOptionsFile = NULL;
401 xmlNode *node = NULL;
402 xmlNode *root = NULL;
403 xmlChar *name = NULL;
404 xmlChar *value = NULL;
405
406 if (!appHandle)
407 {
408 ERR_LOG("appHandle is NULL!\n");
409 return APP_ERROR;
410 }
411
412 if (!appHandle->xmlDir)
413 {
414 ERR_LOG("xmlDir is NULL!\n");
415 return APP_ERROR;
416 }
417
418 if (appHandle->featureOptionsHash)
419 {
420 WARN_LOG("Feature options already loaded, don't reload it!\n");
421 return APP_NO_ERROR;
422 }
423
424 /* Check cus folder xml first */
425 strLen = strlen(appHandle->xmlDir) + strlen(FEATURE_OPTIONS_XML) + 2;
426 featureOptionsFile = (char *)malloc(strLen);
427 sprintf(featureOptionsFile, "%s%s%s", appHandle->xmlDir, FOLDER, FEATURE_OPTIONS_XML);
428
429 if (stat(featureOptionsFile, &fileStat) == -1)
430 {
431 ERR_LOG("No %s file\n", featureOptionsFile);
432 free(featureOptionsFile);
433 return APP_ERROR;
434 }
435
436 appHandle->featureOptionsDoc = xmlParseFile(featureOptionsFile);
437 if (appHandle->featureOptionsDoc == NULL)
438 {
439 ERR_LOG("Failed to parse %s\n", featureOptionsFile);
440 free(featureOptionsFile);
441 return APP_ERROR;
442 }
443 else
444 {
445 INFO_LOG("Load xml file successfully. (%s)\n", featureOptionsFile);
446 }
447 free(featureOptionsFile);
448
449 /* Parse informatino to feature options hash */
450 root = xmlDocGetRootElement(appHandle->featureOptionsDoc);
451 if (!root)
452 {
453 ERR_LOG("Root element is NULL\n");
454 return APP_ERROR;
455 }
456
457 node = findXmlNodeByElemName(root, ELEM_AUDIO_FEATURE_OPTIONS);
458 if (node && node->children)
459 {
460 node = node->children;
461 }
462 else
463 {
464 ERR_LOG("No feature options found!\n");
465 return APP_ERROR;
466 }
467
468 while ((node = findXmlNodeByElemName(node->next, ELEM_PARAM)))
469 {
470 FeatureOption *featureOption;
471 name = xmlGetProp(node, (const xmlChar *)ATTRI_NAME);
472 value = xmlGetProp(node, (const xmlChar *)ATTRI_VALUE);
473
474 featureOption = featureOptionCreate((const char *)name, (const char *)value);
475 HASH_ADD_KEYPTR(hh, appHandle->featureOptionsHash, featureOption->name, strlen(featureOption->name), featureOption);
476
477 if (name)
478 {
479 xmlFree(name);
480 }
481
482 if (value)
483 {
484 xmlFree(value);
485 }
486 }
487
488 return APP_NO_ERROR;
489}
490
491EXPORT APP_STATUS appHandleLoadDirAudioTypeInfo(AppHandle *appHandle)
492{
493 size_t numOfAudioParamXml = 0;
494 char audioType[MAX_AUDIO_TYPE_LEN];
495
496#ifdef __linux__
497 struct dirent **namelist;
498 int i;
499 int total;
500
501 if (!appHandle)
502 {
503 ERR_LOG("appHandle is NULL!\n");
504 return APP_ERROR;
505 }
506
507 total = scandir(appHandle->xmlDir, &namelist, 0, alphasort);
508
509 /* Release old audio type first */
510 appHandleReleaseAudioTypeHash(appHandle);
511
512 if (total < 0)
513 {
514 ERR_LOG("Scandir error\n");
515 }
516 else
517 {
518 for (i = 0; i < total; i++)
519 {
520 if (strstr(namelist[i]->d_name, AUDIO_PARAM_XML_POSFIX) == NULL)
521 {
522 DEBUG_LOG("File name's posfix is not AudioParam.xml (%s)\n", namelist[i]->d_name);
523 continue;
524 }
525
526 sscanf(namelist[i]->d_name, AUDIO_TYPE_FMT_STR(MAX_AUDIO_TYPE_LEN), audioType);
527 if (appHandleIsValidAudioType(appHandle, audioType))
528 {
529 appHandleAddAudioType(appHandle, audioType);
530 }
531 else
532 {
533 WARN_LOG("Invalid audio param xml = %s\n", namelist[i]->d_name);
534 }
535 }
536 }
537#else
538 WIN32_FIND_DATA FindFileData;
539 HANDLE hFind;
540 UT_string *path = NULL;
541
542 if (!appHandle)
543 {
544 ERR_LOG("appHandle is NULL!\n");
545 return APP_ERROR;
546 }
547
548 /* Release old audio type first */
549 appHandleReleaseAudioTypeHash(appHandle);
550
551 /* Check preload xml folder */
552 utstring_new(path);
553 utstring_printf(path, "%s"FOLDER"*"AUDIO_PARAM_XML_POSFIX, appHandle->xmlDir);
554 hFind = FindFirstFile(utstring_body(path), &FindFileData);
555 utstring_free(path);
556
557 if (hFind == INVALID_HANDLE_VALUE)
558 {
559 WARN_LOG("No xml found!\n");
560 return APP_ERROR;
561 }
562
563 do
564 {
565 sscanf(FindFileData.cFileName, AUDIO_TYPE_FMT_STR(MAX_AUDIO_TYPE_LEN), audioType);
566
567 if (appHandleIsValidAudioType(appHandle, audioType))
568 {
569 appHandleAddAudioType(appHandle, audioType);
570 }
571 else
572 {
573 INFO_LOG("Invalid audio param xml = %s\n", FindFileData.cFileName);
574 }
575 }
576 while (FindNextFile(hFind, &FindFileData));
577#endif
578
579 /* Load all XMLs */
580 appHandleLoadAllAudioTypeXml(appHandle);
581 INFO_LOG("Load all audio type XML - ok\n");
582
583 /* Modify data depends on feature options */
584 appHandleReviseXmlDocByFeatureOptions(appHandle);
585
586 /* Load hash info from XML */
587 appHandleLoadAllAudioTypeHash(appHandle);
588 INFO_LOG("Load all audio Hash - ok\n");
589
590 if (appDebugLevel == DEBUG_LEVEL)
591 {
592 appHandleDumpAudioTypeList(appHandle);
593 }
594
595 return APP_NO_ERROR;
596}
597
598EXPORT size_t appHandleGetNumOfAudioType(AppHandle *appHandle)
599{
600 if (!appHandle)
601 {
602 ERR_LOG("appHandle is NULL!\n");
603 return APP_ERROR;
604 }
605
606 return HASH_COUNT(appHandle->audioTypeHash);
607}
608
609EXPORT APP_STATUS appHandleLoadAllAudioTypeXml(AppHandle *appHandle)
610{
611 size_t i;
612 size_t count = appHandleGetNumOfAudioType(appHandle);
613
614 for (i = 0; i < count; i++)
615 {
616 AudioType *audioType = appHandleGetAudioTypeByIndex(appHandle, i);
617
618 /* Load xml struct */
619 if (appHandleLoadAudioTypeXml(appHandle, audioType) == APP_ERROR)
620 {
621 WARN_LOG("Load audio type XML failed. (%s)\n", audioType->name);
622 }
623 }
624
625 return APP_NO_ERROR;
626}
627
628EXPORT APP_STATUS appHandleLoadAudioTypeXml(AppHandle *appHandle, AudioType *audioType)
629{
630 char *audioTypeFile;
631
632 INFO_LOG("audioType = %s\n", audioType->name);
633
634 // Load AudioParamXml
635 audioTypeFile = appHandleGetAudioTypeFilePath(appHandle, audioType->name, AUDIO_PARAM_XML_POSFIX);
636 if (audioTypeFile == NULL)
637 {
638 WARN_LOG("The AudioTypeFile(%s%s) doesn't exist.\n", audioType->name, AUDIO_PARAM_XML_POSFIX);
639 return APP_ERROR;
640 }
641
642 audioType->audioParamDoc = xmlParseFile(audioTypeFile);
643
644 if (audioType->audioParamDoc == NULL)
645 {
646 ERR_LOG("Failed to parse %s\n", audioTypeFile);
647 free(audioTypeFile);
648
649 // Audio param file broken, load preload xml file instead
650 audioTypeFile = appHandleGetPreloadAudioTypeFilePath(appHandle, audioType->name, AUDIO_PARAM_XML_POSFIX);
651 if (audioTypeFile == NULL)
652 {
653 WARN_LOG("The AudioTypeFile(%s%s) doesn't exist.\n", audioType->name, AUDIO_PARAM_XML_POSFIX);
654 return APP_ERROR;
655 }
656
657 WARN_LOG("Trying to load preload %s file instead of broken XML file!\n", audioTypeFile);
658 audioType->audioParamDoc = xmlParseFile(audioTypeFile);
659 if (audioType->audioParamDoc == NULL)
660 {
661 ERR_LOG("Failed to parse %s\n", audioTypeFile);
662 free(audioTypeFile);
663 return APP_ERROR;
664 }
665 else
666 {
667 INFO_LOG("Load xml file successfully. (%s)\n", audioTypeFile);
668 }
669 }
670 else
671 {
672 INFO_LOG("Load xml file successfully. (%s)\n", audioTypeFile);
673 }
674
675 free(audioTypeFile);
676
677 // Load ParamUnitDescXml
678 audioTypeFile = appHandleGetAudioTypeFilePath(appHandle, audioType->name, PARAM_UNIT_DESC_XML_POSFIX);
679 if (audioTypeFile == NULL)
680 {
681 WARN_LOG("The AudioTypeFile(%s%s) doesn't exist.\n", audioType->name, PARAM_UNIT_DESC_XML_POSFIX);
682 return APP_ERROR;
683 }
684
685 audioType->paramUnitDescDoc = xmlParseFile(audioTypeFile);
686 if (audioType->paramUnitDescDoc == NULL)
687 {
688 ERR_LOG("Failed to parse %s%s\n", audioTypeFile, PARAM_UNIT_DESC_XML_POSFIX);
689 free(audioTypeFile);
690 return APP_ERROR;
691 }
692 else
693 {
694 INFO_LOG("Load xml file successfully. (%s)\n", audioTypeFile);
695 }
696 free(audioTypeFile);
697
698#ifdef WIN32
699 // Load ParamTreeViewXml only for tuning tool
700 audioTypeFile = appHandleGetAudioTypeFilePath(appHandle, audioType->name, PARAM_TREE_VIEW_XML_POSFIX);
701 if (audioTypeFile == NULL)
702 {
703 INFO_LOG("The AudioTypeFile(%s%s) doesn't exist.\n", audioType->name, PARAM_TREE_VIEW_XML_POSFIX);
704 free(audioTypeFile);
705 }
706 else
707 {
708 audioType->paramTreeViewDoc = xmlParseFile(audioTypeFile);
709 if (audioType->audioParamDoc == NULL)
710 {
711 DEBUG_LOG("Failed to parse %s%s\n", audioTypeFile, PARAM_TREE_VIEW_XML_POSFIX);
712 }
713 else
714 {
715 INFO_LOG("Load xml file successfully. (%s)\n", audioTypeFile);
716 }
717 free(audioTypeFile);
718 }
719#endif
720
721 /* Get tab name info */
722 audioTypeParseTabName(audioType);
723
724 /* Get version info */
725 if (audioTypeParseXmlVer(audioType) == APP_ERROR)
726 {
727 ERR_LOG("Cannot parse xml version info. (%s)\n", audioType->name);
728 return APP_ERROR;
729 }
730
731#ifndef WIN32
732 /* XML Version check for device driver or HAL */
733 if (!audioTypeIsDeviceSupportedXmlVer(audioType))
734 {
735 abort();
736 }
737#endif
738
739 return APP_NO_ERROR;
740}
741
742EXPORT char *appHandleGetAudioTypeFilePath(AppHandle *appHandle, const char *audioType, const char *posfix)
743{
744 /* Check cus folder xml first */
745 struct stat fileStat;
746 int strLen;
747 char *path;
748
749 if (appHandle->xmlCusDir && !strcmp(posfix, AUDIO_PARAM_XML_POSFIX))
750 {
751 strLen = strlen(appHandle->xmlCusDir) + strlen(audioType) + strlen(posfix) + 2;
752 path = (char *)malloc(strLen);
753 sprintf(path, "%s%s%s%s", appHandle->xmlCusDir, FOLDER, audioType, posfix);
754
755 if (stat(path, &fileStat) != -1)
756 {
757 return path;
758 }
759 else
760 {
761 free(path);
762 }
763 }
764
765 /* Check default folder */
766 strLen = strlen(appHandle->xmlDir) + strlen(audioType) + strlen(posfix) + 2;
767 path = (char *)malloc(strLen);
768 sprintf(path, "%s%s%s%s", appHandle->xmlDir, FOLDER, audioType, posfix);
769
770 if (stat(path, &fileStat) != -1)
771 {
772 return path;
773 }
774
775 free(path);
776 return NULL;
777}
778
779EXPORT char *appHandleGetPreloadAudioTypeFilePath(AppHandle *appHandle, const char *audioType, const char *posfix)
780{
781 /* Check cus folder xml first */
782 struct stat fileStat;
783 int strLen;
784 char *path;
785
786 /* Check default folder */
787 strLen = strlen(appHandle->xmlDir) + strlen(audioType) + strlen(posfix) + 2;
788 path = (char *)malloc(strLen);
789 sprintf(path, "%s%s%s%s", appHandle->xmlDir, FOLDER, audioType, posfix);
790
791 if (stat(path, &fileStat) != -1)
792 {
793 return path;
794 }
795
796 free(path);
797 return NULL;
798}
799
800EXPORT int appHandleIsValidAudioType(AppHandle *appHandle, const char *audioType)
801{
802 char *filePath;
803
804 assert(appHandle != NULL);
805 filePath = appHandleGetAudioTypeFilePath(appHandle, audioType, PARAM_UNIT_DESC_XML_POSFIX);
806 if (filePath == NULL)
807 {
808 ERR_LOG("%s audio type is not valid! (%s is not exist)\n", audioType, filePath);
809 free(filePath);
810 return 0;
811 }
812
813 free(filePath);
814 return 1;
815}
816
817EXPORT AudioType *appHandleAddAudioType(AppHandle *appHandle, const char *audioTypeName)
818{
819 AudioType *audioType;
820
821 if (!appHandle)
822 {
823 ERR_LOG("The appHandle is NULL\n");
824 return NULL;
825 }
826
827 if (!audioTypeName)
828 {
829 ERR_LOG("The audioTypeName is NULL\n");
830 return NULL;
831 }
832
833 audioType = audioTypeCreate(appHandle, audioTypeName);
834
835 /* Add audio type to hash */
836 HASH_ADD_KEYPTR(hh, appHandle->audioTypeHash, audioType->name, strlen(audioType->name), audioType);
837
838 return audioType;
839}
840
841EXPORT AudioType *appHandleGetAudioTypeByIndex(AppHandle *appHandle, size_t index)
842{
843 AudioType *audioType = NULL;
844 size_t i = 0;
845
846 DEBUG_LOG("appHandle = 0x%p, index = %lu\n", appHandle, index);
847
848 if (!appHandle)
849 {
850 ERR_LOG("appHandle is NULL!\n");
851 return NULL;
852 }
853
854 for (audioType = appHandle->audioTypeHash; audioType ; audioType = audioType->hh.next)
855 {
856 if (index == i++)
857 {
858 return audioType;
859 }
860 }
861
862 return NULL;
863}
864
865EXPORT AudioType *appHandleGetAudioTypeByName(AppHandle *appHandle, const char *name)
866{
867 AudioType *audioType = NULL;
868
869 INFO_LOG("appHandle = 0x%p, name = %s\n", appHandle, name);
870
871 if (!appHandle)
872 {
873 ERR_LOG("appHandle is NULL!\n");
874 return NULL;
875 }
876
877 HASH_FIND_STR(appHandle->audioTypeHash, name, audioType);
878
879 return audioType;
880}
881
882EXPORT void appHandleReleaseAudioTypeHash(AppHandle *appHandle)
883{
884 if (appHandle->audioTypeHash)
885 {
886 AudioType *tmp, *item;
887 HASH_ITER(hh, appHandle->audioTypeHash, item, tmp)
888 {
889 HASH_DEL(appHandle->audioTypeHash, item);
890 audioTypeRelease(item);
891 }
892 }
893 appHandle->audioTypeHash = NULL;
894}
895
896EXPORT void appHandleDumpAudioTypeList(AppHandle *appHandle)
897{
898 size_t index = 0;
899 size_t numOfAudioType = appHandleGetNumOfAudioType(appHandle);
900 INFO_LOG("=================================\n");
901 INFO_LOG("Totoal num of Audio Type List = %lu\n", numOfAudioType);
902 for (index = 0; index < numOfAudioType; index++)
903 {
904 AudioType *audioType = appHandleGetAudioTypeByIndex(appHandle, index);
905 INFO_LOG("AudioType[%lu] = %s\n", index, audioType->name);
906 audioTypeDump(audioType);
907 }
908}
909
910EXPORT APP_STATUS appHandleLoadAllAudioTypeHash(AppHandle *appHandle)
911{
912 size_t index = 0;
913 size_t numOfAudioType = appHandleGetNumOfAudioType(appHandle);
914 /* Load stage1 information */
915 for (index = 0; index < numOfAudioType; index++)
916 {
917 AudioType *audioType = appHandleGetAudioTypeByIndex(appHandle, index);
918 audioTypeLoadStage1Hash(audioType);
919 }
920
921 /* Load stage2 information (ex: ParamTreeView's switch object)*/
922 for (index = 0; index < numOfAudioType; index++)
923 {
924 AudioType *audioType = appHandleGetAudioTypeByIndex(appHandle, index);
925 audioTypeLoadStage2Hash(audioType);
926 }
927
928 return APP_NO_ERROR;
929}
930
931EXPORT void appHandleRegXmlChangedCb(AppHandle *appHandle, NOTIFY_CB_FUN callbackFun)
932{
933 INFO_LOG("appHandle = 0x%p, callbackFun = 0x%p\n", appHandle, callbackFun);
934
935 appHandleWriteLock(appHandle, __FUNCTION__);
936
937 if (appHandle && callbackFun)
938 {
939 /* Checking the duplicated callback function registration */
940 NotifyCb *notifyCb;
941 LL_FOREACH(appHandle->noficyCbList, notifyCb)
942 {
943 if (notifyCb->cb == callbackFun)
944 {
945 INFO_LOG("Same callback function found. ignore it\n");
946 appHandleUnlock(appHandle);
947 return;
948 }
949 }
950
951 notifyCb = malloc(sizeof(NotifyCb));
952 notifyCb->cb = callbackFun;
953 LL_APPEND(appHandle->noficyCbList, notifyCb);
954 }
955 else
956 {
957 WARN_LOG("Cannot register xml callback! (AppHandle = 0x%p, callbackFun = 0x%p)\n", appHandle, callbackFun);
958 }
959
960 appHandleUnlock(appHandle);
961}
962
963EXPORT void appHandleUnregXmlChangedCb(AppHandle *appHandle, NOTIFY_CB_FUN callbackFun)
964{
965 INFO_LOG("appHandle = 0x%p, callbackFun = 0x%p\n", appHandle, callbackFun);
966
967 appHandleWriteLock(appHandle, __FUNCTION__);
968
969 if (appHandle && callbackFun)
970 {
971 NotifyCb *notifyCb, *tmp;
972 LL_FOREACH_SAFE(appHandle->noficyCbList, notifyCb, tmp)
973 {
974 if (notifyCb->cb == callbackFun)
975 {
976 LL_DELETE(appHandle->noficyCbList, notifyCb);
977 free(notifyCb);
978 INFO_LOG("Callback function unregistered. (0x%p, 0x%p)\n", callbackFun, callbackFun);
979 break;
980 }
981 }
982 }
983 else
984 {
985 WARN_LOG("Cannot unregister xml callback! (AppHandle = 0x%p, callbackFun = %p)\n", appHandle, callbackFun);
986 }
987
988 appHandleUnlock(appHandle);
989}
990
991EXPORT void *appHandleThreadLoop(void *arg)
992{
993#if defined(WIN32)
994 /* Always disable on WIN32 */
995 return NULL;
996#else
997 /* This thread only work on linux platform */
998 /* Only eng load could monitor custom folder */
999 AppHandle *appHandle = (AppHandle *)arg;
1000 ssize_t len;
1001 char buf[INOTIFY_BUF_SIZE];
1002 char *ptr;
1003 const struct inotify_event *event;
1004
1005#if !defined(APP_FORCE_ENABLE_CUS_XML) && !defined(CONFIG_MT_ENG_BUILD)
1006 /* User load, check NVRam status */
1007 if (isCustXmlEnable())
1008 {
1009 INFO_LOG("User load, cust xml enabled\n");
1010 }
1011 else
1012 {
1013 INFO_LOG("User load but cust xml disabled\n");
1014 return NULL;
1015 }
1016#endif
1017
1018 if (!appHandle->xmlCusDir)
1019 {
1020 WARN_LOG("xmlCusDir is NULL, don't run the appHandleThreadLoop !!!");
1021 exit(1);
1022 }
1023
1024 /* Create folder first to make inotify work */
1025 utilMkdir(appHandle->xmlCusDir);
1026
1027 /* Register signal handler */
1028 struct sigaction sa;
1029 sa.sa_handler = NULL;
1030 sa.sa_sigaction = &signalHandler;
1031 sa.sa_flags = SA_SIGINFO;
1032 sigemptyset(&sa.sa_mask);
1033
1034 if (sigaction(SIGUSR1, &sa, NULL) < 0)
1035 {
1036 ERR_LOG("sigaction fail");
1037 exit(1);
1038 }
1039
1040 /* inotify registration */
1041 appHandle->inotifyFd = inotify_init();
1042 if (appHandle->inotifyFd < 0)
1043 {
1044 ERR_LOG("inotify_init failed !!!");
1045 exit(1);
1046 }
1047
1048 INFO_LOG("Add inotify monitor path = %s, fd = %d\n", appHandle->xmlCusDir, appHandle->inotifyFd);
1049
1050 while (1)
1051 {
1052 if (inotify_add_watch(appHandle->inotifyFd, appHandle->xmlCusDir, IN_CLOSE_WRITE) < 0)
1053 {
1054 ERR_LOG("inotify_add_watch failed !!! try again...");
1055 utilMkdir(appHandle->xmlCusDir);
1056 utilUsleep(1000000);
1057 } else {
1058 break;
1059 }
1060 }
1061
1062 while (!appHandle->appThreadExit)
1063 {
1064 INFO_LOG("inotify read waiting... (fd = %d)\n", appHandle->inotifyFd);
1065 len = read(appHandle->inotifyFd, buf, sizeof(buf));
1066
1067 if (len < 0)
1068 {
1069 if (appHandle->appThreadExit)
1070 {
1071 break;
1072 }
1073
1074 ERR_LOG("inotify read error!\n");
1075 pthread_exit(NULL);
1076 }
1077
1078 /* Loop over all events in the buffer */
1079 for (ptr = buf; ptr < buf + len; ptr += sizeof(struct inotify_event) + event->len)
1080 {
1081 event = (const struct inotify_event *) ptr;
1082 if (event->len)
1083 {
1084 NotifyCb *notifyCb;
1085 char audioTypeName[MAX_AUDIO_TYPE_LEN];
1086 AudioType *audioType;
1087
1088 if (strstr(event->name, AUDIO_PARAM_XML_POSFIX) == NULL)
1089 {
1090 INFO_LOG("File name's posfix is not AudioParam.xml (%s)\n", event->name);
1091 continue;
1092 }
1093
1094 sscanf(event->name, AUDIO_TYPE_FMT_STR(MAX_AUDIO_TYPE_LEN), audioTypeName);
1095 INFO_LOG("XML File chanegd (%s)\n", event->name);
1096
1097 audioType = appHandleGetAudioTypeByName(appHandle, audioTypeName);
1098 if (audioType)
1099 {
1100 audioType->allowReload = 1;
1101 }
1102
1103 /* notify users */
1104 INFO_LOG("Notify all callback function.\n");
1105 LL_FOREACH(appHandle->noficyCbList, notifyCb)
1106 {
1107 INFO_LOG("Notify callback function. (0x%p, %pf)\n", notifyCb->cb, notifyCb->cb);
1108 (*notifyCb->cb)(appHandle, audioTypeName);
1109 }
1110 }
1111 }
1112 }
1113
1114 inotify_rm_watch(appHandle->inotifyFd, IN_CLOSE_NOWRITE);
1115
1116 if (appHandle->inotifyFd)
1117 {
1118 INFO_LOG("close inotify handle %d\n", appHandle->inotifyFd);
1119 close(appHandle->inotifyFd);
1120 }
1121
1122 INFO_LOG("appHandleThreadLoop exit\n");
1123 return NULL;
1124#endif
1125}
1126
1127EXPORT APP_STATUS appHandleReloadAudioType(AppHandle *appHandle, const char *audioTypeName)
1128{
1129 /* Release old audioType */
1130 char *audioTypeFile;
1131 AudioType *audioType;
1132
1133 INFO_LOG("appHandle = 0x%p, audioTypeName = %s\n", appHandle, audioTypeName);
1134
1135 audioType = appHandleGetAudioTypeByName(appHandle, audioTypeName);
1136 if (!audioType)
1137 {
1138 ERR_LOG("Invalid AudioType name = %s\n", audioTypeName);
1139 return APP_ERROR;
1140 }
1141
1142 /* Write lock */
1143 audioTypeWriteLock(audioType, __FUNCTION__);
1144
1145 /* Checking if the audioType reloaded */
1146 if (!audioType->allowReload)
1147 {
1148 INFO_LOG("AudioType is already reloaded!\n");
1149 audioTypeUnlock(audioType);
1150 return APP_NO_ERROR;
1151 }
1152
1153 /* Release audio param data */
1154 audioTypeReleaseAudioParam(audioType);
1155 /* Release audio param xml */
1156 if (audioType->audioParamDoc)
1157 {
1158 xmlFreeDoc(audioType->audioParamDoc);
1159 }
1160
1161 /* Load AudioParam XML */
1162 audioTypeFile = appHandleGetAudioTypeFilePath(appHandle, audioType->name, AUDIO_PARAM_XML_POSFIX);
1163 if (audioTypeFile == NULL)
1164 {
1165 WARN_LOG("The AudioTypeFile(%s%s) doesn't exist.\n", audioType->name, AUDIO_PARAM_XML_POSFIX);
1166 audioTypeUnlock(audioType);
1167 return APP_ERROR;
1168 }
1169
1170 audioType->audioParamDoc = xmlParseFile(audioTypeFile);
1171 if (audioType->audioParamDoc == NULL)
1172 {
1173 ERR_LOG("Failed to parse %s\n", audioTypeFile);
1174 free(audioTypeFile);
1175 audioTypeUnlock(audioType);
1176 return APP_ERROR;
1177 }
1178 else
1179 {
1180 INFO_LOG("Load xml file successfully. (%s)\n", audioTypeFile);
1181 }
1182
1183 free(audioTypeFile);
1184
1185 /* Load AudioParam hash */
1186 if (audioTypeLoadParamUnitHash(audioType) == APP_ERROR)
1187 {
1188 audioTypeUnlock(audioType);
1189 return APP_ERROR;
1190 }
1191
1192 if (audioTypeLoadParamTreeHash(audioType) == APP_ERROR)
1193 {
1194 audioTypeUnlock(audioType);
1195 return APP_ERROR;
1196 }
1197
1198 /* AudioType reloaded */
1199 audioType->allowReload = 0;
1200
1201 audioTypeUnlock(audioType);
1202 return APP_NO_ERROR;
1203}
1204
1205EXPORT const char *appHandleGetFeatureOptionValue(AppHandle *appHandle, const char *featureOptionName)
1206{
1207 FeatureOption *featureOption = NULL;
1208
1209 if (!appHandle)
1210 {
1211 ERR_LOG("appHandle is NULL\n");
1212 return NULL;
1213 }
1214
1215 if (!featureOptionName)
1216 {
1217 DEBUG_LOG("featureOptionName is NULL\n");
1218 return NULL;
1219 }
1220
1221 HASH_FIND_STR(appHandle->featureOptionsHash, featureOptionName, featureOption);
1222 if (featureOption)
1223 {
1224 return featureOption->value;
1225 }
1226
1227 return NULL;
1228}
1229
1230EXPORT int appHandleIsFeatureOptionEnabled(AppHandle *appHandle, const char *featureOptionName)
1231{
1232 const char *featureOptionValueStr;
1233 if (!appHandle)
1234 {
1235 WARN_LOG("appHandle is NULL\n");
1236 return 0;
1237 }
1238
1239 if (!featureOptionName)
1240 {
1241 WARN_LOG("featureOptionName is NULL\n");
1242 return 0;
1243 }
1244
1245 featureOptionValueStr = appHandleGetFeatureOptionValue(appHandle, featureOptionName);
1246 if (featureOptionValueStr)
1247 {
1248 return !strcmp(featureOptionValueStr, "yes");
1249 }
1250 else
1251 {
1252 DEBUG_LOG("No %s such feature option\n", featureOptionName);
1253 return 0;
1254 }
1255}
1256
1257EXPORT size_t appHandleGetNumOfFeatureOption(AppHandle *appHandle)
1258{
1259 if (!appHandle)
1260 {
1261 ERR_LOG("appHandle is NULL!\n");
1262 return APP_ERROR;
1263 }
1264
1265 return HASH_COUNT(appHandle->featureOptionsHash);
1266}
1267
1268EXPORT FeatureOption *appHandleGetFeatureOptionByIndex(AppHandle *appHandle, size_t index)
1269{
1270 FeatureOption *featureOption = NULL;
1271 size_t i = 0;
1272
1273 if (!appHandle)
1274 {
1275 ERR_LOG("appHandle is NULL\n");
1276 return NULL;
1277 }
1278
1279 for (featureOption = appHandle->featureOptionsHash; featureOption ; featureOption = featureOption->hh.next)
1280 {
1281 if (index == i++)
1282 {
1283 return featureOption;
1284 }
1285 }
1286
1287 return NULL;
1288}
1289
1290/* This function is only work for windows */
1291EXPORT void appHandleRedirectIOToConsole()
1292{
1293 INFO_LOG("");
1294#ifdef WIN32
1295 outputLogToStdout = 1;
1296 redirectIOToConsole();
1297#endif
1298}
1299
1300int removeNodeByFeatureOption(AppHandle *appHandle, xmlNode *categoryNode)
1301{
1302 /* Process Category of CategoryTpe Node */
1303 xmlChar *featureOption = xmlNodeGetProp(categoryNode, ATTRI_FEATURE_OPTION);
1304 if (featureOption)
1305 {
1306 int Not = 0;
1307 if (featureOption[0] == '!')
1308 {
1309 Not = 1;
1310 featureOption++;
1311 }
1312
1313 if (!(Not ^ appHandleIsFeatureOptionEnabled(appHandle, (char *)featureOption)))
1314 {
1315 xmlNode *deleteNode = categoryNode;
1316 categoryNode = categoryNode->next;
1317
1318 INFO_LOG("Remove %s category (%s feature option is disabled)\n", xmlNodeGetProp(deleteNode, ATTRI_NAME), featureOption);
1319 xmlUnlinkNode(deleteNode);
1320 xmlFreeNode(deleteNode);
1321 return 1;
1322 }
1323 }
1324
1325 return 0;
1326}
1327
1328EXPORT void appHandleReviseXmlDocByFeatureOptions(AppHandle *appHandle)
1329{
1330 // Travel all audioType's category & category group node
1331 size_t i;
1332 size_t numOfAppHandle = appHandleGetNumOfAudioType(appHandle);
1333 for (i = 0; i < numOfAppHandle; i++)
1334 {
1335 xmlNode *categoryTypeListNode, *categoryTypeNode, *categoryGroupNode, *categoryNode, *prevCategoryGroupNode, *prevCategoryNode, *prevCategoryTypeNode;
1336 AudioType *audioType = appHandleGetAudioTypeByIndex(appHandle, i);
1337 categoryTypeListNode = audioTypeGetCategoryTypeListNode(audioType);
1338 if (!categoryTypeListNode)
1339 {
1340 continue;
1341 }
1342
1343 categoryTypeNode = categoryTypeListNode->children;
1344 while ((categoryTypeNode = findXmlNodeByElemName(categoryTypeNode->next, ELEM_CATEGORY_TYPE)))
1345 {
1346 prevCategoryTypeNode = categoryTypeNode->prev;
1347 if (removeNodeByFeatureOption(appHandle, categoryTypeNode))
1348 {
1349 categoryTypeNode = prevCategoryTypeNode;
1350 continue;
1351 }
1352
1353 /* Process CategoryType node */
1354 categoryGroupNode = categoryTypeNode->children;
1355 while ((categoryGroupNode = findXmlNodeByElemName(categoryGroupNode->next, ELEM_CATEGORY_GROUP)))
1356 {
1357 /* Process CategoryGroup of CategoryType Node */
1358 prevCategoryGroupNode = categoryGroupNode->prev;
1359 if (removeNodeByFeatureOption(appHandle, categoryGroupNode))
1360 {
1361 categoryGroupNode = prevCategoryGroupNode;
1362 continue;
1363 }
1364
1365 categoryNode = categoryGroupNode->children;
1366 while ((categoryNode = findXmlNodeByElemName(categoryNode->next, ELEM_CATEGORY)))
1367 {
1368 /* Process Category of CategoryGroup Node */
1369 prevCategoryNode = categoryNode->prev;
1370 if (removeNodeByFeatureOption(appHandle, categoryNode))
1371 {
1372 categoryNode = prevCategoryNode;
1373 }
1374 }
1375 }
1376
1377 categoryNode = categoryTypeNode->children;
1378 while ((categoryNode = findXmlNodeByElemName(categoryNode->next, ELEM_CATEGORY)))
1379 {
1380 prevCategoryNode = categoryNode->prev;
1381 if (removeNodeByFeatureOption(appHandle, categoryNode))
1382 {
1383 categoryNode = prevCategoryNode;
1384 }
1385 }
1386 }
1387 }
1388}
1389
1390EXPORT APP_STATUS appHandleCompressFiles(const char* srcDir, const char* destFile)
1391{
1392#ifdef WIN32
1393 INFO_LOG("%s(), src = %s, dest = %s\n", __FUNCTION__, srcDir, destFile);
1394 if (!srcDir || !destFile)
1395 {
1396 ERR_LOG("%s(), srcDir or destFile is NULL\n", __FUNCTION__);
1397 return APP_ERROR;
1398 } else {
1399 UT_string *path = NULL;
1400 utstring_new(path);
1401 utstring_printf(path, "a -tzip %s %s\\*", destFile, srcDir);
1402 utilShellExecute("7za.exe", utstring_body(path));
1403 utstring_free(path);
1404 }
1405#else
1406 ERR_LOG("Not support on linux\n");
1407#endif
1408 return APP_NO_ERROR;
1409}
1410
1411EXPORT APP_STATUS appHandleUncompressFile(const char* srcFile, const char* destDir)
1412{
1413#ifdef WIN32
1414 INFO_LOG("%s(), src = %s, dest = %s\n", __FUNCTION__, srcFile, destDir);
1415 if (!srcFile || !destDir)
1416 {
1417 ERR_LOG("%s(), srcFile or destDir is NULL\n", __FUNCTION__);
1418 return APP_ERROR;
1419 } else {
1420 UT_string *path = NULL;
1421 utstring_new(path);
1422 utstring_printf(path, "x %s -y -o%s\\", srcFile, destDir);
1423 utilShellExecute("7za.exe", utstring_body(path));
1424 utstring_free(path);
1425 }
1426#else
1427 ERR_LOG("Not support on linux\n");
1428#endif
1429 return APP_NO_ERROR;
1430}
1431
1432EXPORT APP_STATUS appHandleGetAudioTypeSupportedVerInfo(const char* audioTypeName, int* paramUnitDescVerMaj, int* paramUnitDescVerMin, int* audioParamVerMaj, int* audioParamVerMin)
1433{
1434 int i = 0;
1435 while(audioTypeSupportVerInfo[i].audioTypeName != NULL)
1436 {
1437 if (!strcmp(audioTypeName, audioTypeSupportVerInfo[i].audioTypeName))
1438 {
1439 *paramUnitDescVerMaj = audioTypeSupportVerInfo[i].paramUnitDescVerMaj;
1440 *paramUnitDescVerMin = audioTypeSupportVerInfo[i].paramUnitDescVerMin;
1441 *audioParamVerMaj = audioTypeSupportVerInfo[i].audioParamVerMaj;
1442 *audioParamVerMin = audioTypeSupportVerInfo[i].audioParamVerMin;
1443 return APP_NO_ERROR;
1444 }
1445 i++;
1446 }
1447
1448 ERR_LOG("%s AudioType version support info not found!\n", audioTypeName);
1449 return APP_ERROR;
1450}
1451
1452EXPORT void appHandleShowAudioTypeSupportedVerInfo(AppHandle* appHandle)
1453{
1454 int i = 0;
1455 INFO_LOG("=======================\n");
1456 while(audioTypeSupportVerInfo[i].audioTypeName != NULL)
1457 {
1458 INFO_LOG("[%d] %s, ParamUnitDesc ver(%d.%d), AudioParam ver(%d.%d)\n",
1459 i,
1460 audioTypeSupportVerInfo[i].audioTypeName, audioTypeSupportVerInfo[i].paramUnitDescVerMaj,
1461 audioTypeSupportVerInfo[i].paramUnitDescVerMin, audioTypeSupportVerInfo[i].audioParamVerMaj, audioTypeSupportVerInfo[i].audioParamVerMin);
1462 i++;
1463 }
1464}