All of lore.kernel.org
 help / color / mirror / Atom feed
From: Takashi Iwai <tiwai@suse.de>
To: Jack O'Quin <joq@io.com>
Cc: "Asbjørn Sæbø" <asbjs@stud.ntnu.no>, alsa-devel@lists.sourceforge.net
Subject: Re: Lowest latency: JACK, or ALSA directly?
Date: Wed, 17 Nov 2004 15:55:25 +0100	[thread overview]
Message-ID: <s5hd5ycsexu.wl@alsa2.suse.de> (raw)
In-Reply-To: <87k6srx9wi.fsf@sulphur.joq.us>

[-- Attachment #1: Type: text/plain, Size: 1684 bytes --]

At 12 Nov 2004 11:19:25 -0600,
Jack O'Quin wrote:
> 
> Takashi Iwai <tiwai@suse.de> writes:
> 
> > At 12 Nov 2004 10:42:33 -0600,
> > Jack O'Quin wrote:
> > > The sound card generates an interrupt at the end of each period.  This
> > > determines the input latency.  The hardware buffer holds multiple
> > > periods (you need at least two).  Its size determines the maximum
> > > output latency.  With JACK, there's not much reason to use more than
> > > two or three periods, unless you're running without realtime
> > > privileges.
> > 
> > Regarding JACK's latency:  can JACK handle more than two periods with
> > the minimal latency?  That is, keeping only two periods active (the
> > current playing and the next periods), you can achieve the same
> > latency even if the buffer consists of more than two periods.
> > 
> > I'm asking this because some boards (e.g. RME32/96) have the fixed
> > buffer size, and can't take the configuration as two periods per
> > buffer.  IIRC, JACK fills all the buffer at the first sequence, and
> > this results in the higher latency than necessary.
> > 
> > Correct me if I'm wrong.
> 
> I believe you are correct about this.  You probably understand it
> better than I do.  :-)
> 
> Is this something we could fix in JACK's ALSA driver backend?

We can set different values to avail_min for playback and capture
directions.  For getting the minimal latency, set
(nperiods - 1) * period_size for playback and period_size for
capture.

The patch attached adds a new option -f to specify the filling
periods.  As default (= 0), it's identical with nperiods, so the old
behavior is kept.

Note that it's not tested at all, as usual ;)


Takashi

