diff options
Diffstat (limited to 'audio')
-rw-r--r-- | audio/gsta2dpsink.c | 169 | ||||
-rw-r--r-- | audio/gsta2dpsink.h | 4 |
2 files changed, 118 insertions, 55 deletions
diff --git a/audio/gsta2dpsink.c b/audio/gsta2dpsink.c index 08832524..8a6a44f1 100644 --- a/audio/gsta2dpsink.c +++ b/audio/gsta2dpsink.c @@ -25,14 +25,24 @@ #include <config.h> #endif +#include <unistd.h> +#include <sys/un.h> +#include <sys/socket.h> + #include "ipc.h" -#include "sbc.h" #include "gsta2dpsink.h" GST_DEBUG_CATEGORY_STATIC(a2dp_sink_debug); #define GST_CAT_DEFAULT a2dp_sink_debug +#define DEFAULT_DEVICE "default" + +enum { + PROP_0, + PROP_DEVICE, +}; + GST_BOILERPLATE(GstA2dpSink, gst_a2dp_sink, GstAudioSink, GST_TYPE_AUDIO_SINK); static const GstElementDetails a2dp_sink_details = @@ -41,138 +51,187 @@ static const GstElementDetails a2dp_sink_details = "Plays audio to an A2DP device", "Marcel Holtmann <marcel@holtmann.org>"); -static GstStaticPadTemplate sink_factory = +static GstStaticPadTemplate a2dp_sink_factory = GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS("ANY")); + GST_STATIC_CAPS("audio/x-sbc, " + "rate = (int) { 16000, 32000, 44100, 48000 }, " + "channels = (int) [ 1, 2 ], " + "mode = (string) { mono, dual, stereo, joint }, " + "blocks = (int) { 4, 8, 12, 16 }, " + "subbands = (int) { 4, 8 }, " + "allocation = (string) { snr, loudness }; " + + "audio/mpeg, " + "mpegversion = (int) 1, " + "layer = (int) [ 1, 3 ], " + "rate = (int) { 16000, 22050, 24000, 32000, 44100, 48000 }, " + "channels = (int) [ 1, 2 ]")); static void gst_a2dp_sink_base_init(gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); - GST_DEBUG(""); - gst_element_class_add_pad_template(element_class, - gst_static_pad_template_get(&sink_factory)); + gst_static_pad_template_get(&a2dp_sink_factory)); gst_element_class_set_details(element_class, &a2dp_sink_details); } -static void gst_a2dp_sink_dispose(GObject *object) -{ - G_OBJECT_CLASS(parent_class)->dispose(object); -} - static void gst_a2dp_sink_finalize(GObject *object) { + GstA2dpSink *sink = GST_A2DP_SINK(object); + + g_io_channel_close(sink->server); + + g_free(sink->device); + G_OBJECT_CLASS(parent_class)->finalize(object); } -static void gst_a2dp_sink_get_property(GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) +static void gst_a2dp_sink_set_property(GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) { + GstA2dpSink *sink = GST_A2DP_SINK(object); + switch (prop_id) { + case PROP_DEVICE: + g_free(sink->device); + sink->device = g_value_dup_string(value); + + if (sink->device == NULL) + sink->device = g_strdup(DEFAULT_DEVICE); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } -static void gst_a2dp_sink_set_property(GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) +static void gst_a2dp_sink_get_property(GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) { + GstA2dpSink *sink = GST_A2DP_SINK(object); + switch (prop_id) { + case PROP_DEVICE: + g_value_set_string(value, sink->device); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } -static GstCaps *gst_a2dp_sink_getcaps(GstBaseSink *basesink) +static gboolean gst_a2dp_sink_open(GstAudioSink *self) { - GST_DEBUG_OBJECT(basesink, ""); + GstA2dpSink *sink = GST_A2DP_SINK(self); - return NULL; -} - -static gboolean gst_a2dp_sink_open(GstAudioSink *audiosink) -{ - GST_DEBUG_OBJECT(audiosink, ""); + printf("device %s\n", sink->device); + printf("open\n"); return TRUE; } -static gboolean gst_a2dp_sink_prepare(GstAudioSink *audiosink, +static gboolean gst_a2dp_sink_prepare(GstAudioSink *self, GstRingBufferSpec *spec) { - GST_DEBUG_OBJECT(audiosink, "spec %p", spec); + printf("perpare\n"); + printf("rate %d\n", spec->rate); + printf("channels %d\n", spec->channels); return TRUE; } -static gboolean gst_a2dp_sink_unprepare(GstAudioSink *audiosink) +static gboolean gst_a2dp_sink_unprepare(GstAudioSink *self) { - GST_DEBUG_OBJECT(audiosink, ""); + printf("unprepare\n"); return TRUE; } -static gboolean gst_a2dp_sink_close(GstAudioSink *audiosink) +static gboolean gst_a2dp_sink_close(GstAudioSink *self) { - GST_DEBUG_OBJECT(audiosink, ""); + printf("close\n"); return TRUE; } -static guint gst_a2dp_sink_write(GstAudioSink *audiosink, - gpointer data, guint length) +static guint gst_a2dp_sink_write(GstAudioSink *self, + gpointer data, guint length) { - GST_DEBUG_OBJECT(audiosink, "data %p length %d", data, length); - - return length; + return 0; } static guint gst_a2dp_sink_delay(GstAudioSink *audiosink) { - GST_DEBUG_OBJECT(audiosink, ""); + printf("delay\n"); return 0; } static void gst_a2dp_sink_reset(GstAudioSink *audiosink) { - GST_DEBUG_OBJECT(audiosink, ""); + printf("reset\n"); } -static void gst_a2dp_sink_class_init(GstA2dpSinkClass *klass) +static gboolean server_callback(GIOChannel *chan, + GIOCondition cond, gpointer data) { - GObjectClass *gobject_class = G_OBJECT_CLASS(klass); - GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS(klass); - GstAudioSinkClass *gstaudiosink_class = GST_AUDIO_SINK_CLASS(klass); + printf("callback\n"); - GST_DEBUG(""); + return TRUE; +} + +static void gst_a2dp_sink_class_init(GstA2dpSinkClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + GstAudioSinkClass *audiosink_class = GST_AUDIO_SINK_CLASS(klass); parent_class = g_type_class_peek_parent(klass); - gobject_class->dispose = GST_DEBUG_FUNCPTR(gst_a2dp_sink_dispose); - gobject_class->finalize = GST_DEBUG_FUNCPTR(gst_a2dp_sink_finalize); - gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_a2dp_sink_get_property); - gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_a2dp_sink_set_property); + object_class->finalize = GST_DEBUG_FUNCPTR(gst_a2dp_sink_finalize); + object_class->set_property = GST_DEBUG_FUNCPTR(gst_a2dp_sink_set_property); + object_class->get_property = GST_DEBUG_FUNCPTR(gst_a2dp_sink_get_property); - gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR(gst_a2dp_sink_getcaps); + audiosink_class->open = GST_DEBUG_FUNCPTR(gst_a2dp_sink_open); + audiosink_class->prepare = GST_DEBUG_FUNCPTR(gst_a2dp_sink_prepare); + audiosink_class->unprepare = GST_DEBUG_FUNCPTR(gst_a2dp_sink_unprepare); + audiosink_class->close = GST_DEBUG_FUNCPTR(gst_a2dp_sink_close); + audiosink_class->write = GST_DEBUG_FUNCPTR(gst_a2dp_sink_write); + audiosink_class->delay = GST_DEBUG_FUNCPTR(gst_a2dp_sink_delay); + audiosink_class->reset = GST_DEBUG_FUNCPTR(gst_a2dp_sink_reset); - gstaudiosink_class->open = GST_DEBUG_FUNCPTR(gst_a2dp_sink_open); - gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR(gst_a2dp_sink_prepare); - gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR(gst_a2dp_sink_unprepare); - gstaudiosink_class->close = GST_DEBUG_FUNCPTR(gst_a2dp_sink_close); - gstaudiosink_class->write = GST_DEBUG_FUNCPTR(gst_a2dp_sink_write); - gstaudiosink_class->delay = GST_DEBUG_FUNCPTR(gst_a2dp_sink_delay); - gstaudiosink_class->reset = GST_DEBUG_FUNCPTR(gst_a2dp_sink_reset); + g_object_class_install_property(object_class, PROP_DEVICE, + g_param_spec_string("device", "Device", + "Bluetooth remote device", + DEFAULT_DEVICE, G_PARAM_READWRITE)); GST_DEBUG_CATEGORY_INIT(a2dp_sink_debug, "a2dpsink", 0, "A2DP sink element"); } -static void gst_a2dp_sink_init(GstA2dpSink *a2dpsink, GstA2dpSinkClass *klass) +static void gst_a2dp_sink_init(GstA2dpSink *self, GstA2dpSinkClass *klass) { - GST_DEBUG_OBJECT(a2dpsink, ""); + struct sockaddr_un addr = { AF_UNIX, IPC_SOCKET_NAME }; + int sk; + + self->device = g_strdup(DEFAULT_DEVICE); + + sk = socket(PF_LOCAL, SOCK_STREAM, 0); + if (sk < 0) + return; + + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(sk); + return; + } + + self->server = g_io_channel_unix_new(sk); + + g_io_add_watch(self->server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + server_callback, self); + + g_io_channel_unref(self->server); } diff --git a/audio/gsta2dpsink.h b/audio/gsta2dpsink.h index 9575bc44..c83ec66c 100644 --- a/audio/gsta2dpsink.h +++ b/audio/gsta2dpsink.h @@ -42,6 +42,10 @@ typedef struct _GstA2dpSinkClass GstA2dpSinkClass; struct _GstA2dpSink { GstAudioSink sink; + + gchar *device; + + GIOChannel *server; }; struct _GstA2dpSinkClass { |