qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [5850] Add basic audio functionality to vnc.c


From: malc
Subject: [Qemu-devel] [5850] Add basic audio functionality to vnc.c
Date: Mon, 01 Dec 2008 20:57:49 +0000

Revision: 5850
          http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=5850
Author:   malc
Date:     2008-12-01 20:57:48 +0000 (Mon, 01 Dec 2008)

Log Message:
-----------
Add basic audio functionality to vnc.c

This allows among other things to capturing A/V of running
guests. Ad-hoc client that does this (via script that invokes ffmpeg)
can be found at:
http://repo.or.cz/w/qemu/malc.git?a=tree;f=vcap;hb=capture3

Thanks to Anthony Liguori for comments and review.

Modified Paths:
--------------
    trunk/vnc.c

Modified: trunk/vnc.c
===================================================================
--- trunk/vnc.c 2008-12-01 18:59:50 UTC (rev 5849)
+++ trunk/vnc.c 2008-12-01 20:57:48 UTC (rev 5850)
@@ -28,6 +28,7 @@
 #include "sysemu.h"
 #include "qemu_socket.h"
 #include "qemu-timer.h"
+#include "audio/audio.h"
 
 #define VNC_REFRESH_INTERVAL (1000 / 30)
 
@@ -169,6 +170,9 @@
     int client_green_shift, client_green_max, server_green_shift, 
server_green_max;
     int client_blue_shift, client_blue_max, server_blue_shift, server_blue_max;
 
+    CaptureVoiceOut *audio_cap;
+    audsettings_t as;
+
     VncReadEvent *read_handler;
     size_t read_handler_expect;
     /* input */
@@ -592,7 +596,7 @@
            old_row += ds_get_linesize(vs->ds);
        }
 
-       if (!has_dirty) {
+       if (!has_dirty && !vs->audio_cap) {
            qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + 
VNC_REFRESH_INTERVAL);
            return;
        }
@@ -681,6 +685,71 @@
     buffer->offset += len;
 }
 
+/* audio */
+static void audio_capture_notify(void *opaque, audcnotification_e cmd)
+{
+    VncState *vs = opaque;
+
+    switch (cmd) {
+    case AUD_CNOTIFY_DISABLE:
+        vnc_write_u8(vs, 255);
+        vnc_write_u8(vs, 1);
+        vnc_write_u16(vs, 0);
+        vnc_flush(vs);
+        break;
+
+    case AUD_CNOTIFY_ENABLE:
+        vnc_write_u8(vs, 255);
+        vnc_write_u8(vs, 1);
+        vnc_write_u16(vs, 1);
+        vnc_flush(vs);
+        break;
+    }
+}
+
+static void audio_capture_destroy(void *opaque)
+{
+}
+
+static void audio_capture(void *opaque, void *buf, int size)
+{
+    VncState *vs = opaque;
+
+    vnc_write_u8(vs, 255);
+    vnc_write_u8(vs, 1);
+    vnc_write_u16(vs, 2);
+    vnc_write_u32(vs, size);
+    vnc_write(vs, buf, size);
+    vnc_flush(vs);
+}
+
+static void audio_add(VncState *vs)
+{
+    struct audio_capture_ops ops;
+
+    if (vs->audio_cap) {
+        term_printf ("audio already running\n");
+        return;
+    }
+
+    ops.notify = audio_capture_notify;
+    ops.destroy = audio_capture_destroy;
+    ops.capture = audio_capture;
+
+    vs->audio_cap = AUD_add_capture(NULL, &vs->as, &ops, vs);
+    if (!vs->audio_cap) {
+        term_printf ("Failed to add audio capture\n");
+    }
+}
+
+static void audio_del(VncState *vs)
+{
+    if (vs->audio_cap) {
+        AUD_del_capture(vs->audio_cap, vs);
+        vs->audio_cap = NULL;
+    }
+}
+
 static int vnc_client_io_error(VncState *vs, int ret, int last_errno)
 {
     if (ret == 0 || ret == -1) {
@@ -712,6 +781,7 @@
        }
        vs->wiremode = VNC_WIREMODE_CLEAR;
 #endif /* CONFIG_VNC_TLS */
+        audio_del(vs);
        return 0;
     }
     return ret;
@@ -1138,6 +1208,15 @@
     vnc_flush(vs);
 }
 
+static void send_ext_audio_ack(VncState *vs)
+{
+    vnc_write_u8(vs, 0);
+    vnc_write_u8(vs, 0);
+    vnc_write_u16(vs, 1);
+    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), 
ds_get_height(vs->ds), -259);
+    vnc_flush(vs);
+}
+
 static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
 {
     int i;
@@ -1169,6 +1248,9 @@
         case -258:
             send_ext_key_event_ack(vs);
             break;
+        case -259:
+            send_ext_audio_ack(vs);
+            break;
         case 0x574D5669:
             vs->has_WMVi = 1;
             break;
@@ -1476,6 +1558,48 @@
             ext_key_event(vs, read_u16(data, 2),
                           read_u32(data, 4), read_u32(data, 8));
             break;
+        case 1:
+            if (len == 2)
+                return 4;
+
+            switch (read_u16 (data, 2)) {
+            case 0:
+                audio_add(vs);
+                break;
+            case 1:
+                audio_del(vs);
+                break;
+            case 2:
+                if (len == 4)
+                    return 10;
+                switch (read_u8(data, 4)) {
+                case 0: vs->as.fmt = AUD_FMT_U8; break;
+                case 1: vs->as.fmt = AUD_FMT_S8; break;
+                case 2: vs->as.fmt = AUD_FMT_U16; break;
+                case 3: vs->as.fmt = AUD_FMT_S16; break;
+                case 4: vs->as.fmt = AUD_FMT_U32; break;
+                case 5: vs->as.fmt = AUD_FMT_S32; break;
+                default:
+                    printf("Invalid audio format %d\n", read_u8(data, 4));
+                    vnc_client_error(vs);
+                    break;
+                }
+                vs->as.nchannels = read_u8(data, 5);
+                if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
+                    printf("Invalid audio channel coount %d\n",
+                           read_u8(data, 5));
+                    vnc_client_error(vs);
+                    break;
+                }
+                vs->as.freq = read_u32(data, 6);
+                break;
+            default:
+                printf ("Invalid audio message %d\n", read_u8(data, 4));
+                vnc_client_error(vs);
+                break;
+            }
+            break;
+
         default:
             printf("Msg: %d\n", read_u16(data, 0));
             vnc_client_error(vs);
@@ -2177,6 +2301,11 @@
 
     vnc_colordepth(vs->ds, 32);
     vnc_dpy_resize(vs->ds, 640, 400);
+
+    vs->as.freq = 44100;
+    vs->as.nchannels = 2;
+    vs->as.fmt = AUD_FMT_S16;
+    vs->as.endianness = 0;
 }
 
 #ifdef CONFIG_VNC_TLS
@@ -2269,6 +2398,7 @@
     vs->subauth = VNC_AUTH_INVALID;
     vs->x509verify = 0;
 #endif
+    audio_del(vs);
 }
 
 int vnc_display_password(DisplayState *ds, const char *password)






reply via email to

[Prev in Thread] Current Thread [Next in Thread]