[PATCH] JACK 0.109.2 alsa device disconnect patch

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

[PATCH] JACK 0.109.2 alsa device disconnect patch

Salvatore Di Pietro
Hi all,
I just fitted Sean Meiners' alsa device disconnect patch for JACK 0.109.2.

It enables jackd to detach from the ALSA device, letting its use by
other non-JACK programs whilst in the middle of a jack session, without
closing jackd and its clients. IMHO very useful for i.e common builtin
laptop soundcards which don't support more than one alsa-direct audio
app at once (also commonly known as "no hardware mixing soundcards").

You get an additional example client: jack_device_connect (based on
jack_freewheel, its arguments are "y" or "n") which you use to make jack
release and re-hook to the audio card. Time is paused and all audio from
jack is of course muted and jackd and its client applications are put
into this fake-freewheel mode while jack has released the device; they
continue producing and consuming audio upon jackd re-attaching to the
audio device, with the command "jack_device_connect y".

The original version was for jack 0.100.0, I just modified it to make it
patch successfully on jack 0.109.2. I don't have so advanced programming
skills to understand its inner working, but from a quick read of the
code, for what I can understand, I saw it mainly adds some functions in
jackd (jack_device_disconnect() and jack_device_connect()in
jackd/engine.c) and libjack (jack_set_connected() in client.c,
jack_driver_nt_disconnect() and jack_driver_nt_connect() in driver.c) to
dis/connect to the alsa device.

