Release version 0.99.2-1
[fmit.git] / src / CaptureThread.cpp
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 #include "CaptureThread.h"
21
22 #include <cassert>
23 #include <time.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <iostream>
28 #include <fstream>
29 #include <vector>
30 using namespace std;
31 #include <qdatetime.h>
32
33 double DecodeUnsigned8Bits(void* buffer, int i) {return 2*(((unsigned char*)buffer)[i])/256.0 - 1;}
34 double DecodeSigned8Bits(void* buffer, int i)   {return (((signed char*)buffer)[i])/128.0;}
35 double DecodeUnsigned16Bits(void* buffer, int i){return 2*((unsigned short*)buffer)[i]/65536.0 - 1;}
36 double DecodeSigned16Bits(void* buffer, int i)  {return ((signed short*)buffer)[i]/32768.0;}
37 void AddValue2ChannelFirst(CaptureThreadImpl* impl, double value, int i)
38 {
39         if(i%2==0)
40                 impl->m_capture_thread->m_values.push_front(value);
41 }
42 void AddValue2ChannelMix(CaptureThreadImpl* impl, double value, int i)
43 {
44         if(i%2==0)
45         impl->m_tmp_value = value;
46 //              impl->m_capture_thread->m_values.push_front(value);
47         else
48         impl->m_capture_thread->m_values.push_front((impl->m_tmp_value+value)/2.0);
49 //              impl->m_capture_thread->m_values[0] = (impl->m_capture_thread->m_values[0]+value)/2.0;
50 }
51 void AddValue1Channel(CaptureThreadImpl* impl, double value, int i)
52 {
53         impl->m_capture_thread->m_values.push_front(value);
54 }
55
56 CaptureThread::CaptureThread(const QString& name)
57 {
58         m_current_impl = NULL;
59
60         m_capturing = false;
61         m_packet_size = 0;
62         m_ext_lock = false;
63         m_packet_size_sll = 0;
64
65         m_pause = false;
66         m_mix_multiple_channel = false;
67
68         m_name = name;
69
70 #ifdef CAPTURE_JACK
71         m_impls.push_back(new CaptureThreadImplJACK(this));
72 #endif
73 #ifdef CAPTURE_ALSA
74         m_impls.push_back(new CaptureThreadImplALSA(this));
75 #endif
76 #ifdef CAPTURE_OSS
77         m_impls.push_back(new CaptureThreadImplOSS(this));
78 #endif
79 #ifdef CAPTURE_PORTAUDIO
80         m_impls.push_back(new CaptureThreadImplPortAudio(this));
81 #endif
82
83         listTransports();
84 }
85
86 void CaptureThread::autoDetectTransport()
87 {
88         bool was_capturing = isCapturing();
89         if(was_capturing)
90                 stopCapture();
91
92         QString old_name;
93         if(m_current_impl!=NULL)
94                 old_name = m_current_impl->m_name;
95
96         cerr << "CaptureThread: INFO: Auto detecting a working transport ... " << flush;
97
98         CaptureThreadImpl* impl = NULL;
99         for(vector<CaptureThreadImpl*>::iterator it=m_impls.begin(); impl==NULL && it!=m_impls.end(); it++)
100                 if((*it)->is_available())
101                         impl = *it;
102
103         if(impl!=NULL)
104         {
105                 m_current_impl = impl;
106
107                 cerr << "using " << m_current_impl->m_name.toStdString() << endl;
108
109                 if(m_current_impl->m_name!=old_name)
110                         emit(transportChanged(m_current_impl->m_name));
111
112                 if(was_capturing)
113                         startCapture();
114         }
115         else
116         {
117                 cerr << "no working transport !" << endl;
118
119                 if(old_name!="")
120                         emit(transportChanged(""));
121         }
122 }
123 void CaptureThread::selectTransport(const QString& name)
124 {
125         cerr << "CaptureThread: INFO: using " << name.toStdString() << " transport" << endl;
126         if(getCurrentTransport() && name==getCurrentTransport()->getName())     return;
127
128         bool was_capturing = isCapturing();
129         if(was_capturing)
130                 stopCapture();
131
132         QString old_name;
133         if(m_current_impl!=NULL)
134                 old_name = m_current_impl->m_name;
135
136         CaptureThreadImpl* impl = NULL;
137         for(vector<CaptureThreadImpl*>::iterator it=m_impls.begin(); impl==NULL && it!=m_impls.end(); it++)
138                 if((*it)->m_name==name)
139                         impl = *it;
140
141         if(impl==NULL)
142         {
143                 cerr << "CaptureThread: ERROR: unknown transport '" << name.toStdString() << "'" << endl;
144                 throw QString("CaptureThread: ERROR: unknown transport '")+name+"'";
145         }
146
147         m_current_impl = impl;
148
149         if(m_current_impl->m_name!=old_name)
150                 emit(transportChanged(m_current_impl->m_name));
151
152         if(was_capturing)
153                 startCapture();
154 }
155 void CaptureThread::selectTransport(int index)
156 {
157         assert(index>=0 && index<m_impls.size());
158
159         if(m_impls[index]==getCurrentTransport())       return;
160                 cerr << "CaptureThread: INFO: change transport to " << m_impls[index]->getName().toStdString() << " transport" << endl;
161
162         bool was_capturing = isCapturing();
163         if(was_capturing)
164                 stopCapture();
165
166         m_current_impl = m_impls[index];
167
168         emit(transportChanged(m_current_impl->m_name));
169
170         if(was_capturing)
171                 startCapture();
172 }
173 const vector<CaptureThreadImpl*>& CaptureThread::getTransports() const
174 {
175         return m_impls;
176 }
177 void CaptureThread::listTransports()
178 {
179         cerr << "CaptureThread: INFO: Built in transports" << endl;
180         for(vector<CaptureThreadImpl*>::iterator it=m_impls.begin(); it!=m_impls.end(); it++)
181                 cerr << "CaptureThread: INFO:   " << (*it)->getStatus().toStdString() << "      " << (*it)->m_name.toStdString() << "   " << (*it)->m_descr.toStdString() << endl;
182 }
183 const CaptureThreadImpl* CaptureThread::getCurrentTransport() const
184 {
185         return m_current_impl;
186 }
187 int CaptureThread::getCurrentTransportIndex() const
188 {
189         for(int i=0; i<m_impls.size(); i++)
190                 if(m_impls[i]==getCurrentTransport())
191                         return i;
192
193         return -1;
194 }
195 QString CaptureThread::getCurrentTransportDescr() const
196 {
197         if(m_current_impl==NULL)
198                 return "";
199
200         return m_current_impl->m_descr;
201 }
202 const CaptureThreadImpl* CaptureThread::getTransport(const QString& name) const
203 {
204         for(vector<CaptureThreadImpl*>::const_iterator it=m_impls.begin(); it!=m_impls.end(); it++)
205                 if((*it)->m_name==name)
206                         return *it;
207
208         return NULL;
209 }
210 QString CaptureThread::getFormatDescr() const
211 {
212         if(m_current_impl==NULL)
213                 return "";
214
215         return ""; // TODO
216 }
217
218 void CaptureThread::emitError(const QString& error)
219 {
220         emit(errorRaised(error));
221 }
222 void CaptureThread::emitSamplingRateChanged()
223 {
224         if(m_current_impl->m_sampling_rate>0)
225                 emit(samplingRateChanged(m_current_impl->m_sampling_rate));
226 }
227 void CaptureThread::emitCaptureStarted()
228 {
229         emit(captureStarted());
230 }
231 void CaptureThread::emitCaptureStoped()
232 {
233         emit(captureStoped());
234 }
235 void CaptureThread::emitCaptureToggled(bool value)
236 {
237         emit(captureToggled(value));
238 }
239
240 void CaptureThread::startCapture()
241 {
242         if(m_current_impl==NULL)        return;
243
244         m_current_impl->startCapture();
245 }
246 void CaptureThread::stopCapture()
247 {
248         //      cerr << "CaptureThread::stopCapture" << endl;
249
250         if(m_current_impl==NULL)        return;
251
252         m_current_impl->stopCapture();
253
254         //      cerr << "/CaptureThread::stopCapture" << endl;
255 }
256
257 void CaptureThread::toggleCapture(bool run)
258 {
259         if(run && !m_capturing) startCapture();
260         if(!run && m_capturing) stopCapture();
261 }
262
263 void CaptureThread::reset()
264 {
265         stopCapture();
266         startCapture();
267 }
268
269 void CaptureThread::togglePause(bool pause)
270 {
271         m_pause = pause;
272 }
273
274 int CaptureThread::getSamplingRate() const
275 {
276         if(m_current_impl==NULL)        return SAMPLING_RATE_UNKNOWN;
277
278         return m_current_impl->m_sampling_rate;
279 }
280 void CaptureThread::setSamplingRate(int rate)
281 {
282         if(m_current_impl!=NULL)
283                 m_current_impl->setSamplingRate(rate);
284 }
285 void CaptureThread::setSource(const QString& name)
286 {
287         if(m_current_impl==NULL)
288         {
289                 cerr << "CaptureThread: setSource: ERROR: select a transport first" << endl;
290                 return;
291         }
292
293         if(name!=m_current_impl->m_source)
294         {
295                 m_current_impl->m_source = name;
296                 if(isCapturing())
297                 {
298                         stopCapture();
299                         startCapture();
300                 }
301
302                 emit(sourceChanged(m_current_impl->m_source));
303         }
304 }
305
306 void CaptureThread::setMixMultipleChannels(bool mix)
307 {
308         m_mix_multiple_channel = mix;
309 }
310
311 CaptureThread::~CaptureThread()
312 {
313         stopCapture();
314
315         for(vector<CaptureThreadImpl*>::iterator it=m_impls.begin(); it!=m_impls.end(); it++)
316                 delete *it;
317 }
318
319 // -------------------------------- implementation ------------------------------
320
321 CaptureThreadImpl::CaptureThreadImpl(CaptureThread* capture_thread, const QString& name, const QString& descr)
322 : m_capture_thread(capture_thread)
323 {
324         m_name = name;
325         m_descr = descr;
326         m_status = "";
327
328         m_sampling_rate = CaptureThread::SAMPLING_RATE_UNKNOWN;
329         m_format_size = 0;
330         m_format_signed = true;
331         m_channel_count = 0;
332         m_source = "";
333 }
334
335 const QString& CaptureThreadImpl::getStatus()
336 {
337         if(m_status=="")
338                 is_available();
339
340         return m_status;
341 }
342
343 void CaptureThreadImpl::setFormatDescrsAndFns(int format_size, bool format_signed, bool format_float, int channel_count)
344 {
345         m_format_size = format_size;
346         m_format_signed = format_signed;
347         m_format_float = format_float;
348         m_channel_count = channel_count;
349
350         if(m_format_size==2) // 16bits
351         {
352                 if(m_format_signed)     decodeValue = DecodeSigned16Bits;
353                 else                            decodeValue = DecodeUnsigned16Bits;
354         }
355         else    // 8bits
356         {
357                 if(m_format_signed)     decodeValue = DecodeSigned8Bits;
358                 else                            decodeValue = DecodeUnsigned8Bits;
359         }
360
361         if(m_channel_count==1)
362                 addValue = AddValue1Channel;
363         else if(m_channel_count==2)
364         {
365                 if(m_capture_thread->m_mix_multiple_channel)
366                         addValue = AddValue2ChannelMix;
367                 else
368                         addValue = AddValue2ChannelFirst;
369         }
370
371         cerr << "CaptureThread: INFO: format is " << (m_format_signed?"signed":"unsigned") << " " << (m_format_float?"float":"integer") << " " << m_format_size*8 << "bits with " << m_channel_count << " channel(s)" << endl;
372 }