Hello,
I corrected a bug and did some little optimizations in app_jack.c.

It works great now.

I propose this new file based on revision 140568.

Fabien

/*
 * Asterisk -- An open source telephony toolkit.
 *
 * Copyright (C) 2007 - 2008, Russell Bryant
 *
 * Russell Bryant <russ...@digium.com>
 *
 * See http://www.asterisk.org for more information about
 * the Asterisk project. Please do not directly contact
 * any of the maintainers of this project for assistance;
 * the project provides a web site, mailing lists and IRC
 * channels for your use.
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */

/*!
 * \file
 * \brief Jack Application
 *
 * \author Russell Bryant <russ...@digium.com>
 *
 * This is an application to connect an Asterisk channel to an input
 * and output jack port so that the audio can be processed through
 * another application, or to play audio from another application.
 *
 * \arg http://www.jackaudio.org/
 *
 * \note To install libresample, check it out of the following repository:
 * <code>$ svn co
http://svn.digium.com/svn/thirdparty/libresample/trunk</code>
 *
 * \ingroup applications
 */

/*** MODULEINFO
        <depend>jack</depend>
        <depend>resample</depend>
 ***/

#include "asterisk.h"

ASTERISK_FILE_VERSION(__FILE__, "$Revision: 140568 $")

#include <limits.h>

#include <jack/jack.h>
#include <jack/ringbuffer.h>

#include <libresample.h>

#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/strings.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/audiohook.h"

#define RESAMPLE_QUALITY 1

#define RINGBUFFER_SIZE 16384

/*! \brief Common options between the Jack() app and JACK_HOOK() function */
#define COMMON_OPTIONS \
"    s(<name>) - Connect to the specified jack server name.\n" \
"    i(<name>) - Connect the output port that gets created to the
specified\n" \
"                jack input port.\n" \
"    o(<name>) - Connect the input port that gets created to the
specified\n" \
"                jack output port.\n" \
"    n         - Do not automatically start the JACK server if it is not
already\n" \
"                running.\n" \
"    c(<name>) - By default, Asterisk will use the channel name for the jack
client\n" \
"                name.  Use this option to specify a custom client name.\n"

static char *jack_app = "JACK";
static char *jack_synopsis = 
"JACK (Jack Audio Connection Kit) Application";
static char *jack_desc = 
"JACK([options])\n"
"  When this application is executed, two jack ports will be created; one
input\n"
"and one output.  Other applications can be hooked up to these ports to
access\n"
"the audio coming from, or being sent to the channel.\n"
"  Valid options:\n"
COMMON_OPTIONS
"";

struct jack_data {
        AST_DECLARE_STRING_FIELDS(
                AST_STRING_FIELD(server_name);
                AST_STRING_FIELD(client_name);
                AST_STRING_FIELD(connect_input_port);
                AST_STRING_FIELD(connect_output_port);
        );
        jack_client_t *client;
        jack_port_t *input_port;
        jack_port_t *output_port;
        jack_ringbuffer_t *input_rb;
        jack_ringbuffer_t *output_rb;
        void *output_resampler;
        double output_resample_factor;
        void *input_resampler;
        double input_resample_factor;
        unsigned int stop:1;
        unsigned int has_audiohook:1;
        unsigned int no_start_server:1;
        /*! Only used with JACK_HOOK */
        struct ast_audiohook audiohook;
};

static const struct {
        jack_status_t status;
        const char *str;
} jack_status_table[] = {
        { JackFailure,        "Failure" },
        { JackInvalidOption,  "Invalid Option" },
        { JackNameNotUnique,  "Name Not Unique" },
        { JackServerStarted,  "Server Started" },
        { JackServerFailed,   "Server Failed" },
        { JackServerError,    "Server Error" },
        { JackNoSuchClient,   "No Such Client" },
        { JackLoadFailure,    "Load Failure" },
        { JackInitFailure,    "Init Failure" },
        { JackShmFailure,     "Shared Memory Access Failure" },
        { JackVersionError,   "Version Mismatch" },
};

static const char *jack_status_to_str(jack_status_t status)
{
        int i;

        for (i = 0; i < ARRAY_LEN(jack_status_table); i++) {
                if (jack_status_table[i].status == status)
                        return jack_status_table[i].str;
        }

        return "Unknown Error";
}

