MythTV  master
eldutils.cpp
Go to the documentation of this file.
1 /*
2  * eldutils.cpp (c) Jean-Yves Avenard <jyavenard@mythtv.org>
3  * a utility class to decode EDID Like Data (ELD) byte stream
4  *
5  * Based on ALSA hda_eld.c
6  * Copyright(c) 2008 Intel Corporation.
7  *
8  * Authors:
9  * Wu Fengguang <wfg@linux.intel.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 #include "eldutils.h"
26 
27 #include <cinttypes>
28 #include <sys/types.h>
29 
30 #include <QString>
31 #include <QtEndian>
32 
33 #include "audiooutputbase.h"
34 
35 #define LOC QString("ELDUTILS: ")
36 
38 {
41 };
42 
44 {
50 };
51 
52 static const std::array<const QString,11> cea_speaker_allocation_names {
53  /* 0 */ "FL/FR",
54  /* 1 */ "LFE",
55  /* 2 */ "FC",
56  /* 3 */ "RL/RR",
57  /* 4 */ "RC",
58  /* 5 */ "FLC/FRC",
59  /* 6 */ "RLC/RRC",
60  /* 7 */ "FLW/FRW",
61  /* 8 */ "FLH/FRH",
62  /* 9 */ "TC",
63  /* 10 */ "FCH",
64 };
65 
66 static const std::array<const QString,4> eld_connection_type_names {
67  "HDMI",
68  "DisplayPort",
69  "2-reserved",
70  "3-reserved"
71 };
72 
74 {
80 };
81 
82 static const std::array<const QString,18> audiotype_names {
83  /* 0 */ "undefined",
84  /* 1 */ "LPCM",
85  /* 2 */ "AC3",
86  /* 3 */ "MPEG1",
87  /* 4 */ "MP3",
88  /* 5 */ "MPEG2",
89  /* 6 */ "AAC-LC",
90  /* 7 */ "DTS",
91  /* 8 */ "ATRAC",
92  /* 9 */ "DSD (One Bit Audio)",
93  /* 10 */ "E-AC3",
94  /* 11 */ "DTS-HD",
95  /* 12 */ "TrueHD",
96  /* 13 */ "DST",
97  /* 14 */ "WMAPro",
98  /* 15 */ "HE-AAC",
99  /* 16 */ "HE-AACv2",
100  /* 17 */ "MPEG Surround",
101 };
102 
103 /*
104  * The following two lists are shared between
105  * - HDMI audio InfoFrame (source to sink)
106  * - CEA E-EDID Extension (sink to source)
107  */
108 
109 /*
110  * SF2:SF1:SF0 index => sampling frequency
111  */
112 #define SNDRV_PCM_RATE_5512 (1<<0) /* 5512Hz */
113 #define SNDRV_PCM_RATE_8000 (1<<1) /* 8000Hz */
114 #define SNDRV_PCM_RATE_11025 (1<<2) /* 11025Hz */
115 #define SNDRV_PCM_RATE_16000 (1<<3) /* 16000Hz */
116 #define SNDRV_PCM_RATE_22050 (1<<4) /* 22050Hz */
117 #define SNDRV_PCM_RATE_32000 (1<<5) /* 32000Hz */
118 #define SNDRV_PCM_RATE_44100 (1<<6) /* 44100Hz */
119 #define SNDRV_PCM_RATE_48000 (1<<7) /* 48000Hz */
120 #define SNDRV_PCM_RATE_64000 (1<<8) /* 64000Hz */
121 #define SNDRV_PCM_RATE_88200 (1<<9) /* 88200Hz */
122 #define SNDRV_PCM_RATE_96000 (1<<10) /* 96000Hz */
123 #define SNDRV_PCM_RATE_176400 (1<<11) /* 176400Hz */
124 #define SNDRV_PCM_RATE_192000 (1<<12) /* 192000Hz */
125 
126 static const std::array<const int,8> cea_sampling_frequencies {
127  0, /* 0: Refer to Stream Header */
128  SNDRV_PCM_RATE_32000, /* 1: 32000Hz */
129  SNDRV_PCM_RATE_44100, /* 2: 44100Hz */
130  SNDRV_PCM_RATE_48000, /* 3: 48000Hz */
131  SNDRV_PCM_RATE_88200, /* 4: 88200Hz */
132  SNDRV_PCM_RATE_96000, /* 5: 96000Hz */
133  SNDRV_PCM_RATE_176400, /* 6: 176400Hz */
134  SNDRV_PCM_RATE_192000, /* 7: 192000Hz */
135 };
136 
137 #define GRAB_BITS(buf, byte, lowbit, bits) \
138 ( \
139  ((buf)[byte] >> (lowbit)) & ((1 << (bits)) - 1) \
140 )
141 
142 eld::eld(const char *buf, int size)
143 {
144  m_e.formats = 0LL;
145  update_eld(buf, size);
146 }
147 
148 eld::eld(const eld &rhs)
149 {
150  m_e = rhs.m_e;
151 }
152 
154 {
155  m_e.formats = 0LL;
156  m_e.eld_valid = false;
157 }
158 
159 eld& eld::operator=(const eld &rhs)
160 {
161  if (this == &rhs)
162  return *this;
163  m_e = rhs.m_e;
164  return *this;
165 }
166 
167 void eld::update_sad(int index,
168  const char *buf)
169 {
170  cea_sad *a = m_e.sad + index;
171 
172  int val = GRAB_BITS(buf, 1, 0, 7);
173  a->rates = 0;
174  for (int i = 0; i < 7; i++)
175  if ((val & (1 << i)) != 0)
176  a->rates |= cea_sampling_frequencies[i + 1];
177 
178  a->channels = GRAB_BITS(buf, 0, 0, 3);
179  a->channels++;
180 
181  a->sample_bits = 0;
182  a->max_bitrate = 0;
183 
184  a->format = GRAB_BITS(buf, 0, 3, 4);
185  m_e.formats |= 1 << a->format;
186  switch (a->format)
187  {
189  VBAUDIO("audio coding type 0 not expected");
190  break;
191 
192  case TYPE_LPCM:
193  a->sample_bits = GRAB_BITS(buf, 2, 0, 3);
194  break;
195 
196  case TYPE_AC3:
197  case TYPE_MPEG1:
198  case TYPE_MP3:
199  case TYPE_MPEG2:
200  case TYPE_AACLC:
201  case TYPE_DTS:
202  case TYPE_ATRAC:
203  a->max_bitrate = GRAB_BITS(buf, 2, 0, 8);
204  a->max_bitrate *= 8000;
205  break;
206 
207  case TYPE_SACD:
208  case TYPE_EAC3:
209  case TYPE_DTS_HD:
210  case TYPE_MLP:
211  case TYPE_DST:
212  break;
213 
214  case TYPE_WMAPRO:
215  a->profile = GRAB_BITS(buf, 2, 0, 3);
216  break;
217 
218  case TYPE_REF_CXT:
219  a->format = GRAB_BITS(buf, 2, 3, 5);
220  if (a->format == XTYPE_HE_REF_CT ||
222  {
223  VBAUDIO(QString("audio coding xtype %1 not expected")
224  .arg(a->format));
225  a->format = 0;
226  }
227  else
228  {
230  }
231  break;
232  }
233 }
234 
235 int eld::update_eld(const char *buf, int size)
236 {
237  int mnl = 0;
238 
239  m_e.eld_ver = GRAB_BITS(buf, 0, 3, 5);
240  if (m_e.eld_ver != ELD_VER_CEA_861D &&
242  {
243  VBAUDIO(QString("Unknown ELD version %1").arg(m_e.eld_ver));
244  goto out_fail;
245  }
246 
247  m_e.eld_size = size;
248  m_e.baseline_len = GRAB_BITS(buf, 2, 0, 8);
249  mnl = GRAB_BITS(buf, 4, 0, 5);
250  m_e.cea_edid_ver = GRAB_BITS(buf, 4, 5, 3);
251 
252  m_e.support_hdcp = GRAB_BITS(buf, 5, 0, 1);
253  m_e.support_ai = GRAB_BITS(buf, 5, 1, 1);
254  m_e.conn_type = GRAB_BITS(buf, 5, 2, 2);
255  m_e.sad_count = GRAB_BITS(buf, 5, 4, 4);
256 
257  m_e.aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2;
258  m_e.spk_alloc = GRAB_BITS(buf, 7, 0, 7);
259 
260  m_e.port_id = qFromLittleEndian<uint64_t>(buf + 8);
261 
262  /* not specified, but the spec's tendency is little endian */
263  m_e.manufacture_id = qFromLittleEndian<uint16_t>(buf + 16);
264  m_e.product_id = qFromLittleEndian<uint16_t>(buf + 18);
265 
266  if (ELD_FIXED_BYTES + mnl > size)
267  {
268  VBAUDIO(QString("out of range MNL %1").arg(mnl));
269  goto out_fail;
270  }
271  else
272  {
273  std::string tmp(buf + ELD_FIXED_BYTES, mnl);
274  m_e.monitor_name = QString::fromStdString(tmp);
275  }
276 
277  for (int i = 0; i < m_e.sad_count; i++)
278  {
279  if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size)
280  {
281  VBAUDIO(QString("out of range SAD %1").arg(i));
282  goto out_fail;
283  }
284  update_sad(i, buf + ELD_FIXED_BYTES + mnl + 3 * i);
285  }
286 
287  /*
288  * Assume the highest speakers configuration
289  */
290  if (!m_e.spk_alloc)
291  m_e.spk_alloc = 0xffff;
292 
293  m_e.eld_valid = true;
294  return 0;
295 
296  out_fail:
297  m_e.eld_valid = false;
298  return -1;
299 }
300 
305 QString eld::print_pcm_rates(int pcm)
306 {
307  static const std::array<const uint32_t,12> rates {
308  5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
309  96000, 176400, 192000 };
310  QString result = QString();
311 
312  for (size_t i = 0; i < rates.size(); i++)
313  {
314  if ((pcm & (1 << i)) != 0)
315  {
316  result += QString(" %1").arg(rates[i]);
317  }
318  }
319  return result;
320 }
321 
326 QString eld::print_pcm_bits(int pcm)
327 {
328  static const std::array<const uint8_t,3> bits { 16, 20, 24 };
329  QString result = QString();
330 
331  for (size_t i = 0; i < bits.size(); i++)
332  {
333  if ((pcm & (1 << i)) != 0)
334  {
335  result += QString(" %1").arg(bits[i]);
336  }
337  }
338  return result;
339 }
340 
341 QString eld::sad_desc(int index)
342 {
343  cea_sad *a = m_e.sad + index;
344  if (!a->format)
345  return "";
346 
347  QString buf = print_pcm_rates(a->rates);
348  QString buf2 = ", bits =";
349 
350  if (a->format == TYPE_LPCM)
351  buf2 += print_pcm_bits(a->sample_bits);
352  else if (a->max_bitrate)
353  buf2 = QString(", max bitrate = %1").arg(a->max_bitrate);
354  else
355  buf2 = "";
356 
357  return QString("supports coding type %1:"
358  " channels = %2, rates =%3%4")
359  .arg(audiotype_names[a->format], QString::number(a->channels),
360  buf, buf2);
361 }
362 
364 {
365  QString result = QString();
366 
367  for (size_t i = 0; i < cea_speaker_allocation_names.size(); i++)
368  {
369  if ((m_e.spk_alloc & (1 << i)) != 0)
370  {
371  result += QString(" %1").arg(cea_speaker_allocation_names[i]);
372  }
373  }
374  return result;
375 }
376 
377 QString eld::eld_version_name() const
378 {
379  switch (m_e.eld_ver)
380  {
381  case 2: return "CEA-861D or below";
382  case 31: return "partial";
383  default: return "reserved";
384  }
385 }
386 
387 QString eld::edid_version_name() const
388 {
389  switch (m_e.cea_edid_ver)
390  {
391  case 0: return "no CEA EDID Timing Extension block present";
392  case 1: return "CEA-861";
393  case 2: return "CEA-861-A";
394  case 3: return "CEA-861-B, C or D";
395  default: return "reserved";
396  }
397 }
398 
399 QString eld::info_desc() const
400 {
401  QString result = QString("manufacture_id\t\t0x%1\n")
402  .arg(m_e.manufacture_id, 0, 16);
403  result += QString("product_id\t\t0x%1\n").arg(m_e.product_id, 0, 16);
404  result += QString("port_id\t\t\t0x%1\n").arg((long long)m_e.port_id);
405  result += QString("support_hdcp\t\t%1\n").arg(m_e.support_hdcp);
406  result += QString("support_ai\t\t%1\n").arg(m_e.support_ai);
407  result += QString("audio_sync_delay\t%1\n").arg(m_e.aud_synch_delay);
408  result += QString("sad_count\t\t%1\n").arg(m_e.sad_count);
409  return result;
410 }
411 
412 bool eld::isValid() const
413 {
414  return m_e.eld_valid;
415 }
416 
417 void eld::show()
418 {
419  if (!isValid())
420  {
421  VBAUDIO("Invalid ELD");
422  return;
423  }
424  VBAUDIO(QString("Detected monitor %1 at connection type %2")
425  .arg(product_name().simplified(), connection_name()));
426 
427  if (m_e.spk_alloc)
428  {
429  VBAUDIO(QString("available speakers:%1")
430  .arg(channel_allocation_desc()));
431  }
432  VBAUDIO(QString("max LPCM channels = %1").arg(maxLPCMChannels()));
433  VBAUDIO(QString("max channels = %1").arg(maxChannels()));
434  VBAUDIO(QString("supported codecs = %1").arg(codecs_desc()));
435  for (int i = 0; i < m_e.sad_count; i++)
436  {
437  VBAUDIO(sad_desc(i));
438  }
439 }
440 
441 QString eld::product_name() const
442 {
443  return m_e.monitor_name;
444 }
445 
446 QString eld::connection_name() const
447 {
449 }
450 
452 {
453  int channels = 2; // assume stereo at the minimum
454  for (int i = 0; i < m_e.sad_count; i++)
455  {
456  struct cea_sad *a = m_e.sad + i;
457  if (a->format == TYPE_LPCM)
458  {
459  if (a->channels > channels)
460  channels = a->channels;
461  }
462  }
463  return channels;
464 }
465 
467 {
468  int channels = 2; // assume stereo at the minimum
469  for (int i = 0; i < m_e.sad_count; i++)
470  {
471  struct cea_sad *a = m_e.sad + i;
472  if (a->channels > channels)
473  channels = a->channels;
474  }
475  return channels;
476 }
477 
478 QString eld::codecs_desc() const
479 {
480  QString result = QString();
481  bool found_one = false;
482  for (size_t i = 0; i < audiotype_names.size(); i++)
483  {
484  if ((m_e.formats & (1 << i)) != 0)
485  {
486  if (found_one)
487  result += ", ";
488  result += audiotype_names[i];
489  found_one = true;
490  }
491  }
492  return result;
493 }
eld::TYPE_HE_AAC
@ TYPE_HE_AAC
Definition: eldutils.h:75
eld::eld_data::spk_alloc
int spk_alloc
Definition: eldutils.h:119
eld_versions
eld_versions
Definition: eldutils.cpp:37
eld::TYPE_WMAPRO
@ TYPE_WMAPRO
Definition: eldutils.h:72
VBAUDIO
#define VBAUDIO(str)
Definition: audiooutputbase.h:19
eld::TYPE_MLP
@ TYPE_MLP
Definition: eldutils.h:70
XTYPE_MPEG_SURROUND
@ XTYPE_MPEG_SURROUND
Definition: eldutils.cpp:78
GRAB_BITS
#define GRAB_BITS(buf, byte, lowbit, bits)
Definition: eldutils.cpp:137
SNDRV_PCM_RATE_176400
#define SNDRV_PCM_RATE_176400
Definition: eldutils.cpp:123
eld::show
void show()
Definition: eldutils.cpp:417
eld::eld_data::conn_type
int conn_type
Definition: eldutils.h:117
eld::connection_name
QString connection_name() const
Definition: eldutils.cpp:446
eld::cea_sad::profile
int profile
Definition: eldutils.h:98
eld
Definition: eldutils.h:37
CEA_EDID_VER_CEA861BCD
@ CEA_EDID_VER_CEA861BCD
Definition: eldutils.cpp:48
eld::eld_data::sad_count
int sad_count
Definition: eldutils.h:120
CEA_EDID_VER_CEA861
@ CEA_EDID_VER_CEA861
Definition: eldutils.cpp:46
eld::TYPE_EAC3
@ TYPE_EAC3
Definition: eldutils.h:68
SNDRV_PCM_RATE_88200
#define SNDRV_PCM_RATE_88200
Definition: eldutils.cpp:121
eld::cea_sad::format
int format
Definition: eldutils.h:94
eld::m_e
eld_data m_e
Definition: eldutils.h:125
eld::maxLPCMChannels
int maxLPCMChannels()
Definition: eldutils.cpp:451
eld::TYPE_SACD
@ TYPE_SACD
Definition: eldutils.h:67
eld::TYPE_ATRAC
@ TYPE_ATRAC
Definition: eldutils.h:66
eld::print_pcm_rates
static QString print_pcm_rates(int pcm)
SNDRV_PCM_RATE_* and AC_PAR_PCM values don't match, print correct rates with hdmi-specific routine.
Definition: eldutils.cpp:305
eld::TYPE_MPEG2
@ TYPE_MPEG2
Definition: eldutils.h:63
XTYPE_FIRST_RESERVED
@ XTYPE_FIRST_RESERVED
Definition: eldutils.cpp:79
eld::eld_data::support_ai
int support_ai
Definition: eldutils.h:116
eld::TYPE_REF_STREAM_HEADER
@ TYPE_REF_STREAM_HEADER
Definition: eldutils.h:58
cea_audio_coding_xtypes
cea_audio_coding_xtypes
Definition: eldutils.cpp:73
ELD_FIXED_BYTES
#define ELD_FIXED_BYTES
Definition: eldutils.h:30
eldutils.h
tmp
static guint32 * tmp
Definition: goom_core.cpp:31
ELD_VER_PARTIAL
@ ELD_VER_PARTIAL
Definition: eldutils.cpp:40
eld::TYPE_MPEG1
@ TYPE_MPEG1
Definition: eldutils.h:61
eld::cea_sad::rates
int rates
Definition: eldutils.h:95
eld::update_eld
int update_eld(const char *buf, int size)
Definition: eldutils.cpp:235
eld::update_sad
void update_sad(int index, const char *buf)
Definition: eldutils.cpp:167
cea_sampling_frequencies
static const std::array< const int, 8 > cea_sampling_frequencies
Definition: eldutils.cpp:126
eld::eld
eld()
Definition: eldutils.cpp:153
eld::eld_data::eld_ver
int eld_ver
Definition: eldutils.h:108
eld::cea_sad::sample_bits
int sample_bits
Definition: eldutils.h:96
eld::operator=
eld & operator=(const eld &)
Definition: eldutils.cpp:159
SNDRV_PCM_RATE_48000
#define SNDRV_PCM_RATE_48000
Definition: eldutils.cpp:119
CEA_EDID_VER_RESERVED
@ CEA_EDID_VER_RESERVED
Definition: eldutils.cpp:49
eld::eld_data::manufacture_id
int manufacture_id
Definition: eldutils.h:111
eld::TYPE_DTS
@ TYPE_DTS
Definition: eldutils.h:65
eld::eld_data::formats
uint64_t formats
Definition: eldutils.h:114
cea_edid_versions
cea_edid_versions
Definition: eldutils.cpp:43
eld::maxChannels
int maxChannels()
Definition: eldutils.cpp:466
eld::product_name
QString product_name() const
Definition: eldutils.cpp:441
SNDRV_PCM_RATE_32000
#define SNDRV_PCM_RATE_32000
Definition: eldutils.cpp:117
eld::eld_data::port_id
uint64_t port_id
Definition: eldutils.h:113
eld::eld_data::baseline_len
int baseline_len
Definition: eldutils.h:107
eld::print_pcm_bits
static QString print_pcm_bits(int pcm)
Print the supported PCM fmt bits to the string buffer.
Definition: eldutils.cpp:326
eld::channel_allocation_desc
QString channel_allocation_desc() const
Definition: eldutils.cpp:363
eld::edid_version_name
QString edid_version_name() const
Definition: eldutils.cpp:387
eld::eld_data::eld_valid
bool eld_valid
Definition: eldutils.h:105
eld::TYPE_DTS_HD
@ TYPE_DTS_HD
Definition: eldutils.h:69
XTYPE_HE_REF_CT
@ XTYPE_HE_REF_CT
Definition: eldutils.cpp:75
eld_connection_type_names
static const std::array< const QString, 4 > eld_connection_type_names
Definition: eldutils.cpp:66
SNDRV_PCM_RATE_44100
#define SNDRV_PCM_RATE_44100
Definition: eldutils.cpp:118
eld::TYPE_AC3
@ TYPE_AC3
Definition: eldutils.h:60
audiooutputbase.h
ELD_VER_CEA_861D
@ ELD_VER_CEA_861D
Definition: eldutils.cpp:39
XTYPE_HE_AAC2
@ XTYPE_HE_AAC2
Definition: eldutils.cpp:77
SNDRV_PCM_RATE_192000
#define SNDRV_PCM_RATE_192000
Definition: eldutils.cpp:124
CEA_EDID_VER_NONE
@ CEA_EDID_VER_NONE
Definition: eldutils.cpp:45
eld::TYPE_MP3
@ TYPE_MP3
Definition: eldutils.h:62
eld::eld_data::eld_size
int eld_size
Definition: eldutils.h:106
eld::TYPE_AACLC
@ TYPE_AACLC
Definition: eldutils.h:64
CEA_EDID_VER_CEA861A
@ CEA_EDID_VER_CEA861A
Definition: eldutils.cpp:47
cea_speaker_allocation_names
static const std::array< const QString, 11 > cea_speaker_allocation_names
Definition: eldutils.cpp:52
eld::eld_version_name
QString eld_version_name() const
Definition: eldutils.cpp:377
XTYPE_HE_AAC
@ XTYPE_HE_AAC
Definition: eldutils.cpp:76
eld::eld_data::monitor_name
QString monitor_name
Definition: eldutils.h:110
eld::eld_data::support_hdcp
int support_hdcp
Definition: eldutils.h:115
eld::cea_sad
Definition: eldutils.h:92
eld::TYPE_DST
@ TYPE_DST
Definition: eldutils.h:71
audiotype_names
static const std::array< const QString, 18 > audiotype_names
Definition: eldutils.cpp:82
eld::TYPE_LPCM
@ TYPE_LPCM
Definition: eldutils.h:59
eld::eld_data::product_id
int product_id
Definition: eldutils.h:112
eld::cea_sad::max_bitrate
int max_bitrate
Definition: eldutils.h:97
eld::eld_data::cea_edid_ver
int cea_edid_ver
Definition: eldutils.h:109
eld::codecs_desc
QString codecs_desc() const
Definition: eldutils.cpp:478
eld::eld_data::aud_synch_delay
int aud_synch_delay
Definition: eldutils.h:118
eld::isValid
bool isValid() const
Definition: eldutils.cpp:412
eld::sad_desc
QString sad_desc(int index)
Definition: eldutils.cpp:341
SNDRV_PCM_RATE_96000
#define SNDRV_PCM_RATE_96000
Definition: eldutils.cpp:122
eld::TYPE_REF_CXT
@ TYPE_REF_CXT
Definition: eldutils.h:73
eld::info_desc
QString info_desc() const
Definition: eldutils.cpp:399
eld::eld_data::sad
struct cea_sad sad[ELD_MAX_SAD]
Definition: eldutils.h:122
eld::cea_sad::channels
int channels
Definition: eldutils.h:93