From patchwork Mon Sep 30 20:28:54 2019 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: 1169604 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="LHQeeonu"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46hvhb1PcJz9sPh for ; Tue, 1 Oct 2019 06:51:43 +1000 (AEST) Received: from localhost ([::1]:57200 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2dw-0006nu-Ka for incoming@patchwork.ozlabs.org; Mon, 30 Sep 2019 16:51:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45718) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2HZ-0003uD-CZ for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:34 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iF2HY-0002Pl-2B for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:33 -0400 Received: from mail-wm1-x32d.google.com ([2a00:1450:4864:20::32d]:37110) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iF2HX-0002O5-Re for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:32 -0400 Received: by mail-wm1-x32d.google.com with SMTP id f22so836368wmc.2 for ; Mon, 30 Sep 2019 13:28:31 -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=Gi6tqrqwXbuZC6QjPDbutYBMsb5dVHxRt4y2Z1LxG9o=; b=LHQeeonu+UaERht6lIMhJK4jRh7bNV1Gsf3JjSST+XuhSYk2l19t7Q7X8oXMir0OPU RP4dGNtTrw1sY++rtg1/thjalbb0WCYYEdsJuanotRzxtMV7c/S8M57Y2JIxu+VSLEBz /Zoa9Cie7jE/j4Pehi4dKO16Cz1rUoKDJH1M790dN+6W+Rr0mZxZVKtLlO6xkPWi0g+y ifcR9yk2a8p46O61ARMy0Yo0hnCR7+2kHqKfke+y5rkoTFTNzS7A8qRE/fbXa6+vj2AG TSxEROTcq1WgEVOtI4ja2/uxX3xvdb0qocd5wP+QZAbI1AM9aAKD5adjtO8pgczZo3sK s5ig== 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=Gi6tqrqwXbuZC6QjPDbutYBMsb5dVHxRt4y2Z1LxG9o=; b=EnpBbqeGXG6xkgUOOAMewObQS+NYHkRy2b9rZHbnTiKKNjzLpmd/xlYoLIctVhL7Q0 nMmSC3ZdzsQZCAvxIOhHmIY0ChexLastJDEygnLOayemDlTe4TqJTSxYg3TxMOt7/Zgx EYyq4i7DwCloy7jBm7azyaJCDjsQ0dNPsDzFlMXVgr/4Le0qf4807rZtjkALpZ6/wSRU 7qh4C8mmJP4H2hjPMAswNL8Rp6rNTtuuAbod06VNH4vy8NhMvjx35yZq1ou2DLh2pt5s W3TpntWaYeUx548A6NtL8vblWFQThirQ3r3Rhry1WnpEgZgiNyd3oEPwFIuq95q5589v 27ag== X-Gm-Message-State: APjAAAVxmliU1NZ3EIOhnkir78VfJpfIOMoNuBRGmeu6WhuNDsz4MgVU 7tC01vOwa7QUr8UtTzScakTtAMl1 X-Google-Smtp-Source: APXvYqxVWOgy2+OXMRbM2Q9Ny2Obpiy1mZGZ0ZdHd9W7ycj+eW/B81J3A5n6vHGX5Bra9h9LCDuF/A== X-Received: by 2002:a05:600c:2059:: with SMTP id p25mr799742wmg.50.1569875310676; Mon, 30 Sep 2019 13:28:30 -0700 (PDT) Received: from nullptr.home.dirty-ice.org (2a01-036c-0113-e8f4-0000-0000-0000-0005.pool6.digikabel.hu. [2a01:36c:113:e8f4::5]) by smtp.gmail.com with ESMTPSA id o9sm34402911wrh.46.2019.09.30.13.28.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Sep 2019 13:28:30 -0700 (PDT) From: "=?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?=" X-Google-Original-From: =?utf-8?b?S8WRdsOhZ8OzLCBab2x0w6Fu?= To: qemu-devel@nongnu.org Subject: [PATCH v5 01/10] audio: add mixing-engine option (documentation) Date: Mon, 30 Sep 2019 22:28:54 +0200 Message-Id: X-Mailer: git-send-email 2.23.0 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::32d 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 , Markus Armbruster Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This will allow us to disable mixeng when we use a decent backend. Disabling mixeng have a few advantages: * we no longer convert the audio output from one format to another, when the underlying audio system would just convert it to a third format. We no longer convert, only the underlying system, when needed. * the underlying system probably has better resampling and sample format converting methods anyway... * we may support formats that the mixeng currently does not support (S24 or float samples, more than two channels) * when using an audio server (like pulseaudio) different sound card outputs will show up as separate streams, even if we use only one backend Disadvantages: * audio capturing no longer works (wavcapture, and vnc audio extension) * some backends only support a single playback stream or very picky about the audio format. In this case we can't disable mixeng. However mixeng is not removed, only made optional, so this shouldn't be a big concern. Signed-off-by: Kővágó, Zoltán --- Notes: Changes from v1: * renamed mixeng to mixing-engine qapi/audio.json | 5 +++++ qemu-options.hx | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/qapi/audio.json b/qapi/audio.json index 9fefdf5186..0996705954 100644 --- a/qapi/audio.json +++ b/qapi/audio.json @@ -11,6 +11,10 @@ # General audio backend options that are used for both playback and # recording. # +# @mixing-engine: use QEMU's mixing engine to mix all streams inside QEMU. When +# set to off, fixed-settings must be also off. Not every backend +# is compatible with the off setting (default on, since 4.2) +# # @fixed-settings: use fixed settings for host input/output. When off, # frequency, channels and format must not be # specified (default true) @@ -31,6 +35,7 @@ ## { 'struct': 'AudiodevPerDirectionOptions', 'data': { + '*mixing-engine': 'bool', '*fixed-settings': 'bool', '*frequency': 'uint32', '*channels': 'uint32', diff --git a/qemu-options.hx b/qemu-options.hx index 2a04ca6ac5..3e50956f48 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -433,6 +433,7 @@ DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev, " specifies the audio backend to use\n" " id= identifier of the backend\n" " timer-period= timer period in microseconds\n" + " in|out.mixing-engine= use mixing engine to mix streams inside QEMU\n" " in|out.fixed-settings= use fixed settings for host audio\n" " in|out.frequency= frequency to use with fixed settings\n" " in|out.channels= number of channels to use with fixed settings\n" @@ -503,6 +504,11 @@ Identifies the audio backend. Sets the timer @var{period} used by the audio subsystem in microseconds. Default is 10000 (10 ms). +@item in|out.mixing-engine=on|off +Use QEMU's mixing engine to mix all streams inside QEMU. When off, +@var{fixed-settings} must be off too. Not every backend is fully +compatible with the off setting. Default is on. + @item in|out.fixed-settings=on|off Use fixed settings for host audio. When off, it will change based on how the guest opens the sound card. In this case you must not specify From patchwork Mon Sep 30 20:28:55 2019 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: 1169614 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="CBvlbTH0"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46hvnX577Vz9sPd for ; Tue, 1 Oct 2019 06:56:00 +1000 (AEST) Received: from localhost ([::1]:57226 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2i4-0001uX-U0 for incoming@patchwork.ozlabs.org; Mon, 30 Sep 2019 16:55:56 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45736) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2Ha-0003w2-T3 for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iF2HZ-0002Rm-4n for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:34 -0400 Received: from mail-wm1-x343.google.com ([2a00:1450:4864:20::343]:38590) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iF2HY-0002QW-Rj for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:33 -0400 Received: by mail-wm1-x343.google.com with SMTP id 3so833395wmi.3 for ; Mon, 30 Sep 2019 13:28: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=Pbln1L0UWMrKENno8JQoLEo0GwL8LqG6fEqEAAIjnjc=; b=CBvlbTH0xVU5+l/kL9BYNiQiImTMYQJDeWGnohsEnkopLIMk3jlT5Cg82ddJy9g1p3 bvzWbjqkmnC41MOzvU1rvZ0/UEu3FXs1J0i5PkBSwcj5J/Ye9r5HqPY79z8Eh1KUDxR/ Xy5Py/vHS7tvtRhis7wets/FI+j2ZL8IkmF/PoGpV42q/AXTVUZ0sN/w7L1VoRtZN3aY vHLKj3Lis5FcRKt2dMgnKqg7/scaVG8T5KL+Z5FhtxaEdvU+6FrblbapvA3Dy6cpQw1+ ZwD3EulfYP2I2JuCgcbnpO0SMLiusiWMcBb+fzlJOEzL9pzPifW69V4aTwPHOTzuxU27 SKUQ== 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=Pbln1L0UWMrKENno8JQoLEo0GwL8LqG6fEqEAAIjnjc=; b=AtxhEgg/C7+u7LxHqlqQPF/Cf72D+db7SdmMokbwnuKgMLKSnackrj6FRdToTnOWFR pxG6yk8W4lt78LIH6EW/JjZ53ljoEqSxkgZb4/GCvenIW0QaL9wVduiolEAmNj352AZY SzgyD1E4LzOEt/cx9WyJg21ZaIM/gleUuGxctWd4k1r8VVFkQYe9/6jGm3cNue8/OQ0t KXS+COAusoHVRq66EKIdwIH14XqElvxXLa7/L/yNx3kG0ajKbSu+I+ygfgqM4AKmNlZB ridLtAZ2MYarWiGcpYFfBQSLjni7fdP7x+BFUQx3MiRg1afs4dGRR/SAeTzPrAlriudS dUkg== X-Gm-Message-State: APjAAAXoesstejnLZW8c/NZQJORC2R5/L1iucmPlyemNdwgLyd9PNt0I Nbu+D0qV27lbf0j6L9x/br387HYh X-Google-Smtp-Source: APXvYqxTe/6+1CcG5OCThnMCSbGjvNZ79yVpe1CPvm17ALNEpo7/pk/sZ4f7mpqOgdB+j7Y9jNMC0w== X-Received: by 2002:a1c:4c12:: with SMTP id z18mr707090wmf.45.1569875311576; Mon, 30 Sep 2019 13:28:31 -0700 (PDT) Received: from nullptr.home.dirty-ice.org (2a01-036c-0113-e8f4-0000-0000-0000-0005.pool6.digikabel.hu. [2a01:36c:113:e8f4::5]) by smtp.gmail.com with ESMTPSA id o9sm34402911wrh.46.2019.09.30.13.28.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Sep 2019 13:28:31 -0700 (PDT) From: "=?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?=" X-Google-Original-From: =?utf-8?b?S8WRdsOhZ8OzLCBab2x0w6Fu?= To: qemu-devel@nongnu.org Subject: [PATCH v5 02/10] audio: make mixeng optional Date: Mon, 30 Sep 2019 22:28:55 +0200 Message-Id: <2560ebbb34576c29c4b9deaf3a7444b6b9506428.1569874641.git.DirtY.iCE.hu@gmail.com> X-Mailer: git-send-email 2.23.0 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::343 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Implementation of the previously added mixing-engine option. Signed-off-by: Kővágó, Zoltán --- Notes: Changes from v4: * audio_pcm_hw_add_* always returns a new HW (or fails) when not using mixeng audio/audio.c | 70 ++++++++++++++++++++++++++++++++++++++---- audio/audio_template.h | 24 ++++++++++----- 2 files changed, 80 insertions(+), 14 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 7128ee98dc..d616a4af98 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -838,32 +838,46 @@ static void audio_timer (void *opaque) */ size_t AUD_write(SWVoiceOut *sw, void *buf, size_t size) { + HWVoiceOut *hw; + if (!sw) { /* XXX: Consider options */ return size; } + hw = sw->hw; - if (!sw->hw->enabled) { + if (!hw->enabled) { dolog ("Writing to disabled voice %s\n", SW_NAME (sw)); return 0; } - return audio_pcm_sw_write(sw, buf, size); + if (audio_get_pdo_out(hw->s->dev)->mixing_engine) { + return audio_pcm_sw_write(sw, buf, size); + } else { + return hw->pcm_ops->write(hw, buf, size); + } } size_t AUD_read(SWVoiceIn *sw, void *buf, size_t size) { + HWVoiceIn *hw; + if (!sw) { /* XXX: Consider options */ return size; } + hw = sw->hw; - if (!sw->hw->enabled) { + if (!hw->enabled) { dolog ("Reading from disabled voice %s\n", SW_NAME (sw)); return 0; } - return audio_pcm_sw_read(sw, buf, size); + if (audio_get_pdo_in(hw->s->dev)->mixing_engine) { + return audio_pcm_sw_read(sw, buf, size); + } else { + return hw->pcm_ops->read(hw, buf, size); + } } int AUD_get_buffer_size_out (SWVoiceOut *sw) @@ -1090,6 +1104,26 @@ static void audio_run_out (AudioState *s) HWVoiceOut *hw = NULL; SWVoiceOut *sw; + if (!audio_get_pdo_out(s->dev)->mixing_engine) { + while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) { + /* there is exactly 1 sw for each hw with no mixeng */ + sw = hw->sw_head.lh_first; + + if (hw->pending_disable) { + hw->enabled = 0; + hw->pending_disable = 0; + if (hw->pcm_ops->enable_out) { + hw->pcm_ops->enable_out(hw, false); + } + } + + if (sw->active) { + sw->callback.fn(sw->callback.opaque, INT_MAX); + } + } + return; + } + while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) { size_t played, live, prev_rpos, free; int nb_live, cleanup_required; @@ -1227,6 +1261,17 @@ static void audio_run_in (AudioState *s) { HWVoiceIn *hw = NULL; + if (!audio_get_pdo_in(s->dev)->mixing_engine) { + while ((hw = audio_pcm_hw_find_any_enabled_in(s, hw))) { + /* there is exactly 1 sw for each hw with no mixeng */ + SWVoiceIn *sw = hw->sw_head.lh_first; + if (sw->active) { + sw->callback.fn(sw->callback.opaque, INT_MAX); + } + } + return; + } + while ((hw = audio_pcm_hw_find_any_enabled_in(s, hw))) { SWVoiceIn *sw; size_t captured = 0, min; @@ -1751,6 +1796,11 @@ CaptureVoiceOut *AUD_add_capture( s = audio_init(NULL, NULL); } + if (!audio_get_pdo_out(s->dev)->mixing_engine) { + dolog("Can't capture with mixeng disabled\n"); + return NULL; + } + if (audio_validate_settings (as)) { dolog ("Invalid settings were passed when trying to add capture\n"); audio_print_settings (as); @@ -1905,9 +1955,13 @@ void audio_create_pdos(Audiodev *dev) static void audio_validate_per_direction_opts( AudiodevPerDirectionOptions *pdo, Error **errp) { + if (!pdo->has_mixing_engine) { + pdo->has_mixing_engine = true; + pdo->mixing_engine = true; + } if (!pdo->has_fixed_settings) { pdo->has_fixed_settings = true; - pdo->fixed_settings = true; + pdo->fixed_settings = pdo->mixing_engine; } if (!pdo->fixed_settings && (pdo->has_frequency || pdo->has_channels || pdo->has_format)) { @@ -1915,6 +1969,10 @@ static void audio_validate_per_direction_opts( "You can't use frequency, channels or format with fixed-settings=off"); return; } + if (!pdo->mixing_engine && pdo->fixed_settings) { + error_setg(errp, "You can't use fixed-settings without mixeng"); + return; + } if (!pdo->has_frequency) { pdo->has_frequency = true; @@ -1926,7 +1984,7 @@ static void audio_validate_per_direction_opts( } if (!pdo->has_voices) { pdo->has_voices = true; - pdo->voices = 1; + pdo->voices = pdo->mixing_engine ? 1 : INT_MAX; } if (!pdo->has_format) { pdo->has_format = true; diff --git a/audio/audio_template.h b/audio/audio_template.h index 235d1acbbe..3709a4431c 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -78,13 +78,17 @@ static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw) static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw) { - size_t samples = hw->samples; - if (audio_bug(__func__, samples == 0)) { - dolog("Attempted to allocate empty buffer\n"); - } + if (glue(audio_get_pdo_, TYPE)(hw->s->dev)->mixing_engine) { + size_t samples = hw->samples; + if (audio_bug(__func__, samples == 0)) { + dolog("Attempted to allocate empty buffer\n"); + } - HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample) * samples); - HWBUF->size = samples; + HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample) * samples); + HWBUF->size = samples; + } else { + HWBUF = NULL; + } } static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw) @@ -103,6 +107,10 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw) { int samples; + if (!glue(audio_get_pdo_, TYPE)(sw->s->dev)->mixing_engine) { + return 0; + } + samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio; sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample)); @@ -328,9 +336,9 @@ static HW *glue(audio_pcm_hw_add_, TYPE)(AudioState *s, struct audsettings *as) HW *hw; AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev); - if (pdo->fixed_settings) { + if (!pdo->mixing_engine || pdo->fixed_settings) { hw = glue(audio_pcm_hw_add_new_, TYPE)(s, as); - if (hw) { + if (!pdo->mixing_engine || hw) { return hw; } } From patchwork Mon Sep 30 20:28:56 2019 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: 1169608 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="DkfgoKqK"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46hvkc4cgdz9sPd for ; Tue, 1 Oct 2019 06:53:28 +1000 (AEST) Received: from localhost ([::1]:57212 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2fe-0008WQ-EI for incoming@patchwork.ozlabs.org; Mon, 30 Sep 2019 16:53:26 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45740) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2Hb-0003wi-BA for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iF2HZ-0002U2-RS for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:35 -0400 Received: from mail-wm1-x344.google.com ([2a00:1450:4864:20::344]:37831) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iF2HZ-0002R9-I5 for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:33 -0400 Received: by mail-wm1-x344.google.com with SMTP id f22so836428wmc.2 for ; Mon, 30 Sep 2019 13:28:33 -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=i9UxN713GW0ghifGTVMxk9JG2fJFSnFStux97zyYILs=; b=DkfgoKqK7dUSBf8DHGmdEG6tdSreHj+ZunbCOOpgDN9BUFiobccFSYyI36qNmUcSLu m6akWDsS1jbA0dwrYYLn69g7Rw7RSsbAKRwDALO9fRkCB3ZYbcym/1QQZeDb+wyRWm6W V53k3VtDIzleCogzQrjWQh1cZB6h/2a8Bgvu+8B1UHsY7ksRgl/SdydZsyitcjx5YcNs asctDADf1nAI9r+eMSHlg2RDNtXVjUGrdHPhcNIv7Twjq+OMhNQTC3rHS1E4ieRy0kOI MMTKZBoKSRM7+Wd8BeNBPMqZFPP0PrxHIuMIffMhjHGtinivuGy1pjIopXsAje8vE0cn hg2g== 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=i9UxN713GW0ghifGTVMxk9JG2fJFSnFStux97zyYILs=; b=eJ8FoWpSZFXkG3kmYpPpeDN0/t1Q095HVkXV8xFMH9jg/prVO2vZdBriQHktzNc4jX JEuOmP2JWN0h8PIb4uWJ207kVxGHCUmaOmDdIcLbwz3PmQvjTltsuIPgEUayw5VUqxQx Kdchukm43FBCS+OY/6zgNb2efVQVRKukYN5osBz1F4nKT0XyyM9t79G+9dfbMRKgplqt j93NSSMLfym2/kZqaZUnRaE8bTDuAfmcky//tt4Q8hQXeTMXQebq8qb0RXmlFdNpj+k7 SYVCIQSngmZEhH5Nx9E/6YeLIsgnQGDqNYGgarAhOF+IktMob4CAjq5ERorhh3QxLB1E 5ikQ== X-Gm-Message-State: APjAAAXO+QFEQN6ZHwE18iNiWm+YAGI6ckgVMyq7JB1rLskzKpr78kWx J7bKkGWxfUvCWic6mknk1ez/bJsA X-Google-Smtp-Source: APXvYqyxlEvHNoSfuwsTkH3DHCQ3xw9bC9RnaPTjICSkZtA1cJC4jFY8PdzIMuhRWjjQjkR76YqPHQ== X-Received: by 2002:a7b:c156:: with SMTP id z22mr786150wmi.142.1569875312365; Mon, 30 Sep 2019 13:28:32 -0700 (PDT) Received: from nullptr.home.dirty-ice.org (2a01-036c-0113-e8f4-0000-0000-0000-0005.pool6.digikabel.hu. [2a01:36c:113:e8f4::5]) by smtp.gmail.com with ESMTPSA id o9sm34402911wrh.46.2019.09.30.13.28.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Sep 2019 13:28:31 -0700 (PDT) From: "=?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?=" X-Google-Original-From: =?utf-8?b?S8WRdsOhZ8OzLCBab2x0w6Fu?= To: qemu-devel@nongnu.org Subject: [PATCH v5 03/10] paaudio: get/put_buffer functions Date: Mon, 30 Sep 2019 22:28:56 +0200 Message-Id: X-Mailer: git-send-email 2.23.0 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::344 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This lets us avoid some buffer copying when using mixeng. Signed-off-by: Kővágó, Zoltán --- audio/paaudio.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/audio/paaudio.c b/audio/paaudio.c index ed31f863f7..6ccdf31415 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -98,6 +98,59 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) } \ } while (0) +static void *qpa_get_buffer_in(HWVoiceIn *hw, size_t *size) +{ + PAVoiceIn *p = (PAVoiceIn *) hw; + PAConnection *c = p->g->conn; + int r; + + pa_threaded_mainloop_lock(c->mainloop); + + CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail, + "pa_threaded_mainloop_lock failed\n"); + + if (!p->read_length) { + r = pa_stream_peek(p->stream, &p->read_data, &p->read_length); + CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail, + "pa_stream_peek failed\n"); + } + + *size = MIN(p->read_length, *size); + + pa_threaded_mainloop_unlock(c->mainloop); + return (void *) p->read_data; + +unlock_and_fail: + pa_threaded_mainloop_unlock(c->mainloop); + *size = 0; + return NULL; +} + +static void qpa_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size) +{ + PAVoiceIn *p = (PAVoiceIn *) hw; + PAConnection *c = p->g->conn; + int r; + + pa_threaded_mainloop_lock(c->mainloop); + + CHECK_DEAD_GOTO(c, p->stream, unlock, + "pa_threaded_mainloop_lock failed\n"); + + assert(buf == p->read_data && size <= p->read_length); + + p->read_data += size; + p->read_length -= size; + + if (size && !p->read_length) { + r = pa_stream_drop(p->stream); + CHECK_SUCCESS_GOTO(c, r == 0, unlock, "pa_stream_drop failed\n"); + } + +unlock: + pa_threaded_mainloop_unlock(c->mainloop); +} + static size_t qpa_read(HWVoiceIn *hw, void *data, size_t length) { PAVoiceIn *p = (PAVoiceIn *) hw; @@ -136,6 +189,32 @@ unlock_and_fail: return 0; } +static void *qpa_get_buffer_out(HWVoiceOut *hw, size_t *size) +{ + PAVoiceOut *p = (PAVoiceOut *) hw; + PAConnection *c = p->g->conn; + void *ret; + int r; + + pa_threaded_mainloop_lock(c->mainloop); + + CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail, + "pa_threaded_mainloop_lock failed\n"); + + *size = -1; + r = pa_stream_begin_write(p->stream, &ret, size); + CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail, + "pa_stream_begin_write failed\n"); + + pa_threaded_mainloop_unlock(c->mainloop); + return ret; + +unlock_and_fail: + pa_threaded_mainloop_unlock(c->mainloop); + *size = 0; + return NULL; +} + static size_t qpa_write(HWVoiceOut *hw, void *data, size_t length) { PAVoiceOut *p = (PAVoiceOut *) hw; @@ -698,11 +777,15 @@ static struct audio_pcm_ops qpa_pcm_ops = { .init_out = qpa_init_out, .fini_out = qpa_fini_out, .write = qpa_write, + .get_buffer_out = qpa_get_buffer_out, + .put_buffer_out = qpa_write, /* pa handles it */ .volume_out = qpa_volume_out, .init_in = qpa_init_in, .fini_in = qpa_fini_in, .read = qpa_read, + .get_buffer_in = qpa_get_buffer_in, + .put_buffer_in = qpa_put_buffer_in, .volume_in = qpa_volume_in }; From patchwork Mon Sep 30 20:28:57 2019 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: 1169616 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="ms10rP32"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46hvqw4h1dz9sPd for ; Tue, 1 Oct 2019 06:58:04 +1000 (AEST) Received: from localhost ([::1]:57244 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2k6-0003qG-FR for incoming@patchwork.ozlabs.org; Mon, 30 Sep 2019 16:58:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45755) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2Hc-0003yS-MP for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iF2Ha-0002Vd-Tt for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:36 -0400 Received: from mail-wm1-x344.google.com ([2a00:1450:4864:20::344]:38591) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iF2Ha-0002Ud-N8 for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:34 -0400 Received: by mail-wm1-x344.google.com with SMTP id 3so833478wmi.3 for ; Mon, 30 Sep 2019 13:28:34 -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=hBNbSNYdRxpi4YPwJzeBrQcOF4eLYJl4drOoaIZgmh0=; b=ms10rP32sZnKeZos9wbQQvyQTYP6hSSoy+PMIevApEBnDnUCH+U5N7lOwn7zJ8i8OP J55/UoehyuqCkjnXh3za+clSmtD1E2yfIeBThT3SDWXKqaLjZj50BXew8o6Vot/SMxl+ 4PsIcHim/l16Nj4Lxfbg8YT2ZF8V7TOVNTGT0SOQTQnv6ETypwjD1b4rwCr214678Ld8 jYHdiK/ekYkPTy1UmtSpOatUL8h2n9m8LDAB8kFp0JCUfDrgLv3UrUH6iqIukKt2KYPT E2nEQLlkjeKGEByif/zfbbOVeb/pPnapJx8SJohGvmycOilTlYOqYhJ7xo/KegZMzhky Ej9A== 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=hBNbSNYdRxpi4YPwJzeBrQcOF4eLYJl4drOoaIZgmh0=; b=jl4tadNzrmdNovqktNIIIVG4d8RULhMcN0qo2EtSpaQwDLtTPPQNah0Xee6bLRl70k ss1lBE18PY1kWECF+FIRK/tpOX2oEUmcVMAkqikeuGW7ECWFhBj0rDef3g8YPYC0+xj0 9bizGsORIh7mc3FFs6Dfl92+IrrmUw4YgYkTsByx9bEYlfkquS6fZXpMyAxsT+TTXsBM Akitfx7WAyvV3sp5koFvo/XcHBzMdJHtoYGGKt+JSyjzJIyyV7TfRKXS9LyYAWldCk8Y 0iEV+nbTSdmVwRw+qWz9j4JFLSOd7iJHTvCAJE2y5/d+OVhki0OydBC6wEUDYr40h9Z1 ry8g== X-Gm-Message-State: APjAAAX2+oajA7ubydDTvckZSudbkWkVS5B2ZS2s9Zk3CZvWreMeuiS0 PGZlBOyG9TtBqtSSoQ7x6O5PCEiD X-Google-Smtp-Source: APXvYqxV07HUGkoTkODvSYUa+KlfTCGIZlDoSdzjRr9FO28wFueltvftI7x4Vq7woC9DnPl5tBOiZw== X-Received: by 2002:a1c:4384:: with SMTP id q126mr768052wma.153.1569875313494; Mon, 30 Sep 2019 13:28:33 -0700 (PDT) Received: from nullptr.home.dirty-ice.org (2a01-036c-0113-e8f4-0000-0000-0000-0005.pool6.digikabel.hu. [2a01:36c:113:e8f4::5]) by smtp.gmail.com with ESMTPSA id o9sm34402911wrh.46.2019.09.30.13.28.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Sep 2019 13:28:32 -0700 (PDT) From: "=?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?=" X-Google-Original-From: =?utf-8?b?S8WRdsOhZ8OzLCBab2x0w6Fu?= To: qemu-devel@nongnu.org Subject: [PATCH v5 04/10] audio: support more than two channels in volume setting Date: Mon, 30 Sep 2019 22:28:57 +0200 Message-Id: <5b043a6e1895f78f83e0597aec878635f087ad71.1569874641.git.DirtY.iCE.hu@gmail.com> X-Mailer: git-send-email 2.23.0 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::344 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Kővágó, Zoltán --- audio/audio.c | 30 ++++++++++++++++++++++-------- audio/audio.h | 10 ++++++++++ audio/audio_int.h | 4 ++-- audio/paaudio.c | 20 ++++++++++++-------- audio/spiceaudio.c | 14 ++++++++------ 5 files changed, 54 insertions(+), 24 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index d616a4af98..f1c145dfcd 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1891,31 +1891,45 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) } void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol) +{ + Volume vol = { .mute = mute, .channels = 2, .vol = { lvol, rvol } }; + audio_set_volume_out(sw, &vol); +} + +void audio_set_volume_out(SWVoiceOut *sw, Volume *vol) { if (sw) { HWVoiceOut *hw = sw->hw; - sw->vol.mute = mute; - sw->vol.l = nominal_volume.l * lvol / 255; - sw->vol.r = nominal_volume.r * rvol / 255; + sw->vol.mute = vol->mute; + sw->vol.l = nominal_volume.l * vol->vol[0] / 255; + sw->vol.r = nominal_volume.l * vol->vol[vol->channels > 1 ? 1 : 0] / + 255; if (hw->pcm_ops->volume_out) { - hw->pcm_ops->volume_out(hw, &sw->vol); + hw->pcm_ops->volume_out(hw, vol); } } } void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) +{ + Volume vol = { .mute = mute, .channels = 2, .vol = { lvol, rvol } }; + audio_set_volume_in(sw, &vol); +} + +void audio_set_volume_in(SWVoiceIn *sw, Volume *vol) { if (sw) { HWVoiceIn *hw = sw->hw; - sw->vol.mute = mute; - sw->vol.l = nominal_volume.l * lvol / 255; - sw->vol.r = nominal_volume.r * rvol / 255; + sw->vol.mute = vol->mute; + sw->vol.l = nominal_volume.l * vol->vol[0] / 255; + sw->vol.r = nominal_volume.r * vol->vol[vol->channels > 1 ? 1 : 0] / + 255; if (hw->pcm_ops->volume_in) { - hw->pcm_ops->volume_in(hw, &sw->vol); + hw->pcm_ops->volume_in(hw, vol); } } } diff --git a/audio/audio.h b/audio/audio.h index c74abb8c47..0db3c7dd5e 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -124,6 +124,16 @@ uint64_t AUD_get_elapsed_usec_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts); void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol); void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol); +#define AUDIO_MAX_CHANNELS 16 +typedef struct Volume { + bool mute; + int channels; + uint8_t vol[AUDIO_MAX_CHANNELS]; +} Volume; + +void audio_set_volume_out(SWVoiceOut *sw, Volume *vol); +void audio_set_volume_in(SWVoiceIn *sw, Volume *vol); + SWVoiceIn *AUD_open_in ( QEMUSoundCard *card, SWVoiceIn *sw, diff --git a/audio/audio_int.h b/audio/audio_int.h index 22a703c13e..9176db249b 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -166,7 +166,7 @@ struct audio_pcm_ops { */ size_t (*put_buffer_out)(HWVoiceOut *hw, void *buf, size_t size); void (*enable_out)(HWVoiceOut *hw, bool enable); - void (*volume_out)(HWVoiceOut *hw, struct mixeng_volume *vol); + void (*volume_out)(HWVoiceOut *hw, Volume *vol); int (*init_in) (HWVoiceIn *hw, audsettings *as, void *drv_opaque); void (*fini_in) (HWVoiceIn *hw); @@ -174,7 +174,7 @@ struct audio_pcm_ops { void *(*get_buffer_in)(HWVoiceIn *hw, size_t *size); void (*put_buffer_in)(HWVoiceIn *hw, void *buf, size_t size); void (*enable_in)(HWVoiceIn *hw, bool enable); - void (*volume_in)(HWVoiceIn *hw, struct mixeng_volume *vol); + void (*volume_in)(HWVoiceIn *hw, Volume *vol); }; void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size); diff --git a/audio/paaudio.c b/audio/paaudio.c index 6ccdf31415..d195b1caa8 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -531,20 +531,22 @@ static void qpa_fini_in (HWVoiceIn *hw) } } -static void qpa_volume_out(HWVoiceOut *hw, struct mixeng_volume *vol) +static void qpa_volume_out(HWVoiceOut *hw, Volume *vol) { PAVoiceOut *pa = (PAVoiceOut *) hw; pa_operation *op; pa_cvolume v; PAConnection *c = pa->g->conn; + int i; #ifdef PA_CHECK_VERSION /* macro is present in 0.9.16+ */ pa_cvolume_init (&v); /* function is present in 0.9.13+ */ #endif - v.channels = 2; - v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->l) / UINT32_MAX; - v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->r) / UINT32_MAX; + v.channels = vol->channels; + for (i = 0; i < vol->channels; ++i) { + v.values[i] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->vol[i]) / 255; + } pa_threaded_mainloop_lock(c->mainloop); @@ -571,20 +573,22 @@ static void qpa_volume_out(HWVoiceOut *hw, struct mixeng_volume *vol) pa_threaded_mainloop_unlock(c->mainloop); } -static void qpa_volume_in(HWVoiceIn *hw, struct mixeng_volume *vol) +static void qpa_volume_in(HWVoiceIn *hw, Volume *vol) { PAVoiceIn *pa = (PAVoiceIn *) hw; pa_operation *op; pa_cvolume v; PAConnection *c = pa->g->conn; + int i; #ifdef PA_CHECK_VERSION pa_cvolume_init (&v); #endif - v.channels = 2; - v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->l) / UINT32_MAX; - v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->r) / UINT32_MAX; + v.channels = vol->channels; + for (i = 0; i < vol->channels; ++i) { + v.values[i] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->vol[i]) / 255; + } pa_threaded_mainloop_lock(c->mainloop); diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c index 9860f9c5e1..6ed7f7a79e 100644 --- a/audio/spiceaudio.c +++ b/audio/spiceaudio.c @@ -179,13 +179,14 @@ static void line_out_enable(HWVoiceOut *hw, bool enable) } #if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) -static void line_out_volume(HWVoiceOut *hw, struct mixeng_volume *vol) +static void line_out_volume(HWVoiceOut *hw, Volume *vol) { SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); uint16_t svol[2]; - svol[0] = vol->l / ((1ULL << 16) + 1); - svol[1] = vol->r / ((1ULL << 16) + 1); + assert(vol->channels == 2); + svol[0] = vol->vol[0] * 257; + svol[1] = vol->vol[1] * 257; spice_server_playback_set_volume(&out->sin, 2, svol); spice_server_playback_set_mute(&out->sin, vol->mute); } @@ -262,13 +263,14 @@ static void line_in_enable(HWVoiceIn *hw, bool enable) } #if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2)) -static void line_in_volume(HWVoiceIn *hw, struct mixeng_volume *vol) +static void line_in_volume(HWVoiceIn *hw, Volume *vol) { SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw); uint16_t svol[2]; - svol[0] = vol->l / ((1ULL << 16) + 1); - svol[1] = vol->r / ((1ULL << 16) + 1); + assert(vol->channels == 2); + svol[0] = vol->vol[0] * 257; + svol[1] = vol->vol[1] * 257; spice_server_record_set_volume(&in->sin, 2, svol); spice_server_record_set_mute(&in->sin, vol->mute); } From patchwork Mon Sep 30 20:28:58 2019 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: 1169606 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="TYUf3b1V"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46hvjZ6zPmz9sPd for ; Tue, 1 Oct 2019 06:52:34 +1000 (AEST) Received: from localhost ([::1]:57204 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2em-0007Nu-PQ for incoming@patchwork.ozlabs.org; Mon, 30 Sep 2019 16:52:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45784) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2He-00041b-Sq for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iF2Hc-0002Xg-6e for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:38 -0400 Received: from mail-wr1-x442.google.com ([2a00:1450:4864:20::442]:42180) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iF2Hb-0002WT-Sy for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:36 -0400 Received: by mail-wr1-x442.google.com with SMTP id n14so12800074wrw.9 for ; Mon, 30 Sep 2019 13:28:35 -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=FZBJxE6vgXiUYQRHq25EgBqFYd27odUS2eGRI60cvzc=; b=TYUf3b1VTt6VzE1H+xC99Spq0bTy9N5bXEIZVoyGKy9ieCo1AeYbqt1R6h4CXc1u32 11fHAGeOAAbUe9jic62VeoeX1ldDt0q9ux77TXxCxLDyeEKW0SaW38FbBRRsMYdVFjVY E4vQT7wq722J3LHxBENnglWJs7qBVWEAQ0VE3h0LXqHECWTH1sCpiJunPgaXNhTXbV8x RlNl2ld/77/Ma1GRR54G/NzRBFPNzSt5iatl2IRx/2LRFfkKDXiOxmJRCeWx+tlMVQvq GC39/b9q46ppPLsfyu4u4HataTqEOpUTbYSpAsYFOfH8V3lz96JUvM1ANBm0zJIaSXSX 1TUA== 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=FZBJxE6vgXiUYQRHq25EgBqFYd27odUS2eGRI60cvzc=; b=OXuwPij1vYVvqpw9zgntv7+VybFlPSVTXcLDJx7eCLy/M80gNqdwFTLjvXNM7S1T3z W9R6G4T+RCfewcBG4AY64ves0MbKBrR8i+r2y1B566dgxrUoaqKmB1lZQ2hIiP8mz7kq OYFyKNPjfAFzJ51E/xkIWdca/hQZgUW5QQXsKy+R+Yj0oxe7h7L+t14XhIo1Ivjdg+kw kfLLBhKzlz3qKrwJ/ZjdG6hWz4y2k8HrV8vZQlF5rY8wzS/HNbfZXJqDx7Ur3C8+xcUG YT07TcotJN5R3DAGqedLCIUAaIfi/B7H5BhHmdkMzmtpKm09sw5iJD6SrzDG9TXbCmqE ExGA== X-Gm-Message-State: APjAAAV0rUn/OAUm5UXNjJVOy6Ju6KQ3ZZpAGukDXsMUHG89D4HCV/l5 8wrlqlOqthBRF6IU2DAEQ+sirpku X-Google-Smtp-Source: APXvYqx1L5BTh+C8IH6geYOg3e66D7EDJoQWFpCpR/mrir3hjWnfcNhHK3LrzUZcGxzvZa0yg25Xqw== X-Received: by 2002:a5d:684a:: with SMTP id o10mr14396963wrw.23.1569875314351; Mon, 30 Sep 2019 13:28:34 -0700 (PDT) Received: from nullptr.home.dirty-ice.org (2a01-036c-0113-e8f4-0000-0000-0000-0005.pool6.digikabel.hu. [2a01:36c:113:e8f4::5]) by smtp.gmail.com with ESMTPSA id o9sm34402911wrh.46.2019.09.30.13.28.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Sep 2019 13:28:33 -0700 (PDT) From: "=?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?=" X-Google-Original-From: =?utf-8?b?S8WRdsOhZ8OzLCBab2x0w6Fu?= To: qemu-devel@nongnu.org Subject: [PATCH v5 05/10] audio: replace shift in audio_pcm_info with bytes_per_frame Date: Mon, 30 Sep 2019 22:28:58 +0200 Message-Id: X-Mailer: git-send-email 2.23.0 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::442 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" The bit shifting trick worked because the number of bytes per frame was always a power-of-two (since QEMU only supports mono, stereo and 8, 16 and 32 bit samples). But if we want to add support for surround sound, this no longer holds true. Signed-off-by: Kővágó, Zoltán --- audio/alsaaudio.c | 11 +++--- audio/audio.c | 74 ++++++++++++++++++++--------------------- audio/audio_int.h | 3 +- audio/coreaudio.c | 4 +-- audio/dsound_template.h | 10 +++--- audio/dsoundaudio.c | 4 +-- audio/noaudio.c | 2 +- audio/ossaudio.c | 14 ++++---- audio/spiceaudio.c | 3 +- audio/wavaudio.c | 6 ++-- 10 files changed, 66 insertions(+), 65 deletions(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index cfe42284a6..eddf013a53 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -602,7 +602,7 @@ static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len) { ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; size_t pos = 0; - size_t len_frames = len >> hw->info.shift; + size_t len_frames = len / hw->info.bytes_per_frame; while (len_frames) { char *src = advance(buf, pos); @@ -648,7 +648,7 @@ static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len) } } - pos += written << hw->info.shift; + pos += written * hw->info.bytes_per_frame; if (written < len_frames) { break; } @@ -802,7 +802,8 @@ static size_t alsa_read(HWVoiceIn *hw, void *buf, size_t len) void *dst = advance(buf, pos); snd_pcm_sframes_t nread; - nread = snd_pcm_readi(alsa->handle, dst, len >> hw->info.shift); + nread = snd_pcm_readi( + alsa->handle, dst, len / hw->info.bytes_per_frame); if (nread <= 0) { switch (nread) { @@ -828,8 +829,8 @@ static size_t alsa_read(HWVoiceIn *hw, void *buf, size_t len) } } - pos += nread << hw->info.shift; - len -= nread << hw->info.shift; + pos += nread * hw->info.bytes_per_frame; + len -= nread * hw->info.bytes_per_frame; } return pos; diff --git a/audio/audio.c b/audio/audio.c index f1c145dfcd..c00f4deddd 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -299,12 +299,13 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *a void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as) { - int bits = 8, sign = 0, shift = 0; + int bits = 8, sign = 0, mul; switch (as->fmt) { case AUDIO_FORMAT_S8: sign = 1; case AUDIO_FORMAT_U8: + mul = 1; break; case AUDIO_FORMAT_S16: @@ -312,7 +313,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as) /* fall through */ case AUDIO_FORMAT_U16: bits = 16; - shift = 1; + mul = 2; break; case AUDIO_FORMAT_S32: @@ -320,7 +321,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as) /* fall through */ case AUDIO_FORMAT_U32: bits = 32; - shift = 2; + mul = 4; break; default: @@ -331,9 +332,8 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as) info->bits = bits; info->sign = sign; info->nchannels = as->nchannels; - info->shift = (as->nchannels == 2) + shift; - info->align = (1 << info->shift) - 1; - info->bytes_per_second = info->freq << info->shift; + info->bytes_per_frame = as->nchannels * mul; + info->bytes_per_second = info->freq * info->bytes_per_frame; info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS); } @@ -344,26 +344,25 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) } if (info->sign) { - memset (buf, 0x00, len << info->shift); + memset(buf, 0x00, len * info->bytes_per_frame); } else { switch (info->bits) { case 8: - memset (buf, 0x80, len << info->shift); + memset(buf, 0x80, len * info->bytes_per_frame); break; case 16: { int i; uint16_t *p = buf; - int shift = info->nchannels - 1; short s = INT16_MAX; if (info->swap_endianness) { s = bswap16 (s); } - for (i = 0; i < len << shift; i++) { + for (i = 0; i < len * info->nchannels; i++) { p[i] = s; } } @@ -373,14 +372,13 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) { int i; uint32_t *p = buf; - int shift = info->nchannels - 1; int32_t s = INT32_MAX; if (info->swap_endianness) { s = bswap32 (s); } - for (i = 0; i < len << shift; i++) { + for (i = 0; i < len * info->nchannels; i++) { p[i] = s; } } @@ -558,7 +556,7 @@ static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len) while (len) { st_sample *src = hw->mix_buf->samples + pos; - uint8_t *dst = advance(pcm_buf, clipped << hw->info.shift); + uint8_t *dst = advance(pcm_buf, clipped * hw->info.bytes_per_frame); size_t samples_till_end_of_buf = hw->mix_buf->size - pos; size_t samples_to_clip = MIN(len, samples_till_end_of_buf); @@ -607,7 +605,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size) return 0; } - samples = size >> sw->info.shift; + samples = size / sw->info.bytes_per_frame; if (!live) { return 0; } @@ -642,7 +640,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size) sw->clip (buf, sw->buf, ret); sw->total_hw_samples_acquired += total; - return ret << sw->info.shift; + return ret * sw->info.bytes_per_frame; } /* @@ -715,7 +713,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size) } wpos = (sw->hw->mix_buf->pos + live) % hwsamples; - samples = size >> sw->info.shift; + samples = size / sw->info.bytes_per_frame; dead = hwsamples - live; swlim = ((int64_t) dead << 32) / sw->ratio; @@ -759,13 +757,13 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size) dolog ( "%s: write size %zu ret %zu total sw %zu\n", SW_NAME (sw), - size >> sw->info.shift, + size / sw->info.bytes_per_frame, ret, sw->total_hw_samples_mixed ); #endif - return ret << sw->info.shift; + return ret * sw->info.bytes_per_frame; } #ifdef DEBUG_AUDIO @@ -882,7 +880,7 @@ size_t AUD_read(SWVoiceIn *sw, void *buf, size_t size) int AUD_get_buffer_size_out (SWVoiceOut *sw) { - return sw->hw->mix_buf->size << sw->hw->info.shift; + return sw->hw->mix_buf->size * sw->hw->info.bytes_per_frame; } void AUD_set_active_out (SWVoiceOut *sw, int on) @@ -998,10 +996,10 @@ static size_t audio_get_avail (SWVoiceIn *sw) ldebug ( "%s: get_avail live %d ret %" PRId64 "\n", SW_NAME (sw), - live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift + live, (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame ); - return (((int64_t) live << 32) / sw->ratio) << sw->info.shift; + return (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame; } static size_t audio_get_free(SWVoiceOut *sw) @@ -1025,10 +1023,11 @@ static size_t audio_get_free(SWVoiceOut *sw) #ifdef DEBUG_OUT dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n", SW_NAME (sw), - live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift); + live, dead, (((int64_t) dead << 32) / sw->ratio) * + sw->info.bytes_per_frame); #endif - return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift; + return (((int64_t) dead << 32) / sw->ratio) * sw->info.bytes_per_frame; } static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos, @@ -1047,7 +1046,7 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos, while (n) { size_t till_end_of_hw = hw->mix_buf->size - rpos2; size_t to_write = MIN(till_end_of_hw, n); - size_t bytes = to_write << hw->info.shift; + size_t bytes = to_write * hw->info.bytes_per_frame; size_t written; sw->buf = hw->mix_buf->samples + rpos2; @@ -1082,10 +1081,11 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live) return clipped + live; } - decr = MIN(size >> hw->info.shift, live); + decr = MIN(size / hw->info.bytes_per_frame, live); audio_pcm_hw_clip_out(hw, buf, decr); - proc = hw->pcm_ops->put_buffer_out(hw, buf, decr << hw->info.shift) >> - hw->info.shift; + proc = hw->pcm_ops->put_buffer_out(hw, buf, + decr * hw->info.bytes_per_frame) / + hw->info.bytes_per_frame; live -= proc; clipped += proc; @@ -1234,16 +1234,16 @@ static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples) while (samples) { size_t proc; - size_t size = samples << hw->info.shift; + size_t size = samples * hw->info.bytes_per_frame; void *buf = hw->pcm_ops->get_buffer_in(hw, &size); - assert((size & hw->info.align) == 0); + assert(size % hw->info.bytes_per_frame == 0); if (size == 0) { hw->pcm_ops->put_buffer_in(hw, buf, size); break; } - proc = MIN(size >> hw->info.shift, + proc = MIN(size / hw->info.bytes_per_frame, conv_buf->size - conv_buf->pos); hw->conv(conv_buf->samples + conv_buf->pos, buf, proc); @@ -1251,7 +1251,7 @@ static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples) samples -= proc; conv += proc; - hw->pcm_ops->put_buffer_in(hw, buf, proc << hw->info.shift); + hw->pcm_ops->put_buffer_in(hw, buf, proc * hw->info.bytes_per_frame); } return conv; @@ -1325,7 +1325,7 @@ static void audio_run_capture (AudioState *s) for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { cb->ops.capture (cb->opaque, cap->buf, - to_capture << hw->info.shift); + to_capture * hw->info.bytes_per_frame); } rpos = (rpos + to_capture) % hw->mix_buf->size; live -= to_capture; @@ -1378,7 +1378,7 @@ void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size) ssize_t start; if (unlikely(!hw->buf_emul)) { - size_t calc_size = hw->conv_buf->size << hw->info.shift; + size_t calc_size = hw->conv_buf->size * hw->info.bytes_per_frame; hw->buf_emul = g_malloc(calc_size); hw->size_emul = calc_size; hw->pos_emul = hw->pending_emul = 0; @@ -1414,7 +1414,7 @@ void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size) void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size) { if (unlikely(!hw->buf_emul)) { - size_t calc_size = hw->mix_buf->size << hw->info.shift; + size_t calc_size = hw->mix_buf->size * hw->info.bytes_per_frame; hw->buf_emul = g_malloc(calc_size); hw->size_emul = calc_size; @@ -1833,7 +1833,7 @@ CaptureVoiceOut *AUD_add_capture( audio_pcm_init_info (&hw->info, as); - cap->buf = g_malloc0_n(hw->mix_buf->size, 1 << hw->info.shift); + cap->buf = g_malloc0_n(hw->mix_buf->size, hw->info.bytes_per_frame); hw->clip = mixeng_clip [hw->info.nchannels == 2] @@ -2153,14 +2153,14 @@ size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ticks = now - rate->start_ticks; bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND); - samples = (bytes - rate->bytes_sent) >> info->shift; + samples = (bytes - rate->bytes_sent) / info->bytes_per_frame; if (samples < 0 || samples > 65536) { AUD_log(NULL, "Resetting rate control (%" PRId64 " samples)\n", samples); audio_rate_start(rate); samples = 0; } - ret = MIN(samples << info->shift, bytes_avail); + ret = MIN(samples * info->bytes_per_frame, bytes_avail); rate->bytes_sent += ret; return ret; } diff --git a/audio/audio_int.h b/audio/audio_int.h index 9176db249b..5ba2078346 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -43,8 +43,7 @@ struct audio_pcm_info { int sign; int freq; int nchannels; - int align; - int shift; + int bytes_per_frame; int bytes_per_second; int swap_endianness; }; diff --git a/audio/coreaudio.c b/audio/coreaudio.c index 1427c9f622..66f0f459cf 100644 --- a/audio/coreaudio.c +++ b/audio/coreaudio.c @@ -440,7 +440,7 @@ static OSStatus audioDeviceIOProc( } frameCount = core->audioDevicePropertyBufferFrameSize; - pending_frames = hw->pending_emul >> hw->info.shift; + pending_frames = hw->pending_emul / hw->info.bytes_per_frame; /* if there are not enough samples, set signal and return */ if (pending_frames < frameCount) { @@ -449,7 +449,7 @@ static OSStatus audioDeviceIOProc( return 0; } - len = frameCount << hw->info.shift; + len = frameCount * hw->info.bytes_per_frame; while (len) { size_t write_len; ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul; diff --git a/audio/dsound_template.h b/audio/dsound_template.h index 9f10b688df..7a15f91ce5 100644 --- a/audio/dsound_template.h +++ b/audio/dsound_template.h @@ -98,8 +98,8 @@ static int glue (dsound_lock_, TYPE) ( goto fail; } - if ((p1p && *p1p && (*blen1p & info->align)) || - (p2p && *p2p && (*blen2p & info->align))) { + if ((p1p && *p1p && (*blen1p % info->bytes_per_frame)) || + (p2p && *p2p && (*blen2p % info->bytes_per_frame))) { dolog("DirectSound returned misaligned buffer %ld %ld\n", *blen1p, *blen2p); glue(dsound_unlock_, TYPE)(buf, *p1p, p2p ? *p2p : NULL, *blen1p, @@ -247,14 +247,14 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as, obt_as.endianness = 0; audio_pcm_init_info (&hw->info, &obt_as); - if (bc.dwBufferBytes & hw->info.align) { + if (bc.dwBufferBytes % hw->info.bytes_per_frame) { dolog ( "GetCaps returned misaligned buffer size %ld, alignment %d\n", - bc.dwBufferBytes, hw->info.align + 1 + bc.dwBufferBytes, hw->info.bytes_per_frame ); } hw->size_emul = bc.dwBufferBytes; - hw->samples = bc.dwBufferBytes >> hw->info.shift; + hw->samples = bc.dwBufferBytes / hw->info.bytes_per_frame; ds->s = s; #ifdef DEBUG_DSOUND diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c index d4a4757445..c265c0094b 100644 --- a/audio/dsoundaudio.c +++ b/audio/dsoundaudio.c @@ -320,8 +320,8 @@ static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb, return; } - len1 = blen1 >> hw->info.shift; - len2 = blen2 >> hw->info.shift; + len1 = blen1 / hw->info.bytes_per_frame; + len2 = blen2 / hw->info.bytes_per_frame; #ifdef DEBUG_DSOUND dolog ("clear %p,%ld,%ld %p,%ld,%ld\n", diff --git a/audio/noaudio.c b/audio/noaudio.c index ec8a287f36..ff99b253ff 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -91,7 +91,7 @@ static size_t no_read(HWVoiceIn *hw, void *buf, size_t size) NoVoiceIn *no = (NoVoiceIn *) hw; int64_t bytes = audio_rate_get_bytes(&hw->info, &no->rate, size); - audio_pcm_info_clear_buf(&hw->info, buf, bytes >> hw->info.shift); + audio_pcm_info_clear_buf(&hw->info, buf, bytes / hw->info.bytes_per_frame); return bytes; } diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 0c4451e972..c43faeeea4 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -506,16 +506,16 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as, oss->nfrags = obt.nfrags; oss->fragsize = obt.fragsize; - if (obt.nfrags * obt.fragsize & hw->info.align) { + if (obt.nfrags * obt.fragsize % hw->info.bytes_per_frame) { dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n", - obt.nfrags * obt.fragsize, hw->info.align + 1); + obt.nfrags * obt.fragsize, hw->info.bytes_per_frame); } - hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; + hw->samples = (obt.nfrags * obt.fragsize) / hw->info.bytes_per_frame; oss->mmapped = 0; if (oopts->has_try_mmap && oopts->try_mmap) { - hw->size_emul = hw->samples << hw->info.shift; + hw->size_emul = hw->samples * hw->info.bytes_per_frame; hw->buf_emul = mmap( NULL, hw->size_emul, @@ -644,12 +644,12 @@ static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) oss->nfrags = obt.nfrags; oss->fragsize = obt.fragsize; - if (obt.nfrags * obt.fragsize & hw->info.align) { + if (obt.nfrags * obt.fragsize % hw->info.bytes_per_frame) { dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n", - obt.nfrags * obt.fragsize, hw->info.align + 1); + obt.nfrags * obt.fragsize, hw->info.bytes_per_frame); } - hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; + hw->samples = (obt.nfrags * obt.fragsize) / hw->info.bytes_per_frame; oss->fd = fd; oss->dev = dev; diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c index 6ed7f7a79e..b6b5da4812 100644 --- a/audio/spiceaudio.c +++ b/audio/spiceaudio.c @@ -131,7 +131,8 @@ static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size) if (out->frame) { *size = audio_rate_get_bytes( - &hw->info, &out->rate, (out->fsize - out->fpos) << hw->info.shift); + &hw->info, &out->rate, + (out->fsize - out->fpos) * hw->info.bytes_per_frame); } else { audio_rate_start(&out->rate); } diff --git a/audio/wavaudio.c b/audio/wavaudio.c index 47efdc1b1e..e46d834bd3 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -43,14 +43,14 @@ static size_t wav_write_out(HWVoiceOut *hw, void *buf, size_t len) { WAVVoiceOut *wav = (WAVVoiceOut *) hw; int64_t bytes = audio_rate_get_bytes(&hw->info, &wav->rate, len); - assert(bytes >> hw->info.shift << hw->info.shift == bytes); + assert(bytes % hw->info.bytes_per_frame == 0); if (bytes && fwrite(buf, bytes, 1, wav->f) != 1) { dolog("wav_write_out: fwrite of %" PRId64 " bytes failed\nReason: %s\n", bytes, strerror(errno)); } - wav->total_samples += bytes >> hw->info.shift; + wav->total_samples += bytes / hw->info.bytes_per_frame; return bytes; } @@ -134,7 +134,7 @@ static void wav_fini_out (HWVoiceOut *hw) WAVVoiceOut *wav = (WAVVoiceOut *) hw; uint8_t rlen[4]; uint8_t dlen[4]; - uint32_t datalen = wav->total_samples << hw->info.shift; + uint32_t datalen = wav->total_samples * hw->info.bytes_per_frame; uint32_t rifflen = datalen + 36; if (!wav->f) { From patchwork Mon Sep 30 20:28:59 2019 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: 1169580 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="ne4HFvLz"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46hvPb6Kncz9sNk for ; Tue, 1 Oct 2019 06:38:43 +1000 (AEST) Received: from localhost ([::1]:57016 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2RL-0003dK-Te for incoming@patchwork.ozlabs.org; Mon, 30 Sep 2019 16:38:39 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45767) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2He-00040F-BP for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iF2Hc-0002Yk-QE for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:37 -0400 Received: from mail-wr1-x42d.google.com ([2a00:1450:4864:20::42d]:40069) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iF2Hc-0002XY-JH for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:36 -0400 Received: by mail-wr1-x42d.google.com with SMTP id l3so12807812wru.7 for ; Mon, 30 Sep 2019 13:28:36 -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=I/J8Dq/+F7R0/J6BZwd7lt84Aly4P3hEz64ceVDIF5c=; b=ne4HFvLzpXtVHrUVStWSDQk73R/uQAaUcLR3Arn01TGvqOD6z7h2+0HbIcsliAtQVY D/Z/Q25tqcDELqSl7cbY5M63RQqTU05XEUzXm1kwmm9NULWjPfbC3Udy/WYpzc/h5W74 SBOFsunziguTxHAwi6g+Ij8JxqfCyVtx9KNsz4asd2M63sKowhkGdMtAYmG0TDhRLcz7 WczQB/sqDQ4WGhhLz7iNe7K9jN62OBSqgvHDvsxjOpBeN+o5W9i/xDseTFxSVJf5vyiU Vf5HmawGhijGqFvBKJWHc3fj1w1xxsyIbZkCCEWS5FsQFtm4QOa4cmS+Ndp8vE0rVyRc Z9wQ== 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=I/J8Dq/+F7R0/J6BZwd7lt84Aly4P3hEz64ceVDIF5c=; b=s/fFh0pBFt7r1EoBTe1T4iNXiuf2gNJq/h75ygR/W5+3//QWXgqtX+wkqyYd8bR8Mx l0UcLUKkFBf8Bz2DpqdUj4KWQSi8hdXTU8MrlAOLsusqUTNtMkPVIJxb8ovRaryXB/r2 7PuOTZEKzRGeWUKdp10jJrUEm0s1Ix33g7aUy+rmhykEk1qwPBbaVu9HJxicekf0BuKM Y4mP7anj/UKdLeW2R9V7nBajBRP6PAKfYH5gfQAEHtAZN+2mOvc9agyL0iZM8y4SmBR7 QKYIf9WvS1TimlC/R7T4c0/8/cEovFe6/qIhkEjrMx8kRFFmvqQFjJxJcXLgWTaym5va BHnA== X-Gm-Message-State: APjAAAUKcvflGTOGHo2ZdLHcKKMJ8VsynBdIiLorZC1D3qYChjSXi8yF l073cYxERrWetsf446KJlQ6DVtLz X-Google-Smtp-Source: APXvYqy4Ds+z/KK8Wt/fzmOg3NTxZHIn72dTrtjlyH1dr5zR3EXuzTHmsHBfbb6P2LhKImjahRyXsw== X-Received: by 2002:adf:a415:: with SMTP id d21mr13856343wra.94.1569875315442; Mon, 30 Sep 2019 13:28:35 -0700 (PDT) Received: from nullptr.home.dirty-ice.org (2a01-036c-0113-e8f4-0000-0000-0000-0005.pool6.digikabel.hu. [2a01:36c:113:e8f4::5]) by smtp.gmail.com with ESMTPSA id o9sm34402911wrh.46.2019.09.30.13.28.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Sep 2019 13:28:34 -0700 (PDT) From: "=?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?=" X-Google-Original-From: =?utf-8?b?S8WRdsOhZ8OzLCBab2x0w6Fu?= To: qemu-devel@nongnu.org Subject: [PATCH v5 06/10] audio: basic support for multichannel audio Date: Mon, 30 Sep 2019 22:28:59 +0200 Message-Id: <35de004f4e540b72defda75a9804dd599a497dcb.1569874641.git.DirtY.iCE.hu@gmail.com> X-Mailer: git-send-email 2.23.0 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::42d 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Which currently only means removing some checks. Old code won't require more than two channels, but new code will need it. Signed-off-by: Kővágó, Zoltán --- audio/alsaaudio.c | 7 ------- audio/audio.c | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index eddf013a53..f37ce1ce85 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -493,13 +493,6 @@ static int alsa_open(bool in, struct alsa_params_req *req, goto err; } - if (nchannels != 1 && nchannels != 2) { - alsa_logerr2 (err, typ, - "Can not handle obtained number of channels %d\n", - nchannels); - goto err; - } - if (apdo->buffer_length) { int dir = 0; unsigned int btime = apdo->buffer_length; diff --git a/audio/audio.c b/audio/audio.c index c00f4deddd..7fc3aa9d16 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -242,7 +242,7 @@ static int audio_validate_settings (struct audsettings *as) { int invalid; - invalid = as->nchannels != 1 && as->nchannels != 2; + invalid = as->nchannels < 1; invalid |= as->endianness != 0 && as->endianness != 1; switch (as->fmt) { From patchwork Mon Sep 30 20:29:00 2019 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: 1169619 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="c/HvfcAt"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46hvst2Fl0z9sPh for ; Tue, 1 Oct 2019 06:59:46 +1000 (AEST) Received: from localhost ([::1]:57258 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2lk-0005cG-4C for incoming@patchwork.ozlabs.org; Mon, 30 Sep 2019 16:59:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45780) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2He-00041A-MJ for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iF2Hd-0002Zw-Ea for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:38 -0400 Received: from mail-wr1-x443.google.com ([2a00:1450:4864:20::443]:42181) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iF2Hd-0002Xx-8A for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:37 -0400 Received: by mail-wr1-x443.google.com with SMTP id n14so12800120wrw.9 for ; Mon, 30 Sep 2019 13:28:37 -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=8TTUthXqXhh1DdLxMpTCEbLpELmMAAhIVdhapb9+b1E=; b=c/HvfcAtu2AfeIeujP5gSRO41UANWoaXa+paKfq/UTeBh7oee8LgiklZNUuclrkAt2 EfbMq2AeDpiEtb5Fos+SoTHub5R41mSTeCtUCZIDpxa3RjWwk4sa64Ml0Rii1RvhsF9Q fd2I5pbVCvtjd76BRTUoUDGy3A5babepdN4QeWWWFJbP67qChN3d9v4AuqlLKKlb4Cqn E83g1R/dXpbg0KBQFL2sVuFRhdqXDC2nmjrftRBO0yX5BB/M1Xv79irrtGBmHSnwz/zJ zVdJLEl8BLRkiWAPdca89pYwp8amqtBupgtxomXkCIzc2Bt8fRxklU5M6L/EBRE/mFOx yhkQ== 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=8TTUthXqXhh1DdLxMpTCEbLpELmMAAhIVdhapb9+b1E=; b=NqOV2DVUPWuHDjDWE//TKU0eMUuKNwf8cxbNz2XgDpQXM/uQjXTQhX8jTyEQ0ozzCN Uncozpo5b8iteRIg82D+1Nmct7qEk1mwR79GM32QAFgRZ8S/jJqFJFaGGNchcjhpEWFG Mokffj9KuSYzu/uhLmtnWcGl1nURULMv7dzrlM3TVpoNR0vZ6BR1K+o+yd7ej/BFcvco jSjX729TGBwMhsWMZzT19exkfPefNR4CWrtGpfpnb7JDIPJjBJjC1BXC4CPEwVxH+KmM 3QQUUp+DpbuxIQG2N3PUecBAE1n3OTARgC5+rb/jAZ5ibdHUeW0iFyMAlcA3vnkNEQ8y W65A== X-Gm-Message-State: APjAAAUIt0+0TzobJzIuG4jdtTSmHUGPzLXVgetqUi/9ACQY1NHcpWP4 9xmQBujKRJRxQi64T6e/PYGfB3+T X-Google-Smtp-Source: APXvYqyp75ef/rIs78JqH+Xwrj8XPtSCu/aCYcCN4wpj5scu6ii3yreItD0IDFxI+q/AsD7jvabYNg== X-Received: by 2002:a5d:5352:: with SMTP id t18mr15344507wrv.72.1569875316076; Mon, 30 Sep 2019 13:28:36 -0700 (PDT) Received: from nullptr.home.dirty-ice.org (2a01-036c-0113-e8f4-0000-0000-0000-0005.pool6.digikabel.hu. [2a01:36c:113:e8f4::5]) by smtp.gmail.com with ESMTPSA id o9sm34402911wrh.46.2019.09.30.13.28.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Sep 2019 13:28:35 -0700 (PDT) From: "=?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?=" X-Google-Original-From: =?utf-8?b?S8WRdsOhZ8OzLCBab2x0w6Fu?= To: qemu-devel@nongnu.org Subject: [PATCH v5 07/10] usb-audio: do not count on avail bytes actually available Date: Mon, 30 Sep 2019 22:29:00 +0200 Message-Id: <4efbf065feca430f92c814aa71028df5571acb44.1569874641.git.DirtY.iCE.hu@gmail.com> X-Mailer: git-send-email 2.23.0 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::443 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This assumption is no longer true when mixeng is turned off. Signed-off-by: Kővágó, Zoltán --- hw/usb/dev-audio.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c index ae42e5a2f1..74c99b1f12 100644 --- a/hw/usb/dev-audio.c +++ b/hw/usb/dev-audio.c @@ -319,30 +319,31 @@ static int streambuf_put(struct streambuf *buf, USBPacket *p) { uint32_t free = buf->size - (buf->prod - buf->cons); - if (!free) { + if (free < USBAUDIO_PACKET_SIZE) { return 0; } if (p->iov.size != USBAUDIO_PACKET_SIZE) { return 0; } - assert(free >= USBAUDIO_PACKET_SIZE); + usb_packet_copy(p, buf->data + (buf->prod % buf->size), USBAUDIO_PACKET_SIZE); buf->prod += USBAUDIO_PACKET_SIZE; return USBAUDIO_PACKET_SIZE; } -static uint8_t *streambuf_get(struct streambuf *buf) +static uint8_t *streambuf_get(struct streambuf *buf, size_t *len) { uint32_t used = buf->prod - buf->cons; uint8_t *data; if (!used) { + *len = 0; return NULL; } - assert(used >= USBAUDIO_PACKET_SIZE); data = buf->data + (buf->cons % buf->size); - buf->cons += USBAUDIO_PACKET_SIZE; + *len = MIN(buf->prod - buf->cons, + buf->size - (buf->cons % buf->size)); return data; } @@ -374,16 +375,21 @@ static void output_callback(void *opaque, int avail) USBAudioState *s = opaque; uint8_t *data; - for (;;) { - if (avail < USBAUDIO_PACKET_SIZE) { + while (avail) { + size_t written, len; + + data = streambuf_get(&s->out.buf, &len); + if (!data) { return; } - data = streambuf_get(&s->out.buf); - if (!data) { + + written = AUD_write(s->out.voice, data, len); + avail -= written; + s->out.buf.cons += written; + + if (written < len) { return; } - AUD_write(s->out.voice, data, USBAUDIO_PACKET_SIZE); - avail -= USBAUDIO_PACKET_SIZE; } } From patchwork Mon Sep 30 20:29:01 2019 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: 1169609 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="JMjlQWy5"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46hvlF4bxwz9sPj for ; Tue, 1 Oct 2019 06:54:01 +1000 (AEST) Received: from localhost ([::1]:57216 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2gB-0000qc-FB for incoming@patchwork.ozlabs.org; Mon, 30 Sep 2019 16:53:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45824) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2Hj-00045v-MR for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:47 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iF2Hf-0002bf-2p for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:43 -0400 Received: from mail-wm1-x343.google.com ([2a00:1450:4864:20::343]:51245) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iF2He-0002aE-Ff for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:38 -0400 Received: by mail-wm1-x343.google.com with SMTP id 7so874228wme.1 for ; Mon, 30 Sep 2019 13:28:38 -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=1xbpHh712sivYhk5HmhmXHkxPur7dIJpK6QrNTW7BR0=; b=JMjlQWy5Fzx/GB25cjxm3NR+6d1k7n0X3GoLbuTuuBv+jfUkad2klU3a7yFqaFxLyr So/eb5BR39ScaghzTKSHtWpWXuy+B/cJQDIzyuDlRhoqUdH8RAxEKJ0AiRZLjPyxOO8y 6JvhoiVeCpRsc0LfTeo/KI1JWl42xoSntCiLDk82y34LtXqnycQVmeZ5+WGIaqBClRCm tqcsHSsY7NAaUTtf1Z+qT3N46Gjynw2GSTrCqsIsRGfYkDl93gPBTdKWzL5c9NlkMgW7 QmFkj1E0LA8uspYa7YzI5QgSZNd95WoeF35PTT7t1X2gYdbWdaNLFImshctEal6fHIMT 0fUQ== 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=1xbpHh712sivYhk5HmhmXHkxPur7dIJpK6QrNTW7BR0=; b=BhPOSiZJycZQjL5l+7ZXIYdHkzgnHy/+YlqqotTJpQTtsUlrVn93zknzjTICMYbd0L /GrcAJu8wOUe6HSBkq3t7QlIF9x7i0bj90jZ4J/Sr8jeT5+gTpSGZOjzWQMbOs3iEA44 Et2FYLnMQJqaERfXNSjyHqdadkuAlMzOrsksKmnPXwR/H427+CdgdTS05FeTL+rLNQSA iD+01sDLJaNn53qnAt38mwPJWxSPQYQeg9ZtaU29Nl1ciXpTqJQjOaTRQgMSVp88Dl4c pSQA2J60XrxTYtcqfkbQj2k7+A8p8JsBwItQdj+yjGf3gav9WtCYwWMgSF6fvQUv8As8 GUag== X-Gm-Message-State: APjAAAU000Xa52ALOF+kBON6SVZorKkF++HcPXNQHmMWb/2rTnc1Ovvt zQQTFI6LXM4wUQLto7pew+km8y6z X-Google-Smtp-Source: APXvYqz5G9irYbvl/F1PlA6jXuo0Ds0U3op28MMYcU23m5TW7VjyXRaWVcyXw4KHo5VPAiDBWFvIIA== X-Received: by 2002:a1c:4383:: with SMTP id q125mr691836wma.122.1569875316896; Mon, 30 Sep 2019 13:28:36 -0700 (PDT) Received: from nullptr.home.dirty-ice.org (2a01-036c-0113-e8f4-0000-0000-0000-0005.pool6.digikabel.hu. [2a01:36c:113:e8f4::5]) by smtp.gmail.com with ESMTPSA id o9sm34402911wrh.46.2019.09.30.13.28.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Sep 2019 13:28:36 -0700 (PDT) From: "=?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?=" X-Google-Original-From: =?utf-8?b?S8WRdsOhZ8OzLCBab2x0w6Fu?= To: qemu-devel@nongnu.org Subject: [PATCH v5 08/10] usb-audio: support more than two channels of audio Date: Mon, 30 Sep 2019 22:29:01 +0200 Message-Id: <94d771da13a06784eda88a956f21e80c9ab4ea50.1569874641.git.DirtY.iCE.hu@gmail.com> X-Mailer: git-send-email 2.23.0 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::343 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This commit adds support for 5.1 and 7.1 audio playback. This commit adds a new property to usb-audio: * multi=on|off Whether to enable the 5.1 and 7.1 audio support. When off (default) it continues to emulate the old stereo-only device. When on, it emulates a slightly different audio device that supports 5.1 and 7.1 audio. Signed-off-by: Kővágó, Zoltán --- Notes: According to the spec the channel order is front left, front right, center, lfe, surround left, surround right for 5.1 sound. But alsa uses front left, front right, surround left, surround right, center, lfe. This means if you simply use an alsa device as -audiodev, the surround and center/lfe channels will be swapped. There is not much to do sort of writing a mini mixeng or something like that, but you can easily add a new device to /etc/asound.conf that swaps the channels: pcm.swap { type route slave.pcm "default" # or whatever slave.channels 6 ttable.0.0 1 ttable.1.1 1 ttable.2.4 1 ttable.3.5 1 ttable.4.2 1 ttable.5.3 1 } and use -audiodev alsa,id=foo,out.mixing-engine=off,alsa-out.dev=swap,... (due to how usb and usb-audio works, you'll probably need alsa-out.try-poll=off and some playing with threshold) Pulseaudio allows us to specify channel order, and we default to a compatible order so it should work correctly without extra setup. hw/usb/dev-audio.c | 419 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 366 insertions(+), 53 deletions(-) diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c index 74c99b1f12..e42bdfbdc1 100644 --- a/hw/usb/dev-audio.c +++ b/hw/usb/dev-audio.c @@ -37,11 +37,15 @@ #include "desc.h" #include "audio/audio.h" +static void usb_audio_reinit(USBDevice *dev, unsigned channels); + #define USBAUDIO_VENDOR_NUM 0x46f4 /* CRC16() of "QEMU" */ #define USBAUDIO_PRODUCT_NUM 0x0002 #define DEV_CONFIG_VALUE 1 /* The one and only */ +#define USBAUDIO_MAX_CHANNELS(s) (s->multi ? 8 : 2) + /* Descriptor subtypes for AC interfaces */ #define DST_AC_HEADER 1 #define DST_AC_INPUT_TERMINAL 2 @@ -80,6 +84,27 @@ static const USBDescStrings usb_audio_stringtable = { [STRING_REAL_STREAM] = "Audio Output - 48 kHz Stereo", }; +/* + * A USB audio device supports an arbitrary number of alternate + * interface settings for each interface. Each corresponds to a block + * diagram of parameterized blocks. This can thus refer to things like + * number of channels, data rates, or in fact completely different + * block diagrams. Alternative setting 0 is always the null block diagram, + * which is used by a disabled device. + */ +enum usb_audio_altset { + ALTSET_OFF = 0x00, /* No endpoint */ + ALTSET_STEREO = 0x01, /* Single endpoint */ + ALTSET_51 = 0x02, + ALTSET_71 = 0x03, +}; + +static unsigned altset_channels[] = { + [ALTSET_STEREO] = 2, + [ALTSET_51] = 6, + [ALTSET_71] = 8, +}; + #define U16(x) ((x) & 0xff), (((x) >> 8) & 0xff) #define U24(x) U16(x), (((x) >> 16) & 0xff) #define U32(x) U24(x), (((x) >> 24) & 0xff) @@ -87,7 +112,8 @@ static const USBDescStrings usb_audio_stringtable = { /* * A Basic Audio Device uses these specific values */ -#define USBAUDIO_PACKET_SIZE 192 +#define USBAUDIO_PACKET_SIZE_BASE 96 +#define USBAUDIO_PACKET_SIZE(channels) (USBAUDIO_PACKET_SIZE_BASE * channels) #define USBAUDIO_SAMPLE_RATE 48000 #define USBAUDIO_PACKET_INTERVAL 1 @@ -121,7 +147,7 @@ static const USBDescIface desc_iface[] = { 0x01, /* u8 bTerminalID */ U16(0x0101), /* u16 wTerminalType */ 0x00, /* u8 bAssocTerminal */ - 0x02, /* u16 bNrChannels */ + 0x02, /* u8 bNrChannels */ U16(0x0003), /* u16 wChannelConfig */ 0x00, /* u8 iChannelNames */ STRING_INPUT_TERMINAL, /* u8 iTerminal */ @@ -156,14 +182,14 @@ static const USBDescIface desc_iface[] = { }, },{ .bInterfaceNumber = 1, - .bAlternateSetting = 0, + .bAlternateSetting = ALTSET_OFF, .bNumEndpoints = 0, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING, .iInterface = STRING_NULL_STREAM, },{ .bInterfaceNumber = 1, - .bAlternateSetting = 1, + .bAlternateSetting = ALTSET_STEREO, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING, @@ -199,7 +225,7 @@ static const USBDescIface desc_iface[] = { { .bEndpointAddress = USB_DIR_OUT | 0x01, .bmAttributes = 0x0d, - .wMaxPacketSize = USBAUDIO_PACKET_SIZE, + .wMaxPacketSize = USBAUDIO_PACKET_SIZE(2), .bInterval = 1, .is_audio = 1, /* Stereo Headphone Class-specific @@ -247,17 +273,274 @@ static const USBDesc desc_audio = { .str = usb_audio_stringtable, }; -/* - * A USB audio device supports an arbitrary number of alternate - * interface settings for each interface. Each corresponds to a block - * diagram of parameterized blocks. This can thus refer to things like - * number of channels, data rates, or in fact completely different - * block diagrams. Alternative setting 0 is always the null block diagram, - * which is used by a disabled device. - */ -enum usb_audio_altset { - ALTSET_OFF = 0x00, /* No endpoint */ - ALTSET_ON = 0x01, /* Single endpoint */ +/* multi channel compatible desc */ + +static const USBDescIface desc_iface_multi[] = { + { + .bInterfaceNumber = 0, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .bInterfaceProtocol = 0x04, + .iInterface = STRING_USBAUDIO_CONTROL, + .ndesc = 4, + .descs = (USBDescOther[]) { + { + /* Headphone Class-Specific AC Interface Header Descriptor */ + .data = (uint8_t[]) { + 0x09, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AC_HEADER, /* u8 bDescriptorSubtype */ + U16(0x0100), /* u16 bcdADC */ + U16(0x38), /* u16 wTotalLength */ + 0x01, /* u8 bInCollection */ + 0x01, /* u8 baInterfaceNr */ + } + },{ + /* Generic Stereo Input Terminal ID1 Descriptor */ + .data = (uint8_t[]) { + 0x0c, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AC_INPUT_TERMINAL, /* u8 bDescriptorSubtype */ + 0x01, /* u8 bTerminalID */ + U16(0x0101), /* u16 wTerminalType */ + 0x00, /* u8 bAssocTerminal */ + 0x08, /* u8 bNrChannels */ + U16(0x063f), /* u16 wChannelConfig */ + 0x00, /* u8 iChannelNames */ + STRING_INPUT_TERMINAL, /* u8 iTerminal */ + } + },{ + /* Generic Stereo Feature Unit ID2 Descriptor */ + .data = (uint8_t[]) { + 0x19, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AC_FEATURE_UNIT, /* u8 bDescriptorSubtype */ + 0x02, /* u8 bUnitID */ + 0x01, /* u8 bSourceID */ + 0x02, /* u8 bControlSize */ + U16(0x0001), /* u16 bmaControls(0) */ + U16(0x0002), /* u16 bmaControls(1) */ + U16(0x0002), /* u16 bmaControls(2) */ + U16(0x0002), /* u16 bmaControls(3) */ + U16(0x0002), /* u16 bmaControls(4) */ + U16(0x0002), /* u16 bmaControls(5) */ + U16(0x0002), /* u16 bmaControls(6) */ + U16(0x0002), /* u16 bmaControls(7) */ + U16(0x0002), /* u16 bmaControls(8) */ + STRING_FEATURE_UNIT, /* u8 iFeature */ + } + },{ + /* Headphone Ouptut Terminal ID3 Descriptor */ + .data = (uint8_t[]) { + 0x09, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AC_OUTPUT_TERMINAL, /* u8 bDescriptorSubtype */ + 0x03, /* u8 bUnitID */ + U16(0x0301), /* u16 wTerminalType (SPK) */ + 0x00, /* u8 bAssocTerminal */ + 0x02, /* u8 bSourceID */ + STRING_OUTPUT_TERMINAL, /* u8 iTerminal */ + } + } + }, + },{ + .bInterfaceNumber = 1, + .bAlternateSetting = ALTSET_OFF, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING, + .iInterface = STRING_NULL_STREAM, + },{ + .bInterfaceNumber = 1, + .bAlternateSetting = ALTSET_STEREO, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING, + .iInterface = STRING_REAL_STREAM, + .ndesc = 2, + .descs = (USBDescOther[]) { + { + /* Headphone Class-specific AS General Interface Descriptor */ + .data = (uint8_t[]) { + 0x07, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AS_GENERAL, /* u8 bDescriptorSubtype */ + 0x01, /* u8 bTerminalLink */ + 0x00, /* u8 bDelay */ + 0x01, 0x00, /* u16 wFormatTag */ + } + },{ + /* Headphone Type I Format Type Descriptor */ + .data = (uint8_t[]) { + 0x0b, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AS_FORMAT_TYPE, /* u8 bDescriptorSubtype */ + 0x01, /* u8 bFormatType */ + 0x02, /* u8 bNrChannels */ + 0x02, /* u8 bSubFrameSize */ + 0x10, /* u8 bBitResolution */ + 0x01, /* u8 bSamFreqType */ + U24(USBAUDIO_SAMPLE_RATE), /* u24 tSamFreq */ + } + } + }, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_OUT | 0x01, + .bmAttributes = 0x0d, + .wMaxPacketSize = USBAUDIO_PACKET_SIZE(2), + .bInterval = 1, + .is_audio = 1, + /* Stereo Headphone Class-specific + AS Audio Data Endpoint Descriptor */ + .extra = (uint8_t[]) { + 0x07, /* u8 bLength */ + USB_DT_CS_ENDPOINT, /* u8 bDescriptorType */ + DST_EP_GENERAL, /* u8 bDescriptorSubtype */ + 0x00, /* u8 bmAttributes */ + 0x00, /* u8 bLockDelayUnits */ + U16(0x0000), /* u16 wLockDelay */ + }, + }, + } + },{ + .bInterfaceNumber = 1, + .bAlternateSetting = ALTSET_51, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING, + .iInterface = STRING_REAL_STREAM, + .ndesc = 2, + .descs = (USBDescOther[]) { + { + /* Headphone Class-specific AS General Interface Descriptor */ + .data = (uint8_t[]) { + 0x07, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AS_GENERAL, /* u8 bDescriptorSubtype */ + 0x01, /* u8 bTerminalLink */ + 0x00, /* u8 bDelay */ + 0x01, 0x00, /* u16 wFormatTag */ + } + },{ + /* Headphone Type I Format Type Descriptor */ + .data = (uint8_t[]) { + 0x0b, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AS_FORMAT_TYPE, /* u8 bDescriptorSubtype */ + 0x01, /* u8 bFormatType */ + 0x06, /* u8 bNrChannels */ + 0x02, /* u8 bSubFrameSize */ + 0x10, /* u8 bBitResolution */ + 0x01, /* u8 bSamFreqType */ + U24(USBAUDIO_SAMPLE_RATE), /* u24 tSamFreq */ + } + } + }, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_OUT | 0x01, + .bmAttributes = 0x0d, + .wMaxPacketSize = USBAUDIO_PACKET_SIZE(6), + .bInterval = 1, + .is_audio = 1, + /* Stereo Headphone Class-specific + AS Audio Data Endpoint Descriptor */ + .extra = (uint8_t[]) { + 0x07, /* u8 bLength */ + USB_DT_CS_ENDPOINT, /* u8 bDescriptorType */ + DST_EP_GENERAL, /* u8 bDescriptorSubtype */ + 0x00, /* u8 bmAttributes */ + 0x00, /* u8 bLockDelayUnits */ + U16(0x0000), /* u16 wLockDelay */ + }, + }, + } + },{ + .bInterfaceNumber = 1, + .bAlternateSetting = ALTSET_71, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING, + .iInterface = STRING_REAL_STREAM, + .ndesc = 2, + .descs = (USBDescOther[]) { + { + /* Headphone Class-specific AS General Interface Descriptor */ + .data = (uint8_t[]) { + 0x07, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AS_GENERAL, /* u8 bDescriptorSubtype */ + 0x01, /* u8 bTerminalLink */ + 0x00, /* u8 bDelay */ + 0x01, 0x00, /* u16 wFormatTag */ + } + },{ + /* Headphone Type I Format Type Descriptor */ + .data = (uint8_t[]) { + 0x0b, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AS_FORMAT_TYPE, /* u8 bDescriptorSubtype */ + 0x01, /* u8 bFormatType */ + 0x08, /* u8 bNrChannels */ + 0x02, /* u8 bSubFrameSize */ + 0x10, /* u8 bBitResolution */ + 0x01, /* u8 bSamFreqType */ + U24(USBAUDIO_SAMPLE_RATE), /* u24 tSamFreq */ + } + } + }, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_OUT | 0x01, + .bmAttributes = 0x0d, + .wMaxPacketSize = USBAUDIO_PACKET_SIZE(8), + .bInterval = 1, + .is_audio = 1, + /* Stereo Headphone Class-specific + AS Audio Data Endpoint Descriptor */ + .extra = (uint8_t[]) { + 0x07, /* u8 bLength */ + USB_DT_CS_ENDPOINT, /* u8 bDescriptorType */ + DST_EP_GENERAL, /* u8 bDescriptorSubtype */ + 0x00, /* u8 bmAttributes */ + 0x00, /* u8 bLockDelayUnits */ + U16(0x0000), /* u16 wLockDelay */ + }, + }, + } + } +}; + +static const USBDescDevice desc_device_multi = { + .bcdUSB = 0x0100, + .bMaxPacketSize0 = 64, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 2, + .bConfigurationValue = DEV_CONFIG_VALUE, + .iConfiguration = STRING_CONFIG, + .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER, + .bMaxPower = 0x32, + .nif = ARRAY_SIZE(desc_iface_multi), + .ifs = desc_iface_multi, + } + }, +}; + +static const USBDesc desc_audio_multi = { + .id = { + .idVendor = USBAUDIO_VENDOR_NUM, + .idProduct = USBAUDIO_PRODUCT_NUM, + .bcdDevice = 0, + .iManufacturer = STRING_MANUFACTURER, + .iProduct = STRING_PRODUCT, + .iSerialNumber = STRING_SERIALNUMBER, + }, + .full = &desc_device_multi, + .str = usb_audio_stringtable, }; /* @@ -300,10 +583,11 @@ struct streambuf { uint32_t cons; }; -static void streambuf_init(struct streambuf *buf, uint32_t size) +static void streambuf_init(struct streambuf *buf, uint32_t size, + uint32_t channels) { g_free(buf->data); - buf->size = size - (size % USBAUDIO_PACKET_SIZE); + buf->size = size - (size % USBAUDIO_PACKET_SIZE(channels)); buf->data = g_malloc(buf->size); buf->prod = 0; buf->cons = 0; @@ -315,21 +599,21 @@ static void streambuf_fini(struct streambuf *buf) buf->data = NULL; } -static int streambuf_put(struct streambuf *buf, USBPacket *p) +static int streambuf_put(struct streambuf *buf, USBPacket *p, uint32_t channels) { uint32_t free = buf->size - (buf->prod - buf->cons); - if (free < USBAUDIO_PACKET_SIZE) { + if (free < USBAUDIO_PACKET_SIZE(channels)) { return 0; } - if (p->iov.size != USBAUDIO_PACKET_SIZE) { + if (p->iov.size != USBAUDIO_PACKET_SIZE(channels)) { return 0; } usb_packet_copy(p, buf->data + (buf->prod % buf->size), - USBAUDIO_PACKET_SIZE); - buf->prod += USBAUDIO_PACKET_SIZE; - return USBAUDIO_PACKET_SIZE; + USBAUDIO_PACKET_SIZE(channels)); + buf->prod += USBAUDIO_PACKET_SIZE(channels); + return USBAUDIO_PACKET_SIZE(channels); } static uint8_t *streambuf_get(struct streambuf *buf, size_t *len) @@ -357,14 +641,15 @@ typedef struct USBAudioState { enum usb_audio_altset altset; struct audsettings as; SWVoiceOut *voice; - bool mute; - uint8_t vol[2]; + Volume vol; struct streambuf buf; + uint32_t channels; } out; /* properties */ uint32_t debug; - uint32_t buffer; + uint32_t buffer_user, buffer; + bool multi; } USBAudioState; #define TYPE_USB_AUDIO "usb-audio" @@ -397,10 +682,15 @@ static int usb_audio_set_output_altset(USBAudioState *s, int altset) { switch (altset) { case ALTSET_OFF: - streambuf_init(&s->out.buf, s->buffer); AUD_set_active_out(s->out.voice, false); break; - case ALTSET_ON: + case ALTSET_STEREO: + case ALTSET_51: + case ALTSET_71: + if (s->out.channels != altset_channels[altset]) { + usb_audio_reinit(USB_DEVICE(s), altset_channels[altset]); + } + streambuf_init(&s->out.buf, s->buffer, s->out.channels); AUD_set_active_out(s->out.voice, true); break; default: @@ -431,33 +721,33 @@ static int usb_audio_get_control(USBAudioState *s, uint8_t attrib, switch (aid) { case ATTRIB_ID(MUTE_CONTROL, CR_GET_CUR, 0x0200): - data[0] = s->out.mute; + data[0] = s->out.vol.mute; ret = 1; break; case ATTRIB_ID(VOLUME_CONTROL, CR_GET_CUR, 0x0200): - if (cn < 2) { - uint16_t vol = (s->out.vol[cn] * 0x8800 + 127) / 255 + 0x8000; + if (cn < USBAUDIO_MAX_CHANNELS(s)) { + uint16_t vol = (s->out.vol.vol[cn] * 0x8800 + 127) / 255 + 0x8000; data[0] = vol; data[1] = vol >> 8; ret = 2; } break; case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MIN, 0x0200): - if (cn < 2) { + if (cn < USBAUDIO_MAX_CHANNELS(s)) { data[0] = 0x01; data[1] = 0x80; ret = 2; } break; case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MAX, 0x0200): - if (cn < 2) { + if (cn < USBAUDIO_MAX_CHANNELS(s)) { data[0] = 0x00; data[1] = 0x08; ret = 2; } break; case ATTRIB_ID(VOLUME_CONTROL, CR_GET_RES, 0x0200): - if (cn < 2) { + if (cn < USBAUDIO_MAX_CHANNELS(s)) { data[0] = 0x88; data[1] = 0x00; ret = 2; @@ -479,16 +769,17 @@ static int usb_audio_set_control(USBAudioState *s, uint8_t attrib, switch (aid) { case ATTRIB_ID(MUTE_CONTROL, CR_SET_CUR, 0x0200): - s->out.mute = data[0] & 1; + s->out.vol.mute = data[0] & 1; set_vol = true; ret = 0; break; case ATTRIB_ID(VOLUME_CONTROL, CR_SET_CUR, 0x0200): - if (cn < 2) { + if (cn < USBAUDIO_MAX_CHANNELS(s)) { uint16_t vol = data[0] + (data[1] << 8); if (s->debug) { - fprintf(stderr, "usb-audio: vol %04x\n", (uint16_t)vol); + fprintf(stderr, "usb-audio: cn %d vol %04x\n", cn, + (uint16_t)vol); } vol -= 0x8000; @@ -497,7 +788,7 @@ static int usb_audio_set_control(USBAudioState *s, uint8_t attrib, vol = 255; } - s->out.vol[cn] = vol; + s->out.vol.vol[cn] = vol; set_vol = true; ret = 0; } @@ -506,11 +797,14 @@ static int usb_audio_set_control(USBAudioState *s, uint8_t attrib, if (set_vol) { if (s->debug) { - fprintf(stderr, "usb-audio: mute %d, lvol %3d, rvol %3d\n", - s->out.mute, s->out.vol[0], s->out.vol[1]); + int i; + fprintf(stderr, "usb-audio: mute %d", s->out.vol.mute); + for (i = 0; i < USBAUDIO_MAX_CHANNELS(s); ++i) { + fprintf(stderr, ", vol[%d] %3d", i, s->out.vol.vol[i]); + } + fprintf(stderr, "\n"); } - AUD_set_volume_out(s->out.voice, s->out.mute, - s->out.vol[0], s->out.vol[1]); + audio_set_volume_out(s->out.voice, &s->out.vol); } return ret; @@ -603,7 +897,7 @@ static void usb_audio_handle_dataout(USBAudioState *s, USBPacket *p) return; } - streambuf_put(&s->out.buf, p); + streambuf_put(&s->out.buf, p, s->out.channels); if (p->actual_length < p->iov.size && s->debug > 1) { fprintf(stderr, "usb-audio: output overrun (%zd bytes)\n", p->iov.size - p->actual_length); @@ -645,6 +939,9 @@ static void usb_audio_unrealize(USBDevice *dev, Error **errp) static void usb_audio_realize(USBDevice *dev, Error **errp) { USBAudioState *s = USB_AUDIO(dev); + int i; + + dev->usb_desc = s->multi ? &desc_audio_multi : &desc_audio; usb_desc_create_serial(dev); usb_desc_init(dev); @@ -652,18 +949,35 @@ static void usb_audio_realize(USBDevice *dev, Error **errp) AUD_register_card(TYPE_USB_AUDIO, &s->card); s->out.altset = ALTSET_OFF; - s->out.mute = false; - s->out.vol[0] = 240; /* 0 dB */ - s->out.vol[1] = 240; /* 0 dB */ + s->out.vol.mute = false; + for (i = 0; i < USBAUDIO_MAX_CHANNELS(s); ++i) { + s->out.vol.vol[i] = 240; /* 0 dB */ + } + + usb_audio_reinit(dev, 2); +} + +static void usb_audio_reinit(USBDevice *dev, unsigned channels) +{ + USBAudioState *s = USB_AUDIO(dev); + + s->out.channels = channels; + if (!s->buffer_user) { + s->buffer = 32 * USBAUDIO_PACKET_SIZE(s->out.channels); + } else { + s->buffer = s->buffer_user; + } + + s->out.vol.channels = s->out.channels; s->out.as.freq = USBAUDIO_SAMPLE_RATE; - s->out.as.nchannels = 2; + s->out.as.nchannels = s->out.channels; s->out.as.fmt = AUDIO_FORMAT_S16; s->out.as.endianness = 0; - streambuf_init(&s->out.buf, s->buffer); + streambuf_init(&s->out.buf, s->buffer, s->out.channels); s->out.voice = AUD_open_out(&s->card, s->out.voice, TYPE_USB_AUDIO, s, output_callback, &s->out.as); - AUD_set_volume_out(s->out.voice, s->out.mute, s->out.vol[0], s->out.vol[1]); + audio_set_volume_out(s->out.voice, &s->out.vol); AUD_set_active_out(s->out.voice, 0); } @@ -675,8 +989,8 @@ static const VMStateDescription vmstate_usb_audio = { static Property usb_audio_properties[] = { DEFINE_AUDIO_PROPERTIES(USBAudioState, card), DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0), - DEFINE_PROP_UINT32("buffer", USBAudioState, buffer, - 32 * USBAUDIO_PACKET_SIZE), + DEFINE_PROP_UINT32("buffer", USBAudioState, buffer_user, 0), + DEFINE_PROP_BOOL("multi", USBAudioState, multi, false), DEFINE_PROP_END_OF_LIST(), }; @@ -689,7 +1003,6 @@ static void usb_audio_class_init(ObjectClass *klass, void *data) dc->props = usb_audio_properties; set_bit(DEVICE_CATEGORY_SOUND, dc->categories); k->product_desc = "QEMU USB Audio Interface"; - k->usb_desc = &desc_audio; k->realize = usb_audio_realize; k->handle_reset = usb_audio_handle_reset; k->handle_control = usb_audio_handle_control; From patchwork Mon Sep 30 20:29:02 2019 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: 1169602 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="r+9j5fBp"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46hvfj4nqzz9sPd for ; Tue, 1 Oct 2019 06:50:05 +1000 (AEST) Received: from localhost ([::1]:57180 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2cN-0005Gx-E2 for incoming@patchwork.ozlabs.org; Mon, 30 Sep 2019 16:50:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45799) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2Hg-00043S-AQ for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iF2Hf-0002bY-0n for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:40 -0400 Received: from mail-wm1-x344.google.com ([2a00:1450:4864:20::344]:51246) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iF2He-0002ah-Nv for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:38 -0400 Received: by mail-wm1-x344.google.com with SMTP id 7so874237wme.1 for ; Mon, 30 Sep 2019 13:28:38 -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=csUz3G+oANfAghQDvskgbpzawb3MHELRqPU8L59Mp1o=; b=r+9j5fBpxg2iXZ/pwK5GGJgBTHSX9ohZZLZwfrphP5xJ99fWoYD4Qj+dvNFyh7oeJa 2gHRZ8+RDzLHJipaTtbwbACjWlLBnHA7KHrvyN+klV+tEHPAWMpjx/ztvjwDVYNb5R0M hPRmVrdDVXPr1OlFaNO+VUlg2amIXA5KJCO5bqD7ZbZ8Wp2ei7TLac3UslzOmQc5y1Wh NfH278NNjV3ZXrWKgQswOTr+W18nwtJA2P9nhd7cckzs0/qD1lUcBO0jsJw1FheY8w6R 0zYMNBZfohGxpyQuUFm5uf4kZfCr/sKOauJSij021pVTGk1xSzxJJoLzO2ldIAplIOUS pV8w== 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=csUz3G+oANfAghQDvskgbpzawb3MHELRqPU8L59Mp1o=; b=PDVYRf4TPJqdzWvn268lU8dqmPEo2F3akQPVO5RdEhepx2njGdlqkH+g8s0DhTT1dn 9cna6l2xI/N77+KdMOLrJt4Gdt76GXSARTxPub/3tnv8hZ/e19I6H0IpFrjHiZsoFmVm 6wIfqJKNkD9NrDmWFhdqjSdNpO9Pjj9sePrwer2n+fhkN8SiCdNXOpDJY/iqA/mgCITB ++XmYb/1KFTNRBHcHDNYypBgyONmZmYiN7flJmUfwyeF83M+/TIm/v/7Jyr+6KK9geBv xQbeaKOMVDHkhbP0MpXxHiFYyUwkYuCuJJpPdFQrkDXlANvqlXNH00YFDIwEbdSC0yp8 TLDA== X-Gm-Message-State: APjAAAV//+hnrz8QLgEn+zV2TBTaNHKJ+sYSrwAWaXjImdMDKk4D8Tah SlOcc1npb//67kbk1p3GIT8Amxmi X-Google-Smtp-Source: APXvYqwj2MLAWGG5qz0BviLXevTshuUWdIf+8rgrkIimcTbAQD7rAiT2RlpN8qm0JvX7dYKji7kHOg== X-Received: by 2002:a05:600c:2059:: with SMTP id p25mr800019wmg.50.1569875317622; Mon, 30 Sep 2019 13:28:37 -0700 (PDT) Received: from nullptr.home.dirty-ice.org (2a01-036c-0113-e8f4-0000-0000-0000-0005.pool6.digikabel.hu. [2a01:36c:113:e8f4::5]) by smtp.gmail.com with ESMTPSA id o9sm34402911wrh.46.2019.09.30.13.28.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Sep 2019 13:28:37 -0700 (PDT) From: "=?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?=" X-Google-Original-From: =?utf-8?b?S8WRdsOhZ8OzLCBab2x0w6Fu?= To: qemu-devel@nongnu.org Subject: [PATCH v5 09/10] usbaudio: change playback counters to 64 bit Date: Mon, 30 Sep 2019 22:29:02 +0200 Message-Id: <2c3ce2e69a1be1ff362dca8d6c8f5aa6d228382c.1569874641.git.DirtY.iCE.hu@gmail.com> X-Mailer: git-send-email 2.23.0 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::344 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" With stereo playback, they need about 375 minutes of continuous audio playback to overflow, which is usually not a problem (as stopping and later resuming playback resets the counters). But with 7.1 audio, they only need about 95 minutes to overflow. After the overflow, the buf->prod % USBAUDIO_PACKET_SIZE(channels) assertion no longer holds true, which will result in overflowing the buffer. With 64 bit variables, it would take about 762000 years to overflow. Signed-off-by: Kővágó, Zoltán --- hw/usb/dev-audio.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c index e42bdfbdc1..ea604bbb8e 100644 --- a/hw/usb/dev-audio.c +++ b/hw/usb/dev-audio.c @@ -578,9 +578,9 @@ static const USBDesc desc_audio_multi = { struct streambuf { uint8_t *data; - uint32_t size; - uint32_t prod; - uint32_t cons; + size_t size; + uint64_t prod; + uint64_t cons; }; static void streambuf_init(struct streambuf *buf, uint32_t size, @@ -601,7 +601,7 @@ static void streambuf_fini(struct streambuf *buf) static int streambuf_put(struct streambuf *buf, USBPacket *p, uint32_t channels) { - uint32_t free = buf->size - (buf->prod - buf->cons); + int64_t free = buf->size - (buf->prod - buf->cons); if (free < USBAUDIO_PACKET_SIZE(channels)) { return 0; @@ -610,6 +610,8 @@ static int streambuf_put(struct streambuf *buf, USBPacket *p, uint32_t channels) return 0; } + /* can happen if prod overflows */ + assert(buf->prod % USBAUDIO_PACKET_SIZE(channels) == 0); usb_packet_copy(p, buf->data + (buf->prod % buf->size), USBAUDIO_PACKET_SIZE(channels)); buf->prod += USBAUDIO_PACKET_SIZE(channels); @@ -618,10 +620,10 @@ static int streambuf_put(struct streambuf *buf, USBPacket *p, uint32_t channels) static uint8_t *streambuf_get(struct streambuf *buf, size_t *len) { - uint32_t used = buf->prod - buf->cons; + int64_t used = buf->prod - buf->cons; uint8_t *data; - if (!used) { + if (used <= 0) { *len = 0; return NULL; } From patchwork Mon Sep 30 20:29:03 2019 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: 1169622 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Byr95vn0"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46hvww6XRlz9sPd for ; Tue, 1 Oct 2019 07:02:24 +1000 (AEST) Received: from localhost ([::1]:57284 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2oG-00079u-Ro for incoming@patchwork.ozlabs.org; Mon, 30 Sep 2019 17:02:20 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45807) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iF2Hh-00044U-0C for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iF2Hf-0002cn-Oe for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:40 -0400 Received: from mail-wm1-x341.google.com ([2a00:1450:4864:20::341]:51244) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iF2Hf-0002bQ-Gq for qemu-devel@nongnu.org; Mon, 30 Sep 2019 16:28:39 -0400 Received: by mail-wm1-x341.google.com with SMTP id 7so874260wme.1 for ; Mon, 30 Sep 2019 13:28:39 -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=9lJbQYocXSR3LzW21RYjme2hTgIUpvB0ikUNj0SmxGA=; b=Byr95vn07831RUV2a4jbCWBZmItFbDeMuDk1Mcju/0Zg+6kj933+VAXsnAWiCIY+B2 Pde3MdmLmdSzbOnC7Y6k6dqDi1XBfYiasdfsvhYMKjUwkI/PJySqZ6DXiRQy+sjQhLki GqWPEgwaFociTSP+fJoz/tbMnPVDncjMVBtcJfqtEF22vUXyEDbEhZ4Rr0CBdfVqi+gy ZHSg9s7hKVZfj00d4zyoJRaIBaCAUMeagFKjlObAL7cg8TKy1Db0QrotPLjIlxCxFu2u aXaSDi6cMgiQ1BL/Xy0x58LLmxIYaBcKmEkFqA6NuA7YtiH3K2kKL2ipHSvAL1vObSzt pzEw== 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=9lJbQYocXSR3LzW21RYjme2hTgIUpvB0ikUNj0SmxGA=; b=n5Xol6VIlDLumffXVnx8cvzsXZJTWxKnJ56WMmgaXgGrJxbj7yPTm2AUQoj6iRxVIE NTVWeIYQKe1SzSzLHCnMQtFGNAjnLPMzXHO1Mz4NiRL5F3sjjewhFf91iePj0YxJP333 yMVDCys+e0cQyT7CRWC2g6AlJw5YiwPHyQN04r2omIyzda9KJhoBElX2SkszYRMuhtHA Z0WbI72Lh69Z5WoagTO3cTCQr/jM4+0Dv1WjlCqtVe1N4f3ZVuYVBFdKOQKL8QBtlyjg ziuzU48gEwzUyA1ka+xd15bQWBz9ECl5g2ODk7gDmMX+AcEC0vPRdHowYCRumPu+VxMp a82w== X-Gm-Message-State: APjAAAVx+1KUt+rSss3ZDdqqXfmMzx4E09WZozfU70NmwyAIVhc+8sGr YY8a0BhSgfQ3EOiz6lrGW8u2wihG X-Google-Smtp-Source: APXvYqzM8borh3GRSyhiCmeMRcxrsLXcASHKIBcuvqCaV5QgtreZXQMVWH8tuCvTpFdzdoAsth4rCg== X-Received: by 2002:a7b:ce91:: with SMTP id q17mr712482wmj.25.1569875318269; Mon, 30 Sep 2019 13:28:38 -0700 (PDT) Received: from nullptr.home.dirty-ice.org (2a01-036c-0113-e8f4-0000-0000-0000-0005.pool6.digikabel.hu. [2a01:36c:113:e8f4::5]) by smtp.gmail.com with ESMTPSA id o9sm34402911wrh.46.2019.09.30.13.28.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Sep 2019 13:28:37 -0700 (PDT) From: "=?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?=" X-Google-Original-From: =?utf-8?b?S8WRdsOhZ8OzLCBab2x0w6Fu?= To: qemu-devel@nongnu.org Subject: [PATCH v5 10/10] paaudio: fix channel order for usb-audio 5.1 and 7.1 streams Date: Mon, 30 Sep 2019 22:29:03 +0200 Message-Id: X-Mailer: git-send-email 2.23.0 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::341 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Kővágó, Zoltán --- audio/paaudio.c | 50 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/audio/paaudio.c b/audio/paaudio.c index d195b1caa8..6ff0d17537 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -338,17 +338,59 @@ static pa_stream *qpa_simple_new ( pa_stream_direction_t dir, const char *dev, const pa_sample_spec *ss, - const pa_channel_map *map, const pa_buffer_attr *attr, int *rerror) { int r; - pa_stream *stream; + pa_stream *stream = NULL; pa_stream_flags_t flags; + pa_channel_map map; pa_threaded_mainloop_lock(c->mainloop); - stream = pa_stream_new(c->context, name, ss, map); + pa_channel_map_init(&map); + map.channels = ss->channels; + + /* + * TODO: This currently expects the only frontend supporting more than 2 + * channels is the usb-audio. We will need some means to set channel + * order when a new frontend gains multi-channel support. + */ + switch (ss->channels) { + case 1: + map.map[0] = PA_CHANNEL_POSITION_MONO; + break; + + case 2: + map.map[0] = PA_CHANNEL_POSITION_LEFT; + map.map[1] = PA_CHANNEL_POSITION_RIGHT; + break; + + case 6: + map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + map.map[2] = PA_CHANNEL_POSITION_CENTER; + map.map[3] = PA_CHANNEL_POSITION_LFE; + map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT; + map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; + break; + + case 8: + map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + map.map[2] = PA_CHANNEL_POSITION_CENTER; + map.map[3] = PA_CHANNEL_POSITION_LFE; + map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT; + map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; + map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; + map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; + + default: + dolog("Internal error: unsupported channel count %d\n", ss->channels); + goto fail; + } + + stream = pa_stream_new(c->context, name, ss, &map); if (!stream) { goto fail; } @@ -421,7 +463,6 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, PA_STREAM_PLAYBACK, ppdo->has_name ? ppdo->name : NULL, &ss, - NULL, /* channel map */ &ba, /* buffering attributes */ &error ); @@ -470,7 +511,6 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) PA_STREAM_RECORD, ppdo->has_name ? ppdo->name : NULL, &ss, - NULL, /* channel map */ &ba, /* buffering attributes */ &error );