Re: [Bluez-devel] Patch: inheritance problem in gsta2dpsink

thiagoss
2007-10-05T19:36:24Z

[-- Attachment #1.1: Type: text/plain, Size: 828 bytes --]

This patch adds the prerolling to the gsta2dpsink gstreamer plugin, it sends
the configuration packet to the device and prepares the connection.

It is currently only supporting sbc, needs to be extended to mp3.

This patch includes the full set of changes the previous one did.

I'll be waiting comments, reviews or sugestions.

BR,

Thiago

On 10/1/07, thiagoss <thiagossantos@gmail.com> wrote:
>
> GstA2dpSink was extending GstAudioSink, but there is a problem in that,
> GstAudioSink expects only
> "audio/x-raw-int", "audio/x-raw-float", "audio/x-mulaw" or "audio/x-alaw"
> as media types. GstA2dpSink should support mp3 and sbc, that's causing a
> runtime error. This patch changes the base class from GstAudioSink to
> GstBaseSink, changing the stub functions to be implemented also.
>
>
> Best regards,
>
>
> Thiago
>
>

[-- Attachment #1.2: Type: text/html, Size: 1231 bytes --]

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: gsta2dpsink_preroll.patch --]
[-- Type: text/x-patch; name="gsta2dpsink_preroll.patch", Size: 21202 bytes --]

Index: audio/gsta2dpsink.c
===================================================================
RCS file: /cvsroot/bluez/utils/audio/gsta2dpsink.c,v
retrieving revision 1.3
diff -u -r1.3 gsta2dpsink.c
--- audio/gsta2dpsink.c 26 Aug 2007 14:14:34 -0000 1.3
+++ audio/gsta2dpsink.c 5 Oct 2007 18:49:39 -0000
@@ -28,8 +28,11 @@
#include <unistd.h>
#include <sys/un.h>
#include <sys/socket.h>
+#include <fcntl.h>
+#include <pthread.h>

#include "ipc.h"
+#include "sbc.h"

#include "gsta2dpsink.h"

@@ -37,13 +40,117 @@
#define GST_CAT_DEFAULT a2dp_sink_debug

#define DEFAULT_DEVICE "default"
+#define BUFFER_SIZE 2048
+
+#define GST_A2DP_SINK_MUTEX_LOCK(s) G_STMT_START { \
+ g_mutex_lock (s->sink_lock); \
+ } G_STMT_END
+
+#define GST_A2DP_SINK_MUTEX_UNLOCK(s) G_STMT_START { \
+ g_mutex_unlock (s->sink_lock); \
+ } G_STMT_END
+
+#define GST_A2DP_SINK_WAIT_CON_END(s) G_STMT_START { \
+ s->waiting_con_conf = TRUE; \
+ g_cond_wait (s->con_conf_end, s->sink_lock); \
+ s->waiting_con_conf = FALSE; \
+ } G_STMT_END
+
+#define GST_A2DP_SINK_CONFIGURATION_FAIL(s) G_STMT_START { \
+ s->con_state = NOT_CONFIGURED; \
+ g_cond_signal (s->con_conf_end); \
+ } G_STMT_END
+
+#define GST_A2DP_SINK_CONFIGURATION_SUCCESS(s) G_STMT_START { \
+ s->con_state = CONFIGURED; \
+ g_cond_signal (s->con_conf_end); \
+ } G_STMT_END
+
+struct bluetooth_a2dp {
+ sbc_t sbc; /* Codec data */
+ int codesize; /* SBC codesize */
+ int samples; /* Number of encoded samples */
+ uint8_t buffer[BUFFER_SIZE]; /* Codec transfer buffer */
+ int count; /* Codec transfer buffer counter */
+
+ int nsamples; /* Cumulative number of codec samples */
+ uint16_t seq_num; /* Cumulative packet sequence */
+ int frame_count; /* Current frames in buffer*/
+};
+struct bluetooth_data {
+ struct ipc_data_cfg cfg; /* Bluetooth device config */
+ uint8_t buffer[BUFFER_SIZE]; /* Encoded transfer buffer */
+ int count; /* Transfer buffer counter */
+ struct bluetooth_a2dp a2dp; /* A2DP data */
+
+ pthread_t hw_thread; /* Makes virtual hw pointer move */
+ int pipefd[2]; /* Inter thread communication */
+ int stopped;
+};
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct rtp_header {
+ uint8_t cc:4;
+ uint8_t x:1;
+ uint8_t p:1;
+ uint8_t v:2;
+
+ uint8_t pt:7;
+ uint8_t m:1;
+
+ uint16_t sequence_number;
+ uint32_t timestamp;
+ uint32_t ssrc;
+ uint32_t csrc[0];
+} __attribute__ ((packed));
+
+struct rtp_payload {
+ uint8_t frame_count:4;
+ uint8_t rfa0:1;
+ uint8_t is_last_fragment:1;
+ uint8_t is_first_fragment:1;
+ uint8_t is_fragmented:1;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct rtp_header {
+ uint8_t v:2;
+ uint8_t p:1;
+ uint8_t x:1;
+ uint8_t cc:4;
+
+ uint8_t m:1;
+ uint8_t pt:7;
+
+ uint16_t sequence_number;
+ uint32_t timestamp;
+ uint32_t ssrc;
+ uint32_t csrc[0];
+} __attribute__ ((packed));
+
+struct rtp_payload {
+ uint8_t is_fragmented:1;
+ uint8_t is_first_fragment:1;
+ uint8_t is_last_fragment:1;
+ uint8_t rfa0:1;
+ uint8_t frame_count:4;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+#define IS_SBC(n) (strcmp(n, "audio/x-sbc") == 0)
+#define IS_MPEG(n) (strcmp(n, "audio/mpeg") == 0)

enum {
PROP_0,
PROP_DEVICE,
};

-GST_BOILERPLATE(GstA2dpSink, gst_a2dp_sink, GstAudioSink, GST_TYPE_AUDIO_SINK);
+GST_BOILERPLATE(GstA2dpSink, gst_a2dp_sink, GstBaseSink, GST_TYPE_BASE_SINK);

static const GstElementDetails a2dp_sink_details =
GST_ELEMENT_DETAILS("Bluetooth A2DP sink",
@@ -77,14 +184,45 @@
gst_element_class_set_details(element_class, &a2dp_sink_details);
}

+static void gst_a2dp_sink_bluetooth_exit(GstA2dpSink *sink)
+{
+ struct bluetooth_a2dp *a2dp = &sink->data->a2dp;
+
+ if (sink->stream_fd >= 0) {
+ close(sink->stream_fd);
+ sink->stream_fd = -1;
+ }
+
+ if (sink->data->hw_thread) {
+ pthread_cancel(sink->data->hw_thread);
+ pthread_join(sink->data->hw_thread, 0);
+ }
+
+ if (sink->data->cfg.codec == CFG_CODEC_SBC)
+ sbc_finish(&a2dp->sbc);
+
+ if (sink->data->pipefd[0] > 0)
+ close(sink->data->pipefd[0]);
+
+ if (sink->data->pipefd[1] > 0)
+ close(sink->data->pipefd[1]);
+
+ g_free(sink->data);
+}
+
static void gst_a2dp_sink_finalize(GObject *object)
{
GstA2dpSink *sink = GST_A2DP_SINK(object);

g_io_channel_close(sink->server);
+ g_io_channel_unref(sink->server);
+ gst_a2dp_sink_bluetooth_exit(sink);

g_free(sink->device);

+ g_cond_free(sink->con_conf_end);
+ g_mutex_free(sink->sink_lock);
+
G_OBJECT_CLASS(parent_class)->finalize(object);
}

@@ -124,62 +262,447 @@
}
}

