git-svn-id: svn+ssh://jackaudio.org/trunk/jack@101 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.109.0
@@ -35,8 +35,8 @@ | |||||
#include <jack/hammerfall.h> | #include <jack/hammerfall.h> | ||||
#include <jack/generic.h> | #include <jack/generic.h> | ||||
static int config_max_level = 0; | |||||
static int config_min_level = 0; | |||||
FILE *alog; | |||||
static sample_t gbuf[4096]; | |||||
static void | static void | ||||
alsa_driver_release_channel_dependent_memory (alsa_driver_t *driver) | alsa_driver_release_channel_dependent_memory (alsa_driver_t *driver) | ||||
@@ -364,35 +364,7 @@ alsa_driver_set_parameters (alsa_driver_t *driver, nframes_t frames_per_cycle, n | |||||
switch (driver->sample_format) { | switch (driver->sample_format) { | ||||
case SND_PCM_FORMAT_S32_LE: | case SND_PCM_FORMAT_S32_LE: | ||||
/* XXX must handle the n-bits of 24-in-32 problems here */ | |||||
if (config_max_level) { | |||||
driver->max_level = config_max_level; | |||||
} else { | |||||
driver->max_level = INT_MAX; | |||||
} | |||||
if (config_min_level) { | |||||
driver->min_level = config_min_level; | |||||
} else { | |||||
driver->min_level = INT_MIN; | |||||
} | |||||
break; | |||||
case SND_PCM_FORMAT_S16_LE: | case SND_PCM_FORMAT_S16_LE: | ||||
if (config_max_level) { | |||||
driver->max_level = config_max_level; | |||||
} else { | |||||
driver->max_level = SHRT_MAX; | |||||
} | |||||
if (config_min_level) { | |||||
driver->min_level = config_min_level; | |||||
} else { | |||||
driver->min_level = SHRT_MIN; | |||||
} | |||||
break; | break; | ||||
default: | default: | ||||
@@ -679,6 +651,8 @@ alsa_driver_set_clock_sync_status (alsa_driver_t *driver, channel_t chn, ClockSy | |||||
} | } | ||||
static int under_gdb = FALSE; | static int under_gdb = FALSE; | ||||
static int waitcnt = 0; | |||||
static int | static int | ||||
alsa_driver_wait (alsa_driver_t *driver) | alsa_driver_wait (alsa_driver_t *driver) | ||||
@@ -697,9 +671,11 @@ alsa_driver_wait (alsa_driver_t *driver) | |||||
int need_playback = 1; | int need_playback = 1; | ||||
jack_engine_t *engine = driver->engine; | jack_engine_t *engine = driver->engine; | ||||
int i; | int i; | ||||
static unsigned long long last = 0; | |||||
unsigned long long start; | |||||
again: | again: | ||||
while (need_playback || need_capture) { | while (need_playback || need_capture) { | ||||
int p_timed_out, c_timed_out; | int p_timed_out, c_timed_out; | ||||
@@ -740,6 +716,10 @@ alsa_driver_wait (alsa_driver_t *driver) | |||||
return -1; | return -1; | ||||
} | } | ||||
rdtscll (start); | |||||
// fprintf (stderr, "engine cycle %.6f msecs\n", (((float) (start - last))/450000.0f)); | |||||
last = start; | |||||
if (driver->engine) { | if (driver->engine) { | ||||
struct timeval tv; | struct timeval tv; | ||||
gettimeofday (&tv, NULL); | gettimeofday (&tv, NULL); | ||||
@@ -822,7 +802,9 @@ alsa_driver_wait (alsa_driver_t *driver) | |||||
avail = avail - (avail % driver->frames_per_cycle); | avail = avail - (avail % driver->frames_per_cycle); | ||||
while (avail) { | while (avail) { | ||||
waitcnt++; | |||||
capture_avail = (avail > driver->frames_per_cycle) ? driver->frames_per_cycle : avail; | capture_avail = (avail > driver->frames_per_cycle) ? driver->frames_per_cycle : avail; | ||||
playback_avail = (avail > driver->frames_per_cycle) ? driver->frames_per_cycle : avail; | playback_avail = (avail > driver->frames_per_cycle) ? driver->frames_per_cycle : avail; | ||||
@@ -835,45 +817,72 @@ alsa_driver_wait (alsa_driver_t *driver) | |||||
contiguous = capture_avail < playback_avail ? capture_avail : playback_avail; | contiguous = capture_avail < playback_avail ? capture_avail : playback_avail; | ||||
/* XXX possible race condition here with silence_pending */ | |||||
/* XXX this design is wrong. cf. ardour/audioengine *** FIX ME *** */ | |||||
if (driver->silence_pending) { | |||||
for (chn = 0; chn < driver->playback_nchannels; chn++) { | |||||
if (driver->silence_pending & (1<<chn)) { | |||||
alsa_driver_silence_on_channel (driver, chn, contiguous); | |||||
} | |||||
} | |||||
driver->silence_pending = 0; | |||||
} | |||||
driver->channels_not_done = driver->channel_done_bits; | driver->channels_not_done = driver->channel_done_bits; | ||||
if (engine->process_lock (engine) == 0) { | if (engine->process_lock (engine) == 0) { | ||||
if (engine->process (engine, contiguous)) { | |||||
jack_error ("alsa_pcm: engine processing error - stopping."); | |||||
return -1; | |||||
int ret; | |||||
GSList *prev; | |||||
if ((ret = engine->process (engine, contiguous)) != 0) { | |||||
engine->process_unlock (engine); | |||||
alsa_driver_audio_stop (driver); | |||||
if (ret > 0) { | |||||
engine->post_process (engine); | |||||
} | |||||
return ret; | |||||
} | } | ||||
/* now move data from ports to channels */ | /* now move data from ports to channels */ | ||||
for (chn = 0, node = driver->playback_ports; node; node = g_slist_next (node), chn++) { | |||||
for (chn = 0, prev = 0, node = driver->playback_ports; node; prev = node, node = g_slist_next (node), chn++) { | |||||
jack_port_t *port = (jack_port_t *) node->data; | jack_port_t *port = (jack_port_t *) node->data; | ||||
sample_t *buf; | |||||
/* optimize needless data copying away */ | /* optimize needless data copying away */ | ||||
if (!jack_port_connected (port)) { | |||||
if (chn == 1) { | |||||
nframes_t nn; | |||||
sample_t *prevbuf; | |||||
/* 1 read the actual data from channel 0 */ | |||||
alsa_driver_read_from_channel (driver, 0, gbuf, contiguous); | |||||
buf = gbuf; | |||||
if (jack_port_connected ((jack_port_t *) prev->data)) { | |||||
prevbuf = jack_port_get_buffer (((jack_port_t *) prev->data), contiguous); | |||||
printf ("compare with %p\n", prevbuf); | |||||
for (nn = 0; nn < contiguous; nn++) { | |||||
if (gbuf[nn] != prevbuf[nn]) { | |||||
printf ("%d different at %lu (chn=%d, gbuf=%f, prevbuf=%f\n", | |||||
waitcnt, nn, driver->capture_addr[0][nn], | |||||
gbuf[nn], prevbuf[nn]); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
} else if (chn == 0) { | |||||
if (jack_port_connected (port)) { | |||||
buf = jack_port_get_buffer (port, contiguous); | |||||
printf ("%d buffer = %p\n", waitcnt, buf); | |||||
} else { | |||||
continue; | |||||
} | |||||
} else { | |||||
continue; | continue; | ||||
} | } | ||||
alsa_driver_write_to_channel (driver, chn, jack_port_get_buffer (port, contiguous), contiguous, 0, 1.0); | |||||
alsa_driver_write_to_channel (driver, chn, buf, contiguous, 1.0); | |||||
} | } | ||||
engine->process_unlock (engine); | engine->process_unlock (engine); | ||||
} | |||||
} | |||||
/* Now handle input monitoring */ | /* Now handle input monitoring */ | ||||
@@ -917,10 +926,6 @@ alsa_driver_wait (alsa_driver_t *driver) | |||||
} | } | ||||
engine->post_process (engine); | engine->post_process (engine); | ||||
// rdtscl (now); | |||||
// fprintf (stderr, "engine cycle took %.6f usecs\n", (((float) (now - start))/450.0f)); | |||||
return 0; | return 0; | ||||
} | } | ||||
@@ -932,6 +937,7 @@ alsa_driver_process (nframes_t nframes, void *arg) | |||||
channel_t chn; | channel_t chn; | ||||
jack_port_t *port; | jack_port_t *port; | ||||
GSList *node; | GSList *node; | ||||
sample_t *buf; | |||||
for (chn = 0, node = driver->capture_ports; node; node = g_slist_next (node), chn++) { | for (chn = 0, node = driver->capture_ports; node; node = g_slist_next (node), chn++) { | ||||
@@ -940,8 +946,11 @@ alsa_driver_process (nframes_t nframes, void *arg) | |||||
if (!jack_port_connected (port)) { | if (!jack_port_connected (port)) { | ||||
continue; | continue; | ||||
} | } | ||||
alsa_driver_read_from_channel (driver, chn, jack_port_get_buffer (port, nframes), nframes, 0); | |||||
buf = jack_port_get_buffer (port, nframes); | |||||
alsa_driver_read_from_channel (driver, chn, buf, nframes); | |||||
printf ("%d: read into %p with %d => %f\n", waitcnt, buf, driver->capture_addr[0][0], buf[0]); | |||||
} | } | ||||
return 0; | return 0; | ||||
@@ -1044,12 +1053,6 @@ alsa_driver_change_sample_clock (alsa_driver_t *driver, SampleClockMode mode) | |||||
return driver->hw->change_sample_clock (driver->hw, mode); | return driver->hw->change_sample_clock (driver->hw, mode); | ||||
} | } | ||||
static void | |||||
alsa_driver_mark_channel_silent (alsa_driver_t *driver, unsigned long chn) | |||||
{ | |||||
driver->silence_pending |= (1<<chn); | |||||
} | |||||
static void | static void | ||||
alsa_driver_request_all_monitor_input (alsa_driver_t *driver, int yn) | alsa_driver_request_all_monitor_input (alsa_driver_t *driver, int yn) | ||||
@@ -1181,7 +1184,6 @@ alsa_driver_new (char *name, char *alsa_device, | |||||
driver->capture_nchannels = 0; | driver->capture_nchannels = 0; | ||||
driver->playback_addr = 0; | driver->playback_addr = 0; | ||||
driver->capture_addr = 0; | driver->capture_addr = 0; | ||||
driver->silence_pending = 0; | |||||
driver->silent = 0; | driver->silent = 0; | ||||
driver->all_monitor_in = FALSE; | driver->all_monitor_in = FALSE; | ||||
@@ -1207,12 +1209,15 @@ alsa_driver_new (char *name, char *alsa_device, | |||||
driver->alsa_name = strdup (alsa_device); | driver->alsa_name = strdup (alsa_device); | ||||
if ((err = snd_pcm_open (&driver->capture_handle, alsa_device, SND_PCM_STREAM_CAPTURE, 0)) < 0) { | if ((err = snd_pcm_open (&driver->capture_handle, alsa_device, SND_PCM_STREAM_CAPTURE, 0)) < 0) { | ||||
snd_pcm_close (driver->playback_handle); | |||||
jack_error ("ALSA: Cannot open PCM device %s", name); | jack_error ("ALSA: Cannot open PCM device %s", name); | ||||
free (driver); | free (driver); | ||||
return 0; | return 0; | ||||
} | } | ||||
if (alsa_driver_check_card_type (driver)) { | if (alsa_driver_check_card_type (driver)) { | ||||
snd_pcm_close (driver->capture_handle); | |||||
snd_pcm_close (driver->playback_handle); | |||||
free (driver); | free (driver); | ||||
return 0; | return 0; | ||||
} | } | ||||
@@ -1325,6 +1330,8 @@ driver_initialize (va_list ap) | |||||
char *pcm_name; | char *pcm_name; | ||||
int hw_monitoring; | int hw_monitoring; | ||||
alog = fopen ("/dev/null", "w"); | |||||
pcm_name = va_arg (ap, char *); | pcm_name = va_arg (ap, char *); | ||||
frames_per_interrupt = va_arg (ap, nframes_t); | frames_per_interrupt = va_arg (ap, nframes_t); | ||||
user_nperiods = va_arg(ap, unsigned long); | user_nperiods = va_arg(ap, unsigned long); | ||||
@@ -565,7 +565,6 @@ jack_client_thread (void *arg) | |||||
err++; | err++; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (client->pollfd[1].revents & POLLIN) { | if (client->pollfd[1].revents & POLLIN) { | ||||
@@ -583,12 +582,10 @@ jack_client_thread (void *arg) | |||||
control->state = Running; | control->state = Running; | ||||
if (control->process) { | if (control->process) { | ||||
status = control->process (control->nframes, control->process_arg); | |||||
if (control->process (control->nframes, control->process_arg) == 0) { | |||||
control->state = Finished; | |||||
} | |||||
} else { | } else { | ||||
status = 0; | |||||
} | |||||
if (!status) { | |||||
control->state = Finished; | control->state = Finished; | ||||
} | } | ||||
@@ -725,12 +722,8 @@ jack_client_close (jack_client_t *client) | |||||
{ | { | ||||
GSList *node; | GSList *node; | ||||
jack_request_t req; | |||||
void *status; | void *status; | ||||
req.type = DropClient; | |||||
req.x.client_id = client->control->id; | |||||
/* stop the thread that communicates with the jack server */ | /* stop the thread that communicates with the jack server */ | ||||
pthread_cancel (client->thread); | pthread_cancel (client->thread); | ||||
@@ -758,18 +751,13 @@ jack_client_close (jack_client_t *client) | |||||
close (client->graph_next_fd); | close (client->graph_next_fd); | ||||
} | } | ||||
if (write (client->request_fd, &req, sizeof (req)) != sizeof (req)) { | |||||
jack_error ("cannot send drop client request to server"); | |||||
req.status = -1; | |||||
} | |||||
close (client->event_fd); | close (client->event_fd); | ||||
close (client->request_fd); | close (client->request_fd); | ||||
free (client->pollfd); | free (client->pollfd); | ||||
free (client); | free (client); | ||||
return req.status; | |||||
return 0; | |||||
} | } | ||||
int | int | ||||
@@ -1221,8 +1209,7 @@ jack_port_get_buffer (jack_port_t *port, nframes_t nframes) | |||||
} | } | ||||
port->shared->type_info.mixdown (port, nframes); | port->shared->type_info.mixdown (port, nframes); | ||||
return jack_port_buffer (port); | |||||
return (sample_t *) port->shared->offset; | |||||
} | } | ||||
int | int | ||||
@@ -1393,6 +1380,8 @@ jack_port_request_monitor (jack_port_t *port, int onoff) | |||||
int | int | ||||
jack_ensure_port_monitor_input (jack_port_t *port, int yn) | jack_ensure_port_monitor_input (jack_port_t *port, int yn) | ||||
{ | { | ||||
printf ("ENSURE PORT monitor, req = %d, status = %d\n", yn, port->shared->monitor_requests); | |||||
if (yn) { | if (yn) { | ||||
if (port->shared->monitor_requests == 0) { | if (port->shared->monitor_requests == 0) { | ||||
port->shared->monitor_requests++; | port->shared->monitor_requests++; | ||||
@@ -1570,6 +1559,8 @@ jack_audio_port_mixdown (jack_port_t *port, nframes_t nframes) | |||||
sample_t *buffer; | sample_t *buffer; | ||||
sample_t *dst, *src; | sample_t *dst, *src; | ||||
printf ("audio mixdown on %s\n", port->shared->name); | |||||
/* by the time we've called this, we've already established | /* by the time we've called this, we've already established | ||||
the existence of more than 1 connection to this input port. | the existence of more than 1 connection to this input port. | ||||
*/ | */ | ||||
@@ -441,7 +441,7 @@ jack_process (jack_engine_t *engine, nframes_t nframes) | |||||
client = (jack_client_internal_t *) node->data; | client = (jack_client_internal_t *) node->data; | ||||
if (!client->control->active) { | |||||
if (!client->control->active || client->control->dead) { | |||||
node = g_slist_next (node); | node = g_slist_next (node); | ||||
continue; | continue; | ||||
} | } | ||||
@@ -470,6 +470,8 @@ jack_process (jack_engine_t *engine, nframes_t nframes) | |||||
ctl->state = Triggered; // a race exists if we do this after the write(2) | ctl->state = Triggered; // a race exists if we do this after the write(2) | ||||
printf ("start subgraph\n"); | |||||
if (write (client->subgraph_start_fd, &c, sizeof (c)) != sizeof (c)) { | if (write (client->subgraph_start_fd, &c, sizeof (c)) != sizeof (c)) { | ||||
jack_error ("cannot initiate graph processing (%s)", strerror (errno)); | jack_error ("cannot initiate graph processing (%s)", strerror (errno)); | ||||
engine->process_errors++; | engine->process_errors++; | ||||
@@ -491,7 +493,7 @@ jack_process (jack_engine_t *engine, nframes_t nframes) | |||||
engine->process_errors++; | engine->process_errors++; | ||||
break; | break; | ||||
} | } | ||||
if (pollfd[0].revents == 0) { | if (pollfd[0].revents == 0) { | ||||
jack_error ("subgraph starting at %s timed out (state = %d)", client->control->name, client->control->state); | jack_error ("subgraph starting at %s timed out (state = %d)", client->control->name, client->control->state); | ||||
engine->process_errors++; | engine->process_errors++; | ||||
@@ -508,6 +510,8 @@ jack_process (jack_engine_t *engine, nframes_t nframes) | |||||
} | } | ||||
} | } | ||||
printf ("subgraph done\n"); | |||||
/* Move to next in-process client (or end of client list) */ | /* Move to next in-process client (or end of client list) */ | ||||
while (node) { | while (node) { | ||||
@@ -520,7 +524,7 @@ jack_process (jack_engine_t *engine, nframes_t nframes) | |||||
} | } | ||||
} | } | ||||
return 0; | |||||
return engine->process_errors > 0; | |||||
} | } | ||||
int | int | ||||
@@ -616,7 +620,9 @@ handle_new_client (jack_engine_t *engine, int client_fd) | |||||
} | } | ||||
if (engine->verbose) { | if (engine->verbose) { | ||||
fprintf (stderr, "new client: %s, type %d @ %p\n", client->control->name, req.type, client->control); | |||||
fprintf (stderr, "new client: %s, id = %d type %d @ %p fd = %d\n", | |||||
client->control->name, client->control->id, | |||||
req.type, client->control, client_fd); | |||||
} | } | ||||
res.client_key = client->shm_key; | res.client_key = client->shm_key; | ||||
@@ -648,8 +654,8 @@ handle_new_client (jack_engine_t *engine, int client_fd) | |||||
} | } | ||||
pthread_mutex_lock (&engine->graph_lock); | pthread_mutex_lock (&engine->graph_lock); | ||||
engine->clients = g_slist_prepend (engine->clients, client); | engine->clients = g_slist_prepend (engine->clients, client); | ||||
pthread_mutex_unlock (&engine->graph_lock); | |||||
if (client->control->type != ClientDynamic) { | if (client->control->type != ClientDynamic) { | ||||
if (engine->pfd_max >= engine->pfd_size) { | if (engine->pfd_max >= engine->pfd_size) { | ||||
@@ -662,6 +668,7 @@ handle_new_client (jack_engine_t *engine, int client_fd) | |||||
engine->pfd_max++; | engine->pfd_max++; | ||||
} | } | ||||
pthread_mutex_unlock (&engine->graph_lock); | |||||
return 0; | return 0; | ||||
} | } | ||||
@@ -678,6 +685,8 @@ handle_client_ack_connection (jack_engine_t *engine, int client_fd) | |||||
jack_error ("cannot read ACK connection request from client"); | jack_error ("cannot read ACK connection request from client"); | ||||
return -1; | return -1; | ||||
} | } | ||||
printf ("ack message, id = %lu\n", req.client_id); | |||||
if ((client = jack_client_internal_by_id (engine, req.client_id)) == NULL) { | if ((client = jack_client_internal_by_id (engine, req.client_id)) == NULL) { | ||||
jack_error ("unknown client ID in ACK connection request"); | jack_error ("unknown client ID in ACK connection request"); | ||||
@@ -696,21 +705,6 @@ handle_client_ack_connection (jack_engine_t *engine, int client_fd) | |||||
return 0; | return 0; | ||||
} | } | ||||
static int | |||||
jack_client_drop (jack_engine_t *engine, jack_client_id_t id) | |||||
{ | |||||
jack_client_internal_t *client; | |||||
if ((client = jack_client_internal_by_id (engine, id)) == 0) { | |||||
jack_error ("unknown client ID in DropClient request"); | |||||
return -1; | |||||
} | |||||
jack_remove_client (engine, client); | |||||
return 0; | |||||
} | |||||
static int | static int | ||||
jack_client_activate (jack_engine_t *engine, jack_client_id_t id) | jack_client_activate (jack_engine_t *engine, jack_client_id_t id) | ||||
@@ -758,7 +752,7 @@ jack_client_do_deactivate (jack_engine_t *engine, jack_client_internal_t *client | |||||
if (!jack_client_is_inprocess (client)) { | if (!jack_client_is_inprocess (client)) { | ||||
engine->external_client_cnt--; | engine->external_client_cnt--; | ||||
} | } | ||||
jack_sort_graph (engine, FALSE); | jack_sort_graph (engine, FALSE); | ||||
return 0; | return 0; | ||||
} | } | ||||
@@ -839,7 +833,6 @@ jack_set_timebase (jack_engine_t *engine, jack_client_id_t client) | |||||
static int | static int | ||||
handle_client_jack_error (jack_engine_t *engine, int fd) | handle_client_jack_error (jack_engine_t *engine, int fd) | ||||
{ | { | ||||
jack_client_internal_t *client = 0; | jack_client_internal_t *client = 0; | ||||
GSList *node; | GSList *node; | ||||
@@ -854,8 +847,8 @@ handle_client_jack_error (jack_engine_t *engine, int fd) | |||||
} | } | ||||
if (client == 0) { | if (client == 0) { | ||||
jack_error ("no client found for fd %d\n", fd); | |||||
pthread_mutex_unlock (&engine->graph_lock); | pthread_mutex_unlock (&engine->graph_lock); | ||||
jack_error ("i/o error on unknown client fd %d", fd); | |||||
return -1; | return -1; | ||||
} | } | ||||
@@ -891,6 +884,7 @@ handle_client_io (jack_engine_t *engine, int fd) | |||||
if (read (client->request_fd, &req, sizeof (req)) < sizeof (req)) { | if (read (client->request_fd, &req, sizeof (req)) < sizeof (req)) { | ||||
jack_error ("cannot read request from client"); | jack_error ("cannot read request from client"); | ||||
/* XXX interlock problems with the driver thread here */ | |||||
jack_remove_client (engine, client); | jack_remove_client (engine, client); | ||||
return -1; | return -1; | ||||
} | } | ||||
@@ -918,11 +912,6 @@ handle_client_io (jack_engine_t *engine, int fd) | |||||
req.status = jack_port_do_disconnect (engine, req.x.connect.source_port, req.x.connect.destination_port); | req.status = jack_port_do_disconnect (engine, req.x.connect.source_port, req.x.connect.destination_port); | ||||
break; | break; | ||||
case DropClient: | |||||
req.status = jack_client_drop (engine, req.x.client_id); | |||||
reply_fd = -1; | |||||
break; | |||||
case ActivateClient: | case ActivateClient: | ||||
req.status = jack_client_activate (engine, req.x.client_id); | req.status = jack_client_activate (engine, req.x.client_id); | ||||
break; | break; | ||||
@@ -1045,6 +1034,7 @@ jack_server_thread (void *arg) | |||||
} | } | ||||
if (pfd[i].revents & ~POLLIN) { | if (pfd[i].revents & ~POLLIN) { | ||||
printf ("bad poll status on pfd[%d] (%d) = 0x%x\n", i, pfd[i].fd, pfd[i].revents); | |||||
handle_client_jack_error (engine, pfd[i].fd); | handle_client_jack_error (engine, pfd[i].fd); | ||||
} else if (pfd[i].revents & POLLIN) { | } else if (pfd[i].revents & POLLIN) { | ||||
if (handle_client_io (engine, pfd[i].fd)) { | if (handle_client_io (engine, pfd[i].fd)) { | ||||
@@ -1196,19 +1186,8 @@ jack_become_real_time (pthread_t thread, int priority) | |||||
return 0; | return 0; | ||||
} | } | ||||
void | |||||
cancel_cleanup1 (void *arg) | |||||
{ | |||||
jack_engine_t *engine = (jack_engine_t *) arg; | |||||
if (engine->verbose) { | |||||
fprintf (stderr, "audio thread cancelled or finished\n"); | |||||
} | |||||
engine->driver->stop (engine->driver); | |||||
} | |||||
void | |||||
cancel_cleanup2 (int status, void *arg) | |||||
static void | |||||
cancel_cleanup (int status, void *arg) | |||||
{ | { | ||||
jack_engine_t *engine = (jack_engine_t *) arg; | jack_engine_t *engine = (jack_engine_t *) arg; | ||||
@@ -1230,7 +1209,7 @@ jack_main_thread (void *arg) | |||||
} | } | ||||
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | ||||
on_exit (cancel_cleanup2, engine); | |||||
on_exit (cancel_cleanup, engine); | |||||
if (driver->start (driver)) { | if (driver->start (driver)) { | ||||
jack_error ("cannot start driver"); | jack_error ("cannot start driver"); | ||||
@@ -1238,7 +1217,20 @@ jack_main_thread (void *arg) | |||||
} | } | ||||
while (1) { | while (1) { | ||||
if (driver->wait (driver)) { | |||||
switch (driver->wait (driver)) { | |||||
case -1: | |||||
jack_error ("driver wait function failed, exiting"); | |||||
pthread_exit (0); | |||||
break; | |||||
case 1: | |||||
if (driver->start (driver)) { | |||||
jack_error ("cannot restart driver"); | |||||
pthread_exit (0); | |||||
} | |||||
break; | |||||
default: | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
@@ -1396,11 +1388,17 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client) | |||||
GSList *node; | GSList *node; | ||||
int i; | int i; | ||||
if (engine->verbose) { | |||||
fprintf (stderr, "removing client %s\n", client->control->name); | |||||
} | |||||
/* caller must hold the graph_lock */ | |||||
printf ("remove client\n"); | |||||
/* these stop the process() loop from paying this client any attention, | |||||
as well as stopping jack_deliver_event() from bothering to try to | |||||
talk to the client. | |||||
*/ | |||||
client->control->dead = TRUE; | client->control->dead = TRUE; | ||||
client->control->active = FALSE; | |||||
if (client == engine->timebase_client) { | if (client == engine->timebase_client) { | ||||
engine->timebase_client = 0; | engine->timebase_client = 0; | ||||
@@ -1409,6 +1407,11 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client) | |||||
jack_client_disconnect (engine, client); | jack_client_disconnect (engine, client); | ||||
/* try to force the server thread to return from poll */ | |||||
close (client->event_fd); | |||||
close (client->request_fd); | |||||
for (node = engine->clients; node; node = g_slist_next (node)) { | for (node = engine->clients; node; node = g_slist_next (node)) { | ||||
if (((jack_client_internal_t *) node->data)->control->id == client->control->id) { | if (((jack_client_internal_t *) node->data)->control->id == client->control->id) { | ||||
engine->clients = g_slist_remove_link (engine->clients, node); | engine->clients = g_slist_remove_link (engine->clients, node); | ||||
@@ -1416,13 +1419,13 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client) | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
jack_client_do_deactivate (engine, client); | jack_client_do_deactivate (engine, client); | ||||
/* rearrange the pollfd array so that things work right the | /* rearrange the pollfd array so that things work right the | ||||
next time we go into poll(2). | next time we go into poll(2). | ||||
*/ | */ | ||||
for (i = 0; i < engine->pfd_max; i++) { | for (i = 0; i < engine->pfd_max; i++) { | ||||
if (engine->pfd[i].fd == client->request_fd) { | if (engine->pfd[i].fd == client->request_fd) { | ||||
if (i+1 < engine->pfd_max) { | if (i+1 < engine->pfd_max) { | ||||
@@ -1432,9 +1435,6 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client) | |||||
} | } | ||||
} | } | ||||
close (client->event_fd); | |||||
close (client->request_fd); | |||||
jack_client_delete (engine, client); | jack_client_delete (engine, client); | ||||
} | } | ||||
@@ -1497,7 +1497,8 @@ static int | |||||
jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, jack_event_t *event) | jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, jack_event_t *event) | ||||
{ | { | ||||
char status; | char status; | ||||
int client_err = 0; | |||||
if (client->control->dead) { | if (client->control->dead) { | ||||
return 0; | return 0; | ||||
} | } | ||||
@@ -1530,12 +1531,18 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, jack_ | |||||
} else { | } else { | ||||
if (write (client->event_fd, event, sizeof (*event)) != sizeof (*event)) { | if (write (client->event_fd, event, sizeof (*event)) != sizeof (*event)) { | ||||
jack_error ("cannot send event to client [%s] (%s)", client->control->name, strerror (errno)); | jack_error ("cannot send event to client [%s] (%s)", client->control->name, strerror (errno)); | ||||
return -1; | |||||
client_err++; | |||||
} | } | ||||
if (read (client->event_fd, &status, sizeof (status)) != sizeof (status)) { | |||||
if (!client_err && (read (client->event_fd, &status, sizeof (status)) != sizeof (status))) { | |||||
jack_error ("cannot read event response from client [%s] (%s)", client->control->name, strerror (errno)); | jack_error ("cannot read event response from client [%s] (%s)", client->control->name, strerror (errno)); | ||||
return -1; | |||||
client_err++; | |||||
} | |||||
if (client_err || status != 0) { | |||||
pthread_mutex_lock (&engine->graph_lock); | |||||
jack_remove_client (engine, client); | |||||
pthread_mutex_unlock (&engine->graph_lock); | |||||
} | } | ||||
} | } | ||||
@@ -1704,20 +1711,37 @@ static int | |||||
jack_client_sort (jack_client_internal_t *a, jack_client_internal_t *b) | jack_client_sort (jack_client_internal_t *a, jack_client_internal_t *b) | ||||
{ | { | ||||
/* the driver client always comes after everything else */ | |||||
if (g_slist_find (a->fed_by, b)) { | |||||
if (g_slist_find (b->fed_by, a)) { | |||||
if (a->control->type == ClientDriver) { | |||||
return 1; | |||||
} | |||||
/* feedback loop: if `a' is the driver | |||||
client, let that execute first. | |||||
*/ | |||||
if (b->control->type == ClientDriver) { | |||||
return -1; | |||||
} | |||||
if (a->control->type == ClientDriver) { | |||||
/* b comes after a */ | |||||
return -1; | |||||
} | |||||
} | |||||
if (g_slist_find (a->fed_by, b)) { | |||||
/* a comes after b */ | /* a comes after b */ | ||||
return 1; | return 1; | ||||
} else if (g_slist_find (b->fed_by, a)) { | } else if (g_slist_find (b->fed_by, a)) { | ||||
if (g_slist_find (a->fed_by, b)) { | |||||
/* feedback loop: if `b' is the driver | |||||
client, let that execute first. | |||||
*/ | |||||
if (b->control->type == ClientDriver) { | |||||
/* b comes before a */ | |||||
return 1; | |||||
} | |||||
} | |||||
/* b comes after a */ | /* b comes after a */ | ||||
return -1; | return -1; | ||||
} else { | } else { | ||||
@@ -1775,7 +1799,9 @@ jack_client_feeds (jack_client_internal_t *might, jack_client_internal_t *target | |||||
* | * | ||||
* 3) now sort according to whether or not client1->fed_by (client2) is true. | * 3) now sort according to whether or not client1->fed_by (client2) is true. | ||||
* if the condition is true, client2 must execute before client1 | * if the condition is true, client2 must execute before client1 | ||||
* | |||||
*/ | */ | ||||
static void | static void | ||||
jack_sort_graph (jack_engine_t *engine, int take_lock) | jack_sort_graph (jack_engine_t *engine, int take_lock) | ||||
{ | { | ||||
@@ -2197,10 +2223,14 @@ static void | |||||
jack_port_release (jack_engine_t *engine, jack_port_internal_t *port) | jack_port_release (jack_engine_t *engine, jack_port_internal_t *port) | ||||
{ | { | ||||
/* XXX add the buffer used by the port back the (correct) freelist */ | |||||
pthread_mutex_lock (&engine->port_lock); | pthread_mutex_lock (&engine->port_lock); | ||||
port->shared->in_use = 0; | port->shared->in_use = 0; | ||||
if (port->buffer_info) { | |||||
pthread_mutex_lock (&engine->buffer_lock); | |||||
engine->port_buffer_freelist = g_slist_prepend (engine->port_buffer_freelist, port->buffer_info); | |||||
pthread_mutex_unlock (&engine->buffer_lock); | |||||
} | |||||
pthread_mutex_unlock (&engine->port_lock); | pthread_mutex_unlock (&engine->port_lock); | ||||
} | } | ||||
@@ -2274,7 +2304,7 @@ jack_port_do_register (jack_engine_t *engine, jack_request_t *req) | |||||
pthread_mutex_unlock (&engine->graph_lock); | pthread_mutex_unlock (&engine->graph_lock); | ||||
if (engine->verbose) { | if (engine->verbose) { | ||||
fprintf (stderr, "registered port %s\n", shared->name); | |||||
fprintf (stderr, "registered port %s, offset = %u\n", shared->name, shared->offset); | |||||
} | } | ||||
req->x.port_info.port_id = port_id; | req->x.port_info.port_id = port_id; | ||||
@@ -2349,7 +2379,7 @@ int | |||||
jack_port_assign_buffer (jack_engine_t *engine, jack_port_internal_t *port) | jack_port_assign_buffer (jack_engine_t *engine, jack_port_internal_t *port) | ||||
{ | { | ||||
GSList *node; | GSList *node; | ||||
jack_port_segment_info_t *psi; | |||||
jack_port_segment_info_t *psi = 0; | |||||
jack_port_buffer_info_t *bi; | jack_port_buffer_info_t *bi; | ||||
port->shared->shm_key = -1; | port->shared->shm_key = -1; | ||||
@@ -2367,7 +2397,7 @@ jack_port_assign_buffer (jack_engine_t *engine, jack_port_internal_t *port) | |||||
} | } | ||||
bi = (jack_port_buffer_info_t *) engine->port_buffer_freelist->data; | bi = (jack_port_buffer_info_t *) engine->port_buffer_freelist->data; | ||||
for (node = engine->port_segments; node; node = g_slist_next (node)) { | for (node = engine->port_segments; node; node = g_slist_next (node)) { | ||||
psi = (jack_port_segment_info_t *) node->data; | psi = (jack_port_segment_info_t *) node->data; | ||||
@@ -2375,9 +2405,9 @@ jack_port_assign_buffer (jack_engine_t *engine, jack_port_internal_t *port) | |||||
if (bi->shm_key == psi->shm_key) { | if (bi->shm_key == psi->shm_key) { | ||||
port->shared->shm_key = psi->shm_key; | port->shared->shm_key = psi->shm_key; | ||||
port->shared->offset = bi->offset; | port->shared->offset = bi->offset; | ||||
port->buffer_info = bi; | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (port->shared->shm_key >= 0) { | if (port->shared->shm_key >= 0) { | ||||
@@ -2417,7 +2447,7 @@ jack_get_port_by_name (jack_engine_t *engine, const char *name) | |||||
static int | static int | ||||
jack_send_connection_notification (jack_engine_t *engine, jack_client_id_t client_id, | jack_send_connection_notification (jack_engine_t *engine, jack_client_id_t client_id, | ||||
jack_port_id_t self_id, jack_port_id_t other_id, int connected) | |||||
jack_port_id_t self_id, jack_port_id_t other_id, int connected) | |||||
{ | { | ||||
jack_client_internal_t *client; | jack_client_internal_t *client; | ||||
@@ -77,10 +77,7 @@ typedef struct { | |||||
float max_sample_val; | float max_sample_val; | ||||
unsigned long user_nperiods; | unsigned long user_nperiods; | ||||
unsigned long nfragments; | unsigned long nfragments; | ||||
int max_level; | |||||
int min_level; | |||||
unsigned long last_mask; | unsigned long last_mask; | ||||
unsigned long silence_pending; | |||||
snd_ctl_t *ctl_handle; | snd_ctl_t *ctl_handle; | ||||
snd_pcm_t *playback_handle; | snd_pcm_t *playback_handle; | ||||
snd_pcm_t *capture_handle; | snd_pcm_t *capture_handle; | ||||
@@ -147,11 +144,10 @@ static __inline__ void alsa_driver_silence_on_channel_no_mark (alsa_driver_t *dr | |||||
static __inline__ void alsa_driver_read_from_channel (alsa_driver_t *driver, | static __inline__ void alsa_driver_read_from_channel (alsa_driver_t *driver, | ||||
channel_t channel, sample_t *buf, | channel_t channel, sample_t *buf, | ||||
nframes_t nsamples, | |||||
unsigned long offset) | |||||
nframes_t nsamples) | |||||
{ | { | ||||
driver->read_via_copy (buf, | driver->read_via_copy (buf, | ||||
driver->capture_addr[channel] + offset, | |||||
driver->capture_addr[channel], | |||||
nsamples, | nsamples, | ||||
driver->capture_interleave_skip); | driver->capture_interleave_skip); | ||||
} | } | ||||
@@ -160,10 +156,9 @@ static __inline__ void alsa_driver_write_to_channel (alsa_driver_t *driver, | |||||
channel_t channel, | channel_t channel, | ||||
sample_t *buf, | sample_t *buf, | ||||
nframes_t nsamples, | nframes_t nsamples, | ||||
unsigned long offset, | |||||
gain_t gain) | gain_t gain) | ||||
{ | { | ||||
driver->write_via_copy (driver->playback_addr[channel] + offset, | |||||
driver->write_via_copy (driver->playback_addr[channel], | |||||
buf, | buf, | ||||
nsamples, | nsamples, | ||||
driver->playback_interleave_skip, | driver->playback_interleave_skip, | ||||
@@ -191,11 +191,10 @@ typedef enum { | |||||
ConnectPorts = 3, | ConnectPorts = 3, | ||||
DisconnectPorts = 4, | DisconnectPorts = 4, | ||||
SetTimeBaseClient = 5, | SetTimeBaseClient = 5, | ||||
DropClient = 6, | |||||
ActivateClient = 7, | |||||
DeactivateClient = 8, | |||||
GetPortTotalLatency = 9, | |||||
DisconnectPort = 10 | |||||
ActivateClient = 6, | |||||
DeactivateClient = 7, | |||||
GetPortTotalLatency = 8, | |||||
DisconnectPort = 9 | |||||
} AudioEngineRequestType; | } AudioEngineRequestType; | ||||
typedef struct { | typedef struct { | ||||
@@ -95,6 +95,7 @@ struct _jack_port { | |||||
typedef struct _jack_port_internal { | typedef struct _jack_port_internal { | ||||
struct _jack_port_shared *shared; | struct _jack_port_shared *shared; | ||||
GSList *connections; | GSList *connections; | ||||
void *buffer_info; | |||||
} jack_port_internal_t; | } jack_port_internal_t; | ||||
#endif /* __jack_port_h__ */ | #endif /* __jack_port_h__ */ | ||||
@@ -20,7 +20,7 @@ main (int argc, char *argv[]) | |||||
if (jack_port_request_monitor_by_name (client, "alsa_pcm:in_1", TRUE)) { | if (jack_port_request_monitor_by_name (client, "alsa_pcm:in_1", TRUE)) { | ||||
fprintf (stderr, "could not enable monitoring for in_1\n"); | fprintf (stderr, "could not enable monitoring for in_1\n"); | ||||
} | } | ||||
sleep (10); | |||||
sleep (30); | |||||
if (jack_port_request_monitor_by_name (client, "alsa_pcm:in_1", FALSE)) { | if (jack_port_request_monitor_by_name (client, "alsa_pcm:in_1", FALSE)) { | ||||
fprintf (stderr, "could not disable monitoring for in_1\n"); | fprintf (stderr, "could not disable monitoring for in_1\n"); | ||||
} | } | ||||
@@ -3,6 +3,8 @@ | |||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <jack/jack.h> | #include <jack/jack.h> | ||||
#include <glib.h> | |||||
#include <jack/port.h> | |||||
jack_port_t *input_port; | jack_port_t *input_port; | ||||
jack_port_t *output_port; | jack_port_t *output_port; | ||||
@@ -15,7 +17,6 @@ process (nframes_t nframes, void *arg) | |||||
sample_t *in = (sample_t *) jack_port_get_buffer (input_port, nframes); | sample_t *in = (sample_t *) jack_port_get_buffer (input_port, nframes); | ||||
memcpy (out, in, sizeof (sample_t) * nframes); | memcpy (out, in, sizeof (sample_t) * nframes); | ||||
return 0; | return 0; | ||||
} | } | ||||
@@ -119,7 +120,7 @@ main (int argc, char *argv[]) | |||||
/* Since this is just a toy, run for 5 seconds, then finish */ | /* Since this is just a toy, run for 5 seconds, then finish */ | ||||
sleep (5); | |||||
sleep (2); | |||||
jack_client_close (client); | jack_client_close (client); | ||||
exit (0); | exit (0); | ||||
} | } | ||||