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