SphinxBase 0.6

src/libsphinxad/ad_jack.c

00001 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
00002 /* ====================================================================
00003  * Copyright (c) 2011 Glenn Pierce.  All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer. 
00011  *
00012  * 2. Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in
00014  *    the documentation and/or other materials provided with the
00015  *    distribution.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY GLENN PIERCE ``AS IS'' AND 
00018  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
00019  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00020  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
00021  * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00022  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
00023  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
00024  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
00025  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
00026  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
00027  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  *
00029  * ====================================================================
00030  *
00031  */
00032 /* Sphinx II libad (Linux)
00033  * ^^^^^^^^^^^^^^^^^^^^^^^
00034  *
00035  *
00036  * Glenn Pierce (glennpierce@gmail.com)
00037  * ********************************************************************
00038  */
00039 
00040 #include <fcntl.h>
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include <string.h>
00044 #include <errno.h>
00045 #include <unistd.h>
00046 #include <config.h>
00047 #include <limits.h>
00048 
00049 #include "prim_type.h"
00050 #include "ad.h"
00051 
00052 #include <jack/jack.h>
00053 
00054 #define DEFAULT_DEVICE "system:capture_1"
00055 #define BUFFER_SIZE 352800
00056 
00057 //#define MIC_SPEAKER_PASSTHROUGH_DEBUG
00058 
00059 const size_t sample_size = sizeof(jack_default_audio_sample_t);
00060 const size_t int16_range_over_two = (-SHRT_MIN + SHRT_MAX) / 2.0;
00061 
00062 int
00063 process (jack_nframes_t nframes, void *arg)
00064 {
00065     ad_rec_t *handle = (ad_rec_t *) arg;
00066 
00067     size_t buffer_size = jack_ringbuffer_write_space (handle->rbuffer); 
00068 
00069     jack_default_audio_sample_t *in = (jack_default_audio_sample_t *) jack_port_get_buffer (handle->input_port, nframes);
00070     
00071     if (buffer_size <= 0) {
00072         fprintf(stderr, "JACK: buffer is full. Deactivating JACK client.\n");
00073         return 1;
00074     }
00075 
00076     // Write to jack ringbuffer which should be thread safe
00077     jack_ringbuffer_write (handle->rbuffer, (char*) in, sample_size * nframes);
00078 
00079 #ifdef MIC_SPEAKER_PASSTHROUGH_DEBUG
00080 
00081     jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (handle->output_port, nframes);
00082 
00083     // Output mic output to speakers (Just for testing)
00084     memcpy (out, in, sample_size * nframes);
00085 
00086 #endif
00087 
00088     return 0;      
00089 }
00090 
00091 void
00092 error (const char *desc)
00093 {
00094     fprintf (stderr, "JACK error: %s\n", desc);
00095 }
00096 
00097 void
00098 jack_shutdown (void *arg)
00099 {
00100     exit(1);
00101 }
00102 
00103 int
00104 srate (jack_nframes_t nframes, void *arg)
00105 
00106 {
00107     printf ("JACK: The sample rate is now %u/sec\n", nframes);
00108     return 0;
00109 }
00110 
00111 ad_rec_t *
00112 ad_open_dev(const char *dev, int32 sps)
00113 {
00114     ad_rec_t *handle;
00115     const char **ports;
00116 
00117 #ifdef HAVE_SAMPLERATE_H
00118     int resample_error;
00119     double samplerates_ratio;
00120     jack_nframes_t jack_samplerate;
00121 #endif
00122 
00123     if (dev == NULL) {
00124         dev = DEFAULT_DEVICE;
00125     }
00126 
00127     printf("JACK: Setting default device: %s\n", dev);
00128 
00129     if ((handle = (ad_rec_t *) calloc(1, sizeof(ad_rec_t))) == NULL) {
00130         fprintf(stderr, "calloc(%d) failed\n", (int)sizeof(ad_rec_t));
00131         abort();
00132     }
00133  
00134     /* Tell the JACK server to call error() whenever it
00135        experiences an error.  
00136     */
00137     jack_set_error_function (error);
00138 
00139     /* Try to become a client of the JACK server */
00140     if ((handle->client = jack_client_open ("jack_ad", (jack_options_t)0, NULL)) == 0) {
00141         fprintf (stderr, "jack server not running?\n");
00142         return NULL;
00143     }
00144 
00145 #ifdef HAVE_SAMPLERATE_H
00146     handle->resample_buffer = malloc(BUFFER_SIZE);
00147 
00148     jack_samplerate = jack_get_sample_rate(handle->client);
00149     samplerates_ratio = (double)((double)jack_samplerate / (double)sps);
00150     
00151     handle->rbuffer = jack_ringbuffer_create((int)((double)BUFFER_SIZE * samplerates_ratio));
00152     handle->sample_buffer = malloc((int)((double)BUFFER_SIZE * samplerates_ratio));
00153 #else
00154     handle->rbuffer = jack_ringbuffer_create(BUFFER_SIZE);
00155     handle->sample_buffer = malloc(BUFFER_SIZE);
00156 #endif
00157 
00158     if(handle->rbuffer == NULL) {
00159         fprintf (stderr, "Failed to create jack ringbuffer\n");
00160         return NULL;
00161     }
00162 
00163     /* Tell the JACK server to call `process()' whenever
00164        there is work to be done.
00165     */
00166     jack_set_process_callback (handle->client, process, handle);
00167 
00168     /* Tell the JACK server to call `srate()' whenever
00169        the sample rate of the system changes.
00170     */
00171     jack_set_sample_rate_callback (handle->client, srate, 0);
00172 
00173     /* Tell the JACK server to call `jack_shutdown()' if
00174        it ever shuts down, either entirely, or if it
00175        just decides to stop calling us.
00176     */
00177     jack_on_shutdown (handle->client, jack_shutdown, 0);
00178 
00179 
00180     /* Create the input port */
00181     if((handle->input_port = jack_port_register (handle->client, "jack_ad_input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0)) == 0) {
00182         fprintf (stderr, "cannot register input port!\n");
00183         return NULL;
00184     }
00185    
00186     if((handle->output_port = jack_port_register (handle->client, "jack_ad_output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical|JackPortIsOutput, 0)) == 0) {
00187         fprintf (stderr, "cannot register output port!\n");
00188         return NULL;
00189     }
00190  
00191     /* Tell the JACK server that we are ready to start */
00192     if (jack_activate (handle->client)) {
00193         fprintf (stderr, "cannot activate client");
00194         return NULL;
00195     }
00196 
00197     /* Connect the ports. Note: you can't do this before
00198        the client is activated, because we can't allow
00199        connections to be made to clients that aren't
00200        running.
00201     */
00202 
00203     if ((ports = jack_get_ports (handle->client, dev, NULL, JackPortIsOutput)) == NULL) {
00204         fprintf(stderr, "Cannot find any physical capture ports\n");
00205         return NULL;
00206     }
00207 
00208     if (jack_connect (handle->client, ports[0], jack_port_name (handle->input_port))) {
00209         fprintf (stderr, "cannot connect input ports\n");
00210         return NULL;
00211     }
00212 
00213     free (ports);
00214 
00215 #ifdef MIC_SPEAKER_PASSTHROUGH_DEBUG
00216     int i;
00217     if ((ports = jack_get_ports (handle->client, "system:playback", NULL,
00218                                JackPortIsPhysical|JackPortIsInput)) == NULL) {
00219         fprintf(stderr, "Cannot find any physical playback ports\n");
00220         return NULL;
00221     }
00222 
00223     for (i = 0; ports[i] != NULL; i++) {
00224         if (jack_connect (handle->client, jack_port_name (handle->output_port), ports[i])) {
00225             fprintf (stderr, "cannot connect output ports\n");
00226         }
00227     }
00228 
00229     free (ports);
00230 #endif
00231 
00232 #ifdef HAVE_SAMPLERATE_H
00233     // Initialize the sample rate converter.
00234     if ((handle->resample_state = src_new (SRC_SINC_BEST_QUALITY, 1, &resample_error)) == NULL) {
00235         fprintf (stderr, "Error : src_new() failed: %s\n", src_strerror(resample_error));
00236         return NULL;
00237     }
00238 #endif
00239 
00240     handle->recording = 0;
00241     handle->sps = sps;
00242     handle->bps = sizeof(int16);
00243 
00244     // Give the jack process callback time to run ?
00245     sleep (1);
00246 
00247     return (ad_rec_t *) handle;
00248 }
00249 
00250 ad_rec_t *
00251 ad_open_sps(int32 sps)
00252 {
00253     // Ignored the sps has to set for the jackd server
00254     return ad_open_dev(DEFAULT_DEVICE, sps);
00255 }
00256 
00257 ad_rec_t *
00258 ad_open(void)
00259 {
00260     return ad_open_sps(DEFAULT_SAMPLES_PER_SEC);
00261 }
00262 
00263 int32
00264 ad_close(ad_rec_t * handle)
00265 {
00266     free (handle->sample_buffer);
00267 #ifdef HAVE_SAMPLERATE_H
00268     free (handle->resample_buffer);
00269 #endif
00270     jack_ringbuffer_free (handle->rbuffer);     
00271     jack_client_close (handle->client);
00272     free(handle);
00273 
00274     return 0;
00275 }
00276 
00277 int32
00278 ad_start_rec(ad_rec_t * handle)
00279 {
00280     if (handle->recording)
00281         return AD_ERR_GEN;
00282 
00283     handle->recording = 1;
00284 
00285     return 0;
00286 }
00287 
00288 int32
00289 ad_stop_rec(ad_rec_t * handle)
00290 {
00291     handle->recording = 0;
00292 
00293     return 0;
00294 }
00295 
00296 int32
00297 ad_read(ad_rec_t * handle, int16 * buf, int32 max)
00298 {
00299 #ifdef HAVE_SAMPLERATE_H
00300     int resample_error;
00301 #endif
00302 
00303    if (!handle->recording)
00304        return AD_EOF;
00305 
00306    size_t length = sample_size * max;
00307 
00308 #ifdef HAVE_SAMPLERATE_H
00309 
00310    // Resample the data from the sample rate set in the jack server to that required 
00311    // by sphinx
00312 
00313    length = jack_ringbuffer_peek (handle->rbuffer, (char*) handle->sample_buffer, length);
00314    size_t length_in_samples = length / sample_size;
00315 
00316    if(handle->resample_state == NULL)
00317        return AD_EOF;
00318 
00319    // We will try to downsample if jackd is running at a higher sample rate
00320    jack_nframes_t jack_samplerate = jack_get_sample_rate(handle->client);
00321 
00322    SRC_DATA data;
00323 
00324    data.data_in = handle->sample_buffer;
00325    data.input_frames = length_in_samples;
00326    data.data_out = handle->resample_buffer;
00327    data.output_frames = BUFFER_SIZE / sample_size;
00328    data.src_ratio = (float) handle->sps / jack_samplerate;
00329    data.end_of_input = 0;
00330 
00331    if ((resample_error = src_process(handle->resample_state, &data)) != 0) {
00332        fprintf (stderr, "resample error %s\n", src_strerror (resample_error));
00333        return 1;
00334    }
00335 
00336    for(int i=0; i<data.output_frames_gen; i++) {
00337        buf[i] = (int16) (int16_range_over_two * (handle->resample_buffer[i] + 1.0) + SHRT_MIN);
00338    }
00339 
00340    jack_ringbuffer_read_advance(handle->rbuffer, data.input_frames_used * sample_size); 
00341 
00342    if(length == 0 && (!handle->recording)) {
00343        return AD_EOF;
00344    }
00345 
00346    return data.output_frames_gen;
00347 
00348 #else
00349 
00350    length = jack_ringbuffer_read (handle->rbuffer, (char*) handle->sample_buffer, length);
00351    size_t length_in_samples = length / sample_size;
00352 
00353    for(int i=0; i<length_in_samples; i++) {
00354        buf[i] = (int16) (int16_range_over_two * (handle->sample_buffer[i] + 1.0) + SHRT_MIN);
00355    }
00356 
00357    if(length == 0 && (!handle->recording)) {
00358        return AD_EOF;
00359    }
00360 
00361    return length_in_samples;
00362 
00363 #endif
00364 }