From nobody Mon Feb 9 07:52:53 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1566758916; cv=none; d=zoho.com; s=zohoarc; b=PRZyGp1FAFvCjChouI3vxHnLJC7dsUrhMzXRXJB21+IL65OWt5Cw1uv0eSP0+6i11qmBZ8nfbB6l/WqQktegDnP8XGwffwQ9kA+FxEA0IOualW+PNzpduBrtcGqlKOfbDrQJxdfz0R8uSK0ewDAtKuATYHwE564SM2+vLflegrA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1566758916; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=rsFbVbnzFgbhGTlJO3RN2ZVezjNNoFZHyoBdxLEeg6E=; b=I99/XiAlpquE4iUygvA3PXEsvFMpksWoDt+rIz7LVq/IzAl6LZrSg6LNagUMgF3/gXugnhddSVBbLDOB7REvHj9j43EIXwq51YNUnWJ9ZWYz7uJZTpMsdBpkR6bIKMgXBCKeLAMy31x4e2vIXEoTzoUUZojRktPFWvrn89Zjr9U= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1566758916619667.1188144427178; Sun, 25 Aug 2019 11:48:36 -0700 (PDT) Received: from localhost ([::1]:45694 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1i1xZ4-0002mP-QL for importer@patchew.org; Sun, 25 Aug 2019 14:48:34 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:57641) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1i1xXB-00015I-B3 for qemu-devel@nongnu.org; Sun, 25 Aug 2019 14:46:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1i1xX7-0004jP-FS for qemu-devel@nongnu.org; Sun, 25 Aug 2019 14:46:37 -0400 Received: from mail-qt1-x844.google.com ([2607:f8b0:4864:20::844]:46322) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1i1xX6-0004j7-Ur for qemu-devel@nongnu.org; Sun, 25 Aug 2019 14:46:33 -0400 Received: by mail-qt1-x844.google.com with SMTP id j15so15881678qtl.13 for ; Sun, 25 Aug 2019 11:46:32 -0700 (PDT) Received: from nullptr.home.dirty-ice.org (2a01-036c-0113-61b1-0000-0000-0000-0005.pool6.digikabel.hu. [2a01:36c:113:61b1::5]) by smtp.gmail.com with ESMTPSA id d3sm5348870qtq.32.2019.08.25.11.46.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 25 Aug 2019 11:46:32 -0700 (PDT) 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=rsFbVbnzFgbhGTlJO3RN2ZVezjNNoFZHyoBdxLEeg6E=; b=XyLhndUFC0nEnUyomkOtn434lZtq+Jbufz/Nej+PgeUUj1pOhlJVnhgiaUg+QGZ1oT qE7ffwtPuruwvMII+LvVwU/fqlRtKKL4SUV6z4w+rFUyf7x54P5+ke3MOcDyluTiswU+ VJkt723ZKGaPeCkCzHY20aLd5uz+qrbzGrH9vtiUbhE7ZWEMRGeOepThJmKyt7OfJEf6 sYCre9S+Zn+KCavu+Vdzdlyuoc81SfIpN5MVfxLzhuf1cWfiXan+Py6xhd1vWhdFfF5k 5p0XnfsXXoBeEbXNKsG4QZ/M6Ut34ra0SQi/mJj0hkCLBbRB3N8W/+b+mAizV9ZG2tZp jm4A== 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=rsFbVbnzFgbhGTlJO3RN2ZVezjNNoFZHyoBdxLEeg6E=; b=hjw0AHbzbiTGGzWSXc8REgaN+45xTfvpS6poW7cBy9trXrUSkJzM6InWWJ4dOpunvi ggcumIx0BHUlSpJnVFivcaQEe/AculDBczXGSP6mHKuZUQYEqyLr9Z6u47xP04QJI6Mr 5VbKF8J/KpAg2LK0hTjmvgaeNNudBbL7sj9eKp2bbNBmWY2jnCGvVOZPMbiQXvp5suM7 elqeT/a/l+GyMu5mUeKcGUHT7sd8KnQ3Ezvo0Ee3EEy1ctkH2c/jCXZVooQ9wrAL43T5 qGa6d2XoonWt4CYVuX2JMiT6LiDA6X2vTyHz1yEfVo7NAz/y0n7owkwhCkejZtEWEIqo 5q8Q== X-Gm-Message-State: APjAAAWjXc5kPcrido2AXtpbP3Fthvta4eKMpiyN2iVwZblTcAV1zH9F 1kmWih3VOK/4oq4kM2ZHrT6STfdggdM= X-Google-Smtp-Source: APXvYqwLfHK1tksMp2XqbC9hwlthudRVNHMCgZQ7NTHLdFn1qChEGc192vN1fwiGyO8Dv/V4kH9gJA== X-Received: by 2002:a0c:e1cd:: with SMTP id v13mr12498509qvl.245.1566758792238; Sun, 25 Aug 2019 11:46:32 -0700 (PDT) From: "=?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?=" X-Google-Original-From: =?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?= To: qemu-devel@nongnu.org Date: Sun, 25 Aug 2019 20:46:03 +0200 Message-Id: X-Mailer: git-send-email 2.22.0 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::844 Subject: [Qemu-devel] [PATCH 01/25] audio: api for mixeng code free backends X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Gerd Hoffmann Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Signed-off-by: K=C5=91v=C3=A1g=C3=B3, Zolt=C3=A1n --- audio/audio_int.h | 41 ++++++-- audio/audio_template.h | 1 + audio/audio.c | 211 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 245 insertions(+), 8 deletions(-) diff --git a/audio/audio_int.h b/audio/audio_int.h index a674c5374a..8fb1ca8a8d 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -65,6 +65,8 @@ typedef struct HWVoiceOut { uint64_t ts_helper; =20 struct st_sample *mix_buf; + void *buf_emul; + size_t pos_emul, pending_emul, size_emul; =20 size_t samples; QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; @@ -87,6 +89,8 @@ typedef struct HWVoiceIn { uint64_t ts_helper; =20 struct st_sample *conv_buf; + void *buf_emul; + size_t pos_emul, pending_emul, size_emul; =20 size_t samples; QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head; @@ -147,17 +151,42 @@ struct audio_driver { }; =20 struct audio_pcm_ops { - int (*init_out)(HWVoiceOut *hw, struct audsettings *as, void *drv_opa= que); - void (*fini_out)(HWVoiceOut *hw); + int (*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque); + void (*fini_out)(HWVoiceOut *hw); size_t (*run_out)(HWVoiceOut *hw, size_t live); - int (*ctl_out) (HWVoiceOut *hw, int cmd, ...); + size_t (*write) (HWVoiceOut *hw, void *buf, size_t size); + /* + * get a buffer that after later can be passed to put_buffer_out; opti= onal + * 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, ...); =20 - int (*init_in) (HWVoiceIn *hw, struct audsettings *as, void *drv_opaq= ue); - void (*fini_in) (HWVoiceIn *hw); + int (*init_in) (HWVoiceIn *hw, audsettings *as, void *drv_opaque); + void (*fini_in) (HWVoiceIn *hw); size_t (*run_in)(HWVoiceIn *hw); - int (*ctl_in) (HWVoiceIn *hw, int cmd, ...); + 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, ...); }; =20 +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 2562bf5f00..ff4a173f18 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, =20 static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw) { + g_free(hw->buf_emul); g_free (HWBUF); HWBUF =3D NULL; } diff --git a/audio/audio.c b/audio/audio.c index 7d715332c9..0dfcfeaf06 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -573,6 +573,25 @@ size_t audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm= _buf, return clipped; } =20 +static void audio_pcm_hw_clip_out2(HWVoiceOut *hw, void *pcm_buf, size_t l= en) +{ + size_t clipped =3D 0; + size_t pos =3D hw->rpos; + + while (len) { + st_sample *src =3D hw->mix_buf + pos; + uint8_t *dst =3D advance(pcm_buf, clipped << hw->info.shift); + size_t samples_till_end_of_buf =3D hw->samples - pos; + size_t samples_to_clip =3D MIN(len, samples_till_end_of_buf); + + hw->clip(dst, src, samples_to_clip); + + pos =3D (pos + samples_to_clip) % hw->samples; + len -=3D samples_to_clip; + clipped +=3D samples_to_clip; + } +} + /* * Soft voice (capture) */ @@ -1050,6 +1069,31 @@ static void audio_capture_mix_and_clear(HWVoiceOut *= hw, size_t rpos, mixeng_clear(hw->mix_buf, samples - n); } =20 +static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live) +{ + size_t clipped =3D 0; + + while (live) { + size_t size, decr, proc; + void *buf =3D hw->pcm_ops->get_buffer_out(hw, &size); + + decr =3D MIN(size >> hw->info.shift, live); + audio_pcm_hw_clip_out2(hw, buf, decr); + proc =3D hw->pcm_ops->put_buffer_out(hw, buf, decr << hw->info.shi= ft) >> + hw->info.shift; + + live -=3D proc; + clipped +=3D proc; + hw->rpos =3D (hw->rpos + proc) % hw->samples; + + if (proc =3D=3D 0 || proc < decr) { + break; + } + } + + return clipped; +} + static void audio_run_out (AudioState *s) { HWVoiceOut *hw =3D NULL; @@ -1097,7 +1141,11 @@ static void audio_run_out (AudioState *s) } =20 prev_rpos =3D hw->rpos; - played =3D hw->pcm_ops->run_out (hw, live); + if (hw->pcm_ops->run_out) { + played =3D hw->pcm_ops->run_out(hw, live); + } else { + played =3D audio_pcm_hw_run_out(hw, live); + } replay_audio_out(&played); if (audio_bug(__func__, hw->rpos >=3D hw->samples)) { dolog("hw->rpos=3D%zu hw->samples=3D%zu played=3D%zu\n", @@ -1156,6 +1204,35 @@ static void audio_run_out (AudioState *s) } } =20 +static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples) +{ + size_t conv =3D 0; + + while (samples) { + size_t proc; + size_t size =3D samples << hw->info.shift; + void *buf =3D hw->pcm_ops->get_buffer_in(hw, &size); + + assert((size & hw->info.align) =3D=3D 0); + if (size =3D=3D 0) { + hw->pcm_ops->put_buffer_in(hw, buf, size); + break; + } + + proc =3D MIN(size >> hw->info.shift, + hw->samples - hw->wpos); + + hw->conv(hw->conv_buf + hw->wpos, buf, proc); + hw->wpos =3D (hw->wpos + proc) % hw->samples; + + samples -=3D proc; + conv +=3D proc; + hw->pcm_ops->put_buffer_in(hw, buf, proc << hw->info.shift); + } + + return conv; +} + static void audio_run_in (AudioState *s) { HWVoiceIn *hw =3D NULL; @@ -1165,7 +1242,12 @@ static void audio_run_in (AudioState *s) size_t captured =3D 0, min; =20 if (replay_mode !=3D REPLAY_MODE_PLAY) { - captured =3D hw->pcm_ops->run_in(hw); + if (hw->pcm_ops->run_in) { + captured =3D hw->pcm_ops->run_in(hw); + } else { + captured =3D 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); =20 @@ -1259,12 +1341,137 @@ void audio_run(AudioState *s, const char *msg) #endif } =20 +void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size) +{ + ssize_t start; + + if (unlikely(!hw->buf_emul)) { + size_t calc_size =3D hw->samples << hw->info.shift; + hw->buf_emul =3D g_malloc(calc_size); + hw->size_emul =3D calc_size; + hw->pos_emul =3D hw->pending_emul =3D 0; + } + + while (hw->pending_emul < hw->size_emul) { + size_t read_len =3D MIN(hw->size_emul - hw->pos_emul, + hw->size_emul - hw->pending_emul); + size_t read =3D hw->pcm_ops->read(hw, hw->buf_emul + hw->pos_emul, + read_len); + hw->pending_emul +=3D read; + if (read < read_len) { + break; + } + } + + start =3D ((ssize_t) hw->pos_emul) - hw->pending_emul; + if (start < 0) { + start +=3D hw->size_emul; + } + assert(start >=3D 0 && start < hw->size_emul); + + *size =3D 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 <=3D hw->pending_emul); + hw->pending_emul -=3D size; +} + +void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size) +{ + if (unlikely(!hw->buf_emul)) { + size_t calc_size =3D hw->samples << hw->info.shift; + + hw->buf_emul =3D g_malloc(calc_size); + hw->size_emul =3D calc_size; + hw->pos_emul =3D hw->pending_emul =3D 0; + } + + *size =3D 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 =3D=3D hw->buf_emul + hw->pos_emul && + size + hw->pending_emul <=3D hw->size_emul); + + hw->pending_emul +=3D size; + hw->pos_emul =3D (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 =3D ((ssize_t) hw->pos_emul) - hw->pending_emul; + if (start < 0) { + start +=3D hw->size_emul; + } + assert(start >=3D 0 && start < hw->size_emul); + + write_len =3D MIN(hw->pending_emul, hw->size_emul - start); + + written =3D hw->pcm_ops->write(hw, hw->buf_emul + start, write_len= ); + hw->pending_emul -=3D 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 =3D hw->pcm_ops->get_buffer_out(hw, &dst_size); + copy_size =3D 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 =3D hw->pcm_ops->get_buffer_in(hw, &dst_size); + copy_size =3D 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, bool msg, Audiodev *dev) { s->drv_opaque =3D drv->init(dev); =20 if (s->drv_opaque) { + if (!drv->pcm_ops->get_buffer_in) { + drv->pcm_ops->get_buffer_in =3D audio_generic_get_buffer_in; + drv->pcm_ops->put_buffer_in =3D audio_generic_put_buffer_in; + } + if (!drv->pcm_ops->get_buffer_out) { + drv->pcm_ops->get_buffer_out =3D audio_generic_get_buffer_out; + drv->pcm_ops->put_buffer_out =3D audio_generic_put_buffer_out; + } + audio_init_nb_voices_out(s, drv); audio_init_nb_voices_in(s, drv); s->drv =3D drv; --=20 2.22.0