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