MythTV master
audiooutput.cpp
Go to the documentation of this file.
1#include "libmythbase/mythconfig.h"
2
3#include <algorithm>
4#include <cstdio>
5#include <cstdlib>
6
7// Qt utils: to parse audio list
8#include <QtGlobal>
9#include <QtEndian>
10#include <QFile>
11#include <QDateTime>
12#include <QDir>
13#include <QMutexLocker>
14
15#include "libmythbase/compat.h"
18
19#include "audiooutput.h"
20#include "audiooutputnull.h"
21#ifdef _WIN32
22#include "audiooutputdx.h"
23#include "audiooutputwin.h"
24#endif
25#if CONFIG_AUDIO_OSS
26#include "audiooutputoss.h"
27#endif
28#if CONFIG_AUDIO_ALSA
29#include "audiooutputalsa.h"
30#endif
31#ifdef Q_OS_DARWIN
32#include "audiooutputca.h"
33#endif
34#if CONFIG_AUDIO_JACK
35#include "audiooutputjack.h"
36#endif
37#if CONFIG_AUDIO_PULSEOUTPUT
38#include "audiooutputpulse.h"
39#endif
40#if CONFIG_AUDIO_PULSE
41#include "audiopulsehandler.h"
42#endif
43#ifdef Q_OS_ANDROID
44#include "audiooutputopensles.h"
46#endif
47
48extern "C" {
49#include "libavcodec/avcodec.h" // to get codec id
50}
51#include "audioconvert.h"
53#include "pink.h"
54
55#define LOC QString("AO: ")
56
58{
59#if CONFIG_AUDIO_PULSE
61#endif
62}
63
65 const QString &main_device, const QString &passthru_device,
66 AudioFormat format, int channels, AVCodecID codec, int samplerate,
67 AudioOutputSource source, bool set_initial_vol, bool passthru,
68 int upmixer_startup, AudioOutputSettings *custom)
69{
70 AudioSettings settings(
71 main_device, passthru_device, format, channels, codec, samplerate,
72 source, set_initial_vol, passthru, upmixer_startup, custom);
73
74 return OpenAudio(settings);
75}
76
78 const QString &main_device, const QString &passthru_device,
79 bool willsuspendpa)
80{
81 AudioSettings settings(main_device, passthru_device);
82
83 return OpenAudio(settings, willsuspendpa);
84}
85
87 [[maybe_unused]] bool willsuspendpa)
88{
89 QString &main_device = settings.m_mainDevice;
90 AudioOutput *ret = nullptr;
91
92 // Don't suspend Pulse if unnecessary. This can save 100mS
93 if (settings.m_format == FORMAT_NONE || settings.m_channels <= 0)
94 willsuspendpa = false;
95
96#if CONFIG_AUDIO_PULSE
97 bool pulsestatus = false;
98#else
99 {
100 static bool warned = false;
101 if (!warned && IsPulseAudioRunning())
102 {
103 warned = true;
104 LOG(VB_GENERAL, LOG_WARNING,
105 "WARNING: ***Pulse Audio is running***");
106 }
107 }
108#endif // CONFIG_AUDIO_PULSE
109
110 settings.FixPassThrough();
111
112 if (main_device.startsWith("PulseAudio:"))
113 {
114#if CONFIG_AUDIO_PULSEOUTPUT
115 return new AudioOutputPulseAudio(settings);
116#else
117 LOG(VB_GENERAL, LOG_ERR, "Audio output device is set to PulseAudio "
118 "but PulseAudio support is not compiled in!");
119 return nullptr;
120#endif // CONFIG_AUDIO_PULSEOUTPUT
121 }
122 if (main_device.startsWith("NULL"))
123 {
124 return new AudioOutputNULL(settings);
125 }
126
127#if CONFIG_AUDIO_PULSE
128 if (willsuspendpa)
129 {
130 bool ispulse = false;
131#if CONFIG_AUDIO_ALSA
132 // Check if using ALSA, that the device doesn't contain the word
133 // "pulse" in its hint
134 if (main_device.startsWith("ALSA:"))
135 {
136 QString device_name = main_device;
137
138 device_name.remove(0, 5);
139 QMap<QString, QString> *alsadevs =
141 if (!alsadevs->empty() && alsadevs->contains(device_name))
142 {
143 if (alsadevs->value(device_name).contains("pulse",
144 Qt::CaseInsensitive))
145 {
146 ispulse = true;
147 }
148 }
149 delete alsadevs;
150 }
151#endif // CONFIF_AUDIO_ALSA
152 if (main_device.contains("pulse", Qt::CaseInsensitive))
153 {
154 ispulse = true;
155 }
156 if (!ispulse)
157 {
159 }
160 }
161#endif // CONFIG_AUDIO_PULSE
162
163 if (main_device.startsWith("ALSA:"))
164 {
165#if CONFIG_AUDIO_ALSA
166 settings.TrimDeviceType();
167 ret = new AudioOutputALSA(settings);
168#else
169 LOG(VB_GENERAL, LOG_ERR, "Audio output device is set to an ALSA device "
170 "but ALSA support is not compiled in!");
171#endif
172 }
173 else if (main_device.startsWith("JACK:"))
174 {
175#if CONFIG_AUDIO_JACK
176 settings.TrimDeviceType();
177 ret = new AudioOutputJACK(settings);
178#else
179 LOG(VB_GENERAL, LOG_ERR, "Audio output device is set to a JACK device "
180 "but JACK support is not compiled in!");
181#endif
182 }
183 else if (main_device.startsWith("DirectX:"))
184 {
185#ifdef _WIN32
186 ret = new AudioOutputDX(settings);
187#else
188 LOG(VB_GENERAL, LOG_ERR, "Audio output device is set to DirectX device "
189 "but DirectX support is not compiled in!");
190#endif
191 }
192 else if (main_device.startsWith("Windows:"))
193 {
194#ifdef _WIN32
195 ret = new AudioOutputWin(settings);
196#else
197 LOG(VB_GENERAL, LOG_ERR, "Audio output device is set to a Windows "
198 "device but Windows support is not compiled "
199 "in!");
200#endif
201 }
202 else if (main_device.startsWith("OpenSLES:"))
203 {
204#ifdef Q_OS_ANDROID
205 ret = new AudioOutputOpenSLES(settings);
206#else
207 LOG(VB_GENERAL, LOG_ERR, "Audio output device is set to a OpenSLES "
208 "device but Android support is not compiled "
209 "in!");
210#endif
211 }
212 else if (main_device.startsWith("AudioTrack:"))
213 {
214#ifdef Q_OS_ANDROID
215 ret = new AudioOutputAudioTrack(settings);
216#else
217 LOG(VB_GENERAL, LOG_ERR, "Audio output device is set to AudioTrack "
218 "device but Android support is not compiled "
219 "in!");
220#endif
221 }
222#if CONFIG_AUDIO_OSS
223 else
224 {
225 ret = new AudioOutputOSS(settings);
226 }
227#elif defined(Q_OS_DARWIN)
228 else
229 {
230 ret = new AudioOutputCA(settings);
231 }
232#endif
233
234 if (!ret)
235 {
236 LOG(VB_GENERAL, LOG_CRIT, "No useable audio output driver found.");
237 LOG(VB_GENERAL, LOG_ERR, "Don't disable OSS support unless you're "
238 "not running on Linux.");
239#if CONFIG_AUDIO_PULSE
240 if (pulsestatus)
242#endif
243 return nullptr;
244 }
245#if CONFIG_AUDIO_PULSE
246 ret->m_pulseWasSuspended = pulsestatus;
247#endif
248 return ret;
249}
250
252{
253#if CONFIG_AUDIO_PULSE
256#endif
257 av_frame_free(&m_frame);
258}
259
260void AudioOutput::SetStretchFactor(float /*factor*/)
261{
262}
263
265{
266 return new AudioOutputSettings;
267}
268
270{
271 return new AudioOutputSettings;
272}
273
274bool AudioOutput::CanPassthrough(int /*samplerate*/,
275 int /*channels*/,
276 AVCodecID /*codec*/,
277 int /*profile*/) const
278{
279 return false;
280}
281
283 QString &name, const QString &desc, bool willsuspendpa)
284{
285 AudioOutputSettings aosettings(true);
286
287 AudioOutput *ao = OpenAudio(name, QString(), willsuspendpa);
288 if (ao)
289 {
290 aosettings = *(ao->GetOutputSettingsCleaned());
291 delete ao;
292 }
293 if (aosettings.IsInvalid())
294 {
295 if (!willsuspendpa)
296 return nullptr;
297 QString msg = tr("Invalid or unuseable audio device");
298 return new AudioOutput::AudioDeviceConfig(name, msg);
299 }
300
301 QString capabilities = desc;
302 int max_channels = aosettings.BestSupportedChannelsELD();
303 if (aosettings.hasELD())
304 {
305 if (aosettings.getELD().isValid())
306 {
307 capabilities += tr(" (%1 connected to %2)")
308 .arg(aosettings.getELD().product_name().simplified(),
309 aosettings.getELD().connection_name());
310 }
311 else
312 {
313 capabilities += tr(" (No connection detected)");
314 }
315 }
316
317 QString speakers;
318 switch (max_channels)
319 {
320 case 6:
321 speakers = "5.1";
322 break;
323 case 8:
324 speakers = "7.1";
325 break;
326 default:
327 speakers = "2.0";
328 break;
329 }
330
331 capabilities += tr("\nDevice supports up to %1")
332 .arg(speakers);
333 if (aosettings.canPassthrough() >= 0)
334 {
335 if (aosettings.hasELD() && aosettings.getELD().isValid())
336 {
337 // We have an ELD, show actual reported capabilities
338 capabilities += " (" + aosettings.getELD().codecs_desc() + ")";
339 }
340 else
341 {
342 // build capabilities string, in a similar fashion as reported
343 // by ELD
344 int mask = 0;
345 mask |=
346 (static_cast<int>(aosettings.canLPCM()) << 0) |
347 (static_cast<int>(aosettings.canAC3()) << 1) |
348 (static_cast<int>(aosettings.canDTS()) << 2);
349 static const std::array<const std::string,3> s_typeNames { "LPCM", "AC3", "DTS" };
350
351 if (mask != 0)
352 {
353 capabilities += QObject::tr(" (guessing: ");
354 bool found_one = false;
355 for (unsigned int i = 0; i < 3; i++)
356 {
357 if ((mask & (1 << i)) != 0)
358 {
359 if (found_one)
360 capabilities += ", ";
361 capabilities += QString::fromStdString(s_typeNames[i]);
362 found_one = true;
363 }
364 }
365 capabilities += QString(")");
366 }
367 }
368 }
369 LOG(VB_AUDIO, LOG_INFO, QString("Found %1 (%2)") .arg(name, capabilities));
370 auto *adc = new AudioOutput::AudioDeviceConfig(name, capabilities);
371 adc->m_settings = aosettings;
372 return adc;
373}
374
375#if CONFIG_AUDIO_OSS
376static void fillSelectionsFromDir(const QDir &dir,
378{
379 QFileInfoList entries = dir.entryInfoList();
380 for (const auto& fi : std::as_const(entries))
381 {
382 QString name = fi.absoluteFilePath();
383 QString desc = AudioOutput::tr("OSS device");
386 if (!adc)
387 continue;
388 list->append(*adc);
389 delete adc;
390 }
391}
392#endif
393
395{
396 auto *list = new ADCVect;
397
398#if CONFIG_AUDIO_PULSE
400#endif
401
402#if CONFIG_AUDIO_ALSA
403 QMap<QString, QString> *alsadevs = AudioOutputALSA::GetDevices("pcm");
404
405 if (!alsadevs->empty())
406 {
407 for (auto i = alsadevs->cbegin(); i != alsadevs->cend(); ++i)
408 {
409 const QString& key = i.key();
410 const QString& desc = i.value();
411 QString devname = QString("ALSA:%1").arg(key);
412
413 auto *adc = GetAudioDeviceConfig(devname, desc);
414 if (!adc)
415 continue;
416 list->append(*adc);
417 delete adc;
418 }
419 }
420 delete alsadevs;
421#endif
422#if CONFIG_AUDIO_OSS
423 {
424 QDir dev("/dev", "dsp*", QDir::Name, QDir::System);
425 fillSelectionsFromDir(dev, list);
426 dev.setNameFilters(QStringList("adsp*"));
427 fillSelectionsFromDir(dev, list);
428
429 dev.setPath("/dev/sound");
430 if (dev.exists())
431 {
432 dev.setNameFilters(QStringList("dsp*"));
433 fillSelectionsFromDir(dev, list);
434 dev.setNameFilters(QStringList("adsp*"));
435 fillSelectionsFromDir(dev, list);
436 }
437 }
438#endif
439#if CONFIG_AUDIO_JACK
440 {
441 QString name = "JACK:";
442 QString desc = tr("Use JACK default sound server.");
443 auto *adc = GetAudioDeviceConfig(name, desc);
444 if (adc)
445 {
446 list->append(*adc);
447 delete adc;
448 }
449 }
450#endif
451#ifdef Q_OS_DARWIN
452
453 {
454 QMap<QString, QString> *devs = AudioOutputCA::GetDevices(nullptr);
455 if (!devs->empty())
456 {
457 for (QMap<QString, QString>::const_iterator i = devs->begin();
458 i != devs->end(); ++i)
459 {
460 QString key = i.key();
461 QString desc = i.value();
462 QString devname = QString("CoreAudio:%1").arg(key);
463
464 auto adc = GetAudioDeviceConfig(devname, desc);
465 if (!adc)
466 continue;
467 list->append(*adc);
468 delete adc;
469 }
470 }
471 delete devs;
472 QString name = "CoreAudio:Default Output Device";
473 QString desc = tr("CoreAudio default output");
474 auto adc = GetAudioDeviceConfig(name, desc);
475 if (adc)
476 {
477 list->append(*adc);
478 delete adc;
479 }
480 }
481#endif
482#ifdef _WIN32
483 {
484 QString name = "Windows:";
485 QString desc = "Windows default output";
486 auto adc = GetAudioDeviceConfig(name, desc);
487 if (adc)
488 {
489 list->append(*adc);
490 delete adc;
491 }
492
493 QMap<int, QString> *dxdevs = AudioOutputDX::GetDXDevices();
494
495 if (!dxdevs->empty())
496 {
497 for (QMap<int, QString>::const_iterator i = dxdevs->begin();
498 i != dxdevs->end(); ++i)
499 {
500 QString devdesc = i.value();
501 QString devname = QString("DirectX:%1").arg(devdesc);
502
503 adc = GetAudioDeviceConfig(devname, devdesc);
504 if (!adc)
505 continue;
506 list->append(*adc);
507 delete adc;
508 }
509 }
510 delete dxdevs;
511 }
512#endif
513
514#if CONFIG_AUDIO_PULSE
515 if (pasuspended)
517#endif
518
519#if CONFIG_AUDIO_PULSEOUTPUT
520 {
521 QString name = "PulseAudio:default";
522 QString desc = tr("PulseAudio default sound server.");
523 auto *adc = GetAudioDeviceConfig(name, desc);
524 if (adc)
525 {
526 list->append(*adc);
527 delete adc;
528 }
529 }
530#endif
531
532#ifdef Q_OS_ANDROID
533 {
534 QString name = "OpenSLES:";
535 QString desc = tr("OpenSLES default output. Stereo support only.");
536 auto adc = GetAudioDeviceConfig(name, desc);
537 if (adc)
538 {
539 list->append(*adc);
540 delete adc;
541 }
542 }
543 {
544 QString name = "AudioTrack:";
545 QString desc = tr("Android AudioTrack output. Supports surround sound.");
546 auto adc = GetAudioDeviceConfig(name, desc);
547 if (adc)
548 {
549 list->append(*adc);
550 delete adc;
551 }
552 }
553#endif
554
555 QString name = "NULL";
556 QString desc = "NULL device";
557 auto *adc = GetAudioDeviceConfig(name, desc);
558 if (adc)
559 {
560 list->append(*adc);
561 delete adc;
562 }
563 return list;
564}
565
566int AudioOutput::DecodeAudio(AVCodecContext *ctx,
567 uint8_t *buffer, int &data_size,
568 const AVPacket *pkt)
569{
570 bool got_frame = false;
571
572 data_size = 0;
573 if (!m_frame)
574 {
575 m_frame = av_frame_alloc();
576 if (m_frame == nullptr)
577 {
578 return AVERROR(ENOMEM);
579 }
580 }
581 else
582 {
583 av_frame_unref(m_frame);
584 }
585
586// SUGGESTION
587// Now that avcodec_decode_audio4 is deprecated and replaced
588// by 2 calls (receive frame and send packet), this could be optimized
589// into separate routines or separate threads.
590// Also now that it always consumes a whole buffer some code
591// in the caller may be able to be optimized.
592 int ret = avcodec_receive_frame(ctx,m_frame);
593 if (ret == 0)
594 got_frame = true;
595 if (ret == AVERROR(EAGAIN))
596 ret = 0;
597 if (ret == 0)
598 ret = avcodec_send_packet(ctx, pkt);
599 if (ret == AVERROR(EAGAIN))
600 ret = 0;
601 else if (ret < 0)
602 {
603 std::string error;
604 LOG(VB_AUDIO, LOG_ERR, LOC +
605 QString("audio decode error: %1 (%2)")
607 .arg(got_frame));
608 return ret;
609 }
610 else
611 {
612 ret = pkt->size;
613 }
614
615 if (!got_frame)
616 {
617 LOG(VB_AUDIO, LOG_DEBUG, LOC +
618 QString("audio decode, no frame decoded (%1)").arg(ret));
619 return ret;
620 }
621
622 auto format = (AVSampleFormat)m_frame->format;
623 AudioFormat fmt =
624 AudioOutputSettings::AVSampleFormatToFormat(format, ctx->bits_per_raw_sample);
625
626 data_size = m_frame->nb_samples * m_frame->ch_layout.nb_channels * av_get_bytes_per_sample(format);
627
628 // May need to convert audio to S16
629 AudioConvert converter(fmt, CanProcess(fmt) ? fmt : FORMAT_S16);
630 uint8_t* src = nullptr;
631
632 if (av_sample_fmt_is_planar(format))
633 {
634 src = buffer;
635 converter.InterleaveSamples(m_frame->ch_layout.nb_channels,
636 src,
637 (const uint8_t **)m_frame->extended_data,
638 data_size);
639 }
640 else
641 {
642 // data is already compacted...
643 src = m_frame->extended_data[0];
644 }
645
646 uint8_t* transit = buffer;
647
648 if (!CanProcess(fmt) &&
649 av_get_bytes_per_sample(ctx->sample_fmt) < AudioOutputSettings::SampleSize(converter.Out()))
650 {
651 // this conversion can't be done in place
652 transit = (uint8_t*)av_malloc(data_size * av_get_bytes_per_sample(ctx->sample_fmt)
653 / AudioOutputSettings::SampleSize(converter.Out()));
654 if (!transit)
655 {
656 LOG(VB_AUDIO, LOG_ERR, LOC +
657 QString("audio decode, out of memory"));
658 data_size = 0;
659 return ret;
660 }
661 }
662 if (!CanProcess(fmt) || src != transit)
663 {
664 data_size = converter.Process(transit, src, data_size, true);
665 }
666 if (transit != buffer)
667 {
668 av_free(transit);
669 }
670 return ret;
671}
672
673void AudioOutput::dispatchError(const QString &e)
674{
675 Event event(e);
676 dispatch(event);
677}
678
680{
681 auto it = std::find(m_visuals.begin(), m_visuals.end(), v);
682 if (it == m_visuals.end())
683 m_visuals.push_back(v);
684}
685
687{
688 auto it = std::find(m_visuals.begin(), m_visuals.end(), v);
689 if (it != m_visuals.end())
690 m_visuals.erase(it);
691}
692
693void AudioOutput::dispatchVisual(uchar *buffer, unsigned long b_len,
694 std::chrono::milliseconds timecode,
695 int chan, int prec)
696{
697 if (! buffer)
698 return;
699
700 for (auto & visual : m_visuals)
701 {
702 QMutexLocker locker(visual->mutex());
703 visual->add(buffer, b_len, timecode, chan, prec);
704 }
705}
706
708{
709 for (auto & visual : m_visuals)
710 {
711 QMutexLocker locker(visual->mutex());
712 visual->prepare();
713 }
714}
715
716static char* generatePinkFrames(char* frames, int channels, int channel, int count, int bits)
717{
718 pink_noise_t pink{};
719
721
722 auto *samp16 = (int16_t*) frames;
723 auto *samp32 = (int32_t*) frames;
724
725 while (count-- > 0)
726 {
727 for(int chn = 0 ; chn < channels; chn++)
728 {
729 if (chn==channel)
730 {
731 /* Don't use MAX volume */
732 double res = generate_pink_noise_sample(&pink) *
733 static_cast<float>(0x03fffffff);
734 int32_t ires = res;
735 if (bits == 16)
736 *samp16++ = qToLittleEndian<qint16>(ires >> 16);
737 else
738 *samp32++ = qToLittleEndian<qint32>(ires);
739 }
740 else
741 {
742 if (bits == 16)
743 *samp16++ = 0;
744 else
745 *samp32++ = 0;
746 }
747 }
748 }
749 return frames;
750}
751
752bool AudioOutput::playPinkNoise(char *frames, int channels, int channel, int count, int bits)
753{
754 generatePinkFrames(frames, channels, channel, count, bits);
755 return AddFrames(frames, count, -1ms);
756}
#define LOC
Definition: audiooutput.cpp:55
static char * generatePinkFrames(char *frames, int channels, int channel, int count, int bits)
@ FORMAT_NONE
@ FORMAT_S16
AudioOutputSource
Definition: audiosettings.h:21
AudioFormat Out(void)
Definition: audioconvert.h:49
void InterleaveSamples(int channels, uint8_t *output, const uint8_t *const *input, int data_size)
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...
static QMap< QString, QString > * GetDevices(const char *type)
Implements Core Audio (Mac OS X Hardware Abstraction Layer) output.
Definition: audiooutputca.h:14
static QMap< QString, QString > * GetDevices(const char *type=nullptr)
static QMap< int, QString > * GetDXDevices(void)
eld & getELD(void)
retrieve ELD data
static int SampleSize(AudioFormat format)
bool canLPCM() const
return true if device supports multichannels PCM (deprecated, see canFeature())
bool canAC3() const
return true if device can or may support AC3 (deprecated, see canFeature())
int BestSupportedChannelsELD()
Reports best supported channel number, restricted to ELD range.
bool hasELD() const
get the ELD flag
static AudioFormat AVSampleFormatToFormat(AVSampleFormat format, int bits=0)
Return AVSampleFormat closest equivalent to AudioFormat.
bool canDTS() const
return true if device can or may support DTS (deprecated, see canFeature())
bool IsInvalid() const
return true if class instance is marked invalid.
void addVisual(Visualization *v)
~AudioOutput() override
void removeVisual(Visualization *v)
static AudioOutput * OpenAudio(const QString &main_device, const QString &passthru_device, AudioFormat format, int channels, AVCodecID codec, int samplerate, AudioOutputSource source, bool set_initial_vol, bool passthru, int upmixer_startup=0, AudioOutputSettings *custom=nullptr)
Definition: audiooutput.cpp:64
static ADCVect * GetOutputList(void)
bool m_pulseWasSuspended
Definition: audiooutput.h:227
virtual AudioOutputSettings * GetOutputSettingsUsers(bool digital=true)
QVector< AudioDeviceConfig > ADCVect
Definition: audiooutput.h:55
void dispatchVisual(uchar *b, unsigned long b_len, std::chrono::milliseconds timecode, int chan, int prec)
int DecodeAudio(AVCodecContext *ctx, uint8_t *buffer, int &data_size, const AVPacket *pkt)
Utility routine.
virtual bool CanPassthrough(int samplerate, int channels, AVCodecID codec, int profile) const
static AudioDeviceConfig * GetAudioDeviceConfig(QString &name, const QString &desc, bool willsuspendpa=false)
void dispatchError(const QString &e)
void prepareVisuals()
virtual bool AddFrames(void *buffer, int frames, std::chrono::milliseconds timecode)=0
Add frames to the audiobuffer for playback.
virtual AudioOutputSettings * GetOutputSettingsCleaned(bool digital=true)
virtual uint32_t CanProcess(void)
Definition: audiooutput.h:179
virtual void SetStretchFactor(float factor)
static void Cleanup(void)
Definition: audiooutput.cpp:57
bool playPinkNoise(char *frames, int channels, int channel, int count, int bits)
Generates and plays pink noise from a speaker for testing.
std::vector< Visualization * > m_visuals
Definition: audiooutput.h:229
AVFrame * m_frame
Definition: audiooutput.h:228
const int & channels() const
Definition: audiooutput.h:254
QString m_mainDevice
Definition: audiosettings.h:70
void TrimDeviceType(void)
AudioFormat m_format
Definition: audiosettings.h:72
void FixPassThrough(void)
Event details.
Definition: zmdefines.h:28
void dispatch(const MythEvent &event)
Dispatch an event to all listeners.
static bool Suspend(enum PulseAction action)
QString codecs_desc() const
Definition: eldutils.cpp:471
bool isValid() const
Definition: eldutils.cpp:407
QString connection_name() const
Definition: eldutils.cpp:441
QString product_name() const
Definition: eldutils.cpp:436
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
char * av_make_error_stdstring(std::string &errbuf, int errnum)
A C++ equivalent to av_make_error_string.
Definition: mythaverror.cpp:42
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
bool IsPulseAudioRunning(void)
Is A/V Sync destruction daemon is running on this host?
def error(message)
Definition: smolt.py:409
void initialize_pink_noise(pink_noise_t *pink, int num_rows)
Definition: pink.cpp:42
float generate_pink_noise_sample(pink_noise_t *pink)
Definition: pink.cpp:56
uint fillSelectionsFromDir(const QDir &dir, uint minor_min, uint minor_max, const QString &card, const QRegularExpression &driver, bool allow_duplicates, V2CaptureDeviceList *pList, const QString &cardType)