static gboolean kms_webrtc_session_configure_connection (KmsWebrtcSession * self, KmsSdpSession * sess, SdpMediaConfig * neg_mconf, SdpMediaConfig * remote_mconf, gboolean offerer) { GstSDPMedia *neg_media = kms_sdp_media_config_get_sdp_media (neg_mconf); const gchar *neg_proto_str = gst_sdp_media_get_proto (neg_media); GstSDPMedia *remote_media = kms_sdp_media_config_get_sdp_media (remote_mconf); const gchar *remote_proto_str = gst_sdp_media_get_proto (remote_media); if (g_strcmp0 (neg_proto_str, remote_proto_str) != 0) { GST_WARNING_OBJECT (self, "Negotiated proto ('%s') not matching with remote proto ('%s')", neg_proto_str, remote_proto_str); return FALSE; } if (g_strcmp0 (neg_proto_str, "DTLS/SCTP") != 0) { return FALSE; } kms_webrtc_session_add_connection (self, sess, neg_mconf, offerer); return TRUE; }
static const gchar * kms_ice_nice_agent_sdp_media_add_ice_candidate (KmsWebrtcSession * self, SdpMediaConfig * mconf, NiceAgent * agent, NiceCandidate * cand) { char *media_stream_id; GstSDPMedia *media = kms_sdp_media_config_get_sdp_media (mconf); const gchar *mid; media_stream_id = kms_webrtc_session_get_stream_id (self, mconf); if (media_stream_id == NULL) { return NULL; } if (atoi (media_stream_id) != cand->stream_id) { return NULL; } sdp_media_add_ice_candidate (media, agent, cand); mid = kms_sdp_media_config_get_mid (mconf); if (mid == NULL) { return ""; } return mid; }
static gboolean kms_webrtc_session_add_connection (KmsWebrtcSession * self, KmsSdpSession * sess, SdpMediaConfig * mconf, gboolean offerer) { KmsBaseRtpSession *base_rtp_sess = KMS_BASE_RTP_SESSION (sess); gboolean connected, active; KmsIRtpConnection *conn; conn = kms_base_rtp_session_get_connection (base_rtp_sess, mconf); if (conn == NULL) { GST_ERROR_OBJECT (self, "No connection created"); return FALSE; } g_object_get (conn, "added", &connected, NULL); if (connected) { GST_DEBUG_OBJECT (self, "Conn already added"); return TRUE; } active = sdp_utils_media_is_active (kms_sdp_media_config_get_sdp_media (mconf), offerer); kms_i_rtp_connection_add (conn, GST_BIN (self), active); kms_i_rtp_connection_sink_sync_state_with_parent (conn); kms_i_rtp_connection_src_sync_state_with_parent (conn); return TRUE; }
void kms_webrtc_session_remote_sdp_add_ice_candidate (KmsWebrtcSession * self, KmsIceCandidate * candidate, guint8 index) { KmsSdpSession *sdp_sess = KMS_SDP_SESSION (self); SdpMessageContext *remote_sdp_ctx = sdp_sess->remote_sdp_ctx; GSList *medias; SdpMediaConfig *mconf; if (remote_sdp_ctx == NULL) { GST_INFO_OBJECT (self, "Cannot update remote SDP until it is set."); return; } medias = kms_sdp_message_context_get_medias (remote_sdp_ctx); mconf = g_slist_nth_data (medias, index); if (mconf == NULL) { GST_WARNING_OBJECT (self, "Media not found in remote SDP for index %" G_GUINT16_FORMAT, index); } else { GstSDPMedia *media = kms_sdp_media_config_get_sdp_media (mconf); sdp_media_add_ice_candidate (media, self->agent, candidate); } }
static KmsIRtpConnection * kms_webrtc_session_create_connection (KmsBaseRtpSession * base_rtp_sess, SdpMediaConfig * mconf, const gchar * name, guint16 min_port, guint16 max_port) { KmsWebrtcSession *self = KMS_WEBRTC_SESSION (base_rtp_sess); GstSDPMedia *media = kms_sdp_media_config_get_sdp_media (mconf); KmsWebRtcBaseConnection *conn; self->min_port = min_port; self->max_port = max_port; if (g_strcmp0 (gst_sdp_media_get_proto (media), "DTLS/SCTP") == 0) { GST_DEBUG_OBJECT (self, "Create SCTP connection"); conn = KMS_WEBRTC_BASE_CONNECTION (kms_webrtc_sctp_connection_new (self->agent, self->context, name, min_port, max_port)); } else { GST_DEBUG_OBJECT (self, "Create RTP connection"); conn = KMS_WEBRTC_BASE_CONNECTION (kms_webrtc_connection_new (self->agent, self->context, name)); } return KMS_I_RTP_CONNECTION (conn); }
gint kms_sdp_media_config_get_abs_send_time_id (SdpMediaConfig * mconf) { GstSDPMedia *media = kms_sdp_media_config_get_sdp_media (mconf); guint a; for (a = 0;; a++) { const gchar *attr; gchar **tokens; attr = gst_sdp_media_get_attribute_val_n (media, EXT_MAP, a); if (attr == NULL) { break; } tokens = g_strsplit (attr, " ", 0); if (g_strcmp0 (RTP_HDR_EXT_ABS_SEND_TIME_URI, tokens[1]) == 0) { gint ret = atoi (tokens[0]); g_strfreev (tokens); return ret; } g_strfreev (tokens); } return -1; }
static gboolean kms_base_rtp_session_configure_connection (KmsBaseRtpSession * self, SdpMediaConfig * neg_mconf, SdpMediaConfig * remote_mconf, gboolean offerer) { GstSDPMedia *neg_media = kms_sdp_media_config_get_sdp_media (neg_mconf); const gchar *neg_proto_str = gst_sdp_media_get_proto (neg_media); const gchar *neg_media_str = gst_sdp_media_get_media (neg_media); GstSDPMedia *remote_media = kms_sdp_media_config_get_sdp_media (remote_mconf); const gchar *remote_proto_str = gst_sdp_media_get_proto (remote_media); const gchar *remote_media_str = gst_sdp_media_get_media (remote_media); gboolean active; if (g_strcmp0 (neg_proto_str, remote_proto_str) != 0) { GST_WARNING_OBJECT (self, "Negotiated proto ('%s') not matching with remote proto ('%s')", neg_proto_str, remote_proto_str); return FALSE; } if (!kms_utils_contains_proto (neg_proto_str, "RTP")) { GST_DEBUG_OBJECT (self, "'%s' protocol does not need RTP connection", neg_proto_str); /* It cannot be managed here but could be managed by the child class */ return FALSE; } if (g_strcmp0 (neg_media_str, remote_media_str) != 0) { GST_WARNING_OBJECT (self, "Negotiated media ('%s') not matching with remote media ('%s')", neg_media_str, remote_media_str); return FALSE; } if (kms_base_rtp_session_process_remote_ssrc (self, remote_media, neg_mconf) == NULL) { return TRUE; /* It cannot be managed here but could be managed by the child class */ } active = sdp_utils_media_is_active (neg_media, offerer); return kms_base_rtp_session_add_connection_for_session (self, neg_mconf, active); }
static void kms_rtp_endpoint_start_transport_send (KmsBaseSdpEndpoint * base_sdp_endpoint, gboolean offerer) { KmsRtpEndpoint *self = KMS_RTP_ENDPOINT (base_sdp_endpoint); SdpMessageContext *remote_ctx = kms_base_sdp_endpoint_get_remote_sdp_ctx (base_sdp_endpoint); const GstSDPMessage *sdp = kms_sdp_message_context_get_sdp_message (remote_ctx); const GSList *item = kms_sdp_message_context_get_medias (remote_ctx); const GstSDPConnection *msg_conn = gst_sdp_message_get_connection (sdp); /* Chain up */ KMS_BASE_SDP_ENDPOINT_CLASS (parent_class)->start_transport_send (base_sdp_endpoint, offerer); for (; item != NULL; item = g_slist_next (item)) { SdpMediaConfig *mconf = item->data; GstSDPMedia *media = kms_sdp_media_config_get_sdp_media (mconf); const GstSDPConnection *media_con; KmsRtpBaseConnection *conn; guint port; if (media->port == 0) { continue; } if (gst_sdp_media_connections_len (media) != 0) { media_con = gst_sdp_media_get_connection (media, 0); } else { media_con = msg_conn; } if (media_con == NULL || media_con->address == NULL || media_con->address[0] == '\0') { const gchar *media_str = gst_sdp_media_get_media (media); GST_WARNING_OBJECT (self, "Missing connection information for '%s'", media_str); continue; } conn = kms_rtp_endpoint_media_get_connection (self, mconf); if (conn == NULL) { continue; } port = gst_sdp_media_get_port (media); kms_rtp_base_connection_set_remote_info (conn, media_con->address, port, port + 1); /* TODO: get rtcp port from attr if it exists */ } }
/* Configure media SDP begin */ static gboolean kms_rtp_endpoint_configure_media (KmsBaseSdpEndpoint * base_sdp_endpoint, SdpMediaConfig * mconf) { KmsRtpEndpoint *self = KMS_RTP_ENDPOINT (base_sdp_endpoint); KmsBaseRtpEndpoint *base_rtp = KMS_BASE_RTP_ENDPOINT (self); GstSDPMedia *media = kms_sdp_media_config_get_sdp_media (mconf); guint conn_len, c; guint attr_len, a; KmsRtpBaseConnection *conn; gboolean ret = TRUE; /* Chain up */ ret = KMS_BASE_SDP_ENDPOINT_CLASS (kms_rtp_endpoint_parent_class)->configure_media (base_sdp_endpoint, mconf); if (ret == FALSE) { return FALSE; } conn_len = gst_sdp_media_connections_len (media); for (c = 0; c < conn_len; c++) { gst_sdp_media_remove_connection (media, c); } conn = KMS_RTP_BASE_CONNECTION (kms_base_rtp_endpoint_get_connection (base_rtp, mconf)); if (conn == NULL) { return TRUE; } media->port = kms_rtp_base_connection_get_rtp_port (conn); attr_len = gst_sdp_media_attributes_len (media); for (a = 0; a < attr_len; a++) { const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, a); if (g_strcmp0 (attr->key, "rtcp") == 0) { gst_sdp_media_remove_attribute (media, a); /* TODO: complete rtcp attr with addr and rtcp port */ } } return TRUE; }
static void gst_media_add_remote_candidates (SdpMediaConfig * mconf, KmsWebRtcBaseConnection * conn, const gchar * msg_ufrag, const gchar * msg_pwd) { const GstSDPMedia *media = kms_sdp_media_config_get_sdp_media (mconf); KmsIceBaseAgent *agent = conn->agent; gchar *stream_id = conn->stream_id; const gchar *ufrag, *pwd; guint len, i; ufrag = gst_sdp_media_get_attribute_val (media, SDP_ICE_UFRAG_ATTR); pwd = gst_sdp_media_get_attribute_val (media, SDP_ICE_PWD_ATTR); if (!kms_ice_base_agent_set_remote_credentials (agent, stream_id, ufrag, pwd)) { GST_WARNING ("Cannot set remote media credentials (%s, %s).", ufrag, pwd); if (!kms_ice_base_agent_set_remote_credentials (agent, stream_id, msg_ufrag, msg_pwd)) { GST_WARNING ("Cannot set remote message credentials (%s, %s).", ufrag, pwd); return; } else { GST_DEBUG ("Set remote message credentials OK (%s, %s).", ufrag, pwd); } } else { GST_DEBUG ("Set remote media credentials OK (%s, %s).", ufrag, pwd); } len = gst_sdp_media_attributes_len (media); for (i = 0; i < len; i++) { const GstSDPAttribute *attr; KmsIceCandidate *candidate; gint idx = kms_sdp_media_config_get_id (mconf); const gchar *mid = kms_sdp_media_config_get_mid (mconf); attr = gst_sdp_media_get_attribute (media, i); if (g_strcmp0 (SDP_CANDIDATE_ATTR, attr->key) != 0) { continue; } candidate = kms_ice_candidate_new (attr->value, mid, idx); kms_ice_base_agent_add_ice_candidate (agent, candidate, stream_id); g_object_unref (candidate); } }
gboolean kms_webrtc_session_set_crypto_info (KmsWebrtcSession * self, SdpMediaConfig * mconf) { GstSDPMedia *media = kms_sdp_media_config_get_sdp_media (mconf); gchar *fingerprint; /* Crypto info */ fingerprint = kms_webrtc_session_generate_fingerprint_sdp_attr (self, mconf); if (fingerprint == NULL) { return FALSE; } gst_sdp_media_add_attribute (media, "fingerprint", fingerprint); g_free (fingerprint); return TRUE; }
gboolean kms_webrtc_session_set_ice_credentials (KmsWebrtcSession * self, SdpMediaConfig * mconf) { GstSDPMedia *media = kms_sdp_media_config_get_sdp_media (mconf); KmsWebRtcBaseConnection *conn; gchar *ufrag, *pwd; conn = kms_webrtc_session_get_connection (self, mconf); if (conn == NULL) { return FALSE; } kms_ice_base_agent_get_local_credentials (self->agent, conn->stream_id, &ufrag, &pwd); gst_sdp_media_add_attribute (media, SDP_ICE_UFRAG_ATTR, ufrag); g_free (ufrag); gst_sdp_media_add_attribute (media, SDP_ICE_PWD_ATTR, pwd); g_free (pwd); return TRUE; }
static gboolean kms_webrtc_session_sdp_media_add_default_info (KmsWebrtcSession * self, SdpMediaConfig * mconf, gboolean use_ipv6) { GstSDPMedia *media = kms_sdp_media_config_get_sdp_media (mconf); KmsIceBaseAgent *agent = self->agent; char *stream_id; KmsIceCandidate *rtp_default_candidate, *rtcp_default_candidate; gchar *rtp_addr; gchar *rtcp_addr; const gchar *rtp_addr_type, *rtcp_addr_type; gboolean rtp_is_ipv6, rtcp_is_ipv6; guint rtp_port, rtcp_port; guint conn_len, c; gchar *str; guint attr_len, i; stream_id = kms_webrtc_session_get_stream_id (self, mconf); if (stream_id == NULL) { return FALSE; } rtp_default_candidate = kms_ice_base_agent_get_default_local_candidate (agent, stream_id, NICE_COMPONENT_TYPE_RTP); if (kms_sdp_media_config_is_rtcp_mux (mconf) || kms_sdp_media_config_get_group (mconf) != NULL) { rtcp_default_candidate = kms_ice_base_agent_get_default_local_candidate (agent, stream_id, NICE_COMPONENT_TYPE_RTP); } else { rtcp_default_candidate = kms_ice_base_agent_get_default_local_candidate (agent, stream_id, NICE_COMPONENT_TYPE_RTCP); } if (rtcp_default_candidate == NULL || rtcp_default_candidate == NULL) { GST_WARNING_OBJECT (self, "Error getting ICE candidates. Network can be unavailable."); return FALSE; } rtp_addr = kms_ice_candidate_get_address (rtp_default_candidate); rtp_port = kms_ice_candidate_get_port (rtp_default_candidate); rtp_is_ipv6 = kms_ice_candidate_get_ip_version (rtp_default_candidate) == IP_VERSION_6; rtcp_addr = kms_ice_candidate_get_address (rtcp_default_candidate); rtcp_port = kms_ice_candidate_get_port (rtcp_default_candidate); rtcp_is_ipv6 = kms_ice_candidate_get_ip_version (rtcp_default_candidate) == IP_VERSION_6; rtp_addr_type = rtp_is_ipv6 ? "IP6" : "IP4"; rtcp_addr_type = rtcp_is_ipv6 ? "IP6" : "IP4"; if (use_ipv6 != rtp_is_ipv6) { GST_WARNING_OBJECT (self, "No valid rtp address type: %s", rtp_addr_type); return FALSE; } media->port = rtp_port; conn_len = gst_sdp_media_connections_len (media); for (c = 0; c < conn_len; c++) { gst_sdp_media_remove_connection (media, c); } gst_sdp_media_add_connection (media, "IN", rtp_addr_type, rtp_addr, 0, 0); attr_len = gst_sdp_media_attributes_len (media); for (i = 0; i < attr_len; i++) { const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, i); if (g_strcmp0 (attr->key, "rtcp") == 0) { str = g_strdup_printf ("%d IN %s %s", rtcp_port, rtcp_addr_type, rtcp_addr); gst_sdp_attribute_clear ((GstSDPAttribute *) attr); gst_sdp_attribute_set ((GstSDPAttribute *) attr, "rtcp", str); g_free (str); } } g_free (rtp_addr); g_free (rtcp_addr); g_object_unref (rtp_default_candidate); g_object_unref (rtcp_default_candidate); return TRUE; }