static gboolean gst_dtmf_src_send_event (GstElement * element, GstEvent * event) { GstDTMFSrc *dtmfsrc = GST_DTMF_SRC (element); gboolean ret; GST_LOG_OBJECT (dtmfsrc, "Received an %s event via send_event", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CUSTOM_BOTH: case GST_EVENT_CUSTOM_BOTH_OOB: case GST_EVENT_CUSTOM_UPSTREAM: case GST_EVENT_CUSTOM_DOWNSTREAM: case GST_EVENT_CUSTOM_DOWNSTREAM_OOB: if (gst_event_has_name (event, "dtmf-event")) { ret = gst_dtmf_src_handle_dtmf_event (dtmfsrc, event); break; } /* fall through */ default: ret = GST_ELEMENT_CLASS (parent_class)->send_event (element, event); break; } return ret; }
static gboolean gst_dtmf_src_handle_event (GstBaseSrc * src, GstEvent * event) { GstDTMFSrc *dtmfsrc; gboolean result = FALSE; dtmfsrc = GST_DTMF_SRC (src); GST_LOG_OBJECT (dtmfsrc, "Received an %s event on the src pad", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CUSTOM_UPSTREAM: if (gst_event_has_name (event, "dtmf-event")) { result = gst_dtmf_src_handle_dtmf_event (dtmfsrc, event); break; } /* fall through */ default: result = GST_BASE_SRC_CLASS (parent_class)->event (src, event); break; } return result; }
static gboolean gst_dtmf_src_negotiate (GstBaseSrc * basesrc) { GstDTMFSrc *dtmfsrc = GST_DTMF_SRC (basesrc); GstCaps *caps; GstStructure *s; gboolean ret; caps = gst_pad_get_allowed_caps (GST_BASE_SRC_PAD (basesrc)); if (!caps) caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (basesrc))); if (gst_caps_is_empty (caps)) return FALSE; gst_caps_truncate (caps); s = gst_caps_get_structure (caps, 0); gst_structure_fixate_field_nearest_int (s, "rate", DEFAULT_SAMPLE_RATE); if (!gst_structure_get_int (s, "rate", &dtmfsrc->sample_rate)) { GST_ERROR_OBJECT (dtmfsrc, "Could not get rate"); gst_caps_unref (caps); return FALSE; } ret = gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps); gst_caps_unref (caps); return ret; }
static gboolean gst_dtmf_src_unlock_stop (GstBaseSrc * src) { GstDTMFSrc *dtmfsrc = GST_DTMF_SRC (src); GST_DEBUG_OBJECT (dtmfsrc, "Unlock stopped"); GST_OBJECT_LOCK (dtmfsrc); dtmfsrc->paused = FALSE; GST_OBJECT_UNLOCK (dtmfsrc); return TRUE; }
static void gst_dtmf_src_finalize (GObject * object) { GstDTMFSrc *dtmfsrc; dtmfsrc = GST_DTMF_SRC (object); if (dtmfsrc->event_queue) { g_async_queue_unref (dtmfsrc->event_queue); dtmfsrc->event_queue = NULL; } G_OBJECT_CLASS (gst_dtmf_src_parent_class)->finalize (object); }
static gboolean gst_dtmf_src_handle_event (GstBaseSrc * src, GstEvent * event) { GstDTMFSrc *dtmfsrc; gboolean result = FALSE; dtmfsrc = GST_DTMF_SRC (src); GST_DEBUG_OBJECT (dtmfsrc, "Received an event on the src pad"); if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM) { result = gst_dtmf_src_handle_custom_upstream (dtmfsrc, event); } return result; }
static void gst_dtmf_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstDTMFSrc *dtmfsrc; dtmfsrc = GST_DTMF_SRC (object); switch (prop_id) { case PROP_INTERVAL: g_value_set_uint (value, dtmfsrc->interval); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean gst_dtmf_src_unlock (GstBaseSrc * src) { GstDTMFSrc *dtmfsrc = GST_DTMF_SRC (src); GstDTMFSrcEvent *event = NULL; GST_DEBUG_OBJECT (dtmfsrc, "Called unlock"); GST_OBJECT_LOCK (dtmfsrc); dtmfsrc->paused = TRUE; if (dtmfsrc->clockid) { gst_clock_id_unschedule (dtmfsrc->clockid); } GST_OBJECT_UNLOCK (dtmfsrc); GST_DEBUG_OBJECT (dtmfsrc, "Pushing the PAUSE_TASK event on unlock request"); event = g_slice_new0 (GstDTMFSrcEvent); event->event_type = DTMF_EVENT_TYPE_PAUSE_TASK; g_async_queue_push (dtmfsrc->event_queue, event); return TRUE; }
static GstStateChangeReturn gst_dtmf_src_change_state (GstElement * element, GstStateChange transition) { GstDTMFSrc *dtmfsrc; GstStateChangeReturn result; gboolean no_preroll = FALSE; GstDTMFSrcEvent *event = NULL; dtmfsrc = GST_DTMF_SRC (element); switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: /* Flushing the event queue */ event = g_async_queue_try_pop (dtmfsrc->event_queue); while (event != NULL) { gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event); g_slice_free (GstDTMFSrcEvent, event); event = g_async_queue_try_pop (dtmfsrc->event_queue); } dtmfsrc->last_event_was_start = FALSE; dtmfsrc->timestamp = 0; no_preroll = TRUE; break; default: break; } if ((result = GST_ELEMENT_CLASS (gst_dtmf_src_parent_class)->change_state (element, transition)) == GST_STATE_CHANGE_FAILURE) goto failure; switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: no_preroll = TRUE; break; case GST_STATE_CHANGE_PAUSED_TO_READY: GST_DEBUG_OBJECT (dtmfsrc, "Flushing event queue"); /* Flushing the event queue */ event = g_async_queue_try_pop (dtmfsrc->event_queue); while (event != NULL) { gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event); g_slice_free (GstDTMFSrcEvent, event); event = g_async_queue_try_pop (dtmfsrc->event_queue); } dtmfsrc->last_event_was_start = FALSE; break; default: break; } if (no_preroll && result == GST_STATE_CHANGE_SUCCESS) result = GST_STATE_CHANGE_NO_PREROLL; return result; /* ERRORS */ failure: { GST_ERROR_OBJECT (dtmfsrc, "parent failed state change"); return result; } }
static GstFlowReturn gst_dtmf_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer) { GstBuffer *buf = NULL; GstDTMFSrcEvent *event; GstDTMFSrc *dtmfsrc; GstClock *clock; GstClockID *clockid; GstClockReturn clockret; dtmfsrc = GST_DTMF_SRC (basesrc); do { if (dtmfsrc->last_event == NULL) { GST_DEBUG_OBJECT (dtmfsrc, "popping"); event = g_async_queue_pop (dtmfsrc->event_queue); GST_DEBUG_OBJECT (dtmfsrc, "popped %d", event->event_type); switch (event->event_type) { case DTMF_EVENT_TYPE_STOP: GST_WARNING_OBJECT (dtmfsrc, "Received a DTMF stop event when already stopped"); gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event); break; case DTMF_EVENT_TYPE_START: gst_dtmf_prepare_timestamps (dtmfsrc); event->packet_count = 0; dtmfsrc->last_event = event; event = NULL; gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-processed", dtmfsrc->last_event); break; case DTMF_EVENT_TYPE_PAUSE_TASK: /* * We're pushing it back because it has to stay in there until * the task is really paused (and the queue will then be flushed) */ GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task..."); GST_OBJECT_LOCK (dtmfsrc); if (dtmfsrc->paused) { g_async_queue_push (dtmfsrc->event_queue, event); goto paused_locked; } GST_OBJECT_UNLOCK (dtmfsrc); break; } if (event) g_slice_free (GstDTMFSrcEvent, event); } else if (dtmfsrc->last_event->packet_count * dtmfsrc->interval >= MIN_DUTY_CYCLE) { event = g_async_queue_try_pop (dtmfsrc->event_queue); if (event != NULL) { switch (event->event_type) { case DTMF_EVENT_TYPE_START: GST_WARNING_OBJECT (dtmfsrc, "Received two consecutive DTMF start events"); gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event); break; case DTMF_EVENT_TYPE_STOP: g_slice_free (GstDTMFSrcEvent, dtmfsrc->last_event); dtmfsrc->last_event = NULL; gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-processed", event); break; case DTMF_EVENT_TYPE_PAUSE_TASK: /* * We're pushing it back because it has to stay in there until * the task is really paused (and the queue will then be flushed) */ GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task..."); GST_OBJECT_LOCK (dtmfsrc); if (dtmfsrc->paused) { g_async_queue_push (dtmfsrc->event_queue, event); goto paused_locked; } GST_OBJECT_UNLOCK (dtmfsrc); break; } g_slice_free (GstDTMFSrcEvent, event); } } } while (dtmfsrc->last_event == NULL); GST_LOG_OBJECT (dtmfsrc, "end event check, now wait for the proper time"); clock = gst_element_get_clock (GST_ELEMENT (basesrc)); clockid = gst_clock_new_single_shot_id (clock, dtmfsrc->timestamp + gst_element_get_base_time (GST_ELEMENT (dtmfsrc))); gst_object_unref (clock); GST_OBJECT_LOCK (dtmfsrc); if (!dtmfsrc->paused) { dtmfsrc->clockid = clockid; GST_OBJECT_UNLOCK (dtmfsrc); clockret = gst_clock_id_wait (clockid, NULL); GST_OBJECT_LOCK (dtmfsrc); if (dtmfsrc->paused) clockret = GST_CLOCK_UNSCHEDULED; } else { clockret = GST_CLOCK_UNSCHEDULED; } gst_clock_id_unref (clockid); dtmfsrc->clockid = NULL; GST_OBJECT_UNLOCK (dtmfsrc); if (clockret == GST_CLOCK_UNSCHEDULED) { goto paused; } buf = gst_dtmf_src_create_next_tone_packet (dtmfsrc, dtmfsrc->last_event); GST_LOG_OBJECT (dtmfsrc, "Created buffer of size %" G_GSIZE_FORMAT, gst_buffer_get_size (buf)); *buffer = buf; return GST_FLOW_OK; paused_locked: GST_OBJECT_UNLOCK (dtmfsrc); paused: if (dtmfsrc->last_event) { GST_DEBUG_OBJECT (dtmfsrc, "Stopping current event"); /* Don't forget to release the stream lock */ g_slice_free (GstDTMFSrcEvent, dtmfsrc->last_event); dtmfsrc->last_event = NULL; } return GST_FLOW_FLUSHING; }