SathishKumar Mani | b357a77 | 2012-09-25 23:28:29 -0700 | [diff] [blame] | 1 | /* AudioUtil.cpp |
| 2 | * |
| 3 | * Copyright (C) 2012 The Android Open Source Project |
| 4 | * |
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | */ |
| 17 | |
| 18 | #define LOG_TAG "AudioUtil" |
| 19 | //#define LOG_NDEBUG 0 |
| 20 | #include <utils/Log.h> |
| 21 | |
| 22 | #include "AudioUtil.h" |
| 23 | |
| 24 | int AudioUtil::printFormatFromEDID(unsigned char format) { |
| 25 | switch (format) { |
| 26 | case LPCM: |
| 27 | ALOGV("Format:LPCM"); |
| 28 | break; |
| 29 | case AC3: |
| 30 | ALOGV("Format:AC-3"); |
| 31 | break; |
| 32 | case MPEG1: |
| 33 | ALOGV("Format:MPEG1 (Layers 1 & 2)"); |
| 34 | break; |
| 35 | case MP3: |
| 36 | ALOGV("Format:MP3 (MPEG1 Layer 3)"); |
| 37 | break; |
| 38 | case MPEG2_MULTI_CHANNEL: |
| 39 | ALOGV("Format:MPEG2 (multichannel)"); |
| 40 | break; |
| 41 | case AAC: |
| 42 | ALOGV("Format:AAC"); |
| 43 | break; |
| 44 | case DTS: |
| 45 | ALOGV("Format:DTS"); |
| 46 | break; |
| 47 | case ATRAC: |
| 48 | ALOGV("Format:ATRAC"); |
| 49 | break; |
| 50 | case SACD: |
| 51 | ALOGV("Format:One-bit audio aka SACD"); |
| 52 | break; |
| 53 | case DOLBY_DIGITAL_PLUS: |
| 54 | ALOGV("Format:Dolby Digital +"); |
| 55 | break; |
| 56 | case DTS_HD: |
| 57 | ALOGV("Format:DTS-HD"); |
| 58 | break; |
| 59 | case MAT: |
| 60 | ALOGV("Format:MAT (MLP)"); |
| 61 | break; |
| 62 | case DST: |
| 63 | ALOGV("Format:DST"); |
| 64 | break; |
| 65 | case WMA_PRO: |
| 66 | ALOGV("Format:WMA Pro"); |
| 67 | break; |
| 68 | default: |
| 69 | ALOGV("Invalid format ID...."); |
| 70 | break; |
| 71 | } |
| 72 | return format; |
| 73 | } |
| 74 | |
| 75 | int AudioUtil::getSamplingFrequencyFromEDID(unsigned char byte) { |
| 76 | int nFreq = 0; |
| 77 | |
| 78 | if (byte & BIT(6)) { |
| 79 | ALOGV("192kHz"); |
| 80 | nFreq = 192000; |
| 81 | } else if (byte & BIT(5)) { |
| 82 | ALOGV("176kHz"); |
| 83 | nFreq = 176000; |
| 84 | } else if (byte & BIT(4)) { |
| 85 | ALOGV("96kHz"); |
| 86 | nFreq = 96000; |
| 87 | } else if (byte & BIT(3)) { |
| 88 | ALOGV("88.2kHz"); |
| 89 | nFreq = 88200; |
| 90 | } else if (byte & BIT(2)) { |
| 91 | ALOGV("48kHz"); |
| 92 | nFreq = 48000; |
| 93 | } else if (byte & BIT(1)) { |
| 94 | ALOGV("44.1kHz"); |
| 95 | nFreq = 44100; |
| 96 | } else if (byte & BIT(0)) { |
| 97 | ALOGV("32kHz"); |
| 98 | nFreq = 32000; |
| 99 | } |
| 100 | return nFreq; |
| 101 | } |
| 102 | |
| 103 | int AudioUtil::getBitsPerSampleFromEDID(unsigned char byte, |
| 104 | unsigned char format) { |
| 105 | int nBitsPerSample = 0; |
| 106 | if (format == 1) { |
| 107 | if (byte & BIT(2)) { |
| 108 | ALOGV("24bit"); |
| 109 | nBitsPerSample = 24; |
| 110 | } else if (byte & BIT(1)) { |
| 111 | ALOGV("20bit"); |
| 112 | nBitsPerSample = 20; |
| 113 | } else if (byte & BIT(0)) { |
| 114 | ALOGV("16bit"); |
| 115 | nBitsPerSample = 16; |
| 116 | } |
| 117 | } else { |
| 118 | ALOGV("not lpcm format, return 0"); |
| 119 | return 0; |
| 120 | } |
| 121 | return nBitsPerSample; |
| 122 | } |
| 123 | |
| 124 | bool AudioUtil::getHDMIAudioSinkCaps(EDID_AUDIO_INFO* pInfo) { |
| 125 | unsigned char channels[16]; |
| 126 | unsigned char formats[16]; |
| 127 | unsigned char frequency[16]; |
| 128 | unsigned char bitrate[16]; |
| 129 | unsigned char* data = NULL; |
| 130 | unsigned char* original_data_ptr = NULL; |
| 131 | int count = 0; |
| 132 | bool bRet = false; |
| 133 | const char* file = "/sys/class/graphics/fb1/audio_data_block"; |
| 134 | FILE* fpaudiocaps = fopen(file, "rb"); |
| 135 | if (fpaudiocaps) { |
| 136 | ALOGV("opened audio_caps successfully..."); |
| 137 | fseek(fpaudiocaps, 0, SEEK_END); |
| 138 | long size = ftell(fpaudiocaps); |
| 139 | ALOGV("audiocaps size is %ld\n",size); |
| 140 | data = (unsigned char*) malloc(size); |
| 141 | if (data) { |
| 142 | fseek(fpaudiocaps, 0, SEEK_SET); |
| 143 | original_data_ptr = data; |
| 144 | fread(data, 1, size, fpaudiocaps); |
| 145 | } |
| 146 | fclose(fpaudiocaps); |
| 147 | } else { |
| 148 | ALOGE("failed to open audio_caps"); |
| 149 | } |
| 150 | |
| 151 | if (pInfo && data) { |
| 152 | int length = 0; |
| 153 | memcpy(&count, data, sizeof(int)); |
| 154 | data+= sizeof(int); |
| 155 | ALOGV("#Audio Block Count is %d",count); |
| 156 | memcpy(&length, data, sizeof(int)); |
| 157 | data += sizeof(int); |
| 158 | ALOGV("Total length is %d",length); |
| 159 | unsigned int sad[MAX_SHORT_AUDIO_DESC_CNT]; |
| 160 | int nblockindex = 0; |
| 161 | int nCountDesc = 0; |
| 162 | while (length >= MIN_AUDIO_DESC_LENGTH && count < MAX_SHORT_AUDIO_DESC_CNT) { |
| 163 | sad[nblockindex] = (unsigned int)data[0] + ((unsigned int)data[1] << 8) |
| 164 | + ((unsigned int)data[2] << 16); |
| 165 | nblockindex+=1; |
| 166 | nCountDesc++; |
| 167 | length -= MIN_AUDIO_DESC_LENGTH; |
| 168 | data += MIN_AUDIO_DESC_LENGTH; |
| 169 | } |
| 170 | memset(pInfo, 0, sizeof(EDID_AUDIO_INFO)); |
| 171 | pInfo->nAudioBlocks = nCountDesc; |
| 172 | ALOGV("Total # of audio descriptors %d",nCountDesc); |
| 173 | int nIndex = 0; |
| 174 | while (nCountDesc--) { |
| 175 | channels [nIndex] = (sad[nIndex] & 0x7) + 1; |
| 176 | formats [nIndex] = (sad[nIndex] & 0xFF) >> 3; |
| 177 | frequency[nIndex] = (sad[nIndex] >> 8) & 0xFF; |
| 178 | bitrate [nIndex] = (sad[nIndex] >> 16) & 0xFF; |
| 179 | nIndex++; |
| 180 | } |
| 181 | bRet = true; |
| 182 | for (int i = 0; i < pInfo->nAudioBlocks; i++) { |
| 183 | ALOGV("AUDIO DESC BLOCK # %d\n",i); |
| 184 | |
| 185 | pInfo->AudioBlocksArray[i].nChannels = channels[i]; |
| 186 | ALOGV("pInfo->AudioBlocksArray[i].nChannels %d\n", pInfo->AudioBlocksArray[i].nChannels); |
| 187 | |
| 188 | ALOGV("Format Byte %d\n", formats[i]); |
| 189 | pInfo->AudioBlocksArray[i].nFormatId = (EDID_AUDIO_FORMAT_ID)printFormatFromEDID(formats[i]); |
| 190 | ALOGV("pInfo->AudioBlocksArray[i].nFormatId %d",pInfo->AudioBlocksArray[i].nFormatId); |
| 191 | |
| 192 | ALOGV("Frequency Byte %d\n", frequency[i]); |
| 193 | pInfo->AudioBlocksArray[i].nSamplingFreq = getSamplingFrequencyFromEDID(frequency[i]); |
| 194 | ALOGV("pInfo->AudioBlocksArray[i].nSamplingFreq %d",pInfo->AudioBlocksArray[i].nSamplingFreq); |
| 195 | |
| 196 | ALOGV("BitsPerSample Byte %d\n", bitrate[i]); |
| 197 | pInfo->AudioBlocksArray[i].nBitsPerSample = getBitsPerSampleFromEDID(bitrate[i],formats[i]); |
| 198 | ALOGV("pInfo->AudioBlocksArray[i].nBitsPerSample %d",pInfo->AudioBlocksArray[i].nBitsPerSample); |
| 199 | } |
| 200 | getSpeakerAllocation(pInfo); |
| 201 | } |
| 202 | if (original_data_ptr) |
| 203 | free(original_data_ptr); |
| 204 | |
| 205 | return bRet; |
| 206 | } |
| 207 | |
| 208 | bool AudioUtil::getSpeakerAllocation(EDID_AUDIO_INFO* pInfo) { |
| 209 | int count = 0; |
| 210 | bool bRet = false; |
| 211 | unsigned char* data = NULL; |
| 212 | unsigned char* original_data_ptr = NULL; |
| 213 | const char* spkrfile = "/sys/class/graphics/fb1/spkr_alloc_data_block"; |
| 214 | FILE* fpspkrfile = fopen(spkrfile, "rb"); |
| 215 | if(fpspkrfile) { |
| 216 | ALOGV("opened spkr_alloc_data_block successfully..."); |
| 217 | fseek(fpspkrfile,0,SEEK_END); |
| 218 | long size = ftell(fpspkrfile); |
| 219 | ALOGV("fpspkrfile size is %ld\n",size); |
| 220 | data = (unsigned char*)malloc(size); |
| 221 | if(data) { |
| 222 | original_data_ptr = data; |
| 223 | fseek(fpspkrfile,0,SEEK_SET); |
| 224 | fread(data,1,size,fpspkrfile); |
| 225 | } |
| 226 | fclose(fpspkrfile); |
| 227 | } else { |
| 228 | ALOGE("failed to open fpspkrfile"); |
| 229 | } |
| 230 | |
| 231 | if(pInfo && data) { |
| 232 | int length = 0; |
| 233 | memcpy(&count, data, sizeof(int)); |
| 234 | ALOGV("Count is %d",count); |
| 235 | data += sizeof(int); |
| 236 | memcpy(&length, data, sizeof(int)); |
| 237 | ALOGV("Total length is %d",length); |
| 238 | data+= sizeof(int); |
| 239 | ALOGV("Total speaker allocation Block count # %d\n",count); |
| 240 | bRet = true; |
| 241 | for (int i = 0; i < count; i++) { |
| 242 | ALOGV("Speaker Allocation BLOCK # %d\n",i); |
| 243 | pInfo->nSpeakerAllocation[0] = data[0]; |
| 244 | pInfo->nSpeakerAllocation[1] = data[1]; |
| 245 | pInfo->nSpeakerAllocation[2] = data[2]; |
| 246 | ALOGV("pInfo->nSpeakerAllocation %x %x %x\n", data[0],data[1],data[2]); |
| 247 | |
| 248 | |
| 249 | if (pInfo->nSpeakerAllocation[0] & BIT(7)) { |
| 250 | ALOGV("FLW/FRW"); |
| 251 | } else if (pInfo->nSpeakerAllocation[0] & BIT(6)) { |
| 252 | ALOGV("RLC/RRC"); |
| 253 | } else if (pInfo->nSpeakerAllocation[0] & BIT(5)) { |
| 254 | ALOGV("FLC/FRC"); |
| 255 | } else if (pInfo->nSpeakerAllocation[0] & BIT(4)) { |
| 256 | ALOGV("RC"); |
| 257 | } else if (pInfo->nSpeakerAllocation[0] & BIT(3)) { |
| 258 | ALOGV("RL/RR"); |
| 259 | } else if (pInfo->nSpeakerAllocation[0] & BIT(2)) { |
| 260 | ALOGV("FC"); |
| 261 | } else if (pInfo->nSpeakerAllocation[0] & BIT(1)) { |
| 262 | ALOGV("LFE"); |
| 263 | } else if (pInfo->nSpeakerAllocation[0] & BIT(0)) { |
| 264 | ALOGV("FL/FR"); |
| 265 | } |
| 266 | |
| 267 | if (pInfo->nSpeakerAllocation[1] & BIT(2)) { |
| 268 | ALOGV("FCH"); |
| 269 | } else if (pInfo->nSpeakerAllocation[1] & BIT(1)) { |
| 270 | ALOGV("TC"); |
| 271 | } else if (pInfo->nSpeakerAllocation[1] & BIT(0)) { |
| 272 | ALOGV("FLH/FRH"); |
| 273 | } |
| 274 | } |
| 275 | } |
| 276 | if (original_data_ptr) |
| 277 | free(original_data_ptr); |
| 278 | return bRet; |
| 279 | } |