qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/9] audio: multi channel audio support
@ 2015-08-21 20:36 Kővágó, Zoltán
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 1/9] audio: add mixeng option (documentation) Kővágó, Zoltán
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Kővágó, Zoltán @ 2015-08-21 20:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

This patch series adds support to more than two channels of audio (5.1,
7.1, etc.).  Currently only usb-audio frontend and alsa and pa backends
are updated.  Using more than two channels requires turning off mixeng
(-audiodev backend,id=foo,out.mixeng=off,...).

For backward compatibility reasons, you have to specify multi=on when
creating the usb-audio device:

  -device usb-audio,id=foo,multi=on,...

Please review.

Kővágó, Zoltán (9):
  audio: add mixeng option (documentation)
  audio: make mixeng optional
  paaudio: get/put_buffer functions
  audio: support more than two channels in volume setting
  audio: replace shift in audio_pcm_info with bytes_per_frame
  audio: basic support for multichannel audio
  paaudio: channel-map option
  usb-audio: do not count on avail bytes actually available
  usb-audio: support more than two channels of audio

 audio/alsaaudio.c       |  17 +-
 audio/audio.c           | 176 +++++++++++++------
 audio/audio.h           |  10 ++
 audio/audio_int.h       |   7 +-
 audio/audio_template.h  |  22 ++-
 audio/coreaudio.c       |   4 +-
 audio/dsound_template.h |  10 +-
 audio/dsoundaudio.c     |   4 +-
 audio/noaudio.c         |   2 +-
 audio/ossaudio.c        |  14 +-
 audio/paaudio.c         | 121 +++++++++++--
 audio/spiceaudio.c      |  19 ++-
 audio/wavaudio.c        |   6 +-
 hw/usb/dev-audio.c      | 446 +++++++++++++++++++++++++++++++++++++++++-------
 qapi/audio.json         |  10 +-
 qemu-options.hx         |  15 ++
 16 files changed, 703 insertions(+), 180 deletions(-)

-- 
2.5.0

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH v2 1/9] audio: add mixeng option (documentation)
  2015-08-21 20:36 [Qemu-devel] [PATCH v2 0/9] audio: multi channel audio support Kővágó, Zoltán
