static GstStateChangeReturn fs_rtp_conference_change_state (GstElement *element, GstStateChange transition) { FsRtpConference *self = FS_RTP_CONFERENCE (element); GstStateChangeReturn result; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: if (!self->rtpbin) { GST_ERROR_OBJECT (element, "Could not create the RtpBin subelement"); result = GST_STATE_CHANGE_FAILURE; goto failure; } break; default: break; } if ((result = GST_ELEMENT_CLASS (fs_rtp_conference_parent_class)->change_state ( element, transition)) == GST_STATE_CHANGE_FAILURE) goto failure; return result; failure: { GST_ERROR_OBJECT (element, "parent failed state change"); return result; } }
static FsParticipant * fs_rtp_conference_new_participant (FsConference *conf, GError **error) { FsRtpConference *self = FS_RTP_CONFERENCE (conf); FsParticipant *new_participant = NULL; if (!self->rtpbin) { g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not create Rtpbin"); return NULL; } new_participant = FS_PARTICIPANT_CAST (fs_rtp_participant_new ()); GST_OBJECT_LOCK (self); self->priv->participants = g_list_append (self->priv->participants, new_participant); GST_OBJECT_UNLOCK (self); g_object_weak_ref (G_OBJECT (new_participant), _remove_participant, self); return new_participant; }
static void _rtpbin_pad_added (GstElement *rtpbin, GstPad *new_pad, gpointer user_data) { FsRtpConference *self = FS_RTP_CONFERENCE (user_data); gchar *name; GST_DEBUG_OBJECT (self, "pad %s:%s added", GST_DEBUG_PAD_NAME (new_pad)); name = gst_pad_get_name (new_pad); if (g_str_has_prefix (name, "recv_rtp_src_")) { guint session_id, ssrc, pt; if (sscanf (name, "recv_rtp_src_%u_%u_%u", &session_id, &ssrc, &pt) == 3 && ssrc <= G_MAXUINT32) { FsRtpSession *session = fs_rtp_conference_get_session_by_id (self, session_id); if (session) { fs_rtp_session_new_recv_pad (session, new_pad, ssrc, pt); g_object_unref (session); } } } g_free (name); }
static void fs_rtp_conference_dispose (GObject * object) { FsRtpConference *self = FS_RTP_CONFERENCE (object); GList *item; if (self->priv->disposed) return; if (self->rtpbin) { gst_object_unref (self->rtpbin); self->rtpbin = NULL; } for (item = g_list_first (self->priv->sessions); item; item = g_list_next (item)) g_object_weak_unref (G_OBJECT (item->data), _remove_session, self); g_list_free (self->priv->sessions); self->priv->sessions = NULL; self->priv->sessions_cookie++; for (item = g_list_first (self->priv->participants); item; item = g_list_next (item)) g_object_weak_unref (G_OBJECT (item->data), _remove_participant, self); g_list_free (self->priv->participants); self->priv->participants = NULL; self->priv->disposed = TRUE; G_OBJECT_CLASS (fs_rtp_conference_parent_class)->dispose (object); }
static FsParticipant * fs_rtp_conference_new_participant (FsBaseConference *conf, gchar *cname, GError **error) { FsRtpConference *self = FS_RTP_CONFERENCE (conf); FsParticipant *new_participant = NULL; GList *item = NULL; if (!self->gstrtpbin) { g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not create GstRtpBin"); return NULL; } if (!cname) { g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS, "Invalid NULL cname"); return NULL; } GST_OBJECT_LOCK (self); for (item = g_list_first (self->priv->participants); item; item = g_list_next (item)) { gchar *lcname; g_object_get (item->data, "cname", &lcname, NULL); if (!strcmp (lcname, cname)) { g_free (lcname); break; } g_free (lcname); } GST_OBJECT_UNLOCK (self); if (item) { g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS, "There is already a participant with this cname"); return NULL; } new_participant = FS_PARTICIPANT_CAST (fs_rtp_participant_new (cname)); GST_OBJECT_LOCK (self); self->priv->participants = g_list_append (self->priv->participants, new_participant); GST_OBJECT_UNLOCK (self); g_object_weak_ref (G_OBJECT (new_participant), _remove_participant, self); return new_participant; }
static void fs_rtp_conference_handle_message ( GstBin * bin, GstMessage * message) { FsRtpConference *self = FS_RTP_CONFERENCE (bin); if (!self->gstrtpbin) return; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ELEMENT: { const GstStructure *s = gst_message_get_structure (message); /* we change the structure name and add the session ID to it */ if (gst_structure_has_name (s, "GstRTPBinSDES") && gst_structure_has_field_typed (s, "session", G_TYPE_UINT) && gst_structure_has_field_typed (s, "ssrc", G_TYPE_UINT) && gst_structure_has_field_typed (s, "cname", G_TYPE_STRING)) { guint session_id; guint ssrc; const GValue *val; FsRtpSession *session; const gchar *cname; val = gst_structure_get_value (s, "session"); session_id = g_value_get_uint (val); val = gst_structure_get_value (s, "ssrc"); ssrc = g_value_get_uint (val); cname = gst_structure_get_string (s, "cname"); session = fs_rtp_conference_get_session_by_id (self, session_id); if (session) { fs_rtp_session_associate_ssrc_cname (session, ssrc, cname); g_object_unref (session); } else { GST_WARNING_OBJECT (self,"Our GstRtpBin announced a new association" "for non-existent session %u for ssrc: %u and cname %s", session_id, ssrc, cname); } } /* fallthrough to forward the modified message to the parent */ } default: { GST_BIN_CLASS (parent_class)->handle_message (bin, message); break; } } }
static void _remove_participant (gpointer user_data, GObject *where_the_object_was) { FsRtpConference *self = FS_RTP_CONFERENCE (user_data); GST_OBJECT_LOCK (self); self->priv->participants = g_list_remove_all (self->priv->participants, where_the_object_was); GST_OBJECT_UNLOCK (self); }
static void _remove_session (gpointer user_data, GObject *where_the_object_was) { FsRtpConference *self = FS_RTP_CONFERENCE (user_data); GST_OBJECT_LOCK (self); self->priv->sessions = g_list_remove_all (self->priv->sessions, where_the_object_was); self->priv->sessions_cookie++; GST_OBJECT_UNLOCK (self); }
static void fs_rtp_conference_finalize (GObject * object) { FsRtpConference *self = FS_RTP_CONFERENCE (object); /* Peek will always succeed here because we 'refed the class in the _init */ g_type_class_unref (g_type_class_peek (FS_TYPE_RTP_SUB_STREAM)); g_ptr_array_free (self->priv->threads, TRUE); G_OBJECT_CLASS (fs_rtp_conference_parent_class)->finalize (object); }
static void _rtpbin_on_ssrc_validated (GstElement *rtpbin, guint session_id, guint ssrc, gpointer user_data) { FsRtpConference *self = FS_RTP_CONFERENCE (user_data); FsRtpSession *session = fs_rtp_conference_get_session_by_id (self, session_id); if (session) { fs_rtp_session_ssrc_validated (session, ssrc); g_object_unref (session); } }
static GstCaps * _rtpbin_request_pt_map (GstElement *element, guint session_id, guint pt, gpointer user_data) { FsRtpConference *self = FS_RTP_CONFERENCE (user_data); FsRtpSession *session = NULL; GstCaps *caps = NULL; session = fs_rtp_conference_get_session_by_id (self, session_id); if (session) { caps = fs_rtp_session_request_pt_map (session, pt); g_object_unref (session); } else { GST_WARNING_OBJECT (self,"Rtpbin %p tried to request the caps for " " payload type %u for non-existent session %u", element, pt, session_id); } return caps; }
static void fs_rtp_conference_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { FsRtpConference *self = FS_RTP_CONFERENCE (object); if (!self->rtpbin) return; switch (prop_id) { case PROP_SDES: g_object_set_property (G_OBJECT (self->rtpbin), "sdes", value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void fs_rtp_conference_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { FsRtpConference *self = FS_RTP_CONFERENCE (object); if (!self->gstrtpbin) return; switch (prop_id) { case PROP_SDES_CNAME: g_object_set_property (G_OBJECT (self->gstrtpbin), "sdes-cname", value); break; case PROP_SDES_NAME: g_object_set_property (G_OBJECT (self->gstrtpbin), "sdes-name", value); break; case PROP_SDES_EMAIL: g_object_set_property (G_OBJECT (self->gstrtpbin), "sdes-email", value); break; case PROP_SDES_PHONE: g_object_set_property (G_OBJECT (self->gstrtpbin), "sdes-phone", value); break; case PROP_SDES_LOCATION: g_object_set_property (G_OBJECT (self->gstrtpbin), "sdes-location", value); break; case PROP_SDES_TOOL: g_object_set_property (G_OBJECT (self->gstrtpbin), "sdes-tool", value); break; case PROP_SDES_NOTE: g_object_set_property (G_OBJECT (self->gstrtpbin), "sdes-note", value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static FsSession * fs_rtp_conference_new_session (FsConference *conf, FsMediaType media_type, GError **error) { FsRtpConference *self = FS_RTP_CONFERENCE (conf); FsSession *new_session = NULL; guint id; if (!self->rtpbin) { g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not create Rtpbin"); return NULL; } GST_OBJECT_LOCK (self); do { id = self->priv->max_session_id++; } while (fs_rtp_conference_get_session_by_id_locked (self, id)); GST_OBJECT_UNLOCK (self); new_session = FS_SESSION_CAST (fs_rtp_session_new (media_type, self, id, error)); if (!new_session) { return NULL; } GST_OBJECT_LOCK (self); self->priv->sessions = g_list_append (self->priv->sessions, new_session); self->priv->sessions_cookie++; GST_OBJECT_UNLOCK (self); g_object_weak_ref (G_OBJECT (new_session), _remove_session, self); return new_session; }
static void fs_rtp_conference_handle_message ( GstBin * bin, GstMessage * message) { FsRtpConference *self = FS_RTP_CONFERENCE (bin); if (!self->rtpbin) goto out; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ELEMENT: { const GstStructure *s = gst_message_get_structure (message); /* we change the structure name and add the session ID to it */ if (gst_structure_has_name (s, "application/x-rtp-source-sdes") && gst_structure_has_field_typed (s, "session", G_TYPE_UINT) && gst_structure_has_field_typed (s, "ssrc", G_TYPE_UINT) && gst_structure_has_field_typed (s, "cname", G_TYPE_STRING)) { guint session_id; guint ssrc; const GValue *val; FsRtpSession *session; const gchar *cname; val = gst_structure_get_value (s, "session"); session_id = g_value_get_uint (val); val = gst_structure_get_value (s, "ssrc"); ssrc = g_value_get_uint (val); cname = gst_structure_get_string (s, "cname"); if (!ssrc || !cname) { GST_WARNING_OBJECT (self, "Got GstRTPBinSDES without a ssrc or a cname (ssrc:%u cname:%p)", ssrc, cname); break; } session = fs_rtp_conference_get_session_by_id (self, session_id); if (session) { fs_rtp_session_associate_ssrc_cname (session, ssrc, cname); g_object_unref (session); } else { GST_WARNING_OBJECT (self,"Our RtpBin announced a new association" "for non-existent session %u for ssrc: %u and cname %s", session_id, ssrc, cname); } } else if (gst_structure_has_name (s, "dtmf-event-processed") || gst_structure_has_name (s, "dtmf-event-dropped")) { GList *item; guint cookie; GST_OBJECT_LOCK (self); restart: cookie = self->priv->sessions_cookie; for (item = self->priv->sessions; item; item = item->next) { GST_OBJECT_UNLOCK (self); if (fs_rtp_session_handle_dtmf_event_message (item->data, message)) { gst_message_unref (message); message = NULL; goto out; } GST_OBJECT_LOCK (self); if (cookie != self->priv->sessions_cookie) goto restart; } GST_OBJECT_UNLOCK (self); } } break; case GST_MESSAGE_STREAM_STATUS: { GstStreamStatusType type; guint i; gst_message_parse_stream_status (message, &type, NULL); switch (type) { case GST_STREAM_STATUS_TYPE_ENTER: GST_OBJECT_LOCK (self); for (i = 0; i < self->priv->threads->len; i++) { if (g_ptr_array_index (self->priv->threads, i) == g_thread_self ()) goto done; } g_ptr_array_add (self->priv->threads, g_thread_self ()); done: GST_OBJECT_UNLOCK (self); break; case GST_STREAM_STATUS_TYPE_LEAVE: GST_OBJECT_LOCK (self); while (g_ptr_array_remove_fast (self->priv->threads, g_thread_self ())); GST_OBJECT_UNLOCK (self); break; default: /* Do nothing */ break; } } break; default: break; } out: /* forward all messages to the parent */ if (message) GST_BIN_CLASS (fs_rtp_conference_parent_class)->handle_message (bin, message); }