[Pkg-voip-commits] [janus] 57/282: Implemented hold/unhold (still WIP)
Jonas Smedegaard
dr at jones.dk
Wed Dec 20 21:53:27 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 7f4944defa1d46a7bb468ed4aeecd30f4d3b4d65
Author: Lorenzo Miniero <lminiero at gmail.com>
Date: Tue May 30 17:21:23 2017 +0200
Implemented hold/unhold (still WIP)
---
plugins/janus_sipre.c | 163 ++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 144 insertions(+), 19 deletions(-)
diff --git a/plugins/janus_sipre.c b/plugins/janus_sipre.c
index e773dd7..d365391 100644
--- a/plugins/janus_sipre.c
+++ b/plugins/janus_sipre.c
@@ -16,12 +16,13 @@
* which means all responses (successes and errors) will be delivered
* as events with the same transaction.
*
- * The supported requests are \c register , \c call , \c accept and
+ * The supported requests are \c register , \c call , \c accept, \c hold , \c unhold and
* \c hangup . \c register can be used, as the name suggests, to register
* a username at a SIPre registrar to call and be called; \c call is used
* to send an INVITE to a different SIPre URI through the plugin, while
* \c accept is used to accept the call in case one is invited instead
- * of inviting; finally, \c hangup can be used to terminate the
+ * of inviting; ; \c hold and \c unhold can be used respectively to put a
+ * call on-hold and to resume it; finally, \c hangup can be used to terminate the
* communication at any time, either to hangup (BYE) an ongoing call or
* to cancel/decline (CANCEL/BYE) a call that hasn't started yet.
*
@@ -224,6 +225,7 @@ typedef enum janus_sipre_mqueue_event {
janus_sipre_mqueue_event_do_call,
janus_sipre_mqueue_event_do_accept,
janus_sipre_mqueue_event_do_rcode,
+ janus_sipre_mqueue_event_do_update,
janus_sipre_mqueue_event_do_sipinfo,
janus_sipre_mqueue_event_do_bye,
janus_sipre_mqueue_event_do_destroy,
@@ -242,6 +244,8 @@ static const char *janus_sipre_mqueue_event_string(janus_sipre_mqueue_event even
return "accept";
case janus_sipre_mqueue_event_do_rcode:
return "rcode";
+ case janus_sipre_mqueue_event_do_update:
+ return "update";
case janus_sipre_mqueue_event_do_sipinfo:
return "sipinfo";
case janus_sipre_mqueue_event_do_bye:
@@ -435,10 +439,11 @@ typedef struct janus_sipre_stack {
typedef struct janus_sipre_media {
char *remote_ip;
- int ready:1;
+ gboolean ready;
gboolean autoack;
gboolean require_srtp, has_srtp_local, has_srtp_remote;
- int has_audio:1;
+ gboolean on_hold;
+ gboolean has_audio;
int audio_rtp_fd, audio_rtcp_fd;
int local_audio_rtp_port, remote_audio_rtp_port;
int local_audio_rtcp_port, remote_audio_rtcp_port;
@@ -449,7 +454,8 @@ typedef struct janus_sipre_media {
srtp_policy_t audio_remote_policy, audio_local_policy;
int audio_srtp_suite_in, audio_srtp_suite_out;
gboolean audio_send;
- int has_video:1;
+ janus_sdp_mdirection pre_hold_audio_dir;
+ gboolean has_video;
int video_rtp_fd, video_rtcp_fd;
int local_video_rtp_port, remote_video_rtp_port;
int local_video_rtcp_port, remote_video_rtcp_port;
@@ -460,6 +466,7 @@ typedef struct janus_sipre_media {
srtp_policy_t video_remote_policy, video_local_policy;
int video_srtp_suite_in, video_srtp_suite_out;
gboolean video_send;
+ janus_sdp_mdirection pre_hold_video_dir;
janus_rtp_switching_context context;
int pipefd[2];
gboolean updated;
@@ -1021,12 +1028,13 @@ void janus_sipre_create_session(janus_plugin_session *handle, int *error) {
session->callid = NULL;
session->sdp = NULL;
session->media.remote_ip = NULL;
- session->media.ready = 0;
+ session->media.ready = FALSE;
session->media.autoack = TRUE;
session->media.require_srtp = FALSE;
session->media.has_srtp_local = FALSE;
session->media.has_srtp_remote = FALSE;
- session->media.has_audio = 0;
+ session->media.on_hold = FALSE;
+ session->media.has_audio = FALSE;
session->media.audio_rtp_fd = -1;
session->media.audio_rtcp_fd= -1;
session->media.local_audio_rtp_port = 0;
@@ -1040,7 +1048,8 @@ void janus_sipre_create_session(janus_plugin_session *handle, int *error) {
session->media.audio_srtp_suite_in = 0;
session->media.audio_srtp_suite_out = 0;
session->media.audio_send = TRUE;
- session->media.has_video = 0;
+ session->media.pre_hold_audio_dir = JANUS_SDP_DEFAULT;
+ session->media.has_video = FALSE;
session->media.video_rtp_fd = -1;
session->media.video_rtcp_fd= -1;
session->media.local_video_rtp_port = 0;
@@ -1054,6 +1063,7 @@ void janus_sipre_create_session(janus_plugin_session *handle, int *error) {
session->media.video_srtp_suite_in = 0;
session->media.video_srtp_suite_out = 0;
session->media.video_send = TRUE;
+ session->media.pre_hold_video_dir = JANUS_SDP_DEFAULT;
/* Initialize the RTP context */
janus_rtp_switching_context_reset(&session->media.context);
session->media.pipefd[0] = -1;
@@ -1291,6 +1301,8 @@ void janus_sipre_hangup_media(janus_plugin_session *handle) {
session->status == janus_sipre_call_status_invited ||
session->status == janus_sipre_call_status_incall))
return;
+ session->media.ready = FALSE;
+ session->media.on_hold = FALSE;
session->status = janus_sipre_call_status_closing;
/* Enqueue the BYE */
mqueue_push(mq, janus_sipre_mqueue_event_do_bye, janus_sipre_mqueue_payload_create(session, NULL, 0, NULL));
@@ -1750,11 +1762,11 @@ static void *janus_sipre_handler(void *data) {
/* Allocate RTP ports and merge them with the anonymized SDP */
if(strstr(msg_sdp, "m=audio") && !strstr(msg_sdp, "m=audio 0")) {
JANUS_LOG(LOG_VERB, "Going to negotiate audio...\n");
- session->media.has_audio = 1; /* FIXME Maybe we need a better way to signal this */
+ session->media.has_audio = TRUE; /* FIXME Maybe we need a better way to signal this */
}
if(strstr(msg_sdp, "m=video") && !strstr(msg_sdp, "m=video 0")) {
JANUS_LOG(LOG_VERB, "Going to negotiate video...\n");
- session->media.has_video = 1; /* FIXME Maybe we need a better way to signal this */
+ session->media.has_video = TRUE; /* FIXME Maybe we need a better way to signal this */
}
if(janus_sipre_allocate_local_ports(session) < 0) {
JANUS_LOG(LOG_ERR, "Could not allocate RTP/RTCP ports\n");
@@ -1885,11 +1897,11 @@ static void *janus_sipre_handler(void *data) {
/* Allocate RTP ports and merge them with the anonymized SDP */
if(strstr(msg_sdp, "m=audio") && !strstr(msg_sdp, "m=audio 0")) {
JANUS_LOG(LOG_VERB, "Going to negotiate audio...\n");
- session->media.has_audio = 1; /* FIXME Maybe we need a better way to signal this */
+ session->media.has_audio = TRUE; /* FIXME Maybe we need a better way to signal this */
}
if(strstr(msg_sdp, "m=video") && !strstr(msg_sdp, "m=video 0")) {
JANUS_LOG(LOG_VERB, "Going to negotiate video...\n");
- session->media.has_video = 1; /* FIXME Maybe we need a better way to signal this */
+ session->media.has_video = TRUE; /* FIXME Maybe we need a better way to signal this */
}
if(janus_sipre_allocate_local_ports(session) < 0) {
JANUS_LOG(LOG_ERR, "Could not allocate RTP/RTCP ports\n");
@@ -1935,10 +1947,10 @@ static void *janus_sipre_handler(void *data) {
result = json_object();
json_object_set_new(result, "event", json_string("accepted"));
/* Start the media */
- session->media.ready = 1; /* FIXME Maybe we need a better way to signal this */
+ session->media.ready = TRUE; /* FIXME Maybe we need a better way to signal this */
GError *error = NULL;
char tname[16];
- g_snprintf(tname, sizeof(tname), "siprtp %s", session->account.username);
+ g_snprintf(tname, sizeof(tname), "siprertp %s", session->account.username);
g_thread_try_new(tname, janus_sipre_relay_thread, session, &error);
if(error != NULL) {
JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the RTP/RTCP thread...\n", error->code, error->message ? error->message : "??");
@@ -1959,6 +1971,8 @@ static void *janus_sipre_handler(void *data) {
g_snprintf(error_cause, 512, "Wrong state (no callee?)");
goto error;
}
+ session->media.ready = FALSE;
+ session->media.on_hold = FALSE;
session->status = janus_sipre_call_status_closing;
/* Prepare response */
int response_code = 486;
@@ -1986,6 +2000,79 @@ static void *janus_sipre_handler(void *data) {
result = json_object();
json_object_set_new(result, "event", json_string("declining"));
json_object_set_new(result, "code", json_integer(response_code));
+ } else if(!strcasecmp(request_text, "hold") || !strcasecmp(request_text, "unhold")) {
+ /* We either need to put the call on-hold, or resume it */
+ if(!(session->status == janus_sipre_call_status_inviting || session->status == janus_sipre_call_status_incall)) {
+ JANUS_LOG(LOG_ERR, "Wrong state (not in a call? status=%s)\n", janus_sipre_call_status_string(session->status));
+ /* Ignore */
+ janus_sipre_message_free(msg);
+ continue;
+ //~ g_snprintf(error_cause, 512, "Wrong state (not in a call?)");
+ //~ goto error;
+ }
+ if(session->callee == NULL) {
+ JANUS_LOG(LOG_ERR, "Wrong state (no callee?)\n");
+ error_code = JANUS_SIPRE_ERROR_WRONG_STATE;
+ g_snprintf(error_cause, 512, "Wrong state (no callee?)");
+ goto error;
+ }
+ if(session->sdp == NULL) {
+ JANUS_LOG(LOG_ERR, "Wrong state (no SDP?)\n");
+ error_code = JANUS_SIPRE_ERROR_WRONG_STATE;
+ g_snprintf(error_cause, 512, "Wrong state (no SDP?)");
+ goto error;
+ }
+ gboolean hold = !strcasecmp(request_text, "hold");
+ if(hold != session->media.on_hold) {
+ /* To put the call on-hold, we need to set the direction to recvonly:
+ * resuming it means resuming the direction we had before */
+ session->media.on_hold = hold;
+ janus_sdp_mline *m = janus_sdp_mline_find(session->sdp, JANUS_SDP_AUDIO);
+ if(m) {
+ if(hold) {
+ /* Take note of the original media direction */
+ session->media.pre_hold_audio_dir = m->direction;
+ /* Update the media direction */
+ switch(m->direction) {
+ case JANUS_SDP_DEFAULT:
+ case JANUS_SDP_SENDRECV:
+ m->direction = JANUS_SDP_SENDONLY;
+ break;
+ default:
+ m->direction = JANUS_SDP_INACTIVE;
+ break;
+ }
+ } else {
+ m->direction = session->media.pre_hold_audio_dir;
+ }
+ }
+ m = janus_sdp_mline_find(session->sdp, JANUS_SDP_VIDEO);
+ if(m) {
+ if(hold) {
+ /* Take note of the original media direction */
+ session->media.pre_hold_video_dir = m->direction;
+ /* Update the media direction */
+ switch(m->direction) {
+ case JANUS_SDP_DEFAULT:
+ case JANUS_SDP_SENDRECV:
+ m->direction = JANUS_SDP_SENDONLY;
+ break;
+ default:
+ m->direction = JANUS_SDP_INACTIVE;
+ break;
+ }
+ } else {
+ m->direction = session->media.pre_hold_video_dir;
+ }
+ }
+ /* Send the re-INVITE */
+ char *sdp = janus_sdp_write(session->sdp);
+ session->temp_sdp = sdp;
+ mqueue_push(mq, janus_sipre_mqueue_event_do_update, janus_sipre_mqueue_payload_create(session, NULL, 0, data));
+ }
+ /* Send an ack back */
+ result = json_object();
+ json_object_set_new(result, "event", json_string(hold ? "holding" : "resuming"));
} else if(!strcasecmp(request_text, "hangup")) {
/* Hangup an ongoing call */
if(!(session->status == janus_sipre_call_status_inviting || session->status == janus_sipre_call_status_incall)) {
@@ -2002,6 +2089,8 @@ static void *janus_sipre_handler(void *data) {
g_snprintf(error_cause, 512, "Wrong state (no callee?)");
goto error;
}
+ session->media.ready = FALSE;
+ session->media.on_hold = FALSE;
session->status = janus_sipre_call_status_closing;
/* Enqueue the BYE */
mqueue_push(mq, janus_sipre_mqueue_event_do_bye, janus_sipre_mqueue_payload_create(session, NULL, 0, NULL));
@@ -2318,7 +2407,7 @@ void janus_sipre_sdp_process(janus_sipre_session *session, janus_sdp *sdp, gbool
if(changed)
*changed = TRUE;
}
- session->media.has_audio = 1;
+ session->media.has_audio = TRUE;
session->media.remote_audio_rtp_port = m->port;
session->media.remote_audio_rtcp_port = m->port+1; /* FIXME We're assuming RTCP is on the next port */
if(m->direction == JANUS_SDP_SENDONLY || m->direction == JANUS_SDP_INACTIVE)
@@ -2335,7 +2424,7 @@ void janus_sipre_sdp_process(janus_sipre_session *session, janus_sdp *sdp, gbool
if(changed)
*changed = TRUE;
}
- session->media.has_video = 1;
+ session->media.has_video = TRUE;
session->media.remote_video_rtp_port = m->port;
session->media.remote_video_rtcp_port = m->port+1; /* FIXME We're assuming RTCP is on the next port */
if(m->direction == JANUS_SDP_SENDONLY || m->direction == JANUS_SDP_INACTIVE)
@@ -3215,12 +3304,16 @@ int janus_sipre_cb_answer(const struct sip_msg *msg, void *arg) {
/* Parse SDP */
JANUS_LOG(LOG_VERB, "Peer accepted our call:\n%s", sdp_answer);
session->status = janus_sipre_call_status_incall;
- janus_sipre_sdp_process(session, sdp, TRUE, FALSE, NULL);
+ gboolean changed = FALSE;
+ gboolean update = session->media.ready;
+ janus_sipre_sdp_process(session, sdp, TRUE, update, &changed);
/* If we asked for SRTP and are not getting it, fail */
if(session->media.require_srtp && !session->media.has_srtp_remote) {
JANUS_LOG(LOG_ERR, "\tWe asked for mandatory SRTP but didn't get any in the reply!\n");
janus_sdp_free(sdp);
/* Hangup immediately */
+ session->media.ready = FALSE;
+ session->media.on_hold = FALSE;
session->status = janus_sipre_call_status_closing;
mqueue_push(mq, janus_sipre_mqueue_event_do_bye, janus_sipre_mqueue_payload_create(session, msg, 0, NULL));
g_free(session->callee);
@@ -3232,6 +3325,8 @@ int janus_sipre_cb_answer(const struct sip_msg *msg, void *arg) {
JANUS_LOG(LOG_ERR, "\tNo remote IP address found for RTP, something's wrong with the SDP!\n");
janus_sdp_free(sdp);
/* Hangup immediately */
+ session->media.ready = FALSE;
+ session->media.on_hold = FALSE;
session->status = janus_sipre_call_status_closing;
mqueue_push(mq, janus_sipre_mqueue_event_do_bye, janus_sipre_mqueue_payload_create(session, msg, 0, NULL));
g_free(session->callee);
@@ -3246,10 +3341,15 @@ int janus_sipre_cb_answer(const struct sip_msg *msg, void *arg) {
session->media.video_pt_name = janus_get_codec_from_pt(sdp_answer, session->media.video_pt);
JANUS_LOG(LOG_VERB, "Detected video codec: %d (%s)\n", session->media.video_pt, session->media.video_pt_name);
}
- session->media.ready = 1; /* FIXME Maybe we need a better way to signal this */
+ session->media.ready = TRUE; /* FIXME Maybe we need a better way to signal this */
+ if(update) {
+ /* Don't push to the browser if this is in response to a hold/unhold we sent ourselves */
+ JANUS_LOG(LOG_WARN, "This is an update to an existing call (possibly in response to hold/unhold)\n");
+ return 0;
+ }
GError *error = NULL;
char tname[16];
- g_snprintf(tname, sizeof(tname), "siprtp %s", session->account.username);
+ g_snprintf(tname, sizeof(tname), "siprertp %s", session->account.username);
g_thread_try_new(tname, janus_sipre_relay_thread, session, &error);
if(error != NULL) {
JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the RTP/RTCP thread...\n", error->code, error->message ? error->message : "??");
@@ -3337,6 +3437,8 @@ void janus_sipre_cb_closed(int err, const struct sip_msg *msg, void *arg) {
/* Cleanup */
session->stack.sess = mem_deref(session->stack.sess);
//~ session->stack.reg = mem_deref(session->stack.reg);
+ session->media.ready = FALSE;
+ session->media.on_hold = FALSE;
session->status = janus_sipre_call_status_idle;
}
@@ -3551,6 +3653,8 @@ void janus_sipre_mqueue_handler(int id, void *data, void *arg) {
} else {
/* 3xx, 4xx, 5xx, 6xx */
err = sipsess_reject(session->stack.sess, payload->rcode, janus_sipre_error_reason(payload->rcode), NULL);
+ session->media.ready = FALSE;
+ session->media.on_hold = FALSE;
session->status = janus_sipre_call_status_idle;
}
//~ err = sip_treply(NULL, session->stack.sipstack, payload->msg, payload->rcode, janus_sipre_error_reason(payload->rcode));
@@ -3570,6 +3674,25 @@ void janus_sipre_mqueue_handler(int id, void *data, void *arg) {
g_free(payload);
break;
}
+ case janus_sipre_mqueue_event_do_update: {
+ janus_sipre_mqueue_payload *payload = (janus_sipre_mqueue_payload *)data;
+ janus_sipre_session *session = (janus_sipre_session *)payload->session;
+ JANUS_LOG(LOG_WARN, "[SIPre-%s] Sending SIP re-INVITE\n", session->account.username);
+ /* Convert the SDP into a struct mbuf */
+ struct mbuf *mb = mbuf_alloc(strlen(session->temp_sdp)+1);
+ mbuf_printf(mb, "%s", session->temp_sdp);
+ mbuf_set_pos(mb, 0);
+ /* Send the INVITE */
+ int err = sipsess_modify(session->stack.sess, mb);
+ if(err != 0) {
+ JANUS_LOG(LOG_ERR, "Error attempting to re-INVITE: %d (%s)\n", err, strerror(err));
+ }
+ mem_deref(mb);
+ g_free(session->temp_sdp);
+ session->temp_sdp = NULL;
+ g_free(payload);
+ break;
+ }
case janus_sipre_mqueue_event_do_sipinfo: {
janus_sipre_mqueue_payload *payload = (janus_sipre_mqueue_payload *)data;
janus_sipre_session *session = (janus_sipre_session *)payload->session;
@@ -3626,6 +3749,8 @@ void janus_sipre_mqueue_handler(int id, void *data, void *arg) {
json_object_set_new(info, "reason", json_string("BYE"));
gateway->notify_event(&janus_sipre_plugin, session->handle, info);
}
+ session->media.ready = FALSE;
+ session->media.on_hold = FALSE;
session->status = janus_sipre_call_status_idle;
break;
}
--
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