All of lore.kernel.org
 help / color / mirror / Atom feed
From: Gerd Hoffmann <kraxel@redhat.com>
To: qemu-devel@nongnu.org
Cc: Gerd Hoffmann <kraxel@redhat.com>
Subject: [Qemu-devel] [RfC PATCH 11/11] spice: add audio
Date: Wed, 14 Apr 2010 11:55:22 +0200	[thread overview]
Message-ID: <1271238922-10008-12-git-send-email-kraxel@redhat.com> (raw)
In-Reply-To: <1271238922-10008-1-git-send-email-kraxel@redhat.com>

---
 Makefile.objs      |    1 +
 audio/audio.c      |    3 +
 audio/audio_int.h  |    1 +
 audio/spiceaudio.c |  315 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 320 insertions(+), 0 deletions(-)
 create mode 100644 audio/spiceaudio.c

diff --git a/Makefile.objs b/Makefile.objs
index ab1af88..b11db4c 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -84,6 +84,7 @@ common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
 audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
 audio-obj-$(CONFIG_SDL) += sdlaudio.o
 audio-obj-$(CONFIG_OSS) += ossaudio.o
+audio-obj-$(CONFIG_SPICE) += spiceaudio.o
 audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o
 audio-obj-$(CONFIG_ALSA) += alsaaudio.o
 audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o
diff --git a/audio/audio.c b/audio/audio.c
index dbf0b96..67fc1d3 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -45,6 +45,9 @@
 */
 static struct audio_driver *drvtab[] = {
     CONFIG_AUDIO_DRIVERS
+#ifdef CONFIG_SPICE
+    &spice_audio_driver,
+#endif
     &no_audio_driver,
     &wav_audio_driver
 };
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 06e313f..d1f6c2d 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -209,6 +209,7 @@ extern struct audio_driver coreaudio_audio_driver;
 extern struct audio_driver dsound_audio_driver;
 extern struct audio_driver esd_audio_driver;
 extern struct audio_driver pa_audio_driver;