@ 2015-08-21 20:36 ` Kővágó, Zoltán
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 2/9] audio: make mixeng optional Kővágó, Zoltán
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Kővágó, Zoltán @ 2015-08-21 20:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann, Markus Armbruster

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 <DirtY.iCE.hu@gmail.com>
---
 qapi/audio.json | 5 +++++
 qemu-options.hx | 6 ++++++
 2 files changed, 11 insertions(+)

diff --git a/qapi/audio.json b/qapi/audio.json
index 30613da..2852dcc 100644
--- a/qapi/audio.json
+++ b/qapi/audio.json
@@ -184,6 +184,10 @@
 #
 # General audio backend options that are used for both playback and recording.
 #
+# @mixeng: #optional use QEMU's mixing engine to mix all streams inside QEMU.
+#          When set to off, fixed-settings must be also off.  Not every backend
+#          compatible with the off setting (default on)
+#
 # @fixed-settings: #optional use fixed settings for host input/output.  When
 #                  off, frequency, channels and format must not be specified
 #                  (default on)
@@ -207,6 +211,7 @@
 ##
 { 'struct': 'AudiodevPerDirectionOptions',
   'data': {
+    '*mixeng':         'bool',
     '*fixed-settings': 'bool',
     '*frequency':      'int',
     '*channels':       'int',
diff --git a/qemu-options.hx b/qemu-options.hx
index 09d19a7..4fffb6a 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -329,6 +329,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.mixeng= use mixeng 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"
@@ -397,6 +398,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.mixeng=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
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH v2 2/9] audio: make mixeng optional
  2015-08-21 20:36 [Qemu-devel] [PATCH v2 0/9] audio: multi channel audio support Kővágó, Zoltán
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 1/9] audio: add mixeng option (documentation) Kővágó, Zoltán
@ 2015-08-21 20:36 ` Kővágó, Zoltán
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 3/9] paaudio: get/put_buffer functions Kővágó, Zoltán
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Kővágó, Zoltán @ 2015-08-21 20:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Implementation of the previously added mixeng option.

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
---
 audio/audio.c          | 70 +++++++++++++++++++++++++++++++++++++++++++++-----
 audio/audio_template.h | 22 +++++++++++-----
 2 files changed, 79 insertions(+), 13 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index cb1987b..e048e37 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -793,32 +793,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 (hw->s->dev->out->mixeng) {
+        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 (hw->s->dev->in->mixeng) {
+        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)
@@ -1038,6 +1052,26 @@ static void audio_run_out (AudioState *s)
     HWVoiceOut *hw = NULL;
     SWVoiceOut *sw;
 
+    if (!s->dev->out->mixeng) {
+        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;
@@ -1174,6 +1208,17 @@ static void audio_run_in (AudioState *s)
 {
     HWVoiceIn *hw = NULL;
 
+    if (!s->dev->in->mixeng) {
+        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, min;
@@ -1654,6 +1699,11 @@ CaptureVoiceOut *AUD_add_capture(
         s = QTAILQ_FIRST(&audio_states);
     }
 
+    if (!s->dev->out->mixeng) {
+        dolog("Can't capture with mixeng disabled\n");
+        goto err0;
+    }
+
     if (audio_validate_settings (as)) {
         dolog ("Invalid settings were passed when trying to add capture\n");
         audio_print_settings (as);
@@ -1811,9 +1861,13 @@ QemuOptsList qemu_audiodev_opts = {
 static void validate_per_direction_opts(AudiodevPerDirectionOptions *pdo,
                                         Error **errp)
 {
+    if (!pdo->has_mixeng) {
+        pdo->has_mixeng = true;
+        pdo->mixeng = true;
+    }
     if (!pdo->has_fixed_settings) {
         pdo->has_fixed_settings = true;
-        pdo->fixed_settings = true;
+        pdo->fixed_settings = pdo->mixeng;
     }
     if (!pdo->fixed_settings &&
         (pdo->has_frequency || pdo->has_channels || pdo->has_format)) {
@@ -1821,6 +1875,10 @@ static void validate_per_direction_opts(AudiodevPerDirectionOptions *pdo,
                    "You can't use frequency, channels or format with fixed-settings=off");
         return;
     }
+    if (!pdo->mixeng && pdo->fixed_settings) {
+        error_setg(errp, "You can't use fixed-settings without mixeng");
+        return;
+    }
 
     if (!pdo->has_frequency) {
         pdo->has_frequency = true;
@@ -1832,7 +1890,7 @@ static void validate_per_direction_opts(AudiodevPerDirectionOptions *pdo,
     }
     if (!pdo->has_voices) {
         pdo->has_voices = true;
-        pdo->voices = 1;
+        pdo->voices = pdo->mixeng ? 1 : INT_MAX;
     }
     if (!pdo->has_format) {
         pdo->has_format = true;
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 762efea..f3cbc66 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -78,15 +78,19 @@ 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;
-    if (hw->pcm_ops->glue(buffer_size_, TYPE)) {
-        samples = hw->pcm_ops->glue(buffer_size_, TYPE)(hw);
+    if (hw->s->dev->TYPE->mixeng) {
+        size_t samples;
+        if (hw->pcm_ops->glue(buffer_size_, TYPE)) {
+            samples = hw->pcm_ops->glue(buffer_size_, TYPE)(hw);
+        } else {
+            samples = 1024; /* todo better default */
+        }
+
+        HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample)*samples);
+        HWBUF->size = samples;
     } else {
-        samples = 1024; /* todo better default */
+        HWBUF = NULL;
     }
-
-    HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample)*samples);
-    HWBUF->size = samples;
 }
 
 static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
@@ -105,6 +109,10 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
 {
     int samples;
 
+    if (!sw->s->dev->TYPE->mixeng) {
+        return 0;
+    }
+
     samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio;
 
     sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample));
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH v2 3/9] paaudio: get/put_buffer functions
  2015-08-21 20:36 [Qemu-devel] [PATCH v2 0/9] audio: multi channel audio support Kővágó, Zoltán
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 1/9] audio: add mixeng option (documentation) Kővágó, Zoltán
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 2/9] audio: make mixeng optional Kővágó, Zoltán
@ 2015-08-21 20:36 ` Kővágó, Zoltán
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 4/9] audio: support more than two channels in volume setting Kővágó, Zoltán
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Kővágó, Zoltán @ 2015-08-21 20:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

This lets us avoid some buffer copying when using mixeng.

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
---
 audio/paaudio.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/audio/paaudio.c b/audio/paaudio.c
index 14bf258..8f19995 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -96,6 +96,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;
@@ -134,6 +187,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;
@@ -668,12 +747,16 @@ static struct audio_pcm_ops qpa_pcm_ops = {
     .fini_out = qpa_fini_out,
     .write    = qpa_write,
     .buffer_size_out = qpa_buffer_size_out,
+    .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,
     .buffer_size_in = qpa_buffer_size_in,
+    .get_buffer_in = qpa_get_buffer_in,
+    .put_buffer_in = qpa_put_buffer_in,
     .volume_in = qpa_volume_in
 };
 
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH v2 4/9] audio: support more than two channels in volume setting
  2015-08-21 20:36 [Qemu-devel] [PATCH v2 0/9] audio: multi channel audio support Kővágó, Zoltán
                   ` (2 preceding siblings ...)
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 3/9] paaudio: get/put_buffer functions Kővágó, Zoltán
@ 2015-08-21 20:36 ` Kővágó, Zoltán
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 5/9] audio: replace shift in audio_pcm_info with bytes_per_frame Kővágó, Zoltán
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Kővágó, Zoltán @ 2015-08-21 20:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
---
 audio/audio.c      | 28 ++++++++++++++++++++--------
 audio/audio.h      | 10 ++++++++++
 audio/audio_int.h  |  4 ++--
 audio/paaudio.c    | 20 ++++++++++++--------
 audio/spiceaudio.c | 14 ++++++++------
 5 files changed, 52 insertions(+), 24 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index e048e37..a33f574 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1817,30 +1817,42 @@ 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 a48411a..06f15e3 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -127,6 +127,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 6f2f309..8b53c52 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -158,7 +158,7 @@ struct audio_pcm_ops {
      * size may be smaller */
     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);
@@ -167,7 +167,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 8f19995..c7875da 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -534,20 +534,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);
 
@@ -574,20 +576,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 48ca4e6..833e76f 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -177,13 +177,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);
 }
@@ -264,13 +265,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);
 }
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH v2 5/9] audio: replace shift in audio_pcm_info with bytes_per_frame
  2015-08-21 20:36 [Qemu-devel] [PATCH v2 0/9] audio: multi channel audio support Kővágó, Zoltán
                   ` (3 preceding siblings ...)
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 4/9] audio: support more than two channels in volume setting Kővágó, Zoltán
@ 2015-08-21 20:36 ` Kővágó, Zoltán
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 6/9] audio: basic support for multichannel audio Kővágó, Zoltán
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Kővágó, Zoltán @ 2015-08-21 20:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

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 <DirtY.iCE.hu@gmail.com>
---
 audio/alsaaudio.c       | 10 +++----
 audio/audio.c           | 76 ++++++++++++++++++++++++-------------------------
 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      |  5 ++--
 audio/wavaudio.c        |  6 ++--
 10 files changed, 67 insertions(+), 67 deletions(-)

diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 44f28f4..d37722c 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -613,7 +613,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);
@@ -657,7 +657,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;
         }
@@ -823,7 +823,7 @@ 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) {
@@ -849,8 +849,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 a33f574..4873683 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -267,26 +267,27 @@ 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:
         sign = 1;
     case AUDIO_FORMAT_U16:
         bits = 16;
-        shift = 1;
+        mul = 2;
         break;
 
     case AUDIO_FORMAT_S32:
         sign = 1;
     case AUDIO_FORMAT_U32:
         bits = 32;
-        shift = 2;
+        mul = 4;
         break;
 
     default:
@@ -297,9 +298,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);
 }
 
@@ -310,26 +310,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;
                 }
             }
@@ -339,14 +338,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;
                 }
             }
@@ -529,7 +527,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);
 
@@ -578,7 +576,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;
     }
@@ -613,7 +611,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;
 }
 
 /*
@@ -687,7 +685,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;
@@ -731,13 +729,13 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
     dolog (
         "%s: write size %d ret %d total sw %d\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
@@ -837,7 +835,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)
@@ -952,10 +950,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)
@@ -978,10 +976,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,
@@ -1000,7 +999,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;
@@ -1030,10 +1029,11 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
         size_t size, decr, proc;
         void *buf = hw->pcm_ops->get_buffer_out(hw, &size);
 
-        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;
@@ -1181,16 +1181,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);
@@ -1198,7 +1198,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;
@@ -1268,7 +1268,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;
@@ -1321,7 +1321,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;
@@ -1357,7 +1357,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;
@@ -1745,11 +1745,11 @@ CaptureVoiceOut *AUD_add_capture(
         audio_pcm_init_info (&hw->info, as);
 
         cap->buf = audio_calloc(AUDIO_FUNC, hw->mix_buf->size,
-                                1 << hw->info.shift);
+                                hw->info.bytes_per_frame);
         if (!cap->buf) {
             dolog ("Could not allocate capture buffer "
                    "(%zu samples, each %d bytes)\n",
-                   hw->mix_buf->size, 1 << hw->info.shift);
+                   hw->mix_buf->size, hw->info.bytes_per_frame);
             goto err3;
         }
 
@@ -2058,14 +2058,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, get_ticks_per_sec());
-    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)", 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 8b53c52..0c0289d 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -42,8 +42,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 7fdf469..e5959a2 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -225,7 +225,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) {
@@ -234,7 +234,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 6a10b67..31d356d 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;
-    ds->samples = bc.dwBufferBytes >> hw->info.shift;
+    ds->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 6fcd82e..285c729 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -321,8 +321,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 0618b60..32fbf64 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -86,7 +86,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 667bf4d..f884414 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -510,16 +510,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);
     }
 
-    oss->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
+    oss->samples = (obt.nfrags * obt.fragsize) / hw->info.bytes_per_frame;
 
     oss->mmapped = 0;
     if (oopts->has_try_mmap && oopts->try_mmap) {
-        hw->size_emul = oss->samples << hw->info.shift;
+        hw->size_emul = oss->samples * hw->info.bytes_per_frame;
         hw->buf_emul = mmap (
             NULL,
             hw->size_emul,
@@ -654,12 +654,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);
     }
 
-    oss->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
+    oss->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 833e76f..f42d822 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -131,8 +131,9 @@ static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size)
         out->fpos = 0;
     }
 
-    *size = audio_rate_get_bytes(&hw->info, &out->rate,
-                                 (out->fsize - out->fpos) << hw->info.shift);
+    *size = audio_rate_get_bytes(
+        &hw->info, &out->rate,
+        (out->fsize - out->fpos) * hw->info.bytes_per_frame);
     return out->frame + out->fpos;
 }
 
diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index 5b35173..487a1bb 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -40,14 +40,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 %zu bytes failed\nReaons: %s\n",
               bytes, strerror(errno));
     }
 
-    wav->total_samples += bytes >> hw->info.shift;
+    wav->total_samples += bytes / hw->info.bytes_per_frame;
     return bytes;
 }
 
@@ -130,7 +130,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) {
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH v2 6/9] audio: basic support for multichannel audio
  2015-08-21 20:36 [Qemu-devel] [PATCH v2 0/9] audio: multi channel audio support Kővágó, Zoltán
                   ` (4 preceding siblings ...)
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 5/9] audio: replace shift in audio_pcm_info with bytes_per_frame Kővágó, Zoltán
@ 2015-08-21 20:36 ` Kővágó, Zoltán
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 7/9] paaudio: channel-map option Kővágó, Zoltán
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 8/9] usb-audio: do not count on avail bytes actually available Kővágó, Zoltán
  7 siblings, 0 replies; 9+ messages in thread
From: Kővágó, Zoltán @ 2015-08-21 20:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

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 <DirtY.iCE.hu@gmail.com>
---
 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 d37722c..b86f741 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -499,13 +499,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 (pdo->buffer_count) {
         if (pdo->buffer_len) {
             int64_t req = pdo->buffer_len * pdo->buffer_count;
diff --git a/audio/audio.c b/audio/audio.c
index 4873683..83ac08c 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -210,7 +210,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) {
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH v2 7/9] paaudio: channel-map option
  2015-08-21 20:36 [Qemu-devel] [PATCH v2 0/9] audio: multi channel audio support Kővágó, Zoltán
                   ` (5 preceding siblings ...)
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 6/9] audio: basic support for multichannel audio Kővágó, Zoltán
@ 2015-08-21 20:36 ` Kővágó, Zoltán
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 8/9] usb-audio: do not count on avail bytes actually available Kővágó, Zoltán
  7 siblings, 0 replies; 9+ messages in thread
From: Kővágó, Zoltán @ 2015-08-21 20:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann, Markus Armbruster

Add an option to change the channel map used by pulseaudio.  If not
specified, falls back to an OSS compatible channel map.

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
---
 audio/paaudio.c | 18 ++++++++++++++----
 qapi/audio.json |  5 ++++-
 qemu-options.hx |  9 +++++++++
 3 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/audio/paaudio.c b/audio/paaudio.c
index c7875da..52aa412 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -336,17 +336,27 @@ 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 char *map,
         const pa_buffer_attr *attr,
         int *rerror)
 {
     int r;
     pa_stream *stream;
     pa_stream_flags_t flags;
+    pa_channel_map pa_map;
 
     pa_threaded_mainloop_lock(c->mainloop);
 
-    stream = pa_stream_new(c->context, name, ss, map);
+    if (map && !pa_channel_map_parse(&pa_map, map)) {
+        dolog("Invalid channel map specified: '%s'\n", map);
+        map = NULL;
+    }
+    if (!map) {
+        pa_channel_map_init_extend(&pa_map, ss->channels,
+                                   PA_CHANNEL_MAP_OSS);
+    }
+
+    stream = pa_stream_new(c->context, name, ss, &pa_map);
     if (!stream) {
         goto fail;
     }
@@ -423,7 +433,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
         PA_STREAM_PLAYBACK,
         ppdo->has_name ? ppdo->name : NULL,
         &ss,
-        NULL,                   /* channel map */
+        ppdo->has_channel_map ? ppdo->channel_map : NULL,
         &ba,                    /* buffering attributes */
         &error
         );
@@ -471,7 +481,7 @@ 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 */
+        ppdo->has_channel_map ? ppdo->channel_map : NULL,
         NULL,                   /* buffering attributes */
         &error
         );
diff --git a/qapi/audio.json b/qapi/audio.json
index 2852dcc..f683a55 100644
--- a/qapi/audio.json
+++ b/qapi/audio.json
@@ -119,11 +119,14 @@
 #
 # @name: #optional name of the sink/source to use
 #
+# @channel-map: #optional channel map to use (default: OSS compatible map)
+#
 # Since: 2.5
 ##
 { 'struct': 'AudiodevPaPerDirectionOptions',
   'data': {
-    '*name': 'str' } }
+    '*name':        'str',
+    '*channel-map': 'str' } }
 
 ##
 # @AudiodevPaOptions
diff --git a/qemu-options.hx b/qemu-options.hx
index 4fffb6a..9d17a04 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -365,6 +365,7 @@ DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev,
     "-audiodev pa,id=id[,prop[=value][,...]]\n"
     "                server= PulseAudio server address\n"
     "                sink|source.name= sink/source device name\n"
+    "                sink|source.channel-map= channel map to use\n"
 #endif
 #ifdef CONFIG_SDL
     "-audiodev sdl,id=id[,prop[=value][,...]]\n"
@@ -518,6 +519,14 @@ Sets the PulseAudio @var{server} to connect to.
 @item sink|source.name=@var{sink}
 Use the specified sink/source for playback/recording.
 
+@item sink|source.channel-map=@var{map}
+Use the specified channel map.  The default is an OSS compatible
+channel map.  Do not forget to escape commas inside the map:
+
+@example
+-audiodev pa,id=example,sink.channel-map=front-left,,front-right
+@end example
+
 @end table
 
 @item -audiodev sdl,id=@var{id}[,@var{prop}[=@var{value}][,...]]
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH v2 8/9] usb-audio: do not count on avail bytes actually available
  2015-08-21 20:36 [Qemu-devel] [PATCH v2 0/9] audio: multi channel audio support Kővágó, Zoltán
                   ` (6 preceding siblings ...)
  2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 7/9] paaudio: channel-map option Kővágó, Zoltán
