/**
* SECTION:element myaudiosrc
*
*
*
* Example launch line
* |[
* gst-launch -v -m myaudiosrc ! queue ! alsasink
* ]|
*
*/
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include "gstmyaudiosrc.h"
GST_DEBUG_CATEGORY_STATIC (gst_myaudiosrc_debug);
#define GST_CAT_DEFAULT gst_myaudiosrc_debug
/* Element Properties */
enum
{
PROP_0,
PROP_MY_API
};
static void
gst_myaudiosrc_finalize (GObject * object)
{
Gstmyaudiosrc *src;
src = GST_MYAUDIOSRC (object);
}
/* the capabilities of the inputs and outputs.
*
* describe the real formats here.
*/
static GstStaticPadTemplate src_factory =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
GST_STATIC_CAPS ("audio/x-raw-int, "
"width = (int) {16, 32}, "
"depth = (int) {16, 32}, "
"signed = (boolean) true, "
"channels = (int) {1, 2}, "
"endianness = (int) LITTLE_ENDIAN,"
"rate = (int) [ 8000, 48000 ] "
));
GST_BOILERPLATE (Gstmyaudiosrc, gst_myaudiosrc, GstBaseSrc,
GST_TYPE_BASE_SRC);
static void gst_myaudiosrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_myaudiosrc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstStateChangeReturn gst_myaudiosrc_change_state
(GstElement * element, GstStateChange transition);
static gboolean gst_myaudiosrc_start (GstBaseSrc * basesrc);
static gboolean gst_myaudiosrc_check_get_range (GstBaseSrc * basesrc);
static gboolean
gst_myaudiosrc_is_seekable (GstBaseSrc * psrc)
{
/* we're not seekable... */
return FALSE;
}
static void
gst_myaudiosrc_get_times (GstBaseSrc * basesrc, GstBuffer * buffer,
GstClockTime * start, GstClockTime * end)
{
/* for live sources, sync on the timestamp of the buffer */
if (gst_base_src_is_live (basesrc)) {
GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
/* get duration to calculate end time */
GstClockTime duration = GST_BUFFER_DURATION (buffer);
if (GST_CLOCK_TIME_IS_VALID (duration)) {
*end = timestamp + duration;
}
*start = timestamp;
}
} else {
*start = -1;
*end = -1;
}
}
/*Query handling*/
static gboolean
gst_myaudiosrc_query (GstBaseSrc * bsrc, GstQuery * query)
{
// Gstmyaudiosrc *src = GST_MYAUDIOSRC (bsrc);
gboolean res = TRUE;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_LATENCY: {
GstClockTime min, max;
min = gst_util_uint64_scale_int (GST_SECOND, 1, 30);
max = GST_CLOCK_TIME_NONE;
GST_ERROR ("report latency: live 1, min %" GST_TIME_FORMAT
", max %" GST_TIME_FORMAT, GST_TIME_ARGS (min),
GST_TIME_ARGS (max));
gst_query_set_latency (query, TRUE, min, max);
break;
}
default:
res = FALSE;
}
return res;
}
GstFlowReturn
gst_myaudiosrc_create (GstBaseSrc * psrc, guint64 offset,
guint length, GstBuffer ** buffer)
{
Gstmyaudiosrc *src = GST_MYAUDIOSRC (psrc);
GstBuffer *buf = NULL;
guint64 ts, duration;
guint32 samples;
GstClockTime next_time;
gint64 next_sample, next_bytes;
/*
if (G_UNLIKELY (src->fourcc == NULL))
goto not_negotiated;
*/
while (buf == NULL) {
buf = myapi_get_frame (src->myapi, 0, &ts, &duration);
}
/* Audio Packet */
GST_LOG ("Got Audio Packet of lenght %d, with timestamp %d",
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
samples = length / (2 * 2);
if (offset == -1)
offset = src->offset;
/* now see if we are at the byteoffset we think we are */
if (offset != src->offset) {
GST_DEBUG_OBJECT (src, "seek to new offset %" G_GUINT64_FORMAT, offset);
/* we have a discont in the expected sample offset, do a 'seek' */
src->next_sample = offset / (2 * 2);
src->next_time =
gst_util_uint64_scale_int (src->next_sample, GST_SECOND,
48000);
src->offset = offset;
}
next_sample = src->next_sample + samples;
next_bytes = src->offset + length;
next_time = gst_util_uint64_scale_int (next_sample, GST_SECOND,
48000);
GST_BUFFER_TIMESTAMP (buf) = 0 + src->next_time;
GST_BUFFER_OFFSET (buf) = src->next_sample;
GST_BUFFER_OFFSET_END (buf) = next_sample;
GST_BUFFER_DURATION (buf) = next_time - src->next_time;
gst_object_sync_values (G_OBJECT (src), src->next_time);
src->next_time = next_time;
src->next_sample = next_sample;
src->offset = next_bytes;
GST_DEBUG ("Pushing buffer of size-%d, timestamp-%" GST_TIME_FORMAT \
" duration-%"GST_TIME_FORMAT, GST_BUFFER_SIZE (buf),
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
*buffer = buf;
return GST_FLOW_OK;
/*
not_negotiated:
{
GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL),
("format wasn't negotiated before get function"));
return GST_FLOW_NOT_NEGOTIATED;
}
*/
}
static GstCaps *
gst_myaudiosrc_getcaps (GstBaseSrc * psrc)
{
Gstmyaudiosrc *src = GST_MYAUDIOSRC (psrc);
src->caps = gst_caps_new_simple ("audio/x-raw-int",
"width", G_TYPE_INT, 16,
"depth", G_TYPE_INT, 16,
"channels", G_TYPE_INT, 2,
"rate", G_TYPE_INT, 48000,
"signed", G_TYPE_BOOLEAN, TRUE,
"endianness", G_TYPE_INT, 1234,
NULL);
if (G_UNLIKELY (!src->caps)) {
GST_ERROR ("Unable to generate caps");
}
return src->caps;
}
gboolean
gst_myaudiosrc_open_device (Gstmyaudiosrc *src)
{
GST_INFO_OBJECT (src, "opening Device ");
if (src->myapi == NULL) {
src->myapi = myapi_new ();
}
else {
GST_DEBUG ("Myapi already initialized, using same initialized value");
src->setup = TRUE;
}
return TRUE;
}
gboolean
gst_myaudiosrc_setup (Gstmyaudiosrc *src)
{
gboolean ret = FALSE;
if (myapi_init (src->myapi)) {
if (myapi_start (src->myapi)) {
src->setup = TRUE;
ret = TRUE;
}
}
return ret;
}
/* GObject vmethod implementations */
static void
gst_myaudiosrc_base_init (gpointer gclass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
gst_element_class_set_details_simple(element_class,
"My Audio Source",
"Source/MyAudio",
"Reads Audio Streams ",
" ");
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_factory));
}
/* initialize the myaudiosrc's class */
static void
gst_myaudiosrc_class_init (GstmyaudiosrcClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseSrcClass *gstbasesrc_class;
gobject_class = (GObjectClass *) klass;
gstbasesrc_class = (GstBaseSrcClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_myaudiosrc_finalize);
gobject_class->set_property =
GST_DEBUG_FUNCPTR (gst_myaudiosrc_set_property);
gobject_class->get_property =
GST_DEBUG_FUNCPTR (gst_myaudiosrc_get_property);
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_myaudiosrc_change_state);
gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_myaudiosrc_getcaps);
gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_myaudiosrc_is_seekable);
gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_myaudiosrc_start);
// gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_myaudiosrc_stop);
gstbasesrc_class->check_get_range = GST_DEBUG_FUNCPTR (gst_myaudiosrc_check_get_range);
gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_myaudiosrc_create);
gstbasesrc_class->get_times =
GST_DEBUG_FUNCPTR (gst_myaudiosrc_get_times);
gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_myaudiosrc_query);
/* debug category for fltering log messages */
GST_DEBUG_CATEGORY_INIT (gst_myaudiosrc_debug, "myaudiosrc",
0, "My src Plugin");
}
/* initialize the new element
* instantiate pads and add them to element
* set pad calback functions
* initialize instance structure
*/
static void
gst_myaudiosrc_init (Gstmyaudiosrc * src,
GstmyaudiosrcClass * gclass)
{
/* protects our state changes from multiple invocations */
src->state_rec_lock = g_new (GStaticRecMutex, 1);
g_static_rec_mutex_init (src->state_rec_lock);
src->stream_rec_lock = g_new (GStaticRecMutex, 1);
g_static_rec_mutex_init (src->stream_rec_lock);
gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
gst_base_src_set_live (GST_BASE_SRC (src), TRUE);
src->offset = 0;
src->is_paused = FALSE;
src->setup = FALSE;
src->myapi = NULL;
}
static void
gst_myaudiosrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
Gstmyaudiosrc *src = GST_MYAUDIOSRC (object);
switch (prop_id) {
case PROP_DECKLINK_API:
src->myapi = g_value_get_pointer (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_myaudiosrc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
// Gstmyaudiosrc *src = GST_MYAUDIOSRC (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstStateChangeReturn
gst_myaudiosrc_change_state (GstElement * element,
GstStateChange transition)
{
Gstmyaudiosrc *src;
GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
gboolean no_preroll = FALSE;
src = GST_MYAUDIOSRC (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (!gst_myaudiosrc_open_device (src)) {
goto failure;
}
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
no_preroll = TRUE;
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
if (!src->setup) {
if (!gst_myaudiosrc_setup (src)) {
goto failure;
}
}
GST_ERROR_OBJECT (src, "PAUSED->PLAYING");
/* now we can start playback */
if (src->is_paused) {
GST_ERROR_OBJECT (src, "Resuming Device");
src->is_paused = FALSE;
}
break;
default:
break;
}
if ((result =
GST_ELEMENT_CLASS (parent_class)->change_state (element,
transition)) == GST_STATE_CHANGE_FAILURE)
goto failure;
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_DEBUG ("Stopping the device........");
if (!myapi_stop (src->myapi)) {
GST_ERROR ("Unable to Stop, device ");
return GST_STATE_CHANGE_FAILURE;
}
break;
case GST_STATE_CHANGE_READY_TO_NULL:
src->myapi = NULL;
break;
default:
break;
}
if (no_preroll && result == GST_STATE_CHANGE_SUCCESS)
result = GST_STATE_CHANGE_NO_PREROLL;
return result;
/* ERRORS */
failure:
{
GST_DEBUG_OBJECT (src, "parent failed state change");
return result;
}
}
static gboolean
gst_myaudiosrc_start (GstBaseSrc * basesrc)
{
Gstmyaudiosrc *src = GST_MYAUDIOSRC (basesrc);
src->next_sample = 0;
src->offset = 0;
src->next_time = 0;
src->running_time = 0;
return TRUE;
}
static gboolean
gst_myaudiosrc_check_get_range (GstBaseSrc * basesrc)
{
Gstmyaudiosrc *src;
src = GST_MYAUDIOSRC (basesrc);
src->can_activate_pull = FALSE;
/* if we can operate in pull mode */
return src->can_activate_pull;
}