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