static void log_jack_status(const char *prefix, jack_status_t status)
{
        struct ast_str *str = ast_str_alloca(512);
        int i, first = 0;

        for (i = 0; i < (sizeof(status) * 8); i++) {
                if (!(status & (1 << i)))
                        continue;

                if (!first) {
                        ast_str_set(&str, 0, "%s", jack_status_to_str((1 <<
i)));
                        first = 1;
                } else
                        ast_str_append(&str, 0, ", %s",
jack_status_to_str((1 << i)));
        }
        
        ast_log(LOG_NOTICE, "%s: %s\n", prefix, str->str);
}

static int alloc_resampler(struct jack_data *jack_data, int input)
{
        double from_srate, to_srate, jack_srate;
        void **resampler;
        double *resample_factor;

        if (input && jack_data->input_resampler)
                return 0;

        if (!input && jack_data->output_resampler)
                return 0;

        jack_srate = jack_get_sample_rate(jack_data->client);

        /* XXX Hard coded 8 kHz */

        to_srate = input ? 8000.0 : jack_srate; 
        from_srate = input ? jack_srate : 8000.0;

        resample_factor = input ? &jack_data->input_resample_factor : 
                &jack_data->output_resample_factor;

        if (from_srate == to_srate) {
                /* Awesome!  The jack sample rate is the same as ours.
                 * Resampling isn't needed. */
                *resample_factor = 1.0;
                return 0;
        }

        *resample_factor = to_srate / from_srate;

        resampler = input ? &jack_data->input_resampler :
                &jack_data->output_resampler;

        if (!(*resampler = resample_open(RESAMPLE_QUALITY, 
                *resample_factor, *resample_factor))) {
                ast_log(LOG_ERROR, "Failed to open %s resampler\n", 
                        input ? "input" : "output");
                return -1;
        }

        return 0;
}

/*!
 * \brief Handle jack input port
 *
 * Read nframes number of samples from the input buffer, resample it
 * if necessary, and write it into the appropriate ringbuffer. 
 */
static void handle_input(void *buf, jack_nframes_t nframes, 
        struct jack_data *jack_data)
{
        short s_buf[nframes];
        float *in_buf = buf;
        size_t res;
        int i;
        size_t write_len = sizeof(s_buf);

        if (jack_data->input_resampler) {
                int total_in_buf_used = 0;
                int total_out_buf_used = 0;
                float f_buf[nframes + 1];

                memset(f_buf, 0, sizeof(f_buf));

                while (total_in_buf_used < nframes) {
                        int in_buf_used;
                        int out_buf_used;

                        out_buf_used =
resample_process(jack_data->input_resampler,
                                jack_data->input_resample_factor,
                                &in_buf[total_in_buf_used], nframes -
total_in_buf_used,
                                0, &in_buf_used,
                                &f_buf[total_out_buf_used], ARRAY_LEN(f_buf)
- total_out_buf_used);

                        if (out_buf_used < 0)
                                break;

                        total_out_buf_used += out_buf_used;
                        total_in_buf_used += in_buf_used;
        
                        if (total_out_buf_used == ARRAY_LEN(f_buf)) {
                                ast_log(LOG_ERROR, "Output buffer filled ...
need to increase its size, "
                                        "nframes '%d', total_out_buf_used
'%d'\n", nframes, total_out_buf_used);
                                break;
                        }
                }

                for (i = 0; i < total_out_buf_used; i++)
                        s_buf[i] = ((float) f_buf[i]) * ((float) SHRT_MAX);
                
                write_len = total_out_buf_used * sizeof(int16_t);
        } else {
                /* No resampling needed */

                for (i = 0; i < nframes; i++)
                        s_buf[i] = ((float) in_buf[i]) * ((float) SHRT_MAX);
        }

        res = jack_ringbuffer_write(jack_data->input_rb, (const char *)
s_buf, write_len);
        if (res != write_len) {
                ast_debug(2, "Tried to write %d bytes to the ringbuffer, but
only wrote %d\n",
                        (int) sizeof(s_buf), (int) res);
        }
}

/*!
 * \brief Handle jack output port
 *
 * Read nframes number of samples from the ringbuffer and write it out to
the
 * output port buffer.
 */
static void handle_output(void *buf, jack_nframes_t nframes, 
        struct jack_data *jack_data)
{
        size_t res, len;

