438 lines
13 KiB
C++
438 lines
13 KiB
C++
/*
|
|
* Copyright 2023 Rockchip Electronics Co. LTD
|
|
*
|
|
* 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.
|
|
*
|
|
* author: hh@rock-chips.com
|
|
* date: 2023/03/10
|
|
* module: RKAudioSetting
|
|
*/
|
|
|
|
//#define LOG_NDEBUG 0
|
|
#define LOG_TAG "RkAudioXmlParser"
|
|
|
|
#include <log/log.h>
|
|
#include "RkAudioXmlParser.h"
|
|
|
|
namespace android {
|
|
|
|
//#############audio settting configs##############
|
|
//<sound>
|
|
// <decode setting="yes">
|
|
// ......
|
|
// </decode>
|
|
// <bitstream setting="yes"> # yes means bistream enable, no means bistream disable
|
|
// <mode>auto</mode> # auto means get formats by edid of hdmi
|
|
// <devices>
|
|
// <device>hdmi</device> # passthrough device(spdif or hdmi)
|
|
// </devices>
|
|
// <formats>
|
|
// <format>AC3</format> # formats support to bistream
|
|
// <format>DTS</format>
|
|
// ......
|
|
// </formats>
|
|
// </bitstream>
|
|
//</sound>
|
|
//##################################################
|
|
|
|
// string tag in setting xml
|
|
#define ROOT "sound"
|
|
#define DECODE "decode"
|
|
#define BITSTREAM "bitstream"
|
|
#define MODE "mode"
|
|
#define SETTING "setting"
|
|
#define DEVICES "devices"
|
|
#define DEVICE "device"
|
|
#define FORMATS "formats"
|
|
#define FORMAT "format"
|
|
#define SPEAKER "speaker"
|
|
#define HDMI "hdmi"
|
|
#define SPDIF "spdif"
|
|
#define PCM "pcm"
|
|
#define PCM "pcm"
|
|
#define AUTO "auto"
|
|
#define MANUAL "manual"
|
|
#define ENABLE "yes"
|
|
#define DISABLE "no"
|
|
|
|
//formats tag in setting xml
|
|
#define AC3 "AC3"
|
|
#define EAC3 "EAC3"
|
|
#define EAC3_JOC "EAC3-JOC"
|
|
#define TRUEHD "TRUEHD"
|
|
#define MLP "MLP"
|
|
#define DTS "DTS"
|
|
#define DTSHD "DTSHD"
|
|
|
|
RKAudioXmlParser::RKAudioXmlParser() {
|
|
mXmlDoc = new XMLDocument();
|
|
mPath = new char[256];
|
|
mDevice = AUDIO_DEVICE_DECODE;
|
|
mMode = AUDIO_BITSTREAM_MODE_BUTT;
|
|
for (int i = 0; i < AUDIO_SETTING_FORMAT_BUTT; i++) {
|
|
mFormat[i] = AUDIO_SETTING_UNSUPPORT;
|
|
}
|
|
memset(mPath, 0, 256);
|
|
}
|
|
|
|
RKAudioXmlParser::~RKAudioXmlParser() {
|
|
if (mXmlDoc) {
|
|
delete mXmlDoc;
|
|
mXmlDoc = NULL;
|
|
}
|
|
|
|
if (mPath) {
|
|
delete[] mPath;
|
|
mPath = NULL;
|
|
}
|
|
}
|
|
|
|
int RKAudioXmlParser::load(const char *path) {
|
|
int ret = -1;
|
|
if (path && access(path, F_OK) >= 0) {
|
|
// load /data/system/rt_audio_config.xml
|
|
if (XML_SUCCESS != mXmlDoc->LoadFile(path)) {
|
|
ALOGD("load XML file error(%s)", mXmlDoc->ErrorStr());
|
|
ret = -1;
|
|
} else {
|
|
memcpy(mPath, path, strlen(path));
|
|
ret = readXml();
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool RKAudioXmlParser::isEnable(XMLElement *pEle) {
|
|
bool ret = false;
|
|
const XMLAttribute *mAttri = pEle->FirstAttribute();
|
|
if (mAttri) {
|
|
if (!strcmp(mAttri->Value(), ENABLE)) {
|
|
ret = true;
|
|
} else if (!strcmp(mAttri->Value(), DISABLE)) {
|
|
ret = false;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool RKAudioXmlParser::isFormatSupport(char* format) {
|
|
bool support = false;
|
|
int size = RkAudioSettingUtils::getFormatsArraySize();
|
|
for (int i = 0; i < size; i++) {
|
|
const AudioFormatMaps* maps = RkAudioSettingUtils::getFormatMapByIndex(i);
|
|
if (!strcmp(maps->name, format)) {
|
|
support = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return support;
|
|
}
|
|
|
|
int RKAudioXmlParser::readXml() {
|
|
XMLElement *pRoot = NULL;
|
|
XMLElement *pBitstream = NULL;
|
|
XMLElement *pElement = NULL;
|
|
|
|
pRoot = mXmlDoc->RootElement();
|
|
if (strcmp(pRoot->Value(), ROOT) != 0) {
|
|
ALOGE("load AudioSetting XML error, not contain<sound!>");
|
|
return -1;
|
|
}
|
|
|
|
// parser bitstream configs
|
|
pBitstream = pRoot->FirstChildElement(BITSTREAM);
|
|
if (pBitstream && isEnable(pBitstream)) {
|
|
// get the device, spdif or hdmi
|
|
pElement = pBitstream->FirstChildElement(DEVICES)->FirstChildElement(DEVICE);
|
|
if (pElement == NULL) {
|
|
ALOGE("%s: not find bistream node", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if (!strcmp(pElement->GetText(), HDMI)) {
|
|
mDevice = AUDIO_DEVICE_HDMI_BITSTREAM;
|
|
} else if (!strcmp(pElement->GetText(), SPDIF)) {
|
|
mDevice = AUDIO_DEVICE_SPDIF_PASSTHROUGH;
|
|
} else {
|
|
ALOGE("%s: device = %s is not support", __FUNCTION__, pElement->GetText());
|
|
return -1;
|
|
}
|
|
|
|
// read the bistream mode, auto or manual
|
|
mMode = readBitstreamMode(pBitstream);
|
|
// get support formats
|
|
readBitstreamFormats(pBitstream);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int RKAudioXmlParser::readBitstreamMode(XMLElement *pBitstream) {
|
|
XMLElement *pMode = pBitstream->FirstChildElement(MODE);
|
|
if (pMode) {
|
|
if (!strcmp(pMode->GetText(), MANUAL)) {
|
|
return AUDIO_BITSTREAM_MODE_MANUAL;
|
|
} else if (!strcmp(pMode->GetText(), AUTO)) {
|
|
return AUDIO_BITSTREAM_MODE_AUTO;
|
|
}
|
|
}
|
|
|
|
return AUDIO_BITSTREAM_MODE_BUTT;
|
|
}
|
|
|
|
void RKAudioXmlParser::readBitstreamFormats(XMLElement *pBitstream) {
|
|
XMLElement *pFormat = pBitstream->FirstChildElement(FORMATS)->FirstChildElement(FORMAT);
|
|
while (pFormat) {
|
|
int size = RkAudioSettingUtils::getFormatsArraySize();
|
|
for (int i = 0; i < size; i++) {
|
|
const AudioFormatMaps* maps = RkAudioSettingUtils::getFormatMapByIndex(i);
|
|
if (!strcmp(maps->name, pFormat->GetText())) {
|
|
mFormat[maps->settingFormat] = AUDIO_SETTING_SUPPORT;
|
|
ALOGV("%s: add format = %s", __FUNCTION__, maps->name);
|
|
break;
|
|
}
|
|
}
|
|
|
|
pFormat = pFormat->NextSiblingElement();
|
|
}
|
|
}
|
|
|
|
int RKAudioXmlParser::getDevice() {
|
|
return mDevice;
|
|
}
|
|
|
|
void RKAudioXmlParser::resetFormats() {
|
|
for (int i = 0; i < AUDIO_SETTING_FORMAT_BUTT; i++) {
|
|
mFormat[i] = AUDIO_SETTING_UNSUPPORT;
|
|
}
|
|
}
|
|
|
|
void RKAudioXmlParser::clearXmlFormats() {
|
|
// clean all formats in xml
|
|
int size = RkAudioSettingUtils::getFormatsArraySize();
|
|
for (int i = 0; i < size; i++) {
|
|
const AudioFormatMaps* maps = RkAudioSettingUtils::getFormatMapByIndex(i);
|
|
if (maps) {
|
|
ALOGV("%s: delete format = %s", __FUNCTION__, maps->name);
|
|
deleteXmlFormat((char *)maps->name);
|
|
}
|
|
}
|
|
saveFile();
|
|
}
|
|
|
|
int RKAudioXmlParser::setDevice(int device) {
|
|
if (device == mDevice)
|
|
return 0;
|
|
|
|
mDevice = device;
|
|
resetFormats();
|
|
XMLElement *pBitstream = mXmlDoc->RootElement()->FirstChildElement(BITSTREAM);
|
|
if (device == AUDIO_DEVICE_DECODE) { // set decode
|
|
// set bistream disable to xml
|
|
pBitstream->SetAttribute(SETTING, DISABLE);
|
|
saveFile();
|
|
} else { // set spdif/hdmi bitstream
|
|
// set bistream enable to xml
|
|
pBitstream->SetAttribute(SETTING, ENABLE);
|
|
clearXmlFormats();
|
|
updateXmlDevice(pBitstream, device);
|
|
saveFile();
|
|
// read format from xml
|
|
if (device == AUDIO_DEVICE_HDMI_BITSTREAM) {
|
|
// set auto mode default for hdmi
|
|
setMode(AUDIO_DEVICE_HDMI_BITSTREAM, AUDIO_BITSTREAM_MODE_AUTO);
|
|
} else {
|
|
// set manual mode default for spdif
|
|
setMode(AUDIO_DEVICE_SPDIF_PASSTHROUGH, AUDIO_BITSTREAM_MODE_MANUAL);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int RKAudioXmlParser::checkFormatSupport(int device, int format) {
|
|
if (device != mDevice) {
|
|
ALOGD("%s: query device = %d not equal the setting device = %d", __FUNCTION__, device, mDevice);
|
|
return AUDIO_SETTING_UNSUPPORT;
|
|
}
|
|
|
|
return mFormat[format];
|
|
}
|
|
|
|
int RKAudioXmlParser::setMode(int device, int mode) {
|
|
updateXmlMode(device, mode);
|
|
saveFile();
|
|
mMode = mode;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void RKAudioXmlParser::updateXmlDevice(XMLElement *pNodeEle, int device) {
|
|
XMLElement *pDeviceEle = NULL;
|
|
if (device == AUDIO_DEVICE_DECODE) {
|
|
} else {
|
|
pDeviceEle = pNodeEle->FirstChildElement(DEVICES)->FirstChildElement(DEVICE);
|
|
if (pDeviceEle) {
|
|
if (device == AUDIO_DEVICE_HDMI_BITSTREAM) {
|
|
updateElement(pDeviceEle, HDMI);
|
|
} else if (device == AUDIO_DEVICE_SPDIF_PASSTHROUGH) {
|
|
updateElement(pDeviceEle, SPDIF);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int RKAudioXmlParser::getMode(int device) {
|
|
if (device == AUDIO_DEVICE_DECODE) {
|
|
return AUDIO_DEVICE_DECODE;
|
|
}
|
|
|
|
return mMode;
|
|
}
|
|
|
|
|
|
void RKAudioXmlParser::saveFile() {
|
|
if (mXmlDoc && mPath) {
|
|
if (access(mPath, F_OK) >= 0) {
|
|
mXmlDoc->SaveFile(mPath);
|
|
sync();
|
|
}
|
|
}
|
|
}
|
|
|
|
int RKAudioXmlParser::insertFormat(char *name, int settingFormat) {
|
|
// insert to list
|
|
ALOGV("%s: name = %s, format = %d", __FUNCTION__, name, settingFormat);
|
|
mFormat[settingFormat] = AUDIO_SETTING_SUPPORT;
|
|
// insert to xml
|
|
insertXmlFormat(name);
|
|
saveFile();
|
|
return 0;
|
|
}
|
|
|
|
int RKAudioXmlParser::deleteFormat(char *name, int settingFormat) {
|
|
ALOGV("%s: name = %s, format = %d", __FUNCTION__, name, settingFormat);
|
|
// delete from list
|
|
mFormat[settingFormat] = AUDIO_SETTING_UNSUPPORT;
|
|
// delete from xml
|
|
deleteXmlFormat(name);
|
|
saveFile();
|
|
return 0;
|
|
}
|
|
|
|
void RKAudioXmlParser::insertXmlFormat(char *name) {
|
|
XMLDocument *pDoc = mXmlDoc;
|
|
XMLElement *pFormatsEle = NULL;
|
|
if (mDevice == AUDIO_DEVICE_DECODE) {
|
|
pFormatsEle = pDoc->RootElement()
|
|
->FirstChildElement(DECODE)->FirstChildElement(FORMATS);
|
|
} else {
|
|
pFormatsEle = pDoc->RootElement()
|
|
->FirstChildElement(BITSTREAM)->FirstChildElement(FORMATS);
|
|
}
|
|
|
|
if (pFormatsEle) {
|
|
XMLElement *pFormatEle = pDoc->NewElement(FORMAT);
|
|
pFormatEle->InsertEndChild(pDoc->NewText(name));
|
|
pFormatsEle->InsertEndChild(pFormatEle);
|
|
}
|
|
}
|
|
|
|
void RKAudioXmlParser::deleteXmlFormat(char *name) {
|
|
XMLDocument *pDoc = mXmlDoc;
|
|
XMLElement *pDevicesEle = NULL;
|
|
XMLElement *pDeviceEle = NULL;
|
|
if (mDevice == AUDIO_DEVICE_DECODE) {
|
|
pDevicesEle = pDoc->RootElement()
|
|
->FirstChildElement(DECODE)->FirstChildElement(FORMATS);
|
|
pDeviceEle = pDevicesEle->FirstChildElement(FORMAT);
|
|
} else {
|
|
pDevicesEle = pDoc->RootElement()
|
|
->FirstChildElement(BITSTREAM)->FirstChildElement(FORMATS);
|
|
pDeviceEle = pDevicesEle->FirstChildElement(FORMAT);
|
|
}
|
|
|
|
while (pDeviceEle) {
|
|
if (!strcmp(pDeviceEle->GetText(), name)) {
|
|
pDevicesEle->DeleteChild(pDeviceEle);
|
|
break;
|
|
}
|
|
|
|
pDeviceEle = pDeviceEle->NextSiblingElement();
|
|
}
|
|
}
|
|
|
|
void RKAudioXmlParser::updateXmlMode(int device, int mode) {
|
|
XMLDocument *pDoc = mXmlDoc;
|
|
XMLElement *pModeEle = NULL;
|
|
if (device == AUDIO_DEVICE_DECODE) {
|
|
pModeEle = pDoc->RootElement()
|
|
->FirstChildElement(DECODE)->FirstChildElement(MODE);
|
|
// add codes here
|
|
} else {
|
|
pModeEle = pDoc->RootElement()
|
|
->FirstChildElement(BITSTREAM)->FirstChildElement(MODE);
|
|
if (pModeEle) {
|
|
if (mode == AUDIO_BITSTREAM_MODE_AUTO) {
|
|
updateElement(pModeEle, AUTO);
|
|
} else if (mode == AUDIO_BITSTREAM_MODE_MANUAL) {
|
|
updateElement(pModeEle, MANUAL);
|
|
} else {
|
|
ALOGE("not support mode(%d)", mode);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RKAudioXmlParser::updateElement(XMLElement *pEle, const char *value) {
|
|
if (pEle) {
|
|
if (strcmp(pEle->GetText(), value)) {
|
|
pEle->SetText(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
int RKAudioXmlParser::clearFormats(int device) {
|
|
if (device == AUDIO_DEVICE_DECODE)
|
|
return -1;
|
|
|
|
resetFormats();
|
|
clearXmlFormats();
|
|
return 0;
|
|
}
|
|
|
|
void RKAudioXmlParser::dump() {
|
|
if (mDevice == AUDIO_DEVICE_DECODE) {
|
|
ALOGD("decode mode");
|
|
} else if(mDevice == AUDIO_DEVICE_HDMI_BITSTREAM) {
|
|
const char *mode = (mMode == AUDIO_BITSTREAM_MODE_AUTO) ? "auto" : "manual";
|
|
ALOGD("hdmi passthrough %s mode",mode);
|
|
} else if(mDevice == AUDIO_DEVICE_SPDIF_PASSTHROUGH) {
|
|
ALOGD("spdif passthrough mode");
|
|
}
|
|
|
|
|
|
for (int i = 0; i < AUDIO_SETTING_FORMAT_BUTT; i++) {
|
|
if (mFormat[i] == AUDIO_SETTING_SUPPORT) {
|
|
const AudioFormatMaps* maps = RkAudioSettingUtils::getFormatMapBySettingFormat(i);
|
|
if (maps != NULL) {
|
|
ALOGD("support Format: %s", maps->name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|