I was asked on this list about the interaction of this patch with
realtime watchdogs. I didn't encounter any problem, they were never
triggered (and no crashes or weird things ;) ) as in normal operation,
because they enter this freewheeling-like mode.
I contacted Sean and asked him if it was this way, and he replied:

 >As I remember, that's pretty much it. It puts jack into something like
 >freewheel mode (so that jack clients don't freeze up). And then shuts
 >down the alsa driver. As for the watchdog, I don't remember anything
 >about that, but if I had to guess I'd say it's because jack is put
into >a fake-freewheel mode.

Hope it is useful to who wants to try it: just use

jack_device_connect n

and voila, you can watch youtube videos or use that strange non-jack
aware application you need in that moment, _without_ closing any jack
program.
When you're done, just use

jack_device_connect y

and enjoy all your JACK work just where you left it.

I should perhaps rename the jack_device_connect jack_alsa_connect...

Wanna try it?
Happy JACKing to all, ciao!
--
           salvuz
      POST FATA RESVRGO
  Linux registered user #291700 | machine #174619
  get counted on ---> http://counter.li.org/ <---

diff -Nur jack-audio-connection-kit-0.109.2/drivers/alsa/alsa_driver.c jack-audio-connection-kit-0.109.2-alsa-disconnect/drivers/alsa/alsa_driver.c
--- jack-audio-connection-kit-0.109.2/drivers/alsa/alsa_driver.c 2008-01-30 19:23:52.000000000 +0100
+++ jack-audio-connection-kit-0.109.2-alsa-disconnect/drivers/alsa/alsa_driver.c 2008-03-01 13:40:27.000000000 +0100
@@ -53,6 +53,8 @@
 /* Delay (in process calls) before jackd will report an xrun */
 #define XRUN_REPORT_DELAY 0
 
+static int alsa_driver_connect (alsa_driver_t *driver);
+
 static void
 alsa_driver_release_channel_dependent_memory (alsa_driver_t *driver)
 {
@@ -130,6 +132,7 @@
  jack_error ("control hardware info \"%s\" (%s)",
     driver->alsa_name_playback, snd_strerror (err));
  snd_ctl_close (driver->ctl_handle);
+ driver->ctl_handle = 0;
  }
 
  driver->alsa_driver = strdup(snd_ctl_card_info_get_driver (card_info));
@@ -964,6 +967,9 @@
  snd_pcm_uframes_t poffset, pavail;
  channel_t chn;
 
+ if(!driver->connected)
+ return 0;
+
  driver->poll_last = 0;
  driver->poll_next = 0;
 
@@ -1092,6 +1098,8 @@
  /* silence all capture port buffers, because we might
    be entering offline mode.
  */
+ if (!driver->connected)
+ return 0;
 
  for (chn = 0, node = driver->capture_ports; node;
      node = jack_slist_next (node), chn++) {
@@ -1157,6 +1165,9 @@
  snd_pcm_status_t *status;
  int res;
 
+ if (!driver->connected)
+ return 0;
+
  snd_pcm_status_alloca(&status);
 
  if (driver->capture_handle) {
@@ -1198,6 +1209,9 @@
  jack_nframes_t buffer_frames =
  driver->frames_per_cycle * driver->playback_nperiods;
 
+ if(!driver->connected)
+ return;
+
  for (chn = 0; chn < driver->playback_nchannels; chn++) {
  if (bitset_contains (driver->channels_not_done, chn)) {
  if (driver->silent[chn] < buffer_frames) {
@@ -1924,8 +1938,8 @@
 }
 #endif
 
-static void
-alsa_driver_delete (alsa_driver_t *driver)
+static int
+alsa_driver_disconnect (alsa_driver_t *driver)
 {
  JSList *node;
 
@@ -1945,7 +1959,7 @@
 
  if (driver->playback_handle) {
  snd_pcm_close (driver->playback_handle);
- driver->capture_handle = 0;
+ driver->playback_handle = 0;
  }
 
  if (driver->capture_hw_params) {
@@ -1968,16 +1982,34 @@
  driver->playback_sw_params = 0;
  }
 
+ if(driver->ctl_handle) {
+ snd_ctl_close(driver->ctl_handle);
+ driver->ctl_handle = 0;
+ }
+
  if (driver->pfd) {
  free (driver->pfd);
+ driver->pfd = 0;
  }
-
+
  if (driver->hw) {
  driver->hw->release (driver->hw);
  driver->hw = 0;
  }
+
+ driver->connected = 0;
+
+ return 0;
+}
+
+static void
+alsa_driver_delete (alsa_driver_t *driver)
+{
+ alsa_driver_disconnect(driver);
+
  free(driver->alsa_name_playback);
  free(driver->alsa_name_capture);
+
  free(driver->alsa_driver);
 
  alsa_driver_release_channel_dependent_memory (driver);
@@ -2007,8 +2039,6 @@
  alsa_midi_t *midi_driver
  )
 {
- int err;
-
  alsa_driver_t *driver;
 
  printf ("creating alsa driver ... %s|%s|%" PRIu32 "|%" PRIu32
@@ -2036,6 +2066,8 @@
  driver->nt_start = (JackDriverNTStartFunction) alsa_driver_start;
  driver->nt_stop = (JackDriverNTStopFunction) alsa_driver_stop;
  driver->nt_run_cycle = (JackDriverNTRunCycleFunction) alsa_driver_run_cycle;
+ driver->nt_connect = (JackDriverNTConnectFunction) alsa_driver_connect;
+ driver->nt_disconnect = (JackDriverNTDisconnectFunction) alsa_driver_disconnect;
 
  driver->playback_handle = NULL;
  driver->capture_handle = NULL;
@@ -2095,11 +2127,47 @@
  return NULL;
  }
 
- alsa_driver_hw_specific (driver, hw_monitoring, hw_metering);
+ alsa_driver_hw_specific (driver, driver->hw_monitoring, driver->hw_metering);
+
+ driver->alsa_name_playback = strdup (playback_alsa_device);
+ driver->alsa_name_capture = strdup (capture_alsa_device);
+
+ driver->name = strdup (name);
+
+ driver->playback = playing;
+ driver->capture = capturing;
+
+ driver->frames_per_cycle = frames_per_cycle;
+ driver->user_nperiods = user_nperiods;
+ driver->frame_rate = rate;
+
+ driver->client = client;
+
+ driver->connected = 0;
+
+ // if we don't connect now then the hardware capability detection bits won't
+ // get run before we're asked to register our ports.  and if that happens
+ // our capture & playback port numbers will be 0 causing us to not register anything
+ // and that's bad.
+ if (alsa_driver_connect(driver) != 0) {
+ alsa_driver_delete (driver);
+ return NULL;
+ }
+
+ return (jack_driver_t *)driver;
+}
 
- if (playing) {
+static int
+alsa_driver_connect (alsa_driver_t *driver)
+{
+ int err;
+
+ if (driver->connected)
+ return 0;
+
+ if (driver->playback) {
  if (snd_pcm_open (&driver->playback_handle,
-  playback_alsa_device,
+  driver->alsa_name_playback,
   SND_PCM_STREAM_PLAYBACK,
   SND_PCM_NONBLOCK) < 0) {
  switch (errno) {
@@ -2108,17 +2176,25 @@
     "already in use. Please stop the"
     " application using it and "
     "run JACK again",
-    playback_alsa_device);
- alsa_driver_delete (driver);
- return NULL;
+    driver->alsa_name_playback);
+ return -1;
  break;
 
  case EPERM:
  jack_error ("you do not have permission to open "
     "the audio device \"%s\" for playback",
-    playback_alsa_device);
- alsa_driver_delete (driver);
- return NULL;
+    driver->alsa_name_playback);
+ return -1;
+ break;
+
+ default:
+ if (errno) {
+ char *str = strerror(errno);
+ jack_error ("the playback device \"%s\" could not be opened"
+    " because of: \"%s\"\n",
+    driver->alsa_name_playback,str);
+ return -1;
+ }
  break;
  }
 
@@ -2130,9 +2206,9 @@
  }
  }
 
- if (capturing) {
+ if (driver->capture) {
  if (snd_pcm_open (&driver->capture_handle,
-  capture_alsa_device,
+  driver->alsa_name_capture,
   SND_PCM_STREAM_CAPTURE,
   SND_PCM_NONBLOCK) < 0) {
  switch (errno) {
@@ -2141,17 +2217,25 @@
     "already in use. Please stop the"
     " application using it and "
     "run JACK again",
-    capture_alsa_device);
- alsa_driver_delete (driver);
- return NULL;
+    driver->alsa_name_capture);
+ return -1;
  break;
 
  case EPERM:
  jack_error ("you do not have permission to open "
     "the audio device \"%s\" for capture",
-    capture_alsa_device);
- alsa_driver_delete (driver);
- return NULL;
+    driver->alsa_name_capture);
+ return -1;
+ break;
+
+ default:
+ if (errno) {
+ char *str = strerror(errno);
+ jack_error ("the capture device \"%s\" could not be opened"
+    " because of: \"%s\"\n",
+    driver->alsa_name_playback,str);
+ return -1;
+ }
  break;
  }
 
@@ -2164,40 +2248,38 @@
  }
 
  if (driver->playback_handle == NULL) {
- if (playing) {
+ if (driver->playback) {
 
  /* they asked for playback, but we can't do it */
 
  jack_error ("ALSA: Cannot open PCM device %s for "
     "playback. Falling back to capture-only"
-    " mode", name);
+    " mode", driver->name);
 
  if (driver->capture_handle == NULL) {
  /* can't do anything */
- alsa_driver_delete (driver);
- return NULL;
+ return -1;
  }
 
- playing = FALSE;
+ driver->playback = FALSE;
  }
  }
 
  if (driver->capture_handle == NULL) {
- if (capturing) {
+ if (driver->capture) {
 
  /* they asked for capture, but we can't do it */
 
  jack_error ("ALSA: Cannot open PCM device %s for "
     "capture. Falling back to playback-only"
-    " mode", name);
+    " mode", driver->name);
 
  if (driver->playback_handle == NULL) {
  /* can't do anything */
- alsa_driver_delete (driver);
- return NULL;
+ return -1;
  }
 
- capturing = FALSE;
+ driver->capture = FALSE;
  }
  }
 
@@ -2211,16 +2293,14 @@
      &driver->playback_hw_params)) < 0) {
  jack_error ("ALSA: could not allocate playback hw"
     " params structure");
- alsa_driver_delete (driver);
- return NULL;
+ return -1;
  }
 
  if ((err = snd_pcm_sw_params_malloc (
      &driver->playback_sw_params)) < 0) {
  jack_error ("ALSA: could not allocate playback sw"
     " params structure");
- alsa_driver_delete (driver);
- return NULL;
+ return -1;
  }
  }
 
