--- /dev/null
+// Copyright 2004 "Gilles Degottex"
+
+// This file is part of "Music"
+
+// "Music" is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation; either version 2.1 of the License, or
+// (at your option) any later version.
+//
+// "Music" is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#include "CaptureThread.h"
+
+#include <cassert>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <iostream>
+#include <fstream>
+#include <vector>
+using namespace std;
+
+// ------------------------------ JACK implementation ----------------------------
+#ifdef CAPTURE_JACK
+
+#define JACK_BUFF_SIZE 1024
+
+const size_t g_jack_sample_size = sizeof(jack_default_audio_sample_t);
+
+CaptureThreadImplJACK::CaptureThreadImplJACK(CaptureThread* capture_thread)
+: CaptureThreadImpl(capture_thread, "JACK", "Jack Audio Connection Kit")
+{
+ m_jack_client = NULL;
+ m_jack_port = NULL;
+ m_ringbuffer = NULL;
+
+ m_alive = true;
+ m_in_run = false;
+ m_loop = false;
+}
+
+bool CaptureThreadImplJACK::is_available()
+{
+ if(m_jack_client==NULL)
+ {
+ try
+ {
+ //m_jack_client = jack_client_new((m_capture_thread->m_name+"_test").latin1());
+ m_jack_client = jack_client_open((m_capture_thread->m_name+"_test").toAscii().constData(), JackNoStartServer, NULL);
+ if(m_jack_client==NULL)
+ throw QString("unknown reason");
+ }
+ catch(QString error)
+ {
+ m_jack_client = NULL;
+ m_status = "N/A";
+ return false;
+ }
+ capture_finished();
+ }
+
+ m_status = "available";
+
+ return true;
+}
+
+void CaptureThreadImplJACK::setSamplingRate(int value)
+{
+ cerr << "CaptureThread: ERROR: JACK: setSamplingRate not available with JACK ! change the JACK server sampling rate instead" << endl;
+}
+
+void CaptureThreadImplJACK::startCapture()
+{
+ if(!isRunning())
+ start();
+
+ m_loop = true;
+
+ m_wait_for_start = true;
+ while(m_wait_for_start) // some implementations take a long time to start
+ msleep(50);
+}
+void CaptureThreadImplJACK::stopCapture()
+{
+ m_loop = false;
+
+ while(m_in_run)
+ msleep(50);
+}
+
+void CaptureThreadImplJACK::JackShutdown(void* arg){((CaptureThreadImplJACK*)arg)->jackShutdown();}
+void CaptureThreadImplJACK::jackShutdown()
+{
+// cerr << "CaptureThreadImplJACK::jackShutdown" << endl;
+
+ m_jack_client = NULL;
+ m_jack_port = NULL;
+ if(m_ringbuffer)
+ {
+ jack_ringbuffer_free(m_ringbuffer);
+ m_ringbuffer = NULL;
+ }
+
+ m_capture_thread->emitError("JACK: server shutdown !");
+// cerr << "~CaptureThreadImplJACK::jackShutdown" << endl;
+}
+
+int CaptureThreadImplJACK::JackSampleRate(jack_nframes_t nframes, void* arg){return ((CaptureThreadImplJACK*)arg)->jackSampleRate(nframes);}
+int CaptureThreadImplJACK::jackSampleRate(jack_nframes_t nframes)
+{
+ if(m_sampling_rate!=int(nframes))
+ {
+ if(m_ringbuffer)
+ jack_ringbuffer_free(m_ringbuffer);
+ m_ringbuffer = jack_ringbuffer_create(g_jack_sample_size*nframes); // one second buffer
+
+ m_sampling_rate = nframes;
+ m_capture_thread->emitSamplingRateChanged();
+ }
+
+ return 0;
+}
+
+int CaptureThreadImplJACK::JackProcess(jack_nframes_t nframes, void* arg){return ((CaptureThreadImplJACK*)arg)->jackProcess(nframes);}
+int CaptureThreadImplJACK::jackProcess(jack_nframes_t nframes)
+{
+// cerr << "CaptureThreadImplJACK::jackProcess '" << nframes << "'" << endl;
+
+ if(!m_jack_client || !m_jack_port || !m_ringbuffer) return 0;
+ if(m_capture_thread->m_pause || !m_capture_thread->m_capturing || nframes<=0) return 0;
+
+ void* pin = jack_port_get_buffer(m_jack_port, nframes);
+
+ if(!pin) return 0;
+
+ jack_default_audio_sample_t* in = (jack_default_audio_sample_t*)pin;
+
+ int characters_written = jack_ringbuffer_write(m_ringbuffer, (const char *) ((void *) (in)), g_jack_sample_size*nframes);
+ if (characters_written < g_jack_sample_size*nframes)
+ cerr << "CaptureThreadImplJACK::jackProcess Can not write all frames: ringbuffer full?" << endl;
+
+// int toread = jack_ringbuffer_read_space(m_ringbuffer);
+// cerr << "CaptureThreadImplJACK::jackProcess " << characters_written/g_jack_sample_size << " values written, " << toread/g_jack_sample_size << " to read" << endl;
+
+// cerr << "~CaptureThreadImplJACK::jackProcess" << endl;
+
+ return 0;
+}
+
+void CaptureThreadImplJACK::capture_init()
+{
+ m_jack_client = jack_client_open(m_capture_thread->m_name.toAscii().constData(), JackNoStartServer, NULL);
+ if(!m_jack_client)
+ throw QString("JACK: cannot create client, JACK deamon is running ?");
+
+ jack_set_process_callback(m_jack_client, JackProcess, (void*)this);
+ jack_on_shutdown(m_jack_client, JackShutdown, (void*)this);
+ jack_set_sample_rate_callback(m_jack_client, JackSampleRate, (void*)this);
+
+ cerr << "CaptureThread: INFO: JACK: sampling rate=" << jack_get_sample_rate(m_jack_client) << endl;
+ m_ringbuffer = jack_ringbuffer_create(g_jack_sample_size*jack_get_sample_rate(m_jack_client)); // one second buffer
+
+ int err=0;
+ if((err=jack_activate(m_jack_client))!=0)
+ throw QString("JACK: cannot activate client");
+
+ setFormatDescrsAndFns(g_jack_sample_size, true, true, 1);
+
+ m_jack_port = jack_port_register(m_jack_client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput,0);
+
+ if(m_source!="")
+ {
+ QString dest = QString(jack_get_client_name(m_jack_client))+":input";
+ cerr << "CaptureThread: INFO: JACK: auto-connect '" << m_source.toStdString() << "' with '" << dest.toStdString() << "'" << endl;
+ if((err=jack_connect(m_jack_client, m_source.toAscii().constData(), dest.toAscii().constData()))!=0)
+ m_capture_thread->emitError(QString("JACK: Invalid source '")+m_source+"'");
+ }
+
+ int old_sampling_rate = m_sampling_rate;
+ m_sampling_rate = jack_get_sample_rate(m_jack_client);
+ if(m_sampling_rate!=old_sampling_rate)
+ m_capture_thread->emitSamplingRateChanged();
+
+ m_capture_thread->m_capturing = true;
+ m_capture_thread->emitCaptureStarted();
+ m_capture_thread->emitCaptureToggled(true);
+}
+void CaptureThreadImplJACK::capture_loop()
+{
+// cerr << "CaptureThreadImplJACK::capture_loop " << g_jack_sample_size << endl;
+
+ char dest[JACK_BUFF_SIZE*g_jack_sample_size];
+
+ m_wait_for_start = false;
+ while(m_loop && m_jack_client && m_jack_port && m_ringbuffer)
+ {
+// cerr << "CaptureThreadImplJACK::capture_loop toread=" << toread/g_jack_sample_size << endl;
+ int read = jack_ringbuffer_read(m_ringbuffer, dest, JACK_BUFF_SIZE*g_jack_sample_size);
+ if(read>0)
+ {
+ if(!m_capture_thread->m_pause)
+ {
+// cerr << "CaptureThreadImplJACK::capture_loop locking" << endl;
+ m_capture_thread->m_lock.lock();
+
+// int toread = jack_ringbuffer_read_space(m_ringbuffer);
+// cerr << "CaptureThreadImplJACK::capture_loop in deque='" << m_capture_thread->m_values.size() << "' still toread=" << toread/g_jack_sample_size << endl;
+
+ if(g_jack_sample_size==4)
+ for(int i=0; i<(read/g_jack_sample_size); i++)
+ addValue(this, (double)(((float*)dest)[i]), i);
+ else if(g_jack_sample_size==8)
+ for(int i=0; i<(read/g_jack_sample_size); i++)
+ addValue(this, (double)(((double*)dest)[i]), i);
+
+ m_capture_thread->m_packet_size = (read/g_jack_sample_size);
+ if(m_capture_thread->m_ext_lock)
+ {
+ m_capture_thread->m_packet_size_sll = 0;
+ m_capture_thread->m_ext_lock = false;
+ }
+ m_capture_thread->m_packet_size_sll += (read/g_jack_sample_size);
+
+ m_capture_thread->m_lock.unlock();
+// cerr << "CaptureThreadImplJACK::capture_loop unlocked" << endl;
+ }
+ }
+ else
+ msleep(10);
+ }
+
+// cerr << "~CaptureThreadImplJACK::capture_loop" << endl;
+}
+void CaptureThreadImplJACK::capture_finished()
+{
+// cerr << "CaptureThreadImplJACK::capture_finished" << endl;
+
+ if(m_jack_client!=NULL)
+ {
+ jack_client_close(m_jack_client);
+ m_jack_client = NULL;
+ if(m_ringbuffer)
+ {
+ jack_ringbuffer_free(m_ringbuffer);
+ m_ringbuffer = NULL;
+ }
+
+ m_capture_thread->m_capturing = false;
+ m_capture_thread->emitCaptureStoped();
+ m_capture_thread->emitCaptureToggled(false);
+ }
+}
+void CaptureThreadImplJACK::run()
+{
+// cerr << "CaptureThread: INFO: JACK: capture thread entered" << endl;
+
+// while(m_alive) // TODO need to keep alsa thread alive to let PortAudio working after ALSA !! TODO same for JACK ???
+ {
+ while(m_alive && !m_loop)
+ msleep(50);
+
+ m_in_run = true;
+
+ try
+ {
+// cerr << "CaptureThread: INFO: JACK: capture thread running" << endl;
+
+ capture_init();
+
+ m_capture_thread->m_capturing = true;
+ m_capture_thread->emitCaptureStarted();
+ m_capture_thread->emitCaptureToggled(true);
+
+ capture_loop();
+
+ m_capture_thread->m_capturing = false;
+ m_capture_thread->emitCaptureStoped();
+ m_capture_thread->emitCaptureToggled(false);
+ }
+ catch(QString error)
+ {
+ m_loop = false;
+ cerr << "CaptureThread: ERROR: " << error.toStdString() << endl;
+ m_capture_thread->emitError(error);
+ }
+ m_wait_for_start = false;
+
+ capture_finished();
+
+ m_in_run = false;
+
+// cerr << "CaptureThread: INFO: JACK: capture thread stop running" << endl;
+ }
+
+// cerr << "CaptureThread: INFO: JACK: capture thread exited" << endl;
+}
+CaptureThreadImplJACK::~CaptureThreadImplJACK()
+{
+// cerr << "CaptureThreadImplJACK::~CaptureThreadImplJACK" << endl;
+
+ m_alive = false;
+
+ stopCapture();
+
+ while(isRunning())
+ msleep(50);
+
+// cerr << "~CaptureThreadImplJACK::~CaptureThreadImplJACK" << endl;
+}
+#endif