[gtk-vnc] Convert connection over to use audio objects



commit 61a71e83723c026c637ce8816a188ff75193b5d3
Author: Daniel P. Berrange <berrange redhat com>
Date:   Thu Dec 8 21:45:04 2011 +0000

    Convert connection over to use audio objects
    
    * src/vncconnection.c, src/vncconnection.h: Convert to use
      VncAudio, VncAudioFormat & VncAudioSample objects
    * examples/Makefile.am, examples/gvncviewer.c: Convert to
      use new API & pulse audio object impl
    * src/vncmarshal.txt: Remove unused marshaller

 examples/Makefile.am    |    8 +-
 examples/gvncviewer.c   |   77 ++++----------
 src/libgvnc_sym.version |    9 +-
 src/vncconnection.c     |  272 ++++++++++++++++++++++++++---------------------
 src/vncconnection.h     |   15 ++-
 src/vncmarshal.txt      |    1 -
 6 files changed, 191 insertions(+), 191 deletions(-)
---
diff --git a/examples/Makefile.am b/examples/Makefile.am
index e7f7399..34ad27c 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -10,10 +10,12 @@ gvncviewer_LDADD = ../src/libgtk-vnc-$(GTK_VNC_API_VERSION).la \
                    ../src/libgvnc-1.0.la \
 		   @GTK_CFLAGS@ \
 		   @GTK_LIBS@ \
-		   @VIEW_LIBS@ \
-		   @PULSEAUDIO_LIBS@
+		   @VIEW_LIBS@
+if HAVE_PULSEAUDIO
+gvncviewer_LDADD += ../src/libgvncpulse-1.0.la
+endif
 gvncviewer_CFLAGS = @GTK_CFLAGS@ @WARNING_CFLAGS@ \
-		    @VIEW_CFLAGS@ @PULSEAUDIO_CFLAGS@ -I$(top_srcdir)/src/
+		    @VIEW_CFLAGS@ -I$(top_srcdir)/src/
 
 EXTRA_DIST = gvncviewer.py gvncviewer.js
 
diff --git a/examples/gvncviewer.c b/examples/gvncviewer.c
index a990e36..607cdfa 100644
--- a/examples/gvncviewer.c
+++ b/examples/gvncviewer.c
@@ -18,22 +18,19 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
  */
 
-#include "vncdisplay.h"
-#include "vncutil.h"
+#include "config.h"
+
+#include <vncdisplay.h>
+#include <vncutil.h>
+#ifdef HAVE_PULSEAUDIO
+#include <vncaudiopulse.h>
+#endif
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
 #include <stdlib.h>
 #include <string.h>
 #include <glib.h>
 
-#include "config.h"
-
-#ifdef HAVE_PULSEAUDIO
-#include <pulse/simple.h>
-#include <pulse/error.h>
-#include <pulse/gccmacro.h>
-#endif
-
 #if WITH_LIBVIEW
 #include <libview/autoDrawer.h>
 #endif
@@ -95,7 +92,7 @@ static const GOptionEntry options [] =
 };
 
 #ifdef HAVE_PULSEAUDIO
-static pa_simple *pulse=NULL;
+static VncAudioPulse *pa = NULL;
 #endif
 
 static GtkWidget *vnc;
@@ -167,10 +164,15 @@ static void vnc_initialized(GtkWidget *vncdisplay, GtkWidget *window)
 
 #ifdef HAVE_PULSEAUDIO
 	VncConnection *conn;
+	VncAudioFormat format = {
+		VNC_AUDIO_FORMAT_RAW_S32,
+		2,
+		44100,
+	};
 	conn = vnc_display_get_connection(VNC_DISPLAY(vncdisplay));
-	/* look at do_audio_begin() for the actual Pulse Audio setup */
-        vnc_connection_set_audio_format(conn, 3, 2, 44100);
-        vnc_connection_audio_enable(conn);
+	vnc_connection_set_audio_format(conn, &format);
+	vnc_connection_set_audio(conn, VNC_AUDIO(pa));
+	vnc_connection_audio_enable(conn);
 #endif
 }
 
