From mboxrd@z Thu Jan 1 00:00:00 1970 From: Takashi Iwai Subject: Re: Lowest latency: JACK, or ALSA directly? Date: Wed, 17 Nov 2004 15:55:25 +0100 Message-ID: References: <20041111144152.GA12443@stud.ntnu.no> <87mzxozahr.fsf@sulphur.joq.us> <20041112090416.GA3167@stud.ntnu.no> <87oei3xbly.fsf@sulphur.joq.us> <87k6srx9wi.fsf@sulphur.joq.us> Mime-Version: 1.0 (generated by SEMI 1.14.5 - "Awara-Onsen") Content-Type: multipart/mixed; boundary="Multipart_Wed_Nov_17_15:55:25_2004-1" Return-path: In-Reply-To: <87k6srx9wi.fsf@sulphur.joq.us> Sender: alsa-devel-admin@lists.sourceforge.net Errors-To: alsa-devel-admin@lists.sourceforge.net List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , List-Archive: To: Jack O'Quin Cc: =?ISO-8859-1?Q?Asbj=F8rn_S=E6b=F8?= , alsa-devel@lists.sourceforge.net List-Id: alsa-devel@alsa-project.org --Multipart_Wed_Nov_17_15:55:25_2004-1 Content-Type: text/plain; charset=US-ASCII At 12 Nov 2004 11:19:25 -0600, Jack O'Quin wrote: > > Takashi Iwai 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 --Multipart_Wed_Nov_17_15:55:25_2004-1 Content-Type: text/plain; charset=US-ASCII --- 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; --Multipart_Wed_Nov_17_15:55:25_2004-1-- ------------------------------------------------------- This SF.Net email is sponsored by: InterSystems CACHE FREE OODBMS DOWNLOAD - A multidimensional database that combines robust object and relational technologies, making it a perfect match for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8