Message ID | 1516794545-9868-1-git-send-email-twischer@de.adit-jv.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wed, 24 Jan 2018 12:49:05 +0100, <twischer@de.adit-jv.com> wrote: > > From: Timo Wischer <twischer@de.adit-jv.com> > > instead of using buffer_size as wrap around. No, the ioplug backend has to report the position from 0 to buffer_size. > This is required to detect Xruns. The XRUN can be reported back from the backend just by returning an error from pointer callback. > It is also required to allow the JACK thread > to processes the whole ALSA audio buffer at once > without calling snd_pcm_avail_update() in between. > > For example when the hw_ptr will be updated with > hw_ptr += buffer_size > and it is using the buffer_size as wrap around > hw_ptr %= buffer_size > would result in the same value as before the add operation. > > Due to that the user application would not recognize > that the complete audio buffer was copied. This has nothing to do with the reported position. If this happens, it simply means an XRUN. You should report the error instead. thanks, Takashi
Hello Takashi, > This has nothing to do with the reported position. If this happens, it simply means an XRUN. You should report the error instead. When the ALSA buffer is full and the JACK daemon is requesting exactly the amount of samples of the buffer size I do not see an under run here. After such an operation the ALSA buffer is empty but the JACK daemon has not read more samples than available. Exactly in this case we would increment the hw_ptr += buffer_size but this would not be recognized by the ALSA library when we are using a wrap around of buffer_size. > No, the ioplug backend has to report the position from 0 to buffer_size. I know but I think the ioplug API implementation has possibly to be changed to allow exactly such use cases as described above. Or do you have another idea how to report such a hw_ptr change? Best regards Timo Wischer Advanced Driver Information Technology GmbH Engineering Software Base (ADITG/ESB) Robert-Bosch-Str. 200 31139 Hildesheim Germany Tel. +49 5121 49 6938 Fax +49 5121 49 6999 twischer@de.adit-jv.com ADIT is a joint venture company of Robert Bosch GmbH/Robert Bosch Car Multimedia GmbH and DENSO Corporation Sitz: Hildesheim, Registergericht: Amtsgericht Hildesheim HRB 3438 Geschäftsführung: Wilhelm Grabow, Ken Yaguchi
On Tue, 13 Feb 2018 15:56:08 +0100, Wischer, Timo (ADITG/ESB) wrote: > > Hello Takashi, > > > This has nothing to do with the reported position. If this happens, > it simply means an XRUN. You should report the error instead. > > When the ALSA buffer is full and the JACK daemon is requesting exactly the amount of samples of the buffer size > I do not see an under run here. > After such an operation the ALSA buffer is empty > but the JACK daemon has not read more samples than available. The backend has nothing to do with such a case. This happens only when the application uses periods=1, and then it implies that the application must know of the situation. The ioplug simulates the say the hardware device would behave. It notifies the period elapse via file-descriptor and it reports the DMA ring-buffer position. The ring buffer is between 0 to buffer size, you must not exceed it in the reporting. Takashi > Exactly in this case we would increment the hw_ptr += buffer_size > but this would not be recognized by the ALSA library > when we are using a wrap around of buffer_size. > > > > No, the ioplug backend has to report the position from 0 to buffer_size. > > I know but I think the ioplug API implementation has possibly to be changed to allow exactly such use cases > as described above. > > Or do you have another idea how to report such a hw_ptr change? > > Best regards > > Timo Wischer > > Advanced Driver Information Technology GmbH > Engineering Software Base (ADITG/ESB) > Robert-Bosch-Str. 200 > 31139 Hildesheim > Germany > > Tel. +49 5121 49 6938 > Fax +49 5121 49 6999 > twischer@de.adit-jv.com > > ADIT is a joint venture company of Robert Bosch GmbH/Robert Bosch Car Multimedia GmbH and DENSO Corporation > Sitz: Hildesheim, Registergericht: Amtsgericht Hildesheim HRB 3438 > Geschäftsführung: Wilhelm Grabow, Ken Yaguchi >
Hello Takashi, > This happens only when the application uses periods=1, It can also happen with 2 periods per buffer e.g. when the user application is too late. I will try to illustrate the use case with the following time line: Time line: 0--R1-W1-R2--R3-W2-W3-... 0 buffer is full (2 periods) R1 JACK daemon reads 1 period (1 period left in the buffer) W1 User application writes 1 period (2 periods in the buffer) R2 JACK daemon reads 1 period (1 period left in the buffer) R3 JACK daemon reads 1 period (buffer empty) But it is not yet an under run because JACK has not yet read invalid data. Due to the blocked user application (e.g low scheduling priority) the pointer() callback was not called before the second read. In this case the next pointer() call has to result in a delta of 2 periods. But this is not possible if pointer() is not allowed to return >=buffer_size. W2 User application writes 1 period (1 periods in the buffer) W3 User application writes 1 period (2 periods in the buffer) Continue with 0 > It notifies the period elapse via file-descriptor But this notification will be processed later if the user application is blocked at the moment (e.g. by higher priority tasks). Do you also see my problem, now? Best regards Timo Wischer Advanced Driver Information Technology GmbH Engineering Software Base (ADITG/ESB) Robert-Bosch-Str. 200 31139 Hildesheim Germany Tel. +49 5121 49 6938 Fax +49 5121 49 6999 twischer@de.adit-jv.com ADIT is a joint venture company of Robert Bosch GmbH/Robert Bosch Car Multimedia GmbH and DENSO Corporation Sitz: Hildesheim, Registergericht: Amtsgericht Hildesheim HRB 3438 Geschäftsführung: Wilhelm Grabow, Ken Yaguchi
On Thu, 15 Feb 2018 11:36:21 +0100, Wischer, Timo (ADITG/ESB) wrote: > > Hello Takashi, > > > This happens only when the application uses periods=1, > > It can also happen with 2 periods per buffer e.g. when the user application is too late. > I will try to illustrate the use case with the following time line: > > Time line: 0--R1-W1-R2--R3-W2-W3-... > > 0 buffer is full (2 periods) > R1 JACK daemon reads 1 period (1 period left in the buffer) > W1 User application writes 1 period (2 periods in the buffer) > R2 JACK daemon reads 1 period (1 period left in the buffer) > R3 JACK daemon reads 1 period (buffer empty) > But it is not yet an under run because JACK has not yet read invalid data. > Due to the blocked user application (e.g low scheduling priority) the pointer() callback was not called before the second read. > In this case the next pointer() call has to result in a delta of 2 periods. > But this is not possible if pointer() is not allowed to return >=buffer_size. > > W2 User application writes 1 period (1 periods in the buffer) > W3 User application writes 1 period (2 periods in the buffer) > Continue with 0 > > > It notifies the period elapse via file-descriptor > But this notification will be processed later if the user application is blocked at the moment (e.g. by higher priority tasks). > > Do you also see my problem, now? I know that's the problem, but you're scratching in the wrong surface. This isn't the issue to be fixed in the backend side. The fact that the pointer callback returns 0 to buffer_size-1 is *the* design. You can't ignore that. If you need to improve such a situation, you'd have to fix in the ioplug implementation itself, not the jack plugin. Takashi
diff --git a/jack/pcm_jack.c b/jack/pcm_jack.c index 3aed332..c22a5d0 100644 --- a/jack/pcm_jack.c +++ b/jack/pcm_jack.c @@ -40,6 +40,7 @@ typedef struct { char **port_names; unsigned int num_ports; + snd_pcm_uframes_t boundary; unsigned int hw_ptr; unsigned int sample_bits; snd_pcm_uframes_t min_avail; @@ -130,6 +131,21 @@ static int snd_pcm_jack_poll_revents(snd_pcm_ioplug_t *io, static snd_pcm_sframes_t snd_pcm_jack_pointer(snd_pcm_ioplug_t *io) { snd_pcm_jack_t *jack = io->private_data; + + /* ALSA library is calulating the delta between the last pointer and + * the current one. + * Normally it is expecting a value between 0 and buffer_size. + * The following example would result in an negative delta + * which would result in a hw_ptr which will be reduced. + * last_hw = jack->boundary - io->buffer_size + * hw = 0 + * But we cannot use + * return jack->hw_ptr % io->buffer_size; + * because in this case an update of + * hw_ptr += io->buffer_size + * would not be recognized by the ALSA library. + * Therefore we are using jack->boundary as the wrap around. + */ return jack->hw_ptr; } @@ -162,7 +178,7 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io) while (xfer < nframes) { snd_pcm_uframes_t frames = nframes - xfer; - snd_pcm_uframes_t offset = hw_ptr; + snd_pcm_uframes_t offset = hw_ptr % io->buffer_size; snd_pcm_uframes_t cont = io->buffer_size - offset; if (cont < frames) @@ -176,7 +192,8 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io) } hw_ptr += frames; - hw_ptr %= io->buffer_size; + if (hw_ptr >= jack->boundary) + hw_ptr -= jack->boundary; xfer += frames; } jack->hw_ptr = hw_ptr; @@ -200,6 +217,8 @@ static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io) err = snd_pcm_sw_params_current(io->pcm, swparams); if (err == 0) { snd_pcm_sw_params_get_avail_min(swparams, &jack->min_avail); + /* get boundary for available calulation */ + snd_pcm_sw_params_get_boundary(swparams, &jack->boundary); } /* deactivate jack connections if this is XRUN recovery */