From patchwork Sun Dec 23 20:52:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?Wm9sdMOhbiBLxZF2w6Fnw7M=?= X-Patchwork-Id: 10741861 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E54141822 for ; Sun, 23 Dec 2018 21:19:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D33B3286E6 for ; Sun, 23 Dec 2018 21:19:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C767C28783; Sun, 23 Dec 2018 21:19:52 +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=-7.7 required=2.0 tests=BAYES_00,DKIM_ADSP_CUSTOM_MED, DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 022D7286E6 for ; Sun, 23 Dec 2018 21:19:52 +0000 (UTC) Received: from localhost ([127.0.0.1]:59877 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gbBA6-0006ks-5j for patchwork-qemu-devel@patchwork.kernel.org; Sun, 23 Dec 2018 16:19:50 -0500 Received: from eggs.gnu.org ([208.118.235.92]:52423) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gbAk4-00083O-Oo for qemu-devel@nongnu.org; Sun, 23 Dec 2018 15:53:01 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gbAk2-0002p4-UB for qemu-devel@nongnu.org; Sun, 23 Dec 2018 15:52:56 -0500 Received: from mail-wm1-x342.google.com ([2a00:1450:4864:20::342]:36147) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1gbAk2-0002l4-Kp for qemu-devel@nongnu.org; Sun, 23 Dec 2018 15:52:54 -0500 Received: by mail-wm1-x342.google.com with SMTP id p6so10418101wmc.1 for ; Sun, 23 Dec 2018 12:52:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Xx8jsSimDtCrlyE22EoFoyLHbKim9wAP8S82IzGMhm0=; b=GxpxeYAqRjukJkin9yYx6jB/cLQHSbGspFKgHVTLVu3IzJhZ8M4S9GLNtPlAWMIezP 8UKApOfEjNfSM7kQxtqgP2MwZHhMLeer4qzeVZa76jbclQtc2wM1xllmrzvYcYjz7GxK X/B34Td4sc0f20cgWtXY8MlMBP1ziioO+iE4y1S9Osz63whm7PnQu6tsGSw4zGvv1awF W4yKYpxH2TscY6EEUh6qvAOiwT8WBhei1aT8NiJ0urG+4hPqmMaGPLgj+YPPY97LMStE cCPXqimFUhZd9YgDGzj8OXhgABIBG9xZihV6lyHxsdYHDdy4qRHgwK9yaBSmqtD4sAhl bkKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Xx8jsSimDtCrlyE22EoFoyLHbKim9wAP8S82IzGMhm0=; b=VWF9CKEnzT2fe0CFRSykwS83UEWJCWxDzIzkGxzw+qyC1ERMnJi0nD7eMiPAGl+NCh 93S0iM+7IOrXdZcgEtXvfTu1YS5X1ss6BG9Y3XYs0Bk9HC18jE+7TLEy/KLJcHj/RMtT d7BnTSpRJfRWn23VoJtIQbQH8EfpVg9uDM/7oSznVQ7cNXCoQESPzx1hRIeGvKmNmA4Q fx+Kx3BxdFqw+fvvtuRxQJSKVlX8U8qX63lXrvvbvSRvcptdiXX+JzFC7q3DYJjA44Fu Mo/z73DRZI4RmqXVVctwAw9ifv35afltzgxZejcwZ3JCNfveaT5GmwT2fTj5riih9qKv NYWw== X-Gm-Message-State: AJcUukf4vIL91zHQbzEhbp/KPMbFt/DKAFpHgXl/yEcmHTfR1k1I9SFA l3/D1h8eMGDxVItvqKcx6GQEbCdLn2M= X-Google-Smtp-Source: ALg8bN6KO4bvW23iPcW3LYKle/rebSFK7I6dmoeg2MyYdQOuRXK+2PePadkCxnZZgs6yhha3Mp8Avg== X-Received: by 2002:a1c:8d49:: with SMTP id p70mr10749336wmd.68.1545598373273; Sun, 23 Dec 2018 12:52:53 -0800 (PST) Received: from nullptr.home.dirty-ice.org (2a01-036c-0113-24a3-0000-0000-0000-0005.pool6.digikabel.hu. [2a01:36c:113:24a3::5]) by smtp.gmail.com with ESMTPSA id g198sm25456920wmd.23.2018.12.23.12.52.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 23 Dec 2018 12:52:52 -0800 (PST) From: " =?utf-8?b?S8WRdsOhZ8OzLCBab2x0w6Fu?= " X-Google-Original-From: =?utf-8?b?S8WRdsOhZ8OzLCBab2x0w6Fu?= To: qemu-devel@nongnu.org Date: Sun, 23 Dec 2018 21:52:04 +0100 Message-Id: <59bee9fad02c04c6600eba20dafb0c4cd1b31007.1545598229.git.DirtY.iCE.hu@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::342 Subject: [Qemu-devel] [PATCH v2 28/52] audio: api for mixeng code free backends X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Gerd Hoffmann Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Kővágó, Zoltán --- audio/audio.c | 211 ++++++++++++++++++++++++++++++++++++++++- audio/audio_int.h | 45 +++++++-- audio/audio_template.h | 1 + 3 files changed, 247 insertions(+), 10 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 27a8a31a64..1897e22444 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -575,6 +575,25 @@ size_t audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, return clipped; } +static void audio_pcm_hw_clip_out2(HWVoiceOut *hw, void *pcm_buf, size_t len) +{ + size_t clipped = 0; + size_t pos = hw->rpos; + + while (len) { + st_sample *src = hw->mix_buf + pos; + uint8_t *dst = advance (pcm_buf, clipped << hw->info.shift); + size_t samples_till_end_of_buf = hw->samples - pos; + size_t samples_to_clip = MIN(len, samples_till_end_of_buf); + + hw->clip (dst, src, samples_to_clip); + + pos = (pos + samples_to_clip) % hw->samples; + len -= samples_to_clip; + clipped += samples_to_clip; + } +} + /* * Soft voice (capture) */ @@ -1052,6 +1071,31 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos, mixeng_clear(hw->mix_buf, samples - n); } +static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live) +{ + size_t clipped = 0; + + while (live) { + size_t size, decr, proc; + void *buf = hw->pcm_ops->get_buffer_out(hw, &size); + + decr = MIN(size >> hw->info.shift, live); + audio_pcm_hw_clip_out2(hw, buf, decr); + proc = hw->pcm_ops->put_buffer_out(hw, buf, decr << hw->info.shift) >> + hw->info.shift; + + live -= proc; + clipped += proc; + hw->rpos = (hw->rpos + proc) % hw->samples; + + if (proc == 0 || proc < decr) { + break; + } + } + + return clipped; +} + static void audio_run_out (AudioState *s) { HWVoiceOut *hw = NULL; @@ -1099,7 +1143,11 @@ static void audio_run_out (AudioState *s) } prev_rpos = hw->rpos; - played = hw->pcm_ops->run_out (hw, live); + if (hw->pcm_ops->run_out) { + played = hw->pcm_ops->run_out(hw, live); + } else { + played = audio_pcm_hw_run_out(hw, live); + } replay_audio_out(&played); if (audio_bug(__func__, hw->rpos >= hw->samples)) { dolog("hw->rpos=%zu hw->samples=%zu played=%zu\n", @@ -1158,6 +1206,35 @@ static void audio_run_out (AudioState *s) } } +static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples) +{ + size_t conv = 0; + + while (samples) { + size_t proc; + size_t size = samples << hw->info.shift; + void *buf = hw->pcm_ops->get_buffer_in(hw, &size); + + assert((size & hw->info.align) == 0); + if (size == 0) { + hw->pcm_ops->put_buffer_in(hw, buf, size); + break; + } + + proc = MIN(size >> hw->info.shift, + hw->samples - hw->wpos); + + hw->conv(hw->conv_buf + hw->wpos, buf, proc); + hw->wpos = (hw->wpos + proc) % hw->samples; + + samples -= proc; + conv += proc; + hw->pcm_ops->put_buffer_in(hw, buf, proc << hw->info.shift); + } + + return conv; +} + static void audio_run_in (AudioState *s) { HWVoiceIn *hw = NULL; @@ -1167,7 +1244,12 @@ static void audio_run_in (AudioState *s) size_t captured = 0, min; if (replay_mode != REPLAY_MODE_PLAY) { - captured = hw->pcm_ops->run_in(hw); + if (hw->pcm_ops->run_in) { + captured = hw->pcm_ops->run_in(hw); + } else { + captured = audio_pcm_hw_run_in( + hw, hw->samples - audio_pcm_hw_get_live_in(hw)); + } } replay_audio_in(&captured, hw->conv_buf, &hw->wpos, hw->samples); @@ -1261,12 +1343,137 @@ void audio_run(AudioState *s, const char *msg) #endif } +void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size) +{ + ssize_t start; + + if (unlikely(!hw->buf_emul)) { + size_t calc_size = hw->samples << hw->info.shift; + hw->buf_emul = g_malloc(calc_size); + hw->size_emul = calc_size; + hw->pos_emul = hw->pending_emul = 0; + } + + while (hw->pending_emul < hw->size_emul) { + size_t read_len = MIN(hw->size_emul - hw->pos_emul, + hw->size_emul - hw->pending_emul); + size_t read = hw->pcm_ops->read(hw, hw->buf_emul + hw->pos_emul, + read_len); + hw->pending_emul += read; + if (read < read_len) { + break; + } + } + + start = ((ssize_t) hw->pos_emul) - hw->pending_emul; + if (start < 0) { + start += hw->size_emul; + } + assert(start >= 0 && start < hw->size_emul); + + *size = MIN(hw->pending_emul, hw->size_emul - start); + return hw->buf_emul + start; +} + +void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size) +{ + assert(size <= hw->pending_emul); + hw->pending_emul -= size; +} + +void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size) +{ + if (unlikely(!hw->buf_emul)) { + size_t calc_size = hw->samples << hw->info.shift; + + hw->buf_emul = g_malloc(calc_size); + hw->size_emul = calc_size; + hw->pos_emul = hw->pending_emul = 0; + } + + *size = MIN(hw->size_emul - hw->pending_emul, + hw->size_emul - hw->pos_emul); + return hw->buf_emul + hw->pos_emul; +} + +size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf, + size_t size) +{ + assert(buf == hw->buf_emul + hw->pos_emul && + size + hw->pending_emul <= hw->size_emul); + + hw->pending_emul += size; + hw->pos_emul = (hw->pos_emul + size) % hw->size_emul; + + return size; +} + +size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size) +{ + audio_generic_put_buffer_out_nowrite(hw, buf, size); + + while (hw->pending_emul) { + size_t write_len, written; + ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul; + if (start < 0) { + start += hw->size_emul; + } + assert(start >= 0 && start < hw->size_emul); + + write_len = MIN(hw->pending_emul, hw->size_emul - start); + + written = hw->pcm_ops->write(hw, hw->buf_emul + start, write_len); + hw->pending_emul -= written; + + if (written < write_len) { + break; + } + } + + /* + * fake we have written everything. non-written data remain in pending_emul, + * so we do not have to clip them multiple times + */ + return size; +} + +size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size) +{ + size_t dst_size, copy_size; + void *dst = hw->pcm_ops->get_buffer_out(hw, &dst_size); + copy_size = MIN(size, dst_size); + + memcpy(dst, buf, copy_size); + return hw->pcm_ops->put_buffer_out(hw, buf, copy_size); +} + +size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size) +{ + size_t dst_size, copy_size; + void *dst = hw->pcm_ops->get_buffer_in(hw, &dst_size); + copy_size = MIN(size, dst_size); + + memcpy(dst, buf, copy_size); + hw->pcm_ops->put_buffer_in(hw, buf, copy_size); + return copy_size; +} + + static int audio_driver_init(AudioState *s, struct audio_driver *drv, Audiodev *dev) { s->drv_opaque = drv->init(dev); if (s->drv_opaque) { + if (!drv->pcm_ops->get_buffer_in) { + drv->pcm_ops->get_buffer_in = audio_generic_get_buffer_in; + drv->pcm_ops->put_buffer_in = audio_generic_put_buffer_in; + } + if (!drv->pcm_ops->get_buffer_out) { + drv->pcm_ops->get_buffer_out = audio_generic_get_buffer_out; + drv->pcm_ops->put_buffer_out = audio_generic_put_buffer_out; + } + audio_init_nb_voices_out(s, drv); audio_init_nb_voices_in(s, drv); s->drv = drv; diff --git a/audio/audio_int.h b/audio/audio_int.h index 330c465d0b..5c361d9451 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -64,6 +64,8 @@ typedef struct HWVoiceOut { uint64_t ts_helper; struct st_sample *mix_buf; + void *buf_emul; + size_t pos_emul, pending_emul, size_emul; size_t samples; QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; @@ -86,6 +88,8 @@ typedef struct HWVoiceIn { uint64_t ts_helper; struct st_sample *conv_buf; + void *buf_emul; + size_t pos_emul, pending_emul, size_emul; size_t samples; QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head; @@ -146,17 +150,42 @@ struct audio_driver { }; struct audio_pcm_ops { - int (*init_out)(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque); - void (*fini_out)(HWVoiceOut *hw); - int (*run_out) (HWVoiceOut *hw, int live); - int (*ctl_out) (HWVoiceOut *hw, int cmd, ...); + int (*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque); + void (*fini_out)(HWVoiceOut *hw); + int (*run_out) (HWVoiceOut *hw, int live); + size_t (*write) (HWVoiceOut *hw, void *buf, size_t size); + /* + * get a buffer that after later can be passed to put_buffer_out; optional + * returns the buffer, and writes it's size to size (in bytes) + * this is unrelated to the above buffer_size_out function + */ + void *(*get_buffer_out)(HWVoiceOut *hw, size_t *size); + /* + * put back the buffer returned by get_buffer_out; optional + * buf must be equal the pointer returned by get_buffer_out, + * size may be smaller + */ + size_t (*put_buffer_out)(HWVoiceOut *hw, void *buf, size_t size); + int (*ctl_out) (HWVoiceOut *hw, int cmd, ...); - int (*init_in) (HWVoiceIn *hw, struct audsettings *as, void *drv_opaque); - void (*fini_in) (HWVoiceIn *hw); - int (*run_in) (HWVoiceIn *hw); - int (*ctl_in) (HWVoiceIn *hw, int cmd, ...); + int (*init_in) (HWVoiceIn *hw, audsettings *as, void *drv_opaque); + void (*fini_in) (HWVoiceIn *hw); + int (*run_in) (HWVoiceIn *hw); + size_t (*read) (HWVoiceIn *hw, void *buf, size_t size); + void *(*get_buffer_in)(HWVoiceIn *hw, size_t *size); + void (*put_buffer_in)(HWVoiceIn *hw, void *buf, size_t size); + int (*ctl_in) (HWVoiceIn *hw, int cmd, ...); }; +void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size); +void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size); +void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size); +size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size); +size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf, + size_t size); +size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size); +size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size); + struct capture_callback { struct audio_capture_ops ops; void *opaque; diff --git a/audio/audio_template.h b/audio/audio_template.h index fecbf1a046..33cdb66d7f 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -71,6 +71,7 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s, static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw) { + g_free(hw->buf_emul); g_free (HWBUF); HWBUF = NULL; }