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