MythTV  master
audiooutput.cpp
Go to the documentation of this file.
1 #include <cstdio>
2 #include <cstdlib>
3 
4 using namespace std;
5 
6 // Qt utils: to parse audio list
7 #include <QFile>
8 #include <QDateTime>
9 #include <QDir>
10 
11 #include "mythconfig.h"
12 #include "audiooutput.h"
13 #include "mythmiscutil.h"
14 #include "compat.h"
15 
16 #include "audiooutputnull.h"
17 #ifdef _WIN32
18 #include "audiooutputdx.h"
19 #include "audiooutputwin.h"
20 #endif
21 #ifdef USING_OSS
22 #include "audiooutputoss.h"
23 #endif
24 #ifdef USING_ALSA
25 #include "audiooutputalsa.h"
26 #endif
27 #if CONFIG_DARWIN
28 #include "audiooutputca.h"
29 #endif
30 #ifdef USING_JACK
31 #include "audiooutputjack.h"
32 #endif
33 #ifdef USING_PULSEOUTPUT
34 #include "audiooutputpulse.h"
35 #endif
36 #ifdef USING_PULSE
37 #include "audiopulsehandler.h"
38 #endif
39 #ifdef Q_OS_ANDROID
40 #include "audiooutputopensles.h"
41 #endif
42 #ifdef USING_OPENMAX
43 #include "audiooutput_omx.h"
44 #endif
45 
46 extern "C" {
47 #include "libavcodec/avcodec.h" // to get codec id
48 }
49 #include "audioconvert.h"
50 
51 #define LOC QString("AO: ")
52 
54 {
55 #ifdef USING_PULSE
57 #endif
58 }
59 
61  const QString &main_device, const QString &passthru_device,
62  AudioFormat format, int channels, int codec, int samplerate,
63  AudioOutputSource source, bool set_initial_vol, bool passthru,
64  int upmixer_startup, AudioOutputSettings *custom)
65 {
66  AudioSettings settings(
67  main_device, passthru_device, format, channels, codec, samplerate,
68  source, set_initial_vol, passthru, upmixer_startup, custom);
69 
70  return OpenAudio(settings);
71 }
72 
74  const QString &main_device, const QString &passthru_device,
75  bool willsuspendpa)
76 {
77  AudioSettings settings(main_device, passthru_device);
78 
79  return OpenAudio(settings, willsuspendpa);
80 }
81 
83  bool willsuspendpa)
84 {
85  QString &main_device = settings.main_device;
86  AudioOutput *ret = nullptr;
87 
88  // Don't suspend Pulse if unnecessary. This can save 100mS
89  if (settings.format == FORMAT_NONE || settings.channels <= 0)
90  willsuspendpa = false;
91 
92 #ifdef USING_PULSE
93  bool pulsestatus = false;
94 #else
95  {
96  static bool warned = false;
97  if (!warned && IsPulseAudioRunning())
98  {
99  warned = true;
100  LOG(VB_GENERAL, LOG_WARNING,
101  "WARNING: ***Pulse Audio is running***");
102  }
103  }
104 #endif
105 
106  settings.FixPassThrough();
107 
108  if (main_device.startsWith("PulseAudio:"))
109  {
110 #ifdef USING_PULSEOUTPUT
111  return new AudioOutputPulseAudio(settings);
112 #else
113  LOG(VB_GENERAL, LOG_ERR, "Audio output device is set to PulseAudio "
114  "but PulseAudio support is not compiled in!");
115  return nullptr;
116 #endif
117  }
118  else if (main_device.startsWith("NULL"))
119  {
120  return new AudioOutputNULL(settings);
121  }
122 
123 #ifdef USING_PULSE
124  if (willsuspendpa)
125  {
126  bool ispulse = false;
127 #ifdef USING_ALSA
128  // Check if using ALSA, that the device doesn't contain the word
129  // "pulse" in its hint
130  if (main_device.startsWith("ALSA:"))
131  {
132  QString device_name = main_device;
133 
134  device_name.remove(0, 5);
135  QMap<QString, QString> *alsadevs =
137  if (!alsadevs->empty() && alsadevs->contains(device_name))
138  {
139  if (alsadevs->value(device_name).contains("pulse",
140  Qt::CaseInsensitive))
141  {
142  ispulse = true;
143  }
144  }
145  delete alsadevs;
146  }
147 #endif
148  if (main_device.contains("pulse", Qt::CaseInsensitive))
149  {
150  ispulse = true;
151  }
152  if (!ispulse)
153  {
155  }
156  }
157 #else // USING_PULSE
158  // Quiet warning error when not compiling with pulseaudio
159  Q_UNUSED(willsuspendpa);
160 #endif
161 
162  if (main_device.startsWith("ALSA:"))
163  {
164 #ifdef USING_ALSA
165  settings.TrimDeviceType();
166  ret = new AudioOutputALSA(settings);
167 #else
168  LOG(VB_GENERAL, LOG_ERR, "Audio output device is set to an ALSA device "
169  "but ALSA support is not compiled in!");
170 #endif
171  }
172  else if (main_device.startsWith("JACK:"))
173  {
174 #ifdef USING_JACK
175  settings.TrimDeviceType();
176  ret = new AudioOutputJACK(settings);
177 #else
178  LOG(VB_GENERAL, LOG_ERR, "Audio output device is set to a JACK device "
179  "but JACK support is not compiled in!");
180 #endif
181  }
182  else if (main_device.startsWith("DirectX:"))
183  {
184 #ifdef _WIN32
185  ret = new AudioOutputDX(settings);
186 #else
187  LOG(VB_GENERAL, LOG_ERR, "Audio output device is set to DirectX device "
188  "but DirectX support is not compiled in!");
189 #endif
190  }
191  else if (main_device.startsWith("Windows:"))
192  {
193 #ifdef _WIN32
194  ret = new AudioOutputWin(settings);
195 #else
196  LOG(VB_GENERAL, LOG_ERR, "Audio output device is set to a Windows "
197  "device but Windows support is not compiled "
198  "in!");
199 #endif
200  }
201  else if (main_device.startsWith("OpenSLES:"))
202  {
203 #ifdef Q_OS_ANDROID
204  ret = new AudioOutputOpenSLES(settings);
205 #else
206  LOG(VB_GENERAL, LOG_ERR, "Audio output device is set to a OpenSLES "
207  "device but Android support is not compiled "
208  "in!");
209 #endif
210  }
211  else if (main_device.startsWith("OpenMAX:"))
212  {
213 #ifdef USING_OPENMAX
214  if (!getenv("NO_OPENMAX_AUDIO"))
215  ret = new AudioOutputOMX(settings);
216 #else
217  LOG(VB_GENERAL, LOG_ERR, "Audio output device is set to a OpenMAX "
218  "device but OpenMAX support is not compiled "
219  "in!");
220 #endif
221  }
222 #if defined(USING_OSS)
223  else
224  ret = new AudioOutputOSS(settings);
225 #elif CONFIG_DARWIN
226  else
227  ret = new AudioOutputCA(settings);
228 #endif
229 
230  if (!ret)
231  {
232  LOG(VB_GENERAL, LOG_CRIT, "No useable audio output driver found.");
233  LOG(VB_GENERAL, LOG_ERR, "Don't disable OSS support unless you're "
234  "not running on Linux.");
235 #ifdef USING_PULSE
236  if (pulsestatus)
238 #endif
239  return nullptr;
240  }
241 #ifdef USING_PULSE
242  ret->pulsewassuspended = pulsestatus;
243 #endif
244  return ret;
245 }
246 
248 {
249 #ifdef USING_PULSE
250  if (pulsewassuspended)
252 #endif
253  av_frame_free(&_frame);
254 }
255 
256 void AudioOutput::SetStretchFactor(float /*factor*/)
257 {
258 }
259 
261 {
262  return new AudioOutputSettings;
263 }
264 
266 {
267  return new AudioOutputSettings;
268 }
269 
270 bool AudioOutput::CanPassthrough(int /*samplerate*/,
271  int /*channels*/,
272  int /*codec*/,
273  int /*profile*/) const
274 {
275  return false;
276 }
277 
278 // TODO: get rid of this if possible... need to see what uses GetError() and
279 // GetWarning() and why. These would give more useful logs as macros
280 void AudioOutput::Error(const QString &msg)
281 {
282  lastError = msg;
283  LOG(VB_GENERAL, LOG_ERR, "AudioOutput Error: " + lastError);
284 }
285 
286 void AudioOutput::SilentError(const QString &msg)
287 {
288  lastError = msg;
289 }
290 
291 void AudioOutput::Warn(const QString &msg)
292 {
293  lastWarn = msg;
294  LOG(VB_GENERAL, LOG_WARNING, "AudioOutput Warning: " + lastWarn);
295 }
296 
298 {
299  lastError.clear();
300 }
301 
303 {
304  lastWarn.clear();
305 }
306 
308  QString &name, QString &desc, bool willsuspendpa)
309 {
310  AudioOutputSettings aosettings(true);
312 
313  AudioOutput *ao = OpenAudio(name, QString(), willsuspendpa);
314  if (ao)
315  {
316  aosettings = *(ao->GetOutputSettingsCleaned());
317  delete ao;
318  }
319  if (aosettings.IsInvalid())
320  {
321  if (!willsuspendpa)
322  return nullptr;
323  else
324  {
325  QString msg = tr("Invalid or unuseable audio device");
326  return new AudioOutput::AudioDeviceConfig(name, msg);
327  }
328  }
329 
330  QString capabilities = desc;
331  int max_channels = aosettings.BestSupportedChannelsELD();
332  if (aosettings.hasELD())
333  {
334  if (aosettings.getELD().isValid())
335  {
336  capabilities += tr(" (%1 connected to %2)")
337  .arg(aosettings.getELD().product_name().simplified())
338  .arg(aosettings.getELD().connection_name());
339  }
340  else
341  {
342  capabilities += tr(" (No connection detected)");
343  }
344  }
345 
346  QString speakers;
347  switch (max_channels)
348  {
349  case 6:
350  speakers = "5.1";
351  break;
352  case 8:
353  speakers = "7.1";
354  break;
355  default:
356  speakers = "2.0";
357  break;
358  }
359 
360  capabilities += tr("\nDevice supports up to %1")
361  .arg(speakers);
362  if (aosettings.canPassthrough() >= 0)
363  {
364  if (aosettings.hasELD() && aosettings.getELD().isValid())
365  {
366  // We have an ELD, show actual reported capabilities
367  capabilities += " (" + aosettings.getELD().codecs_desc() + ")";
368  }
369  else
370  {
371  // build capabilities string, in a similar fashion as reported
372  // by ELD
373  int mask = 0;
374  mask |=
375  (aosettings.canLPCM() << 0) |
376  (aosettings.canAC3() << 1) |
377  (aosettings.canDTS() << 2);
378  // cppcheck-suppress variableScope
379  static const char *type_names[] = { "LPCM", "AC3", "DTS" };
380 
381  if (mask != 0)
382  {
383  capabilities += QObject::tr(" (guessing: ");
384  bool found_one = false;
385  for (unsigned int i = 0; i < 3; i++)
386  {
387  if ((mask & (1 << i)) != 0)
388  {
389  if (found_one)
390  capabilities += ", ";
391  capabilities += type_names[i];
392  found_one = true;
393  }
394  }
395  capabilities += QString(")");
396  }
397  }
398  }
399  LOG(VB_AUDIO, LOG_INFO, QString("Found %1 (%2)")
400  .arg(name).arg(capabilities));
401  adc = new AudioOutput::AudioDeviceConfig(name, capabilities);
402  adc->settings = aosettings;
403  return adc;
404 }
405 
406 #ifdef USING_OSS
407 static void fillSelectionsFromDir(const QDir &dir,
408  AudioOutput::ADCVect *list)
409 {
410  QFileInfoList il = dir.entryInfoList();
411  for (QFileInfoList::Iterator it = il.begin();
412  it != il.end(); ++it )
413  {
414  QFileInfo &fi = *it;
415  QString name = fi.absoluteFilePath();
416  QString desc = AudioOutput::tr("OSS device");
419  if (!adc)
420  continue;
421  list->append(*adc);
422  delete adc;
423  }
424 }
425 #endif
426 
428 {
429  ADCVect *list = new ADCVect;
430  AudioDeviceConfig *adc;
431 
432 #ifdef USING_PULSE
434 #endif
435 
436 #ifdef USING_ALSA
437  QMap<QString, QString> *alsadevs = AudioOutputALSA::GetDevices("pcm");
438 
439  if (!alsadevs->empty())
440  {
441  for (QMap<QString, QString>::const_iterator i = alsadevs->begin();
442  i != alsadevs->end(); ++i)
443  {
444  QString key = i.key();
445  QString desc = i.value();
446  QString devname = QString("ALSA:%1").arg(key);
447 
448  adc = GetAudioDeviceConfig(devname, desc);
449  if (!adc)
450  continue;
451  list->append(*adc);
452  delete adc;
453  }
454  }
455  delete alsadevs;
456 #endif
457 #ifdef USING_OSS
458  {
459  QDir dev("/dev", "dsp*", QDir::Name, QDir::System);
460  fillSelectionsFromDir(dev, list);
461  dev.setNameFilters(QStringList("adsp*"));
462  fillSelectionsFromDir(dev, list);
463 
464  dev.setPath("/dev/sound");
465  if (dev.exists())
466  {
467  dev.setNameFilters(QStringList("dsp*"));
468  fillSelectionsFromDir(dev, list);
469  dev.setNameFilters(QStringList("adsp*"));
470  fillSelectionsFromDir(dev, list);
471  }
472  }
473 #endif
474 #ifdef USING_JACK
475  {
476  QString name = "JACK:";
477  QString desc = tr("Use JACK default sound server.");
478  adc = GetAudioDeviceConfig(name, desc);
479  if (adc)
480  {
481  list->append(*adc);
482  delete adc;
483  }
484  }
485 #endif
486 #if CONFIG_DARWIN
487 
488  {
489  QMap<QString, QString> *devs = AudioOutputCA::GetDevices(nullptr);
490  if (!devs->empty())
491  {
492  for (QMap<QString, QString>::const_iterator i = devs->begin();
493  i != devs->end(); ++i)
494  {
495  QString key = i.key();
496  QString desc = i.value();
497  QString devname = QString("CoreAudio:%1").arg(key);
498 
499  adc = GetAudioDeviceConfig(devname, desc);
500  if (!adc)
501  continue;
502  list->append(*adc);
503  delete adc;
504  }
505  }
506  delete devs;
507  QString name = "CoreAudio:Default Output Device";
508  QString desc = tr("CoreAudio default output");
509  adc = GetAudioDeviceConfig(name, desc);
510  if (adc)
511  {
512  list->append(*adc);
513  delete adc;
514  }
515  }
516 #endif
517 #ifdef _WIN32
518  {
519  QString name = "Windows:";
520  QString desc = "Windows default output";
521  adc = GetAudioDeviceConfig(name, desc);
522  if (adc)
523  {
524  list->append(*adc);
525  delete adc;
526  }
527 
528  QMap<int, QString> *dxdevs = AudioOutputDX::GetDXDevices();
529 
530  if (!dxdevs->empty())
531  {
532  for (QMap<int, QString>::const_iterator i = dxdevs->begin();
533  i != dxdevs->end(); ++i)
534  {
535  QString desc = i.value();
536  QString devname = QString("DirectX:%1").arg(desc);
537 
538  adc = GetAudioDeviceConfig(devname, desc);
539  if (!adc)
540  continue;
541  list->append(*adc);
542  delete adc;
543  }
544  }
545  delete dxdevs;
546  }
547 #endif
548 
549 #ifdef USING_PULSE
550  if (pasuspended)
552 #endif
553 
554 #ifdef USING_PULSEOUTPUT
555  {
556  QString name = "PulseAudio:default";
557  QString desc = tr("PulseAudio default sound server.");
558  adc = GetAudioDeviceConfig(name, desc);
559  if (adc)
560  {
561  list->append(*adc);
562  delete adc;
563  }
564  }
565 #endif
566 
567 #ifdef ANDROID
568  {
569  QString name = "OpenSLES:";
570  QString desc = tr("OpenSLES default output.");
571  adc = GetAudioDeviceConfig(name, desc);
572  if (adc)
573  {
574  list->append(*adc);
575  delete adc;
576  }
577  }
578 #endif
579 
580 #ifdef USING_OPENMAX
581  if (!getenv("NO_OPENMAX_AUDIO"))
582  {
583  QString name = "OpenMAX:analog";
584  QString desc = tr("OpenMAX analog output.");
585  adc = GetAudioDeviceConfig(name, desc);
586  if (adc)
587  {
588  list->append(*adc);
589  delete adc;
590  }
591 
592  name = "OpenMAX:hdmi";
593  desc = tr("OpenMAX HDMI output.");
594  adc = GetAudioDeviceConfig(name, desc);
595  if (adc)
596  {
597  list->append(*adc);
598  delete adc;
599  }
600  }
601 #endif
602 
603  QString name = "NULL";
604  QString desc = "NULL device";
605  adc = GetAudioDeviceConfig(name, desc);
606  if (adc)
607  {
608  list->append(*adc);
609  delete adc;
610  }
611  return list;
612 }
613 
621 int AudioOutput::DecodeAudio(AVCodecContext *ctx,
622  uint8_t *buffer, int &data_size,
623  const AVPacket *pkt)
624 {
625  bool got_frame = false;
626  int ret;
627  char error[AV_ERROR_MAX_STRING_SIZE];
628 
629  data_size = 0;
630  if (!_frame)
631  {
632  if (!(_frame = av_frame_alloc()))
633  {
634  return AVERROR(ENOMEM);
635  }
636  }
637  else
638  {
639  av_frame_unref(_frame);
640  }
641 
642 // SUGGESTION
643 // Now that avcodec_decode_audio4 is deprecated and replaced
644 // by 2 calls (receive frame and send packet), this could be optimized
645 // into separate routines or separate threads.
646 // Also now that it always consumes a whole buffer some code
647 // in the caller may be able to be optimized.
648  ret = avcodec_receive_frame(ctx,_frame);
649  if (ret == 0)
650  got_frame = true;
651  if (ret == AVERROR(EAGAIN))
652  ret = 0;
653  if (ret == 0)
654  ret = avcodec_send_packet(ctx, pkt);
655  if (ret == AVERROR(EAGAIN))
656  ret = 0;
657  else if (ret < 0)
658  {
659  LOG(VB_AUDIO, LOG_ERR, LOC +
660  QString("audio decode error: %1 (%2)")
661  .arg(av_make_error_string(error, sizeof(error), ret))
662  .arg(got_frame));
663  return ret;
664  }
665  else
666  ret = pkt->size;
667 
668  if (!got_frame)
669  {
670  LOG(VB_AUDIO, LOG_DEBUG, LOC +
671  QString("audio decode, no frame decoded (%1)").arg(ret));
672  return ret;
673  }
674 
675  AVSampleFormat format = (AVSampleFormat)_frame->format;
676  AudioFormat fmt =
677  AudioOutputSettings::AVSampleFormatToFormat(format, ctx->bits_per_raw_sample);
678 
679  data_size = _frame->nb_samples * _frame->channels * av_get_bytes_per_sample(format);
680 
681  // May need to convert audio to S16
682  AudioConvert converter(fmt, CanProcess(fmt) ? fmt : FORMAT_S16);
683  uint8_t* src;
684 
685  if (av_sample_fmt_is_planar(format))
686  {
687  src = buffer;
688  converter.InterleaveSamples(_frame->channels,
689  src,
690  (const uint8_t **)_frame->extended_data,
691  data_size);
692  }
693  else
694  {
695  // data is already compacted...
696  src = _frame->extended_data[0];
697  }
698 
699  uint8_t* transit = buffer;
700 
701  if (!CanProcess(fmt) &&
702  av_get_bytes_per_sample(ctx->sample_fmt) < AudioOutputSettings::SampleSize(converter.Out()))
703  {
704  // this conversion can't be done in place
705  transit = (uint8_t*)av_malloc(data_size * av_get_bytes_per_sample(ctx->sample_fmt)
706  / AudioOutputSettings::SampleSize(converter.Out()));
707  if (!transit)
708  {
709  LOG(VB_AUDIO, LOG_ERR, LOC +
710  QString("audio decode, out of memory"));
711  data_size = 0;
712  return ret;
713  }
714  }
715  if (!CanProcess(fmt) || src != transit)
716  {
717  data_size = converter.Process(transit, src, data_size, true);
718  }
719  if (transit != buffer)
720  {
721  av_free(transit);
722  }
723  return ret;
724 }
void Warn(const QString &msg)
virtual AudioOutputSettings * GetOutputSettingsUsers(bool digital=true)
void Error(const QString &msg)
bool IsInvalid()
return true if class instance is marked invalid.
QString codecs_desc()
Definition: eldutils.cpp:513
static AudioOutput * OpenAudio(const QString &audiodevice, const QString &passthrudevice, AudioFormat format, int channels, int codec, int samplerate, AudioOutputSource source, bool set_initial_vol, bool passthru, int upmixer_startup=0, AudioOutputSettings *custom=nullptr)
Definition: audiooutput.cpp:60
static void error(const char *str,...)
Definition: vbi.c:41
QVector< AudioDeviceConfig > ADCVect
Definition: audiooutput.h:42
static QMap< QString, QString > * GetDevices(const char *type)
QString connection_name()
Definition: eldutils.cpp:481
static QMap< QString, QString > * GetDevices(const char *type=nullptr)
bool pulsewassuspended
Definition: audiooutput.h:203
int BestSupportedChannelsELD()
Reports best supported channel number, restricted to ELD range.
int Process(void *out, const void *in, int bytes, bool noclip=false)
Process Parameters: out : destination buffer where converted samples will be copied in : source buffe...
virtual ~AudioOutput()
virtual AudioOutputSettings * GetOutputSettingsCleaned(bool digital=true)
#define LOC
Definition: audiooutput.cpp:51
void TrimDeviceType(void)
QString product_name()
Definition: eldutils.cpp:476
AudioOutputSettings settings
Definition: audiooutput.h:32
static QMap< int, QString > * GetDXDevices(void)
static int SampleSize(AudioFormat format)
AudioFormat Out(void)
Definition: audioconvert.h:48
ELD & getELD(void)
retrieve ELD data
void InterleaveSamples(int channels, uint8_t *output, const uint8_t *const *input, int data_size)
bool IsPulseAudioRunning(void)
Is A/V Sync destruction daemon is running on this host?
const char * name
Definition: ParseText.cpp:339
virtual void SetStretchFactor(float factor)
virtual int DecodeAudio(AVCodecContext *ctx, uint8_t *buffer, int &data_size, const AVPacket *pkt)
Utility routine.
void * av_malloc(unsigned int size)
static AudioDeviceConfig * GetAudioDeviceConfig(QString &name, QString &desc, bool willsuspendpa=false)
static bool Suspend(enum PulseAction action)
AudioOutputSource
Definition: audiosettings.h:17
void SilentError(const QString &msg)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
AudioFormat format
Definition: audiosettings.h:65
bool canLPCM()
return true if device supports multichannels PCM (deprecated, see canFeature())
static void Cleanup(void)
Definition: audiooutput.cpp:53
void ClearWarning(void)
bool isValid()
Definition: eldutils.cpp:444
virtual bool CanPassthrough(int samplerate, int channels, int codec, int profile) const
Implements Core Audio (Mac OS X Hardware Abstraction Layer) output.
Definition: audiooutputca.h:13
void av_free(void *ptr)
void ClearError(void)
bool hasELD()
get the ELD flag
static AudioFormat AVSampleFormatToFormat(AVSampleFormat format, int bits=0)
Return AVSampleFormat closest equivalent to AudioFormat.
bool canDTS()
return true if device can or may support DTS (deprecated, see canFeature())
static ADCVect * GetOutputList(void)
QString main_device
Definition: audiosettings.h:63
bool canAC3()
return true if device can or may support AC3 (deprecated, see canFeature())
static void fillSelectionsFromDir(const QDir &dir, AudioOutput::ADCVect *list)
void FixPassThrough(void)