Marc, What does VMC stand for here? Is it related to my idea of virtual media controller, or just a coincidence? Looks like it is related, as it is a transport API to be used for anyone wanting to pass arbitrary data through additional Spice channel - correct? If so, I suggest renaming this component so it has more generic and clear name - as VMC may be confusing for others... I don't have good proposals right now though, only semi-good like data_stream, custom_stream, generic_stream, transport_stream... Also, having a comment inside the header describing the purpose of the API would help. Small update from us: we are doing an internal VMC proof of concept, it is based on closed and open-source software we're familiar with - to speed the things up. For this initial PoC, we're using our own wrapper over Google WebRTC media engine (instead of GStreamer, which we need to learn) and Apache Thrift RPC transported over TCP socket. Things look good so far - remote control of speakers and mic work fine, working on an IP call now... After that, I'm planning to work on a GStreamer-based prototype - and later use this VmcStream to implement Thrift transport interface. Actually, what do you think about using Thrift for RPC? It looks like suiting our needs better than Google Protocol Buffers - at least it is a complete RPC solution while protobuf provides only marshaling, the whole RPC needs to be added on top of it... On Sat, Nov 16, 2013 at 1:15 AM, Marc-André Lureau <marcandre.lureau@xxxxxxxxx> wrote: > From: Marc-André Lureau <marcandre.lureau@xxxxxxxxxx> > > This allows to use conveniently GIOStream APIs without caring about > coroutine and Spice messages details. > --- > gtk/Makefile.am | 2 + > gtk/channel-base.c | 48 ++++++ > gtk/channel-port.c | 33 +--- > gtk/spice-channel-priv.h | 8 + > gtk/vmcstream.c | 436 +++++++++++++++++++++++++++++++++++++++++++++++ > gtk/vmcstream.h | 69 ++++++++ > 6 files changed, 566 insertions(+), 30 deletions(-) > create mode 100644 gtk/vmcstream.c > create mode 100644 gtk/vmcstream.h > > diff --git a/gtk/Makefile.am b/gtk/Makefile.am > index f82e614..7b38d1c 100644 > --- a/gtk/Makefile.am > +++ b/gtk/Makefile.am > @@ -253,6 +253,8 @@ libspice_client_glib_2_0_la_SOURCES = \ > usbutil.c \ > usbutil.h \ > $(USB_ACL_HELPER_SRCS) \ > + vmcstream.c \ > + vmcstream.h \ > \ > decode.h \ > decode-glz.c \ > diff --git a/gtk/channel-base.c b/gtk/channel-base.c > index 646042d..363dda5 100644 > --- a/gtk/channel-base.c > +++ b/gtk/channel-base.c > @@ -232,3 +232,51 @@ void spice_channel_set_handlers(SpiceChannelClass *klass, > spice_channel_add_base_handlers(klass); > set_handlers(klass, handlers, n); > } > + > +static void > +vmc_write_free_cb(uint8_t *data, void *user_data) > +{ > + GSimpleAsyncResult *result = user_data; > + > + g_simple_async_result_complete_in_idle(result); > + g_object_unref(result); > +} > + > +G_GNUC_INTERNAL > +void spice_vmc_write_async(SpiceChannel *self, > + const void *buffer, gsize count, > + GCancellable *cancellable, > + GAsyncReadyCallback callback, > + gpointer user_data) > +{ > + SpiceMsgOut *msg; > + GSimpleAsyncResult *simple; > + > + simple = g_simple_async_result_new(G_OBJECT(self), callback, user_data, > + spice_port_write_async); > + g_simple_async_result_set_op_res_gssize(simple, count); > + > + msg = spice_msg_out_new(SPICE_CHANNEL(self), SPICE_MSGC_SPICEVMC_DATA); > + spice_marshaller_add_ref_full(msg->marshaller, (uint8_t*)buffer, count, > + vmc_write_free_cb, simple); > + spice_msg_out_send(msg); > +} > + > +G_GNUC_INTERNAL > +gssize spice_vmc_write_finish(SpiceChannel *self, > + GAsyncResult *result, GError **error) > +{ > + GSimpleAsyncResult *simple; > + > + g_return_val_if_fail(result != NULL, -1); > + > + simple = (GSimpleAsyncResult *)result; > + > + if (g_simple_async_result_propagate_error(simple, error)) > + return -1; > + > + g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(self), > + spice_port_write_async), -1); > + > + return g_simple_async_result_get_op_res_gssize(simple); > +} > diff --git a/gtk/channel-port.c b/gtk/channel-port.c > index 11948bb..ec3de86 100644 > --- a/gtk/channel-port.c > +++ b/gtk/channel-port.c > @@ -286,14 +286,6 @@ static void port_handle_msg(SpiceChannel *channel, SpiceMsgIn *in) > emit_main_context(channel, SPICE_PORT_DATA, buf, size); > } > > -static void port_write_free_cb(uint8_t *data, void *user_data) > -{ > - GSimpleAsyncResult *result = user_data; > - > - g_simple_async_result_complete(result); > - g_object_unref(result); > -} > - > /** > * spice_port_write_async: > * @port: A #SpicePortChannel > @@ -317,9 +309,7 @@ void spice_port_write_async(SpicePortChannel *self, > GAsyncReadyCallback callback, > gpointer user_data) > { > - GSimpleAsyncResult *simple; > SpicePortChannelPrivate *c; > - SpiceMsgOut *msg; > > g_return_if_fail(SPICE_IS_PORT_CHANNEL(self)); > g_return_if_fail(buffer != NULL); > @@ -332,14 +322,8 @@ void spice_port_write_async(SpicePortChannel *self, > return; > } > > - simple = g_simple_async_result_new(G_OBJECT(self), callback, user_data, > - spice_port_write_async); > - g_simple_async_result_set_op_res_gssize(simple, count); > - > - msg = spice_msg_out_new(SPICE_CHANNEL(self), SPICE_MSGC_SPICEVMC_DATA); > - spice_marshaller_add_ref_full(msg->marshaller, (uint8_t*)buffer, count, > - port_write_free_cb, simple); > - spice_msg_out_send(msg); > + spice_vmc_write_async(SPICE_CHANNEL(self), buffer, count, > + cancellable, callback, user_data); > } > > /** > @@ -357,20 +341,9 @@ void spice_port_write_async(SpicePortChannel *self, > gssize spice_port_write_finish(SpicePortChannel *self, > GAsyncResult *result, GError **error) > { > - GSimpleAsyncResult *simple; > - > g_return_val_if_fail(SPICE_IS_PORT_CHANNEL(self), -1); > - g_return_val_if_fail(result != NULL, -1); > - > - simple = (GSimpleAsyncResult *)result; > - > - if (g_simple_async_result_propagate_error(simple, error)) > - return -1; > - > - g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(self), > - spice_port_write_async), -1); > > - return g_simple_async_result_get_op_res_gssize(simple); > + return spice_vmc_write_finish(SPICE_CHANNEL(self), result, error); > } > > /** > diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h > index 351126f..1e35e1f 100644 > --- a/gtk/spice-channel-priv.h > +++ b/gtk/spice-channel-priv.h > @@ -196,6 +196,14 @@ void spice_caps_set(GArray *caps, guint32 cap, const gchar *desc); > > gchar *spice_channel_supported_string(void); > > +void spice_vmc_write_async(SpiceChannel *self, > + const void *buffer, gsize count, > + GCancellable *cancellable, > + GAsyncReadyCallback callback, > + gpointer user_data); > +gssize spice_vmc_write_finish(SpiceChannel *self, > + GAsyncResult *result, GError **error); > + > G_END_DECLS > > #endif /* __SPICE_CLIENT_CHANNEL_PRIV_H__ */ > diff --git a/gtk/vmcstream.c b/gtk/vmcstream.c > new file mode 100644 > index 0000000..02af959 > --- /dev/null > +++ b/gtk/vmcstream.c > @@ -0,0 +1,436 @@ > +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ > +/* > + Copyright (C) 2013 Red Hat, Inc. > + > + This library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + This library is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with this library; if not, see <http://www.gnu.org/licenses/>. > +*/ > +#include <string.h> > + > +#include "vmcstream.h" > +#include "spice-channel-priv.h" > +#include "gio-coroutine.h" > + > +struct _SpiceVmcInputStream > +{ > + GInputStream parent_instance; > + GSimpleAsyncResult *result; > + struct coroutine *coroutine; > + > + SpiceChannel *channel; > + guint8 *buffer; > + gsize count; > + > + GCancellable *cancellable; > + gulong cancel_id; > +}; > + > +struct _SpiceVmcInputStreamClass > +{ > + GInputStreamClass parent_class; > +}; > + > +static gssize spice_vmc_input_stream_read (GInputStream *stream, > + void *buffer, > + gsize count, > + GCancellable *cancellable, > + GError **error); > +static void spice_vmc_input_stream_read_async (GInputStream *stream, > + void *buffer, > + gsize count, > + int io_priority, > + GCancellable *cancellable, > + GAsyncReadyCallback callback, > + gpointer user_data); > +static gssize spice_vmc_input_stream_read_finish (GInputStream *stream, > + GAsyncResult *result, > + GError **error); > +static gssize spice_vmc_input_stream_skip (GInputStream *stream, > + gsize count, > + GCancellable *cancellable, > + GError **error); > +static gboolean spice_vmc_input_stream_close (GInputStream *stream, > + GCancellable *cancellable, > + GError **error); > +static void spice_vmc_input_stream_finalize (GObject *object); > + > +G_DEFINE_TYPE_WITH_CODE(SpiceVmcInputStream, spice_vmc_input_stream, G_TYPE_INPUT_STREAM,) > + > + > +static void > +spice_vmc_input_stream_class_init(SpiceVmcInputStreamClass *klass) > +{ > + GObjectClass *object_class; > + GInputStreamClass *istream_class; > + > + object_class = G_OBJECT_CLASS(klass); > + object_class->finalize = spice_vmc_input_stream_finalize; > + > + istream_class = G_INPUT_STREAM_CLASS(klass); > + istream_class->read_fn = spice_vmc_input_stream_read; > + istream_class->read_async = spice_vmc_input_stream_read_async; > + istream_class->read_finish = spice_vmc_input_stream_read_finish; > + istream_class->skip = spice_vmc_input_stream_skip; > + istream_class->close_fn = spice_vmc_input_stream_close; > +} > + > +static void > +spice_vmc_input_stream_finalize(GObject *object) > +{ > + G_OBJECT_CLASS (spice_vmc_input_stream_parent_class)->finalize(object); > +} > + > +static void > +spice_vmc_input_stream_init(SpiceVmcInputStream *self) > +{ > +} > + > +static SpiceVmcInputStream * > +spice_vmc_input_stream_new(void) > +{ > + SpiceVmcInputStream *self; > + > + self = g_object_new(SPICE_TYPE_VMC_INPUT_STREAM, NULL); > + > + return self; > +} > + > +/* coroutine */ > +G_GNUC_INTERNAL void > +spice_vmc_input_stream_co_data(SpiceVmcInputStream *self, > + const gpointer d, gsize size) > +{ > + guint8 *data = d; > + > + g_return_if_fail(SPICE_IS_VMC_INPUT_STREAM(self)); > + g_return_if_fail(self->coroutine == NULL); > + > + self->coroutine = coroutine_self(); > + > + while (size > 0) { > + if (!self->result) > + coroutine_yield(NULL); > + > + g_return_if_fail(self->result != NULL); > + > + gsize min = MIN(self->count, size); > + memcpy(self->buffer, data, min); > + > + size -= min; > + data += min; > + > + self->count -= min; > + self->buffer += min; > + > + if (self->count == 0) { > + g_simple_async_result_complete_in_idle(self->result); > + g_clear_object(&self->result); > + } > + } > + > + self->coroutine = NULL; > +} > + > +static void > +read_cancelled(GCancellable *cancellable, > + gpointer user_data) > +{ > + SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(user_data); > + > + g_simple_async_result_complete_in_idle(self->result); > + g_clear_object(&self->result); > +} > + > +static void > +spice_vmc_input_stream_read_async(GInputStream *stream, > + void *buffer, > + gsize count, > + int io_priority, > + GCancellable *cancellable, > + GAsyncReadyCallback callback, > + gpointer user_data) > +{ > + SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(stream); > + GSimpleAsyncResult *result; > + > + /* no concurrent read permitted by ginputstream */ > + g_return_if_fail(self->result == NULL); > + self->buffer = buffer; > + self->count = count; > + result = g_simple_async_result_new(G_OBJECT(self), > + callback, > + user_data, > + spice_vmc_input_stream_read_async); > + g_simple_async_result_set_op_res_gssize(result, count); > + self->result = result; > + self->cancellable = g_object_ref(cancellable); > + if (cancellable) > + self->cancel_id = > + g_cancellable_connect(cancellable, G_CALLBACK(read_cancelled), self, NULL); > + > + if (self->coroutine) > + coroutine_yieldto(self->coroutine, NULL); > +} > + > +static gssize > +spice_vmc_input_stream_read_finish(GInputStream *stream, > + GAsyncResult *result, > + GError **error) > +{ > + GSimpleAsyncResult *simple; > + SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(stream); > + > + g_return_val_if_fail(g_simple_async_result_is_valid(result, > + G_OBJECT(self), > + spice_vmc_input_stream_read_async), > + -1); > + > + if (self->cancellable) { > + g_cancellable_disconnect(self->cancellable, self->cancel_id); > + g_clear_object(&self->cancellable); > + } > + > + simple = (GSimpleAsyncResult *)result; > + > + if (g_simple_async_result_propagate_error(simple, error)) > + return -1; > + > + return g_simple_async_result_get_op_res_gssize(simple); > +} > + > +static gssize > +spice_vmc_input_stream_read(GInputStream *stream, > + void *buffer, > + gsize count, > + GCancellable *cancellable, > + GError **error) > +{ > + g_return_val_if_reached(-1); > +} > + > +static gssize > +spice_vmc_input_stream_skip(GInputStream *stream, > + gsize count, > + GCancellable *cancellable, > + GError **error) > +{ > + g_return_val_if_reached(-1); > +} > + > +static gboolean > +spice_vmc_input_stream_close(GInputStream *stream, > + GCancellable *cancellable, > + GError **error) > +{ > + g_return_val_if_reached(TRUE); > +} > + > +/* OUTPUT */ > + > +struct _SpiceVmcOutputStream > +{ > + GOutputStream parent_instance; > + > + SpiceChannel *channel; /* weak */ > +}; > + > +struct _SpiceVmcOutputStreamClass > +{ > + GOutputStreamClass parent_class; > +}; > + > +static void spice_vmc_output_stream_finalize (GObject *object); > +static gssize spice_vmc_output_stream_write_fn (GOutputStream *stream, > + const void *buffer, > + gsize count, > + GCancellable *cancellable, > + GError **error); > +static gssize spice_vmc_output_stream_write_finish (GOutputStream *stream, > + GAsyncResult *result, > + GError **error); > +static void spice_vmc_output_stream_write_async (GOutputStream *stream, > + const void *buffer, > + gsize count, > + int io_priority, > + GCancellable *cancellable, > + GAsyncReadyCallback callback, > + gpointer user_data); > + > +G_DEFINE_TYPE_WITH_CODE(SpiceVmcOutputStream, spice_vmc_output_stream, G_TYPE_OUTPUT_STREAM,) > + > + > +static void > +spice_vmc_output_stream_class_init(SpiceVmcOutputStreamClass *klass) > +{ > + GObjectClass *object_class; > + GOutputStreamClass *ostream_class; > + > + object_class = G_OBJECT_CLASS(klass); > + object_class->finalize = spice_vmc_output_stream_finalize; > + > + ostream_class = G_OUTPUT_STREAM_CLASS(klass); > + ostream_class->write_fn = spice_vmc_output_stream_write_fn; > + ostream_class->write_async = spice_vmc_output_stream_write_async; > + ostream_class->write_finish = spice_vmc_output_stream_write_finish; > +} > + > +static void > +spice_vmc_output_stream_finalize(GObject *object) > +{ > + G_OBJECT_CLASS(spice_vmc_output_stream_parent_class)->finalize(object); > +} > + > +static void > +spice_vmc_output_stream_init(SpiceVmcOutputStream *self) > +{ > +} > + > +static SpiceVmcOutputStream * > +spice_vmc_output_stream_new(SpiceChannel *channel) > +{ > + SpiceVmcOutputStream *self; > + > + self = g_object_new(SPICE_TYPE_VMC_OUTPUT_STREAM, NULL); > + self->channel = channel; > + > + return self; > +} > + > +static gssize > +spice_vmc_output_stream_write_fn(GOutputStream *stream, > + const void *buffer, > + gsize count, > + GCancellable *cancellable, > + GError **error) > +{ > + SpiceVmcOutputStream *self = SPICE_VMC_OUTPUT_STREAM(stream); > + SpiceMsgOut *msg_out; > + > + msg_out = spice_msg_out_new(SPICE_CHANNEL(self->channel), > + SPICE_MSGC_SPICEVMC_DATA); > + spice_marshaller_add(msg_out->marshaller, buffer, count); > + spice_msg_out_send(msg_out); > + > + return count; > +} > + > +static gssize > +spice_vmc_output_stream_write_finish(GOutputStream *stream, > + GAsyncResult *result, > + GError **error) > +{ > + SpiceVmcOutputStream *self = SPICE_VMC_OUTPUT_STREAM(stream); > + > + return spice_vmc_write_finish(self->channel, result, error); > +} > + > +static void > +spice_vmc_output_stream_write_async(GOutputStream *stream, > + const void *buffer, > + gsize count, > + int io_priority, > + GCancellable *cancellable, > + GAsyncReadyCallback callback, > + gpointer user_data) > +{ > + SpiceVmcOutputStream *self = SPICE_VMC_OUTPUT_STREAM(stream); > + > + spice_vmc_write_async(self->channel, buffer, count, > + cancellable, callback, > + self); > +} > + > +/* STREAM */ > + > +struct _SpiceVmcStream > +{ > + GIOStream parent_instance; > + > + SpiceChannel *channel; /* weak */ > + SpiceVmcInputStream *in; > + SpiceVmcOutputStream *out; > +}; > + > +struct _SpiceVmcStreamClass > +{ > + GIOStreamClass parent_class; > +}; > + > +static void spice_vmc_stream_finalize (GObject *object); > +static GInputStream * spice_vmc_stream_get_input_stream (GIOStream *stream); > +static GOutputStream * spice_vmc_stream_get_output_stream (GIOStream *stream); > + > +G_DEFINE_TYPE_WITH_CODE(SpiceVmcStream, spice_vmc_stream, G_TYPE_IO_STREAM,) > + > +static void > +spice_vmc_stream_class_init(SpiceVmcStreamClass *klass) > +{ > + GObjectClass *object_class; > + GIOStreamClass *iostream_class; > + > + object_class = G_OBJECT_CLASS(klass); > + object_class->finalize = spice_vmc_stream_finalize; > + > + iostream_class = G_IO_STREAM_CLASS(klass); > + iostream_class->get_input_stream = spice_vmc_stream_get_input_stream; > + iostream_class->get_output_stream = spice_vmc_stream_get_output_stream; > +} > + > +static void > +spice_vmc_stream_finalize(GObject *object) > +{ > + SpiceVmcStream *self = SPICE_VMC_STREAM(object); > + > + g_clear_object(&self->in); > + g_clear_object(&self->out); > + > + G_OBJECT_CLASS(spice_vmc_stream_parent_class)->finalize(object); > +} > + > +static void > +spice_vmc_stream_init(SpiceVmcStream *self) > +{ > +} > + > +SpiceVmcStream * > +spice_vmc_stream_new(SpiceChannel *channel) > +{ > + SpiceVmcStream *self; > + > + self = g_object_new(SPICE_TYPE_VMC_STREAM, NULL); > + self->channel = channel; > + > + return self; > +} > + > +static GInputStream * > +spice_vmc_stream_get_input_stream(GIOStream *stream) > +{ > + SpiceVmcStream *self = SPICE_VMC_STREAM(stream); > + > + if (!self->in) > + self->in = spice_vmc_input_stream_new(); > + > + return G_INPUT_STREAM(self->in); > +} > + > +static GOutputStream * > +spice_vmc_stream_get_output_stream(GIOStream *stream) > +{ > + SpiceVmcStream *self = SPICE_VMC_STREAM(stream); > + > + if (!self->out) > + self->out = spice_vmc_output_stream_new(self->channel); > + > + return G_OUTPUT_STREAM(self->out); > +} > diff --git a/gtk/vmcstream.h b/gtk/vmcstream.h > new file mode 100644 > index 0000000..f6a1f4a > --- /dev/null > +++ b/gtk/vmcstream.h > @@ -0,0 +1,69 @@ > +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ > +/* > + Copyright (C) 2013 Red Hat, Inc. > + > + This library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + This library is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with this library; if not, see <http://www.gnu.org/licenses/>. > +*/ > +#ifndef __SPICE_VMC_STREAM_H__ > +#define __SPICE_VMC_STREAM_H__ > + > +#include <gio/gio.h> > + > +#include "spice-types.h" > + > +G_BEGIN_DECLS > + > +#define SPICE_TYPE_VMC_INPUT_STREAM (spice_vmc_input_stream_get_type ()) > +#define SPICE_VMC_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SPICE_TYPE_VMC_INPUT_STREAM, SpiceVmcInputStream)) > +#define SPICE_VMC_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SPICE_TYPE_VMC_INPUT_STREAM, SpiceVmcInputStreamClass)) > +#define SPICE_IS_VMC_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SPICE_TYPE_VMC_INPUT_STREAM)) > +#define SPICE_IS_VMC_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SPICE_TYPE_VMC_INPUT_STREAM)) > +#define SPICE_VMC_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SPICE_TYPE_VMC_INPUT_STREAM, SpiceVmcInputStreamClass)) > + > +typedef struct _SpiceVmcInputStreamClass SpiceVmcInputStreamClass; > +typedef struct _SpiceVmcInputStream SpiceVmcInputStream; > + > +GType spice_vmc_input_stream_get_type (void) G_GNUC_CONST; > +void spice_vmc_input_stream_co_data (SpiceVmcInputStream *input, > + const gpointer data, > + gsize size); > + > +#define SPICE_TYPE_VMC_OUTPUT_STREAM (spice_vmc_output_stream_get_type ()) > +#define SPICE_VMC_OUTPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SPICE_TYPE_VMC_OUTPUT_STREAM, SpiceVmcOutputStream)) > +#define SPICE_VMC_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SPICE_TYPE_VMC_OUTPUT_STREAM, SpiceVmcOutputStreamClass)) > +#define SPICE_IS_VMC_OUTPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SPICE_TYPE_VMC_OUTPUT_STREAM)) > +#define SPICE_IS_VMC_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SPICE_TYPE_VMC_OUTPUT_STREAM)) > +#define SPICE_VMC_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SPICE_TYPE_VMC_OUTPUT_STREAM, SpiceVmcOutputStreamClass)) > + > +typedef struct _SpiceVmcOutputStreamClass SpiceVmcOutputStreamClass; > +typedef struct _SpiceVmcOutputStream SpiceVmcOutputStream; > + > +GType spice_vmc_output_stream_get_type (void) G_GNUC_CONST; > + > +#define SPICE_TYPE_VMC_STREAM (spice_vmc_stream_get_type ()) > +#define SPICE_VMC_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SPICE_TYPE_VMC_STREAM, SpiceVmcStream)) > +#define SPICE_VMC_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SPICE_TYPE_VMC_STREAM, SpiceVmcStreamClass)) > +#define SPICE_IS_VMC_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SPICE_TYPE_VMC_STREAM)) > +#define SPICE_IS_VMC_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SPICE_TYPE_VMC_STREAM)) > +#define SPICE_VMC_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SPICE_TYPE_VMC_STREAM, SpiceVmcStreamClass)) > + > +typedef struct _SpiceVmcStreamClass SpiceVmcStreamClass; > +typedef struct _SpiceVmcStream SpiceVmcStream; > + > +GType spice_vmc_stream_get_type (void) G_GNUC_CONST; > +SpiceVmcStream* spice_vmc_stream_new (SpiceChannel *channel); > + > +G_END_DECLS > + > +#endif /* __SPICE_VMC_STREAM_H__ */ > -- > 1.8.3.1 > > _______________________________________________ > Spice-devel mailing list > Spice-devel@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/spice-devel -- Best regards, Fedor _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel