Release version 0.99.2-1
[fmit.git] / src / CaptureThreadImplOSS.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
32 // ------------------------------ OSS implementation ----------------------------
33 #ifdef CAPTURE_OSS
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <sys/ioctl.h>
40 #include <sys/soundcard.h>
41
42 #define OSS_BUFF_SIZE 1024
43
44 CaptureThreadImplOSS::CaptureThreadImplOSS(CaptureThread* capture_thread)
45         : CaptureThreadImpl(capture_thread, "OSS", QString("Open Sound System"))
46 {
47         m_fd_in = 0;
48         m_oss_buffer = NULL;
49         m_format = -1;
50
51         m_source = "/dev/dsp";
52
53         //      oss_sysinfo si; // definition ??
54 //      ioctl(m_fd_in, OSS_SYSINFO, &si);
55 //      m_fd_in = open(m_source, O_RDONLY, 0));
56 //      m_descr = QString("Open Sound System (")+QString::number(SOUND_VERSION, 16)+":"+si.version+")");
57 //      close(m_fd_in);
58 //      m_fd_in = 0;
59         m_descr = QString("Open Sound System (lib:")+QString::number(SOUND_VERSION, 16)+")";
60
61         m_alive = true;
62         m_in_run = false;
63         m_loop = false;
64 }
65
66 bool CaptureThreadImplOSS::is_available()
67 {
68         if(m_fd_in==0)
69         {
70                 try
71                 {
72                         if((m_fd_in = open (m_source.toAscii().constData(), O_RDONLY, 0)) == -1)
73                                 throw QString(strerror(errno));
74                 }
75                 catch(QString error)
76                 {
77                         m_fd_in = 0;
78
79                         m_status = "N/A ("+error+")";
80
81                         return false;
82                 }
83
84                 capture_finished();
85         }
86
87         m_status = "OK";
88
89         //      cerr << "CaptureThread: INFO: OSS seems available" << endl;
90
91         return true;
92 }
93
94 void CaptureThreadImplOSS::startCapture()
95 {
96         if(!isRunning())
97                 start();
98
99         m_loop = true;
100
101         m_wait_for_start = true;
102         while(m_wait_for_start) // some implementations take a long time to start
103                 msleep(10);
104 }
105 void CaptureThreadImplOSS::stopCapture()
106 {
107         m_loop = false;
108
109         while(m_in_run)
110                 msleep(10);
111 }
112
113 void CaptureThreadImplOSS::set_params(bool test)
114 {
115         if(m_source=="")
116                 throw QString("OSS: set the source first");
117         if((m_fd_in = open (m_source.toAscii().constData(), O_RDONLY, 0))==-1)
118                 throw QString("OSS: ")+QString(strerror(errno));
119
120         if(!test)
121         {
122                 if(m_format==-1)
123                 {
124                         // Formats
125                         m_format = AFMT_S16_NE; /* Native 16 bits */
126                         if(ioctl(m_fd_in, SNDCTL_DSP_SETFMT, &m_format)==-1)
127                                 throw QString("OSS: cannot set format (%1)").arg(strerror(errno));
128
129                         if(m_format != AFMT_S16_NE)
130                                 throw QString("OSS: cannot set format to signed 16bits");
131                 }
132                 else
133                 {
134                         if(ioctl(m_fd_in, SNDCTL_DSP_SETFMT, &m_format)==-1)
135                                 throw QString("OSS: cannot set format (%1)").arg(strerror(errno));
136                 }
137
138                 m_format_size = 2;
139                 m_format_signed = true;
140                 m_format_float = false;
141
142                 // Channel count
143                 unsigned int channel_count = 1;
144                 if(ioctl(m_fd_in, SNDCTL_DSP_CHANNELS, &channel_count)==-1)
145                         throw QString("OSS: cannot set channel count to 1 (%1)").arg(strerror(errno));
146
147                 if(channel_count != 1)
148                         throw QString("OSS: the device doesn't support mono mode");
149
150                 /*              if(m_channel_count>1)   // TODO
151                 {
152                         QString err_msg = QString("OSS: cannot set channel count to one (")+QString::number(m_channel_count)+" instead)";
153                         cerr << "CaptureThread: WARNING: " << err_msg << endl;
154                 }*/
155
156                 setFormatDescrsAndFns(2, true, false, channel_count);
157         }
158
159         if(m_sampling_rate==CaptureThread::SAMPLING_RATE_MAX || m_sampling_rate==CaptureThread::SAMPLING_RATE_UNKNOWN)
160         {
161                 int old_sampling_rate = m_sampling_rate;
162
163                 cerr << "CaptureThread: INFO: OSS: sampling rate set to max or undefined, try to determinate it." << endl;
164
165                 list<int> sampling_rates;
166                 sampling_rates.push_front(8000);        sampling_rates.push_front(11025);       sampling_rates.push_front(16000);
167                 sampling_rates.push_front(22050);       sampling_rates.push_front(24000);       sampling_rates.push_front(32000);
168                 sampling_rates.push_front(44100);
169
170                 int err = -1;
171                 while(err<0)
172                 {
173                         if(sampling_rates.empty())
174                                 throw QString("OSS: cannot set any sample rate (%1)").arg(strerror(errno));
175
176                         m_sampling_rate = sampling_rates.front();
177                         cerr << "CaptureThread: INFO: OSS: try sampling rate " << m_sampling_rate << " ..." << flush;
178                         err = ioctl(m_fd_in, SNDCTL_DSP_SPEED, &m_sampling_rate);
179
180                         if(err==-1)     cerr << " failed" << endl;
181                         else            cerr << " success" << endl;
182
183                         sampling_rates.pop_front();
184                 }
185
186                 if(old_sampling_rate!=m_sampling_rate)
187                         m_capture_thread->emitSamplingRateChanged();
188         }
189         else
190         {
191                 if(ioctl(m_fd_in, SNDCTL_DSP_SPEED, &m_sampling_rate)==-1)
192                         throw QString("OSS: cannot set sampling rate (")+QString(strerror(errno))+")";
193         }
194 }
195
196 void CaptureThreadImplOSS::setSamplingRate(int value)
197 {
198 //      cerr << "CaptureThreadImplOSS::setSamplingRate " << value << endl;
199
200         assert(value>0 || value==CaptureThread::SAMPLING_RATE_MAX);
201
202         if(m_sampling_rate!=value || value==CaptureThread::SAMPLING_RATE_MAX)
203         {
204                 bool was_running = m_capture_thread->isCapturing();
205                 if(was_running) m_capture_thread->stopCapture();
206
207                 m_sampling_rate = value;
208
209                 if(m_sampling_rate==CaptureThread::SAMPLING_RATE_MAX)
210                 {
211                         try
212                         {
213                                 set_params(true);
214                         }
215                         catch(QString error)
216                         {
217                                 cerr << "CaptureThread: ERROR: " << error.toStdString() << endl;
218                                 m_capture_thread->emitError(error);
219                         }
220
221                         // it was just for testing
222                         capture_finished();
223                 }
224                 else
225                         m_capture_thread->emitSamplingRateChanged();
226
227                 if(was_running) m_capture_thread->startCapture();
228         }
229
230 //      cerr << "~CaptureThreadImplOSS::setSamplingRate" << endl;
231 }
232
233 void CaptureThreadImplOSS::capture_init()
234 {
235         set_params(false);
236
237         m_oss_buffer = new char[m_channel_count*OSS_BUFF_SIZE*16/8];
238 }
239 void CaptureThreadImplOSS::capture_loop()
240 {
241 //      cerr << "CaptureThreadImplOSS::capture_loop" << endl;
242
243         bool format_signed = true;
244         int l=0;
245
246         m_wait_for_start = false;
247         while(m_loop)
248         {
249                 int ret_val = read(m_fd_in, m_oss_buffer, sizeof(m_oss_buffer));
250
251                 if(ret_val==-1)
252                 {
253                         cerr << "CaptureThread: WARNING: OSS: " << strerror(errno) << endl;
254                         msleep(1000);   // TODO which behavior ?
255 //                      m_loop = false;// TODO which behavior ?
256                 }
257                 else
258                 {
259                         ret_val /= m_format_size;
260
261                         if(!m_capture_thread->m_pause)
262                         {
263                                 m_capture_thread->m_lock.lock();
264
265                                 for(int i=0; i<ret_val*m_channel_count; i++)
266                                         addValue(this, decodeValue(m_oss_buffer, i), i);
267
268                                 m_capture_thread->m_packet_size = ret_val;
269                                 if(m_capture_thread->m_ext_lock)
270                                 {
271                                         m_capture_thread->m_packet_size_sll = 0;
272                                         m_capture_thread->m_ext_lock = false;
273                                 }
274                                 m_capture_thread->m_packet_size_sll += ret_val;
275
276                                 m_capture_thread->m_lock.unlock();
277                         }
278                 }
279         }
280
281 //      cerr << "~CaptureThreadImplOSS::capture_loop" << endl;
282 }
283 void CaptureThreadImplOSS::capture_finished()
284 {
285         if(m_oss_buffer!=NULL)
286         {
287                 delete[] m_oss_buffer;
288                 m_oss_buffer = NULL;
289         }
290
291         if(m_fd_in!=0)
292         {
293                 close(m_fd_in);
294                 m_fd_in = 0;
295         }
296 }
297
298 void CaptureThreadImplOSS::run()
299 {
300 //      cerr << "CaptureThread: INFO: OSS: capture thread entered" << endl;
301
302 //      while(m_alive)  // TODO ?? need to keep oss thread alive to let PortAudio working after ALSA ??
303         {
304                 while(m_alive && !m_loop)
305                         msleep(10);
306
307                 m_in_run = true;
308
309                 try
310                 {
311                         //                      cerr << "CaptureThread: INFO: capture thread running" << endl;
312
313                         capture_init();
314
315                         m_capture_thread->m_capturing = true;
316                         m_capture_thread->emitCaptureStarted();
317                         m_capture_thread->emitCaptureToggled(true);
318
319                         capture_loop();
320
321                         m_capture_thread->m_capturing = false;
322                         m_capture_thread->emitCaptureStoped();
323                         m_capture_thread->emitCaptureToggled(false);
324                 }
325                 catch(QString error)
326                 {
327                         m_loop = false;
328                         cerr << "CaptureThread: ERROR: " << error.toStdString() << endl;
329                         m_capture_thread->emitError(error);
330                 }
331                 m_wait_for_start = false;
332
333                 capture_finished();
334
335                 m_in_run = false;
336
337                 //              cerr << "CaptureThread: INFO: capture thread stop running" << endl;
338         }
339
340 //      cerr << "CaptureThread: INFO: OSS: capture thread exited" << endl;
341 }
342
343 CaptureThreadImplOSS::~CaptureThreadImplOSS()
344 {
345 //      cerr << "CaptureThreadImplOSS::~CaptureThreadImplOSS" << endl;
346
347         m_alive = false;
348
349         stopCapture();
350
351         while(isRunning())
352                 msleep(10);
353
354 //      cerr << "~CaptureThreadImplOSS::~CaptureThreadImplOSS" << endl;
355 }
356
357 #endif