1 // Copyright 2004 "Gilles Degottex"
2 
3 // This file is part of "Music"
4 
5 // "Music" is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation; either version 2.1 of the License, or
8 // (at your option) any later version.
9 //
10 // "Music" is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 
19 
20 #ifndef _CaptureThread_h_
21 #define _CaptureThread_h_
22 
23 #include <deque>
24 #include <vector>
25 using namespace std;
26 #include <qobject.h>
27 #include <qthread.h>
28 #include <qmutex.h>
29 
30 class CaptureThread;
31 
32 // ----------------------- the implementations ----------------------
33 
34 class CaptureThreadImpl;
35 
36 void AddValue2ChannelFirst(CaptureThreadImpl* impl, double value, int i);
37 void AddValue2ChannelMix(CaptureThreadImpl* impl, double value, int i);
38 void AddValue1Channel(CaptureThreadImpl* impl, double value, int i);
39 
40 class CaptureThreadImpl
41 {
42 	friend class CaptureThread;
43 	friend void AddValue2ChannelFirst(CaptureThreadImpl* impl, double value, int i);
44 	friend void AddValue2ChannelMix(CaptureThreadImpl* impl, double value, int i);
45 	friend void AddValue1Channel(CaptureThreadImpl* impl, double value, int i);
46 
47   protected:
48 	CaptureThread* m_capture_thread;
49 	QString m_name;
50 	QString m_descr;
51 
52 	int m_sampling_rate;
53 	QString m_source;
54 	QString m_status;
55 
56 	int m_format_size;
57 	bool m_format_signed;
58 	bool m_format_float;
59 	int m_channel_count;
60 
61 	virtual void setSamplingRate(int rate)=0;
62 	virtual void startCapture()=0;
63 	virtual void stopCapture()=0;
64 	virtual bool is_available()=0;
65 
66     double m_tmp_value; // used when two channels have to be mixed down
67 	double (*decodeValue)(void* buffer, int i); // not used for JACK
68 	void (*addValue)(CaptureThreadImpl* impl, double value, int i);
69 	void setFormatDescrsAndFns(int format_size, bool format_signed, bool format_float, int channel_count);
70 
71   public:
72 	CaptureThreadImpl(CaptureThread* capture_thread, const QString& name, const QString& descr);
73 
74 	const QString& getStatus();
75 
getName()76 	const QString& getName() const {return m_name;}
getDescription()77 	const QString& getDescription() const {return m_descr;}
getSource()78 	const QString& getSource() const {return m_source;}
79     QString getASCIISource() const;
80 
~CaptureThreadImpl()81 	virtual ~CaptureThreadImpl(){}
82 };
83 
84 // ---------------------- the Qt implementation ---------------------
85 
86 #ifdef CAPTURE_QT
87 #include <QAudioDeviceInfo>
88 #include <QAudioInput>
89 class CaptureThreadImplQt : public QObject, public CaptureThreadImpl
90 {
91     Q_OBJECT
92 
93     void set_params(bool test=false);
94 
95     void capture_init();
96     void capture_finished();
97 
98     const QList<QAudioDeviceInfo> m_availableAudioInputDevices;
99     QAudioDeviceInfo    m_audioInputDevice;
100     QAudioInput*        m_audioInput;
101     QIODevice*          m_audioInputIODevice;
102 
103     QAudio::State       m_state;
104 
105     QAudioFormat        m_format;
106 
107   public:
108     CaptureThreadImplQt(CaptureThread* capture_thread);
109 
110     virtual void setSamplingRate(int rate);
111     virtual void startCapture();
112     virtual void stopCapture();
113     virtual bool is_available();
114 
115     ~CaptureThreadImplQt();
116 
117 public slots:
118     void audioStateChanged(QAudio::State state);
119     void audioDataReady();
120 };
121 #endif
122 
123 // ---------------------- the ALSA implementation ---------------------
124 
125 #ifdef CAPTURE_ALSA
126 #include <alsa/asoundlib.h>
127 class CaptureThreadImplALSA : public CaptureThreadImpl, public QThread
128 {
129 	snd_pcm_t* m_alsa_capture_handle;
130 	snd_pcm_hw_params_t* m_alsa_hw_params;
131 	char* m_alsa_buffer;
132 	snd_pcm_format_t m_format;
133 
134 	// view
135 	volatile bool m_alive;
136 	volatile bool m_in_run;
137 
138 	// control
139 	volatile bool m_loop;
140 	volatile bool m_wait_for_start;
141 
142 	void set_params(bool test=false);
143 	void capture_init();
144 	void capture_loop();
145 	void capture_finished();
146 
147 	virtual void run();
148 
149   public:
150 	CaptureThreadImplALSA(CaptureThread* capture_thread);
151 
152 	virtual void setSamplingRate(int rate);
153 	virtual void startCapture();
154 	virtual void stopCapture();
155 	virtual bool is_available();
156 
157 	~CaptureThreadImplALSA();
158 };
159 #endif
160 
161 // ---------------------- the JACK implementation ---------------------
162 
163 #ifdef CAPTURE_JACK
164 #include <jack/jack.h>
165 #include <jack/ringbuffer.h>
166 class CaptureThreadImplJACK : public CaptureThreadImpl, public QThread
167 {
168 	static int JackProcess(jack_nframes_t nframes, void* arg);
169 	static void JackShutdown(void* arg);
170 	static int JackSampleRate(jack_nframes_t nframes, void* arg);
171 
172     jack_ringbuffer_t* m_ringbuffer;
173 	jack_client_t* m_jack_client;
174 	jack_port_t* m_jack_port;
175 	int jackSampleRate(jack_nframes_t nframes);
176 	int jackProcess(jack_nframes_t nframes);
177 	void jackShutdown();
178 
179     // view
180     volatile bool m_alive;
181     volatile bool m_in_run;
182 
183     // control
184     volatile bool m_loop;
185     volatile bool m_wait_for_start;
186 
187     void capture_init();
188     void capture_loop();
189 	void capture_finished();
190 
191     virtual void run();
192 
193   public:
194 	CaptureThreadImplJACK(CaptureThread* capture_thread);
195 
196 	virtual void setSamplingRate(int rate);
197 	virtual void startCapture();
198 	virtual void stopCapture();
199 	virtual bool is_available();
200 
201     ~CaptureThreadImplJACK();
202 };
203 #endif
204 
205 // ---------------------- the PortAudio implementation ---------------------
206 
207 #ifdef CAPTURE_PORTAUDIO
208 #include <portaudio.h>
209 class CaptureThreadImplPortAudio : public CaptureThreadImpl
210 {
211 	static int PortAudioCallback( const void *inputBuffer, void *outputBuffer,
212 							   unsigned long framesPerBuffer,
213 							   const PaStreamCallbackTimeInfo* timeInfo,
214 							   PaStreamCallbackFlags statusFlags,
215 							   void *userData );
216 
217 	int portAudioCallback(const void *inputBuffer,
218 						  unsigned long framesPerBuffer,
219 						  const PaStreamCallbackTimeInfo* timeInfo,
220 						  PaStreamCallbackFlags statusFlags);
221 
222 	PaStream* m_stream;
223 	PaError m_err;
224 
225 	void set_params(bool test=false);
226 	virtual void capture_init();
227 	virtual void capture_finished();
228 
229   public:
230 	CaptureThreadImplPortAudio(CaptureThread* capture_thread);
231 
232 	virtual void setSamplingRate(int rate);
233 	virtual void startCapture();
234 	virtual void stopCapture();
235 	virtual bool is_available();
236 
237 	virtual ~CaptureThreadImplPortAudio();
238 };
239 #endif
240 
241 // ---------------------- the OSS implementation ---------------------
242 
243 #ifdef CAPTURE_OSS
244 class CaptureThreadImplOSS : public CaptureThreadImpl, public QThread
245 {
246 	int m_fd_in;
247 	char* m_oss_buffer;
248 	int m_format;
249 
250 	// view
251 	volatile bool m_alive;
252 	volatile bool m_in_run;
253 
254 	// control
255 	volatile bool m_loop;
256 	volatile bool m_wait_for_start;
257 
258 	void set_params(bool test=false);
259 	void capture_init();
260 	void capture_loop();
261 	void capture_finished();
262 
263 	virtual void run();
264 
265   public:
266 	CaptureThreadImplOSS(CaptureThread* capture_thread);
267 
268 	virtual void setSamplingRate(int rate);
269 	virtual void startCapture();
270 	virtual void stopCapture();
271 	virtual bool is_available();
272 
273 	~CaptureThreadImplOSS();
274 };
275 #endif
276 
277 // --------------------- the real accessible thread -------------------------
278 
279 class CaptureThread : public QObject
280 {
281 	Q_OBJECT
282 
283 	friend class CaptureThreadImpl;
284 #ifdef CAPTURE_QT
285     friend class CaptureThreadImplQt;
286 #endif
287 #ifdef CAPTURE_ALSA
288 	friend class CaptureThreadImplALSA;
289 #endif
290 #ifdef CAPTURE_JACK
291 	friend class CaptureThreadImplJACK;
292 #endif
293 #ifdef CAPTURE_PORTAUDIO
294 	friend class CaptureThreadImplPortAudio;
295 #endif
296 #ifdef CAPTURE_OSS
297 	friend class CaptureThreadImplOSS;
298 #endif
299 
300 	vector<CaptureThreadImpl*> m_impls;
301 	CaptureThreadImpl* m_current_impl;
302 
303 	void emitError(const QString& error);
304 	void emitSamplingRateChanged();
305 	void emitCaptureStarted();
306 	void emitCaptureStoped();
307 	void emitCaptureToggled(bool value);
308 
309 	bool m_capturing;
310 
311 	int m_packet_size;
312 	int m_packet_size_sll;
313 	QString m_name;
314 
315 	// control
316 	volatile bool m_pause;
317 	bool m_mix_multiple_channel;
318 
319 	QMutex m_lock;
320 	bool m_ext_lock;
321 
322   public:
323 
324 	deque<double> m_values;
325 
326 	enum {SAMPLING_RATE_UNKNOWN=-1, SAMPLING_RATE_MAX=0};
327 
328 	CaptureThread(const QString& name="bastard_thread");
329 
lock()330 	void lock()						{m_lock.lock(); m_ext_lock=true;}
unlock()331 	void unlock()					{m_lock.unlock();}
332 
isCapturing()333 	bool isCapturing() const						{return m_capturing;}
334 	int getSamplingRate() const;
getPacketSize()335 	int getPacketSize() const						{return m_packet_size;}
getPacketSizeSinceLastLock()336 	int getPacketSizeSinceLastLock() const			{return m_packet_size_sll;}
getNbPendingData()337     int getNbPendingData() const					{return int(m_values.size());}
338 	const CaptureThreadImpl* getCurrentTransport() const;
339 	int getCurrentTransportIndex() const;
340 	QString getCurrentTransportDescr() const;
341 	QString getFormatDescr() const;
342 	const vector<CaptureThreadImpl*>& getTransports() const;
343 	const CaptureThreadImpl* getTransport(const QString& name) const;
344 	void listTransports();
345 
346 	virtual ~CaptureThread();
347 
348   signals:
349 	void samplingRateChanged(int sampling_rate);
350 	void portNameChanged(const QString& name);
351 	void sourceChanged(const QString& src);
352 	void transportChanged(const QString& name);
353 	void captureStarted();
354 	void captureStoped();
355 	void captureToggled(bool run);
356 	void errorRaised(const QString& error);
357 
358   public slots:
359 	//! auto detect a working transport
360 	void autoDetectTransport();
361 	//! select a specific transport
362 	void selectTransport(const QString& name);
363 	//! select a specific transport
364 	void selectTransport(int index);
365 	//! reset capture (stop/start)
366 	void reset();
367 	//! start capture
368 	void startCapture();
369 	//! stop capture
370 	void stopCapture();
371 	//! set capture status
372 	void toggleCapture(bool run);
373 	//! set pause status
374 	/*! keep capture system connected, but throw away all incoming data
375 	 */
376 	void togglePause(bool pause);
377 
378 	//! set the sampling rate
379 	/*! not always available, depending on the implementation
380 	 * (reset the capture system !)
381 	 */
382 	void setSamplingRate(int value);
383 	//! the source name
384 	/*! 'hw:0' for example for ALSA, something like alsa_pcm:capture_1 for JACK
385 	 * (reset the capture system !)
386 	 */
387 	void setSource(const QString& src);
388 
389 	void setMixMultipleChannels(bool mix);
390 };
391 
392 #endif // _CaptureThread_h_
393