[-- Attachment #2: Type: text/plain, Size: 5417 bytes --]

--- jack-audio-connection-kit-0.99.0/drivers/alsa/alsa_driver.c-dist	2004-11-15 15:00:06.000000000 +0100
+++ jack-audio-connection-kit-0.99.0/drivers/alsa/alsa_driver.c	2004-11-17 15:53:45.517659988 +0100
@@ -508,8 +508,15 @@ alsa_driver_configure_stream (alsa_drive
 	}
 #endif
 
-	if ((err = snd_pcm_sw_params_set_avail_min (
-		     handle, sw_params, driver->frames_per_cycle)) < 0) {
+	if (handle == driver->playback_handle)
+		err = snd_pcm_sw_params_set_avail_min (
+			handle, sw_params,
+			driver->frames_per_cycle * (driver->user_nperiods - driver->user_nfills + 1));
+	else
+		err = snd_pcm_sw_params_set_avail_min (
+			handle, sw_params, driver->frames_per_cycle);
+			
+	if (err < 0) {
 		jack_error ("ALSA: cannot set avail min for %s", stream_name);
 		return -1;
 	}
@@ -527,6 +534,7 @@ static int 
 alsa_driver_set_parameters (alsa_driver_t *driver,
 			    jack_nframes_t frames_per_cycle,
 			    jack_nframes_t user_nperiods,
+			    jack_nframes_t user_nfills,
 			    jack_nframes_t rate)
 {
 	int dir;
@@ -542,6 +550,15 @@ alsa_driver_set_parameters (alsa_driver_
 	driver->frames_per_cycle = frames_per_cycle;
 	driver->user_nperiods = user_nperiods;
 
+	if (user_nfills < 2)
+		user_nfills = user_nperiods;
+	else if (user_nfills > user_nperiods) {
+		fprintf (stderr, "nfills %d > nperiods %d\n",
+			 (int)user_nfills, (int)user_nperiods);
+		user_nfills = user_nperiods;
+	}
+	driver->user_nfills = user_nfills;
+
 	fprintf (stderr, "configuring for %" PRIu32 "Hz, period = %"
 		 PRIu32 " frames, buffer = %" PRIu32 " periods\n",
 		 rate, frames_per_cycle, user_nperiods);
@@ -835,13 +852,15 @@ static int
 alsa_driver_reset_parameters (alsa_driver_t *driver,
 			      jack_nframes_t frames_per_cycle,
 			      jack_nframes_t user_nperiods,
+			      jack_nframes_t user_nfills,
 			      jack_nframes_t rate)
 {
 	/* XXX unregister old ports ? */
 	alsa_driver_release_channel_dependent_memory (driver);
 	return alsa_driver_set_parameters (driver,
 					   frames_per_cycle,
-					   user_nperiods, rate);
+					   user_nperiods,
+					   user_nfills,rate);
 }
 
 static int
@@ -955,11 +974,11 @@ alsa_driver_start (alsa_driver_t *driver
 		
 		for (chn = 0; chn < driver->playback_nchannels; chn++) {
 			alsa_driver_silence_on_channel (driver, chn,
-							driver->buffer_frames);
+							driver->user_nfills * driver->frames_per_cycle);
 		}
 		
 		snd_pcm_mmap_commit (driver->playback_handle, poffset,
-				     driver->buffer_frames);
+				     driver->user_nfills * driver->frames_per_cycle);
 		
 		if ((err = snd_pcm_start (driver->playback_handle)) < 0) {
 			jack_error ("could not start playback (%s)",
@@ -1444,6 +1463,7 @@ alsa_driver_bufsize (alsa_driver_t* driv
 {
 	return alsa_driver_reset_parameters (driver, nframes,
 					     driver->user_nperiods,
+					     driver->user_nfills,
 					     driver->frame_rate);
 }
 
@@ -1853,6 +1873,7 @@ alsa_driver_new (char *name, char *playb
 		 jack_client_t *client, 
 		 jack_nframes_t frames_per_cycle,
 		 jack_nframes_t user_nperiods,
+		 jack_nframes_t user_nfills,
 		 jack_nframes_t rate,
 		 int hw_monitoring,
 		 int hw_metering,
@@ -2092,7 +2113,8 @@ alsa_driver_new (char *name, char *playb
 	}
 
 	if (alsa_driver_set_parameters (driver, frames_per_cycle,
-					user_nperiods, rate)) {
+					user_nperiods,
+					user_nfills, rate)) {
 		alsa_driver_delete (driver);
 		return 0;
 	}
@@ -2270,6 +2292,14 @@ driver_get_descriptor ()
 	strcpy (params[i].long_desc, params[i].short_desc);
 
 	i++;
+	strcpy (params[i].name, "nfills");
+	params[i].character  = 'f';
+	params[i].type       = JackDriverParamUInt;
+	params[i].value.ui   = 0;
+	strcpy (params[i].short_desc, "Number of filled periods");
+	strcpy (params[i].long_desc, params[i].short_desc);
+
+	i++;
 	strcpy (params[i].name, "hwmon");
 	params[i].character  = 'H';
 	params[i].type       = JackDriverParamBool;
@@ -2360,6 +2390,7 @@ driver_initialize (jack_client_t *client
         jack_nframes_t srate = 48000;
 	jack_nframes_t frames_per_interrupt = 1024;
 	unsigned long user_nperiods = 2;
+	unsigned long user_nfills = 0;
 	char *playback_pcm_name = "hw:0";
 	char *capture_pcm_name = "hw:0";
 	int hw_monitoring = FALSE;
@@ -2429,6 +2460,10 @@ driver_initialize (jack_client_t *client
 			user_nperiods = param->value.ui;
 			break;
 				
+		case 'f':
+			user_nfills = param->value.ui;
+			break;
+
 		case 's':
 			soft_mode = param->value.i;
 			break;
@@ -2462,7 +2497,7 @@ driver_initialize (jack_client_t *client
 	return alsa_driver_new ("alsa_pcm", playback_pcm_name,
 				capture_pcm_name, client,
 				frames_per_interrupt, 
-				user_nperiods, srate, hw_monitoring,
+				user_nperiods, user_nfills, srate, hw_monitoring,
 				hw_metering, capture, playback, dither,
 				soft_mode, monitor, 
 				user_capture_nchnls, user_playback_nchnls,
--- jack-audio-connection-kit-0.99.0/drivers/alsa/alsa_driver.h-dist	2004-11-15 15:06:52.000000000 +0100
+++ jack-audio-connection-kit-0.99.0/drivers/alsa/alsa_driver.h	2004-11-15 15:14:30.000000000 +0100
@@ -91,6 +91,7 @@ typedef struct {
     snd_pcm_format_t              capture_sample_format;
     float                         max_sample_val;
     unsigned long                 user_nperiods;
+    unsigned long                 user_nfills;
     unsigned long                 nfragments;
     unsigned long                 last_mask;
     snd_ctl_t                    *ctl_handle;

  reply	other threads:[~2004-11-17 14:55 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-11-11 14:41 Lowest latency: JACK, or ALSA directly? Asbjørn Sæbø
2004-11-11 15:11 ` Jack O'Quin
2004-11-12  9:04   ` Asbjørn Sæbø
2004-11-12 16:42     ` Jack O'Quin
2004-11-12 17:01       ` Takashi Iwai
2004-11-12 17:19         ` Jack O'Quin
2004-11-17 14:55           ` Takashi Iwai [this message]
2004-11-17 17:32             ` Jack O'Quin
2004-11-17 18:28               ` Takashi Iwai
2004-11-17 19:41                 ` Takashi Iwai
2004-11-18  2:07                   ` Jack O'Quin
2004-11-18 12:38                     ` Takashi Iwai
2004-11-11 15:34 ` Paul Davis
2004-11-12  9:11   ` Asbjørn Sæbø
2004-11-12 14:47   ` Gilles Degottex
2004-11-12 15:28     ` Giuliano Pochini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=s5hd5ycsexu.wl@alsa2.suse.de \
    --to=tiwai@suse.de \
    --cc=alsa-devel@lists.sourceforge.net \
    --cc=asbjs@stud.ntnu.no \
    --cc=joq@io.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.