You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
280 lines
9.0 KiB
280 lines
9.0 KiB
/* AudioUtil.cpp
|
|
*
|
|
* Copyright (C) 2012 The Android Open Source Project
|
|
*
|
|
* 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 "AudioUtil"
|
|
//#define LOG_NDEBUG 0
|
|
#include <utils/Log.h>
|
|
|
|
#include "AudioUtil.h"
|
|
|
|
int AudioUtil::printFormatFromEDID(unsigned char format) {
|
|
switch (format) {
|
|
case LPCM:
|
|
ALOGV("Format:LPCM");
|
|
break;
|
|
case AC3:
|
|
ALOGV("Format:AC-3");
|
|
break;
|
|
case MPEG1:
|
|
ALOGV("Format:MPEG1 (Layers 1 & 2)");
|
|
break;
|
|
case MP3:
|
|
ALOGV("Format:MP3 (MPEG1 Layer 3)");
|
|
break;
|
|
case MPEG2_MULTI_CHANNEL:
|
|
ALOGV("Format:MPEG2 (multichannel)");
|
|
break;
|
|
case AAC:
|
|
ALOGV("Format:AAC");
|
|
break;
|
|
case DTS:
|
|
ALOGV("Format:DTS");
|
|
break;
|
|
case ATRAC:
|
|
ALOGV("Format:ATRAC");
|
|
break;
|
|
case SACD:
|
|
ALOGV("Format:One-bit audio aka SACD");
|
|
break;
|
|
case DOLBY_DIGITAL_PLUS:
|
|
ALOGV("Format:Dolby Digital +");
|
|
break;
|
|
case DTS_HD:
|
|
ALOGV("Format:DTS-HD");
|
|
break;
|
|
case MAT:
|
|
ALOGV("Format:MAT (MLP)");
|
|
break;
|
|
case DST:
|
|
ALOGV("Format:DST");
|
|
break;
|
|
case WMA_PRO:
|
|
ALOGV("Format:WMA Pro");
|
|
break;
|
|
default:
|
|
ALOGV("Invalid format ID....");
|
|
break;
|
|
}
|
|
return format;
|
|
}
|
|
|
|
int AudioUtil::getSamplingFrequencyFromEDID(unsigned char byte) {
|
|
int nFreq = 0;
|
|
|
|
if (byte & BIT(6)) {
|
|
ALOGV("192kHz");
|
|
nFreq = 192000;
|
|
} else if (byte & BIT(5)) {
|
|
ALOGV("176kHz");
|
|
nFreq = 176000;
|
|
} else if (byte & BIT(4)) {
|
|
ALOGV("96kHz");
|
|
nFreq = 96000;
|
|
} else if (byte & BIT(3)) {
|
|
ALOGV("88.2kHz");
|
|
nFreq = 88200;
|
|
} else if (byte & BIT(2)) {
|
|
ALOGV("48kHz");
|
|
nFreq = 48000;
|
|
} else if (byte & BIT(1)) {
|
|
ALOGV("44.1kHz");
|
|
nFreq = 44100;
|
|
} else if (byte & BIT(0)) {
|
|
ALOGV("32kHz");
|
|
nFreq = 32000;
|
|
}
|
|
return nFreq;
|
|
}
|
|
|
|
int AudioUtil::getBitsPerSampleFromEDID(unsigned char byte,
|
|
unsigned char format) {
|
|
int nBitsPerSample = 0;
|
|
if (format == 1) {
|
|
if (byte & BIT(2)) {
|
|
ALOGV("24bit");
|
|
nBitsPerSample = 24;
|
|
} else if (byte & BIT(1)) {
|
|
ALOGV("20bit");
|
|
nBitsPerSample = 20;
|
|
} else if (byte & BIT(0)) {
|
|
ALOGV("16bit");
|
|
nBitsPerSample = 16;
|
|
}
|
|
} else {
|
|
ALOGV("not lpcm format, return 0");
|
|
return 0;
|
|
}
|
|
return nBitsPerSample;
|
|
}
|
|
|
|
bool AudioUtil::getHDMIAudioSinkCaps(EDID_AUDIO_INFO* pInfo) {
|
|
unsigned char channels[16];
|
|
unsigned char formats[16];
|
|
unsigned char frequency[16];
|
|
unsigned char bitrate[16];
|
|
unsigned char* data = NULL;
|
|
unsigned char* original_data_ptr = NULL;
|
|
int count = 0;
|
|
bool bRet = false;
|
|
const char* file = "/sys/class/graphics/fb1/audio_data_block";
|
|
FILE* fpaudiocaps = fopen(file, "rb");
|
|
if (fpaudiocaps) {
|
|
ALOGV("opened audio_caps successfully...");
|
|
fseek(fpaudiocaps, 0, SEEK_END);
|
|
long size = ftell(fpaudiocaps);
|
|
ALOGV("audiocaps size is %ld\n",size);
|
|
data = (unsigned char*) malloc(size);
|
|
if (data) {
|
|
fseek(fpaudiocaps, 0, SEEK_SET);
|
|
original_data_ptr = data;
|
|
fread(data, 1, size, fpaudiocaps);
|
|
}
|
|
fclose(fpaudiocaps);
|
|
} else {
|
|
ALOGE("failed to open audio_caps");
|
|
}
|
|
|
|
if (pInfo && data) {
|
|
int length = 0;
|
|
memcpy(&count, data, sizeof(int));
|
|
data+= sizeof(int);
|
|
ALOGV("#Audio Block Count is %d",count);
|
|
memcpy(&length, data, sizeof(int));
|
|
data += sizeof(int);
|
|
ALOGV("Total length is %d",length);
|
|
unsigned int sad[MAX_SHORT_AUDIO_DESC_CNT];
|
|
int nblockindex = 0;
|
|
int nCountDesc = 0;
|
|
while (length >= MIN_AUDIO_DESC_LENGTH && count < MAX_SHORT_AUDIO_DESC_CNT) {
|
|
sad[nblockindex] = (unsigned int)data[0] + ((unsigned int)data[1] << 8)
|
|
+ ((unsigned int)data[2] << 16);
|
|
nblockindex+=1;
|
|
nCountDesc++;
|
|
length -= MIN_AUDIO_DESC_LENGTH;
|
|
data += MIN_AUDIO_DESC_LENGTH;
|
|
}
|
|
memset(pInfo, 0, sizeof(EDID_AUDIO_INFO));
|
|
pInfo->nAudioBlocks = nCountDesc;
|
|
ALOGV("Total # of audio descriptors %d",nCountDesc);
|
|
int nIndex = 0;
|
|
while (nCountDesc--) {
|
|
channels [nIndex] = (sad[nIndex] & 0x7) + 1;
|
|
formats [nIndex] = (sad[nIndex] & 0xFF) >> 3;
|
|
frequency[nIndex] = (sad[nIndex] >> 8) & 0xFF;
|
|
bitrate [nIndex] = (sad[nIndex] >> 16) & 0xFF;
|
|
nIndex++;
|
|
}
|
|
bRet = true;
|
|
for (int i = 0; i < pInfo->nAudioBlocks; i++) {
|
|
ALOGV("AUDIO DESC BLOCK # %d\n",i);
|
|
|
|
pInfo->AudioBlocksArray[i].nChannels = channels[i];
|
|
ALOGV("pInfo->AudioBlocksArray[i].nChannels %d\n", pInfo->AudioBlocksArray[i].nChannels);
|
|
|
|
ALOGV("Format Byte %d\n", formats[i]);
|
|
pInfo->AudioBlocksArray[i].nFormatId = (EDID_AUDIO_FORMAT_ID)printFormatFromEDID(formats[i]);
|
|
ALOGV("pInfo->AudioBlocksArray[i].nFormatId %d",pInfo->AudioBlocksArray[i].nFormatId);
|
|
|
|
ALOGV("Frequency Byte %d\n", frequency[i]);
|
|
pInfo->AudioBlocksArray[i].nSamplingFreq = getSamplingFrequencyFromEDID(frequency[i]);
|
|
ALOGV("pInfo->AudioBlocksArray[i].nSamplingFreq %d",pInfo->AudioBlocksArray[i].nSamplingFreq);
|
|
|
|
ALOGV("BitsPerSample Byte %d\n", bitrate[i]);
|
|
pInfo->AudioBlocksArray[i].nBitsPerSample = getBitsPerSampleFromEDID(bitrate[i],formats[i]);
|
|
ALOGV("pInfo->AudioBlocksArray[i].nBitsPerSample %d",pInfo->AudioBlocksArray[i].nBitsPerSample);
|
|
}
|
|
getSpeakerAllocation(pInfo);
|
|
}
|
|
if (original_data_ptr)
|
|
free(original_data_ptr);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
bool AudioUtil::getSpeakerAllocation(EDID_AUDIO_INFO* pInfo) {
|
|
int count = 0;
|
|
bool bRet = false;
|
|
unsigned char* data = NULL;
|
|
unsigned char* original_data_ptr = NULL;
|
|
const char* spkrfile = "/sys/class/graphics/fb1/spkr_alloc_data_block";
|
|
FILE* fpspkrfile = fopen(spkrfile, "rb");
|
|
if(fpspkrfile) {
|
|
ALOGV("opened spkr_alloc_data_block successfully...");
|
|
fseek(fpspkrfile,0,SEEK_END);
|
|
long size = ftell(fpspkrfile);
|
|
ALOGV("fpspkrfile size is %ld\n",size);
|
|
data = (unsigned char*)malloc(size);
|
|
if(data) {
|
|
original_data_ptr = data;
|
|
fseek(fpspkrfile,0,SEEK_SET);
|
|
fread(data,1,size,fpspkrfile);
|
|
}
|
|
fclose(fpspkrfile);
|
|
} else {
|
|
ALOGE("failed to open fpspkrfile");
|
|
}
|
|
|
|
if(pInfo && data) {
|
|
int length = 0;
|
|
memcpy(&count, data, sizeof(int));
|
|
ALOGV("Count is %d",count);
|
|
data += sizeof(int);
|
|
memcpy(&length, data, sizeof(int));
|
|
ALOGV("Total length is %d",length);
|
|
data+= sizeof(int);
|
|
ALOGV("Total speaker allocation Block count # %d\n",count);
|
|
bRet = true;
|
|
for (int i = 0; i < count; i++) {
|
|
ALOGV("Speaker Allocation BLOCK # %d\n",i);
|
|
pInfo->nSpeakerAllocation[0] = data[0];
|
|
pInfo->nSpeakerAllocation[1] = data[1];
|
|
pInfo->nSpeakerAllocation[2] = data[2];
|
|
ALOGV("pInfo->nSpeakerAllocation %x %x %x\n", data[0],data[1],data[2]);
|
|
|
|
|
|
if (pInfo->nSpeakerAllocation[0] & BIT(7)) {
|
|
ALOGV("FLW/FRW");
|
|
} else if (pInfo->nSpeakerAllocation[0] & BIT(6)) {
|
|
ALOGV("RLC/RRC");
|
|
} else if (pInfo->nSpeakerAllocation[0] & BIT(5)) {
|
|
ALOGV("FLC/FRC");
|
|
} else if (pInfo->nSpeakerAllocation[0] & BIT(4)) {
|
|
ALOGV("RC");
|
|
} else if (pInfo->nSpeakerAllocation[0] & BIT(3)) {
|
|
ALOGV("RL/RR");
|
|
} else if (pInfo->nSpeakerAllocation[0] & BIT(2)) {
|
|
ALOGV("FC");
|
|
} else if (pInfo->nSpeakerAllocation[0] & BIT(1)) {
|
|
ALOGV("LFE");
|
|
} else if (pInfo->nSpeakerAllocation[0] & BIT(0)) {
|
|
ALOGV("FL/FR");
|
|
}
|
|
|
|
if (pInfo->nSpeakerAllocation[1] & BIT(2)) {
|
|
ALOGV("FCH");
|
|
} else if (pInfo->nSpeakerAllocation[1] & BIT(1)) {
|
|
ALOGV("TC");
|
|
} else if (pInfo->nSpeakerAllocation[1] & BIT(0)) {
|
|
ALOGV("FLH/FRH");
|
|
}
|
|
}
|
|
}
|
|
if (original_data_ptr)
|
|
free(original_data_ptr);
|
|
return bRet;
|
|
}
|