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.
279 lines
9.0 KiB
279 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; |
|
}
|
|
|