@@ -2229,23 +2309,20 @@
      &driver->capture_hw_params)) < 0) {
  jack_error ("ALSA: could not allocate capture hw"
     " params structure");
- alsa_driver_delete (driver);
- return NULL;
+ return -1;
  }
 
  if ((err = snd_pcm_sw_params_malloc (
      &driver->capture_sw_params)) < 0) {
  jack_error ("ALSA: could not allocate capture sw"
     " params structure");
- alsa_driver_delete (driver);
- return NULL;
+ return -1;
  }
  }
 
- if (alsa_driver_set_parameters (driver, frames_per_cycle,
- user_nperiods, rate)) {
- alsa_driver_delete (driver);
- return NULL;
+ if (alsa_driver_set_parameters (driver, driver->frames_per_cycle,
+ driver->user_nperiods, driver->frame_rate)) {
+ return -1;
  }
 
  driver->capture_and_playback_not_synced = FALSE;
@@ -2257,9 +2334,9 @@
  }
  }
 
- driver->client = client;
+ driver->connected = 1;
 
- return (jack_driver_t *) driver;
+ return 0;
 }
 
 int
diff -Nur jack-audio-connection-kit-0.109.2/drivers/alsa/alsa_driver.h jack-audio-connection-kit-0.109.2-alsa-disconnect/drivers/alsa/alsa_driver.h
--- jack-audio-connection-kit-0.109.2/drivers/alsa/alsa_driver.h 2008-01-30 19:23:52.000000000 +0100
+++ jack-audio-connection-kit-0.109.2-alsa-disconnect/drivers/alsa/alsa_driver.h 2008-03-01 13:40:27.000000000 +0100
@@ -136,6 +136,12 @@
     pthread_mutex_t clock_sync_lock;
     unsigned long next_clock_sync_listener_id;
 
+    char playback : 1;
+    char capture : 1;
+    char connected : 1;
+
+    char *name;
+
     int running;
     int run;
 
