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 20:41:20 +0100	[thread overview]
Message-ID: <s5h4qjos1pb.wl@alsa2.suse.de> (raw)
In-Reply-To: <s5h6544s529.wl@alsa2.suse.de>

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

At Wed, 17 Nov 2004 19:28:46 +0100,
I wrote:
> 
> With this model, basically the number of periods in the buffer doesn't
> mean the latency at all but is required just for the stream
> configuration.  The required condition is only nperiods >= 2.
> So, this option isn't even necessary if we query the nearest buffer
> size to "f-val * period_size".  Maybe this would be a better
> implementation from the perspective of usability.

Ok, the attached below is more radical change.  The -f option is
removed and the semantics of -n option is changed.  It means the
minimal playback latency requested by user.
The buffer size doesn't have to be exactly nperiods * period_size.
JACK accepts more periods returned from the driver than requested.
Also, the different number of periods are accepted, too, for playback
and capture directions.

Untested as usual :)


(BTW, the jack code is still based on the older ALSA API.
 Is this intentional?)

Takashi

[-- Attachment #2: Type: text/plain, Size: 8768 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 20:34:42.623799183 +0100
@@ -325,6 +325,7 @@ alsa_driver_configure_stream (alsa_drive
 			      snd_pcm_t *handle, 
 			      snd_pcm_hw_params_t *hw_params, 
 			      snd_pcm_sw_params_t *sw_params, 
+			      unsigned int *nperiodsp,
 			      unsigned long *nchns,unsigned long sample_width)
 {
 	int err, format;
@@ -436,13 +437,23 @@ alsa_driver_configure_stream (alsa_drive
 		return -1;
 	}
 
-	if ((err = snd_pcm_hw_params_set_periods (handle, hw_params,
-						  driver->user_nperiods, 0))
+	*nperiodsp = driver->user_nperiods;
+	snd_pcm_hw_params_set_periods_min (handle, hw_params, nperiodsp, NULL);
+	*nperiodsp = driver->user_nperiods;
+	if ((*nperiodsp = snd_pcm_hw_params_set_periods_near (handle, hw_params,
+							      *nperiodsp, NULL))
 	    < 0) {
 		jack_error ("ALSA: cannot set number of periods to %u for %s",
-			    driver->user_nperiods, stream_name);
+			    *nperiodsp, stream_name);
 		return -1;
 	}
+
+	if (*nperiodsp < driver->user_nperiods) {
+		jack_error ("ALSA: got smaller periods %u than %u for %s",
+			    *nperiodsp, (unsigned int)driver->user_nperiods, stream_name);
+		return -1;
+	}
+	fprintf(stderr, "nperiods = %d for %s\n", *nperiodsp, stream_name);
 	
 	if (!jack_power_of_two(driver->frames_per_cycle)) {
 		jack_error("JACK: frames must be a power of two "
@@ -451,12 +462,12 @@ alsa_driver_configure_stream (alsa_drive
 	}
 
 	if ((err = snd_pcm_hw_params_set_buffer_size (handle, hw_params,
-						      driver->user_nperiods *
+						      *nperiodsp *
 						      driver->frames_per_cycle))
 	    < 0) {
 		jack_error ("ALSA: cannot set buffer length to %" PRIu32
 			    " for %s",
-			    driver->user_nperiods * driver->frames_per_cycle,
+			    *nperiodsp * driver->frames_per_cycle,
 			    stream_name);
 		return -1;
 	}
@@ -475,7 +486,7 @@ alsa_driver_configure_stream (alsa_drive
 		return -1;
 	}
 
-	stop_th = driver->user_nperiods * driver->frames_per_cycle;
+	stop_th = *nperiodsp * driver->frames_per_cycle;
 	if (driver->soft_mode) {
 		stop_th = (snd_pcm_uframes_t)-1;
 	}
@@ -496,20 +507,27 @@ alsa_driver_configure_stream (alsa_drive
 
 #if 0
 	fprintf (stderr, "set silence size to %lu * %lu = %lu\n",
-		 driver->frames_per_cycle, driver->user_nperiods,
-		 driver->frames_per_cycle * driver->user_nperiods);
+		 driver->frames_per_cycle, *nperiodsp,
+		 driver->frames_per_cycle * *nperiodsp);
 
 	if ((err = snd_pcm_sw_params_set_silence_size (
 		     handle, sw_params,
-		     driver->frames_per_cycle * driver->user_nperiods)) < 0) {
+		     driver->frames_per_cycle * *nperiodsp)) < 0) {
 		jack_error ("ALSA: cannot set silence size for %s",
 			    stream_name);
 		return -1;
 	}
 #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 * (*nperiodsp - driver->user_nperiods + 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;
 	}
@@ -532,8 +550,6 @@ alsa_driver_set_parameters (alsa_driver_
 	int dir;
 	unsigned int p_period_size = 0;
 	unsigned int c_period_size = 0;
-	unsigned int p_nfragments = 0;
-	unsigned int c_nfragments = 0;
 	channel_t chn;
 	unsigned int pr = 0;
 	unsigned int cr = 0;
@@ -554,6 +570,7 @@ alsa_driver_set_parameters (alsa_driver_
 			    driver->capture_handle,
 			    driver->capture_hw_params,
 			    driver->capture_sw_params,
+			    &driver->capture_nperiods,
 			    &driver->capture_nchannels,
 			    driver->capture_sample_bytes)) {
 			jack_error ("ALSA: cannot configure capture channel");
@@ -569,6 +586,7 @@ alsa_driver_set_parameters (alsa_driver_
 			    driver->playback_handle,
 			    driver->playback_hw_params,
 			    driver->playback_sw_params,
+			    &driver->playback_nperiods,
 			    &driver->playback_nchannels,
 			    driver->playback_sample_bytes)) {
 			jack_error ("ALSA: cannot configure playback channel");
@@ -623,9 +641,6 @@ alsa_driver_set_parameters (alsa_driver_
 		p_period_size =
 			snd_pcm_hw_params_get_period_size (
 				driver->playback_hw_params, &dir);
-		p_nfragments =
-			snd_pcm_hw_params_get_periods (
-				driver->playback_hw_params, &dir);
 		driver->playback_sample_format = (snd_pcm_format_t)
 			snd_pcm_hw_params_get_format (
 				driver->playback_hw_params);
@@ -647,9 +662,6 @@ alsa_driver_set_parameters (alsa_driver_
 		c_period_size =
 			snd_pcm_hw_params_get_period_size (
 				driver->capture_hw_params, &dir);
-		c_nfragments =
-			snd_pcm_hw_params_get_periods (
-				driver->capture_hw_params, &dir);
 		driver->capture_sample_format = (snd_pcm_format_t)
 			snd_pcm_hw_params_get_format (
 				driver->capture_hw_params);
@@ -667,26 +679,6 @@ alsa_driver_set_parameters (alsa_driver_
 		}
 	}
 
-	if (driver->capture_handle && driver->playback_handle) {
-		if (p_nfragments != c_nfragments) {
-			jack_error ("alsa_pcm: different period counts for "
-				    "playback and capture!");
-			return -1;
-		}
-
-		driver->nfragments = c_nfragments;
-
-	} else if (driver->capture_handle) {
-
-		driver->nfragments = c_nfragments;
-
-	} else {
-
-		driver->nfragments = p_nfragments;
-
-	}
-
-	driver->buffer_frames = driver->frames_per_cycle * driver->nfragments;
 	driver->playback_sample_bytes =
 		snd_pcm_format_physical_width (driver->playback_sample_format)
 		/ 8;
@@ -934,7 +926,7 @@ alsa_driver_start (alsa_driver_t *driver
 		
 		pavail = snd_pcm_avail_update (driver->playback_handle);
 
-		if (pavail != driver->buffer_frames) {
+		if (pavail != driver->frames_per_cycle * driver->playback_nperiods) {
 			jack_error ("ALSA: full buffer not available at start");
 			return -1;
 		}
@@ -955,11 +947,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_nperiods * driver->frames_per_cycle);
 		}
 		
 		snd_pcm_mmap_commit (driver->playback_handle, poffset,
-				     driver->buffer_frames);
+				     driver->user_nperiods * driver->frames_per_cycle);
 		
 		if ((err = snd_pcm_start (driver->playback_handle)) < 0) {
 			jack_error ("could not start playback (%s)",
@@ -1107,10 +1099,11 @@ alsa_driver_silence_untouched_channels (
 					jack_nframes_t nframes)
 {
 	channel_t chn;
+	jack_nframes_t buffer_frames = driver->frames_per_cycle * driver->playback_nperiods;
 
 	for (chn = 0; chn < driver->playback_nchannels; chn++) {
 		if ((driver->channels_not_done & (1<<chn))) { 
-			if (driver->silent[chn] < driver->buffer_frames) {
+			if (driver->silent[chn] < buffer_frames) {
 				alsa_driver_silence_on_channel_no_mark (
 					driver, chn, nframes);
 				driver->silent[chn] += nframes;
@@ -1686,7 +1679,7 @@ alsa_driver_attach (alsa_driver_t *drive
 		 * (external) latency
 		*/
 		jack_port_set_latency (port, driver->frames_per_cycle
-				       * driver->nfragments);
+				       * driver->user_nperiods);
 
 		driver->playback_ports =
 			jack_slist_append (driver->playback_ports, port);
@@ -1901,7 +1894,6 @@ alsa_driver_new (char *name, char *playb
 	driver->ctl_handle = 0;
 	driver->hw = 0;
 	driver->capture_and_playback_not_synced = FALSE;
-	driver->nfragments = 0;
 	driver->max_nchannels = 0;
 	driver->user_nchannels = 0;
 	driver->playback_nchannels = 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-17 20:34:46.671045579 +0100
@@ -84,14 +84,14 @@ typedef struct {
     char                         *alsa_name_playback;
     char                         *alsa_name_capture;
     char                         *alsa_driver;
-    snd_pcm_uframes_t             buffer_frames;
     unsigned long                 channels_not_done;
     unsigned long                 channel_done_bits;
     snd_pcm_format_t              playback_sample_format;
     snd_pcm_format_t              capture_sample_format;
     float                         max_sample_val;
     unsigned long                 user_nperiods;
-    unsigned long                 nfragments;
+    unsigned int                  playback_nperiods;
+    unsigned int                  capture_nperiods;
     unsigned long                 last_mask;
     snd_ctl_t                    *ctl_handle;
     snd_pcm_t                    *playback_handle;

  reply	other threads:[~2004-11-17 19:41 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
2004-11-17 17:32             ` Jack O'Quin
2004-11-17 18:28               ` Takashi Iwai
2004-11-17 19:41                 ` Takashi Iwai [this message]
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=s5h4qjos1pb.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