Exemple #1
0
static gboolean
gst_a2dp_sink_init_avdtp_sink (GstA2dpSink * self)
{
  GstElement *sink;

  if (self->sink == NULL)
    sink = gst_element_factory_make ("avdtpsink", "avdtpsink");
  else
    sink = GST_ELEMENT (self->sink);

  if (sink == NULL) {
    GST_ERROR_OBJECT (self, "Couldn't create avdtpsink");
    return FALSE;
  }

  if (!gst_bin_add (GST_BIN (self), sink)) {
    GST_ERROR_OBJECT (self, "failed to add avdtpsink " "to the bin");
    goto cleanup_and_fail;
  }

  self->sink = GST_AVDTP_SINK (sink);
  g_object_set (G_OBJECT (self->sink), "device", self->device, NULL);
  g_object_set (G_OBJECT (self->sink), "transport", self->transport, NULL);

  gst_element_sync_state_with_parent (sink);

  return TRUE;

cleanup_and_fail:
  if (sink != NULL)
    g_object_unref (G_OBJECT (sink));

  return FALSE;
}
static void gst_avdtp_sink_tag(const GstTagList *taglist,
			const gchar *tag, gpointer user_data)
{
	gboolean crc;
	gchar *channel_mode = NULL;
	GstAvdtpSink *self = GST_AVDTP_SINK(user_data);

	if (strcmp(tag, "has-crc") == 0) {

		if (!gst_tag_list_get_boolean(taglist, tag, &crc)) {
			GST_WARNING_OBJECT(self, "failed to get crc tag");
			return;
		}

		gst_avdtp_sink_set_crc(self, crc);

	} else if (strcmp(tag, "channel-mode") == 0) {

		if (!gst_tag_list_get_string(taglist, tag, &channel_mode)) {
			GST_WARNING_OBJECT(self,
				"failed to get channel-mode tag");
			return;
		}

		self->channel_mode = gst_avdtp_sink_get_channel_mode(
					channel_mode);
		if (self->channel_mode == -1)
			GST_WARNING_OBJECT(self, "Received invalid channel "
					"mode: %s", channel_mode);
		g_free(channel_mode);

	} else
		GST_DEBUG_OBJECT(self, "received unused tag: %s", tag);
}
static gboolean gst_avdtp_sink_unlock(GstBaseSink *basesink)
{
	GstAvdtpSink *self = GST_AVDTP_SINK(basesink);

	if (self->stream != NULL)
		g_io_channel_flush(self->stream, NULL);

	return TRUE;
}
Exemple #4
0
static gboolean gst_a2dp_sink_init_avdtp_sink(GstA2dpSink *self)
{
	GstElement *sink;

	/* check if we don't need a new sink */
	if (self->sink_is_in_bin)
		return TRUE;

	if (self->sink == NULL)
		sink = gst_element_factory_make("avdtpsink", "avdtpsink");
	else
		sink = GST_ELEMENT(self->sink);

	if (sink == NULL) {
		GST_ERROR_OBJECT(self, "Couldn't create avdtpsink");
		return FALSE;
	}

	if (!gst_bin_add(GST_BIN(self), sink)) {
		GST_ERROR_OBJECT(self, "failed to add avdtpsink "
			"to the bin");
		goto cleanup_and_fail;
	}

	if (gst_element_set_state(sink, GST_STATE_READY) ==
			GST_STATE_CHANGE_FAILURE) {
		GST_ERROR_OBJECT(self, "avdtpsink failed to go to ready");
		goto remove_element_and_fail;
	}

	if (!gst_element_link(GST_ELEMENT(self->rtp), sink)) {
		GST_ERROR_OBJECT(self, "couldn't link rtpsbcpay "
			"to avdtpsink");
		goto remove_element_and_fail;
	}

	self->sink = GST_AVDTP_SINK(sink);
	self->sink_is_in_bin = TRUE;
	g_object_set(G_OBJECT(self->sink), "device", self->device, NULL);

	gst_element_set_state(sink, GST_STATE_PAUSED);

	return TRUE;

remove_element_and_fail:
	gst_element_set_state(sink, GST_STATE_NULL);
	gst_bin_remove(GST_BIN(self), sink);
	return FALSE;

cleanup_and_fail:
	if (sink != NULL)
		g_object_unref(G_OBJECT(sink));

	return FALSE;
}
static gboolean server_callback(GIOChannel *chan,
					GIOCondition cond, gpointer data)
{
	if (cond & G_IO_HUP || cond & G_IO_NVAL)
		return FALSE;
	else if (cond & G_IO_ERR)
		GST_WARNING_OBJECT(GST_AVDTP_SINK(data),
					"Untreated callback G_IO_ERR");

	return TRUE;
}
static void gst_avdtp_sink_finalize(GObject *object)
{
	GstAvdtpSink *self = GST_AVDTP_SINK(object);

	if (self->data)
		gst_avdtp_sink_stop(GST_BASE_SINK(self));

	if (self->device)
		g_free(self->device);

	g_mutex_free(self->sink_lock);

	G_OBJECT_CLASS(parent_class)->finalize(object);
}
Exemple #7
0
static gboolean server_callback(GIOChannel *chan,
					GIOCondition cond, gpointer data)
{
	GstAvdtpSink *sink;

	if (cond & G_IO_HUP || cond & G_IO_NVAL)
		return FALSE;
	else if (cond & G_IO_ERR) {
		sink = GST_AVDTP_SINK(data);
		GST_WARNING_OBJECT(sink, "Untreated callback G_IO_ERR");
	}

	return TRUE;
}
static gboolean gst_avdtp_sink_event(GstBaseSink *basesink,
			GstEvent *event)
{
	GstAvdtpSink *self = GST_AVDTP_SINK(basesink);
	GstTagList *taglist = NULL;

	if (GST_EVENT_TYPE(event) == GST_EVENT_TAG) {
		/* we check the tags, mp3 has tags that are importants and
		 * are outside caps */
		gst_event_parse_tag(event, &taglist);
		gst_tag_list_foreach(taglist, gst_avdtp_sink_tag, self);
	}

	return TRUE;
}
static GstFlowReturn gst_avdtp_sink_preroll(GstBaseSink *basesink,
					GstBuffer *buffer)
{
	GstAvdtpSink *sink = GST_AVDTP_SINK(basesink);
	gboolean ret;

	GST_AVDTP_SINK_MUTEX_LOCK(sink);

	ret = gst_avdtp_sink_stream_start(sink);

	GST_AVDTP_SINK_MUTEX_UNLOCK(sink);

	if (!ret)
		return GST_FLOW_ERROR;

	return GST_FLOW_OK;
}
static void gst_avdtp_sink_get_property(GObject *object, guint prop_id,
					GValue *value, GParamSpec *pspec)
{
	GstAvdtpSink *sink = GST_AVDTP_SINK(object);

	switch (prop_id) {
	case PROP_DEVICE:
		g_value_set_string(value, sink->device);
		break;

	case PROP_AUTOCONNECT:
		g_value_set_boolean(value, sink->autoconnect);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
		break;
	}
}
static GstFlowReturn gst_avdtp_sink_buffer_alloc(GstBaseSink *basesink,
				guint64 offset, guint size, GstCaps *caps,
				GstBuffer **buf)
{
	GstAvdtpSink *self = GST_AVDTP_SINK(basesink);

	*buf = gst_buffer_new_and_alloc(size);
	if (!(*buf)) {
		GST_ERROR_OBJECT(self, "buffer allocation failed");
		return GST_FLOW_ERROR;
	}

	gst_buffer_set_caps(*buf, caps);

	GST_BUFFER_OFFSET(*buf) = offset;

	return GST_FLOW_OK;
}
static GstFlowReturn gst_avdtp_sink_render(GstBaseSink *basesink,
					GstBuffer *buffer)
{
	GstAvdtpSink *self = GST_AVDTP_SINK(basesink);
	gsize ret;
	GIOError err;

	err = g_io_channel_write(self->stream,
				(gchar *) GST_BUFFER_DATA(buffer),
				(gsize) (GST_BUFFER_SIZE(buffer)), &ret);

	if (err != G_IO_ERROR_NONE) {
		GST_ERROR_OBJECT(self, "Error while writting to socket: %d %s",
				errno, strerror(errno));
		return GST_FLOW_ERROR;
	}

	return GST_FLOW_OK;
}
static gboolean gst_avdtp_sink_start(GstBaseSink *basesink)
{
	GstAvdtpSink *self = GST_AVDTP_SINK(basesink);
	gint sk;
	gint err;

	GST_INFO_OBJECT(self, "start");

	self->watch_id = 0;

	sk = bt_audio_service_open();
	if (sk <= 0) {
		err = errno;
		GST_ERROR_OBJECT(self, "Cannot open connection to bt "
			"audio service: %s %d", strerror(err), err);
		goto failed;
	}

	self->server = g_io_channel_unix_new(sk);
	self->watch_id = g_io_add_watch(self->server, G_IO_HUP | G_IO_ERR |
					G_IO_NVAL, server_callback, self);

	self->data = g_new0(struct bluetooth_data, 1);

	self->stream = NULL;
	self->stream_caps = NULL;
	self->mp3_using_crc = -1;
	self->channel_mode = -1;

	if (!gst_avdtp_sink_get_capabilities(self)) {
		GST_ERROR_OBJECT(self, "failed to get capabilities "
				"from device");
		goto failed;
	}

	return TRUE;

failed:
	bt_audio_service_close(sk);
	return FALSE;
}
static gboolean gst_avdtp_sink_stop(GstBaseSink *basesink)
{
	GstAvdtpSink *self = GST_AVDTP_SINK(basesink);

	GST_INFO_OBJECT(self, "stop");

	if (self->watch_id != 0) {
		g_source_remove(self->watch_id);
		self->watch_id = 0;
	}

	if (self->server) {
		bt_audio_service_close(g_io_channel_unix_get_fd(self->server));
		g_io_channel_unref(self->server);
		self->server = NULL;
	}

	if (self->stream) {
		g_io_channel_shutdown(self->stream, TRUE, NULL);
		g_io_channel_unref(self->stream);
		self->stream = NULL;
	}

	if (self->data) {
		g_free(self->data);
		self->data = NULL;
	}

	if (self->stream_caps) {
		gst_caps_unref(self->stream_caps);
		self->stream_caps = NULL;
	}

	if (self->dev_caps) {
		gst_caps_unref(self->dev_caps);
		self->dev_caps = NULL;
	}

	return TRUE;
}
Exemple #15
0
static GstStateChangeReturn gst_a2dp_sink_change_state(GstElement *element,
			GstStateChange transition)
{
	GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
	GstA2dpSink *self = GST_A2DP_SINK(element);

	switch (transition) {
	case GST_STATE_CHANGE_READY_TO_PAUSED:
		self->taglist = gst_tag_list_new();

		gst_a2dp_sink_init_fakesink(self);
		break;

	case GST_STATE_CHANGE_NULL_TO_READY:
		self->sink_is_in_bin = FALSE;
		self->sink = GST_AVDTP_SINK(gst_element_factory_make(
				"avdtpsink", "avdtpsink"));
		if (self->sink == NULL) {
			GST_WARNING_OBJECT(self, "failed to create avdtpsink");
			return GST_STATE_CHANGE_FAILURE;
		}

		if (self->device != NULL)
			gst_avdtp_sink_set_device(self->sink,
					self->device);

		g_object_set(G_OBJECT(self->sink), "auto-connect",
					self->autoconnect, NULL);

		ret = gst_element_set_state(GST_ELEMENT(self->sink),
			GST_STATE_READY);
		break;
	default:
		break;
	}

	if (ret == GST_STATE_CHANGE_FAILURE)
		return ret;

	ret = GST_ELEMENT_CLASS(parent_class)->change_state(element,
								transition);

	switch (transition) {
	case GST_STATE_CHANGE_PAUSED_TO_READY:
		if (self->taglist) {
			gst_tag_list_free(self->taglist);
			self->taglist = NULL;
		}
		if (self->newseg_event != NULL) {
			gst_event_unref(self->newseg_event);
			self->newseg_event = NULL;
		}
		gst_a2dp_sink_remove_fakesink(self);
		break;

	case GST_STATE_CHANGE_READY_TO_NULL:
		if (self->sink_is_in_bin) {
			if (!gst_bin_remove(GST_BIN(self),
						GST_ELEMENT(self->sink)))
				GST_WARNING_OBJECT(self, "Failed to remove "
						"avdtpsink from bin");
		} else if (self->sink != NULL) {
			gst_element_set_state(GST_ELEMENT(self->sink),
					GST_STATE_NULL);
			g_object_unref(G_OBJECT(self->sink));
		}

		self->sink = NULL;

		gst_a2dp_sink_remove_dynamic_elements(self);
		break;
	default:
		break;
	}

	return ret;
}