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