diff -Nur jack-audio-connection-kit-0.109.2/example-clients/Makefile.am jack-audio-connection-kit-0.109.2-alsa-disconnect/example-clients/Makefile.am
--- jack-audio-connection-kit-0.109.2/example-clients/Makefile.am 2008-01-30 19:23:43.000000000 +0100
+++ jack-audio-connection-kit-0.109.2-alsa-disconnect/example-clients/Makefile.am 2008-03-01 13:40:27.000000000 +0100
@@ -36,6 +36,7 @@
                jack_bufsize \
        jack_lsp \
        jack_freewheel \
+       jack_device_connect \
        jack_evmon \
        jack_alias \
        $(JACKREC) \
@@ -101,6 +102,10 @@
 jack_freewheel_LDFLAGS = @OS_LDFLAGS@
 jack_freewheel_LDADD = ../libjack/libjack.la
 
+jack_device_connect_SOURCES = device_connect.c
+jack_device_connect_LDFLAGS = @OS_LDFLAGS@
+jack_device_connect_LDADD = ../libjack/libjack.la
+
 if HAVE_SNDFILE
 jackrec_SOURCES = capture_client.c
 jackrec_LDFLAGS = @SNDFILE_LIBS@ @OS_LDFLAGS@
diff -Nur jack-audio-connection-kit-0.109.2/example-clients/Makefile.in jack-audio-connection-kit-0.109.2-alsa-disconnect/example-clients/Makefile.in
--- jack-audio-connection-kit-0.109.2/example-clients/Makefile.in 2008-01-30 19:24:36.000000000 +0100
+++ jack-audio-connection-kit-0.109.2-alsa-disconnect/example-clients/Makefile.in 2008-03-01 13:48:04.000000000 +0100
@@ -40,7 +40,7 @@
 target_triplet = @target@
 bin_PROGRAMS = jack_load$(EXEEXT) jack_unload$(EXEEXT) \
  jack_simple_client$(EXEEXT) jack_monitor_client$(EXEEXT) \
- jack_impulse_grabber$(EXEEXT) jack_connect$(EXEEXT) \
+ jack_impulse_grabber$(EXEEXT) jack_connect$(EXEEXT) jack_device_connect$(EXEEXT) \
  jack_disconnect$(EXEEXT) jack_metro$(EXEEXT) \
  jack_showtime$(EXEEXT) jack_bufsize$(EXEEXT) jack_lsp$(EXEEXT) \
  jack_freewheel$(EXEEXT) jack_evmon$(EXEEXT) \
@@ -85,6 +85,9 @@
 am_jack_connect_OBJECTS = connect.$(OBJEXT)
 jack_connect_OBJECTS = $(am_jack_connect_OBJECTS)
 jack_connect_DEPENDENCIES = ../libjack/libjack.la
+am_jack_device_connect_OBJECTS = device_connect.$(OBJEXT)
+jack_device_connect_OBJECTS = $(am_jack_device_connect_OBJECTS)
+jack_device_connect_DEPENDENCIES = ../libjack/libjack.la
 am_jack_disconnect_OBJECTS = connect.$(OBJEXT)
 jack_disconnect_OBJECTS = $(am_jack_disconnect_OBJECTS)
 jack_disconnect_DEPENDENCIES = ../libjack/libjack.la
@@ -149,7 +152,7 @@
  $(AM_LDFLAGS) $(LDFLAGS) -o $@
 SOURCES = $(inprocess_la_SOURCES) $(intime_la_SOURCES) \
  $(jack_alias_SOURCES) $(jack_bufsize_SOURCES) \
- $(jack_connect_SOURCES) $(jack_disconnect_SOURCES) \
+ $(jack_connect_SOURCES) $(jack_device_connect_SOURCES) $(jack_disconnect_SOURCES) \
  $(jack_evmon_SOURCES) $(jack_freewheel_SOURCES) \
  $(jack_impulse_grabber_SOURCES) $(jack_load_SOURCES) \
  $(jack_lsp_SOURCES) $(jack_metro_SOURCES) \
@@ -160,7 +163,7 @@
  $(jackrec_SOURCES)
 DIST_SOURCES = $(inprocess_la_SOURCES) $(intime_la_SOURCES) \
  $(jack_alias_SOURCES) $(jack_bufsize_SOURCES) \
- $(jack_connect_SOURCES) $(jack_disconnect_SOURCES) \
+ $(jack_connect_SOURCES) $(jack_device_connect_SOURCES) $(jack_disconnect_SOURCES) \
  $(jack_evmon_SOURCES) $(jack_freewheel_SOURCES) \
  $(jack_impulse_grabber_SOURCES) $(jack_load_SOURCES) \
  $(jack_lsp_SOURCES) $(jack_metro_SOURCES) \
@@ -351,6 +354,9 @@
 jack_connect_SOURCES = connect.c
 jack_connect_LDFLAGS = @OS_LDFLAGS@
 jack_connect_LDADD = ../libjack/libjack.la
