Alsa-Devel Archive on 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox