rtp_engine.h: No sense allowing payload types larger than RFC allows.
[asterisk/asterisk.git] / include / asterisk / rtp_engine.h
index 9d6c7b4..d6a9be5 100644 (file)
@@ -71,26 +71,30 @@ extern "C" {
 
 #include "asterisk/astobj2.h"
 #include "asterisk/frame.h"
+#include "asterisk/format_cap.h"
 #include "asterisk/netsock2.h"
 #include "asterisk/sched.h"
 #include "asterisk/res_srtp.h"
 #include "asterisk/stasis.h"
+#include "asterisk/vector.h"
 
-/* Maximum number of payloads supported */
-#if defined(LOW_MEMORY)
+/*! Maximum number of payload types RTP can support. */
 #define AST_RTP_MAX_PT 128
-#else
-#define AST_RTP_MAX_PT 196
-#endif
 
-/* Maximum number of generations */
+/*! First dynamic RTP payload type */
+#define AST_RTP_PT_FIRST_DYNAMIC 96
+
+/*! Maximum number of generations */
 #define AST_RED_MAX_GENERATION 5
 
-/* Maximum size of an Asterisk channel unique ID. Should match AST_MAX_UNIQUEID.
- * Note that we don't use that defined value directly here to avoid a hard dependency
- * on channel.h
+/*!
+ * Maximum size of an internal Asterisk channel unique ID.
+ *
+ * \note Must match the AST_MAX_UNIQUEID(AST_MAX_PUBLIC_UNIQUEID) value.
+ * We don't use that defined value directly here to avoid a hard
+ * dependency on channel.h.
  */
-#define MAX_CHANNEL_ID 150
+#define MAX_CHANNEL_ID 152
 
 struct ast_rtp_instance;
 struct ast_rtp_glue;
@@ -242,7 +246,7 @@ struct ast_rtp_payload_type {
        int asterisk_format;
        /*! If asterisk_format is set, this is the internal
         * asterisk format represented by the payload */
-       struct ast_format format;
+       struct ast_format *format;
        /*! Actual internal RTP specific value of the payload */
        int rtp_code;
        /*! Actual payload number */
@@ -387,6 +391,12 @@ enum ast_rtp_ice_component_type {
        AST_RTP_ICE_COMPONENT_RTCP = 2,
 };
 
+/*! \brief ICE role during negotiation */
+enum ast_rtp_ice_role {
+       AST_RTP_ICE_ROLE_CONTROLLED,
+       AST_RTP_ICE_ROLE_CONTROLLING,
+};
+
 /*! \brief Structure for an ICE candidate */
 struct ast_rtp_engine_ice_candidate {
        char *foundation;                     /*!< Foundation identifier */
@@ -416,6 +426,12 @@ struct ast_rtp_engine_ice {
        struct ao2_container *(*get_local_candidates)(struct ast_rtp_instance *instance);
        /*! Callback for telling the ICE support that it is talking to an ice-lite implementation */
        void (*ice_lite)(struct ast_rtp_instance *instance);
+       /*! Callback for changing our role in negotiation */
+       void (*set_role)(struct ast_rtp_instance *instance, enum ast_rtp_ice_role role);
+       /*! Callback for requesting a TURN session */
+       void (*turn_request)(struct ast_rtp_instance *instance, enum ast_rtp_ice_component_type component,
+               enum ast_transport transport, const char *server, unsigned int port,
+               const char *username, const char *password);
 };
 
 /*! \brief DTLS setup types */
@@ -428,22 +444,31 @@ enum ast_rtp_dtls_setup {
 
 /*! \brief DTLS connection states */
 enum ast_rtp_dtls_connection {
-        AST_RTP_DTLS_CONNECTION_NEW,      /*!< Endpoint wants to use a new connection */
+       AST_RTP_DTLS_CONNECTION_NEW,      /*!< Endpoint wants to use a new connection */
        AST_RTP_DTLS_CONNECTION_EXISTING, /*!< Endpoint wishes to use existing connection */
 };
 
 /*! \brief DTLS fingerprint hashes */
 enum ast_rtp_dtls_hash {
-       AST_RTP_DTLS_HASH_SHA1, /*!< SHA-1 fingerprint hash */
+       AST_RTP_DTLS_HASH_SHA256, /*!< SHA-256 fingerprint hash */
+       AST_RTP_DTLS_HASH_SHA1,   /*!< SHA-1 fingerprint hash */
+};
+
+/*! \brief DTLS verification settings */
+enum ast_rtp_dtls_verify {
+       AST_RTP_DTLS_VERIFY_NONE = 0,               /*!< Don't verify anything */
+       AST_RTP_DTLS_VERIFY_FINGERPRINT = (1 << 0), /*!< Verify the fingerprint */
+       AST_RTP_DTLS_VERIFY_CERTIFICATE = (1 << 1), /*!< Verify the certificate */
 };
 
 /*! \brief DTLS configuration structure */
 struct ast_rtp_dtls_cfg {
        unsigned int enabled:1;                /*!< Whether DTLS support is enabled or not */
-       unsigned int verify:1;                 /*!< Whether to request and verify a client certificate when acting as server */
        unsigned int rekey;                    /*!< Interval at which to renegotiate and rekey - defaults to 0 (off) */
        enum ast_rtp_dtls_setup default_setup; /*!< Default setup type to use for outgoing */
        enum ast_srtp_suite suite;             /*!< Crypto suite in use */
+       enum ast_rtp_dtls_hash hash;               /*!< Hash to use for fingerprint */
+       enum ast_rtp_dtls_verify verify;           /*!< What should be verified */
        char *certfile;                        /*!< Certificate file */
        char *pvtfile;                         /*!< Private key file */
        char *cipher;                          /*!< Cipher to use */
@@ -469,8 +494,10 @@ struct ast_rtp_engine_dtls {
        void (*set_setup)(struct ast_rtp_instance *instance, enum ast_rtp_dtls_setup setup);
        /*! Set the remote fingerprint */
        void (*set_fingerprint)(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash, const char *fingerprint);
+       /*! Get the local fingerprint hash type */
+       enum ast_rtp_dtls_hash (*get_fingerprint_hash)(struct ast_rtp_instance *instance);
        /*! Get the local fingerprint */
-       const char *(*get_fingerprint)(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash);
+       const char *(*get_fingerprint)(struct ast_rtp_instance *instance);
 };
 
 /*! Structure that represents an RTP stack (engine) */
@@ -504,8 +531,6 @@ struct ast_rtp_engine {
        void (*prop_set)(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value);
        /*! Callback for setting a payload.  If asterisk  is to be used, asterisk_format will be set, otherwise value in code is used. */
        void (*payload_set)(struct ast_rtp_instance *instance, int payload, int asterisk_format, struct ast_format *format, int code);
-       /*! Callback for setting packetization preferences */
-       void (*packetization_set)(struct ast_rtp_instance *instance, struct ast_codec_pref *pref);
        /*! Callback for setting the remote address that RTP is to be sent to */
        void (*remote_address_set)(struct ast_rtp_instance *instance, struct ast_sockaddr *sa);
        /*! Callback for changing DTMF mode */
@@ -553,11 +578,16 @@ struct ast_rtp_engine {
 /*! Structure that represents codec and packetization information */
 struct ast_rtp_codecs {
        /*! Payloads present */
-       struct ao2_container *payloads;
-       /*! Codec packetization preferences */
-       struct ast_codec_pref pref;
+       AST_VECTOR(, struct ast_rtp_payload_type *) payloads;
+       /*! The framing for this media session */
+       unsigned int framing;
+       /*! RW lock that protects elements in this structure */
+       ast_rwlock_t codecs_lock;
 };
 
+#define AST_RTP_CODECS_NULL_INIT \
+    { .payloads = { 0, }, .framing = 0, .codecs_lock = AST_RWLOCK_INIT_VALUE, }
+
 /*! Structure that represents the glue that binds an RTP instance to a channel */
 struct ast_rtp_glue {
        /*! Name of the channel driver that this glue is responsible for */
@@ -594,13 +624,25 @@ struct ast_rtp_glue {
        enum ast_rtp_glue_result (*get_trtp_info)(struct ast_channel *chan, struct ast_rtp_instance **instance);
        /*! Callback for updating the destination that the remote side should send RTP to */
        int (*update_peer)(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_rtp_instance *vinstance, struct ast_rtp_instance *tinstance, const struct ast_format_cap *cap, int nat_active);
-       /*! Callback for retrieving codecs that the channel can do.  Result returned in result_cap*/
+       /*! Callback for retrieving codecs that the channel can do.  Result returned in result_cap. */
        void (*get_codec)(struct ast_channel *chan, struct ast_format_cap *result_cap);
        /*! Linked list information */
        AST_RWLIST_ENTRY(ast_rtp_glue) entry;
 };
 
-#define ast_rtp_engine_register(engine) ast_rtp_engine_register2(engine, ast_module_info->self)
+/*!
+ * \brief Allocation routine for \ref ast_rtp_payload_type
+ *
+ * \retval NULL on error
+ * \retval An ao2 ref counted \c ast_rtp_payload_type on success.
+ *
+ * \note The \c ast_rtp_payload_type returned by this function is an
+ *       ao2 ref counted object.
+ *
+ */
+struct ast_rtp_payload_type *ast_rtp_engine_alloc_payload_type(void);
+
+#define ast_rtp_engine_register(engine) ast_rtp_engine_register2(engine, AST_MODULE_SELF)
 
 /*!
  * \brief Register an RTP engine
@@ -653,7 +695,7 @@ int ast_rtp_engine_register_srtp(struct ast_srtp_res *srtp_res, struct ast_srtp_
 void ast_rtp_engine_unregister_srtp(void);
 int ast_rtp_engine_srtp_is_registered(void);
 
-#define ast_rtp_glue_register(glue) ast_rtp_glue_register2(glue, ast_module_info->self)
+#define ast_rtp_glue_register(glue) ast_rtp_glue_register2(glue, AST_MODULE_SELF)
 
 /*!
  * \brief Register RTP glue
@@ -833,6 +875,40 @@ int ast_rtp_instance_write(struct ast_rtp_instance *instance, struct ast_frame *
 struct ast_frame *ast_rtp_instance_read(struct ast_rtp_instance *instance, int rtcp);
 
 /*!
+ * \brief Set the incoming source address of the remote endpoint that we are sending RTP to
+ *
+ * This sets the incoming source address the engine is sending RTP to. Usually this
+ * will be the same as the requested target address, however in the case where
+ * the engine "learns" the address (for instance, symmetric RTP enabled) this
+ * will then contain the learned address.
+ *
+ * \param instance The RTP instance to change the address on
+ * \param address Address to set it to
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int ast_rtp_instance_set_incoming_source_address(struct ast_rtp_instance *instance,
+                                                const struct ast_sockaddr *address);
+
+/*!
+ * \brief Set the requested target address of the remote endpoint
+ *
+ * This should always be the address of the remote endpoint. Consequently, this can differ
+ * from the address the engine is sending RTP to.  However, usually they will be the same
+ * except in some circumstances (for instance when the engine "learns" the address if
+ * symmetric RTP is enabled).
+ *
+ * \param instance The RTP instance to change the address on
+ * \param address Address to set it to
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int ast_rtp_instance_set_requested_target_address(struct ast_rtp_instance *instance,
+                                                 const struct ast_sockaddr *address);
+
+/*!
  * \brief Set the address of the remote endpoint that we are sending RTP to
  *
  * \param instance The RTP instance to change the address on
@@ -852,7 +928,8 @@ struct ast_frame *ast_rtp_instance_read(struct ast_rtp_instance *instance, int r
  *
  * \since 1.8
  */
-int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, const struct ast_sockaddr *address);
+#define ast_rtp_instance_set_remote_address(instance, address) \
+       ast_rtp_instance_set_requested_target_address((instance), (address));
 
 /*!
  * \brief Set the address that we are expecting to receive RTP on
@@ -920,6 +997,32 @@ void ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struc
 int ast_rtp_instance_get_and_cmp_local_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address);
 
 /*!
+ * \brief Get the incoming source address of the remote endpoint
+ *
+ * This returns the remote address the engine is sending RTP to. Usually this
+ * will be the same as the requested target address, however in the case where
+ * the engine "learns" the address (for instance, symmetric RTP enabled) this
+ * will then contain the learned address.
+ *
+ * \param instance The instance that we want to get the incoming source address for
+ * \param address A structure to put the address into
+ */
+void ast_rtp_instance_get_incoming_source_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address);
+
+/*!
+ * \brief Get the requested target address of the remote endpoint
+ *
+ * This returns the explicitly set address of a remote endpoint. Meaning this won't change unless
+ * specifically told to change. In most cases this should be the same as the incoming source
+ * address, except in cases where the engine "learns" the address in which case this and the
+ * incoming source address might differ.
+ *
+ * \param instance The instance that we want to get the requested target address for
+ * \param address A structure to put the address into
+ */
+void ast_rtp_instance_get_requested_target_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address);
+
+/*!
  * \brief Get the address of the remote endpoint that we are sending RTP to
  *
  * \param instance The instance that we want to get the remote address for
@@ -937,7 +1040,20 @@ int ast_rtp_instance_get_and_cmp_local_address(struct ast_rtp_instance *instance
  *
  * \since 1.8
  */
-void ast_rtp_instance_get_remote_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address);
+#define ast_rtp_instance_get_remote_address(instance, address) \
+       ast_rtp_instance_get_incoming_source_address((instance), (address));
+
+/*!
+ * \brief Get the requested target address of the remote endpoint and
+ *        compare it to the given address
+ *
+ * \param instance The instance that we want to get the remote address for
+ * \param address An initialized address that may be overwritten addresses differ
+ *
+ * \retval 0 address was not changed
+ * \retval 1 address was changed
+ */
+int ast_rtp_instance_get_and_cmp_requested_target_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address);
 
 /*!
  * \brief Get the address of the remote endpoint that we are sending RTP to, comparing its address to another
@@ -960,8 +1076,8 @@ void ast_rtp_instance_get_remote_address(struct ast_rtp_instance *instance, stru
  *
  * \since 1.8
  */
-
-int ast_rtp_instance_get_and_cmp_remote_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address);
+#define ast_rtp_instance_get_and_cmp_remote_address(instance, address) \
+       ast_rtp_instance_get_and_cmp_requested_target_address((instance), (address));
 
 /*!
  * \brief Set the value of an RTP instance extended property
@@ -1095,25 +1211,6 @@ void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs);
 void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance);
 
 /*!
- * \brief Set payload information on an RTP instance to the default
- *
- * \param codecs The codecs structure to set defaults on
- * \param instance Optionally the instance that the codecs structure belongs to
- *
- * Example usage:
- *
- * \code
- * struct ast_rtp_codecs codecs;
- * ast_rtp_codecs_payloads_default(&codecs, NULL);
- * \endcode
- *
- * This sets the default payloads on the codecs structure.
- *
- * \since 1.8
- */
-void ast_rtp_codecs_payloads_default(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance);
-
-/*!
  * \brief Copy payload information from one RTP instance to another
  *
  * \param src The source codecs structure
@@ -1227,20 +1324,36 @@ void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp
  * \param codecs Codecs structure to look in
  * \param payload Numerical payload to look up
  *
- * \retval Payload information
+ * \retval Payload information.
+ * \retval NULL if payload does not exist.
+ *
+ * \note The payload returned by this function has its reference count increased.
+ *       Callers are responsible for decrementing the reference count.
  *
  * Example usage:
  *
  * \code
- * struct ast_rtp_payload_type payload_type;
- * payload_type = ast_rtp_codecs_payload_lookup(&codecs, 0);
+ * struct ast_rtp_payload_type *payload_type;
+ * payload_type = ast_rtp_codecs_get_payload(&codecs, 0);
  * \endcode
  *
  * This looks up the information for payload '0' from the codecs structure.
+ */
+struct ast_rtp_payload_type *ast_rtp_codecs_get_payload(struct ast_rtp_codecs *codecs, int payload);
+
+/*!
+ * \brief Update the format associated with a payload in a codecs structure
  *
- * \since 1.8
+ * \param codecs Codecs structure to operate on
+ * \param payload Numerical payload to look up
+ * \param format The format to replace the existing one
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ *
+ * \since 13
  */
-struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup(struct ast_rtp_codecs *codecs, int payload);
+int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int payload, struct ast_format *format);
 
 /*!
  * \brief Retrieve the actual ast_format stored on the codecs structure for a specific payload
@@ -1251,11 +1364,35 @@ struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup(struct ast_rtp_codecs
  * \retval pointer to format structure on success
  * \retval NULL on failure
  *
+ * \note The format returned by this function has its reference count increased.
+ *       Callers are responsible for decrementing the reference count.
+ *
  * \since 10.0
  */
 struct ast_format *ast_rtp_codecs_get_payload_format(struct ast_rtp_codecs *codecs, int payload);
 
 /*!
+ * \brief Set the framing used for a set of codecs
+ *
+ * \param codecs Codecs structure to set framing on
+ * \param framing The framing value to set on the codecs
+ *
+ * \since 13.0.0
+ */
+void ast_rtp_codecs_set_framing(struct ast_rtp_codecs *codecs, unsigned int framing);
+
+/*!
+ * \brief Get the framing used for a set of codecs
+ *
+ * \param codecs Codecs structure to get the framing from
+ *
+ * \retval The framing to be used for the media stream associated with these codecs
+ *
+ * \since 13.0.0
+ */
+unsigned int ast_rtp_codecs_get_framing(struct ast_rtp_codecs *codecs);
+
+/*!
  * \brief Get the sample rate associated with known RTP payload types
  *
  * \param asterisk_format True if the value in format is to be used.
@@ -1280,7 +1417,7 @@ unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, struct ast_format
  * \code
  * struct ast_format_cap *astformats = ast_format_cap_alloc_nolock()
  * int nonastformats;
- * ast_rtp_codecs_payload_formats(&codecs, &astformats, &nonastformats);
+ * ast_rtp_codecs_payload_formats(&codecs, astformats, &nonastformats);
  * \endcode
  *
  * This retrieves all the formats known about in the codecs structure and puts the Asterisk ones in the integer
@@ -1311,6 +1448,7 @@ void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_fo
  * \since 1.8
  */
 int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code);
