[Pkg-voip-commits] [janus] 148/282: Made EchoTest and VideoCall recordings aware of negotiated codecs
Jonas Smedegaard
dr at jones.dk
Wed Dec 20 21:53:36 UTC 2017
This is an automated email from the git hooks/post-receive script.
js pushed a commit to annotated tag debian/0.2.6-1
in repository janus.
commit 531365e8350424aed3237d9441be2bf582482ff8
Author: Lorenzo Miniero <lminiero at gmail.com>
Date: Tue Oct 24 14:54:04 2017 +0200
Made EchoTest and VideoCall recordings aware of negotiated codecs
---
plugins/janus_echotest.c | 23 +++++++++--
plugins/janus_recordplay.c | 81 +++++++++++-------------------------
plugins/janus_videocall.c | 53 ++++++++++++++++++++++--
sdp-utils.c | 101 +++++++++++++++++++++++++++++++++++++++++++++
sdp-utils.h | 25 +++++++++++
5 files changed, 217 insertions(+), 66 deletions(-)
diff --git a/plugins/janus_echotest.c b/plugins/janus_echotest.c
index 28f3a7c..1aa0533 100644
--- a/plugins/janus_echotest.c
+++ b/plugins/janus_echotest.c
@@ -185,6 +185,8 @@ typedef struct janus_echotest_session {
gboolean has_data;
gboolean audio_active;
gboolean video_active;
+ const char *acodec; /* Codec used for audio, if available */
+ const char *vcodec; /* Codec used for video, if available */
uint32_t bitrate, peer_bitrate;
janus_rtp_switching_context context;
uint32_t ssrc[3]; /* Only needed in case VP8 simulcasting is involved */
@@ -454,6 +456,10 @@ json_t *janus_echotest_query_session(janus_plugin_session *handle) {
json_t *info = json_object();
json_object_set_new(info, "audio_active", session->audio_active ? json_true() : json_false());
json_object_set_new(info, "video_active", session->video_active ? json_true() : json_false());
+ if(session->acodec)
+ json_object_set_new(info, "audio_codec", json_string(session->acodec));
+ if(session->vcodec)
+ json_object_set_new(info, "video_codec", json_string(session->vcodec));
json_object_set_new(info, "bitrate", json_integer(session->bitrate));
json_object_set_new(info, "peer-bitrate", json_integer(session->peer_bitrate));
if(session->ssrc[0] != 0) {
@@ -816,6 +822,8 @@ void janus_echotest_hangup_media(janus_plugin_session *handle) {
session->has_data = FALSE;
session->audio_active = TRUE;
session->video_active = TRUE;
+ session->acodec = NULL;
+ session->vcodec = NULL;
session->bitrate = 0;
session->peer_bitrate = 0;
session->ssrc[0] = 0;
@@ -1052,7 +1060,7 @@ static void *janus_echotest_handler(void *data) {
if(recording_base) {
/* Use the filename and path we have been provided */
g_snprintf(filename, 255, "%s-audio", recording_base);
- session->arc = janus_recorder_create(NULL, "opus", filename);
+ session->arc = janus_recorder_create(NULL, session->acodec, filename);
if(session->arc == NULL) {
/* FIXME We should notify the fact the recorder could not be created */
JANUS_LOG(LOG_ERR, "Couldn't open an audio recording file for this EchoTest user!\n");
@@ -1060,7 +1068,7 @@ static void *janus_echotest_handler(void *data) {
} else {
/* Build a filename */
g_snprintf(filename, 255, "echotest-%p-%"SCNi64"-audio", session, now);
- session->arc = janus_recorder_create(NULL, "opus", filename);
+ session->arc = janus_recorder_create(NULL, session->acodec, filename);
if(session->arc == NULL) {
/* FIXME We should notify the fact the recorder could not be created */
JANUS_LOG(LOG_ERR, "Couldn't open an audio recording file for this EchoTest user!\n");
@@ -1073,7 +1081,7 @@ static void *janus_echotest_handler(void *data) {
if(recording_base) {
/* Use the filename and path we have been provided */
g_snprintf(filename, 255, "%s-video", recording_base);
- session->vrc = janus_recorder_create(NULL, "vp8", filename);
+ session->vrc = janus_recorder_create(NULL, session->vcodec, filename);
if(session->vrc == NULL) {
/* FIXME We should notify the fact the recorder could not be created */
JANUS_LOG(LOG_ERR, "Couldn't open an video recording file for this EchoTest user!\n");
@@ -1081,7 +1089,7 @@ static void *janus_echotest_handler(void *data) {
} else {
/* Build a filename */
g_snprintf(filename, 255, "echotest-%p-%"SCNi64"-video", session, now);
- session->vrc = janus_recorder_create(NULL, "vp8", filename);
+ session->vrc = janus_recorder_create(NULL, session->vcodec, filename);
if(session->vrc == NULL) {
/* FIXME We should notify the fact the recorder could not be created */
JANUS_LOG(LOG_ERR, "Couldn't open an video recording file for this EchoTest user!\n");
@@ -1203,6 +1211,13 @@ static void *janus_echotest_handler(void *data) {
session->ssrc[1] = 0;
session->ssrc[2] = 0;
}
+ /* Check which codecs we ended up using */
+ janus_sdp_find_first_codecs(answer, &session->acodec, &session->vcodec);
+ JANUS_LOG(LOG_WARN, "%s, %s\n", session->acodec, session->vcodec);
+ if(session->acodec == NULL)
+ session->has_audio = FALSE;
+ if(session->vcodec == NULL)
+ session->has_video = FALSE;
char *sdp = janus_sdp_write(answer);
janus_sdp_free(offer);
janus_sdp_free(answer);
diff --git a/plugins/janus_recordplay.c b/plugins/janus_recordplay.c
index dbc8da8..18634fe 100644
--- a/plugins/janus_recordplay.c
+++ b/plugins/janus_recordplay.c
@@ -428,16 +428,6 @@ void janus_recordplay_send_rtcp_feedback(janus_plugin_session *handle, int video
#define AUDIO_PT 111
#define VIDEO_PT 100
-/* Preferred codecs when negotiating audio and video to record */
-static const char *preferred_audio_codecs[] = {
- "opus", "pcmu", "pcma", "g722", "isac16", "isac32"
-};
-static uint audio_codecs = sizeof(preferred_audio_codecs)/sizeof(*preferred_audio_codecs);
-static const char *preferred_video_codecs[] = {
- "vp8", "vp9", "h264"
-};
-static uint video_codecs = sizeof(preferred_video_codecs)/sizeof(*preferred_video_codecs);
-
/* Helper method to check which codec was used in a specific recording */
static const char *janus_recordplay_parse_codec(const char *dir, const char *filename) {
if(dir == NULL || filename == NULL)
@@ -487,11 +477,11 @@ static const char *janus_recordplay_parse_codec(const char *dir, const char *fil
if(prebuffer[0] == 'v') {
JANUS_LOG(LOG_VERB, "This is an old video recording, assuming VP8\n");
fclose(file);
- return preferred_video_codecs[0];
+ return "opus";
} else if(prebuffer[0] == 'a') {
JANUS_LOG(LOG_VERB, "This is an old audio recording, assuming Opus\n");
fclose(file);
- return preferred_audio_codecs[0];
+ return "vp8";
}
}
JANUS_LOG(LOG_WARN, "Unsupported recording media type...\n");
@@ -550,14 +540,12 @@ static const char *janus_recordplay_parse_codec(const char *dir, const char *fil
return NULL;
}
const char *c = json_string_value(codec);
- uint i=0;
- for(i=0; i<(video ? video_codecs : audio_codecs); i++) {
- if(!strcasecmp(c, (video ? preferred_video_codecs[i] : preferred_audio_codecs[i]))) {
- /* Found! */
- json_decref(info);
- fclose(file);
- return video ? preferred_video_codecs[i] : preferred_audio_codecs[i];
- }
+ const char *mcodec = janus_sdp_match_preferred_codec(video ? JANUS_SDP_VIDEO : JANUS_SDP_AUDIO, (char *)c);
+ if(mcodec != NULL) {
+ /* Found! */
+ json_decref(info);
+ fclose(file);
+ return mcodec;
}
json_decref(info);
}
@@ -1290,44 +1278,21 @@ static void *janus_recordplay_handler(void *data) {
janus_mutex_init(&rec->mutex);
/* Check which codec we should record for audio and/or video */
gboolean audio = FALSE, video = FALSE;
- GList *temp = offer->m_lines;
- while(temp) {
- /* Which media are available? */
- janus_sdp_mline *m = (janus_sdp_mline *)temp->data;
- if(m->type == JANUS_SDP_AUDIO && m->port > 0 &&
- m->direction != JANUS_SDP_RECVONLY && m->direction != JANUS_SDP_INACTIVE) {
- audio = TRUE;
- if(rec->acodec == NULL) {
- uint i=0;
- for(i=0; i<audio_codecs; i++) {
- if(janus_sdp_get_codec_pt(offer, preferred_audio_codecs[i]) > 0) {
- rec->acodec = preferred_audio_codecs[i];
- break;
- }
- }
- if(rec->acodec == NULL) {
- JANUS_LOG(LOG_WARN, "No supported audio codec found..?\n");
- audio = FALSE;
- }
- }
- } else if(m->type == JANUS_SDP_VIDEO && m->port > 0 &&
- m->direction != JANUS_SDP_RECVONLY && m->direction != JANUS_SDP_INACTIVE) {
- video = TRUE;
- if(rec->vcodec == NULL) {
- uint i=0;
- for(i=0; i<video_codecs; i++) {
- if(janus_sdp_get_codec_pt(offer, preferred_video_codecs[i]) > 0) {
- rec->vcodec = preferred_video_codecs[i];
- break;
- }
- }
- if(rec->vcodec == NULL) {
- JANUS_LOG(LOG_WARN, "No supported video codec found..?\n");
- video = FALSE;
- }
- }
- }
- temp = temp->next;
+ janus_sdp_find_preferred_codecs(offer, &rec->acodec, &rec->vcodec);
+ /* We found preferred codecs: let's just make sure the direction is what we need */
+ janus_sdp_mline *m = janus_sdp_mline_find(offer, JANUS_SDP_AUDIO);
+ if(m != NULL && m->direction == JANUS_SDP_RECVONLY)
+ rec->acodec = NULL;
+ audio = (rec->acodec != NULL);
+ if(audio) {
+ JANUS_LOG(LOG_WARN, "Audio codec: %s\n", rec->acodec);
+ }
+ m = janus_sdp_mline_find(offer, JANUS_SDP_VIDEO);
+ if(m != NULL && m->direction == JANUS_SDP_RECVONLY)
+ rec->vcodec = NULL;
+ video = (rec->vcodec != NULL);
+ if(video) {
+ JANUS_LOG(LOG_WARN, "Video codec: %s\n", rec->acodec);
}
rec->audio_pt = AUDIO_PT;
if(rec->acodec) {
diff --git a/plugins/janus_videocall.c b/plugins/janus_videocall.c
index c37b077..f2be10d 100644
--- a/plugins/janus_videocall.c
+++ b/plugins/janus_videocall.c
@@ -238,6 +238,7 @@
#include "../record.h"
#include "../rtp.h"
#include "../rtcp.h"
+#include "../sdp-utils.h"
#include "../utils.h"
@@ -361,6 +362,8 @@ typedef struct janus_videocall_session {
gboolean has_data;
gboolean audio_active;
gboolean video_active;
+ const char *acodec; /* Codec used for audio, if available */
+ const char *vcodec; /* Codec used for video, if available */
uint32_t bitrate;
guint16 slowlink_count;
struct janus_videocall_session *peer;
@@ -401,6 +404,7 @@ static janus_mutex sessions_mutex = JANUS_MUTEX_INITIALIZER;
#define JANUS_VIDEOCALL_ERROR_ALREADY_IN_CALL 480
#define JANUS_VIDEOCALL_ERROR_NO_CALL 481
#define JANUS_VIDEOCALL_ERROR_MISSING_SDP 482
+#define JANUS_VIDEOCALL_ERROR_INVALID_SDP 483
/* VideoCall watchdog/garbage collector (sort of) */
@@ -628,6 +632,11 @@ json_t *janus_videocall_query_session(janus_plugin_session *handle) {
json_object_set_new(info, "peer", session->peer->username ? json_string(session->peer->username) : NULL);
json_object_set_new(info, "audio_active", session->audio_active ? json_true() : json_false());
json_object_set_new(info, "video_active", session->video_active ? json_true() : json_false());
+ if(session->acodec)
+ json_object_set_new(info, "audio_codec", json_string(session->acodec));
+ if(session->vcodec)
+ json_object_set_new(info, "video_codec", json_string(session->vcodec));
+ json_object_set_new(info, "video_active", session->video_active ? json_true() : json_false());
json_object_set_new(info, "bitrate", json_integer(session->bitrate));
json_object_set_new(info, "slowlink_count", json_integer(session->slowlink_count));
}
@@ -1011,6 +1020,8 @@ void janus_videocall_hangup_media(janus_plugin_session *handle) {
session->has_data = FALSE;
session->audio_active = TRUE;
session->video_active = TRUE;
+ session->acodec = NULL;
+ session->vcodec = NULL;
session->bitrate = 0;
janus_rtp_switching_context_reset(&session->context);
}
@@ -1185,6 +1196,15 @@ static void *janus_videocall_handler(void *data) {
g_snprintf(error_cause, 512, "Missing SDP");
goto error;
}
+ char error_str[512];
+ janus_sdp *offer = janus_sdp_parse(msg_sdp, error_str, sizeof(error_str));
+ if(offer == NULL) {
+ JANUS_LOG(LOG_ERR, "Error parsing offer: %s\n", error_str);
+ error_code = JANUS_VIDEOCALL_ERROR_INVALID_SDP;
+ g_snprintf(error_cause, 512, "Error parsing offer: %s", error_str);
+ goto error;
+ }
+ janus_sdp_free(offer);
janus_mutex_lock(&sessions_mutex);
session->peer = peer;
peer->peer = session;
@@ -1240,6 +1260,14 @@ static void *janus_videocall_handler(void *data) {
g_snprintf(error_cause, 512, "Missing SDP");
goto error;
}
+ char error_str[512];
+ janus_sdp *answer = janus_sdp_parse(msg_sdp, error_str, sizeof(error_str));
+ if(answer == NULL) {
+ JANUS_LOG(LOG_ERR, "Error parsing answer: %s\n", error_str);
+ error_code = JANUS_VIDEOCALL_ERROR_INVALID_SDP;
+ g_snprintf(error_cause, 512, "Error parsing answer: %s", error_str);
+ goto error;
+ }
JANUS_LOG(LOG_VERB, "%s is accepting a call from %s\n", session->username, session->peer->username);
JANUS_LOG(LOG_VERB, "This is involving a negotiation (%s) as well:\n%s\n", msg_sdp_type, msg_sdp);
session->has_audio = (strstr(msg_sdp, "m=audio") != NULL);
@@ -1262,6 +1290,23 @@ static void *janus_videocall_handler(void *data) {
session->peer->ssrc[2] = 0;
}
}
+ /* Check which codecs we ended up using */
+ janus_sdp_find_first_codecs(answer, &session->acodec, &session->vcodec);
+ if(session->acodec == NULL) {
+ session->has_audio = FALSE;
+ if(session->peer)
+ session->peer->has_audio = FALSE;
+ } else if(session->peer) {
+ session->peer->acodec = session->acodec;
+ }
+ if(session->vcodec == NULL) {
+ session->has_video = FALSE;
+ if(session->peer)
+ session->peer->has_video = FALSE;
+ } else if(session->peer) {
+ session->peer->vcodec = session->vcodec;
+ }
+ janus_sdp_free(answer);
/* Send SDP to our peer */
json_t *jsep = json_pack("{ssss}", "type", msg_sdp_type, "sdp", msg_sdp);
json_t *call = json_object();
@@ -1372,7 +1417,7 @@ static void *janus_videocall_handler(void *data) {
if(recording_base) {
/* Use the filename and path we have been provided */
g_snprintf(filename, 255, "%s-audio", recording_base);
- session->arc = janus_recorder_create(NULL, "opus", filename);
+ session->arc = janus_recorder_create(NULL, session->acodec, filename);
if(session->arc == NULL) {
/* FIXME We should notify the fact the recorder could not be created */
JANUS_LOG(LOG_ERR, "Couldn't open an audio recording file for this VideoCall user!\n");
@@ -1383,7 +1428,7 @@ static void *janus_videocall_handler(void *data) {
session->username ? session->username : "unknown",
(session->peer && session->peer->username) ? session->peer->username : "unknown",
now);
- session->arc = janus_recorder_create(NULL, "opus", filename);
+ session->arc = janus_recorder_create(NULL, session->acodec, filename);
if(session->arc == NULL) {
/* FIXME We should notify the fact the recorder could not be created */
JANUS_LOG(LOG_ERR, "Couldn't open an audio recording file for this VideoCall user!\n");
@@ -1396,7 +1441,7 @@ static void *janus_videocall_handler(void *data) {
if(recording_base) {
/* Use the filename and path we have been provided */
g_snprintf(filename, 255, "%s-video", recording_base);
- session->vrc = janus_recorder_create(NULL, "vp8", filename);
+ session->vrc = janus_recorder_create(NULL, session->vcodec, filename);
if(session->vrc == NULL) {
/* FIXME We should notify the fact the recorder could not be created */
JANUS_LOG(LOG_ERR, "Couldn't open an video recording file for this VideoCall user!\n");
@@ -1407,7 +1452,7 @@ static void *janus_videocall_handler(void *data) {
session->username ? session->username : "unknown",
(session->peer && session->peer->username) ? session->peer->username : "unknown",
now);
- session->vrc = janus_recorder_create(NULL, "vp8", filename);
+ session->vrc = janus_recorder_create(NULL, session->vcodec, filename);
if(session->vrc == NULL) {
/* FIXME We should notify the fact the recorder could not be created */
JANUS_LOG(LOG_ERR, "Couldn't open an video recording file for this VideoCall user!\n");
diff --git a/sdp-utils.c b/sdp-utils.c
index 5c853ca..66961f2 100644
--- a/sdp-utils.c
+++ b/sdp-utils.c
@@ -20,6 +20,16 @@
#define JANUS_BUFSIZE 8192
+/* Preferred codecs when negotiating audio/video, and number of supported codecs */
+const char *janus_preferred_audio_codecs[] = {
+ "opus", "pcmu", "pcma", "g722", "isac16", "isac32"
+};
+uint janus_audio_codecs = sizeof(janus_preferred_audio_codecs)/sizeof(*janus_preferred_audio_codecs);
+const char *janus_preferred_video_codecs[] = {
+ "vp8", "vp9", "h264"
+};
+uint janus_video_codecs = sizeof(janus_preferred_video_codecs)/sizeof(*janus_preferred_video_codecs);
+
void janus_sdp_free(janus_sdp *sdp) {
if(!sdp)
return;
@@ -785,6 +795,97 @@ char *janus_sdp_write(janus_sdp *imported) {
return sdp;
}
+void janus_sdp_find_preferred_codecs(janus_sdp *sdp, const char **acodec, const char **vcodec) {
+ if(sdp == NULL)
+ return;
+ gboolean audio = FALSE, video = FALSE;
+ GList *temp = sdp->m_lines;
+ while(temp) {
+ /* Which media are available? */
+ janus_sdp_mline *m = (janus_sdp_mline *)temp->data;
+ if(m->type == JANUS_SDP_AUDIO && m->port > 0 && m->direction != JANUS_SDP_INACTIVE) {
+ if(audio == FALSE) {
+ uint i=0;
+ for(i=0; i<janus_audio_codecs; i++) {
+ if(janus_sdp_get_codec_pt(sdp, janus_preferred_audio_codecs[i]) > 0) {
+ audio = TRUE;
+ if(acodec)
+ *acodec = janus_preferred_audio_codecs[i];
+ break;
+ }
+ }
+ }
+ } else if(m->type == JANUS_SDP_VIDEO && m->port > 0 && m->direction != JANUS_SDP_INACTIVE) {
+ if(video == FALSE) {
+ uint i=0;
+ for(i=0; i<janus_video_codecs; i++) {
+ if(janus_sdp_get_codec_pt(sdp, janus_preferred_video_codecs[i]) > 0) {
+ if(vcodec)
+ *vcodec = janus_preferred_video_codecs[i];
+ break;
+ }
+ }
+ }
+ }
+ if(audio && video)
+ break;
+ temp = temp->next;
+ }
+}
+
+void janus_sdp_find_first_codecs(janus_sdp *sdp, const char **acodec, const char **vcodec) {
+ if(sdp == NULL)
+ return;
+ gboolean audio = FALSE, video = FALSE;
+ GList *temp = sdp->m_lines;
+ while(temp) {
+ /* Which media are available? */
+ janus_sdp_mline *m = (janus_sdp_mline *)temp->data;
+ if(m->type == JANUS_SDP_AUDIO && m->port > 0 && m->direction != JANUS_SDP_INACTIVE) {
+ if(audio == FALSE && m->ptypes) {
+ int pt = GPOINTER_TO_INT(m->ptypes->data);
+ const char *codec = janus_sdp_get_codec_name(sdp, pt);
+ codec = janus_sdp_match_preferred_codec(m->type, (char *)codec);
+ if(codec) {
+ audio = TRUE;
+ if(acodec)
+ *acodec = codec;
+ }
+ }
+ } else if(m->type == JANUS_SDP_VIDEO && m->port > 0 && m->direction != JANUS_SDP_INACTIVE) {
+ if(video == FALSE && m->ptypes) {
+ int pt = GPOINTER_TO_INT(m->ptypes->data);
+ const char *codec = janus_sdp_get_codec_name(sdp, pt);
+ codec = janus_sdp_match_preferred_codec(m->type, (char *)codec);
+ if(codec) {
+ video = TRUE;
+ if(vcodec)
+ *vcodec = codec;
+ }
+ }
+ }
+ if(audio && video)
+ break;
+ temp = temp->next;
+ }
+}
+
+const char *janus_sdp_match_preferred_codec(janus_sdp_mtype type, char *codec) {
+ if(codec == NULL)
+ return NULL;
+ if(type != JANUS_SDP_AUDIO && type != JANUS_SDP_VIDEO)
+ return NULL;
+ gboolean video = (type == JANUS_SDP_VIDEO);
+ uint i=0;
+ for(i=0; i<(video ? janus_video_codecs : janus_audio_codecs); i++) {
+ if(!strcasecmp(codec, (video ? janus_preferred_video_codecs[i] : janus_preferred_audio_codecs[i]))) {
+ /* Found! */
+ return video ? janus_preferred_video_codecs[i] : janus_preferred_audio_codecs[i];
+ }
+ }
+ return NULL;
+}
+
janus_sdp *janus_sdp_new(const char *name, const char *address) {
janus_sdp *sdp = g_malloc0(sizeof(janus_sdp));
/* Fill in some predefined stuff */
diff --git a/sdp-utils.h b/sdp-utils.h
index ba21c7b..24003e8 100644
--- a/sdp-utils.h
+++ b/sdp-utils.h
@@ -93,6 +93,31 @@ janus_sdp_mdirection janus_sdp_parse_mdirection(const char *direction);
* @returns The direction as a string, if valid, or NULL otherwise */
const char *janus_sdp_mdirection_str(janus_sdp_mdirection direction);
+/*! \brief Helper method to return the preferred audio and video codecs in an SDP offer or answer,
+ * (where by preferred we mean the codecs we prefer ourselves, and not the m-line SDP order)
+ * as long as the m-line direction is not disabled (port=0 or direction=inactive) in the SDP
+ * \note The acodec and vcodec arguments are input/output, and they'll be set to a static value
+ * in janus_preferred_audio_codecs and janus_preferred_video_codecs, so don't free them.
+ * @param[in] sdp The Janus SDP object to parse
+ * @param[out] acodec The audio codec that was found
+ * @param[out] vcodec The video codec that was found */
+void janus_sdp_find_preferred_codecs(janus_sdp *sdp, const char **acodec, const char **vcodec);
+/*! \brief Helper method to return the first audio and video codecs in an SDP offer or answer,
+ * (no matter whether we personally prefer them ourselves or not)
+ * as long as the m-line direction is not disabled (port=0 or direction=inactive) in the SDP
+ * \note The acodec and vcodec arguments are input/output, and they'll be set to a static value
+ * in janus_preferred_audio_codecs and janus_preferred_video_codecs, so don't free them.
+ * @param[in] sdp The Janus SDP object to parse
+ * @param[out] acodec The audio codec that was found
+ * @param[out] vcodec The video codec that was found */
+void janus_sdp_find_first_codecs(janus_sdp *sdp, const char **acodec, const char **vcodec);
+/*! \brief Helper method to match a codec to one of the preferred codecs
+ * \note Don't free the returned value, as it's a constant value
+ * @param[in] type The type of media to match
+ * @param[in] codec The codec to match
+ * @returns The codec, if found, or NULL otherwise */
+const char *janus_sdp_match_preferred_codec(janus_sdp_mtype type, char *codec);
+
/*! \brief SDP m-line representation */
typedef struct janus_sdp_mline {
/*! \brief Media type as a janus_sdp_mtype enumerator */
--
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