MythTV master
audiooutputbase.cpp
Go to the documentation of this file.
1// C++ headers
2#include <algorithm>
3#include <array>
4#include <cmath>
5#include <limits>
6#include <numbers>
7#include <thread>
8
9#include <unistd.h> // getpid
10
11// SoundTouch
12#pragma GCC diagnostic push
13#pragma GCC diagnostic ignored "-Wundef"
14#if __has_include(<soundtouch/SoundTouch.h>)
15#include <soundtouch/SoundTouch.h>
16#else
17#include <SoundTouch.h>
18#endif
19#pragma GCC diagnostic pop
20
21extern "C" {
22#include "libavcodec/defs.h"
23}
24
25// Qt headers
26#include <QtGlobal>
27#include <QChar> // Fix Qt6 GCC SFINAE warning
28#include <QMutexLocker>
29#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
30#include <QtProcessorDetection>
31#endif
32
33// MythTV headers
34#include "libmythbase/compat.h"
37
38#include "audioconvert.h"
39#include "audiooutputbase.h"
41#include "freesurround.h"
42#include "spdifencoder.h"
43
44// AC3 encode currently disabled for Android
45#ifdef Q_OS_ANDROID
46#define DISABLE_AC3_ENCODE
47#endif
48
49#define LOC QString("AOBase: ")
50
51// Replacing "m_audioBuffer + org_waud" with
52// "&m_audioBuffer[org_waud]" should provide bounds
53// checking with c++17 arrays.
54#define WPOS (&m_audioBuffer[org_waud])
55#define RPOS (&m_audioBuffer[m_raud])
56#define ABUF (m_audioBuffer.data())
57#define STST soundtouch::SAMPLETYPE
58
59// 1,2,5 and 7 channels are currently valid for upmixing if required
60static constexpr int UPMIX_CHANNEL_MASK { (1<<1)|(1<<2)|(1<<5)|(1<<7) };
61static constexpr bool IS_VALID_UPMIX_CHANNEL(int ch)
62{ return ((1 << ch) & UPMIX_CHANNEL_MASK) != 0; }
63
64/*
65 SMPTE channel layout
66 DUAL-MONO L R
67 DUAL-MONO-LFE L R LFE
68 MONO M
69 MONO-LFE M LFE
70 STEREO L R
71 STEREO-LFE L R LFE
72 3F L R C
73 3F-LFE L R C LFE
74 2F1 L R S
75 2F1-LFE L R LFE S
76 3F1 L R C S
77 3F1-LFE L R C LFE S
78 2F2 L R LS RS
79 2F2-LFE L R LFE LS RS
80 3F2 L R C LS RS
81 3F2-LFE L R C LFE LS RS
82 3F3R-LFE L R C LFE BC LS RS
83 3F4-LFE L R C LFE Rls Rrs LS RS
84 */
85
86static const float m6db = 0.5;
87static const float m3db = 1.0F / std::numbers::sqrt2_v<float>; // 3dB = SQRT(1/2)
88static const float mm3db = -1.0F / std::numbers::sqrt2_v<float>; // -3dB = SQRT(1/2)
89static const float msqrt_1_3 = -std::numbers::inv_sqrt3_v<float>; // -SQRT(1/3)
90static const float sqrt_2_3 = std::numbers::sqrt2_v<float> /
91 std::numbers::sqrt3_v<float>; // SQRT(2/3)
92static const float sqrt_2_3by3db = std::numbers::inv_sqrt3_v<float>; // SQRT(2/3)*-3dB = SQRT(2/3)*SQRT(1/2)=SQRT(1/3)
93static const float msqrt_1_3bym3db = 1.0F / (std::numbers::sqrt2_v<float> *
94 std::numbers::sqrt3_v<float>); // -SQRT(1/3)*-3dB = -SQRT(1/3)*SQRT(1/2) = -SQRT(1/6)
95
96using two_speaker_ratio = std::array<float,2>;
97using two_speaker_set = std::array<two_speaker_ratio,8>;
98static const std::array<two_speaker_set,8> stereo_matrix
99{{
100//1F L R
101 {{
102 { 1, 1 }, // M
103 }},
104
105//2F L R
106 {{
107 { 1, 0 }, // L
108 { 0, 1 }, // R
109 }},
110
111//3F L R
112 {{
113 { 1, 0 }, // L
114 { 0, 1 }, // R
115 { 1, 1 }, // C
116 }},
117
118//3F1R L R
119 {{
120 { 1, 0 }, // L
121 { 0, 1 }, // R
122 { m3db, m3db }, // C
123 { mm3db, m3db }, // S
124 }},
125
126//3F2R L R
127 {{
128 { 1, 0 }, // L
129 { 0, 1 }, // R
130 { m3db, m3db }, // C
131 { sqrt_2_3, msqrt_1_3 }, // LS
132 { msqrt_1_3, sqrt_2_3 }, // RS
133 }},
134
135//3F2R.1 L R
136 {{
137 { 1, 0 }, // L
138 { 0, 1 }, // R
139 { m3db, m3db }, // C
140 { 0, 0 }, // LFE
141 { sqrt_2_3, msqrt_1_3 }, // LS
142 { msqrt_1_3, sqrt_2_3 }, // RS
143 }},
144
145// 3F3R.1 L R
146 {{
147 { 1, 0 }, // L
148 { 0, 1 }, // R
149 { m3db, m3db }, // C
150 { 0, 0 }, // LFE
151 { m6db, m6db }, // Cs
152 { sqrt_2_3, msqrt_1_3 }, // LS
153 { msqrt_1_3, sqrt_2_3 }, // RS
154 }},
155
156// 3F4R.1 L R
157 {{
158 { 1, 0 }, // L
159 { 0, 1 }, // R
160 { m3db, m3db }, // C
161 { 0, 0 }, // LFE
162 { sqrt_2_3by3db, msqrt_1_3bym3db }, // Rls
163 { msqrt_1_3bym3db, sqrt_2_3by3db }, // Rrs
166 }}
167}};
168
169using six_speaker_ratio = std::array<float,6>;
170using six_speaker_set = std::array<six_speaker_ratio,8>;
171static const std::array<six_speaker_set,3> s51_matrix
172{{
173 // 3F2R.1 in -> 3F2R.1 out
174 // L R C LFE LS RS
175 {{
176 { 1, 0, 0, 0, 0, 0 }, // L
177 { 0, 1, 0, 0, 0, 0 }, // R
178 { 0, 0, 1, 0, 0, 0 }, // C
179 { 0, 0, 0, 1, 0, 0 }, // LFE
180 { 0, 0, 0, 0, 1, 0 }, // LS
181 { 0, 0, 0, 0, 0, 1 }, // RS
182 }},
183 // 3F3R.1 in -> 3F2R.1 out
184 // Used coefficient found at http://www.yamahaproaudio.com/training/self_training/data/smqr_en.pdf
185 // L R C LFE LS RS
186 {{
187 { 1, 0, 0, 0, 0, 0 }, // L
188 { 0, 1, 0, 0, 0, 0 }, // R
189 { 0, 0, 1, 0, 0, 0 }, // C
190 { 0, 0, 0, 1, 0, 0 }, // LFE
191 { 0, 0, 0, 0, m3db, m3db }, // Cs
192 { 0, 0, 0, 0, 1, 0 }, // LS
193 { 0, 0, 0, 0, 0, 1 }, // RS
194 }},
195 // 3F4R.1 -> 3F2R.1 out
196 // L R C LFE LS RS
197 {{
198 { 1, 0, 0, 0, 0, 0 }, // L
199 { 0, 1, 0, 0, 0, 0 }, // R
200 { 0, 0, 1, 0, 0, 0 }, // C
201 { 0, 0, 0, 1, 0, 0 }, // LFE
202 { 0, 0, 0, 0, m3db, 0 }, // Rls
203 { 0, 0, 0, 0, 0, m3db }, // Rrs
204 { 0, 0, 0, 0, m3db, 0 }, // LS
205 { 0, 0, 0, 0, 0, m3db }, // RS
206 }}
207}};
208
209static int DownmixFrames(int channels_in, int channels_out,
210 float *dst, const float *src, int frames)
211{
212 if (channels_in < channels_out)
213 return -1;
214
215 //LOG(VB_AUDIO, LOG_INFO, QString("Downmixing %1 frames (in:%2 out:%3)")
216 // .arg(frames).arg(channels_in).arg(channels_out));
217 if (channels_out == 2)
218 {
219 int index = channels_in - 1;
220 for (int n=0; n < frames; n++)
221 {
222 for (int i=0; i < channels_out; i++)
223 {
224 float tmp = 0.0F;
225 for (int j=0; j < channels_in; j++)
226 tmp += src[j] * stereo_matrix[index][j][i];
227 *dst++ = tmp;
228 }
229 src += channels_in;
230 }
231 }
232 else if (channels_out == 6)
233 {
234 int index = channels_in - 6;
235 for (int n=0; n < frames; n++)
236 {
237 for (int i=0; i < channels_out; i++)
238 {
239 float tmp = 0.0F;
240 for (int j=0; j < channels_in; j++)
241 tmp += src[j] * s51_matrix[index][j][i];
242 *dst++ = tmp;
243 }
244 src += channels_in;
245 }
246 }
247 else
248 {
249 return -1;
250 }
251
252 return frames;
253}
254
255#ifdef Q_PROCESSOR_X86
256// Check cpuid for SSE2 support on x86 / x86_64
257static inline bool sse2_check()
258{
259#ifdef Q_PROCESSOR_X86_64
260 return true;
261#else
262 static int has_sse2 = -1;
263 if (has_sse2 != -1)
264 return (bool)has_sse2;
265 __asm__(
266 // -fPIC - we may not clobber ebx/rbx
267 "push %%ebx \n\t"
268 "mov $1, %%eax \n\t"
269 "cpuid \n\t"
270 "and $0x4000000, %%edx \n\t"
271 "shr $26, %%edx \n\t"
272 "pop %%ebx \n\t"
273 :"=d"(has_sse2)
274 ::"%eax","%ecx"
275 );
276 return (bool)has_sse2;
277#endif
278}
279#endif //Q_PROCESSOR_X86
280
286{
287#ifdef Q_PROCESSOR_X86
288 return sse2_check();
289#else
290 return false;
291#endif
292}
293
300static void adjustVolume(void *buf, int len, int volume,
301 bool music, bool upmix)
302{
303 float g = volume / 100.0F;
304 auto *fptr = (float *)buf;
305 int samples = len >> 2;
306 int i = 0;
307
308 // Should be exponential - this'll do
309 g *= g;
310
311 // Try to ~ match stereo volume when upmixing
312 if (upmix)
313 g *= 1.5F;
314
315 // Music is relatively loud
316 if (music)
317 g *= 0.4F;
318
319 if (g == 1.0F)
320 return;
321
322#ifdef Q_PROCESSOR_X86
323 if (sse2_check() && samples >= 16)
324 {
325 int loops = samples >> 4;
326 i = loops << 4;
327
328 __asm__ volatile (
329 "movss %2, %%xmm0 \n\t"
330 "punpckldq %%xmm0, %%xmm0 \n\t"
331 "punpckldq %%xmm0, %%xmm0 \n\t"
332 "1: \n\t"
333 "movups (%0), %%xmm1 \n\t"
334 "movups 16(%0), %%xmm2 \n\t"
335 "mulps %%xmm0, %%xmm1 \n\t"
336 "movups 32(%0), %%xmm3 \n\t"
337 "mulps %%xmm0, %%xmm2 \n\t"
338 "movups 48(%0), %%xmm4 \n\t"
339 "mulps %%xmm0, %%xmm3 \n\t"
340 "movups %%xmm1, (%0) \n\t"
341 "mulps %%xmm0, %%xmm4 \n\t"
342 "movups %%xmm2, 16(%0) \n\t"
343 "movups %%xmm3, 32(%0) \n\t"
344 "movups %%xmm4, 48(%0) \n\t"
345 "add $64, %0 \n\t"
346 "sub $1, %%ecx \n\t"
347 "jnz 1b \n\t"
348 :"+r"(fptr)
349 :"c"(loops),"m"(g)
350 :"xmm0","xmm1","xmm2","xmm3","xmm4"
351 );
352 }
353#endif //Q_PROCESSOR_X86
354 for (; i < samples; i++)
355 *fptr++ *= g;
356}
357
358template <class AudioDataType>
359static void tMuteChannel(AudioDataType *buffer, int channels, int ch, int frames)
360{
361 AudioDataType *s1 = buffer + ch;
362 AudioDataType *s2 = buffer - ch + 1;
363
364 for (int i = 0; i < frames; i++)
365 {
366 *s1 = *s2;
367 s1 += channels;
368 s2 += channels;
369 }
370}
371
378static void muteChannel(int obits, int channels, int ch,
379 void *buffer, int bytes)
380{
381 int frames = bytes / ((obits >> 3) * channels);
382
383 if (obits == 8)
384 tMuteChannel((uint8_t *)buffer, channels, ch, frames);
385 else if (obits == 16)
386 tMuteChannel((short *)buffer, channels, ch, frames);
387 else
388 tMuteChannel((int *)buffer, channels, ch, frames);
389}
390
392{
393 switch(q)
394 {
395 case QUALITY_DISABLED: return "disabled";
396 case QUALITY_LOW: return "low";
397 case QUALITY_MEDIUM: return "medium";
398 case QUALITY_HIGH: return "high";
399 default: return "unknown";
400 }
401}
402
404 MThread("AudioOutputBase"),
405 // protected
406 m_mainDevice(settings.GetMainDevice()),
407 m_passthruDevice(settings.GetPassthruDevice()),
408 m_source(settings.m_source),
409 m_setInitialVol(settings.m_setInitialVol)
410{
411 m_srcIn = m_srcInBuf.data();
412
413 if (m_mainDevice.startsWith("AudioTrack:"))
414 m_usesSpdif = false;
415 // Handle override of SRC quality settings
416 if (gCoreContext->GetBoolSetting("SRCQualityOverride", false))
417 {
419 // Extra test to keep backward compatibility with earlier SRC setting
420 m_srcQuality = std::min<int>(m_srcQuality, QUALITY_HIGH);
421
422 LOG(VB_AUDIO, LOG_INFO, LOC + QString("SRC quality = %1").arg(quality_string(m_srcQuality)));
423 }
424}
425
432{
433 if (!m_killAudio)
434 LOG(VB_GENERAL, LOG_ERR, LOC + "Programmer Error: "
435 "~AudioOutputBase called, but KillAudio has not been called!");
436
437 // We got this from a subclass, delete it
438 delete m_outputSettings;
439 delete m_outputSettingsRaw;
441 {
444 }
445
446 if (m_kAudioSRCOutputSize > 0)
447 delete[] m_srcOut;
448
449#ifndef NDEBUG
450 assert(m_memoryCorruptionTest0 == 0xdeadbeef);
451 assert(m_memoryCorruptionTest1 == 0xdeadbeef);
452 assert(m_memoryCorruptionTest2 == 0xdeadbeef);
453 assert(m_memoryCorruptionTest3 == 0xdeadbeef);
454#endif
455}
456
458{
459 if (settings.m_custom)
460 {
461 // got a custom audio report already, use it
462 // this was likely provided by the AudioTest utility
464 *m_outputSettings = *settings.m_custom;
468 return;
469 }
470
471 // Ask the subclass what we can send to the device
474
478
480 gCoreContext->GetBoolSetting("AudioDefaultUpmix", false) :
481 false;
482 if (settings.m_upmixer == 1) // music, upmixer off
483 m_upmixDefault = false;
484 else if (settings.m_upmixer == 2) // music, upmixer on
485 m_upmixDefault = true;
486}
487
494{
495 // If we've already checked the port, use the cache
496 // version instead
497 if (!m_discreteDigital || !digital)
498 {
499 digital = false;
501 return m_outputSettingsRaw;
502 }
504 {
506 }
507
508 AudioOutputSettings* aosettings = GetOutputSettings(digital);
509 if (aosettings)
510 aosettings->GetCleaned();
511 else
512 aosettings = new AudioOutputSettings(true);
513
514 if (digital)
515 return (m_outputSettingsDigitalRaw = aosettings);
516 return (m_outputSettingsRaw = aosettings);
517}
518
525{
526 if (!m_discreteDigital || !digital)
527 {
528 digital = false;
530 return m_outputSettings;
531 }
533 {
535 }
536
537 auto* aosettings = new AudioOutputSettings;
538
539 *aosettings = *GetOutputSettingsCleaned(digital);
540 aosettings->GetUsers();
541
542 if (digital)
543 return (m_outputSettingsDigital = aosettings);
544 return (m_outputSettings = aosettings);
545}
546
550bool AudioOutputBase::CanPassthrough(int samplerate, int channels,
551 AVCodecID codec, int profile) const
552{
554 bool ret = !(m_internalVol && SWVolume());
555
556 switch(codec)
557 {
558 case AV_CODEC_ID_AC3:
559 arg = FEATURE_AC3;
560 break;
561 case AV_CODEC_ID_DTS:
562 switch(profile)
563 {
564 case AV_PROFILE_DTS:
565 case AV_PROFILE_DTS_ES:
566 case AV_PROFILE_DTS_96_24:
567 arg = FEATURE_DTS;
568 break;
569 case AV_PROFILE_DTS_HD_HRA:
570 case AV_PROFILE_DTS_HD_MA:
571 arg = FEATURE_DTSHD;
572 break;
573 default:
574 break;
575 }
576 break;
577 case AV_CODEC_ID_EAC3:
578 arg = FEATURE_EAC3;
579 break;
580 case AV_CODEC_ID_TRUEHD:
581 arg = FEATURE_TRUEHD;
582 break;
583 default:
584 arg = FEATURE_NONE;
585 break;
586 }
587 // we can't passthrough any other codecs than those defined above
590 ret &= m_outputSettingsDigital->IsSupportedRate(samplerate);
591 // if we must resample to 48kHz ; we can't passthrough
592 ret &= (samplerate == 48000) ||
593 !gCoreContext->GetBoolSetting("Audio48kOverride", false);
594 // Don't know any cards that support spdif clocked at < 44100
595 // Some US cable transmissions have 2ch 32k AC-3 streams
596 ret &= samplerate >= 44100;
597 if (!ret)
598 return false;
599 // Will passthrough if surround audio was defined. Amplifier will
600 // do the downmix if required
601 bool willupmix = m_maxChannels >= 6 && (channels <= 2 && m_upmixDefault);
602 ret &= !willupmix;
603 // unless audio is configured for stereo. We can passthrough otherwise
604 ret |= m_maxChannels == 2;
605
606 return ret;
607}
608
613{
614 if (rate > 0)
615 m_sourceBitRate = rate;
616}
617
624{
625 if (m_stretchFactor == lstretchfactor && m_pSoundStretch)
626 return;
627
628 m_stretchFactor = lstretchfactor;
629
632 if (channels < 1 || channels > 8 || !m_isConfigured)
633 return;
634
635 bool willstretch = m_stretchFactor < 0.99F || m_stretchFactor > 1.01F;
636 m_effStretchFactor = lroundf(100000.0F * lstretchfactor);
637
638 if (m_pSoundStretch)
639 {
640 if (!willstretch && m_forcedProcessing)
641 {
642 m_forcedProcessing = false;
643 m_processing = false;
644 delete m_pSoundStretch;
645 m_pSoundStretch = nullptr;
646 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Cancelling time stretch"));
648 m_raud = 0;
649 m_waud = 0;
651 }
652 else
653 {
654 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Changing time stretch to %1")
655 .arg(m_stretchFactor));
657 }
658 }
659 else if (willstretch)
660 {
661 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Using time stretch %1").arg(m_stretchFactor));
662 m_pSoundStretch = new soundtouch::SoundTouch();
663 m_pSoundStretch->setSampleRate(m_sampleRate);
664 m_pSoundStretch->setChannels(channels);
666#if defined(Q_PROCESSOR_ARM) || defined(Q_OS_ANDROID)
667 // use less demanding settings for Raspberry pi
668 m_pSoundStretch->setSetting(SETTING_SEQUENCE_MS, 82);
669 m_pSoundStretch->setSetting(SETTING_USE_AA_FILTER, 0);
670 m_pSoundStretch->setSetting(SETTING_USE_QUICKSEEK, 1);
671#else
672 m_pSoundStretch->setSetting(SETTING_SEQUENCE_MS, 35);
673#endif
674 /* If we weren't already processing we need to turn on float conversion
675 adjust sample and frame sizes accordingly and dump the contents of
676 the audiobuffer */
677 if (!m_processing)
678 {
679 m_processing = true;
680 m_forcedProcessing = true;
686 m_raud = 0;
687 m_waud = 0;
690 m_pauseAudio = true;
691 m_actuallyPaused = false;
692 m_unpauseWhenReady = true;
693 }
694 }
695}
696
700void AudioOutputBase::SetStretchFactor(float lstretchfactor)
701{
702 QMutexLocker lock(&m_audioBufLock);
703 SetStretchFactorLocked(lstretchfactor);
704}
705
710{
711 return m_stretchFactor;
712}
713
718{
719 return m_needsUpmix && m_upmixer;
720}
721
726{
727 // Can only upmix from mono/stereo to 6 ch
728 if (m_maxChannels == 2 || m_sourceChannels > 2)
729 return false;
730
732
735 m_upmixDefault ? false : m_passthru);
736 Reconfigure(settings);
737 return IsUpmixing();
738}
739
744{
745 return m_sourceChannels <= 2 && m_maxChannels > 2;
746}
747
748/*
749 * Setup samplerate and number of channels for passthrough
750 * Create SPDIF encoder and true if successful
751 */
752bool AudioOutputBase::SetupPassthrough(AVCodecID codec, int codec_profile,
753 int &samplerate_tmp, int &channels_tmp)
754{
755 if (codec == AV_CODEC_ID_DTS &&
757 {
758 // We do not support DTS-HD bitstream so force extraction of the
759 // DTS core track instead
760 codec_profile = AV_PROFILE_DTS;
761 }
763 codec, codec_profile,
764 samplerate_tmp, channels_tmp,
766 LOG(VB_AUDIO, LOG_INFO, LOC + "Setting " + log + " passthrough");
767
768 delete m_spdifEnc;
769
770 // No spdif encoder needed for certain devices
771 if (m_usesSpdif)
772 m_spdifEnc = new SPDIFEncoder("spdif", codec);
773 else
774 m_spdifEnc = nullptr;
775 if (m_spdifEnc && m_spdifEnc->Succeeded() && codec == AV_CODEC_ID_DTS)
776 {
777 switch(codec_profile)
778 {
779 case AV_PROFILE_DTS:
780 case AV_PROFILE_DTS_ES:
781 case AV_PROFILE_DTS_96_24:
783 break;
784 case AV_PROFILE_DTS_HD_HRA:
785 case AV_PROFILE_DTS_HD_MA:
786 m_spdifEnc->SetMaxHDRate(samplerate_tmp * channels_tmp / 2);
787 break;
788 }
789 }
790
792 {
793 delete m_spdifEnc;
794 m_spdifEnc = nullptr;
795 return false;
796 }
797 return true;
798}
799
801{
802 if (digital)
804 return m_outputSettings;
805}
806
813{
814 AudioSettings settings = orig_settings;
815 int lsource_channels = settings.m_channels;
816 int lconfigured_channels = m_configuredChannels;
817 bool lneeds_upmix = false;
818 bool lneeds_downmix = false;
819 bool lreenc = false;
820 bool lenc = false;
821
822 if (!settings.m_usePassthru)
823 {
824 // Do we upmix stereo or mono?
825 lconfigured_channels =
826 (m_upmixDefault && lsource_channels <= 2) ? 6 : lsource_channels;
827 bool cando_channels =
828 m_outputSettings->IsSupportedChannels(lconfigured_channels);
829
830 // check if the number of channels could be transmitted via AC3 encoding
831#ifndef DISABLE_AC3_ENCODE
834 lconfigured_channels > 2 && lconfigured_channels <= 6);
835#endif
836 if (!lenc && !cando_channels)
837 {
838 // if hardware doesn't support source audio configuration
839 // we will upmix/downmix to what we can
840 // (can safely assume hardware supports stereo)
841 switch (lconfigured_channels)
842 {
843 case 7:
844 lconfigured_channels = 8;
845 break;
846 case 8:
847 case 5:
848 lconfigured_channels = 6;
849 break;
850 case 6:
851 case 4:
852 case 3:
853 case 2: //Will never happen
854 lconfigured_channels = 2;
855 break;
856 case 1:
857 lconfigured_channels = m_upmixDefault ? 6 : 2;
858 break;
859 default:
860 lconfigured_channels = 2;
861 break;
862 }
863 }
864 // Make sure we never attempt to output more than what we can
865 // the upmixer can only upmix to 6 channels when source < 6
866 if (lsource_channels <= 6)
867 lconfigured_channels = std::min(lconfigured_channels, 6);
868 lconfigured_channels = std::min(lconfigured_channels, m_maxChannels);
869 /* Encode to AC-3 if we're allowed to passthru but aren't currently
870 and we have more than 2 channels but multichannel PCM is not
871 supported or if the device just doesn't support the number of
872 channels */
873#ifndef DISABLE_AC3_ENCODE
876 lconfigured_channels > 2) ||
877 !m_outputSettings->IsSupportedChannels(lconfigured_channels));
878 /* Might we reencode a bitstream that's been decoded for timestretch?
879 If the device doesn't support the number of channels - see below */
881 (settings.m_codec == AV_CODEC_ID_AC3 ||
882 settings.m_codec == AV_CODEC_ID_DTS))
883 {
884 lreenc = true;
885 }
886#endif
887 // Enough channels? Upmix if not, but only from mono/stereo/5.0 to 5.1
888 if (IS_VALID_UPMIX_CHANNEL(settings.m_channels) &&
889 settings.m_channels < lconfigured_channels)
890 {
891 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Needs upmix from %1 -> %2 channels")
892 .arg(settings.m_channels).arg(lconfigured_channels));
893 settings.m_channels = lconfigured_channels;
894 lneeds_upmix = true;
895 }
896 else if (settings.m_channels > lconfigured_channels)
897 {
898 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Needs downmix from %1 -> %2 channels")
899 .arg(settings.m_channels).arg(lconfigured_channels));
900 settings.m_channels = lconfigured_channels;
901 lneeds_downmix = true;
902 }
903 }
904
905 bool general_deps = true;
906
907 /* Set samplerate_tmp and channels_tmp to appropriate values
908 if passing through */
909 int samplerate_tmp = 0;
910 int channels_tmp = 0;
911 if (settings.m_usePassthru)
912 {
913 samplerate_tmp = settings.m_sampleRate;
914 SetupPassthrough(settings.m_codec, settings.m_codecProfile,
915 samplerate_tmp, channels_tmp);
916 general_deps = m_sampleRate == samplerate_tmp && m_channels == channels_tmp;
917 general_deps &= m_format == m_outputFormat && m_format == FORMAT_S16;
918 }
919 else
920 {
921 general_deps =
922 settings.m_format == m_format && lsource_channels == m_sourceChannels;
923 }
924
925 // Check if anything has changed
926 general_deps &=
927 settings.m_sampleRate == m_sourceSampleRate &&
928 settings.m_usePassthru == m_passthru &&
929 lconfigured_channels == m_configuredChannels &&
930 lneeds_upmix == m_needsUpmix && lreenc == m_reEnc &&
931 lneeds_downmix == m_needsDownmix;
932
933 if (general_deps && m_isConfigured)
934 {
935 LOG(VB_AUDIO, LOG_INFO, LOC + "Reconfigure(): No change -> exiting");
936 // if passthrough, source channels may have changed
937 m_sourceChannels = lsource_channels;
938 return;
939 }
940
941 m_isConfigured = false;
942 KillAudio();
943
944 QMutexLocker lock(&m_audioBufLock);
945 QMutexLocker lockav(&m_avsyncLock);
946
947 m_raud = 0;
948 m_waud = 0;
951
952 m_channels = settings.m_channels;
953 m_sourceChannels = lsource_channels;
954 m_reEnc = lreenc;
955 m_codec = settings.m_codec;
956 m_passthru = settings.m_usePassthru;
957 m_configuredChannels = lconfigured_channels;
958 m_needsUpmix = lneeds_upmix;
959 m_needsDownmix = lneeds_downmix;
960 m_format = m_outputFormat = settings.m_format;
962 m_enc = lenc;
963
964 m_killAudio = m_pauseAudio = false;
965 m_wasPaused = true;
966
967 // Don't try to do anything if audio hasn't been
968 // initialized yet (e.g. rubbish was provided)
969 if (m_sourceChannels <= 0 || m_format <= 0 || m_sampleRate <= 0)
970 {
971 return;
972 }
973
974 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Original codec was %1, %2, %3 kHz, %4 channels")
975 .arg(avcodec_get_name(m_codec),
977 .arg(m_sampleRate/1000)
978 .arg(m_sourceChannels));
979
981 {
982 QString message {QCoreApplication::translate("AudioOutputBase",
983 "Aborting Audio Reconfigure. Can't handle audio with more than 8 channels.")};
984 dispatchError(message);
985 LOG(VB_GENERAL, LOG_ERR, message);
986 return;
987 }
988
989 LOG(VB_AUDIO, LOG_INFO, LOC + QString("enc(%1), passthru(%2), features (%3) "
990 "configured_channels(%4), %5 channels supported(%6) "
991 "max_channels(%7)")
992 .arg(m_enc)
993 .arg(m_passthru)
996 .arg(m_channels)
997 .arg(OutputSettings(m_enc || m_passthru)->IsSupportedChannels(m_channels))
998 .arg(m_maxChannels));
999
1000 int dest_rate = 0;
1001
1002 // Force resampling if we are encoding to AC3 and sr > 48k
1003 // or if 48k override was checked in settings
1004 if ((m_sampleRate != 48000 &&
1005 gCoreContext->GetBoolSetting("Audio48kOverride", false)) ||
1006 (m_enc && (m_sampleRate > 48000)))
1007 {
1008 LOG(VB_AUDIO, LOG_INFO, LOC + "Forcing resample to 48 kHz");
1009 if (m_srcQuality < 0)
1011 m_needResampler = true;
1012 dest_rate = 48000;
1013 }
1014 // this will always be false for passthrough audio as
1015 // CanPassthrough() already tested these conditions
1016 else
1017 {
1020 if (m_needResampler)
1021 {
1023 }
1024 }
1025
1027 {
1028 m_sampleRate = dest_rate;
1029
1030 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Resampling from %1 kHz to %2 kHz with quality %3")
1031 .arg(settings.m_sampleRate/1000).arg(m_sampleRate/1000)
1033
1035
1036 int error = 0;
1037 m_srcCtx = src_new(2-m_srcQuality, chans, &error);
1038 if (error)
1039 {
1040 QString message {QCoreApplication::translate("AudioOutputBase", "Error creating resampler: %1")
1041 .arg(src_strerror(error))};
1042 dispatchError(message);
1043 LOG(VB_GENERAL, LOG_ERR, message);
1044 m_srcCtx = nullptr;
1045 return;
1046 }
1047
1048 m_srcData.src_ratio = (double)m_sampleRate / settings.m_sampleRate;
1049 m_srcData.data_in = m_srcIn;
1050 int newsize = (int)((kAudioSRCInputSize * m_srcData.src_ratio) + 15)
1051 & ~0xf;
1052
1053 if (m_kAudioSRCOutputSize < newsize)
1054 {
1055 m_kAudioSRCOutputSize = newsize;
1056 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Resampler allocating %1").arg(newsize));
1057 delete[] m_srcOut;
1058 m_srcOut = new float[m_kAudioSRCOutputSize];
1059 }
1060 m_srcData.data_out = m_srcOut;
1061 m_srcData.output_frames = m_kAudioSRCOutputSize / chans;
1062 m_srcData.end_of_input = 0;
1063 }
1064
1065 if (m_enc)
1066 {
1067 if (m_reEnc)
1068 LOG(VB_AUDIO, LOG_INFO, LOC + "Reencoding decoded AC-3/DTS to AC-3");
1069
1070 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Creating AC-3 Encoder with sr = %1, ch = %2")
1072
1074 if (!m_encoder->Init(AV_CODEC_ID_AC3, 448000, m_sampleRate,
1076 {
1077 QString message {QCoreApplication::translate("AudioOutputBase", "AC-3 encoder initialization failed")};
1078 dispatchError(message);
1079 LOG(VB_GENERAL, LOG_ERR, message);
1080 delete m_encoder;
1081 m_encoder = nullptr;
1082 m_enc = false;
1083 // upmixing will fail if we needed the encoder
1084 m_needsUpmix = false;
1085 }
1086 }
1087
1088 if (m_passthru)
1089 {
1090 //AC3, DTS, DTS-HD MA and TrueHD all use 16 bits samples
1091 m_channels = channels_tmp;
1092 m_sampleRate = samplerate_tmp;
1096 }
1097 else
1098 {
1101 }
1102
1103 // Turn on float conversion?
1105 m_stretchFactor != 1.0F || (m_internalVol && SWVolume()) ||
1107 !OutputSettings(m_enc || m_passthru)->IsSupportedFormat(m_outputFormat))
1108 {
1109 LOG(VB_AUDIO, LOG_INFO, LOC + "Audio processing enabled");
1110 m_processing = true;
1111 if (m_enc)
1112 m_outputFormat = FORMAT_S16; // Output s16le for AC-3 encoder
1113 else
1115 }
1116
1120
1121 if (m_enc)
1122 m_channels = 2; // But only post-encoder
1123
1126
1127 LOG(VB_GENERAL, LOG_INFO, LOC +
1128 QString("Opening audio device '%1' ch %2(%3) sr %4 sf %5 reenc %6")
1131
1133 m_framesBuffered = 0;
1134 m_currentSeconds = -1s;
1135 m_sourceBitRate = -1;
1136 m_effDsp = m_sampleRate * 100;
1137
1138 // Actually do the device specific open call
1139 if (!OpenDevice())
1140 {
1141 QString message {QCoreApplication::translate("AudioOutputBase", "Aborting reconfigure")};
1142 dispatchError(message);
1143 LOG(VB_GENERAL, LOG_INFO, LOC + message);
1144 return;
1145 }
1146
1147 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Audio fragment size: %1").arg(m_fragmentSize));
1148
1149 // Only used for software volume
1151 {
1152 LOG(VB_AUDIO, LOG_INFO, LOC + "Software volume enabled");
1153 m_volumeControl = gCoreContext->GetSetting("MixerControl", "PCM");
1154 m_volumeControl += "MixerVolume";
1156 }
1157
1161
1163 {
1167 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Create %1 quality upmixer done")
1169 }
1170
1171 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Audio Stretch Factor: %1").arg(m_stretchFactor));
1173
1174 // Setup visualisations, zero the visualisations buffers
1176
1179
1180 m_isConfigured = true;
1181
1183
1184 LOG(VB_AUDIO, LOG_INFO, LOC + "Ending Reconfigure()");
1185}
1186
1188{
1190 return true;
1191
1192 start();
1193 m_audioThreadExists = true;
1194
1195 return true;
1196}
1197
1198
1200{
1202 {
1203 wait();
1204 m_audioThreadExists = false;
1205 }
1206}
1207
1212{
1213 m_killAudioLock.lock();
1214
1215 LOG(VB_AUDIO, LOG_INFO, LOC + "Killing AudioOutputDSP");
1216 m_killAudio = true;
1218 QMutexLocker lock(&m_audioBufLock);
1219
1220 if (m_pSoundStretch)
1221 {
1222 delete m_pSoundStretch;
1223 m_pSoundStretch = nullptr;
1225 m_stretchFactor = 1.0F;
1226 }
1227
1228 if (m_encoder)
1229 {
1230 delete m_encoder;
1231 m_encoder = nullptr;
1232 }
1233
1234 if (m_upmixer)
1235 {
1236 delete m_upmixer;
1237 m_upmixer = nullptr;
1238 }
1239
1240 if (m_srcCtx)
1241 {
1242 src_delete(m_srcCtx);
1243 m_srcCtx = nullptr;
1244 }
1245
1247
1248 CloseDevice();
1249
1250 m_killAudioLock.unlock();
1251}
1252
1253void AudioOutputBase::Pause(bool paused)
1254{
1255 if (!paused && m_unpauseWhenReady)
1256 return;
1257 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Pause %1").arg(paused));
1258 if (m_pauseAudio != paused)
1260 m_pauseAudio = paused;
1261 m_unpauseWhenReady = false;
1262 m_actuallyPaused = false;
1263}
1264
1266{
1267 Reset();
1268 Pause(true);
1269 m_unpauseWhenReady = true;
1270}
1271
1276{
1277 QMutexLocker lock(&m_audioBufLock);
1278 QMutexLocker lockav(&m_avsyncLock);
1279
1281 m_framesBuffered = 0;
1282 if (m_encoder)
1283 {
1284 m_raud = 0; // empty ring buffer
1285 m_waud = 0;
1286 m_audioBuffer.fill(0);
1287 }
1288 else
1289 {
1290 m_waud = m_raud; // empty ring buffer
1291 }
1293 m_currentSeconds = -1s;
1295 m_unpauseWhenReady = false;
1296 // clear any state that could remember previous audio in any active filters
1297 if (m_needsUpmix && m_upmixer)
1298 m_upmixer->flush();
1299 if (m_pSoundStretch)
1300 m_pSoundStretch->clear();
1301 if (m_encoder)
1302 m_encoder->clear();
1303
1304 // Setup visualisations, zero the visualisations buffers
1306}
1307
1314void AudioOutputBase::SetTimecode(std::chrono::milliseconds timecode)
1315{
1316 m_audbufTimecode = m_audioTime = timecode;
1317 m_framesBuffered = (timecode.count() * m_sourceSampleRate) / 1000;
1318}
1319
1327{
1328 LOG(VB_AUDIO, LOG_INFO, LOC + QString("SetEffDsp: %1").arg(dsprate));
1329 m_effDsp = dsprate;
1330}
1331
1336{
1337 if (m_waud >= m_raud)
1338 return m_waud - m_raud;
1339 return kAudioRingBufferSize - (m_raud - m_waud);
1340}
1341
1346{
1347 return kAudioRingBufferSize - audiolen() - 1;
1348 /* There is one wasted byte in the buffer. The case where m_waud = m_raud is
1349 interpreted as an empty buffer, so the fullest the buffer can ever
1350 be is kAudioRingBufferSize - 1. */
1351}
1352
1361{
1363 return audiolen();
1365}
1366
1370std::chrono::milliseconds AudioOutputBase::GetAudiotime(void)
1371{
1372 if (m_audbufTimecode == 0ms || !m_isConfigured)
1373 return 0ms;
1374
1375 // output bits per 10 frames
1376 int64_t obpf = 0;
1377
1378 if (m_passthru && !usesSpdif())
1379 {
1380 obpf = m_sourceBitRate * 10 / m_sourceSampleRate;
1381 }
1382 else if (m_enc && !usesSpdif())
1383 {
1384 // re-encode bitrate is hardcoded at 448000
1385 obpf = 448000 * 10 / m_sourceSampleRate;
1386 }
1387 else
1388 {
1389 obpf = static_cast<int64_t>(m_outputBytesPerFrame) * 80;
1390 }
1391
1392 /* We want to calculate 'm_audioTime', which is the timestamp of the audio
1393 Which is leaving the sound card at this instant.
1394
1395 We use these variables:
1396
1397 'm_effDsp' is 100 * frames/sec
1398
1399 'm_audbufTimecode' is the timecode in milliseconds of the
1400 audio that has just been written into the buffer.
1401
1402 'm_effStretchFactor' is stretch factor * 100,000
1403
1404 'totalbuffer' is the total # of bytes in our audio buffer, and the
1405 sound card's buffer. */
1406
1407
1408 QMutexLocker lockav(&m_avsyncLock);
1409
1410 int64_t soundcard_buffer = GetBufferedOnSoundcard(); // bytes
1411
1412 /* audioready tells us how many bytes are in audiobuffer
1413 scaled appropriately if output format != internal format */
1414 int64_t main_buffer = audioready();
1415
1416 std::chrono::milliseconds oldaudiotime = m_audioTime;
1417
1418 /* timecode is the stretch adjusted version
1419 of major post-stretched buffer contents
1420 processing latencies are catered for in AddData/SetAudiotime
1421 to eliminate race */
1422
1423 m_audioTime = m_audbufTimecode - std::chrono::milliseconds(m_effDsp && obpf ?
1424 ((main_buffer + soundcard_buffer) * int64_t(m_effStretchFactor)
1425 * 80 / int64_t(m_effDsp) / obpf) : 0);
1426
1427 /* audiotime should never go backwards, but we might get a negative
1428 value if GetBufferedOnSoundcard() isn't updated by the driver very
1429 quickly (e.g. ALSA) */
1430 if (m_audioTime < oldaudiotime)
1431 m_audioTime = oldaudiotime;
1432
1433 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + QString("GetAudiotime audt=%1 abtc=%2 mb=%3 sb=%4 tb=%5 "
1434 "sr=%6 obpf=%7 bpf=%8 esf=%9 edsp=%10 sbr=%11")
1435 .arg(m_audioTime.count()) // 1
1436 .arg(m_audbufTimecode.count()) // 2
1437 .arg(main_buffer) // 3
1438 .arg(soundcard_buffer) // 4
1439 .arg(main_buffer+soundcard_buffer) // 5
1440 .arg(m_sampleRate).arg(obpf) // 6, 7
1441 .arg(m_bytesPerFrame) // 8
1442 .arg(m_effStretchFactor) // 9
1443 .arg(m_effDsp).arg(m_sourceBitRate) // 10, 11
1444 );
1445
1446 return m_audioTime;
1447}
1448
1454void AudioOutputBase::SetAudiotime(int frames, std::chrono::milliseconds timecode)
1455{
1456 int64_t processframes_stretched = 0;
1457 int64_t processframes_unstretched = 0;
1458 std::chrono::milliseconds old_audbuf_timecode = m_audbufTimecode;
1459
1460 if (!m_isConfigured)
1461 return;
1462
1463 if (m_needsUpmix && m_upmixer)
1464 processframes_unstretched -= m_upmixer->frameLatency();
1465
1466 if (m_pSoundStretch)
1467 {
1468 processframes_unstretched -= m_pSoundStretch->numUnprocessedSamples();
1469 processframes_stretched -= m_pSoundStretch->numSamples();
1470 }
1471
1472 if (m_encoder)
1473 {
1474 processframes_stretched -= m_encoder->Buffered();
1475 }
1476
1478 timecode + std::chrono::milliseconds(m_effDsp ? (((frames + processframes_unstretched) * 100000) +
1479 (processframes_stretched * m_effStretchFactor)
1480 ) / m_effDsp : 0);
1481
1482 // check for timecode wrap and reset audiotime if detected
1483 // timecode will always be monotonic asc if not seeked and reset
1484 // happens if seek or pause happens
1485 if (m_audbufTimecode < old_audbuf_timecode)
1486 m_audioTime = 0ms;
1487
1488 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + QString("SetAudiotime atc=%1 tc=%2 f=%3 pfu=%4 pfs=%5")
1489 .arg(m_audbufTimecode.count())
1490 .arg(timecode.count())
1491 .arg(frames)
1492 .arg(processframes_unstretched)
1493 .arg(processframes_stretched));
1494#ifdef AUDIOTSTESTING
1495 GetAudiotime();
1496#endif
1497}
1498
1504std::chrono::milliseconds AudioOutputBase::GetAudioBufferedTime(void)
1505{
1506 std::chrono::milliseconds ret = m_audbufTimecode - GetAudiotime();
1507 // Pulse can give us values that make this -ve
1508 if (ret < 0ms)
1509 return 0ms;
1510 return ret;
1511}
1512
1516void AudioOutputBase::SetSWVolume(int new_volume, bool save)
1517{
1518 m_volume = new_volume;
1519 if (save && m_volumeControl != nullptr)
1521}
1522
1527{
1528 return m_volume;
1529}
1530
1540{
1541 int bpf = m_bytesPerFrame;
1542 int len = frames * bpf;
1543 int afree = audiofree();
1544
1545 if (len <= afree)
1546 return len;
1547
1548 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Audio buffer overflow, %1 frames lost!")
1549 .arg(frames - (afree / bpf)));
1550
1551 frames = afree / bpf;
1552 len = frames * bpf;
1553
1554 if (!m_srcCtx)
1555 return len;
1556
1557 int error = src_reset(m_srcCtx);
1558 if (error)
1559 {
1560 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error occurred while resetting resampler: %1")
1561 .arg(src_strerror(error)));
1562 m_srcCtx = nullptr;
1563 }
1564
1565 return len;
1566}
1567
1574int AudioOutputBase::CopyWithUpmix(char *buffer, int frames, uint &org_waud)
1575{
1576 int len = CheckFreeSpace(frames);
1577 int bdiff = kAudioRingBufferSize - org_waud;
1578 int bpf = m_bytesPerFrame;
1579 ptrdiff_t off = 0;
1580
1581 if (!m_needsUpmix)
1582 {
1583 int num = len;
1584
1585 if (bdiff <= num)
1586 {
1587 memcpy(WPOS, buffer, bdiff);
1588 num -= bdiff;
1589 off = bdiff;
1590 org_waud = 0;
1591 }
1592 if (num > 0)
1593 memcpy(WPOS, buffer + off, num);
1594 org_waud = (org_waud + num) % kAudioRingBufferSize;
1595 return len;
1596 }
1597
1598 // Convert mono to stereo as most devices can't accept mono
1599 if (!m_upmixer)
1600 {
1601 // we're always in the case
1602 // m_configuredChannels == 2 && m_sourceChannels == 1
1603 int bdFrames = bdiff / bpf;
1604 if (bdFrames <= frames)
1605 {
1606 AudioConvert::MonoToStereo(WPOS, buffer, bdFrames);
1607 frames -= bdFrames;
1608 off = bdFrames * sizeof(float); // 1 channel of floats
1609 org_waud = 0;
1610 }
1611 if (frames > 0)
1612 AudioConvert::MonoToStereo(WPOS, buffer + off, frames);
1613
1614 org_waud = (org_waud + (frames * bpf)) % kAudioRingBufferSize;
1615 return len;
1616 }
1617
1618 // Upmix to 6ch via FreeSurround
1619 // Calculate frame size of input
1620 off = m_processing ? sizeof(float) : AudioOutputSettings::SampleSize(m_format);
1621 off *= m_sourceChannels;
1622
1623 int i = 0;
1624 len = 0;
1625 while (i < frames)
1626 {
1627 i += m_upmixer->putFrames(buffer + (i * off), frames - i, m_sourceChannels);
1628 int nFrames = m_upmixer->numFrames();
1629 if (!nFrames)
1630 continue;
1631
1632 len += CheckFreeSpace(nFrames);
1633
1634 int bdFrames = (kAudioRingBufferSize - org_waud) / bpf;
1635 if (bdFrames < nFrames)
1636 {
1637 if ((org_waud % bpf) != 0)
1638 {
1639 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Upmixing: org_waud = %1 (bpf = %2)")
1640 .arg(org_waud)
1641 .arg(bpf));
1642 }
1643 m_upmixer->receiveFrames((float *)(WPOS), bdFrames);
1644 nFrames -= bdFrames;
1645 org_waud = 0;
1646 }
1647 if (nFrames > 0)
1648 m_upmixer->receiveFrames((float *)(WPOS), nFrames);
1649
1650 org_waud = (org_waud + (nFrames * bpf)) % kAudioRingBufferSize;
1651 }
1652 return len;
1653}
1654
1660bool AudioOutputBase::AddFrames(void *in_buffer, int in_frames,
1661 std::chrono::milliseconds timecode)
1662{
1663 return AddData(in_buffer, in_frames * m_sourceBytesPerFrame, timecode,
1664 in_frames);
1665}
1666
1672bool AudioOutputBase::AddData(void *in_buffer, int in_len,
1673 std::chrono::milliseconds timecode,
1674 int /*in_frames*/)
1675{
1676 int frames = in_len / m_sourceBytesPerFrame;
1677 int bpf = m_bytesPerFrame;
1678 int len = in_len;
1679 bool music = false;
1680
1681 if (!m_isConfigured)
1682 {
1683 LOG(VB_GENERAL, LOG_ERR, "AddData called with audio framework not "
1684 "initialised");
1685 m_lengthLastData = 0ms;
1686 return false;
1687 }
1688
1689 /* See if we're waiting for new samples to be buffered before we unpause
1690 post channel change, seek, etc. Wait for 4 fragments to be buffered */
1692 {
1693 m_unpauseWhenReady = false;
1694 Pause(false);
1695 }
1696
1697 // Don't write new samples if we're resetting the buffer or reconfiguring
1698 QMutexLocker lock(&m_audioBufLock);
1699
1700 uint org_waud = m_waud;
1701 int afree = audiofree();
1702 int used = kAudioRingBufferSize - afree;
1703
1704 if (m_passthru && m_spdifEnc)
1705 {
1706 if (m_processing)
1707 {
1708 /*
1709 * We shouldn't encounter this case, but it can occur when
1710 * timestretch just got activated. So we will just drop the
1711 * data
1712 */
1713 LOG(VB_AUDIO, LOG_INFO,
1714 "Passthrough activated with audio processing. Dropping audio");
1715 return false;
1716 }
1717 // mux into an IEC958 packet
1718 m_spdifEnc->WriteFrame((unsigned char *)in_buffer, len);
1720 if (len > 0)
1721 {
1722 in_buffer = m_spdifEnc->GetProcessedBuffer();
1723 m_spdifEnc->Reset();
1724 frames = len / m_sourceBytesPerFrame;
1725 }
1726 else
1727 {
1728 frames = 0;
1729 }
1730 }
1732 ((double)(len * 1000) / (m_sourceSampleRate * m_sourceBytesPerFrame));
1733
1734 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + QString("AddData frames=%1, bytes=%2, used=%3, free=%4, "
1735 "timecode=%5 needsupmix=%6")
1736 .arg(frames).arg(len).arg(used).arg(afree).arg(timecode.count())
1737 .arg(m_needsUpmix));
1738
1739 // Mythmusic doesn't give us timestamps
1740 if (timecode < 0ms)
1741 {
1742 timecode = std::chrono::milliseconds((m_framesBuffered * 1000) / m_sourceSampleRate);
1743 m_framesBuffered += frames;
1744 music = true;
1745 }
1746
1747 if (hasVisual())
1748 {
1749 // Send original samples to any attached visualisations
1750 dispatchVisual((uchar *)in_buffer, len, timecode, m_sourceChannels,
1752 }
1753
1754 // Calculate amount of free space required in ringbuffer
1755 if (m_processing)
1756 {
1757 int sampleSize = AudioOutputSettings::SampleSize(m_format);
1758 if (sampleSize <= 0)
1759 {
1760 // Would lead to division by zero (or unexpected results if negative)
1761 LOG(VB_GENERAL, LOG_ERR, LOC + "Sample size is <= 0, AddData returning false");
1762 return false;
1763 }
1764
1765 // Final float conversion space requirement
1766 len = sizeof(m_srcInBuf[0]) / sampleSize * len;
1767
1768 // Account for changes in number of channels
1769 if (m_needsDownmix)
1770 len = (len * m_configuredChannels ) / m_sourceChannels;
1771
1772 // Check we have enough space to write the data
1774 len = lround(ceil(static_cast<double>(len) * m_srcData.src_ratio));
1775
1776 if (m_needsUpmix)
1777 len = (len * m_configuredChannels ) / m_sourceChannels;
1778
1779 // Include samples in upmix buffer that may be flushed
1780 if (m_needsUpmix && m_upmixer)
1781 len += m_upmixer->numUnprocessedFrames() * bpf;
1782
1783 // Include samples in soundstretch buffers
1784 if (m_pSoundStretch)
1785 len += (m_pSoundStretch->numUnprocessedSamples() +
1786 (int)(m_pSoundStretch->numSamples() / m_stretchFactor)) * bpf;
1787 }
1788
1789 if (len > afree)
1790 {
1791 LOG(VB_GENERAL, LOG_ERR, LOC + "Buffer is full, AddData returning false");
1792 return false; // would overflow
1793 }
1794
1795 int frames_remaining = frames;
1796 int frames_final = 0;
1797 int maxframes = (kAudioSRCInputSize / m_sourceChannels) & ~0xf;
1798 int offset = 0;
1799
1800 while(frames_remaining > 0)
1801 {
1802 void *buffer = (char *)in_buffer + offset;
1803 frames = frames_remaining;
1804 len = frames * m_sourceBytesPerFrame;
1805
1806 if (m_processing)
1807 {
1808 if (frames > maxframes)
1809 {
1810 frames = maxframes;
1811 len = frames * m_sourceBytesPerFrame;
1812 offset += len;
1813 }
1814 // Convert to floats
1815 AudioConvert::toFloat(m_format, m_srcIn, buffer, len);
1816 }
1817
1818 frames_remaining -= frames;
1819
1820 // Perform downmix if necessary
1821 if (m_needsDownmix)
1822 {
1825 m_srcIn, m_srcIn, frames) < 0)
1826 LOG(VB_GENERAL, LOG_ERR, LOC + "Error occurred while downmixing");
1827 }
1828
1829 // Resample if necessary
1831 {
1832 m_srcData.input_frames = frames;
1833 int error = src_process(m_srcCtx, &m_srcData);
1834
1835 if (error)
1836 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error occurred while resampling audio: %1")
1837 .arg(src_strerror(error)));
1838
1839 buffer = m_srcOut;
1840 frames = m_srcData.output_frames_gen;
1841 }
1842 else if (m_processing)
1843 {
1844 buffer = m_srcIn;
1845 }
1846
1847 /* we want the timecode of the last sample added but we are given the
1848 timecode of the first - add the time in ms that the frames added
1849 represent */
1850
1851 // Copy samples into audiobuffer, with upmix if necessary
1852 len = CopyWithUpmix((char *)buffer, frames, org_waud);
1853 if (len <= 0)
1854 {
1855 continue;
1856 }
1857
1858 frames = len / bpf;
1859 frames_final += frames;
1860
1861 int bdiff = kAudioRingBufferSize - m_waud;
1862 if ((len % bpf) != 0 && bdiff < len)
1863 {
1864 LOG(VB_GENERAL, LOG_ERR, LOC + QString("AddData: Corruption likely: len = %1 (bpf = %2)")
1865 .arg(len)
1866 .arg(bpf));
1867 }
1868 if ((bdiff % bpf) != 0 && bdiff < len)
1869 {
1870 LOG(VB_GENERAL, LOG_ERR, LOC + QString("AddData: Corruption likely: bdiff = %1 (bpf = %2)")
1871 .arg(bdiff)
1872 .arg(bpf));
1873 }
1874
1875 if (m_pSoundStretch)
1876 {
1877 // does not change the timecode, only the number of samples
1878 org_waud = m_waud;
1879 int bdFrames = bdiff / bpf;
1880
1881 if (bdiff < len)
1882 {
1883 m_pSoundStretch->putSamples((STST *)(WPOS), bdFrames);
1884 m_pSoundStretch->putSamples((STST *)ABUF, (len - bdiff) / bpf);
1885 }
1886 else
1887 {
1888 m_pSoundStretch->putSamples((STST *)(WPOS), frames);
1889 }
1890
1891 int nFrames = m_pSoundStretch->numSamples();
1892 if (nFrames > frames)
1893 CheckFreeSpace(nFrames);
1894
1895 len = nFrames * bpf;
1896
1897 if (nFrames > bdFrames)
1898 {
1899 nFrames -= m_pSoundStretch->receiveSamples((STST *)(WPOS),
1900 bdFrames);
1901 org_waud = 0;
1902 }
1903 if (nFrames > 0)
1904 nFrames = m_pSoundStretch->receiveSamples((STST *)(WPOS),
1905 nFrames);
1906
1907 org_waud = (org_waud + (nFrames * bpf)) % kAudioRingBufferSize;
1908 }
1909
1910 if (m_internalVol && SWVolume())
1911 {
1912 org_waud = m_waud;
1913 int num = len;
1914
1915 if (bdiff <= num)
1916 {
1917 adjustVolume(WPOS, bdiff, m_volume, music, m_needsUpmix && m_upmixer);
1918 num -= bdiff;
1919 org_waud = 0;
1920 }
1921 if (num > 0)
1923 org_waud = (org_waud + num) % kAudioRingBufferSize;
1924 }
1925
1926 if (m_encoder)
1927 {
1928 org_waud = m_waud;
1929 int to_get = 0;
1930
1931 if (bdiff < len)
1932 {
1934 to_get = m_encoder->Encode(ABUF, len - bdiff,
1936 }
1937 else
1938 {
1939 to_get = m_encoder->Encode(WPOS, len,
1941 }
1942
1943 if (bdiff <= to_get)
1944 {
1945 m_encoder->GetFrames(WPOS, bdiff);
1946 to_get -= bdiff ;
1947 org_waud = 0;
1948 }
1949 if (to_get > 0)
1950 m_encoder->GetFrames(WPOS, to_get);
1951
1952 org_waud = (org_waud + to_get) % kAudioRingBufferSize;
1953 }
1954
1955 m_waud = org_waud;
1956 }
1957
1958 SetAudiotime(frames_final, timecode);
1959
1960 return true;
1961}
1962
1967{
1968 std::chrono::milliseconds ct = GetAudiotime();
1969
1970 if (ct < 0ms)
1971 ct = 0ms;
1972
1973 if (m_sourceBitRate == -1)
1974 m_sourceBitRate = static_cast<long>(m_sourceSampleRate) * m_sourceChannels *
1976
1977 if (duration_cast<std::chrono::seconds>(ct) != m_currentSeconds)
1978 {
1979 m_currentSeconds = duration_cast<std::chrono::seconds>(ct);
1982 dispatch(e);
1983 }
1984}
1985
1991{
1993 total = kAudioRingBufferSize;
1994}
1995
2002{
2003 auto *zeros = new(std::align_val_t(16)) uchar[m_fragmentSize];
2004 auto *fragment = new(std::align_val_t(16)) uchar[m_fragmentSize];
2005 memset(zeros, 0, m_fragmentSize);
2006
2007 // to reduce startup latency, write silence in 8ms chunks
2008 int zero_fragment_size = 8 * m_sampleRate * m_outputBytesPerFrame / 1000;
2009 zero_fragment_size = std::min(zero_fragment_size, m_fragmentSize);
2010
2011 while (!m_killAudio)
2012 {
2013 if (m_pauseAudio)
2014 {
2015 if (!m_actuallyPaused)
2016 {
2017 LOG(VB_AUDIO, LOG_INFO, LOC + "OutputAudioLoop: audio paused");
2018 Event e(Event::kPaused);
2019 dispatch(e);
2020 m_wasPaused = true;
2021 }
2022
2023 m_actuallyPaused = true;
2024 m_audioTime = 0ms; // mark 'audiotime' as invalid.
2025
2026 WriteAudio(zeros, zero_fragment_size);
2027 continue;
2028 }
2029
2030 if (m_wasPaused)
2031 {
2032 LOG(VB_AUDIO, LOG_INFO, LOC + "OutputAudioLoop: Play Event");
2033 Event e(Event::kPlaying);
2034 dispatch(e);
2035 m_wasPaused = false;
2036 }
2037
2038 /* do audio output */
2039 int ready = audioready();
2040
2041 // wait for the buffer to fill with enough to play
2042 if (m_fragmentSize > ready)
2043 {
2044 if (ready > 0) // only log if we're sending some audio
2045 {
2046 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + QString("audio waiting for buffer to fill: "
2047 "have %1 want %2")
2048 .arg(ready).arg(m_fragmentSize));
2049 }
2050
2051 std::this_thread::sleep_for(10ms);
2052 continue;
2053 }
2054
2055#ifdef AUDIOTSTESTING
2056 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + "WriteAudio Start");
2057#endif
2058 Status();
2059
2060 // delay setting raud until after phys buffer is filled
2061 // so GetAudiotime will be accurate without locking
2063 volatile uint next_raud = m_raud;
2064 if (GetAudioData(fragment, m_fragmentSize, true, &next_raud))
2065 {
2067 {
2068 WriteAudio(fragment, m_fragmentSize);
2070 m_raud = next_raud;
2071 }
2072 }
2073#ifdef AUDIOTSTESTING
2074 GetAudiotime();
2075 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + "WriteAudio Done");
2076#endif
2077
2078 }
2079
2080 ::operator delete[] (zeros, std::align_val_t(16));
2081 ::operator delete[] (fragment, std::align_val_t(16));
2082 LOG(VB_AUDIO, LOG_INFO, LOC + "OutputAudioLoop: Stop Event");
2083 Event e(Event::kStopped);
2084 dispatch(e);
2085}
2086
2094int AudioOutputBase::GetAudioData(uchar *buffer, int size, bool full_buffer,
2095 volatile uint *local_raud)
2096{
2097
2098#define LRPOS (&m_audioBuffer[*local_raud])
2099 // re-check audioready() in case things changed.
2100 // for example, ClearAfterSeek() might have run
2101 int avail_size = audioready();
2102 int frag_size = size;
2103 int written_size = size;
2104
2105 if (local_raud == nullptr)
2106 local_raud = &m_raud;
2107
2108 if (!full_buffer && (size > avail_size))
2109 {
2110 // when full_buffer is false, return any available data
2111 frag_size = avail_size;
2112 written_size = frag_size;
2113 }
2114
2115 if (!avail_size || (frag_size <= 0) || (frag_size > avail_size))
2116 return 0;
2117
2118 int bdiff = kAudioRingBufferSize - m_raud;
2119
2121
2122 if (obytes <= 0)
2123 return 0;
2124
2125 bool fromFloats = m_processing && !m_enc && m_outputFormat != FORMAT_FLT;
2126
2127 // Scale if necessary
2128 if (fromFloats && obytes != sizeof(float))
2129 frag_size *= sizeof(float) / obytes;
2130
2131 int off = 0;
2132
2133 if (bdiff <= frag_size)
2134 {
2135 if (fromFloats)
2136 {
2138 LRPOS, bdiff);
2139 }
2140 else
2141 {
2142 memcpy(buffer, LRPOS, bdiff);
2143 off = bdiff;
2144 }
2145
2146 frag_size -= bdiff;
2147 *local_raud = 0;
2148 }
2149 if (frag_size > 0)
2150 {
2151 if (fromFloats)
2152 {
2154 LRPOS, frag_size);
2155 }
2156 else
2157 {
2158 memcpy(buffer + off, LRPOS, frag_size);
2159 }
2160 }
2161
2162 *local_raud += frag_size;
2163
2164 // Mute individual channels through mono->stereo duplication
2165 MuteState mute_state = GetMuteState();
2166 if (!m_enc && !m_passthru &&
2167 written_size && m_configuredChannels > 1 &&
2168 (mute_state == kMuteLeft || mute_state == kMuteRight))
2169 {
2170 muteChannel(obytes << 3, m_configuredChannels,
2171 mute_state == kMuteLeft ? 0 : 1,
2172 buffer, written_size);
2173 }
2174
2175 return written_size;
2176}
2177
2182{
2183 while (!m_pauseAudio && audioready() > m_fragmentSize)
2184 std::this_thread::sleep_for(1ms);
2185 if (m_pauseAudio)
2186 {
2187 // Audio is paused and can't be drained, clear ringbuffer
2188 QMutexLocker lock(&m_audioBufLock);
2189
2190 m_raud = 0;
2191 m_waud = 0;
2192 }
2193}
2194
2199{
2200 RunProlog();
2201 LOG(VB_AUDIO, LOG_INFO, LOC + QString("kickoffOutputAudioLoop: pid = %1").arg(getpid()));
2203 LOG(VB_AUDIO, LOG_INFO, LOC + "kickoffOutputAudioLoop exiting");
2204 RunEpilog();
2205}
2206
2207int AudioOutputBase::readOutputData(unsigned char* /*read_buffer*/, size_t /*max_length*/)
2208{
2209 LOG(VB_GENERAL, LOG_ERR, LOC + "AudioOutputBase should not be getting asked to readOutputData()");
2210 return 0;
2211}
#define assert(x)
static void tMuteChannel(AudioDataType *buffer, int channels, int ch, int frames)
#define LOC
static const std::array< six_speaker_set, 3 > s51_matrix
static const float msqrt_1_3bym3db
static void muteChannel(int obits, int channels, int ch, void *buffer, int bytes)
Mute individual channels through mono->stereo duplication.
std::array< float, 2 > two_speaker_ratio
#define ABUF
static const float sqrt_2_3by3db
static const float sqrt_2_3
std::array< float, 6 > six_speaker_ratio
static int DownmixFrames(int channels_in, int channels_out, float *dst, const float *src, int frames)
static constexpr int UPMIX_CHANNEL_MASK
static constexpr bool IS_VALID_UPMIX_CHANNEL(int ch)
static const float m3db
static const float mm3db
static const std::array< two_speaker_set, 8 > stereo_matrix
std::array< six_speaker_ratio, 8 > six_speaker_set
static const float m6db
std::array< two_speaker_ratio, 8 > two_speaker_set
#define WPOS
#define LRPOS
static void adjustVolume(void *buf, int len, int volume, bool music, bool upmix)
Adjust the volume of samples.
static const float msqrt_1_3
#define STST
@ FORMAT_FLT
@ FORMAT_S16
DigitalFeature
@ FEATURE_DTS
@ FEATURE_AC3
@ FEATURE_DTSHD
@ FEATURE_NONE
@ FEATURE_EAC3
@ FEATURE_LPCM
@ FEATURE_TRUEHD
@ AUDIOOUTPUT_VIDEO
Definition: audiosettings.h:23
static int toFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert integer samples to floats.
static void MonoToStereo(void *dst, const void *src, int samples)
Convert a mono stream to stereo by copying and interleaving samples.
static int fromFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert float samples to integers.
void KillAudio(void)
Kill the output thread and cleanup.
virtual void StopOutputThread(void)
void Reconfigure(const AudioSettings &settings) override
(Re)Configure AudioOutputBase
bool IsUpmixing(void) override
Source is currently being upmixed.
bool ToggleUpmix(void) override
Toggle between stereo and upmixed 5.1 if the source material is stereo.
AudioOutputSource m_source
void SetStretchFactor(float factor) override
Set the timestretch factor.
bool usesSpdif() const
std::chrono::seconds m_currentSeconds
AudioOutputSettings * GetOutputSettingsUsers(bool digital=false) override
Returns capabilities supported by the audio device amended to take into account the digital audio opt...
soundtouch::SoundTouch * m_pSoundStretch
AudioOutputBase(const AudioSettings &settings)
virtual bool StartOutputThread(void)
void OutputAudioLoop(void)
Run in the output thread, write frames to the output device as they become available and there's spac...
void SetEffDsp(int dsprate) override
Set the effective DSP rate.
int GetSWVolume(void) override
Get the volume for software volume control.
int audiofree() const
Get the free space in the audiobuffer in bytes.
std::chrono::milliseconds m_lengthLastData
volatile uint m_waud
AudioFormat m_outputFormat
std::chrono::milliseconds m_audbufTimecode
timecode of audio most recently placed into buffer
int CheckFreeSpace(int &frames)
Check that there's enough space in the audiobuffer to write the provided number of frames.
bool AddFrames(void *buffer, int frames, std::chrono::milliseconds timecode) override
Add frames to the audiobuffer and perform any required processing.
QMutex m_audioBufLock
Writes to the audiobuffer, reconfigures and audiobuffer resets can only take place while holding this...
void SetTimecode(std::chrono::milliseconds timecode) override
Set the timecode of the samples most recently added to the audiobuffer.
bool CanUpmix(void) override
Upmixing of the current source is available if requested.
float GetStretchFactor(void) const override
Get the timetretch factor.
void InitSettings(const AudioSettings &settings)
AudioOutputSettings * m_outputSettingsRaw
AudioOutputDigitalEncoder * m_encoder
std::array< uchar, kAudioRingBufferSize > m_audioBuffer
main audio buffer
void SetStretchFactorLocked(float factor)
Set the timestretch factor.
virtual void WriteAudio(unsigned char *aubuf, int size)=0
bool CanPassthrough(int samplerate, int channels, AVCodecID codec, int profile) const override
Test if we can output digital audio and if sample rate is supported.
virtual AudioOutputSettings * GetOutputSettings(bool)
void SetAudiotime(int frames, std::chrono::milliseconds timecode)
Set the timecode of the top of the ringbuffer Exclude all other processing elements as they dont vary...
std::chrono::milliseconds GetAudioBufferedTime(void) override
Get the difference in timecode between the samples that are about to become audible and the samples m...
virtual bool OpenDevice(void)=0
AudioOutputSettings * GetOutputSettingsCleaned(bool digital=true) override
Returns capabilities supported by the audio device amended to take into account the digital audio opt...
static const char * quality_string(int q)
SRC_STATE * m_srcCtx
AudioFormat m_format
bool AddData(void *buffer, int len, std::chrono::milliseconds timecode, int frames) override
Add data to the audiobuffer and perform any required processing.
std::chrono::milliseconds m_audioTime
timecode of audio leaving the soundcard (same units as timecodes)
virtual void Status(void)
Report status via an AudioOutput::Event.
int audiolen() const
Get the number of bytes in the audiobuffer.
static const uint kAudioSRCInputSize
std::array< float, kAudioSRCInputSize > m_srcInBuf
void Reset(void) override
Reset the audiobuffer, timecode and mythmusic visualisation.
void Pause(bool paused) override
int GetAudioData(uchar *buffer, int buf_size, bool full_buffer, volatile uint *local_raud=nullptr)
Copy frames from the audiobuffer into the buffer provided.
~AudioOutputBase() override
Destructor.
volatile uint m_raud
Audio circular buffer.
void Drain(void) override
Block until all available frames have been written to the device.
std::chrono::milliseconds GetAudiotime(void) override
Calculate the timecode of the samples that are about to become audible.
bool SetupPassthrough(AVCodecID codec, int codec_profile, int &samplerate_tmp, int &channels_tmp)
virtual int GetBufferedOnSoundcard(void) const =0
Return the size in bytes of frames currently in the audio buffer adjusted with the audio playback lat...
int readOutputData(unsigned char *read_buffer, size_t max_length) override
void SetSWVolume(int new_volume, bool save) override
Set the volume for software volume control.
virtual void CloseDevice(void)=0
AudioOutputSettings * m_outputSettingsDigital
void run() override
Main routine for the output thread.
SPDIFEncoder * m_spdifEnc
FreeSurround * m_upmixer
void GetBufferStatus(uint &fill, uint &total) override
Fill in the number of bytes in the audiobuffer and the total size of the audiobuffer.
void PauseUntilBuffered(void) override
int64_t m_framesBuffered
int CopyWithUpmix(char *buffer, int frames, uint &org_waud)
Copy frames into the audiobuffer, upmixing en route if necessary.
AudioOutputSettings * m_outputSettings
int audioready() const
Get the scaled number of bytes in the audiobuffer, i.e.
AudioOutputSettings * m_outputSettingsDigitalRaw
AudioOutputSettings * OutputSettings(bool digital=true)
static const uint kAudioRingBufferSize
Audio Buffer Size – should be divisible by 32,24,16,12,10,8,6,4,2..
void SetSourceBitrate(int rate) override
Set the bitrate of the source material, reported in periodic AudioOutput::Events.
QMutex m_avsyncLock
must hold avsync_lock to read or write 'audiotime' and 'audiotime_updated'
bool has_optimized_SIMD() override
Returns true if the processor supports MythTV's optimized SIMD for AudioConvert.
AsyncLooseLock m_resetActive
bool Init(AVCodecID codec_id, int bitrate, int samplerate, int channels)
int GetFrames(void *ptr, int maxlen)
int Encode(void *input, int len, AudioFormat format)
bool IsSupportedChannels(int channels)
static int SampleSize(AudioFormat format)
AudioFormat BestSupportedFormat()
bool canFeature(DigitalFeature arg) const
return DigitalFeature mask.
int GetMaxHDRate() const
return the highest iec958 rate supported.
bool IsSupportedRate(int rate)
int NearestSupportedRate(int rate)
AudioOutputSettings * GetCleaned(bool newcopy=false)
Returns capabilities supported by the audio device amended to take into account the digital audio opt...
static const char * FormatToString(AudioFormat format)
static int FormatToBits(AudioFormat format)
static QString FeaturesToString(DigitalFeature arg)
Display in human readable form the digital features supported by the output device.
static QString GetPassthroughParams(int codec, int codec_profile, int &samplerate, int &channels, bool canDTSHDMA)
Setup samplerate and number of channels for passthrough.
bool IsSupportedFormat(AudioFormat format)
bool m_isConfigured
Definition: audiooutput.h:226
bool hasVisual(void)
Definition: audiooutput.h:203
void dispatchVisual(uchar *b, unsigned long b_len, std::chrono::milliseconds timecode, int chan, int prec)
void dispatchError(const QString &e)
void prepareVisuals()
const int & channels() const
Definition: audiooutput.h:254
AVCodecID m_codec
Definition: audiosettings.h:74
AudioFormat m_format
Definition: audiosettings.h:72
AudioOutputSettings * m_custom
custom contains a pointer to the audio device capabilities if defined, AudioOutput will not try to au...
Definition: audiosettings.h:92
Event details.
Definition: zmdefines.h:28
uint frameLatency() const
uint numFrames() const
uint receiveFrames(void *buffer, uint maxFrames)
uint numUnprocessedFrames() const
uint putFrames(void *buffer, uint numFrames, uint numChannels)
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:49
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:180
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:267
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:193
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:284
void SaveSetting(const QString &key, int newValue)
QString GetSetting(const QString &key, const QString &defaultval="")
int GetNumSetting(const QString &key, int defaultval=0)
bool GetBoolSetting(const QString &key, bool defaultval=false)
void dispatch(const MythEvent &event)
Dispatch an event to all listeners.
unsigned char * GetProcessedBuffer()
void Reset()
Reset the internal encoder buffer.
int GetProcessedSize()
void WriteFrame(unsigned char *data, int size)
Encode data through created muxer unsigned char data: pointer to data to encode int size: size of dat...
bool Succeeded() const
Definition: spdifencoder.h:24
bool SetMaxHDRate(int rate)
Set the maximum HD rate.
virtual MuteState GetMuteState(void) const
Definition: volumebase.cpp:151
bool SWVolume(void) const
Definition: volumebase.cpp:107
bool m_internalVol
Definition: volumebase.h:43
void UpdateVolume(void)
Definition: volumebase.cpp:179
void SyncVolume(void)
Definition: volumebase.cpp:210
void SetChannels(int new_channels)
Definition: volumebase.cpp:219
unsigned int uint
Definition: compat.h:60
static const std::array< const uint64_t, 4 > samples
Definition: element.cpp:46
std::chrono::milliseconds millisecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
Definition: mythchrono.h:80
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
def error(message)
Definition: smolt.py:409
None log(str msg, int level=LOGDEBUG)
Definition: xbmc.py:9
MuteState
Definition: volumebase.h:8
@ kMuteLeft
Definition: volumebase.h:10
@ kMuteRight
Definition: volumebase.h:11