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