Browse Source

Add jack_mp_thread_wait client example.

git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@1803 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.70
sletz 17 years ago
parent
commit
82cd319729
4 changed files with 566 additions and 0 deletions
  1. +1
    -0
      ChangeLog
  2. +207
    -0
      example-clients/mp_tw.cpp
  3. +204
    -0
      example-clients/tw.c
  4. +154
    -0
      macosx/Jackdmp.xcodeproj/project.pbxproj

+ 1
- 0
ChangeLog View File

@@ -22,6 +22,7 @@ Tim Blechmann
* Remove checking thread in CoreAudio driver, better device state change recovery strategy: the driver is stopped and restarted.
* jack_thread_wait implementation.
* Add jack_thread_wait client example.
* Add jack_mp_thread_wait client example.

2008-01-30 Stephane Letz <letz@grame.fr>


+ 207
- 0
example-clients/mp_tw.cpp View File

@@ -0,0 +1,207 @@

/** @file mp_thread_client.c
*
* @brief This simple client demonstrates the use of "jack_thread_wait" function in a multi-threaded context.
A set of n threads (the jack process thread + (n - 1) helper threads) are used to work on a global queue of tasks.
The last finishing thread gives control back to libjack using the "jack_thread_wait" function. Other threads suspend
on a condition variable and are resumed next cycle by the libjack suspended thread.
*/
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define __SMP__ 1

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

//#include "jack.h"
//#include "thread.h"
#include <math.h>
#include "JackAtomic.h"
jack_port_t *input_port;
jack_port_t *output_port;
jack_client_t *client;
int buffer_size;
#define WORK_AT_EACH_CYCLE 1000
#define WORK_AT_EACH_LOOP 15
static SInt32 cycle_work_count = 0;
pthread_cond_t cond;
pthread_mutex_t mutex;
jack_nframes_t last_time = 0;
static int print_count = 50;
int result = 0;

typedef struct thread_context
{
pthread_t thread;
int num;
};
// Simulate workload
static int fib(int n)
{
if (n < 2)
return n;
else
return fib(n - 2) + fib(n - 1);
}

static void do_some_work(void *arg)
{
result = fib(WORK_AT_EACH_LOOP);
}
static void resume_all_threads(void *arg)
{
thread_context* context = (thread_context*)arg;
jack_nframes_t cur_time = jack_frame_time(client);
if (--print_count == 0) {
printf("resume_all_threads from thread = %ld jack_frame_time = %u jack_cpu_load = %f\n", context->num, (cur_time - last_time), jack_cpu_load(client));
print_count = 50;
}
pthread_mutex_lock(&mutex); // Hum...
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex); // Hum...
cycle_work_count = WORK_AT_EACH_CYCLE;
last_time = cur_time;
}
static void suspend_jack_thread(void *arg)
{
jack_thread_wait(client, 0);
}
static void suspend_worker_thread(void *arg)
{
pthread_mutex_lock(&mutex); // Hum...
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex); // Hum...
}
static void * worker_aux_thread(void *arg)
{
while (1) {
int val = DEC_ATOMIC(&cycle_work_count);
if (val == 1) { // Last thread
suspend_jack_thread(arg);
resume_all_threads(arg);
} else if (val < 1) {
suspend_worker_thread(arg);
} else {
do_some_work(arg);
}
}
return 0;
}
static void * worker_thread(void *arg)
{
suspend_worker_thread(arg); // Start in "suspended" state
worker_aux_thread(arg);
return 0;
}
// Example of audio process
int process(jack_nframes_t nframes, void *arg)
{
resume_all_threads(arg);
worker_aux_thread(arg);
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[])
{
thread_context* worker_threads;
int n, nthreads = 0;
if (argc == 2)
nthreads = atoi(argv[1]);
worker_threads = (thread_context *) malloc (sizeof (thread_context) * nthreads);
/* open a client connection to the JACK server */
if ((client = jack_client_open("mp_thread_test", JackNoStartServer, NULL)) == NULL) {
fprintf(stderr, "Cannot open client\n");
exit(1);
}
buffer_size = jack_get_buffer_size(client);
/* tell the JACK server to call the 'callback' function
*/
worker_threads[0].num = 0;
jack_set_process_callback(client, process, &worker_threads[0]);
/* 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);
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
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);
}
fprintf(stderr, "Creating %d threads\n", nthreads);
for (n = 1; n <= nthreads; ++n) {
worker_threads[n].num = n;
if (jack_client_create_thread(client, &worker_threads[n].thread, 90, 1, worker_thread, &worker_threads[n]) < 0)
exit(1);
jack_acquire_real_time_scheduling (worker_threads[n].thread, 90);
}
/* 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);
}
while (1) {
#ifdef WIN32
Sleep(1000);
#else
sleep(1);
#endif
}
jack_client_close(client);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
exit(0);
}

+ 204
- 0
example-clients/tw.c View File

@@ -0,0 +1,204 @@
/** @file simple_client.c
*
* @brief This simple client demonstrates the basic features of JACK
* as they would be used by many applications.
*/

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <jack/jack.h>

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.
*/
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;
}

