/
audiooutputbase.h
294 lines (234 loc) · 8.49 KB
/
audiooutputbase.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
#ifndef AUDIOOUTPUTBASE
#define AUDIOOUTPUTBASE
// POSIX headers
#include <sys/time.h> // for struct timeval
// C++ headers
#include <iostream>
using namespace std;
// Qt headers
#include <QString>
#include <QMutex>
#include <QWaitCondition>
// MythTV headers
#include "audiooutput.h"
// external/libsamplerate
#include "samplerate.h"
#include "mythlogging.h"
#include "mthread.h"
#define VBAUDIO(str) LOG(VB_AUDIO, LOG_INFO, LOC + str)
#define VBAUDIOTS(str) LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + str)
#define VBGENERAL(str) LOG(VB_GENERAL, LOG_INFO, LOC + str)
#define VBERROR(str) LOG(VB_GENERAL, LOG_ERR, LOC + str)
#define VBWARN(str) LOG(VB_GENERAL, LOG_WARNING, LOC + str)
#define VBERRENO(str) Error(LOC + str + ": " + ENO)
#define VBERRNOCONST(str) LOG(VB_GENERAL, LOG_ERR, LOC + str + ": " + ENO)
namespace soundtouch {
class SoundTouch;
};
class FreeSurround;
class AudioOutputDigitalEncoder;
struct AVCodecContext;
class AsyncLooseLock
{
public:
AsyncLooseLock() { head = tail = 0; }
void Clear() { head = tail = 0; }
void Ref() { head++; }
bool TestAndDeref() { bool r; if ((r=(head != tail))) tail++; return r; }
private:
int head;
int tail;
};
// Forward declaration of SPDIF encoder
class SPDIFEncoder;
class AudioOutputBase : public AudioOutput, public MThread
{
public:
const char *quality_string(int q);
AudioOutputBase(const AudioSettings &settings);
virtual ~AudioOutputBase();
AudioOutputSettings* GetOutputSettingsCleaned(bool digital = true);
AudioOutputSettings* GetOutputSettingsUsers(bool digital = false);
// reconfigure sound out for new params
virtual void Reconfigure(const AudioSettings &settings);
// dsprate is in 100 * samples/second
virtual void SetEffDsp(int dsprate);
// timestretch
virtual void SetStretchFactor(float factor);
virtual float GetStretchFactor(void) const;
virtual int GetChannels(void) const { return channels; }
virtual AudioFormat GetFormat(void) const { return format; };
virtual int GetBytesPerFrame(void) const { return source_bytes_per_frame; };
virtual bool CanPassthrough(int samplerate, int channels,
int codec, int profile) const;
virtual bool CanDownmix(void) const { return true; };
virtual bool IsUpmixing(void);
virtual bool ToggleUpmix(void);
virtual bool CanUpmix(void);
virtual void Reset(void);
void SetSWVolume(int new_volume, bool save);
int GetSWVolume(void);
// timecode is in milliseconds.
virtual bool AddFrames(void *buffer, int frames, int64_t timecode);
virtual bool AddData(void *buffer, int len, int64_t timecode, int frames);
virtual bool NeedDecodingBeforePassthrough() const { return false; };
virtual int64_t LengthLastData(void) const { return m_length_last_data; }
virtual void SetTimecode(int64_t timecode);
virtual bool IsPaused(void) const { return actually_paused; }
virtual void Pause(bool paused);
void PauseUntilBuffered(void);
// Wait for all data to finish playing
virtual void Drain(void);
virtual int64_t GetAudiotime(void);
virtual int64_t GetAudioBufferedTime(void);
// Send output events showing current progress
virtual void Status(void);
virtual void SetSourceBitrate(int rate);
virtual void GetBufferStatus(uint &fill, uint &total);
// Only really used by the AudioOutputNULL object
virtual void bufferOutputData(bool y){ buffer_output_data_for_use = y; }
virtual int readOutputData(unsigned char *read_buffer, int max_length);
static const uint kAudioSRCInputSize = 16384;
/// Audio Buffer Size -- should be divisible by 32,24,16,12,10,8,6,4,2..
static const uint kAudioRingBufferSize = 3072000u;
protected:
// Following function must be called from subclass constructor
void InitSettings(const AudioSettings &settings);
// You need to implement the following functions
virtual bool OpenDevice(void) = 0;
virtual void CloseDevice(void) = 0;
virtual void WriteAudio(uchar *aubuf, int size) = 0;
/**
* Return the size in bytes of frames currently in the audio buffer adjusted
* with the audio playback latency
*/
virtual int GetBufferedOnSoundcard(void) const = 0;
// Default implementation only supports 2ch s16le at 48kHz
virtual AudioOutputSettings* GetOutputSettings(bool digital)
{ return new AudioOutputSettings; }
// You need to call this from any implementation in the dtor.
void KillAudio(void);
// The following functions may be overridden, but don't need to be
virtual bool StartOutputThread(void);
virtual void StopOutputThread(void);
int GetAudioData(uchar *buffer, int buf_size, bool fill_buffer,
volatile uint *local_raud = NULL);
void OutputAudioLoop(void);
virtual void run();
int CheckFreeSpace(int &frames);
inline int audiolen(); // number of valid bytes in audio buffer
int audiofree(); // number of free bytes in audio buffer
int audioready(); // number of bytes ready to be written
void SetStretchFactorLocked(float factor);
// For audiooutputca
int GetBaseAudBufTimeCode() const { return audbuf_timecode; }
protected:
// Basic details about the audio stream
int channels;
int codec;
int bytes_per_frame;
int output_bytes_per_frame;
AudioFormat format;
AudioFormat output_format;
int samplerate;
//int bitrate;
int effdsp; // from the recorded stream (NuppelVideo)
int fragment_size;
long soundcard_buffer_size;
QString main_device, passthru_device;
bool m_discretedigital;
bool passthru, enc, reenc;
float stretchfactor;
int eff_stretchfactor; // scaled to 100000 as effdsp is
AudioOutputSource source;
bool killaudio;
bool pauseaudio, actually_paused, was_paused, unpause_when_ready;
bool set_initial_vol;
bool buffer_output_data_for_use; // used by AudioOutputNULL
int configured_channels;
int max_channels;
enum
{
QUALITY_DISABLED = -1,
QUALITY_LOW = 0,
QUALITY_MEDIUM = 1,
QUALITY_HIGH = 2,
};
int src_quality;
private:
bool SetupPassthrough(int codec, int codec_profile,
int &samplerate_tmp, int &channels_tmp);
AudioOutputSettings* OutputSettings(bool digital = true);
int CopyWithUpmix(char *buffer, int frames, uint &org_waud);
void SetAudiotime(int frames, int64_t timecode);
AudioOutputSettings *output_settingsraw;
AudioOutputSettings *output_settings;
AudioOutputSettings *output_settingsdigitalraw;
AudioOutputSettings *output_settingsdigital;
bool need_resampler;
SRC_STATE *src_ctx;
soundtouch::SoundTouch *pSoundStretch;
AudioOutputDigitalEncoder *encoder;
FreeSurround *upmixer;
int source_channels;
int source_samplerate;
int source_bytes_per_frame;
bool upmix_default;
bool needs_upmix;
bool needs_downmix;
int surround_mode;
float old_stretchfactor;
int volume;
QString volumeControl;
bool processing;
int64_t frames_buffered;
bool audio_thread_exists;
/**
* Writes to the audiobuffer, reconfigures and audiobuffer resets can only
* take place while holding this lock
*/
QMutex audio_buflock;
/**
* must hold avsync_lock to read or write 'audiotime' and
* 'audiotime_updated'
*/
QMutex avsync_lock;
/**
* timecode of audio leaving the soundcard (same units as timecodes)
*/
int64_t audiotime;
/**
* Audio circular buffer
*/
volatile uint raud, waud; // read and write positions
/**
* timecode of audio most recently placed into buffer
*/
int64_t audbuf_timecode;
AsyncLooseLock reset_active;
QMutex killAudioLock;
long current_seconds;
long source_bitrate;
float *src_in;
// All actual buffers
SRC_DATA src_data;
uint memory_corruption_test0;
float src_in_buf[kAudioSRCInputSize + 16];
uint memory_corruption_test1;
float *src_out;
int kAudioSRCOutputSize;
uint memory_corruption_test2;
/**
* main audio buffer
*/
uchar audiobuffer[kAudioRingBufferSize];
uint memory_corruption_test3;
uint m_configure_succeeded;
int64_t m_length_last_data;
// SPDIF Encoder for digital passthrough
SPDIFEncoder *m_spdifenc;
// Flag indicating if SetStretchFactor enabled audio float processing
bool m_forcedprocessing;
int m_previousbpf;
};
#endif