@ 2015-08-21 20:36 ` Kővágó, Zoltán
  7 siblings, 0 replies; 9+ messages in thread
From: Kővágó, Zoltán @ 2015-08-21 20:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

This assumption is no longer true when mixeng is turned off.

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
---
 hw/usb/dev-audio.c | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c
index 48ac992..ddd80e0 100644
--- a/hw/usb/dev-audio.c
+++ b/hw/usb/dev-audio.c
@@ -317,27 +317,28 @@ 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;
     }
-    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;
 }
 
@@ -369,16 +370,21 @@ static void output_callback(void *opaque, int avail)
     USBAudioState *s = opaque;
     uint8_t *data;
 
-    for (;;) {
-        if (avail < USBAUDIO_PACKET_SIZE) {
-            return;
-        }
-        data = streambuf_get(&s->out.buf);
+    while (avail) {
+        size_t written, len;
+
+        data = streambuf_get(&s->out.buf, &len);
         if (!data) {
             return;
         }
-        AUD_write(s->out.voice, data, USBAUDIO_PACKET_SIZE);
-        avail -= USBAUDIO_PACKET_SIZE;
+
+        written = AUD_write(s->out.voice, data, len);
+        avail -= written;
+        s->out.buf.cons += written;
+
+        if (written < len) {
+            return;
+        }
     }
 }
 
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2015-08-21 20:36 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-08-21 20:36 [Qemu-devel] [PATCH v2 0/9] audio: multi channel audio support Kővágó, Zoltán
2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 1/9] audio: add mixeng option (documentation) Kővágó, Zoltán
2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 2/9] audio: make mixeng optional Kővágó, Zoltán
2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 3/9] paaudio: get/put_buffer functions Kővágó, Zoltán
2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 4/9] audio: support more than two channels in volume setting Kővágó, Zoltán
2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 5/9] audio: replace shift in audio_pcm_info with bytes_per_frame Kővágó, Zoltán
2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 6/9] audio: basic support for multichannel audio Kővágó, Zoltán
2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 7/9] paaudio: channel-map option Kővágó, Zoltán
2015-08-21 20:36 ` [Qemu-devel] [PATCH v2 8/9] usb-audio: do not count on avail bytes actually available Kővágó, Zoltán

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).