+extern struct audio_driver spice_audio_driver;
 extern struct audio_driver winwave_audio_driver;
 extern struct mixeng_volume nominal_volume;
 
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
new file mode 100644
index 0000000..0e18f2f
--- /dev/null
+++ b/audio/spiceaudio.c
@@ -0,0 +1,315 @@
+#include "hw/hw.h"
+#include "qemu-timer.h"
+#include "qemu-spice.h"
+
+#define AUDIO_CAP "spice"
+#include "audio.h"
+#include "audio_int.h"
+
+#define LINE_IN_SAMPLES 1024
+#define LINE_OUT_SAMPLES 1024
+
+typedef struct SpiceVoiceOut {
+    HWVoiceOut            hw;
+    SpicePlaybackInstance sin;
+    uint32_t              *frame;
+    uint32_t              *fpos;
+    uint32_t              fsize;
+    uint64_t              prev_ticks;
+    int                   active;
+} SpiceVoiceOut;
+
+typedef struct SpiceVoiceIn {
+    HWVoiceIn             hw;
+    SpiceRecordInstance   sin;
+    uint64_t              prev_ticks;
+    int                   active;
+    uint32_t              samples[LINE_IN_SAMPLES];
+} SpiceVoiceIn;
+
+static SpicePlaybackInterface playback_sif = {
+    .base.type          = SPICE_INTERFACE_PLAYBACK,
+    .base.description   = "playback",
+    .base.major_version = SPICE_INTERFACE_PLAYBACK_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_PLAYBACK_MINOR,
+};
+
+static SpiceRecordInterface record_sif = {
+    .base.type          = SPICE_INTERFACE_RECORD,
+    .base.description   = "record",
+    .base.major_version = SPICE_INTERFACE_RECORD_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_RECORD_MINOR,
+};
+
+static void *spice_audio_init(void)
+{
+    if (!using_spice)
+        return NULL;
+    return qemu_malloc(42);
+}
+
+static void spice_audio_fini(void *opaque)
+{
+    qemu_free(opaque);
+}
+
+static uint64_t get_monotonic_time(void)
+{
+    struct timespec time_space;
+    clock_gettime(CLOCK_MONOTONIC, &time_space);
+    return (uint64_t)time_space.tv_sec * 1000 * 1000 * 1000 + time_space.tv_nsec;
+}
+
+/* playback */
+
+static int line_out_init(HWVoiceOut *hw, struct audsettings *as)
+{
+    SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
+    struct audsettings settings;
+
+    settings.freq       = SPICE_INTERFACE_PLAYBACK_FREQ;
+    settings.nchannels  = SPICE_INTERFACE_PLAYBACK_CHAN;
+    settings.fmt        = AUD_FMT_S16;
+    settings.endianness = AUDIO_HOST_ENDIANNESS;
+
+    audio_pcm_init_info(&hw->info, &settings);
+    hw->samples = LINE_OUT_SAMPLES;
+    out->active = 0;
+
+    out->sin.base.sif = &playback_sif.base;
+    spice_server_add_interface(spice_server, &out->sin.base);
+    return 0;
+}
+
+static void line_out_fini(HWVoiceOut *hw)
+{
+    SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
+
+    spice_server_remove_interface(&out->sin.base);
+}
+
+static int line_out_run(HWVoiceOut *hw, int live)
+{
+    SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
+    int rpos, decr;
+    int samples;
+    uint64_t now;
+    uint64_t ticks;
+    uint64_t bytes;
+
+    if (!live) {
+        return 0;
+    }
+
+    now = get_monotonic_time();
+    ticks = now - out->prev_ticks;
+    bytes = (ticks * hw->info.bytes_per_second) / (1000 * 1000 * 1000);
+    out->prev_ticks = now;
+
+    decr = (bytes > INT_MAX)
+        ? INT_MAX >> hw->info.shift
+        : (bytes + (1 << (hw->info.shift - 1))) >> hw->info.shift;
+    decr = audio_MIN(live, decr);
+
+    samples = decr;
+    rpos = hw->rpos;
+    while (samples) {
+        int left_till_end_samples = hw->samples - rpos;
+        int len = audio_MIN(samples, left_till_end_samples);
+
+        if (!out->frame) {
+            spice_server_playback_get_buffer(&out->sin, &out->frame, &out->fsize);
+            out->fpos = out->frame;
+        }
+        if (out->frame) {
+            len = audio_MIN(len, out->fsize);
+            hw->clip(out->fpos, hw->mix_buf + rpos, len);
+            out->fsize -= len;
+            out->fpos  += len;
+            if (out->fsize == 0) {
+                spice_server_playback_put_samples(&out->sin, out->frame);
+                out->frame = out->fpos = NULL;
+            }
+        }
+        rpos = (rpos + len) % hw->samples;
+        samples -= len;
+    }
+    hw->rpos = rpos;
+    return decr;
+}
+
+static int line_out_write(SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write(sw, buf, len);
+}
+
+static int line_out_ctl(HWVoiceOut *hw, int cmd, ...)
+{
+    SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        if (out->active) {
+            break;
+        }
+        out->active = 1;
+        out->prev_ticks = get_monotonic_time();
+        spice_server_playback_start(&out->sin);
+        break;
+    case VOICE_DISABLE:
+        if (!out->active) {
+            break;
+        }
+        out->active = 0;
+        if (out->frame) {
+            memset(out->fpos, 0, out->fsize << 2);
+            spice_server_playback_put_samples(&out->sin, out->frame);
+            out->frame = out->fpos = NULL;
+            spice_server_playback_stop(&out->sin);
+        }
+        break;
+    }
+    return 0;
+}
+
+/* record */
+
+static int line_in_init(HWVoiceIn *hw, struct audsettings *as)
+{
+    SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw);
+    struct audsettings settings;
+
+    settings.freq       = SPICE_INTERFACE_RECORD_FREQ;
+    settings.nchannels  = SPICE_INTERFACE_RECORD_CHAN;
+    settings.fmt        = AUD_FMT_S16;
+    settings.endianness = AUDIO_HOST_ENDIANNESS;
+
+    audio_pcm_init_info(&hw->info, &settings);
+    hw->samples = LINE_IN_SAMPLES;
+    in->active = 0;
+
+    in->sin.base.sif = &record_sif.base;
+    spice_server_add_interface(spice_server, &in->sin.base);
+    return 0;
+}
+
+static void line_in_fini(HWVoiceIn *hw)
+{
+    SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw);
+
+    spice_server_remove_interface(&in->sin.base);
+}
+
+static int line_in_run(HWVoiceIn *hw)
+{
+    SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw);
+    int num_samples;
+    int ready;
+    int len[2];
+    uint64_t now;
+    uint64_t ticks;
+    uint64_t delta_samp;
+    uint32_t *samples;
+
+    if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in(hw))) {
+        return 0;
+    }
+
+    now = get_monotonic_time();
+    ticks = now - in->prev_ticks;
+    in->prev_ticks = now;
+    delta_samp = (ticks * hw->info.bytes_per_second) / (1000 * 1000 * 1000);
+    delta_samp = (delta_samp + (1 << (hw->info.shift - 1))) >> hw->info.shift;
+
+    num_samples = audio_MIN(num_samples, delta_samp);
+
+    ready = spice_server_record_get_samples(&in->sin, in->samples, num_samples);
+    samples = in->samples;
+    if (ready == 0) {
+        static uint32_t silence[LINE_IN_SAMPLES];
+        samples = silence;
+        ready = LINE_IN_SAMPLES;
+    }
+
+    num_samples = audio_MIN(ready, num_samples);
+
+    if (hw->wpos + num_samples > hw->samples) {
+        len[0] = hw->samples - hw->wpos;
+        len[1] = num_samples - len[0];
+    } else {
+        len[0] = num_samples;
+        len[1] = 0;
+    }
+
+    hw->conv(hw->conv_buf + hw->wpos, samples, len[0], &nominal_volume);
+
+    if (len[1]) {
+        hw->conv(hw->conv_buf, samples + len[0], len[1],
+                 &nominal_volume);
+    }
+
+    hw->wpos = (hw->wpos + num_samples) % hw->samples;
+
+    return num_samples;
+}
+
+static int line_in_read(SWVoiceIn *sw, void *buf, int size)
+{
+    return audio_pcm_sw_read(sw, buf, size);
+}
+
+static int line_in_ctl(HWVoiceIn *hw, int cmd, ...)
+{
+    SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw);
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        if (in->active) {
+            break;
+        }
+        in->active = 1;
+        in->prev_ticks = get_monotonic_time();
+        spice_server_record_start(&in->sin);
+        break;
+    case VOICE_DISABLE:
+        if (!in->active) {
+            break;
+        }
+        in->active = 0;
+        spice_server_record_stop(&in->sin);
+        break;
+    }
+    return 0;
+}
+
+static struct audio_option audio_options[] = {
+    { /* end of list */ },
+};
+
+static struct audio_pcm_ops audio_callbacks = {
+    .init_out = line_out_init,
+    .fini_out = line_out_fini,
+    .run_out  = line_out_run,
+    .write    = line_out_write,
+    .ctl_out  = line_out_ctl,
+
+    .init_in  = line_in_init,
+    .fini_in  = line_in_fini,
+    .run_in   = line_in_run,
+    .read     = line_in_read,
+    .ctl_in   = line_in_ctl,
+};
+
+struct audio_driver spice_audio_driver = {
+    .name           = "spice",
+    .descr          = "spice audio driver",
+    .options        = audio_options,
+    .init           = spice_audio_init,
+    .fini           = spice_audio_fini,
+    .pcm_ops        = &audio_callbacks,
+    .can_be_default = 1,
+    .max_voices_out = 1,
+    .max_voices_in  = 1,
+    .voice_size_out = sizeof(SpiceVoiceOut),
+    .voice_size_in  = sizeof(SpiceVoiceIn),
+};
-- 
1.6.6.1

  parent reply	other threads:[~2010-04-14  9:56 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-04-14  9:55 [Qemu-devel] [RfC PATCH 00/11] Add spice support to qemu Gerd Hoffmann
2010-04-14  9:55 ` [Qemu-devel] [RfC PATCH 01/11] vgabios update to 0.6c, add bios for qxl/unstable Gerd Hoffmann
2010-04-14  9:55 ` [Qemu-devel] [RfC PATCH 02/11] add spice into the configure file Gerd Hoffmann
2010-04-14  9:55 ` [Qemu-devel] [RfC PATCH 03/11] spice: core bits Gerd Hoffmann
2010-04-14  9:55 ` [Qemu-devel] [RfC PATCH 04/11] spice: add keyboard Gerd Hoffmann
2010-04-14  9:55 ` [Qemu-devel] [RfC PATCH 05/11] spice: add mouse Gerd Hoffmann
2010-04-14  9:55 ` [Qemu-devel] [RfC PATCH 06/11] spice: simple display Gerd Hoffmann
2010-04-14  9:55 ` [Qemu-devel] [RfC PATCH 07/11] spice: tls support Gerd Hoffmann
2010-04-14  9:55 ` [Qemu-devel] [RfC PATCH 08/11] spice: add qxl device Gerd Hoffmann
2010-04-14 16:52   ` Blue Swirl
2010-04-14 23:08     ` [Qemu-devel] " Paolo Bonzini
2010-04-15 16:47       ` Blue Swirl
2010-04-15 19:27         ` Richard Henderson
2010-04-16  8:02       ` Gerd Hoffmann
2010-04-16 10:18         ` Paolo Bonzini
2010-04-16 10:34           ` Gerd Hoffmann
2010-04-16 12:53           ` Richard Henderson
2010-04-14 22:21   ` [Qemu-devel] " Alexander Graf
2010-04-16  8:08     ` Gerd Hoffmann
2010-04-14  9:55 ` [Qemu-devel] [RfC PATCH 09/11] qxl: local rendering for sdl/vnc Gerd Hoffmann
2010-04-14  9:55 ` [Qemu-devel] [RfC PATCH 10/11] spice: add tablet support Gerd Hoffmann
2010-04-14  9:55 ` Gerd Hoffmann [this message]
2010-04-14 20:51   ` [Qemu-devel] [RfC PATCH 11/11] spice: add audio malc
2010-04-14 23:14     ` [Qemu-devel] " Paolo Bonzini
2010-04-15  0:13       ` malc
2010-04-15  0:26         ` Paolo Bonzini
2010-04-15  0:29           ` malc
2010-04-16  8:40     ` [Qemu-devel] " Gerd Hoffmann
2010-04-16 11:13       ` Gerd Hoffmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1271238922-10008-12-git-send-email-kraxel@redhat.com \
    --to=kraxel@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.