[Pkg-voip-commits] [janus] 89/163: Added text2pcap support for handles traffic

Jonas Smedegaard dr at jones.dk
Sat Oct 28 01:22:13 UTC 2017


This is an automated email from the git hooks/post-receive script.

js pushed a commit to annotated tag debian/0.2.5-1
in repository janus.

commit 0ada6b639277cedf28b9176c6b1715e0ec2a46f2
Author: Lorenzo Miniero <lminiero at gmail.com>
Date:   Tue Sep 5 19:22:03 2017 +0200

    Added text2pcap support for handles traffic
---
 Makefile.am  |   4 +-
 ice.c        |  19 ++++++-
 ice.h        |   5 ++
 janus.c      |  56 +++++++++++++++++++
 mainpage.dox |  43 +++++++++++++++
 text2pcap.c  | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 text2pcap.h  |  94 ++++++++++++++++++++++++++++++++
 7 files changed, 394 insertions(+), 2 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index c8baa3e..0b6ca01 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -29,7 +29,7 @@ bin_PROGRAMS = janus
 
 headerdir = $(includedir)/janus
 header_HEADERS = apierror.h config.h log.h debug.h mutex.h record.h \
-	rtcp.h rtp.h sdp-utils.h ip-utils.h utils.h
+	rtcp.h rtp.h sdp-utils.h ip-utils.h utils.h text2pcap.h
 
 pluginsheaderdir = $(includedir)/janus/plugins
 pluginsheader_HEADERS = plugins/plugin.h
@@ -130,6 +130,8 @@ janus_SOURCES = \
 	utils.h \
 	version.c \
 	version.h \
+	text2pcap.c \
+	text2pcap.h \
 	plugins/plugin.c \
 	plugins/plugin.h \
 	transports/transport.h \
diff --git a/ice.c b/ice.c
index a100cf5..7974a38 100644
--- a/ice.c
+++ b/ice.c
@@ -1104,6 +1104,10 @@ gint janus_ice_handle_destroy(void *gateway_session, guint64 handle_id) {
 	/* Notify the plugin that the session's over */
 	plugin_t->destroy_session(handle->app_handle, &error);
 	/* Get rid of the handle now */
+	if(g_atomic_int_compare_and_exchange(&handle->dump_packets, 1, 0)) {
+		janus_text2pcap_close(handle->text2pcap);
+		g_clear_pointer(&handle->text2pcap, janus_text2pcap_free);
+	}
 	janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
 	janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP);
 	if(handle->iceloop) {
@@ -2058,6 +2062,9 @@ static void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint comp
 						JANUS_LOG(LOG_VERB, "[%"SCNu64"]     Peer audio SSRC: %u\n", handle->handle_id, stream->audio_ssrc_peer);
 					}
 				}
+				/* Do we need to dump this packet for debugging? */
+				if(g_atomic_int_get(&handle->dump_packets))
+					janus_text2pcap_dump(handle->text2pcap, JANUS_TEXT2PCAP_RTP, TRUE, buf, buflen, NULL);
 				/* Pass the data to the responsible plugin */
 				janus_plugin *plugin = (janus_plugin *)handle->app;
 				if(plugin && plugin->incoming_rtp)
