From 9ffa1f410a95fd78a9f8a49ee43fac6ecae7a0e5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 7 Sep 2011 15:13:47 +0900 Subject: [PATCH] Detect the silent death of the jack client thread. When jackd gets an unhandled xrun, it stops all processing but neglects to tell the client about it. Thus, add a bit of a watchdog function to s_update() and assume the client thread is dead if there's no sign of life after one second. No more hanging on exit. --- TODO | 10 +++--- libs/audio/renderer/snd_jack.c | 58 +++++++++++++++++++++++++++++----- 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/TODO b/TODO index 8cced4db9..11797f1f9 100644 --- a/TODO +++ b/TODO @@ -14,28 +14,30 @@ X ~/.quakeforgerc should support all commands, not just set and setrom X software PCXs don't work in X11 at least if you're using 16/24/32 color X ogg support X server-side demos +X Scitech MGL used in win32 is screwed - dump it and use SDL +X kill MAX_STATIC_ENTITIES +X stateful console (eg, rcon mode, chat mode, normal command mode...) M it seems possible to crash a QF server still - need to fix this! M merge nq and qw code bases M mingw cross compiling -X Scitech MGL used in win32 is screwed - dump it and use SDL M software targets should mix color at 16/16 or 24/32 color I GL is still way too slow I Client side QuakeC. I menu rewrite I clean up TODO ;) -o kill MAX_STATIC_ENTITIES o doublesize modes (eg, render in 320x240 but display in 640x480) o allow qf clients to download .lit files from qf servers. o better server control of certain cvars o triggers (f_respawn, f_death, f_took; cl_triggers) -X stateful console (eg, rcon mode, chat mode, normal command mode...) o scripted hud o add a U_PHYSICAL field to entities. it should include a solid bit, a rotated bbox bit, and mins/maxs for the bbos o gui for serverlist -o add favorates serverlist manipulation +o add favorites serverlist manipulation o redo serverlist filtering for better flexability and/or easier use o add individual server ping/info request from console +? dynamically allocate missing fields, particularly ones not needed by the + progs. ? more direct intra-team comms (eg, talk to offense or defense directly) ? Draw_Pic and friends need a cleanup in GL at least ? Draw_Pic and other tex draw functions should use local palettes diff --git a/libs/audio/renderer/snd_jack.c b/libs/audio/renderer/snd_jack.c index f6d28d8de..664c2e1fd 100644 --- a/libs/audio/renderer/snd_jack.c +++ b/libs/audio/renderer/snd_jack.c @@ -53,6 +53,8 @@ static __attribute__ ((used)) const char rcsid[] = static int sound_started = 0; static int snd_blocked = 0; static int snd_shutdown = 0; +static int snd_alive = 0; +static double snd_alive_time = 0; static jack_client_t *jack_handle; static jack_port_t *jack_out[2]; static dma_t _snd_shm; @@ -78,12 +80,38 @@ s_start_sound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin, SND_StartSound (entnum, entchannel, sfx, origin, fvol, attenuation); } +static void +s_finish_channels (void) +{ + int i; + channel_t *ch; + + for (i = 0; i < MAX_CHANNELS; i++) { + ch = &snd_channels[i]; + ch->done = ch->stop = 1; + } +} + static void s_update (const vec3_t origin, const vec3_t forward, const vec3_t right, const vec3_t up) { + double now = Sys_DoubleTime (); + if (!sound_started) return; + if (snd_alive) { + snd_alive = 0; + snd_alive_time = now; + } else { + if (!snd_shutdown) { + if (now - snd_alive_time > 1.0) { + Sys_Printf ("jackd client thread seems to have died\n"); + s_finish_channels (); + snd_shutdown = 1; + } + } + } if (snd_shutdown) { if (snd_shutdown == 1) { snd_shutdown++; @@ -120,8 +148,10 @@ s_jack_activate (void) } ports = jack_get_ports (jack_handle, 0, 0, JackPortIsPhysical | JackPortIsInput); - //for (i = 0; ports[i]; i++) - // Sys_Printf ("%s\n", ports[i]); + if (developer->int_val & SYS_SND) { + for (i = 0; ports[i]; i++) + Sys_Printf ("%s\n", ports[i]); + } for (i = 0; i < 2; i++) jack_connect (jack_handle, jack_port_name (jack_out[i]), ports[i]); free (ports); @@ -254,6 +284,7 @@ snd_jack_process (jack_nframes_t nframes, void *arg) { int i; + snd_alive = 1; for (i = 0; i < 2; i++) output[i] = (float *) jack_port_get_buffer (jack_out[i], nframes); SND_PaintChannels (snd_paintedtime + nframes); @@ -263,13 +294,21 @@ snd_jack_process (jack_nframes_t nframes, void *arg) static void snd_jack_shutdown (void *arg) { - int i; - channel_t *ch; snd_shutdown = 1; - for (i = 0; i < MAX_CHANNELS; i++) { - ch = &snd_channels[i]; - ch->done = ch->stop = 1; - } + s_finish_channels (); +} + +static void +snd_jack_error (const char *desc) +{ + fprintf (stderr, "snd_jack: %s\n", desc); +} + +static int +snd_jack_xrun (void *arg) +{ + fprintf (stderr, "snd_jack: xrun\n"); + return 0; } static void @@ -291,12 +330,15 @@ s_init (void) SND_SFX_Init (); SND_Channels_Init (); + jack_set_error_function (snd_jack_error); if ((jack_handle = jack_client_open ("QuakeForge", JackServerName | JackNoStartServer, 0, snd_jack_server->string)) == 0) { Sys_Printf ("Could not connect to JACK\n"); return; } + if (jack_set_xrun_callback (jack_handle, snd_jack_xrun, 0)) + Sys_Printf ("Could not set xrun callback\n"); jack_set_process_callback (jack_handle, snd_jack_process, 0); jack_on_shutdown (jack_handle, snd_jack_shutdown, 0); for (i = 0; i < 2; i++)