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