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 
printFormatFromEDID(unsigned char format)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 
getSamplingFrequencyFromEDID(unsigned char byte)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 
getBitsPerSampleFromEDID(unsigned char byte,unsigned char format)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 
getHDMIAudioSinkCaps(EDID_AUDIO_INFO * pInfo)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 
getSpeakerAllocation(EDID_AUDIO_INFO * pInfo)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 }
280