@@ -195,40 +197,6 @@ static void vnc_disconnected(GtkWidget *vncdisplay G_GNUC_UNUSED)
 	gtk_main_quit();
 }
 
-#ifdef HAVE_PULSEAUDIO
-static void do_audio_data(GtkWidget *vncdisplay G_GNUC_UNUSED,
-	const char *data, unsigned int len)
-{
-	int paerror;
-
-	if (pulse && pa_simple_write(pulse, data, len, &paerror)<0)
-	{
-		printf("pa_simple_write() failed with: %s\n", pa_strerror(paerror));
-		pa_simple_free(pulse);
-		pulse=NULL;
-	}
-}
-
-
-static void do_audio_begin(GtkWidget *vncdisplay G_GNUC_UNUSED)
-{
-	pa_sample_spec pulse_spec;
-
-	pulse_spec.format=PA_SAMPLE_S16LE;
-	pulse_spec.channels=2;
-	pulse_spec.rate=44100;
-
-	pulse = pa_simple_new(NULL, "gtk-vnc", PA_STREAM_PLAYBACK, NULL, "gvncviewer", &pulse_spec, NULL, NULL, NULL);
-
-}
-
-static void do_audio_end(GtkWidget *vncdisplay G_GNUC_UNUSED)
-{
-	if (pulse) pa_simple_free(pulse);
-	pulse=NULL;
-}
-#endif
-
 static void send_caf1(GtkWidget *menu G_GNUC_UNUSED, GtkWidget *vncdisplay)
 {
 	guint keys[] = { GDK_Control_L, GDK_Alt_L, GDK_F1 };
@@ -650,6 +618,10 @@ int main(int argc, char **argv)
 #endif
 	menubar = gtk_menu_bar_new();
 
+#if HAVE_PULSEAUDIO
+	pa = vnc_audio_pulse_new();
+#endif
+
 	gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
 
 	sendkey = gtk_menu_item_new_with_mnemonic("_Send Key");
@@ -790,15 +762,6 @@ int main(int argc, char **argv)
 			 G_CALLBACK(window_state_event), layout);
 #endif
 
-#ifdef HAVE_PULSEAUDIO
-	g_signal_connect(vnc, "vnc-audio-begin",
-			 G_CALLBACK(do_audio_begin), NULL);
-	g_signal_connect(vnc, "vnc-audio-end",
-			 G_CALLBACK(do_audio_end), NULL);
-	g_signal_connect(vnc, "vnc-audio-data",
-			 G_CALLBACK(do_audio_data), NULL);
-#endif
-
 	gtk_main();
 
 	return 0;
diff --git a/src/libgvnc_sym.version b/src/libgvnc_sym.version
index 2efcec5..64a09dc 100644
--- a/src/libgvnc_sym.version
+++ b/src/libgvnc_sym.version
@@ -80,6 +80,11 @@
 	vnc_connection_auth_get_type;
 	vnc_connection_auth_vencrypt_get_type;
 	vnc_connection_credential_get_type;
+	vnc_connection_audio_enable;
+	vnc_connection_audio_disable;
+	vnc_connection_set_audio_format;
+	vnc_connection_get_audio_format;
+	vnc_connection_set_audio;
 
 	vnc_util_set_debug;
 	vnc_util_get_debug;
@@ -92,10 +97,6 @@
 	vnc_pixel_format_free;
 	vnc_pixel_format_get_type;
 
-	vnc_connection_audio_enable;
-	vnc_connection_audio_disable;
-	vnc_connection_set_audio_format;
-
     local:
 	*;
 };
diff --git a/src/vncconnection.c b/src/vncconnection.c
index 3791356..aea507e 100644
--- a/src/vncconnection.c
+++ b/src/vncconnection.c
@@ -185,9 +185,10 @@ struct _VncConnectionPrivate
 	gboolean audio_format_pending;
 	gboolean audio_enable_pending;
 	gboolean audio_disable_pending;
