strip added smb:// shares of their user/pass when adding, and instead store that...
[vuplus_xbmc] / xbmc / cores / AudioEngine / Utils / AEELDParser.cpp
1 /*
2  *      Copyright (C) 2012 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "AEELDParser.h"
23 #include "utils/EndianSwap.h"
24 #include <string.h>
25
26 #include <stdio.h>
27
28 #define GRAB_BITS(buf, byte, lowbit, bits) ((buf[byte] >> (lowbit)) & ((1 << (bits)) - 1))
29
30 typedef struct
31 {
32   uint8_t     eld_ver;
33   uint8_t     baseline_eid_len;
34   uint8_t     cea_edid_ver;
35   uint8_t     monitor_name_length;
36   uint8_t     sad_count;
37   uint8_t     conn_type;
38   bool        s_ai;
39   bool        hdcp;
40   uint8_t     audio_sync_delay;
41   bool        rlrc; /* rear left and right of center */
42   bool        flrc; /* front left and right of center */
43   bool        rc;   /* rear center */
44   bool        rlr;  /* rear left and right */
45   bool        fc;   /* front center */
46   bool        lfe;  /* LFE */
47   bool        flr;  /* front left and right */
48   uint64_t    port_id;
49   char        mfg_name[4];
50   uint16_t    product_code;
51   std::string monitor_name;
52 } ELDHeader;
53
54 #define ELD_VER_CEA_816D         2
55 #define ELD_VER_PARTIAL          31
56
57 #define ELD_EDID_VER_NONE        0
58 #define ELD_EDID_VER_CEA_861     1
59 #define ELD_EDID_VER_CEA_861_A   2
60 #define ELD_EDID_VER_CEA_861_BCD 3
61
62 #define ELD_CONN_TYPE_HDMI       0
63 #define ELD_CONN_TYPE_DP         1
64 #define ELD_CONN_TYPE_RESERVED1  2
65 #define ELD_CONN_TYPE_RESERVED2  3
66
67 #define CEA_861_FORMAT_RESERVED1 0
68 #define CEA_861_FORMAT_LPCM      1
69 #define CEA_861_FORMAT_AC3       2
70 #define CEA_861_FORMAT_MPEG1     3
71 #define CEA_861_FORMAT_MP3       4
72 #define CEA_861_FORMAT_MPEG2     5
73 #define CEA_861_FORMAT_AAC       6
74 #define CEA_861_FORMAT_DTS       7
75 #define CEA_861_FORMAT_ATRAC     8
76 #define CEA_861_FORMAT_SACD      9
77 #define CEA_861_FORMAT_EAC3      10
78 #define CEA_861_FORMAT_DTSHD     11
79 #define CEA_861_FORMAT_MLP       12
80 #define CEA_861_FORMAT_DST       13
81 #define CEA_861_FORMAT_WMAPRO    14
82 #define CEA_861_FORMAT_RESERVED2 15
83
84 #define rtrim(s) s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end())
85
86 void CAEELDParser::Parse(const uint8_t *data, size_t length, CAEDeviceInfo& info)
87 {
88   ELDHeader header;
89   header.eld_ver = (data[0 ] & 0xF8) >> 3;
90   if (header.eld_ver != ELD_VER_CEA_816D && header.eld_ver != ELD_VER_PARTIAL)
91     return;
92
93   header.baseline_eid_len    =  data[2 ];
94   header.cea_edid_ver        = (data[4 ] & 0xE0) >> 5;
95   header.monitor_name_length =  data[4 ] & 0x1F;
96   header.sad_count           = (data[5 ] & 0xF0) >> 4;
97   header.conn_type           = (data[5 ] & 0x0C) >> 2;
98   header.s_ai                = (data[5 ] & 0x02) == 0x02;
99   header.hdcp                = (data[5 ] & 0x01) == 0x01;
100   header.audio_sync_delay    =  data[6 ];
101   header.rlrc                = (data[7 ] & 0x40) == 0x40;
102   header.flrc                = (data[7 ] & 0x20) == 0x20;
103   header.rc                  = (data[7 ] & 0x10) == 0x10;
104   header.rlr                 = (data[7 ] & 0x08) == 0x08;
105   header.fc                  = (data[7 ] & 0x04) == 0x04;
106   header.lfe                 = (data[7 ] & 0x02) == 0x02;
107   header.flr                 = (data[7 ] & 0x01) == 0x01;
108   header.port_id             = Endian_SwapLE64(*((uint64_t*)(data + 8)));
109   header.mfg_name[0]         = 'A' + ((data[16] >> 2) & 0x1F) - 1;
110   header.mfg_name[1]         = 'A' + (((data[16] << 3) | (data[17] >> 5)) & 0x1F) - 1;
111   header.mfg_name[2]         = 'A' + (data[17] & 0x1F) - 1;
112   header.mfg_name[3]         = '\0';
113   header.product_code        = Endian_SwapLE16(*((uint16_t*)(data + 18)));
114
115   switch (header.conn_type)
116   {
117     case ELD_CONN_TYPE_HDMI: info.m_deviceType = AE_DEVTYPE_HDMI; break;
118     case ELD_CONN_TYPE_DP  : info.m_deviceType = AE_DEVTYPE_DP  ; break;
119   }
120
121   info.m_displayNameExtra = header.mfg_name;
122   if (header.monitor_name_length <= 16)
123   {
124     header.monitor_name.assign((const char *)(data + 20), header.monitor_name_length);
125     rtrim(header.monitor_name);
126     if (header.monitor_name.length() > 0)
127     {
128       info.m_displayNameExtra.append(" ");
129       info.m_displayNameExtra.append(header.monitor_name);
130       if (header.conn_type == ELD_CONN_TYPE_HDMI)
131         info.m_displayNameExtra.append(" on HDMI"       );
132       else
133         info.m_displayNameExtra.append(" on DisplayPort");
134     }
135   }
136
137   if (header.flr)
138   {
139     if (!info.m_channels.HasChannel(AE_CH_FL))
140       info.m_channels += AE_CH_FL;
141     if (!info.m_channels.HasChannel(AE_CH_FR))
142       info.m_channels += AE_CH_FR;
143   }
144
145   if (header.lfe)
146     if (!info.m_channels.HasChannel(AE_CH_LFE))
147       info.m_channels += AE_CH_LFE;
148
149   if (header.fc)
150     if (!info.m_channels.HasChannel(AE_CH_FC))
151       info.m_channels += AE_CH_FC;
152
153   if (header.rlr)
154   {
155     if (!info.m_channels.HasChannel(AE_CH_BL))
156       info.m_channels += AE_CH_BL;
157     if (!info.m_channels.HasChannel(AE_CH_BR))
158       info.m_channels += AE_CH_BR;
159   }
160
161   if (header.rc)
162     if (!info.m_channels.HasChannel(AE_CH_BC))
163       info.m_channels += AE_CH_BC;
164
165   if (header.flrc)
166   {
167     if (!info.m_channels.HasChannel(AE_CH_FLOC))
168       info.m_channels += AE_CH_FLOC;
169     if (!info.m_channels.HasChannel(AE_CH_FROC))
170       info.m_channels += AE_CH_FROC;
171   }
172
173   if (header.rlrc)
174   {
175     if (!info.m_channels.HasChannel(AE_CH_BLOC))
176       info.m_channels += AE_CH_BLOC;
177     if (!info.m_channels.HasChannel(AE_CH_BROC))
178       info.m_channels += AE_CH_BROC;
179   }
180
181   const uint8_t *sad = data + 20 + header.monitor_name_length;
182   for(uint8_t i = 0; i < header.sad_count; ++i)
183   {
184     uint8_t offset = i * 3;
185     uint8_t formatCode   = (sad[offset + 0] >> 3) & 0xF;
186     //uint8_t channelCount = (sad[offset + 0] & 0x7) + 1;
187     //uint8_t sampleRates  =  sad[offset + 1];
188
189     AEDataFormat fmt = AE_FMT_INVALID;
190     switch (formatCode)
191     {
192       case CEA_861_FORMAT_AAC  : fmt = AE_FMT_AAC   ; break;
193       case CEA_861_FORMAT_AC3  : fmt = AE_FMT_AC3   ; break;
194       case CEA_861_FORMAT_DTS  : fmt = AE_FMT_DTS   ; break;
195       case CEA_861_FORMAT_DTSHD: fmt = AE_FMT_DTSHD ; break;
196       case CEA_861_FORMAT_EAC3 : fmt = AE_FMT_EAC3  ; break;
197       case CEA_861_FORMAT_LPCM : fmt = AE_FMT_LPCM  ; break;
198       case CEA_861_FORMAT_MLP  : fmt = AE_FMT_TRUEHD; break;
199     }
200
201     if (fmt == AE_FMT_INVALID)
202       continue;
203
204     if (std::find(info.m_dataFormats.begin(), info.m_dataFormats.end(), fmt) == info.m_dataFormats.end())
205       info.m_dataFormats.push_back(fmt);
206   }
207 }