MythTV  master
audiooutputalsa.cpp
Go to the documentation of this file.
1 #include <cstdint>
2 #include <cstdio>
3 #include <cstdlib>
4 #include <ctime>
5 #include <sys/time.h>
6 
7 #include "config.h"
8 
9 using namespace std;
10 
11 #include <QFile>
12 #include "mythcorecontext.h"
13 #include "audiooutputalsa.h"
14 
15 #define LOC QString("ALSA: ")
16 
17 // redefine assert as no-op to quiet some compiler warnings
18 // about assert always evaluating true in alsa headers.
19 #undef assert
20 #define assert(x)
21 
22 #define CHANNELS_MIN 1
23 #define CHANNELS_MAX 8
24 
25 #define OPEN_FLAGS (SND_PCM_NO_AUTO_RESAMPLE|SND_PCM_NO_AUTO_FORMAT| \
26  SND_PCM_NO_AUTO_CHANNELS)
27 
28 #define FILTER_FLAGS ~(SND_PCM_NO_AUTO_FORMAT)
29 
30 #define AERROR(str) VBERROR((str) + QString(": %1").arg(snd_strerror(err)))
31 #define CHECKERR(str) { if (err < 0) { AERROR(str); return err; } }
32 
34  AudioOutputBase(settings)
35 {
36  m_mixer.handle = nullptr;
37  m_mixer.elem = nullptr;
38 
39  // Set everything up
40  if (m_passthru_device == "auto")
41  {
43 
44  int len = m_passthru_device.length();
45  int args = m_passthru_device.indexOf(":");
46 
47  /*
48  * AES description:
49  * AES0=6 AES1=0x82 AES2=0x00 AES3=0x01.
50  * AES0 = NON_AUDIO | PRO_MODE
51  * AES1 = original stream, original PCM coder
52  * AES2 = source and channel unspecified
53  * AES3 = sample rate unspecified
54  */
55  bool s48k = gCoreContext->GetBoolSetting("SPDIFRateOverride", false);
56  QString iecarg = QString("AES0=6,AES1=0x82,AES2=0x00") +
57  (s48k ? QString() : QString(",AES3=0x01"));
58  QString iecarg2 = QString("AES0=6 AES1=0x82 AES2=0x00") +
59  (s48k ? QString() : QString(" AES3=0x01"));
60 
61  if (args < 0)
62  {
63  /* no existing parameters: add it behind device name */
64  m_passthru_device += ":" + iecarg;
65  }
66  else
67  {
68  do
69  ++args;
70  while (args < m_passthru_device.length() &&
71  m_passthru_device[args].isSpace());
72  if (args == m_passthru_device.length())
73  {
74  /* ":" but no parameters */
75  m_passthru_device += iecarg;
76  }
77  else if (m_passthru_device[args] != '{')
78  {
79  /* a simple list of parameters: add it at the end of the list */
80  m_passthru_device += "," + iecarg;
81  }
82  else
83  {
84  /* parameters in config syntax: add it inside the { } block */
85  do
86  --len;
87  while (len > 0 && m_passthru_device[len].isSpace());
88  if (m_passthru_device[len] == '}')
90  m_passthru_device.insert(len, " " + iecarg2);
91  }
92  }
93  }
94  else if (m_passthru_device.toLower() == "default")
96  else
97  m_discretedigital = true;
98 
99  InitSettings(settings);
100  if (settings.m_init)
101  Reconfigure(settings);
102 }
103 
105 {
106  KillAudio();
107 }
108 
109 int AudioOutputALSA::TryOpenDevice(int open_mode, bool try_ac3)
110 {
111  QString real_device;
112  QByteArray dev_ba;
113  int err = -1;
114 
115  if (try_ac3)
116  {
117  dev_ba = m_passthru_device.toLatin1();
118  VBAUDIO(QString("OpenDevice %1 for passthrough").arg(m_passthru_device));
119  err = snd_pcm_open(&m_pcm_handle, dev_ba.constData(),
120  SND_PCM_STREAM_PLAYBACK, open_mode);
121 
123 
124  if (m_discretedigital)
125  return err;
126 
127  if (err < 0)
128  {
129  VBAUDIO(QString("Auto setting passthrough failed (%1), defaulting "
130  "to main device").arg(snd_strerror(err)));
131  }
132  }
133  if (!try_ac3 || err < 0)
134  {
135  // passthru open failed, retry default device
136  VBAUDIO(QString("OpenDevice %1").arg(m_main_device));
137  dev_ba = m_main_device.toLatin1();
138  err = snd_pcm_open(&m_pcm_handle, dev_ba.constData(),
139  SND_PCM_STREAM_PLAYBACK, open_mode);
141  }
142  return err;
143 }
144 
145 int AudioOutputALSA::GetPCMInfo(int &card, int &device, int &subdevice)
146 {
147  // Check for saved values
148  if (m_card != -1 && m_device != -1 && m_subdevice != -1)
149  {
150  card = m_card;
151  device = m_device;
152  subdevice = m_subdevice;
153  return 0;
154  }
155 
156  if (!m_pcm_handle)
157  return -1;
158 
159  int err;
160  snd_pcm_info_t *pcm_info = nullptr;
161  int tcard, tdevice, tsubdevice;
162 
163  snd_pcm_info_alloca(&pcm_info);
164 
165  err = snd_pcm_info(m_pcm_handle, pcm_info);
166  CHECKERR("snd_pcm_info");
167 
168  err = snd_pcm_info_get_card(pcm_info);
169  CHECKERR("snd_pcm_info_get_card");
170  tcard = err;
171 
172  err = snd_pcm_info_get_device(pcm_info);
173  CHECKERR("snd_pcm_info_get_device");
174  tdevice = err;
175 
176  err = snd_pcm_info_get_subdevice(pcm_info);
177  CHECKERR("snd_pcm_info_get_subdevice");
178  tsubdevice = err;
179 
180  m_card = card = tcard;
181  m_device = device = tdevice;
182  m_subdevice = subdevice = tsubdevice;
183 
184  return 0;
185  }
186 
187 bool AudioOutputALSA::IncPreallocBufferSize(int requested, int buffer_time)
188 {
189  int card, device, subdevice;
190 
191  m_pbufsize = 0;
192 
193  if (GetPCMInfo(card, device, subdevice) < 0)
194  return false;
195 
196  const QString pf = QString("/proc/asound/card%1/pcm%2p/sub%3/prealloc")
197  .arg(card).arg(device).arg(subdevice);
198 
199  QFile pfile(pf);
200  QFile mfile(pf + "_max");
201 
202  if (!pfile.open(QIODevice::ReadOnly))
203  {
204  VBERROR(QString("Error opening %1. Fix reading permissions.").arg(pf));
205  return false;
206  }
207 
208  if (!mfile.open(QIODevice::ReadOnly))
209  {
210  VBERROR(QString("Error opening %1").arg(pf + "_max"));
211  return false;
212  }
213 
214  int cur = pfile.readAll().trimmed().toInt();
215  int max = mfile.readAll().trimmed().toInt();
216 
217  int size = ((int)(cur * (float)requested / (float)buffer_time)
218  / 64 + 1) * 64;
219 
220  VBAUDIO(QString("Hardware audio buffer cur: %1 need: %2 max allowed: %3")
221  .arg(cur).arg(size).arg(max));
222 
223  if (cur == max)
224  {
225  // It's already the maximum it can be, no point trying further
226  pfile.close();
227  mfile.close();
228  return false;
229  }
230  if (size > max || !size)
231  {
232  size = max;
233  }
234 
235  pfile.close();
236  mfile.close();
237 
238  VBWARN(QString("Try to manually increase audio buffer with: echo %1 "
239  "| sudo tee %2").arg(size).arg(pf));
240  return false;
241 }
242 
243 QByteArray *AudioOutputALSA::GetELD(int card, int device, int subdevice)
244 {
245  QByteArray *result = nullptr;
246  snd_hctl_t *hctl;
247  snd_hctl_elem_t *elem;
248  snd_ctl_elem_info_t *info; snd_ctl_elem_info_alloca(&info);
249  snd_ctl_elem_id_t *id; snd_ctl_elem_id_alloca(&id);
250  snd_ctl_elem_value_t *control; snd_ctl_elem_value_alloca(&control);
251  snd_ctl_elem_type_t type;
252 
253  int err;
254 
255  snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM);
256  snd_ctl_elem_id_set_name(id, "ELD");
257  snd_ctl_elem_id_set_device(id, device);
258  snd_ctl_elem_id_set_subdevice(id, subdevice);
259  if ((err = snd_hctl_open(&hctl,
260  QString("hw:%1").arg(card).toLatin1().constData(),
261  0)) < 0)
262  {
263  VBAUDIO(QString("Control %1 open error: %2")
264  .arg(card)
265  .arg(snd_strerror(err)));
266  return nullptr;
267  }
268  if ((err = snd_hctl_load(hctl)) < 0)
269  {
270  VBAUDIO(QString("Control %1 load error: %2")
271  .arg(card)
272  .arg(snd_strerror(err)));
273  /* frees automatically the control which cannot be added. */
274  return nullptr;
275  }
276  elem = snd_hctl_find_elem(hctl, id);
277  if (elem)
278  {
279  if ((err = snd_hctl_elem_info(elem, info)) < 0)
280  {
281  VBAUDIO(QString("Control %1 snd_hctl_elem_info error: %2")
282  .arg(card)
283  .arg(snd_strerror(err)));
284  snd_hctl_close(hctl);
285  return nullptr;
286  }
287  unsigned int count = snd_ctl_elem_info_get_count(info);
288  type = snd_ctl_elem_info_get_type(info);
289  if (!snd_ctl_elem_info_is_readable(info))
290  {
291  VBAUDIO(QString("Control %1 element info is not readable")
292  .arg(card));
293  snd_hctl_close(hctl);
294  return nullptr;
295  }
296  if ((err = snd_hctl_elem_read(elem, control)) < 0)
297  {
298  VBAUDIO(QString("Control %1 element read error: %2")
299  .arg(card)
300  .arg(snd_strerror(err)));
301  snd_hctl_close(hctl);
302  return nullptr;
303  }
304  if (type != SND_CTL_ELEM_TYPE_BYTES)
305  {
306  VBAUDIO(QString("Control %1 element is of the wrong type")
307  .arg(card));
308  snd_hctl_close(hctl);
309  return nullptr;
310  }
311  result = new QByteArray((char *)snd_ctl_elem_value_get_bytes(control),
312  count);
313  }
314  snd_hctl_close(hctl);
315  return result;
316 }
317 
319 {
320  snd_pcm_hw_params_t *params;
321  snd_pcm_format_t afmt = SND_PCM_FORMAT_UNKNOWN;
322  AudioFormat fmt;
323  int err;
324 
325  AudioOutputSettings *settings = new AudioOutputSettings();
326 
327  if (m_pcm_handle)
328  {
329  snd_pcm_close(m_pcm_handle);
330  m_pcm_handle = nullptr;
331  }
332 
333  if ((err = TryOpenDevice(OPEN_FLAGS, passthrough)) < 0)
334  {
335  AERROR(QString("snd_pcm_open(\"%1\")").arg(m_lastdevice));
336  delete settings;
337  return nullptr;
338  }
339 
340  snd_pcm_hw_params_alloca(&params);
341 
342  if ((err = snd_pcm_hw_params_any(m_pcm_handle, params)) < 0)
343  {
344  snd_pcm_close(m_pcm_handle);
345  if ((err = TryOpenDevice(OPEN_FLAGS&FILTER_FLAGS, passthrough)) < 0)
346  {
347  AERROR(QString("snd_pcm_open(\"%1\")").arg(m_lastdevice));
348  delete settings;
349  return nullptr;
350  }
351  if ((err = snd_pcm_hw_params_any(m_pcm_handle, params)) < 0)
352  {
353  AERROR("No playback configurations available");
354  snd_pcm_close(m_pcm_handle);
355  m_pcm_handle = nullptr;
356  delete settings;
357  return nullptr;
358  }
359  Warn("Supported audio format detection will be inacurrate "
360  "(using plugin?)");
361  }
362 
363  while (int rate = settings->GetNextRate())
364  if(snd_pcm_hw_params_test_rate(m_pcm_handle, params, rate, 0) >= 0)
365  settings->AddSupportedRate(rate);
366 
367  while ((fmt = settings->GetNextFormat()))
368  {
369  switch (fmt)
370  {
371  case FORMAT_U8: afmt = SND_PCM_FORMAT_U8; break;
372  case FORMAT_S16: afmt = SND_PCM_FORMAT_S16; break;
373  case FORMAT_S24LSB: afmt = SND_PCM_FORMAT_S24; break;
374  case FORMAT_S24: afmt = SND_PCM_FORMAT_S32; break;
375  case FORMAT_S32: afmt = SND_PCM_FORMAT_S32; break;
376  case FORMAT_FLT: afmt = SND_PCM_FORMAT_FLOAT; break;
377  default: continue;
378  }
379  if (snd_pcm_hw_params_test_format(m_pcm_handle, params, afmt) >= 0)
380  settings->AddSupportedFormat(fmt);
381  }
382 
383  for (uint channels = CHANNELS_MIN; channels <= CHANNELS_MAX; channels++)
384  if (snd_pcm_hw_params_test_channels(m_pcm_handle, params, channels) >= 0)
385  settings->AddSupportedChannels(channels);
386 
387  int card, device, subdevice;
388  if (GetPCMInfo(card, device, subdevice) >= 0)
389  {
390  // Check if we can retrieve ELD for this device
391  QByteArray *eld = GetELD(card, device, subdevice);
392  if (eld != nullptr)
393  {
394  VBAUDIO(QString("Successfully retrieved ELD data"));
395  settings->setELD(eld);
396  delete eld;
397  }
398  }
399  else
400  {
401  VBAUDIO("Can't get card and device number");
402  }
403 
404  snd_pcm_close(m_pcm_handle);
405  m_pcm_handle = nullptr;
406 
407  /* Check if name or description contains information
408  to know if device can accept passthrough or not */
409  QMap<QString, QString> *alsadevs = GetDevices("pcm");
410  while (true)
411  {
412  QString real_device = ((passthrough && m_discretedigital) ?
414 
415  QString desc = alsadevs->value(real_device);
416 
417  settings->setPassthrough(1); // yes passthrough
418  if (real_device.contains("digital", Qt::CaseInsensitive) ||
419  desc.contains("digital", Qt::CaseInsensitive))
420  break;
421  if (real_device.contains("iec958", Qt::CaseInsensitive))
422  break;
423  if (real_device.contains("spdif", Qt::CaseInsensitive))
424  break;
425  if (real_device.contains("hdmi", Qt::CaseInsensitive))
426  break;
427 
428  settings->setPassthrough(-1); // no passthrough
429  // PulseAudio does not support passthrough
430  if (real_device.contains("pulse", Qt::CaseInsensitive) ||
431  desc.contains("pulse", Qt::CaseInsensitive))
432  break;
433  if (real_device.contains("analog", Qt::CaseInsensitive) ||
434  desc.contains("analog", Qt::CaseInsensitive))
435  break;
436  if (real_device.contains("surround", Qt::CaseInsensitive) ||
437  desc.contains("surround", Qt::CaseInsensitive))
438  break;
439 
440  settings->setPassthrough(0); // maybe passthrough
441  break;
442  }
443  delete alsadevs;
444  return settings;
445 }
446 
448 {
449  snd_pcm_format_t format;
450  uint buffer_time, period_time;
451  int err;
452 
453  if (m_pcm_handle != nullptr)
454  CloseDevice();
455 
456  if ((err = TryOpenDevice(0, m_passthru || m_enc)) < 0)
457  {
458  AERROR(QString("snd_pcm_open(\"%1\")").arg(m_lastdevice));
459  if (m_pcm_handle)
460  CloseDevice();
461  return false;
462  }
463 
464  switch (m_output_format)
465  {
466  case FORMAT_U8: format = SND_PCM_FORMAT_U8; break;
467  case FORMAT_S16: format = SND_PCM_FORMAT_S16; break;
468  case FORMAT_S24LSB: format = SND_PCM_FORMAT_S24; break;
469  case FORMAT_S24: format = SND_PCM_FORMAT_S32; break;
470  case FORMAT_S32: format = SND_PCM_FORMAT_S32; break;
471  case FORMAT_FLT: format = SND_PCM_FORMAT_FLOAT; break;
472  default:
473  Error(QObject::tr("Unknown sample format: %1").arg(m_output_format));
474  return false;
475  }
476 
477  // buffer 0.5s worth of samples
478  buffer_time = gCoreContext->GetNumSetting("ALSABufferOverride", 500) * 1000;
479 
480  period_time = 4; // aim for an interrupt every (1/4th of buffer_time)
481 
483  buffer_time, period_time);
484  if (err < 0)
485  {
486  AERROR("Unable to set ALSA parameters");
487  CloseDevice();
488  return false;
489  }
490 
491  if (internal_vol && !OpenMixer())
492  VBERROR("Unable to open audio mixer. Volume control disabled");
493 
494  // Device opened successfully
495  return true;
496 }
497 
499 {
500  if (m_mixer.handle)
501  snd_mixer_close(m_mixer.handle);
502  m_mixer.handle = nullptr;
503  if (m_pcm_handle)
504  {
505  snd_pcm_drain(m_pcm_handle);
506  snd_pcm_close(m_pcm_handle);
507  m_pcm_handle = nullptr;
508  }
509 }
510 
511 template <class AudioDataType>
512 static inline void _ReorderSmpteToAlsa(AudioDataType *buf, uint frames,
513  uint extrach)
514 {
515  AudioDataType tmpC, tmpLFE, *buf2;
516 
517  for (uint i = 0; i < frames; i++)
518  {
519  buf = buf2 = buf + 2;
520 
521  tmpC = *buf++;
522  tmpLFE = *buf++;
523  *buf2++ = *buf++;
524  *buf2++ = *buf++;
525  *buf2++ = tmpC;
526  *buf2++ = tmpLFE;
527  buf += extrach;
528  }
529 }
530 
531 static inline void ReorderSmpteToAlsa(void *buf, uint frames,
532  AudioFormat format, uint extrach)
533 {
534  switch(AudioOutputSettings::FormatToBits(format))
535  {
536  case 8: _ReorderSmpteToAlsa((uchar *)buf, frames, extrach); break;
537  case 16: _ReorderSmpteToAlsa((short *)buf, frames, extrach); break;
538  default: _ReorderSmpteToAlsa((int *)buf, frames, extrach); break;
539  }
540 }
541 
542 void AudioOutputALSA::WriteAudio(uchar *aubuf, int size)
543 {
544  uchar *tmpbuf = aubuf;
546  int err;
547 
548  if (m_pcm_handle == nullptr)
549  {
550  Error("WriteAudio() called with pcm_handle == nullptr!");
551  return;
552  }
553 
554  //Audio received is in SMPTE channel order, reorder to ALSA unless passthru
555  if (!m_passthru && (m_channels == 6 || m_channels == 8))
556  {
558  }
559 
560  LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO,
561  QString("WriteAudio: Preparing %1 bytes (%2 frames)")
562  .arg(size).arg(frames));
563 
564  while (frames > 0)
565  {
566  int lw = snd_pcm_writei(m_pcm_handle, tmpbuf, frames);
567 
568  if (lw >= 0)
569  {
570  if ((uint)lw < frames)
571  VBAUDIO(QString("WriteAudio: short write %1 bytes (ok)")
572  .arg(lw * m_output_bytes_per_frame));
573 
574  frames -= lw;
575  tmpbuf += lw * m_output_bytes_per_frame; // bytes
576  continue;
577  }
578 
579  err = lw;
580 
581  switch (err)
582  {
583  case -EPIPE:
584  if (snd_pcm_state(m_pcm_handle) == SND_PCM_STATE_XRUN)
585  {
586  VBAUDIO("WriteAudio: buffer underrun");
587  if ((err = snd_pcm_prepare(m_pcm_handle)) < 0)
588  {
589  AERROR("WriteAudio: unable to recover from xrun");
590  return;
591  }
592  }
593  break;
594 
595 #if ESTRPIPE != EPIPE
596  case -ESTRPIPE:
597  VBAUDIO("WriteAudio: device is suspended");
598  while ((err = snd_pcm_resume(m_pcm_handle)) == -EAGAIN)
599  usleep(200);
600 
601  if (err < 0)
602  {
603  VBERROR("WriteAudio: resume failed");
604  if ((err = snd_pcm_prepare(m_pcm_handle)) < 0)
605  {
606  AERROR("WriteAudio: unable to recover from suspend");
607  return;
608  }
609  }
610  break;
611 #endif
612 
613  case -EBADFD:
614  Error(
615  QString("WriteAudio: device is in a bad state (state = %1)")
616  .arg(snd_pcm_state(m_pcm_handle)));
617  return;
618 
619  default:
620  AERROR(QString("WriteAudio: Write failed, state: %1, err")
621  .arg(snd_pcm_state(m_pcm_handle)));
622  return;
623  }
624  }
625 }
626 
628 {
629  if (m_pcm_handle == nullptr)
630  {
631  VBERROR("getBufferedOnSoundcard() called with pcm_handle == nullptr!");
632  return 0;
633  }
634 
635  snd_pcm_sframes_t delay = 0;
636 
637  /* Delay is the total delay from writing to the pcm until the samples
638  hit the DAC - includes buffered samples and any fixed latencies */
639  if (snd_pcm_delay(m_pcm_handle, &delay) < 0)
640  return 0;
641 
642  // BUG: calling snd_pcm_state causes noise and repeats on the Raspberry Pi
643  return delay * m_output_bytes_per_frame;
644 }
645 
653 int AudioOutputALSA::SetParameters(snd_pcm_t *handle, snd_pcm_format_t format,
654  uint channels, uint rate, uint buffer_time,
655  uint period_time)
656 {
657  int err;
658  snd_pcm_hw_params_t *params;
659  snd_pcm_sw_params_t *swparams;
660  snd_pcm_uframes_t period_size, period_size_min, period_size_max;
661  snd_pcm_uframes_t buffer_size, buffer_size_min, buffer_size_max;
662 
663  VBAUDIO(QString("SetParameters(format=%1, channels=%2, rate=%3, "
664  "buffer_time=%4, period_time=%5)")
665  .arg(format).arg(channels).arg(rate).arg(buffer_time)
666  .arg(period_time));
667 
668  if (handle == nullptr)
669  {
670  Error(QObject::tr("SetParameters() called with handle == nullptr!"));
671  return -1;
672  }
673 
674  snd_pcm_hw_params_alloca(&params);
675  snd_pcm_sw_params_alloca(&swparams);
676 
677  /* choose all parameters */
678  err = snd_pcm_hw_params_any(handle, params);
679  CHECKERR("No playback configurations available");
680 
681  /* set the interleaved read/write format */
682  err = snd_pcm_hw_params_set_access(handle, params,
683  SND_PCM_ACCESS_RW_INTERLEAVED);
684  CHECKERR(QString("Interleaved RW audio not available"));
685 
686  /* set the sample format */
687  err = snd_pcm_hw_params_set_format(handle, params, format);
688  CHECKERR(QString("Sample format %1 not available").arg(format));
689 
690  /* set the count of channels */
691  err = snd_pcm_hw_params_set_channels(handle, params, channels);
692  CHECKERR(QString("Channels count %1 not available").arg(channels));
693 
694  /* set the stream rate */
696  {
697  err = snd_pcm_hw_params_set_rate_resample(handle, params, 1);
698  CHECKERR(QString("Resampling setup failed").arg(rate));
699 
700  uint rrate = rate;
701  err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, nullptr);
702  CHECKERR(QString("Rate %1Hz not available for playback: %s").arg(rate));
703 
704  if (rrate != rate)
705  {
706  VBERROR(QString("Rate doesn't match (requested %1Hz, got %2Hz)")
707  .arg(rate).arg(err));
708  return err;
709  }
710  }
711  else
712  {
713  err = snd_pcm_hw_params_set_rate(handle, params, rate, 0);
714  CHECKERR(QString("Samplerate %1 Hz not available").arg(rate));
715  }
716 
717  /* get the buffer parameters */
718  (void) snd_pcm_hw_params_get_buffer_size_min(params, &buffer_size_min);
719  (void) snd_pcm_hw_params_get_buffer_size_max(params, &buffer_size_max);
720  (void) snd_pcm_hw_params_get_period_size_min(params, &period_size_min, nullptr);
721  (void) snd_pcm_hw_params_get_period_size_max(params, &period_size_max, nullptr);
722  VBAUDIO(QString("Buffer size range from %1 to %2")
723  .arg(buffer_size_min)
724  .arg(buffer_size_max));
725  VBAUDIO(QString("Period size range from %1 to %2")
726  .arg(period_size_min)
727  .arg(period_size_max));
728 
729  /* set the buffer time */
730  uint original_buffer_time = buffer_time;
731  bool canincrease = true;
732  err = snd_pcm_hw_params_set_buffer_time_near(handle, params,
733  &buffer_time, nullptr);
734  if (err < 0)
735  {
736  int dir = -1;
737  uint buftmp = buffer_time;
738  int attempt = 0;
739  do
740  {
741  err = snd_pcm_hw_params_set_buffer_time_near(handle, params,
742  &buffer_time, &dir);
743  if (err < 0)
744  {
745  AERROR(QString("Unable to set buffer time to %1us, retrying")
746  .arg(buffer_time));
747  /*
748  * with some drivers, snd_pcm_hw_params_set_buffer_time_near
749  * only works once, if that's the case no point trying with
750  * different values
751  */
752  if ((buffer_time <= 100000) ||
753  (attempt > 0 && buffer_time == buftmp))
754  {
755  VBERROR("Couldn't set buffer time, giving up");
756  return err;
757  }
758  buffer_time -= 100000;
759  canincrease = false;
760  attempt++;
761  }
762  }
763  while (err < 0);
764  }
765 
766  /* See if we need to increase the prealloc'd buffer size
767  If buffer_time is too small we could underrun - make 10% difference ok */
768  if (buffer_time * 1.10F < (float)original_buffer_time)
769  {
770  VBWARN(QString("Requested %1us got %2 buffer time")
771  .arg(original_buffer_time).arg(buffer_time));
772  // We need to increase preallocated buffer size in the driver
773  if (canincrease && m_pbufsize < 0)
774  {
775  IncPreallocBufferSize(original_buffer_time, buffer_time);
776  }
777  }
778 
779  VBAUDIO(QString("Buffer time = %1 us").arg(buffer_time));
780 
781  /* set the period time */
782  err = snd_pcm_hw_params_set_periods_near(handle, params,
783  &period_time, nullptr);
784  CHECKERR(QString("Unable to set period time %1").arg(period_time));
785  VBAUDIO(QString("Period time = %1 periods").arg(period_time));
786 
787  /* write the parameters to device */
788  err = snd_pcm_hw_params(handle, params);
789  CHECKERR("Unable to set hw params for playback");
790 
791  err = snd_pcm_get_params(handle, &buffer_size, &period_size);
792  CHECKERR("Unable to get PCM params");
793  VBAUDIO(QString("Buffer size = %1 | Period size = %2")
794  .arg(buffer_size).arg(period_size));
795 
796  /* set member variables */
798  m_fragment_size = (period_size >> 1) * m_output_bytes_per_frame;
799 
800  /* get the current swparams */
801  err = snd_pcm_sw_params_current(handle, swparams);
802  CHECKERR("Unable to get current swparams");
803 
804  /* start the transfer after period_size */
805  err = snd_pcm_sw_params_set_start_threshold(handle, swparams, period_size);
806  CHECKERR("Unable to set start threshold");
807 
808  /* allow the transfer when at least period_size samples can be processed */
809  err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_size);
810  CHECKERR("Unable to set avail min");
811 
812  /* write the parameters to the playback device */
813  err = snd_pcm_sw_params(handle, swparams);
814  CHECKERR("Unable to set sw params");
815 
816  err = snd_pcm_prepare(handle);
817  CHECKERR("Unable to prepare the PCM");
818 
819  return 0;
820 }
821 
822 int AudioOutputALSA::GetVolumeChannel(int channel) const
823 {
824  int retvol = 0;
825 
826  if (!m_mixer.elem)
827  return retvol;
828 
829  snd_mixer_selem_channel_id_t chan = (snd_mixer_selem_channel_id_t) channel;
830  if (!snd_mixer_selem_has_playback_channel(m_mixer.elem, chan))
831  return retvol;
832 
833  long mixervol;
834  int chk;
835  if ((chk = snd_mixer_selem_get_playback_volume(m_mixer.elem,
836  chan,
837  &mixervol)) < 0)
838  {
839  VBERROR(QString("failed to get channel %1 volume, mixer %2/%3: %4")
840  .arg(channel).arg(m_mixer.device)
841  .arg(m_mixer.control)
842  .arg(snd_strerror(chk)));
843  }
844  else
845  {
846  retvol = (m_mixer.volrange != 0L) ? (mixervol - m_mixer.volmin) *
847  100.0F / m_mixer.volrange + 0.5F
848  : 0;
849  retvol = max(retvol, 0);
850  retvol = min(retvol, 100);
851  VBAUDIO(QString("get volume channel %1: %2")
852  .arg(channel).arg(retvol));
853  }
854  return retvol;
855 }
856 
857 void AudioOutputALSA::SetVolumeChannel(int channel, int volume)
858 {
859  if (!(internal_vol && m_mixer.elem))
860  return;
861 
862  long mixervol = (int64_t(volume) * m_mixer.volrange) / 100 + m_mixer.volmin;
863  mixervol = max(mixervol, m_mixer.volmin);
864  mixervol = min(mixervol, m_mixer.volmax);
865 
866  snd_mixer_selem_channel_id_t chan = (snd_mixer_selem_channel_id_t) channel;
867 
868  if (snd_mixer_selem_has_playback_switch(m_mixer.elem))
869  snd_mixer_selem_set_playback_switch(m_mixer.elem, chan, (volume > 0));
870 
871  if (snd_mixer_selem_set_playback_volume(m_mixer.elem, chan, mixervol) < 0)
872  VBERROR(QString("failed to set channel %1 volume").arg(channel));
873  else
874  VBAUDIO(QString("channel %1 volume set %2 => %3")
875  .arg(channel).arg(volume).arg(mixervol));
876 }
877 
879 {
880  if (!m_pcm_handle)
881  {
882  VBERROR("mixer setup without a pcm");
883  return false;
884  }
885  m_mixer.device = gCoreContext->GetSetting("MixerDevice", "default");
886  m_mixer.device = m_mixer.device.remove(QString("ALSA:"));
887  if (m_mixer.device.toLower() == "software")
888  return true;
889 
890  m_mixer.control = gCoreContext->GetSetting("MixerControl", "PCM");
891 
892  QString mixer_device_tag = QString("mixer device %1").arg(m_mixer.device);
893 
894  int chk;
895  if ((chk = snd_mixer_open(&m_mixer.handle, 0)) < 0)
896  {
897  VBERROR(QString("failed to open mixer device %1: %2")
898  .arg(mixer_device_tag).arg(snd_strerror(chk)));
899  return false;
900  }
901 
902  QByteArray dev_ba = m_mixer.device.toLatin1();
903  struct snd_mixer_selem_regopt regopts =
904  {1, SND_MIXER_SABSTRACT_NONE, dev_ba.constData(), nullptr, nullptr};
905 
906  if ((chk = snd_mixer_selem_register(m_mixer.handle, &regopts, nullptr)) < 0)
907  {
908  snd_mixer_close(m_mixer.handle);
909  m_mixer.handle = nullptr;
910  VBERROR(QString("failed to register %1: %2")
911  .arg(mixer_device_tag).arg(snd_strerror(chk)));
912  return false;
913  }
914 
915  if ((chk = snd_mixer_load(m_mixer.handle)) < 0)
916  {
917  snd_mixer_close(m_mixer.handle);
918  m_mixer.handle = nullptr;
919  VBERROR(QString("failed to load %1: %2")
920  .arg(mixer_device_tag).arg(snd_strerror(chk)));
921  return false;
922  }
923 
924  m_mixer.elem = nullptr;
925  uint elcount = snd_mixer_get_count(m_mixer.handle);
926  snd_mixer_elem_t* elx = snd_mixer_first_elem(m_mixer.handle);
927 
928  for (uint ctr = 0; elx != nullptr && ctr < elcount; ctr++)
929  {
930  QString tmp = QString(snd_mixer_selem_get_name(elx));
931  if (m_mixer.control == tmp &&
932  !snd_mixer_selem_is_enumerated(elx) &&
933  snd_mixer_selem_has_playback_volume(elx) &&
934  snd_mixer_selem_is_active(elx))
935  {
936  m_mixer.elem = elx;
937  VBAUDIO(QString("found playback control %1 on %2")
938  .arg(m_mixer.control)
939  .arg(mixer_device_tag));
940  break;
941  }
942  elx = snd_mixer_elem_next(elx);
943  }
944  if (!m_mixer.elem)
945  {
946  snd_mixer_close(m_mixer.handle);
947  m_mixer.handle = nullptr;
948  VBERROR(QString("no playback control %1 found on %2")
949  .arg(m_mixer.control).arg(mixer_device_tag));
950  return false;
951  }
952  if ((snd_mixer_selem_get_playback_volume_range(m_mixer.elem,
953  &m_mixer.volmin,
954  &m_mixer.volmax) < 0))
955  {
956  snd_mixer_close(m_mixer.handle);
957  m_mixer.handle = nullptr;
958  VBERROR(QString("failed to get volume range on %1/%2")
959  .arg(mixer_device_tag).arg(m_mixer.control));
960  return false;
961  }
962 
963  m_mixer.volrange = m_mixer.volmax - m_mixer.volmin;
964  VBAUDIO(QString("mixer volume range on %1/%2 - min %3, max %4, range %5")
965  .arg(mixer_device_tag).arg(m_mixer.control)
966  .arg(m_mixer.volmin).arg(m_mixer.volmax).arg(m_mixer.volrange));
967  VBAUDIO(QString("%1/%2 set up successfully")
968  .arg(mixer_device_tag)
969  .arg(m_mixer.control));
970 
971  if (m_set_initial_vol)
972  {
973  int initial_vol;
974  if (m_mixer.control == "PCM")
975  initial_vol = gCoreContext->GetNumSetting("PCMMixerVolume", 80);
976  else
977  initial_vol = gCoreContext->GetNumSetting("MasterMixerVolume", 80);
978  for (int ch = 0; ch < m_channels; ++ch)
979  SetVolumeChannel(ch, initial_vol);
980  }
981 
982  return true;
983 }
984 
985 QMap<QString, QString> *AudioOutputALSA::GetDevices(const char *type)
986 {
987  QMap<QString, QString> *alsadevs = new QMap<QString, QString>();
988  void **hints, **n;
989 
990  if (snd_device_name_hint(-1, type, &hints) < 0)
991  return alsadevs;
992  n = hints;
993 
994  while (*n != nullptr)
995  {
996  char *name = snd_device_name_get_hint(*n, "NAME");
997  char *desc = snd_device_name_get_hint(*n, "DESC");
998  if (name && desc && (strcmp(name, "null") != 0))
999  alsadevs->insert(name, desc);
1000  if (name)
1001  free(name);
1002  if (desc)
1003  free(desc);
1004  n++;
1005  }
1006  snd_device_name_free_hint(hints);
1007  // Work around ALSA bug < 1.0.22 ; where snd_device_name_hint can corrupt
1008  // global ALSA memory context
1009 #if SND_LIB_MAJOR == 1
1010 #if SND_LIB_MINOR == 0
1011 #if SND_LIB_SUBMINOR < 22
1012  snd_config_update_free_global();
1013 #endif
1014 #endif
1015 #endif
1016  return alsadevs;
1017 }
bool IncPreallocBufferSize(int requested, int buffer_time)
struct AudioOutputALSA::@0 m_mixer
void InitSettings(const AudioSettings &settings)
void Warn(const QString &msg)
AudioOutputALSA(const AudioSettings &settings)
#define CHANNELS_MIN
void Error(const QString &msg)
#define CHANNELS_MAX
void SetVolumeChannel(int channel, int volume) override
~AudioOutputALSA() override
void setELD(QByteArray *ba)
set ELD data
static QMap< QString, QString > * GetDevices(const char *type)
void setPassthrough(int val)
void CloseDevice(void) override
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define FILTER_FLAGS
static int FormatToBits(AudioFormat format)
static guint32 * tmp
Definition: goom_core.c:35
#define AERROR(str)
static void ReorderSmpteToAlsa(void *buf, uint frames, AudioFormat format, uint extrach)
#define VBERROR(str)
QString m_passthru_device
AudioOutputSettings * GetOutputSettings(bool passthrough) override
snd_mixer_elem_t * elem
#define VBWARN(str)
QString GetSetting(const QString &key, const QString &defaultval="")
AudioFormat m_output_format
int GetVolumeChannel(int channel) const override
const char * name
Definition: ParseText.cpp:328
bool OpenDevice(void) override
bool internal_vol
Definition: volumebase.h:41
#define CHECKERR(str)
#define OPEN_FLAGS
int GetBufferedOnSoundcard(void) const override
Return the size in bytes of frames currently in the audio buffer adjusted with the audio playback lat...
QByteArray * GetELD(int card, int device, int subdevice)
int GetNumSetting(const QString &key, int defaultval=0)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static void _ReorderSmpteToAlsa(AudioDataType *buf, uint frames, uint extrach)
bool GetBoolSetting(const QString &key, bool defaultval=false)
int GetPCMInfo(int &card, int &device, int &subdevice)
void AddSupportedRate(int rate)
int TryOpenDevice(int open_mode, bool try_ac3)
void KillAudio(void)
Kill the output thread and cleanup.
void Reconfigure(const AudioSettings &settings) override
(Re)Configure AudioOutputBase
snd_pcm_t * m_pcm_handle
snd_mixer_t * handle
int SetParameters(snd_pcm_t *handle, snd_pcm_format_t format, uint channels, uint rate, uint buffer_time, uint period_time)
Set the various ALSA audio parameters.
const char * frames[3]
Definition: element.c:46
void AddSupportedFormat(AudioFormat format)
static void usleep(unsigned long time)
Definition: mthread.cpp:348
void AddSupportedChannels(int channels)
bool m_init
If set to false, AudioOutput instance will not try to initially open the audio device.
Definition: audiosettings.h:80
#define VBAUDIO(str)
void WriteAudio(unsigned char *aubuf, int size) override