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
24int 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
75int 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
103int 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
124bool 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
208bool 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