return 0;
}

int
process (jack_nframes_t nframes, void* arg)
{
jack_client_t* client = (jack_client_t*) arg;

while ((nframes = jack_thread_wait (client, _process (nframes))) != 0);

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;

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);
}

/* tell the JACK server to call `process()' whenever
there is work to be done.
*/

jack_set_process_callback (client, process, client);

/* 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);
}

+ 154
- 0
macosx/Jackdmp.xcodeproj/project.pbxproj View File

@@ -87,6 +87,7 @@
/* Begin PBXBuildFile section */
4B0A28ED0D520852002EFF74 /* tw.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A28EC0D520852002EFF74 /* tw.c */; };
4B0A29260D52108E002EFF74 /* tw.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A28EC0D520852002EFF74 /* tw.c */; };
4B0A29830D523269002EFF74 /* mp_tw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A29820D523269002EFF74 /* mp_tw.cpp */; };
4B35C41E0D4731D1000DE7AE /* Jackdmp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF8D2250834F06A00C94B91 /* Jackdmp.cpp */; };
4B35C4290D4731D1000DE7AE /* JackMachPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B799AD707899652003F3F15 /* JackMachPort.h */; };
4B35C42A0D4731D1000DE7AE /* JackError.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF8D1770834EE4800C94B91 /* JackError.h */; };
@@ -1007,6 +1008,8 @@
4B0A28E60D52073D002EFF74 /* jack_thread_wait */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jack_thread_wait; sourceTree = BUILT_PRODUCTS_DIR; };
4B0A28EC0D520852002EFF74 /* tw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tw.c; path = "../example-clients/tw.c"; sourceTree = SOURCE_ROOT; };
4B0A292D0D52108E002EFF74 /* jack_thread_wait */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jack_thread_wait; sourceTree = BUILT_PRODUCTS_DIR; };
4B0A296D0D5231DC002EFF74 /* jack_mp_thread_wait */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jack_mp_thread_wait; sourceTree = BUILT_PRODUCTS_DIR; };
4B0A29820D523269002EFF74 /* mp_tw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mp_tw.cpp; path = "../example-clients/mp_tw.cpp"; sourceTree = SOURCE_ROOT; };
4B123D3308B3954300540632 /* JackGlobalsClient.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackGlobalsClient.cpp; path = ../common/JackGlobalsClient.cpp; sourceTree = SOURCE_ROOT; };
4B123D3608B3954A00540632 /* JackGlobalsServer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackGlobalsServer.cpp; path = ../common/JackGlobalsServer.cpp; sourceTree = SOURCE_ROOT; };
4B2C28F908DAD01E00249230 /* JackGlobals.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackGlobals.cpp; path = ../common/JackGlobals.cpp; sourceTree = SOURCE_ROOT; };
@@ -1236,6 +1239,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4B0A29670D5231DC002EFF74 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
4B35C41F0D4731D1000DE7AE /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -1717,6 +1727,7 @@
4B35C63E0D4731D3000DE7AE /* inprocess.so */,
4B0A28E60D52073D002EFF74 /* jack_thread_wait */,
4B0A292D0D52108E002EFF74 /* jack_thread_wait */,
4B0A296D0D5231DC002EFF74 /* jack_mp_thread_wait */,
);
name = Products;
sourceTree = "<group>";
@@ -1724,6 +1735,7 @@
4B03383E0797E19900686131 /* Simple clients */ = {
isa = PBXGroup;
children = (
4B0A29820D523269002EFF74 /* mp_tw.cpp */,
4B0A28EC0D520852002EFF74 /* tw.c */,
4B5A1BDC0CD1CD420005BF74 /* midisine.c */,
4B5A1BBD0CD1CC110005BF74 /* midiseq.c */,
@@ -2083,6 +2095,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4B0A29640D5231DC002EFF74 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
4B35C41C0D4731D1000DE7AE /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
@@ -2736,6 +2755,25 @@
productReference = 4B0A292D0D52108E002EFF74 /* jack_thread_wait */;
productType = "com.apple.product-type.tool";
};
4B0A29630D5231DC002EFF74 /* jack_mp_thread_wait */ = {
isa = PBXNativeTarget;
buildConfigurationList = 4B0A29690D5231DC002EFF74 /* Build configuration list for PBXNativeTarget "jack_mp_thread_wait" */;
buildPhases = (
4B0A29640D5231DC002EFF74 /* Headers */,
4B0A29650D5231DC002EFF74 /* Sources */,
4B0A29670D5231DC002EFF74 /* Frameworks */,
4B0A29680D5231DC002EFF74 /* Rez */,
);
buildRules = (
);
dependencies = (
);
name = jack_mp_thread_wait;
productInstallPath = /usr/local/bin;
productName = testSem;
productReference = 4B0A296D0D5231DC002EFF74 /* jack_mp_thread_wait */;
productType = "com.apple.product-type.tool";
};
4B35C41B0D4731D1000DE7AE /* jackdmp framework 64bits */ = {
isa = PBXNativeTarget;
buildConfigurationList = 4B35C4210D4731D1000DE7AE /* Build configuration list for PBXNativeTarget "jackdmp framework 64bits" */;
@@ -3781,6 +3819,7 @@
4BA692A60CBE4BC700EAD520 /* jack_load Universal */,
4BA692CA0CBE4C9000EAD520 /* jack_unload Universal */,
4B0A28DC0D52073D002EFF74 /* jack_thread_wait */,
4B0A29630D5231DC002EFF74 /* jack_mp_thread_wait */,
4B699D4F097D421600A18468 /* synchroServer Universal */,
4B699D67097D421600A18468 /* synchroClient Universal */,
4B699D7F097D421700A18468 /* synchroServerClient Universal */,
@@ -3880,6 +3919,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4B0A29680D5231DC002EFF74 /* Rez */ = {
isa = PBXRezBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
4B35C4200D4731D1000DE7AE /* Rez */ = {
isa = PBXRezBuildPhase;
buildActionMask = 2147483647;
@@ -4207,6 +4253,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4B0A29650D5231DC002EFF74 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4B0A29830D523269002EFF74 /* mp_tw.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
4B35C41D0D4731D1000DE7AE /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -5338,6 +5392,96 @@
};
name = Default;
};
4B0A296A0D5231DC002EFF74 /* Development */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
i386,
ppc,
);
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
HEADER_SEARCH_PATHS = ../common;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = (
"-framework",
Jackmp,
);
OTHER_REZFLAGS = "";
PRODUCT_NAME = jack_mp_thread_wait;
REZ_EXECUTABLE = YES;
SDKROOT = "";
SECTORDER_FLAGS = "";
WARNING_CFLAGS = (
"-Wmost",
"-Wno-four-char-constants",
"-Wno-unknown-pragmas",
);
ZERO_LINK = YES;
};
name = Development;
};
4B0A296B0D5231DC002EFF74 /* Deployment */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
i386,
ppc,
);
COPY_PHASE_STRIP = YES;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_OPTIMIZATION_LEVEL = 3;
HEADER_SEARCH_PATHS = ../common;
MACOSX_DEPLOYMENT_TARGET = 10.4;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = (
"-framework",
Jackmp,
);
OTHER_REZFLAGS = "";
PRODUCT_NAME = jack_mp_thread_wait;
REZ_EXECUTABLE = YES;
SDKROOT = "";
SECTORDER_FLAGS = "";
WARNING_CFLAGS = (
"-Wmost",
"-Wno-four-char-constants",
"-Wno-unknown-pragmas",
);
ZERO_LINK = NO;
};
name = Deployment;
};
4B0A296C0D5231DC002EFF74 /* Default */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
i386,
ppc,
);
GCC_OPTIMIZATION_LEVEL = 3;
HEADER_SEARCH_PATHS = ../common;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = (
"-framework",
Jackmp,
);
OTHER_REZFLAGS = "";
PRODUCT_NAME = jack_mp_thread_wait;
REZ_EXECUTABLE = YES;
SDKROOT = "";
SECTORDER_FLAGS = "";
WARNING_CFLAGS = (
"-Wmost",
"-Wno-four-char-constants",
"-Wno-unknown-pragmas",
);
};
name = Default;
};
4B35C4220D4731D1000DE7AE /* Development */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -11531,6 +11675,16 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Default;
};
4B0A29690D5231DC002EFF74 /* Build configuration list for PBXNativeTarget "jack_mp_thread_wait" */ = {
isa = XCConfigurationList;
buildConfigurations = (
4B0A296A0D5231DC002EFF74 /* Development */,
4B0A296B0D5231DC002EFF74 /* Deployment */,
4B0A296C0D5231DC002EFF74 /* Default */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Default;
};
4B35C4210D4731D1000DE7AE /* Build configuration list for PBXNativeTarget "jackdmp framework 64bits" */ = {
isa = XCConfigurationList;
buildConfigurations = (


Loading…
Cancel
Save