Add support for MNCC HOLD/RETRIEVE
Handle MO hold and retrieve and pass this to the SIP side. Handle the 200 from the SIP side in response to our HOLD-ing re-INVITE. With this commit we now handle MO hold and therefore also handle call-waiting and swapping. Change-Id: Ife7bdab20cde92b7ce550215bab28b36a0f302e9
This commit is contained in:
parent
bd2d14bd4a
commit
ba7450cf26
35
src/mncc.c
35
src/mncc.c
|
@ -188,6 +188,8 @@ static bool send_rtp_connect(struct mncc_call_leg *leg, struct call_leg *other)
|
|||
* FIXME: mncc.payload_msg_type should already be compatible.. but
|
||||
* payload_type should be different..
|
||||
*/
|
||||
struct in_addr net = { .s_addr = other->ip };
|
||||
LOGP(DMNCC, LOGL_DEBUG, "SEND rtp_connect: IP=(%s) PORT=(%u)\n", inet_ntoa(net), mncc.port);
|
||||
rc = write(leg->conn->fd.fd, &mncc, sizeof(mncc));
|
||||
if (rc != sizeof(mncc)) {
|
||||
LOGP(DMNCC, LOGL_ERROR, "Failed to send message leg(%u)\n",
|
||||
|
@ -687,14 +689,40 @@ static void check_hold_ind(struct mncc_connection *conn, const char *buf, int rc
|
|||
{
|
||||
const struct gsm_mncc *data;
|
||||
struct mncc_call_leg *leg;
|
||||
struct call_leg *other_leg;
|
||||
|
||||
leg = find_leg(conn, buf, rc, &data);
|
||||
if (!leg)
|
||||
return;
|
||||
|
||||
LOGP(DMNCC, LOGL_DEBUG,
|
||||
"leg(%u) is req hold. rejecting.\n", leg->callref);
|
||||
mncc_send(leg->conn, MNCC_HOLD_REJ, leg->callref);
|
||||
"leg(%u) is req hold.\n", leg->callref);
|
||||
other_leg = call_leg_other(&leg->base);
|
||||
other_leg->hold_call(other_leg);
|
||||
mncc_send(leg->conn, MNCC_HOLD_CNF, leg->callref);
|
||||
leg->state = MNCC_CC_HOLD;
|
||||
}
|
||||
|
||||
static void check_retrieve_ind(struct mncc_connection *conn, const char *buf, int rc)
|
||||
{
|
||||
const struct gsm_mncc *data;
|
||||
struct mncc_call_leg *leg;
|
||||
struct call_leg *other_leg;
|
||||
|
||||
leg = find_leg(conn, buf, rc, &data);
|
||||
if (!leg)
|
||||
return;
|
||||
|
||||
LOGP(DMNCC, LOGL_DEBUG,
|
||||
"leg(%u) is req unhold.\n", leg->callref);
|
||||
other_leg = call_leg_other(&leg->base);
|
||||
other_leg->retrieve_call(other_leg);
|
||||
mncc_send(leg->conn, MNCC_RETRIEVE_CNF, leg->callref);
|
||||
/* In case of call waiting/swap, At this point we need to tell the MSC to send
|
||||
* audio to the port of the original call
|
||||
*/
|
||||
leg->state = MNCC_CC_CONNECTED;
|
||||
send_rtp_connect(leg, other_leg);
|
||||
}
|
||||
|
||||
static void check_stp_cnf(struct mncc_connection *conn, const char *buf, int rc)
|
||||
|
@ -938,6 +966,9 @@ static int mncc_data(struct osmo_fd *fd, unsigned int what)
|
|||
case MNCC_HOLD_IND:
|
||||
check_hold_ind(conn, buf, rc);
|
||||
break;
|
||||
case MNCC_RETRIEVE_IND:
|
||||
check_retrieve_ind(conn, buf, rc);
|
||||
break;
|
||||
case MNCC_START_DTMF_IND:
|
||||
check_dtmf_start(conn, buf, rc);
|
||||
break;
|
||||
|
|
27
src/sip.c
27
src/sip.c
|
@ -98,7 +98,7 @@ static void call_connect(struct sip_call_leg *leg, const sip_t *sip)
|
|||
return;
|
||||
}
|
||||
|
||||
LOGP(DSIP, LOGL_NOTICE, "leg(%p) is now connected.\n", leg);
|
||||
LOGP(DSIP, LOGL_NOTICE, "leg(%p) is now connected(%s).\n", leg, sip->sip_call_id->i_id);
|
||||
leg->state = SIP_CC_CONNECTED;
|
||||
other->connect_call(other);
|
||||
nua_ack(leg->nua_handle, TAG_END());
|
||||
|
@ -111,7 +111,7 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh,
|
|||
struct sip_call_leg *leg;
|
||||
const char *from = NULL, *to = NULL;
|
||||
|
||||
LOGP(DSIP, LOGL_DEBUG, "Incoming call handle(%p)\n", nh);
|
||||
LOGP(DSIP, LOGL_DEBUG, "Incoming call(%s) handle(%p)\n", sip->sip_call_id->i_id, nh);
|
||||
|
||||
if (!sdp_screen_sdp(sip)) {
|
||||
LOGP(DSIP, LOGL_ERROR, "No supported codec.\n");
|
||||
|
@ -158,6 +158,11 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh,
|
|||
call_leg_release(&leg->base);
|
||||
return;
|
||||
}
|
||||
struct in_addr net = { .s_addr = leg->base.ip };
|
||||
LOGP(DSIP, LOGL_DEBUG, "SDP Extracted: IP=(%s) PORT=(%u) PAYLOAD=(%u).\n",
|
||||
inet_ntoa(net),
|
||||
leg->base.port,
|
||||
leg->base.payload_type);
|
||||
|
||||
leg->base.release_call = sip_release_call;
|
||||
leg->base.ring_call = sip_ring_call;
|
||||
|
@ -179,6 +184,8 @@ static void sip_handle_reinvite(struct sip_call_leg *leg, nua_handle_t *nh, cons
|
|||
|
||||
char *sdp;
|
||||
sdp_mode_t mode = sdp_sendrecv;
|
||||
uint32_t ip = leg->base.ip;
|
||||
uint16_t port = leg->base.port;
|
||||
|
||||
LOGP(DSIP, LOGL_NOTICE, "re-INVITE for call %s\n", sip->sip_call_id->i_id);
|
||||
|
||||
|
@ -197,6 +204,9 @@ static void sip_handle_reinvite(struct sip_call_leg *leg, nua_handle_t *nh, cons
|
|||
return;
|
||||
}
|
||||
|
||||
struct in_addr net = { .s_addr = leg->base.ip };
|
||||
LOGP(DSIP, LOGL_NOTICE, "pre re-INVITE have IP:port (%s:%u)\n", inet_ntoa(net), leg->base.port);
|
||||
|
||||
if (mode == sdp_sendonly) {
|
||||
/* SIP side places call on HOLD */
|
||||
sdp = sdp_create_file(leg, other, sdp_recvonly);
|
||||
|
@ -210,9 +220,13 @@ static void sip_handle_reinvite(struct sip_call_leg *leg, nua_handle_t *nh, cons
|
|||
call_leg_release(&leg->base);
|
||||
return;
|
||||
}
|
||||
struct in_addr net = { .s_addr = leg->base.ip };
|
||||
LOGP(DSIP, LOGL_NOTICE, "Media IP:port in re-INVITE: (%s:%u)\n", inet_ntoa(net), leg->base.port);
|
||||
if (ip != leg->base.ip || port != leg->base.port) {
|
||||
LOGP(DSIP, LOGL_NOTICE, "re-INVITE changes media connection.\n");
|
||||
}
|
||||
if (other->update_rtp)
|
||||
other->update_rtp(leg->base.call->remote);
|
||||
|
||||
sdp = sdp_create_file(leg, other, sdp_sendrecv);
|
||||
}
|
||||
|
||||
|
@ -297,8 +311,8 @@ static int status2cause(int status)
|
|||
|
||||
void nua_callback(nua_event_t event, int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tags[])
|
||||
{
|
||||
LOGP(DSIP, LOGL_DEBUG, "SIP event(%u) status(%d) phrase(%s) %p\n",
|
||||
event, status, phrase, hmagic);
|
||||
LOGP(DSIP, LOGL_DEBUG, "SIP event[%s] status(%d) phrase(%s) %p\n",
|
||||
nua_event_name(event), status, phrase, hmagic);
|
||||
|
||||
if (event == nua_r_invite) {
|
||||
struct sip_call_leg *leg;
|
||||
|
@ -361,6 +375,7 @@ void nua_callback(nua_event_t event, int status, char const *phrase, nua_t *nua,
|
|||
other->release_call(other);
|
||||
} else if (event == nua_i_invite) {
|
||||
/* new incoming leg or re-INVITE */
|
||||
LOGP(DSIP, LOGL_NOTICE, "Processing INVITE Call-ID: %s\n", sip->sip_call_id->i_id);
|
||||
|
||||
if (status == 100) {
|
||||
struct sip_call_leg *leg = sip_find_leg(nh);
|
||||
|
@ -382,6 +397,8 @@ void nua_callback(nua_event_t event, int status, char const *phrase, nua_t *nua,
|
|||
call_leg_release(&leg->base);
|
||||
if (other)
|
||||
other->release_call(other);
|
||||
} else {
|
||||
LOGP(DSIP, LOGL_DEBUG, "Did not handle event[%s] status(%d)\n", nua_event_name(event), status);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue