shared_tester_functions.cpp 29.73 KiB
/*
 * Copyright (c) 2010-2022 Belledonne Communications SARL.
 * This file is part of Liblinphone
 * (see https://gitlab.linphone.org/BC/public/liblinphone).
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <bctoolbox/tester.h>
#include "c-wrapper/internal/c-tools.h"
#include "call/call.h"
#include "conference/conference-info.h"
#include "conference/params/media-session-params.h"
#include "conference/participant-device.h"
#include "conference/session/media-session.h"
#include "liblinphone_tester.h"
#include "mediastreamer2/msmire.h"
#include "sal/call-op.h"
#include "sal/sal_media_description.h"
#include "shared_tester_functions.h"
#include "tester_utils.h"
using namespace std;
#include <sstream>
using namespace LinphonePrivate;
static void check_ice_from_rtp(LinphoneCall *c1, LinphoneCall *c2, LinphoneStreamType stream_type) {
	MediaStream *ms;
	LinphoneCallStats *stats;
	switch (stream_type) {
		case LinphoneStreamTypeAudio:
			ms = linphone_call_get_stream(c1, LinphoneStreamTypeAudio);
			break;
		case LinphoneStreamTypeVideo:
			ms = linphone_call_get_stream(c1, LinphoneStreamTypeVideo);
			break;
		case LinphoneStreamTypeText:
			ms = linphone_call_get_stream(c1, LinphoneStreamTypeText);
			break;
		default:
			lError() << "Unknown stream type [" << linphone_stream_type_to_string(stream_type) << "]";
			BC_ASSERT_FALSE(stream_type >= LinphoneStreamTypeUnknown);
			return;
	stats = linphone_call_get_audio_stats(c1);
	if (linphone_call_stats_get_ice_state(stats) == LinphoneIceStateHostConnection && media_stream_started(ms)) {
		struct sockaddr_storage remaddr;
		socklen_t remaddrlen = sizeof(remaddr);
		char ip[NI_MAXHOST] = {0};
		int port = 0;
		std::string expected_addr;
		AudioStream *astream;
		const LinphoneCallParams *cp1 = linphone_call_get_current_params(c1);
		const LinphoneCallParams *cp2 = linphone_call_get_current_params(c2);
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
if (linphone_call_params_get_update_call_when_ice_completed(cp1) && linphone_call_params_get_update_call_when_ice_completed(cp2)) { memset(&remaddr, 0, remaddrlen); LinphonePrivate::SalCallOp *op = LinphonePrivate::Call::toCpp(c2)->getOp(); const std::shared_ptr<SalMediaDescription> &result_desc = op->getFinalMediaDescription(); const auto &result_stream = result_desc->getStreamIdx(0); if (result_stream != Utils::getEmptyConstRefObject<SalStreamDescription>()) { expected_addr = result_stream.getRtpAddress(); } if (expected_addr.empty()) { expected_addr = result_desc->getConnectionAddress(); } astream = (AudioStream *)linphone_call_get_stream(c1, LinphoneStreamTypeAudio); if ((expected_addr.find(':') == std::string::npos) && (astream->ms.sessions.rtp_session->rtp.gs.rem_addr.ss_family == AF_INET6)) { bctbx_sockaddr_ipv6_to_ipv4((struct sockaddr *)&astream->ms.sessions.rtp_session->rtp.gs.rem_addr, (struct sockaddr *)&remaddr, &remaddrlen); } else { memcpy(&remaddr, &astream->ms.sessions.rtp_session->rtp.gs.rem_addr, astream->ms.sessions.rtp_session->rtp.gs.rem_addrlen); } bctbx_sockaddr_to_ip_address((struct sockaddr *)&remaddr, remaddrlen, ip, sizeof(ip), &port); BC_ASSERT_STRING_EQUAL(ip, expected_addr.c_str()); } } linphone_call_stats_unref(stats); } bool_t check_ice(LinphoneCoreManager *caller, LinphoneCoreManager *callee, LinphoneIceState state) { LinphoneCall *c1, *c2; bool_t global_success = TRUE; bool_t audio_success = FALSE; bool_t video_success = FALSE; bool_t text_success = FALSE; bool_t audio_enabled, video_enabled, realtime_text_enabled; MSTimeSpec ts; c1 = linphone_core_get_call_by_remote_address2(caller->lc, callee->identity); c2 = linphone_core_get_call_by_remote_address2(callee->lc, caller->identity); BC_ASSERT_PTR_NOT_NULL(c1); BC_ASSERT_PTR_NOT_NULL(c2); if (!c1 || !c2) return FALSE; linphone_call_ref(c1); linphone_call_ref(c2); BC_ASSERT_EQUAL(linphone_call_params_video_enabled(linphone_call_get_current_params(c1)), linphone_call_params_video_enabled(linphone_call_get_current_params(c2)), int, "%d"); BC_ASSERT_EQUAL(linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(c1)), linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(c2)), int, "%d"); audio_enabled = linphone_call_params_audio_enabled(linphone_call_get_current_params(c1)); video_enabled = linphone_call_params_video_enabled(linphone_call_get_current_params(c1)); realtime_text_enabled = linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(c1)); if (audio_enabled) { liblinphone_tester_clock_start(&ts); LinphoneCallStats *stats1 = NULL; LinphoneCallStats *stats2 = NULL; do { if ((c1 != NULL) && (c2 != NULL)) { stats1 = linphone_call_get_audio_stats(c1); stats2 = linphone_call_get_audio_stats(c2); if (linphone_call_stats_get_ice_state(stats1) == state && linphone_call_stats_get_ice_state(stats2) == state) { audio_success = TRUE; check_ice_from_rtp(c1, c2, LinphoneStreamTypeAudio); check_ice_from_rtp(c2, c1, LinphoneStreamTypeAudio); break; }
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
linphone_core_iterate(caller->lc); linphone_core_iterate(callee->lc); linphone_call_stats_unref(stats1); linphone_call_stats_unref(stats2); stats1 = stats2 = NULL; } ms_usleep(20000); } while (!liblinphone_tester_clock_elapsed(&ts, 10000)); if (stats1) linphone_call_stats_unref(stats1); if (stats2) linphone_call_stats_unref(stats2); } if (video_enabled) { liblinphone_tester_clock_start(&ts); LinphoneCallStats *stats1 = NULL; LinphoneCallStats *stats2 = NULL; do { if ((c1 != NULL) && (c2 != NULL)) { stats1 = linphone_call_get_video_stats(c1); stats2 = linphone_call_get_video_stats(c2); if (linphone_call_stats_get_ice_state(stats1) == state && linphone_call_stats_get_ice_state(stats2) == state) { video_success = TRUE; check_ice_from_rtp(c1, c2, LinphoneStreamTypeVideo); check_ice_from_rtp(c2, c1, LinphoneStreamTypeVideo); break; } linphone_core_iterate(caller->lc); linphone_core_iterate(callee->lc); linphone_call_stats_unref(stats1); linphone_call_stats_unref(stats2); stats1 = stats2 = NULL; } ms_usleep(20000); } while (!liblinphone_tester_clock_elapsed(&ts, 10000)); if (stats1) linphone_call_stats_unref(stats1); if (stats2) linphone_call_stats_unref(stats2); } if (realtime_text_enabled) { liblinphone_tester_clock_start(&ts); LinphoneCallStats *stats1 = NULL; LinphoneCallStats *stats2 = NULL; do { if ((c1 != NULL) && (c2 != NULL)) { stats1 = linphone_call_get_text_stats(c1); stats2 = linphone_call_get_text_stats(c2); if (linphone_call_stats_get_ice_state(stats1) == state && linphone_call_stats_get_ice_state(stats2) == state) { text_success = TRUE; check_ice_from_rtp(c1, c2, LinphoneStreamTypeText); check_ice_from_rtp(c2, c1, LinphoneStreamTypeText); break; } linphone_core_iterate(caller->lc); linphone_core_iterate(callee->lc); linphone_call_stats_unref(stats1); linphone_call_stats_unref(stats2); stats1 = stats2 = NULL; } ms_usleep(20000); } while (!liblinphone_tester_clock_elapsed(&ts, 10000)); if (stats1) linphone_call_stats_unref(stats1); if (stats2) linphone_call_stats_unref(stats2); } linphone_call_unref(c1); linphone_call_unref(c2); if (audio_enabled) global_success = global_success && audio_success; if (video_enabled) global_success = global_success && video_success; if (realtime_text_enabled) global_success = global_success && text_success;
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
return global_success; } bool_t check_ice_sdp(LinphoneCall *call) { SalMediaDescription *desc = _linphone_call_get_local_desc(call); belle_sdp_session_description_t *sdp = desc->toSdp(); const char *value = belle_sdp_session_description_get_attribute_value(sdp, "ice-ufrag"); if (value) return TRUE; return FALSE; } bool_t is_srtp_secured(LinphoneCall *call, LinphoneStreamType ctype) { SalStreamType type = SalOther; switch (ctype) { case LinphoneStreamTypeAudio: type = SalAudio; break; case LinphoneStreamTypeVideo: type = SalVideo; break; case LinphoneStreamTypeText: type = SalText; break; default: type = SalOther; break; } SalMediaDescription *desc = _linphone_call_get_result_desc(call); const SalStreamDescription &stream = desc->findBestStream(type); if (stream == Utils::getEmptyConstRefObject<SalStreamDescription>()) return FALSE; if (stream.hasSrtp()) { const auto &streamCryptos = stream.getCryptos(); for (const auto &crypto : streamCryptos) { const auto &algo = crypto.algo; // return (!ms_crypto_suite_is_unencrypted(algo) && !ms_crypto_suite_is_unauthenticated(algo)); return (!ms_crypto_suite_is_unencrypted(algo)); } } return FALSE; } void check_media_stream(LinphoneCall *call, bool_t is_null) { LinphonePrivate::Call *c = LinphonePrivate::Call::toCpp(call); const auto &params = linphone_call_get_current_params(call); if (is_null || (params && !linphone_call_params_audio_enabled(params))) { BC_ASSERT_PTR_NULL(c->getMediaStream(LinphoneStreamTypeAudio)); } else { BC_ASSERT_PTR_NOT_NULL(c->getMediaStream(LinphoneStreamTypeAudio)); } if (is_null || (params && !linphone_call_params_video_enabled(params))) { BC_ASSERT_PTR_NULL(c->getMediaStream(LinphoneStreamTypeVideo)); } else { BC_ASSERT_PTR_NOT_NULL(c->getMediaStream(LinphoneStreamTypeVideo)); } if (is_null || (params && !linphone_call_params_realtime_text_enabled(params))) { BC_ASSERT_PTR_NULL(c->getMediaStream(LinphoneStreamTypeText)); } else { BC_ASSERT_PTR_NOT_NULL(c->getMediaStream(LinphoneStreamTypeText)); } } void check_result_desc_rtp_rtcp_ports(LinphoneCall *call, int rtp_port, int rtcp_port) { SalMediaDescription *desc = _linphone_call_get_result_desc(call); for (auto &stream : desc->streams) { BC_ASSERT_EQUAL(stream.rtp_port, rtp_port, int, "%d"); BC_ASSERT_EQUAL(stream.rtcp_port, rtcp_port, int, "%d");
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
} } void check_local_desc_stream(LinphoneCall *call) { const auto &desc = _linphone_call_get_local_desc(call); const auto &core = linphone_call_get_core(call); const auto &params = linphone_call_get_params(call); const auto &audioStream = desc->findBestStream(SalAudio); if (audioStream != Utils::getEmptyConstRefObject<SalStreamDescription>()) { const auto &streamDir = audioStream.getDirection(); const auto &callParamsAudioDir = sal_dir_from_call_params_dir(linphone_call_params_get_audio_direction(params)); if (params && linphone_call_params_audio_enabled(params)) { BC_ASSERT_EQUAL(streamDir, callParamsAudioDir, int, "%d"); } else { BC_ASSERT_EQUAL(streamDir, linphone_core_get_keep_stream_direction_for_rejected_stream(core) ? callParamsAudioDir : SalStreamInactive, int, "%d"); BC_ASSERT_EQUAL(audioStream.rtp_port, 0, int, "%d"); BC_ASSERT_EQUAL(audioStream.rtcp_port, 0, int, "%d"); } } const auto &videoStream = desc->findBestStream(SalVideo); if (videoStream != Utils::getEmptyConstRefObject<SalStreamDescription>()) { const auto &streamDir = videoStream.getDirection(); const auto &callParamsVideoDir = sal_dir_from_call_params_dir(linphone_call_params_get_video_direction(params)); if (params && linphone_call_params_video_enabled(params)) { BC_ASSERT_EQUAL(streamDir, callParamsVideoDir, int, "%d"); } else { BC_ASSERT_EQUAL(streamDir, linphone_core_get_keep_stream_direction_for_rejected_stream(core) ? callParamsVideoDir : SalStreamInactive, int, "%d"); BC_ASSERT_EQUAL(videoStream.rtp_port, 0, int, "%d"); BC_ASSERT_EQUAL(videoStream.rtcp_port, 0, int, "%d"); } } const auto &textStream = desc->findBestStream(SalText); if (textStream != Utils::getEmptyConstRefObject<SalStreamDescription>()) { const auto &streamDir = textStream.getDirection(); if (params && linphone_call_params_realtime_text_enabled(params)) { BC_ASSERT_EQUAL(streamDir, SalStreamSendRecv, int, "%d"); } else { BC_ASSERT_EQUAL(streamDir, linphone_core_get_keep_stream_direction_for_rejected_stream(core) ? SalStreamSendRecv : SalStreamInactive, int, "%d"); BC_ASSERT_EQUAL(textStream.rtp_port, 0, int, "%d"); BC_ASSERT_EQUAL(textStream.rtcp_port, 0, int, "%d"); } } } void _linphone_call_check_nb_streams(const LinphoneCall *call, const int nb_audio_streams, const int nb_video_streams, const int nb_text_streams) { const SalMediaDescription *call_result_desc = _linphone_call_get_result_desc(call); BC_ASSERT_PTR_NOT_NULL(call_result_desc); if (call_result_desc) { BC_ASSERT_EQUAL((int)call_result_desc->getNbStreams(), nb_audio_streams + nb_video_streams + nb_text_streams, int, "%i"); BC_ASSERT_EQUAL((int)call_result_desc->nbStreamsOfType(SalAudio), nb_audio_streams, int, "%i"); BC_ASSERT_EQUAL((int)call_result_desc->nbStreamsOfType(SalVideo), nb_video_streams, int, "%i"); BC_ASSERT_EQUAL((int)call_result_desc->nbStreamsOfType(SalText), nb_text_streams, int, "%i"); } }
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
int _linphone_call_get_nb_audio_steams(const LinphoneCall *call) { const SalMediaDescription *call_result_desc = _linphone_call_get_result_desc(call); return (int)call_result_desc->nbStreamsOfType(SalAudio); } int _linphone_call_get_nb_video_steams(const LinphoneCall *call) { const SalMediaDescription *call_result_desc = _linphone_call_get_result_desc(call); return (int)call_result_desc->nbStreamsOfType(SalVideo); } int _linphone_call_get_nb_text_steams(const LinphoneCall *call) { const SalMediaDescription *call_result_desc = _linphone_call_get_result_desc(call); return (int)call_result_desc->nbStreamsOfType(SalText); } LinphoneConferenceLayout _linphone_participant_device_get_layout(const LinphoneParticipantDevice *participant_device) { const auto &session = static_pointer_cast<MediaSession>(LinphonePrivate::ParticipantDevice::toCpp(participant_device)->getSession()); if (session) { return (LinphoneConferenceLayout)session->getRemoteParams()->getConferenceVideoLayout(); } return LinphoneConferenceLayoutGrid; } bool_t _linphone_participant_device_get_audio_enabled(const LinphoneParticipantDevice *participant_device) { const auto &session = static_pointer_cast<MediaSession>(LinphonePrivate::ParticipantDevice::toCpp(participant_device)->getSession()); if (session) { return (session->getCurrentParams()->audioEnabled()) ? TRUE : FALSE; } return FALSE; } bool_t _linphone_participant_device_get_video_enabled(const LinphoneParticipantDevice *participant_device) { const auto &session = static_pointer_cast<MediaSession>(LinphonePrivate::ParticipantDevice::toCpp(participant_device)->getSession()); if (session) { return (session->getCurrentParams()->videoEnabled()) ? TRUE : FALSE; } return FALSE; } bool_t _linphone_participant_device_get_real_time_text_enabled(const LinphoneParticipantDevice *participant_device) { const auto &session = static_pointer_cast<MediaSession>(LinphonePrivate::ParticipantDevice::toCpp(participant_device)->getSession()); if (session) { return (session->getCurrentParams()->realtimeTextEnabled()) ? TRUE : FALSE; } return FALSE; } void _linphone_call_check_nb_active_streams(const LinphoneCall *call, const int nb_audio_streams, const int nb_video_streams, const int nb_text_streams) { BC_ASSERT_EQUAL(Call::toCpp(call)->getMediaStreamsNb(LinphoneStreamTypeAudio), nb_audio_streams, int, "%d"); BC_ASSERT_EQUAL(Call::toCpp(call)->getMediaStreamsNb(LinphoneStreamTypeVideo), nb_video_streams, int, "%d"); BC_ASSERT_EQUAL(Call::toCpp(call)->getMediaStreamsNb(LinphoneStreamTypeText), nb_text_streams, int, "%d"); } void check_video_conference(bctbx_list_t *lcs, LinphoneCoreManager *lc1, LinphoneCoreManager *lc2, LinphoneConferenceLayout layout) { LinphoneCall *call1 = linphone_core_get_current_call(lc1->lc); LinphoneCall *call2 = linphone_core_get_current_call(lc2->lc); BC_ASSERT_PTR_NOT_NULL(call1); BC_ASSERT_PTR_NOT_NULL(call2); if (call1 && call2) {
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
VideoStream *vstream1s = (VideoStream *)linphone_call_get_stream(call1, LinphoneStreamTypeVideo); BC_ASSERT_PTR_NOT_NULL(vstream1s); VideoStream *vstream2s = (VideoStream *)linphone_call_get_stream(call2, LinphoneStreamTypeVideo); BC_ASSERT_PTR_NOT_NULL(vstream2s); BC_ASSERT_TRUE(vstream1s && vstream1s->source && ms_filter_get_id(vstream1s->source) == MS_MIRE_ID); BC_ASSERT_TRUE(vstream2s && vstream2s->source && ms_filter_get_id(vstream2s->source) == MS_MIRE_ID); MSMireControl c1 = {{0, 5, 10, 15, 20, 25}}; MSMireControl c2 = {{100, 120, 140, 160, 180, 200}}; if (vstream1s && vstream1s->source && ms_filter_get_id(vstream1s->source) == MS_MIRE_ID) { ms_filter_call_method(vstream1s->source, MS_MIRE_SET_COLOR, &c1); } if (vstream2s && vstream2s->source && ms_filter_get_id(vstream2s->source) == MS_MIRE_ID) { ms_filter_call_method(vstream2s->source, MS_MIRE_SET_COLOR, &c2); } wait_for_list(lcs, NULL, 5, liblinphone_tester_sip_timeout); LinphoneConference *conference1 = linphone_call_get_conference(call1); BC_ASSERT_PTR_NOT_NULL(conference1); if (conference1) { int nb = (linphone_conference_get_participant_count(conference1) + 2); BC_ASSERT_EQUAL(Call::toCpp(call1)->getMediaStreamsNb(LinphoneStreamTypeVideo), nb, int, "%d"); } LinphoneConference *conference2 = linphone_call_get_conference(call1); BC_ASSERT_PTR_NOT_NULL(conference2); if (conference2) { int nb = (linphone_conference_get_participant_count(conference2) + 2); BC_ASSERT_EQUAL(Call::toCpp(call2)->getMediaStreamsNb(LinphoneStreamTypeVideo), nb, int, "%d"); } linphone_call_check_rtp_sessions(call1); linphone_call_check_rtp_sessions(call2); BC_ASSERT_TRUE(linphone_call_compare_video_color(call1, c2, MediaStreamRecvOnly, vstream2s->label)); BC_ASSERT_TRUE(linphone_call_compare_video_color(call2, c1, MediaStreamRecvOnly, vstream1s->label)); if (layout != LinphoneConferenceLayoutGrid) { BC_ASSERT_TRUE(linphone_call_compare_video_color(call2, c1, MediaStreamSendRecv, "")); } } } void check_video_conference_with_local_participant(bctbx_list_t *participants, LinphoneConferenceLayout layout, bool_t local_participant) { for (bctbx_list_t *it = participants; it; it = bctbx_list_next(it)) { LinphoneCoreManager *m = (LinphoneCoreManager *)bctbx_list_get_data(it); LinphoneCall *call = linphone_core_get_current_call(m->lc); BC_ASSERT_PTR_NOT_NULL(call); if (call) { const LinphoneCallParams *call_params = linphone_call_get_current_params(call); const bool_t video_enabled = linphone_call_params_video_enabled(call_params); int nb = (static_cast<int>((bctbx_list_size(participants) + (local_participant ? 2 : 1)))); if (!video_enabled) { if (layout == LinphoneConferenceLayoutActiveSpeaker) { // Only thumbnail corresponding to the participant is going to be inactivated nb--; } else if (layout == LinphoneConferenceLayoutGrid) { // main and thumbnail corresponding to the participant are going to be inactivated nb -= 2; } } BC_ASSERT_EQUAL(Call::toCpp(call)->getMediaStreamsNb(LinphoneStreamTypeVideo), nb, int, "%d"); if (video_enabled) { linphone_call_check_rtp_sessions(call); } } } }
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
void _linphone_conference_video_change(bctbx_list_t *lcs, LinphoneCoreManager *mgr1, LinphoneCoreManager *mgr2, LinphoneCoreManager *mgr3) { MSMireControl c1 = {{0, 5, 10, 15, 20, 25}}; MSMireControl c3 = {{100, 120, 140, 160, 180, 200}}; for (LinphoneCoreManager *mgr : {mgr1, mgr2, mgr3}) { LinphoneCall *call = linphone_core_get_current_call(mgr->lc); BC_ASSERT_PTR_NOT_NULL(call); if (!call) return; VideoStream *vstream = (VideoStream *)linphone_call_get_stream(call, LinphoneStreamTypeVideo); if (mgr != mgr2) { // mgr2 is audio only BC_ASSERT_TRUE(vstream && vstream->source && ms_filter_get_id(vstream->source) == MS_MIRE_ID); if (vstream && vstream->source && ms_filter_get_id(vstream->source) == MS_MIRE_ID) { if (mgr == mgr1) ms_filter_call_method(vstream->source, MS_MIRE_SET_COLOR, &c1); else ms_filter_call_method(vstream->source, MS_MIRE_SET_COLOR, &c3); } } else { BC_ASSERT_PTR_NULL(vstream); } } LinphoneCall *call1 = linphone_core_get_current_call(mgr1->lc); LinphoneConference *confMgr1 = linphone_call_get_conference(call1); LinphoneConference *confMgr3 = linphone_call_get_conference(linphone_core_get_current_call(mgr3->lc)); // mgr3 speaks and mgr1's video change linphone_core_enable_mic(mgr1->lc, FALSE); linphone_core_enable_mic(mgr2->lc, FALSE); lInfo() << __func__ << ": mgr3 speaks"; wait_for_list(lcs, NULL, 0, 5000); BC_ASSERT_TRUE(linphone_call_compare_video_color(call1, c3, MediaStreamSendRecv, "")); // mgr1 should see mgr3 as active speaker LinphoneParticipantDevice *device = linphone_conference_get_active_speaker_participant_device(confMgr1); if (BC_ASSERT_PTR_NOT_NULL(device)) { const LinphoneAddress *addrMgr1 = linphone_participant_device_get_address(device); LinphoneParticipant *participant = linphone_conference_get_me(confMgr3); bctbx_list_t *devices = linphone_participant_get_devices(participant); const LinphoneAddress *addrMgr3 = linphone_participant_device_get_address((LinphoneParticipantDevice *)devices->data); BC_ASSERT_TRUE(linphone_address_equal(addrMgr1, addrMgr3)); bctbx_list_free_with_data(devices, (bctbx_list_free_func)linphone_participant_device_unref); } // mgr2 does not see any active speaker as it has no video LinphoneConference *confMgr2 = linphone_call_get_conference(linphone_core_get_current_call(mgr2->lc)); device = linphone_conference_get_active_speaker_participant_device(confMgr2); BC_ASSERT_PTR_NULL(device); // mgr2 speaks until mgr1's video change linphone_core_enable_mic(mgr2->lc, TRUE); linphone_core_enable_mic(mgr3->lc, FALSE); lInfo() << __func__ << ": mgr2 speaks"; /* mg2 is audio-only, so this shall not affect video on other participants */ wait_for_list(lcs, NULL, 0, 5000); BC_ASSERT_FALSE(linphone_call_compare_video_color(call1, c3, MediaStreamSendRecv, "")); BC_ASSERT_FALSE(linphone_call_compare_video_color(call1, c1, MediaStreamSendRecv, "")); // mgr1 should see mgr2 as active speaker even though it has no video as it's speaking device = linphone_conference_get_active_speaker_participant_device(confMgr1); if (BC_ASSERT_PTR_NOT_NULL(device)) { const LinphoneAddress *addrMgr1 = linphone_participant_device_get_address(device); LinphoneParticipant *participant = linphone_conference_get_me(confMgr2);
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
bctbx_list_t *devices = linphone_participant_get_devices(participant); const LinphoneAddress *addrMgr2 = linphone_participant_device_get_address((LinphoneParticipantDevice *)devices->data); BC_ASSERT_TRUE(linphone_address_equal(addrMgr1, addrMgr2)); bctbx_list_free_with_data(devices, (bctbx_list_free_func)linphone_participant_device_unref); } // mgr1 speaks and mgr1's video not change lInfo() << __func__ << ": mgr1 speaks"; linphone_core_enable_mic(mgr2->lc, FALSE); linphone_core_enable_mic(mgr1->lc, TRUE); wait_for_list(lcs, NULL, 0, 5000); BC_ASSERT_TRUE(linphone_call_compare_video_color(call1, c3, MediaStreamSendRecv, "")); BC_ASSERT_FALSE(linphone_call_compare_video_color(call1, c1, MediaStreamSendRecv, "")); // mgr3 should see mgr1 as active speaker device = linphone_conference_get_active_speaker_participant_device(confMgr3); if (BC_ASSERT_PTR_NOT_NULL(device)) { const LinphoneAddress *addrMgr3 = linphone_participant_device_get_address(device); LinphoneParticipant *participant = linphone_conference_get_me(confMgr1); bctbx_list_t *devices = linphone_participant_get_devices(participant); const LinphoneAddress *addrMgr1 = linphone_participant_device_get_address((LinphoneParticipantDevice *)devices->data); BC_ASSERT_TRUE(linphone_address_equal(addrMgr3, addrMgr1)); bctbx_list_free_with_data(devices, (bctbx_list_free_func)linphone_participant_device_unref); } } const char *_linphone_call_get_subject(LinphoneCall *call) { SalCallOp *op = Call::toCpp(call)->getOp(); return L_STRING_TO_C(op->getSubject()); } static std::string get_ice_default_candidate(LinphoneCoreManager *m) { std::string rtpAddress; rtpAddress = _linphone_call_get_local_desc(linphone_core_get_current_call(m->lc))->getStreamIdx(0).getRtpAddress(); if (!rtpAddress.empty()) { return rtpAddress; } else { std::string cAddress = _linphone_call_get_local_desc(linphone_core_get_current_call(m->lc))->getConnectionAddress(); return cAddress; } } static bool address_in_list(const std::string &ip, const bctbx_list_t *addresses) { if (ip.empty()) return FALSE; for (; addresses != NULL; addresses = addresses->next) { if (ip.compare((const char *)addresses->data) == 0) return true; } return false; } static void check_expected_candidate_type(LinphoneCoreManager *m, TesterIceCandidateType expected_type, const bctbx_list_t *local_addresses) { std::string ip = get_ice_default_candidate(m); const struct addrinfo *ai = linphone_core_get_stun_server_addrinfo(m->lc); std::string relayIP; // bctbx_message("default-candidate=%s", ip.c_str()); if (ai) { char rawip[64] = {0}; bctbx_addrinfo_to_ip_address(ai, rawip, sizeof(rawip), NULL); relayIP = rawip;
631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
} switch (expected_type) { case TesterIceCandidateHost: BC_ASSERT_TRUE(address_in_list(ip, local_addresses)); break; case TesterIceCandidateSflrx: BC_ASSERT_FALSE(address_in_list(ip, local_addresses)); BC_ASSERT_TRUE(ip != relayIP); break; case TesterIceCandidateRelay: BC_ASSERT_TRUE(ip == relayIP); break; } } void liblinphone_tester_check_ice_default_candidates(LinphoneCoreManager *marie, TesterIceCandidateType marie_expected_type, LinphoneCoreManager *pauline, TesterIceCandidateType pauline_expected_type) { bctbx_list_t *local_addresses = linphone_fetch_local_addresses(); check_expected_candidate_type(marie, marie_expected_type, local_addresses); check_expected_candidate_type(pauline, pauline_expected_type, local_addresses); bctbx_list_free_with_data(local_addresses, bctbx_free); } int liblinphone_tester_send_data(const void *buffer, size_t length, const char *dest_ip, int dest_port, int sock_type) { struct addrinfo hints; struct addrinfo *res = NULL; int err = 0; std::ostringstream service; bctbx_socket_t sock; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = sock_type; service << dest_port; err = bctbx_getaddrinfo(dest_ip, service.str().c_str(), &hints, &res); if (err != 0) { bctbx_error("liblinphone_tester_send_data: bctbx_getaddrinfo() failed: %s", gai_strerror(err)); return -1; } sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sock == (bctbx_socket_t)-1) { bctbx_error("liblinphone_tester_send_data: socket creation failed."); return -1; } err = bctbx_connect(sock, (struct sockaddr *)res->ai_addr, (socklen_t)res->ai_addrlen); if (err != 0) { bctbx_error("liblinphone_tester_send_data: connection failed: %s", getSocketError()); goto end; } err = bctbx_send(sock, buffer, length, 0); if (err == -1) { bctbx_error("liblinphone_tester_send_data: send() failed: %s", getSocketError()); goto end; } end: bctbx_freeaddrinfo(res); bctbx_socket_close(sock); return err; } bool_t linphone_conference_type_is_full_state(const char *text) { std::string data(text); return ((data.find("state=\"full\"") != std::string::npos) && (data.find("state=\"partial\"") == std::string::npos) && (data.find("state=\"deleted\"") == std::string::npos)) ? TRUE
701702703704705706707708709710711712713714715716717718719720721722723724
: FALSE; } void linphone_conference_info_check_participant(const LinphoneConferenceInfo *conference_info, LinphoneAddress *address, int sequence_number) { const auto &sequence = LinphonePrivate::ConferenceInfo::toCpp(conference_info) ->getParticipantParam(*L_GET_CPP_PTR_FROM_C_OBJECT(address), "X-SEQ"); BC_ASSERT_TRUE(!sequence.empty()); if (!sequence.empty()) { const int sequenceNumber = std::atoi(sequence.c_str()); BC_ASSERT_EQUAL(sequenceNumber, sequence_number, int, "%d"); } } void linphone_conference_info_check_organizer(const LinphoneConferenceInfo *conference_info, int sequence_number) { const auto &sequence = LinphonePrivate::ConferenceInfo::toCpp(conference_info)->getOrganizerParam("X-SEQ"); BC_ASSERT_TRUE(!sequence.empty()); if (!sequence.empty()) { const int sequenceNumber = std::atoi(sequence.c_str()); BC_ASSERT_EQUAL(sequenceNumber, sequence_number, int, "%d"); } }