+jack_device_connect_SOURCES = connect.c
+jack_device_connect_LDFLAGS = @OS_LDFLAGS@
+jack_device_connect_LDADD = ../libjack/libjack.la
 jack_disconnect_SOURCES = connect.c
 jack_disconnect_LDFLAGS = @OS_LDFLAGS@
 jack_disconnect_LDADD = ../libjack/libjack.la
@@ -524,6 +530,9 @@
 jack_connect$(EXEEXT): $(jack_connect_OBJECTS) $(jack_connect_DEPENDENCIES)
  @rm -f jack_connect$(EXEEXT)
  $(LINK) $(jack_connect_LDFLAGS) $(jack_connect_OBJECTS) $(jack_connect_LDADD) $(LIBS)
+jack_device_connect$(EXEEXT): $(jack_device_connect_OBJECTS) $(jack_device_connect_DEPENDENCIES)
+ @rm -f jack_device_connect$(EXEEXT)
+ $(LINK) $(jack_device_connect_LDFLAGS) $(jack_device_connect_OBJECTS) $(jack_device_connect_LDADD) $(LIBS)
 jack_disconnect$(EXEEXT): $(jack_disconnect_OBJECTS) $(jack_disconnect_DEPENDENCIES)
  @rm -f jack_disconnect$(EXEEXT)
  $(LINK) $(jack_disconnect_LDFLAGS) $(jack_disconnect_OBJECTS) $(jack_disconnect_LDADD) $(LIBS)
diff -Nur jack-audio-connection-kit-0.109.2/example-clients/device_connect.c jack-audio-connection-kit-0.109.2-alsa-disconnect/example-clients/device_connect.c
--- jack-audio-connection-kit-0.109.2/example-clients/device_connect.c 1970-01-01 01:00:00.000000000 +0100
+++ jack-audio-connection-kit-0.109.2-alsa-disconnect/example-clients/device_connect.c 2008-03-01 13:40:27.000000000 +0100
@@ -0,0 +1,86 @@
+/*
+ *  freewheel - start/stop JACK "freewheeling" mode
+ *
+ *  Copyright (C) 2003 Paul Davis.
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <jack/jack.h>
+#include <jack/transport.h>
+
+char *package; /* program name */
+jack_client_t *client;
+int onoff;
+
+void jack_shutdown(void *arg)
+{
+ fprintf(stderr, "JACK shut down, exiting ...\n");
+ exit(1);
+}
+
+void signal_handler(int sig)
+{
+ jack_client_close(client);
+ fprintf(stderr, "signal received, exiting ...\n");
+ exit(0);
+}
+
+void parse_arguments(int argc, char *argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s y|n\n", package);
+ exit(9);
+ }
+
+ if (argv[1][0] == 'y' || argv[1][0] == 'Y' || argv[1][0] == '1') {
+ onoff = 1;
+ } else {
+ onoff = 0;
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ parse_arguments (argc, argv);
+
+ /* become a JACK client */
+ if ((client = jack_client_new ("device_connect")) == 0) {
+ fprintf (stderr, "JACK server not running?\n");
+ exit(1);
+ }
+
+ signal (SIGQUIT, signal_handler);
+ signal (SIGTERM, signal_handler);
+ signal (SIGHUP, signal_handler);
+ signal (SIGINT, signal_handler);
+
+ jack_on_shutdown (client, jack_shutdown, 0);
+
+ if (jack_set_connected (client, onoff)) {
+ fprintf (stderr, "failed to reset connect state\n");
+ }
+
+ jack_client_close(client);
+
+ return 0;
+}
diff -Nur jack-audio-connection-kit-0.109.2/jack/driver.h jack-audio-connection-kit-0.109.2-alsa-disconnect/jack/driver.h
--- jack-audio-connection-kit-0.109.2/jack/driver.h 2008-01-30 19:23:50.000000000 +0100
+++ jack-audio-connection-kit-0.109.2-alsa-disconnect/jack/driver.h 2008-03-01 13:40:27.000000000 +0100
@@ -60,6 +60,9 @@
 typedef int       (*JackDriverStartFunction)(struct _jack_driver *);
 typedef int  (*JackDriverBufSizeFunction)(struct _jack_driver *,
        jack_nframes_t nframes);
+typedef int       (*JackDriverConnectFunction)(struct _jack_driver *);
+typedef int       (*JackDriverDisconnectFunction)(struct _jack_driver *);
+
 /*
    Call sequence summary:
 
@@ -221,7 +224,9 @@
     JackDriverNullCycleFunction null_cycle; \
     JackDriverStopFunction stop; \
     JackDriverStartFunction start; \
-    JackDriverBufSizeFunction bufsize;
+    JackDriverBufSizeFunction bufsize; \
+    JackDriverConnectFunction connect; \
+    JackDriverDisconnectFunction disconnect;
 
     JACK_DRIVER_DECL /* expand the macro */
 
