diff --git a/src/crypto/dtls_srtp.cpp b/src/crypto/dtls_srtp.cpp
index f12a810e86ebf5821f4e671c3ecce4051b213598..55a9e6c3fa068603f89df99804ea5926dcfa1104 100644
--- a/src/crypto/dtls_srtp.cpp
+++ b/src/crypto/dtls_srtp.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2022 Belledonne Communications SARL.
+ * Copyright (c) 2010-2025 Belledonne Communications SARL.
  *
  * This file is part of mediastreamer2
  * (see https://gitlab.linphone.org/BC/public/mediastreamer2).
@@ -18,8 +18,10 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <array>
 #include <bctoolbox/defs.h>
 #include <mutex>
+#include <queue>
 
 #include "mediastreamer2/dtls_srtp.h"
 #include "mediastreamer2/mediastream.h"
@@ -30,89 +32,123 @@
 
 #include "bctoolbox/crypto.h"
 
-typedef struct _DtlsBcToolBoxContexts {
+namespace {
+/** A class to manage all crypto contexts needed by Dtls-Srtp */
+class DtlsCrypto {
+public:
 	bctbx_x509_certificate_t *crt;
 	bctbx_ssl_config_t *ssl_config;
 	bctbx_ssl_context_t *ssl;
 	bctbx_rng_context_t *rng;
 	bctbx_signing_key_t *pkey;
-} DtlsBcToolBoxContext;
 
-/**
- * incoming DTLS message are stored in a chain buffer to feed handshake when needed
- */
-typedef struct _DtlsRawPacket {
-	unsigned char *data;
-	size_t length;
-	void *next;
-} DtlsRawPacket;
+	DtlsCrypto()
+	    : crt(bctbx_x509_certificate_new()), ssl_config(bctbx_ssl_config_new()), ssl(nullptr),
+	      rng(bctbx_rng_context_new()), pkey(bctbx_signing_key_new()) {
+	}
+	~DtlsCrypto() {
+		bctbx_rng_context_free(rng);
+		bctbx_signing_key_free(pkey);
+		bctbx_x509_certificate_free(crt);
+		bctbx_ssl_context_free(ssl);
+		bctbx_ssl_config_free(ssl_config);
+	}
+};
 
 /* DTLS only allow use of AES128 so we have 16 bytes key and 14 byte salt in any case */
-#define DTLS_SRTP_KEY_LEN 16
-#define DTLS_SRTP_SALT_LEN 14
-#define DTLS_SRTP_KEY_MATERIAL_LEN 128
+constexpr size_t DtlsSrtpKeyLen = 16;
+constexpr size_t DtlsSrtpSaltLen = 14;
+// key material generated during the DTLS handshake: a pair of key+salt : one for reception, one for sending
+constexpr size_t DtlsSrtpKeyMaterial = 2 * (DtlsSrtpKeyLen + DtlsSrtpSaltLen);
+// period in ms to trigger the repetition timer
+constexpr uint64_t DtlsRepetitionTimerPoll = 100;
 
 /* Do not modify this values: fingerprint_verified MUST be > handshake_over*/
-#define DTLS_STATUS_CONTEXT_NOT_READY 0
-#define DTLS_STATUS_CONTEXT_READY 1
-#define DTLS_STATUS_HANDSHAKE_ONGOING 2
-#define DTLS_STATUS_HANDSHAKE_OVER 3
-#define DTLS_STATUS_FINGERPRINT_VERIFIED 4
-
-#define DTLS_REPETITION_TIMER_POLL 100
+enum class DtlsStatus : uint8_t {
+	ContextNotReady = 0,
+	ContextReady = 1,
+	HandshakeOngoing = 2,
+	HandshakeOver = 3,
+	FingerprintVerified = 4,
+};
+} // anonymous namespace
 
 struct _MSDtlsSrtpContext {
-	MSMediaStreamSessions *stream_sessions;
-	MSDtlsSrtpRole role;        /**< can be unset(at init on caller side), client or server */
-	char peer_fingerprint[256]; /**< used to store peer fingerprint passed through SDP */
+	MSMediaStreamSessions *mStreamSessions;
+	MSDtlsSrtpRole mRole;         /**< can be unset(at init on caller side), client or server */
+	std::string mPeerFingerprint; /**< used to store peer fingerprint passed through SDP */
 	int mtu;
 	RtpTransportModifier *rtp_modifier;
-	DtlsBcToolBoxContext
-	    *rtp_dtls_context;      /**< a structure containing all contexts needed by DTLS handshake for RTP channel */
-	uint8_t rtp_channel_status; /**< channel status : DTLS_STATUS_CONTEXT_NOT_READY, DTLS_STATUS_CONTEXT_READY,
-	                               DTLS_STATUS_HANDSHAKE_ONGOING, DTLS_STATUS_HANDSHAKE_OVER,
-	                               DTLS_STATUS_FINGERPRINT_VERIFIED */
-	uint8_t rtp_channel_key_material[DTLS_SRTP_KEY_MATERIAL_LEN]; /**< Store the key material generated by the handshake
+	DtlsCrypto mDtlsCryptoContext; /**< a structure containing all contexts needed by DTLS handshake for RTP channel */
+	DtlsStatus mChannelStatus;     /**< channel status :not ready, ready, hanshake on going, handshake over, fingerprint
+	                                  verified */
+	std::array<uint8_t, DtlsSrtpKeyMaterial> mSrtpKeyMaterial; /**< Store the key material generated by the handshake
 	                                                                 on rtp channel */
-	MSCryptoSuite rtp_agreed_srtp_protection_profile;             /**< agreed protection profile on rtp channel */
-	DtlsRawPacket *rtp_incoming_buffer; /**< buffer of incoming DTLS packet to be read by mbedtls callback */
-	uint64_t rtp_time_reference;        /**< an epoch in ms, used to manage retransmission when we are client */
-	bool retry_sending;                 /**< a flag to set a retry after failed packet sending */
-	std::mutex mtx;                     /**< lock any operation on this context */
+	MSCryptoSuite mSrtpProtectionProfile;                      /**< agreed protection profile on rtp channel */
+	std::queue<std::vector<uint8_t>>
+	    mRtpIncomingBuffer;      /**< buffer of incoming DTLS packet to be read by mbedtls callback */
+	uint64_t rtp_time_reference; /**< an epoch in ms, used to manage retransmission when we are client */
+	bool retry_sending;          /**< a flag to set a retry after failed packet sending */
+	std::mutex mtx;              /**< lock any operation on this context */
+
+	_MSDtlsSrtpContext() = delete;
+	_MSDtlsSrtpContext(MSMediaStreamSessions *sessions, MSDtlsSrtpParams *params) {
+		mRole = params->role;
+		mtu = params->mtu;
+		rtp_time_reference = 0;
+		retry_sending = false;
+
+		mStreamSessions = sessions;
+		mChannelStatus = DtlsStatus::ContextNotReady;
+		mSrtpProtectionProfile = MS_CRYPTO_SUITE_INVALID;
+	};
+	~_MSDtlsSrtpContext() = default;
+
+	int initialiseDtlsCryptoContext(MSDtlsSrtpParams *params);
+	void start();
+	void createSslContext();
+	void setRole(MSDtlsSrtpRole role);
+	void checkChannelStatus();
+	void setKeyMaterial();
+	int processDtlsPacket(mblk_t *msg);
 };
 
+namespace {
 /***********************************************/
 /***** LOCAL FUNCTIONS                     *****/
 /***********************************************/
-namespace {
-/*** DtlsBcToolBox context create/dstroy ***/
-
-DtlsBcToolBoxContext *ms_dtls_srtp_bctbx_context_new(void) {
-	// allocate the memory
-	DtlsBcToolBoxContext *ctx = ms_new0(DtlsBcToolBoxContext, 1);
-
-	// create and initialise the requested fields
-	ctx->rng = bctbx_rng_context_new();
-	ctx->pkey = bctbx_signing_key_new();
-	ctx->crt = bctbx_x509_certificate_new();
-	ctx->ssl_config = bctbx_ssl_config_new();
-	ctx->ssl = NULL;
-	return ctx;
-}
-
-void ms_dtls_srtp_bctbx_context_free(DtlsBcToolBoxContext *ctx) {
-	if (ctx != NULL) {
-		bctbx_rng_context_free(ctx->rng);
-		bctbx_signing_key_free(ctx->pkey);
-		bctbx_x509_certificate_free(ctx->crt);
-		bctbx_ssl_context_free(ctx->ssl);
-		bctbx_ssl_config_free(ctx->ssl_config);
-		ms_free(ctx);
-	}
-}
+// Fingerprint size should never be more than 255 (actually less than that with supported types:
+// SHA-512 is 64 bytes long -> 3*64 for its hexa and : representation +8 for the prefix = 200
+constexpr size_t maxFingerPrintSize = 255;
 
 /**************************/
 /**** Helper functions ****/
+// case-insensitive prefix comparison of fingerprints
+bool startsWithCaseInsensitive(const std::string &fingerprint, const char *prefix, size_t prefixSize) {
+	if (fingerprint.size() < prefixSize) {
+		return false;
+	}
+	for (size_t i = 0; i < prefixSize; ++i) {
+		if (std::tolower(static_cast<unsigned char>(fingerprint[i])) != prefix[i]) {
+			return false;
+		}
+	}
+	return true;
+}
+// case-insensitive compare for whole fingerprints
+bool caseInsensitiveCompare(const std::string &fingerprint, const char *cStr) {
+	size_t cStrLen = strlen(cStr);
+	if (fingerprint.size() != cStrLen) {
+		return false;
+	}
+	for (size_t i = 0; i < cStrLen; ++i) {
+		if (std::tolower(static_cast<unsigned char>(fingerprint[i])) !=
+		    std::tolower(static_cast<unsigned char>(cStr[i]))) {
+			return false;
+		}
+	}
+	return true;
+}
 /**
  * @Brief Compute the certificate fingerprint(hash of DER formated certificate)
  * hash function to use shall be the same used by certificate signature(this is a way to ensure that the hash function
@@ -127,7 +163,7 @@ void ms_dtls_srtp_bctbx_context_free(DtlsBcToolBoxContext *ctx) {
  * @return 0 if the fingerprint doesn't match, 1 is they do.
  */
 uint8_t ms_dtls_srtp_check_certificate_fingerprint(const bctbx_x509_certificate_t *certificate,
-                                                   const char *peer_fingerprint) {
+                                                   const std::string &peer_fingerprint) {
 	char fingerprint[256]; /* maximum length of the fingerprint for sha-512: 8+3*64+1 so we're good with 256 bytes
 	                          buffer */
 	bctbx_md_type_t hash_function = BCTBX_MD_UNDEFINED;
@@ -135,18 +171,18 @@ uint8_t ms_dtls_srtp_check_certificate_fingerprint(const bctbx_x509_certificate_
 	int32_t ret = 0;
 
 	/* get Hash algorithm used from peer fingerprint */
-	if (strncasecmp(peer_fingerprint, "sha-1 ", 6) == 0) {
+	if (startsWithCaseInsensitive(peer_fingerprint, "sha-1 ", 6) == 0) {
 		hash_function = BCTBX_MD_SHA1;
-	} else if (strncasecmp(peer_fingerprint, "sha-224 ", 8) == 0) {
+	} else if (startsWithCaseInsensitive(peer_fingerprint, "sha-224 ", 8) == 0) {
 		hash_function = BCTBX_MD_SHA224;
-	} else if (strncasecmp(peer_fingerprint, "sha-256 ", 8) == 0) {
+	} else if (startsWithCaseInsensitive(peer_fingerprint, "sha-256 ", 8) == 0) {
 		hash_function = BCTBX_MD_SHA256;
-	} else if (strncasecmp(peer_fingerprint, "sha-384 ", 8) == 0) {
+	} else if (startsWithCaseInsensitive(peer_fingerprint, "sha-384 ", 8) == 0) {
 		hash_function = BCTBX_MD_SHA384;
-	} else if (strncasecmp(peer_fingerprint, "sha-512 ", 8) == 0) {
+	} else if (startsWithCaseInsensitive(peer_fingerprint, "sha-512 ", 8) == 0) {
 		hash_function = BCTBX_MD_SHA512;
 	} else { /* we have an unknown hash function: return null */
-		ms_error("DTLS-SRTP received invalid peer fingerprint %s, hash function unknown", peer_fingerprint);
+		ms_error("DTLS-SRTP received invalid peer fingerprint %s, hash function unknown", peer_fingerprint.c_str());
 		return 0;
 	}
 
@@ -168,11 +204,11 @@ uint8_t ms_dtls_srtp_check_certificate_fingerprint(const bctbx_x509_certificate_
 	}
 
 	/* compare fingerprints */
-	if (strncasecmp((const char *)fingerprint, peer_fingerprint, strlen((const char *)fingerprint)) == 0) {
+	if (caseInsensitiveCompare(peer_fingerprint, (char *)fingerprint) == 0) {
 		return 1;
 	} else {
-		ms_error("DTLS Handshake successful but fingerprints differ received : %s computed %s", peer_fingerprint,
-		         fingerprint);
+		ms_error("DTLS Handshake successful but fingerprints differ received : %s computed %s",
+		         peer_fingerprint.c_str(), fingerprint);
 		return 0;
 	}
 }
@@ -205,275 +241,24 @@ void schedule_rtp(struct _RtpTransportModifier *t) {
 	if (ctx->retry_sending) {
 		std::lock_guard<std::mutex> lock(ctx->mtx);
 		ctx->retry_sending = false;
-		bctbx_ssl_handshake(ctx->rtp_dtls_context->ssl);
+		bctbx_ssl_handshake(ctx->mDtlsCryptoContext.ssl);
 		return;
 	}
 	/* the retransmission timer increasing value is managed by the crypto lib
 	 * just poke it each 100ms */
 	if (ctx->rtp_time_reference > 0) { /* only when retransmission timer is armed */
 		auto current_time = bctbx_get_cur_time_ms();
-		if (current_time - ctx->rtp_time_reference > DTLS_REPETITION_TIMER_POLL) {
+		if (current_time - ctx->rtp_time_reference > DtlsRepetitionTimerPoll) {
 			std::lock_guard<std::mutex> lock(ctx->mtx);
 			if (ctx->rtp_time_reference >
 			    0) { /* recheck the timer is still armed once we're into the guarded section */
-				bctbx_ssl_handshake(ctx->rtp_dtls_context->ssl);
+				bctbx_ssl_handshake(ctx->mDtlsCryptoContext.ssl);
 				ctx->rtp_time_reference = bctbx_get_cur_time_ms();
 			}
 		}
 	}
 }
 
-void ms_dtls_srtp_set_role_nolock(MSDtlsSrtpContext *context, MSDtlsSrtpRole role);
-void ms_dtls_srtp_start_nolock(MSDtlsSrtpContext *context);
-
-/**
- * Check if the incoming message is a DTLS packet.
- * If it is, store it in the context incoming buffer and call the bctoolbox function wich will process it.
- * This function also manages the client retransmission timer
- *
- * @param[in] 		msg	the incoming message
- * @param[in/out]	ctx	the context containing the incoming buffer to store the DTLS packet
- * @return	the value returned by the bctoolbox function processing the packet(ssl_handshake)
- */
-int ms_dtls_srtp_process_dtls_packet(mblk_t *msg, MSDtlsSrtpContext *ctx) {
-	size_t msgLength = msgdsize(msg);
-	bctbx_ssl_context_t *ssl = ctx->rtp_dtls_context->ssl;
-	uint8_t channel_status = ctx->rtp_channel_status;
-	int ret = 0;
-
-	/* UGLY PATCH CLIENT HELLO PACKET PARSING */
-	const int Content_Type_Index = 0;
-	const int Content_Length_Index = 11;
-	const int Handshake_Type_Index = 13;
-	const int Handshake_Message_Length_Index = 14;
-	const int Handshake_Message_Seq_Index = 17;
-	const int Handshake_Frag_Offset_Index = 19;
-	const int Handshake_Frag_Length_Index = 22;
-	const size_t Handshake_Header_Length = 25;
-	unsigned char *frag = msg->b_rptr;
-	size_t base_index = 0;
-	int message_length = 0;
-	int message_seq = 0;
-	int current_message_seq = -1;
-	int frag_offset = 0;
-	int frag_length = 0;
-	unsigned char *reassembled_packet = NULL;
-	/* end of UGLY PATCH CLIENT HELLO PACKET PARSING */
-
-	DtlsRawPacket *incoming_dtls_packet;
-	incoming_dtls_packet = (DtlsRawPacket *)ms_malloc0(sizeof(DtlsRawPacket));
-	incoming_dtls_packet->next = NULL;
-	incoming_dtls_packet->data = (unsigned char *)ms_malloc(msgLength);
-	incoming_dtls_packet->length = msgLength;
-	memcpy(incoming_dtls_packet->data, msg->b_rptr, msgLength);
-
-	/*required by webrtc in server case when ice is not completed yet*/
-	/* no more required because change is performed by ice.c once a check list is ready
-	 * rtp_session_update_remote_sock_addr(rtp_session, msg,is_rtp,FALSE);*/
-
-	ms_message("DTLS Receive RTP packet len %d sessions: %p rtp session %p", (int)msgLength, ctx->stream_sessions,
-	           ctx->stream_sessions->rtp_session);
-
-	/* UGLY PATCH CLIENT HELLO PACKET PARSING */
-	/* Parse the DTLS packet to check if we have a Client Hello packet fragmented at DTLS level but all set in one
-	 * datagram (some kind of bug in certain versions openssl produce that and mbedtls does not support Client Hello
-	 * fragmentation ) This patch is not very resistant to any change and target that very particular situation, a
-	 * better solution should be to implement support of Client Hello Fragmentation in mbedtls */
-	if (msgLength > Handshake_Header_Length && frag[Content_Type_Index] == 0x16 &&
-	    frag[Handshake_Type_Index] ==
-	        0x01) { // If the first fragment(there may be only one) is of a DTLS Handshake Client Hello message
-		while (base_index + Handshake_Header_Length <
-		       msgLength) { // loop on the message, parsing all fragments it may contain (loop until we have at
-			                // least enough unparsed byte to read a handshake header)
-			if (frag[Content_Type_Index] == 0x16) {       // Type index 0x16 is DLTS Handshake message
-				if (frag[Handshake_Type_Index] == 0x01) { // Handshake type 0x01 is Client Hello
-					// Get message length
-					message_length = frag[Handshake_Message_Length_Index] << 16 |
-					                 frag[Handshake_Message_Length_Index + 1] << 8 |
-					                 frag[Handshake_Message_Length_Index + 2];
-
-					// message sequence number
-					message_seq = frag[Handshake_Message_Seq_Index] << 8 | frag[Handshake_Message_Seq_Index + 1];
-					if (current_message_seq == -1) {
-						current_message_seq = message_seq;
-					}
-
-					// fragment offset
-					frag_offset = frag[Handshake_Frag_Offset_Index] << 16 | frag[Handshake_Frag_Offset_Index + 1] << 8 |
-					              frag[Handshake_Frag_Offset_Index + 2];
-
-					// and fragment length
-					frag_length = frag[Handshake_Frag_Length_Index] << 16 | frag[Handshake_Frag_Length_Index + 1] << 8 |
-					              frag[Handshake_Frag_Length_Index + 2];
-
-					// check the message is not malformed and would lead us to read after the message buffer
-					// or write after our reassembled packet buffer
-					if (base_index + Handshake_Header_Length + frag_length <=
-					        msgLength // we will read frag_length starting at base_index (frag in the code)+ header
-					    && frag_length + frag_offset <=
-					           message_length) { // we will write in the reassembled buffer frag_length byte,
-						                         // starting at frag_offset, the buffer is message_length long
-
-						// If message length and fragment length differs, we have a fragmented Client Hello
-						// Check they are part of the same message (message_seq)
-						// We will just collect all fragments (in our very particuliar case, they are all in the
-						// same datagram so we do not need long term storage, juste parsing this packet)
-						if (message_length != frag_length && message_seq == current_message_seq) {
-							if (reassembled_packet == NULL) { // this is first fragment we get
-								reassembled_packet =
-								    (unsigned char *)ms_malloc(Handshake_Header_Length + message_length);
-								// copy the header
-								memcpy(reassembled_packet, msg->b_rptr, Handshake_Header_Length);
-								// set the message length to be in line with reassembled fragments
-								reassembled_packet[Content_Length_Index] = ((message_length + 12) >> 8) & 0xFF;
-								reassembled_packet[Content_Length_Index + 1] = (message_length + 12) & 0xFF;
-
-								// set the frag length to be the same than message length
-								reassembled_packet[Handshake_Frag_Length_Index] =
-								    reassembled_packet[Handshake_Message_Length_Index];
-								reassembled_packet[Handshake_Frag_Length_Index + 1] =
-								    reassembled_packet[Handshake_Message_Length_Index + 1];
-								reassembled_packet[Handshake_Frag_Length_Index + 2] =
-								    reassembled_packet[Handshake_Message_Length_Index + 2];
-							}
-							// copy the received fragment
-							memcpy(reassembled_packet + Handshake_Header_Length + frag_offset,
-							       frag + Handshake_Header_Length, frag_length);
-						}
-
-						// read what is next in the datagram
-						base_index += Handshake_Header_Length + frag_length; // bytes parsed so far
-						frag += Handshake_Header_Length + frag_length; // point to the begining of the next fragment
-					} else {                                           // message is malformed in a nasty way
-						ms_warning("DTLS Received RTP packet len %d sessions: %p rtp session %p is malformed in an "
-						           "agressive way",
-						           (int)msgLength, ctx->stream_sessions, ctx->stream_sessions->rtp_session);
-						base_index = msgLength; // get out of the while
-						ms_free(reassembled_packet);
-						reassembled_packet = NULL;
-					}
-				} else {
-					base_index = msgLength; // get out of the while
-					ms_free(reassembled_packet);
-					reassembled_packet = NULL;
-				}
-			}
-		}
-	}
-	// if we made a reassembled client hello packet, use this one as incoming dlts packet and discard the original
-	// one
-	if (reassembled_packet != NULL) {
-		ms_message("DTLS re-assembled a fragmented Client Hello packet");
-		ms_free(incoming_dtls_packet->data);
-		incoming_dtls_packet->data = (unsigned char *)ms_malloc(Handshake_Header_Length + message_length);
-		incoming_dtls_packet->length = Handshake_Header_Length + message_length;
-		memcpy(incoming_dtls_packet->data, reassembled_packet, Handshake_Header_Length + message_length);
-		ms_free(reassembled_packet);
-	}
-	/* end of UGLY PATCH CLIENT HELLO PACKET PARSING */
-
-	/* store the packet in the incoming buffer */
-	if (ctx->rtp_incoming_buffer == NULL) { /* buffer is empty */
-		ctx->rtp_incoming_buffer = incoming_dtls_packet;
-	} else { /* queue it at the end of current buffer */
-		DtlsRawPacket *last_packet = ctx->rtp_incoming_buffer;
-		while (last_packet->next != NULL)
-			last_packet = (DtlsRawPacket *)(last_packet->next);
-		last_packet->next = incoming_dtls_packet;
-	}
-
-	/* while DTLS handshake is on going route DTLS packets to bctoolbox engine through ssl_handshake() */
-	if (channel_status < DTLS_STATUS_HANDSHAKE_OVER) {
-		/* role is unset but we receive a packet: we are caller and shall initialise as server and then process the
-		 * incoming packet */
-		if (ctx->role == MSDtlsSrtpRoleUnset) {
-			ms_dtls_srtp_set_role_nolock(
-			    ctx, MSDtlsSrtpRoleIsServer); /* this call will update role and complete server setup */
-			ms_dtls_srtp_start_nolock(
-			    ctx); /* complete the ssl setup and change channel_status to DTLS_STATUS_HANDSHAKE_ONGOING */
-			ssl = ctx->rtp_dtls_context->ssl;
-		}
-		/* process the packet and store result */
-		ret = bctbx_ssl_handshake(ssl);
-		ms_message("DTLS Handshake process RTP packet len %d sessions: %p rtp session %p return %s0x%0x",
-		           (int)msgLength, ctx->stream_sessions, ctx->stream_sessions->rtp_session, ret > 0 ? "+" : "-",
-		           ret > 0 ? ret : -ret);
-
-		/* if we are client, manage the retransmission timer */
-		if (ctx->role == MSDtlsSrtpRoleIsClient) {
-			ctx->rtp_time_reference = bctbx_get_cur_time_ms();
-		}
-	} else { /* when DTLS handshake is over, route DTLS packets to bctoolbox engine through ssl_read() */
-		/* we need a buffer to store the message read even if we don't use it */
-		unsigned char *buf = (unsigned char *)ms_malloc(msgLength + 1);
-		ret = bctbx_ssl_read(ssl, buf, msgLength);
-		ms_message("DTLS Handshake read RTP packet len %d sessions: %p rtp session %p return %s0x%0x", (int)msgLength,
-		           ctx->stream_sessions, ctx->stream_sessions->rtp_session, ret > 0 ? "+" : "-", ret > 0 ? ret : -ret);
-		ms_free(buf);
-	}
-
-	/* report the error in logs only when different than requested read(waiting for data) */
-	if (ret < 0 && ret != BCTBX_ERROR_NET_WANT_READ) {
-		char err_str[512];
-		err_str[0] = '\0';
-		bctbx_strerror(ret, err_str, 512);
-		ms_warning("DTLS Handshake returns -0x%x : %s [on sessions: %p rtp session %p]", -ret, err_str,
-		           ctx->stream_sessions, ctx->stream_sessions->rtp_session);
-	}
-	return ret;
-}
-
-void ms_dtls_srtp_check_channels_status(MSDtlsSrtpContext *ctx) {
-	/* Check if we're are ready: rtp_channel done and rtcp mux on */
-	if ((ctx->rtp_channel_status == DTLS_STATUS_FINGERPRINT_VERIFIED) &&
-	    (rtp_session_rtcp_mux_enabled(ctx->stream_sessions->rtp_session))) {
-		OrtpEventData *eventData;
-		OrtpEvent *ev;
-		ev = ortp_event_new(ORTP_EVENT_DTLS_ENCRYPTION_CHANGED);
-		eventData = ortp_event_get_data(ev);
-		eventData->info.dtls_stream_encrypted = 1;
-		rtp_session_dispatch_event(ctx->stream_sessions->rtp_session, ev);
-		ms_message("DTLS Event dispatched to all: secrets are on for this stream");
-	}
-}
-
-/* Get keys from context and set then in the SRTP context according to the given stream type
- *
- * @param	ctx		Pointer to the MSDtlsSrtpContext structure
- */
-void ms_dtls_srtp_set_srtp_key_material(MSDtlsSrtpContext *ctx) {
-
-	uint8_t key[256];
-	MSCryptoSuite srtp_protection_profile = MS_CRYPTO_SUITE_INVALID;
-	uint8_t *key_material;
-
-	srtp_protection_profile = ctx->rtp_agreed_srtp_protection_profile;
-	key_material = ctx->rtp_channel_key_material;
-
-	if (ctx->role == MSDtlsSrtpRoleIsServer) {
-		/* reception(client write) key and salt +16bits padding */
-		memcpy(key, key_material, DTLS_SRTP_KEY_LEN);
-		memcpy(key + DTLS_SRTP_KEY_LEN, key_material + 2 * DTLS_SRTP_KEY_LEN, DTLS_SRTP_SALT_LEN);
-		ms_media_stream_sessions_set_srtp_recv_key(ctx->stream_sessions, srtp_protection_profile, key,
-		                                           DTLS_SRTP_KEY_LEN + DTLS_SRTP_SALT_LEN, MSSrtpKeySourceDTLS);
-		/* emission(server write) key and salt +16bits padding */
-		memcpy(key, key_material + DTLS_SRTP_KEY_LEN, DTLS_SRTP_KEY_LEN);
-		memcpy(key + DTLS_SRTP_KEY_LEN, key_material + 2 * DTLS_SRTP_KEY_LEN + DTLS_SRTP_SALT_LEN, DTLS_SRTP_SALT_LEN);
-		ms_media_stream_sessions_set_srtp_send_key(ctx->stream_sessions, srtp_protection_profile, key,
-		                                           DTLS_SRTP_KEY_LEN + DTLS_SRTP_SALT_LEN, MSSrtpKeySourceDTLS);
-	} else if (ctx->role == MSDtlsSrtpRoleIsClient) { /* this enpoint act as DTLS client */
-		/* emission(client write) key and salt +16bits padding */
-		memcpy(key, key_material, DTLS_SRTP_KEY_LEN);
-		memcpy(key + DTLS_SRTP_KEY_LEN, key_material + 2 * DTLS_SRTP_KEY_LEN, DTLS_SRTP_SALT_LEN);
-		ms_media_stream_sessions_set_srtp_send_key(ctx->stream_sessions, srtp_protection_profile, key,
-		                                           DTLS_SRTP_KEY_LEN + DTLS_SRTP_SALT_LEN, MSSrtpKeySourceDTLS);
-		/* reception(server write) key and salt +16bits padding */
-		memcpy(key, key_material + DTLS_SRTP_KEY_LEN, DTLS_SRTP_KEY_LEN);
-		memcpy(key + DTLS_SRTP_KEY_LEN, key_material + 2 * DTLS_SRTP_KEY_LEN + DTLS_SRTP_SALT_LEN, DTLS_SRTP_SALT_LEN);
-		ms_media_stream_sessions_set_srtp_recv_key(ctx->stream_sessions, srtp_protection_profile, key,
-		                                           DTLS_SRTP_KEY_LEN + DTLS_SRTP_SALT_LEN, MSSrtpKeySourceDTLS);
-	}
-}
 /********************************************/
 /**** bctoolbox DTLS packet I/O functions ****/
 
@@ -493,13 +278,13 @@ void ms_dtls_srtp_set_srtp_key_material(MSDtlsSrtpContext *ctx) {
  */
 int ms_dtls_srtp_rtp_sendData(void *ctx, const unsigned char *data, size_t length) {
 	MSDtlsSrtpContext *context = (MSDtlsSrtpContext *)ctx;
-	RtpSession *session = context->stream_sessions->rtp_session;
+	RtpSession *session = context->mStreamSessions->rtp_session;
 	RtpTransport *rtpt = NULL;
 	mblk_t *msg;
 	int ret;
 
-	ms_message("DTLS Send RTP packet len %d sessions: %p rtp session %p", (int)length, context->stream_sessions,
-	           context->stream_sessions->rtp_session);
+	ms_message("DTLS Send RTP packet len %d sessions: %p rtp session %p", (int)length, context->mStreamSessions,
+	           context->mStreamSessions->rtp_session);
 
 	/* get RTP transport from session */
 	rtp_session_get_transports(session, &rtpt, NULL);
@@ -513,28 +298,30 @@ int ms_dtls_srtp_rtp_sendData(void *ctx, const unsigned char *data, size_t lengt
 	/* sending failed - allow to retry at the next schedule tick */
 	if (ret < 0) {
 		ms_warning("DTLS Send RTP packet len %d sessions: %p rtp session %p failed returns %d", (int)length,
-		           context->stream_sessions, context->stream_sessions->rtp_session, ret);
+		           context->mStreamSessions, context->mStreamSessions->rtp_session, ret);
 		context->retry_sending = true;
 		return BCTBX_ERROR_NET_WANT_WRITE;
 	}
 	return ret;
 }
 
-int ms_dtls_srtp_rtp_DTLSread(void *ctx, unsigned char *buf, BCTBX_UNUSED(size_t len)) {
+int ms_dtls_srtp_rtp_DTLSread(void *ctx, unsigned char *buf, size_t len) {
 	MSDtlsSrtpContext *context = (MSDtlsSrtpContext *)ctx;
 
 	/* do we have something in the incoming buffer */
-	if (context->rtp_incoming_buffer == NULL) {
+	if (context->mRtpIncomingBuffer.empty()) {
 		return BCTBX_ERROR_NET_WANT_READ;
-	} else { /* read the first packet in the buffer and delete it */
-		DtlsRawPacket *next_packet = (DtlsRawPacket *)(context->rtp_incoming_buffer->next);
-		size_t dataLength = context->rtp_incoming_buffer->length;
-		memcpy(buf, context->rtp_incoming_buffer->data, dataLength);
-		ms_free(context->rtp_incoming_buffer->data);
-		ms_free(context->rtp_incoming_buffer);
-		context->rtp_incoming_buffer = next_packet;
-
-		return (int)dataLength;
+	} else { /* read the first packet in the buffer */
+		auto packet = context->mRtpIncomingBuffer.front();
+		auto packetSize = packet.size();
+		if (packet.size() > len) {
+			ms_error("DTLS wants to read incoming packet of size %d but provides a buffer size %d to read it",
+			         (int)(packetSize), (int)(len));
+			return BCTBX_ERROR_NET_WANT_READ;
+		}
+		memcpy(buf, packet.data(), packetSize);
+		context->mRtpIncomingBuffer.pop(); // remove the packet from incoming buffer
+		return (int)packetSize;
 	}
 }
 
@@ -547,7 +334,7 @@ int ms_dtls_srtp_rtp_process_on_receive(struct _RtpTransportModifier *t, mblk_t
 	size_t msgLength = msgdsize(msg);
 
 	/* check if we have an on-going handshake */
-	if (ctx->rtp_channel_status == DTLS_STATUS_CONTEXT_NOT_READY) {
+	if (ctx->mChannelStatus == DtlsStatus::ContextNotReady) {
 		return (int)msgLength;
 	}
 
@@ -563,27 +350,27 @@ int ms_dtls_srtp_rtp_process_on_receive(struct _RtpTransportModifier *t, mblk_t
 
 	std::lock_guard<std::mutex> lock(ctx->mtx);
 	/* process it */
-	int ret = ms_dtls_srtp_process_dtls_packet(msg, ctx);
+	int ret = ctx->processDtlsPacket(msg);
 	if ((ret == 0) &&
-	    (ctx->rtp_channel_status ==
-	     DTLS_STATUS_HANDSHAKE_ONGOING)) { /* handshake is over, give the keys to srtp : 128 bits client write - 128
+	    (ctx->mChannelStatus ==
+	     DtlsStatus::HandshakeOngoing)) { /* handshake is over, give the keys to srtp : 128 bits client write - 128
 		                                      bits server write - 112 bits client salt - 112 server salt */
-		ctx->rtp_channel_status = DTLS_STATUS_HANDSHAKE_OVER;
+		ctx->mChannelStatus = DtlsStatus::HandshakeOver;
 
 		/* check the srtp profile get selected during handshake */
-		ctx->rtp_agreed_srtp_protection_profile = ms_dtls_srtp_bctbx_protection_profile_to_ms_crypto_suite(
-		    bctbx_ssl_get_dtls_srtp_protection_profile(ctx->rtp_dtls_context->ssl));
-		if (ctx->rtp_agreed_srtp_protection_profile == MS_CRYPTO_SUITE_INVALID) {
+		ctx->mSrtpProtectionProfile = ms_dtls_srtp_bctbx_protection_profile_to_ms_crypto_suite(
+		    bctbx_ssl_get_dtls_srtp_protection_profile(ctx->mDtlsCryptoContext.ssl));
+		if (ctx->mSrtpProtectionProfile == MS_CRYPTO_SUITE_INVALID) {
 			ms_message("DTLS RTP handshake successful but unable to agree on srtp_profile to use");
 			return 0;
 		} else {
 			/* Get key material generated by DTLS handshake */
-			size_t dtls_srtp_key_material_length = DTLS_SRTP_KEY_MATERIAL_LEN;
+			size_t dtls_srtp_key_material_length = ctx->mSrtpKeyMaterial.size();
 			ms_message("DTLS Handshake on RTP channel successful, srtp protection profile %d",
-			           ctx->rtp_agreed_srtp_protection_profile);
+			           ctx->mSrtpProtectionProfile);
 
 			ctx->rtp_time_reference = 0; /* unarm the timer */
-			ret = bctbx_ssl_get_dtls_srtp_key_material(ctx->rtp_dtls_context->ssl, ctx->rtp_channel_key_material,
+			ret = bctbx_ssl_get_dtls_srtp_key_material(ctx->mDtlsCryptoContext.ssl, ctx->mSrtpKeyMaterial.data(),
 			                                           &dtls_srtp_key_material_length);
 			if (ret < 0) {
 				ms_error("DTLS RTP Handshake : Unable to retrieve DTLS SRTP key material [-0x%x]", -ret);
@@ -591,23 +378,23 @@ int ms_dtls_srtp_rtp_process_on_receive(struct _RtpTransportModifier *t, mblk_t
 			}
 
 			/* Check certificate fingerprint */
-			if (ctx->peer_fingerprint[0] == '\0') { /* fingerprint not set yet - peer's 200Ok didn't arrived yet */
-				ms_warning("DTLS-SRTP: RTP empty peer_fingerprint - waiting for it");
+			if (ctx->mPeerFingerprint.empty()) { /* fingerprint not set yet - peer's 200Ok didn't arrived yet */
+				ms_warning("DTLS-SRTP: RTP empty peer fingerprint - waiting for it");
 				return 0;
 			}
 
-			if (ms_dtls_srtp_check_certificate_fingerprint(bctbx_ssl_get_peer_certificate(ctx->rtp_dtls_context->ssl),
-			                                               (const char *)(ctx->peer_fingerprint)) == 1) {
-				ms_dtls_srtp_set_srtp_key_material(ctx);
-				ctx->rtp_channel_status = DTLS_STATUS_FINGERPRINT_VERIFIED;
-				ms_dtls_srtp_check_channels_status(ctx);
+			if (ms_dtls_srtp_check_certificate_fingerprint(bctbx_ssl_get_peer_certificate(ctx->mDtlsCryptoContext.ssl),
+			                                               ctx->mPeerFingerprint) == 1) {
+				ctx->setKeyMaterial();
+				ctx->mChannelStatus = DtlsStatus::FingerprintVerified;
+				ctx->checkChannelStatus();
 			}
 		}
 
-		if (ctx->role != MSDtlsSrtpRoleIsServer) { /* close the connection only if we are client, if we are server,
+		if (ctx->mRole != MSDtlsSrtpRoleIsServer) { /* close the connection only if we are client, if we are server,
 			                                          the client may ask again for last packets */
 			/*FireFox version 43 requires DTLS channel to be kept openned, probably a bug in FireFox ret =
-			 * ssl_close_notify( &(ctx->rtp_dtls_context->ssl) );*/
+			 * ssl_close_notify( &(ctx->mDtlsCryptoContext.ssl) );*/
 		}
 	}
 	return 0;
@@ -626,7 +413,7 @@ void ms_dtls_srtp_transport_modifier_destroy(RtpTransportModifier *tp) {
 int ms_dtls_srtp_transport_modifier_new(MSDtlsSrtpContext *ctx, RtpTransportModifier **rtpt) {
 	if (rtpt) {
 		*rtpt = ms_new0(RtpTransportModifier, 1);
-		(*rtpt)->data = ctx; /* back link to get access to the other fields of the OrtoZrtpContext from the
+		(*rtpt)->data = ctx; /* back link to get access to the other fields of the MSDtlsSrtpContext from the
 		                        RtpTransportModifier structure */
 		(*rtpt)->t_process_on_send = ms_dtls_srtp_rtp_process_on_send;
 		(*rtpt)->t_process_on_receive = ms_dtls_srtp_rtp_process_on_receive;
@@ -636,138 +423,353 @@ int ms_dtls_srtp_transport_modifier_new(MSDtlsSrtpContext *ctx, RtpTransportModi
 	return 0;
 }
 
-void ms_dtls_srtp_set_transport(MSDtlsSrtpContext *userData, RtpSession *s) {
+void ms_dtls_srtp_set_transport(MSDtlsSrtpContext *ctx, RtpSession *s) {
 	RtpTransport *rtpt = NULL;
 	RtpTransportModifier *rtp_modifier;
 
 	rtp_session_get_transports(s, &rtpt, NULL);
-
-	ms_dtls_srtp_transport_modifier_new(userData, &rtp_modifier);
-
+	ms_dtls_srtp_transport_modifier_new(ctx, &rtp_modifier);
 	meta_rtp_transport_append_modifier(rtpt, rtp_modifier);
-
 	/* save transport modifier into context, needed to inject packets generated by DTLS */
-	userData->rtp_modifier = rtp_modifier;
+	ctx->rtp_modifier = rtp_modifier;
 }
+} // anonymous namespace
 
-int ms_dtls_srtp_initialise_bctbx_dtls_context(DtlsBcToolBoxContext *dtlsContext, MSDtlsSrtpParams *params) {
+/***********************************************/
+/***** MSDtlsSrtpContext methods           *****/
+/***********************************************/
+int MSDtlsSrtpContext::initialiseDtlsCryptoContext(MSDtlsSrtpParams *params) {
 	int ret;
 	bctbx_dtls_srtp_profile_t dtls_srtp_protection_profiles[2] = {BCTBX_SRTP_AES128_CM_HMAC_SHA1_80,
 	                                                              BCTBX_SRTP_AES128_CM_HMAC_SHA1_32};
 
 	/* initialise certificate */
-	ret = bctbx_x509_certificate_parse(dtlsContext->crt, (const char *)params->pem_certificate,
+	ret = bctbx_x509_certificate_parse(mDtlsCryptoContext.crt, (const char *)params->pem_certificate,
 	                                   strlen(params->pem_certificate) + 1);
 	if (ret < 0) {
 		return ret;
 	}
 
-	ret = bctbx_signing_key_parse(dtlsContext->pkey, (const char *)params->pem_pkey, strlen(params->pem_pkey) + 1, NULL,
-	                              0);
+	ret = bctbx_signing_key_parse(mDtlsCryptoContext.pkey, (const char *)params->pem_pkey, strlen(params->pem_pkey) + 1,
+	                              NULL, 0);
 	if (ret != 0) {
 		return ret;
 	}
 
 	/* configure ssl */
 	if (params->role == MSDtlsSrtpRoleIsClient) {
-		bctbx_ssl_config_defaults(dtlsContext->ssl_config, BCTBX_SSL_IS_CLIENT, BCTBX_SSL_TRANSPORT_DATAGRAM);
+		bctbx_ssl_config_defaults(mDtlsCryptoContext.ssl_config, BCTBX_SSL_IS_CLIENT, BCTBX_SSL_TRANSPORT_DATAGRAM);
 	} else { /* configure it by default as server, nothing is actually performed until we start the channel but this
 		        helps to get correct defaults settings */
-		bctbx_ssl_config_defaults(dtlsContext->ssl_config, BCTBX_SSL_IS_SERVER, BCTBX_SSL_TRANSPORT_DATAGRAM);
+		bctbx_ssl_config_defaults(mDtlsCryptoContext.ssl_config, BCTBX_SSL_IS_SERVER, BCTBX_SSL_TRANSPORT_DATAGRAM);
 	}
 
 	bctbx_ssl_config_set_dtls_srtp_protection_profiles(
-	    dtlsContext->ssl_config, dtls_srtp_protection_profiles,
+	    mDtlsCryptoContext.ssl_config, dtls_srtp_protection_profiles,
 	    2); /* TODO: get param from caller to select available profiles */
 
-	bctbx_ssl_config_set_rng(dtlsContext->ssl_config, (int (*)(void *, unsigned char *, size_t))bctbx_rng_get,
-	                         dtlsContext->rng);
+	bctbx_ssl_config_set_rng(mDtlsCryptoContext.ssl_config, (int (*)(void *, unsigned char *, size_t))bctbx_rng_get,
+	                         mDtlsCryptoContext.rng);
 
 	/* set certificates */
 	/* this will force server to send his certificate to client as we need it to compute the fingerprint even if we
 	 * won't verify it */
-	bctbx_ssl_config_set_authmode(dtlsContext->ssl_config, BCTBX_SSL_VERIFY_OPTIONAL);
-	bctbx_ssl_config_set_own_cert(dtlsContext->ssl_config, dtlsContext->crt, dtlsContext->pkey);
+	bctbx_ssl_config_set_authmode(mDtlsCryptoContext.ssl_config, BCTBX_SSL_VERIFY_OPTIONAL);
+	bctbx_ssl_config_set_own_cert(mDtlsCryptoContext.ssl_config, mDtlsCryptoContext.crt, mDtlsCryptoContext.pkey);
 	/* This is useless as peer would certainly be a self signed certificate and we won't verify it but avoid runtime
 	 * warnings */
-	bctbx_ssl_config_set_ca_chain(dtlsContext->ssl_config, dtlsContext->crt);
+	bctbx_ssl_config_set_ca_chain(mDtlsCryptoContext.ssl_config, mDtlsCryptoContext.crt);
 
 	/* we are not ready yet to actually start the ssl context, this will be done by calling bctbx_ssl_context_setup when
 	 * stream starts */
 	return 0;
 }
-void ms_dtls_srtp_create_ssl_context(MSDtlsSrtpContext *context) {
-	ms_message("DTLS create a new ssl context on stream session %p", context->stream_sessions);
-	/* create the ssl context for this connection */
-	if (context->rtp_dtls_context->ssl != NULL) {
-		bctbx_ssl_context_free(context->rtp_dtls_context->ssl);
-	}
-	context->rtp_dtls_context->ssl = bctbx_ssl_context_new();
-}
 
-void ms_dtls_srtp_set_role_nolock(MSDtlsSrtpContext *context, MSDtlsSrtpRole role) {
+void MSDtlsSrtpContext::setRole(MSDtlsSrtpRole role) {
 	/* if role has changed and handshake already setup and going, reset the session */
-	if (context->role != role) {
-		if ((context->rtp_channel_status == DTLS_STATUS_HANDSHAKE_ONGOING) ||
-		    (context->rtp_channel_status == DTLS_STATUS_HANDSHAKE_OVER)) {
-			bctbx_ssl_session_reset(context->rtp_dtls_context->ssl);
+	if (mRole != role) {
+		if ((mChannelStatus == DtlsStatus::HandshakeOngoing) || (mChannelStatus == DtlsStatus::HandshakeOver)) {
+			bctbx_ssl_session_reset(mDtlsCryptoContext.ssl);
 		}
 	} else {
 		return;
 	}
 
-	/* if role is isServer and was Unset, we must complete the server setup */
-	if (((context->role == MSDtlsSrtpRoleIsClient) || (context->role == MSDtlsSrtpRoleUnset)) &&
-	    (role == MSDtlsSrtpRoleIsServer)) {
-		bctbx_ssl_config_set_endpoint(context->rtp_dtls_context->ssl_config, BCTBX_SSL_IS_SERVER);
+	/* if role is server and was Unset or Client, we must complete the server setup */
+	if (((mRole == MSDtlsSrtpRoleIsClient) || (mRole == MSDtlsSrtpRoleUnset)) && (role == MSDtlsSrtpRoleIsServer)) {
+		bctbx_ssl_config_set_endpoint(mDtlsCryptoContext.ssl_config, BCTBX_SSL_IS_SERVER);
 	}
 	ms_message("DTLS set role from [%s] to [%s] for context [%p]",
-	           context->role == MSDtlsSrtpRoleIsServer
-	               ? "server"
-	               : (context->role == MSDtlsSrtpRoleIsClient ? "client" : "unset role"),
+	           mRole == MSDtlsSrtpRoleIsServer ? "server" : (mRole == MSDtlsSrtpRoleIsClient ? "client" : "unset role"),
 	           role == MSDtlsSrtpRoleIsServer ? "server" : (role == MSDtlsSrtpRoleIsClient ? "client" : "unset role"),
-	           context);
-	context->role = role;
+	           this);
+	mRole = role;
 }
 
-void ms_dtls_srtp_start_nolock(MSDtlsSrtpContext *context) {
+void MSDtlsSrtpContext::createSslContext() {
+	ms_message("DTLS create a new ssl context on stream session %p", mStreamSessions);
+	/* create the ssl context for this connection */
+	if (mDtlsCryptoContext.ssl != NULL) {
+		bctbx_ssl_context_free(mDtlsCryptoContext.ssl);
+	}
+	mDtlsCryptoContext.ssl = bctbx_ssl_context_new();
+}
 
-	ms_message(
-	    "DTLS start stream on stream sessions [%p], RTCP mux is %s, MTU is %d, role is %s", context->stream_sessions,
-	    rtp_session_rtcp_mux_enabled(context->stream_sessions->rtp_session) ? "enabled" : "disabled", context->mtu,
-	    context->role == MSDtlsSrtpRoleIsServer ? "server"
-	                                            : (context->role == MSDtlsSrtpRoleIsClient ? "client" : "unset role"));
+void MSDtlsSrtpContext::start() {
+	ms_message("DTLS start stream on stream sessions [%p], RTCP mux is %s, MTU is %d, role is %s", mStreamSessions,
+	           rtp_session_rtcp_mux_enabled(mStreamSessions->rtp_session) ? "enabled" : "disabled", mtu,
+	           mRole == MSDtlsSrtpRoleIsServer ? "server"
+	                                           : (mRole == MSDtlsSrtpRoleIsClient ? "client" : "unset role"));
 
 	/* if we are client, start the handshake(send a clientHello) */
-	if (context->role == MSDtlsSrtpRoleIsClient) {
-		ms_dtls_srtp_create_ssl_context(context);
-		bctbx_ssl_config_set_endpoint(context->rtp_dtls_context->ssl_config, BCTBX_SSL_IS_CLIENT);
+	if (mRole == MSDtlsSrtpRoleIsClient) {
+		createSslContext();
+		bctbx_ssl_config_set_endpoint(mDtlsCryptoContext.ssl_config, BCTBX_SSL_IS_CLIENT);
 		/* complete ssl setup*/
-		bctbx_ssl_context_setup(context->rtp_dtls_context->ssl, context->rtp_dtls_context->ssl_config);
-		bctbx_ssl_set_io_callbacks(context->rtp_dtls_context->ssl, context, ms_dtls_srtp_rtp_sendData,
-		                           ms_dtls_srtp_rtp_DTLSread);
-		bctbx_ssl_set_mtu(context->rtp_dtls_context->ssl, context->mtu);
+		bctbx_ssl_context_setup(mDtlsCryptoContext.ssl, mDtlsCryptoContext.ssl_config);
+		bctbx_ssl_set_io_callbacks(mDtlsCryptoContext.ssl, this, ms_dtls_srtp_rtp_sendData, ms_dtls_srtp_rtp_DTLSread);
+		bctbx_ssl_set_mtu(mDtlsCryptoContext.ssl, mtu);
 		/* and start the handshake */
-		bctbx_ssl_handshake(context->rtp_dtls_context->ssl);
-		context->rtp_time_reference = bctbx_get_cur_time_ms(); /* arm the timer for retransmission */
-		context->rtp_channel_status = DTLS_STATUS_HANDSHAKE_ONGOING;
+		bctbx_ssl_handshake(mDtlsCryptoContext.ssl);
+		rtp_time_reference = bctbx_get_cur_time_ms(); /* arm the timer for retransmission */
+		mChannelStatus = DtlsStatus::HandshakeOngoing;
 	}
 
 	/* if we are server and we didn't started yet the DTLS engine, do it now */
-	if (context->role == MSDtlsSrtpRoleIsServer) {
-		if (context->rtp_channel_status == DTLS_STATUS_CONTEXT_READY) {
-			ms_dtls_srtp_create_ssl_context(context);
-			bctbx_ssl_config_set_endpoint(context->rtp_dtls_context->ssl_config, BCTBX_SSL_IS_SERVER);
+	if (mRole == MSDtlsSrtpRoleIsServer) {
+		if (mChannelStatus == DtlsStatus::ContextReady) {
+			createSslContext();
+			bctbx_ssl_config_set_endpoint(mDtlsCryptoContext.ssl_config, BCTBX_SSL_IS_SERVER);
 			/* complete ssl setup*/
-			bctbx_ssl_context_setup(context->rtp_dtls_context->ssl, context->rtp_dtls_context->ssl_config);
-			bctbx_ssl_set_io_callbacks(context->rtp_dtls_context->ssl, context, ms_dtls_srtp_rtp_sendData,
+			bctbx_ssl_context_setup(mDtlsCryptoContext.ssl, mDtlsCryptoContext.ssl_config);
+			bctbx_ssl_set_io_callbacks(mDtlsCryptoContext.ssl, this, ms_dtls_srtp_rtp_sendData,
 			                           ms_dtls_srtp_rtp_DTLSread);
-			bctbx_ssl_set_mtu(context->rtp_dtls_context->ssl, context->mtu);
-			context->rtp_channel_status = DTLS_STATUS_HANDSHAKE_ONGOING;
+			bctbx_ssl_set_mtu(mDtlsCryptoContext.ssl, mtu);
+			mChannelStatus = DtlsStatus::HandshakeOngoing;
+		}
+	}
+}
+
+void MSDtlsSrtpContext::checkChannelStatus() {
+	/* Check if we're are ready: rtp_channel done and rtcp mux on */
+	if ((mChannelStatus == DtlsStatus::FingerprintVerified) &&
+	    (rtp_session_rtcp_mux_enabled(mStreamSessions->rtp_session))) {
+		OrtpEventData *eventData;
+		OrtpEvent *ev;
+		ev = ortp_event_new(ORTP_EVENT_DTLS_ENCRYPTION_CHANGED);
+		eventData = ortp_event_get_data(ev);
+		eventData->info.dtls_stream_encrypted = 1;
+		rtp_session_dispatch_event(mStreamSessions->rtp_session, ev);
+		ms_message("DTLS Event dispatched to all: secrets are on for this stream");
+	}
+}
+
+/* Get keys from context and set then in the SRTP context according to the given stream type
+ */
+void MSDtlsSrtpContext::setKeyMaterial() {
+
+	uint8_t key[256];
+	uint8_t *key_material = mSrtpKeyMaterial.data();
+
+	if (mRole == MSDtlsSrtpRoleIsServer) {
+		/* reception(client write) key and salt +16bits padding */
+		memcpy(key, key_material, DtlsSrtpKeyLen);
+		memcpy(key + DtlsSrtpKeyLen, key_material + 2 * DtlsSrtpKeyLen, DtlsSrtpSaltLen);
+		ms_media_stream_sessions_set_srtp_recv_key(mStreamSessions, mSrtpProtectionProfile, key,
+		                                           DtlsSrtpKeyLen + DtlsSrtpSaltLen, MSSrtpKeySourceDTLS);
+		/* emission(server write) key and salt +16bits padding */
+		memcpy(key, key_material + DtlsSrtpKeyLen, DtlsSrtpKeyLen);
+		memcpy(key + DtlsSrtpKeyLen, key_material + 2 * DtlsSrtpKeyLen + DtlsSrtpSaltLen, DtlsSrtpSaltLen);
+		ms_media_stream_sessions_set_srtp_send_key(mStreamSessions, mSrtpProtectionProfile, key,
+		                                           DtlsSrtpKeyLen + DtlsSrtpSaltLen, MSSrtpKeySourceDTLS);
+	} else if (mRole == MSDtlsSrtpRoleIsClient) { /* this enpoint act as DTLS client */
+		/* emission(client write) key and salt +16bits padding */
+		memcpy(key, key_material, DtlsSrtpKeyLen);
+		memcpy(key + DtlsSrtpKeyLen, key_material + 2 * DtlsSrtpKeyLen, DtlsSrtpSaltLen);
+		ms_media_stream_sessions_set_srtp_send_key(mStreamSessions, mSrtpProtectionProfile, key,
+		                                           DtlsSrtpKeyLen + DtlsSrtpSaltLen, MSSrtpKeySourceDTLS);
+		/* reception(server write) key and salt +16bits padding */
+		memcpy(key, key_material + DtlsSrtpKeyLen, DtlsSrtpKeyLen);
+		memcpy(key + DtlsSrtpKeyLen, key_material + 2 * DtlsSrtpKeyLen + DtlsSrtpSaltLen, DtlsSrtpSaltLen);
+		ms_media_stream_sessions_set_srtp_recv_key(mStreamSessions, mSrtpProtectionProfile, key,
+		                                           DtlsSrtpKeyLen + DtlsSrtpSaltLen, MSSrtpKeySourceDTLS);
+	}
+}
+
+/**
+ * Check if the incoming message is a DTLS packet.
+ * If it is, store it in the context incoming buffer and call the bctoolbox function wich will process it.
+ * This function also manages the client retransmission timer
+ *
+ * @param[in] 		msg	the incoming message
+ * @return	the value returned by the bctoolbox function processing the packet(ssl_handshake)
+ */
+int MSDtlsSrtpContext::processDtlsPacket(mblk_t *msg) {
+	size_t msgLength = msgdsize(msg);
+	bctbx_ssl_context_t *ssl = mDtlsCryptoContext.ssl;
+	int ret = 0;
+
+	/* UGLY PATCH CLIENT HELLO PACKET PARSING */
+	const int Content_Type_Index = 0;
+	const int Content_Length_Index = 11;
+	const int Handshake_Type_Index = 13;
+	const int Handshake_Message_Length_Index = 14;
+	const int Handshake_Message_Seq_Index = 17;
+	const int Handshake_Frag_Offset_Index = 19;
+	const int Handshake_Frag_Length_Index = 22;
+	const size_t Handshake_Header_Length = 25;
+	unsigned char *frag = msg->b_rptr;
+	size_t base_index = 0;
+	int message_length = 0;
+	int message_seq = 0;
+	int current_message_seq = -1;
+	int frag_offset = 0;
+	int frag_length = 0;
+	unsigned char *reassembled_packet = NULL;
+	/* end of UGLY PATCH CLIENT HELLO PACKET PARSING */
+
+	/*required by webrtc in server case when ice is not completed yet*/
+	/* no more required because change is performed by ice.c once a check list is ready
+	 * rtp_session_update_remote_sock_addr(rtp_session, msg,is_rtp,FALSE);*/
+
+	ms_message("DTLS Receive RTP packet len %d sessions: %p rtp session %p", (int)msgLength, mStreamSessions,
+	           mStreamSessions->rtp_session);
+
+	/* UGLY PATCH CLIENT HELLO PACKET PARSING */
+	/* Parse the DTLS packet to check if we have a Client Hello packet fragmented at DTLS level but all set in one
+	 * datagram (some kind of bug in certain versions openssl produce that and mbedtls does not support Client Hello
+	 * fragmentation ) This patch is not very resistant to any change and target that very particular situation, a
+	 * better solution should be to implement support of Client Hello Fragmentation in mbedtls */
+	if (msgLength > Handshake_Header_Length && frag[Content_Type_Index] == 0x16 &&
+	    frag[Handshake_Type_Index] ==
+	        0x01) { // If the first fragment(there may be only one) is of a DTLS Handshake Client Hello message
+		while (base_index + Handshake_Header_Length <
+		       msgLength) { // loop on the message, parsing all fragments it may contain (loop until we have at
+			                // least enough unparsed byte to read a handshake header)
+			if (frag[Content_Type_Index] == 0x16) {       // Type index 0x16 is DLTS Handshake message
+				if (frag[Handshake_Type_Index] == 0x01) { // Handshake type 0x01 is Client Hello
+					// Get message length
+					message_length = frag[Handshake_Message_Length_Index] << 16 |
+					                 frag[Handshake_Message_Length_Index + 1] << 8 |
+					                 frag[Handshake_Message_Length_Index + 2];
+
+					// message sequence number
+					message_seq = frag[Handshake_Message_Seq_Index] << 8 | frag[Handshake_Message_Seq_Index + 1];
+					if (current_message_seq == -1) {
+						current_message_seq = message_seq;
+					}
+
+					// fragment offset
+					frag_offset = frag[Handshake_Frag_Offset_Index] << 16 | frag[Handshake_Frag_Offset_Index + 1] << 8 |
+					              frag[Handshake_Frag_Offset_Index + 2];
+
+					// and fragment length
+					frag_length = frag[Handshake_Frag_Length_Index] << 16 | frag[Handshake_Frag_Length_Index + 1] << 8 |
+					              frag[Handshake_Frag_Length_Index + 2];
+
+					// check the message is not malformed and would lead us to read after the message buffer
+					// or write after our reassembled packet buffer
+					if (base_index + Handshake_Header_Length + frag_length <=
+					        msgLength // we will read frag_length starting at base_index (frag in the code)+ header
+					    && frag_length + frag_offset <=
+					           message_length) { // we will write in the reassembled buffer frag_length byte,
+						                         // starting at frag_offset, the buffer is message_length long
+
+						// If message length and fragment length differs, we have a fragmented Client Hello
+						// Check they are part of the same message (message_seq)
+						// We will just collect all fragments (in our very particuliar case, they are all in the
+						// same datagram so we do not need long term storage, juste parsing this packet)
+						if (message_length != frag_length && message_seq == current_message_seq) {
+							if (reassembled_packet == NULL) { // this is first fragment we get
+								reassembled_packet =
+								    (unsigned char *)ms_malloc(Handshake_Header_Length + message_length);
+								// copy the header
+								memcpy(reassembled_packet, msg->b_rptr, Handshake_Header_Length);
+								// set the message length to be in line with reassembled fragments
+								reassembled_packet[Content_Length_Index] = ((message_length + 12) >> 8) & 0xFF;
+								reassembled_packet[Content_Length_Index + 1] = (message_length + 12) & 0xFF;
+
+								// set the frag length to be the same than message length
+								reassembled_packet[Handshake_Frag_Length_Index] =
+								    reassembled_packet[Handshake_Message_Length_Index];
+								reassembled_packet[Handshake_Frag_Length_Index + 1] =
+								    reassembled_packet[Handshake_Message_Length_Index + 1];
+								reassembled_packet[Handshake_Frag_Length_Index + 2] =
+								    reassembled_packet[Handshake_Message_Length_Index + 2];
+							}
+							// copy the received fragment
+							memcpy(reassembled_packet + Handshake_Header_Length + frag_offset,
+							       frag + Handshake_Header_Length, frag_length);
+						}
+
+						// read what is next in the datagram
+						base_index += Handshake_Header_Length + frag_length; // bytes parsed so far
+						frag += Handshake_Header_Length + frag_length; // point to the begining of the next fragment
+					} else {                                           // message is malformed in a nasty way
+						ms_warning("DTLS Received RTP packet len %d sessions: %p rtp session %p is malformed in an "
+						           "agressive way",
+						           (int)msgLength, mStreamSessions, mStreamSessions->rtp_session);
+						base_index = msgLength; // get out of the while
+						ms_free(reassembled_packet);
+						reassembled_packet = NULL;
+					}
+				} else {
+					base_index = msgLength; // get out of the while
+					ms_free(reassembled_packet);
+					reassembled_packet = NULL;
+				}
+			}
+		}
+	}
+	/* end of UGLY PATCH CLIENT HELLO PACKET PARSING */
+	// if we made a reassembled client hello packet, use this one as incoming dlts packet
+	if (reassembled_packet != NULL) {
+		ms_message("DTLS re-assembled a fragmented Client Hello packet");
+		mRtpIncomingBuffer.emplace(reassembled_packet, reassembled_packet + Handshake_Header_Length + message_length);
+		ms_free(reassembled_packet);
+	} else { // otherwise enqueue the one we received
+		mRtpIncomingBuffer.emplace(msg->b_rptr, msg->b_rptr + msgLength);
+	}
+
+	/* while DTLS handshake is on going route DTLS packets to bctoolbox engine through ssl_handshake() */
+	if (mChannelStatus < DtlsStatus::HandshakeOver) {
+		/* role is unset but we receive a packet: we are caller and shall initialise as server and then process the
+		 * incoming packet */
+		if (mRole == MSDtlsSrtpRoleUnset) {
+			setRole(MSDtlsSrtpRoleIsServer); /* this call will update role and complete server setup */
+			start();                         /* complete the ssl setup and change channel_status to handshake ongoing */
+			ssl = mDtlsCryptoContext.ssl;
+		}
+		/* process the packet and store result */
+		ret = bctbx_ssl_handshake(ssl);
+		ms_message("DTLS Handshake process RTP packet len %d sessions: %p rtp session %p return %s0x%0x",
+		           (int)msgLength, mStreamSessions, mStreamSessions->rtp_session, ret > 0 ? "+" : "-",
+		           ret > 0 ? ret : -ret);
+
+		/* if we are client, manage the retransmission timer */
+		if (mRole == MSDtlsSrtpRoleIsClient) {
+			rtp_time_reference = bctbx_get_cur_time_ms();
 		}
+	} else { /* when DTLS handshake is over, route DTLS packets to bctoolbox engine through ssl_read() */
+		/* we need a buffer to store the message read even if we don't use it */
+		unsigned char *buf = (unsigned char *)ms_malloc(msgLength + 1);
+		ret = bctbx_ssl_read(ssl, buf, msgLength);
+		ms_message("DTLS Handshake read RTP packet len %d sessions: %p rtp session %p return %s0x%0x", (int)msgLength,
+		           mStreamSessions, mStreamSessions->rtp_session, ret > 0 ? "+" : "-", ret > 0 ? ret : -ret);
+		ms_free(buf);
 	}
+
+	/* report the error in logs only when different than requested read(waiting for data) */
+	if (ret < 0 && ret != BCTBX_ERROR_NET_WANT_READ) {
+		char err_str[512];
+		err_str[0] = '\0';
+		bctbx_strerror(ret, err_str, 512);
+		ms_warning("DTLS Handshake returns -0x%x : %s [on sessions: %p rtp session %p]", -ret, err_str, mStreamSessions,
+		           mStreamSessions->rtp_session);
+	}
+	return ret;
 }
-} // namespace
+
 /***********************************************/
 /***** EXPORTED FUNCTIONS                  *****/
 /***********************************************/
@@ -776,7 +778,7 @@ void ms_dtls_srtp_start_nolock(MSDtlsSrtpContext *context) {
 extern "C" void ms_dtls_srtp_set_stream_sessions(MSDtlsSrtpContext *dtls_context,
                                                  MSMediaStreamSessions *stream_sessions) {
 	if (dtls_context != NULL) {
-		dtls_context->stream_sessions = stream_sessions;
+		dtls_context->mStreamSessions = stream_sessions;
 	}
 }
 
@@ -790,25 +792,23 @@ extern "C" void ms_dtls_srtp_set_peer_fingerprint(MSDtlsSrtpContext *ctx, const
 	if (ctx) {
 		std::lock_guard<std::mutex> lock(ctx->mtx);
 
-		size_t peer_fingerprint_length = strlen(peer_fingerprint) + 1; // include the null termination
-		if (peer_fingerprint_length > sizeof(ctx->peer_fingerprint)) {
-			memcpy(ctx->peer_fingerprint, peer_fingerprint, sizeof(ctx->peer_fingerprint));
+		if (strlen(peer_fingerprint) > maxFingerPrintSize) {
 			ms_error("DTLS-SRTP received from SDP INVITE a peer fingerprint %d bytes length wich is longer than "
-			         "maximum storage %d bytes",
-			         (int)peer_fingerprint_length, (int)sizeof(ctx->peer_fingerprint));
+			         "maximum allowed size: %d bytes, ignore it",
+			         (int)(strlen(peer_fingerprint)), (int)maxFingerPrintSize);
 		} else {
-			memcpy(ctx->peer_fingerprint, peer_fingerprint, peer_fingerprint_length);
+			ctx->mPeerFingerprint = peer_fingerprint;
 		}
-		ms_message("DTLS-SRTP peer fingerprint is %s", ctx->peer_fingerprint);
+		ms_message("DTLS-SRTP peer fingerprint is %s", ctx->mPeerFingerprint.c_str());
 
 		/* Check if any of the context has finished its handshake and was waiting for the fingerprint */
-		if (ctx->rtp_channel_status == DTLS_STATUS_HANDSHAKE_OVER) {
+		if (ctx->mChannelStatus == DtlsStatus::HandshakeOver) {
 			ms_message("DTLS SRTP : late fingerprint arrival, check it after RTP Handshake is over");
-			if (ms_dtls_srtp_check_certificate_fingerprint(bctbx_ssl_get_peer_certificate(ctx->rtp_dtls_context->ssl),
-			                                               (const char *)(ctx->peer_fingerprint)) == 1) {
-				ms_dtls_srtp_set_srtp_key_material(ctx);
-				ctx->rtp_channel_status = DTLS_STATUS_FINGERPRINT_VERIFIED;
-				ms_dtls_srtp_check_channels_status(ctx);
+			if (ms_dtls_srtp_check_certificate_fingerprint(bctbx_ssl_get_peer_certificate(ctx->mDtlsCryptoContext.ssl),
+			                                               ctx->mPeerFingerprint) == 1) {
+				ctx->setKeyMaterial();
+				ctx->mChannelStatus = DtlsStatus::FingerprintVerified;
+				ctx->checkChannelStatus();
 			}
 		}
 	}
@@ -820,66 +820,50 @@ extern "C" void ms_dtls_srtp_reset_context(MSDtlsSrtpContext *context) {
 
 		ms_message("Reseting DTLS context [%p] and SSL connections", context);
 
-		if ((context->rtp_channel_status == DTLS_STATUS_HANDSHAKE_ONGOING) ||
-		    (context->rtp_channel_status == DTLS_STATUS_HANDSHAKE_OVER)) {
-			bctbx_ssl_session_reset(context->rtp_dtls_context->ssl);
+		if ((context->mChannelStatus == DtlsStatus::HandshakeOngoing) ||
+		    (context->mChannelStatus == DtlsStatus::HandshakeOver)) {
+			bctbx_ssl_session_reset(context->mDtlsCryptoContext.ssl);
 		}
 
-		context->rtp_channel_status = DTLS_STATUS_CONTEXT_READY;
-		context->rtp_agreed_srtp_protection_profile = MS_CRYPTO_SUITE_INVALID;
+		context->mChannelStatus = DtlsStatus::ContextReady;
+		context->mSrtpProtectionProfile = MS_CRYPTO_SUITE_INVALID;
 
-		context->role = MSDtlsSrtpRoleUnset;
+		context->mRole = MSDtlsSrtpRoleUnset;
 	}
 }
 
 extern "C" MSDtlsSrtpRole ms_dtls_srtp_get_role(const MSDtlsSrtpContext *context) {
-	return context->role;
+	return context->mRole;
 }
 
 extern "C" void ms_dtls_srtp_set_role(MSDtlsSrtpContext *context, MSDtlsSrtpRole role) {
 	if (context) {
 		std::lock_guard<std::mutex> lock(context->mtx);
-		ms_dtls_srtp_set_role_nolock(context, role);
+		context->setRole(role);
 	}
 }
 
 extern "C" MSDtlsSrtpContext *ms_dtls_srtp_context_new(MSMediaStreamSessions *sessions, MSDtlsSrtpParams *params) {
-	MSDtlsSrtpContext *userData;
-	RtpSession *s = sessions->rtp_session;
-	int ret;
-
-	/* Create and init the mbedtls DTLS contexts */
-	DtlsBcToolBoxContext *rtp_dtls_context = ms_dtls_srtp_bctbx_context_new();
 
 	ms_message("Creating DTLS-SRTP engine on stream sessions [%p] as %s, RTCP mux is %s", sessions,
 	           params->role == MSDtlsSrtpRoleIsServer
 	               ? "server"
 	               : (params->role == MSDtlsSrtpRoleIsClient ? "client" : "unset role"),
-	           rtp_session_rtcp_mux_enabled(s) ? "enabled" : "disabled");
-
-	/* create and link user data */
-	userData = ms_new0(MSDtlsSrtpContext, 1);
-	userData->rtp_dtls_context = rtp_dtls_context;
-	userData->role = params->role;
-	userData->mtu = params->mtu;
-	userData->rtp_time_reference = 0;
-	userData->retry_sending = false;
-
-	userData->stream_sessions = sessions;
-	userData->rtp_incoming_buffer = NULL;
-	userData->rtp_channel_status = DTLS_STATUS_CONTEXT_NOT_READY;
-	userData->rtp_agreed_srtp_protection_profile = MS_CRYPTO_SUITE_INVALID;
-	ms_dtls_srtp_set_transport(userData, s);
-
-	ret = ms_dtls_srtp_initialise_bctbx_dtls_context(rtp_dtls_context, params);
+	           rtp_session_rtcp_mux_enabled(sessions->rtp_session) ? "enabled" : "disabled");
+
+	/* create context and link it to the rtp session */
+	auto context = new MSDtlsSrtpContext(sessions, params);
+	ms_dtls_srtp_set_transport(context, sessions->rtp_session);
+
+	int ret = context->initialiseDtlsCryptoContext(params);
 	if (ret != 0) {
 		ms_error("DTLS init error : rtp bctoolbox context init returned -0x%0x on stream session [%p]", -ret, sessions);
+		delete context;
 		return NULL;
 	}
 
-	userData->rtp_channel_status = DTLS_STATUS_CONTEXT_READY;
-
-	return userData;
+	context->mChannelStatus = DtlsStatus::ContextReady;
+	return context;
 }
 
 extern "C" void ms_dtls_srtp_start(MSDtlsSrtpContext *context) {
@@ -889,21 +873,10 @@ extern "C" void ms_dtls_srtp_start(MSDtlsSrtpContext *context) {
 		return;
 	}
 	std::lock_guard<std::mutex> lock(context->mtx);
-	ms_dtls_srtp_start_nolock(context);
+	context->start();
 }
 
 extern "C" void ms_dtls_srtp_context_destroy(MSDtlsSrtpContext *ctx) {
-	/* clean bctoolbox contexts */
-	ms_dtls_srtp_bctbx_context_free(ctx->rtp_dtls_context);
-
-	/* clean incoming buffers */
-	while (ctx->rtp_incoming_buffer != NULL) {
-		DtlsRawPacket *next_packet = (DtlsRawPacket *)(ctx->rtp_incoming_buffer->next);
-		ms_free(ctx->rtp_incoming_buffer->data);
-		ms_free(ctx->rtp_incoming_buffer);
-		ctx->rtp_incoming_buffer = next_packet;
-	}
-
-	ms_free(ctx);
+	delete ctx;
 	ms_message("DTLS-SRTP context destroyed");
 }