-	guint8   audio_format;
-	guint8   audio_channels;
-	guint32  audio_frequency;
+	VncAudioFormat audio_format;
+	VncAudio *audio;
+	VncAudioSample *audio_sample;
+	guint audio_timer;
 };
 
 G_DEFINE_TYPE(VncConnection, vnc_connection, G_TYPE_OBJECT);
@@ -212,18 +213,13 @@ enum {
 	VNC_INITIALIZED,
 	VNC_DISCONNECTED,
 
-	VNC_AUDIO_BEGIN,
-	VNC_AUDIO_END,
-	VNC_AUDIO_DATA,
-
 	VNC_LAST_SIGNAL,
 };
 
 static guint signals[VNC_LAST_SIGNAL] = { 0, 0, 0, 0,
 					  0, 0, 0, 0,
 					  0, 0, 0, 0,
-					  0, 0, 0, 0,
-					  0, 0 };
+					  0, 0, 0 };
 
 #define nibhi(a) (((a) >> 4) & 0x0F)
 #define niblo(a) ((a) & 0x0F)
@@ -417,10 +413,6 @@ struct signal_data
 			int width;
 			int height;
 		} size;
-		struct {
-			int length;
-			char *data;
-		} audio;
 		VncPixelFormat *pixelFormat;
 		const char *authReason;
 		unsigned int authUnsupported;
@@ -523,16 +515,6 @@ static gboolean do_vnc_connection_emit_main_context(gpointer opaque)
 			      data->params.authTypes);
 		break;
 
-	case VNC_AUDIO_DATA:
-		g_signal_emit(G_OBJECT(data->conn),
-			      signals[data->signum],
-			      0,
-			      data->params.audio.data,
-			      data->params.audio.length);
-		break;
-
-	case VNC_AUDIO_BEGIN:
-	case VNC_AUDIO_END:
 	case VNC_CONNECTED:
 	case VNC_INITIALIZED:
 	case VNC_DISCONNECTED:
@@ -1513,33 +1495,58 @@ gboolean vnc_connection_set_pixel_format(VncConnection *conn,
 }
 
 
-gboolean vnc_connection_set_audio_format(VncConnection *conn, guint32 format, guint32 channels, guint32 frequency)
+gboolean vnc_connection_set_audio(VncConnection *conn,
+				  VncAudio *audio)
+{
+	VncConnectionPrivate *priv = conn->priv;
+
+	if (priv->audio)
+		g_object_unref(priv->audio);
+	priv->audio = audio;
+	if (priv->audio)
+		g_object_ref(priv->audio);
+
+	return !vnc_connection_has_error(conn);
+}
+
+
+static void vnc_connection_send_audio_format(VncConnection *conn)
 {
 	VncConnectionPrivate *priv = conn->priv;
 
+	vnc_connection_buffered_write_u8(conn,  255);
+	vnc_connection_buffered_write_u8(conn,  1); /* VNC_CONNECTION_QEMU_AUDIO */
+	vnc_connection_buffered_write_u16(conn, 2); /* VNC_CONNECTION_QEMU_AUDIO_SET_FORMAT */
+
+	vnc_connection_buffered_write_u8(conn,  priv->audio_format.format);
+	vnc_connection_buffered_write_u8(conn,  priv->audio_format.nchannels);
+	vnc_connection_buffered_write_u32(conn, priv->audio_format.frequency);
+	vnc_connection_buffered_flush(conn);
+	priv->audio_format_pending=FALSE;
+}
+
+gboolean vnc_connection_set_audio_format(VncConnection *conn,
+					 const VncAudioFormat *fmt)
+{
+	VncConnectionPrivate *priv = conn->priv;
+
+	memcpy(&priv->audio_format, fmt, sizeof(*fmt));
+	priv->audio_format_pending = TRUE;
+
 	if (priv->has_audio)
-	{
-		vnc_connection_buffered_write_u8(conn,  255);
-		vnc_connection_buffered_write_u8(conn,  1); /* VNC_CONNECTION_QEMU_AUDIO */
-		vnc_connection_buffered_write_u16(conn, 2); /* VNC_CONNECTION_QEMU_AUDIO_SET_FORMAT */
-		
-		vnc_connection_buffered_write_u8(conn,  format);
-		vnc_connection_buffered_write_u8(conn,  channels);
-		vnc_connection_buffered_write_u32(conn, frequency);
-		vnc_connection_buffered_flush(conn);
-		priv->audio_format_pending=FALSE;
-	}	
-	else
-	{
-		priv->audio_format_pending=TRUE;
-		priv->audio_format=format;
-		priv->audio_channels=channels;
-		priv->audio_frequency=frequency;
-	}
-		
+		vnc_connection_send_audio_format(conn);
+
 	return !vnc_connection_has_error(conn);
 }
 
