summaryrefslogtreecommitdiffstats
path: root/audio/gsta2dpsink.c
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2007-11-01 19:45:00 +0000
committerLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2007-11-01 19:45:00 +0000
commit96d6078ada20a76f885ea04893aac5f0ca5fe48d (patch)
tree5a555aaae3228f5c5faf2497b71227557aecc650 /audio/gsta2dpsink.c
parenta4bc7122fb5c7e4545cf8055cf71d1e88515998f (diff)
Fix sbc negotiation and improves buffer handling by using GstAdapter.
Diffstat (limited to 'audio/gsta2dpsink.c')
-rw-r--r--audio/gsta2dpsink.c84
1 files changed, 82 insertions, 2 deletions
diff --git a/audio/gsta2dpsink.c b/audio/gsta2dpsink.c
index be81efe8..e605158f 100644
--- a/audio/gsta2dpsink.c
+++ b/audio/gsta2dpsink.c
@@ -37,6 +37,7 @@
#include "ipc.h"
#include "rtp.h"
+#include "gstsbcutil.h"
#include "gsta2dpsink.h"
@@ -143,10 +144,17 @@ static gboolean gst_a2dp_sink_stop(GstBaseSink *basesink)
self->watch_id = 0;
}
+ if (self->stream) {
+ g_io_channel_flush(self->stream, NULL);
+ g_io_channel_close(self->stream);
+ g_io_channel_unref(self->stream);
+ self->stream = NULL;
+ }
+
if (self->server) {
g_io_channel_close(self->server);
g_io_channel_unref(self->server);
- self->stream = NULL;
+ self->server = NULL;
}
if (self->data) {
@@ -154,6 +162,16 @@ static gboolean gst_a2dp_sink_stop(GstBaseSink *basesink)
self->data = NULL;
}
+ if (self->sbc) {
+ g_free(self->sbc);
+ self->sbc = NULL;
+ }
+
+ if (self->dev_caps) {
+ gst_caps_unref(self->dev_caps);
+ self->dev_caps = NULL;
+ }
+
return TRUE;
}
@@ -250,6 +268,25 @@ static gint gst_a2dp_sink_bluetooth_recvmsg_fd(GstA2dpSink *sink)
return -EINVAL;
}
+static void gst_a2dp_sink_check_dev_caps(GstA2dpSink *self)
+{
+ GstStructure *structure;
+ GstCaps *dev_caps;
+ gint channels;
+
+ structure = gst_caps_get_structure(self->dev_caps, 0);
+ if (!gst_structure_get_int(structure, "channels", &channels))
+ channels = 2; /* FIXME how to get channels */
+ dev_caps = gst_sbc_caps_from_sbc(&(self->data->cfg), self->sbc,
+ channels);
+
+ self->new_dev_caps = TRUE;
+ gst_caps_unref(self->dev_caps);
+ self->dev_caps = gst_caps_ref(dev_caps);
+
+
+}
+
static int gst_a2dp_sink_bluetooth_a2dp_init(GstA2dpSink *self,
struct ipc_codec_sbc *sbc)
{
@@ -406,6 +443,9 @@ static gboolean gst_a2dp_sink_conf_resp(GstA2dpSink *sink)
}
memcpy(&sink->data->cfg, cfg, sizeof(*cfg));
+ memcpy(sink->sbc, sbc, sizeof(struct ipc_codec_sbc));
+
+ gst_a2dp_sink_check_dev_caps(sink);
GST_DEBUG_OBJECT(sink, "Device configuration:\n\tchannel=%p\n\t"
"fd_opt=%u\n\tpkt_len=%u\n\tsample_size=%u\n\trate=%u",
@@ -414,6 +454,7 @@ static gboolean gst_a2dp_sink_conf_resp(GstA2dpSink *sink)
sink->data->cfg.rate);
if (sink->data->cfg.codec == CFG_CODEC_SBC) {
+ /* FIXME is this necessary? */
ret = gst_a2dp_sink_bluetooth_a2dp_init(sink, sbc);
if (ret < 0)
return FALSE;
@@ -577,8 +618,12 @@ static gboolean gst_a2dp_sink_start(GstBaseSink *basesink)
self->data = g_new0(struct bluetooth_data, 1);
memset(self->data, 0, sizeof(struct bluetooth_data));
+ self->sbc = g_new0(struct ipc_codec_sbc, 1);
+
self->stream = NULL;
self->con_state = NOT_CONFIGURED;
+ self->new_dev_caps = FALSE;
+ self->dev_caps = NULL;
self->waiting_con_conf = FALSE;
@@ -718,8 +763,16 @@ static gboolean gst_a2dp_sink_set_caps(GstBaseSink *basesink, GstCaps *caps)
GstA2dpSink *self = GST_A2DP_SINK(basesink);
GST_A2DP_SINK_MUTEX_LOCK(self);
- if (self->con_state == NOT_CONFIGURED)
+ if (self->con_state == NOT_CONFIGURED) {
gst_a2dp_sink_start_dev_conf(self, caps);
+
+ if (self->dev_caps)
+ gst_caps_unref(self->dev_caps);
+ self->dev_caps = gst_caps_ref(caps);
+
+ /* we suppose the device will accept this caps */
+ self->new_dev_caps = FALSE;
+ }
GST_A2DP_SINK_MUTEX_UNLOCK(self);
return TRUE;
@@ -735,6 +788,30 @@ static gboolean gst_a2dp_sink_unlock(GstBaseSink *basesink)
return TRUE;
}
+static GstFlowReturn gst_a2dp_sink_buffer_alloc(GstBaseSink *basesink,
+ guint64 offset, guint size, GstCaps* caps,
+ GstBuffer **buf)
+{
+ GstA2dpSink *self = GST_A2DP_SINK(basesink);
+
+ *buf = gst_buffer_new_and_alloc(size);
+ if (!(*buf)) {
+ GST_ERROR_OBJECT(self, "buffer allocation failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (self->new_dev_caps && self->dev_caps) {
+ GST_INFO_OBJECT(self, "new caps from device");
+ gst_buffer_set_caps(*buf, self->dev_caps);
+ self->new_dev_caps = FALSE;
+ } else
+ gst_buffer_set_caps(*buf, caps);
+
+ GST_BUFFER_OFFSET(*buf) = offset;
+
+ return GST_FLOW_OK;
+}
+
static void gst_a2dp_sink_class_init(GstA2dpSinkClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
@@ -754,6 +831,8 @@ static void gst_a2dp_sink_class_init(GstA2dpSinkClass *klass)
basesink_class->preroll = GST_DEBUG_FUNCPTR(gst_a2dp_sink_preroll);
basesink_class->set_caps = GST_DEBUG_FUNCPTR(gst_a2dp_sink_set_caps);
basesink_class->unlock = GST_DEBUG_FUNCPTR(gst_a2dp_sink_unlock);
+ basesink_class->buffer_alloc =
+ GST_DEBUG_FUNCPTR(gst_a2dp_sink_buffer_alloc);
g_object_class_install_property(object_class, PROP_DEVICE,
g_param_spec_string("device", "Device",
@@ -768,6 +847,7 @@ static void gst_a2dp_sink_init(GstA2dpSink *self, GstA2dpSinkClass *klass)
{
self->device = NULL;
self->data = NULL;
+ self->sbc = NULL;
self->stream = NULL;
self->con_state = NOT_CONFIGURED;