@@ -273,6 +278,8 @@
 typedef int  (*JackDriverNTBufSizeFunction)(struct _jack_driver_nt *,
        jack_nframes_t nframes);
 typedef int       (*JackDriverNTRunCycleFunction)(struct _jack_driver_nt *);
+typedef int       (*JackDriverNTConnectFunction)(struct _jack_driver_nt *);
+typedef int       (*JackDriverNTDisconnectFunction)(struct _jack_driver_nt *);
 
 typedef struct _jack_driver_nt {
 
@@ -287,7 +294,9 @@
     JackDriverNTStopFunction nt_stop; \
     JackDriverNTStartFunction nt_start; \
     JackDriverNTBufSizeFunction nt_bufsize; \
-    JackDriverNTRunCycleFunction nt_run_cycle;
+    JackDriverNTRunCycleFunction nt_run_cycle; \
+    JackDriverNTConnectFunction nt_connect; \
+    JackDriverNTDisconnectFunction nt_disconnect;
 #define nt_read read
 #define nt_write write
 #define nt_null_cycle null_cycle
diff -Nur jack-audio-connection-kit-0.109.2/jack/engine.h jack-audio-connection-kit-0.109.2-alsa-disconnect/jack/engine.h
--- jack-audio-connection-kit-0.109.2/jack/engine.h 2008-01-30 19:23:50.000000000 +0100
+++ jack-audio-connection-kit-0.109.2-alsa-disconnect/jack/engine.h 2008-03-01 13:40:27.000000000 +0100
@@ -109,6 +109,7 @@
     unsigned long   external_client_cnt;
     int    rtpriority;
     char    freewheeling;
+    char            connected;
     char    verbose;
     char    do_munlock;
     const char   *server_name;
diff -Nur jack-audio-connection-kit-0.109.2/jack/internal.h jack-audio-connection-kit-0.109.2-alsa-disconnect/jack/internal.h
--- jack-audio-connection-kit-0.109.2/jack/internal.h 2008-01-30 19:23:50.000000000 +0100
+++ jack-audio-connection-kit-0.109.2-alsa-disconnect/jack/internal.h 2008-03-01 13:40:27.000000000 +0100
@@ -172,7 +172,9 @@
   StartFreewheel,
   StopFreewheel,
   ClientRegistered,
-  ClientUnregistered
+  ClientUnregistered,
+  Connected,
+  Disconnected
 } JackEventType;
 
 typedef struct {
@@ -338,7 +340,9 @@
  IntClientName = 21,
  IntClientUnload = 22,
  RecomputeTotalLatencies = 23,
- RecomputeTotalLatency = 24
+ RecomputeTotalLatency = 24,
+ Connect = 42,
+ Disconnect = 43
 } RequestType;
 
 struct _jack_request {
diff -Nur jack-audio-connection-kit-0.109.2/jack/jack.h jack-audio-connection-kit-0.109.2-alsa-disconnect/jack/jack.h
--- jack-audio-connection-kit-0.109.2/jack/jack.h 2008-01-30 19:23:50.000000000 +0100
+++ jack-audio-connection-kit-0.109.2-alsa-disconnect/jack/jack.h 2008-03-01 13:40:27.000000000 +0100
@@ -246,6 +246,8 @@
  */
 int jack_set_freewheel(jack_client_t* client, int onoff);
 
+int jack_set_connected(jack_client_t* client, int connected);
+
 /**
  * Change the buffer size passed to the @a process_callback.
  *
diff -Nur jack-audio-connection-kit-0.109.2/jackd/engine.c jack-audio-connection-kit-0.109.2-alsa-disconnect/jackd/engine.c
--- jack-audio-connection-kit-0.109.2/jackd/engine.c 2008-01-30 19:23:51.000000000 +0100
+++ jack-audio-connection-kit-0.109.2-alsa-disconnect/jackd/engine.c 2008-03-01 13:40:27.000000000 +0100
@@ -128,6 +128,8 @@
 static void jack_check_acyclic (jack_engine_t* engine);
 static void jack_compute_all_port_total_latencies (jack_engine_t *engine);
 static void jack_compute_port_total_latency (jack_engine_t *engine, jack_port_shared_t*);
+static int  jack_device_connect (jack_engine_t *engine);
+static int  jack_device_disconnect (jack_engine_t *engine);
 
 
 static inline int
@@ -911,7 +913,11 @@
 
  while (1) {
  usleep (1000 * JACKD_WATCHDOG_TIMEOUT);
- if (!engine->freewheeling && engine->watchdog_check == 0) {
+ if ( ! engine->connected ) {
+ // cheap trick to avoid a potential race condition when we reconnect
+ engine->watchdog_check = 1;
+ }
+ else if (!engine->freewheeling && engine->watchdog_check == 0) {
 
  jack_error ("jackd watchdog: timeout - killing jackd");
 
@@ -1270,6 +1276,14 @@
  req->status = jack_stop_freewheeling (engine);
  break;
 
+ case Connect:
+ req->status = jack_device_connect (engine);
+ break;
+
+ case Disconnect:
+ req->status = jack_device_disconnect (engine);
+ break;
+
  case SetBufferSize:
  req->status = jack_set_buffer_size_request (engine,
    req->x.nframes);
@@ -1630,6 +1644,8 @@
 
  engine->clients = 0;
 
+ engine->connected = 0;
+
  engine->pfd_size = 16;
  engine->pfd_max = 0;
  engine->pfd = (struct pollfd *) malloc (sizeof (struct pollfd)
@@ -1956,6 +1972,71 @@
  return 0;
 }
 
+static int  jack_device_connect (jack_engine_t *engine)
+{
+ jack_event_t event;
+ void *ftstatus;
+
+ if (engine->connected) {
+ VERBOSE (engine, "connect when already connected\n");
+ return 0;
+ }
+
+ if (engine->driver == NULL) {
+ jack_error ("cannot connect without a driver!");
+ return -1;
+ }
+
+ if(engine->driver->connect (engine->driver))
+ {
+ jack_error ("driver will not connect");
+ return -1;
+ }
+
+ if(engine->driver->start (engine->driver))
+ {
+ jack_error ("driver will not start after disconnection");
+ return -1;
+ }
+
+ engine->connected = 1;
+ /* tell everyone we've connected */
+
+ event.type = Connected;
+ jack_deliver_event_to_all (engine, &event);
+
+ return 0;
+}
+
+static int jack_device_disconnect (jack_engine_t *engine)
+{
+ jack_event_t event;
+
+ if(!engine->connected)
+ {
+ VERBOSE (engine, "disconnect when already disconnected\n");
+ return 0;
+ }
+
+ if (engine->driver == NULL) {
+ jack_error ("cannot disconnect without a driver!");
+ return -1;
+ }
+
+ if (engine->driver->stop (engine->driver)) {
+ jack_error ("could not stop driver for disconnection");
+ return -1;
+ }
+
+ engine->driver->disconnect (engine->driver);
+ engine->connected = 0;
+
+ event.type = Disconnected;
+ jack_deliver_event_to_all (engine, &event);
+
+ return 0;
+}
+
 static int
 jack_run_one_cycle (jack_engine_t *engine, jack_nframes_t nframes,
     float delayed_usecs)
