git-svn-id: svn+ssh://jackaudio.org/trunk/jack@114 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.109.0
| @@ -565,7 +565,7 @@ alsa_driver_audio_start (alsa_driver_t *driver) | |||
| if (driver->pfd) | |||
| free (driver->pfd); | |||
| driver->pfd = (struct pollfd *) malloc (sizeof (struct pollfd) * | |||
| (driver->playback_nfds + driver->capture_nfds + 1)); | |||
| (driver->playback_nfds + driver->capture_nfds + 2)); | |||
| return 0; | |||
| } | |||
| @@ -648,28 +648,25 @@ alsa_driver_set_clock_sync_status (alsa_driver_t *driver, channel_t chn, ClockSy | |||
| } | |||
| static int under_gdb = FALSE; | |||
| static int waitcnt = 0; | |||
| static int | |||
| alsa_driver_wait (alsa_driver_t *driver) | |||
| static nframes_t | |||
| alsa_driver_wait (alsa_driver_t *driver, int fd, int *status) | |||
| { | |||
| snd_pcm_sframes_t avail = 0; | |||
| snd_pcm_sframes_t contiguous = 0; | |||
| snd_pcm_sframes_t capture_avail = 0; | |||
| snd_pcm_sframes_t playback_avail = 0; | |||
| snd_pcm_uframes_t capture_offset = 0; | |||
| snd_pcm_uframes_t playback_offset = 0; | |||
| int xrun_detected; | |||
| channel_t chn; | |||
| GSList *node; | |||
| int need_capture = 1; | |||
| int need_playback = 1; | |||
| jack_engine_t *engine = driver->engine; | |||
| int need_capture; | |||
| int need_playback; | |||
| int i; | |||
| static unsigned long long last = 0; | |||
| unsigned long long start; | |||
| *status = -1; | |||
| need_capture = 1; | |||
| if (fd >= 0) { | |||
| need_playback = 0; | |||
| } else { | |||
| need_playback = 1; | |||
| } | |||
| again: | |||
| @@ -698,6 +695,12 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| driver->pfd[nfds].events |= POLLERR; | |||
| } | |||
| if (fd >= 0) { | |||
| driver->pfd[nfds].fd = fd; | |||
| driver->pfd[nfds].events = POLLIN|POLLERR|POLLHUP|POLLNVAL; | |||
| nfds++; | |||
| } | |||
| if (poll (driver->pfd, nfds, 1000) < 0) { | |||
| if (errno == EINTR) { | |||
| printf ("poll interrupt\n"); | |||
| @@ -706,16 +709,27 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| if (under_gdb) { | |||
| goto again; | |||
| } | |||
| return 1; | |||
| return 0; | |||
| } | |||
| jack_error ("ALSA::Device: poll call failed (%s)", strerror (errno)); | |||
| return -1; | |||
| return 0; | |||
| } | |||
| rdtscll (start); | |||
| // fprintf (stderr, "engine cycle %.6f msecs\n", (((float) (start - last))/450000.0f)); | |||
| last = start; | |||
| /* check to see if it was the extra FD that caused us to return from poll | |||
| */ | |||
| if (fd >= 0) { | |||
| if (driver->pfd[nfds-1].revents == 0) { | |||
| /* we timed out on the extra fd */ | |||
| return -1; | |||
| } else { | |||
| /* if POLLIN was the only bit set, we're OK */ | |||
| *status = 0; | |||
| return (driver->pfd[nfds-1].revents == POLLIN) ? 0 : -1; | |||
| } | |||
| } | |||
| if (driver->engine) { | |||
| struct timeval tv; | |||
| @@ -729,7 +743,7 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| for (i = 0; i < driver->playback_nfds; i++) { | |||
| if (driver->pfd[i].revents & POLLERR) { | |||
| jack_error ("ALSA: poll reports error on playback stream."); | |||
| return -1; | |||
| return 0; | |||
| } | |||
| if (driver->pfd[i].revents == 0) { | |||
| @@ -748,7 +762,7 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| for (i = ci; i < nfds; i++) { | |||
| if (driver->pfd[i].revents & POLLERR) { | |||
| jack_error ("ALSA: poll reports error on capture stream."); | |||
| return -1; | |||
| return 0; | |||
| } | |||
| if (driver->pfd[i].revents == 0) { | |||
| @@ -763,7 +777,7 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| if (p_timed_out == driver->playback_nfds && c_timed_out == driver->capture_nfds) { | |||
| jack_error ("ALSA: poll time out"); | |||
| return -1; | |||
| return 0; | |||
| } | |||
| } | |||
| @@ -787,23 +801,37 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| } | |||
| if (xrun_detected) { | |||
| return alsa_driver_xrun_recovery (driver); | |||
| *status = alsa_driver_xrun_recovery (driver); | |||
| return 0; | |||
| } | |||
| *status = 0; | |||
| avail = capture_avail < playback_avail ? capture_avail : playback_avail; | |||
| /* constrain the available count to the nearest (round down) number of | |||
| periods. | |||
| */ | |||
| avail = avail - (avail % driver->frames_per_cycle); | |||
| return avail - (avail % driver->frames_per_cycle); | |||
| } | |||
| while (avail) { | |||
| static int | |||
| alsa_driver_process (alsa_driver_t *driver, nframes_t nframes) | |||
| { | |||
| snd_pcm_sframes_t contiguous = 0; | |||
| snd_pcm_sframes_t capture_avail = 0; | |||
| snd_pcm_sframes_t playback_avail = 0; | |||
| snd_pcm_uframes_t capture_offset = 0; | |||
| snd_pcm_uframes_t playback_offset = 0; | |||
| channel_t chn; | |||
| GSList *node; | |||
| jack_engine_t *engine = driver->engine; | |||
| waitcnt++; | |||
| while (nframes) { | |||
| capture_avail = (avail > driver->frames_per_cycle) ? driver->frames_per_cycle : avail; | |||
| playback_avail = (avail > driver->frames_per_cycle) ? driver->frames_per_cycle : avail; | |||
| capture_avail = (nframes > driver->frames_per_cycle) ? driver->frames_per_cycle : nframes; | |||
| playback_avail = (nframes > driver->frames_per_cycle) ? driver->frames_per_cycle : nframes; | |||
| if (alsa_driver_get_channel_addresses (driver, | |||
| (snd_pcm_uframes_t *) &capture_avail, | |||
| @@ -817,9 +845,25 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| driver->channels_not_done = driver->channel_done_bits; | |||
| if (engine->process_lock (engine) == 0) { | |||
| channel_t chn; | |||
| jack_port_t *port; | |||
| GSList *node; | |||
| int ret; | |||
| GSList *prev; | |||
| for (chn = 0, node = driver->capture_ports; node; node = g_slist_next (node), chn++) { | |||
| port = (jack_port_t *) node->data; | |||
| if (!jack_port_connected (port)) { | |||
| continue; | |||
| } | |||
| alsa_driver_read_from_channel (driver, chn, jack_port_get_buffer (port, nframes), nframes); | |||
| } | |||
| snd_pcm_mmap_commit (driver->capture_handle, capture_offset, contiguous); | |||
| if ((ret = engine->process (engine, contiguous)) != 0) { | |||
| engine->process_unlock (engine); | |||
| alsa_driver_audio_stop (driver); | |||
| @@ -831,7 +875,7 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| /* now move data from ports to channels */ | |||
| for (chn = 0, prev = 0, node = driver->playback_ports; node; prev = node, node = g_slist_next (node), chn++) { | |||
| for (chn = 0, node = driver->playback_ports; node; node = g_slist_next (node), chn++) { | |||
| jack_port_t *port = (jack_port_t *) node->data; | |||
| @@ -880,39 +924,15 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| alsa_driver_silence_untouched_channels (driver, contiguous); | |||
| } | |||
| snd_pcm_mmap_commit (driver->capture_handle, capture_offset, contiguous); | |||
| snd_pcm_mmap_commit (driver->playback_handle, playback_offset, contiguous); | |||
| avail -= contiguous; | |||
| nframes -= contiguous; | |||
| } | |||
| engine->post_process (engine); | |||
| return 0; | |||
| } | |||
| static int | |||
| alsa_driver_process (nframes_t nframes, void *arg) | |||
| { | |||
| alsa_driver_t *driver = (alsa_driver_t *) arg; | |||
| channel_t chn; | |||
| jack_port_t *port; | |||
| GSList *node; | |||
| for (chn = 0, node = driver->capture_ports; node; node = g_slist_next (node), chn++) { | |||
| port = (jack_port_t *) node->data; | |||
| if (!jack_port_connected (port)) { | |||
| continue; | |||
| } | |||
| alsa_driver_read_from_channel (driver, chn, jack_port_get_buffer (port, nframes), nframes); | |||
| } | |||
| return 0; | |||
| } | |||
| static void | |||
| alsa_driver_attach (alsa_driver_t *driver, jack_engine_t *engine) | |||
| @@ -933,8 +953,6 @@ alsa_driver_attach (alsa_driver_t *driver, jack_engine_t *engine) | |||
| return; | |||
| } | |||
| jack_set_process_callback (driver->client, alsa_driver_process, driver); | |||
| for (chn = 0; chn < driver->capture_nchannels; chn++) { | |||
| snprintf (buf, sizeof(buf) - 1, "in_%lu", chn+1); | |||
| port = jack_port_register (driver->client, buf, | |||
| @@ -1128,6 +1146,7 @@ alsa_driver_new (char *name, char *alsa_device, | |||
| driver->attach = (JackDriverAttachFunction) alsa_driver_attach; | |||
| driver->detach = (JackDriverDetachFunction) alsa_driver_detach; | |||
| driver->wait = (JackDriverWaitFunction) alsa_driver_wait; | |||
| driver->process = (JackDriverProcessFunction) alsa_driver_process; | |||
| driver->start = (JackDriverStartFunction) alsa_driver_audio_start; | |||
| driver->stop = (JackDriverStopFunction) alsa_driver_audio_stop; | |||
| @@ -5,7 +5,7 @@ AC_CONFIG_AUX_DIR(.) | |||
| JACK_MAJOR_VERSION=0 | |||
| JACK_MINOR_VERSION=11 | |||
| JACK_MICRO_VERSION=6 | |||
| JACK_MICRO_VERSION=7 | |||
| BETA= | |||
| @@ -28,7 +28,8 @@ | |||
| static int dummy_attach (jack_driver_t *drv, jack_engine_t *eng) { return 0; } | |||
| static int dummy_detach (jack_driver_t *drv, jack_engine_t *eng) { return 0; } | |||
| static int dummy_wait (jack_driver_t *drv) { return 0; } | |||
| static nframes_t dummy_wait (jack_driver_t *drv, int fd, int *status) { *status = 0; return 0; } | |||
| static int dummy_process (jack_driver_t *drv, nframes_t nframes) { return 0; } | |||
| static int dummy_stop (jack_driver_t *drv) { return 0; } | |||
| static int dummy_start (jack_driver_t *drv) { return 0; } | |||
| @@ -41,6 +42,7 @@ jack_driver_init (jack_driver_t *driver) | |||
| driver->attach = dummy_attach; | |||
| driver->detach = dummy_detach; | |||
| driver->wait = dummy_wait; | |||
| driver->process = dummy_process; | |||
| driver->start = dummy_start; | |||
| driver->stop = dummy_stop; | |||
| } | |||
| @@ -368,7 +368,7 @@ jack_add_port_segment (jack_engine_t *engine, unsigned long nports) | |||
| /* convert the first chunk of the segment into a zero-filled area */ | |||
| if (engine->silent_buffer == 0) { | |||
| if (engine->silent_buffer == NULL) { | |||
| engine->silent_buffer = (jack_port_buffer_info_t *) engine->port_buffer_freelist->data; | |||
| engine->port_buffer_freelist = g_slist_remove_link (engine->port_buffer_freelist, engine->port_buffer_freelist); | |||
| @@ -420,12 +420,11 @@ jack_engine_process_unlock (jack_engine_t *engine) | |||
| static int | |||
| jack_process (jack_engine_t *engine, nframes_t nframes) | |||
| { | |||
| int err = 0; | |||
| jack_client_internal_t *client; | |||
| jack_client_control_t *ctl; | |||
| GSList *node; | |||
| struct pollfd pollfd[1]; | |||
| char c; | |||
| int status; | |||
| engine->process_errors = 0; | |||
| @@ -439,7 +438,7 @@ jack_process (jack_engine_t *engine, nframes_t nframes) | |||
| engine->control->time.frame = engine->timebase_client->control->frame_time; | |||
| } | |||
| for (node = engine->clients; err == 0 && node; ) { | |||
| for (node = engine->clients; engine->process_errors == 0 && node; ) { | |||
| client = (jack_client_internal_t *) node->data; | |||
| @@ -454,14 +453,20 @@ jack_process (jack_engine_t *engine, nframes_t nframes) | |||
| /* in-process client ("plugin") */ | |||
| ctl->state = Running; | |||
| if (ctl->process) { | |||
| ctl->state = Running; | |||
| if (ctl->process (nframes, ctl->process_arg) == 0) { | |||
| ctl->state = Finished; | |||
| } else { | |||
| jack_error ("in-process client %s failed", client->control->name); | |||
| engine->process_errors++; | |||
| break; | |||
| } | |||
| if (ctl->process (nframes, ctl->process_arg) == 0) { | |||
| ctl->state = Finished; | |||
| } else { | |||
| jack_error ("in-process client %s failed", client->control->name); | |||
| engine->process_errors++; | |||
| break; | |||
| ctl->state = Finished; | |||
| } | |||
| node = g_slist_next (node); | |||
| @@ -478,28 +483,11 @@ jack_process (jack_engine_t *engine, nframes_t nframes) | |||
| break; | |||
| } | |||
| /* now wait for the result. use poll instead of read so that we | |||
| can timeout effectively. | |||
| */ | |||
| pollfd[0].fd = client->subgraph_wait_fd; | |||
| pollfd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL; | |||
| if (poll (pollfd, 1, engine->driver->period_interval) < 0) { | |||
| if (errno == EINTR) { | |||
| continue; | |||
| } | |||
| jack_error ("engine cannot poll for graph completion (%s)", strerror (errno)); | |||
| engine->process_errors++; | |||
| break; | |||
| } | |||
| if (pollfd[0].revents == 0) { | |||
| jack_error ("subgraph starting at %s timed out (state = %d)", client->control->name, client->control->state); | |||
| engine->process_errors++; | |||
| break; | |||
| } else if (pollfd[0].revents & ~POLLIN) { | |||
| jack_error ("error/hangup on graph wait fd"); | |||
| engine->driver->wait (engine->driver, client->subgraph_wait_fd, &status); | |||
| if (status != 0) { | |||
| jack_error ("subgraph starting at %s timed out (status = %d, state = %d)", | |||
| client->control->name, status, client->control->state); | |||
| engine->process_errors++; | |||
| break; | |||
| } else { | |||
| @@ -542,7 +530,7 @@ jack_load_client (jack_engine_t *engine, jack_client_internal_t *client, const c | |||
| handle = dlopen (path_to_so, RTLD_NOW|RTLD_GLOBAL); | |||
| if (handle == 0) { | |||
| if (handle == NULL) { | |||
| if ((errstr = dlerror ()) != 0) { | |||
| jack_error ("can't load \"%s\": %s", path_to_so, errstr); | |||
| } else { | |||
| @@ -844,8 +832,8 @@ handle_client_jack_error (jack_engine_t *engine, int fd) | |||
| } | |||
| } | |||
| if (client == 0) { | |||
| jack_error ("no client found for fd %d\n", fd); | |||
| if (client == NULL) { | |||
| /* client removed by driver thread */ | |||
| pthread_mutex_unlock (&engine->graph_lock); | |||
| return -1; | |||
| } | |||
| @@ -875,7 +863,7 @@ handle_client_io (jack_engine_t *engine, int fd) | |||
| pthread_mutex_unlock (&engine->graph_lock); | |||
| if (client == 0) { | |||
| if (client == NULL) { | |||
| jack_error ("client input on unknown fd %d!", fd); | |||
| return -1; | |||
| } | |||
| @@ -1214,10 +1202,20 @@ jack_main_thread (void *arg) | |||
| } | |||
| while (1) { | |||
| switch (driver->wait (driver)) { | |||
| case -1: | |||
| int status; | |||
| nframes_t nframes; | |||
| nframes = driver->wait (driver, -1, &status); | |||
| if (status != 0) { | |||
| jack_error ("driver wait function failed, exiting"); | |||
| pthread_exit (0); | |||
| } | |||
| switch (driver->process (driver, nframes)) { | |||
| case -1: | |||
| jack_error ("driver process function failed, exiting"); | |||
| pthread_exit (0); | |||
| break; | |||
| case 1: | |||
| @@ -1239,7 +1237,7 @@ int | |||
| jack_run (jack_engine_t *engine) | |||
| { | |||
| if (engine->driver == 0) { | |||
| if (engine->driver == NULL) { | |||
| jack_error ("engine driver not set; cannot start"); | |||
| return -1; | |||
| } | |||
| @@ -1626,7 +1624,7 @@ jack_rechain_graph (jack_engine_t *engine, int take_lock) | |||
| } else { | |||
| if (subgraph_client == 0) { | |||
| if (subgraph_client == NULL) { | |||
| /* start a new subgraph. the engine will start the chain | |||
| by writing to the nth FIFO. | |||
| @@ -1667,7 +1665,7 @@ jack_trace_terminal (jack_client_internal_t *c1, jack_client_internal_t *rbase) | |||
| GSList *existing; | |||
| GSList *node; | |||
| if (c1->fed_by == 0) { | |||
| if (c1->fed_by == NULL) { | |||
| return; | |||
| } | |||
| @@ -1893,12 +1891,12 @@ jack_port_do_connect (jack_engine_t *engine, | |||
| jack_port_internal_t *srcport, *dstport; | |||
| jack_port_id_t src_id, dst_id; | |||
| if ((srcport = jack_get_port_by_name (engine, source_port)) == 0) { | |||
| if ((srcport = jack_get_port_by_name (engine, source_port)) == NULL) { | |||
| jack_error ("unknown source port in attempted connection [%s]", source_port); | |||
| return -1; | |||
| } | |||
| if ((dstport = jack_get_port_by_name (engine, destination_port)) == 0) { | |||
| if ((dstport = jack_get_port_by_name (engine, destination_port)) == NULL) { | |||
| jack_error ("unknown destination port in attempted connection [%s]", destination_port); | |||
| return -1; | |||
| } | |||
| @@ -2053,12 +2051,12 @@ jack_port_do_disconnect (jack_engine_t *engine, | |||
| jack_port_internal_t *srcport, *dstport; | |||
| int ret = -1; | |||
| if ((srcport = jack_get_port_by_name (engine, source_port)) == 0) { | |||
| if ((srcport = jack_get_port_by_name (engine, source_port)) == NULL) { | |||
| jack_error ("unknown source port in attempted disconnection [%s]", source_port); | |||
| return -1; | |||
| } | |||
| if ((dstport = jack_get_port_by_name (engine, destination_port)) == 0) { | |||
| if ((dstport = jack_get_port_by_name (engine, destination_port)) == NULL) { | |||
| jack_error ("unknown destination port in attempted connection [%s]", destination_port); | |||
| return -1; | |||
| } | |||
| @@ -2281,7 +2279,7 @@ jack_port_do_register (jack_engine_t *engine, jack_request_t *req) | |||
| jack_client_internal_t *client; | |||
| pthread_mutex_lock (&engine->graph_lock); | |||
| if ((client = jack_client_internal_by_id (engine, req->x.port_info.client_id)) == 0) { | |||
| if ((client = jack_client_internal_by_id (engine, req->x.port_info.client_id)) == NULL) { | |||
| jack_error ("unknown client id in port registration request"); | |||
| return -1; | |||
| } | |||
| @@ -2466,7 +2464,7 @@ jack_send_connection_notification (jack_engine_t *engine, jack_client_id_t clien | |||
| jack_client_internal_t *client; | |||
| jack_event_t event; | |||
| if ((client = jack_client_internal_by_id (engine, client_id)) == 0) { | |||
| if ((client = jack_client_internal_by_id (engine, client_id)) == NULL) { | |||
| jack_error ("no such client %d during connection notification", client_id); | |||
| return -1; | |||
| } | |||
| @@ -37,11 +37,12 @@ typedef struct { | |||
| struct _jack_engine; | |||
| struct _jack_driver; | |||
| typedef int (*JackDriverAttachFunction)(struct _jack_driver *, struct _jack_engine *); | |||
| typedef int (*JackDriverDetachFunction)(struct _jack_driver *, struct _jack_engine *); | |||
| typedef int (*JackDriverWaitFunction)(struct _jack_driver *); | |||
| typedef int (*JackDriverStopFunction)(struct _jack_driver *); | |||
| typedef int (*JackDriverStartFunction)(struct _jack_driver *); | |||
| typedef int (*JackDriverAttachFunction)(struct _jack_driver *, struct _jack_engine *); | |||
| typedef int (*JackDriverDetachFunction)(struct _jack_driver *, struct _jack_engine *); | |||
| typedef nframes_t (*JackDriverWaitFunction)(struct _jack_driver *, int fd, int *status); | |||
| typedef int (*JackDriverProcessFunction)(struct _jack_driver *, nframes_t); | |||
| typedef int (*JackDriverStopFunction)(struct _jack_driver *); | |||
| typedef int (*JackDriverStartFunction)(struct _jack_driver *); | |||
| #define JACK_DRIVER_DECL \ | |||
| nframes_t period_interval; \ | |||
| @@ -50,6 +51,7 @@ typedef int (*JackDriverStartFunction)(struct _jack_driver *); | |||
| JackDriverAttachFunction attach; \ | |||
| JackDriverDetachFunction detach; \ | |||
| JackDriverWaitFunction wait; \ | |||
| JackDriverProcessFunction process; \ | |||
| JackDriverStartFunction stop; \ | |||
| JackDriverStopFunction start; | |||