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
7// POSIX headers
8#include <unistd.h>
9#include <sys/time.h>
10
11// SoundTouch
12#if __has_include(<soundtouch/SoundTouch.h>)
13#include <soundtouch/SoundTouch.h>
14#else
15#include <SoundTouch.h>
16#endif
17
18// Qt headers
19#include <QtGlobal>
20#include <QMutexLocker>
21
22// MythTV headers
23#include "libmythbase/compat.h"
24#include "libmythbase/mythconfig.h"
27
28#include "audioconvert.h"
29#include "audiooutputbase.h"
31#include "freesurround.h"
32#include "spdifencoder.h"
33
34// AC3 encode currently disabled for Android
35#ifdef Q_OS_ANDROID
36#define DISABLE_AC3_ENCODE
37#endif
38
39#define LOC QString("AOBase: ")
40
41// Replacing "m_audioBuffer + org_waud" with
42// "&m_audioBuffer[org_waud]" should provide bounds
43// checking with c++17 arrays.
44#define WPOS (&m_audioBuffer[org_waud])
45#define RPOS (&m_audioBuffer[m_raud])
46#define ABUF (m_audioBuffer.data())
47#define STST soundtouch::SAMPLETYPE
48
49// 1,2,5 and 7 channels are currently valid for upmixing if required
50static constexpr int UPMIX_CHANNEL_MASK { (1<<1)|(1<<2)|(1<<5)|(1<<7) };
51static constexpr bool IS_VALID_UPMIX_CHANNEL(int ch)
52{ return ((1 << ch) & UPMIX_CHANNEL_MASK) != 0; }
53
54/*
55 SMPTE channel layout
56 DUAL-MONO L R
57 DUAL-MONO-LFE L R LFE
58 MONO M
59 MONO-LFE M LFE
60 STEREO L R
61 STEREO-LFE L R LFE
62 3F L R C
63 3F-LFE L R C LFE
64 2F1 L R S
65 2F1-LFE L R LFE S
66 3F1 L R C S
67 3F1-LFE L R C LFE S
68 2F2 L R LS RS
69 2F2-LFE L R LFE LS RS
70 3F2 L R C LS RS
71 3F2-LFE L R C LFE LS RS
72 3F3R-LFE L R C LFE BC LS RS
73 3F4-LFE L R C LFE Rls Rrs LS RS
74 */
75
76static const float m6db = 0.5;
77static const float m3db = 0.7071067811865476F; // 3dB = SQRT(2)
78static const float mm3db = -0.7071067811865476F; // -3dB = SQRT(1/2)
79static const float msqrt_1_3 = -0.577350269189626F; // -SQRT(1/3)
80static const float sqrt_2_3 = 0.816496580927726F; // SQRT(2/3)
81static const float sqrt_2_3by3db = 0.577350269189626F; // SQRT(2/3)*-3dB = SQRT(2/3)*SQRT(1/2)=SQRT(1/3)
82static const float msqrt_1_3bym3db = 0.408248290463863F; // -SQRT(1/3)*-3dB = -SQRT(1/3)*SQRT(1/2) = -SQRT(1/6)
83
84using two_speaker_ratio = std::array<float,2>;
85using two_speaker_set = std::array<two_speaker_ratio,8>;
86static const std::array<two_speaker_set,8> stereo_matrix
87{{
88//1F L R
89 {{
90 { 1, 1 }, // M
91 }},
92
93//2F L R
94 {{
95 { 1, 0 }, // L
96 { 0, 1 }, // R
97 }},
98
99//3F L R
100 {{
101 { 1, 0 }, // L
102 { 0, 1 }, // R
103 { 1, 1 }, // C
104 }},
105
106//3F1R L R
107 {{
108 { 1, 0 }, // L
109 { 0, 1 }, // R
110 { m3db, m3db }, // C
111 { mm3db, m3db }, // S
112 }},
113
114//3F2R L R
115 {{
116 { 1, 0 }, // L
117 { 0, 1 }, // R
118 { m3db, m3db }, // C
119 { sqrt_2_3, msqrt_1_3 }, // LS
120 { msqrt_1_3, sqrt_2_3 }, // RS
121 }},
122
123//3F2R.1 L R
124 {{
125 { 1, 0 }, // L
126 { 0, 1 }, // R
127 { m3db, m3db }, // C
128 { 0, 0 }, // LFE
129 { sqrt_2_3, msqrt_1_3 }, // LS
130 { msqrt_1_3, sqrt_2_3 }, // RS
131 }},
132
133// 3F3R.1 L R
134 {{
135 { 1, 0 }, // L
136 { 0, 1 }, // R
137 { m3db, m3db }, // C
138 { 0, 0 }, // LFE
139 { m6db, m6db }, // Cs
140 { sqrt_2_3, msqrt_1_3 }, // LS
141 { msqrt_1_3, sqrt_2_3 }, // RS
142 }},
143
144// 3F4R.1 L R
145 {{
146 { 1, 0 }, // L
147 { 0, 1 }, // R
148 { m3db, m3db }, // C
149 { 0, 0 }, // LFE
150 { sqrt_2_3by3db, msqrt_1_3bym3db }, // Rls
151 { msqrt_1_3bym3db, sqrt_2_3by3db }, // Rrs
154 }}
155}};
156
157using six_speaker_ratio = std::array<float,6>;
158using six_speaker_set = std::array<six_speaker_ratio,8>;
159static const std::array<six_speaker_set,3> s51_matrix
160{{
161 // 3F2R.1 in -> 3F2R.1 out
162 // L R C LFE LS RS
163 {{
164 { 1, 0, 0, 0, 0, 0 }, // L
165 { 0, 1, 0, 0, 0, 0 }, // R
166 { 0, 0, 1, 0, 0, 0 }, // C
167 { 0, 0, 0, 1, 0, 0 }, // LFE
168 { 0, 0, 0, 0, 1, 0 }, // LS
169 { 0, 0, 0, 0, 0, 1 }, // RS
170 }},
171 // 3F3R.1 in -> 3F2R.1 out
172 // Used coefficient found at http://www.yamahaproaudio.com/training/self_training/data/smqr_en.pdf
173 // L R C LFE LS RS
174 {{
175 { 1, 0, 0, 0, 0, 0 }, // L
176 { 0, 1, 0, 0, 0, 0 }, // R
177 { 0, 0, 1, 0, 0, 0 }, // C
178 { 0, 0, 0, 1, 0, 0 }, // LFE
179 { 0, 0, 0, 0, m3db, m3db }, // Cs
180 { 0, 0, 0, 0, 1, 0 }, // LS
181 { 0, 0, 0, 0, 0, 1 }, // RS
182 }},
183 // 3F4R.1 -> 3F2R.1 out
184 // L R C LFE LS RS
185 {{
186 { 1, 0, 0, 0, 0, 0 }, // L
187 { 0, 1, 0, 0, 0, 0 }, // R
188 { 0, 0, 1, 0, 0, 0 }, // C
189 { 0, 0, 0, 1, 0, 0 }, // LFE
190 { 0, 0, 0, 0, m3db, 0 }, // Rls
191 { 0, 0, 0, 0, 0, m3db }, // Rrs
192 { 0, 0, 0, 0, m3db, 0 }, // LS
193 { 0, 0, 0, 0, 0, m3db }, // RS
194 }}
195}};
196
197static int DownmixFrames(int channels_in, int channels_out,
198 float *dst, const float *src, int frames)
199{
200 if (channels_in < channels_out)
201 return -1;
202
203 //LOG(VB_AUDIO, LOG_INFO, QString("Downmixing %1 frames (in:%2 out:%3)")
204 // .arg(frames).arg(channels_in).arg(channels_out));
205 if (channels_out == 2)
206 {
207 int index = channels_in - 1;
208 for (int n=0; n < frames; n++)
209 {
210 for (int i=0; i < channels_out; i++)
211 {
212 float tmp = 0.0F;
213 for (int j=0; j < channels_in; j++)
214 tmp += src[j] * stereo_matrix[index][j][i];
215 *dst++ = tmp;
216 }
217 src += channels_in;
218 }
219 }
220 else if (channels_out == 6)
221 {
222 int index = channels_in - 6;
223 for (int n=0; n < frames; n++)
224 {
225 for (int i=0; i < channels_out; i++)
226 {
227 float tmp = 0.0F;
228 for (int j=0; j < channels_in; j++)
229 tmp += src[j] * s51_matrix[index][j][i];
230 *dst++ = tmp;
231 }
232 src += channels_in;
233 }
234 }
235 else
236 {
237 return -1;
238 }
239
240 return frames;
241}
242
243#ifdef Q_PROCESSOR_X86
244// Check cpuid for SSE2 support on x86 / x86_64
245static inline bool sse2_check()
246{
247#ifdef Q_PROCESSOR_X86_64
248 return true;
249#else
250 static int has_sse2 = -1;
251 if (has_sse2 != -1)
252 return (bool)has_sse2;
253 __asm__(
254 // -fPIC - we may not clobber ebx/rbx
255 "push %%ebx \n\t"
256 "mov $1, %%eax \n\t"
257 "cpuid \n\t"
258 "and $0x4000000, %%edx \n\t"
259 "shr $26, %%edx \n\t"
260 "pop %%ebx \n\t"
261 :"=d"(has_sse2)
262 ::"%eax","%ecx"
263 );
264 return (bool)has_sse2;
265#endif
266}
267#endif //Q_PROCESSOR_X86
268
274{
275#ifdef Q_PROCESSOR_X86
276 return sse2_check();
277#else
278 return false;
279#endif
280}
281
288static void adjustVolume(void *buf, int len, int volume,
289 bool music, bool upmix)
290{
291 float g = volume / 100.0F;
292 auto *fptr = (float *)buf;
293 int samples = len >> 2;
294 int i = 0;
295
296 // Should be exponential - this'll do
297 g *= g;
298
299 // Try to ~ match stereo volume when upmixing
300 if (upmix)
301 g *= 1.5F;
302
303 // Music is relatively loud
304 if (music)
305 g *= 0.4F;
306
307 if (g == 1.0F)
308 return;
309
310#ifdef Q_PROCESSOR_X86
311 if (sse2_check() && samples >= 16)
312 {
313 int loops = samples >> 4;
314 i = loops << 4;
315
316 __asm__ volatile (
317 "movss %2, %%xmm0 \n\t"
318 "punpckldq %%xmm0, %%xmm0 \n\t"
319 "punpckldq %%xmm0, %%xmm0 \n\t"
320 "1: \n\t"
321 "movups (%0), %%xmm1 \n\t"
322 "movups 16(%0), %%xmm2 \n\t"
323 "mulps %%xmm0, %%xmm1 \n\t"
324 "movups 32(%0), %%xmm3 \n\t"
325 "mulps %%xmm0, %%xmm2 \n\t"
326 "movups 48(%0), %%xmm4 \n\t"
327 "mulps %%xmm0, %%xmm3 \n\t"
328 "movups %%xmm1, (%0) \n\t"
329 "mulps %%xmm0, %%xmm4 \n\t"
330 "movups %%xmm2, 16(%0) \n\t"
331 "movups %%xmm3, 32(%0) \n\t"
332 "movups %%xmm4, 48(%0) \n\t"
333 "add $64, %0 \n\t"
334 "sub $1, %%ecx \n\t"
335 "jnz 1b \n\t"
336 :"+r"(fptr)
337 :"c"(loops),"m"(g)
338 :"xmm0","xmm1","xmm2","xmm3","xmm4"
339 );
340 }
341#endif //Q_PROCESSOR_X86
342 for (; i < samples; i++)
343 *fptr++ *= g;
344}
345
346template <class AudioDataType>
347static void tMuteChannel(AudioDataType *buffer, int channels, int ch, int frames)
348{
349 AudioDataType *s1 = buffer + ch;
350 AudioDataType *s2 = buffer - ch + 1;
351
352 for (int i = 0; i < frames; i++)
353 {
354 *s1 = *s2;
355 s1 += channels;
356 s2 += channels;
357 }
358}
359
366static void muteChannel(int obits, int channels, int ch,
367 void *buffer, int bytes)
368{
369 int frames = bytes / ((obits >> 3) * channels);
370
371 if (obits == 8)
372 tMuteChannel((uint8_t *)buffer, channels, ch, frames);
373 else if (obits == 16)
374 tMuteChannel((short *)buffer, channels, ch, frames);
375 else
376 tMuteChannel((int *)buffer, channels, ch, frames);
377}
378
380{
381 switch(q)
382 {
383 case QUALITY_DISABLED: return "disabled";
384 case QUALITY_LOW: return "low";
385 case QUALITY_MEDIUM: return "medium";
386 case QUALITY_HIGH: return "high";
387 default: return "unknown";
388 }
389}
390
392 MThread("AudioOutputBase"),
393 // protected
394 m_mainDevice(settings.GetMainDevice()),
395 m_passthruDevice(settings.GetPassthruDevice()),
396 m_source(settings.m_source),
397 m_setInitialVol(settings.m_setInitialVol)
398{
399 m_srcIn = m_srcInBuf.data();
400
401 if (m_mainDevice.startsWith("AudioTrack:"))
402 m_usesSpdif = false;
403 // Handle override of SRC quality settings
404 if (gCoreContext->GetBoolSetting("SRCQualityOverride", false))
405 {
407 // Extra test to keep backward compatibility with earlier SRC setting
408 m_srcQuality = std::min<int>(m_srcQuality, QUALITY_HIGH);
409
410 LOG(VB_AUDIO, LOG_INFO, LOC + QString("SRC quality = %1").arg(quality_string(m_srcQuality)));
411 }
412}
413
420{
421 if (!m_killAudio)
422 LOG(VB_GENERAL, LOG_ERR, LOC + "Programmer Error: "
423 "~AudioOutputBase called, but KillAudio has not been called!");
424
425 // We got this from a subclass, delete it
426 delete m_outputSettings;
427 delete m_outputSettingsRaw;
429 {
432 }
433
434 if (m_kAudioSRCOutputSize > 0)
435 delete[] m_srcOut;
436
437#ifndef NDEBUG
438 assert(m_memoryCorruptionTest0 == 0xdeadbeef);
439 assert(m_memoryCorruptionTest1 == 0xdeadbeef);
440 assert(m_memoryCorruptionTest2 == 0xdeadbeef);
441 assert(m_memoryCorruptionTest3 == 0xdeadbeef);
442#endif
443}
444
446{
447 if (settings.m_custom)
448 {
449 // got a custom audio report already, use it
450 // this was likely provided by the AudioTest utility
452 *m_outputSettings = *settings.m_custom;
456 return;
457 }
458
459 // Ask the subclass what we can send to the device
462
466
468 gCoreContext->GetBoolSetting("AudioDefaultUpmix", false) :
469 false;
470 if (settings.m_upmixer == 1) // music, upmixer off
471 m_upmixDefault = false;
472 else if (settings.m_upmixer == 2) // music, upmixer on
473 m_upmixDefault = true;
474}
475
482{
483 // If we've already checked the port, use the cache
484 // version instead
485 if (!m_discreteDigital || !digital)
486 {
487 digital = false;
489 return m_outputSettingsRaw;
490 }
492 {
494 }
495
496 AudioOutputSettings* aosettings = GetOutputSettings(digital);
497 if (aosettings)
498 aosettings->GetCleaned();
499 else
500 aosettings = new AudioOutputSettings(true);
501
502 if (digital)
503 return (m_outputSettingsDigitalRaw = aosettings);
504 return (m_outputSettingsRaw = aosettings);
505}
506
513{
514 if (!m_discreteDigital || !digital)
515 {
516 digital = false;
518 return m_outputSettings;
519 }
521 {
523 }
524
525 auto* aosettings = new AudioOutputSettings;
526
527 *aosettings = *GetOutputSettingsCleaned(digital);
528 aosettings->GetUsers();
529
530 if (digital)
531 return (m_outputSettingsDigital = aosettings);
532 return (m_outputSettings = aosettings);
533}
534
538bool AudioOutputBase::CanPassthrough(int samplerate, int channels,
539 AVCodecID codec, int profile) const
540{
542 bool ret = !(m_internalVol && SWVolume());
543
544 switch(codec)
545 {
546 case AV_CODEC_ID_AC3:
547 arg = FEATURE_AC3;
548 break;
549 case AV_CODEC_ID_DTS:
550 switch(profile)
551 {
552 case FF_PROFILE_DTS:
553 case FF_PROFILE_DTS_ES:
554 case FF_PROFILE_DTS_96_24:
555 arg = FEATURE_DTS;
556 break;
557 case FF_PROFILE_DTS_HD_HRA:
558 case FF_PROFILE_DTS_HD_MA:
559 arg = FEATURE_DTSHD;
560 break;
561 default:
562 break;
563 }
564 break;
565 case AV_CODEC_ID_EAC3:
566 arg = FEATURE_EAC3;
567 break;
568 case AV_CODEC_ID_TRUEHD:
569 arg = FEATURE_TRUEHD;
570 break;
571 default:
572 arg = FEATURE_NONE;
573 break;
574 }
575 // we can't passthrough any other codecs than those defined above
578 ret &= m_outputSettingsDigital->IsSupportedRate(samplerate);
579 // if we must resample to 48kHz ; we can't passthrough
580 ret &= (samplerate == 48000) ||
581 !gCoreContext->GetBoolSetting("Audio48kOverride", false);
582 // Don't know any cards that support spdif clocked at < 44100
583 // Some US cable transmissions have 2ch 32k AC-3 streams
584 ret &= samplerate >= 44100;
585 if (!ret)
586 return false;
587 // Will passthrough if surround audio was defined. Amplifier will
588 // do the downmix if required
589 bool willupmix = m_maxChannels >= 6 && (channels <= 2 && m_upmixDefault);
590 ret &= !willupmix;
591 // unless audio is configured for stereo. We can passthrough otherwise
592 ret |= m_maxChannels == 2;
593
594 return ret;
595}
596
601{
602 if (rate > 0)
603 m_sourceBitRate = rate;
604}
605
612{
613 if (m_stretchFactor == lstretchfactor && m_pSoundStretch)
614 return;
615
616 m_stretchFactor = lstretchfactor;
617
620 if (channels < 1 || channels > 8 || !m_isConfigured)
621 return;
622
623 bool willstretch = m_stretchFactor < 0.99F || m_stretchFactor > 1.01F;
624 m_effStretchFactor = lroundf(100000.0F * lstretchfactor);
625
626 if (m_pSoundStretch)
627 {
628 if (!willstretch && m_forcedProcessing)
629 {
630 m_forcedProcessing = false;
631 m_processing = false;
632 delete m_pSoundStretch;
633 m_pSoundStretch = nullptr;
634 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Cancelling time stretch"));
636 m_waud = m_raud = 0;
638 }
639 else
640 {
641 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Changing time stretch to %1")
642 .arg(m_stretchFactor));
644 }
645 }
646 else if (willstretch)
647 {
648 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Using time stretch %1").arg(m_stretchFactor));
649 m_pSoundStretch = new soundtouch::SoundTouch();
650 m_pSoundStretch->setSampleRate(m_sampleRate);
651 m_pSoundStretch->setChannels(channels);
653#if defined(Q_PROCESSOR_ARM) || defined(Q_OS_ANDROID)
654 // use less demanding settings for Raspberry pi
655 m_pSoundStretch->setSetting(SETTING_SEQUENCE_MS, 82);
656 m_pSoundStretch->setSetting(SETTING_USE_AA_FILTER, 0);
657 m_pSoundStretch->setSetting(SETTING_USE_QUICKSEEK, 1);
658#else
659 m_pSoundStretch->setSetting(SETTING_SEQUENCE_MS, 35);
660#endif
661 /* If we weren't already processing we need to turn on float conversion
662 adjust sample and frame sizes accordingly and dump the contents of
663 the audiobuffer */
664 if (!m_processing)
665 {
666 m_processing = true;
667 m_forcedProcessing = true;
673 m_waud = m_raud = 0;
676 m_pauseAudio = true;
677 m_actuallyPaused = false;
678 m_unpauseWhenReady = true;
679 }
680 }
681}
682
686void AudioOutputBase::SetStretchFactor(float lstretchfactor)
687{
688 QMutexLocker lock(&m_audioBufLock);
689 SetStretchFactorLocked(lstretchfactor);
690}
691
696{
697 return m_stretchFactor;
698}
699
704{
705 return m_needsUpmix && m_upmixer;
706}
707
712{
713 // Can only upmix from mono/stereo to 6 ch
714 if (m_maxChannels == 2 || m_sourceChannels > 2)
715 return false;
716
718
721 m_upmixDefault ? false : m_passthru);
722 Reconfigure(settings);
723 return IsUpmixing();
724}
725
730{
731 return m_sourceChannels <= 2 && m_maxChannels > 2;
732}
733
734/*
735 * Setup samplerate and number of channels for passthrough
736 * Create SPDIF encoder and true if successful
737 */
738bool AudioOutputBase::SetupPassthrough(AVCodecID codec, int codec_profile,
739 int &samplerate_tmp, int &channels_tmp)
740{
741 if (codec == AV_CODEC_ID_DTS &&
743 {
744 // We do not support DTS-HD bitstream so force extraction of the
745 // DTS core track instead
746 codec_profile = FF_PROFILE_DTS;
747 }
749 codec, codec_profile,
750 samplerate_tmp, channels_tmp,
752 LOG(VB_AUDIO, LOG_INFO, LOC + "Setting " + log + " passthrough");
753
754 delete m_spdifEnc;
755
756 // No spdif encoder needed for certain devices
757 if (m_usesSpdif)
758 m_spdifEnc = new SPDIFEncoder("spdif", codec);
759 else
760 m_spdifEnc = nullptr;
761 if (m_spdifEnc && m_spdifEnc->Succeeded() && codec == AV_CODEC_ID_DTS)
762 {
763 switch(codec_profile)
764 {
765 case FF_PROFILE_DTS:
766 case FF_PROFILE_DTS_ES:
767 case FF_PROFILE_DTS_96_24:
769 break;
770 case FF_PROFILE_DTS_HD_HRA:
771 case FF_PROFILE_DTS_HD_MA:
772 m_spdifEnc->SetMaxHDRate(samplerate_tmp * channels_tmp / 2);
773 break;
774 }
775 }
776
778 {
779 delete m_spdifEnc;
780 m_spdifEnc = nullptr;
781 return false;
782 }
783 return true;
784}
785
787{
788 if (digital)
790 return m_outputSettings;
791}
792
799{
800 AudioSettings settings = orig_settings;
801 int lsource_channels = settings.m_channels;
802 int lconfigured_channels = m_configuredChannels;
803 bool lneeds_upmix = false;
804 bool lneeds_downmix = false;
805 bool lreenc = false;
806 bool lenc = false;
807
808 if (!settings.m_usePassthru)
809 {
810 // Do we upmix stereo or mono?
811 lconfigured_channels =
812 (m_upmixDefault && lsource_channels <= 2) ? 6 : lsource_channels;
813 bool cando_channels =
814 m_outputSettings->IsSupportedChannels(lconfigured_channels);
815
816 // check if the number of channels could be transmitted via AC3 encoding
817#ifndef DISABLE_AC3_ENCODE
820 lconfigured_channels > 2 && lconfigured_channels <= 6);
821#endif
822 if (!lenc && !cando_channels)
823 {
824 // if hardware doesn't support source audio configuration
825 // we will upmix/downmix to what we can
826 // (can safely assume hardware supports stereo)
827 switch (lconfigured_channels)
828 {
829 case 7:
830 lconfigured_channels = 8;
831 break;
832 case 8:
833 case 5:
834 lconfigured_channels = 6;
835 break;
836 case 6:
837 case 4:
838 case 3:
839 case 2: //Will never happen
840 lconfigured_channels = 2;
841 break;
842 case 1:
843 lconfigured_channels = m_upmixDefault ? 6 : 2;
844 break;
845 default:
846 lconfigured_channels = 2;
847 break;
848 }
849 }
850 // Make sure we never attempt to output more than what we can
851 // the upmixer can only upmix to 6 channels when source < 6
852 if (lsource_channels <= 6)
853 lconfigured_channels = std::min(lconfigured_channels, 6);
854 lconfigured_channels = std::min(lconfigured_channels, m_maxChannels);
855 /* Encode to AC-3 if we're allowed to passthru but aren't currently
856 and we have more than 2 channels but multichannel PCM is not
857 supported or if the device just doesn't support the number of
858 channels */
859#ifndef DISABLE_AC3_ENCODE
862 lconfigured_channels > 2) ||
863 !m_outputSettings->IsSupportedChannels(lconfigured_channels));
864 /* Might we reencode a bitstream that's been decoded for timestretch?
865 If the device doesn't support the number of channels - see below */
867 (settings.m_codec == AV_CODEC_ID_AC3 ||
868 settings.m_codec == AV_CODEC_ID_DTS))
869 {
870 lreenc = true;
871 }
872#endif
873 // Enough channels? Upmix if not, but only from mono/stereo/5.0 to 5.1
874 if (IS_VALID_UPMIX_CHANNEL(settings.m_channels) &&
875 settings.m_channels < lconfigured_channels)
876 {
877 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Needs upmix from %1 -> %2 channels")
878 .arg(settings.m_channels).arg(lconfigured_channels));
879 settings.m_channels = lconfigured_channels;
880 lneeds_upmix = true;
881 }
882 else if (settings.m_channels > lconfigured_channels)
883 {
884 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Needs downmix from %1 -> %2 channels")
885 .arg(settings.m_channels).arg(lconfigured_channels));
886 settings.m_channels = lconfigured_channels;
887 lneeds_downmix = true;
888 }
889 }
890
891 bool general_deps = true;
892
893 /* Set samplerate_tmp and channels_tmp to appropriate values
894 if passing through */
895 int samplerate_tmp = 0;
896 int channels_tmp = 0;
897 if (settings.m_usePassthru)
898 {
899 samplerate_tmp = settings.m_sampleRate;
900 SetupPassthrough(settings.m_codec, settings.m_codecProfile,
901 samplerate_tmp, channels_tmp);
902 general_deps = m_sampleRate == samplerate_tmp && m_channels == channels_tmp;
903 general_deps &= m_format == m_outputFormat && m_format == FORMAT_S16;
904 }
905 else
906 {
907 general_deps =
908 settings.m_format == m_format && lsource_channels == m_sourceChannels;
909 }
910
911 // Check if anything has changed
912 general_deps &=
913 settings.m_sampleRate == m_sourceSampleRate &&
914 settings.m_usePassthru == m_passthru &&
915 lconfigured_channels == m_configuredChannels &&
916 lneeds_upmix == m_needsUpmix && lreenc == m_reEnc &&
917 lneeds_downmix == m_needsDownmix;
918
919 if (general_deps && m_isConfigured)
920 {
921 LOG(VB_AUDIO, LOG_INFO, LOC + "Reconfigure(): No change -> exiting");
922 // if passthrough, source channels may have changed
923 m_sourceChannels = lsource_channels;
924 return;
925 }
926
927 m_isConfigured = false;
928 KillAudio();
929
930 QMutexLocker lock(&m_audioBufLock);
931 QMutexLocker lockav(&m_avsyncLock);
932
933 m_waud = m_raud = 0;
936
937 m_channels = settings.m_channels;
938 m_sourceChannels = lsource_channels;
939 m_reEnc = lreenc;
940 m_codec = settings.m_codec;
941 m_passthru = settings.m_usePassthru;
942 m_configuredChannels = lconfigured_channels;
943 m_needsUpmix = lneeds_upmix;
944 m_needsDownmix = lneeds_downmix;
945 m_format = m_outputFormat = settings.m_format;
947 m_enc = lenc;
948
949 m_killAudio = m_pauseAudio = false;
950 m_wasPaused = true;
951
952 // Don't try to do anything if audio hasn't been
953 // initialized yet (e.g. rubbish was provided)
954 if (m_sourceChannels <= 0 || m_format <= 0 || m_sampleRate <= 0)
955 {
956 return;
957 }
958
959 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Original codec was %1, %2, %3 kHz, %4 channels")
960 .arg(avcodec_get_name(m_codec),
962 .arg(m_sampleRate/1000)
963 .arg(m_sourceChannels));
964
966 {
967 QString message {QCoreApplication::translate("AudioOutputBase",
968 "Aborting Audio Reconfigure. Can't handle audio with more than 8 channels.")};
969 dispatchError(message);
970 LOG(VB_GENERAL, LOG_ERR, message);
971 return;
972 }
973
974 LOG(VB_AUDIO, LOG_INFO, LOC + QString("enc(%1), passthru(%2), features (%3) "
975 "configured_channels(%4), %5 channels supported(%6) "
976 "max_channels(%7)")
977 .arg(m_enc)
978 .arg(m_passthru)
981 .arg(m_channels)
982 .arg(OutputSettings(m_enc || m_passthru)->IsSupportedChannels(m_channels))
983 .arg(m_maxChannels));
984
985 int dest_rate = 0;
986
987 // Force resampling if we are encoding to AC3 and sr > 48k
988 // or if 48k override was checked in settings
989 if ((m_sampleRate != 48000 &&
990 gCoreContext->GetBoolSetting("Audio48kOverride", false)) ||
991 (m_enc && (m_sampleRate > 48000)))
992 {
993 LOG(VB_AUDIO, LOG_INFO, LOC + "Forcing resample to 48 kHz");
994 if (m_srcQuality < 0)
996 m_needResampler = true;
997 dest_rate = 48000;
998 }
999 // this will always be false for passthrough audio as
1000 // CanPassthrough() already tested these conditions
1001 else
1002 {
1005 if (m_needResampler)
1006 {
1008 }
1009 }
1010
1012 {
1013 m_sampleRate = dest_rate;
1014
1015 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Resampling from %1 kHz to %2 kHz with quality %3")
1016 .arg(settings.m_sampleRate/1000).arg(m_sampleRate/1000)
1018
1020
1021 int error = 0;
1022 m_srcCtx = src_new(2-m_srcQuality, chans, &error);
1023 if (error)
1024 {
1025 QString message {QCoreApplication::translate("AudioOutputBase", "Error creating resampler: %1")
1026 .arg(src_strerror(error))};
1027 dispatchError(message);
1028 LOG(VB_GENERAL, LOG_ERR, message);
1029 m_srcCtx = nullptr;
1030 return;
1031 }
1032
1033 m_srcData.src_ratio = (double)m_sampleRate / settings.m_sampleRate;
1034 m_srcData.data_in = m_srcIn;
1035 int newsize = (int)((kAudioSRCInputSize * m_srcData.src_ratio) + 15)
1036 & ~0xf;
1037
1038 if (m_kAudioSRCOutputSize < newsize)
1039 {
1040 m_kAudioSRCOutputSize = newsize;
1041 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Resampler allocating %1").arg(newsize));
1042 delete[] m_srcOut;
1043 m_srcOut = new float[m_kAudioSRCOutputSize];
1044 }
1045 m_srcData.data_out = m_srcOut;
1046 m_srcData.output_frames = m_kAudioSRCOutputSize / chans;
1047 m_srcData.end_of_input = 0;
1048 }
1049
1050 if (m_enc)
1051 {
1052 if (m_reEnc)
1053 LOG(VB_AUDIO, LOG_INFO, LOC + "Reencoding decoded AC-3/DTS to AC-3");
1054
1055 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Creating AC-3 Encoder with sr = %1, ch = %2")
1057
1059 if (!m_encoder->Init(AV_CODEC_ID_AC3, 448000, m_sampleRate,
1061 {
1062 QString message {QCoreApplication::translate("AudioOutputBase", "AC-3 encoder initialization failed")};
1063 dispatchError(message);
1064 LOG(VB_GENERAL, LOG_ERR, message);
1065 delete m_encoder;
1066 m_encoder = nullptr;
1067 m_enc = false;
1068 // upmixing will fail if we needed the encoder
1069 m_needsUpmix = false;
1070 }
1071 }
1072
1073 if (m_passthru)
1074 {
1075 //AC3, DTS, DTS-HD MA and TrueHD all use 16 bits samples
1076 m_channels = channels_tmp;
1077 m_sampleRate = samplerate_tmp;
1081 }
1082 else
1083 {
1086 }
1087
1088 // Turn on float conversion?
1090 m_stretchFactor != 1.0F || (m_internalVol && SWVolume()) ||
1092 !OutputSettings(m_enc || m_passthru)->IsSupportedFormat(m_outputFormat))
1093 {
1094 LOG(VB_AUDIO, LOG_INFO, LOC + "Audio processing enabled");
1095 m_processing = true;
1096 if (m_enc)
1097 m_outputFormat = FORMAT_S16; // Output s16le for AC-3 encoder
1098 else
1100 }
1101
1105
1106 if (m_enc)
1107 m_channels = 2; // But only post-encoder
1108
1111
1112 LOG(VB_GENERAL, LOG_INFO, LOC +
1113 QString("Opening audio device '%1' ch %2(%3) sr %4 sf %5 reenc %6")
1116
1118 m_framesBuffered = 0;
1119 m_currentSeconds = -1s;
1120 m_sourceBitRate = -1;
1121 m_effDsp = m_sampleRate * 100;
1122
1123 // Actually do the device specific open call
1124 if (!OpenDevice())
1125 {
1126 QString message {QCoreApplication::translate("AudioOutputBase", "Aborting reconfigure")};
1127 dispatchError(message);
1128 LOG(VB_GENERAL, LOG_INFO, LOC + message);
1129 return;
1130 }
1131
1132 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Audio fragment size: %1").arg(m_fragmentSize));
1133
1134 // Only used for software volume
1136 {
1137 LOG(VB_AUDIO, LOG_INFO, LOC + "Software volume enabled");
1138 m_volumeControl = gCoreContext->GetSetting("MixerControl", "PCM");
1139 m_volumeControl += "MixerVolume";
1141 }
1142
1146
1148 {
1152 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Create %1 quality upmixer done")
1154 }
1155
1156 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Audio Stretch Factor: %1").arg(m_stretchFactor));
1158
1159 // Setup visualisations, zero the visualisations buffers
1161
1164
1165 m_isConfigured = true;
1166
1168
1169 LOG(VB_AUDIO, LOG_INFO, LOC + "Ending Reconfigure()");
1170}
1171
1173{
1175 return true;
1176
1177 start();
1178 m_audioThreadExists = true;
1179
1180 return true;
1181}
1182
1183
1185{
1187 {
1188 wait();
1189 m_audioThreadExists = false;
1190 }
1191}
1192
1197{
1198 m_killAudioLock.lock();
1199
1200 LOG(VB_AUDIO, LOG_INFO, LOC + "Killing AudioOutputDSP");
1201 m_killAudio = true;
1203 QMutexLocker lock(&m_audioBufLock);
1204
1205 if (m_pSoundStretch)
1206 {
1207 delete m_pSoundStretch;
1208 m_pSoundStretch = nullptr;
1210 m_stretchFactor = 1.0F;
1211 }
1212
1213 if (m_encoder)
1214 {
1215 delete m_encoder;
1216 m_encoder = nullptr;
1217 }
1218
1219 if (m_upmixer)
1220 {
1221 delete m_upmixer;
1222 m_upmixer = nullptr;
1223 }
1224
1225 if (m_srcCtx)
1226 {
1227 src_delete(m_srcCtx);
1228 m_srcCtx = nullptr;
1229 }
1230
1232
1233 CloseDevice();
1234
1235 m_killAudioLock.unlock();
1236}
1237
1238void AudioOutputBase::Pause(bool paused)
1239{
1240 if (!paused && m_unpauseWhenReady)
1241 return;
1242 LOG(VB_AUDIO, LOG_INFO, LOC + QString("Pause %1").arg(paused));
1243 if (m_pauseAudio != paused)
1245 m_pauseAudio = paused;
1246 m_unpauseWhenReady = false;
1247 m_actuallyPaused = false;
1248}
1249
1251{
1252 Reset();
1253 Pause(true);
1254 m_unpauseWhenReady = true;
1255}
1256
1261{
1262 QMutexLocker lock(&m_audioBufLock);
1263 QMutexLocker lockav(&m_avsyncLock);
1264
1266 m_framesBuffered = 0;
1267 if (m_encoder)
1268 {
1269 m_waud = m_raud = 0; // empty ring buffer
1270 m_audioBuffer.fill(0);
1271 }
1272 else
1273 {
1274 m_waud = m_raud; // empty ring buffer
1275 }
1277 m_currentSeconds = -1s;
1279 m_unpauseWhenReady = false;
1280 // clear any state that could remember previous audio in any active filters
1281 if (m_needsUpmix && m_upmixer)
1282 m_upmixer->flush();
1283 if (m_pSoundStretch)
1284 m_pSoundStretch->clear();
1285 if (m_encoder)
1286 m_encoder->clear();
1287
1288 // Setup visualisations, zero the visualisations buffers
1290}
1291
1298void AudioOutputBase::SetTimecode(std::chrono::milliseconds timecode)
1299{
1300 m_audbufTimecode = m_audioTime = timecode;
1301 m_framesBuffered = (timecode.count() * m_sourceSampleRate) / 1000;
1302}
1303
1311{
1312 LOG(VB_AUDIO, LOG_INFO, LOC + QString("SetEffDsp: %1").arg(dsprate));
1313 m_effDsp = dsprate;
1314}
1315
1320{
1321 if (m_waud >= m_raud)
1322 return m_waud - m_raud;
1323 return kAudioRingBufferSize - (m_raud - m_waud);
1324}
1325
1330{
1331 return kAudioRingBufferSize - audiolen() - 1;
1332 /* There is one wasted byte in the buffer. The case where m_waud = m_raud is
1333 interpreted as an empty buffer, so the fullest the buffer can ever
1334 be is kAudioRingBufferSize - 1. */
1335}
1336
1345{
1347 return audiolen();
1349}
1350
1354std::chrono::milliseconds AudioOutputBase::GetAudiotime(void)
1355{
1356 if (m_audbufTimecode == 0ms || !m_isConfigured)
1357 return 0ms;
1358
1359 // output bits per 10 frames
1360 int64_t obpf = 0;
1361
1362 if (m_passthru && !usesSpdif())
1363 obpf = m_sourceBitRate * 10 / m_sourceSampleRate;
1364 else if (m_enc && !usesSpdif())
1365 {
1366 // re-encode bitrate is hardcoded at 448000
1367 obpf = 448000 * 10 / m_sourceSampleRate;
1368 }
1369 else
1370 {
1371 obpf = static_cast<int64_t>(m_outputBytesPerFrame) * 80;
1372 }
1373
1374 /* We want to calculate 'm_audioTime', which is the timestamp of the audio
1375 Which is leaving the sound card at this instant.
1376
1377 We use these variables:
1378
1379 'm_effDsp' is 100 * frames/sec
1380
1381 'm_audbufTimecode' is the timecode in milliseconds of the
1382 audio that has just been written into the buffer.
1383
1384 'm_effStretchFactor' is stretch factor * 100,000
1385
1386 'totalbuffer' is the total # of bytes in our audio buffer, and the
1387 sound card's buffer. */
1388
1389
1390 QMutexLocker lockav(&m_avsyncLock);
1391
1392 int64_t soundcard_buffer = GetBufferedOnSoundcard(); // bytes
1393
1394 /* audioready tells us how many bytes are in audiobuffer
1395 scaled appropriately if output format != internal format */
1396 int64_t main_buffer = audioready();
1397
1398 std::chrono::milliseconds oldaudiotime = m_audioTime;
1399
1400 /* timecode is the stretch adjusted version
1401 of major post-stretched buffer contents
1402 processing latencies are catered for in AddData/SetAudiotime
1403 to eliminate race */
1404
1405 m_audioTime = m_audbufTimecode - std::chrono::milliseconds(m_effDsp && obpf ?
1406 ((main_buffer + soundcard_buffer) * int64_t(m_effStretchFactor)
1407 * 80 / int64_t(m_effDsp) / obpf) : 0);
1408
1409 /* audiotime should never go backwards, but we might get a negative
1410 value if GetBufferedOnSoundcard() isn't updated by the driver very
1411 quickly (e.g. ALSA) */
1412 if (m_audioTime < oldaudiotime)
1413 m_audioTime = oldaudiotime;
1414
1415 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + QString("GetAudiotime audt=%1 abtc=%2 mb=%3 sb=%4 tb=%5 "
1416 "sr=%6 obpf=%7 bpf=%8 esf=%9 edsp=%10 sbr=%11")
1417 .arg(m_audioTime.count()) // 1
1418 .arg(m_audbufTimecode.count()) // 2
1419 .arg(main_buffer) // 3
1420 .arg(soundcard_buffer) // 4
1421 .arg(main_buffer+soundcard_buffer) // 5
1422 .arg(m_sampleRate).arg(obpf) // 6, 7
1423 .arg(m_bytesPerFrame) // 8
1424 .arg(m_effStretchFactor) // 9
1425 .arg(m_effDsp).arg(m_sourceBitRate) // 10, 11
1426 );
1427
1428 return m_audioTime;
1429}
1430
1436void AudioOutputBase::SetAudiotime(int frames, std::chrono::milliseconds timecode)
1437{
1438 int64_t processframes_stretched = 0;
1439 int64_t processframes_unstretched = 0;
1440 std::chrono::milliseconds old_audbuf_timecode = m_audbufTimecode;
1441
1442 if (!m_isConfigured)
1443 return;
1444
1445 if (m_needsUpmix && m_upmixer)
1446 processframes_unstretched -= m_upmixer->frameLatency();
1447
1448 if (m_pSoundStretch)
1449 {
1450 processframes_unstretched -= m_pSoundStretch->numUnprocessedSamples();
1451 processframes_stretched -= m_pSoundStretch->numSamples();
1452 }
1453
1454 if (m_encoder)
1455 {
1456 processframes_stretched -= m_encoder->Buffered();
1457 }
1458
1460 timecode + std::chrono::milliseconds(m_effDsp ? ((frames + processframes_unstretched) * 100000 +
1461 (processframes_stretched * m_effStretchFactor)
1462 ) / m_effDsp : 0);
1463
1464 // check for timecode wrap and reset audiotime if detected
1465 // timecode will always be monotonic asc if not seeked and reset
1466 // happens if seek or pause happens
1467 if (m_audbufTimecode < old_audbuf_timecode)
1468 m_audioTime = 0ms;
1469
1470 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + QString("SetAudiotime atc=%1 tc=%2 f=%3 pfu=%4 pfs=%5")
1471 .arg(m_audbufTimecode.count())
1472 .arg(timecode.count())
1473 .arg(frames)
1474 .arg(processframes_unstretched)
1475 .arg(processframes_stretched));
1476#ifdef AUDIOTSTESTING
1477 GetAudiotime();
1478#endif
1479}
1480
1486std::chrono::milliseconds AudioOutputBase::GetAudioBufferedTime(void)
1487{
1488 std::chrono::milliseconds ret = m_audbufTimecode - GetAudiotime();
1489 // Pulse can give us values that make this -ve
1490 if (ret < 0ms)
1491 return 0ms;
1492 return ret;
1493}
1494
1498void AudioOutputBase::SetSWVolume(int new_volume, bool save)
1499{
1500 m_volume = new_volume;
1501 if (save && m_volumeControl != nullptr)
1503}
1504
1509{
1510 return m_volume;
1511}
1512
1522{
1523 int bpf = m_bytesPerFrame;
1524 int len = frames * bpf;
1525 int afree = audiofree();
1526
1527 if (len <= afree)
1528 return len;
1529
1530 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Audio buffer overflow, %1 frames lost!")
1531 .arg(frames - (afree / bpf)));
1532
1533 frames = afree / bpf;
1534 len = frames * bpf;
1535
1536 if (!m_srcCtx)
1537 return len;
1538
1539 int error = src_reset(m_srcCtx);
1540 if (error)
1541 {
1542 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error occurred while resetting resampler: %1")
1543 .arg(src_strerror(error)));
1544 m_srcCtx = nullptr;
1545 }
1546
1547 return len;
1548}
1549
1556int AudioOutputBase::CopyWithUpmix(char *buffer, int frames, uint &org_waud)
1557{
1558 int len = CheckFreeSpace(frames);
1559 int bdiff = kAudioRingBufferSize - org_waud;
1560 int bpf = m_bytesPerFrame;
1561 ptrdiff_t off = 0;
1562
1563 if (!m_needsUpmix)
1564 {
1565 int num = len;
1566
1567 if (bdiff <= num)
1568 {
1569 memcpy(WPOS, buffer, bdiff);
1570 num -= bdiff;
1571 off = bdiff;
1572 org_waud = 0;
1573 }
1574 if (num > 0)
1575 memcpy(WPOS, buffer + off, num);
1576 org_waud = (org_waud + num) % kAudioRingBufferSize;
1577 return len;
1578 }
1579
1580 // Convert mono to stereo as most devices can't accept mono
1581 if (!m_upmixer)
1582 {
1583 // we're always in the case
1584 // m_configuredChannels == 2 && m_sourceChannels == 1
1585 int bdFrames = bdiff / bpf;
1586 if (bdFrames <= frames)
1587 {
1588 AudioConvert::MonoToStereo(WPOS, buffer, bdFrames);
1589 frames -= bdFrames;
1590 off = bdFrames * sizeof(float); // 1 channel of floats
1591 org_waud = 0;
1592 }
1593 if (frames > 0)
1594 AudioConvert::MonoToStereo(WPOS, buffer + off, frames);
1595
1596 org_waud = (org_waud + frames * bpf) % kAudioRingBufferSize;
1597 return len;
1598 }
1599
1600 // Upmix to 6ch via FreeSurround
1601 // Calculate frame size of input
1602 off = m_processing ? sizeof(float) : AudioOutputSettings::SampleSize(m_format);
1603 off *= m_sourceChannels;
1604
1605 int i = 0;
1606 len = 0;
1607 while (i < frames)
1608 {
1609 i += m_upmixer->putFrames(buffer + (i * off), frames - i, m_sourceChannels);
1610 int nFrames = m_upmixer->numFrames();
1611 if (!nFrames)
1612 continue;
1613
1614 len += CheckFreeSpace(nFrames);
1615
1616 int bdFrames = (kAudioRingBufferSize - org_waud) / bpf;
1617 if (bdFrames < nFrames)
1618 {
1619 if ((org_waud % bpf) != 0)
1620 {
1621 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Upmixing: org_waud = %1 (bpf = %2)")
1622 .arg(org_waud)
1623 .arg(bpf));
1624 }
1625 m_upmixer->receiveFrames((float *)(WPOS), bdFrames);
1626 nFrames -= bdFrames;
1627 org_waud = 0;
1628 }
1629 if (nFrames > 0)
1630 m_upmixer->receiveFrames((float *)(WPOS), nFrames);
1631
1632 org_waud = (org_waud + nFrames * bpf) % kAudioRingBufferSize;
1633 }
1634 return len;
1635}
1636
1642bool AudioOutputBase::AddFrames(void *in_buffer, int in_frames,
1643 std::chrono::milliseconds timecode)
1644{
1645 return AddData(in_buffer, in_frames * m_sourceBytesPerFrame, timecode,
1646 in_frames);
1647}
1648
1654bool AudioOutputBase::AddData(void *in_buffer, int in_len,
1655 std::chrono::milliseconds timecode,
1656 int /*in_frames*/)
1657{
1658 int frames = in_len / m_sourceBytesPerFrame;
1659 int bpf = m_bytesPerFrame;
1660 int len = in_len;
1661 bool music = false;
1662
1663 if (!m_isConfigured)
1664 {
1665 LOG(VB_GENERAL, LOG_ERR, "AddData called with audio framework not "
1666 "initialised");
1667 m_lengthLastData = 0ms;
1668 return false;
1669 }
1670
1671 /* See if we're waiting for new samples to be buffered before we unpause
1672 post channel change, seek, etc. Wait for 4 fragments to be buffered */
1674 {
1675 m_unpauseWhenReady = false;
1676 Pause(false);
1677 }
1678
1679 // Don't write new samples if we're resetting the buffer or reconfiguring
1680 QMutexLocker lock(&m_audioBufLock);
1681
1682 uint org_waud = m_waud;
1683 int afree = audiofree();
1684 int used = kAudioRingBufferSize - afree;
1685
1686 if (m_passthru && m_spdifEnc)
1687 {
1688 if (m_processing)
1689 {
1690 /*
1691 * We shouldn't encounter this case, but it can occur when
1692 * timestretch just got activated. So we will just drop the
1693 * data
1694 */
1695 LOG(VB_AUDIO, LOG_INFO,
1696 "Passthrough activated with audio processing. Dropping audio");
1697 return false;
1698 }
1699 // mux into an IEC958 packet
1700 m_spdifEnc->WriteFrame((unsigned char *)in_buffer, len);
1702 if (len > 0)
1703 {
1704 in_buffer = m_spdifEnc->GetProcessedBuffer();
1705 m_spdifEnc->Reset();
1706 frames = len / m_sourceBytesPerFrame;
1707 }
1708 else
1709 {
1710 frames = 0;
1711 }
1712 }
1714 ((double)(len * 1000) / (m_sourceSampleRate * m_sourceBytesPerFrame));
1715
1716 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + QString("AddData frames=%1, bytes=%2, used=%3, free=%4, "
1717 "timecode=%5 needsupmix=%6")
1718 .arg(frames).arg(len).arg(used).arg(afree).arg(timecode.count())
1719 .arg(m_needsUpmix));
1720
1721 // Mythmusic doesn't give us timestamps
1722 if (timecode < 0ms)
1723 {
1724 timecode = std::chrono::milliseconds((m_framesBuffered * 1000) / m_sourceSampleRate);
1725 m_framesBuffered += frames;
1726 music = true;
1727 }
1728
1729 if (hasVisual())
1730 {
1731 // Send original samples to any attached visualisations
1732 dispatchVisual((uchar *)in_buffer, len, timecode, m_sourceChannels,
1734 }
1735
1736 // Calculate amount of free space required in ringbuffer
1737 if (m_processing)
1738 {
1739 int sampleSize = AudioOutputSettings::SampleSize(m_format);
1740 if (sampleSize <= 0)
1741 {
1742 // Would lead to division by zero (or unexpected results if negative)
1743 LOG(VB_GENERAL, LOG_ERR, LOC + "Sample size is <= 0, AddData returning false");
1744 return false;
1745 }
1746
1747 // Final float conversion space requirement
1748 len = sizeof(m_srcInBuf[0]) / sampleSize * len;
1749
1750 // Account for changes in number of channels
1751 if (m_needsDownmix)
1752 len = (len * m_configuredChannels ) / m_sourceChannels;
1753
1754 // Check we have enough space to write the data
1756 len = lround(ceil(static_cast<double>(len) * m_srcData.src_ratio));
1757
1758 if (m_needsUpmix)
1759 len = (len * m_configuredChannels ) / m_sourceChannels;
1760
1761 // Include samples in upmix buffer that may be flushed
1762 if (m_needsUpmix && m_upmixer)
1763 len += m_upmixer->numUnprocessedFrames() * bpf;
1764
1765 // Include samples in soundstretch buffers
1766 if (m_pSoundStretch)
1767 len += (m_pSoundStretch->numUnprocessedSamples() +
1768 (int)(m_pSoundStretch->numSamples() / m_stretchFactor)) * bpf;
1769 }
1770
1771 if (len > afree)
1772 {
1773 LOG(VB_GENERAL, LOG_ERR, LOC + "Buffer is full, AddData returning false");
1774 return false; // would overflow
1775 }
1776
1777 int frames_remaining = frames;
1778 int frames_final = 0;
1779 int maxframes = (kAudioSRCInputSize / m_sourceChannels) & ~0xf;
1780 int offset = 0;
1781
1782 while(frames_remaining > 0)
1783 {
1784 void *buffer = (char *)in_buffer + offset;
1785 frames = frames_remaining;
1786 len = frames * m_sourceBytesPerFrame;
1787
1788 if (m_processing)
1789 {
1790 if (frames > maxframes)
1791 {
1792 frames = maxframes;
1793 len = frames * m_sourceBytesPerFrame;
1794 offset += len;
1795 }
1796 // Convert to floats
1797 AudioConvert::toFloat(m_format, m_srcIn, buffer, len);
1798 }
1799
1800 frames_remaining -= frames;
1801
1802 // Perform downmix if necessary
1803 if (m_needsDownmix)
1804 {
1807 m_srcIn, m_srcIn, frames) < 0)
1808 LOG(VB_GENERAL, LOG_ERR, LOC + "Error occurred while downmixing");
1809 }
1810
1811 // Resample if necessary
1813 {
1814 m_srcData.input_frames = frames;
1815 int error = src_process(m_srcCtx, &m_srcData);
1816
1817 if (error)
1818 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error occurred while resampling audio: %1")
1819 .arg(src_strerror(error)));
1820
1821 buffer = m_srcOut;
1822 frames = m_srcData.output_frames_gen;
1823 }
1824 else if (m_processing)
1825 {
1826 buffer = m_srcIn;
1827 }
1828
1829 /* we want the timecode of the last sample added but we are given the
1830 timecode of the first - add the time in ms that the frames added
1831 represent */
1832
1833 // Copy samples into audiobuffer, with upmix if necessary
1834 len = CopyWithUpmix((char *)buffer, frames, org_waud);
1835 if (len <= 0)
1836 {
1837 continue;
1838 }
1839
1840 frames = len / bpf;
1841 frames_final += frames;
1842
1843 int bdiff = kAudioRingBufferSize - m_waud;
1844 if ((len % bpf) != 0 && bdiff < len)
1845 {
1846 LOG(VB_GENERAL, LOG_ERR, LOC + QString("AddData: Corruption likely: len = %1 (bpf = %2)")
1847 .arg(len)
1848 .arg(bpf));
1849 }
1850 if ((bdiff % bpf) != 0 && bdiff < len)
1851 {
1852 LOG(VB_GENERAL, LOG_ERR, LOC + QString("AddData: Corruption likely: bdiff = %1 (bpf = %2)")
1853 .arg(bdiff)
1854 .arg(bpf));
1855 }
1856
1857 if (m_pSoundStretch)
1858 {
1859 // does not change the timecode, only the number of samples
1860 org_waud = m_waud;
1861 int bdFrames = bdiff / bpf;
1862
1863 if (bdiff < len)
1864 {
1865 m_pSoundStretch->putSamples((STST *)(WPOS), bdFrames);
1866 m_pSoundStretch->putSamples((STST *)ABUF, (len - bdiff) / bpf);
1867 }
1868 else
1869 {
1870 m_pSoundStretch->putSamples((STST *)(WPOS), frames);
1871 }
1872
1873 int nFrames = m_pSoundStretch->numSamples();
1874 if (nFrames > frames)
1875 CheckFreeSpace(nFrames);
1876
1877 len = nFrames * bpf;
1878
1879 if (nFrames > bdFrames)
1880 {
1881 nFrames -= m_pSoundStretch->receiveSamples((STST *)(WPOS),
1882 bdFrames);
1883 org_waud = 0;
1884 }
1885 if (nFrames > 0)
1886 nFrames = m_pSoundStretch->receiveSamples((STST *)(WPOS),
1887 nFrames);
1888
1889 org_waud = (org_waud + nFrames * bpf) % kAudioRingBufferSize;
1890 }
1891
1892 if (m_internalVol && SWVolume())
1893 {
1894 org_waud = m_waud;
1895 int num = len;
1896
1897 if (bdiff <= num)
1898 {
1899 adjustVolume(WPOS, bdiff, m_volume, music, m_needsUpmix && m_upmixer);
1900 num -= bdiff;
1901 org_waud = 0;
1902 }
1903 if (num > 0)
1905 org_waud = (org_waud + num) % kAudioRingBufferSize;
1906 }
1907
1908 if (m_encoder)
1909 {
1910 org_waud = m_waud;
1911 int to_get = 0;
1912
1913 if (bdiff < len)
1914 {
1916 to_get = m_encoder->Encode(ABUF, len - bdiff,
1918 }
1919 else
1920 {
1921 to_get = m_encoder->Encode(WPOS, len,
1923 }
1924
1925 if (bdiff <= to_get)
1926 {
1927 m_encoder->GetFrames(WPOS, bdiff);
1928 to_get -= bdiff ;
1929 org_waud = 0;
1930 }
1931 if (to_get > 0)
1932 m_encoder->GetFrames(WPOS, to_get);
1933
1934 org_waud = (org_waud + to_get) % kAudioRingBufferSize;
1935 }
1936
1937 m_waud = org_waud;
1938 }
1939
1940 SetAudiotime(frames_final, timecode);
1941
1942 return true;
1943}
1944
1949{
1950 std::chrono::milliseconds ct = GetAudiotime();
1951
1952 if (ct < 0ms)
1953 ct = 0ms;
1954
1955 if (m_sourceBitRate == -1)
1956 m_sourceBitRate = static_cast<long>(m_sourceSampleRate) * m_sourceChannels *
1958
1959 if (duration_cast<std::chrono::seconds>(ct) != m_currentSeconds)
1960 {
1961 m_currentSeconds = duration_cast<std::chrono::seconds>(ct);
1964 dispatch(e);
1965 }
1966}
1967
1973{
1975 total = kAudioRingBufferSize;
1976}
1977
1984{
1985 auto *zeros = new(std::align_val_t(16)) uchar[m_fragmentSize];
1986 auto *fragment = new(std::align_val_t(16)) uchar[m_fragmentSize];
1987 memset(zeros, 0, m_fragmentSize);
1988
1989 // to reduce startup latency, write silence in 8ms chunks
1990 int zero_fragment_size = 8 * m_sampleRate * m_outputBytesPerFrame / 1000;
1991 zero_fragment_size = std::min(zero_fragment_size, m_fragmentSize);
1992
1993 while (!m_killAudio)
1994 {
1995 if (m_pauseAudio)
1996 {
1997 if (!m_actuallyPaused)
1998 {
1999 LOG(VB_AUDIO, LOG_INFO, LOC + "OutputAudioLoop: audio paused");
2000 Event e(Event::kPaused);
2001 dispatch(e);
2002 m_wasPaused = true;
2003 }
2004
2005 m_actuallyPaused = true;
2006 m_audioTime = 0ms; // mark 'audiotime' as invalid.
2007
2008 WriteAudio(zeros, zero_fragment_size);
2009 continue;
2010 }
2011
2012 if (m_wasPaused)
2013 {
2014 LOG(VB_AUDIO, LOG_INFO, LOC + "OutputAudioLoop: Play Event");
2015 Event e(Event::kPlaying);
2016 dispatch(e);
2017 m_wasPaused = false;
2018 }
2019
2020 /* do audio output */
2021 int ready = audioready();
2022
2023 // wait for the buffer to fill with enough to play
2024 if (m_fragmentSize > ready)
2025 {
2026 if (ready > 0) // only log if we're sending some audio
2027 {
2028 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + QString("audio waiting for buffer to fill: "
2029 "have %1 want %2")
2030 .arg(ready).arg(m_fragmentSize));
2031 }
2032
2033 usleep(10ms);
2034 continue;
2035 }
2036
2037#ifdef AUDIOTSTESTING
2038 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + "WriteAudio Start");
2039#endif
2040 Status();
2041
2042 // delay setting raud until after phys buffer is filled
2043 // so GetAudiotime will be accurate without locking
2045 volatile uint next_raud = m_raud;
2046 if (GetAudioData(fragment, m_fragmentSize, true, &next_raud))
2047 {
2049 {
2050 WriteAudio(fragment, m_fragmentSize);
2052 m_raud = next_raud;
2053 }
2054 }
2055#ifdef AUDIOTSTESTING
2056 GetAudiotime();
2057 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + "WriteAudio Done");
2058#endif
2059
2060 }
2061
2062 ::operator delete[] (zeros, std::align_val_t(16));
2063 ::operator delete[] (fragment, std::align_val_t(16));
2064 LOG(VB_AUDIO, LOG_INFO, LOC + "OutputAudioLoop: Stop Event");
2065 Event e(Event::kStopped);
2066 dispatch(e);
2067}
2068
2076int AudioOutputBase::GetAudioData(uchar *buffer, int size, bool full_buffer,
2077 volatile uint *local_raud)
2078{
2079
2080#define LRPOS (&m_audioBuffer[*local_raud])
2081 // re-check audioready() in case things changed.
2082 // for example, ClearAfterSeek() might have run
2083 int avail_size = audioready();
2084 int frag_size = size;
2085 int written_size = size;
2086
2087 if (local_raud == nullptr)
2088 local_raud = &m_raud;
2089
2090 if (!full_buffer && (size > avail_size))
2091 {
2092 // when full_buffer is false, return any available data
2093 frag_size = avail_size;
2094 written_size = frag_size;
2095 }
2096
2097 if (!avail_size || (frag_size > avail_size))
2098 return 0;
2099
2100 int bdiff = kAudioRingBufferSize - m_raud;
2101
2103
2104 if (obytes <= 0)
2105 return 0;
2106
2107 bool fromFloats = m_processing && !m_enc && m_outputFormat != FORMAT_FLT;
2108
2109 // Scale if necessary
2110 if (fromFloats && obytes != sizeof(float))
2111 frag_size *= sizeof(float) / obytes;
2112
2113 int off = 0;
2114
2115 if (bdiff <= frag_size)
2116 {
2117 if (fromFloats)
2118 {
2120 LRPOS, bdiff);
2121 }
2122 else
2123 {
2124 memcpy(buffer, LRPOS, bdiff);
2125 off = bdiff;
2126 }
2127
2128 frag_size -= bdiff;
2129 *local_raud = 0;
2130 }
2131 if (frag_size > 0)
2132 {
2133 if (fromFloats)
2134 {
2136 LRPOS, frag_size);
2137 }
2138 else
2139 {
2140 memcpy(buffer + off, LRPOS, frag_size);
2141 }
2142 }
2143
2144 *local_raud += frag_size;
2145
2146 // Mute individual channels through mono->stereo duplication
2147 MuteState mute_state = GetMuteState();
2148 if (!m_enc && !m_passthru &&
2149 written_size && m_configuredChannels > 1 &&
2150 (mute_state == kMuteLeft || mute_state == kMuteRight))
2151 {
2152 muteChannel(obytes << 3, m_configuredChannels,
2153 mute_state == kMuteLeft ? 0 : 1,
2154 buffer, written_size);
2155 }
2156
2157 return written_size;
2158}
2159
2164{
2165 while (!m_pauseAudio && audioready() > m_fragmentSize)
2166 usleep(1ms);
2167 if (m_pauseAudio)
2168 {
2169 // Audio is paused and can't be drained, clear ringbuffer
2170 QMutexLocker lock(&m_audioBufLock);
2171
2172 m_waud = m_raud = 0;
2173 }
2174}
2175
2180{
2181 RunProlog();
2182 LOG(VB_AUDIO, LOG_INFO, LOC + QString("kickoffOutputAudioLoop: pid = %1").arg(getpid()));
2184 LOG(VB_AUDIO, LOG_INFO, LOC + "kickoffOutputAudioLoop exiting");
2185 RunEpilog();
2186}
2187
2188int AudioOutputBase::readOutputData(unsigned char* /*read_buffer*/, size_t /*max_length*/)
2189{
2190 LOG(VB_GENERAL, LOG_ERR, LOC + "AudioOutputBase should not be getting asked to readOutputData()");
2191 return 0;
2192}
#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:196
static void usleep(std::chrono::microseconds time)
Definition: mthread.cpp:335
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
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:150
bool SWVolume(void) const
Definition: volumebase.cpp:106
bool m_internalVol
Definition: volumebase.h:43
void UpdateVolume(void)
Definition: volumebase.cpp:178
void SyncVolume(void)
Definition: volumebase.cpp:209
void SetChannels(int new_channels)
Definition: volumebase.cpp:218
unsigned int uint
Definition: compat.h:68
static const std::array< const uint64_t, 4 > samples
Definition: element.cpp:46
static guint32 * tmp
Definition: goom_core.cpp:26
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::milliseconds > millisecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
Definition: mythchrono.h:91
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