mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-05 04:11:08 +00:00
Merge "res_pjsip: Add "webrtc" configuration option"
This commit is contained in:
@@ -1595,7 +1595,9 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi
|
||||
/* FIXME: Only use this for VP8. Additional work would have to be done to
|
||||
* fully support other video codecs */
|
||||
|
||||
if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_vp8) != AST_FORMAT_CMP_NOT_EQUAL) {
|
||||
if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_vp8) != AST_FORMAT_CMP_NOT_EQUAL ||
|
||||
(channel->session->endpoint->media.webrtc &&
|
||||
ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_h264) != AST_FORMAT_CMP_NOT_EQUAL)) {
|
||||
/* FIXME Fake RTP write, this will be sent as an RTCP packet. Ideally the
|
||||
* RTP engine would provide a way to externally write/schedule RTCP
|
||||
* packets */
|
||||
|
@@ -790,6 +790,14 @@
|
||||
; (default: 1)
|
||||
;max_video_streams= ; The maximum number of allowed negotiated video streams
|
||||
; (default: 1)
|
||||
;webrtc= ; When set to "yes" this also enables the following values that are needed
|
||||
; for webrtc: rtcp_mux, use_avpf, ice_support, and use_received_transport.
|
||||
; The following configuration settings also get defaulted as follows:
|
||||
; media_encryption=dtls
|
||||
; dtls_verify=fingerprint
|
||||
; dtls_setup=actpass
|
||||
; A dtls_cert_file and a dtls_ca_file still need to be specified.
|
||||
; Default for this option is "no"
|
||||
|
||||
;==========================AUTH SECTION OPTIONS=========================
|
||||
;[auth]
|
||||
|
@@ -690,6 +690,8 @@ struct ast_sip_endpoint_media_configuration {
|
||||
unsigned int max_video_streams;
|
||||
/*! Use BUNDLE */
|
||||
unsigned int bundle;
|
||||
/*! Enable webrtc settings and defaults */
|
||||
unsigned int webrtc;
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -2060,6 +2062,24 @@ int ast_sip_append_body(pjsip_tx_data *tdata, const char *body_text);
|
||||
*/
|
||||
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size);
|
||||
|
||||
/*!
|
||||
* \brief Create and copy a pj_str_t into a standard character buffer.
|
||||
*
|
||||
* pj_str_t is not NULL-terminated. Any place that expects a NULL-
|
||||
* terminated string needs to have the pj_str_t copied into a separate
|
||||
* buffer.
|
||||
*
|
||||
* Copies the pj_str_t contents into a newly allocated buffer pointed to
|
||||
* by dest. NULL-terminates the buffer.
|
||||
*
|
||||
* \note Caller is responsible for freeing the allocated memory.
|
||||
*
|
||||
* \param dest [out] The destination buffer
|
||||
* \param src The pj_str_t to copy
|
||||
* \retval Number of characters copied or negative value on error
|
||||
*/
|
||||
int ast_copy_pj_str2(char **dest, const pj_str_t *src);
|
||||
|
||||
/*!
|
||||
* \brief Get the looked-up endpoint on an out-of dialog request or response
|
||||
*
|
||||
|
@@ -105,6 +105,8 @@ struct ast_sip_session_media {
|
||||
int bundle_group;
|
||||
/*! \brief Whether this stream is currently bundled or not */
|
||||
unsigned int bundled;
|
||||
/*! \brief RTP/Media streams association identifier */
|
||||
char *msid;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@@ -1010,6 +1010,18 @@
|
||||
underlying transport. Note that enabling bundle will also enable the rtcp_mux option.
|
||||
</para></description>
|
||||
</configOption>
|
||||
<configOption name="webrtc" default="no">
|
||||
<synopsis>Defaults and enables some options that are relevant to WebRTC</synopsis>
|
||||
<description><para>
|
||||
When set to "yes" this also enables the following values that are needed in
|
||||
order for basic WebRTC support to work: rtcp_mux, use_avpf, ice_support, and
|
||||
use_received_transport. The following configuration settings also get defaulted
|
||||
as follows:</para>
|
||||
<para>media_encryption=dtls</para>
|
||||
<para>dtls_verify=fingerprint</para>
|
||||
<para>dtls_setup=actpass</para>
|
||||
</description>
|
||||
</configOption>
|
||||
</configObject>
|
||||
<configObject name="auth">
|
||||
<synopsis>Authentication type</synopsis>
|
||||
@@ -4244,6 +4256,18 @@ void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
|
||||
dest[chars_to_copy] = '\0';
|
||||
}
|
||||
|
||||
int ast_copy_pj_str2(char **dest, const pj_str_t *src)
|
||||
{
|
||||
int res = ast_asprintf(dest, "%.*s", (int)pj_strlen(src), pj_strbuf(src));
|
||||
|
||||
if (res < 0) {
|
||||
*dest = NULL;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int ast_sip_is_content_type(pjsip_media_type *content_type, char *type, char *subtype)
|
||||
{
|
||||
pjsip_media_type compare;
|
||||
|
@@ -2,6 +2,7 @@
|
||||
global:
|
||||
LINKER_SYMBOL_PREFIXast_sip_*;
|
||||
LINKER_SYMBOL_PREFIXast_copy_pj_str;
|
||||
LINKER_SYMBOL_PREFIXast_copy_pj_str2;
|
||||
LINKER_SYMBOL_PREFIXast_pjsip_rdata_get_endpoint;
|
||||
local:
|
||||
*;
|
||||
|
@@ -1363,8 +1363,30 @@ static int sip_endpoint_apply_handler(const struct ast_sorcery *sorcery, void *o
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (endpoint->media.bundle) {
|
||||
endpoint->media.rtcp_mux = 1;
|
||||
endpoint->media.rtcp_mux |= endpoint->media.bundle;
|
||||
|
||||
/*
|
||||
* If webrtc has been enabled then enable those attributes, and default
|
||||
* some, that are needed in order for webrtc to work.
|
||||
*/
|
||||
endpoint->media.bundle |= endpoint->media.webrtc;
|
||||
endpoint->media.rtcp_mux |= endpoint->media.webrtc;
|
||||
endpoint->media.rtp.use_avpf |= endpoint->media.webrtc;
|
||||
endpoint->media.rtp.ice_support |= endpoint->media.webrtc;
|
||||
endpoint->media.rtp.use_received_transport |= endpoint->media.webrtc;
|
||||
|
||||
if (endpoint->media.webrtc) {
|
||||
endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_DTLS;
|
||||
endpoint->media.rtp.dtls_cfg.enabled = 1;
|
||||
endpoint->media.rtp.dtls_cfg.default_setup = AST_RTP_DTLS_SETUP_ACTPASS;
|
||||
endpoint->media.rtp.dtls_cfg.verify = AST_RTP_DTLS_VERIFY_FINGERPRINT;
|
||||
|
||||
if (ast_strlen_zero(endpoint->media.rtp.dtls_cfg.certfile) ||
|
||||
(ast_strlen_zero(endpoint->media.rtp.dtls_cfg.cafile))) {
|
||||
ast_log(LOG_ERROR, "WebRTC can't be enabled on endpoint '%s' - a DTLS cert "
|
||||
"or ca file has not been specified", ast_sorcery_object_get_id(endpoint));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1990,6 +2012,7 @@ int ast_res_pjsip_initialize_configuration(void)
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_audio_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_audio_streams));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_video_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_video_streams));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "bundle", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.bundle));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "webrtc", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.webrtc));
|
||||
|
||||
if (ast_sip_initialize_sorcery_transport()) {
|
||||
ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
|
||||
|
@@ -1025,6 +1025,65 @@ static void process_ssrc_attributes(struct ast_sip_session *session, struct ast_
|
||||
}
|
||||
}
|
||||
|
||||
static void process_msid_attribute(struct ast_sip_session *session,
|
||||
struct ast_sip_session_media *session_media, pjmedia_sdp_media *media)
|
||||
{
|
||||
pjmedia_sdp_attr *attr;
|
||||
|
||||
if (!session->endpoint->media.webrtc) {
|
||||
return;
|
||||
}
|
||||
|
||||
attr = pjmedia_sdp_media_find_attr2(media, "msid", NULL);
|
||||
if (attr) {
|
||||
ast_free(session_media->msid);
|
||||
ast_copy_pj_str2(&session_media->msid, &attr->value);
|
||||
}
|
||||
}
|
||||
|
||||
static void add_msid_to_stream(struct ast_sip_session *session,
|
||||
struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
|
||||
{
|
||||
pj_str_t stmp;
|
||||
pjmedia_sdp_attr *attr;
|
||||
|
||||
if (!session->endpoint->media.webrtc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(session_media->msid)) {
|
||||
char uuid1[AST_UUID_STR_LEN], uuid2[AST_UUID_STR_LEN];
|
||||
|
||||
if (ast_asprintf(&session_media->msid, "{%s} {%s}",
|
||||
ast_uuid_generate_str(uuid1, sizeof(uuid1)),
|
||||
ast_uuid_generate_str(uuid2, sizeof(uuid2))) < 0) {
|
||||
session_media->msid = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
attr = pjmedia_sdp_attr_create(pool, "msid", pj_cstr(&stmp, session_media->msid));
|
||||
pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
|
||||
}
|
||||
|
||||
static void add_rtcp_fb_to_stream(struct ast_sip_session *session,
|
||||
struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
|
||||
{
|
||||
pj_str_t stmp;
|
||||
pjmedia_sdp_attr *attr;
|
||||
|
||||
if (!session->endpoint->media.webrtc || session_media->type != AST_MEDIA_TYPE_VIDEO) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* For now just automatically add it the stream even though it hasn't
|
||||
* necessarily been negotiated.
|
||||
*/
|
||||
attr = pjmedia_sdp_attr_create(pool, "rtcp-fb", pj_cstr(&stmp, "* ccm fir"));
|
||||
pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
|
||||
}
|
||||
|
||||
/*! \brief Function which negotiates an incoming media stream */
|
||||
static int negotiate_incoming_sdp_stream(struct ast_sip_session *session,
|
||||
struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp,
|
||||
@@ -1068,7 +1127,7 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session,
|
||||
}
|
||||
|
||||
process_ssrc_attributes(session, session_media, stream);
|
||||
|
||||
process_msid_attribute(session, session_media, stream);
|
||||
session_media_transport = ast_sip_session_media_get_transport(session, session_media);
|
||||
|
||||
if (session_media_transport == session_media || !session_media->bundled) {
|
||||
@@ -1527,6 +1586,8 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
|
||||
}
|
||||
|
||||
add_ssrc_to_stream(session, session_media, pool, media);
|
||||
add_msid_to_stream(session, session_media, pool, media);
|
||||
add_rtcp_fb_to_stream(session, session_media, pool, media);
|
||||
|
||||
/* Add the media stream to the SDP */
|
||||
sdp->media[sdp->media_count++] = media;
|
||||
|
@@ -395,6 +395,7 @@ static void session_media_dtor(void *obj)
|
||||
}
|
||||
|
||||
ast_free(session_media->mid);
|
||||
ast_free(session_media->msid);
|
||||
}
|
||||
|
||||
struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_session *session,
|
||||
@@ -3573,15 +3574,17 @@ static int add_bundle_groups(struct ast_sip_session *session, pj_pool_t *pool, p
|
||||
int index, mid_id;
|
||||
struct sip_session_media_bundle_group *bundle_group;
|
||||
|
||||
if (session->endpoint->media.webrtc) {
|
||||
attr = pjmedia_sdp_attr_create(pool, "msid-semantic", pj_cstr(&stmp, "WMS *"));
|
||||
pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr);
|
||||
}
|
||||
|
||||
if (!session->endpoint->media.bundle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(bundle_groups, 0, sizeof(bundle_groups));
|
||||
|
||||
attr = pjmedia_sdp_attr_create(pool, "msid-semantic", pj_cstr(&stmp, "WMS *"));
|
||||
pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr);
|
||||
|
||||
/* Build the bundle group layout so we can then add it to the SDP */
|
||||
for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) {
|
||||
struct ast_sip_session_media *session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
|
||||
|
Reference in New Issue
Block a user