        len = nframes * sizeof(float);

        res = jack_ringbuffer_read(jack_data->output_rb, buf, len);

        if (len != res) {
                ast_debug(2, "Wanted %d bytes to send to the output port, "
                        "but only got %d\n", (int) len, (int) res);
        }
}

static int jack_process(jack_nframes_t nframes, void *arg)
{
        struct jack_data *jack_data = arg;
        void *input_port_buf, *output_port_buf;

        if (!jack_data->input_resample_factor)
                alloc_resampler(jack_data, 1);

        input_port_buf = jack_port_get_buffer(jack_data->input_port,
nframes);
        handle_input(input_port_buf, nframes, jack_data);

        output_port_buf = jack_port_get_buffer(jack_data->output_port,
nframes);
        handle_output(output_port_buf, nframes, jack_data);

        return 0;
}

static void jack_shutdown(void *arg)
{
        struct jack_data *jack_data = arg;

        jack_data->stop = 1;
}

static struct jack_data *destroy_jack_data(struct jack_data *jack_data)
{
        if (jack_data->input_port) {
                jack_port_unregister(jack_data->client,
jack_data->input_port);
                jack_data->input_port = NULL;
        }

        if (jack_data->output_port) {
                jack_port_unregister(jack_data->client,
jack_data->output_port);
                jack_data->output_port = NULL;
        }

        if (jack_data->client) {
                jack_client_close(jack_data->client);
                jack_data->client = NULL;
        }

        if (jack_data->input_rb) {
                jack_ringbuffer_free(jack_data->input_rb);
                jack_data->input_rb = NULL;
        }

        if (jack_data->output_rb) {
                jack_ringbuffer_free(jack_data->output_rb);
                jack_data->output_rb = NULL;
        }

        if (jack_data->output_resampler) {
                resample_close(jack_data->output_resampler);
                jack_data->output_resampler = NULL;
        }
        
        if (jack_data->input_resampler) {
                resample_close(jack_data->input_resampler);
                jack_data->input_resampler = NULL;
        }

        if (jack_data->has_audiohook)
                ast_audiohook_destroy(&jack_data->audiohook);

        ast_string_field_free_memory(jack_data);

        ast_free(jack_data);

