Skip to content

Commit b04234c

Browse files
Add support for "progress" request on SIP Plugin (#3466)
1 parent bcdaf4e commit b04234c

File tree

1 file changed

+83
-35
lines changed

1 file changed

+83
-35
lines changed

src/plugins/janus_sip.c

+83-35
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,18 @@
3636
* as events with the same transaction.
3737
*
3838
* The supported requests are \c register , \c unregister , \c call ,
39-
* \c accept, \c decline , \c info , \c message , \c dtmf_info ,
39+
* \progress , \c accept , \c decline , \c info , \c message , \c dtmf_info ,
4040
* \c subscribe , \c unsubscribe , \c transfer , \c recording ,
4141
* \c hold , \c unhold , \c update and \c hangup . \c register can be used,
4242
* as the name suggests, to register a username at a SIP registrar to
4343
* call and be called, while \c unregister unregisters it; \c call is used
44-
* to send an INVITE to a different SIP URI through the plugin, while
45-
* \c accept and \c decline are used to accept or reject the call in
46-
* case one is invited instead of inviting; \c transfer takes care of
47-
* attended and blind transfers (see \ref siptr for more details);
48-
* \c hold and \c unhold can be used respectively to put a
44+
* to send an INVITE to a different SIP URI through the plugin; in case one
45+
* is invited instead of inviting, \c progress, \c accept and \c decline
46+
* requests may be used. \c progress request is optional, and it is used to
47+
* send 183 Session Progress response back to the caller, while
48+
* \c accept and \c decline are used to accept or reject the call respectively;
49+
* \c transfer takes care of attended and blind transfers (see \ref siptr for
50+
* more details); \c hold and \c unhold can be used respectively to put a
4951
* call on-hold and to resume it; \c info allows you to send a generic
5052
* SIP INFO request, while \c dtmf_info is focused on using INFO for DTMF
5153
* instead; \c message is the method you use to send a SIP message
@@ -299,8 +301,28 @@
299301
\endverbatim
300302
*
301303
* The \c incomingcall may or may not be accompanied by a JSEP offer, depending
302-
* on whether the caller sent an offerless INVITE or a regular one. Either
303-
* way, you can accept the incoming call with the \c accept request:
304+
* on whether the caller sent an offerless INVITE or a regular one. Optionally,
305+
* you can progress the incoming call with the \c progress request:
306+
*
307+
\verbatim
308+
{
309+
"request" : "progress",
310+
"srtp" : "<whether to mandate (sdes_mandatory) or offer (sdes_optional) SRTP support; optional>",
311+
"headers" : "<object with key/value mappings (header name/value), to specify custom headers to add to the SIP OK; optional>"
312+
"autoaccept_reinvites" : <true|false, whether we should blindly accept re-INVITEs with a 200 OK instead of relaying the SDP to the browser; optional, TRUE by default>
313+
}
314+
\endverbatim
315+
*
316+
* A \c progressing event will be sent back, as this is an asynchronous request.
317+
*
318+
* This will result in a <code>183 Session Progress</code> to be sent back to the caller.
319+
* A \c progress request must always be accompanied by a JSEP answer (if the
320+
* \c incomingcall event contained an offer) or offer (in case it was an
321+
* offerless INVITE). This request can be used to inform the caller that the early
322+
* media is available, such as ringback audio, announcements or other audio streams,
323+
* without the call being fully established.
324+
*
325+
* Furthermore, you can accept the incoming call with the \c accept request:
304326
*
305327
\verbatim
306328
{
@@ -314,13 +336,13 @@
314336
* An \c accepting event will be sent back, as this is an asynchronous request.
315337
*
316338
* This will result in a <code>200 OK</code> to be sent back to the caller.
317-
* An \c accept request must always be accompanied by a JSEP answer (if the
318-
* \c incomingcall event contained an offer) or offer (in case it was an
319-
* offerless INVITE). In the former case, an \c accepted event will be
320-
* sent back just to confirm the call can be considered established;
321-
* in the latter case, instead, an \c accepting event will be sent back
322-
* instead, and an \c accepted event will only follow later, as soon as
323-
* a JSEP answer is available in the SIP ACK the caller sent back.
339+
* As was the case for \c progress request, an \c accept request must always
340+
* be accompanied by a JSEP answer (if the \c incomingcall event contained an
341+
* offer) or offer (in case it was an offerless INVITE). In the former case,
342+
* an \c accepted event will be sent back just to confirm the call can be
343+
* considered established; in the latter case, instead, an \c accepting event
344+
* will be sent back instead, and an \c accepted event will only follow later,
345+
* as soon as a JSEP answer is available in the SIP ACK the caller sent back.
324346
*
325347
* Notice that in case you get an incoming call while you're in another
326348
* call, you will NOT get an \c incomingcall event, but a \c missed_call
@@ -808,6 +830,11 @@ static struct janus_json_parameter accept_parameters[] = {
808830
{"headers", JSON_OBJECT, 0},
809831
{"autoaccept_reinvites", JANUS_JSON_BOOL, 0}
810832
};
833+
static struct janus_json_parameter progress_parameters[] = {
834+
{"srtp", JSON_STRING, 0},
835+
{"headers", JSON_OBJECT, 0},
836+
{"autoaccept_reinvites", JANUS_JSON_BOOL, 0}
837+
};
811838
static struct janus_json_parameter decline_parameters[] = {
812839
{"code", JANUS_JSON_INTEGER, 0},
813840
{"headers", JSON_OBJECT, 0},
@@ -920,6 +947,7 @@ typedef enum {
920947
janus_sip_call_status_idle = 0,
921948
janus_sip_call_status_inviting,
922949
janus_sip_call_status_invited,
950+
janus_sip_call_status_progress,
923951
janus_sip_call_status_incall,
924952
janus_sip_call_status_incall_reinviting,
925953
janus_sip_call_status_incall_reinvited,
@@ -934,6 +962,8 @@ static const char *janus_sip_call_status_string(janus_sip_call_status status) {
934962
return "inviting";
935963
case janus_sip_call_status_invited:
936964
return "invited";
965+
case janus_sip_call_status_progress:
966+
return "progress";
937967
case janus_sip_call_status_incall:
938968
return "incall";
939969
case janus_sip_call_status_incall_reinviting:
@@ -2551,7 +2581,7 @@ void janus_sip_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp *pack
25512581
JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
25522582
return;
25532583
}
2554-
if(!janus_sip_call_is_established(session))
2584+
if(!janus_sip_call_is_established(session) && session->status != janus_sip_call_status_progress)
25552585
return;
25562586
gboolean video = packet->video;
25572587
char *buf = packet->buffer;
@@ -2679,7 +2709,7 @@ void janus_sip_incoming_rtcp(janus_plugin_session *handle, janus_plugin_rtcp *pa
26792709
JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
26802710
return;
26812711
}
2682-
if(!janus_sip_call_is_established(session))
2712+
if(!janus_sip_call_is_established(session) && session->status != janus_sip_call_status_progress)
26832713
return;
26842714
gboolean video = packet->video;
26852715
char *buf = packet->buffer;
@@ -3937,13 +3967,20 @@ static void *janus_sip_handler(void *data) {
39373967
result = json_object();
39383968
json_object_set_new(result, "event", json_string("calling"));
39393969
json_object_set_new(result, "call_id", json_string(session->callid));
3940-
} else if(!strcasecmp(request_text, "accept")) {
3941-
if(session->status != janus_sip_call_status_invited) {
3970+
} else if(!strcasecmp(request_text, "accept") || !strcasecmp(request_text, "progress")) {
3971+
gboolean progress = !strcasecmp(request_text, "progress");
3972+
if(progress && session->status != janus_sip_call_status_invited) {
39423973
JANUS_LOG(LOG_ERR, "Wrong state (not invited? status=%s)\n", janus_sip_call_status_string(session->status));
39433974
error_code = JANUS_SIP_ERROR_WRONG_STATE;
39443975
g_snprintf(error_cause, 512, "Wrong state (not invited? status=%s)", janus_sip_call_status_string(session->status));
39453976
goto error;
39463977
}
3978+
if(!progress && session->status != janus_sip_call_status_invited && session->status != janus_sip_call_status_progress) {
3979+
JANUS_LOG(LOG_ERR, "Wrong state (not invited or progress? status=%s)\n", janus_sip_call_status_string(session->status));
3980+
error_code = JANUS_SIP_ERROR_WRONG_STATE;
3981+
g_snprintf(error_cause, 512, "Wrong state (not invited or progress? status=%s)", janus_sip_call_status_string(session->status));
3982+
goto error;
3983+
}
39473984
janus_mutex_lock(&session->mutex);
39483985
if(session->callee == NULL) {
39493986
janus_mutex_unlock(&session->mutex);
@@ -3953,7 +3990,8 @@ static void *janus_sip_handler(void *data) {
39533990
goto error;
39543991
}
39553992
janus_mutex_unlock(&session->mutex);
3956-
JANUS_VALIDATE_JSON_OBJECT(root, accept_parameters,
3993+
struct janus_json_parameter *params = progress ? progress_parameters : accept_parameters;
3994+
JANUS_VALIDATE_JSON_OBJECT(root, params,
39573995
error_code, error_cause, TRUE,
39583996
JANUS_SIP_ERROR_MISSING_ELEMENT, JANUS_SIP_ERROR_INVALID_ELEMENT);
39593997
if(error_code != 0)
@@ -3982,9 +4020,9 @@ static void *janus_sip_handler(void *data) {
39824020
if(session->media.has_video)
39834021
has_srtp = (has_srtp && session->media.has_srtp_remote_video);
39844022
if(session->media.require_srtp && !has_srtp) {
3985-
JANUS_LOG(LOG_ERR, "Can't accept the call: SDES-SRTP required, but caller didn't offer it\n");
4023+
JANUS_LOG(LOG_ERR, "Can't %s the call: SDES-SRTP required, but caller didn't offer it\n", progress ? "progress" : "accept");
39864024
error_code = JANUS_SIP_ERROR_TOO_STRICT;
3987-
g_snprintf(error_cause, 512, "Can't accept the call: SDES-SRTP required, but caller didn't offer it");
4025+
g_snprintf(error_cause, 512, "Can't %s the call: SDES-SRTP required, but caller didn't offer it", progress ? "progress" : "accept");
39884026
goto error;
39894027
}
39904028
answer_srtp = answer_srtp || session->media.has_srtp_remote_audio || session->media.has_srtp_remote_video;
@@ -4006,8 +4044,8 @@ static void *janus_sip_handler(void *data) {
40064044
g_snprintf(error_cause, 512, "Media encryption unsupported by this plugin");
40074045
goto error;
40084046
}
4009-
/* Accept a call from another peer */
4010-
JANUS_LOG(LOG_VERB, "We're accepting the call from %s\n", session->callee);
4047+
/* Accept/Progress a call from another peer */
4048+
JANUS_LOG(LOG_VERB, "We're %s the call from %s\n", progress ? "progressing" : "accepting", session->callee);
40114049
gboolean answer = !strcasecmp(msg_sdp_type, "answer");
40124050
if(!answer) {
40134051
JANUS_LOG(LOG_VERB, "This is a response to an offerless INVITE\n");
@@ -4042,7 +4080,7 @@ static void *janus_sip_handler(void *data) {
40424080
session->media.has_video = TRUE; /* FIXME Maybe we need a better way to signal this */
40434081
}
40444082
janus_mutex_lock(&session->mutex);
4045-
if(janus_sip_allocate_local_ports(session, FALSE) < 0) {
4083+
if(janus_sip_allocate_local_ports(session, session->status == janus_sip_call_status_progress ? TRUE : FALSE) < 0) {
40464084
janus_mutex_unlock(&session->mutex);
40474085
JANUS_LOG(LOG_ERR, "Could not allocate RTP/RTCP ports\n");
40484086
janus_sdp_destroy(parsed_sdp);
@@ -4070,7 +4108,7 @@ static void *janus_sip_handler(void *data) {
40704108
/* Take note of the SDP (may be useful for UPDATEs or re-INVITEs) */
40714109
janus_sdp_destroy(session->sdp);
40724110
session->sdp = parsed_sdp;
4073-
JANUS_LOG(LOG_VERB, "Prepared SDP for 200 OK:\n%s", sdp);
4111+
JANUS_LOG(LOG_VERB, "Prepared SDP for %s:\n%s", progress ? "183 Session Progress" : "200 OK", sdp);
40744112
/* If the user negotiated simulcasting, just stick with the base substream */
40754113
json_t *msg_simulcast = json_object_get(msg->jsep, "simulcast");
40764114
if(msg_simulcast) {
@@ -4079,30 +4117,39 @@ static void *janus_sip_handler(void *data) {
40794117
if(s && json_array_size(s) > 0)
40804118
session->media.simulcast_ssrc = json_integer_value(json_array_get(s, 0));
40814119
}
4120+
const char *event_value;
4121+
if(progress) {
4122+
event_value = "progressed";
4123+
} else if(answer) {
4124+
event_value = "accepted";
4125+
} else {
4126+
event_value = "accepting";
4127+
}
40824128
/* Also notify event handlers */
40834129
if(notify_events && gateway->events_is_enabled()) {
40844130
json_t *info = json_object();
4085-
json_object_set_new(info, "event", json_string(answer ? "accepted" : "accepting"));
4131+
json_object_set_new(info, "event", json_string(event_value));
40864132
if(session->callid)
40874133
json_object_set_new(info, "call-id", json_string(session->callid));
40884134
gateway->notify_event(&janus_sip_plugin, session->handle, info);
40894135
}
40904136
/* Check if the OK needs to be enriched with custom headers */
40914137
char custom_headers[2048];
40924138
janus_sip_parse_custom_headers(root, (char *)&custom_headers, sizeof(custom_headers));
4093-
/* Send 200 OK */
4139+
/* Send 200 OK/183 Session progress */
40944140
if(!answer) {
40954141
if(session->transaction)
40964142
g_free(session->transaction);
40974143
session->transaction = msg->transaction ? g_strdup(msg->transaction) : NULL;
40984144
}
40994145
g_atomic_int_set(&session->hangingup, 0);
4100-
janus_sip_call_update_status(session, janus_sip_call_status_incall);
4146+
janus_sip_call_update_status(session, progress ? janus_sip_call_status_progress : janus_sip_call_status_incall);
41014147
if(session->stack->s_nh_i == NULL) {
4102-
JANUS_LOG(LOG_WARN, "NUA Handle for 200 OK still null??\n");
4148+
JANUS_LOG(LOG_WARN, "NUA Handle for %s null\n", progress ? "183 Session Progress" : "200 OK");
41034149
}
4150+
int sip_response = progress ? 183 : 200;
41044151
nua_respond(session->stack->s_nh_i,
4105-
200, sip_status_phrase(200),
4152+
sip_response, sip_status_phrase(sip_response),
41064153
SOATAG_USER_SDP_STR(sdp),
41074154
SOATAG_RTP_SELECT(SOA_RTP_SELECT_COMMON),
41084155
NUTAG_AUTOANSWER(0),
@@ -4112,7 +4159,7 @@ static void *janus_sip_handler(void *data) {
41124159
g_free(sdp);
41134160
/* Send an ack back */
41144161
result = json_object();
4115-
json_object_set_new(result, "event", json_string(answer ? "accepted" : "accepting"));
4162+
json_object_set_new(result, "event", json_string(event_value));
41164163
if(answer) {
41174164
/* Start the media */
41184165
session->media.ready = TRUE; /* FIXME Maybe we need a better way to signal this */
@@ -4349,7 +4396,7 @@ static void *janus_sip_handler(void *data) {
43494396
}
43504397
}
43514398
/* Reject an incoming call */
4352-
if(session->status != janus_sip_call_status_invited) {
4399+
if(session->status != janus_sip_call_status_invited && session->status != janus_sip_call_status_progress) {
43534400
JANUS_LOG(LOG_ERR, "Wrong state (not invited? status=%s)\n", janus_sip_call_status_string(session->status));
43544401
/* Ignore */
43554402
janus_sip_message_free(msg);
@@ -4593,8 +4640,8 @@ static void *janus_sip_handler(void *data) {
45934640
json_object_set_new(result, "event", json_string(hold ? "holding" : "resuming"));
45944641
} else if(!strcasecmp(request_text, "hangup")) {
45954642
/* Hangup an ongoing call */
4596-
if(!janus_sip_call_is_established(session) && session->status != janus_sip_call_status_inviting) {
4597-
JANUS_LOG(LOG_ERR, "Wrong state (not established/inviting? status=%s)\n",
4643+
if(!janus_sip_call_is_established(session) && session->status != janus_sip_call_status_inviting && session->status != janus_sip_call_status_progress) {
4644+
JANUS_LOG(LOG_ERR, "Wrong state (not established/inviting/progress? status=%s)\n",
45984645
janus_sip_call_status_string(session->status));
45994646
/* Ignore */
46004647
janus_sip_message_free(msg);
@@ -4630,6 +4677,7 @@ static void *janus_sip_handler(void *data) {
46304677
} else if(!strcasecmp(request_text, "recording")) {
46314678
/* Start or stop recording */
46324679
if(!(session->status == janus_sip_call_status_inviting || /* Presume it makes sense to start recording with early media? */
4680+
session->status == janus_sip_call_status_progress ||
46334681
janus_sip_call_is_established(session))) {
46344682
JANUS_LOG(LOG_ERR, "Wrong state (not in a call? status=%s)\n", janus_sip_call_status_string(session->status));
46354683
g_snprintf(error_cause, 512, "Wrong state (not in a call?)");

0 commit comments

Comments
 (0)