Release version 0.99.2-1
[fmit.git] / src / CaptureThreadImplJACK.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 // ------------------------------ JACK implementation ----------------------------
33 #ifdef CAPTURE_JACK
34
35 #define JACK_BUFF_SIZE 1024
36
37 const size_t g_jack_sample_size = sizeof(jack_default_audio_sample_t);
38
39 CaptureThreadImplJACK::CaptureThreadImplJACK(CaptureThread* capture_thread)
40 : CaptureThreadImpl(capture_thread, "JACK", "Jack Audio Connection Kit")
41 {
42         m_jack_client = NULL;
43         m_jack_port = NULL;
44     m_ringbuffer = NULL;
45
46     m_alive = true;
47     m_in_run = false;
48     m_loop = false;
49 }
50
51 bool CaptureThreadImplJACK::is_available()
52 {
53         if(m_jack_client==NULL)
54         {
55                 try
56                 {
57                         //m_jack_client = jack_client_new((m_capture_thread->m_name+"_test").latin1());
58             m_jack_client = jack_client_open((m_capture_thread->m_name+"_test").toAscii().constData(), JackNoStartServer, NULL);
59             if(m_jack_client==NULL)
60                                 throw QString("unknown reason");
61                 }
62                 catch(QString error)
63                 {
64                         m_jack_client = NULL;
65                         m_status = "N/A";
66                         return false;
67                 }
68                 capture_finished();
69         }
70
71         m_status = "available";
72
73         return true;
74 }
75
76 void CaptureThreadImplJACK::setSamplingRate(int value)
77 {
78         cerr << "CaptureThread: ERROR: JACK: setSamplingRate not available with JACK ! change the JACK server sampling rate instead" << endl;
79 }
80
81 void CaptureThreadImplJACK::startCapture()
82 {
83     if(!isRunning())
84         start();
85
86     m_loop = true;
87
88     m_wait_for_start = true;
89     while(m_wait_for_start) // some implementations take a long time to start
90         msleep(50);
91 }
92 void CaptureThreadImplJACK::stopCapture()
93 {
94     m_loop = false;
95
96     while(m_in_run)
97         msleep(50);
98 }
99
100 void CaptureThreadImplJACK::JackShutdown(void* arg){((CaptureThreadImplJACK*)arg)->jackShutdown();}
101 void CaptureThreadImplJACK::jackShutdown()
102 {
103 //     cerr << "CaptureThreadImplJACK::jackShutdown" << endl;
104
105         m_jack_client = NULL;
106     m_jack_port = NULL;
107     if(m_ringbuffer)
108     {
109         jack_ringbuffer_free(m_ringbuffer);
110         m_ringbuffer = NULL;
111     }
112
113         m_capture_thread->emitError("JACK: server shutdown !");
114 //     cerr << "~CaptureThreadImplJACK::jackShutdown" << endl;
115 }
116
117 int CaptureThreadImplJACK::JackSampleRate(jack_nframes_t nframes, void* arg){return ((CaptureThreadImplJACK*)arg)->jackSampleRate(nframes);}
118 int CaptureThreadImplJACK::jackSampleRate(jack_nframes_t nframes)
119 {
120         if(m_sampling_rate!=int(nframes))
121         {
122         if(m_ringbuffer)
123             jack_ringbuffer_free(m_ringbuffer);
124         m_ringbuffer = jack_ringbuffer_create(g_jack_sample_size*nframes); // one second buffer
125
126                 m_sampling_rate = nframes;
127                 m_capture_thread->emitSamplingRateChanged();
128         }
129
130         return 0;
131 }
132
133 int CaptureThreadImplJACK::JackProcess(jack_nframes_t nframes, void* arg){return ((CaptureThreadImplJACK*)arg)->jackProcess(nframes);}
134 int CaptureThreadImplJACK::jackProcess(jack_nframes_t nframes)
135 {
136 //      cerr << "CaptureThreadImplJACK::jackProcess '" << nframes << "'" << endl;
137
138     if(!m_jack_client || !m_jack_port || !m_ringbuffer) return 0;
139         if(m_capture_thread->m_pause || !m_capture_thread->m_capturing || nframes<=0)   return 0;
140
141         void* pin = jack_port_get_buffer(m_jack_port, nframes);
142
143         if(!pin) return 0;
144
145         jack_default_audio_sample_t* in = (jack_default_audio_sample_t*)pin;
146
147     int characters_written = jack_ringbuffer_write(m_ringbuffer, (const char *) ((void *) (in)), g_jack_sample_size*nframes);
148     if (characters_written < g_jack_sample_size*nframes)
149         cerr << "CaptureThreadImplJACK::jackProcess Can not write all frames: ringbuffer full?" << endl;
150
151 //     int toread = jack_ringbuffer_read_space(m_ringbuffer);
152 //     cerr << "CaptureThreadImplJACK::jackProcess " << characters_written/g_jack_sample_size << " values written, " << toread/g_jack_sample_size << " to read" << endl;
153
154 //     cerr << "~CaptureThreadImplJACK::jackProcess" << endl;
155
156         return 0;
157 }
158
159 void CaptureThreadImplJACK::capture_init()
160 {
161     m_jack_client = jack_client_open(m_capture_thread->m_name.toAscii().constData(), JackNoStartServer, NULL);
162         if(!m_jack_client)
163                 throw QString("JACK: cannot create client, JACK deamon is running ?");
164
165         jack_set_process_callback(m_jack_client, JackProcess, (void*)this);
166         jack_on_shutdown(m_jack_client, JackShutdown, (void*)this);
167         jack_set_sample_rate_callback(m_jack_client, JackSampleRate, (void*)this);
168
169     cerr << "CaptureThread: INFO: JACK: sampling rate=" << jack_get_sample_rate(m_jack_client) << endl;
170     m_ringbuffer = jack_ringbuffer_create(g_jack_sample_size*jack_get_sample_rate(m_jack_client)); // one second buffer
171
172     int err=0;
173         if((err=jack_activate(m_jack_client))!=0)
174                 throw QString("JACK: cannot activate client");
175
176         setFormatDescrsAndFns(g_jack_sample_size, true, true, 1);
177
178         m_jack_port = jack_port_register(m_jack_client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput,0);
179
180         if(m_source!="")
181     {
182         QString dest = QString(jack_get_client_name(m_jack_client))+":input";
183         cerr << "CaptureThread: INFO: JACK: auto-connect '" << m_source.toStdString() << "' with '" << dest.toStdString() << "'" << endl;
184         if((err=jack_connect(m_jack_client, m_source.toAscii().constData(), dest.toAscii().constData()))!=0)
185             m_capture_thread->emitError(QString("JACK: Invalid source '")+m_source+"'");
186     }
187
188         int old_sampling_rate = m_sampling_rate;
189         m_sampling_rate = jack_get_sample_rate(m_jack_client);
190         if(m_sampling_rate!=old_sampling_rate)
191                 m_capture_thread->emitSamplingRateChanged();
192
193         m_capture_thread->m_capturing = true;
194         m_capture_thread->emitCaptureStarted();
195         m_capture_thread->emitCaptureToggled(true);
196 }
197 void CaptureThreadImplJACK::capture_loop()
198 {
199 //     cerr << "CaptureThreadImplJACK::capture_loop " << g_jack_sample_size << endl;
200
201     char dest[JACK_BUFF_SIZE*g_jack_sample_size];
202
203     m_wait_for_start = false;
204     while(m_loop && m_jack_client && m_jack_port && m_ringbuffer)
205     {
206 //         cerr << "CaptureThreadImplJACK::capture_loop toread=" << toread/g_jack_sample_size << endl;
207         int read = jack_ringbuffer_read(m_ringbuffer, dest, JACK_BUFF_SIZE*g_jack_sample_size);
208         if(read>0)
209         {
210             if(!m_capture_thread->m_pause)
211             {
212 //                 cerr << "CaptureThreadImplJACK::capture_loop locking" << endl;
213                 m_capture_thread->m_lock.lock();
214
215 //                 int toread = jack_ringbuffer_read_space(m_ringbuffer);
216 //                 cerr << "CaptureThreadImplJACK::capture_loop in deque='" << m_capture_thread->m_values.size() << "' still toread=" << toread/g_jack_sample_size << endl;
217
218                 if(g_jack_sample_size==4)
219                     for(int i=0; i<(read/g_jack_sample_size); i++)
220                         addValue(this, (double)(((float*)dest)[i]), i);
221                 else if(g_jack_sample_size==8)
222                     for(int i=0; i<(read/g_jack_sample_size); i++)
223                         addValue(this, (double)(((double*)dest)[i]), i);
224
225                 m_capture_thread->m_packet_size = (read/g_jack_sample_size);
226                 if(m_capture_thread->m_ext_lock)
227                 {
228                     m_capture_thread->m_packet_size_sll = 0;
229                     m_capture_thread->m_ext_lock = false;
230                 }
231                 m_capture_thread->m_packet_size_sll += (read/g_jack_sample_size);
232
233                 m_capture_thread->m_lock.unlock();
234 //                 cerr << "CaptureThreadImplJACK::capture_loop unlocked" << endl;
235             }
236         }
237         else
238             msleep(10);
239     }
240
241 //     cerr << "~CaptureThreadImplJACK::capture_loop" << endl;
242 }
243 void CaptureThreadImplJACK::capture_finished()
244 {
245 //      cerr << "CaptureThreadImplJACK::capture_finished" << endl;
246
247         if(m_jack_client!=NULL)
248         {
249                 jack_client_close(m_jack_client);
250                 m_jack_client = NULL;
251         if(m_ringbuffer)
252         {
253             jack_ringbuffer_free(m_ringbuffer);
254             m_ringbuffer = NULL;
255         }
256
257                 m_capture_thread->m_capturing = false;
258                 m_capture_thread->emitCaptureStoped();
259                 m_capture_thread->emitCaptureToggled(false);
260         }
261 }
262 void CaptureThreadImplJACK::run()
263 {
264 //  cerr << "CaptureThread: INFO: JACK: capture thread entered" << endl;
265
266 //  while(m_alive)  // TODO need to keep alsa thread alive to let PortAudio working after ALSA !! TODO same for JACK ???
267     {
268         while(m_alive && !m_loop)
269             msleep(50);
270
271         m_in_run = true;
272
273         try
274         {
275 //             cerr << "CaptureThread: INFO: JACK: capture thread running" << endl;
276
277             capture_init();
278
279             m_capture_thread->m_capturing = true;
280             m_capture_thread->emitCaptureStarted();
281             m_capture_thread->emitCaptureToggled(true);
282
283             capture_loop();
284
285             m_capture_thread->m_capturing = false;
286             m_capture_thread->emitCaptureStoped();
287             m_capture_thread->emitCaptureToggled(false);
288         }
289         catch(QString error)
290         {
291             m_loop = false;
292             cerr << "CaptureThread: ERROR: " << error.toStdString() << endl;
293             m_capture_thread->emitError(error);
294         }
295         m_wait_for_start = false;
296
297         capture_finished();
298
299         m_in_run = false;
300
301 //         cerr << "CaptureThread: INFO: JACK: capture thread stop running" << endl;
302     }
303
304 //     cerr << "CaptureThread: INFO: JACK: capture thread exited" << endl;
305 }
306 CaptureThreadImplJACK::~CaptureThreadImplJACK()
307 {
308 //  cerr << "CaptureThreadImplJACK::~CaptureThreadImplJACK" << endl;
309
310     m_alive = false;
311
312     stopCapture();
313
314     while(isRunning())
315         msleep(50);
316
317 //  cerr << "~CaptureThreadImplJACK::~CaptureThreadImplJACK" << endl;
318 }
319 #endif