MythTV master
audiooutputbase.h
Go to the documentation of this file.
1#ifndef AUDIOOUTPUTBASE
2#define AUDIOOUTPUTBASE
3
4// POSIX headers
5#include <sys/time.h> // for struct timeval
6
7#include <samplerate.h> // libsamplerate
8
9// Qt headers
10#include <QString>
11#include <QMutex>
12#include <QWaitCondition>
13
14// MythTV headers
15#include "libmythbase/mthread.h"
16
17#include "audiooutput.h"
18
19namespace soundtouch {
20class SoundTouch;
21};
22class FreeSurround;
24struct AVCodecContext;
25
27{
28public:
29 AsyncLooseLock() = default;
30 void Clear() { m_head = m_tail = 0; }
31 void Ref() { m_head++; }
32 bool TestAndDeref() { bool r = (m_head != m_tail); if (r) m_tail++; return r; }
33private:
34 int m_head {0};
35 int m_tail {0};
36};
37
38// Forward declaration of SPDIF encoder
39class SPDIFEncoder;
40
41class AudioOutputBase : public AudioOutput, public MThread
42{
43 public:
44 static const char *quality_string(int q);
45 explicit AudioOutputBase(const AudioSettings &settings);
46 ~AudioOutputBase() override;
47
48 AudioOutputSettings* GetOutputSettingsCleaned(bool digital = true) override; // AudioOutput
49 AudioOutputSettings* GetOutputSettingsUsers(bool digital = false) override; // AudioOutput
50
51 // reconfigure sound out for new params
52 void Reconfigure(const AudioSettings &settings) override; // AudioOutput
53
54 // dsprate is in 100 * samples/second
55 void SetEffDsp(int dsprate) override; // AudioOutput
56
57 // timestretch
58 void SetStretchFactor(float factor) override; // AudioOutput
59 float GetStretchFactor(void) const override; // AudioOutput
60 int GetChannels(void) const override { return m_channels; } // AudioOutput
61 AudioFormat GetFormat(void) const override { return m_format; }; // AudioOutput
62 int GetBytesPerFrame(void) const override // AudioOutput
63 { return m_sourceBytesPerFrame; }
64
65 bool CanPassthrough(int samplerate, int channels,
66 AVCodecID codec, int profile) const override; // AudioOutput
67 bool CanDownmix(void) const override { return true; } // AudioOutput
68 bool IsUpmixing(void) override; // AudioOutput
69 bool ToggleUpmix(void) override; // AudioOutput
70 bool CanUpmix(void) override; // AudioOutput
71 bool CanProcess(AudioFormat /*fmt*/) override { return true; } // AudioOutput
72 uint32_t CanProcess(void) override // AudioOutput
73 {
74 // we support all codec
75 return ~(((~0ULL) >> FORMAT_FLT) << FORMAT_FLT);
76 }
77
78 void Reset(void) override; // AudioOutput
79
80 void SetSWVolume(int new_volume, bool save) override; // VolumeBase
81 int GetSWVolume(void) override; // VolumeBase
82
83 // timecode is in milliseconds.
84 bool AddFrames(void *buffer, int frames, std::chrono::milliseconds timecode) override; // AudioOutput
85 bool AddData(void *buffer, int len, std::chrono::milliseconds timecode, int frames) override; // AudioOutput
86 bool NeedDecodingBeforePassthrough() const override { return false; }; // AudioOutput
87 std::chrono::milliseconds LengthLastData(void) const override { return m_lengthLastData; } // AudioOutput
88
89 void SetTimecode(std::chrono::milliseconds timecode) override; // AudioOutput
90 bool IsPaused(void) const override { return m_actuallyPaused; } // AudioOutput
91 void Pause(bool paused) override; // AudioOutput
92 void PauseUntilBuffered(void) override; // AudioOutput
93
94 // Wait for all data to finish playing
95 void Drain(void) override; // AudioOutput
96
97 std::chrono::milliseconds GetAudiotime(void) override; // AudioOutput
98 std::chrono::milliseconds GetAudioBufferedTime(void) override; // AudioOutput
99
100 // Send output events showing current progress
101 virtual void Status(void);
102
103 void SetSourceBitrate(int rate) override; // AudioOutput
104
105 void GetBufferStatus(uint &fill, uint &total) override; // AudioOutput
106
107 // Only really used by the AudioOutputNULL object
108 void bufferOutputData(bool y) override // AudioOutput
110 int readOutputData(unsigned char *read_buffer, size_t max_length) override; // AudioOutput
111
112 static const uint kAudioSRCInputSize = 16384;
113
115 // In other words, divisible by 96.
116 static const uint kAudioRingBufferSize = 10239936U;
117
118 bool has_optimized_SIMD() override; // AudioOutput
119
120 protected:
121 // Following function must be called from subclass constructor
122 void InitSettings(const AudioSettings &settings);
123
124 // You need to implement the following functions
125 virtual bool OpenDevice(void) = 0;
126 virtual void CloseDevice(void) = 0;
127 virtual void WriteAudio(unsigned char *aubuf, int size) = 0;
132 virtual int GetBufferedOnSoundcard(void) const = 0;
133 // Default implementation only supports 2ch s16le at 48kHz
134 virtual AudioOutputSettings* GetOutputSettings(bool /*digital*/)
135 { return new AudioOutputSettings; }
136 // You need to call this from any implementation in the dtor.
137 void KillAudio(void);
138
139 // The following functions may be overridden, but don't need to be
140 virtual bool StartOutputThread(void);
141 virtual void StopOutputThread(void);
142
143 int GetAudioData(uchar *buffer, int buf_size, bool full_buffer,
144 volatile uint *local_raud = nullptr);
145
146 void OutputAudioLoop(void);
147
148 void run() override; // MThread
149
150 int CheckFreeSpace(int &frames);
151
152 inline int audiolen() const; // number of valid bytes in audio buffer
153 int audiofree() const; // number of free bytes in audio buffer
154 int audioready() const; // number of bytes ready to be written
155
156 void SetStretchFactorLocked(float factor);
157
158 // For audiooutputca
159 std::chrono::milliseconds GetBaseAudBufTimeCode() const
160 { return m_audbufTimecode; }
161
162 bool usesSpdif() const { return m_usesSpdif; }
163
164 protected:
165 // Basic details about the audio stream
166 int m_channels {-1};
167 AVCodecID m_codec {AV_CODEC_ID_NONE};
172 int m_sampleRate {-1};
173 int m_effDsp {0}; // from the recorded stream (NuppelVideo)
176
179 bool m_discreteDigital {false};
180
181 bool m_passthru {false};
182 bool m_enc {false};
183 bool m_reEnc {false};
184
185 float m_stretchFactor {1.0F};
186 int m_effStretchFactor {100000}; // scaled to 100000 ase ffdsp is
188
189 bool m_killAudio {false};
190
191 bool m_pauseAudio {false};
192 bool m_actuallyPaused {false};
193 bool m_wasPaused {false};
194 bool m_unpauseWhenReady {false};
196 bool m_bufferOutputDataForUse {false}; // used by AudioOutputNULL
197
200 enum : std::int8_t
201 {
206 };
210
211 private:
212 bool SetupPassthrough(AVCodecID codec, int codec_profile,
213 int &samplerate_tmp, int &channels_tmp);
214 AudioOutputSettings* OutputSettings(bool digital = true);
215 int CopyWithUpmix(char *buffer, int frames, uint &org_waud);
216 void SetAudiotime(int frames, std::chrono::milliseconds timecode);
221 bool m_needResampler {false};
222 SRC_STATE *m_srcCtx {nullptr};
223 soundtouch::SoundTouch *m_pSoundStretch {nullptr};
226
229 bool m_upmixDefault {false};
230 bool m_needsUpmix {false};
231 bool m_needsDownmix {false};
233 float m_oldStretchFactor {1.0F};
234 int m_volume {80};
236
237 bool m_processing {false};
238
239 int64_t m_framesBuffered {0};
240
242
248
254
258 std::chrono::milliseconds m_audioTime {0ms};
259
263 volatile uint m_raud {0}; // read position
264 volatile uint m_waud {0}; // write position
268 std::chrono::milliseconds m_audbufTimecode {0ms};
270
272
273 std::chrono::seconds m_currentSeconds {-1s};
274
275 float *m_srcIn;
276
277 // All actual buffers
278 SRC_DATA m_srcData {};
279 [[maybe_unused]] uint m_memoryCorruptionTest0 {0xdeadbeef};
280 alignas(16) std::array<float,kAudioSRCInputSize> m_srcInBuf {};
281 [[maybe_unused]] uint m_memoryCorruptionTest1 {0xdeadbeef};;
282 float *m_srcOut {nullptr};
284 [[maybe_unused]] uint m_memoryCorruptionTest2 {0xdeadbeef};;
288 std::array<uchar,kAudioRingBufferSize> m_audioBuffer {0};
289 [[maybe_unused]] uint m_memoryCorruptionTest3 {0xdeadbeef};;
290 std::chrono::milliseconds m_lengthLastData {0ms};
291
292 // SPDIF Encoder for digital passthrough
293 bool m_usesSpdif {true};
295
296 // Flag indicating if SetStretchFactor enabled audio float processing
297 bool m_forcedProcessing {false};
299};
300
301#endif
@ FORMAT_NONE
@ FORMAT_FLT
AudioOutputSource
Definition: audiosettings.h:21
AsyncLooseLock()=default
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.
QString m_passthruDevice
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)
int GetBytesPerFrame(void) const override
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
uint32_t CanProcess(void) override
AudioFormat m_outputFormat
bool IsPaused(void) const override
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)
std::chrono::milliseconds GetBaseAudBufTimeCode() const
AudioFormat GetFormat(void) const override
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.
bool CanProcess(AudioFormat) override
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.
int GetChannels(void) const override
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.
bool CanDownmix(void) const override
virtual void CloseDevice(void)=0
AudioOutputSettings * m_outputSettingsDigital
void run() override
Main routine for the output thread.
SPDIFEncoder * m_spdifEnc
void bufferOutputData(bool y) override
FreeSurround * m_upmixer
bool NeedDecodingBeforePassthrough() const override
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
std::chrono::milliseconds LengthLastData(void) const override
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
const int & channels() const
Definition: audiooutput.h:254
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:49
unsigned int uint
Definition: compat.h:68