+
+const VncAudioFormat *vnc_connection_get_audio_format(VncConnection *conn)
+{
+	VncConnectionPrivate *priv = conn->priv;
+	return &priv->audio_format;
+}
+
+
 gboolean vnc_connection_audio_enable(VncConnection *conn)
 {
 	VncConnectionPrivate *priv = conn->priv;
@@ -2758,41 +2765,6 @@ static gboolean vnc_connection_validate_boundary(VncConnection *conn,
 }
 
 
-static void vnc_audio_sink_begin(VncConnection *conn)
-{
-	VncConnectionPrivate *priv = conn->priv;
-	struct signal_data sigdata;
-
-        if (priv->has_error)
-                return;
-
-	vnc_connection_emit_main_context(conn, VNC_AUDIO_BEGIN, &sigdata);
-}
-
-static void vnc_audio_sink_end(VncConnection *conn)
-{
-	VncConnectionPrivate *priv = conn->priv;
-	struct signal_data sigdata;
-
-        if (priv->has_error)
-                return;
-
-	vnc_connection_emit_main_context(conn, VNC_AUDIO_END, &sigdata);
-}
-
-static void vnc_audio_sink_data(VncConnection *conn, char *data, guint32 n_length)
-{
-	VncConnectionPrivate *priv = conn->priv;
-	struct signal_data sigdata;
-
-        if (priv->has_error)
-                return;
-
-	sigdata.params.audio.data = data;
-	sigdata.params.audio.length = n_length;
-	vnc_connection_emit_main_context(conn, VNC_AUDIO_DATA, &sigdata);
-}
-
 static gboolean vnc_connection_framebuffer_update(VncConnection *conn, gint32 etype,
 						  guint16 x, guint16 y,
 						  guint16 width, guint16 height)
@@ -2868,10 +2840,12 @@ static gboolean vnc_connection_framebuffer_update(VncConnection *conn, gint32 et
 	case VNC_CONNECTION_ENCODING_AUDIO:
 		priv->has_audio=TRUE;
 
-		if (priv->audio_disable_pending) vnc_connection_audio_disable(conn);
-		if (priv->audio_format_pending)  vnc_connection_set_audio_format(conn, priv->audio_format, priv->audio_channels, priv->audio_frequency);
-		if (priv->audio_enable_pending)  vnc_connection_audio_enable(conn);
-		
+		if (priv->audio_disable_pending)
+			vnc_connection_audio_disable(conn);
+		if (priv->audio_format_pending)
+			vnc_connection_send_audio_format(conn);
+		if (priv->audio_enable_pending)
+			vnc_connection_audio_enable(conn);
 		break;
 	default:
 		VNC_DEBUG("Received an unknown encoding type: %d", etype);
@@ -2882,6 +2856,60 @@ static gboolean vnc_connection_framebuffer_update(VncConnection *conn, gint32 et
 	return !vnc_connection_has_error(conn);
 }
 
+
+struct audio_action_data
+{
+	VncConnection *conn;
+	struct coroutine *caller;
+	int action;
+};
+
+static gboolean do_vnc_connection_audio_action(gpointer opaque)
+{
+	struct audio_action_data *data = opaque;
+	VncConnectionPrivate *priv = data->conn->priv;
+
+	VNC_DEBUG("Audio action main context %d", data->action);
+
+	switch (data->action) {
+	case 0:
+		vnc_audio_playback_stop(priv->audio);
+		break;
+	case 1:
+		vnc_audio_playback_start(priv->audio, &priv->audio_format);
+		break;
+	case 2:
+		vnc_audio_playback_data(priv->audio, priv->audio_sample);
+		break;
+	}
+
+	coroutine_yieldto(data->caller, NULL);
+	return FALSE;
+}
+
+static void vnc_connection_audio_action(VncConnection *conn,
+					int action)
+{
+	struct audio_action_data data = {
+		conn,
+		coroutine_self(),
+		action,
+	};
+
+	VNC_DEBUG("Emit audio action %d\n", action);
+
+	g_idle_add(do_vnc_connection_audio_action, &data);
+
+	/* This switches to the system coroutine context, lets
+	 * the idle function run to dispatch the action, and
+	 * finally returns once complete. ie this is synchronous
+	 * from the POV of the VNC coroutine despite there being
+	 * an idle function involved
+	 */
+	coroutine_yield(NULL);
+}
+
+
 static gboolean vnc_connection_server_message(VncConnection *conn)
 {
 	VncConnectionPrivate *priv = conn->priv;
@@ -3000,7 +3028,6 @@ static gboolean vnc_connection_server_message(VncConnection *conn)
 		case 1: { /* QEMU audio */
 			guint16 n_subtype;
 			guint32 n_length;
-			char *data;
 
 			n_subtype = vnc_connection_read_u16(conn);
 			switch (n_subtype) {
@@ -3011,15 +3038,44 @@ static gboolean vnc_connection_server_message(VncConnection *conn)
 					priv->has_error = TRUE;
 					break;
 				}
-				data = g_new(char, n_length);
-				vnc_connection_read(conn, data, n_length);
 				if (priv->has_error)
 					break;
-				vnc_audio_sink_data(conn, data, n_length);
-				g_free(data);
+
+				if (!priv->audio) {
+					VNC_DEBUG("No audio playback available");
+					priv->has_error = TRUE;
+					break;
+				}
+				priv->audio_sample = vnc_audio_sample_new(n_length);
+				vnc_connection_read(conn,
+						    priv->audio_sample->data,
+						    n_length);
+				priv->audio_sample->length += n_length;
+
+				vnc_connection_audio_action(conn, 2);
+
+				vnc_audio_sample_free(priv->audio_sample);
+				priv->audio_sample = NULL;
+				break;
+			case 1:
+				if (priv->audio)
+					vnc_connection_audio_action(conn, 1);
+				else
+					priv->has_error = TRUE;
+				break;
+			case 0:
+				if (priv->audio) {
+					if (priv->audio_sample) {
+						g_source_remove(priv->audio_timer);
+						vnc_connection_audio_action(conn, 2);
+						vnc_audio_sample_free(priv->audio_sample);
+						priv->audio_sample = NULL;
+					}
+					vnc_connection_audio_action(conn, 0);
+				} else {
+					priv->has_error = TRUE;
+				}
 				break;
-			case 1: vnc_audio_sink_begin(conn); break;
-			case 0: vnc_audio_sink_end(conn);  break;
 			default:
 				VNC_DEBUG("Received unknown QEMU audio message: %u", (int)n_subtype);
 				priv->has_error = TRUE;
@@ -4335,6 +4391,13 @@ static void vnc_connection_finalize (GObject *object)
 	if (priv->fb)
 		g_object_unref(G_OBJECT(priv->fb));
 
+	if (priv->audio)
+		g_object_unref(G_OBJECT(priv->audio));
+	if (priv->audio_sample)
+		g_object_unref(G_OBJECT(priv->audio_sample));
+	if (priv->audio_timer)
+		g_source_remove(priv->audio_timer);
+
 	G_OBJECT_CLASS(vnc_connection_parent_class)->finalize (object);
 }
 
@@ -4524,37 +4587,6 @@ static void vnc_connection_class_init(VncConnectionClass *klass)
 			      G_TYPE_NONE,
 			      0);
 
-	signals[VNC_AUDIO_BEGIN] =
-		g_signal_new ("vnc-audio-begin",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_FIRST,
-			      G_STRUCT_OFFSET (VncConnectionClass, vnc_audio_begin),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__VOID,
-			      G_TYPE_NONE,
-			      0);
-
-	signals[VNC_AUDIO_END] =
-		g_signal_new ("vnc-audio-end",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_FIRST,
-			      G_STRUCT_OFFSET (VncConnectionClass, vnc_audio_end),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__VOID,
-			      G_TYPE_NONE,
-			      0);
-
-	signals[VNC_AUDIO_DATA] =
-		g_signal_new ("vnc-audio-data",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_FIRST,
-			      G_STRUCT_OFFSET (VncConnectionClass, vnc_audio_data),
-			      NULL, NULL,
-			      g_cclosure_user_marshal_VOID__POINTER_UINT,
-			      G_TYPE_NONE,
-			      2,
-			      G_TYPE_POINTER,
-			      G_TYPE_UINT);
 
 	g_type_class_add_private(klass, sizeof(VncConnectionPrivate));
 }
diff --git a/src/vncconnection.h b/src/vncconnection.h
index f8054ee..ee05d29 100644
--- a/src/vncconnection.h
+++ b/src/vncconnection.h
@@ -27,6 +27,7 @@
 #include <vncframebuffer.h>
 #include <vnccursor.h>
 #include <vncutil.h>
+#include <vncaudio.h>
 
 G_BEGIN_DECLS
 
@@ -72,10 +73,6 @@ struct _VncConnectionClass
 	void (*vnc_initialized)(VncConnection *conn);
 	void (*vnc_disconnected)(VncConnection *conn);
 
-	void (*vnc_audio_begin)(VncConnection *conn);
-	void (*vnc_audio_end)(VncConnection *conn);
-	void (*vnc_audio_data)(VncConnection *conn, const char *data, unsigned int length);
-
 	/*
 	 * If adding fields to this struct, remove corresponding
 	 * amount of padding to avoid changing overall struct size
@@ -115,7 +112,7 @@ typedef enum {
 
 	VNC_CONNECTION_ENCODING_POINTER_CHANGE = -257,
 	VNC_CONNECTION_ENCODING_EXT_KEY_EVENT = -258,
-        VNC_CONNECTION_ENCODING_AUDIO = -259,
+	VNC_CONNECTION_ENCODING_AUDIO = -259,
 } VncConnectionEncoding;
 
 typedef enum {
@@ -205,7 +202,13 @@ VncCursor *vnc_connection_get_cursor(VncConnection *conn);
 gboolean vnc_connection_get_abs_pointer(VncConnection *conn);
 gboolean vnc_connection_get_ext_key_event(VncConnection *conn);
 
-gboolean vnc_connection_set_audio_format(VncConnection *conn, guint32 format, guint32 channels, guint32 frequency);
+gboolean vnc_connection_set_audio(VncConnection *conn,
+				  VncAudio *audio);
+
+gboolean vnc_connection_set_audio_format(VncConnection *conn,
+					 const VncAudioFormat *fmt);
+const VncAudioFormat *vnc_connection_get_audio_format(VncConnection *conn);
+
 gboolean vnc_connection_audio_enable(VncConnection *conn);
 gboolean vnc_connection_audio_disable(VncConnection *conn);
 
diff --git a/src/vncmarshal.txt b/src/vncmarshal.txt
index 23248cc..b60bcaf 100644
--- a/src/vncmarshal.txt
+++ b/src/vncmarshal.txt
@@ -1,4 +1,3 @@
 VOID:INT,INT
 VOID:INT,INT,INT,INT
 VOID:UINT,BOXED
-VOID:POINTER,UINT



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