diff --git a/sdp-utils.c b/sdp-utils.c index eee3359f26..a8bdbe909d 100644 --- a/sdp-utils.c +++ b/sdp-utils.c @@ -659,7 +659,7 @@ int janus_sdp_get_codec_pt_full(janus_sdp *sdp, const char *codec, const char *p if(sdp == NULL || codec == NULL) return -1; /* Check the format string (note that we only parse what browsers can negotiate) */ - gboolean video = FALSE, vp9 = FALSE, h264 = FALSE; + gboolean video = FALSE, vp9 = FALSE, av1 = FALSE, h264 = FALSE; const char *format = NULL, *format2 = NULL; if(!strcasecmp(codec, "opus")) { format = "opus/48000/2"; @@ -734,7 +734,7 @@ int janus_sdp_get_codec_pt_full(janus_sdp *sdp, const char *codec, const char *p if(pt < 0) { JANUS_LOG(LOG_ERR, "Invalid payload type (%s)\n", a->value); } else if(strstr(a->value, format) || strstr(a->value, format2)) { - if(profile != NULL && (vp9 || h264)) { + if(profile != NULL && (vp9 || h264 || av1)) { /* Let's keep track of this payload type */ pts = g_list_append(pts, GINT_TO_POINTER(pt)); } else { @@ -790,6 +790,15 @@ int janus_sdp_get_codec_pt_full(janus_sdp *sdp, const char *codec, const char *p g_list_free(pts); return pt; } + } else if(av1) { + char av1_profile[20]; + g_snprintf(av1_profile, sizeof(profile), "profile=%s", profile); + if(strstr(a->value, av1_profile) != NULL) { + /* Found */ + JANUS_LOG(LOG_VERB, "AV1 profile %s found --> %d\n", profile, pt); + g_list_free(pts); + return pt; + } } } ma = ma->next; @@ -1214,8 +1223,8 @@ janus_sdp *janus_sdp_generate_offer(const char *name, const char *address, ...) gboolean do_audio = TRUE, do_video = TRUE, do_data = TRUE, audio_dtmf = FALSE, video_rtcpfb = TRUE, data_legacy = TRUE; const char *audio_codec = NULL, *video_codec = NULL, - *vp9_profile = NULL, *h264_profile = NULL, - *audio_fmtp = NULL, *video_fmtp = NULL; + *vp9_profile = NULL, *av1_profile = NULL, *av1_level_idx = NULL, + *av1_tier = NULL, *h264_profile = NULL, *audio_fmtp = NULL, *video_fmtp = NULL; int audio_pt = 111, video_pt = 96, opusred_pt = 0; janus_sdp_mdirection audio_dir = JANUS_SDP_SENDRECV, video_dir = JANUS_SDP_SENDRECV; GHashTable *audio_extmaps = NULL, *audio_extids = NULL, @@ -1238,6 +1247,12 @@ janus_sdp *janus_sdp_generate_offer(const char *name, const char *address, ...) video_codec = va_arg(args, char *); } else if(property == JANUS_SDP_OA_VP9_PROFILE) { vp9_profile = va_arg(args, char *); + } else if(property == JANUS_SDP_OA_AV1_PROFILE) { + av1_profile = va_arg(args, char *); + } else if(property == JANUS_SDP_OA_AV1_LEVEL_IDX) { + av1_level_idx = va_arg(args, char *); + } else if(property == JANUS_SDP_OA_AV1_TIER) { + av1_tier = va_arg(args, char *); } else if(property == JANUS_SDP_OA_H264_PROFILE) { h264_profile = va_arg(args, char *); } else if(property == JANUS_SDP_OA_AUDIO_PT) { @@ -1430,6 +1445,13 @@ janus_sdp *janus_sdp_generate_offer(const char *name, const char *address, ...) /* Add a profile-id fmtp attribute */ a = janus_sdp_attribute_create("fmtp", "%d profile-id=%s", video_pt, vp9_profile); m->attributes = g_list_append(m->attributes, a); + } else if(!strcasecmp(video_codec, "av1")) { + /* Add a profile fmtp attribute */ + a = janus_sdp_attribute_create("fmtp", "%d profile=%s;level-idx=%s;tier=%s", + video_pt, av1_profile ? av1_profile : "0", /* If not present, it MUST be inferred to be 0 ("Main" profile). */ + av1_level_idx ? av1_level_idx : "5", /* If not present, it MUST be inferred to be 5. */ + av1_tier ? av1_tier : "0"); /* If not present, it MUST be inferred to be 0. */ + m->attributes = g_list_append(m->attributes, a); } else if(!strcasecmp(video_codec, "h264") && h264_profile) { /* Add a profile-level-id fmtp attribute */ a = janus_sdp_attribute_create("fmtp", "%d profile-level-id=%s;packetization-mode=1", video_pt, h264_profile); @@ -1484,8 +1506,8 @@ janus_sdp *janus_sdp_generate_answer(janus_sdp *offer, ...) { gboolean do_audio = TRUE, do_video = TRUE, do_data = TRUE, audio_dtmf = FALSE, audio_opusred = FALSE, video_rtcpfb = TRUE; const char *audio_codec = NULL, *video_codec = NULL, - *vp9_profile = NULL, *h264_profile = NULL, - *audio_fmtp = NULL, *video_fmtp = NULL; + *vp9_profile = NULL, *av1_profile = NULL, *av1_level_idx = NULL, *av1_tier = NULL, + *h264_profile = NULL, *audio_fmtp = NULL, *video_fmtp = NULL; char *custom_audio_fmtp = NULL; GList *extmaps = NULL; janus_sdp_mdirection audio_dir = JANUS_SDP_SENDRECV, video_dir = JANUS_SDP_SENDRECV; @@ -1507,6 +1529,12 @@ janus_sdp *janus_sdp_generate_answer(janus_sdp *offer, ...) { video_codec = va_arg(args, char *); } else if(property == JANUS_SDP_OA_VP9_PROFILE) { vp9_profile = va_arg(args, char *); + } else if(property == JANUS_SDP_OA_AV1_PROFILE) { + av1_profile = va_arg(args, char *); + } else if(property == JANUS_SDP_OA_AV1_LEVEL_IDX) { + av1_level_idx = va_arg(args, char *); + } else if(property == JANUS_SDP_OA_AV1_TIER) { + av1_tier = va_arg(args, char *); } else if(property == JANUS_SDP_OA_H264_PROFILE) { h264_profile = va_arg(args, char *); } else if(property == JANUS_SDP_OA_AUDIO_DTMF) { @@ -1704,6 +1732,8 @@ janus_sdp *janus_sdp_generate_answer(janus_sdp *offer, ...) { const char *video_profile = NULL; if(codec && !strcasecmp(codec, "vp9")) video_profile = vp9_profile; + else if(codec && !strcasecmp(codec, "av1")) + video_profile = av1_profile; else if(codec && !strcasecmp(codec, "h264")) video_profile = h264_profile; int pt = janus_sdp_get_codec_pt_full(offer, codec, video_profile); @@ -1802,6 +1832,13 @@ janus_sdp *janus_sdp_generate_answer(janus_sdp *offer, ...) { /* Add a profile-id fmtp attribute */ a = janus_sdp_attribute_create("fmtp", "%d profile-id=%s", pt, vp9_profile); am->attributes = g_list_append(am->attributes, a); + } else if(!strcasecmp(codec, "av1")) { + /* Add a profile fmtp attribute */ + a = janus_sdp_attribute_create("fmtp", "%d profile=%s;level-idx=%s;tier=%s", pt, + av1_profile ? av1_profile : "0", + av1_level_idx ? av1_level_idx : "5", + av1_tier ? av1_tier : "0"); + am->attributes = g_list_append(am->attributes, a); } else if(!strcasecmp(codec, "h264") && h264_profile) { /* Add a profile-level-id fmtp attribute */ a = janus_sdp_attribute_create("fmtp", "%d profile-level-id=%s;packetization-mode=1", pt, h264_profile); @@ -1856,6 +1893,7 @@ janus_sdp *janus_sdp_generate_answer(janus_sdp *offer, ...) { /* Check if we need to copy the fmtp attribute too */ if(((!strcasecmp(codec, "vp8") && video_fmtp == NULL)) || ((!strcasecmp(codec, "vp9") && vp9_profile == NULL && video_fmtp == NULL)) || + ((!strcasecmp(codec, "av1") && av1_profile == NULL && av1_tier == NULL && av1_level_idx == NULL && video_fmtp == NULL)) || ((!strcasecmp(codec, "h264") && h264_profile == NULL && video_fmtp == NULL))) { /* FIXME Copy the fmtp attribute (we should check if we support it) */ a = janus_sdp_attribute_create("fmtp", "%s", a->value); diff --git a/sdp-utils.h b/sdp-utils.h index fc8de95257..10200fb0c1 100644 --- a/sdp-utils.h +++ b/sdp-utils.h @@ -262,6 +262,12 @@ JANUS_SDP_OA_AUDIO_CODEC, JANUS_SDP_OA_VIDEO_CODEC, /*! \brief When generating an offer or answer automatically, use this profile for VP9 (depends on value that follows) */ JANUS_SDP_OA_VP9_PROFILE, +/*! \brief When generating an offer or answer automatically, use this profile for AV1 (depends on value that follows) */ +JANUS_SDP_OA_AV1_PROFILE, +/*! \brief When generating an offer or answer automatically, use this level-idx for AV1 (depends on value that follows) */ +JANUS_SDP_OA_AV1_LEVEL_IDX, +/*! \brief When generating an offer or answer automatically, use this tier for AV1 (depends on value that follows) */ +JANUS_SDP_OA_AV1_TIER, /*! \brief When generating an offer or answer automatically, use this profile for H.264 (depends on value that follows) */ JANUS_SDP_OA_H264_PROFILE, /*! \brief When generating an offer (this is ignored for answers), use this payload type for audio (depends on value that follows) */