@@ -2230,6 +2237,9 @@ static void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint comp
 			if(res != srtp_err_status_ok) {
 				JANUS_LOG(LOG_ERR, "[%"SCNu64"]     SRTCP unprotect error: %s (len=%d-->%d)\n", handle->handle_id, janus_srtp_error_str(res), len, buflen);
 			} else {
+				/* Do we need to dump this packet for debugging? */
+				if(g_atomic_int_get(&handle->dump_packets))
+					janus_text2pcap_dump(handle->text2pcap, JANUS_TEXT2PCAP_RTCP, TRUE, buf, buflen, NULL);
 				/* Check if there's an RTCP BYE: in case, let's wrap up */
 				if(janus_rtcp_has_bye(buf, buflen)) {
 					JANUS_LOG(LOG_VERB, "[%"SCNu64"] Got RTCP BYE on stream %"SCNu16" (component %"SCNu16"), closing...\n", handle->handle_id, stream->stream_id, component->component_id);
@@ -3756,7 +3766,10 @@ void *janus_ice_send_thread(void *data) {
 					janus_rtcp_fix_ssrc(NULL, sbuf, pkt->length, 1, 0,
 						video ? stream->video_ssrc_peer : stream->audio_ssrc_peer);
 				}
-
+				/* Do we need to dump this packet for debugging? */
+				if(g_atomic_int_get(&handle->dump_packets))
+					janus_text2pcap_dump(handle->text2pcap, JANUS_TEXT2PCAP_RTCP, FALSE, sbuf, pkt->length, NULL);
+				/* Encrypt SRTCP */
 				int protected = pkt->length;
 				int res = 0;
 				if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_PLAN_B)) {
@@ -3846,6 +3859,10 @@ void *janus_ice_send_thread(void *data) {
 						rtp_header *header = (rtp_header *)sbuf;
 						header->ssrc = htonl(video ? stream->video_ssrc : stream->audio_ssrc);
 					}
+					/* Do we need to dump this packet for debugging? */
+					if(g_atomic_int_get(&handle->dump_packets))
+						janus_text2pcap_dump(handle->text2pcap, JANUS_TEXT2PCAP_RTP, FALSE, sbuf, pkt->length, NULL);
+					/* Encrypt SRTP */
 					int protected = pkt->length;
 					int res = srtp_protect(component->dtls->srtp_out, sbuf, &protected);
 					if(res != srtp_err_status_ok) {
diff --git a/ice.h b/ice.h
index 4a00a92..0a0f7ec 100644
--- a/ice.h
+++ b/ice.h
@@ -24,6 +24,7 @@
 #include "dtls.h"
 #include "sctp.h"
 #include "rtcp.h"
+#include "text2pcap.h"
 #include "utils.h"
 #include "plugins/plugin.h"
 
@@ -335,6 +336,10 @@ struct janus_ice_handle {
 	guint srtp_errors_count;
 	/*! \brief Count of the recent SRTP replay errors, in order to avoid spamming the logs */
 	gint last_srtp_error;
+	/*! \brief Flag to decide whether or not packets need to be dumped to a text2pcap file */
+	volatile gint dump_packets;
+	/*! \brief In case this session must be saved to text2pcap, the instance to dump packets to */
+	janus_text2pcap *text2pcap;
 	/*! \brief Mutex to lock/unlock the ICE session */
 	janus_mutex mutex;
 };
diff --git a/janus.c b/janus.c
index fe1a7f7..e4bbf65 100644
--- a/janus.c
+++ b/janus.c
@@ -132,6 +132,10 @@ static struct janus_json_parameter mnq_parameters[] = {
 static struct janus_json_parameter nmt_parameters[] = {
 	{"no_media_timer", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}
 };
+static struct janus_json_parameter text2pcap_parameters[] = {
+	{"folder", JSON_STRING, 0},
+	{"filename", JSON_STRING, 0}
+};
 
 /* Admin/Monitor helpers */
 json_t *janus_admin_stream_summary(janus_ice_stream *stream);
@@ -2197,6 +2201,53 @@ int janus_process_incoming_admin_request(janus_request *request) {
 		goto jsondone;
 	} else {
 		/* Handle-related */
+		if(!strcasecmp(message_text, "start_text2pcap")) {
+			/* Start dumping RTP and RTCP packets to a text2pcap file */
+			JANUS_VALIDATE_JSON_OBJECT(root, text2pcap_parameters,
+				error_code, error_cause, FALSE,
+				JANUS_ERROR_MISSING_MANDATORY_ELEMENT, JANUS_ERROR_INVALID_ELEMENT_TYPE);
+			if(error_code != 0) {
+				ret = janus_process_error_string(request, session_id, transaction_text, error_code, error_cause);
+				goto jsondone;
+			}
+			const char *folder = json_string_value(json_object_get(root, "folder"));
+			const char *filename = json_string_value(json_object_get(root, "filename"));
+			if(handle->text2pcap != NULL) {
+				ret = janus_process_error(request, session_id, transaction_text, JANUS_ERROR_UNKNOWN, "text2pcap already started");
+				goto jsondone;
+			}
+			handle->text2pcap = janus_text2pcap_create(folder, filename);
+			if(handle->text2pcap == NULL) {
+				ret = janus_process_error(request, session_id, transaction_text, JANUS_ERROR_UNKNOWN, "Error starting text2pcap dump");
+				goto jsondone;
+			}
+			g_atomic_int_set(&handle->dump_packets, 1);
+			/* Prepare JSON reply */
+			json_t *reply = json_object();
+			json_object_set_new(reply, "janus", json_string("success"));
+			json_object_set_new(reply, "transaction", json_string(transaction_text));
+			/* Send the success reply */
+			ret = janus_process_success(request, reply);
+			goto jsondone;
+		} else if(!strcasecmp(message_text, "stop_text2pcap")) {
+			/* Stop dumping RTP and RTCP packets to a text2pcap file */
+			if(handle->text2pcap == NULL) {
+				ret = janus_process_error(request, session_id, transaction_text, JANUS_ERROR_UNKNOWN, "text2pcap not started");
+				goto jsondone;
+			}
+			if(g_atomic_int_compare_and_exchange(&handle->dump_packets, 1, 0)) {
+				janus_text2pcap_close(handle->text2pcap);
+				g_clear_pointer(&handle->text2pcap, janus_text2pcap_free);
+			}
+			/* Prepare JSON reply */
+			json_t *reply = json_object();
+			json_object_set_new(reply, "janus", json_string("success"));
+			json_object_set_new(reply, "transaction", json_string(transaction_text));
+			/* Send the success reply */
+			ret = janus_process_success(request, reply);
+			goto jsondone;
+		}
+		/* If this is not a request to start/stop debugging to text2pcap, it must be a handle_info */
 		if(strcasecmp(message_text, "handle_info")) {
 			ret = janus_process_error(request, session_id, transaction_text, JANUS_ERROR_INVALID_REQUEST_PATH, "Unhandled request '%s' at this path", message_text);
 			goto jsondone;
@@ -2272,6 +2323,11 @@ int janus_process_incoming_admin_request(janus_request *request) {
 			json_object_set_new(info, "pending-trickles", json_integer(g_list_length(handle->pending_trickles)));
 		if(handle->queued_packets)
 			json_object_set_new(info, "queued-packets", json_integer(g_async_queue_length(handle->queued_packets)));
+		if(g_atomic_int_get(&handle->dump_packets)) {
+			json_object_set_new(info, "dump-to-text2pcap", json_true());
+			if(handle->text2pcap && handle->text2pcap->filename)
+			json_object_set_new(info, "text2pcap-file", json_string(handle->text2pcap->filename));
+		}
 		json_t *streams = json_array();
 		if(handle->audio_stream) {
 			json_t *s = janus_admin_stream_summary(handle->audio_stream);
diff --git a/mainpage.dox b/mainpage.dox
index a355b59..05788a6 100644
--- a/mainpage.dox
+++ b/mainpage.dox
@@ -1664,6 +1664,9 @@ var websocket = new WebSocket('ws://1.2.3.4:8188', 'janus-protocol');
  * \note Right now, this new API mostly allows you to retrieve information,
  * but only act on part of it: for more interaction (e.g., to force a
  * session removal), you can rely on the existing \ref rest for the purpose.
+ * Besides, notice that this is a pull-based API. If you're interested in
+ * asynchronous notifications about the internal state of core and plugins,
+ * check the recently added janus_eventhandler mechanism instead.
  *
  * The API, for security reasons, is typically noy enabled by default in any of the
  * transport plugins: that's definitely the case for the stock transport
@@ -1685,6 +1688,9 @@ var websocket = new WebSocket('ws://1.2.3.4:8188', 'janus-protocol');
  * - \c list_handles: list all the ICE handles currently active in a Janus
  * session (returns an array of handle identifiers);
  * - \c handle_info: list all the available info on a specific ICE handle;
+ * - \c start_text2pcap: start dumping incoming and outgoing RTP/RTCP packets
+ * of a handle to a text2pcap file (e.g., for ex-post analysis via Wireshark);
+ * - \c stop_text2pcap: stop the text2pcap dump;
  * - \c set_session_timeout: change the session timeout value in Janus on the fly;
  * - \c set_log_level: change the log level in Janus on the fly;
  * - \c set_locking_debug: selectively enable/disable a live debugging of
@@ -1820,6 +1826,43 @@ POST /admin/12345678/98765432
  * in input/output statistics statistics (bytes, bytes per seconds, NACKs,
  * etc.) or the SDP/ICE/DTLS states.
  *
+ * As anticipated, you can also enable/disable the dumping of the RTP/RTCP
+ * packets a handle is sending and receiving to a text2pcap file. This is
+ * especially useful for debugging reasons, e.g., to check whether or not
+ * there are issues in a specific packet Janus is sending or receiving
+ * with tools like Wireshark. Notice that this is not supposed to be used
+ * for recording Janus streams: while it can be used for that, the
+ * janus_recorder utility is much more suited for the task, and is what
+ * all plugins make use of when they're interested in recordings.
+ *
+ * The syntax for the \c start_text2pcap command is trivial, as all you
+ * need to specify are information on the handle to dump, and information
+ * on the target file (target folder and filename):
+ *
+\verbatim
+POST /admin/12345678/98765432
+{
+	"janus" : "start_text2pcap",
+	"folder" : "<folder to save the dump to; optional, current folder if missing>",
+	"filename" : "<filename of the dump; optional, random filename if missing>",
+	"transaction" : "<random alphanumeric string>",
+	"admin_secret" : "<password specified in janus.cfg, if any>"
+}
+\endverbatim
+ *
+ * If successful, the full path of the dump file can be obtained by doing
+ * a \c handle_info request. A \c start_text2pcap command is even easier
+ * to generate, as it doesn't need any parameter:
+ *
+\verbatim
+POST /admin/12345678/98765432
+{
+	"janus" : "stop_text2pcap",
+	"transaction" : "<random alphanumeric string>",
+	"admin_secret" : "<password specified in janus.cfg, if any>"
+}
+\endverbatim
+ *
  * Finally, the syntax for the \c set_log_level and \c set_locking_debug
  * commands is quite straightforward:
  *
diff --git a/text2pcap.c b/text2pcap.c
new file mode 100644
index 0000000..6944ea2
--- /dev/null
+++ b/text2pcap.c
@@ -0,0 +1,175 @@
+/*! \file    text2pcap.c
+ * \author   Lorenzo Miniero <lorenzo at meetecho.com>
+ * \copyright GNU General Public License v3
+ * \brief    Dumping of RTP/RTCP packets to text2pcap format
+ * \details  Implementation of a simple helper utility that can be used
+ * to dump incoming and outgoing RTP/RTCP packets to text2pcap format.
+ * The resulting file can then be passed to the \c text2pcap application
+ * in order to get a \c .pcap or \c .pcapng file that can be analyzed
+ * via Wireshark or similar applications, e.g.:
+ *
+\verbatim
+/usr/sbin/text2pcap -D -n -l 1 -i 17 -u 1000,2000 -t '%H:%M:%S.' dump.txt dump.pcapng
+/usr/sbin/wireshark dump.pcapng
+\endverbatim
+ *
+ * While plugins are free to take advantage of this functionality, it's been
+ * specifically added to make debugging from the core easier. Enabling and
+ * disabling the dump of RTP/RTCP packets for the media traffic of a
+ * specific handle is done via the \ref admin so check the documentation
+ * of that section for more details. Notice that starting a new dump on
+ * an existing filename will result in the new packets to be appended.
+ *
+ * \note Motivation and inspiration for this work came from a
+ * <a href="https://blog.mozilla.org/webrtc/debugging-encrypted-rtp-is-more-fun-than-it-used-to-be/">similar effort</a>
+ * recently done in Firefox, and from a discussion related to a
+ * <a href="https://webrtchacks.com/video_replay/">blog post</a> on
+ * WebRTC hacks, where guidelines are provided with respect to debugging
+ * based on pcap files.
+ *
+ * \ingroup core
+ * \ref core
+ */
+
+#include <sys/time.h>
+ 
+#include "text2pcap.h"
+#include "debug.h"
+#include "utils.h"
+
+#define CASE_STR(name) case name: return #name
+const char *janus_text2pcap_packet_string(janus_text2pcap_packet type) {
+	switch(type) {
+		CASE_STR(JANUS_TEXT2PCAP_RTP);
+		CASE_STR(JANUS_TEXT2PCAP_RTCP);
+		CASE_STR(JANUS_TEXT2PCAP_DATA);
+		default:
+			break;
+	}
+	return NULL;
+}
+
+janus_text2pcap *janus_text2pcap_create(const char *dir, const char *filename) {
+	/* Create the text2pcap instance */
+	janus_text2pcap *tp = g_malloc0(sizeof(janus_text2pcap));
+	if(tp == NULL) {
+		JANUS_LOG(LOG_FATAL, "Memory error!\n");
+		return NULL;
+	}
+	tp->filename = NULL;
+	tp->file = NULL;
+	g_atomic_int_set(&tp->writable, 0);
+	if(dir != NULL) {
+		/* Create the directory, if needed */
+		if(janus_mkdir(dir, 0755) < 0) {
+			JANUS_LOG(LOG_ERR, "mkdir error: %d\n", errno);
+			return NULL;
+		}
+	}
+	char newname[1024];
+	memset(newname, 0, 1024);
+	if(filename == NULL) {
+		/* Choose a random username */
+		g_snprintf(newname, 1024, "janus-text2pcap-%"SCNu32".txt", janus_random_uint32());
+	} else {
+		/* Just copy the filename */
+		g_snprintf(newname, 1024, "%s", filename);
+	}
+	/* Try opening the file now */
+	if(dir == NULL) {
+		tp->file = fopen(newname, "ab");
+		if(tp->file == NULL)
+			tp->file = fopen(newname, "wb");
+		if(tp->file != NULL)
+			tp->filename = g_strdup(newname);
+	} else {
+		char path[1024];
+		memset(path, 0, 1024);
+		g_snprintf(path, 1024, "%s/%s", dir, newname);
+		tp->file = fopen(path, "ab");
+		if(tp->file == NULL)
+			tp->file = fopen(path, "wb");
+		if(tp->file != NULL)
+			tp->filename = g_strdup(path);
+	}
+	if(tp->file == NULL) {
+		JANUS_LOG(LOG_ERR, "fopen error: %d\n", errno);
+		return NULL;
+	}
+	g_atomic_int_set(&tp->writable, 1);
+	janus_mutex_init(&tp->mutex);
+	return tp;
+}
+
+int janus_text2pcap_dump(janus_text2pcap *instance,
+		janus_text2pcap_packet type, gboolean incoming, char *buf, int len, char *custom) {
+	if(instance == NULL || buf == NULL || len < 1)
+		return -1;
+	janus_mutex_lock_nodebug(&instance->mutex);
+	if(instance->file == NULL || !g_atomic_int_get(&instance->writable)) {
+		janus_mutex_unlock_nodebug(&instance->mutex);
+		return -1;
+	}
+	/* Prepare text representation of the packet */
+	char buffer[5000], timestamp[20], usec[10], byte[10];
+	memset(timestamp, 0, sizeof(timestamp));
+	memset(usec, 0, sizeof(usec));
+	time_t t = time(NULL);
+	struct tm *tm = localtime(&t);
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	strftime(timestamp, sizeof(timestamp), "%H:%M:%S", tm);
+	g_snprintf(usec, sizeof(usec), ".%ld", tv.tv_usec);
+	g_strlcat(timestamp, usec, sizeof(timestamp));
+	memset(buffer, 0, sizeof(buffer));
+	g_snprintf(buffer, sizeof(buffer), "%s %s 000000 ", incoming ? "I" : "O", timestamp);
+	int i=0;
+	for(i=0; i<len; i++) {
+		memset(byte, 0, sizeof(byte));
+		g_snprintf(byte, sizeof(byte), " %02x", (unsigned char)buf[i]);
+		g_strlcat(buffer, byte, sizeof(buffer));
+	}
+	g_strlcat(buffer, " ", sizeof(buffer));
+	g_strlcat(buffer, janus_text2pcap_packet_string(type), sizeof(buffer));
+	if(custom && strlen(custom)) {
+		g_strlcat(buffer, " ", sizeof(buffer));
+		g_strlcat(buffer, custom, sizeof(buffer));
+	}
+	g_strlcat(buffer, "\r\n", sizeof(buffer));
+	/* Save textified packet on file */
+	int temp = 0, buflen = strlen(buffer), tot = buflen;
+	while(tot > 0) {
+		temp = fwrite(buffer+buflen-tot, sizeof(char), tot, instance->file);
+		if(temp <= 0) {
+			JANUS_LOG(LOG_ERR, "Error dumping packet...\n");
+			janus_mutex_unlock_nodebug(&instance->mutex);
+			return -2;
+		}
+		tot -= temp;
+	}
+	/* Done */
+	janus_mutex_unlock_nodebug(&instance->mutex);
+	return 0;
+}
+
+int janus_text2pcap_close(janus_text2pcap *instance) {
+	if(instance == NULL)
+		return -1;
+	janus_mutex_lock_nodebug(&instance->mutex);
+	if(!g_atomic_int_compare_and_exchange(&instance->writable, 1, 0)) {
+		janus_mutex_unlock_nodebug(&instance->mutex);
+		return 0;
+	}
+	fclose(instance->file);
+	instance->file = NULL;
+	janus_mutex_unlock_nodebug(&instance->mutex);
+	return 0;
+}
+
+void janus_text2pcap_free(janus_text2pcap *instance) {
+	if(instance == NULL)
+		return;
+	janus_text2pcap_close(instance);
+	g_free(instance->filename);
+	g_free(instance);
+}
diff --git a/text2pcap.h b/text2pcap.h
new file mode 100644
index 0000000..a246c3f
--- /dev/null
+++ b/text2pcap.h
@@ -0,0 +1,94 @@
+/*! \file    text2pcap.h
+ * \author   Lorenzo Miniero <lorenzo at meetecho.com>
+ * \copyright GNU General Public License v3
+ * \brief    Dumping of RTP/RTCP packets to text2pcap format (headers)
+ * \details  Implementation of a simple helper utility that can be used
+ * to dump incoming and outgoing RTP/RTCP packets to text2pcap format.
+ * The resulting file can then be passed to the \c text2pcap application
+ * in order to get a \c .pcap or \c .pcapng file that can be analyzed
+ * via Wireshark or similar applications, e.g.:
+ *
+\verbatim
+/usr/sbin/text2pcap -D -n -l 1 -i 17 -u 1000,2000 -t '%H:%M:%S.' dump.txt dump.pcapng
+/usr/sbin/wireshark dump.pcapng
+\endverbatim
+ *
+ * While plugins are free to take advantage of this functionality, it's been
+ * specifically added to make debugging from the core easier. Enabling and
+ * disabling the dump of RTP/RTCP packets for the media traffic of a
+ * specific handle is done via the \ref admin so check the documentation
+ * of that section for more details. Notice that starting a new dump on
+ * an existing filename will result in the new packets to be appended.
+ *
+ * \note Motivation and inspiration for this work came from a
+ * <a href="https://blog.mozilla.org/webrtc/debugging-encrypted-rtp-is-more-fun-than-it-used-to-be/">similar effort</a>
+ * recently done in Firefox, and from a discussion related to a
+ * <a href="https://webrtchacks.com/video_replay/">blog post</a> on
+ * WebRTC hacks, where guidelines are provided with respect to debugging
+ * based on pcap files.
+ *
+ * \ingroup core
+ * \ref core
+ */
+ 
+#ifndef _JANUS_TEXT2PCAP_H
+#define _JANUS_TEXT2PCAP_H
+
+#include <glib.h>
+
+#include <inttypes.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mutex.h"
+
+/*! \brief Instance of a text2pcap recorder */
+typedef struct janus_text2pcap {
+	/*! \brief Absolute path to where the text2pcap file is stored */ 
+	char *filename;
+	/*! \brief Pointer to the file handle */
+	FILE *file;
+	/*! \brief Whether we can write to this file or not */
+	volatile int writable;
+	/*! \brief Mutex to lock/unlock this recorder instance */ 
+	janus_mutex mutex;
+} janus_text2pcap;
+
+/*! \brief Packet types we can dump */
+typedef enum janus_text2pcap_packet {
+	JANUS_TEXT2PCAP_RTP,
+	JANUS_TEXT2PCAP_RTCP,
+	JANUS_TEXT2PCAP_DATA
+} janus_text2pcap_packet;
+const char *janus_text2pcap_packet_string(janus_text2pcap_packet type);
+
+/*! \brief Create a text2pcap recorder
+ * \note If no target directory is provided, the current directory will be used. If no filename
+ * is passed, a random filename will be used.
+ * @param[in] dir Path of the directory to save the recording into (will try to create it if it doesn't exist)
+ * @param[in] filename Filename to use for the recording
+ * @returns A valid janus_text2pcap instance in case of success, NULL otherwise */
+janus_text2pcap *janus_text2pcap_create(const char *dir, const char *filename);
+
+/*! \brief Dump an RTP or RTCP packet
+ * @param[in] instance Instance of the janus_text2pcap recorder to dump the packet to
+ * @param[in] type Type of the packet we're going to dump
+ * @param[in] incoming Whether this is an incoming or outgoing packet
+ * @param[in] buf Packet data to dump
+ * @param[in] len Size of the packet data to dump
+ * @param[in] custom Optional string to append to the line
+ * @returns 0 in case of success, a negative integer otherwise */
+int janus_text2pcap_dump(janus_text2pcap *instance,
+	janus_text2pcap_packet type, gboolean incoming, char *buf, int len, char *custom);
+
+/*! \brief Close a text2pcap recorder
+ * @param[in] instance Instance of the janus_text2pcap recorder to close
+ * @returns 0 in case of success, a negative integer otherwise */
+int janus_text2pcap_close(janus_text2pcap *instance);
+
+/*! \brief Free a text2pcap instance
+ * @param[in] instance Instance of the janus_text2pcap recorder to free */
+void janus_text2pcap_free(janus_text2pcap *instance);
+
+#endif

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-voip/janus.git



More information about the Pkg-voip-commits mailing list