+
 /*!
  * \brief Search for a payload code in the ast_rtp_codecs structure
  *
@@ -1371,8 +1509,8 @@ const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_f
  * char buf[256] = "";
  * struct ast_format tmp_fmt;
  * struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
- * ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_ULAW, 0));
- * ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_GSM, 0));
+ * ast_format_cap_append(cap, ast_format_set(&tmp_fmt, AST_FORMAT_ULAW, 0));
+ * ast_format_cap_append(cap, ast_format_set(&tmp_fmt, AST_FORMAT_GSM, 0));
  * char *mime = ast_rtp_lookup_mime_multiple2(&buf, sizeof(buf), cap, 0, 1, 0);
  * ast_format_cap_destroy(cap);
  * \endcode
@@ -1384,25 +1522,6 @@ const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_f
 char *ast_rtp_lookup_mime_multiple2(struct ast_str *buf, struct ast_format_cap *ast_format_capability, int rtp_capability, const int asterisk_format, enum ast_rtp_options options);
 
 /*!
- * \brief Set codec packetization preferences
- *
- * \param codecs Codecs structure to muck with
- * \param instance Optionally the instance that the codecs structure belongs to
- * \param prefs Codec packetization preferences
- *
- * Example usage:
- *
- * \code
- * ast_rtp_codecs_packetization_set(&codecs, NULL, &prefs);
- * \endcode
- *
- * This sets the packetization preferences pointed to by prefs on the codecs structure pointed to by codecs.
- *
- * \since 1.8
- */
-void ast_rtp_codecs_packetization_set(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_codec_pref *prefs);
-
-/*!
  * \brief Begin sending a DTMF digit
  *
  * \param instance The RTP instance to send the DTMF on
@@ -1742,6 +1861,8 @@ int ast_rtp_instance_get_stats(struct ast_rtp_instance *instance, struct ast_rtp
  * \param chan Channel to set the statistics on
  * \param instance The RTP instance that statistics will be retrieved from
  *
+ * \note Absolutely _NO_ channel locks should be held before calling this function.
+ *
  * Example usage:
  *
  * \code
@@ -2087,12 +2208,12 @@ struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance);
 
 /*! \brief Custom formats declared in codecs.conf at startup must be communicated to the rtp_engine
  * so their mime type can payload number can be initialized. */
