summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
Diffstat (limited to 'audio')
-rw-r--r--audio/gsta2dpsink.c169
-rw-r--r--audio/gsta2dpsink.h4
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 {