diff --git a/ChangeLog b/ChangeLog index 5d7cb793..6bdc220a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21,6 +21,7 @@ Marc-Olivier Barre 2008-03-05 Stephane Letz * libjackdmp.so renamed to libjackservermp.so and same for OSX framework. + * tw1.c example added (new thread model). 2008-03-02 Stephane Letz diff --git a/common/JackAPI.cpp b/common/JackAPI.cpp index e962590e..6af9ada1 100644 --- a/common/JackAPI.cpp +++ b/common/JackAPI.cpp @@ -69,7 +69,7 @@ extern "C" // new EXPORT jack_nframes_t jack_cycle_wait (jack_client_t*); EXPORT void jack_cycle_signal (jack_client_t*, int status); - EXPORT int jack_set_process_thread(jack_client_t* client, JackRTThread fun, void *arg); + EXPORT int jack_set_process_thread(jack_client_t* client, JackThreadCallback fun, void *arg); EXPORT int jack_set_thread_init_callback (jack_client_t *client, JackThreadInitCallback thread_init_callback, @@ -707,7 +707,7 @@ EXPORT void jack_cycle_signal(jack_client_t* ext_client, int status) } } -EXPORT int jack_set_process_thread(jack_client_t* ext_client, JackRTThread fun, void *arg) +EXPORT int jack_set_process_thread(jack_client_t* ext_client, JackThreadCallback fun, void *arg) { #ifdef __CLIENTDEBUG__ JackLibGlobals::CheckContext(); diff --git a/common/JackAPIWrapper.cpp b/common/JackAPIWrapper.cpp index 0df54e98..0e467bc4 100644 --- a/common/JackAPIWrapper.cpp +++ b/common/JackAPIWrapper.cpp @@ -52,7 +52,7 @@ extern "C" // new EXPORT jack_nframes_t jack_cycle_wait (jack_client_t*); EXPORT void jack_cycle_signal (jack_client_t*, int status); - EXPORT int jack_set_process_thread(jack_client_t* client, JackRTThread fun, void *arg); + EXPORT int jack_set_process_thread(jack_client_t* client, JackThreadCallback fun, void *arg); EXPORT int jack_set_thread_init_callback (jack_client_t *client, JackThreadInitCallback thread_init_callback, diff --git a/common/JackClient.cpp b/common/JackClient.cpp index 864daa01..44ecb2f4 100644 --- a/common/JackClient.cpp +++ b/common/JackClient.cpp @@ -406,7 +406,7 @@ jack_nframes_t JackClient::CycleWait() return GetEngineControl()->fBufferSize; } -int JackClient::SetProcessThread(JackRTThread fun, void *arg) +int JackClient::SetProcessThread(JackThreadCallback fun, void *arg) { if (IsActive()) { jack_error("You cannot set callbacks on an active client"); diff --git a/common/JackClient.h b/common/JackClient.h index 17ec12e4..594d8b7e 100644 --- a/common/JackClient.h +++ b/common/JackClient.h @@ -66,7 +66,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface JackPortConnectCallback fPortConnect; JackTimebaseCallback fTimebase; JackSyncCallback fSync; - JackRTThread fThreadFun; + JackThreadCallback fThreadFun; void* fProcessArg; void* fGraphOrderArg; @@ -178,7 +178,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface virtual jack_nframes_t CycleWait(); void CycleSignal(int status); - int SetProcessThread(JackRTThread fun, void *arg); + int SetProcessThread(JackThreadCallback fun, void *arg); // JackRunnableInterface interface bool Init(); diff --git a/common/jack/jack.h b/common/jack/jack.h index b32e677a..afd51d95 100644 --- a/common/jack/jack.h +++ b/common/jack/jack.h @@ -203,7 +203,7 @@ extern "C" void jack_cycle_signal (jack_client_t* client, int status); - int jack_set_process_thread(jack_client_t* client, JackRTThread fun, void *arg); + int jack_set_process_thread(jack_client_t* client, JackThreadCallback fun, void *arg); /** * Tell JACK to call @a thread_init_callback once just after diff --git a/common/jack/types.h b/common/jack/types.h index 502a97c8..c7e143bb 100644 --- a/common/jack/types.h +++ b/common/jack/types.h @@ -215,7 +215,7 @@ typedef void (*JackPortConnectCallback)(jack_port_id_t a, jack_port_id_t b, int typedef void (*JackFreewheelCallback)(int starting, void *arg); -typedef void *(*JackRTThread)(void* arg); +typedef void *(*JackThreadCallback)(void* arg); /** * Used for the type argument of jack_port_register() for default diff --git a/example-clients/tw1.c b/example-clients/tw1.c new file mode 100644 index 00000000..82081da3 --- /dev/null +++ b/example-clients/tw1.c @@ -0,0 +1,257 @@ +/** @file simple_client.c + * + * @brief This simple client demonstrates the basic features of JACK + * as they would be used by many applications. + */ + +#include +#include +#include +#include +#include + +#include +#include + +jack_port_t *input_port; +jack_port_t *output_port; +jack_client_t *client; + +/* a simple state machine for this client */ +volatile enum { + Init, + Run, + Exit +} client_state = Init; + +/** + * The process callback for this JACK application is called in a + * special realtime thread once for each audio cycle. + * + * This client follows a simple rule: when the JACK transport is + * running, copy the input port to the output. When it stops, exit. + */ + + +/** + * The process callback for this JACK application is called in a + * special realtime thread once for each audio cycle. + * + * This client follows a simple rule: when the JACK transport is + * running, copy the input port to the output. When it stops, exit. + */ +int +_process (jack_nframes_t nframes) +{ + jack_default_audio_sample_t *in, *out; + jack_transport_state_t ts = jack_transport_query(client, NULL); + + if (ts == JackTransportRolling) { + + if (client_state == Init) + client_state = Run; + + in = jack_port_get_buffer (input_port, nframes); + out = jack_port_get_buffer (output_port, nframes); + memcpy (out, in, + sizeof (jack_default_audio_sample_t) * nframes); + + } else if (ts == JackTransportStopped) { + + if (client_state == Run) { + client_state = Exit; + printf("END\n"); + return -1; // to stop the thread + } + } + + return 0; +} + +static void* jack_thread(void *arg) +{ + jack_client_t* client = (jack_client_t*) arg; + + while (1) { + jack_nframes_t frames = jack_cycle_wait (client); + int status = _process(frames); + jack_cycle_signal (client, status); + } + + return 0; +} + +/* +static void* jack_thread(void *arg) +{ + jack_client_t* client = (jack_client_t*) arg; + + while (1) { + jack_nframes_t frames; + int status; + // cycle 1 + frames = jack_cycle_wait (client); + status = _process(frames); + jack_cycle_signal (client, status); + // cycle 2 + frames = jack_cycle_wait (client); + status = _process(frames); + jack_cycle_signal (client, status); + // cycle 3 + frames = jack_cycle_wait (client); + status = _process(frames); + jack_cycle_signal (client, status); + // cycle 4 + frames = jack_cycle_wait (client); + status = _process(frames); + jack_cycle_signal (client, status); + } + + return 0; +} +*/ + +/** + * JACK calls this shutdown_callback if the server ever shuts down or + * decides to disconnect the client. + */ +void +jack_shutdown (void *arg) +{ + exit (1); +} + +int +main (int argc, char *argv[]) +{ + const char **ports; + const char *client_name; + const char *server_name = NULL; + jack_options_t options = JackNullOption; + jack_status_t status; + //pthread_t thread; + + if (argc >= 2) { /* client name specified? */ + client_name = argv[1]; + if (argc >= 3) { /* server name specified? */ + server_name = argv[2]; + options |= JackServerName; + } + } else { /* use basename of argv[0] */ + client_name = strrchr(argv[0], '/'); + if (client_name == 0) { + client_name = argv[0]; + } else { + client_name++; + } + } + + /* open a client connection to the JACK server */ + + client = jack_client_open (client_name, options, &status, server_name); + if (client == NULL) { + fprintf (stderr, "jack_client_open() failed, " + "status = 0x%2.0x\n", status); + if (status & JackServerFailed) { + fprintf (stderr, "Unable to connect to JACK server\n"); + } + exit (1); + } + if (status & JackServerStarted) { + fprintf (stderr, "JACK server started\n"); + } + if (status & JackNameNotUnique) { + client_name = jack_get_client_name(client); + fprintf (stderr, "unique name `%s' assigned\n", client_name); + } + + /* create RT thread + */ + + /* + if (jack_client_create_thread(client, &thread, 90, 1, jack_thread, client) < 0) + exit(1); + jack_acquire_real_time_scheduling (thread, 90); + */ + + if (jack_set_process_thread(client, jack_thread, client) < 0) + exit(1); + + /* tell the JACK server to call `jack_shutdown()' if + it ever shuts down, either entirely, or if it + just decides to stop calling us. + */ + + jack_on_shutdown (client, jack_shutdown, 0); + + /* display the current sample rate. + */ + + printf ("engine sample rate: %" PRIu32 "\n", + jack_get_sample_rate (client)); + + /* create two ports */ + + input_port = jack_port_register (client, "input", + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsInput, 0); + output_port = jack_port_register (client, "output", + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput, 0); + + if ((input_port == NULL) || (output_port == NULL)) { + fprintf(stderr, "no more JACK ports available\n"); + exit (1); + } + + /* Tell the JACK server that we are ready to roll. Our + * process() callback will start running now. */ + + if (jack_activate (client)) { + fprintf (stderr, "cannot activate client"); + exit (1); + } + + /* Connect the ports. You can't do this before the client is + * activated, because we can't make connections to clients + * that aren't running. Note the confusing (but necessary) + * orientation of the driver backend ports: playback ports are + * "input" to the backend, and capture ports are "output" from + * it. + */ + + ports = jack_get_ports (client, NULL, NULL, + JackPortIsPhysical|JackPortIsOutput); + if (ports == NULL) { + fprintf(stderr, "no physical capture ports\n"); + exit (1); + } + + if (jack_connect (client, ports[0], jack_port_name (input_port))) { + fprintf (stderr, "cannot connect input ports\n"); + } + + free (ports); + + ports = jack_get_ports (client, NULL, NULL, + JackPortIsPhysical|JackPortIsInput); + if (ports == NULL) { + fprintf(stderr, "no physical playback ports\n"); + exit (1); + } + + if (jack_connect (client, jack_port_name (output_port), ports[0])) { + fprintf (stderr, "cannot connect output ports\n"); + } + + free (ports); + + /* keep running until the transport stops */ + + while (client_state != Exit) { + sleep (1); + } + + jack_client_close (client); + exit (0); +}