-static gboolean gst_a2dp_sink_open(GstAudioSink *self)
+static gint gst_a2dp_sink_bluetooth_recvmsg_fd(GstA2dpSink *sink)
+{
+ char cmsg_b[CMSG_SPACE(sizeof(int))], m;
+ int err, ret;
+ struct iovec iov = { &m, sizeof(m) };
+ struct msghdr msgh;
+ struct cmsghdr *cmsg;
+
+ memset(&msgh, 0, sizeof(msgh));
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ msgh.msg_control = &cmsg_b;
+ msgh.msg_controllen = CMSG_LEN(sizeof(int));
+
+ ret = recvmsg(g_io_channel_unix_get_fd(sink->server), &msgh, 0);
+ if (ret < 0) {
+ err = errno;
+ GST_ERROR_OBJECT(sink, "Unable to receive fd: %s (%d)",
+ strerror(err), err);
+ return -err;
+ }
+
+ /* Receive auxiliary data in msgh */
+ for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET
+ && cmsg->cmsg_type == SCM_RIGHTS) {
+ sink->stream_fd = (*(int *) CMSG_DATA(cmsg));
+ GST_DEBUG_OBJECT(sink, "stream_fd=%d",
+ sink->stream_fd);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int gst_a2dp_sink_bluetooth_a2dp_init(GstA2dpSink *sink,
+ struct ipc_codec_sbc *sbc)
{
- GstA2dpSink *sink = GST_A2DP_SINK(self);
+ struct bluetooth_a2dp *a2dp = &sink->data->a2dp;
+ struct ipc_data_cfg *cfg = &sink->data->cfg;
+
+ if (cfg == NULL) {
+ GST_ERROR_OBJECT(sink, "Error getting codec parameters");
+ return -1;
+ }
+
+ if (cfg->codec != CFG_CODEC_SBC)
+ return -1;

- printf("device %s\n", sink->device);
- printf("open\n");
+ /* FIXME: init using flags? */
+ sbc_init(&a2dp->sbc, 0);
+ a2dp->sbc.rate = cfg->rate;
+ a2dp->sbc.channels = cfg->mode == CFG_MODE_MONO ? 1 : 2;
+ if (cfg->mode == CFG_MODE_MONO || cfg->mode == CFG_MODE_JOINT_STEREO)
+ a2dp->sbc.joint = 1;
+ a2dp->sbc.allocation = sbc->allocation;
+ a2dp->sbc.subbands = sbc->subbands;
+ a2dp->sbc.blocks = sbc->blocks;
+ a2dp->sbc.bitpool = sbc->bitpool;
+ a2dp->codesize = a2dp->sbc.subbands * a2dp->sbc.blocks *
+ a2dp->sbc.channels * 2;
+ a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
+
+ GST_DEBUG_OBJECT(sink, "Codec parameters: \
+ \tallocation=%u\n\tsubbands=%u\n \
+ \tblocks=%u\n\tbitpool=%u\n",
+ a2dp->sbc.allocation, a2dp->sbc.subbands, a2dp->sbc.blocks,
+ a2dp->sbc.bitpool);
+
+ return 0;
+}
+
+static gboolean gst_a2dp_sink_init_pkt_conf(GstA2dpSink *sink,
+ GstCaps *caps, struct ipc_packet *pkt)
+{
+
+ struct ipc_data_cfg *cfg = (void *) pkt->data;
+ struct ipc_codec_sbc *sbc = (void *) cfg->data;
+ const GValue *value = NULL;
+ const char *pref, *name;
+ GstStructure *structure = gst_caps_get_structure(caps,0);
+
+ name = gst_structure_get_name(structure);
+ /* FIXME only sbc supported here, should suport mp3 */
+ if (!(IS_SBC(name))) {
+ GST_ERROR_OBJECT(sink, "Unsupported format %s", name);
+ return FALSE;
+ }
+
+ strncpy(pkt->device, sink->device, 18);
+ pkt->role = PKT_ROLE_HIFI;
+
+ value = gst_structure_get_value(structure, "rate");
+ cfg->rate = g_value_get_int(value);
+
+ value = gst_structure_get_value(structure, "mode");
+ pref = g_value_get_string(value);
+ if (strcmp(pref, "auto") == 0)
+ cfg->mode = CFG_MODE_AUTO;
+ else if (strcmp(pref, "mono") == 0)
+ cfg->mode = CFG_MODE_MONO;
+ else if (strcmp(pref, "dual") == 0)
+ cfg->mode = CFG_MODE_DUAL_CHANNEL;
+ else if (strcmp(pref, "stereo") == 0)
+ cfg->mode = CFG_MODE_STEREO;
+ else if (strcmp(pref, "joint") == 0)
+ cfg->mode = CFG_MODE_JOINT_STEREO;
+ else {
+ GST_ERROR_OBJECT(sink, "Invalid mode %s", pref);
+ return FALSE;
+ }
+
+ value = gst_structure_get_value(structure, "allocation");
+ pref = g_value_get_string(value);
+ if (strcmp(pref, "auto") == 0)
+ sbc->allocation = CFG_ALLOCATION_AUTO;
+ else if (strcmp(pref, "loudness") == 0)
+ sbc->allocation = CFG_ALLOCATION_LOUDNESS;
+ else if (strcmp(pref, "snr") == 0)
+ sbc->allocation = CFG_ALLOCATION_SNR;
+ else {
+ GST_ERROR_OBJECT(sink, "Invalid allocation: %s", pref);
+ return FALSE;
+ }
+
+ value = gst_structure_get_value(structure, "subbands");
+ sbc->subbands = g_value_get_int(value);
+
+ value = gst_structure_get_value(structure, "blocks");
+ sbc->blocks = g_value_get_int(value);
+/* FIXME how can I obtain the bitpool ?
+ if (strcmp(id, "bitpool") == 0) {
+ if (snd_config_get_string(n, &bitpool) < 0) {
+ SNDERR("Invalid type for %s", id);
+ return -EINVAL;
+ }
+
+ sbc->bitpool = atoi(bitpool);
+ continue;
+ }
+
+ SNDERR("Unknown field %s", id);
+ return -EINVAL;
+ }
+*/
+ sbc->bitpool = 32;
+
+ pkt->length = sizeof(*cfg) + sizeof(*sbc);
+ pkt->type = PKT_TYPE_CFG_REQ;
+ pkt->error = PKT_ERROR_NONE;

return TRUE;
+
}

-static gboolean gst_a2dp_sink_prepare(GstAudioSink *self,
- GstRingBufferSpec *spec)
+static gboolean gst_a2dp_sink_start(GstBaseSink *basesink)
{
- printf("perpare\n");
- printf("rate %d\n", spec->rate);
- printf("channels %d\n", spec->channels);
+ g_print("start\n");

return TRUE;
}

-static gboolean gst_a2dp_sink_unprepare(GstAudioSink *self)
+static gboolean gst_a2dp_sink_stop(GstBaseSink *basesink)
{
- printf("unprepare\n");
+ g_print("stop\n");

return TRUE;
}

-static gboolean gst_a2dp_sink_close(GstAudioSink *self)
+static gboolean gst_a2dp_sink_send_conf_pkt(GstA2dpSink *sink, GstCaps *caps)
{
- printf("close\n");
+ gchar buf[IPC_MTU];
+ struct ipc_packet *pkt = (void *) buf;
+ gboolean ret;
+ GIOError io_error;
+
+ g_assert(sink->con_state == NOT_CONFIGURED);
+
+ pkt = (void*) buf;
+ ret = gst_a2dp_sink_init_pkt_conf(sink, caps, pkt);
+ if (!ret) {
+ GST_ERROR_OBJECT(sink, "Couldn't initialize parse caps \
+ to packet configuration");
+ return FALSE;
+ }
+
+ sink->con_state = CONFIGURING_INIT;
+
+ io_error = g_io_channel_write(sink->server, (gchar*)pkt,
+ sizeof(*pkt) + pkt->length, &ret);
+ if (io_error != G_IO_ERROR_NONE) {
+ GST_ERROR_OBJECT(sink, "Error ocurred while sending \
+ configurarion packet");
+ sink->con_state = NOT_CONFIGURED;
+ return FALSE;
+ }
+
+ GST_DEBUG_OBJECT(sink, "%d bytes sent", ret);
+ sink->con_state = CONFIGURING_SENT_CONF;

return TRUE;
}

-static guint gst_a2dp_sink_write(GstAudioSink *self,
- gpointer data, guint length)
+static gboolean gst_a2dp_sink_start_dev_conf(GstA2dpSink *sink, GstCaps *caps)
{
- return 0;
+ gboolean ret;
+
+ g_assert(sink->con_state == NOT_CONFIGURED);
+
+ GST_DEBUG_OBJECT(sink, "starting device configuration");
+
+ ret = gst_a2dp_sink_send_conf_pkt(sink, caps);
+
+ return ret;
}

-static guint gst_a2dp_sink_delay(GstAudioSink *audiosink)
+static GstFlowReturn gst_a2dp_sink_preroll(GstBaseSink *basesink,
+ GstBuffer *buffer)
{
- printf("delay\n");
+ GstA2dpSink *sink;
+ sink = GST_A2DP_SINK(basesink);

- return 0;
+ GST_A2DP_SINK_MUTEX_LOCK(sink);
+
+ if (sink->con_state == NOT_CONFIGURED)
+ gst_a2dp_sink_start_dev_conf(sink, GST_BUFFER_CAPS(buffer));
+
+ /* wait for the connection process to finish */
+ if (sink->con_state != CONFIGURED)
+ GST_A2DP_SINK_WAIT_CON_END(sink);
+
+ GST_A2DP_SINK_MUTEX_UNLOCK(sink);
+
+ if (sink->con_state != CONFIGURED)
+ return GST_FLOW_ERROR;
+
+ return GST_FLOW_OK;
}

-static void gst_a2dp_sink_reset(GstAudioSink *audiosink)
+static GstFlowReturn gst_a2dp_sink_render(GstBaseSink *basesink,
+ GstBuffer *buffer)
{
- printf("reset\n");
+ g_print("render\n");
+
+ return GST_FLOW_OK;
+}
+
+static gboolean gst_a2dp_sink_conf_resp(GstA2dpSink *sink)
+{
+ gchar buf[IPC_MTU];
+ GIOError io_error;
+ guint ret;
+ struct ipc_packet *pkt = (void *) buf;
+ struct ipc_data_cfg *cfg = (void *) pkt->data;
+
+ memset(buf, 0, sizeof(buf));
+
+ io_error = g_io_channel_read(sink->server, (gchar*)buf,
+ sizeof(*pkt) + sizeof(*cfg), &ret);
+ if (io_error != G_IO_ERROR_NONE && ret > 0) {
+ GST_ERROR_OBJECT(sink, "Error ocurred while receiving \
+ configurarion packet answer");
+ return FALSE;
+ }
+
+ sink->total = ret;
+ if (pkt->type != PKT_TYPE_CFG_RSP) {
+ GST_ERROR_OBJECT(sink, "Unexpected packet type %d \
+ received", pkt->type);
+ return FALSE;
+ }
+
+ if (pkt->error != PKT_ERROR_NONE) {
+ GST_ERROR_OBJECT(sink, "Error %d while configuring \
+ device", pkt->error);
+ return FALSE;
+ }
+
+ if (cfg->codec != CFG_CODEC_SBC) {
+ GST_ERROR_OBJECT(sink, "Unsupported format");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean gst_a2dp_sink_conf_recv_dev_conf(GstA2dpSink *sink)
+{
+ gchar buf[IPC_MTU];
+ GIOError io_error;
+ guint ret=0;
+ struct ipc_packet *pkt = (void *) buf;
+ struct ipc_data_cfg *cfg = (void *) pkt->data;
+ struct ipc_codec_sbc *sbc = (void *) cfg->data;
+
+ io_error = g_io_channel_read(sink->server, (gchar*)sbc,
+ sizeof(*sbc), &ret);
+ if (io_error != G_IO_ERROR_NONE) {
+ GST_ERROR_OBJECT(sink, "Error while reading data from socket \
+ %s (%d)", strerror(errno), errno);
+ return FALSE;
+ } else if (ret == 0) {
+ GST_ERROR_OBJECT(sink, "Read 0 bytes from socket");
+ return FALSE;
+ }
+
+ sink->total += ret;
+ GST_DEBUG_OBJECT(sink, "OK - %d bytes received", sink->total);
+
+ if (pkt->length != (sink->total - sizeof(struct ipc_packet))) {
+ GST_ERROR_OBJECT(sink, "Error while configuring device: \
+ packet size doesn't match");
+ return FALSE;
+ }
+
+ memcpy(&sink->data->cfg, cfg, sizeof(*cfg));
+
+ GST_DEBUG_OBJECT(sink, "Device configuration:\n\tfd=%d\n\tfd_opt=%u\n\
+ \tpkt_len=%u\n\tsample_size=%u\n\trate=%u",
+ sink->stream_fd, sink->data->cfg.fd_opt, \
+ sink->data->cfg.pkt_len, sink->data->cfg.sample_size, \
+ sink->data->cfg.rate);
+
+ if (sink->data->cfg.codec == CFG_CODEC_SBC) {
+ ret = gst_a2dp_sink_bluetooth_a2dp_init(sink, sbc);
+ if (ret < 0)
+ return FALSE;
+
+ }
+ return TRUE;
+}
+
+static gboolean gst_a2dp_sink_conf_recv_stream_fd(GstA2dpSink *sink)
+{
+ guint ret=0;
+ ret = gst_a2dp_sink_bluetooth_recvmsg_fd(sink);
+ if (ret < 0)
+ return FALSE;
+
+ if (sink->stream_fd == -1) {
+ GST_ERROR_OBJECT(sink, "Error while configuring device: \
+ could not acquire audio socket");
+ return FALSE;
+ }
+
+ /* It is possible there is some outstanding
+ data in the pipe - we have to empty it */
+ while (recv(sink->stream_fd, sink->data->buffer,
+ sink->data->cfg.pkt_len, MSG_DONTWAIT) > 0);
+
+ memset(sink->data->buffer, 0, sizeof(sink->data->buffer));
+
+ return TRUE;
+}
+
+static void gst_a2dp_sink_conf_recv_data(GstA2dpSink *sink)
+{
+ /*
+ * We hold the lock, since we can send a signal.
+ * It is a good practice, according to the glib api.
+ */
+ GST_A2DP_SINK_MUTEX_LOCK(sink);
+
+ switch (sink->con_state) {
+ case CONFIGURING_SENT_CONF:
+ if (gst_a2dp_sink_conf_resp(sink)) {
+ sink->con_state = CONFIGURING_RCVD_CONF_RSP;
+ } else {
+ GST_A2DP_SINK_CONFIGURATION_FAIL(sink);
+ }
+ break;
+ case CONFIGURING_RCVD_CONF_RSP:
+ if (gst_a2dp_sink_conf_recv_dev_conf(sink)) {
+ sink->con_state = CONFIGURING_RCVD_DEV_CONF;
+ } else {
+ GST_A2DP_SINK_CONFIGURATION_FAIL(sink);
+ }
+ case CONFIGURING_RCVD_DEV_CONF:
+ if (gst_a2dp_sink_conf_recv_stream_fd(sink)) {
+ GST_A2DP_SINK_CONFIGURATION_SUCCESS(sink);
+ } else {
+ GST_A2DP_SINK_CONFIGURATION_FAIL(sink);
+ }
+ break;
+ }
+
+ GST_A2DP_SINK_MUTEX_UNLOCK(sink);
+
+}
+
+static gboolean gst_a2dp_sink_set_caps(GstBaseSink *self, GstCaps *caps)
+{
+ GstA2dpSink *sink;
+
+ sink = GST_A2DP_SINK(self);
+
+ GST_A2DP_SINK_MUTEX_LOCK(sink);
+ if (sink->con_state == NOT_CONFIGURED) {
+ gst_a2dp_sink_start_dev_conf(sink, caps);
+ }
+ GST_A2DP_SINK_MUTEX_UNLOCK(sink);
+
+ return TRUE;
+}
+
+static gboolean gst_a2dp_sink_unlock(GstBaseSink *self)
+{
+ g_print("unlock\n");
+
+ return FALSE;
}

static gboolean server_callback(GIOChannel *chan,
GIOCondition cond, gpointer data)
{
- printf("callback\n");
+ GstA2dpSink *sink = GST_A2DP_SINK(data);
+
+ switch (cond) {
+ case G_IO_IN:
+ if (sink->con_state != NOT_CONFIGURED &&
+ sink->con_state != CONFIGURED)
+ gst_a2dp_sink_conf_recv_data(sink);
+ else
+ GST_WARNING_OBJECT(sink, "Unexpected data received");
+ break;
+ case G_IO_HUP:
+ g_print("callback G_IO_HUP\n");
+ break;
+ case G_IO_ERR:
+ g_print("callback G_IO_ERR\n");
+ break;
+ case G_IO_NVAL:
+ g_print("callback G_IO_NVAL\n");
+ break;
+ default:
+ g_print("unexpected callback\n");
+ break;
+
+ }

return TRUE;
}
@@ -187,21 +710,22 @@
static void gst_a2dp_sink_class_init(GstA2dpSinkClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
- GstAudioSinkClass *audiosink_class = GST_AUDIO_SINK_CLASS(klass);
+ GstBaseSinkClass *basesink_class = GST_BASE_SINK_CLASS(klass);

parent_class = g_type_class_peek_parent(klass);

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);
-
- 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);
+ object_class->set_property = GST_DEBUG_FUNCPTR(
+ gst_a2dp_sink_set_property);
+ object_class->get_property = GST_DEBUG_FUNCPTR(
+ gst_a2dp_sink_get_property);
+
+ basesink_class->start = GST_DEBUG_FUNCPTR(gst_a2dp_sink_start);
+ basesink_class->stop = GST_DEBUG_FUNCPTR(gst_a2dp_sink_stop);
+ basesink_class->render = GST_DEBUG_FUNCPTR(gst_a2dp_sink_render);
+ 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);

g_object_class_install_property(object_class, PROP_DEVICE,
g_param_spec_string("device", "Device",
@@ -215,15 +739,23 @@
static void gst_a2dp_sink_init(GstA2dpSink *self, GstA2dpSinkClass *klass)
{
struct sockaddr_un addr = { AF_UNIX, IPC_SOCKET_NAME };
- int sk;
+ gint sk;
+ gint err;

self->device = g_strdup(DEFAULT_DEVICE);

sk = socket(PF_LOCAL, SOCK_STREAM, 0);
- if (sk < 0)
+ if (sk < 0) {
+ err = errno;
+ GST_ERROR_OBJECT(self, "Cannot open socket: %s (%d)",
+ strerror(err), err);
return;
+ }

if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ err = errno;
+ GST_ERROR_OBJECT(self, "Connection fail %s (%d)",
+ strerror(err), err);
close(sk);
return;
}
@@ -233,5 +765,24 @@
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);
+ self->data = g_new0(struct bluetooth_data, 1);
+ memset(self->data, 0, sizeof(struct bluetooth_data));
+
+ self->data->pipefd[0] = -1;
+ self->data->pipefd[1] = -1;
+
+ if (pipe(self->data->pipefd) < 0)
+ GST_ERROR_OBJECT(self, "%s (%d)", strerror(errno), errno);
+ if (fcntl(self->data->pipefd[0], F_SETFL, O_NONBLOCK) < 0)
+ GST_ERROR_OBJECT(self, "%s (%d)", strerror(errno), errno);
+ if (fcntl(self->data->pipefd[1], F_SETFL, O_NONBLOCK) < 0)
+ GST_ERROR_OBJECT(self, "%s (%d)", strerror(errno), errno);
+
+ self->stream_fd = -1;
+ self->con_state = NOT_CONFIGURED;
+
+ self->con_conf_end = g_cond_new();
+ self->waiting_con_conf = FALSE;
+ self->sink_lock = g_mutex_new();
+
}
Index: audio/gsta2dpsink.h
===================================================================
RCS file: /cvsroot/bluez/utils/audio/gsta2dpsink.h,v
retrieving revision 1.3
diff -u -r1.3 gsta2dpsink.h
--- audio/gsta2dpsink.h 26 Aug 2007 14:14:34 -0000 1.3
+++ audio/gsta2dpsink.h 5 Oct 2007 18:49:40 -0000
@@ -22,7 +22,7 @@
*/

#include <gst/gst.h>
-#include <gst/audio/gstaudiosink.h>
+#include <gst/base/gstbasesink.h>

G_BEGIN_DECLS

@@ -37,19 +37,41 @@
#define GST_IS_A2DP_SINK_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_A2DP_SINK))

+enum {
+ NOT_CONFIGURED,
+ CONFIGURING_INIT,
+ CONFIGURING_SENT_CONF,
+ CONFIGURING_RCVD_CONF_RSP,
+ CONFIGURING_RCVD_DEV_CONF,
+ CONFIGURED
+};
+
typedef struct _GstA2dpSink GstA2dpSink;
typedef struct _GstA2dpSinkClass GstA2dpSinkClass;

+struct bluetooth_data;
+
struct _GstA2dpSink {
- GstAudioSink sink;
+ GstBaseSink sink;

gchar *device;
+ gint stream_fd;

+ struct bluetooth_data *data;
GIOChannel *server;
+
+ gint con_state;
+
+ GCond *con_conf_end;
+ gboolean waiting_con_conf;
+ GMutex *sink_lock;
+
+ gint total;
+
};

struct _GstA2dpSinkClass {
- GstAudioSinkClass parent_class;
+ GstBaseSinkClass parent_class;
};

GType gst_a2dp_sink_get_type(void);

[-- Attachment #3: Type: text/plain, Size: 314 bytes --]

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems? Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/

[-- Attachment #4: Type: text/plain, Size: 164 bytes --]