MythTV  master
cddecoder.cpp
Go to the documentation of this file.
1 #define DO_NOT_WANT_PARANOIA_COMPATIBILITY
2 #include "cddecoder.h"
3 
4 // C
5 #include <cstdlib>
6 #include <cstring>
7 #include <unistd.h>
8 
9 // Qt
10 #include <QFile>
11 #include <QIODevice>
12 #include <QObject>
13 #include <QString>
14 
15 // libcdio
16 // cdda already included via cddecoder.h
17 #include <cdio/logging.h>
18 
19 // MythTV
21 #include <libmyth/mythcontext.h>
23 
24 extern "C" {
25 #include <libavcodec/avcodec.h>
26 }
27 
28 // MythMusic
29 #include "constants.h"
30 
31 static constexpr const char* CDEXT { ".cda" };
32 static constexpr long kSamplesPerSec { 44100 };
33 
34 // Handle cdio log output
35 static void logger(cdio_log_level_t level, const char *message)
36 {
37  switch (level)
38  {
39  case CDIO_LOG_DEBUG:
40  break;
41  case CDIO_LOG_INFO:
42  LOG(VB_MEDIA, LOG_DEBUG, QString("INFO cdio: %1").arg(message));
43  break;
44  case CDIO_LOG_WARN:
45  LOG(VB_MEDIA, LOG_DEBUG, QString("WARN cdio: %1").arg(message));
46  break;
47  case CDIO_LOG_ERROR:
48  case CDIO_LOG_ASSERT:
49  LOG(VB_GENERAL, LOG_ERR, QString("ERROR cdio: %1").arg(message));
50  break;
51  }
52 }
53 
54 // Open a cdio device
55 static CdIo_t * openCdio(const QString& name)
56 {
57  // Setup log handler
58  static int s_logging;
59  if (!s_logging)
60  {
61  s_logging = 1;
62  cdio_log_set_handler(&logger);
63  }
64 
65  CdIo_t *cdio = cdio_open(name.toLatin1(), DRIVER_DEVICE);
66  if (!cdio)
67  {
68  LOG(VB_MEDIA, LOG_INFO, QString("CdDecoder: cdio_open(%1) failed").
69  arg(name));
70  }
71  return cdio;
72 }
73 
74 // Stack-based cdio device open
76 {
77  CdIo_t* m_cdio {nullptr};
78 
79  void* operator new(std::size_t); // Stack only
80  // No copying
81  StCdioDevice(const StCdioDevice&);
83 
84 public:
85  explicit StCdioDevice(const QString& dev) : m_cdio(openCdio(dev)) { }
86  ~StCdioDevice() { if (m_cdio) cdio_destroy(m_cdio); }
87 
88  operator CdIo_t*() const { return m_cdio; } // NOLINT(google-explicit-constructor)
89 };
90 
91 
93  Decoder(d, o)
94 {
95  setURL(file);
96 }
97 
98 // virtual
100 {
101  if (m_inited)
102  deinit();
103 }
104 
105 void CdDecoder::setDevice(const QString &dev)
106 {
107  m_deviceName = dev;
108 #ifdef WIN32
109  // libcdio needs the drive letter with no path
110  if (m_deviceName.endsWith('\\'))
111  m_deviceName.chop(1);
112 #endif
113 }
114 
115 // pure virtual
117 {
118  m_userStop = true;
119 }
120 
121 // private
123 {
124  while (m_seekTime <= +0.)
125  {
126  if(output()->AddFrames(m_outputBuf, m_bksFrames, -1ms))
127  {
128  if (m_outputAt >= m_bks)
129  {
130  m_outputAt -= m_bks;
131  std::memmove(m_outputBuf, m_outputBuf + m_bks, m_outputAt);
132  }
133  break;
134  }
135  ::usleep(output()->GetAudioBufferedTime().count()<<9);
136  }
137 }
138 
139 //static
140 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
141 QMutex& CdDecoder::getCdioMutex()
142 {
143  static QMutex s_mtx(QMutex::Recursive);
144  return s_mtx;
145 }
146 #else
147 QRecursiveMutex& CdDecoder::getCdioMutex()
148 {
149  static QRecursiveMutex s_mtx;
150  return s_mtx;
151 }
152 #endif
153 
154 // pure virtual
156 {
157  if (m_inited)
158  return true;
159 
160  m_inited = m_userStop = m_finish = false;
161  m_freq = m_bitrate = 0L;
163  m_chan = 0;
164  m_seekTime = -1.;
165 
166  if (output())
168 
169  m_trackNum = getURL().section('.', 0, 0).toUInt();
170 
171  QMutexLocker lock(&getCdioMutex());
172 
173  m_cdio = openCdio(m_deviceName);
174  if (!m_cdio)
175  return false;
176 
177  m_start = cdio_get_track_lsn(m_cdio, m_trackNum);
178  m_end = cdio_get_track_last_lsn(m_cdio, m_trackNum);
179  if (CDIO_INVALID_LSN == m_start ||
180  CDIO_INVALID_LSN == m_end)
181  {
182  LOG(VB_MEDIA, LOG_INFO, "CdDecoder: No tracks on " + m_deviceName);
183  cdio_destroy(m_cdio), m_cdio = nullptr;
184  return false;
185  }
186 
187  LOG(VB_MEDIA, LOG_DEBUG, QString("CdDecoder track=%1 lsn start=%2 end=%3")
188  .arg(m_trackNum).arg(m_start).arg(m_end));
189  m_curPos = m_start;
190 
191  m_device = cdio_cddap_identify_cdio(m_cdio, 0, nullptr);
192  if (nullptr == m_device)
193  {
194  LOG(VB_GENERAL, LOG_ERR,
195  QString("Error: CdDecoder: cdio_cddap_identify(%1) failed")
196  .arg(m_deviceName));
197  cdio_destroy(m_cdio), m_cdio = nullptr;
198  return false;
199  }
200 
201  cdio_cddap_verbose_set(m_device,
202  VERBOSE_LEVEL_CHECK(VB_MEDIA, LOG_ANY) ? CDDA_MESSAGE_PRINTIT :
203  CDDA_MESSAGE_FORGETIT,
204  VERBOSE_LEVEL_CHECK(VB_MEDIA, LOG_DEBUG) ? CDDA_MESSAGE_PRINTIT :
205  CDDA_MESSAGE_FORGETIT);
206 
207  if (DRIVER_OP_SUCCESS == cdio_cddap_open(m_device))
208  {
209  // cdio_get_track_last_lsn is unreliable on discs with data at end
210  lsn_t end2 = cdio_cddap_track_lastsector(m_device, m_trackNum);
211  if (end2 < m_end)
212  {
213  LOG(VB_MEDIA, LOG_INFO, QString("CdDecoder: trim last lsn from %1 to %2")
214  .arg(m_end).arg(end2));
215  m_end = end2;
216  }
217 
218  // FIXME can't use cdio_paranoia until we find a way to cleanly
219  // detect when the user has ejected a CD otherwise we enter a
220  // recursive loop in cdio_paranoia_read_limited()
221  //m_paranoia = cdio_paranoia_init(m_device);
222  if (nullptr != m_paranoia)
223  {
224  cdio_paranoia_modeset(m_paranoia, PARANOIA_MODE_DISABLE);
225  (void)cdio_paranoia_seek(m_paranoia, m_start, SEEK_SET);
226  }
227  else
228  {
229  LOG(VB_GENERAL, LOG_WARNING, "CD reading with paranoia is disabled");
230  }
231  }
232  else
233  {
234  LOG(VB_GENERAL, LOG_ERR,
235  QString("Warn: drive '%1' is not cdda capable").
236  arg(m_deviceName));
237  }
238 
239  int chnls = cdio_get_track_channels(m_cdio, m_trackNum);
240  m_chan = chnls > 0 ? chnls : 2;
242 
243  if (output())
244  {
245  const AudioSettings settings(FORMAT_S16, m_chan,
246  AV_CODEC_ID_PCM_S16LE, m_freq, false /* AC3/DTS passthru */);
247  output()->Reconfigure(settings);
249  }
250 
251  // 20ms worth
252  m_bks = (m_freq * m_chan * 2) / 50;
253  m_bksFrames = m_freq / 50;
254  // decode 8 bks worth of samples each time we need more
255  m_decodeBytes = m_bks << 3;
256 
257  m_outputBuf = reinterpret_cast< char* >(
258  ::av_malloc(m_decodeBytes + CDIO_CD_FRAMESIZE_RAW * 2));
259  m_outputAt = 0;
260 
261  setCDSpeed(2);
262 
263  m_inited = true;
264 
265  return m_inited;
266 }
267 
268 // pure virtual
269 void CdDecoder::seek(double pos)
270 {
271  m_seekTime = pos;
272  if (output())
274 }
275 
276 // private
278 {
279  setCDSpeed(-1);
280 
281  QMutexLocker lock(&getCdioMutex());
282 
283  if (m_paranoia)
284  cdio_paranoia_free(m_paranoia), m_paranoia = nullptr;
285  if (m_device)
286  cdio_cddap_close(m_device), m_device = nullptr, m_cdio = nullptr;
287  if (m_cdio)
288  cdio_destroy(m_cdio), m_cdio = nullptr;
289 
290  if (m_outputBuf)
291  ::av_free(m_outputBuf), m_outputBuf = nullptr;
292 
293  m_inited = m_userStop = m_finish = false;
294  m_freq = m_bitrate = 0L;
296  m_chan = 0;
297  setOutput(nullptr);
298 }
299 
300 // private virtual
302 {
303  RunProlog();
304 
305  if (!m_inited)
306  {
307  RunEpilog();
308  return;
309  }
310 
312  // NB block scope required to prevent re-entrancy
313  {
314  DecoderEvent e(m_stat);
315  dispatch(e);
316  }
317 
318  // account for possible frame expansion in aobase (upmix, float conv)
319  const std::size_t thresh = m_bks * 6;
320 
321  while (!m_finish && !m_userStop)
322  {
323  if (m_seekTime >= +0.)
324  {
325  m_curPos = m_start + static_cast< lsn_t >(
326  (m_seekTime * kSamplesPerSec) / CD_FRAMESAMPLES);
327  if (m_paranoia)
328  {
329  QMutexLocker lock(&getCdioMutex());
330  cdio_paranoia_seek(m_paranoia, m_curPos, SEEK_SET);
331  }
332 
333  m_outputAt = 0;
334  m_seekTime = -1.;
335  }
336 
337  if (m_outputAt < m_bks)
338  {
339  while (m_outputAt < m_decodeBytes &&
340  !m_finish && !m_userStop && m_seekTime <= +0.)
341  {
342  if (m_curPos < m_end)
343  {
344  QMutexLocker lock(&getCdioMutex());
345  if (m_paranoia)
346  {
347  int16_t *cdbuffer = cdio_paranoia_read_limited(
348  m_paranoia, nullptr, 10);
349  if (cdbuffer)
350  memcpy(&m_outputBuf[m_outputAt],
351  cdbuffer, CDIO_CD_FRAMESIZE_RAW);
352  }
353  else
354  {
355  driver_return_code_t c = cdio_read_audio_sector(
356  m_cdio, &m_outputBuf[m_outputAt], m_curPos);
357  if (DRIVER_OP_SUCCESS != c)
358  {
359  LOG(VB_MEDIA, LOG_DEBUG,
360  QString("cdio_read_audio_sector(%1) error %2").
361  arg(m_curPos).arg(c));
362  memset( &m_outputBuf[m_outputAt],
363  0, CDIO_CD_FRAMESIZE_RAW);
364 
365  // stop if we got an error
366  m_userStop = true;
367  }
368  }
369 
370  m_outputAt += CDIO_CD_FRAMESIZE_RAW;
371  ++(m_curPos);
372  }
373  else
374  {
375  m_finish = true;
376  }
377  }
378  }
379 
380  if (!output())
381  continue;
382 
383  // Wait until we need to decode or supply more samples
384  uint fill = 0;
385  uint total = 0;
386  while (!m_finish && !m_userStop && m_seekTime <= +0.)
387  {
388  output()->GetBufferStatus(fill, total);
389  // Make sure we have decoded samples ready and that the
390  // audiobuffer is reasonably populated
391  if (fill < (thresh << 6))
392  break;
393  // Wait for half of the buffer to drain
394  ::usleep(output()->GetAudioBufferedTime().count()<<9);
395  }
396 
397  // write a block if there's sufficient space for it
398  if (!m_userStop &&
399  m_outputAt >= m_bks &&
400  fill <= total - thresh)
401  {
402  writeBlock();
403  }
404  }
405 
406  if (m_userStop)
407  m_inited = false;
408  else if (output())
409  {
410  // Drain our buffer
411  while (m_outputAt >= m_bks)
412  writeBlock();
413 
414  // Drain ao buffer
415  output()->Drain();
416  }
417 
418  if (m_finish)
420  else if (m_userStop)
422  else
424 
425  // NB block scope required to step onto next track
426  {
427  DecoderEvent e(m_stat);
428  dispatch(e);
429  }
430 
431  deinit();
432 
433  RunEpilog();
434 }
435 
436 //public
437 void CdDecoder::setCDSpeed(int speed)
438 {
439  QMutexLocker lock(&getCdioMutex());
440 
442  if (cdio)
443  {
444  driver_return_code_t c = cdio_set_speed(cdio, speed >= 0 ? speed : 1);
445  if (DRIVER_OP_SUCCESS != c)
446  {
447  LOG(VB_MEDIA, LOG_INFO,
448  QString("Error: cdio_set_speed('%1',%2) failed").
449  arg(m_deviceName).arg(speed));
450  }
451  }
452 }
453 
454 //public
456 {
457  QMutexLocker lock(&getCdioMutex());
458 
460  if (!cdio)
461  return 0;
462 
463  track_t tracks = cdio_get_num_tracks(cdio);
464  if (CDIO_INVALID_TRACK != tracks)
465  LOG(VB_MEDIA, LOG_DEBUG, QString("getNumTracks = %1").arg(tracks));
466  else
467  tracks = -1;
468 
469  return tracks;
470 }
471 
472 //public
474 {
475  QMutexLocker lock(&getCdioMutex());
476 
478  if (!cdio)
479  return 0;
480 
481  int nAudio = 0;
482  const track_t last = cdio_get_last_track_num(cdio);
483  if (CDIO_INVALID_TRACK != last)
484  {
485  for (track_t t = cdio_get_first_track_num(cdio) ; t <= last; ++t)
486  {
487  if (TRACK_FORMAT_AUDIO == cdio_get_track_format(cdio, t))
488  ++nAudio;
489  }
490  LOG(VB_MEDIA, LOG_DEBUG, QString("getNumCDAudioTracks = %1").arg(nAudio));
491  }
492 
493  return nAudio;
494 }
495 
496 //public
498 {
499  m_setTrackNum = track;
500  return getMetadata();
501 }
502 
503 
504 // Create a TOC
505 static lsn_t s_lastAudioLsn;
506 
507 //virtual
509 {
510  QString artist;
511  QString album;
512  QString compilation_artist;
513  QString title;
514  QString genre;
515  int year = 0;
516  std::chrono::milliseconds length = 0s;
517  track_t tracknum = 0;
518 
519  if (-1 == m_setTrackNum)
520  tracknum = getURL().toUInt();
521  else
522  {
523  tracknum = m_setTrackNum;
524  setURL(QString("%1%2").arg(tracknum).arg(CDEXT));
525  }
526 
527  QMutexLocker lock(&getCdioMutex());
528 
530  if (!cdio)
531  return nullptr;
532 
533  const track_t lastTrack = cdio_get_last_track_num(cdio);
534  if (CDIO_INVALID_TRACK == lastTrack)
535  return nullptr;
536 
537  if (TRACK_FORMAT_AUDIO != cdio_get_track_format(cdio, tracknum))
538  return nullptr;
539 
540  // Assume disc changed if max LSN different
541  bool isDiscChanged = false;
542  static lsn_t s_totalSectors;
543  lsn_t totalSectors = cdio_get_track_lsn(cdio, CDIO_CDROM_LEADOUT_TRACK);
544  if (s_totalSectors != totalSectors)
545  {
546  s_totalSectors = totalSectors;
547  isDiscChanged = true;
548  }
549 
550  // NB cdio_get_track_last_lsn is unreliable for the last audio track
551  // of discs with data tracks beyond
552  lsn_t end = cdio_get_track_last_lsn(cdio, tracknum);
553  if (isDiscChanged)
554  {
555  const track_t audioTracks = getNumCDAudioTracks();
556  s_lastAudioLsn = cdio_get_track_last_lsn(cdio, audioTracks);
557 
558  if (audioTracks < lastTrack)
559  {
560  cdrom_drive_t *dev = cdio_cddap_identify_cdio(cdio, 0, nullptr);
561  if (nullptr != dev)
562  {
563  if (DRIVER_OP_SUCCESS == cdio_cddap_open(dev))
564  {
565  // NB this can be S L O W but is reliable
566  lsn_t end2 = cdio_cddap_track_lastsector(dev,
568  if (CDIO_INVALID_LSN != end2)
569  s_lastAudioLsn = end2;
570  }
571  cdio_cddap_close_no_free_cdio(dev);
572  }
573  }
574  }
575 
576  if (s_lastAudioLsn && s_lastAudioLsn < end)
577  end = s_lastAudioLsn;
578 
579  const lsn_t start = cdio_get_track_lsn(cdio, tracknum);
580  if (CDIO_INVALID_LSN != start && CDIO_INVALID_LSN != end)
581  {
582  length = std::chrono::milliseconds(((end - start + 1) * 1000 + CDIO_CD_FRAMES_PER_SEC/2) /
583  CDIO_CD_FRAMES_PER_SEC);
584  }
585 
586  bool isCompilation = false;
587 
588 // Disabled - cd-text access on discs without it is S L O W
589 #define CDTEXT 0 // NOLINT(cppcoreguidelines-macro-usage)
590 #if CDTEXT
591  static int s_iCdtext;
592  if (isDiscChanged)
593  s_iCdtext = -1;
594 
595  if (s_iCdtext)
596  {
597  // cdio_get_cdtext can't take >5 seconds on some CD's without cdtext
598  if (s_iCdtext < 0)
599  LOG(VB_MEDIA, LOG_INFO,
600  QString("Getting cdtext for track %1...").arg(tracknum));
601  cdtext_t * cdtext = cdio_get_cdtext(m_cdio, tracknum);
602  if (nullptr != cdtext)
603  {
604  genre = cdtext_get_const(CDTEXT_GENRE, cdtext);
605  artist = cdtext_get_const(CDTEXT_PERFORMER, cdtext);
606  title = cdtext_get_const(CDTEXT_TITLE, cdtext);
607  const char* isrc = cdtext_get_const(CDTEXT_ISRC, cdtext);
608  /* ISRC codes are 12 characters long, in the form CCXXXYYNNNNN
609  * CC = country code
610  * XXX = registrant e.g. BMG
611  * CC = year withou century
612  * NNNNN = unique ID
613  */
614  if (isrc && strlen(isrc) >= 7)
615  {
616  year = (isrc[5] - '0') * 10 + (isrc[6] - '0');
617  year += (year <= 30) ? 2000 : 1900;
618  }
619 
620  cdtext_destroy(cdtext);
621 
622  if (!title.isNull())
623  {
624  if (s_iCdtext < 0)
625  LOG(VB_MEDIA, LOG_INFO, "Found cdtext track title");
626  s_iCdtext = 1;
627 
628  // Get disc info
629  cdtext = cdio_get_cdtext(cdio, 0);
630  if (nullptr != cdtext)
631  {
632  compilation_artist = cdtext_get_const(
633  CDTEXT_PERFORMER, cdtext);
634  if (!compilation_artist.isEmpty() &&
635  artist != compilation_artist)
636  isCompilation = true;
637 
638  album = cdtext_get_const(CDTEXT_TITLE, cdtext);
639 
640  if (genre.isNull())
641  genre = cdtext_get_const(CDTEXT_GENRE, cdtext);
642 
643  cdtext_destroy(cdtext);
644  }
645  }
646  else
647  {
648  if (s_iCdtext < 0)
649  LOG(VB_MEDIA, LOG_INFO, "No cdtext title for track");
650  s_iCdtext = 0;
651  }
652  }
653  else
654  {
655  if (s_iCdtext < 0)
656  LOG(VB_MEDIA, LOG_INFO, "No cdtext");
657  s_iCdtext = 0;
658  }
659  }
660 
661  if (title.isEmpty() || artist.isEmpty() || album.isEmpty())
662 #endif // CDTEXT
663  {
664  //TODO: add MusicBrainz lookup
665  }
666 
667  if (compilation_artist.toLower().left(7) == "various")
668  compilation_artist = tr("Various Artists");
669 
670  if (artist.isEmpty())
671  {
672  artist = compilation_artist;
673  compilation_artist.clear();
674  }
675 
676  if (title.isEmpty())
677  title = tr("Track %1").arg(tracknum);
678 
679  auto *m = new MusicMetadata(getURL(), artist, compilation_artist, album,
680  title, genre, year, tracknum, length);
681  if (m)
682  m->setCompilation(isCompilation);
683 
684  return m;
685 }
686 
687 // pure virtual
688 bool CdDecoderFactory::supports(const QString &source) const
689 {
690  return (source.right(extension().length()).toLower() == extension());
691 }
692 
693 // pure virtual
694 const QString &CdDecoderFactory::extension() const
695 {
696  static QString s_ext(CDEXT);
697  return s_ext;
698 }
699 
700 // pure virtual
701 const QString &CdDecoderFactory::description() const
702 {
703  static QString s_desc(tr("Audio CD parser"));
704  return s_desc;
705 }
706 
707 // pure virtual
708 Decoder *CdDecoderFactory::create(const QString &file, AudioOutput *output, bool deletable)
709 {
710  if (deletable)
711  return new CdDecoder(file, this, output);
712 
713  static CdDecoder *s_decoder;
714  if (! s_decoder)
715  {
716  s_decoder = new CdDecoder(file, this, output);
717  }
718  else
719  {
720  s_decoder->setURL(file);
721  s_decoder->setOutput(output);
722  }
723 
724  return s_decoder;
725 }
726 
CdDecoder::getMetadata
MusicMetadata * getMetadata(void)
Definition: cddecoder.cpp:508
CdDecoder::m_setTrackNum
int m_setTrackNum
Definition: cddecoder.h:76
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
CdDecoder::m_seekTime
double m_seekTime
Definition: cddecoder.h:74
CdDecoder::m_bitrate
long m_bitrate
Definition: cddecoder.h:72
FORMAT_S16
@ FORMAT_S16
Definition: audiooutputsettings.h:27
CdDecoder::m_decodeBytes
std::size_t m_decodeBytes
Definition: cddecoder.h:69
s_mtx
static QMutex s_mtx
Definition: netstream.cpp:52
CdDecoderFactory::description
const QString & description() const override
Definition: cddecoder.cpp:701
CdDecoder::deinit
void deinit()
Definition: cddecoder.cpp:277
CdDecoder::getCdioMutex
static QRecursiveMutex & getCdioMutex()
Definition: cddecoder.cpp:147
CdDecoderFactory::create
Decoder * create(const QString &file, AudioOutput *output, bool deletable) override
Definition: cddecoder.cpp:708
MThread::usleep
static void usleep(std::chrono::microseconds time)
Definition: mthread.cpp:335
CdDecoder::writeBlock
void writeBlock()
Definition: cddecoder.cpp:122
VERBOSE_LEVEL_CHECK
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
CdDecoder::initialize
bool initialize() override
Definition: cddecoder.cpp:155
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
StCdioDevice::StCdioDevice
StCdioDevice(const QString &dev)
Definition: cddecoder.cpp:85
MusicMetadata
Definition: musicmetadata.h:80
DecoderFactory
Definition: decoder.h:117
build_compdb.file
file
Definition: build_compdb.py:55
StCdioDevice::StCdioDevice
StCdioDevice(const StCdioDevice &)
MythObservable::dispatch
void dispatch(const MythEvent &event)
Dispatch an event to all listeners.
Definition: mythobservable.cpp:73
StCdioDevice::m_cdio
CdIo_t * m_cdio
Definition: cddecoder.cpp:77
AudioOutput::Drain
virtual void Drain(void)=0
AudioSettings
Definition: audiosettings.h:28
cddecoder.h
StCdioDevice::operator=
StCdioDevice & operator=(const StCdioDevice &)
StCdioDevice
Definition: cddecoder.cpp:75
AudioOutput
Definition: audiooutput.h:26
CdDecoder::m_userStop
volatile bool m_userStop
Definition: cddecoder.h:53
Decoder
Definition: decoder.h:70
CdDecoder::seek
void seek(double pos) override
Definition: cddecoder.cpp:269
kSamplesPerSec
static constexpr long kSamplesPerSec
Definition: cddecoder.cpp:32
CdDecoder
Definition: cddecoder.h:20
CdDecoder::setCDSpeed
void setCDSpeed(int speed)
Definition: cddecoder.cpp:437
s_lastAudioLsn
static lsn_t s_lastAudioLsn
Definition: cddecoder.cpp:505
hardwareprofile.i18n.t
t
Definition: i18n.py:36
AudioOutput::SetSourceBitrate
virtual void SetSourceBitrate(int)
Definition: audiooutput.h:146
DecoderEvent
Definition: decoder.h:29
CdDecoder::m_outputAt
std::size_t m_outputAt
Definition: cddecoder.h:65
CdDecoder::m_bksFrames
std::size_t m_bksFrames
Definition: cddecoder.h:68
StCdioDevice::~StCdioDevice
~StCdioDevice()
Definition: cddecoder.cpp:86
CdDecoder::m_inited
volatile bool m_inited
Definition: cddecoder.h:52
CDEXT
static constexpr const char * CDEXT
Definition: cddecoder.cpp:31
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
CdDecoder::m_freq
long m_freq
Definition: cddecoder.h:71
Decoder::getURL
QString getURL(void) const
Definition: decoder.h:91
DecoderEvent::kStopped
static const Type kStopped
Definition: decoder.h:46
uint
unsigned int uint
Definition: compat.h:81
CdDecoder::~CdDecoder
~CdDecoder() override
Definition: cddecoder.cpp:99
CdDecoder::setDevice
void setDevice(const QString &dev)
Definition: cddecoder.cpp:105
Decoder::setURL
void setURL(const QString &url)
Definition: decoder.h:83
CdDecoder::getNumTracks
int getNumTracks()
Definition: cddecoder.cpp:455
CdDecoderFactory::supports
bool supports(const QString &source) const override
Definition: cddecoder.cpp:688
CdDecoder::CdDecoder
CdDecoder(const QString &file, DecoderFactory *d, AudioOutput *o)
Definition: cddecoder.cpp:92
AudioOutput::Reconfigure
virtual void Reconfigure(const AudioSettings &settings)=0
DecoderEvent::kFinished
static const Type kFinished
Definition: decoder.h:47
CdDecoder::m_stat
DecoderEvent::Type m_stat
Definition: cddecoder.h:63
CdDecoder::getNumCDAudioTracks
int getNumCDAudioTracks()
Definition: cddecoder.cpp:473
DecoderEvent::kDecoding
static const Type kDecoding
Definition: decoder.h:45
CdDecoder::run
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: cddecoder.cpp:301
CdDecoder::m_deviceName
QString m_deviceName
Definition: cddecoder.h:55
AudioOutput::GetBufferStatus
virtual void GetBufferStatus(uint &fill, uint &total)
Definition: audiooutput.h:151
constants.h
audiooutput.h
Decoder::setOutput
void setOutput(AudioOutput *o)
Definition: decoder.cpp:45
CdDecoder::m_bks
std::size_t m_bks
Definition: cddecoder.h:67
logger
static void logger(cdio_log_level_t level, const char *message)
Definition: cddecoder.cpp:35
mythcontext.h
CdDecoder::m_chan
int m_chan
Definition: cddecoder.h:73
Decoder::lock
virtual void lock(void)
Definition: decoder.h:85
d
static const iso6937table * d
Definition: iso6937tables.cpp:1025
Decoder::output
AudioOutput * output()
Definition: decoder.h:81
CdDecoderFactory::extension
const QString & extension() const override
Definition: cddecoder.cpp:694
CdDecoder::stop
void stop() override
Definition: cddecoder.cpp:116
output
#define output
Definition: synaesthesia.cpp:220
CdDecoder::m_trackNum
int m_trackNum
Definition: cddecoder.h:77
DecoderEvent::kError
static const Type kError
Definition: decoder.h:48
AudioOutput::PauseUntilBuffered
virtual void PauseUntilBuffered(void)=0
musicmetadata.h
CdDecoder::m_outputBuf
char * m_outputBuf
Definition: cddecoder.h:64
openCdio
static CdIo_t * openCdio(const QString &name)
Definition: cddecoder.cpp:55
CdDecoder::m_finish
bool m_finish
Definition: cddecoder.h:70