diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2010-10-18 15:13:39 +0200 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2010-10-18 15:15:18 +0200 |
commit | 0776f1100997d4fe1b1b46cfb9501950b8626407 (patch) | |
tree | bbc1476292267526fce3edc60587ea20e95d2675 | |
parent | 16aac9ed6b927a0277aed4cf33176f6dc265f725 (diff) |
sound: add recording [not finished yet]
-rw-r--r-- | gtk/channel-record.c | 117 | ||||
-rw-r--r-- | gtk/channel-record.h | 41 | ||||
-rw-r--r-- | gtk/spice-channel-priv.h | 1 | ||||
-rw-r--r-- | gtk/spice-channel.c | 3 | ||||
-rw-r--r-- | gtk/spice-client.h | 1 | ||||
-rw-r--r-- | gtk/spice-pulse.c | 50 |
6 files changed, 206 insertions, 7 deletions
diff --git a/gtk/channel-record.c b/gtk/channel-record.c index e69de29..c2eb27a 100644 --- a/gtk/channel-record.c +++ b/gtk/channel-record.c @@ -0,0 +1,117 @@ +#include "spice-client.h" +#include "spice-common.h" + +#include "spice-marshal.h" + +#define SPICE_RECORD_CHANNEL_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), SPICE_TYPE_RECORD_CHANNEL, spice_record_channel)) + +struct spice_record_channel { + int mode; +}; + +G_DEFINE_TYPE(SpiceRecordChannel, spice_record_channel, SPICE_TYPE_CHANNEL) + +enum { + SPICE_RECORD_START, + SPICE_RECORD_STOP, + + SPICE_RECORD_LAST_SIGNAL, +}; + +static guint signals[SPICE_RECORD_LAST_SIGNAL]; + +static void spice_record_handle_msg(SpiceChannel *channel, spice_msg_in *msg); + +/* ------------------------------------------------------------------ */ + +static void spice_record_channel_init(SpiceRecordChannel *channel) +{ + spice_record_channel *c; + + c = channel->priv = SPICE_RECORD_CHANNEL_GET_PRIVATE(channel); + memset(c, 0, sizeof(*c)); +} + +static void spice_record_channel_finalize(GObject *obj) +{ + if (G_OBJECT_CLASS(spice_record_channel_parent_class)->finalize) + G_OBJECT_CLASS(spice_record_channel_parent_class)->finalize(obj); +} + +static void spice_record_channel_class_init(SpiceRecordChannelClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + SpiceChannelClass *channel_class = SPICE_CHANNEL_CLASS(klass); + + gobject_class->finalize = spice_record_channel_finalize; + channel_class->handle_msg = spice_record_handle_msg; + + signals[SPICE_RECORD_START] = + g_signal_new("spice-record-start", + G_OBJECT_CLASS_TYPE(gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(SpiceRecordChannelClass, spice_record_start), + NULL, NULL, + g_cclosure_user_marshal_VOID__INT_INT_INT, + G_TYPE_NONE, + 3, + G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); + + signals[SPICE_RECORD_STOP] = + g_signal_new("spice-record-stop", + G_OBJECT_CLASS_TYPE(gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(SpiceRecordChannelClass, spice_record_stop), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + g_type_class_add_private(klass, sizeof(spice_record_channel)); +} + +/* ------------------------------------------------------------------ */ + +static void record_handle_start(SpiceChannel *channel, spice_msg_in *in) +{ + spice_record_channel *c = SPICE_RECORD_CHANNEL(channel)->priv; + SpiceMsgRecordStart *start = spice_msg_in_parsed(in); + +#if 0 + fprintf(stderr, "%s: fmt %d channels %d freq %d time %d\n", __FUNCTION__, + start->format, start->channels, start->frequency, start->time); +#endif + + switch (c->mode) { + case SPICE_AUDIO_DATA_MODE_RAW: + g_signal_emit(channel, signals[SPICE_RECORD_START], 0, + start->format, start->channels, start->frequency); + break; + default: + fprintf(stderr, "%s: unhandled mode\n", __FUNCTION__); + break; + } +} + +static void record_handle_stop(SpiceChannel *channel, spice_msg_in *in) +{ + g_signal_emit(channel, signals[SPICE_RECORD_STOP], 0); +} + +static spice_msg_handler record_handlers[] = { + [ SPICE_MSG_SET_ACK ] = spice_channel_handle_set_ack, + [ SPICE_MSG_PING ] = spice_channel_handle_ping, + [ SPICE_MSG_NOTIFY ] = spice_channel_handle_notify, + + [ SPICE_MSG_RECORD_START ] = record_handle_start, + [ SPICE_MSG_RECORD_STOP ] = record_handle_stop, +}; + +static void spice_record_handle_msg(SpiceChannel *channel, spice_msg_in *msg) +{ + int type = spice_msg_in_type(msg); + assert(type < SPICE_N_ELEMENTS(record_handlers)); + assert(record_handlers[type] != NULL); + record_handlers[type](channel, msg); +} diff --git a/gtk/channel-record.h b/gtk/channel-record.h index e69de29..f880637 100644 --- a/gtk/channel-record.h +++ b/gtk/channel-record.h @@ -0,0 +1,41 @@ +#ifndef __SPICE_CLIENT_RECORD_CHANNEL_H__ +#define __SPICE_CLIENT_RECORD_CHANNEL_H__ + +#include "spice-client.h" + +G_BEGIN_DECLS + +#define SPICE_TYPE_RECORD_CHANNEL (spice_record_channel_get_type()) +#define SPICE_RECORD_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SPICE_TYPE_RECORD_CHANNEL, SpiceRecordChannel)) +#define SPICE_RECORD_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SPICE_TYPE_RECORD_CHANNEL, SpiceRecordChannelClass)) +#define SPICE_IS_RECORD_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SPICE_TYPE_RECORD_CHANNEL)) +#define SPICE_IS_RECORD_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SPICE_TYPE_RECORD_CHANNEL)) +#define SPICE_RECORD_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), SPICE_TYPE_RECORD_CHANNEL, SpiceRecordChannelClass)) + +typedef struct _SpiceRecordChannel SpiceRecordChannel; +typedef struct _SpiceRecordChannelClass SpiceRecordChannelClass; +typedef struct spice_record_channel spice_record_channel; + +struct _SpiceRecordChannel { + SpiceChannel parent; + spice_record_channel *priv; + /* Do not add fields to this struct */ +}; + +struct _SpiceRecordChannelClass { + SpiceChannelClass parent_class; + + /* signals */ + void (*spice_record_start)(SpiceRecordChannel *channel, + gint format, gint channels, gint freq); + void (*spice_record_data)(SpiceRecordChannel *channel, gpointer *data, gint size); + void (*spice_record_stop)(SpiceRecordChannel *channel); + + /* Do not add fields to this struct */ +}; + +GType spice_record_channel_get_type(void); + +G_END_DECLS + +#endif /* __SPICE_CLIENT_RECORD_CHANNEL_H__ */ diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h index 4ad1897..8cb1d94 100644 --- a/gtk/spice-channel-priv.h +++ b/gtk/spice-channel-priv.h @@ -34,7 +34,6 @@ struct spice_channel { spice_watch *watch; SSL_CTX *ctx; SSL *ssl; - int tls; int connection_id; diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c index 4f9f831..ed9908c 100644 --- a/gtk/spice-channel.c +++ b/gtk/spice-channel.c @@ -803,6 +803,9 @@ SpiceChannel *spice_channel_new(SpiceSession *s, int type, int id) case SPICE_CHANNEL_PLAYBACK: gtype = SPICE_TYPE_PLAYBACK_CHANNEL; break; + case SPICE_CHANNEL_RECORD: + gtype = SPICE_TYPE_RECORD_CHANNEL; + break; default: return NULL; } diff --git a/gtk/spice-client.h b/gtk/spice-client.h index 63f0843..ed00f5f 100644 --- a/gtk/spice-client.h +++ b/gtk/spice-client.h @@ -23,6 +23,7 @@ #include "channel-cursor.h" #include "channel-inputs.h" #include "channel-playback.h" +#include "channel-record.h" /* debug bits */ #define PANIC(fmt, ...) \ diff --git a/gtk/spice-pulse.c b/gtk/spice-pulse.c index 26e7496..0bf2bcc 100644 --- a/gtk/spice-pulse.c +++ b/gtk/spice-pulse.c @@ -12,15 +12,19 @@ struct stream { pa_sample_spec spec; pa_stream *stream; + int state; }; struct spice_pulse { SpiceSession *session; SpiceChannel *pchannel; + SpiceChannel *rchannel; pa_glib_mainloop *mainloop; pa_context *context; + int state; struct stream playback; + struct stream record; }; G_DEFINE_TYPE(SpicePulse, spice_pulse, G_TYPE_OBJECT) @@ -70,7 +74,7 @@ static void spice_pulse_class_init(SpicePulseClass *klass) /* ------------------------------------------------------------------ */ static void playback_start(SpicePlaybackChannel *channel, gint format, gint channels, - gint frequency, gpointer data) + gint frequency, gpointer data) { SpicePulse *pulse = data; spice_pulse *p = SPICE_PULSE_GET_PRIVATE(pulse); @@ -79,6 +83,9 @@ static void playback_start(SpicePlaybackChannel *channel, gint format, gint chan state = pa_context_get_state(p->context); switch (state) { case PA_CONTEXT_READY: + if (p->state != state) { + fprintf(stderr, "%s: pulse context ready\n", __FUNCTION__); + } if (p->playback.stream && (p->playback.spec.rate != frequency || p->playback.spec.channels != channels)) { @@ -88,6 +95,7 @@ static void playback_start(SpicePlaybackChannel *channel, gint format, gint chan } if (p->playback.stream == NULL) { assert(format == SPICE_AUDIO_FMT_S16); + p->playback.state = PA_STREAM_READY; p->playback.spec.format = PA_SAMPLE_S16LE; p->playback.spec.rate = frequency; p->playback.spec.channels = channels; @@ -100,10 +108,13 @@ static void playback_start(SpicePlaybackChannel *channel, gint format, gint chan } break; default: - fprintf(stderr, "%s: pulse context not ready (%s)\n", - __FUNCTION__, STATE_NAME(context_state_names, state)); + if (p->state != state) { + fprintf(stderr, "%s: pulse context not ready (%s)\n", + __FUNCTION__, STATE_NAME(context_state_names, state)); + } break; } + p->state = state; } static void playback_data(SpicePlaybackChannel *channel, gpointer *audio, gint size, @@ -119,13 +130,19 @@ static void playback_data(SpicePlaybackChannel *channel, gpointer *audio, gint s state = pa_stream_get_state(p->playback.stream); switch (state) { case PA_STREAM_READY: + if (p->playback.state != state) { + fprintf(stderr, "%s: pulse playback stream ready\n", __FUNCTION__); + } pa_stream_write(p->playback.stream, audio, size, NULL, 0, PA_SEEK_RELATIVE); break; default: - fprintf(stderr, "%s: pulse playback stream not ready (%s)\n", - __FUNCTION__, STATE_NAME(stream_state_names, state)); + if (p->playback.state != state) { + fprintf(stderr, "%s: pulse playback stream not ready (%s)\n", + __FUNCTION__, STATE_NAME(stream_state_names, state)); + } break; } + p->playback.state = state; } static void playback_stop(SpicePlaybackChannel *channel, gpointer data) @@ -139,6 +156,17 @@ static void playback_stop(SpicePlaybackChannel *channel, gpointer data) pa_stream_cork(p->playback.stream, 1, NULL, NULL); } +static void record_start(SpicePlaybackChannel *channel, gint format, gint channels, + gint frequency, gpointer data) +{ + fprintf(stderr, "%s\n", __FUNCTION__); +} + +static void record_stop(SpicePlaybackChannel *channel, gpointer data) +{ + fprintf(stderr, "%s\n", __FUNCTION__); +} + static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data) { SpicePulse *pulse = data; @@ -154,6 +182,15 @@ static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data) G_CALLBACK(playback_stop), pulse); spice_channel_connect(channel); } + + if (SPICE_IS_RECORD_CHANNEL(channel)) { + p->rchannel = channel; + g_signal_connect(channel, "spice-record-start", + G_CALLBACK(record_start), pulse); + g_signal_connect(channel, "spice-record-stop", + G_CALLBACK(record_stop), pulse); + spice_channel_connect(channel); + } } SpicePulse *spice_pulse_new(SpiceSession *session, GMainLoop *mainloop, @@ -176,7 +213,8 @@ SpicePulse *spice_pulse_new(SpiceSession *session, GMainLoop *mainloop, g_list_free(list); p->mainloop = pa_glib_mainloop_new(g_main_loop_get_context(mainloop)); - p->context = pa_context_new(pa_glib_mainloop_get_api(p->mainloop), name); + p->state = PA_CONTEXT_READY; + p->context = pa_context_new(pa_glib_mainloop_get_api(p->mainloop), name); pa_context_connect(p->context, NULL, 0, NULL); return pulse; |