@@ -3398,6 +3479,7 @@
  if (engine->driver) {
  engine->driver->detach (engine->driver, engine);
  engine->driver = 0;
+ engine->connected = 0;
  }
 
  engine->driver = driver;
@@ -3409,7 +3491,7 @@
  engine->rolling_interval =
  jack_rolling_interval (driver->period_usecs);
  }
-
+ engine->connected = 1;
  return 0;
 }
 
diff -Nur jack-audio-connection-kit-0.109.2/libjack/client.c jack-audio-connection-kit-0.109.2-alsa-disconnect/libjack/client.c
--- jack-audio-connection-kit-0.109.2/libjack/client.c 2008-01-30 19:23:43.000000000 +0100
+++ jack-audio-connection-kit-0.109.2-alsa-disconnect/libjack/client.c 2008-03-01 13:40:27.000000000 +0100
@@ -1205,6 +1205,14 @@
  return jack_client_deliver_request (client, &request);
 }
 
+int
+jack_set_connected(jack_client_t* client, int connected)
+{
+ jack_request_t request;
+ request.type = connected ? Connect : Disconnect;
+ return jack_client_deliver_request (client, &request);
+}
+
 void
 jack_start_freewheel (jack_client_t* client)
 {
diff -Nur jack-audio-connection-kit-0.109.2/libjack/driver.c jack-audio-connection-kit-0.109.2-alsa-disconnect/libjack/driver.c
--- jack-audio-connection-kit-0.109.2/libjack/driver.c 2008-01-30 19:23:43.000000000 +0100
+++ jack-audio-connection-kit-0.109.2-alsa-disconnect/libjack/driver.c 2008-03-01 13:40:27.000000000 +0100
@@ -46,6 +46,8 @@
   jack_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; }
+static int dummy_connect (jack_driver_t *drv) { return 0; }
+static int dummy_disconnect (jack_driver_t *drv) { return 0; }
 
 void
 jack_driver_init (jack_driver_t *driver)
@@ -60,6 +62,8 @@
  driver->bufsize = dummy_bufsize;
  driver->start = dummy_start;
  driver->stop = dummy_stop;
+ driver->connect = dummy_connect;
+ driver->disconnect = dummy_disconnect;
 }
 
 
@@ -199,6 +203,34 @@
 }
 
 static int
+jack_driver_nt_connect (jack_driver_nt_t * driver)
+{
+ int err;
+
+ err = driver->nt_connect (driver);
+ if (err) {
+ jack_error ("DRIVER NT: could not connect driver");
+ return err;
+ }
+
+ return 0;
+}
+
+static int
+jack_driver_nt_disconnect (jack_driver_nt_t * driver)
+{
+ int err;
+
+ err = driver->nt_disconnect (driver);
+ if (err) {
+ jack_error ("DRIVER NT: could not disconnect driver");
+ return err;
+ }
+
+ return 0;
+}
+
+static int
 jack_driver_nt_bufsize (jack_driver_nt_t * driver, jack_nframes_t nframes)
 {
  int err;
@@ -235,10 +267,14 @@
  driver->bufsize      = (JackDriverBufSizeFunction)   jack_driver_nt_bufsize;
  driver->stop         = (JackDriverStartFunction)     jack_driver_nt_stop;
  driver->start        = (JackDriverStopFunction)      jack_driver_nt_start;
+ driver->connect      = (JackDriverConnectFunction)   jack_driver_nt_connect;
+ driver->disconnect   = (JackDriverDisconnectFunction)jack_driver_nt_disconnect;
 
  driver->nt_bufsize   = (JackDriverNTBufSizeFunction) dummy_bufsize;
  driver->nt_start     = (JackDriverNTStartFunction)   dummy_start;
  driver->nt_stop      = (JackDriverNTStopFunction)    dummy_stop;
+ driver->nt_connect   = (JackDriverNTConnectFunction) dummy_connect;
+ driver->nt_disconnect= (JackDriverNTDisconnectFunction)dummy_connect;
  driver->nt_attach    =                               dummy_nt_attach;
  driver->nt_detach    =                               dummy_nt_detach;
  driver->nt_run_cycle =                               dummy_nt_run_cycle;

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Jackit-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jackit-devel
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] JACK 0.109.2 alsa device disconnect patch

Stéphane Letz

Le 14 mars 08 à 16:32, Salvatore Di Pietro a écrit :

> jack_set_connected


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Jackit-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jackit-devel
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] JACK 0.109.2 alsa device disconnect patch

Stéphane Letz
In reply to this post by Salvatore Di Pietro

Le 14 mars 08 à 16:32, Salvatore Di Pietro a écrit :

> Hi all,
> I just fitted Sean Meiners' alsa device disconnect patch for JACK  
> 0.109.2.
>
> It enables jackd to detach from the ALSA device, letting its use by  
> other non-JACK programs whilst in the middle of a jack session,  
> without closing jackd and its clients. IMHO very useful for i.e  
> common builtin laptop soundcards which don't support more than one  
> alsa-direct audio app at once (also commonly known as "no hardware  
> mixing soundcards").
>
> You get an additional example client: jack_device_connect (based on  
> jack_freewheel, its arguments are "y" or "n") which you use to make  
> jack release and re-hook to the audio card. Time is paused and all  
> audio from jack is of course muted and jackd and its client  
> applications are put into this fake-freewheel mode while jack has  
> released the device; they continue producing and consuming audio  
> upon jackd re-attaching to the audio device, with the command  
> "jack_device_connect y".
>
> The original version was for jack 0.100.0, I just modified it to  
> make it patch successfully on jack 0.109.2. I don't have so  
> advanced programming skills to understand its inner working, but  
> from a quick read of the code, for what I can understand, I saw it  
> mainly adds some functions in jackd (jack_device_disconnect() and  
> jack_device_connect()in jackd/engine.c) and libjack  
> (jack_set_connected() in client.c, jack_driver_nt_disconnect() and  
> jack_driver_nt_connect() in driver.c) to dis/connect to the alsa  
> device.
>
> I was asked on this list about the interaction of this patch with  
> realtime watchdogs. I didn't encounter any problem, they were never  
> triggered (and no crashes or weird things ;) ) as in normal  
> operation, because they enter this freewheeling-like mode.
> I contacted Sean and asked him if it was this way, and he replied:
>
> >As I remember, that's pretty much it. It puts jack into something  
> like >freewheel mode (so that jack clients don't freeze up). And  
> then shuts >down the alsa driver. As for the watchdog, I don't  
> remember anything >about that, but if I had to guess I'd say it's  
> because jack is put into >a fake-freewheel mode.
>
> Hope it is useful to who wants to try it: just use
>
> jack_device_connect n
>
> and voila, you can watch youtube videos or use that strange non-
> jack aware application you need in that moment, _without_ closing  
> any jack program.
> When you're done, just use
>
> ja

Hi,

I don't think this patch should go for jack 1.0 for several reasons:

- it is quite intrusive and add a new API jack_set_connected on the  
client side.

- dynamically changing backend is something that was discussed at LAC  
and that should be better done in a new "server control" API that  
will be part of jack2. Changing the backend is conceptually more a  
server control operation. This API is yet to be completely defined  
but should allow much better control of the server, like dynamically  
gettting/setting backend parameters, starting/stopping the server,  
dynamically changing backend....

Stephane


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Jackit-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jackit-devel