-int ast_rtp_engine_load_format(const struct ast_format *format);
+int ast_rtp_engine_load_format(struct ast_format *format);
 
 /*! \brief Formats requiring the use of a format attribute interface must have that
  * interface registered in order for the rtp engine to handle it correctly.  If an
  * attribute interface is unloaded, this function must be called to notify the rtp_engine. */
-int ast_rtp_engine_unload_format(const struct ast_format *format);
+int ast_rtp_engine_unload_format(struct ast_format *format);
 
 /*!
  * \brief Obtain a pointer to the ICE support present on an RTP instance
@@ -2167,6 +2288,38 @@ void ast_rtp_publish_rtcp_message(struct ast_rtp_instance *rtp,
                struct ast_rtp_rtcp_report *report,
                struct ast_json *blob);
 
+/*!
+ * \brief Get the last RTP transmission time
+ *
+ * \param rtp The instance from which to get the last transmission time
+ * \return The last RTP transmission time
+ */
+time_t ast_rtp_instance_get_last_tx(const struct ast_rtp_instance *rtp);
+
+/*!
+ * \brief Set the last RTP transmission time
+ *
+ * \param rtp The instance on which to set the last transmission time
+ * \param time The last transmission time
+ */
+void ast_rtp_instance_set_last_tx(struct ast_rtp_instance *rtp, time_t time);
+
+/*
+ * \brief Get the last RTP reception time
+ *
+ * \param rtp The instance from which to get the last reception time
+ * \return The last RTP reception time
+ */
+time_t ast_rtp_instance_get_last_rx(const struct ast_rtp_instance *rtp);
+
+/*!
+ * \brief Set the last RTP reception time
+ *
+ * \param rtp The instance on which to set the last reception time
+ * \param time The last reception time
+ */
+void ast_rtp_instance_set_last_rx(struct ast_rtp_instance *rtp, time_t time);
+
 /*! \addtogroup StasisTopicsAndMessages
  * @{
  */
@@ -2195,7 +2348,7 @@ struct stasis_message_type *ast_rtp_rtcp_received_type(void);
  */
 struct stasis_topic *ast_rtp_topic(void);
 
-/* }@ */
+/* @} */
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }