/** * 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; }