        return NULL;
}

static int init_jack_data(struct ast_channel *chan, struct jack_data
*jack_data)
{
        const char *client_name;
        jack_status_t status = 0;
        jack_options_t jack_options = JackNullOption;

        if (!ast_strlen_zero(jack_data->client_name)) {
                client_name = jack_data->client_name;
        } else {
                ast_channel_lock(chan);
                client_name = ast_strdupa(chan->name);
                ast_channel_unlock(chan);
        }

        if (!(jack_data->output_rb = jack_ringbuffer_create(RINGBUFFER_SIZE
* 2)))
                return -1;

        if (!(jack_data->input_rb =
jack_ringbuffer_create(RINGBUFFER_SIZE)))
                return -1;

        if (jack_data->no_start_server)
                jack_options |= JackNoStartServer;

        if (!ast_strlen_zero(jack_data->server_name)) {
                jack_options |= JackServerName;
                jack_data->client = jack_client_open(client_name,
jack_options, &status,
                        jack_data->server_name);
        } else {
                jack_data->client = jack_client_open(client_name,
jack_options, &status);
        }

        if (status)
                log_jack_status("Client Open Status", status);

        if (!jack_data->client)
                return -1;

        jack_data->input_port = jack_port_register(jack_data->client,
"input",
                JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput |
JackPortIsTerminal, 0);
        if (!jack_data->input_port) {
                ast_log(LOG_ERROR, "Failed to create input port for jack
port\n");
                return -1;
        }

        jack_data->output_port = jack_port_register(jack_data->client,
"output",
                JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput |
JackPortIsTerminal, 0);
        if (!jack_data->output_port) {
                ast_log(LOG_ERROR, "Failed to create output port for jack
port\n");
                return -1;
        }

        if (jack_set_process_callback(jack_data->client, jack_process,
jack_data)) {
                ast_log(LOG_ERROR, "Failed to register process callback with
jack client\n");
                return -1;
        }

        jack_on_shutdown(jack_data->client, jack_shutdown, jack_data);

        if (jack_activate(jack_data->client)) {
                ast_log(LOG_ERROR, "Unable to activate jack client\n");
                return -1;
        }

        while (!ast_strlen_zero(jack_data->connect_input_port)) {
                const char **ports;
                int i;

                ports = jack_get_ports(jack_data->client,
jack_data->connect_input_port,
                        NULL, JackPortIsInput);

                if (!ports) {
                        ast_log(LOG_ERROR, "No input port matching '%s' was
found\n",
                                jack_data->connect_input_port);
                        break;
                }

                for (i = 0; ports[i]; i++) {
                        ast_debug(1, "Found port '%s' that matched specified
input port '%s'\n",
                                ports[i], jack_data->connect_input_port);
                }

                if (jack_connect(jack_data->client,
jack_port_name(jack_data->output_port), ports[0])) {
                        ast_log(LOG_ERROR, "Failed to connect '%s' to
'%s'\n", ports[0],
                                jack_port_name(jack_data->output_port));
                } else {
                        ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
                                jack_port_name(jack_data->output_port));
                }

                free((void *) ports);

                break;
        }

        while (!ast_strlen_zero(jack_data->connect_output_port)) {
                const char **ports;
                int i;

                ports = jack_get_ports(jack_data->client,
jack_data->connect_output_port,
                        NULL, JackPortIsOutput);

                if (!ports) {
                        ast_log(LOG_ERROR, "No output port matching '%s' was
found\n",
                                jack_data->connect_output_port);
                        break;
                }

                for (i = 0; ports[i]; i++) {
                        ast_debug(1, "Found port '%s' that matched specified
output port '%s'\n",
                                ports[i], jack_data->connect_output_port);
                }

                if (jack_connect(jack_data->client, ports[0],
jack_port_name(jack_data->input_port))) {
                        ast_log(LOG_ERROR, "Failed to connect '%s' to
'%s'\n", ports[0],
                                jack_port_name(jack_data->input_port));
                } else {
                        ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
                                jack_port_name(jack_data->input_port));
                }

                free((void *) ports);

                break;
        }

        return 0;
}

static int queue_voice_frame(struct jack_data *jack_data, struct ast_frame
*f)
{
        float f_buf[f->samples * 8];
        size_t f_buf_used = 0;
        int i;
        int16_t *s_buf = f->data.ptr;
        size_t res;

        // memset(f_buf, 0, sizeof(f_buf)); // not needed if no resample

        if (!jack_data->output_resample_factor)
                alloc_resampler(jack_data, 0);

        if (jack_data->output_resampler) {              
                float in_buf[f->samples];
                int total_in_buf_used = 0;
                int total_out_buf_used = 0;

                memset(f_buf, 0, sizeof(f_buf));

                // memset(in_buf, 0, sizeof(in_buf)); // not needed (see the
next for)

                for (i = 0; i < f->samples; i++)
                        in_buf[i] = ((float) s_buf[i]) / ((float) SHRT_MAX);

                while (total_in_buf_used < ARRAY_LEN(in_buf)) {
                        int in_buf_used;
                        int out_buf_used;

                        out_buf_used =
resample_process(jack_data->output_resampler, 
                                jack_data->output_resample_factor,
                                &in_buf[total_in_buf_used],
ARRAY_LEN(in_buf) - total_in_buf_used, 
                                0, &in_buf_used, 
                                &f_buf[total_out_buf_used], ARRAY_LEN(f_buf)
- total_out_buf_used);

                        if (out_buf_used < 0)
                                break;

                        total_out_buf_used += out_buf_used;
                        total_in_buf_used += in_buf_used;

                        if (total_out_buf_used == ARRAY_LEN(f_buf)) {
                                ast_log(LOG_ERROR, "Output buffer filled ...
need to increase its size\n");
                                break;
                        }
                }

                f_buf_used = total_out_buf_used;
                if (f_buf_used > ARRAY_LEN(f_buf))
                        f_buf_used = ARRAY_LEN(f_buf);
        } else {
                /* No resampling needed */

                for (i = 0; i < f->samples; i++)
                        f_buf[i] = ((float) s_buf[i]) / ((float) SHRT_MAX);

                f_buf_used = f->samples;
        }

        res = jack_ringbuffer_write(jack_data->output_rb, (const char *)
f_buf, f_buf_used * sizeof(float));
        if (res != (f_buf_used * sizeof(float))) {
                ast_debug(2, "Tried to write %d bytes to the ringbuffer, but
only wrote %d\n",
                        (int) (f_buf_used * sizeof(float)), (int) res);
        }

        return 0;
}

/*!
 * \brief handle jack audio
 *
 * \param[in]  chan The Asterisk channel to write the frames to if no output
frame
 *             is provided.
 * \param[in]  jack_data This is the jack_data struct that contains the
input
 *             ringbuffer that audio will be read from.
 * \param[out] out_frame If this argument is non-NULL, then assuming there
is
 *             enough data avilable in the ringbuffer, the audio in this
frame
 *             will get replaced with audio from the input buffer.  If there
is
 *             not enough data available to read at this time, then the
frame
 *             data gets zeroed out.
 *
 * Read data from the input ringbuffer, which is the properly resampled
audio
 * that was read from the jack input port.  Write it to the channel in 20 ms
frames,
 * or fill up an output frame instead if one is provided.
 *
 * \return Nothing.
 */
static void handle_jack_audio(struct ast_channel *chan, struct jack_data
*jack_data,
        struct ast_frame *out_frame)
{       
        short buf[160];
        struct ast_frame f = {
                .frametype = AST_FRAME_VOICE,
                .subclass = AST_FORMAT_SLINEAR,
                .src = "JACK",
                .data.ptr = buf,
                .datalen = sizeof(buf),
                .samples = ARRAY_LEN(buf),
        };

        for (;;) {
                size_t res, read_len;
                char *read_buf;

                read_len = out_frame ? out_frame->datalen : sizeof(buf);
                read_buf = out_frame ? out_frame->data.ptr : buf;

                res = jack_ringbuffer_read_space(jack_data->input_rb);

                if (res < read_len) {
                        /* Not enough data ready for another frame, move on
... */
                        if (out_frame) {
                                ast_debug(1, "Sending an empty frame for the
JACK_HOOK\n");
                                memset(out_frame->data.ptr, 0,
out_frame->datalen);
                        }
                        break;
                }

                res = jack_ringbuffer_read(jack_data->input_rb, (char *)
read_buf, read_len);

                if (res < read_len) {
                        ast_log(LOG_ERROR, "Error reading from ringbuffer,
even though it said there was enough data\n");
                        break;
                }

                if (out_frame) {
                        /* If an output frame was provided, then we just
want to fill up the
                         * buffer in that frame and return. */
                        break;
                }

                ast_write(chan, &f);
        }
}

enum {
        OPT_SERVER_NAME =    (1 << 0),
        OPT_INPUT_PORT =     (1 << 1),
        OPT_OUTPUT_PORT =    (1 << 2),
        OPT_NOSTART_SERVER = (1 << 3),
        OPT_CLIENT_NAME =    (1 << 4),
};

enum {
        OPT_ARG_SERVER_NAME,
        OPT_ARG_INPUT_PORT,
        OPT_ARG_OUTPUT_PORT,
        OPT_ARG_CLIENT_NAME,

        /* Must be the last element */
        OPT_ARG_ARRAY_SIZE,
};

AST_APP_OPTIONS(jack_exec_options, BEGIN_OPTIONS
        AST_APP_OPTION_ARG('s', OPT_SERVER_NAME, OPT_ARG_SERVER_NAME),
        AST_APP_OPTION_ARG('i', OPT_INPUT_PORT, OPT_ARG_INPUT_PORT),
        AST_APP_OPTION_ARG('o', OPT_OUTPUT_PORT, OPT_ARG_OUTPUT_PORT),
        AST_APP_OPTION('n', OPT_NOSTART_SERVER),
        AST_APP_OPTION_ARG('c', OPT_CLIENT_NAME, OPT_ARG_CLIENT_NAME),
END_OPTIONS );

static struct jack_data *jack_data_alloc(void)
{
        struct jack_data *jack_data;

        if (!(jack_data = ast_calloc(1, sizeof(*jack_data))))
                return NULL;
        
        if (ast_string_field_init(jack_data, 32)) {
                ast_free(jack_data);
                return NULL;
        }

        return jack_data;
}

/*!
 * \note This must be done before calling init_jack_data().
 */
static int handle_options(struct jack_data *jack_data, const char
*__options_str)
{
        struct ast_flags options = { 0, };
        char *option_args[OPT_ARG_ARRAY_SIZE];
        char *options_str;

        options_str = ast_strdupa(__options_str);

        ast_app_parse_options(jack_exec_options, &options, option_args,
options_str);

        if (ast_test_flag(&options, OPT_SERVER_NAME)) {
                if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME]))
                        ast_string_field_set(jack_data, server_name,
option_args[OPT_ARG_SERVER_NAME]);
                else {
                        ast_log(LOG_ERROR, "A server name must be provided
with the s() option\n");
                        return -1;
                }
        }

        if (ast_test_flag(&options, OPT_CLIENT_NAME)) {
                if (!ast_strlen_zero(option_args[OPT_ARG_CLIENT_NAME]))
                        ast_string_field_set(jack_data, client_name,
option_args[OPT_ARG_CLIENT_NAME]);
                else {
                        ast_log(LOG_ERROR, "A client name must be provided
with the c() option\n");
                        return -1;
                }
        }

        if (ast_test_flag(&options, OPT_INPUT_PORT)) {
                if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT]))
                        ast_string_field_set(jack_data, connect_input_port,
option_args[OPT_ARG_INPUT_PORT]);
                else {
                        ast_log(LOG_ERROR, "A name must be provided with the
i() option\n");
                        return -1;
                }
        }

        if (ast_test_flag(&options, OPT_OUTPUT_PORT)) {
                if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT]))
                        ast_string_field_set(jack_data, connect_output_port,
option_args[OPT_ARG_OUTPUT_PORT]);
                else {
                        ast_log(LOG_ERROR, "A name must be provided with the
o() option\n");
                        return -1;
                }
        }

        jack_data->no_start_server = ast_test_flag(&options,
OPT_NOSTART_SERVER) ? 1 : 0;

        return 0;
}

