Skip to content

Commit

Permalink
ua: add support for hold+answer
Browse files Browse the repository at this point in the history
- added ua_hold_answer() which will first put on-hold the active
  call (if exist) and then answer the new incoming call

fixes #50
  • Loading branch information
alfredh committed Oct 11, 2015
1 parent bf9a477 commit 25225de
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 5 deletions.
1 change: 1 addition & 0 deletions include/baresip.h
Expand Up @@ -511,6 +511,7 @@ int ua_connect(struct ua *ua, struct call **callp,
void ua_hangup(struct ua *ua, struct call *call,
uint16_t scode, const char *reason);
int ua_answer(struct ua *ua, struct call *call);
int ua_hold_answer(struct ua *ua, struct call *call);
int ua_options_send(struct ua *ua, const char *uri,
options_resp_h *resph, void *arg);
int ua_sipfd(const struct ua *ua);
Expand Down
2 changes: 1 addition & 1 deletion modules/menu/menu.c
Expand Up @@ -292,7 +292,7 @@ static int cmd_answer(struct re_printf *pf, void *unused)
(void)pf;
(void)unused;

ua_answer(uag_cur(), NULL);
ua_hold_answer(uag_cur(), NULL);

return 0;
}
Expand Down
18 changes: 16 additions & 2 deletions src/call.c
Expand Up @@ -65,6 +65,7 @@ struct call {
time_t time_conn; /**< Time when call initiated */
time_t time_stop; /**< Time when call stopped */
bool got_offer; /**< Got SDP Offer from Peer */
bool on_hold; /**< True if call is on hold */
struct mnat_sess *mnats; /**< Media NAT session */
bool mnat_wait; /**< Waiting for MNAT to establish */
struct menc_sess *mencs; /**< Media encryption session state */
Expand Down Expand Up @@ -779,8 +780,13 @@ int call_hold(struct call *call, bool hold)
if (!call || !call->sess)
return EINVAL;

if (hold == call->on_hold)
return 0;

info("call: %s %s\n", hold ? "hold" : "resume", call->peer_uri);

call->on_hold = hold;

FOREACH_STREAM
stream_hold(le->data, hold);

Expand Down Expand Up @@ -909,8 +915,10 @@ int call_info(struct re_printf *pf, const struct call *call)
if (!call)
return 0;

return re_hprintf(pf, "%H %8s %s", print_duration, call,
state_name(call->state), call->peer_uri);
return re_hprintf(pf, "%H %9s %s %s", print_duration, call,
state_name(call->state),
call->on_hold ? "(on hold)" : " ",
call->peer_uri);
}


Expand Down Expand Up @@ -1654,3 +1662,9 @@ void call_set_xrtpstat(struct call *call)
"X-RTP-Stat: %H\r\n",
audio_print_rtpstat, call->audio);
}


bool call_is_onhold(const struct call *call)
{
return call ? call->on_hold : false;
}
1 change: 1 addition & 0 deletions src/core.h
Expand Up @@ -171,6 +171,7 @@ int call_notify_sipfrag(struct call *call, uint16_t scode,
const char *reason, ...);
int call_af(const struct call *call);
void call_set_xrtpstat(struct call *call);
bool call_is_onhold(const struct call *call);


/*
Expand Down
75 changes: 73 additions & 2 deletions src/ua.c
Expand Up @@ -249,6 +249,38 @@ static const char *translate_errorcode(uint16_t scode)
}


static struct call *ua_find_call_onhold(const struct ua *ua)
{
struct le *le;

if (!ua)
return NULL;

for (le = ua->calls.tail; le; le = le->prev) {

struct call *call = le->data;

if (call_is_onhold(call))
return call;
}

return NULL;
}


static void resume_call(struct ua *ua)
{
struct call *call;

call = ua_find_call_onhold(ua);
if (call) {
ua_printf(ua, "resuming previous call with '%s'\n",
call_peeruri(call));
call_hold(call, false);
}
}


static void call_event_handler(struct call *call, enum call_event ev,
const char *str, void *arg)
{
Expand Down Expand Up @@ -328,6 +360,8 @@ static void call_event_handler(struct call *call, enum call_event ev,
}
ua_event(ua, UA_EVENT_CALL_CLOSED, call, str);
mem_deref(call);

resume_call(ua);
break;

case CALL_EVENT_TRANSFER:
Expand Down Expand Up @@ -770,6 +804,8 @@ void ua_hangup(struct ua *ua, struct call *call,
(void)call_hangup(call, scode, reason);

mem_deref(call);

resume_call(ua);
}


Expand All @@ -792,14 +828,49 @@ int ua_answer(struct ua *ua, struct call *call)
return ENOENT;
}

/* todo: put previous call on-hold (if configured) */

ua->play = mem_deref(ua->play);

return call_answer(call, 200);
}


/**
* Put the current call on hold and answer the incoming call
*
* @param ua User-Agent
* @param call Call to answer, or NULL for current call
*
* @return 0 if success, otherwise errorcode
*/
int ua_hold_answer(struct ua *ua, struct call *call)
{
struct call *pcall;
int err;

if (!ua)
return EINVAL;

if (!call) {
call = ua_call(ua);
if (!call)
return ENOENT;
}

/* put previous call on-hold */
pcall = ua_prev_call(ua);
if (pcall) {
ua_printf(ua, "putting call with '%s' on hold\n",
call_peeruri(pcall));

err = call_hold(pcall, true);
if (err)
return err;
}

return ua_answer(ua, call);
}


int ua_print_status(struct re_printf *pf, const struct ua *ua)
{
struct le *le;
Expand Down

0 comments on commit 25225de

Please sign in to comment.