Files
2026-08-24 10:03:24 +08:00

671 lines
23 KiB
C

/*
* Copyright (C) 2025 Amlogic Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "audio_mpegh"
//#define LOG_NDEBUG 0
#include <stdint.h>
#include <stddef.h>
#include <cutils/str_parms.h>
#include <cutils/properties.h>
#include "audio_buffer.h"
#include "audio_hw.h"
#include "audio_mpegh.h"
#include "aml_mpegh_uimanager.h"
#include "aml_audio_log.h"
#include "aml_dump_debug.h"
#include "aml_malloc_debug.h"
#include "aml_audio_stream.h"
#define AML_MPEGH_BASE64_BUFSIZE ((AML_MPEGH_PERSISTENCE_BUFSIZE + 2) / 3) * 4
#define AML_MPEGH_UIMANAGER_PROP_DUMP_FLAG "vendor.media.audio.mpegh.uimanager.dump"
#define AML_MPEGH_UIMANAGER_PROP_DEBUG_FLAG "vendor.media.audio.mpegh.uimanager.debug"
typedef struct ActionEventNode {
char* event;
struct ActionEventNode* next;
} ActionEventNode;
typedef struct {
ActionEventNode* head;
ActionEventNode* tail;
size_t size;
} ActionEventQueue;
typedef struct KeyValue {
char* key;
char* value;
struct KeyValue* next;
} KeyValue;
static KeyValue* uiManagerSystemSetting = NULL;
static ActionEventQueue g_actionQueue = {NULL, NULL, 0};
int str_parms_has_key(struct str_parms *str_parms, const char *key);
static KeyValue* findKey(const char* key) {
if (key == NULL || *key == '\0') {
AM_LOGE("findKey: invalid key (NULL or empty)!");
return NULL;
}
KeyValue* current = uiManagerSystemSetting;
while (current != NULL) {
if (strcmp(current->key, key) == 0) {
return current;
}
current = current->next;
}
return NULL;
}
static void freeKeyValue(KeyValue* kv) {
if (kv == NULL) return;
aml_audio_free(kv->key);
aml_audio_free(kv->value);
aml_audio_free(kv);
}
int saveMpeghSysActioneventXml(const char* key, const char* value) {
if (key == NULL || key[0] == '\0' || value == NULL) {
return -1;
}
KeyValue* existing = findKey(key);
if (existing != NULL) {
aml_audio_free(existing->value);
existing->value = strdup(value);
if (existing->value == NULL) {
return -1;
}
return 0;
} else {
KeyValue* newNode = (KeyValue*)aml_audio_malloc(sizeof(KeyValue));
if (newNode == NULL) {
return -1;
}
newNode->key = strdup(key);
newNode->value = strdup(value);
if (newNode->key == NULL || newNode->value == NULL) {
freeKeyValue(newNode);
return -1;
}
newNode->next = uiManagerSystemSetting;
uiManagerSystemSetting = newNode;
return 0;
}
}
void freeUiManagerSystemSetting() {
KeyValue* current = uiManagerSystemSetting;
while (current != NULL) {
KeyValue* next = current->next;
freeKeyValue(current);
current = next;
}
uiManagerSystemSetting = NULL;
}
const char *mpeghSystemActionEventXml[] = {
"<ActionEvent uuid=\"00000000-0000-0000-0000-000000000000\" version=\"11.0\" actionType=\"70\" paramInt=\"0\" paramText=\"%s\"/>",
"<ActionEvent uuid=\"00000000-0000-0000-0000-000000000000\" version=\"11.0\" actionType=\"71\" paramInt=\"0\" paramText=\"%s\"/>",
"<ActionEvent uuid=\"00000000-0000-0000-0000-000000000000\" version=\"11.0\" actionType=\"12\" paramFloat=\"%s\"/>",
"<ActionEvent uuid=\"00000000-0000-0000-0000-000000000000\" version=\"11.0\" actionType=\"31\" paramInt=\"%s\"/>",
"<ActionEvent uuid=\"00000000-0000-0000-0000-000000000000\" version=\"11.0\" actionType=\"10\" paramInt=\"%s\"/>",
"<ActionEvent uuid=\"00000000-0000-0000-0000-000000000000\" version=\"11.0\" actionType=\"21\" paramBool=\"%s\"/>",
"<ActionEvent uuid=\"00000000-0000-0000-0000-000000000000\" version=\"11.0\" actionType=\"11\" paramFloat=\"%s\"/>",
"<ActionEvent uuid=\"00000000-0000-0000-0000-000000000000\" version=\"11.0\" actionType=\"20\" paramFloat=\"%s\"/>"
};
static const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int aml_mpegh_base64_encode(const unsigned char* input, int input_length, struct aml_audio_device *adev) {
if (!input || !input_length || !adev) {
ALOGE("%s parameters invalid", __func__);
return -1;
}
int enc_len = 4 * ((input_length + 2) / 3);
adev->mpegh_base64_encode_mem = aml_audio_realloc(adev->mpegh_base64_encode_mem, enc_len + 1);
char * enc_buf = (char*)adev->mpegh_base64_encode_mem;
int i, j = 0;
for (i = 0; i < input_length; i += 3) {
int val = (input[i] << 16);
if (i + 1 < input_length) {
val |= (input[i + 1] << 8);
}
if (i + 2 < input_length) {
val |= input[i + 2];
}
enc_buf[j++] = base64_table[(val >> 18) & 0x3F];
enc_buf[j++] = base64_table[(val >> 12) & 0x3F];
enc_buf[j++] = (i + 1 < input_length) ? base64_table[(val >> 6) & 0x3F] : '=';
enc_buf[j++] = (i + 2 < input_length) ? base64_table[val & 0x3F] : '=';
}
enc_buf[j] = '\0';
return 0;
}
int base64_decode(char* input, int input_length, struct aml_audio_device *adev) {
if (!input || !input_length || !adev) {
ALOGE("%s input param invalid", __func__);
return -1;
}
if (input_length % 4 != 0) {
ALOGE("%s input length not a multiple of 4", __func__);
return -1;
}
int output_len = input_length / 4 * 3;
if (input_length > 0 && input[input_length - 1] == '=') output_len--;
if (input_length > 1 && input[input_length - 2] == '=') output_len--;
//The size of the persistencemem must be a multiple of 1024.
if (output_len % 1024) {
output_len -= (output_len % 1024);
}
ALOGI("%s input_length = %d, output_len = %d", __func__, input_length, output_len);
unsigned char* decoded_data = (unsigned char*)adev->mpegh_ui_persistencemem;
unsigned char decoding_table[256];
memset(decoding_table, 0xFF, 256);
for (int i = 0; i < 64; i++) {
decoding_table[(unsigned char)base64_table[i]] = i;
}
for (int i = 0, j = 0; i < input_length;) {
unsigned char a = input[i] == '=' ? 0 & i++ : decoding_table[(unsigned char)input[i++]];
unsigned char b = input[i] == '=' ? 0 & i++ : decoding_table[(unsigned char)input[i++]];
unsigned char c = input[i] == '=' ? 0 & i++ : decoding_table[(unsigned char)input[i++]];
unsigned char d = input[i] == '=' ? 0 & i++ : decoding_table[(unsigned char)input[i++]];
if (a == 0xFF || b == 0xFF || c == 0xFF || d == 0xFF) {
return -1;
}
uint32_t triple = (a << 3 * 6) | (b << 2 * 6) | (c << 1 * 6) | (d << 0 * 6);
if (j < output_len) decoded_data[j++] = (unsigned char)((triple >> 2 * 8) & 0xFF);
if (j < output_len) decoded_data[j++] = (unsigned char)((triple >> 1 * 8) & 0xFF);
if (j < output_len) decoded_data[j++] = (unsigned char)((triple >> 0 * 8) & 0xFF);
}
return 0;
}
int aml_mpegh_applyxmlaction(struct aml_audio_device *adev, char *xmlstr, int xmlsize)
{
struct aml_stream_out *aml_out = NULL;
int ret = -1;
AM_LOGI("enter:xmlsize:%d", xmlsize);
AM_LOGV("xmlinstr::\r\n%s\r\n", xmlstr);
for (int i = 0 ; i < STREAM_NUM_MAX; i++) {
aml_out = adev->active_outputs[i];
if (aml_out && (AUDIO_FORMAT_MPEGH == aml_out->hal_internal_format)) {
AM_LOGI("got mpegh stream: aml_out:%p format:0x%x", aml_out, aml_out->hal_internal_format);
mpegh_uimanager_oper_t *uioper = aml_out->mpegh_uimanager_handle;
int flagsout = 0;
ret = aml_mpegh_uimanager_applyxmlaction(uioper, xmlstr, xmlsize, &flagsout);
break;
}
}
return ret;
}
int assembleMpeghSystemActionEventXml(int key, char* value, char **xmlbuf)
{
if (key < 0 || key > 7 || !value || !xmlbuf) {
AM_LOGI("Invalid param key:%d, value:%p, xmlbuf:%p\n", key, value, (void *)xmlbuf);
return -1;
}
int len = snprintf(NULL, 0, mpeghSystemActionEventXml[key], value) + 1;
*xmlbuf = (char *)aml_audio_malloc(len);
if (!*xmlbuf) return -1;
snprintf(*xmlbuf, len, mpeghSystemActionEventXml[key], value);
return 0;
}
void initActionEventQueue() {
g_actionQueue.head = NULL;
g_actionQueue.tail = NULL;
g_actionQueue.size = 0;
}
void addNewActionEvent(char* event) {
if (event == NULL) {
return;
}
ActionEventNode* newNode = (ActionEventNode*)aml_audio_malloc(sizeof(ActionEventNode));
if (newNode == NULL) {
AM_LOGI("no memory for new node.");
return;
}
newNode->event = (char*)aml_audio_malloc(strlen(event) + 1);
if (newNode->event == NULL) {
AM_LOGI("event memory alloc fail.");
aml_audio_free(newNode);
return;
}
strcpy(newNode->event, event);
newNode->next = NULL;
if (g_actionQueue.tail == NULL) {
g_actionQueue.head = newNode;
g_actionQueue.tail = newNode;
} else {
g_actionQueue.tail->next = newNode;
g_actionQueue.tail = newNode;
}
g_actionQueue.size++;
AM_LOGI("ActionEventQueue size = %zu", g_actionQueue.size);
}
int isActionEventQueueEmpty() {
return (g_actionQueue.size == 0) ? 1 : 0;
}
char* getActionEventQueueFront() {
if (isActionEventQueueEmpty()) {
return NULL;
}
return g_actionQueue.head->event;
}
void popActionEventQueue() {
if (isActionEventQueueEmpty()) {
return;
}
ActionEventNode* temp = g_actionQueue.head;
g_actionQueue.head = g_actionQueue.head->next;
if (!g_actionQueue.head) {
g_actionQueue.tail = NULL;
}
aml_audio_free(temp->event);
aml_audio_free(temp);
g_actionQueue.size--;
}
void destroyActionEventQueue() {
ActionEventNode* current = g_actionQueue.head;
while (current != NULL) {
ActionEventNode* next = current->next;
aml_audio_free(current->event);
aml_audio_free(current);
current = next;
}
initActionEventQueue();
}
int aml_mpegh_savepersistencememory(struct aml_audio_device *adev, void *persistencemem, int persistencememsize)
{
if (!persistencemem || persistencememsize <= 0)
return -1;
memset(adev->mpegh_ui_persistencemem, 0, adev->mpegh_ui_persistencememsize);
int ret = base64_decode((char *)persistencemem, persistencememsize, adev);
if (ret < 0) {
AM_LOGE("base64 decode error");
return -1;
}
return 0;
}
bool aml_get_is_exist_active_mpegh_stream(struct aml_audio_device *adev)
{
struct aml_stream_out *aml_out = NULL;
bool retValue = false;
for (int i = 0 ; i < STREAM_NUM_MAX; i++) {
aml_out = adev->active_outputs[i];
if (aml_out && !(aml_out->standby) && is_mpegh_format(aml_out->hal_internal_format)) {
retValue = true;
break;
}
}
AM_LOGI("aml_out:%p, retValue:%d", aml_out, retValue);
return retValue;
}
static int getActionType(const char* xml) {
if (xml == NULL || *xml == '\0') {
AM_LOGE("XML string is NULL or empty");
return -1;
}
const char* key = "actionType=\"";
const char* pos = strstr(xml, key);
if (pos == NULL) {
AM_LOGE("Not found actionType");
return -1;
}
pos += strlen(key);
const char* end = strchr(pos, '"');
if (end == NULL) {
AM_LOGE("Actionevent format error (missing end quote)");
return -1;
}
size_t val_len = end - pos;
char* valueStr = (char*)malloc(val_len + 1); // +1 用于 '\0'
if (valueStr == NULL) {
AM_LOGE("Malloc failed (out of memory)");
return -1;
}
strncpy(valueStr, pos, val_len);
valueStr[val_len] = '\0';
char* converted = NULL;
errno = 0;
long value = strtol(valueStr, &converted, 10);
int ret = -1;
if (valueStr == converted) {
AM_LOGE("actionType is not a valid number");
} else if (errno == ERANGE) {
AM_LOGE("actionType out of range (overflow)");
} else if (value < 0 || value > 90) {
AM_LOGE("actionType invalid (value=%ld, must be 0-90)", value);
} else {
ret = (int)value;
AM_LOGE("actionType = %d", ret);
}
free(valueStr);
valueStr = NULL;
return ret;
}
int aml_mpegh_process(void **mpegh_uimanager_handle,
struct audio_buffer *abuffer, int *asiupdate)
{
struct audio_buffer *abuffer_out = abuffer;
struct aml_audio_device *adev = adev_get_handle();
void *mpegh_uiop = *mpegh_uimanager_handle;
int ret = -1;
int isupdate = 0;
AM_LOGV("enter");
if (NULL == mpegh_uimanager_handle) {
AM_LOGE("mpegh_uimanager_handle:%p, error!", mpegh_uimanager_handle);
goto exit;
}
if (false == check_audio_buffer_valid(abuffer)) {
AM_LOGE("audio buffer checked fail");
goto exit;
}
if (!mpegh_uiop) {
ret = aml_mpegh_uimanager_open(&mpegh_uiop);
if (ret != 0) {
AM_LOGE(" aml_mpegh_uimanager_open fail, ret:%d, mpegh_uimanager_handle:%p", ret, mpegh_uiop);
goto exit;
}
*mpegh_uimanager_handle = mpegh_uiop;
//set persistency ctx
if (adev->mpegh_ui_persistencemem && adev->mpegh_ui_persistencememsize > 0) {
ret = aml_mpegh_uimanager_setpersistencememory(mpegh_uiop, (char*)adev->mpegh_ui_persistencemem, adev->mpegh_ui_persistencememsize);
if (ret != 0) {
AM_LOGE(" aml_mpegh_uimanager_setpersistencememory fail, ret:%d", ret);
}
}
//set system setting
KeyValue *current = uiManagerSystemSetting;
while (current != NULL) {
char *system_setting_xml = current->value;
aml_mpegh_applyxmlaction(adev, system_setting_xml, strlen(system_setting_xml));
current = current->next;
}
}
while (!isActionEventQueueEmpty()) {
char* xml = getActionEventQueueFront();
if (xml) {
aml_mpegh_applyxmlaction(adev, xml, strlen(xml));
}
popActionEventQueue();
}
ret = aml_mpegh_uimanager_feedmhas(mpegh_uiop, abuffer_out->buffer, abuffer_out->size);
if (ret != 0) {
AM_LOGE(" aml_mpegh_uimanager_feedmhas fail, ret:%d", ret);
goto exit;
}
void *outbuf = NULL;
int outlen = 0;
ret = aml_mpegh_uimanager_updatemhas(mpegh_uiop,
abuffer_out->buffer, abuffer_out->size, &outbuf, &outlen);
if (ret > 0 && ret != MPEGH_UI_NOT_ALLOWED) {
AM_LOGE(" aml_mpegh_uimanager_updatemhas fail, ret:%d", ret);
goto exit;
}
abuffer_out->buffer = outbuf;
abuffer_out->size = outlen;
if (MPEGH_UI_OK == ret) {
ret = aml_mpegh_uimanager_getxmlscenestate(mpegh_uiop, &isupdate);
if ((0 == ret) && (1 == isupdate)) {
mpegh_uimanager_oper_t *uioper = mpegh_uiop;
AM_LOGI("getxml::::\r\n%s \r\n ::::end", uioper->xmloutbuf);
*asiupdate = 1;
if (get_debug_value(AML_DUMP_AUDIOHAL_IN)) {
static int count = 0;
aml_dump_audio_bitstreams_with_id("xmlscenestate.txt", uioper->xmloutbuf, strlen(uioper->xmloutbuf), count++);
}
}
}
exit:
return ret;
}
int aml_mpegh_close(struct aml_audio_device *adev, void *handle)
{
AM_LOGI("enter!");
if (!handle || !adev) {
AM_LOGE("NULL handle or adev");
return -1;
}
mpegh_uimanager_oper_t * uioper = (mpegh_uimanager_oper_t *) handle;
aml_mpegh_uimanager_getpersistencememory(uioper, &adev->mpegh_ui_persistencemem, &adev->mpegh_ui_persistencememsize);
if (property_get_bool(AML_MPEGH_UIMANAGER_PROP_DUMP_FLAG, 0) && adev->mpegh_ui_persistencememsize) {
aml_dump_audio_bitstreams("mpegh_ui_persistency.txt", adev->mpegh_ui_persistencemem, adev->mpegh_ui_persistencememsize);
}
aml_mpegh_uimanager_close(uioper);
return 0;
}
char *aml_mpegh_getxmlsceneinfo(struct aml_audio_device *adev)
{
struct aml_stream_out *aml_out = NULL;
mpegh_uimanager_oper_t *uioper = NULL;
AM_LOGI("enter");
for (int i = 0 ; i < STREAM_NUM_MAX; i++) {
aml_out = adev->active_outputs[i];
if (aml_out && (AUDIO_FORMAT_MPEGH == aml_out->hal_internal_format)) {
uioper = aml_out->mpegh_uimanager_handle;
AM_LOGI("got mpegh stream:aml_out:%p format:0x%x, uioper:%p", aml_out, aml_out->hal_internal_format, uioper);
break;
}
}
if ((NULL == uioper) || (NULL == uioper->xmloutbuf)) {
return NULL;
}
AM_LOGV("xmloutstr::\r\n%s\r\n", uioper->xmloutbuf);
return uioper->xmloutbuf;
}
int set_mpegh_parameters(struct aml_audio_device *adev, struct str_parms *parms)
{
int ret = -1;
int actionType = -1;
char value[128] = {'\0'};
//view setting
ret = str_parms_get_str(parms, "mpegh_action_event", value, sizeof(value));
if (ret >= 0) {
actionType = getActionType(value);
if (actionType == 0) {
memset(adev->mpegh_audioscenexml, 0, adev->mpegh_audioscenexmlsize);
AM_LOGI("mpegh reset, clear mpegh_audioscenexml!");
}
//save event to queue
addNewActionEvent(value);
return ret;
}
//set persistency ctx
if (str_parms_has_key(parms, "mpegh_persistency_ctx")) {
char *mpegh_persictency_buf = (char *)aml_audio_calloc(1, (AML_MPEGH_BASE64_BUFSIZE + 1));
ret = str_parms_get_str(parms, "mpegh_persistency_ctx", mpegh_persictency_buf, (AML_MPEGH_BASE64_BUFSIZE + 1));
if (ret >= 0) {
ret = aml_mpegh_savepersistencememory(adev, (void*)mpegh_persictency_buf, AML_MPEGH_BASE64_BUFSIZE);
AM_LOGD("set mpegh persistency ctx:, ret:%d", ret);
}
aml_audio_free(mpegh_persictency_buf);
mpegh_persictency_buf = NULL;
return ret;
}
//system setting
ret = str_parms_get_str(parms, "mpegh_audio_lang", value, sizeof(value));
if (ret >= 0) {
//Splicing system actionevent XML
char * mpegh_action_event = NULL;
ret = assembleMpeghSystemActionEventXml(AML_MPEGH_AUDIO_LANG, value, &mpegh_action_event);
//store system setting to queue when exist active mpegh stream.
if (aml_get_is_exist_active_mpegh_stream(adev)) {
addNewActionEvent(mpegh_action_event);
}
//store or update system setting
if (mpegh_action_event) {
saveMpeghSysActioneventXml("mpegh_audio_lang", mpegh_action_event);
}
aml_audio_free(mpegh_action_event);
mpegh_action_event = NULL;
return ret;
}
ret = str_parms_get_str(parms, "mpegh_label_lang", value, sizeof(value));
if (ret >= 0) {
char * mpegh_action_event = NULL;
ret = assembleMpeghSystemActionEventXml(AML_MPEGH_LABEL_LANG, value, &mpegh_action_event);
if (aml_get_is_exist_active_mpegh_stream(adev)) {
addNewActionEvent(mpegh_action_event);
}
if (mpegh_action_event) {
saveMpeghSysActioneventXml("mpegh_label_lang", mpegh_action_event);
}
aml_audio_free(mpegh_action_event);
mpegh_action_event = NULL;
return ret;
}
ret = str_parms_get_str(parms, "mpegh_drc_att", value, sizeof(value));
if (ret >= 0) {
char * mpegh_action_event = NULL;
ret = assembleMpeghSystemActionEventXml(AML_MPEGH_DRC_ATT, value, &mpegh_action_event);
if (aml_get_is_exist_active_mpegh_stream(adev)) {
addNewActionEvent(mpegh_action_event);
}
if (mpegh_action_event) {
saveMpeghSysActioneventXml("mpegh_drc_att", mpegh_action_event);
}
aml_audio_free(mpegh_action_event);
mpegh_action_event = NULL;
return ret;
}
ret = str_parms_get_str(parms, "mpegh_accessibility", value, sizeof(value));
if (ret >= 0) {
char * mpegh_action_event = NULL;
ret = assembleMpeghSystemActionEventXml(AML_MPEGH_ACCESSIBILITY, value, &mpegh_action_event);
if (aml_get_is_exist_active_mpegh_stream(adev)) {
addNewActionEvent(mpegh_action_event);
}
if (mpegh_action_event) {
saveMpeghSysActioneventXml("mpegh_accessibility", mpegh_action_event);
}
aml_audio_free(mpegh_action_event);
mpegh_action_event = NULL;
return ret;
}
ret = str_parms_get_str(parms, "mpegh_drc_effect", value, sizeof(value));
if (ret >= 0) {
char * mpegh_action_event = NULL;
ret = assembleMpeghSystemActionEventXml(AML_MPEGH_DRC_EFFECT, value, &mpegh_action_event);
if (aml_get_is_exist_active_mpegh_stream(adev)) {
addNewActionEvent(mpegh_action_event);
}
if (mpegh_action_event) {
saveMpeghSysActioneventXml("mpegh_drc_effect", mpegh_action_event);
}
aml_audio_free(mpegh_action_event);
mpegh_action_event = NULL;
return ret;
}
ret = str_parms_get_str(parms, "mpegh_drc_album", value, sizeof(value));
if (ret >= 0) {
char * mpegh_action_event = NULL;
ret = assembleMpeghSystemActionEventXml(AML_MPEGH_DRC_ALBUM, value, &mpegh_action_event);
if (aml_get_is_exist_active_mpegh_stream(adev)) {
addNewActionEvent(mpegh_action_event);
}
if (mpegh_action_event) {
saveMpeghSysActioneventXml("mpegh_drc_album", mpegh_action_event);
}
aml_audio_free(mpegh_action_event);
mpegh_action_event = NULL;
return ret;
}
ret = str_parms_get_str(parms, "mpegh_drc_boost", value, sizeof(value));
if (ret >= 0) {
char * mpegh_action_event = NULL;
ret = assembleMpeghSystemActionEventXml(AML_MPEGH_DRC_BOOST, value, &mpegh_action_event);
if (aml_get_is_exist_active_mpegh_stream(adev)) {
addNewActionEvent(mpegh_action_event);
}
if (mpegh_action_event) {
saveMpeghSysActioneventXml("mpegh_drc_boost", mpegh_action_event);
}
aml_audio_free(mpegh_action_event);
mpegh_action_event = NULL;
return ret;
}
ret = str_parms_get_str(parms, "mpegh_tl", value, sizeof(value));
if (ret >= 0) {
char * mpegh_action_event = NULL;
ret = assembleMpeghSystemActionEventXml(AML_MPEGH_TL, value, &mpegh_action_event);
if (aml_get_is_exist_active_mpegh_stream(adev)) {
addNewActionEvent(mpegh_action_event);
}
if (mpegh_action_event) {
saveMpeghSysActioneventXml("mpegh_tl", mpegh_action_event);
}
aml_audio_free(mpegh_action_event);
mpegh_action_event = NULL;
return ret;
}
return ret;
}