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 // Qt headers
8 #include <QString>
9 #include <QMutex>
10 #include <QWaitCondition>
11 
12 // MythTV headers
13 #include "audiooutput.h"
14 #include "mythlogging.h"
15 #include "mthread.h"
16 
17 #include "samplerate.h"
18 
19 #define VBAUDIO(str) LOG(VB_AUDIO, LOG_INFO, LOC + (str))
20 #define VBAUDIOTS(str) LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + (str))
21 #define VBGENERAL(str) LOG(VB_GENERAL, LOG_INFO, LOC + (str))
22 #define VBERROR(str) LOG(VB_GENERAL, LOG_ERR, LOC + (str))
23 #define VBWARN(str) LOG(VB_GENERAL, LOG_WARNING, LOC + (str))
24 #define VBERRENO(str) Error(LOC + (str) + ": " + ENO)
25 #define VBERRNOCONST(str) LOG(VB_GENERAL, LOG_ERR, LOC + (str) + ": " + ENO)
26 
27 namespace soundtouch {
28 class SoundTouch;
29 };
30 class FreeSurround;
32 struct AVCodecContext;
33 
35 {
36 public:
37  AsyncLooseLock() = default;
38  void Clear() { m_head = m_tail = 0; }
39  void Ref() { m_head++; }
40  bool TestAndDeref() { bool r; if ((r=(m_head != m_tail))) m_tail++; return r; }
41 private:
42  int m_head {0};
43  int m_tail {0};
44 };
45 
46 // Forward declaration of SPDIF encoder
47 class SPDIFEncoder;
48 
49 class AudioOutputBase : public AudioOutput, public MThread
50 {
51  public:
52  static const char *quality_string(int q);
53  explicit AudioOutputBase(const AudioSettings &settings);
54  ~AudioOutputBase() override;
55 
56  AudioOutputSettings* GetOutputSettingsCleaned(bool digital = true) override; // AudioOutput
57  AudioOutputSettings* GetOutputSettingsUsers(bool digital = false) override; // AudioOutput
58 
59  // reconfigure sound out for new params
60  void Reconfigure(const AudioSettings &settings) override; // AudioOutput
61 
62  // dsprate is in 100 * samples/second
63  void SetEffDsp(int dsprate) override; // AudioOutput
64 
65  // timestretch
66  void SetStretchFactor(float factor) override; // AudioOutput
67  float GetStretchFactor(void) const override; // AudioOutput
68  int GetChannels(void) const override { return m_channels; } // AudioOutput
69  AudioFormat GetFormat(void) const override { return m_format; }; // AudioOutput
70  int GetBytesPerFrame(void) const override // AudioOutput
71  { return m_source_bytes_per_frame; }
72 
73  bool CanPassthrough(int samplerate, int channels,
74  AVCodecID codec, int profile) const override; // AudioOutput
75  bool CanDownmix(void) const override { return true; } // AudioOutput
76  bool IsUpmixing(void) override; // AudioOutput
77  bool ToggleUpmix(void) override; // AudioOutput
78  bool CanUpmix(void) override; // AudioOutput
79  bool CanProcess(AudioFormat /*fmt*/) override { return true; } // AudioOutput
80  uint32_t CanProcess(void) override // AudioOutput
81  {
82  // we support all codec
83  return ~(((~0ULL) >> FORMAT_FLT) << FORMAT_FLT);
84  }
85 
86  void Reset(void) override; // AudioOutput
87 
88  void SetSWVolume(int new_volume, bool save) override; // VolumeBase
89  int GetSWVolume(void) override; // VolumeBase
90 
91  // timecode is in milliseconds.
92  bool AddFrames(void *buffer, int frames, int64_t timecode) override; // AudioOutput
93  bool AddData(void *buffer, int len, int64_t timecode, int frames) override; // AudioOutput
94  bool NeedDecodingBeforePassthrough() const override { return false; }; // AudioOutput
95  int64_t LengthLastData(void) const override { return m_length_last_data; } // AudioOutput
96 
97  void SetTimecode(int64_t timecode) override; // AudioOutput
98  bool IsPaused(void) const override { return m_actually_paused; } // AudioOutput
99  void Pause(bool paused) override; // AudioOutput
100  void PauseUntilBuffered(void) override; // AudioOutput
101 
102  // Wait for all data to finish playing
103  void Drain(void) override; // AudioOutput
104 
105  int64_t GetAudiotime(void) override; // AudioOutput
106  int64_t GetAudioBufferedTime(void) override; // AudioOutput
107 
108  // Send output events showing current progress
109  virtual void Status(void);
110 
111  void SetSourceBitrate(int rate) override; // AudioOutput
112 
113  void GetBufferStatus(uint &fill, uint &total) override; // AudioOutput
114 
115  // Only really used by the AudioOutputNULL object
116  void bufferOutputData(bool y) override // AudioOutput
118  int readOutputData(unsigned char *read_buffer, int max_length) override; // AudioOutput
119 
120  static const uint kAudioSRCInputSize = 16384;
121 
123  // In other words, divisible by 96.
124  static const uint kAudioRingBufferSize = 10239936U;
125 
126  protected:
127  // Following function must be called from subclass constructor
128  void InitSettings(const AudioSettings &settings);
129 
130  // You need to implement the following functions
131  virtual bool OpenDevice(void) = 0;
132  virtual void CloseDevice(void) = 0;
133  virtual void WriteAudio(unsigned char *aubuf, int size) = 0;
138  virtual int GetBufferedOnSoundcard(void) const = 0;
139  // Default implementation only supports 2ch s16le at 48kHz
140  virtual AudioOutputSettings* GetOutputSettings(bool /*digital*/)
141  { return new AudioOutputSettings; }
142  // You need to call this from any implementation in the dtor.
143  void KillAudio(void);
144 
145  // The following functions may be overridden, but don't need to be
146  virtual bool StartOutputThread(void);
147  virtual void StopOutputThread(void);
148 
149  int GetAudioData(uchar *buffer, int buf_size, bool full_buffer,
150  volatile uint *local_raud = nullptr);
151 
152  void OutputAudioLoop(void);
153 
154  void run() override; // MThread
155 
156  int CheckFreeSpace(int &frames);
157 
158  inline int audiolen() const; // number of valid bytes in audio buffer
159  int audiofree() const; // number of free bytes in audio buffer
160  int audioready() const; // number of bytes ready to be written
161 
162  void SetStretchFactorLocked(float factor);
163 
164  // For audiooutputca
165  int GetBaseAudBufTimeCode() const { return m_audbuf_timecode; }
166 
167  bool usesSpdif() const { return m_usesSpdif; }
168 
169  protected:
170  // Basic details about the audio stream
171  int m_channels {-1};
172  AVCodecID m_codec {AV_CODEC_ID_NONE};
177  int m_samplerate {-1};
178  //int m_bitrate;
179  int m_effdsp {0}; // from the recorded stream (NuppelVideo)
182 
183  QString m_main_device;
185  bool m_discretedigital {false};
186 
187  bool m_passthru {false};
188  bool m_enc {false};
189  bool m_reenc {false};
190 
191  float m_stretchfactor {1.0F};
192  int m_eff_stretchfactor {100000}; // scaled to 100000 ase ffdsp is
194 
195  bool m_killaudio {false};
196 
197  bool m_pauseaudio {false};
198  bool m_actually_paused {false};
199  bool m_was_paused {false};
200  bool m_unpause_when_ready {false};
202  bool m_buffer_output_data_for_use {false}; // used by AudioOutputNULL
203 
205  int m_max_channels {0};
206  enum
207  {
212  };
214  long m_source_bitrate {-1};
216 
217  private:
218  bool SetupPassthrough(AVCodecID codec, int codec_profile,
219  int &samplerate_tmp, int &channels_tmp);
220  AudioOutputSettings* OutputSettings(bool digital = true);
221  int CopyWithUpmix(char *buffer, int frames, uint &org_waud);
222  void SetAudiotime(int frames, int64_t timecode);
227  bool m_need_resampler {false};
228  SRC_STATE *m_src_ctx {nullptr};
229  soundtouch::SoundTouch *m_pSoundStretch {nullptr};
232 
235  bool m_upmix_default {false};
236  bool m_needs_upmix {false};
237  bool m_needs_downmix {false};
239  float m_old_stretchfactor {1.0F};
240  int m_volume {80};
242 
243  bool m_processing {false};
244 
245  int64_t m_frames_buffered {0};
246 
247  bool m_audio_thread_exists {false};
248 
254 
260 
264  int64_t m_audiotime {0};
265 
269  volatile uint m_raud {0}; // read position
270  volatile uint m_waud {0}; // write position
274  int64_t m_audbuf_timecode {0};
276 
277  QMutex m_killAudioLock {QMutex::NonRecursive};
278 
279  long m_current_seconds {-1};
280 
281  float *m_src_in;
282 
283  // All actual buffers
284  SRC_DATA m_src_data {};
288  float *m_src_out {nullptr};
296  bool m_configure_succeeded {false};
297  int64_t m_length_last_data {0};
298 
299  // SPDIF Encoder for digital passthrough
300  bool m_usesSpdif {true};
302 
303  // Flag indicating if SetStretchFactor enabled audio float processing
304  bool m_forcedprocessing {false};
305  int m_previousbpf {0};
306 };
307 
308 #endif
virtual void WriteAudio(unsigned char *aubuf, int size)=0
virtual void CloseDevice(void)=0
AsyncLooseLock()=default
static const uint kAudioRingBufferSize
Audio Buffer Size – should be divisible by 32,24,16,12,10,8,6,4,2..
void bufferOutputData(bool y) override
void InitSettings(const AudioSettings &settings)
virtual bool OpenDevice(void)=0
bool IsPaused(void) const override
QMutex m_audio_buflock
Writes to the audiobuffer, reconfigures and audiobuffer resets can only take place while holding this...
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:46
QMutex m_avsync_lock
must hold avsync_lock to read or write 'audiotime' and 'audiotime_updated'
void SetStretchFactor(float factor) override
Set the timestretch factor.
volatile uint m_raud
Audio circular buffer.
virtual int GetBufferedOnSoundcard(void) const =0
Return the size in bytes of frames currently in the audio buffer adjusted with the audio playback lat...
virtual void StopOutputThread(void)
bool ToggleUpmix(void) override
Toggle between stereo and upmixed 5.1 if the source material is stereo.
bool AddData(void *buffer, int len, int64_t timecode, int frames) override
Add data to the audiobuffer and perform any required processing.
int GetAudioData(uchar *buffer, int buf_size, bool full_buffer, volatile uint *local_raud=nullptr)
Copy frames from the audiobuffer into the buffer provided.
int64_t GetAudioBufferedTime(void) override
Get the difference in timecode between the samples that are about to become audible and the samples m...
unsigned int uint
Definition: compat.h:140
bool NeedDecodingBeforePassthrough() const override
int64_t GetAudiotime(void) override
Calculate the timecode of the samples that are about to become audible.
int audiofree() const
Get the free space in the audiobuffer in bytes.
SRC_STATE * m_src_ctx
uchar m_audiobuffer[kAudioRingBufferSize]
main audio buffer
int64_t m_audiotime
timecode of audio leaving the soundcard (same units as timecodes)
AudioFormat m_format
int GetBaseAudBufTimeCode() const
AudioOutputSource source
AudioOutputBase(const AudioSettings &settings)
volatile uint m_waud
unsigned char r
Definition: ParseText.cpp:329
void OutputAudioLoop(void)
Run in the output thread, write frames to the output device as they become available and there's spac...
void Reset(void) override
Reset the audiobuffer, timecode and mythmusic visualisation.
QString m_passthru_device
bool IsUpmixing(void) override
Source is currently being upmixed.
int64_t m_audbuf_timecode
timecode of audio most recently placed into buffer
void SetSWVolume(int new_volume, bool save) override
Set the volume for software volume control.
bool CanUpmix(void) override
Upmixing of the current source is available if requested.
int audiolen() const
Get the number of bytes in the audiobuffer.
void SetSourceBitrate(int rate) override
Set the bitrate of the source material, reported in periodic OutputEvents.
AudioOutputSettings * m_output_settingsdigital
AudioOutputSettings * OutputSettings(bool digital=true)
bool CanProcess(AudioFormat) override
uint m_memory_corruption_test3
void SetTimecode(int64_t timecode) override
Set the timecode of the samples most recently added to the audiobuffer.
bool usesSpdif() const
int64_t LengthLastData(void) const override
uint m_memory_corruption_test0
int GetSWVolume(void) override
Get the volume for software volume control.
AudioFormat m_output_format
uint m_memory_corruption_test1
virtual void Status(void)
Report status via an OutputEvent.
AudioOutputSettings * GetOutputSettingsUsers(bool digital=false) override
Returns capabilities supported by the audio device amended to take into account the digital audio opt...
AudioFormat GetFormat(void) const override
int GetBytesPerFrame(void) 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.
float m_src_in_buf[kAudioSRCInputSize+16]
bool SetupPassthrough(AVCodecID codec, int codec_profile, int &samplerate_tmp, int &channels_tmp)
bool m_buffer_output_data_for_use
uint m_memory_corruption_test2
void SetAudiotime(int frames, int64_t timecode)
Set the timecode of the top of the ringbuffer Exclude all other processing elements as they dont vary...
FreeSurround * m_upmixer
AudioOutputSource
Definition: audiosettings.h:17
static const uint kAudioSRCInputSize
void PauseUntilBuffered(void) override
virtual bool StartOutputThread(void)
int64_t m_frames_buffered
AudioOutputSettings * m_output_settings
AudioOutputSettings * GetOutputSettingsCleaned(bool digital=true) override
Returns capabilities supported by the audio device amended to take into account the digital audio opt...
void Pause(bool paused) override
void KillAudio(void)
Kill the output thread and cleanup.
void Reconfigure(const AudioSettings &settings) override
(Re)Configure AudioOutputBase
int CheckFreeSpace(int &frames)
Check that there's enough space in the audiobuffer to write the provided number of frames.
SPDIFEncoder * m_spdifenc
bool AddFrames(void *buffer, int frames, int64_t timecode) override
Add frames to the audiobuffer and perform any required processing.
int CopyWithUpmix(char *buffer, int frames, uint &org_waud)
Copy frames into the audiobuffer, upmixing en route if necessary.
soundtouch::SoundTouch * m_pSoundStretch
AsyncLooseLock m_reset_active
AudioOutputSettings * m_output_settingsraw
virtual AudioOutputSettings * GetOutputSettings(bool)
void SetEffDsp(int dsprate) override
Set the effective DSP rate.
~AudioOutputBase() override
Destructor.
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.
const char * frames[3]
Definition: element.c:46
void Drain(void) override
Block until all available frames have been written to the device.
static const char * quality_string(int q)
AudioOutputDigitalEncoder * m_encoder
void run() override
Main routine for the output thread.
float GetStretchFactor(void) const override
Get the timetretch factor.
int audioready() const
Get the scaled number of bytes in the audiobuffer, i.e.
uint32_t CanProcess(void) override
int GetChannels(void) const override
void SetStretchFactorLocked(float factor)
Set the timestretch factor.
int64_t m_length_last_data
AudioOutputSettings * m_output_settingsdigitalraw
int readOutputData(unsigned char *read_buffer, int max_length) override
bool CanDownmix(void) const override