Release version 0.99.2-1
[fmit.git] / src / CaptureThread.h
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
76         const QString& getName() const {return m_name;}
77         const QString& getDescription() const {return m_descr;}
78         const QString& getSource() const {return m_source;}
79
80         virtual ~CaptureThreadImpl(){}
81 };
82
83 // ---------------------- the ALSA implementation ---------------------
84
85 #ifdef CAPTURE_ALSA
86 #include <alsa/asoundlib.h>
87 class CaptureThreadImplALSA : public CaptureThreadImpl, public QThread
88 {
89         snd_pcm_t* m_alsa_capture_handle;
90         snd_pcm_hw_params_t* m_alsa_hw_params;
91         char* m_alsa_buffer;
92         snd_pcm_format_t m_format;
93
94         // view
95         volatile bool m_alive;
96         volatile bool m_in_run;
97
98         // control
99         volatile bool m_loop;
100         volatile bool m_wait_for_start;
101
102         void set_params(bool test=false);
103         void capture_init();
104         void capture_loop();
105         void capture_finished();
106
107         virtual void run();
108
109   public:
110         CaptureThreadImplALSA(CaptureThread* capture_thread);
111
112         virtual void setSamplingRate(int rate);
113         virtual void startCapture();
114         virtual void stopCapture();
115         virtual bool is_available();
116
117         ~CaptureThreadImplALSA();
118 };
119 #endif
120
121 // ---------------------- the JACK implementation ---------------------
122
123 #ifdef CAPTURE_JACK
124 #include <jack/jack.h>
125 #include <jack/ringbuffer.h>
126 class CaptureThreadImplJACK : public CaptureThreadImpl, public QThread
127 {
128         static int JackProcess(jack_nframes_t nframes, void* arg);
129         static void JackShutdown(void* arg);
130         static int JackSampleRate(jack_nframes_t nframes, void* arg);
131
132     jack_ringbuffer_t* m_ringbuffer;
133         jack_client_t* m_jack_client;
134         jack_port_t* m_jack_port;
135         int jackSampleRate(jack_nframes_t nframes);
136         int jackProcess(jack_nframes_t nframes);
137         void jackShutdown();
138
139     // view
140     volatile bool m_alive;
141     volatile bool m_in_run;
142
143     // control
144     volatile bool m_loop;
145     volatile bool m_wait_for_start;
146
147     void capture_init();
148     void capture_loop();
149         void capture_finished();
150
151     virtual void run();
152
153   public:
154         CaptureThreadImplJACK(CaptureThread* capture_thread);
155
156         virtual void setSamplingRate(int rate);
157         virtual void startCapture();
158         virtual void stopCapture();
159         virtual bool is_available();
160     
161     ~CaptureThreadImplJACK();
162 };
163 #endif
164
165 // ---------------------- the PortAudio implementation ---------------------
166
167 #ifdef CAPTURE_PORTAUDIO
168 #include <portaudio.h>
169 class CaptureThreadImplPortAudio : public CaptureThreadImpl
170 {
171         static int PortAudioCallback( const void *inputBuffer, void *outputBuffer,
172                                                            unsigned long framesPerBuffer,
173                                                            const PaStreamCallbackTimeInfo* timeInfo,
174                                                            PaStreamCallbackFlags statusFlags,
175                                                            void *userData );
176
177         int portAudioCallback(const void *inputBuffer,
178                                                   unsigned long framesPerBuffer,
179                                                   const PaStreamCallbackTimeInfo* timeInfo,
180                                                   PaStreamCallbackFlags statusFlags);
181
182         PaStream* m_stream;
183         PaError m_err;
184
185         void set_params(bool test=false);
186         virtual void capture_init();
187         virtual void capture_finished();
188
189   public:
190         CaptureThreadImplPortAudio(CaptureThread* capture_thread);
191
192         virtual void setSamplingRate(int rate);
193         virtual void startCapture();
194         virtual void stopCapture();
195         virtual bool is_available();
196
197         virtual ~CaptureThreadImplPortAudio();
198 };
199 #endif
200
201 // ---------------------- the OSS implementation ---------------------
202
203 #ifdef CAPTURE_OSS
204 class CaptureThreadImplOSS : public CaptureThreadImpl, public QThread
205 {
206         int m_fd_in;
207         char* m_oss_buffer;
208         int m_format;
209
210         // view
211         volatile bool m_alive;
212         volatile bool m_in_run;
213
214         // control
215         volatile bool m_loop;
216         volatile bool m_wait_for_start;
217
218         void set_params(bool test=false);
219         void capture_init();
220         void capture_loop();
221         void capture_finished();
222
223         virtual void run();
224
225   public:
226         CaptureThreadImplOSS(CaptureThread* capture_thread);
227
228         virtual void setSamplingRate(int rate);
229         virtual void startCapture();
230         virtual void stopCapture();
231         virtual bool is_available();
232
233         ~CaptureThreadImplOSS();
234 };
235 #endif
236
237 // --------------------- the real accessible thread -------------------------
238
239 class CaptureThread : public QObject
240 {
241         Q_OBJECT
242
243         friend class CaptureThreadImpl;
244 #ifdef CAPTURE_ALSA
245         friend class CaptureThreadImplALSA;
246 #endif
247 #ifdef CAPTURE_JACK
248         friend class CaptureThreadImplJACK;
249 #endif
250 #ifdef CAPTURE_PORTAUDIO
251         friend class CaptureThreadImplPortAudio;
252 #endif
253 #ifdef CAPTURE_OSS
254         friend class CaptureThreadImplOSS;
255 #endif
256
257         vector<CaptureThreadImpl*> m_impls;
258         CaptureThreadImpl* m_current_impl;
259
260         void emitError(const QString& error);
261         void emitSamplingRateChanged();
262         void emitCaptureStarted();
263         void emitCaptureStoped();
264         void emitCaptureToggled(bool value);
265
266         bool m_capturing;
267
268         int m_packet_size;
269         int m_packet_size_sll;
270         QString m_name;
271
272         // control
273         volatile bool m_pause;
274         bool m_mix_multiple_channel;
275
276         QMutex m_lock;
277         bool m_ext_lock;
278
279   public:
280
281         deque<double> m_values;
282
283         enum {SAMPLING_RATE_UNKNOWN=-1, SAMPLING_RATE_MAX=0};
284
285         CaptureThread(const QString& name="bastard_thread");
286
287         void lock()                                             {m_lock.lock(); m_ext_lock=true;}
288         void unlock()                                   {m_lock.unlock();}
289
290         bool isCapturing() const                                                {return m_capturing;}
291         int getSamplingRate() const;
292         int getPacketSize() const                                               {return m_packet_size;}
293         int getPacketSizeSinceLastLock() const                  {return m_packet_size_sll;}
294         int getNbPendingData() const                                    {return m_values.size();}
295         const CaptureThreadImpl* getCurrentTransport() const;
296         int getCurrentTransportIndex() const;
297         QString getCurrentTransportDescr() const;
298         QString getFormatDescr() const;
299         const vector<CaptureThreadImpl*>& getTransports() const;
300         const CaptureThreadImpl* getTransport(const QString& name) const;
301         void listTransports();
302
303         virtual ~CaptureThread();
304
305   signals:
306         void samplingRateChanged(int sampling_rate);
307         void portNameChanged(const QString& name);
308         void sourceChanged(const QString& src);
309         void transportChanged(const QString& name);
310         void captureStarted();
311         void captureStoped();
312         void captureToggled(bool run);
313         void errorRaised(const QString& error);
314
315   public slots:
316         //! auto detect a working transport
317         void autoDetectTransport();
318         //! select a specific transport
319         void selectTransport(const QString& name);
320         //! select a specific transport
321         void selectTransport(int index);
322         //! reset capture (stop/start)
323         void reset();
324         //! start capture
325         void startCapture();
326         //! stop capture
327         void stopCapture();
328         //! set capture status
329         void toggleCapture(bool run);
330         //! set pause status
331         /*! keep capture system connected, but throw away all incoming data
332          */
333         void togglePause(bool pause);
334
335         //! set the sampling rate
336         /*! not always available, depending on the implementation
337          * (reset the capture system !)
338          */
339         void setSamplingRate(int value);
340         //! the source name
341         /*! 'hw:0' for example for ALSA, something like alsa_pcm:capture_1 for JACK
342          * (reset the capture system !)
343          */
344         void setSource(const QString& src);
345
346         void setMixMultipleChannels(bool mix);
347 };
348
349 #endif // _CaptureThread_h_