static int jack_exec(struct ast_channel *chan, void *data)
{
        struct jack_data *jack_data;
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(options);
        );

        if (!(jack_data = jack_data_alloc()))
                return -1;

        args.options = data;

        if (!ast_strlen_zero(args.options) && handle_options(jack_data,
args.options)) {
                destroy_jack_data(jack_data);
                return -1;
        }

        if (init_jack_data(chan, jack_data)) {
                destroy_jack_data(jack_data);
                return -1;
        }

        if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
                destroy_jack_data(jack_data);
                return -1;
        }

        if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
                destroy_jack_data(jack_data);
                return -1;
        }

        while (!jack_data->stop) {
                struct ast_frame *f;

                ast_waitfor(chan, -1);

                f = ast_read(chan);
                if (!f) {
                        jack_data->stop = 1;
                        continue;
                }

                switch (f->frametype) {
                case AST_FRAME_CONTROL:
                        if (f->subclass == AST_CONTROL_HANGUP)
                                jack_data->stop = 1;
                        break;
                case AST_FRAME_VOICE:
                        queue_voice_frame(jack_data, f);
                default:
                        break;
                }

                ast_frfree(f);

                handle_jack_audio(chan, jack_data, NULL);
        }

        jack_data = destroy_jack_data(jack_data);

        return 0;
}

