1
0
Fork 0
mirror of https://gitlab.gnome.org/GNOME/calls.git synced 2024-12-12 07:37:35 +00:00
Purism-Calls/tests/test-sip.c
Evangelos Ribeiro Tzaras babd013bd7 Remove CallsCredentials and adapt to changes
The provider knows best which credentials it needs and CallsCredentials
was not generic to begin with, so get rid of it.
2021-07-20 10:17:17 +02:00

559 lines
17 KiB
C

/*
* Copyright (C) 2021 Purism SPC
*
* SPDX-License-Identifier: GPL-3.0+
*
* Author: Evangelos Ribeiro Tzaras <evangelos.tzaras@puri.sm>
*/
#include "calls-provider.h"
#include "calls-sip-media-manager.h"
#include "calls-sip-provider.h"
#include "calls-sip-origin.h"
#include "calls-sip-util.h"
#include "calls-account.h"
#include "gst-rfc3551.h"
#include <gtk/gtk.h>
#include <sofia-sip/su_uniqueid.h>
#include <libpeas/peas.h>
typedef struct {
CallsSipProvider *provider;
CallsSipOrigin *origin_alice;
CallsSipOrigin *origin_bob;
CallsSipOrigin *origin_offline;
} SipFixture;
static gboolean is_call_test_done = FALSE;
static gboolean are_call_tests_done = FALSE;
static void
test_sip_provider_object (SipFixture *fixture,
gconstpointer user_data)
{
SipEngineState state;
g_assert_true (G_IS_OBJECT (fixture->provider));
g_assert_true (CALLS_IS_MESSAGE_SOURCE (fixture->provider));
g_assert_true (CALLS_IS_PROVIDER (fixture->provider));
g_assert_true (CALLS_IS_SIP_PROVIDER (fixture->provider));
g_object_get (fixture->provider,
"sip-state", &state,
NULL);
g_assert_cmpint (state, ==, SIP_ENGINE_READY);
}
static void
test_sip_provider_origins (SipFixture *fixture,
gconstpointer user_data)
{
GListModel *origins;
origins = calls_provider_get_origins (CALLS_PROVIDER (fixture->provider));
g_assert_cmpuint (g_list_model_get_n_items (origins), ==, 0);
}
static void
setup_sip_provider (SipFixture *fixture,
gconstpointer user_data)
{
CallsProvider *provider = calls_provider_load_plugin ("sip");
fixture->provider = CALLS_SIP_PROVIDER (provider);
is_call_test_done = FALSE;
are_call_tests_done = FALSE;
}
static void
tear_down_sip_provider (SipFixture *fixture,
gconstpointer user_data)
{
g_clear_object (&fixture->provider);
calls_provider_unload_plugin ("sip");
}
static void
test_sip_origin_objects (SipFixture *fixture,
gconstpointer user_data)
{
CallsAccountState state_alice, state_bob, state_offline;
g_assert_true (G_IS_OBJECT (fixture->origin_alice));
g_assert_true (G_IS_OBJECT (fixture->origin_bob));
g_assert_true (G_IS_OBJECT (fixture->origin_offline));
g_assert_true (CALLS_IS_MESSAGE_SOURCE (fixture->origin_alice));
g_assert_true (CALLS_IS_MESSAGE_SOURCE (fixture->origin_bob));
g_assert_true (CALLS_IS_MESSAGE_SOURCE (fixture->origin_offline));
g_assert_true (CALLS_IS_ORIGIN (fixture->origin_alice));
g_assert_true (CALLS_IS_ORIGIN (fixture->origin_bob));
g_assert_true (CALLS_IS_ORIGIN (fixture->origin_offline));
g_assert_true (CALLS_IS_SIP_ORIGIN (fixture->origin_alice));
g_assert_true (CALLS_IS_SIP_ORIGIN (fixture->origin_bob));
g_assert_true (CALLS_IS_SIP_ORIGIN (fixture->origin_offline));
g_object_get (fixture->origin_alice,
"account-state", &state_alice,
NULL);
g_object_get (fixture->origin_bob,
"account-state", &state_bob,
NULL);
g_object_get (fixture->origin_offline,
"account-state", &state_offline,
NULL);
g_assert_cmpint (state_alice, ==, CALLS_ACCOUNT_ONLINE);
g_assert_cmpint (state_bob, ==, CALLS_ACCOUNT_ONLINE);
g_assert_cmpint (state_offline, ==, CALLS_ACCOUNT_OFFLINE);
}
static void
test_sip_origin_call_lists (SipFixture *fixture,
gconstpointer user_data)
{
g_autoptr (GList) calls_alice = NULL;
g_autoptr (GList) calls_bob = NULL;
g_autoptr (GList) calls_offline = NULL;
calls_alice = calls_origin_get_calls (CALLS_ORIGIN (fixture->origin_alice));
g_assert_null (calls_alice);
calls_bob = calls_origin_get_calls (CALLS_ORIGIN (fixture->origin_bob));
g_assert_null (calls_bob);
calls_offline = calls_origin_get_calls (CALLS_ORIGIN (fixture->origin_offline));
g_assert_null (calls_offline);
}
static gboolean
on_call_hangup_cb (gpointer user_data)
{
CallsCall *call = CALLS_CALL (user_data);
g_debug ("Hanging up call");
calls_call_hang_up (call);
return G_SOURCE_REMOVE;
}
static gboolean
on_call_answer_cb (gpointer user_data)
{
CallsCall *call = CALLS_CALL (user_data);
g_debug ("Answering incoming call");
calls_call_answer (call);
return G_SOURCE_REMOVE;
}
static void
on_autoreject_state_changed_cb (CallsCall *call,
CallsCallState new_state,
CallsCallState old_state,
gpointer user_data)
{
g_assert_cmpint (old_state, ==, CALLS_CALL_STATE_INCOMING);
g_assert_cmpint (new_state, ==, CALLS_CALL_STATE_DISCONNECTED);
g_object_unref (call);
is_call_test_done = TRUE;
}
static void
on_state_changed_cb (CallsCall *call,
CallsCallState new_state,
CallsCallState old_state,
gpointer user_data)
{
gboolean schedule_hangup = GPOINTER_TO_INT (user_data);
switch (old_state) {
case CALLS_CALL_STATE_INCOMING:
case CALLS_CALL_STATE_DIALING:
g_assert_cmpint (new_state, ==, CALLS_CALL_STATE_ACTIVE);
if (schedule_hangup)
g_idle_add ((GSourceFunc) on_call_hangup_cb, call);
break;
case CALLS_CALL_STATE_ACTIVE:
g_assert_cmpint (new_state, ==, CALLS_CALL_STATE_DISCONNECTED);
g_object_unref (call);
if (is_call_test_done)
are_call_tests_done = TRUE;
is_call_test_done = TRUE;
break;
default:
g_assert_not_reached ();
}
}
static gboolean
on_incoming_call_autoaccept_cb (CallsOrigin *origin,
CallsCall *call,
gpointer user_data)
{
CallsCallState state = calls_call_get_state (call);
g_assert_cmpint (state, ==, CALLS_CALL_STATE_INCOMING);
g_object_ref (call);
g_idle_add ((GSourceFunc) on_call_answer_cb, call);
g_signal_connect (call, "state-changed",
(GCallback) on_state_changed_cb, user_data);
return G_SOURCE_REMOVE;
}
static gboolean
on_incoming_call_autoreject_cb (CallsOrigin *origin,
CallsCall *call,
gpointer user_data)
{
CallsCallState state = calls_call_get_state (call);
g_assert_cmpint (state, ==, CALLS_CALL_STATE_INCOMING);
g_object_ref (call);
g_idle_add ((GSourceFunc) on_call_hangup_cb, call);
g_signal_connect (call, "state-changed",
(GCallback) on_autoreject_state_changed_cb, NULL);
return G_SOURCE_REMOVE;
}
static gboolean
on_outgoing_call_cb (CallsOrigin *origin,
CallsCall *call,
gpointer user_data)
{
CallsCallState state = calls_call_get_state (call);
g_assert_cmpint (state, ==, CALLS_CALL_STATE_DIALING);
g_object_ref (call);
g_signal_connect (call, "state-changed",
(GCallback) on_state_changed_cb, user_data);
return G_SOURCE_REMOVE;
}
static void
test_sip_call_direct_calls (SipFixture *fixture,
gconstpointer user_data)
{
gint local_port_alice, local_port_bob;
g_autofree gchar *address_alice = NULL;
g_autofree gchar *address_bob = NULL;
gulong handler_alice, handler_bob;
g_object_get (fixture->origin_alice,
"local-port", &local_port_alice,
NULL);
address_alice = g_strdup_printf ("sip:alice@127.0.0.1:%d",
local_port_alice);
g_object_get (fixture->origin_bob,
"local-port", &local_port_bob,
NULL);
address_bob = g_strdup_printf ("sip:bob@127.0.0.1:%d",
local_port_bob);
/* Case 1: Bob calls Alice, Alice rejects call */
g_debug ("Call test: Stage 1");
handler_alice =
g_signal_connect (fixture->origin_alice,
"call-added",
G_CALLBACK (on_incoming_call_autoreject_cb),
NULL);
calls_origin_dial (CALLS_ORIGIN (fixture->origin_bob), address_alice);
while (!is_call_test_done)
g_main_context_iteration (NULL, TRUE);
is_call_test_done = FALSE;
are_call_tests_done = FALSE;
g_signal_handler_disconnect (fixture->origin_alice, handler_alice);
/* Case 2: Alice calls Bob, Bob accepts and hangs up shortly after */
g_debug ("Call test: Stage 2");
handler_alice =
g_signal_connect (fixture->origin_alice,
"call-added",
G_CALLBACK (on_outgoing_call_cb),
GINT_TO_POINTER (FALSE));
handler_bob =
g_signal_connect (fixture->origin_bob,
"call-added",
G_CALLBACK (on_incoming_call_autoaccept_cb),
GINT_TO_POINTER (TRUE));
calls_origin_dial (CALLS_ORIGIN (fixture->origin_alice), address_bob);
while (!are_call_tests_done)
g_main_context_iteration (NULL, TRUE);
is_call_test_done = FALSE;
are_call_tests_done = FALSE;
g_signal_handler_disconnect (fixture->origin_alice, handler_alice);
g_signal_handler_disconnect (fixture->origin_bob, handler_bob);
/* Case 3: Alice calls Bob, Bob accepts and Alice hangs up shortly after */
g_debug ("Call test: Stage 3");
handler_alice =
g_signal_connect (fixture->origin_alice,
"call-added",
G_CALLBACK (on_outgoing_call_cb),
GINT_TO_POINTER (TRUE));
handler_bob =
g_signal_connect (fixture->origin_bob,
"call-added",
G_CALLBACK (on_incoming_call_autoaccept_cb),
GINT_TO_POINTER (FALSE));
calls_origin_dial (CALLS_ORIGIN (fixture->origin_alice), address_bob);
while (!are_call_tests_done)
g_main_context_iteration (NULL, TRUE);
is_call_test_done = FALSE;
are_call_tests_done = FALSE;
g_signal_handler_disconnect (fixture->origin_alice, handler_alice);
g_signal_handler_disconnect (fixture->origin_bob, handler_bob);
}
static void
setup_sip_origins (SipFixture *fixture,
gconstpointer user_data)
{
setup_sip_provider (fixture, user_data);
fixture->origin_alice =
calls_sip_provider_add_origin_full (fixture->provider,
NULL,
"alice",
NULL,
NULL,
NULL,
0,
FALSE,
TRUE,
5060);
fixture->origin_bob =
calls_sip_provider_add_origin_full (fixture->provider,
NULL,
"bob",
NULL,
NULL,
NULL,
0,
FALSE,
TRUE,
5061);
fixture->origin_offline =
calls_sip_provider_add_origin_full (fixture->provider,
"sip.imaginary-host.org",
"username",
"password",
NULL,
"UDP",
0,
FALSE,
FALSE,
0);
}
static void
tear_down_sip_origins (SipFixture *fixture,
gconstpointer user_data)
{
tear_down_sip_provider (fixture, user_data);
}
static gboolean
find_string_in_sdp_message (const char *sdp,
const char *string)
{
char **split_string = NULL;
gboolean found = FALSE;
split_string = g_strsplit (sdp, "\r\n", -1);
for (guint i = 0; split_string[i] != NULL; i++) {
if (g_strcmp0 (split_string[i], string) == 0) {
found = TRUE;
break;
}
}
g_strfreev (split_string);
return found;
}
static void
test_sip_media_manager (void)
{
g_autoptr (CallsSipMediaManager) manager = calls_sip_media_manager_default ();
char *sdp_message = NULL;
GList *codecs = NULL;
/* Check single codecs */
codecs = g_list_append (NULL, media_codec_by_name ("PCMA"));
/* PCMA RTP */
sdp_message =
calls_sip_media_manager_get_capabilities (manager, 40002, FALSE, codecs);
g_assert_true (sdp_message);
g_assert_true (find_string_in_sdp_message (sdp_message,
"m=audio 40002 RTP/AVP 8"));
g_assert_true (find_string_in_sdp_message (sdp_message,
"a=rtpmap:8 PCMA/8000"));
g_assert_true (find_string_in_sdp_message (sdp_message,
"a=rtcp:40003"));
g_free (sdp_message);
/* PCMA SRTP */
sdp_message =
calls_sip_media_manager_get_capabilities (manager, 42002, TRUE, codecs);
g_assert_true (sdp_message);
g_assert_true (find_string_in_sdp_message (sdp_message,
"m=audio 42002 RTP/SAVP 8"));
g_clear_pointer (&codecs, g_list_free);
g_free (sdp_message);
/* G722 RTP */
codecs = g_list_append (NULL, media_codec_by_name ("G722"));
sdp_message =
calls_sip_media_manager_get_capabilities (manager, 42042, FALSE, codecs);
g_assert_true (sdp_message);
g_assert_true (find_string_in_sdp_message (sdp_message,
"m=audio 42042 RTP/AVP 9"));
g_assert_true (find_string_in_sdp_message (sdp_message,
"a=rtpmap:9 G722/8000"));
g_assert_true (find_string_in_sdp_message (sdp_message,
"a=rtcp:42043"));
g_clear_pointer (&codecs, g_list_free);
g_free (sdp_message);
/* G722 PCMU PCMA RTP (in this order) */
codecs = g_list_append (NULL, media_codec_by_name ("G722"));
codecs = g_list_append (codecs, media_codec_by_name ("PCMU"));
codecs = g_list_append (codecs, media_codec_by_name ("PCMA"));
sdp_message =
calls_sip_media_manager_get_capabilities (manager, 33340, FALSE, codecs);
g_assert_true (sdp_message);
g_assert_true (find_string_in_sdp_message (sdp_message,
"m=audio 33340 RTP/AVP 9 0 8"));
g_assert_true (find_string_in_sdp_message (sdp_message,
"a=rtpmap:9 G722/8000"));
g_assert_true (find_string_in_sdp_message (sdp_message,
"a=rtpmap:0 PCMU/8000"));
g_assert_true (find_string_in_sdp_message (sdp_message,
"a=rtpmap:8 PCMA/8000"));
g_clear_pointer (&codecs, g_list_free);
g_free (sdp_message);
/* GSM PCMA G722 PCMU (in this order) */
codecs = g_list_append (NULL, media_codec_by_name ("GSM"));
codecs = g_list_append (codecs, media_codec_by_name ("PCMA"));
codecs = g_list_append (codecs, media_codec_by_name ("G722"));
codecs = g_list_append (codecs, media_codec_by_name ("PCMU"));
sdp_message =
calls_sip_media_manager_get_capabilities (manager, 18098, TRUE, codecs);
g_assert_true (sdp_message);
g_assert_true (find_string_in_sdp_message (sdp_message,
"m=audio 18098 RTP/SAVP 3 8 9 0"));
g_clear_pointer (&codecs, g_list_free);
g_free (sdp_message);
g_test_expect_message ("CallsSipMediaManager", G_LOG_LEVEL_WARNING,
"No supported codecs found. Can't build meaningful SDP message");
sdp_message =
calls_sip_media_manager_get_capabilities (manager, 25048, FALSE, NULL);
g_test_assert_expected_messages ();
g_assert_true (sdp_message);
g_assert_true (find_string_in_sdp_message (sdp_message,
"m=audio 0 RTP/AVP"));
g_free (sdp_message);
}
gint
main (gint argc,
gchar *argv[])
{
gtk_test_init (&argc, &argv, NULL);
#ifdef PLUGIN_BUILDDIR
peas_engine_add_search_path (peas_engine_get_default (), PLUGIN_BUILDDIR, NULL);
#endif
/* this is a workaround for an issue with sofia: https://github.com/freeswitch/sofia-sip/issues/58 */
su_random64 ();
g_test_add ("/Calls/SIP/provider_object", SipFixture, NULL,
setup_sip_provider, test_sip_provider_object, tear_down_sip_provider);
g_test_add ("/Calls/SIP/provider_origins", SipFixture, NULL,
setup_sip_provider, test_sip_provider_origins, tear_down_sip_provider);
g_test_add ("/Calls/SIP/origin_objects", SipFixture, NULL,
setup_sip_origins, test_sip_origin_objects, tear_down_sip_origins);
g_test_add ("/Calls/SIP/origin_call_lists", SipFixture, NULL,
setup_sip_origins, test_sip_origin_call_lists, tear_down_sip_origins);
g_test_add ("/Calls/SIP/calls_direct_call", SipFixture, NULL,
setup_sip_origins, test_sip_call_direct_calls, tear_down_sip_origins);
g_test_add_func ("/Calls/SIP/media_manager", test_sip_media_manager);
return g_test_run();
}