[asterisk-commits] russell: branch russell/jack r96744 - /team/russell/jack/apps/app_jack.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Sat Jan 5 17:20:14 CST 2008


Author: russell
Date: Sat Jan  5 17:20:14 2008
New Revision: 96744

URL: http://svn.digium.com/view/asterisk?view=rev&rev=96744
Log:
Add a couple of more options to app_jack.  These let you specify port names to
connect to when we create our jack ports for the channel.  This is _extremely_
handy when you already know exactly what you want to connect the channel to so
that you don't have to go about doing it by some other means ...

Modified:
    team/russell/jack/apps/app_jack.c

Modified: team/russell/jack/apps/app_jack.c
URL: http://svn.digium.com/view/asterisk/team/russell/jack/apps/app_jack.c?view=diff&rev=96744&r1=96743&r2=96744
==============================================================================
--- team/russell/jack/apps/app_jack.c (original)
+++ team/russell/jack/apps/app_jack.c Sat Jan  5 17:20:14 2008
@@ -72,15 +72,23 @@
 "the audio coming from, or being sent to the channel.\n"
 "  Valid options:\n"
 "    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"
 "";
 
 struct jack_data {
+	AST_DECLARE_STRING_FIELDS(
+		AST_STRING_FIELD(server_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;
-	const char *server_name;
 	void *output_resampler;
 	double output_resample_factor;
 	void *input_resampler;
@@ -238,7 +246,7 @@
 
 	res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len);
 	if (res != write_len) {
-		ast_debug(1, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
+		ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
 			(int) sizeof(s_buf), (int) res);
 	}
 }
@@ -259,7 +267,7 @@
 	res = jack_ringbuffer_read(jack_data->output_rb, buf, len);
 
 	if (len != res) {
-		ast_debug(1, "Wanted %d bytes to send to the output port, "
+		ast_debug(2, "Wanted %d bytes to send to the output port, "
 			"but only got %d\n", (int) len, (int) res);
 	}
 }
@@ -288,7 +296,7 @@
 	jack_data->stop = 1;
 }
 
-static void destroy_jack_data(struct jack_data *jack_data)
+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);
@@ -324,6 +332,12 @@
 		resample_close(jack_data->input_resampler);
 		jack_data->input_resampler = NULL;
 	}
+
+	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)
@@ -335,15 +349,11 @@
 	chan_name = ast_strdupa(chan->name);
 	ast_channel_unlock(chan);
 
-	if (!(jack_data->output_rb = jack_ringbuffer_create(RINGBUFFER_SIZE))) {
-		destroy_jack_data(jack_data);
-		return -1;
-	}
-
-	if (!(jack_data->input_rb = jack_ringbuffer_create(RINGBUFFER_SIZE))) {
-		destroy_jack_data(jack_data);
-		return -1;
-	}
+	if (!(jack_data->output_rb = jack_ringbuffer_create(RINGBUFFER_SIZE)))
+		return -1;
+
+	if (!(jack_data->input_rb = jack_ringbuffer_create(RINGBUFFER_SIZE)))
+		return -1;
 
 	if (!ast_strlen_zero(jack_data->server_name)) {
 		jack_data->client = jack_client_open(chan_name, JackServerName, &status,
@@ -355,16 +365,13 @@
 	if (status)
 		log_jack_status("Client Open Status", status);
 
-	if (!jack_data->client) {
-		destroy_jack_data(jack_data);
-		return -1;
-	}
+	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");
-		destroy_jack_data(jack_data);
 		return -1;
 	}
 
@@ -372,13 +379,11 @@
 		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");
-		destroy_jack_data(jack_data);
 		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");
-		destroy_jack_data(jack_data);
 		return -1;
 	}
 
@@ -386,8 +391,57 @@
 
 	if (jack_activate(jack_data->client)) {
 		ast_log(LOG_ERROR, "Unable to activate jack client\n");
-		destroy_jack_data(jack_data);
-		return -1;
+		return -1;
+	}
+
+	while (!ast_strlen_zero(jack_data->connect_input_port)) {
+		const char **ports;
+
+		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;
+		}
+
+		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;
+
+		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;
+		}
+
+		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;
@@ -452,7 +506,7 @@
 
 	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(1, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
+		ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
 			(int) (f_buf_used * sizeof(float)), (int) res);
 	}
 
@@ -499,82 +553,147 @@
 }
 
 enum {
-	OPT_SERVERNAME = (1 << 0),
+	OPT_SERVER_NAME = (1 << 0),
+	OPT_INPUT_PORT =  (1 << 1),
+	OPT_OUTPUT_PORT = (1 << 2),
 };
 
 enum {
-	OPT_ARG_SERVERNAME,
+	OPT_ARG_SERVER_NAME,
+	OPT_ARG_INPUT_PORT,
+	OPT_ARG_OUTPUT_PORT,
 	/* Must be the last element */
 	OPT_ARG_ARRAY_SIZE,
 };
 
 AST_APP_OPTIONS(jack_exec_options, BEGIN_OPTIONS
-	AST_APP_OPTION_ARG('s', OPT_SERVERNAME, OPT_ARG_SERVERNAME),
+	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),
 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_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;
+		}
+	}
+
+	return 0;
+}
+
 static int jack_exec(struct ast_channel *chan, void *data)
 {
-	int res = 0;
-	struct jack_data jack_data = { NULL, };
+	struct jack_data *jack_data;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(options);
 	);
-	struct ast_flags options = { 0, };
-	char *option_args[OPT_ARG_ARRAY_SIZE];
+
+	if (!(jack_data = jack_data_alloc()))
+		return -1;
 
 	args.options = data;
 
 	if (!ast_strlen_zero(args.options)) {
-		ast_app_parse_options(jack_exec_options, &options, option_args, args.options);
-		if (ast_test_flag(&options, OPT_SERVERNAME)) {
-			if (!ast_strlen_zero(option_args[OPT_ARG_SERVERNAME]))
-				jack_data.server_name = option_args[OPT_ARG_SERVERNAME];
-			else
-				ast_log(LOG_ERROR, "A server name must be provided with the s() option\n");
-		}
-	}
-
-	if (init_jack_data(chan, &jack_data)) {
-		destroy_jack_data(&jack_data);
-		return -1;
-	}
-
-	if (ast_set_read_format(chan, AST_FORMAT_SLINEAR))
-		return -1;
-
-	if (ast_set_write_format(chan, AST_FORMAT_SLINEAR))
-		return -1;
-
-	while (!jack_data.stop) {
+		if (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;
+			jack_data->stop = 1;
 			continue;
 		}
 
 		switch (f->frametype) {
 		case AST_FRAME_CONTROL:
 			if (f->subclass == AST_CONTROL_HANGUP)
-				jack_data.stop = 1;
+				jack_data->stop = 1;
 			break;
 		case AST_FRAME_VOICE:
-			queue_voice_frame(&jack_data, f);
+			queue_voice_frame(jack_data, f);
 		default:
 			break;
 		}
 
 		ast_frfree(f);
 
-		handle_jack_audio(chan, &jack_data);
-	}
-
-	destroy_jack_data(&jack_data);
-
-	return res;
+		handle_jack_audio(chan, jack_data);
+	}
+
+	jack_data = destroy_jack_data(jack_data);
+
+	return 0;
 }
 
 static int unload_module(void)




More information about the asterisk-commits mailing list