diff options
Diffstat (limited to 'src/rmd_jack.c')
-rw-r--r-- | src/rmd_jack.c | 209 |
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 |