static gboolean src_activate_mode(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean active) { GstErDtlsEnc *self = GST_ER_DTLS_ENC (parent); gboolean success = TRUE; g_return_val_if_fail(mode == GST_PAD_MODE_PUSH, FALSE); if (active) { GST_DEBUG_OBJECT(self, "src pad activating in push mode"); self->send_initial_events = TRUE; success = gst_pad_start_task(pad, (GstTaskFunction) src_task_loop, self->src, NULL); if (!success) { GST_WARNING_OBJECT(self, "failed to activate pad task"); } } else { GST_DEBUG_OBJECT(self, "deactivating src pad"); g_mutex_lock(&self->queue_lock); GST_PAD_MODE(pad) = GST_PAD_MODE_NONE; g_cond_signal(&self->queue_cond_add); g_mutex_unlock(&self->queue_lock); success = gst_pad_stop_task(pad); if (!success) { GST_WARNING_OBJECT(self, "failed to deactivate pad task"); } } return success; }
static GstStateChangeReturn gst_er_dtls_enc_change_state(GstElement *element, GstStateChange transition) { GstErDtlsEnc *self = GST_ER_DTLS_ENC(element); GstStateChangeReturn ret; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: if (self->connection_id) { self->connection = gst_er_dtls_dec_fetch_connection(self->connection_id); if (!self->connection) { GST_WARNING_OBJECT(self, "invalid connection id: '%s', connection not found or already in use", self->connection_id); return GST_STATE_CHANGE_FAILURE; } g_signal_connect_object(self->connection, "on-encoder-key", G_CALLBACK(on_key_received), self, 0); er_dtls_connection_set_send_callback(self->connection, g_cclosure_new(G_CALLBACK(on_send_data), self, NULL)); } else { GST_WARNING_OBJECT(self, "trying to change state to ready without connection id"); return GST_STATE_CHANGE_FAILURE; } break; case GST_STATE_CHANGE_READY_TO_PAUSED: GST_DEBUG_OBJECT(self, "starting connection %s", self->connection_id); er_dtls_connection_start(self->connection, self->is_client); gst_pad_set_active(self->src, TRUE); break; case GST_STATE_CHANGE_PAUSED_TO_READY: GST_DEBUG_OBJECT(self, "stopping connection %s", self->connection_id); gst_pad_set_active(self->src, FALSE); er_dtls_connection_stop(self->connection); break; case GST_STATE_CHANGE_READY_TO_NULL: GST_DEBUG_OBJECT(self, "closing connection %s", self->connection_id); er_dtls_connection_close(self->connection); er_dtls_connection_set_send_callback(self->connection, NULL); if (self->connection) { g_object_unref(self->connection); self->connection = NULL; } break; default: break; } ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition); return ret; }
static void gst_er_dtls_enc_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GstErDtlsEnc *self = GST_ER_DTLS_ENC(object); switch (prop_id) { case PROP_CONNECTION_ID: self->connection_id = g_value_dup_string(value); break; case PROP_IS_CLIENT: self->is_client = g_value_get_boolean(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(self, prop_id, pspec); } }
static GstFlowReturn sink_chain(GstPad *pad, GstObject *parent, GstBuffer *buffer) { GstErDtlsEnc *self = GST_ER_DTLS_ENC(parent); GstMapInfo map_info; gint ret; gst_buffer_map(buffer, &map_info, GST_MAP_READ); if (map_info.size) { ret = er_dtls_connection_send(self->connection, map_info.data, map_info.size); if (ret != map_info.size) { GST_WARNING_OBJECT(self, "error sending data: %d B were written, expected value was %zd B", ret, map_info.size); } } gst_buffer_unmap(buffer, &map_info); gst_buffer_unref(buffer); return GST_FLOW_OK; }
static void gst_er_dtls_enc_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GstErDtlsEnc *self = GST_ER_DTLS_ENC(object); switch (prop_id) { case PROP_CONNECTION_ID: g_value_set_string(value, self->connection_id); break; case PROP_IS_CLIENT: g_value_set_boolean(value, self->is_client); break; case PROP_ENCODER_KEY: g_value_set_boxed(value, self->encoder_key); break; case PROP_SRTP_CIPHER: g_value_set_uint(value, self->srtp_cipher); break; case PROP_SRTP_AUTH: g_value_set_uint(value, self->srtp_auth); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(self, prop_id, pspec); } }
static void gst_er_dtls_enc_finalize(GObject *object) { GstErDtlsEnc *self = GST_ER_DTLS_ENC(object); if (self->encoder_key) { gst_buffer_unref(self->encoder_key); self->encoder_key = NULL; } g_mutex_lock(&self->queue_lock); g_ptr_array_set_free_func(self->queue, (GDestroyNotify) gst_buffer_unref); g_ptr_array_unref(self->queue); self->queue = NULL; g_mutex_unlock(&self->queue_lock); g_mutex_clear(&self->queue_lock); g_cond_clear(&self->queue_cond_add); GST_LOG_OBJECT(self, "finalized"); G_OBJECT_CLASS(parent_class)->finalize(object); }
static void src_task_loop(GstPad *pad) { GstErDtlsEnc *self = GST_ER_DTLS_ENC(GST_PAD_PARENT(pad)); GstFlowReturn ret; GstPad *peer; gboolean peer_is_active; if (!gst_pad_is_active(pad)) { GST_LOG_OBJECT(self, "src task loop entered on inactive pad"); return; } GST_TRACE_OBJECT(self, "src loop: acquiring lock"); g_mutex_lock(&self->queue_lock); GST_TRACE_OBJECT(self, "src loop: acquired lock"); while (!self->queue->len) { GST_TRACE_OBJECT(self, "src loop: queue empty, waiting for add"); g_cond_wait(&self->queue_cond_add, &self->queue_lock); GST_TRACE_OBJECT(self, "src loop: add signaled"); if (!gst_pad_is_active(pad)) { GST_LOG_OBJECT(self, "pad inactive, task returning"); GST_TRACE_OBJECT(self, "src loop: releasing lock"); g_mutex_unlock(&self->queue_lock); return; } } GST_TRACE_OBJECT(self, "src loop: queue has element"); peer = gst_pad_get_peer(pad); peer_is_active = gst_pad_is_active(peer); gst_object_unref(peer); if (peer_is_active) { GstBuffer *buffer; gboolean start_connection_timeout = FALSE; if (self->send_initial_events) { GstSegment segment; gchar s_id[32]; GstCaps *caps; g_snprintf (s_id, sizeof (s_id), "erdtlsenc-%08x", g_random_int ()); gst_pad_push_event (self->src, gst_event_new_stream_start (s_id)); caps = gst_caps_new_empty_simple ("application/x-dtls"); gst_pad_push_event (self->src, gst_event_new_caps (caps)); gst_caps_unref (caps); gst_segment_init (&segment, GST_FORMAT_BYTES); gst_pad_push_event (self->src, gst_event_new_segment (&segment)); self->send_initial_events = FALSE; start_connection_timeout = TRUE; } buffer = g_ptr_array_remove_index(self->queue, 0); GST_TRACE_OBJECT(self, "src loop: releasing lock"); g_mutex_unlock(&self->queue_lock); ret = gst_pad_push(self->src, buffer); if (start_connection_timeout) er_dtls_connection_start_timeout (self->connection); if (G_UNLIKELY(ret != GST_FLOW_OK)) { GST_WARNING_OBJECT(self, "failed to push buffer on src pad: %s", gst_flow_get_name(ret)); } } else { g_warn_if_reached(); GST_TRACE_OBJECT(self, "src loop: releasing lock"); g_mutex_unlock(&self->queue_lock); } }