static void jack_hook_ds_destroy(void *data)
{
        struct jack_data *jack_data = data;

        destroy_jack_data(jack_data);
}

static const struct ast_datastore_info jack_hook_ds_info = {
        .type = "JACK_HOOK",
        .destroy = jack_hook_ds_destroy,
};

static int jack_hook_callback(struct ast_audiohook *audiohook, struct
ast_channel *chan, 
        struct ast_frame *frame, enum ast_audiohook_direction direction)
{
        struct ast_datastore *datastore;
        struct jack_data *jack_data;

        if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
                return 0;

        if (frame->frametype != AST_FRAME_VOICE)
                return 0;

        if (frame->subclass != AST_FORMAT_SLINEAR) 
        {
                ast_log(LOG_WARNING, "Expected frame in SLINEAR for the
audiohook, but got format %d\n",
                                frame->subclass);
                return 0;
        }

        ast_channel_lock(chan);

        if (!(datastore = ast_channel_datastore_find(chan,
&jack_hook_ds_info, NULL))) {
                ast_log(LOG_ERROR, "JACK_HOOK datastore not found for
'%s'\n", chan->name);
                ast_channel_unlock(chan);
                return -1;
        }

        jack_data = datastore->data;

        if (direction != AST_AUDIOHOOK_DIRECTION_READ)
        {
                queue_voice_frame(jack_data, frame);
        }
        else
        {
                handle_jack_audio(chan, jack_data, frame);
        }

        ast_channel_unlock(chan);

        return 0;
}

static int enable_jack_hook(struct ast_channel *chan, char *data)
{
        struct ast_datastore *datastore;
        struct jack_data *jack_data = NULL;
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(mode);
                AST_APP_ARG(options);
        );

