[gtk-vnc] Convert connection over to use audio objects
- From: Daniel P. Berrange <dberrange src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk-vnc] Convert connection over to use audio objects
- Date: Fri, 9 Dec 2011 17:41:49 +0000 (UTC)
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]