| /* 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; |
| } |