summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlfred E. Heggestad <aeh@db.org>2015-10-11 11:24:37 +0200
committerAlfred E. Heggestad <aeh@db.org>2015-10-11 11:24:37 +0200
commit25225de72f2ba6c89abe862e2e027906c9ef8a76 (patch)
treeb1cf229229b7e29249d57fd0e41eee3ebbd9d147
parentbf9a477a0fc1ab83690a2083a02708e85224b3c1 (diff)
ua: add support for hold+answer
- added ua_hold_answer() which will first put on-hold the active call (if exist) and then answer the new incoming call fixes #50
-rw-r--r--include/baresip.h1
-rw-r--r--modules/menu/menu.c2
-rw-r--r--src/call.c18
-rw-r--r--src/core.h1
-rw-r--r--src/ua.c75
5 files changed, 92 insertions, 5 deletions
diff --git a/include/baresip.h b/include/baresip.h
index 3ac753e..9c87e95 100644
--- a/include/baresip.h
+++ b/include/baresip.h
@@ -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);
diff --git a/modules/menu/menu.c b/modules/menu/menu.c
index 08bd49c..b5f6354 100644
--- a/modules/menu/menu.c
+++ b/modules/menu/menu.c
@@ -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;
}
diff --git a/src/call.c b/src/call.c
index 322f468..c67980d 100644
--- a/src/call.c
+++ b/src/call.c
@@ -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 */
@@ -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);
@@ -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);
}
@@ -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;
+}
diff --git a/src/core.h b/src/core.h
index bf0a14b..43b720c 100644
--- a/src/core.h
+++ b/src/core.h
@@ -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);
/*
diff --git a/src/ua.c b/src/ua.c
index 8585309..461d223 100644
--- a/src/ua.c
+++ b/src/ua.c
@@ -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)
{
@@ -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:
@@ -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);
}
@@ -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;