        AST_STANDARD_APP_ARGS(args, data);

        ast_channel_lock(chan);

        if ((datastore = ast_channel_datastore_find(chan,
&jack_hook_ds_info, NULL))) {
                ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n",
chan->name);
                goto return_error;
        }

        if (ast_strlen_zero(args.mode) || strcasecmp(args.mode,
"manipulate")) {
                ast_log(LOG_ERROR, "'%s' is not a supported mode.  Only
manipulate is supported.\n", 
                        S_OR(args.mode, "<none>"));
                goto return_error;
        }

        if (!(jack_data = jack_data_alloc()))
                goto return_error;

        if (!ast_strlen_zero(args.options) && handle_options(jack_data,
args.options))
                goto return_error;

        if (init_jack_data(chan, jack_data))
                goto return_error;

        if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL)))
                goto return_error;

        jack_data->has_audiohook = 1;
        ast_audiohook_init(&jack_data->audiohook,
AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK");
        jack_data->audiohook.manipulate_callback = jack_hook_callback;

        datastore->data = jack_data;

        if (ast_audiohook_attach(chan, &jack_data->audiohook))
                goto return_error;

        if (ast_channel_datastore_add(chan, datastore))
                goto return_error;

        ast_channel_unlock(chan);

        return 0;

return_error:
        ast_channel_unlock(chan);

        if (jack_data)
                destroy_jack_data(jack_data);

        return -1;
}

static int disable_jack_hook(struct ast_channel *chan)
{
        struct ast_datastore *datastore;
        struct jack_data *jack_data;

        ast_channel_lock(chan);

        if (!(datastore = ast_channel_datastore_find(chan,
&jack_hook_ds_info, NULL))) {
                ast_channel_unlock(chan);
                ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n");
                return -1;
        }

        ast_channel_datastore_remove(chan, datastore);

        jack_data = datastore->data;
        ast_audiohook_detach(&jack_data->audiohook);

        /* Keep the channel locked while we destroy the datastore, so that
we can
         * ensure that all of the jack stuff is stopped just in case another
frame
         * tries to come through the audiohook callback. */
        ast_datastore_free(datastore);

        ast_channel_unlock(chan);

        return 0;
}

