3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2004-2007 Marcel Holtmann <marcel@holtmann.org>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include <sys/socket.h>
34 #include <netinet/in.h>
36 #include <bluetooth/bluetooth.h>
40 #include "gstsbcutil.h"
42 #include "gsta2dpsink.h"
48 CONFIGURING_SENT_CONF,
49 CONFIGURING_RCVD_DEV_CONF,
53 GST_DEBUG_CATEGORY_STATIC (a2dp_sink_debug);
54 #define GST_CAT_DEFAULT a2dp_sink_debug
56 #define BUFFER_SIZE 2048
58 #define GST_A2DP_SINK_MUTEX_LOCK(s) G_STMT_START { \
59 g_mutex_lock (s->sink_lock); \
62 #define GST_A2DP_SINK_MUTEX_UNLOCK(s) G_STMT_START { \
63 g_mutex_unlock (s->sink_lock); \
66 #define GST_A2DP_SINK_WAIT_CON_END(s) G_STMT_START { \
67 s->waiting_con_conf = TRUE; \
68 g_cond_wait (s->con_conf_end, s->sink_lock); \
69 s->waiting_con_conf = FALSE; \
72 #define GST_A2DP_SINK_CONFIGURATION_FAIL(s) G_STMT_START { \
73 s->con_state = NOT_CONFIGURED; \
74 g_cond_signal (s->con_conf_end); \
77 #define GST_A2DP_SINK_CONFIGURATION_SUCCESS(s) G_STMT_START { \
78 s->con_state = CONFIGURED; \
79 g_cond_signal (s->con_conf_end); \
84 struct ipc_data_cfg cfg; /* Bluetooth device config */
85 int samples; /* Number of encoded samples */
86 gchar buffer[BUFFER_SIZE]; /* Codec transfer buffer */
87 gsize count; /* Codec transfer buffer counter */
89 int nsamples; /* Cumulative number of codec samples */
90 uint16_t seq_num; /* Cumulative packet sequence */
91 int frame_count; /* Current frames in buffer */
94 #define IS_SBC(n) (strcmp((n), "audio/x-sbc") == 0)
95 #define IS_MPEG(n) (strcmp((n), "audio/mpeg") == 0)
103 GST_BOILERPLATE (GstA2dpSink, gst_a2dp_sink, GstBaseSink, GST_TYPE_BASE_SINK);
105 static const GstElementDetails a2dp_sink_details =
106 GST_ELEMENT_DETAILS ("Bluetooth A2DP sink",
108 "Plays audio to an A2DP device",
109 "Marcel Holtmann <marcel@holtmann.org>");
111 static GstStaticPadTemplate a2dp_sink_factory =
112 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
113 GST_STATIC_CAPS ("audio/x-sbc, "
114 "rate = (int) { 16000, 32000, 44100, 48000 }, "
115 "channels = (int) [ 1, 2 ], "
116 "mode = (string) { mono, dual, stereo, joint }, "
117 "blocks = (int) { 4, 8, 12, 16 }, "
118 "subbands = (int) { 4, 8 }, "
119 "allocation = (string) { snr, loudness },"
120 "bitpool = (int) [ 2, 64 ]; "
122 "mpegversion = (int) 1, "
123 "layer = (int) [ 1, 3 ], "
124 "rate = (int) { 16000, 22050, 24000, 32000, 44100, 48000 }, "
125 "channels = (int) [ 1, 2 ]"));
128 gst_a2dp_sink_base_init (gpointer g_class)
130 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
132 gst_element_class_add_pad_template (element_class,
133 gst_static_pad_template_get (&a2dp_sink_factory));
135 gst_element_class_set_details (element_class, &a2dp_sink_details);
139 gst_a2dp_sink_stop (GstBaseSink * basesink)
141 GstA2dpSink *self = GST_A2DP_SINK (basesink);
143 GST_INFO_OBJECT (self, "stop");
145 self->con_state = NOT_CONFIGURED;
147 if (self->watch_id != 0) {
148 g_source_remove (self->watch_id);
153 g_io_channel_flush (self->stream, NULL);
154 g_io_channel_close (self->stream);
155 g_io_channel_unref (self->stream);
160 g_io_channel_close (self->server);
161 g_io_channel_unref (self->server);
175 if (self->dev_caps) {
176 gst_caps_unref (self->dev_caps);
177 self->dev_caps = NULL;
184 gst_a2dp_sink_finalize (GObject * object)
186 GstA2dpSink *self = GST_A2DP_SINK (object);
189 gst_a2dp_sink_stop (GST_BASE_SINK (self));
192 g_free (self->device);
194 /* unlock any thread waiting for this signal */
195 GST_A2DP_SINK_MUTEX_LOCK (self);
196 GST_A2DP_SINK_CONFIGURATION_FAIL (self);
197 GST_A2DP_SINK_MUTEX_UNLOCK (self);
199 g_cond_free (self->con_conf_end);
200 g_mutex_free (self->sink_lock);
202 G_OBJECT_CLASS (parent_class)->finalize (object);
206 gst_a2dp_sink_set_property (GObject * object, guint prop_id,
207 const GValue * value, GParamSpec * pspec)
209 GstA2dpSink *sink = GST_A2DP_SINK (object);
214 g_free (sink->device);
215 sink->device = g_value_dup_string (value);
219 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
225 gst_a2dp_sink_get_property (GObject * object, guint prop_id,
226 GValue * value, GParamSpec * pspec)
228 GstA2dpSink *sink = GST_A2DP_SINK (object);
232 g_value_set_string (value, sink->device);
236 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
242 gst_a2dp_sink_bluetooth_recvmsg_fd (GstA2dpSink * sink)
244 char cmsg_b[CMSG_SPACE (sizeof (int))], m;
245 int err, ret, stream_fd;
246 struct iovec iov = { &m, sizeof (m) };
248 struct cmsghdr *cmsg;
250 memset (&msgh, 0, sizeof (msgh));
253 msgh.msg_control = &cmsg_b;
254 msgh.msg_controllen = CMSG_LEN (sizeof (int));
256 ret = recvmsg (g_io_channel_unix_get_fd (sink->server), &msgh, 0);
259 GST_ERROR_OBJECT (sink, "Unable to receive fd: %s (%d)",
260 strerror (err), err);
264 /* Receive auxiliary data in msgh */
265 for (cmsg = CMSG_FIRSTHDR (&msgh); cmsg != NULL;
266 cmsg = CMSG_NXTHDR (&msgh, cmsg)) {
267 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
268 stream_fd = (*(int *) CMSG_DATA (cmsg));
269 sink->stream = g_io_channel_unix_new (stream_fd);
271 GST_DEBUG_OBJECT (sink, "stream_fd=%d", stream_fd);
280 gst_a2dp_sink_check_dev_caps (GstA2dpSink * self)
282 GstStructure *structure;
286 structure = gst_caps_get_structure (self->dev_caps, 0);
287 if (!gst_structure_get_int (structure, "channels", &channels))
288 channels = 2; /* FIXME how to get channels */
289 dev_caps = gst_sbc_caps_from_sbc (&(self->data->cfg), self->sbc, channels);
291 self->new_dev_caps = TRUE;
292 gst_caps_unref (self->dev_caps);
293 self->dev_caps = gst_caps_ref (dev_caps);
299 gst_a2dp_sink_bluetooth_a2dp_init (GstA2dpSink * self,
300 struct ipc_codec_sbc *sbc)
302 struct bluetooth_data *data = self->data;
303 struct ipc_data_cfg *cfg = &data->cfg;
306 GST_ERROR_OBJECT (self, "Error getting codec parameters");
310 if (cfg->codec != CFG_CODEC_SBC)
313 data->count = sizeof (struct rtp_header) + sizeof (struct rtp_payload);
315 GST_DEBUG_OBJECT (self, "Codec parameters: "
316 "\tallocation=%u\n\tsubbands=%u\n "
317 "\tblocks=%u\n\tbitpool=%u\n",
318 sbc->allocation, sbc->subbands, sbc->blocks, sbc->bitpool);
324 gst_a2dp_sink_init_pkt_conf (GstA2dpSink * sink,
325 GstCaps * caps, struct ipc_packet *pkt)
328 struct ipc_data_cfg *cfg = (void *) pkt->data;
329 struct ipc_codec_sbc *sbc = (void *) cfg->data;
330 const GValue *value = NULL;
331 const char *pref, *name;
332 GstStructure *structure = gst_caps_get_structure (caps, 0);
334 name = gst_structure_get_name (structure);
335 /* FIXME only sbc supported here, should suport mp3 */
336 if (!(IS_SBC (name))) {
337 GST_ERROR_OBJECT (sink, "Unsupported format %s", name);
342 strncpy (pkt->device, sink->device, 18);
344 pkt->role = PKT_ROLE_HIFI;
346 value = gst_structure_get_value (structure, "rate");
347 cfg->rate = g_value_get_int (value);
349 value = gst_structure_get_value (structure, "mode");
350 pref = g_value_get_string (value);
351 if (strcmp (pref, "auto") == 0)
352 cfg->mode = CFG_MODE_AUTO;
353 else if (strcmp (pref, "mono") == 0)
354 cfg->mode = CFG_MODE_MONO;
355 else if (strcmp (pref, "dual") == 0)
356 cfg->mode = CFG_MODE_DUAL_CHANNEL;
357 else if (strcmp (pref, "stereo") == 0)
358 cfg->mode = CFG_MODE_STEREO;
359 else if (strcmp (pref, "joint") == 0)
360 cfg->mode = CFG_MODE_JOINT_STEREO;
362 GST_ERROR_OBJECT (sink, "Invalid mode %s", pref);
366 value = gst_structure_get_value (structure, "allocation");
367 pref = g_value_get_string (value);
368 if (strcmp (pref, "auto") == 0)
369 sbc->allocation = CFG_ALLOCATION_AUTO;
370 else if (strcmp (pref, "loudness") == 0)
371 sbc->allocation = CFG_ALLOCATION_LOUDNESS;
372 else if (strcmp (pref, "snr") == 0)
373 sbc->allocation = CFG_ALLOCATION_SNR;
375 GST_ERROR_OBJECT (sink, "Invalid allocation: %s", pref);
379 value = gst_structure_get_value (structure, "subbands");
380 sbc->subbands = g_value_get_int (value);
382 value = gst_structure_get_value (structure, "blocks");
383 sbc->blocks = g_value_get_int (value);
385 value = gst_structure_get_value (structure, "bitpool");
386 sbc->bitpool = g_value_get_int (value);
388 pkt->length = sizeof (*cfg) + sizeof (*sbc);
389 pkt->type = PKT_TYPE_CFG_REQ;
390 pkt->error = PKT_ERROR_NONE;
396 gst_a2dp_sink_conf_resp (GstA2dpSink * sink)
402 struct ipc_packet *pkt = (void *) buf;
403 struct ipc_data_cfg *cfg = (void *) pkt->data;
404 struct ipc_codec_sbc *sbc = (void *) cfg->data;
406 memset (buf, 0, sizeof (buf));
408 io_error = g_io_channel_read (sink->server, (gchar *) buf,
409 sizeof (*pkt) + sizeof (*cfg), &ret);
410 if (io_error != G_IO_ERROR_NONE && ret > 0) {
411 GST_ERROR_OBJECT (sink, "Error ocurred while receiving "
412 "configurarion packet answer");
417 if (pkt->type != PKT_TYPE_CFG_RSP) {
418 GST_ERROR_OBJECT (sink, "Unexpected packet type %d " "received", pkt->type);
422 if (pkt->error != PKT_ERROR_NONE) {
423 GST_ERROR_OBJECT (sink, "Error %d while configuring " "device", pkt->error);
427 if (cfg->codec != CFG_CODEC_SBC) {
428 GST_ERROR_OBJECT (sink, "Unsupported format");
432 io_error = g_io_channel_read (sink->server, (gchar *) sbc,
433 sizeof (*sbc), &ret);
434 if (io_error != G_IO_ERROR_NONE) {
435 GST_ERROR_OBJECT (sink, "Error while reading data from socket "
436 "%s (%d)", strerror (errno), errno);
438 } else if (ret == 0) {
439 GST_ERROR_OBJECT (sink, "Read 0 bytes from socket");
444 GST_DEBUG_OBJECT (sink, "OK - %d bytes received", total);
446 if (pkt->length != (total - sizeof (struct ipc_packet))) {
447 GST_ERROR_OBJECT (sink, "Error while configuring device: "
448 "packet size doesn't match");
452 memcpy (&sink->data->cfg, cfg, sizeof (*cfg));
453 memcpy (sink->sbc, sbc, sizeof (struct ipc_codec_sbc));
455 gst_a2dp_sink_check_dev_caps (sink);
457 GST_DEBUG_OBJECT (sink, "Device configuration:\n\tchannel=%p\n\t"
458 "fd_opt=%u\n\tpkt_len=%u\n\tsample_size=%u\n\trate=%u",
459 sink->stream, sink->data->cfg.fd_opt,
460 sink->data->cfg.pkt_len, sink->data->cfg.sample_size,
461 sink->data->cfg.rate);
463 if (sink->data->cfg.codec == CFG_CODEC_SBC) {
464 /* FIXME is this necessary? */
465 ret = gst_a2dp_sink_bluetooth_a2dp_init (sink, sbc);
474 gst_a2dp_sink_conf_recv_stream_fd (GstA2dpSink * self)
476 struct bluetooth_data *data = self->data;
484 ret = gst_a2dp_sink_bluetooth_recvmsg_fd (self);
489 GST_ERROR_OBJECT (self, "Error while configuring device: "
490 "could not acquire audio socket");
494 /* set stream socket to nonblock */
495 GST_LOG_OBJECT (self, "setting stream socket to nonblock");
496 flags = g_io_channel_get_flags (self->stream);
497 flags |= G_IO_FLAG_NONBLOCK;
498 status = g_io_channel_set_flags (self->stream, flags, &gerr);
499 if (status != G_IO_STATUS_NORMAL) {
501 GST_WARNING_OBJECT (self, "Error while "
502 "setting server socket to nonblock: " "%s", gerr->message);
504 GST_WARNING_OBJECT (self, "Error while "
505 "setting server " "socket to nonblock");
508 /* It is possible there is some outstanding
509 data in the pipe - we have to empty it */
510 GST_LOG_OBJECT (self, "emptying stream pipe");
512 err = g_io_channel_read (self->stream, data->buffer,
513 (gsize) data->cfg.pkt_len, &read);
514 if (err != G_IO_ERROR_NONE || read <= 0)
518 /* set stream socket to block */
519 GST_LOG_OBJECT (self, "setting stream socket to block");
520 flags = g_io_channel_get_flags (self->stream);
521 flags &= ~G_IO_FLAG_NONBLOCK;
522 status = g_io_channel_set_flags (self->stream, flags, &gerr);
523 if (status != G_IO_STATUS_NORMAL) {
525 GST_WARNING_OBJECT (self, "Error while "
526 "setting server socket to block:" "%s", gerr->message);
528 GST_WARNING_OBJECT (self, "Error while "
529 "setting server " "socket to block");
532 memset (data->buffer, 0, sizeof (data->buffer));
538 gst_a2dp_sink_conf_recv_data (GstA2dpSink * sink)
541 * We hold the lock, since we can send a signal.
542 * It is a good practice, according to the glib api.
544 GST_A2DP_SINK_MUTEX_LOCK (sink);
546 switch (sink->con_state) {
547 case CONFIGURING_SENT_CONF:
548 if (gst_a2dp_sink_conf_resp (sink))
549 sink->con_state = CONFIGURING_RCVD_DEV_CONF;
551 GST_A2DP_SINK_CONFIGURATION_FAIL (sink);
553 case CONFIGURING_RCVD_DEV_CONF:
554 if (gst_a2dp_sink_conf_recv_stream_fd (sink))
555 GST_A2DP_SINK_CONFIGURATION_SUCCESS (sink);
557 GST_A2DP_SINK_CONFIGURATION_FAIL (sink);
561 GST_A2DP_SINK_MUTEX_UNLOCK (sink);
566 server_callback (GIOChannel * chan, GIOCondition cond, gpointer data)
570 if (cond & G_IO_HUP || cond & G_IO_NVAL)
572 else if (cond & G_IO_ERR) {
573 sink = GST_A2DP_SINK (data);
574 GST_WARNING_OBJECT (sink, "Untreated callback G_IO_ERR");
575 } else if (cond & G_IO_IN) {
576 sink = GST_A2DP_SINK (data);
577 if (sink->con_state != NOT_CONFIGURED && sink->con_state != CONFIGURED)
578 gst_a2dp_sink_conf_recv_data (sink);
580 GST_WARNING_OBJECT (sink, "Unexpected data received");
582 sink = GST_A2DP_SINK (data);
583 GST_WARNING_OBJECT (sink, "Unexpected callback call");
590 gst_a2dp_sink_start (GstBaseSink * basesink)
592 GstA2dpSink *self = GST_A2DP_SINK (basesink);
593 struct sockaddr_un addr = { AF_UNIX, IPC_SOCKET_NAME };
597 GST_INFO_OBJECT (self, "start");
601 sk = socket (PF_LOCAL, SOCK_STREAM, 0);
604 GST_ERROR_OBJECT (self, "Cannot open socket: %s (%d)", strerror (err), err);
608 if (connect (sk, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
610 GST_ERROR_OBJECT (self, "Connection fail %s (%d)", strerror (err), err);
615 self->server = g_io_channel_unix_new (sk);
617 self->watch_id = g_io_add_watch (self->server, G_IO_IN | G_IO_HUP |
618 G_IO_ERR | G_IO_NVAL, server_callback, self);
620 self->data = g_new0 (struct bluetooth_data, 1);
621 memset (self->data, 0, sizeof (struct bluetooth_data));
623 self->sbc = g_new0 (struct ipc_codec_sbc, 1);
626 self->con_state = NOT_CONFIGURED;
627 self->new_dev_caps = FALSE;
628 self->dev_caps = NULL;
630 self->waiting_con_conf = FALSE;
636 gst_a2dp_sink_send_conf_pkt (GstA2dpSink * sink, GstCaps * caps)
639 struct ipc_packet *pkt = (void *) buf;
644 g_assert (sink->con_state == NOT_CONFIGURED);
646 memset (pkt, 0, sizeof (buf));
647 ret = gst_a2dp_sink_init_pkt_conf (sink, caps, pkt);
649 GST_ERROR_OBJECT (sink, "Couldn't initialize parse caps "
650 "to packet configuration");
654 sink->con_state = CONFIGURING_INIT;
656 io_error = g_io_channel_write (sink->server, (gchar *) pkt,
657 sizeof (*pkt) + pkt->length, &bytes_sent);
658 if (io_error != G_IO_ERROR_NONE) {
659 GST_ERROR_OBJECT (sink, "Error ocurred while sending "
660 "configurarion packet");
661 sink->con_state = NOT_CONFIGURED;
665 GST_DEBUG_OBJECT (sink, "%d bytes sent", bytes_sent);
666 sink->con_state = CONFIGURING_SENT_CONF;
672 gst_a2dp_sink_start_dev_conf (GstA2dpSink * sink, GstCaps * caps)
676 g_assert (sink->con_state == NOT_CONFIGURED);
678 GST_DEBUG_OBJECT (sink, "starting device configuration");
680 ret = gst_a2dp_sink_send_conf_pkt (sink, caps);
686 gst_a2dp_sink_preroll (GstBaseSink * basesink, GstBuffer * buffer)
688 GstA2dpSink *sink = GST_A2DP_SINK (basesink);
690 GST_A2DP_SINK_MUTEX_LOCK (sink);
692 if (sink->con_state == NOT_CONFIGURED)
693 gst_a2dp_sink_start_dev_conf (sink, GST_BUFFER_CAPS (buffer));
695 /* wait for the connection process to finish */
696 if (sink->con_state != CONFIGURED)
697 GST_A2DP_SINK_WAIT_CON_END (sink);
699 GST_A2DP_SINK_MUTEX_UNLOCK (sink);
701 if (sink->con_state != CONFIGURED)
702 return GST_FLOW_ERROR;
708 gst_a2dp_sink_avdtp_write (GstA2dpSink * self)
711 struct bluetooth_data *data = self->data;
712 struct rtp_header *header;
713 struct rtp_payload *payload;
716 header = (void *) data->buffer;
717 payload = (void *) (data->buffer + sizeof (*header));
719 memset (data->buffer, 0, sizeof (*header) + sizeof (*payload));
721 payload->frame_count = data->frame_count;
724 header->sequence_number = htons (data->seq_num);
725 header->timestamp = htonl (data->nsamples);
726 header->ssrc = htonl (1);
728 err = g_io_channel_write (self->stream, data->buffer, data->count, &ret);
729 if (err != G_IO_ERROR_NONE) {
730 GST_ERROR_OBJECT (self, "Error while sending data");
734 /* Reset buffer of data to send */
735 data->count = sizeof (struct rtp_header) + sizeof (struct rtp_payload);
736 data->frame_count = 0;
744 gst_a2dp_sink_render (GstBaseSink * basesink, GstBuffer * buffer)
746 GstA2dpSink *self = GST_A2DP_SINK (basesink);
747 struct bluetooth_data *data = self->data;
751 encoded = GST_BUFFER_SIZE (buffer);
753 if (data->count + encoded >= data->cfg.pkt_len) {
754 ret = gst_a2dp_sink_avdtp_write (self);
756 return GST_FLOW_ERROR;
759 memcpy (data->buffer + data->count, GST_BUFFER_DATA (buffer), encoded);
760 data->count += encoded;
767 gst_a2dp_sink_set_caps (GstBaseSink * basesink, GstCaps * caps)
769 GstA2dpSink *self = GST_A2DP_SINK (basesink);
771 GST_A2DP_SINK_MUTEX_LOCK (self);
772 if (self->con_state == NOT_CONFIGURED) {
773 gst_a2dp_sink_start_dev_conf (self, caps);
776 gst_caps_unref (self->dev_caps);
777 self->dev_caps = gst_caps_ref (caps);
779 /* we suppose the device will accept this caps */
780 self->new_dev_caps = FALSE;
782 GST_A2DP_SINK_MUTEX_UNLOCK (self);
788 gst_a2dp_sink_unlock (GstBaseSink * basesink)
790 GstA2dpSink *self = GST_A2DP_SINK (basesink);
792 if (self->stream != NULL)
793 g_io_channel_flush (self->stream, NULL);
799 gst_a2dp_sink_buffer_alloc (GstBaseSink * basesink,
800 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf)
802 GstA2dpSink *self = GST_A2DP_SINK (basesink);
804 *buf = gst_buffer_new_and_alloc (size);
806 GST_ERROR_OBJECT (self, "buffer allocation failed");
807 return GST_FLOW_ERROR;
810 if (self->new_dev_caps && self->dev_caps) {
811 GST_INFO_OBJECT (self, "new caps from device");
812 gst_buffer_set_caps (*buf, self->dev_caps);
813 self->new_dev_caps = FALSE;
815 gst_buffer_set_caps (*buf, caps);
817 GST_BUFFER_OFFSET (*buf) = offset;
823 gst_a2dp_sink_class_init (GstA2dpSinkClass * klass)
825 GObjectClass *object_class = G_OBJECT_CLASS (klass);
826 GstBaseSinkClass *basesink_class = GST_BASE_SINK_CLASS (klass);
828 parent_class = g_type_class_peek_parent (klass);
830 object_class->finalize = GST_DEBUG_FUNCPTR (gst_a2dp_sink_finalize);
831 object_class->set_property = GST_DEBUG_FUNCPTR (gst_a2dp_sink_set_property);
832 object_class->get_property = GST_DEBUG_FUNCPTR (gst_a2dp_sink_get_property);
834 basesink_class->start = GST_DEBUG_FUNCPTR (gst_a2dp_sink_start);
835 basesink_class->stop = GST_DEBUG_FUNCPTR (gst_a2dp_sink_stop);
836 basesink_class->render = GST_DEBUG_FUNCPTR (gst_a2dp_sink_render);
837 basesink_class->preroll = GST_DEBUG_FUNCPTR (gst_a2dp_sink_preroll);
838 basesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_a2dp_sink_set_caps);
839 basesink_class->unlock = GST_DEBUG_FUNCPTR (gst_a2dp_sink_unlock);
840 basesink_class->buffer_alloc = GST_DEBUG_FUNCPTR (gst_a2dp_sink_buffer_alloc);
842 g_object_class_install_property (object_class, PROP_DEVICE,
843 g_param_spec_string ("device", "Device",
844 "Bluetooth remote device address", NULL, G_PARAM_READWRITE));
846 GST_DEBUG_CATEGORY_INIT (a2dp_sink_debug, "a2dpsink", 0, "A2DP sink element");
850 gst_a2dp_sink_init (GstA2dpSink * self, GstA2dpSinkClass * klass)
857 self->con_state = NOT_CONFIGURED;
859 self->con_conf_end = g_cond_new ();
860 self->waiting_con_conf = FALSE;
861 self->sink_lock = g_mutex_new ();