summaryrefslogtreecommitdiff
path: root/src/rmd_jack.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rmd_jack.c')
-rw-r--r--src/rmd_jack.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/src/rmd_jack.c b/src/rmd_jack.c
new file mode 100644
index 0000000..841017f
--- /dev/null
+++ b/src/rmd_jack.c
@@ -0,0 +1,209 @@
+/******************************************************************************
+* recordMyDesktop *
+*******************************************************************************
+* *
+* Copyright (C) 2006,2007,2008 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program 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 General Public License for more details. *
+* *
+* You should have received a copy of the GNU 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 *
+* *
+* *
+* *
+* For further information contact me at johnvarouhakis@gmail.com *
+******************************************************************************/
+
+#include "config.h"
+#include "rmd_jack.h"
+
+#include "rmd_types.h"
+
+#include <pthread.h>
+
+#include <string.h>
+
+#ifdef HAVE_LIBJACK
+
+
+/**
+* Callback for capture through jack
+*
+* \param nframes Number of frames captured
+*
+* \param jdata_t Pointer to JackData struct containing port
+* and client information
+*
+* \returns Zero always
+*/
+static int rmdJackCapture(jack_nframes_t nframes, void *jdata_t) {
+ JackData *jdata = (JackData *)jdata_t;
+
+ if (!jdata->pdata->running || jdata->pdata->paused || !jdata->capture_started)
+ return 0;
+
+ for(int i = 0; i < jdata->nports; i++)
+ jdata->portbuf[i] = jack_port_get_buffer(jdata->ports[i], nframes);
+
+
+ pthread_mutex_lock(jdata->sound_buffer_mutex);
+//vorbis analysis buffer wants uninterleaved data
+//so we are simply placing the buffers for every channel
+//sequentially on the ringbuffer
+ for(int i = 0; i < jdata->nports; i++)
+ jack_ringbuffer_write( jdata->sound_buffer,
+ (void *)(jdata->portbuf[i]),
+ nframes *
+ sizeof(jack_default_audio_sample_t));
+
+ pthread_cond_signal(jdata->sound_data_read);
+ pthread_mutex_unlock(jdata->sound_buffer_mutex);
+
+ return 0;
+}
+
+/**
+* Register and Activate specified ports
+*
+* \param jdata_t Pointer to JackData struct containing port
+* and client information
+*
+* \returns 0 on Success, 1 on failure
+*/
+static int rmdSetupPorts(JackData *jdata) {
+ jdata->ports = malloc(sizeof(jack_port_t *) * jdata->nports);
+ jdata->portbuf = malloc(sizeof(jack_default_audio_sample_t *) * jdata->nports);
+ memset(jdata->portbuf, 0, sizeof(jack_default_audio_sample_t *) * jdata->nports);
+
+ for(int i = 0; i < jdata->nports; i++) {
+ char name[64];//recordMyDesktop:input_n<64 is enough for full name
+ char num[8];
+ strcpy(name, "input_");
+ snprintf(num, 8, "%d", i + 1);
+ strcat(name, num);
+
+ jdata->ports[i] = jack_port_register( jdata->client,
+ name,
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsInput,
+ 0);
+
+ if (!jdata->ports[i]) {
+ fprintf(stderr, "Cannot register input port \"%s\"!\n", name);
+ return 1;
+ }
+
+ if (jack_connect(jdata->client, jdata->port_names[i], jack_port_name(jdata->ports[i]))) {
+
+ fprintf(stderr, "Cannot connect input port %s to %s\n",
+ jack_port_name(jdata->ports[i]),
+ jdata->port_names[i]);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+//in case the jack server shuts down
+//the program should stop recording,
+//encode the result(if not on the fly)
+//an exit cleanly.
+static void rmdJackShutdown(void *jdata_t) {
+ JackData *jdata = (JackData *)jdata_t;
+
+ jdata->pdata->running = FALSE;
+
+ fprintf (stderr, "JACK shutdown\n");
+}
+
+int rmdStartJackClient(JackData *jdata) {
+ float ring_buffer_size = 0.0;
+ int pid;
+ char pidbuf[8];
+ char rmd_client_name[32];
+
+ //construct the jack client name
+ //which is recordMyDesktop-pid
+ //in order to allow multiple
+ //instances of recordMyDesktop
+ //to connetc to a Jack Server
+ strcpy(rmd_client_name, "recordMyDesktop-");
+ pid = getpid();
+ snprintf( pidbuf, 8, "%d", pid );
+ strcat(rmd_client_name, pidbuf);
+
+ if ((jdata->client = jack_client_new(rmd_client_name)) == 0) {
+ fprintf(stderr, "Could not create new client!\n"
+ "Make sure that Jack server is running!\n");
+ return 15;
+ }
+//in contrast to ALSA and OSS, Jack dictates frequency
+//and buffersize to the values it was launched with.
+//Supposedly jack_set_buffer_size can set the buffersize
+//but that causes some kind of halt and keeps giving me
+//zero buffers.
+//recordMyDesktop cannot handle buffer size changes.
+//FIXME
+//There is a callback for buffer size changes that I should use.
+//It will provide clean exits, instead of ?segfaults? .
+//Continuing though is not possible, with the current layout
+//(it might be in some cases, but it will certainly be the cause
+//of unpredicted problems). A clean exit is preferable
+//and any recording up to that point will be encoded and saved.
+ jdata->frequency = jack_get_sample_rate(jdata->client);
+ jdata->buffersize = jack_get_buffer_size(jdata->client);
+ ring_buffer_size = ( jdata->ringbuffer_secs*
+ jdata->frequency*
+ sizeof(jack_default_audio_sample_t)*
+ jdata->nports);
+ jdata->sound_buffer = jack_ringbuffer_create((int)(ring_buffer_size+0.5));//round up
+ jack_set_process_callback(jdata->client, rmdJackCapture, jdata);
+ jack_on_shutdown(jdata->client, rmdJackShutdown, jdata);
+
+ if (jack_activate(jdata->client)) {
+ fprintf(stderr, "cannot activate client!\n");
+ return 16;
+ }
+
+ if (rmdSetupPorts(jdata)) {
+ jack_client_close(jdata->client);
+ return 17;
+ }
+
+ return 0;
+}
+
+int rmdStopJackClient(JackData *jdata) {
+ int ret = 0;
+
+ jack_ringbuffer_free(jdata->sound_buffer);
+ if (jack_client_close(jdata->client)) {
+ fprintf(stderr, "Cannot close Jack client!\n");
+ ret = 1;
+ }
+
+/*TODO*/
+//I need to make some kind of program/thread
+//flow diagram to see where it's safe to dlclose
+//because here it causes a segfault.
+
+// if (dlclose(jdata->jack_lib_handle)) {
+// fprintf(stderr, "Cannot unload Jack library!\n");
+// ret=1;
+// }
+// else fprintf(stderr, "Unloaded Jack library.\n");
+
+ return ret;
+}
+
+#endif
© All Rights Reserved