summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2010-10-18 15:13:39 +0200
committerGerd Hoffmann <kraxel@redhat.com>2010-10-18 15:15:18 +0200
commit0776f1100997d4fe1b1b46cfb9501950b8626407 (patch)
treebbc1476292267526fce3edc60587ea20e95d2675
parent16aac9ed6b927a0277aed4cf33176f6dc265f725 (diff)
sound: add recording [not finished yet]
-rw-r--r--gtk/channel-record.c117
-rw-r--r--gtk/channel-record.h41
-rw-r--r--gtk/spice-channel-priv.h1
-rw-r--r--gtk/spice-channel.c3
-rw-r--r--gtk/spice-client.h1
-rw-r--r--gtk/spice-pulse.c50
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;