From e0482fc6e6d5f8cd2a5e99180bba2e5aa474aac0 Mon Sep 17 00:00:00 2001 From: Evangelos Ribeiro Tzaras Date: Fri, 19 Feb 2021 17:34:57 +0100 Subject: [PATCH] sip: initial call handling * implement answering and hangup * (de)activate media pipeline --- plugins/sip/calls-sip-call.c | 64 +++++++++++++++++++++++++++++++--- plugins/sip/calls-sip-call.h | 4 +++ plugins/sip/calls-sip-origin.c | 64 ++++++++++++++++++++++------------ plugins/sip/calls-sip-util.h | 1 - 4 files changed, 106 insertions(+), 27 deletions(-) diff --git a/plugins/sip/calls-sip-call.c b/plugins/sip/calls-sip-call.c index dcc3047..553bd73 100644 --- a/plugins/sip/calls-sip-call.c +++ b/plugins/sip/calls-sip-call.c @@ -22,6 +22,8 @@ * */ +#define G_LOG_DOMAIN "CallsSipCall" + #include "calls-sip-call.h" #include "calls-message-source.h" @@ -94,18 +96,34 @@ static void answer (CallsCall *call) { CallsSipCall *self; + g_autofree gchar *local_sdp = NULL; g_assert (CALLS_IS_CALL (call)); g_assert (CALLS_IS_SIP_CALL (call)); self = CALLS_SIP_CALL (call); + g_assert (self->nh); + if (self->state != CALLS_CALL_STATE_INCOMING) { g_warning ("Call must be in 'incoming' state in order to answer"); return; } - /* need to include SDP answer here */ + /* XXX dynamically get free ports */ + calls_sip_call_setup_local_media (self, 19042, 19043); + + local_sdp = calls_sip_media_manager_static_capabilities (self->manager, + 19042, + FALSE); + + g_assert (local_sdp); + g_debug ("Setting local SDP to string:\n%s", local_sdp); + + nua_respond (self->nh, 200, NULL, + SOATAG_USER_SDP_STR (local_sdp), + SOATAG_AF (SOA_AF_IP4_IP6), + TAG_END ()); change_state (self, CALLS_CALL_STATE_ACTIVE); } @@ -120,6 +138,31 @@ hang_up (CallsCall *call) self = CALLS_SIP_CALL (call); + switch (self->state) { + case CALLS_CALL_STATE_DIALING: + nua_cancel (self->nh, TAG_END ()); + g_debug ("Hanging up on outgoing ringing call"); + break; + + case CALLS_CALL_STATE_ACTIVE: + nua_bye (self->nh, TAG_END ()); + + g_debug ("Hanging up ongoing call"); + break; + + case CALLS_CALL_STATE_INCOMING: + nua_respond (self->nh, 480, NULL, TAG_END ()); + g_debug ("Hanging up incoming call"); + break; + + case CALLS_CALL_STATE_DISCONNECTED: + g_warning ("Tried hanging up already disconnected call"); + return; + + default: + g_warning ("Hanging up not possible in state %d", self->state); + } + change_state (self, CALLS_CALL_STATE_DISCONNECTED); } @@ -301,14 +344,15 @@ calls_sip_call_setup_remote_media (CallsSipCall *self, void calls_sip_call_activate_media (CallsSipCall *self, - gboolean enabled) + gboolean enabled) { g_return_if_fail (CALLS_IS_SIP_CALL (self)); + g_return_if_fail (CALLS_IS_SIP_MEDIA_PIPELINE (self->pipeline)); if (enabled) { - ; + calls_sip_media_pipeline_start (self->pipeline); } else { - ; + calls_sip_media_pipeline_stop (self->pipeline); } } @@ -336,3 +380,15 @@ calls_sip_call_new (const gchar *number, return call; } + + +void +calls_sip_call_set_state (CallsSipCall *self, + CallsCallState state) +{ + g_return_if_fail (CALLS_IS_SIP_CALL (self)); + + g_print ("Changed call state to %d\n", state); + self->state = state; + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CALL_STATE]); +} diff --git a/plugins/sip/calls-sip-call.h b/plugins/sip/calls-sip-call.h index 7558653..02a9286 100644 --- a/plugins/sip/calls-sip-call.h +++ b/plugins/sip/calls-sip-call.h @@ -24,6 +24,8 @@ #pragma once +#include "calls-call.h" + #include #include @@ -45,5 +47,7 @@ void calls_sip_call_setup_local_media (CallsSipCall *self guint port_rtcp); void calls_sip_call_activate_media (CallsSipCall *self, gboolean enabled); +void calls_sip_call_set_state (CallsSipCall *self, + CallsCallState state); G_END_DECLS diff --git a/plugins/sip/calls-sip-origin.c b/plugins/sip/calls-sip-origin.c index 32a80d3..6754189 100644 --- a/plugins/sip/calls-sip-origin.c +++ b/plugins/sip/calls-sip-origin.c @@ -269,8 +269,8 @@ sip_i_state (int status, default: return; } - g_object_set (call, "state", state, NULL); + calls_sip_call_set_state (call, state); } @@ -288,20 +288,22 @@ sip_callback (nua_event_t event, CallsSipOrigin *origin = CALLS_SIP_ORIGIN (magic); /* op currently unused */ CallsSipHandles *op = hmagic; + const char * from = NULL; + switch (event) { case nua_i_invite: - /* This needs to be handled by CallsSipCall */ - //g_debug ("incoming call INVITE: %03d %s", status, phrase); - //origin->oper->incoming_call_handle = nh; - ///* We can only handle a single call */ - //if (origin->call_state != SIP_CALL_READY) { - // const char * from = NULL; + tl_gets (tags, SIPTAG_FROM_STR_REF (from), TAG_END ()); - // tl_gets (tags, SIPTAG_FROM_STR_REF (from), TAG_END ()); + g_debug ("incoming call INVITE: %03d %s from %s", status, phrase, from); + + /* reject if there already is a ongoing call */ + if (op->call_handle) { + nua_respond (nh, 486, NULL, TAG_END ()); + g_debug ("Cannot handle more than one call. Rejecting"); + } + else + calls_sip_origin_create_inbound (origin, from, nh); - // g_debug ("Rejecting call from %s", from); - // nua_respond (nh, 486, NULL, TAG_END ()); - //} break; case nua_r_invite: @@ -440,7 +442,6 @@ setup_sip_handles (CallsSipOrigin *self) NUTAG_REGISTRAR (self->host), TAG_END ()); oper->call_handle = NULL; - oper->incoming_call_handle = NULL; return oper; } @@ -564,6 +565,10 @@ remove_call (CallsSipOrigin *self, "nua-handle", &nh, NULL); + /* TODO support multiple simultaneous calls */ + if (self->oper->call_handle == nh) + self->oper->call_handle = NULL; + g_hash_table_remove (self->call_handles, nh); nua_handle_unref (nh); @@ -596,7 +601,6 @@ remove_calls (CallsSipOrigin *self, g_hash_table_remove_all (self->call_handles); g_clear_pointer (&self->oper->call_handle, nua_handle_unref); - g_clear_pointer (&self->oper->incoming_call_handle, nua_handle_unref); } @@ -646,15 +650,26 @@ add_call (CallsSipOrigin *self, SOATAG_AF (SOA_AF_IP4_IP6), TAG_END ()); + if (self->oper->call_handle) + nua_handle_unref (self->oper->call_handle); + self->oper->call_handle = handle; + g_hash_table_insert (self->call_handles, handle, sip_call); + + if (!inbound) + nua_invite (self->oper->call_handle, + SIPTAG_TO_STR (address), + SOATAG_RTP_SORT (SOA_RTP_SORT_REMOTE), + SOATAG_RTP_SELECT (SOA_RTP_SELECT_ALL), + TAG_END ()); + call = CALLS_CALL (sip_call); g_signal_connect_swapped (call, "state-changed", G_CALLBACK (on_call_state_changed_cb), self); self->calls = g_list_append (self->calls, sip_call); - g_hash_table_insert (self->call_handles, handle, sip_call); g_signal_emit_by_name (CALLS_ORIGIN (self), "call-added", call); } @@ -665,6 +680,7 @@ dial (CallsOrigin *origin, const gchar *address) { CallsSipOrigin *self; + nua_handle_t *nh; g_assert (CALLS_ORIGIN (origin)); g_assert (CALLS_IS_SIP_ORIGIN (origin)); @@ -676,15 +692,14 @@ dial (CallsOrigin *origin, self = CALLS_SIP_ORIGIN (origin); - if (self->oper->call_handle) - nua_handle_unref (self->oper->call_handle); + nh = nua_handle (self->nua, self->oper, + NUTAG_MEDIA_ENABLE (1), + SOATAG_ACTIVE_AUDIO (SOA_ACTIVE_SENDRECV), + TAG_END ()); - self->oper->call_handle = nua_handle (self->nua, self->oper, - NUTAG_MEDIA_ENABLE (1), - SOATAG_ACTIVE_AUDIO (SOA_ACTIVE_SENDRECV), - TAG_END ()); + g_debug ("Calling `%s'", address); - add_call (CALLS_SIP_ORIGIN (origin), address, FALSE, self->oper->call_handle); + add_call (CALLS_SIP_ORIGIN (origin), address, FALSE, nh); } @@ -821,7 +836,6 @@ calls_sip_origin_dispose (GObject *object) if (self->oper) { g_clear_pointer (&self->oper->call_handle, nua_handle_unref); - g_clear_pointer (&self->oper->incoming_call_handle, nua_handle_unref); g_clear_pointer (&self->oper->register_handle, nua_handle_unref); } @@ -978,6 +992,12 @@ calls_sip_origin_create_inbound (CallsSipOrigin *self, g_return_if_fail (address != NULL); g_return_if_fail (CALLS_IS_SIP_ORIGIN (self)); + /* TODO support multiple calls */ + if (self->oper->call_handle) + nua_handle_unref (self->oper->call_handle); + + self->oper->call_handle = handle; + add_call (self, address, TRUE, handle); } diff --git a/plugins/sip/calls-sip-util.h b/plugins/sip/calls-sip-util.h index 9bf47c6..b796fe4 100644 --- a/plugins/sip/calls-sip-util.h +++ b/plugins/sip/calls-sip-util.h @@ -38,7 +38,6 @@ typedef struct { nua_handle_t *register_handle; nua_handle_t *call_handle; - nua_handle_t *incoming_call_handle; CallsSipContext *context; } CallsSipHandles;