static int jack_hook_write(struct ast_channel *chan, const char *cmd, char
*data, 
        const char *value)
{
        int res;

        if (!strcasecmp(value, "on"))
                res = enable_jack_hook(chan, data);
        else if (!strcasecmp(value, "off"))
                res = disable_jack_hook(chan);
        else {
                ast_log(LOG_ERROR, "'%s' is not a valid value for
JACK_HOOK()\n", value); 
                res = -1;
        }

        return res;
}

static struct ast_custom_function jack_hook_function = {
        .name = "JACK_HOOK",
        .synopsis = "Enable a jack hook on a channel",
        .syntax = "JACK_HOOK(<mode>,[options])",
        .desc =
        "   The JACK_HOOK allows turning on or off jack connectivity to this
channel.\n"
        "When the JACK_HOOK is turned on, jack ports will get created that
allow\n"
        "access to the audio stream for this channel.  The mode specifies
which mode\n"
        "this hook should run in.  A mode must be specified when turning the
JACK_HOOK.\n"
        "on.  However, all arguments are optional when turning it off.\n"
        "\n"
        "   Valid modes are:\n"
#if 0
        /* XXX TODO */
        "    spy -        Create a read-only audio hook.  Only an output
jack port will\n"
        "                 get created.\n"
        "    whisper -    Create a write-only audio hook.  Only an input
jack port will\n"
        "                 get created.\n"
#endif
        "    manipulate - Create a read/write audio hook.  Both an input and
an output\n"
        "                 jack port will get created.  Audio from the
channel will be\n"
        "                 sent out the output port and will be replaced by
the audio\n"
        "                 coming in on the input port as it gets passed
on.\n"
        "\n"
        "   Valid options are:\n"
        COMMON_OPTIONS
        "\n"
        " Examples:\n"
        "   To turn on the JACK_HOOK,\n"
        "
Set(JACK_HOOK(manipulate,i(pure_data_0:input0)o(pure_data_0:output0))=on)\n"
        "   To turn off the JACK_HOOK,\n"
        "     Set(JACK_HOOK()=off)\n"
        "",
        .write = jack_hook_write,
};

static int unload_module(void)
{
        int res;

        res = ast_unregister_application(jack_app);
        res |= ast_custom_function_unregister(&jack_hook_function);

        return res;
}

static int load_module(void)
{
        if (ast_register_application(jack_app, jack_exec, jack_synopsis,
jack_desc)) {
                return AST_MODULE_LOAD_DECLINE;
        }

        if (ast_custom_function_register(&jack_hook_function)) {
                ast_unregister_application(jack_app);
                return AST_MODULE_LOAD_DECLINE;
        }

        return AST_MODULE_LOAD_SUCCESS;
}

AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "JACK Interface");


-----Message d'origine-----
De : asterisk-dev-boun...@lists.digium.com
[mailto:asterisk-dev-boun...@lists.digium.com] De la part de Fabien COMTE
Envoyé : lundi 5 octobre 2009 16:18
À : asterisk-users@lists.digium.com; asterisk-...@lists.digium.com
Objet : [asterisk-dev] Questions about app_jack.c

Hello,

My configuration is :
Card 0 - kernel dummy sound card
Card 1 - my soundcard

I have a jackd running in background. My jackd launch command is :
jackd --port-max 16 --realtime --no-mlock -d alsa --playback hw:1,0
--capture hw:1,0 --rate 8000 --period 1024 --shorts --inchannels 2
--outchannels 2 --dither triangular &

1 ) I open asterisk with chan_alsa.so connected (with asoundrc) to the
kernel dummy sound card (allow me dial command). I do a call with a
JACK_HOOK from app_jack.so, sound is sent but no one is received.

My extensions.conf :
exten => _0.,1,Answer 
exten =>
_0.,n,Set(JACK_HOOK(manipulate,c(asterisk))i(from_voip:input)o(to_voip:outpu
t)))=on)
exten => _0.,n,Dial(SIP/freephonie-out/${EXTEN:1})

Asterisk command :
console dial 0xxxxxxxx

2) Jackd works well with anothers applications when I force them to use jack
as input/output. -> probably not a jack configuration problem.

3) If I kill jackd and I use chan_alsa.so with the real soundcard, it works.
-> probably not a network or sip configuration problem.


4) If I replace "f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);" with "f_buf[i] =
0.5 * sin(0.3454 * ((float) i));" in app_jack.c and I retry the test 2, I
get test sound. 
It looks like no sound was read in channel...

Do you have any idea ?

Fabien





_______________________________________________
--Bandwidth and Colocation Provided by http://www.api-digital.com--

AstriCon 2009 - October 13 - 15 Phoenix, Arizona
Register Now: http://www.astricon.net

asterisk-dev mailing list
To UNSUBSCRIBE or update options visit:
   http://lists.digium.com/mailman/listinfo/asterisk-dev




_______________________________________________
-- Bandwidth and Colocation Provided by http://www.api-digital.com --

AstriCon 2009 - October 13 - 15 Phoenix, Arizona
Register Now: http://www.astricon.net

asterisk-users mailing list
To UNSUBSCRIBE or update options visit:
   http://lists.digium.com/mailman/listinfo/asterisk-users

Reply via email to