blob: a435c6a2a1f6a214e0e724835c2d3f3d4046e228 [file] [log] [blame]
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2012 Collabora Ltd.
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include "a2dp-codecs.h"
#include <gio/gunixfdlist.h>
#include <gst/gst.h>
#include "gstavdtputil.h"
#include "bluez.h"
#define TEMPLATE_MAX_BITPOOL 64
GST_DEBUG_CATEGORY_EXTERN (avdtp_debug);
#define GST_CAT_DEFAULT avdtp_debug
static void gst_avdtp_connection_transport_release (GstAvdtpConnection * conn);
static gboolean
on_state_change (BluezMediaTransport1 * proxy, GParamSpec * pspec,
GstAvdtpConnection * conn)
{
const gchar *newstate;
gboolean is_idle;
newstate = bluez_media_transport1_get_state (proxy);
is_idle = g_str_equal (newstate, "idle");
if (!conn->data.is_acquired && !is_idle) {
GST_DEBUG ("Re-acquiring connection");
gst_avdtp_connection_acquire (conn, TRUE);
} else if (is_idle) {
/* We don't know if we need to release the transport -- that may have been
* done for us by bluez already! Or not ... so release it just in case, but
* mark its stale beforehand to suppress any errors. */
GST_DEBUG ("Marking connection stale");
conn->data.is_acquired = FALSE;
gst_avdtp_connection_transport_release (conn);
} else
GST_DEBUG ("State is %s, acquired is %s", newstate,
conn->data.is_acquired ? "true" : "false");
return TRUE;
}
gboolean
gst_avdtp_connection_acquire (GstAvdtpConnection * conn, gboolean use_try)
{
GVariant *handle = NULL;
GUnixFDList *fd_list = NULL;
GError *err = NULL;
int fd;
uint16_t imtu, omtu;
if (conn->transport == NULL) {
GST_ERROR ("No transport specified");
return FALSE;
}
if (conn->data.conn == NULL) {
conn->data.conn =
bluez_media_transport1_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE, "org.bluez", conn->transport, NULL, &err);
if (conn->data.conn == NULL) {
GST_ERROR ("Failed to create proxy for media transport: %s",
err && err->message ? err->message : "Unknown error");
g_clear_error (&err);
return FALSE;
}
g_signal_connect (conn->data.conn, "notify::state",
G_CALLBACK (on_state_change), conn);
}
if (conn->data.is_acquired) {
GST_INFO ("Transport is already acquired");
return TRUE;
}
if (use_try) {
if (!bluez_media_transport1_call_try_acquire_sync (conn->data.conn,
NULL, &handle, &imtu, &omtu, &fd_list, NULL, &err))
goto fail;
} else {
if (!bluez_media_transport1_call_acquire_sync (conn->data.conn,
NULL, &handle, &imtu, &omtu, &fd_list, NULL, &err))
goto fail;
}
fd = g_unix_fd_list_get (fd_list, g_variant_get_handle (handle), &err);
if (fd < 0)
goto fail;
g_variant_unref (handle);
g_object_unref (fd_list);
conn->stream = g_io_channel_unix_new (fd);
g_io_channel_set_encoding (conn->stream, NULL, NULL);
g_io_channel_set_close_on_unref (conn->stream, TRUE);
conn->data.link_mtu = omtu;
conn->data.is_acquired = TRUE;
return TRUE;
fail:
GST_ERROR ("Failed to %s transport stream: %s", use_try ? "try_acquire" :
"acquire", err && err->message ? err->message : "unknown error");
g_clear_error (&err);
if (handle)
g_variant_unref (handle);
conn->data.is_acquired = FALSE;
return FALSE;
}
static void
gst_avdtp_connection_transport_release (GstAvdtpConnection * conn)
{
GError *err = NULL;
if (!bluez_media_transport1_call_release_sync (conn->data.conn, NULL, &err)) {
/* We don't care about errors if the transport was already marked stale */
if (!conn->data.is_acquired) {
g_clear_error (&err);
return;
}
GST_ERROR ("Failed to release transport stream: %s", err->message ?
err->message : "unknown error");
g_clear_error (&err);
}
conn->data.is_acquired = FALSE;
}
void
gst_avdtp_connection_release (GstAvdtpConnection * conn)
{
if (conn->stream) {
g_io_channel_shutdown (conn->stream, TRUE, NULL);
g_io_channel_unref (conn->stream);
conn->stream = NULL;
}
if (conn->data.uuid) {
g_free (conn->data.uuid);
conn->data.uuid = NULL;
}
if (conn->data.config) {
g_free (conn->data.config);
conn->data.config = NULL;
}
if (conn->data.conn) {
if (conn->transport)
gst_avdtp_connection_transport_release (conn);
g_clear_object (&conn->data.conn);
}
}
void
gst_avdtp_connection_reset (GstAvdtpConnection * conn)
{
gst_avdtp_connection_release (conn);
if (conn->device) {
g_free (conn->device);
conn->device = NULL;
}
if (conn->transport) {
g_free (conn->transport);
conn->transport = NULL;
}
}
void
gst_avdtp_connection_set_device (GstAvdtpConnection * conn, const char *device)
{
if (conn->device)
g_free (conn->device);
conn->device = g_strdup (device);
}
void
gst_avdtp_connection_set_transport (GstAvdtpConnection * conn,
const char *transport)
{
if (conn->transport)
g_free (conn->transport);
conn->transport = g_strdup (transport);
}
gboolean
gst_avdtp_connection_get_properties (GstAvdtpConnection * conn)
{
GVariant *var;
conn->data.codec = bluez_media_transport1_get_codec (conn->data.conn);
conn->data.uuid = bluez_media_transport1_dup_uuid (conn->data.conn);
var = bluez_media_transport1_dup_configuration (conn->data.conn);
conn->data.config_size = g_variant_get_size (var);
conn->data.config = g_new0 (guint8, conn->data.config_size);
g_variant_store (var, conn->data.config);
g_variant_unref (var);
return TRUE;
}
static GstStructure *
gst_avdtp_util_parse_sbc_raw (void *config)
{
a2dp_sbc_t *sbc = (a2dp_sbc_t *) config;
GstStructure *structure;
GValue *value;
GValue *list;
gboolean mono, stereo;
structure = gst_structure_new_empty ("audio/x-sbc");
value = g_value_init (g_new0 (GValue, 1), G_TYPE_STRING);
list = g_value_init (g_new0 (GValue, 1), GST_TYPE_LIST);
/* mode */
if (sbc->channel_mode & SBC_CHANNEL_MODE_MONO) {
g_value_set_static_string (value, "mono");
gst_value_list_prepend_value (list, value);
}
if (sbc->channel_mode & SBC_CHANNEL_MODE_STEREO) {
g_value_set_static_string (value, "stereo");
gst_value_list_prepend_value (list, value);
}
if (sbc->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL) {
g_value_set_static_string (value, "dual");
gst_value_list_prepend_value (list, value);
}
if (sbc->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO) {
g_value_set_static_string (value, "joint");
gst_value_list_prepend_value (list, value);
}
if (gst_value_list_get_size (list) == 1)
gst_structure_set_value (structure, "channel-mode", value);
else
gst_structure_take_value (structure, "channel-mode", list);
g_value_unset (value);
g_value_reset (list);
/* subbands */
value = g_value_init (value, G_TYPE_INT);
if (sbc->subbands & SBC_SUBBANDS_4) {
g_value_set_int (value, 4);
gst_value_list_prepend_value (list, value);
}
if (sbc->subbands & SBC_SUBBANDS_8) {
g_value_set_int (value, 8);
gst_value_list_prepend_value (list, value);
}
if (gst_value_list_get_size (list) == 1)
gst_structure_set_value (structure, "subbands", value);
else
gst_structure_take_value (structure, "subbands", list);
g_value_unset (value);
g_value_reset (list);
/* blocks */
value = g_value_init (value, G_TYPE_INT);
if (sbc->block_length & SBC_BLOCK_LENGTH_16) {
g_value_set_int (value, 16);
gst_value_list_prepend_value (list, value);
}
if (sbc->block_length & SBC_BLOCK_LENGTH_12) {
g_value_set_int (value, 12);
gst_value_list_prepend_value (list, value);
}
if (sbc->block_length & SBC_BLOCK_LENGTH_8) {
g_value_set_int (value, 8);
gst_value_list_prepend_value (list, value);
}
if (sbc->block_length & SBC_BLOCK_LENGTH_4) {
g_value_set_int (value, 4);
gst_value_list_prepend_value (list, value);
}
if (gst_value_list_get_size (list) == 1)
gst_structure_set_value (structure, "blocks", value);
else
gst_structure_take_value (structure, "blocks", list);
g_value_unset (value);
g_value_reset (list);
/* allocation */
g_value_init (value, G_TYPE_STRING);
if (sbc->allocation_method & SBC_ALLOCATION_LOUDNESS) {
g_value_set_static_string (value, "loudness");
gst_value_list_prepend_value (list, value);
}
if (sbc->allocation_method & SBC_ALLOCATION_SNR) {
g_value_set_static_string (value, "snr");
gst_value_list_prepend_value (list, value);
}
if (gst_value_list_get_size (list) == 1)
gst_structure_set_value (structure, "allocation-method", value);
else
gst_structure_take_value (structure, "allocation-method", list);
g_value_unset (value);
g_value_reset (list);
/* rate */
g_value_init (value, G_TYPE_INT);
if (sbc->frequency & SBC_SAMPLING_FREQ_48000) {
g_value_set_int (value, 48000);
gst_value_list_prepend_value (list, value);
}
if (sbc->frequency & SBC_SAMPLING_FREQ_44100) {
g_value_set_int (value, 44100);
gst_value_list_prepend_value (list, value);
}
if (sbc->frequency & SBC_SAMPLING_FREQ_32000) {
g_value_set_int (value, 32000);
gst_value_list_prepend_value (list, value);
}
if (sbc->frequency & SBC_SAMPLING_FREQ_16000) {
g_value_set_int (value, 16000);
gst_value_list_prepend_value (list, value);
}
if (gst_value_list_get_size (list) == 1)
gst_structure_set_value (structure, "rate", value);
else
gst_structure_take_value (structure, "rate", list);
g_value_unset (value);
g_value_reset (list);
/* bitpool */
value = g_value_init (value, GST_TYPE_INT_RANGE);
gst_value_set_int_range (value,
MIN (sbc->min_bitpool, TEMPLATE_MAX_BITPOOL),
MIN (sbc->max_bitpool, TEMPLATE_MAX_BITPOOL));
gst_structure_set_value (structure, "bitpool", value);
g_value_unset (value);
/* channels */
mono = FALSE;
stereo = FALSE;
if (sbc->channel_mode & SBC_CHANNEL_MODE_MONO)
mono = TRUE;
if ((sbc->channel_mode & SBC_CHANNEL_MODE_STEREO) ||
(sbc->channel_mode &
SBC_CHANNEL_MODE_DUAL_CHANNEL) ||
(sbc->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO))
stereo = TRUE;
if (mono && stereo) {
g_value_init (value, GST_TYPE_INT_RANGE);
gst_value_set_int_range (value, 1, 2);
} else {
g_value_init (value, G_TYPE_INT);
if (mono)
g_value_set_int (value, 1);
else if (stereo)
g_value_set_int (value, 2);
else {
GST_ERROR ("Unexpected number of channels");
g_value_set_int (value, 0);
}
}
gst_structure_set_value (structure, "channels", value);
g_value_unset (value);
g_free (value);
g_value_unset (list);
g_free (list);
return structure;
}
static GstStructure *
gst_avdtp_util_parse_mpeg_raw (void *config)
{
a2dp_mpeg_t *mpeg = (a2dp_mpeg_t *) config;
GstStructure *structure;
GValue *value;
GValue *list;
gboolean valid_layer = FALSE;
gboolean mono, stereo;
structure = gst_structure_new_empty ("audio/mpeg");
value = g_new0 (GValue, 1);
g_value_init (value, G_TYPE_INT);
list = g_value_init (g_new0 (GValue, 1), GST_TYPE_LIST);
g_value_set_int (value, 1);
gst_value_list_prepend_value (list, value);
g_value_set_int (value, 2);
gst_value_list_prepend_value (list, value);
gst_structure_set_value (structure, "mpegversion", list);
g_free (list);
/* layer */
list = g_value_init (g_new0 (GValue, 1), GST_TYPE_LIST);
if (mpeg->layer & MPEG_LAYER_MP1) {
g_value_set_int (value, 1);
gst_value_list_prepend_value (list, value);
valid_layer = TRUE;
}
if (mpeg->layer & MPEG_LAYER_MP2) {
g_value_set_int (value, 2);
gst_value_list_prepend_value (list, value);
valid_layer = TRUE;
}
if (mpeg->layer & MPEG_LAYER_MP3) {
g_value_set_int (value, 3);
gst_value_list_prepend_value (list, value);
valid_layer = TRUE;
}
if (list) {
if (gst_value_list_get_size (list) == 1)
gst_structure_set_value (structure, "layer", value);
else
gst_structure_set_value (structure, "layer", list);
g_free (list);
list = NULL;
}
if (!valid_layer) {
gst_structure_free (structure);
g_free (value);
return NULL;
}
/* rate */
list = g_value_init (g_new0 (GValue, 1), GST_TYPE_LIST);
if (mpeg->frequency & MPEG_SAMPLING_FREQ_48000) {
g_value_set_int (value, 48000);
gst_value_list_prepend_value (list, value);
}
if (mpeg->frequency & MPEG_SAMPLING_FREQ_44100) {
g_value_set_int (value, 44100);
gst_value_list_prepend_value (list, value);
}
if (mpeg->frequency & MPEG_SAMPLING_FREQ_32000) {
g_value_set_int (value, 32000);
gst_value_list_prepend_value (list, value);
}
if (mpeg->frequency & MPEG_SAMPLING_FREQ_24000) {
g_value_set_int (value, 24000);
gst_value_list_prepend_value (list, value);
}
if (mpeg->frequency & MPEG_SAMPLING_FREQ_22050) {
g_value_set_int (value, 22050);
gst_value_list_prepend_value (list, value);
}
if (mpeg->frequency & MPEG_SAMPLING_FREQ_16000) {
g_value_set_int (value, 16000);
gst_value_list_prepend_value (list, value);
}
g_value_unset (value);
if (list) {
if (gst_value_list_get_size (list) == 1)
gst_structure_set_value (structure, "rate", value);
else
gst_structure_set_value (structure, "rate", list);
g_free (list);
list = NULL;
}
/* channels */
mono = FALSE;
stereo = FALSE;
if (mpeg->channel_mode & MPEG_CHANNEL_MODE_MONO)
mono = TRUE;
if ((mpeg->channel_mode & MPEG_CHANNEL_MODE_STEREO) ||
(mpeg->channel_mode &
MPEG_CHANNEL_MODE_DUAL_CHANNEL) ||
(mpeg->channel_mode & MPEG_CHANNEL_MODE_JOINT_STEREO))
stereo = TRUE;
if (mono && stereo) {
g_value_init (value, GST_TYPE_INT_RANGE);
gst_value_set_int_range (value, 1, 2);
} else {
g_value_init (value, G_TYPE_INT);
if (mono)
g_value_set_int (value, 1);
else if (stereo)
g_value_set_int (value, 2);
else {
GST_ERROR ("Unexpected number of channels");
g_value_set_int (value, 0);
}
}
gst_structure_set_value (structure, "channels", value);
g_free (value);
return structure;
}
static GstStructure *
gst_avdtp_util_parse_aac_raw (void *config)
{
GstStructure *structure;
GValue value = G_VALUE_INIT;
GValue value_str = G_VALUE_INIT;
GValue list = G_VALUE_INIT;
a2dp_aac_t aac_local = { 0 };
a2dp_aac_t *aac = &aac_local;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
uint8_t *raw = (uint8_t *) config;
aac->object_type = raw[0];
aac->frequency = (raw[1] << 4) | ((raw[2] & 0xFF) >> 4);
aac->channels = (raw[2] >> 2) & 0x3;
aac->rfa = raw[2] & 0x3;
aac->vbr = (raw[3] >> 7) & 0x1;
aac->bitrate = (raw[4] << 16) | (raw[3] << 8) | raw[4];
aac->bitrate &= ~0x800000;
#elif G_BYTE_ORDER == G_BIG_ENDIAN
*aac = *((a2dp_aac_t *) config);
#else
#error "Unknown byte order"
#endif
GST_LOG ("aac objtype=%x freq=%x rfa=%x channels=%x vbr=%x bitrate=%x",
aac->object_type, aac->frequency, aac->rfa, aac->channels, aac->vbr,
aac->bitrate);
structure = gst_structure_new_empty ("audio/mpeg");
g_value_init (&value, G_TYPE_INT);
g_value_init (&value_str, G_TYPE_STRING);
/* mpegversion */
g_value_init (&list, GST_TYPE_LIST);
if (aac->object_type & AAC_OBJECT_TYPE_MPEG2_AAC_LC) {
g_value_set_int (&value, 2);
gst_value_list_prepend_value (&list, &value);
}
if ((aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LC)
|| (aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LTP)
|| (aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_SCALABLE)) {
g_value_set_int (&value, 4);
gst_value_list_prepend_value (&list, &value);
}
if (gst_value_list_get_size (&list) == 1)
gst_structure_set_value (structure, "mpegversion", &value);
else
gst_structure_set_value (structure, "mpegversion", &list);
g_value_reset (&list);
/* base-profile */
if (aac->object_type & AAC_OBJECT_TYPE_MPEG2_AAC_LC
|| aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LC) {
g_value_set_string (&value_str, "lc");
gst_value_list_prepend_value (&list, &value_str);
}
if (aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LTP) {
g_value_set_string (&value_str, "ltp");
gst_value_list_prepend_value (&list, &value_str);
}
if (aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_SCALABLE) {
g_value_set_string (&value_str, "ssr");
gst_value_list_prepend_value (&list, &value_str);
}
if (gst_value_list_get_size (&list) == 1)
gst_structure_set_value (structure, "base-profile", &value_str);
else
gst_structure_set_value (structure, "base-profile", &list);
g_value_reset (&list);
/* rate */
g_value_init (&list, GST_TYPE_LIST);
if (aac->frequency & AAC_SAMPLING_FREQ_8000) {
g_value_set_int (&value, 8000);
gst_value_list_prepend_value (&list, &value);
}
if (aac->frequency & AAC_SAMPLING_FREQ_11025) {
g_value_set_int (&value, 11025);
gst_value_list_prepend_value (&list, &value);
}
if (aac->frequency & AAC_SAMPLING_FREQ_12000) {
g_value_set_int (&value, 12000);
gst_value_list_prepend_value (&list, &value);
}
if (aac->frequency & AAC_SAMPLING_FREQ_16000) {
g_value_set_int (&value, 16000);
gst_value_list_prepend_value (&list, &value);
}
if (aac->frequency & AAC_SAMPLING_FREQ_22050) {
g_value_set_int (&value, 22050);
gst_value_list_prepend_value (&list, &value);
}
if (aac->frequency & AAC_SAMPLING_FREQ_24000) {
g_value_set_int (&value, 24000);
gst_value_list_prepend_value (&list, &value);
}
if (aac->frequency & AAC_SAMPLING_FREQ_32000) {
g_value_set_int (&value, 32000);
gst_value_list_prepend_value (&list, &value);
}
if (aac->frequency & AAC_SAMPLING_FREQ_44100) {
g_value_set_int (&value, 44100);
gst_value_list_prepend_value (&list, &value);
}
if (aac->frequency & AAC_SAMPLING_FREQ_48000) {
g_value_set_int (&value, 48000);
gst_value_list_prepend_value (&list, &value);
}
if (aac->frequency & AAC_SAMPLING_FREQ_64000) {
g_value_set_int (&value, 64000);
gst_value_list_prepend_value (&list, &value);
}
if (aac->frequency & AAC_SAMPLING_FREQ_88200) {
g_value_set_int (&value, 88200);
gst_value_list_prepend_value (&list, &value);
}
if (aac->frequency & AAC_SAMPLING_FREQ_96000) {
g_value_set_int (&value, 96000);
gst_value_list_prepend_value (&list, &value);
}
if (gst_value_list_get_size (&list) == 1)
gst_structure_set_value (structure, "rate", &value);
else
gst_structure_set_value (structure, "rate", &list);
g_value_reset (&list);
/* channels */
g_value_init (&list, GST_TYPE_LIST);
if (aac->channels & AAC_CHANNELS_1) {
g_value_set_int (&value, 1);
gst_value_list_prepend_value (&list, &value);
}
if (aac->channels & AAC_CHANNELS_2) {
g_value_set_int (&value, 2);
gst_value_list_prepend_value (&list, &value);
}
if (gst_value_list_get_size (&list) == 1)
gst_structure_set_value (structure, "channels", &value);
else
gst_structure_set_value (structure, "channels", &list);
GST_LOG ("AAC caps: %" GST_PTR_FORMAT, structure);
g_value_unset (&list);
g_value_unset (&value);
g_value_unset (&value_str);
return structure;
}
GstCaps *
gst_avdtp_connection_get_caps (GstAvdtpConnection * conn)
{
GstCaps *caps;
GstStructure *structure;
if (conn->data.config_size == 0 || conn->data.config == NULL)
return NULL;
switch (conn->data.codec) {
case A2DP_CODEC_SBC:
structure = gst_avdtp_util_parse_sbc_raw (conn->data.config);
break;
case A2DP_CODEC_MPEG12:
structure = gst_avdtp_util_parse_mpeg_raw (conn->data.config);
break;
case A2DP_CODEC_MPEG24:
structure = gst_avdtp_util_parse_aac_raw (conn->data.config);
break;
default:
GST_ERROR ("Unsupported configuration");
return NULL;
}
if (structure == NULL)
return FALSE;
caps = gst_caps_new_full (structure, NULL);
return caps;
}
gboolean
gst_avdtp_connection_conf_recv_stream_fd (GstAvdtpConnection * conn)
{
struct bluetooth_data *data = &conn->data;
GIOStatus status;
GIOFlags flags;
int fd;
int priority;
/* Proceed if stream was already acquired */
if (conn->stream == NULL) {
GST_ERROR ("Error while configuring device: "
"could not acquire audio socket");
return FALSE;
}
/* set stream socket to nonblock */
flags = g_io_channel_get_flags (conn->stream);
flags |= G_IO_FLAG_NONBLOCK;
status = g_io_channel_set_flags (conn->stream, flags, NULL);
if (status != G_IO_STATUS_NORMAL)
GST_WARNING ("Error while setting server socket to nonblock");
fd = g_io_channel_unix_get_fd (conn->stream);
/* It is possible there is some outstanding
data in the pipe - we have to empty it */
while (1) {
ssize_t bread = read (fd, data->buffer, data->link_mtu);
if (bread <= 0)
break;
}
/* set stream socket to block */
flags = g_io_channel_get_flags (conn->stream);
flags &= ~G_IO_FLAG_NONBLOCK;
status = g_io_channel_set_flags (conn->stream, flags, NULL);
if (status != G_IO_STATUS_NORMAL)
GST_WARNING ("Error while setting server socket to block");
priority = 6;
if (setsockopt (fd, SOL_SOCKET, SO_PRIORITY, (const void *) &priority,
sizeof (priority)) < 0)
GST_WARNING ("Unable to set socket to low delay");
memset (data->buffer, 0, sizeof (data->buffer));
return TRUE;
}