From patchwork Mon Feb 26 08:14:11 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Timo Wischer X-Patchwork-Id: 10241375 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id B3F2160208 for ; Mon, 26 Feb 2018 08:14:34 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9C3092912A for ; Mon, 26 Feb 2018 08:14:34 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 908AD29A5A; Mon, 26 Feb 2018 08:14:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EBEC92912A for ; Mon, 26 Feb 2018 08:14:32 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 6C63C2679F6; Mon, 26 Feb 2018 09:14:31 +0100 (CET) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 44FED2679F6; Mon, 26 Feb 2018 09:14:28 +0100 (CET) Received: from smtp1.de.adit-jv.com (smtp1.de.adit-jv.com [62.225.105.245]) by alsa0.perex.cz (Postfix) with ESMTP id 2B660267045; Mon, 26 Feb 2018 09:14:23 +0100 (CET) Received: from localhost (smtp1.de.adit-jv.com [127.0.0.1]) by smtp1.de.adit-jv.com (Postfix) with ESMTP id 0268B3C09A1; Mon, 26 Feb 2018 09:14:22 +0100 (CET) Received: from smtp1.de.adit-jv.com ([127.0.0.1]) by localhost (smtp1.de.adit-jv.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id swTm9z5HEBJa; Mon, 26 Feb 2018 09:14:15 +0100 (CET) Received: from HI2EXCH01.adit-jv.com (hi2exch01.adit-jv.com [10.72.92.24]) (using TLSv1 with cipher ECDHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp1.de.adit-jv.com (Postfix) with ESMTPS id 4537C3C0BAE; Mon, 26 Feb 2018 09:14:13 +0100 (CET) Received: from HI2EXCH01.adit-jv.com ([fe80::69bf:8148:2f13:f289]) by HI2EXCH01.adit-jv.com ([fe80::69bf:8148:2f13:f289%12]) with mapi id 14.03.0382.000; Mon, 26 Feb 2018 09:14:13 +0100 From: "Wischer, Timo (ADITG/ESB)" To: "patch@alsa-project.org" Thread-Topic: [PATCH - JACK PCM plugin] jack: Do not Xrun the ALSA buffer Thread-Index: AQHTlQnmwvjNrZpZ3kq0/1t7yLxfmaO2hiyv Date: Mon, 26 Feb 2018 08:14:11 +0000 Message-ID: References: <1516794784-9993-1-git-send-email-twischer@de.adit-jv.com> In-Reply-To: <1516794784-9993-1-git-send-email-twischer@de.adit-jv.com> Accept-Language: en-US, de-DE Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.72.93.172] MIME-Version: 1.0 Cc: Takashi Iwai , "alsa-devel@alsa-project.org" Subject: Re: [alsa-devel] [PATCH - JACK PCM plugin] jack: Do not Xrun the ALSA buffer X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP Hello all, Due to merged [1] (see [2]) [3] can be merged without conflicts, now. @Takashi: Thanks for merging [2]. Please give a feedback if there is anything which has to be changed. The biggest change in snd_pcm_jack_process_cb() occurs due to the movement of the snd_pcm_area_silence() call to the end of this function. This is required to fill the buffer with silence if there is not enough audio data available for JACK. [1] http://mailman.alsa-project.org/pipermail/alsa-devel/2018-January/130986.html [2] http://git.alsa-project.org/?p=alsa-plugins.git;a=commit;h=3e6ace6fe045c580dc5490d87eff6b616f7769ef [3] http://mailman.alsa-project.org/pipermail/alsa-devel/2018-January/130987.html 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 diff --git a/jack/pcm_jack.c b/jack/pcm_jack.c index c22a5d0..a4f35f4 100644 --- a/jack/pcm_jack.c +++ b/jack/pcm_jack.c @@ -54,6 +54,68 @@ typedef struct { static int snd_pcm_jack_stop(snd_pcm_ioplug_t *io); + +static inline snd_pcm_uframes_t snd_pcm_jack_playback_avail(const snd_pcm_ioplug_t* const io, + const snd_pcm_uframes_t hw_ptr, + const snd_pcm_uframes_t appl_ptr) +{ + const snd_pcm_jack_t* const jack = io->private_data; + + /* cannot use io->hw_ptr without calling snd_pcm_avail_update() + * because it is not guranteed that snd_pcm_jack_pointer() was already + * called + */ + snd_pcm_sframes_t avail; + avail = hw_ptr + io->buffer_size - appl_ptr; + if (avail < 0) + avail += jack->boundary; + else if ((snd_pcm_uframes_t) avail >= jack->boundary) + avail -= jack->boundary; + return avail; +} + +static inline snd_pcm_uframes_t snd_pcm_jack_capture_avail(const snd_pcm_ioplug_t* const io, + const snd_pcm_uframes_t hw_ptr, + const snd_pcm_uframes_t appl_ptr) +{ + const snd_pcm_jack_t* const jack = io->private_data; + + /* cannot use io->hw_ptr without calling snd_pcm_avail_update() + * because it is not guranteed that snd_pcm_jack_pointer() was already + * called + */ + snd_pcm_sframes_t avail; + avail = hw_ptr - appl_ptr; + if (avail < 0) + avail += jack->boundary; + return avail; +} + +static inline snd_pcm_uframes_t snd_pcm_jack_avail(const snd_pcm_ioplug_t* const io, + const snd_pcm_uframes_t hw_ptr, + const snd_pcm_uframes_t appl_ptr) +{ + return (io->stream == SND_PCM_STREAM_PLAYBACK) ? + snd_pcm_jack_playback_avail(io, hw_ptr, appl_ptr) : + snd_pcm_jack_capture_avail(io, hw_ptr, appl_ptr); +} + +static inline snd_pcm_uframes_t snd_pcm_jack_hw_avail(const snd_pcm_ioplug_t* const io, + const snd_pcm_uframes_t hw_ptr, + const snd_pcm_uframes_t appl_ptr) +{ + /* available data/space which can be transfered by the user application */ + const snd_pcm_uframes_t user_avail = snd_pcm_jack_avail(io, hw_ptr, + appl_ptr); + + if (user_avail > io->buffer_size) { + /* there was an Xrun */ + return 0; + } + /* available data/space which can be transfered by the DMA */ + return io->buffer_size - user_avail; +} + static int pcm_poll_block_check(snd_pcm_ioplug_t *io) { static char buf[32]; @@ -154,7 +216,6 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io) { snd_pcm_jack_t *jack = io->private_data; snd_pcm_uframes_t hw_ptr; - const snd_pcm_channel_area_t *areas; snd_pcm_uframes_t xfer = 0; unsigned int channel; @@ -164,40 +225,57 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io) jack->areas[channel].first = 0; jack->areas[channel].step = jack->sample_bits; } - - if (io->state != SND_PCM_STATE_RUNNING) { - if (io->stream == SND_PCM_STREAM_PLAYBACK) { - for (channel = 0; channel < io->channels; channel++) - snd_pcm_area_silence(&jack->areas[channel], 0, nframes, io->format); - return 0; - } - } hw_ptr = jack->hw_ptr; - areas = snd_pcm_ioplug_mmap_areas(io); - - while (xfer < nframes) { - snd_pcm_uframes_t frames = nframes - xfer; - snd_pcm_uframes_t offset = hw_ptr % io->buffer_size; - snd_pcm_uframes_t cont = io->buffer_size - offset; - - if (cont < frames) - frames = cont; + if (io->state == SND_PCM_STATE_RUNNING) { + const snd_pcm_channel_area_t *areas = snd_pcm_ioplug_mmap_areas(io); + + while (xfer < nframes) { + snd_pcm_uframes_t frames = nframes - xfer; + snd_pcm_uframes_t offset = hw_ptr % io->buffer_size; + snd_pcm_uframes_t cont = io->buffer_size - offset; + snd_pcm_uframes_t hw_avail = + snd_pcm_jack_hw_avail(io, hw_ptr, + io->appl_ptr); + + /* stop copying if there is no more data available */ + if (hw_avail <= 0) + break; + + /* split the snd_pcm_area_copy() function into two parts + * if the data to copy passes the buffer wrap around + */ + if (cont < frames) + frames = cont; + + if (hw_avail < frames) + frames = hw_avail; + + for (channel = 0; channel < io->channels; channel++) { + if (io->stream == SND_PCM_STREAM_PLAYBACK) + snd_pcm_area_copy(&jack->areas[channel], xfer, &areas[channel], offset, frames, io->format); + else + snd_pcm_area_copy(&areas[channel], offset, &jack->areas[channel], xfer, frames, io->format); + } - for (channel = 0; channel < io->channels; channel++) { - if (io->stream == SND_PCM_STREAM_PLAYBACK) - snd_pcm_area_copy(&jack->areas[channel], xfer, &areas[channel], offset, frames, io->format); - else - snd_pcm_area_copy(&areas[channel], offset, &jack->areas[channel], xfer, frames, io->format); + hw_ptr += frames; + if (hw_ptr >= jack->boundary) + hw_ptr -= jack->boundary; + xfer += frames; } - - hw_ptr += frames; - if (hw_ptr >= jack->boundary) - hw_ptr -= jack->boundary; - xfer += frames; } jack->hw_ptr = hw_ptr; + /* check if requested frames were copied */ + if (xfer < nframes) { + /* always fill the not yet written JACK buffer with silence */ + if (io->stream == SND_PCM_STREAM_PLAYBACK) { + const snd_pcm_uframes_t samples = nframes - xfer; + for (channel = 0; channel < io->channels; channel++) + snd_pcm_area_silence(&jack->areas[channel], xfer, samples, io->format); + } + } + pcm_poll_unblock_check(io); /* unblock socket for polling if needed */ return 0;