From 5f3273b847ae7be8e202ff56650701bf04bd1b70 Mon Sep 17 00:00:00 2001 From: Andrea Gianarda <andrea.gianarda@belledonne-communications.com> Date: Tue, 29 Aug 2023 12:28:31 +0200 Subject: [PATCH] Source code: - Add callback to notify the application that a participant has changed role in the conference - Take into account role when creating the list of participant informations of a conference - Give priority to the conference information stored in the database over that cached in the call log object - When a participant is added, give the application a pointer to it with all the informations up to date - In the event of a full state, reduce the number of database accesses by updating the conference information in the callback onFullStateReceived. Previously, for every participant added a DB access was required in order to update the conference information Tests: - Add verification of role and sequence id of every participant info in the conference information in the call logs and conference information - add helper functions to ease checking of conference informations --- coreapi/conference-cbs.h | 1 + coreapi/conference.cpp | 7 + coreapi/local_conference.cpp | 8 +- coreapi/private_functions.h | 12 + coreapi/remote_conference.cpp | 65 +- coreapi/remote_conference.h | 4 + coreapi/tester_utils.h | 3 + include/linphone/api/c-callbacks.h | 8 + include/linphone/api/c-conference-cbs.h | 17 + include/linphone/api/c-participant-info.h | 2 +- include/linphone/enums/event-log-enums.h | 3 + src/c-wrapper/api/c-call-log.cpp | 2 +- src/c-wrapper/api/c-conference-cbs.cpp | 10 + src/c-wrapper/api/c-conference-info.cpp | 11 + src/c-wrapper/api/c-conference.cpp | 6 + src/c-wrapper/api/c-participant-info.cpp | 10 +- src/call/call-log.cpp | 7 +- src/call/call-log.h | 2 +- src/chat/chat-message/chat-message.cpp | 3 +- src/chat/chat-room/chat-room.cpp | 1 + src/chat/chat-room/server-group-chat-room.cpp | 2 +- src/chat/encryption/encryption-engine.h | 2 +- src/conference/conference-info.cpp | 35 +- src/conference/conference-interface.h | 9 + src/conference/conference-scheduler.cpp | 42 +- src/conference/conference.cpp | 133 +++- src/conference/conference.h | 12 +- .../local-conference-event-handler.cpp | 2 +- .../remote-conference-event-handler.cpp | 83 +- .../remote-conference-event-handler.h | 5 + src/conference/notify-conference-listener.cpp | 6 + src/conference/notify-conference-listener.h | 8 + src/conference/participant-device.cpp | 1 + src/conference/participant-info.cpp | 6 +- src/conference/participant-info.h | 4 +- src/conference/participant.cpp | 13 + src/conference/participant.h | 12 +- src/conference/session/call-session.cpp | 9 +- src/conference/session/call-session.h | 9 +- src/db/main-db.cpp | 62 +- src/db/main-db.h | 2 +- src/event-log/event-log.cpp | 9 + src/event-log/event-log.h | 3 + tester/liblinphone_tester.h | 1 + tester/local_conference_edition_tester.cpp | 506 +++++------- tester/local_conference_tester_functions.cpp | 742 ++++++++++-------- tester/local_conference_tester_functions.h | 65 +- tester/local_ice_conference_tester.cpp | 16 +- tester/local_inpromptu_conference_tester.cpp | 372 +++++---- tester/local_scheduled_conference_tester.cpp | 297 +++++-- tester/tester.c | 8 + 51 files changed, 1683 insertions(+), 975 deletions(-) diff --git a/coreapi/conference-cbs.h b/coreapi/conference-cbs.h index 282610b0c8..8aca741765 100644 --- a/coreapi/conference-cbs.h +++ b/coreapi/conference-cbs.h @@ -35,6 +35,7 @@ public: LinphoneConferenceCbsParticipantRemovedCb participantRemovedCb; LinphoneConferenceCbsParticipantDeviceAddedCb participantDeviceAddedCb; LinphoneConferenceCbsParticipantDeviceRemovedCb participantDeviceRemovedCb; + LinphoneConferenceCbsParticipantRoleChangedCb participantRoleChangedCb; LinphoneConferenceCbsParticipantAdminStatusChangedCb participantAdminStatusChangedCb; LinphoneConferenceCbsParticipantDeviceMediaCapabilityChangedCb participantDeviceMediaCapabilityChangedCb; LinphoneConferenceCbsParticipantDeviceMediaAvailabilityChangedCb participantDeviceMediaAvailabilityChangedCb; diff --git a/coreapi/conference.cpp b/coreapi/conference.cpp index 947a6b9a75..e0796feb73 100644 --- a/coreapi/conference.cpp +++ b/coreapi/conference.cpp @@ -550,9 +550,16 @@ ConferenceInfo::participant_list_t Conference::getFullParticipantList() const { }); if (pIt == participantList.end()) { auto participantInfo = Factory::get()->createParticipantInfo(pAddress); + participantInfo->setRole(p->getRole()); participantList.push_back(participantInfo); } } + if (isIn()) { + auto me = getMe(); + auto participantInfo = Factory::get()->createParticipantInfo(me->getAddress()); + participantInfo->setRole(me->getRole()); + participantList.push_back(participantInfo); + } return participantList; } diff --git a/coreapi/local_conference.cpp b/coreapi/local_conference.cpp index 6a90697f95..f3071c6df1 100644 --- a/coreapi/local_conference.cpp +++ b/coreapi/local_conference.cpp @@ -217,18 +217,20 @@ void LocalConference::updateConferenceInformation(SalCallOp *op) { } conferenceInfo->setState(infoState); + long long conferenceInfoId = -1; #ifdef HAVE_DB_STORAGE auto &mainDb = getCore()->getPrivate()->mainDb; if (mainDb) { lInfo() << "Inserting conference information to database in order to be able to recreate the conference " << *getConferenceAddress() << " in case of restart"; - mainDb->insertConferenceInfo(conferenceInfo); + conferenceInfoId = mainDb->insertConferenceInfo(conferenceInfo); } #endif auto callLog = session->getLog(); if (callLog) { callLog->setConferenceInfo(conferenceInfo); + callLog->setConferenceInfoId(conferenceInfoId); } if (resourceList.isEmpty()) { setState(ConferenceInterface::State::TerminationPending); @@ -463,6 +465,7 @@ void LocalConference::confirmCreation() { session->startIncomingNotification(false); const auto &conferenceInfo = createOrGetConferenceInfo(); + long long conferenceInfoId = -1; #ifdef HAVE_DB_STORAGE /// Method startIncomingNotification can move the conference to the CreationFailed state if the organizer /// doesn't have any of the codecs the server supports @@ -476,13 +479,14 @@ void LocalConference::confirmCreation() { lInfo() << "Inserting conference information to database in order to be able to recreate the conference " << conferenceAddressStr << " in case of restart"; - mainDb->insertConferenceInfo(conferenceInfo); + conferenceInfoId = mainDb->insertConferenceInfo(conferenceInfo); } } #endif auto callLog = session->getLog(); if (callLog) { callLog->setConferenceInfo(conferenceInfo); + callLog->setConferenceInfoId(conferenceInfoId); } } else { diff --git a/coreapi/private_functions.h b/coreapi/private_functions.h index 4020cacddc..6870c277d9 100644 --- a/coreapi/private_functions.h +++ b/coreapi/private_functions.h @@ -422,6 +422,8 @@ void _linphone_conference_notify_participant_device_added(LinphoneConference *co const LinphoneParticipantDevice *participant_device); void _linphone_conference_notify_participant_device_removed(LinphoneConference *conference, const LinphoneParticipantDevice *participant_device); +void _linphone_conference_notify_participant_role_changed(LinphoneConference *conference, + const LinphoneParticipant *participant); void _linphone_conference_notify_participant_admin_status_changed(LinphoneConference *conference, const LinphoneParticipant *participant); void _linphone_conference_notify_participant_device_media_capability_changed( @@ -1006,9 +1008,19 @@ bctbx_list_t *linphone_core_get_supported_media_encryptions_at_compile_time(); LinphoneConferenceState linphone_chat_room_state_to_conference_state(LinphoneChatRoomState state); LinphoneChatRoomState linphone_conference_state_to_chat_room_state(LinphoneConferenceState state); +// FIXME: Remove this declaration, use LINPHONE_PUBLIC as ugly workaround, already defined in tester_utils.h +LINPHONE_PUBLIC int linphone_participant_info_get_sequence_number(const LinphoneParticipantInfo *participant_info); +LINPHONE_PUBLIC void linphone_participant_info_set_sequence_number(LinphoneParticipantInfo *participant_info, + int sequence); + +LINPHONE_PUBLIC void linphone_conference_info_set_ics_sequence(LinphoneConferenceInfo *conference_info, + unsigned int sequence); LINPHONE_PUBLIC unsigned int linphone_conference_info_get_ics_sequence(const LinphoneConferenceInfo *conference_info); LINPHONE_PUBLIC const char *linphone_conference_info_get_utf8_ics_uid(const LinphoneConferenceInfo *conference_info); +LINPHONE_PUBLIC void linphone_conference_info_set_ics_uid(LinphoneConferenceInfo *conference_info, const char *uid); LINPHONE_PUBLIC const char *linphone_conference_info_get_ics_uid(const LinphoneConferenceInfo *conference_info); +LINPHONE_PUBLIC void linphone_conference_info_set_state(LinphoneConferenceInfo *conference_info, + LinphoneConferenceInfoState state); LinphoneDigestAuthenticationPolicy *linphone_digest_authentication_policy_new(void); LinphoneDigestAuthenticationPolicy *linphone_digest_authentication_policy_new_from_config(LinphoneConfig *config); diff --git a/coreapi/remote_conference.cpp b/coreapi/remote_conference.cpp index 3202cb76ac..ef830fab76 100644 --- a/coreapi/remote_conference.cpp +++ b/coreapi/remote_conference.cpp @@ -811,8 +811,7 @@ bool RemoteConference::transferToFocus(std::shared_ptr<LinphonePrivate::Call> ca const auto &remoteAddress = call->getRemoteAddress(); lInfo() << "Transfering call (local address " << call->getLocalAddress()->toString() << " remote address " << (remoteAddress ? remoteAddress->toString() : "Unknown") << ") to focus " << *referToAddr; - const auto &participantAddress = participant->getAddress(); - updateParticipantsInConferenceInfo(participantAddress); + updateParticipantInConferenceInfo(participant); if (call->transfer(referToAddr->toString()) == 0) { m_transferingCalls.push_back(call); return true; @@ -859,7 +858,7 @@ void RemoteConference::onFocusCallStateChanged(LinphoneCallState state) { switch (state) { case LinphoneCallStreamsRunning: { - updateParticipantsInConferenceInfo(getMe()->getAddress()); + updateParticipantInConferenceInfo(getMe()); const auto &previousState = session->getPreviousState(); // NOTIFY that a participant has been added only if it follows a resume of the call if (previousState == CallSession::State::Resuming) { @@ -1272,8 +1271,22 @@ void RemoteConference::onParticipantAdded(const shared_ptr<ConferenceParticipant const std::shared_ptr<Participant> &participant) { const std::shared_ptr<Address> &pAddr = event->getParticipantAddress(); - const auto &participantAddress = participant->getAddress(); - updateParticipantsInConferenceInfo(participantAddress); + // When receiving a participant added notification, we must recreate the conference informations in order to get the + // participant list up to date + const auto conferenceInfo = getUpdatedConferenceInfo(); + auto callLog = getMainSession() ? getMainSession()->getLog() : nullptr; + if (callLog) { + callLog->setConferenceInfo(conferenceInfo); + } + +#ifdef HAVE_DB_STORAGE + auto &mainDb = getCore()->getPrivate()->mainDb; + if (mainDb) { + lInfo() << "Updating conference information of conference " << *getConferenceAddress() + << " because participant " << *pAddr << " has been added to the conference"; + mainDb->insertConferenceInfo(conferenceInfo); + } +#endif // HAVE_DB_STORAGE if (isMe(pAddr)) { if (getState() == ConferenceInterface::State::CreationPending) { @@ -1305,10 +1318,37 @@ void RemoteConference::onParticipantAdded(const shared_ptr<ConferenceParticipant } } +void RemoteConference::onSubjectChanged(BCTBX_UNUSED(const std::shared_ptr<ConferenceSubjectEvent> &event)) { + const auto conferenceInfo = createOrGetConferenceInfo(); + auto callLog = getMainSession() ? getMainSession()->getLog() : nullptr; + if (callLog) { + callLog->setConferenceInfo(conferenceInfo); + } +} + +void RemoteConference::onParticipantSetRole(BCTBX_UNUSED(const std::shared_ptr<ConferenceParticipantEvent> &event), + BCTBX_UNUSED(const std::shared_ptr<Participant> &participant)) { + + updateParticipantRoleInConferenceInfo(participant); + const auto conferenceInfo = createOrGetConferenceInfo(); + auto callLog = getMainSession() ? getMainSession()->getLog() : nullptr; + if (callLog) { + callLog->setConferenceInfo(conferenceInfo); + } +} + void RemoteConference::onParticipantRemoved(const shared_ptr<ConferenceParticipantEvent> &event, BCTBX_UNUSED(const std::shared_ptr<Participant> &participant)) { const std::shared_ptr<Address> &pAddr = event->getParticipantAddress(); + // When receiving a participant removed notification, we must recreate the conference informations in order to get + // the security level and the participant list up to date + const auto conferenceInfo = createOrGetConferenceInfo(); + auto callLog = getMainSession() ? getMainSession()->getLog() : nullptr; + if (callLog) { + callLog->setConferenceInfo(conferenceInfo); + } + if (isMe(pAddr)) { lInfo() << "Unsubscribing all devices of me (address " << *pAddr << ") from conference " << *getConferenceAddress(); @@ -1437,11 +1477,8 @@ void RemoteConference::onParticipantDeviceMediaAvailabilityChanged( void RemoteConference::onFullStateReceived() { // When receiving a full state, we must recreate the conference informations in order to get the security level and // the participant list up to date - const auto conferenceInfo = createOrGetConferenceInfo(); - auto callLog = getMainSession() ? getMainSession()->getLog() : nullptr; - if (callLog) { - callLog->setConferenceInfo(conferenceInfo); - } + const auto conferenceInfo = getUpdatedConferenceInfo(); + long long conferenceInfoId = -1; #ifdef HAVE_DB_STORAGE // Store into DB after the start incoming notification in order to have a valid conference address being the contact @@ -1449,10 +1486,16 @@ void RemoteConference::onFullStateReceived() { auto &mainDb = getCore()->getPrivate()->mainDb; if (mainDb) { lInfo() << "Inserting conference information to database related to conference " << *getConferenceAddress(); - mainDb->insertConferenceInfo(conferenceInfo); + conferenceInfoId = mainDb->insertConferenceInfo(conferenceInfo); } #endif // HAVE_DB_STORAGE + auto callLog = getMainSession() ? getMainSession()->getLog() : nullptr; + if (callLog) { + callLog->setConferenceInfo(conferenceInfo); + callLog->setConferenceInfoId(conferenceInfoId); + } + auto requestStreams = [this]() -> LinphoneStatus { lInfo() << "Sending re-INVITE in order to get streams after joining conference " << *getConferenceAddress(); setState(ConferenceInterface::State::Created); diff --git a/coreapi/remote_conference.h b/coreapi/remote_conference.h index 35fc7deae7..7d6e72d120 100644 --- a/coreapi/remote_conference.h +++ b/coreapi/remote_conference.h @@ -139,6 +139,10 @@ public: virtual void setParticipantAdminStatus(const std::shared_ptr<LinphonePrivate::Participant> &participant, bool isAdmin) override; + + virtual void onSubjectChanged(const std::shared_ptr<ConferenceSubjectEvent> &event) override; + virtual void onParticipantSetRole(const std::shared_ptr<ConferenceParticipantEvent> &event, + const std::shared_ptr<Participant> &participant) override; virtual void setSubject(const std::string &subject) override; virtual bool update(const ConferenceParamsInterface ¶ms) override; diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h index 505aafa174..537ed2bfb4 100644 --- a/coreapi/tester_utils.h +++ b/coreapi/tester_utils.h @@ -306,6 +306,9 @@ LINPHONE_PUBLIC const char *linphone_core_get_ephemeral_version(const LinphoneCo LINPHONE_PUBLIC size_t linphone_chat_room_get_previouses_conference_ids_count(LinphoneChatRoom *cr); LINPHONE_PUBLIC void linphone_conference_info_set_uri(LinphoneConferenceInfo *conference_info, const LinphoneAddress *uri); +LINPHONE_PUBLIC int linphone_participant_info_get_sequence_number(const LinphoneParticipantInfo *participant_info); +LINPHONE_PUBLIC void linphone_participant_info_set_sequence_number(LinphoneParticipantInfo *participant_info, + int sequence); LINPHONE_PUBLIC bool_t linphone_participant_preserve_session(const LinphoneParticipant *participant); LINPHONE_PUBLIC bool_t linphone_conference_params_is_static(const LinphoneConferenceParams *params); diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index ff0e359793..267fc237fc 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -657,6 +657,14 @@ typedef void (*LinphoneConferenceCbsParticipantDeviceMediaAvailabilityChangedCb) typedef void (*LinphoneConferenceCbsParticipantDeviceMediaCapabilityChangedCb)(LinphoneConference *conference, const LinphoneParticipantDevice *device); +/** + * Callback used to notify a conference that the role of a participant has been changed. + * @param[in] conference #LinphoneConference object @notnil + * @param[in] participant #LinphoneParticipant whose role has changed @notnil + */ +typedef void (*LinphoneConferenceCbsParticipantRoleChangedCb)(LinphoneConference *conference, + const LinphoneParticipant *participant); + /** * Callback used to notify a conference that the admin status of a participant has been changed. * @param[in] conference #LinphoneConference object @notnil diff --git a/include/linphone/api/c-conference-cbs.h b/include/linphone/api/c-conference-cbs.h index 8502f87db3..61d5d81319 100644 --- a/include/linphone/api/c-conference-cbs.h +++ b/include/linphone/api/c-conference-cbs.h @@ -128,6 +128,23 @@ LINPHONE_PUBLIC void linphone_conference_cbs_set_participant_device_removed(LinphoneConferenceCbs *cbs, LinphoneConferenceCbsParticipantDeviceRemovedCb cb); +/** + * Get the participant role changed callback. + * @param[in] cbs #LinphoneConferenceCbs object. + * @return The current participant role changed callback. + */ +LINPHONE_PUBLIC LinphoneConferenceCbsParticipantRoleChangedCb +linphone_conference_cbs_get_participant_role_changed(const LinphoneConferenceCbs *cbs); + +/** + * Set the participant role changed callback. + * @param[in] cbs #LinphoneConferenceCbs object. + * @param[in] cb The participant role changed callback to be used. + */ +LINPHONE_PUBLIC void +linphone_conference_cbs_set_participant_role_changed(LinphoneConferenceCbs *cbs, + LinphoneConferenceCbsParticipantRoleChangedCb cb); + /** * Get the participant admin status changed callback. * @param[in] cbs #LinphoneConferenceCbs object. diff --git a/include/linphone/api/c-participant-info.h b/include/linphone/api/c-participant-info.h index 7266c17f10..81b6866b92 100644 --- a/include/linphone/api/c-participant-info.h +++ b/include/linphone/api/c-participant-info.h @@ -36,7 +36,7 @@ extern "C" { * Create a new #LinphoneParticipantInfo object. * @return The newly created #LinphoneParticipantInfo object. @notnil */ -LINPHONE_PUBLIC LinphoneParticipantInfo *linphone_participant_info_new(LinphoneAddress *address); +LINPHONE_PUBLIC LinphoneParticipantInfo *linphone_participant_info_new(const LinphoneAddress *address); /** * Take a reference on a #LinphoneParticipantInfo. diff --git a/include/linphone/enums/event-log-enums.h b/include/linphone/enums/event-log-enums.h index 1c5220c465..b80bc7663b 100644 --- a/include/linphone/enums/event-log-enums.h +++ b/include/linphone/enums/event-log-enums.h @@ -41,6 +41,9 @@ typedef enum _EventLogType { LinphoneEventLogTypeConferenceChatMessage = 5, /**< Conference chat message event */ LinphoneEventLogTypeConferenceParticipantAdded = 6, /**< Conference participant (added) event */ LinphoneEventLogTypeConferenceParticipantRemoved = 7, /**< Conference participant (removed) event */ + LinphoneEventLogTypeConferenceParticipantRoleUnknown = 25, /**< Conference participant (role unknown) event */ + LinphoneEventLogTypeConferenceParticipantRoleSpeaker = 26, /**< Conference participant (role speaker) event */ + LinphoneEventLogTypeConferenceParticipantRoleListener = 27, /**< Conference participant (role listener) event */ LinphoneEventLogTypeConferenceParticipantSetAdmin = 8, /**< Conference participant (set admin) event */ LinphoneEventLogTypeConferenceParticipantUnsetAdmin = 9, /**< Conference participant (unset admin) event */ LinphoneEventLogTypeConferenceParticipantDeviceAdded = 10, /**< Conference participant device (added) event */ diff --git a/src/c-wrapper/api/c-call-log.cpp b/src/c-wrapper/api/c-call-log.cpp index 77db2278da..6646511a59 100644 --- a/src/c-wrapper/api/c-call-log.cpp +++ b/src/c-wrapper/api/c-call-log.cpp @@ -134,7 +134,7 @@ LinphoneQualityReporting *linphone_call_log_get_quality_reporting(LinphoneCallLo } LinphoneConferenceInfo *linphone_call_log_get_conference_info(LinphoneCallLog *call_log) { - auto confInfo = CallLog::toCpp(call_log)->getConferenceInfo(); + auto &confInfo = CallLog::toCpp(call_log)->getConferenceInfo(); if (confInfo) return confInfo->toC(); return nullptr; diff --git a/src/c-wrapper/api/c-conference-cbs.cpp b/src/c-wrapper/api/c-conference-cbs.cpp index f26f2b2ba9..c0daf012e4 100644 --- a/src/c-wrapper/api/c-conference-cbs.cpp +++ b/src/c-wrapper/api/c-conference-cbs.cpp @@ -88,6 +88,16 @@ void linphone_conference_cbs_set_participant_device_removed(LinphoneConferenceCb ConferenceCbs::toCpp(cbs)->participantDeviceRemovedCb = cb; } +LinphoneConferenceCbsParticipantRoleChangedCb +linphone_conference_cbs_get_participant_role_changed(const LinphoneConferenceCbs *cbs) { + return ConferenceCbs::toCpp(cbs)->participantRoleChangedCb; +} + +void linphone_conference_cbs_set_participant_role_changed(LinphoneConferenceCbs *cbs, + LinphoneConferenceCbsParticipantRoleChangedCb cb) { + ConferenceCbs::toCpp(cbs)->participantRoleChangedCb = cb; +} + LinphoneConferenceCbsParticipantAdminStatusChangedCb linphone_conference_cbs_get_participant_admin_status_changed(const LinphoneConferenceCbs *cbs) { return ConferenceCbs::toCpp(cbs)->participantAdminStatusChangedCb; diff --git a/src/c-wrapper/api/c-conference-info.cpp b/src/c-wrapper/api/c-conference-info.cpp index 8150998bb4..1e3d73aa7d 100644 --- a/src/c-wrapper/api/c-conference-info.cpp +++ b/src/c-wrapper/api/c-conference-info.cpp @@ -147,10 +147,18 @@ void linphone_conference_info_set_subject(LinphoneConferenceInfo *conference_inf ConferenceInfo::toCpp(conference_info)->setSubject(L_C_TO_STRING(subject)); } +void linphone_conference_info_set_ics_sequence(LinphoneConferenceInfo *conference_info, unsigned int sequence) { + ConferenceInfo::toCpp(conference_info)->setIcsSequence(sequence); +} + unsigned int linphone_conference_info_get_ics_sequence(const LinphoneConferenceInfo *conference_info) { return ConferenceInfo::toCpp(conference_info)->getIcsSequence(); } +void linphone_conference_info_set_ics_uid(LinphoneConferenceInfo *conference_info, const char *uid) { + return ConferenceInfo::toCpp(conference_info)->setIcsUid(L_C_TO_STRING(uid)); +} + const char *linphone_conference_info_get_ics_uid(const LinphoneConferenceInfo *conference_info) { return L_STRING_TO_C(ConferenceInfo::toCpp(conference_info)->getIcsUid()); } @@ -182,6 +190,9 @@ char *linphone_conference_info_get_icalendar_string(const LinphoneConferenceInfo return NULL; } +void linphone_conference_info_set_state(LinphoneConferenceInfo *conference_info, LinphoneConferenceInfoState state) { + ConferenceInfo::toCpp(conference_info)->setState(static_cast<ConferenceInfo::State>(state)); +} LinphoneConferenceInfoState linphone_conference_info_get_state(const LinphoneConferenceInfo *conference_info) { return (LinphoneConferenceInfoState)ConferenceInfo::toCpp(conference_info)->getState(); } diff --git a/src/c-wrapper/api/c-conference.cpp b/src/c-wrapper/api/c-conference.cpp index 551cc2c0ae..be6455f5a1 100644 --- a/src/c-wrapper/api/c-conference.cpp +++ b/src/c-wrapper/api/c-conference.cpp @@ -102,6 +102,12 @@ void _linphone_conference_notify_participant_device_state_changed(LinphoneConfer state); } +void _linphone_conference_notify_participant_role_changed(LinphoneConference *conference, + const LinphoneParticipant *participant) { + LINPHONE_HYBRID_OBJECT_INVOKE_CBS(Conference, MediaConference::Conference::toCpp(conference), + linphone_conference_cbs_get_participant_role_changed, participant); +} + void _linphone_conference_notify_participant_admin_status_changed(LinphoneConference *conference, const LinphoneParticipant *participant) { LINPHONE_HYBRID_OBJECT_INVOKE_CBS(Conference, MediaConference::Conference::toCpp(conference), diff --git a/src/c-wrapper/api/c-participant-info.cpp b/src/c-wrapper/api/c-participant-info.cpp index 53a1435769..5bf965e5cd 100644 --- a/src/c-wrapper/api/c-participant-info.cpp +++ b/src/c-wrapper/api/c-participant-info.cpp @@ -28,7 +28,7 @@ using namespace LinphonePrivate; -LinphoneParticipantInfo *linphone_participant_info_new(LinphoneAddress *address) { +LinphoneParticipantInfo *linphone_participant_info_new(const LinphoneAddress *address) { return ParticipantInfo::createCObject(Address::toCpp(address)->getSharedFromThis()); } @@ -58,6 +58,14 @@ LinphoneParticipantRole linphone_participant_info_get_role(const LinphonePartici return (LinphoneParticipantRole)ParticipantInfo::toCpp(participant_info)->getRole(); } +int linphone_participant_info_get_sequence_number(const LinphoneParticipantInfo *participant_info) { + return ParticipantInfo::toCpp(participant_info)->getSequenceNumber(); +} + +void linphone_participant_info_set_sequence_number(LinphoneParticipantInfo *participant_info, int sequence) { + ParticipantInfo::toCpp(participant_info)->setSequenceNumber(sequence); +} + void linphone_participant_info_add_parameter(LinphoneParticipantInfo *participant_info, const char *name, const char *value) { diff --git a/src/call/call-log.cpp b/src/call/call-log.cpp index ec5964a2d1..6762ce1ca6 100644 --- a/src/call/call-log.cpp +++ b/src/call/call-log.cpp @@ -208,9 +208,10 @@ void CallLog::setConferenceInfo(std::shared_ptr<ConferenceInfo> conferenceInfo) mConferenceInfo = conferenceInfo; } -std::shared_ptr<ConferenceInfo> CallLog::getConferenceInfo() { - if (mConferenceInfo != nullptr) return mConferenceInfo; - +std::shared_ptr<ConferenceInfo> &CallLog::getConferenceInfo() { + // The conference info stored in the database is always up to date, therefore try to update the cache all the time + // if there id is valid Nonetheless, the cache variable is required if the core disables the storage of information + // in the database. if (mConferenceInfoId != -1) { setConferenceInfo(L_GET_PRIVATE(getCore())->mainDb->getConferenceInfo(mConferenceInfoId)); } diff --git a/src/call/call-log.h b/src/call/call-log.h index 29eac9fa1a..147811271f 100644 --- a/src/call/call-log.h +++ b/src/call/call-log.h @@ -93,7 +93,7 @@ public: void setConferenceInfoId(long long conferenceInfoId); void setConferenceInfo(std::shared_ptr<ConferenceInfo> conferenceInfo); - std::shared_ptr<ConferenceInfo> getConferenceInfo(); + std::shared_ptr<ConferenceInfo> &getConferenceInfo(); std::string toString() const override; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 528c051a36..a6d0eb3b11 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -152,7 +152,8 @@ void ChatMessagePrivate::setParticipantState(const std::shared_ptr<Address> &par LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(chatRoom); auto me = chatRoom->getMe(); - auto participant = participantAddress == me->getAddress() ? me : chatRoom->findParticipant(participantAddress); + auto participant = + participantAddress->weakEqual(*me->getAddress()) ? me : chatRoom->findParticipant(participantAddress); ParticipantImdnState imdnState(participant, newState, stateChangeTime); // Legacy callbacks, deprecated ! diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 955cb19ad1..fd566c4b63 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -29,6 +29,7 @@ #include "chat/chat-message/is-composing-message.h" #include "chat/chat-message/notification-message-p.h" #include "chat/chat-room/chat-room-p.h" +#include "conference/conference.h" #include "content/content-manager.h" #include "core/core-p.h" #include "linphone/utils/algorithm.h" diff --git a/src/chat/chat-room/server-group-chat-room.cpp b/src/chat/chat-room/server-group-chat-room.cpp index 38cd2f93fb..2cb00c390c 100644 --- a/src/chat/chat-room/server-group-chat-room.cpp +++ b/src/chat/chat-room/server-group-chat-room.cpp @@ -1047,7 +1047,7 @@ shared_ptr<CallSession> ServerGroupChatRoomPrivate::makeSession(const std::share csp.addCustomHeader("One-To-One-Chat-Room", "true"); if (capabilities & ServerGroupChatRoom::Capabilities::Encrypted) csp.addCustomHeader("End-To-End-Encrypted", "true"); - if (capabilities & ClientGroupChatRoom::Capabilities::Ephemeral) { + if (capabilities & ServerGroupChatRoom::Capabilities::Ephemeral) { csp.addCustomHeader("Ephemerable", "true"); csp.addCustomHeader("Ephemeral-Life-Time", to_string(params->getEphemeralLifetime())); } diff --git a/src/chat/encryption/encryption-engine.h b/src/chat/encryption/encryption-engine.h index c2cb005e61..da7d63a3d2 100644 --- a/src/chat/encryption/encryption-engine.h +++ b/src/chat/encryption/encryption-engine.h @@ -25,7 +25,7 @@ #include <memory> -#include "chat/chat-room/client-group-chat-room.h" +#include "chat/chat-room/chat-room.h" #include "chat/modifier/chat-message-modifier.h" #include "core/core-accessor.h" #include "linphone/lpconfig.h" diff --git a/src/conference/conference-info.cpp b/src/conference/conference-info.cpp index 4bbceb4fad..69b4f66b89 100644 --- a/src/conference/conference-info.cpp +++ b/src/conference/conference-info.cpp @@ -111,8 +111,21 @@ void ConferenceInfo::addParticipants(const ConferenceInfo::participant_list_t &p void ConferenceInfo::addParticipant(const std::shared_ptr<const ParticipantInfo> &participantInfo) { const auto &address = participantInfo->getAddress(); - if (hasParticipant(address)) { - mParticipants.push_back(participantInfo->clone()->toSharedPtr()); + if (!hasParticipant(address)) { + std::shared_ptr<ParticipantInfo> newInfo = nullptr; + // Check whetner the participant to be added is the organizer + if (mOrganizer && (participantInfo->getAddress()->weakEqual(*mOrganizer->getAddress()))) { + // Update the organizer role and parameters + newInfo = mOrganizer; + newInfo->setRole(participantInfo->getRole()); + newInfo->addParameters(participantInfo->getAllParameters()); + } else { + newInfo = participantInfo->clone()->toSharedPtr(); + } + mParticipants.push_back(newInfo); + lInfo() << "Participant with address " << *address << " has been added to conference info " << this + << " (address " << (getUri() ? getUri()->toString() : std::string("<unknown address>")) + << ") with role " << newInfo->getRole(); } else { lInfo() << "Participant with address " << *address << " is already in the list of conference info " << this << " (address " << (getUri() ? getUri()->toString() : std::string("<unknown address>")) << ")"; @@ -134,13 +147,25 @@ void ConferenceInfo::removeParticipant(const std::shared_ptr<const Address> &par lInfo() << "Unable to remove participant with address " << *participant << " in conference info " << this << " (address " << (getUri() ? getUri()->toString() : std::string("<unknown address>")) << ")"; } else { + lInfo() << "Participant with address " << *participant << " has been removed from conference info " << this + << " (address " << (getUri() ? getUri()->toString() : std::string("<unknown address>")) << ")"; mParticipants.erase(it); } } void ConferenceInfo::updateParticipant(const std::shared_ptr<const ParticipantInfo> &participantInfo) { - removeParticipant(participantInfo); - addParticipant(participantInfo); + const auto &address = participantInfo->getAddress(); + if (hasParticipant(address)) { + lInfo() << "Updating participant with address " << *address << " in conference info " << this << " (address " + << (getUri() ? getUri()->toString() : std::string("<unknown address>")) << ")"; + removeParticipant(participantInfo); + addParticipant(participantInfo); + } else { + lError() << "Unable to update informations of participant with address " << *participantInfo->getAddress() + << " in conference info " << this << " (address " + << (getUri() ? getUri()->toString() : std::string("<unknown address>")) + << ") because he/she has not been found in the list of participants"; + } } ConferenceInfo::participant_list_t::const_iterator @@ -150,7 +175,7 @@ ConferenceInfo::findParticipantIt(const std::shared_ptr<const Address> &address) } bool ConferenceInfo::hasParticipant(const std::shared_ptr<const Address> &address) const { - return (findParticipantIt(address) == mParticipants.end()); + return (findParticipantIt(address) != mParticipants.end()); } const std::shared_ptr<ParticipantInfo> diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index e2c28568e7..cf45b8dd52 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -349,6 +349,15 @@ public: virtual void onEphemeralLifetimeChanged(BCTBX_UNUSED(const std::shared_ptr<ConferenceEphemeralMessageEvent> &event)){}; + /* + * This fonction is called each time a participant changes its role in the conference after full state notification. + * @param[in] event informations related to the participant new role. @notnil + * @param[in] participant participant whose role changed. @notnil + */ + virtual void onParticipantSetRole(BCTBX_UNUSED(const std::shared_ptr<ConferenceParticipantEvent> &event), + BCTBX_UNUSED(const std::shared_ptr<Participant> &participant)) { + } + /* * This fonction is called each time a new admin is set by the focus after full state notification. * @param[in] event informations related to the new admin participant. @notnil diff --git a/src/conference/conference-scheduler.cpp b/src/conference/conference-scheduler.cpp index 387a356215..aa44a4a8f8 100644 --- a/src/conference/conference-scheduler.cpp +++ b/src/conference/conference-scheduler.cpp @@ -23,7 +23,9 @@ #include "account/account.h" #include "c-wrapper/c-wrapper.h" #include "chat/chat-message/chat-message-p.h" +#include "conference/conference-params.h" #include "conference/conference-scheduler.h" +#include "conference/conference.h" #include "conference/params/call-session-params-p.h" #include "conference/participant-info.h" #include "conference/session/media-session.h" @@ -474,11 +476,12 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar const bool participantFound = (std::find_if(participants.cbegin(), participants.cend(), [&sender](const auto &p) { return (sender->weakEqual(*p->getAddress())); }) != participants.cend()); + const auto &conferenceAddress = mConferenceInfo->getUri(); const auto organizer = mConferenceInfo->getOrganizerAddress(); if (!sender->weakEqual(*organizer) && !participantFound) { lWarning() << "[Conference Scheduler] [" << this << "] Unable to find the address " << *sender << " sending invitations among the list of participants or the organizer (" << *organizer - << ") of conference " << *mConferenceInfo->getUri(); + << ") of conference " << *conferenceAddress; return; } @@ -493,6 +496,14 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar return; } + std::shared_ptr<ConferenceInfo> dbConferenceInfo = nullptr; +#ifdef HAVE_DB_STORAGE + auto &mainDb = getCore()->getPrivate()->mainDb; + if (mainDb && conferenceAddress) { + dbConferenceInfo = getCore()->getPrivate()->mainDb->getConferenceInfoFromURI(conferenceAddress); + } +#endif // HAVE_DB_STORAGE + std::list<std::shared_ptr<Address>> invitees; for (const auto &participantInfo : participants) { invitees.push_back(participantInfo->getAddress()); @@ -521,6 +532,19 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar const auto &participantInfo = mConferenceInfo->findParticipant(participant); if (participantInfo) { auto newParticipantInfo = participantInfo->clone()->toSharedPtr(); + if (newParticipantInfo->getRole() == Participant::Role::Unknown) { + // Search if the role of the participant info stored in the database is different. + // We hit this case, if a client creates an inpromptu conference on a server and sends the ICS + // invitation as well. If the network connection is fast enough, it may happen that that the client + // already received the NOTIFY full state, therefore the server already took the decision on the + // participant role In such a scenario, the participant information stored in the conference scheduler + // should stick with it + const auto &dbParticipantInfo = + (dbConferenceInfo) ? dbConferenceInfo->findParticipant(newParticipantInfo->getAddress()) : nullptr; + if (dbParticipantInfo) { + newParticipantInfo->setRole(dbParticipantInfo->getRole()); + } + } const auto &sequence = newParticipantInfo->getSequenceNumber(); const auto newSequence = (sequence < 0) ? 0 : sequence + 1; newParticipantInfo->setSequenceNumber(newSequence); @@ -530,11 +554,14 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar const auto &organizerInfo = mConferenceInfo->getOrganizer(); if (organizerInfo) { - auto newOrganizerInfo = organizerInfo->clone()->toSharedPtr(); - const auto &sequence = newOrganizerInfo->getSequenceNumber(); - const auto newSequence = (sequence < 0) ? 0 : sequence + 1; - newOrganizerInfo->setSequenceNumber(newSequence); - mConferenceInfo->setOrganizer(newOrganizerInfo); + auto organizerAmongParticipants = (mConferenceInfo->findParticipant(organizerInfo->getAddress()) != nullptr); + if (!organizerAmongParticipants) { + auto newOrganizerInfo = organizerInfo->clone()->toSharedPtr(); + const auto &sequence = newOrganizerInfo->getSequenceNumber(); + const auto newSequence = (sequence < 0) ? 0 : sequence + 1; + newOrganizerInfo->setSequenceNumber(newSequence); + mConferenceInfo->setOrganizer(newOrganizerInfo); + } } if (!sender->weakEqual(*organizer)) { @@ -567,8 +594,7 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar remoteAddress = participant; } shared_ptr<AbstractChatRoom> chatRoom = - getCore()->getPrivate()->searchChatRoom(chatRoomParams, sender, remoteAddress, participantList); - + getCore()->getPrivate()->searchChatRoom(chatRoomParams, sender, remoteAddress, participantList); if (!chatRoom) { lInfo() << "[Conference Scheduler] [" << this << "] Existing chat room between [" << *sender << "] and [" diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 961fcf8270..ddaa61cad5 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -94,7 +94,7 @@ bool Conference::addParticipant(BCTBX_UNUSED(std::shared_ptr<Call> call)) { bool Conference::addParticipant(const std::shared_ptr<Address> &participantAddress) { shared_ptr<Participant> participant = findParticipant(participantAddress); if (participant) { - lWarning() << "Not adding participant '" << participantAddress->toString() + lWarning() << "Not adding participant '" << *participantAddress << "' because it is already a participant of the Conference"; return false; } @@ -523,6 +523,34 @@ shared_ptr<ConferenceParticipantEvent> Conference::notifyParticipantRemoved( return event; } +shared_ptr<ConferenceParticipantEvent> +Conference::notifyParticipantSetRole(time_t creationTime, + const bool isFullState, + const std::shared_ptr<Participant> &participant, + Participant::Role role) { + EventLog::Type eventType = EventLog::Type::None; + switch (role) { + case Participant::Role::Speaker: + eventType = EventLog::Type::ConferenceParticipantRoleSpeaker; + break; + case Participant::Role::Listener: + eventType = EventLog::Type::ConferenceParticipantRoleListener; + break; + case Participant::Role::Unknown: + eventType = EventLog::Type::ConferenceParticipantRoleUnknown; + break; + } + shared_ptr<ConferenceParticipantEvent> event = + make_shared<ConferenceParticipantEvent>(eventType, creationTime, conferenceId, participant->getAddress()); + event->setFullState(isFullState); + event->setNotifyId(lastNotify); + + for (const auto &l : confListeners) { + l->onParticipantSetRole(event, participant); + } + return event; +} + shared_ptr<ConferenceParticipantEvent> Conference::notifyParticipantSetAdmin( time_t creationTime, const bool isFullState, const std::shared_ptr<Participant> &participant, bool isAdmin) { shared_ptr<ConferenceParticipantEvent> event = make_shared<ConferenceParticipantEvent>( @@ -718,6 +746,29 @@ std::shared_ptr<ConferenceInfo> Conference::createConferenceInfo() const { return nullptr; } +const std::shared_ptr<ConferenceInfo> Conference::getUpdatedConferenceInfo() const { + auto conferenceInfo = createOrGetConferenceInfo(); + + // Update me only if he/she is already in the list of participants info + const auto &meAddress = getMe()->getAddress(); + const auto ¤tParticipants = conferenceInfo->getParticipants(); + const auto meInfoIt = + std::find_if(currentParticipants.begin(), currentParticipants.end(), + [&meAddress](const auto &p) { return (meAddress->weakEqual(*p->getAddress())); }); + if (meInfoIt != currentParticipants.end()) { + updateParticipantInfoInConferenceInfo(conferenceInfo, getMe()); + } + + for (const auto &participant : getParticipants()) { + updateParticipantInfoInConferenceInfo(conferenceInfo, participant); + } + + conferenceInfo->setSecurityLevel(confParams->getSecurityLevel()); + conferenceInfo->setSubject(confParams->getSubject()); + + return conferenceInfo; +} + std::shared_ptr<ConferenceInfo> Conference::createConferenceInfoWithCustomParticipantList( const std::shared_ptr<Address> &organizer, const ConferenceInfo::participant_list_t invitedParticipants) const { std::shared_ptr<ConferenceInfo> info = ConferenceInfo::create(); @@ -811,27 +862,34 @@ void Conference::updateSubjectInConferenceInfo(const std::string &subject) const #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif // _MSC_VER -void Conference::updateParticipantsInConferenceInfo(const std::shared_ptr<Address> &participantAddress) const { +void Conference::updateParticipantRoleInConferenceInfo(const std::shared_ptr<Participant> &participant) const { #ifdef HAVE_DB_STORAGE if ((getState() == ConferenceInterface::State::CreationPending) || (getState() == ConferenceInterface::State::Created)) { auto info = createOrGetConferenceInfo(); + if (info) { - const auto ¤tParticipants = info->getParticipants(); - const auto participantAddressIt = std::find_if( - currentParticipants.begin(), currentParticipants.end(), - [&participantAddress](const auto &p) { return (participantAddress->weakEqual(*p->getAddress())); }); - if (participantAddressIt == currentParticipants.end()) { - info->addParticipant(participantAddress); + const auto &address = participant->getAddress(); + const auto &newRole = participant->getRole(); + const auto &participantInfo = info->findParticipant(address); + if (participantInfo) { + auto newParticipantInfo = participantInfo->clone()->toSharedPtr(); + newParticipantInfo->setRole(newRole); + + info->updateParticipant(newParticipantInfo); // Store into DB after the start incoming notification in order to have a valid conference address being // the contact address of the call auto &mainDb = getCore()->getPrivate()->mainDb; if (mainDb) { lInfo() << "Updating conference information of conference " << *getConferenceAddress() - << " because participant " << *participantAddress << " has been added"; + << " because the role of participant " << *address << " changed to " << newRole; mainDb->insertConferenceInfo(info); } + } else { + lError() << "Unable to update role of participant " << *address << " to " << newRole + << " because it cannot be found in the conference info linked to conference " + << *getConferenceAddress(); } } } @@ -841,4 +899,61 @@ void Conference::updateParticipantsInConferenceInfo(const std::shared_ptr<Addres #pragma GCC diagnostic pop #endif // _MSC_VER +bool Conference::updateParticipantInfoInConferenceInfo(std::shared_ptr<ConferenceInfo> &info, + const std::shared_ptr<Participant> &participant) const { + bool update = false; + const auto &participantAddress = participant->getAddress(); + const auto ¤tParticipants = info->getParticipants(); + const auto participantInfoIt = + std::find_if(currentParticipants.begin(), currentParticipants.end(), [&participantAddress](const auto &p) { + return (participantAddress->weakEqual(*p->getAddress())); + }); + + const auto &participantRole = participant->getRole(); + if (participantInfoIt == currentParticipants.end()) { + auto participantInfo = ParticipantInfo::create(participantAddress); + participantInfo->setRole(participantRole); + info->addParticipant(participantInfo); + update = true; + } else { + auto participantInfo = (*participantInfoIt)->clone()->toSharedPtr(); + if (participantInfo->getRole() != participantRole) { + participantInfo->setRole(participantRole); + info->updateParticipant(participantInfo); + update = true; + } + } + return update; +} + +void Conference::updateParticipantInConferenceInfo(const std::shared_ptr<Participant> &participant) const { + const auto &participantAddress = participant->getAddress(); + if (!participant) { + lError() << "Conference " << *getConferenceAddress() + << " received a request to update the conference info to add participant with address " + << *participantAddress << " but it looks like he/she is not part of this conference"; + return; + } + +#ifdef HAVE_DB_STORAGE + if ((getState() == ConferenceInterface::State::CreationPending) || + (getState() == ConferenceInterface::State::Created)) { + auto info = createOrGetConferenceInfo(); + if (info) { + bool update = updateParticipantInfoInConferenceInfo(info, participant); + + // Store into DB after the start incoming notification in order to have a valid conference address being + // the contact address of the call + auto &mainDb = getCore()->getPrivate()->mainDb; + if (mainDb && update) { + lInfo() << "Updating conference information of conference " << *getConferenceAddress() + << " because participant " << *participantAddress + << " has been added or has modified its informations"; + mainDb->insertConferenceInfo(info); + } + } + } +#endif // HAVE_DB_STORAGE +} + LINPHONE_END_NAMESPACE diff --git a/src/conference/conference.h b/src/conference/conference.h index f595355e1a..f53956b69a 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -30,6 +30,7 @@ #include "conference/conference-interface.h" #include "conference/conference-listener.h" #include "conference/conference-params.h" +#include "conference/participant.h" #include "core/core-accessor.h" #include "linphone/core.h" #include "linphone/types.h" @@ -143,6 +144,11 @@ public: time_t creationTime, const bool isFullState, const std::shared_ptr<Participant> &participant); virtual std::shared_ptr<ConferenceParticipantEvent> notifyParticipantRemoved( time_t creationTime, const bool isFullState, const std::shared_ptr<Participant> &participant); + virtual std::shared_ptr<ConferenceParticipantEvent> + notifyParticipantSetRole(time_t creationTime, + const bool isFullState, + const std::shared_ptr<Participant> &participant, + Participant::Role role); virtual std::shared_ptr<ConferenceParticipantEvent> notifyParticipantSetAdmin( time_t creationTime, const bool isFullState, const std::shared_ptr<Participant> &participant, bool isAdmin); virtual std::shared_ptr<ConferenceSubjectEvent> @@ -203,8 +209,11 @@ public: void clearParticipants(); void updateSubjectInConferenceInfo(const std::string &subject) const; - void updateParticipantsInConferenceInfo(const std::shared_ptr<Address> &participantAddress) const; + void updateParticipantInConferenceInfo(const std::shared_ptr<Participant> &participant) const; + bool updateParticipantInfoInConferenceInfo(std::shared_ptr<ConferenceInfo> &info, + const std::shared_ptr<Participant> &participant) const; void updateSecurityLevelInConferenceInfo(const ConferenceParams::SecurityLevel &level) const; + void updateParticipantRoleInConferenceInfo(const std::shared_ptr<Participant> &participant) const; protected: explicit Conference(const std::shared_ptr<Core> &core, @@ -249,6 +258,7 @@ protected: virtual std::shared_ptr<ConferenceInfo> createConferenceInfoWithCustomParticipantList(const std::shared_ptr<Address> &organizer, const ConferenceInfo::participant_list_t invitedParticipants) const; + const std::shared_ptr<ConferenceInfo> getUpdatedConferenceInfo() const; private: L_DISABLE_COPY(Conference); diff --git a/src/conference/handlers/local-conference-event-handler.cpp b/src/conference/handlers/local-conference-event-handler.cpp index 6b00ee27e5..5791ddf383 100644 --- a/src/conference/handlers/local-conference-event-handler.cpp +++ b/src/conference/handlers/local-conference-event-handler.cpp @@ -1128,7 +1128,7 @@ void LocalConferenceEventHandler::onParticipantAdded(const std::shared_ptr<Confe // Do not send notify if conference pointer is null. It may mean that the confernece has been terminated if (conf) { notifyAllExcept(makeContent(createNotifyParticipantAdded(participant->getAddress())), participant); - conf->updateParticipantsInConferenceInfo(participant->getAddress()); + conf->updateParticipantInConferenceInfo(participant); if (conf) { shared_ptr<Core> core = conf->getCore(); diff --git a/src/conference/handlers/remote-conference-event-handler.cpp b/src/conference/handlers/remote-conference-event-handler.cpp index 4d9c980f5b..a782dec7d7 100644 --- a/src/conference/handlers/remote-conference-event-handler.cpp +++ b/src/conference/handlers/remote-conference-event-handler.cpp @@ -80,6 +80,45 @@ bool RemoteConferenceEventHandler::getInitialSubscriptionUnderWayFlag() const { return initialSubscriptionUnderWay; } +void RemoteConferenceEventHandler::fillParticipantAttributes( + std::shared_ptr<Participant> &participant, + xsd::cxx::tree::optional<LinphonePrivate::Xsd::ConferenceInfo::UserRolesType> &roles, + StateType state, + bool isFullState, + bool notify) const { + if (roles) { + auto &entry = roles->getEntry(); + + time_t creationTime = time(nullptr); + + // Admin + bool isAdmin = (find(entry, "admin") != entry.end() ? true : false); + if (participant->isAdmin() != isAdmin) { + participant->setAdmin(isAdmin); + if (!isFullState && notify) { + conf->notifyParticipantSetAdmin(creationTime, isFullState, participant, isAdmin); + } + } + + // Role + bool isSpeaker = (find(entry, "speaker") != entry.end() ? true : false); + bool isListener = (find(entry, "listener") != entry.end() ? true : false); + Participant::Role role = Participant::Role::Unknown; + if (isListener) { + role = Participant::Role::Listener; + } else if (isSpeaker || (state == StateType::full)) { + // When a participant is added, then set its role to speaker by default to be backward compatible + role = Participant::Role::Speaker; + } + if (participant->getRole() != role) { + participant->setRole(role); + if (!isFullState && notify) { + conf->notifyParticipantSetRole(creationTime, isFullState, participant, role); + } + } + } +} + void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xmlBody) { istringstream data(xmlBody); unique_ptr<ConferenceType> confInfo; @@ -101,7 +140,7 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm if (!peerAddress || (*entityAddress != *peerAddress)) { const std::string peerAddressString = peerAddress ? peerAddress->toString() : std::string("<unknown>"); - lError() << "Unable to process received NOTIFY because the entity address " << entityAddress->toString() + lError() << "Unable to process received NOTIFY because the entity address " << *entityAddress << " doesn't match the peer address " << peerAddressString; return; } @@ -274,9 +313,10 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm return (*address == *currentParticipant->getAddress()); }); + auto &roles = user.getRoles(); if (state == StateType::deleted) { if (conf->isMe(address)) { - lInfo() << "Participant " << address->toString() << " requested to be deleted is me."; + lInfo() << "Participant " << *address << " requested to be deleted is me."; continue; } else if (participant) { conf->participants.remove(participant); @@ -288,17 +328,19 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm continue; } else { - lWarning() << "Participant " << address->toString() << " removed but not in the list of participants!"; + lWarning() << "Participant " << *address << " removed but not in the list of participants!"; } } else if (state == StateType::full) { if (conf->isMe(address)) { - lInfo() << "Participant " << address->toString() << " requested to be added is me."; + lInfo() << "Participant " << *address << " requested to be added is me."; + fillParticipantAttributes(participant, roles, state, isFullState, false); } else if (participant) { lWarning() << "Participant " << *participant << " added but already in the list of participants!"; } else { participant = Participant::create(conf, address); + fillParticipantAttributes(participant, roles, state, isFullState, false); + conf->participants.push_back(participant); - conf->updateParticipantsInConferenceInfo(address); lInfo() << "Participant " << *participant << " is successfully added - conference " << conferenceAddressString << " has " << conf->getParticipantCount() << " participants"; if (!isFullState || @@ -315,37 +357,14 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm } if (!participant) { - lDebug() << "Participant " << address->toString() + lDebug() << "Participant " << *address << " is not in the list of participants however it is trying to change the list of devices or " "change role! Resubscribing to conference " << conferenceAddressString << " to clear things up."; requestFullState(); } else { - auto &roles = user.getRoles(); - if (roles) { - auto &entry = roles->getEntry(); - - // Admin - bool isAdmin = (find(entry, "admin") != entry.end() ? true : false); - if (participant->isAdmin() != isAdmin) { - participant->setAdmin(isAdmin); - if (!isFullState) { - conf->notifyParticipantSetAdmin(creationTime, isFullState, participant, isAdmin); - } - } - - // Role - bool isSpeaker = (find(entry, "speaker") != entry.end() ? true : false); - bool isListener = (find(entry, "listener") != entry.end() ? true : false); - if (isListener) { - participant->setRole(Participant::Role::Listener); - } else if (isSpeaker || (state == StateType::full)) { - // When a participant is added, then set its role to speaker by default to be backward compatible - participant->setRole(Participant::Role::Speaker); - } - } - + fillParticipantAttributes(participant, roles, state, isFullState, true); for (const auto &endpoint : user.getEndpoint()) { if (!endpoint.getEntity().present()) continue; @@ -560,7 +579,7 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm if (conf->isMe(address) && conf->getMainSession()) device->setSession(conf->getMainSession()); if (state == StateType::full) { - lInfo() << "Participant device " << gruu->toString() << " has been successfully added"; + lInfo() << "Participant device " << *gruu << " has been successfully added"; bool sendNotify = (!oldParticipants.empty() && (pIt == oldParticipants.cend())) && !conf->isMe(address); if (pIt != oldParticipants.cend()) { @@ -575,7 +594,7 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm conf->notifyParticipantDeviceAdded(creationTime, isFullState, participant, device); } } else { - lInfo() << "Participant device " << gruu->toString() << " has been successfully updated"; + lInfo() << "Participant device " << *gruu << " has been successfully updated"; } } else { lDebug() << "Unable to update media direction of device " << *gruu diff --git a/src/conference/handlers/remote-conference-event-handler.h b/src/conference/handlers/remote-conference-event-handler.h index a10308733e..06442ef197 100644 --- a/src/conference/handlers/remote-conference-event-handler.h +++ b/src/conference/handlers/remote-conference-event-handler.h @@ -95,6 +95,11 @@ private: void unsubscribePrivate(); void updateInitialSubcriptionUnderWay(std::shared_ptr<Event> notifyLev); time_t dateTimeToTimeT(const Xsd::XmlSchema::DateTime &xsdTime) const; + void fillParticipantAttributes(std::shared_ptr<Participant> &participant, + xsd::cxx::tree::optional<LinphonePrivate::Xsd::ConferenceInfo::UserRolesType> &roles, + Xsd::ConferenceInfo::StateType state, + bool isFullState, + bool notify) const; L_DISABLE_COPY(RemoteConferenceEventHandler); }; diff --git a/src/conference/notify-conference-listener.cpp b/src/conference/notify-conference-listener.cpp index 00eb03061a..9aea415252 100644 --- a/src/conference/notify-conference-listener.cpp +++ b/src/conference/notify-conference-listener.cpp @@ -43,6 +43,12 @@ void NotifyConferenceListener::onParticipantRemoved( _linphone_conference_notify_participant_removed(conf->toC(), participant->toC()); } +void NotifyConferenceListener::onParticipantSetRole( + BCTBX_UNUSED(const std::shared_ptr<ConferenceParticipantEvent> &event), + const std::shared_ptr<Participant> &participant) { + _linphone_conference_notify_participant_role_changed(conf->toC(), participant->toC()); +} + void NotifyConferenceListener::onParticipantSetAdmin( BCTBX_UNUSED(const std::shared_ptr<ConferenceParticipantEvent> &event), const std::shared_ptr<Participant> &participant) { diff --git a/src/conference/notify-conference-listener.h b/src/conference/notify-conference-listener.h index 71b904d421..e2d38abf53 100644 --- a/src/conference/notify-conference-listener.h +++ b/src/conference/notify-conference-listener.h @@ -54,6 +54,14 @@ public: virtual void onParticipantRemoved(const std::shared_ptr<ConferenceParticipantEvent> &event, const std::shared_ptr<Participant> &participant) override; + /* + * This fonction is called each time a participant changes its role in the conference after full state notification. + * @param[in] event informations related to the participant new role. @notnil + * @param[in] participant participant whose role changed. @notnil + */ + virtual void onParticipantSetRole(const std::shared_ptr<ConferenceParticipantEvent> &event, + const std::shared_ptr<Participant> &participant) override; + /* * This fonction is called each time a new admin is set by the focus after full state notification. * @param[in] event informations related to the new admin participant. @notnil diff --git a/src/conference/participant-device.cpp b/src/conference/participant-device.cpp index 7d28895ef0..5185ae9bbd 100644 --- a/src/conference/participant-device.cpp +++ b/src/conference/participant-device.cpp @@ -20,6 +20,7 @@ #include "participant-device.h" #include "chat/encryption/encryption-engine.h" +#include "conference/conference.h" #include "conference/params/media-session-params-p.h" #include "conference/params/media-session-params.h" #include "conference/session/call-session-p.h" diff --git a/src/conference/participant-info.cpp b/src/conference/participant-info.cpp index 09ec6728e3..8bb692aa85 100644 --- a/src/conference/participant-info.cpp +++ b/src/conference/participant-info.cpp @@ -28,7 +28,7 @@ LINPHONE_BEGIN_NAMESPACE const std::string ParticipantInfo::sequenceParameter = "X-SEQ"; const std::string ParticipantInfo::roleParameter = "X-ROLE"; -ParticipantInfo::ParticipantInfo(const std::shared_ptr<Address> &address) { +ParticipantInfo::ParticipantInfo(const std::shared_ptr<const Address> &address) { mAddress = Address::create(address->getUri()); } @@ -111,6 +111,10 @@ void ParticipantInfo::removeParameter(const std::string &name) { } } +ParticipantInfo::participant_params_t ParticipantInfo::getParameters() const { + return mParameters; +} + ParticipantInfo::participant_params_t ParticipantInfo::getAllParameters() const { auto params = mParameters; if (mSequence >= 0) { diff --git a/src/conference/participant-info.h b/src/conference/participant-info.h index df9be9bcaf..aa184628a9 100644 --- a/src/conference/participant-info.h +++ b/src/conference/participant-info.h @@ -38,7 +38,7 @@ public: static const std::string sequenceParameter; static const std::string roleParameter; - ParticipantInfo(const std::shared_ptr<Address> &address); + ParticipantInfo(const std::shared_ptr<const Address> &address); virtual ~ParticipantInfo(); ParticipantInfo(const ParticipantInfo &other); @@ -60,6 +60,8 @@ public: bool hasParameter(const std::string &name) const; void removeParameter(const std::string &name); + // getParameters() return only parameters that do not have a dedicated member in the class, i.e. mParameters + ParticipantInfo::participant_params_t getParameters() const; ParticipantInfo::participant_params_t getAllParameters() const; static const std::string memberParametersToString(const participant_params_t ¶ms); diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index cbcc72344f..a0a280bf85 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -22,6 +22,7 @@ #include "participant.h" +#include "conference/conference.h" #include "core/core.h" #include "params/media-session-params.h" #include "participant.h" @@ -275,6 +276,18 @@ Participant::getSecurityLevelExcept(const std::shared_ptr<ParticipantDevice> &ig // ----------------------------------------------------------------------------- +std::shared_ptr<Core> Participant::getCore() const { + return mConference ? mConference->getCore() : nullptr; +} + +Conference *Participant::getConference() const { + return mConference; +} + +void Participant::setConference(Conference *conference) { + mConference = conference; +} + bool Participant::isAdmin() const { return isThisAdmin; } diff --git a/src/conference/participant.h b/src/conference/participant.h index 8c76500296..dcefcd4409 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -149,15 +149,9 @@ public: }; protected: - std::shared_ptr<Core> getCore() const { - return mConference ? mConference->getCore() : nullptr; - } - Conference *getConference() const { - return mConference; - } - void setConference(Conference *conference) { - mConference = conference; - } + std::shared_ptr<Core> getCore() const; + Conference *getConference() const; + void setConference(Conference *conference); std::shared_ptr<CallSession> createSession(const Conference &conference, const CallSessionParams *params, diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 6e40226c88..70e83e689b 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -20,13 +20,12 @@ #include <bctoolbox/defs.h> -#include "linphone/api/c-content.h" -#include "linphone/core.h" - #include "account/account.h" #include "address/address.h" #include "c-wrapper/c-wrapper.h" +#include "call/call-log.h" #include "call/call.h" +#include "conference.h" #include "conference/conference-scheduler.h" #include "conference/params/call-session-params-p.h" #include "conference/participant.h" @@ -34,9 +33,9 @@ #include "conference/session/call-session.h" #include "core/core-p.h" #include "factory/factory.h" +#include "linphone/api/c-content.h" +#include "linphone/core.h" #include "logger/logger.h" - -#include "conference.h" #include "private.h" using namespace std; diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 5b890fbab9..ebb7a65e53 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -23,8 +23,8 @@ #include "address/address.h" #include "conference/conference-id.h" -#include "conference/conference.h" #include "conference/params/call-session-params.h" +#include "core/core-accessor.h" #include "core/core-listener.h" #include "linphone/misc.h" #include "object/object.h" @@ -34,13 +34,18 @@ LINPHONE_BEGIN_NAMESPACE +class CallLog; class CallSessionPrivate; +class CallSessionListener; class Content; class Core; +class Conference; namespace MediaConference { class Conference; -} +class RemoteConference; +class LocalConference; +} // namespace MediaConference class LINPHONE_PUBLIC CallSession : public Object, public CoreAccessor { friend class Call; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 4b3d491cb1..d903def193 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1033,6 +1033,9 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceInfoEvent(const ConferenceId case EventLog::Type::ConferenceParticipantAdded: case EventLog::Type::ConferenceParticipantRemoved: + case EventLog::Type::ConferenceParticipantRoleUnknown: + case EventLog::Type::ConferenceParticipantRoleSpeaker: + case EventLog::Type::ConferenceParticipantRoleListener: case EventLog::Type::ConferenceParticipantSetAdmin: case EventLog::Type::ConferenceParticipantUnsetAdmin: eventLog = selectConferenceParticipantEvent(conferenceId, type, row); @@ -1923,28 +1926,6 @@ shared_ptr<ConferenceInfo> MainDbPrivate::selectConferenceInfo(const soci::row & conferenceInfo->setSecurityLevel( static_cast<ConferenceParams::SecurityLevel>(dbSession.getUnsignedInt(row, 10, 0))); - static const string participantQuery = - "SELECT sip_address.value, conference_info_participant.deleted, conference_info_participant.params" - " FROM sip_address, conference_info, conference_info_participant" - " WHERE conference_info.id = :conferenceInfoId" - " AND sip_address.id = conference_info_participant.participant_sip_address_id" - " AND conference_info_participant.conference_info_id = conference_info.id"; - - soci::session *session = dbSession.getBackendSession(); - soci::rowset<soci::row> participantRows = (session->prepare << participantQuery, soci::use(dbConferenceInfoId)); - for (const auto &participantRow : participantRows) { - int deleted = participantRow.get<int>(1); - if (deleted == 0) { - std::shared_ptr<Address> participantAddress = Address::create(participantRow.get<string>(0)); - const string participantParamsStr = participantRow.get<string>(2); - ParticipantInfo::participant_params_t participantParams = - ParticipantInfo::stringToMemberParameters(participantParamsStr); - auto participantInfo = ParticipantInfo::create(participantAddress); - participantInfo->setParameters(participantParams); - conferenceInfo->addParticipant(participantInfo); - } - } - // For backward compability purposes, get the organizer from conference_info table and set the sequence number to // that of the conference info stored in the db It may be overridden if the conference organizer has been stored in // table conference_info_organizer. @@ -1957,6 +1938,7 @@ shared_ptr<ConferenceInfo> MainDbPrivate::selectConferenceInfo(const soci::row & " AND sip_address.id = conference_info_organizer.organizer_sip_address_id" " AND conference_info_organizer.conference_info_id = conference_info.id"; + soci::session *session = dbSession.getBackendSession(); soci::rowset<soci::row> organizerRows = (session->prepare << organizerQuery, soci::use(dbConferenceInfoId)); for (const auto &organizerRow : organizerRows) { organizerAddress = Address::create(organizerRow.get<string>(0)); @@ -1967,6 +1949,27 @@ shared_ptr<ConferenceInfo> MainDbPrivate::selectConferenceInfo(const soci::row & organizerInfo->setParameters(organizerParams); conferenceInfo->setOrganizer(organizerInfo); + static const string participantQuery = + "SELECT sip_address.value, conference_info_participant.deleted, conference_info_participant.params" + " FROM sip_address, conference_info, conference_info_participant" + " WHERE conference_info.id = :conferenceInfoId" + " AND sip_address.id = conference_info_participant.participant_sip_address_id" + " AND conference_info_participant.conference_info_id = conference_info.id"; + + soci::rowset<soci::row> participantRows = (session->prepare << participantQuery, soci::use(dbConferenceInfoId)); + for (const auto &participantRow : participantRows) { + int deleted = participantRow.get<int>(1); + if (deleted == 0) { + std::shared_ptr<Address> participantAddress = Address::create(participantRow.get<string>(0)); + const string participantParamsStr = participantRow.get<string>(2); + ParticipantInfo::participant_params_t participantParams = + ParticipantInfo::stringToMemberParameters(participantParamsStr); + auto participantInfo = ParticipantInfo::create(participantAddress); + participantInfo->setParameters(participantParams); + conferenceInfo->addParticipant(participantInfo); + } + } + cache(conferenceInfo, dbConferenceInfoId); return conferenceInfo; @@ -3497,6 +3500,9 @@ bool MainDb::addEvent(const shared_ptr<EventLog> &eventLog) { case EventLog::Type::ConferenceParticipantAdded: case EventLog::Type::ConferenceParticipantRemoved: + case EventLog::Type::ConferenceParticipantRoleUnknown: + case EventLog::Type::ConferenceParticipantRoleSpeaker: + case EventLog::Type::ConferenceParticipantRoleListener: case EventLog::Type::ConferenceParticipantSetAdmin: case EventLog::Type::ConferenceParticipantUnsetAdmin: eventId = d->insertConferenceParticipantEvent(eventLog); @@ -3574,6 +3580,9 @@ bool MainDb::updateEvent(const shared_ptr<EventLog> &eventLog) { case EventLog::Type::ConferenceCallEnded: case EventLog::Type::ConferenceParticipantAdded: case EventLog::Type::ConferenceParticipantRemoved: + case EventLog::Type::ConferenceParticipantRoleUnknown: + case EventLog::Type::ConferenceParticipantRoleSpeaker: + case EventLog::Type::ConferenceParticipantRoleListener: case EventLog::Type::ConferenceParticipantSetAdmin: case EventLog::Type::ConferenceParticipantUnsetAdmin: case EventLog::Type::ConferenceParticipantDeviceAdded: @@ -5318,18 +5327,19 @@ std::shared_ptr<ConferenceInfo> MainDb::getConferenceInfoFromURI(const std::shar return nullptr; } -void MainDb::insertConferenceInfo(const std::shared_ptr<ConferenceInfo> &conferenceInfo) { +long long MainDb::insertConferenceInfo(const std::shared_ptr<ConferenceInfo> &conferenceInfo) { #ifdef HAVE_DB_STORAGE if (isInitialized()) { auto dbConfInfo = getConferenceInfoFromURI(conferenceInfo->getUri()); - L_DB_TRANSACTION { + return L_DB_TRANSACTION { L_D(); - - d->insertConferenceInfo(conferenceInfo, dbConfInfo); + auto id = d->insertConferenceInfo(conferenceInfo, dbConfInfo); tr.commit(); + return id; }; } #endif + return -1; } void MainDb::deleteConferenceInfo(const std::shared_ptr<ConferenceInfo> &conferenceInfo) { diff --git a/src/db/main-db.h b/src/db/main-db.h index e3f3de999f..46f6cdf66a 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -211,7 +211,7 @@ public: std::list<std::shared_ptr<ConferenceInfo>> getConferenceInfos(time_t afterThisTime = -1) const; std::shared_ptr<ConferenceInfo> getConferenceInfo(long long conferenceInfoId) const; std::shared_ptr<ConferenceInfo> getConferenceInfoFromURI(const std::shared_ptr<Address> &uri) const; - void insertConferenceInfo(const std::shared_ptr<ConferenceInfo> &conferenceInfo); + long long insertConferenceInfo(const std::shared_ptr<ConferenceInfo> &conferenceInfo); void deleteConferenceInfo(const std::shared_ptr<ConferenceInfo> &conferenceInfo); // --------------------------------------------------------------------------- diff --git a/src/event-log/event-log.cpp b/src/event-log/event-log.cpp index 50eca2da86..a93a34a1cb 100644 --- a/src/event-log/event-log.cpp +++ b/src/event-log/event-log.cpp @@ -94,6 +94,15 @@ std::ostream &operator<<(std::ostream &lhs, EventLog::Type e) { case EventLog::Type::ConferenceParticipantRemoved: lhs << "ConferenceParticipantRemoved"; break; + case EventLog::Type::ConferenceParticipantRoleUnknown: + lhs << "ConferenceParticipantRoleUnknown"; + break; + case EventLog::Type::ConferenceParticipantRoleSpeaker: + lhs << "ConferenceParticipantRoleSpeaker"; + break; + case EventLog::Type::ConferenceParticipantRoleListener: + lhs << "ConferenceParticipantRoleListener"; + break; case EventLog::Type::ConferenceParticipantSetAdmin: lhs << "ConferenceParticipantSetAdmin"; break; diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index 1fcb199f3f..e43d4193ab 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -49,6 +49,9 @@ public: ConferenceChatMessage = LinphoneEventLogTypeConferenceChatMessage, ConferenceParticipantAdded = LinphoneEventLogTypeConferenceParticipantAdded, ConferenceParticipantRemoved = LinphoneEventLogTypeConferenceParticipantRemoved, + ConferenceParticipantRoleUnknown = LinphoneEventLogTypeConferenceParticipantRoleUnknown, + ConferenceParticipantRoleSpeaker = LinphoneEventLogTypeConferenceParticipantRoleSpeaker, + ConferenceParticipantRoleListener = LinphoneEventLogTypeConferenceParticipantRoleListener, ConferenceParticipantSetAdmin = LinphoneEventLogTypeConferenceParticipantSetAdmin, ConferenceParticipantUnsetAdmin = LinphoneEventLogTypeConferenceParticipantUnsetAdmin, ConferenceParticipantDeviceAdded = LinphoneEventLogTypeConferenceParticipantDeviceAdded, diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 5a7d9aab9f..c508e8b8a0 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -460,6 +460,7 @@ typedef struct _stats { int tmmbr_received_from_cb; int number_of_participants_added; + int number_of_participant_role_changed; int number_of_participant_admin_statuses_changed; int number_of_participants_removed; int number_of_subject_changed; diff --git a/tester/local_conference_edition_tester.cpp b/tester/local_conference_edition_tester.cpp index 162802832c..64514173ce 100644 --- a/tester/local_conference_edition_tester.cpp +++ b/tester/local_conference_edition_tester.cpp @@ -96,10 +96,12 @@ static void edit_simple_conference_base(bool_t from_organizer, const char *initialSubject = "Test characters: <S-F12><S-F11><S-F6> £$%§"; const char *description = "Testing characters"; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : invitedParticipants) { - participantList.insert(std::make_pair(p, role)); + participantList.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker; } @@ -128,17 +130,19 @@ static void edit_simple_conference_base(bool_t from_organizer, participants.push_back(lise.getCMgr()); + LinphoneParticipantRole role = LinphoneParticipantRoleListener; stats focus_stat = focus.getStats(); stats marie_stat = marie.getStats(); linphone_conference_info_set_subject(conf_info, initialSubject); linphone_conference_info_set_description(conf_info, description); - LinphoneParticipantInfo *lise_participant_info = linphone_participant_info_new(lise.getCMgr()->identity); - linphone_participant_info_set_role(lise_participant_info, LinphoneParticipantRoleListener); + LinphoneParticipantInfo *lise_participant_info = + add_participant_info_to_list(&participants_info, lise.getCMgr()->identity, role, -1); linphone_conference_info_add_participant_2(conf_info, lise_participant_info); - linphone_participant_info_unref(lise_participant_info); + participantList.insert(std::make_pair(lise.getCMgr(), lise_participant_info)); if (role_changed) { - LinphoneParticipantRole current_pauline_role = participantList[pauline.getCMgr()]; + LinphoneParticipantRole current_pauline_role = + linphone_participant_info_get_role(participantList[pauline.getCMgr()]); LinphoneParticipantRole new_pauline_role = (current_pauline_role == LinphoneParticipantRoleListener) ? LinphoneParticipantRoleSpeaker : LinphoneParticipantRoleListener; @@ -155,9 +159,19 @@ static void edit_simple_conference_base(bool_t from_organizer, linphone_participant_info_clone(old_pauline_partipant_info); linphone_participant_info_set_role(pauline_participant_info, new_pauline_role); linphone_conference_info_update_participant(conf_info, pauline_participant_info); + + linphone_participant_info_set_role(participantList[pauline.getCMgr()], new_pauline_role); + const bctbx_list_t *participant_info_it = bctbx_list_find_custom( + participants_info, (int (*)(const void *, const void *))find_matching_participant_info, + pauline_participant_info); + BC_ASSERT_PTR_NOT_NULL(participant_info_it); + if (participant_info_it) { + LinphoneParticipantInfo *participant_info_found = + (LinphoneParticipantInfo *)bctbx_list_get_data(participant_info_it); + linphone_participant_info_set_role(participant_info_found, new_pauline_role); + } linphone_participant_info_unref(pauline_participant_info); } - participantList[pauline.getCMgr()] = new_pauline_role; } const auto ics_participant_number = 3; @@ -254,49 +268,6 @@ static void edit_simple_conference_base(bool_t from_organizer, linphone_factory_create_conference_info_from_icalendar_content(linphone_factory_get(), original_content); if (BC_ASSERT_PTR_NOT_NULL(conf_info_from_original_content)) { - BC_ASSERT_TRUE(linphone_address_weak_equal( - marie.getCMgr()->identity, - linphone_conference_info_get_organizer(conf_info_from_original_content))); - BC_ASSERT_TRUE(linphone_address_weak_equal( - confAddr, linphone_conference_info_get_uri(conf_info_from_original_content))); - - const bctbx_list_t *ics_participants = - linphone_conference_info_get_participant_infos(conf_info_from_original_content); - BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), ics_participant_number, size_t, - "%zu"); - - if (start_time > 0) { - BC_ASSERT_EQUAL((long long)linphone_conference_info_get_date_time( - conf_info_from_original_content), - (long long)start_time, long long, "%lld"); - if (end_time > 0) { - const int duration_m = - linphone_conference_info_get_duration(conf_info_from_original_content); - const int duration_s = duration_m * 60; - BC_ASSERT_EQUAL(duration_s, (int)(end_time - start_time), int, "%d"); - BC_ASSERT_EQUAL(duration_m, duration, int, "%d"); - } - } - if (initialSubject) { - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_subject(conf_info_from_original_content), - initialSubject); - } else { - BC_ASSERT_PTR_NULL( - linphone_conference_info_get_subject(conf_info_from_original_content)); - } - if (description) { - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_description(conf_info_from_original_content), - description); - } else { - BC_ASSERT_PTR_NULL( - linphone_conference_info_get_description(conf_info_from_original_content)); - } - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_ics_uid(conf_info_from_original_content), uid); - const unsigned int ics_sequence = - linphone_conference_info_get_ics_sequence(conf_info_from_original_content); int exp_sequence = 0; if (mgr == lise.getCMgr()) { exp_sequence = 0; @@ -304,20 +275,24 @@ static void edit_simple_conference_base(bool_t from_organizer, exp_sequence = (sequence + 1); } - BC_ASSERT_EQUAL(ics_sequence, exp_sequence, int, "%d"); - LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateNew; - if (mgr == lise.getCMgr()) { exp_state = LinphoneConferenceInfoStateNew; } else { exp_state = LinphoneConferenceInfoStateUpdated; } - BC_ASSERT_EQUAL( - (int)linphone_conference_info_get_state(conf_info_from_original_content), - (int)exp_state, int, "%d"); + update_sequence_number(&participants_info, {lise.getCMgr()->identity}, + (mgr == focus.getCMgr()) ? 0 : 1, + (mgr == focus.getCMgr()) ? -1 : 0); + + check_conference_info_against_db(mgr, confAddr, conf_info_from_original_content); linphone_conference_info_unref(conf_info_from_original_content); + + check_conference_info_in_db(mgr, uid, confAddr, marie.getCMgr()->identity, + participants_info, start_time, duration, initialSubject, + description, exp_sequence, exp_state, security_level, + FALSE); } } linphone_chat_message_unref(msg); @@ -334,6 +309,8 @@ static void edit_simple_conference_base(bool_t from_organizer, if (join) { std::list<LinphoneCoreManager *> conferenceMgrs{focus.getCMgr(), marie.getCMgr(), pauline.getCMgr()}; std::list<LinphoneCoreManager *> members{marie.getCMgr(), pauline.getCMgr()}; + add_participant_info_to_list(&participants_info, marie.getCMgr()->identity, LinphoneParticipantRoleSpeaker, + 0); stats focus_stat = focus.getStats(); for (auto mgr : members) { @@ -392,20 +369,8 @@ static void edit_simple_conference_base(bool_t from_organizer, focus_stat.number_of_participant_devices_joined + 2, liblinphone_tester_sip_timeout)); - std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList; - for (const auto &member : members) { - try { - const auto &participantInfo = participantList.at(member); - memberList.insert(std::make_pair(member, participantInfo)); - } catch (std::out_of_range &) { - if (member == marie.getCMgr()) { - memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker)); - } else { - ms_fatal("Unable to find active participant %s in the participant list", - linphone_core_get_identity(member->lc)); - } - } - } + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList = + fill_memmber_list(members, participantList, marie.getCMgr(), participants_info); wait_for_conference_streams({focus, marie, pauline, laure, michelle, lise}, conferenceMgrs, focus.getCMgr(), memberList, confAddr, TRUE); @@ -578,7 +543,15 @@ static void edit_simple_conference_base(bool_t from_organizer, bctbx_list_t *initialInfos = NULL; for (const auto &participant : initialParticipants) { LinphoneParticipantInfo *info = linphone_participant_info_new(participant->identity); - initialInfos = bctbx_list_append(initialInfos, info); + const bctbx_list_t *participant_info_it = bctbx_list_find_custom( + participants_info, (int (*)(const void *, const void *))find_matching_participant_info, info); + BC_ASSERT_PTR_NOT_NULL(participant_info_it); + if (participant_info_it) { + LinphoneParticipantInfo *participant_info_found = + (LinphoneParticipantInfo *)bctbx_list_get_data(participant_info_it); + initialInfos = bctbx_list_append(initialInfos, participant_info_found); + } + linphone_participant_info_unref(info); } for (int attempt = 0; attempt < 3; attempt++) { @@ -597,8 +570,9 @@ static void edit_simple_conference_base(bool_t from_organizer, linphone_conference_info_set_description(conf_info, description2); if (add) { linphone_conference_info_add_participant(conf_info, michelle.getCMgr()->identity); - participants.push_back(michelle.getCMgr()); } else { + // If marie was in the list of participants, she will be removed as well but she will be kept as + // organizer linphone_conference_info_set_participant_infos(conf_info, initialInfos); } @@ -646,6 +620,24 @@ static void edit_simple_conference_base(bool_t from_organizer, focus_stat.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout)); + if (add) { + LinphoneParticipantRole role = LinphoneParticipantRoleUnknown; + add_participant_info_to_list(&participants_info, michelle.getCMgr()->identity, role, 0); + } else { + for (const auto &mgr : {michelle.getCMgr(), marie.getCMgr()}) { + LinphoneParticipantInfo *participant_info = linphone_participant_info_new(mgr->identity); + bctbx_list_t *participant_info_found_it = bctbx_list_find_custom( + participants_info, (int (*)(const void *, const void *))find_matching_participant_info, + participant_info); + if (participant_info_found_it) { + LinphoneParticipantInfo *participant_info_found = + (LinphoneParticipantInfo *)bctbx_list_get_data(participant_info_found_it); + participants_info = bctbx_list_remove(participants_info, participant_info_found); + linphone_participant_info_unref(participant_info_found); + } + linphone_participant_info_unref(participant_info); + } + } LinphoneChatRoomParams *chat_room_params = linphone_core_create_default_chat_room_params(manager_editing->lc); linphone_chat_room_params_set_backend(chat_room_params, LinphoneChatRoomBackendBasic); @@ -717,51 +709,6 @@ static void edit_simple_conference_base(bool_t from_organizer, linphone_factory_create_conference_info_from_icalendar_content( linphone_factory_get(), original_content); if (BC_ASSERT_PTR_NOT_NULL(conf_info_from_original_content)) { - BC_ASSERT_TRUE(linphone_address_weak_equal( - marie.getCMgr()->identity, - linphone_conference_info_get_organizer(conf_info_from_original_content))); - BC_ASSERT_TRUE(linphone_address_weak_equal( - confAddr, - linphone_conference_info_get_uri(conf_info_from_original_content))); - - const bctbx_list_t *ics_participants = - linphone_conference_info_get_participant_infos( - conf_info_from_original_content); - BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), ics_participant_number, - size_t, "%zu"); - - if (start_time > 0) { - BC_ASSERT_EQUAL((long long)linphone_conference_info_get_date_time( - conf_info_from_original_content), - (long long)start_time, long long, "%lld"); - if (end_time > 0) { - const int duration_m = linphone_conference_info_get_duration( - conf_info_from_original_content); - const int duration_s = duration_m * 60; - BC_ASSERT_EQUAL(duration_s, (int)(end_time - start_time), int, "%d"); - BC_ASSERT_EQUAL(duration_m, duration, int, "%d"); - } - } - if (subject) { - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_subject(conf_info_from_original_content), - subject); - } else { - BC_ASSERT_PTR_NULL( - linphone_conference_info_get_subject(conf_info_from_original_content)); - } - if (description2) { - BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description( - conf_info_from_original_content), - description2); - } else { - BC_ASSERT_PTR_NULL(linphone_conference_info_get_description( - conf_info_from_original_content)); - } - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_ics_uid(conf_info_from_original_content), uid); - const unsigned int ics_sequence = - linphone_conference_info_get_ics_sequence(conf_info_from_original_content); int exp_sequence = 0; if (mgr == michelle.getCMgr()) { if (add) { @@ -775,8 +722,6 @@ static void edit_simple_conference_base(bool_t from_organizer, exp_sequence = (sequence + attempt + 1); } - BC_ASSERT_EQUAL(ics_sequence, exp_sequence, int, "%d"); - LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateNew; if (mgr == michelle.getCMgr()) { if (add) { @@ -787,11 +732,34 @@ static void edit_simple_conference_base(bool_t from_organizer, } else { exp_state = LinphoneConferenceInfoStateUpdated; } - BC_ASSERT_EQUAL( - (int)linphone_conference_info_get_state(conf_info_from_original_content), - (int)exp_state, int, "%d"); + update_sequence_number(&participants_info, {michelle.getCMgr()->identity}, + (mgr == focus.getCMgr()) ? 0 : (sequence + attempt + 1), + (mgr == focus.getCMgr()) ? -1 : 0); + + LinphoneParticipantInfo *participant_info = + linphone_participant_info_new(lise.getCMgr()->identity); + const bctbx_list_t *participant_info_it = bctbx_list_find_custom( + participants_info, + (int (*)(const void *, const void *))find_matching_participant_info, + participant_info); + BC_ASSERT_PTR_NOT_NULL(participant_info_it); + if (participant_info_it) { + LinphoneParticipantInfo *participant_info_found = + (LinphoneParticipantInfo *)bctbx_list_get_data(participant_info_it); + linphone_participant_info_set_sequence_number(participant_info_found, + (attempt + 1)); + } + linphone_participant_info_unref(participant_info); + + check_conference_info_against_db(mgr, confAddr, + conf_info_from_original_content); linphone_conference_info_unref(conf_info_from_original_content); + + check_conference_info_in_db(mgr, uid, confAddr, marie.getCMgr()->identity, + participants_info, start_time, duration, subject, + description2, exp_sequence, exp_state, + security_level, FALSE); } } linphone_chat_message_unref(msg); @@ -858,34 +826,71 @@ static void edit_simple_conference_base(bool_t from_organizer, } else if (mgr == lise.getCMgr()) { exp_sequence = use_default_account ? (attempt + 1) : 0; } else { - exp_sequence = use_default_account ? (sequence + attempt + 1) : 1; + exp_sequence = use_default_account ? (attempt + 2) : 1; } } - check_conference_info(mgr, confAddr, marie.getCMgr(), - ((use_default_account && add) ? 4 : 3) + - ((((attempt == 0) && join) || (mgr == focus.getCMgr())) ? 1 : 0), - start_time, duration, exp_subject, exp_description, exp_sequence, - exp_state, security_level); - if (mgr != focus.getCMgr()) { - for (auto &p : participants) { - int exp_participant_sequence = 0; - // If not using the default account (which was used to create the conference), the - // conference scheduler errors out and Michelle is not added - if ((use_default_account) || (p != michelle.getCMgr())) { - if (!use_default_account) { - exp_participant_sequence = (p == lise.getCMgr()) ? 0 : 1; - } else if (p == michelle.getCMgr()) { - exp_participant_sequence = 0; - } else if (p == lise.getCMgr()) { - exp_participant_sequence = attempt + 1; - } else { - exp_participant_sequence = attempt + 2; - } - linphone_conference_info_check_participant(info, p->identity, - exp_participant_sequence); + ms_message("%s - END mgr %s", __func__, linphone_core_get_identity(mgr->lc)); + bool is_focus = (mgr == focus.getCMgr()); + bctbx_list_t *participants_info2 = bctbx_list_copy_with_data( + participants_info, (bctbx_list_copy_func)linphone_participant_info_clone); + if (is_focus) { + add_participant_info_to_list(&participants_info2, marie.getCMgr()->identity, + LinphoneParticipantRoleSpeaker, 0); + } + + // If not using the default account (which was used to create the conference), the + // conference scheduler errors out and Michelle is not added + int exp_sequence_number = 0; + if (use_default_account) { + if (is_focus) { + exp_sequence_number = (attempt + 1); + } else { + exp_sequence_number = (attempt + 2); + } + } else { + if (is_focus) { + exp_sequence_number = 0; + } else { + exp_sequence_number = 1; + } + } + std::list<LinphoneAddress *> new_participants{michelle.getCMgr()->identity}; + if (!join || (is_focus && (attempt > 0))) { + new_participants.push_back(marie.getCMgr()->identity); + } + update_sequence_number(&participants_info2, new_participants, exp_sequence_number, + (mgr == focus.getCMgr()) ? -1 : 0); + + LinphoneParticipantInfo *lise_participant_info = + linphone_participant_info_new(lise.getCMgr()->identity); + const bctbx_list_t *participant_info_it = bctbx_list_find_custom( + participants_info2, (int (*)(const void *, const void *))find_matching_participant_info, + lise_participant_info); + BC_ASSERT_PTR_NOT_NULL(participant_info_it); + if (participant_info_it) { + int exp_lise_sequence_number = 0; + if (use_default_account) { + if (is_focus) { + exp_lise_sequence_number = attempt; + } else { + exp_lise_sequence_number = (attempt + 1); + } + } else { + if (is_focus) { + exp_lise_sequence_number = -1; + } else { + exp_lise_sequence_number = 0; } } + LinphoneParticipantInfo *participant_info_found = + (LinphoneParticipantInfo *)bctbx_list_get_data(participant_info_it); + linphone_participant_info_set_sequence_number(participant_info_found, + exp_lise_sequence_number); + } + linphone_participant_info_unref(lise_participant_info); + + if (!is_focus) { int exp_organizer_sequence = 0; if (use_default_account) { exp_organizer_sequence = attempt + 2; @@ -894,6 +899,13 @@ static void edit_simple_conference_base(bool_t from_organizer, } linphone_conference_info_check_organizer(info, exp_organizer_sequence); } + + check_conference_info_in_db(mgr, uid, confAddr, marie.getCMgr()->identity, participants_info2, + start_time, duration, exp_subject, exp_description, exp_sequence, + exp_state, security_level, FALSE); + + bctbx_list_free_with_data(participants_info2, + (bctbx_list_free_func)linphone_participant_info_unref); } if (info) { linphone_conference_info_unref(info); @@ -903,7 +915,7 @@ static void edit_simple_conference_base(bool_t from_organizer, } add = !add; } - bctbx_list_free_with_data(initialInfos, (void (*)(void *))linphone_participant_info_unref); + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); ms_free(uid); ms_free(conference_address_str); linphone_address_unref(alternative_address); @@ -996,10 +1008,12 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo const char *description = "Testing characters"; LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : participants) { - participantList.insert(std::make_pair(p, role)); + participantList.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker; } @@ -1034,6 +1048,26 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo linphone_core_get_identity(michelle.getLc()), linphone_core_get_identity(laure.getLc())); ms_free(conference_address_str); + // Remove Laure from list of expected participants + LinphoneParticipantInfo *laure_participant_info = linphone_participant_info_new(laure.getCMgr()->identity); + bctbx_list_t *laure_participant_info_found_it = bctbx_list_find_custom( + participants_info, (int (*)(const void *, const void *))find_matching_participant_info, + laure_participant_info); + BC_ASSERT_PTR_NOT_NULL(laure_participant_info_found_it); + if (laure_participant_info_found_it) { + LinphoneParticipantInfo *laure_participant_info_found = + (LinphoneParticipantInfo *)bctbx_list_get_data(laure_participant_info_found_it); + participants_info = bctbx_list_remove(participants_info, laure_participant_info_found); + linphone_participant_info_unref(laure_participant_info_found); + } + linphone_participant_info_unref(laure_participant_info); + participantList.erase(laure.getCMgr()); + + // Add michelle to list of expected participants + participantList.insert(std::make_pair( + michelle.getCMgr(), add_participant_info_to_list(&participants_info, michelle.getCMgr()->identity, + LinphoneParticipantRoleUnknown, 0))); + stats focus_stat = focus.getStats(); LinphoneConferenceInfo *conf_info = linphone_core_find_conference_information_from_uri(marie.getLc(), confAddr); @@ -1133,49 +1167,6 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo linphone_factory_create_conference_info_from_icalendar_content(linphone_factory_get(), original_content); if (BC_ASSERT_PTR_NOT_NULL(conf_info_from_original_content)) { - BC_ASSERT_TRUE(linphone_address_weak_equal( - marie.getCMgr()->identity, - linphone_conference_info_get_organizer(conf_info_from_original_content))); - BC_ASSERT_TRUE(linphone_address_weak_equal( - confAddr, linphone_conference_info_get_uri(conf_info_from_original_content))); - - const bctbx_list_t *ics_participants = - linphone_conference_info_get_participant_infos(conf_info_from_original_content); - BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), participants.size(), size_t, "%zu"); - - if (start_time > 0) { - BC_ASSERT_EQUAL( - (long long)linphone_conference_info_get_date_time(conf_info_from_original_content), - (long long)start_time, long long, "%lld"); - if (end_time > 0) { - const int duration_m = - linphone_conference_info_get_duration(conf_info_from_original_content); - const int duration_s = duration_m * 60; - BC_ASSERT_EQUAL(duration_s, (int)(end_time - start_time), int, "%d"); - BC_ASSERT_EQUAL(duration_m, duration, int, "%d"); - } - } - if (subject) { - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_subject(conf_info_from_original_content), subject); - } else { - BC_ASSERT_PTR_NULL( - linphone_conference_info_get_subject(conf_info_from_original_content)); - } - if (description2) { - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_description(conf_info_from_original_content), - description2); - } else { - BC_ASSERT_PTR_NULL( - linphone_conference_info_get_description(conf_info_from_original_content)); - } - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_ics_uid(conf_info_from_original_content), uid); - const unsigned int ics_sequence = - linphone_conference_info_get_ics_sequence(conf_info_from_original_content); - BC_ASSERT_EQUAL(ics_sequence, (mgr == michelle.getCMgr()) ? 0 : (sequence + 1), int, "%d"); - LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateNew; if (mgr == laure.getCMgr()) { exp_state = LinphoneConferenceInfoStateCancelled; @@ -1184,9 +1175,15 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo } else { exp_state = LinphoneConferenceInfoStateUpdated; } - BC_ASSERT_EQUAL((int)linphone_conference_info_get_state(conf_info_from_original_content), - (int)exp_state, int, "%d"); + update_sequence_number(&participants_info, {michelle.getCMgr()->identity}, + (mgr == focus.getCMgr()) ? 0 : 1, (mgr == focus.getCMgr()) ? -1 : 0); + + const unsigned int ics_sequence = (mgr == michelle.getCMgr()) ? 0 : (sequence + 1); + check_conference_info_members(conf_info_from_original_content, uid, confAddr, + marie.getCMgr()->identity, participants_info, start_time, + duration, subject, description2, ics_sequence, exp_state, + security_level, FALSE); linphone_conference_info_unref(conf_info_from_original_content); } } @@ -1224,13 +1221,19 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo exp_state = LinphoneConferenceInfoStateUpdated; } } - check_conference_info(mgr, confAddr, marie.getCMgr(), participants.size(), start_time, duration, - exp_subject, exp_description, exp_sequence, exp_state, security_level); + + update_sequence_number(&participants_info, {michelle.getCMgr()->identity}, + (mgr == focus.getCMgr()) ? 0 : 1, (mgr == focus.getCMgr()) ? -1 : 0); + + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, + start_time, duration, exp_subject, exp_description, exp_sequence, exp_state, + security_level, FALSE); } if (info) { linphone_conference_info_unref(info); } } + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); linphone_conference_info_unref(conf_info); ms_free(uid); linphone_address_unref(confAddr); @@ -1277,10 +1280,12 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) { const char *description = "Testing characters"; LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : participants) { - participantList.insert(std::make_pair(p, role)); + participantList.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker; } @@ -1402,52 +1407,15 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) { linphone_factory_create_conference_info_from_icalendar_content(linphone_factory_get(), original_content); if (BC_ASSERT_PTR_NOT_NULL(conf_info_from_original_content)) { - BC_ASSERT_TRUE(linphone_address_weak_equal( - marie.getCMgr()->identity, - linphone_conference_info_get_organizer(conf_info_from_original_content))); - BC_ASSERT_TRUE(linphone_address_weak_equal( - confAddr, linphone_conference_info_get_uri(conf_info_from_original_content))); - - const bctbx_list_t *ics_participants = - linphone_conference_info_get_participant_infos(conf_info_from_original_content); - BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), 3, size_t, "%zu"); - - if (start_time > 0) { - BC_ASSERT_EQUAL( - (long long)linphone_conference_info_get_date_time(conf_info_from_original_content), - (long long)start_time, long long, "%lld"); - if (end_time > 0) { - const int duration_m = - linphone_conference_info_get_duration(conf_info_from_original_content); - BC_ASSERT_EQUAL(duration_m, new_duration, int, "%d"); - } - } - if (initialSubject) { - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_subject(conf_info_from_original_content), - initialSubject); - } else { - BC_ASSERT_PTR_NULL( - linphone_conference_info_get_subject(conf_info_from_original_content)); - } - if (description) { - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_description(conf_info_from_original_content), - description); - } else { - BC_ASSERT_PTR_NULL( - linphone_conference_info_get_description(conf_info_from_original_content)); - } - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_ics_uid(conf_info_from_original_content), uid); - const unsigned int ics_sequence = - linphone_conference_info_get_ics_sequence(conf_info_from_original_content); - BC_ASSERT_EQUAL(ics_sequence, (sequence + 1), int, "%d"); - + const unsigned int ics_sequence = (sequence + 1); LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateUpdated; - BC_ASSERT_EQUAL((int)linphone_conference_info_get_state(conf_info_from_original_content), - (int)exp_state, int, "%d"); + update_sequence_number(&participants_info, {}, (mgr == focus.getCMgr()) ? 0 : 1, + (mgr == focus.getCMgr()) ? -1 : 0); + check_conference_info_members(conf_info_from_original_content, uid, confAddr, + marie.getCMgr()->identity, participants_info, start_time, + new_duration, initialSubject, description, ics_sequence, + exp_state, security_level, FALSE); linphone_conference_info_unref(conf_info_from_original_content); } } @@ -1598,56 +1566,17 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) { linphone_factory_create_conference_info_from_icalendar_content(linphone_factory_get(), original_content); if (BC_ASSERT_PTR_NOT_NULL(conf_info_from_original_content)) { - BC_ASSERT_TRUE(linphone_address_weak_equal( - marie.getCMgr()->identity, - linphone_conference_info_get_organizer(conf_info_from_original_content))); - BC_ASSERT_TRUE(linphone_address_weak_equal( - confAddr, linphone_conference_info_get_uri(conf_info_from_original_content))); - - const bctbx_list_t *ics_participants = - linphone_conference_info_get_participant_infos(conf_info_from_original_content); - BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), 0, size_t, "%zu"); - - if (start_time > 0) { - BC_ASSERT_EQUAL( - (long long)linphone_conference_info_get_date_time(conf_info_from_original_content), - (long long)start_time, long long, "%lld"); - if (end_time > 0) { - const int duration_m = - linphone_conference_info_get_duration(conf_info_from_original_content); - BC_ASSERT_EQUAL(duration_m, new_duration, int, "%d"); - } - } - if (subject) { - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_subject(conf_info_from_original_content), subject); - } else { - BC_ASSERT_PTR_NULL( - linphone_conference_info_get_subject(conf_info_from_original_content)); - } - if (description2) { - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_description(conf_info_from_original_content), - description2); - } else { - BC_ASSERT_PTR_NULL( - linphone_conference_info_get_description(conf_info_from_original_content)); - } - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_ics_uid(conf_info_from_original_content), uid); - const unsigned int ics_sequence = - linphone_conference_info_get_ics_sequence(conf_info_from_original_content); - BC_ASSERT_EQUAL(ics_sequence, (sequence + 1), int, "%d"); - + const unsigned int ics_sequence = (sequence + 1); LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateNew; if (mgr == focus.getCMgr()) { exp_state = LinphoneConferenceInfoStateUpdated; } else { exp_state = LinphoneConferenceInfoStateCancelled; } - BC_ASSERT_EQUAL((int)linphone_conference_info_get_state(conf_info_from_original_content), - (int)exp_state, int, "%d"); - + check_conference_info_members(conf_info_from_original_content, uid, confAddr, + marie.getCMgr()->identity, NULL, start_time, new_duration, + subject, description2, ics_sequence, exp_state, + security_level, FALSE); linphone_conference_info_unref(conf_info_from_original_content); } } @@ -1671,19 +1600,20 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) { unsigned int exp_sequence = 0; LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateCancelled; - unsigned int exp_participant_number = 0; if (mgr == focus.getCMgr()) { exp_sequence = 0; } else { exp_sequence = (sequence + 1); } - check_conference_info(mgr, confAddr, marie.getCMgr(), exp_participant_number, start_time, new_duration, - exp_subject, exp_description, exp_sequence, exp_state, security_level); + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, NULL, start_time, + new_duration, exp_subject, exp_description, exp_sequence, exp_state, + security_level, FALSE); } if (info) { linphone_conference_info_unref(info); } } + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); linphone_conference_info_unref(conf_info); ms_free(uid); linphone_address_unref(confAddr); diff --git a/tester/local_conference_tester_functions.cpp b/tester/local_conference_tester_functions.cpp index 6bcd04088c..d5da877468 100644 --- a/tester/local_conference_tester_functions.cpp +++ b/tester/local_conference_tester_functions.cpp @@ -1573,47 +1573,201 @@ void conference_scheduler_invitations_sent(LinphoneConferenceScheduler *schedule stat->number_of_ConferenceSchedulerInvitationsSent++; } -void check_conference_info(LinphoneCoreManager *mgr, - LinphoneAddress *confAddr, - LinphoneCoreManager *organizer, - size_t no_members, - long long start_time, - int duration, - const char *subject, - const char *description, - unsigned int sequence, - LinphoneConferenceInfoState state, - LinphoneConferenceSecurityLevel security_level) { +std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> +fill_memmber_list(std::list<LinphoneCoreManager *> members, + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList, + LinphoneCoreManager *organizer, + bctbx_list_t *participants_info) { + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList; + for (const auto &member : members) { + try { + auto &participantInfo = participantList.at(member); + LinphoneParticipantRole role = linphone_participant_info_get_role(participantInfo); + if (role == LinphoneParticipantRoleUnknown) { + role = LinphoneParticipantRoleSpeaker; + linphone_participant_info_set_role(participantInfo, role); + } + memberList.insert(std::make_pair(member, participantInfo)); + } catch (std::out_of_range &) { + if (member == organizer) { + memberList.insert( + std::make_pair(member, add_participant_info_to_list(&participants_info, member->identity, + LinphoneParticipantRoleSpeaker, 0))); + } else { + ms_fatal("Unable to find active participant %s in the participant list", + linphone_core_get_identity(member->lc)); + } + } + } + return memberList; +} + +void check_conference_info_in_db(LinphoneCoreManager *mgr, + const char *uid, + LinphoneAddress *confAddr, + LinphoneAddress *organizer, + bctbx_list_t *participantList, + long long start_time, + int duration, // in minutes + const char *subject, + const char *description, + unsigned int sequence, + LinphoneConferenceInfoState state, + LinphoneConferenceSecurityLevel security_level, + bool_t skip_participant_info) { LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(mgr->lc, confAddr); if (BC_ASSERT_PTR_NOT_NULL(info)) { - BC_ASSERT_TRUE(linphone_address_weak_equal(organizer->identity, linphone_conference_info_get_organizer(info))); - BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, linphone_conference_info_get_uri(info))); + check_conference_info_members(info, uid, confAddr, organizer, participantList, start_time, duration, subject, + description, sequence, state, security_level, skip_participant_info); + linphone_conference_info_unref(info); + } +} - const bctbx_list_t *info_participants = linphone_conference_info_get_participant_infos(info); - BC_ASSERT_EQUAL(bctbx_list_size(info_participants), no_members, size_t, "%zu"); - BC_ASSERT_EQUAL((int)linphone_conference_info_get_security_level(info), (int)security_level, int, "%0d"); +void check_conference_info_against_db(LinphoneCoreManager *mgr, + LinphoneAddress *confAddr, + const LinphoneConferenceInfo *info1) { + LinphoneConferenceInfo *info2 = linphone_core_find_conference_information_from_uri(mgr->lc, confAddr); + if (BC_ASSERT_PTR_NOT_NULL(info2)) { + compare_conference_infos(info1, info2, FALSE); + linphone_conference_info_unref(info2); + } +} + +void check_conference_info_members(const LinphoneConferenceInfo *info, + const char *uid, + LinphoneAddress *confAddr, + LinphoneAddress *organizer, + bctbx_list_t *participantList, + long long start_time, + int duration, // in minutes + const char *subject, + const char *description, + unsigned int sequence, + LinphoneConferenceInfoState state, + LinphoneConferenceSecurityLevel security_level, + bool_t skip_participant_info) { + LinphoneConferenceInfo *info2 = linphone_conference_info_new(); + linphone_conference_info_set_ics_uid(info2, uid); + linphone_conference_info_set_uri(info2, confAddr); + linphone_conference_info_set_organizer(info2, organizer); + linphone_conference_info_set_participant_infos(info2, participantList); + linphone_conference_info_set_date_time(info2, start_time); + linphone_conference_info_set_duration(info2, duration); + linphone_conference_info_set_subject(info2, subject); + linphone_conference_info_set_description(info2, description); + linphone_conference_info_set_ics_sequence(info2, sequence); + linphone_conference_info_set_state(info2, state); + linphone_conference_info_set_security_level(info2, security_level); + compare_conference_infos(info, info2, skip_participant_info); + linphone_conference_info_unref(info2); +} + +void compare_conference_infos(const LinphoneConferenceInfo *info1, + const LinphoneConferenceInfo *info2, + bool_t skip_participant_info) { + BC_ASSERT_PTR_NOT_NULL(info1); + BC_ASSERT_PTR_NOT_NULL(info2); + if (info1 && info2) { + BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_conference_info_get_organizer(info1), + linphone_conference_info_get_organizer(info2))); + BC_ASSERT_TRUE( + linphone_address_equal(linphone_conference_info_get_uri(info1), linphone_conference_info_get_uri(info2))); + + const bctbx_list_t *info1_participants = linphone_conference_info_get_participant_infos(info1); + const bctbx_list_t *info2_participants = linphone_conference_info_get_participant_infos(info2); + BC_ASSERT_EQUAL(bctbx_list_size(info1_participants), bctbx_list_size(info2_participants), size_t, "%zu"); + for (const bctbx_list_t *it = info1_participants; it; it = bctbx_list_next(it)) { + const LinphoneParticipantInfo *participant_info1 = (LinphoneParticipantInfo *)bctbx_list_get_data(it); + const bctbx_list_t *participant_info2_it = bctbx_list_find_custom( + info2_participants, (int (*)(const void *, const void *))find_matching_participant_info, + participant_info1); + BC_ASSERT_PTR_NOT_NULL(participant_info2_it); + if (participant_info2_it) { + const LinphoneParticipantInfo *participant_info2 = + (LinphoneParticipantInfo *)bctbx_list_get_data(participant_info2_it); + BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_info_get_address(participant_info1), + linphone_participant_info_get_address(participant_info2))); + if (!skip_participant_info) { + BC_ASSERT_EQUAL(linphone_participant_info_get_role(participant_info1), + linphone_participant_info_get_role(participant_info2), int, "%0d"); + BC_ASSERT_EQUAL(linphone_participant_info_get_sequence_number(participant_info1), + linphone_participant_info_get_sequence_number(participant_info2), int, "%0d"); + } + } + } - if (start_time > 0) { - BC_ASSERT_EQUAL((long long)linphone_conference_info_get_date_time(info), start_time, long long, "%lld"); + BC_ASSERT_EQUAL((int)linphone_conference_info_get_security_level(info1), + (int)linphone_conference_info_get_security_level(info2), int, "%0d"); + + time_t start_time1 = linphone_conference_info_get_date_time(info1); + time_t start_time2 = linphone_conference_info_get_date_time(info2); + + if ((start_time1 > 0) && (start_time2 > 0)) { + BC_ASSERT_EQUAL((long long)start_time1, (long long)start_time2, long long, "%lld"); } else { - BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(info), 0, long long, "%lld"); + if ((start_time1 != 0) && (start_time1 != -1)) { + BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(info1), 0, long long, + "%lld"); + } + if ((start_time2 != 0) && (start_time2 != -1)) { + BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(info2), 0, long long, + "%lld"); + } } - const int duration_m = linphone_conference_info_get_duration(info); - BC_ASSERT_EQUAL(duration_m, ((duration < 0) ? 0 : duration), int, "%d"); - if (subject) { - BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_subject(info), subject); + + const int duration1_m = linphone_conference_info_get_duration(info1); + const int duration2_m = linphone_conference_info_get_duration(info2); + // BC_ASSERT_EQUAL(duration_m, ((duration < 0) ? 0 : duration), int, "%d"); + BC_ASSERT_EQUAL(duration1_m, duration2_m, int, "%d"); + + const char *subject1 = linphone_conference_info_get_subject(info1); + const char *subject2 = linphone_conference_info_get_subject(info2); + if (subject1 && subject2) { + BC_ASSERT_STRING_EQUAL(subject1, subject2); } else { - BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(info)); + BC_ASSERT_PTR_NULL(subject1); + BC_ASSERT_PTR_NULL(subject2); + } + + const char *description1 = linphone_conference_info_get_description(info1); + const char *description2 = linphone_conference_info_get_description(info2); + if (description1 && description2) { + BC_ASSERT_STRING_EQUAL(description1, description2); + } + + const unsigned int ics_sequence1 = linphone_conference_info_get_ics_sequence(info1); + const unsigned int ics_sequence2 = linphone_conference_info_get_ics_sequence(info2); + BC_ASSERT_EQUAL(ics_sequence1, ics_sequence2, int, "%d"); + BC_ASSERT_EQUAL((int)linphone_conference_info_get_state(info1), (int)linphone_conference_info_get_state(info2), + int, "%d"); + + const char *uid1 = linphone_conference_info_get_ics_uid(info1); + const char *uid2 = linphone_conference_info_get_ics_uid(info2); + if (uid1 && uid2) { + BC_ASSERT_STRING_EQUAL(uid1, uid2); } - if (description) { - BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description(info), description); + } +} + +void update_sequence_number(bctbx_list_t **participants_info, + const std::list<LinphoneAddress *> new_participants, + int exp_sequence, + int exp_new_participant_sequence) { + // Increment sequence number of participants + for (const bctbx_list_t *it = *participants_info; it; it = bctbx_list_next(it)) { + LinphoneParticipantInfo *participant_info = (LinphoneParticipantInfo *)bctbx_list_get_data(it); + bool is_new_participant = false; + for (const auto &address : new_participants) { + is_new_participant |= + !!linphone_address_weak_equal(linphone_participant_info_get_address(participant_info), address); + } + int sequence_number = 0; + if (is_new_participant) { + sequence_number = exp_new_participant_sequence; } else { - BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(info)); + sequence_number = exp_sequence; } - const unsigned int ics_sequence = linphone_conference_info_get_ics_sequence(info); - BC_ASSERT_EQUAL(ics_sequence, sequence, int, "%d"); - BC_ASSERT_EQUAL((int)linphone_conference_info_get_state(info), (int)state, int, "%d"); - linphone_conference_info_unref(info); + linphone_participant_info_set_sequence_number(participant_info, sequence_number); } } @@ -1634,10 +1788,35 @@ static bool have_common_audio_payload(LinphoneCoreManager *mgr1, LinphoneCoreMan return found; } +int find_matching_participant_info(const LinphoneParticipantInfo *info1, const LinphoneParticipantInfo *info2) { + return !linphone_address_weak_equal(linphone_participant_info_get_address(info1), + linphone_participant_info_get_address(info2)); +} + +LinphoneParticipantInfo *add_participant_info_to_list(bctbx_list_t **participants_info, + const LinphoneAddress *address, + LinphoneParticipantRole role, + int sequence) { + LinphoneParticipantInfo *ret = NULL; + LinphoneParticipantInfo *participant_info = linphone_participant_info_new(address); + linphone_participant_info_set_role(participant_info, role); + linphone_participant_info_set_sequence_number(participant_info, sequence); + const bctbx_list_t *participant_info_it = bctbx_list_find_custom( + *participants_info, (int (*)(const void *, const void *))find_matching_participant_info, participant_info); + if (participant_info_it) { + ret = (LinphoneParticipantInfo *)bctbx_list_get_data(participant_info_it); + } else { + ret = linphone_participant_info_ref(participant_info); + *participants_info = bctbx_list_append(*participants_info, ret); + } + linphone_participant_info_unref(participant_info); + return ret; +} + LinphoneAddress * create_conference_on_server(Focus &focus, ClientConference &organizer, - std::map<LinphoneCoreManager *, LinphoneParticipantRole> requested_participants, + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> requested_participants, time_t start_time, time_t end_time, const char *subject, @@ -1648,21 +1827,18 @@ create_conference_on_server(Focus &focus, coresList = bctbx_list_append(coresList, organizer.getLc()); std::vector<stats> participant_stats; std::map<LinphoneCoreManager *, LinphoneCall *> previous_calls; - bctbx_list_t *participant_infos = NULL; + bctbx_list_t *participants_info = NULL; std::list<LinphoneCoreManager *> participants; const LinphoneConferenceInfo *updated_conf_info = NULL; bool focus_organizer_common_payload = have_common_audio_payload(organizer.getCMgr(), focus.getCMgr()); bool dialout = ((end_time <= 0) && (start_time <= 0)); bool found_me = false; char *conference_address_str = NULL; - size_t organizer_expected_participant_number = 0; - size_t participant_expected_participant_number = 0; char *uid = NULL; LinphoneConferenceInfo *info = NULL; - for (const auto &[mgr, role] : requested_participants) { - LinphoneParticipantInfo *participant_info = linphone_participant_info_new(mgr->identity); - linphone_participant_info_set_role(participant_info, role); - participant_infos = bctbx_list_append(participant_infos, participant_info); + for (const auto &[mgr, participant_info] : requested_participants) { + LinphoneParticipantInfo *info = linphone_participant_info_clone(participant_info); + participants_info = bctbx_list_append(participants_info, info); if (mgr == organizer.getCMgr()) { found_me = true; } else { @@ -1672,6 +1848,10 @@ create_conference_on_server(Focus &focus, } } + int duration = 0; + if ((end_time >= 0) && (start_time >= 0) && (end_time > start_time)) { + duration = static_cast<int>((end_time - start_time) / 60); // duration is expected to be set in minutes + } stats organizer_stat = organizer.getStats(); stats focus_stat = focus.getStats(); @@ -1695,11 +1875,8 @@ create_conference_on_server(Focus &focus, linphone_account_get_params(default_account))) : linphone_address_new(linphone_core_get_identity(organizer.getLc())); linphone_conference_info_set_organizer(conf_info, organizer_address); - linphone_conference_info_set_participant_infos(conf_info, participant_infos); - if ((end_time >= 0) && (start_time >= 0) && (end_time > start_time)) { - linphone_conference_info_set_duration( - conf_info, (int)((end_time - start_time) / 60)); // duration is expected to be set in minutes - } + linphone_conference_info_set_participant_infos(conf_info, participants_info); + linphone_conference_info_set_duration(conf_info, duration); linphone_conference_info_set_date_time(conf_info, start_time); linphone_conference_info_set_subject(conf_info, subject); linphone_conference_info_set_description(conf_info, description); @@ -1717,7 +1894,6 @@ create_conference_on_server(Focus &focus, int call_errors_cnt = 0; LinphoneAddress *conference_address = NULL; if (dialout) { - if (focus_organizer_common_payload) { BC_ASSERT_TRUE(wait_for_list(coresList, &organizer.getStats().number_of_LinphoneCallOutgoingInit, organizer_stat.number_of_LinphoneCallOutgoingInit + 1, @@ -1810,16 +1986,30 @@ create_conference_on_server(Focus &focus, linphone_conference_info_unref(info); } - organizer_expected_participant_number = - requested_participants.size() + ((!dialout || send_ics || found_me) ? 0 : 1); - participant_expected_participant_number = - requested_participants.size() + ((!dialout || send_ics || found_me) ? 0 : 1); + if (dialout && !send_ics && !found_me) { + add_participant_info_to_list(&participants_info, organizer.getCMgr()->identity, LinphoneParticipantRoleSpeaker, + 0); + } + + for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) { + LinphoneParticipantInfo *participant_info_el = (LinphoneParticipantInfo *)bctbx_list_get_data(info_it); + if (dialout && !send_ics) { + linphone_participant_info_set_role(participant_info_el, LinphoneParticipantRoleUnknown); + linphone_participant_info_set_sequence_number(participant_info_el, -1); + } else { + linphone_participant_info_set_sequence_number(participant_info_el, 0); + if (dialout && send_ics && + (linphone_participant_info_get_role(participant_info_el) == LinphoneParticipantRoleUnknown)) { + linphone_participant_info_set_role(participant_info_el, LinphoneParticipantRoleSpeaker); + } + } + } + if (!dialout) { // This check is not reliable when the conference is dialing participants - check_conference_info(organizer.getCMgr(), conference_address, organizer.getCMgr(), - organizer_expected_participant_number, start_time, - ((start_time > 0) && (end_time > 0)) ? (int)(end_time - start_time) / 60 : 0, subject, - description, 0, LinphoneConferenceInfoStateNew, security_level); + check_conference_info_in_db(organizer.getCMgr(), uid, conference_address, organizer.getCMgr()->identity, + participants_info, start_time, duration, subject, description, 0, + LinphoneConferenceInfoStateNew, security_level, FALSE); } idx = 0; @@ -1867,89 +2057,19 @@ create_conference_on_server(Focus &focus, if (!BC_ASSERT_PTR_NOT_NULL(conf_info_in_db)) { goto end; } + check_conference_info_members(conf_info_in_db, uid, conference_address, organizer_address, + participants_info, start_time, duration, subject, description, 0, + LinphoneConferenceInfoStateNew, + LinphoneConferenceSecurityLevelNone, dialout); LinphoneConferenceInfo *conf_info_from_original_content = linphone_factory_create_conference_info_from_icalendar_content(linphone_factory_get(), original_content); if (BC_ASSERT_PTR_NOT_NULL(conf_info_from_original_content)) { - BC_ASSERT_TRUE(linphone_address_weak_equal( - organizer_address, - linphone_conference_info_get_organizer(conf_info_from_original_content))); - BC_ASSERT_TRUE(linphone_address_equal( - linphone_conference_info_get_organizer(conf_info_in_db), - linphone_conference_info_get_organizer(conf_info_from_original_content))); - BC_ASSERT_TRUE(linphone_address_weak_equal( - conference_address, linphone_conference_info_get_uri(conf_info_from_original_content))); - BC_ASSERT_TRUE(linphone_address_equal( - linphone_conference_info_get_uri(conf_info_in_db), - linphone_conference_info_get_uri(conf_info_from_original_content))); - - const bctbx_list_t *ics_participants = - linphone_conference_info_get_participant_infos(conf_info_from_original_content); - BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), participant_expected_participant_number, - size_t, "%zu"); - - const bctbx_list_t *ics_participants_db = - linphone_conference_info_get_participant_infos(conf_info_in_db); - BC_ASSERT_EQUAL(bctbx_list_size(ics_participants_db), - participant_expected_participant_number, size_t, "%zu"); - - if (start_time > 0) { - BC_ASSERT_EQUAL( - (long long)linphone_conference_info_get_date_time(conf_info_from_original_content), - (long long)start_time, long long, "%lld"); - BC_ASSERT_EQUAL( - (long long)linphone_conference_info_get_date_time(conf_info_in_db), - (long long)linphone_conference_info_get_date_time(conf_info_from_original_content), - long long, "%lld"); - if (end_time > 0) { - const int duration_s = - linphone_conference_info_get_duration(conf_info_from_original_content) * 60; - BC_ASSERT_EQUAL(duration_s, (int)(end_time - start_time), int, "%d"); - BC_ASSERT_EQUAL( - (int)linphone_conference_info_get_duration(conf_info_in_db), - (int)linphone_conference_info_get_duration(conf_info_from_original_content), - int, "%0d"); - } - } - if (subject) { - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_subject(conf_info_from_original_content), subject); - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_subject(conf_info_in_db), - linphone_conference_info_get_subject(conf_info_from_original_content)); - } else { - BC_ASSERT_PTR_NULL( - linphone_conference_info_get_subject(conf_info_from_original_content)); - BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(conf_info_in_db)); - } - if (description) { - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_description(conf_info_from_original_content), - description); - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_description(conf_info_from_original_content), - linphone_conference_info_get_description(conf_info_in_db)); - } else { - BC_ASSERT_PTR_NULL( - linphone_conference_info_get_description(conf_info_from_original_content)); - BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(conf_info_in_db)); - } - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_ics_uid(conf_info_from_original_content), uid); - BC_ASSERT_STRING_EQUAL( - linphone_conference_info_get_ics_uid(conf_info_in_db), - linphone_conference_info_get_ics_uid(conf_info_from_original_content)); - - const unsigned int ics_sequence = - linphone_conference_info_get_ics_sequence(conf_info_in_db); - BC_ASSERT_EQUAL(ics_sequence, 0, int, "%d"); - BC_ASSERT_EQUAL(linphone_conference_info_get_ics_sequence(conf_info_in_db), - linphone_conference_info_get_ics_sequence(conf_info_from_original_content), - unsigned int, "%0u"); + compare_conference_infos(conf_info_from_original_content, conf_info_in_db, FALSE); linphone_conference_info_unref(conf_info_from_original_content); - linphone_conference_info_unref(conf_info_in_db); } + linphone_conference_info_unref(conf_info_in_db); linphone_chat_message_unref(msg); } } @@ -1964,11 +2084,11 @@ create_conference_on_server(Focus &focus, goto end; } // Encryption is None because we haven't received yet the NOTIFY full state with this information - check_conference_info(mgr, conference_address, organizer.getCMgr(), - participant_expected_participant_number, start_time, - ((start_time > 0) && (end_time > 0)) ? (int)(end_time - start_time) / 60 : 0, - subject, (!!send_ics) ? description : NULL, 0, LinphoneConferenceInfoStateNew, - LinphoneConferenceSecurityLevelNone); + check_conference_info_members( + conf_info_in_db, uid, conference_address, organizer.getCMgr()->identity, participants_info, + start_time, ((start_time > 0) && (end_time > 0)) ? (int)(end_time - start_time) / 60 : 0, + subject, (!!send_ics) ? description : NULL, 0, LinphoneConferenceInfoStateNew, + LinphoneConferenceSecurityLevelNone, dialout); if (!!send_ics) { for (auto &p : participants) { linphone_conference_info_check_participant(conf_info_in_db, p->identity, 0); @@ -1985,15 +2105,10 @@ create_conference_on_server(Focus &focus, idx++; } - if (uid) { - ms_free(uid); - } - if (conference_address && !dialout) { - check_conference_info(organizer.getCMgr(), conference_address, organizer.getCMgr(), - organizer_expected_participant_number, start_time, - (((start_time > 0) && (end_time > 0)) ? (int)(end_time - start_time) / 60 : 0), subject, - description, 0, LinphoneConferenceInfoStateNew, security_level); + check_conference_info_in_db(organizer.getCMgr(), uid, conference_address, organizer.getCMgr()->identity, + participants_info, start_time, duration, subject, description, 0, + LinphoneConferenceInfoStateNew, security_level, FALSE); } BC_ASSERT_EQUAL(organizer.getStats().number_of_LinphoneConferenceStateTerminationPending, @@ -2010,11 +2125,14 @@ create_conference_on_server(Focus &focus, ms_free(conference_address_str); end: + if (uid) { + ms_free(uid); + } + if (organizer_address) linphone_address_unref(organizer_address); linphone_conference_scheduler_unref(conference_scheduler); bctbx_list_free(coresList); - bctbx_list_free_with_data(participant_infos, (bctbx_list_free_func)linphone_participant_info_unref); - + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); return conference_address; } @@ -2099,7 +2217,7 @@ size_t compute_no_audio_streams(LinphoneCall *call, LinphoneConference *conferen void wait_for_conference_streams(std::initializer_list<std::reference_wrapper<CoreManager>> coreMgrs, std::list<LinphoneCoreManager *> conferenceMgrs, LinphoneCoreManager *focus, - std::map<LinphoneCoreManager *, LinphoneParticipantRole> members, + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> members, const LinphoneAddress *confAddr, bool_t enable_video) { for (auto mgr : conferenceMgrs) { @@ -2231,13 +2349,14 @@ void wait_for_conference_streams(std::initializer_list<std::reference_wrapper<Co bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref); } - for (const auto &[mMgr, role] : members) { + for (const auto &[mMgr, info] : members) { LinphoneParticipant *p = linphone_conference_is_me(conference, mMgr->identity) ? linphone_conference_get_me(conference) : linphone_conference_find_participant(conference, mMgr->identity); participant_check &= (p != nullptr); if (p) { - participant_check &= (linphone_participant_get_role(p) == role); + participant_check &= + (linphone_participant_get_role(p) == linphone_participant_info_get_role(info)); } } } @@ -2628,10 +2747,14 @@ void create_conference_base(time_t start_time, const char *initialSubject = "Test characters: ^ :) ¤ çà @"; const char *description = "Paris Baker"; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; - participantList.insert(std::make_pair(laure.getCMgr(), LinphoneParticipantRoleListener)); - participantList.insert(std::make_pair(pauline.getCMgr(), LinphoneParticipantRoleSpeaker)); - + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; + participantList.insert( + std::make_pair(laure.getCMgr(), add_participant_info_to_list(&participants_info, laure.getCMgr()->identity, + LinphoneParticipantRoleListener, -1))); + participantList.insert(std::make_pair( + pauline.getCMgr(), add_participant_info_to_list(&participants_info, pauline.getCMgr()->identity, + LinphoneParticipantRoleSpeaker, -1))); LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time, initialSubject, description, TRUE, security_level); BC_ASSERT_PTR_NOT_NULL(confAddr); @@ -2749,21 +2872,8 @@ void create_conference_base(time_t start_time, focus_stat.number_of_participant_devices_joined + 3, liblinphone_tester_sip_timeout)); - std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList; - for (const auto &member : members) { - try { - const auto &participantInfo = participantList.at(member); - memberList.insert(std::make_pair(member, participantInfo)); - } catch (std::out_of_range &) { - if (member == marie.getCMgr()) { - memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker)); - } else { - ms_fatal("Unable to find active participant %s in the participant list", - linphone_core_get_identity(member->lc)); - } - } - } - + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList = + fill_memmber_list(members, participantList, marie.getCMgr(), participants_info); wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(), memberList, confAddr, enable_video); @@ -3764,6 +3874,9 @@ void create_conference_base(time_t start_time, conferenceMgrs.push_back(michelle.getCMgr()); members.push_back(michelle.getCMgr()); + participantList.insert(std::make_pair( + michelle.getCMgr(), add_participant_info_to_list(&participants_info, michelle.getCMgr()->identity, + LinphoneParticipantRoleListener, 0))); extra_participants = 1; @@ -3876,22 +3989,8 @@ void create_conference_base(time_t start_time, liblinphone_tester_sip_timeout)); } - std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList; - for (const auto &member : members) { - try { - const auto &participantInfo = participantList.at(member); - memberList.insert(std::make_pair(member, participantInfo)); - } catch (std::out_of_range &) { - if (member == marie.getCMgr()) { - memberList.insert(std::make_pair(member, LinphoneParticipantRoleSpeaker)); - } else if (member == michelle.getCMgr()) { - memberList.insert(std::make_pair(member, LinphoneParticipantRoleListener)); - } else { - ms_fatal("Unable to find active participant %s in the participant list", - linphone_core_get_identity(member->lc)); - } - } - } + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList = + fill_memmber_list(members, participantList, marie.getCMgr(), participants_info); wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(), memberList, confAddr, enable_video); @@ -4786,6 +4885,7 @@ void create_conference_base(time_t start_time, ms_free(conference_address_str); linphone_address_unref(confAddr); + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); bctbx_list_free(coresList); } } @@ -4847,13 +4947,16 @@ void create_conference_with_late_participant_addition_base(time_t start_time, } time_t end_time = (duration <= 0) ? -1 : (start_time + duration * 60); + int actual_duration = (duration < 0) ? 0 : duration; const char *initialSubject = "Weekly recap"; const char *description = "What happened in the past week"; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : participants) { - participantList.insert(std::make_pair(p, role)); + participantList.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker; } @@ -4870,6 +4973,8 @@ void create_conference_with_late_participant_addition_base(time_t start_time, auto conferenceMgrs = members; conferenceMgrs.push_back(focus.getCMgr()); + update_sequence_number(&participants_info, {}, 0, -1); + if (start_time < 0) { BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallOutgoingInit, marie_stat.number_of_LinphoneCallOutgoingInit + 1, @@ -4889,8 +4994,9 @@ void create_conference_with_late_participant_addition_base(time_t start_time, } } else if (confAddr) { for (auto mgr : members) { - check_conference_info(mgr, confAddr, marie.getCMgr(), participants.size(), start_time, duration, - initialSubject, description, 0, LinphoneConferenceInfoStateNew, security_level); + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, + start_time, actual_duration, initialSubject, description, 0, + LinphoneConferenceInfoStateNew, security_level, FALSE); LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr); linphone_call_params_set_video_direction(new_params, LinphoneMediaDirectionSendRecv); @@ -4937,6 +5043,7 @@ void create_conference_with_late_participant_addition_base(time_t start_time, } } + add_participant_info_to_list(&participants_info, marie.getCMgr()->identity, LinphoneParticipantRoleSpeaker, 0); for (auto mgr : participants) { BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1, liblinphone_tester_sip_timeout)); @@ -4952,8 +5059,9 @@ void create_conference_with_late_participant_addition_base(time_t start_time, BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_NotifyFullStateReceived, 1, liblinphone_tester_sip_timeout)); - check_conference_info(mgr, confAddr, marie.getCMgr(), members.size(), start_time, duration, initialSubject, - description, 0, LinphoneConferenceInfoStateNew, security_level); + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, start_time, + actual_duration, initialSubject, description, 0, LinphoneConferenceInfoStateNew, + security_level, FALSE); LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr); BC_ASSERT_PTR_NOT_NULL(pcall); @@ -4962,31 +5070,7 @@ void create_conference_with_late_participant_addition_base(time_t start_time, BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log)); LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log); if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) { - BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_conference_info_get_organizer(call_log_info), - marie.getCMgr()->identity)); - BC_ASSERT_TRUE( - linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr)); - - const bctbx_list_t *info_participants = - linphone_conference_info_get_participant_infos(call_log_info); - // Original participants + Marie who joined the conference - BC_ASSERT_EQUAL(bctbx_list_size(info_participants), static_cast<int>(members.size()), size_t, - "%zu"); - - if (start_time > 0) { - BC_ASSERT_EQUAL((long long)linphone_conference_info_get_date_time(call_log_info), start_time, - long long, "%lld"); - } - const int duration_m = linphone_conference_info_get_duration(call_log_info); - BC_ASSERT_EQUAL(duration_m, ((duration < 0) ? 0 : duration), int, "%d"); - BC_ASSERT_EQUAL((int)linphone_conference_info_get_security_level(call_log_info), - (int)security_level, int, "%0d"); - if (initialSubject) { - BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_subject(call_log_info), initialSubject); - } else { - BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(call_log_info)); - } - BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description(call_log_info), description); + check_conference_info_against_db(mgr, confAddr, call_log_info); } } } @@ -5032,20 +5116,8 @@ void create_conference_with_late_participant_addition_base(time_t start_time, LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr); BC_ASSERT_PTR_NOT_NULL(fconference); - std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList; - for (const auto &member : members) { - try { - const auto &participantInfo = participantList.at(member); - memberList.insert(std::make_pair(member, participantInfo)); - } catch (std::out_of_range &) { - if (member == marie.getCMgr()) { - memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker)); - } else { - ms_fatal("Unable to find active participant %s in the participant list", - linphone_core_get_identity(member->lc)); - } - } - } + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList = + fill_memmber_list(members, participantList, marie.getCMgr(), participants_info); wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(), memberList, confAddr, TRUE); @@ -5209,6 +5281,8 @@ void create_conference_with_late_participant_addition_base(time_t start_time, int participant_added = ((one_addition) ? 1 : 2); + LinphoneParticipantInfo *berthe_participant_info = add_participant_info_to_list( + &participants_info, berthe.getCMgr()->identity, LinphoneParticipantRoleListener, -1); if (accept) { if (berthe_call) { linphone_call_accept(berthe_call); @@ -5216,7 +5290,8 @@ void create_conference_with_late_participant_addition_base(time_t start_time, conferenceMgrs.push_back(berthe.getCMgr()); members.push_back(berthe.getCMgr()); - memberList.insert(std::make_pair(berthe.getCMgr(), LinphoneParticipantRoleListener)); + participantList.insert(std::make_pair(berthe.getCMgr(), berthe_participant_info)); + memberList.insert(std::make_pair(berthe.getCMgr(), berthe_participant_info)); BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning, focus_stat.number_of_LinphoneCallStreamsRunning + 2, @@ -5245,7 +5320,10 @@ void create_conference_with_late_participant_addition_base(time_t start_time, conferenceMgrs.push_back(michelle.getCMgr()); members.push_back(michelle.getCMgr()); - memberList.insert(std::make_pair(michelle.getCMgr(), LinphoneParticipantRoleListener)); + LinphoneParticipantInfo *participant_info = add_participant_info_to_list( + &participants_info, michelle.getCMgr()->identity, LinphoneParticipantRoleListener, -1); + participantList.insert(std::make_pair(michelle.getCMgr(), participant_info)); + memberList.insert(std::make_pair(michelle.getCMgr(), participant_info)); BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning, focus_stat.number_of_LinphoneCallStreamsRunning + 4, @@ -5523,10 +5601,23 @@ void create_conference_with_late_participant_addition_base(time_t start_time, bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref); } - check_conference_info( - mgr, confAddr, marie.getCMgr(), 5, 0, 0, initialSubject, - ((!one_addition && (mgr == michelle.getCMgr())) || (mgr == berthe.getCMgr())) ? NULL : description, 0, - LinphoneConferenceInfoStateNew, security_level); + bctbx_list_t *participants_info2 = + bctbx_list_copy_with_data(participants_info, (bctbx_list_copy_func)linphone_participant_info_clone); + const char *description2 = NULL; + if ((!one_addition && (mgr == michelle.getCMgr())) || (mgr == berthe.getCMgr())) { + for (bctbx_list_t *it = participants_info2; it; it = bctbx_list_next(it)) { + LinphoneParticipantInfo *participant_info = (LinphoneParticipantInfo *)bctbx_list_get_data(it); + linphone_participant_info_set_sequence_number(participant_info, -1); + } + } else { + description2 = description; + } + + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info2, 0, 0, + initialSubject, description2, 0, LinphoneConferenceInfoStateNew, security_level, + FALSE); + + bctbx_list_free_with_data(participants_info2, (bctbx_list_free_func)linphone_participant_info_unref); } // wait bit more to detect side effect if any @@ -5534,6 +5625,7 @@ void create_conference_with_late_participant_addition_base(time_t start_time, return false; }); + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); linphone_address_unref(confAddr); bctbx_list_free(coresList); } @@ -5598,10 +5690,12 @@ void two_overlapping_conferences_base(bool_t same_organizer, bool_t dialout) { time_t end_time1 = (start_time1 + 600); const char *subject1 = "Colleagues"; const char *description1 = NULL; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList1; + bctbx_list_t *participants_info1 = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList1; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : participants1) { - participantList1.insert(std::make_pair(p, role)); + participantList1.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info1, p->identity, role, -1))); role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker; } @@ -5756,11 +5850,13 @@ void two_overlapping_conferences_base(bool_t same_organizer, bool_t dialout) { mgr_in_conf2.push_back(marie.getCMgr()); } } - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList2; + bctbx_list_t *participants_info2 = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList2; for (auto &p : participants2) { role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker; - participantList2.insert(std::make_pair(p, role)); + participantList2.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info2, p->identity, role, -1))); } LinphoneAddress *confAddr2 = @@ -6432,6 +6528,8 @@ void two_overlapping_conferences_base(bool_t same_organizer, bool_t dialout) { // wait bit more to detect side effect if any CoreManagerAssert({focus, marie, pauline, laure, michelle}).waitUntil(chrono::seconds(2), [] { return false; }); + bctbx_list_free_with_data(participants_info1, (bctbx_list_free_func)linphone_participant_info_unref); + bctbx_list_free_with_data(participants_info2, (bctbx_list_free_func)linphone_participant_info_unref); ms_free(conference1_address_str); ms_free(conference2_address_str); linphone_address_unref(focusUri); @@ -6492,10 +6590,12 @@ void create_one_participant_conference_toggle_video_base(LinphoneConferenceLayou const char *description = "- <F2><F3>\n\\çà "; LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : participants) { - participantList.insert(std::make_pair(p, role)); + participantList.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker; } @@ -7119,6 +7219,7 @@ void create_one_participant_conference_toggle_video_base(LinphoneConferenceLayou } } + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); linphone_address_unref(confAddr); bctbx_list_free(coresList); } @@ -7167,10 +7268,12 @@ void create_conference_with_active_call_base(bool_t dialout) { time_t start_time = (dialout) ? -1 : (ms_time(NULL) + 10); bool_t send_ics = TRUE; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : participants) { - participantList.insert(std::make_pair(p, role)); + participantList.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); if (role == LinphoneParticipantRoleSpeaker) { role = LinphoneParticipantRoleListener; } else if (role == LinphoneParticipantRoleListener) { @@ -7179,12 +7282,15 @@ void create_conference_with_active_call_base(bool_t dialout) { role = LinphoneParticipantRoleSpeaker; } } - participantList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleListener)); + participantList.insert( + std::make_pair(marie.getCMgr(), add_participant_info_to_list(&participants_info, marie.getCMgr()->identity, + LinphoneParticipantRoleListener, -1))); + LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, -1, initialSubject, description, send_ics, security_level); BC_ASSERT_PTR_NOT_NULL(confAddr); - // the conference server calls Berthe - who knows why...... + // Berthe calls the conference server - who knows why...... LinphoneCallParams *new_params = linphone_core_create_call_params(berthe.getLc(), NULL); LinphoneContent *content = linphone_core_create_content(berthe.getLc()); @@ -7227,12 +7333,15 @@ void create_conference_with_active_call_base(bool_t dialout) { } BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived, - focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 1, 5000)); + focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 1, + liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionTerminated, - focus_stat.number_of_LinphoneSubscriptionTerminated + 1, 5000)); - BC_ASSERT_TRUE( - wait_for_list(coresList, &berthe.getStats().number_of_LinphoneSubscriptionOutgoingProgress, 1, 5000)); - BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneSubscriptionError, 1, 5000)); + focus_stat.number_of_LinphoneSubscriptionTerminated + 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneSubscriptionOutgoingProgress, 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneSubscriptionError, 1, + liblinphone_tester_sip_timeout)); if (dialout) { // Chat room creation to send ICS BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, @@ -7301,6 +7410,19 @@ void create_conference_with_active_call_base(bool_t dialout) { } linphone_call_params_unref(new_params); + if (!dialout) { + add_participant_info_to_list(&participants_info, berthe.getCMgr()->identity, + LinphoneParticipantRoleListener, -1); + } + + update_sequence_number(&participants_info, {berthe.getCMgr()->identity}, 0, -1); + for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) { + LinphoneParticipantInfo *participant_info_el = (LinphoneParticipantInfo *)bctbx_list_get_data(info_it); + if (linphone_participant_info_get_role(participant_info_el) == LinphoneParticipantRoleUnknown) { + linphone_participant_info_set_role(participant_info_el, LinphoneParticipantRoleSpeaker); + } + } + for (auto mgr : participants) { BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1, liblinphone_tester_sip_timeout)); @@ -7309,14 +7431,20 @@ void create_conference_with_active_call_base(bool_t dialout) { BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated, 1, liblinphone_tester_sip_timeout)); - BC_ASSERT_TRUE( - wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1, 5000)); - BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1, 5000)); + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1, + liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_NotifyFullStateReceived, 1, liblinphone_tester_sip_timeout)); - check_conference_info(mgr, confAddr, marie.getCMgr(), 4, 0, 0, initialSubject, - (send_ics) ? description : NULL, 0, LinphoneConferenceInfoStateNew, security_level); + if (!dialout) { + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_participant_devices_added, 1, + liblinphone_tester_sip_timeout)); + } + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, 0, 0, + initialSubject, (send_ics) ? description : NULL, 0, + LinphoneConferenceInfoStateNew, security_level, FALSE); LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr); BC_ASSERT_PTR_NOT_NULL(pcall); @@ -7325,31 +7453,7 @@ void create_conference_with_active_call_base(bool_t dialout) { BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log)); LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log); if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) { - BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_conference_info_get_organizer(call_log_info), - marie.getCMgr()->identity)); - BC_ASSERT_TRUE( - linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr)); - - const bctbx_list_t *info_participants = - linphone_conference_info_get_participant_infos(call_log_info); - // Original participants + Marie who joined the conference - BC_ASSERT_EQUAL(bctbx_list_size(info_participants), 4, size_t, "%zu"); - BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(call_log_info), 0, - long long, "%lld"); - const int duration_m = linphone_conference_info_get_duration(call_log_info); - BC_ASSERT_EQUAL(duration_m, 0, int, "%d"); - BC_ASSERT_EQUAL((int)linphone_conference_info_get_security_level(call_log_info), - (int)security_level, int, "%0d"); - if (initialSubject) { - BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_subject(call_log_info), initialSubject); - } else { - BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(call_log_info)); - } - if (send_ics) { - BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description(call_log_info), description); - } else { - BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(call_log_info)); - } + check_conference_info_against_db(mgr, confAddr, call_log_info); } } } @@ -7377,13 +7481,15 @@ void create_conference_with_active_call_base(bool_t dialout) { BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive, focus_stat.number_of_LinphoneSubscriptionActive + 4, 5000)); + int no_participants = (dialout) ? 4 : 5; BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added, - focus_stat.number_of_participants_added + 4, liblinphone_tester_sip_timeout)); + focus_stat.number_of_participants_added + no_participants, + liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added, - focus_stat.number_of_participant_devices_added + 4, + focus_stat.number_of_participant_devices_added + no_participants, liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined, - focus_stat.number_of_participant_devices_joined + 4, + focus_stat.number_of_participant_devices_joined + no_participants, liblinphone_tester_sip_timeout)); LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr); @@ -7452,19 +7558,35 @@ void create_conference_with_active_call_base(bool_t dialout) { } bool role_check = true; - for (auto m : participantList) { - LinphoneCoreManager *mMgr = m.first; - LinphoneParticipantRole role = m.second; + for (const auto &[mMgr, info] : participantList) { LinphoneParticipant *p = linphone_conference_is_me(conference, mMgr->identity) ? linphone_conference_get_me(conference) : linphone_conference_find_participant(conference, mMgr->identity); role_check &= (p != nullptr); if (p) { - role_check &= (linphone_participant_get_role(p) == role); + role_check &= + (linphone_participant_get_role(p) == linphone_participant_info_get_role(info)); } } return role_check; }); + + if (mgr != focus.getCMgr()) { + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, 0, 0, + initialSubject, (send_ics) ? description : NULL, 0, + LinphoneConferenceInfoStateNew, security_level, FALSE); + + LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr); + BC_ASSERT_PTR_NOT_NULL(pcall); + if (pcall) { + LinphoneCallLog *call_log = linphone_call_get_call_log(pcall); + BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log)); + LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log); + if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) { + check_conference_info_against_db(mgr, confAddr, call_log_info); + } + } + } } // wait bit more to detect side effect if any @@ -7690,35 +7812,17 @@ void create_conference_with_active_call_base(bool_t dialout) { for (bctbx_list_t *it = mgr_focus_call_log; it; it = bctbx_list_next(it)) { LinphoneCallLog *call_log = (LinphoneCallLog *)it->data; BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log)); + LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log); + if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) { + check_conference_info_against_db(mgr, confAddr, call_log_info); + } } bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref); } - LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(mgr->lc, confAddr); - if (BC_ASSERT_PTR_NOT_NULL(info)) { - BC_ASSERT_TRUE(linphone_address_weak_equal(marie.getCMgr()->identity, - linphone_conference_info_get_organizer(info))); - BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, linphone_conference_info_get_uri(info))); - - const bctbx_list_t *info_participants = linphone_conference_info_get_participant_infos(info); - // Original participants + Marie who joined the conference - BC_ASSERT_EQUAL(bctbx_list_size(info_participants), (dialout) ? 4 : 5, size_t, "%zu"); - - BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(info), 0, long long, "%lld"); - const int duration_m = linphone_conference_info_get_duration(info); - BC_ASSERT_EQUAL(duration_m, 0, int, "%d"); - if (initialSubject) { - BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_subject(info), initialSubject); - } else { - BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(info)); - } - if (send_ics || (mgr == marie.getCMgr())) { - BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description(info), description); - } else { - BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(info)); - } - linphone_conference_info_unref(info); - } + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, start_time, + 0, initialSubject, (send_ics || (mgr == marie.getCMgr())) ? description : NULL, + 0, LinphoneConferenceInfoStateNew, security_level, FALSE); } // wait bit more to detect side effect if any @@ -7726,6 +7830,7 @@ void create_conference_with_active_call_base(bool_t dialout) { return false; }); + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); linphone_address_unref(confAddr); bctbx_list_free(coresList); } @@ -7808,9 +7913,11 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice, linphone_conference_params_unref(conf_params); BC_ASSERT_PTR_NOT_NULL(conf); + bctbx_list_t *participants_info = NULL; std::list<stats> participant_stats; for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) { participant_stats.push_back(mgr->stat); + add_participant_info_to_list(&participants_info, mgr->identity, LinphoneParticipantRoleSpeaker, -1); } if (conf) { @@ -7921,8 +8028,9 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice, } if (confAddr) { - check_conference_info(mgr, confAddr, marie.getCMgr(), 3, 0, 0, initialSubject, NULL, 0, - LinphoneConferenceInfoStateNew, security_level); + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, 0, 0, + initialSubject, NULL, 0, LinphoneConferenceInfoStateNew, security_level, + FALSE); } } @@ -7952,8 +8060,8 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice, BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_subject_changed, old_stats.number_of_subject_changed + 1, liblinphone_tester_sip_timeout)); if (confAddr) { - check_conference_info(mgr, confAddr, marie.getCMgr(), 3, 0, 0, newSubject, NULL, 0, - LinphoneConferenceInfoStateNew, security_level); + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, 0, 0, + newSubject, NULL, 0, LinphoneConferenceInfoStateNew, security_level, FALSE); } participant_stats.pop_front(); } @@ -8128,8 +8236,8 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice, } if (confAddr) { - check_conference_info(mgr, confAddr, marie.getCMgr(), 3, 0, 0, newSubject, NULL, 0, - LinphoneConferenceInfoStateNew, security_level); + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, 0, 0, + newSubject, NULL, 0, LinphoneConferenceInfoStateNew, security_level, FALSE); } } @@ -8273,6 +8381,7 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice, LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc)); LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), uri); + linphone_address_unref(uri); BC_ASSERT_PTR_NOT_NULL(ccall); if (ccall) { const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall); @@ -8363,6 +8472,7 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice, } } + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); linphone_conference_unref(conf); linphone_address_unref(confAddr); bctbx_list_free(coresList); diff --git a/tester/local_conference_tester_functions.h b/tester/local_conference_tester_functions.h index bdce9c14cd..fd01e888a0 100644 --- a/tester/local_conference_tester_functions.h +++ b/tester/local_conference_tester_functions.h @@ -385,7 +385,7 @@ void create_conference_base(time_t start_time, void wait_for_conference_streams(std::initializer_list<std::reference_wrapper<CoreManager>> coreMgrs, std::list<LinphoneCoreManager *> conferenceMgrs, LinphoneCoreManager *focus, - std::map<LinphoneCoreManager *, LinphoneParticipantRole> members, + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> members, const LinphoneAddress *confAddr, bool_t enable_video); @@ -408,7 +408,7 @@ void create_conference_with_active_call_base(bool_t dialout); LinphoneAddress * create_conference_on_server(Focus &focus, ClientConference &organizer, - std::map<LinphoneCoreManager *, LinphoneParticipantRole> requested_participants, + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> requested_participants, time_t start_time, time_t end_time, const char *subject, @@ -427,17 +427,47 @@ void set_video_settings_in_conference(LinphoneCoreManager *focus, size_t compute_no_video_streams(bool_t enable_video, LinphoneCall *call, LinphoneConference *conference); -void check_conference_info(LinphoneCoreManager *mgr, - LinphoneAddress *confAddr, - LinphoneCoreManager *organizer, - size_t no_members, - long long start_time, - int duration, - const char *subject, - const char *description, - unsigned int sequence, - LinphoneConferenceInfoState state, - LinphoneConferenceSecurityLevel security_level); +std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> +fill_memmber_list(std::list<LinphoneCoreManager *> members, + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList, + LinphoneCoreManager *organizer, + bctbx_list_t *participants_info); + +void check_conference_info_against_db(LinphoneCoreManager *mgr, + LinphoneAddress *confAddr, + const LinphoneConferenceInfo *info1); + +void check_conference_info_in_db(LinphoneCoreManager *mgr, + const char *uid, + LinphoneAddress *confAddr, + LinphoneAddress *organizer, + bctbx_list_t *participantList, + long long start_time, + int duration, + const char *subject, + const char *description, + unsigned int sequence, + LinphoneConferenceInfoState state, + LinphoneConferenceSecurityLevel security_level, + bool_t skip_participant_info); + +void check_conference_info_members(const LinphoneConferenceInfo *info, + const char *uid, + LinphoneAddress *confAddr, + LinphoneAddress *organizer, + bctbx_list_t *participantList, + long long start_time, + int duration, + const char *subject, + const char *description, + unsigned int sequence, + LinphoneConferenceInfoState state, + LinphoneConferenceSecurityLevel security_level, + bool_t skip_participant_info); + +void compare_conference_infos(const LinphoneConferenceInfo *info1, + const LinphoneConferenceInfo *info2, + bool_t skip_participant_info); size_t compute_no_audio_streams(LinphoneCall *call, LinphoneConference *conference); @@ -446,6 +476,15 @@ void conference_scheduler_state_changed(LinphoneConferenceScheduler *scheduler, void conference_scheduler_invitations_sent(LinphoneConferenceScheduler *scheduler, const bctbx_list_t *failed_addresses); +void update_sequence_number(bctbx_list_t **participants_info, + const std::list<LinphoneAddress *> new_participants, + int exp_sequence, + int exp_new_participant_sequence); +int find_matching_participant_info(const LinphoneParticipantInfo *info1, const LinphoneParticipantInfo *info2); +LinphoneParticipantInfo *add_participant_info_to_list(bctbx_list_t **participants_info, + const LinphoneAddress *address, + LinphoneParticipantRole role, + int sequence); } // namespace LinphoneTest #endif // LOCAL_CONFERENCE_TESTER_FUNCTIONS_H_ diff --git a/tester/local_ice_conference_tester.cpp b/tester/local_ice_conference_tester.cpp index e6fb8998ae..4e4f63925b 100644 --- a/tester/local_ice_conference_tester.cpp +++ b/tester/local_ice_conference_tester.cpp @@ -132,10 +132,14 @@ static void abort_call_to_ice_conference(void) { stats focus_stat = focus.getStats(); - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; + bctbx_list_t *participant_infos = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : participants) { - participantList.insert(std::make_pair(p, role)); + LinphoneParticipantInfo *participant_info = linphone_participant_info_new(p->identity); + linphone_participant_info_set_role(participant_info, role); + participant_infos = bctbx_list_append(participant_infos, participant_info); + participantList.insert(std::make_pair(p, participant_info)); role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker; } @@ -447,6 +451,7 @@ static void abort_call_to_ice_conference(void) { // wait bit more to detect side effect if any CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; }); + bctbx_list_free_with_data(participant_infos, (bctbx_list_free_func)linphone_participant_info_unref); linphone_address_unref(confAddr); bctbx_list_free(coresList); } @@ -475,10 +480,9 @@ static test_t local_conference_scheduled_ice_conference_tests[] = { TEST_ONE_TAG("Create simple end-to-end encrypted ICE conference", LinphoneTest::create_simple_end_to_end_encrypted_ice_conference, "ICE"), - TEST_TWO_TAGS("Create simple ICE conference by merging calls", - LinphoneTest::create_simple_ice_conference_merging_calls, - "LeaksMemory", - "ICE"), /* because of aborted calls*/ + TEST_ONE_TAG("Create simple ICE conference by merging calls", + LinphoneTest::create_simple_ice_conference_merging_calls, + "ICE"), /* because of aborted calls*/ TEST_TWO_TAGS("Abort call to ICE conference", LinphoneTest::abort_call_to_ice_conference, "LeaksMemory", diff --git a/tester/local_inpromptu_conference_tester.cpp b/tester/local_inpromptu_conference_tester.cpp index 9b70e97c58..0968969839 100644 --- a/tester/local_inpromptu_conference_tester.cpp +++ b/tester/local_inpromptu_conference_tester.cpp @@ -99,10 +99,12 @@ static void create_conference_dial_out_base(bool_t send_ics, const char *initialSubject = "Schedule of the trip towards the top of Europe"; const char *description = "To the top of the Mont Blanc!!!! :-)"; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; - LinphoneParticipantRole role = LinphoneParticipantRoleUnknown; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; + LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : participants) { - participantList.insert(std::make_pair(p, role)); + participantList.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); if (role == LinphoneParticipantRoleSpeaker) { role = LinphoneParticipantRoleListener; } else if (role == LinphoneParticipantRoleListener) { @@ -214,12 +216,37 @@ static void create_conference_dial_out_base(bool_t send_ics, } } + bctbx_list_t *participants_info2 = NULL; + for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) { + const LinphoneParticipantInfo *participant_info_el = + (LinphoneParticipantInfo *)bctbx_list_get_data(info_it); + const LinphoneAddress *address = linphone_participant_info_get_address(participant_info_el); + const int sequence = (send_ics) ? 0 : -1; + LinphoneParticipantRole role = LinphoneParticipantRoleUnknown; + LinphoneParticipantRole current_role = linphone_participant_info_get_role(participant_info_el); + if (send_ics) { + if (current_role == LinphoneParticipantRoleUnknown) { + role = LinphoneParticipantRoleSpeaker; + } else { + role = current_role; + } + } else { + role = LinphoneParticipantRoleUnknown; + } + add_participant_info_to_list(&participants_info2, address, role, sequence); + } + + if (!send_ics) { + add_participant_info_to_list(&participants_info2, marie.getCMgr()->identity, LinphoneParticipantRoleUnknown, + -1); + } + if (confAddr) { for (auto mgr : participants) { - // Encryption is None because we haven't received yet the NOTIFY full stae with this information - check_conference_info(mgr, confAddr, marie.getCMgr(), (send_ics) ? 4 : 5, 0, 0, initialSubject, - (accept && send_ics) ? description : NULL, 0, LinphoneConferenceInfoStateNew, - LinphoneConferenceSecurityLevelNone); + // Encryption is None because we haven't received yet the NOTIFY full state yet + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info2, 0, 0, + initialSubject, (accept && send_ics) ? description : NULL, 0, + LinphoneConferenceInfoStateNew, LinphoneConferenceSecurityLevelNone, FALSE); LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr); BC_ASSERT_PTR_NOT_NULL(pcall); @@ -235,10 +262,37 @@ static void create_conference_dial_out_base(bool_t send_ics, } } - int participant_conference_info_participants = 5; + bctbx_list_free_with_data(participants_info2, (bctbx_list_free_func)linphone_participant_info_unref); + + add_participant_info_to_list(&participants_info, marie.getCMgr()->identity, LinphoneParticipantRoleSpeaker, + (send_ics) ? 0 : -1); + if (accept) { + update_sequence_number(&participants_info, {}, (send_ics) ? 0 : -1, -1); + int participant_no = static_cast<int>(participants.size()); for (auto mgr : participants) { + + bctbx_list_t *participants_info3 = NULL; + for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) { + const LinphoneParticipantInfo *participant_info_el = + (LinphoneParticipantInfo *)bctbx_list_get_data(info_it); + const LinphoneAddress *address = linphone_participant_info_get_address(participant_info_el); + const int sequence = linphone_participant_info_get_sequence_number(participant_info_el); + bool found = false; + for (const auto &mgr : codec_mismatch_members) { + found |= !!linphone_address_weak_equal(address, mgr->identity); + } + LinphoneParticipantRole role = LinphoneParticipantRoleUnknown; + LinphoneParticipantRole current_role = linphone_participant_info_get_role(participant_info_el); + if (!found && (current_role == LinphoneParticipantRoleUnknown)) { + role = LinphoneParticipantRoleSpeaker; + } else { + role = current_role; + } + add_participant_info_to_list(&participants_info3, address, role, sequence); + } + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1, liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated, 1, @@ -249,9 +303,9 @@ static void create_conference_dial_out_base(bool_t send_ics, liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_NotifyFullStateReceived, 1, liblinphone_tester_sip_timeout)); - check_conference_info(mgr, confAddr, marie.getCMgr(), participant_conference_info_participants, 0, 0, - initialSubject, (send_ics) ? description : NULL, 0, - LinphoneConferenceInfoStateNew, security_level); + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info3, 0, 0, + initialSubject, (send_ics) ? description : NULL, 0, + LinphoneConferenceInfoStateNew, security_level, FALSE); LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr); BC_ASSERT_PTR_NOT_NULL(pcall); if (pcall) { @@ -259,32 +313,10 @@ static void create_conference_dial_out_base(bool_t send_ics, BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log)); LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log); if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) { - BC_ASSERT_TRUE(linphone_address_weak_equal( - linphone_conference_info_get_organizer(call_log_info), marie.getCMgr()->identity)); - BC_ASSERT_TRUE( - linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr)); - const bctbx_list_t *info_participants = - linphone_conference_info_get_participant_infos(call_log_info); - // Original participants + Marie who joined the conference - BC_ASSERT_EQUAL(bctbx_list_size(info_participants), participant_conference_info_participants, - size_t, "%zu"); - BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(call_log_info), 0, - long long, "%lld"); - const int duration_m = linphone_conference_info_get_duration(call_log_info); - BC_ASSERT_EQUAL(duration_m, 0, int, "%d"); - if (initialSubject) { - BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_subject(call_log_info), initialSubject); - } else { - BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(call_log_info)); - } - if (send_ics) { - BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description(call_log_info), - description); - } else { - BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(call_log_info)); - } + check_conference_info_against_db(mgr, confAddr, call_log_info); } } + bctbx_list_free_with_data(participants_info3, (bctbx_list_free_func)linphone_participant_info_unref); } if (enable_ice) { @@ -334,24 +366,8 @@ static void create_conference_dial_out_base(bool_t send_ics, LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr); BC_ASSERT_PTR_NOT_NULL(fconference); - std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList; - for (const auto &member : members) { - try { - const auto &participantInfo = participantList.at(member); - auto role = participantInfo; - if (role == LinphoneParticipantRoleUnknown) { - role = LinphoneParticipantRoleSpeaker; - } - memberList.insert(std::make_pair(member, role)); - } catch (std::out_of_range &) { - if (member == marie.getCMgr()) { - memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker)); - } else { - ms_fatal("Unable to find active participant %s in the participant list", - linphone_core_get_identity(member->lc)); - } - } - } + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList = + fill_memmber_list(members, participantList, marie.getCMgr(), participants_info); wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(), memberList, confAddr, enable_video); @@ -378,11 +394,34 @@ static void create_conference_dial_out_base(bool_t send_ics, no_participants = static_cast<int>(members.size()); BC_ASSERT_FALSE(linphone_conference_is_in(pconference)); } else { + bctbx_list_t *participants_info3 = NULL; + for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) { + const LinphoneParticipantInfo *participant_info_el = + (LinphoneParticipantInfo *)bctbx_list_get_data(info_it); + const LinphoneAddress *address = linphone_participant_info_get_address(participant_info_el); + const int sequence = linphone_participant_info_get_sequence_number(participant_info_el); + bool found = false; + for (const auto &mgr : codec_mismatch_members) { + found |= !!linphone_address_weak_equal(address, mgr->identity); + } + LinphoneParticipantRole role = LinphoneParticipantRoleUnknown; + LinphoneParticipantRole current_role = + linphone_participant_info_get_role(participant_info_el); + if (((mgr == marie.getCMgr()) || !found) && + (current_role == LinphoneParticipantRoleUnknown)) { + role = LinphoneParticipantRoleSpeaker; + } else { + role = current_role; + } + add_participant_info_to_list(&participants_info3, address, role, sequence); + } - check_conference_info(mgr, confAddr, marie.getCMgr(), participant_conference_info_participants, - 0, 0, initialSubject, - (send_ics || (mgr == marie.getCMgr())) ? description : NULL, 0, - LinphoneConferenceInfoStateNew, security_level); + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info3, + 0, 0, initialSubject, + (send_ics || (mgr == marie.getCMgr())) ? description : NULL, 0, + LinphoneConferenceInfoStateNew, security_level, FALSE); + bctbx_list_free_with_data(participants_info3, + (bctbx_list_free_func)linphone_participant_info_unref); no_participants = participant_no; BC_ASSERT_TRUE(linphone_conference_is_in(pconference)); @@ -406,10 +445,9 @@ static void create_conference_dial_out_base(bool_t send_ics, linphone_video_activation_policy_unref(pol); size_t no_streams_audio = 0; - size_t no_max_streams_audio = - (security_level == LinphoneConferenceSecurityLevelEndToEnd) - ? static_cast<size_t>(participant_conference_info_participants) - : 1; + size_t no_max_streams_audio = (security_level == LinphoneConferenceSecurityLevelEndToEnd) + ? bctbx_list_size(participants_info) + : 1; size_t no_max_streams_video = (enabled || (mgr == marie.getCMgr())) ? ((security_level == LinphoneConferenceSecurityLevelEndToEnd) ? 2 * (participants.size() + 1) @@ -442,36 +480,7 @@ static void create_conference_dial_out_base(bool_t send_ics, BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log)); LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log); if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) { - BC_ASSERT_TRUE(linphone_address_weak_equal( - linphone_conference_info_get_organizer(call_log_info), marie.getCMgr()->identity)); - BC_ASSERT_TRUE(linphone_address_weak_equal( - linphone_conference_info_get_uri(call_log_info), confAddr)); - - const bctbx_list_t *info_participants = - linphone_conference_info_get_participant_infos(call_log_info); - // Original participants + Marie who joined the conference - BC_ASSERT_EQUAL(bctbx_list_size(info_participants), - participant_conference_info_participants, size_t, "%zu"); - - BC_ASSERT_GREATER_STRICT( - (long long)linphone_conference_info_get_date_time(call_log_info), 0, long long, - "%lld"); - const int duration_m = linphone_conference_info_get_duration(call_log_info); - BC_ASSERT_EQUAL(duration_m, 0, int, "%d"); - BC_ASSERT_EQUAL((int)linphone_conference_info_get_security_level(call_log_info), - (int)security_level, int, "%0d"); - if (initialSubject) { - BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_subject(call_log_info), - initialSubject); - } else { - BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(call_log_info)); - } - if (send_ics || (mgr == marie.getCMgr())) { - BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description(call_log_info), - description); - } else { - BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(call_log_info)); - } + check_conference_info_against_db(mgr, confAddr, call_log_info); } } @@ -777,14 +786,41 @@ static void create_conference_dial_out_base(bool_t send_ics, BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(mgr_focus_call_log), 1, unsigned int, "%u"); for (bctbx_list_t *it = mgr_focus_call_log; it; it = bctbx_list_next(it)) { LinphoneCallLog *call_log = (LinphoneCallLog *)it->data; + LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log); + if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) { + check_conference_info_against_db(mgr, confAddr, call_log_info); + } BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log)); } bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref); } - check_conference_info( - mgr, confAddr, marie.getCMgr(), participant_conference_info_participants, 0, 0, initialSubject, + + bctbx_list_t *participants_info3 = NULL; + for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) { + const LinphoneParticipantInfo *participant_info_el = + (LinphoneParticipantInfo *)bctbx_list_get_data(info_it); + const LinphoneAddress *address = linphone_participant_info_get_address(participant_info_el); + const int sequence = linphone_participant_info_get_sequence_number(participant_info_el); + bool found = false; + for (const auto &mgr : codec_mismatch_members) { + found |= !!linphone_address_weak_equal(address, mgr->identity); + } + LinphoneParticipantRole role = LinphoneParticipantRoleUnknown; + LinphoneParticipantRole current_role = linphone_participant_info_get_role(participant_info_el); + if ((mgr != marie.getCMgr()) && !accept) { + role = LinphoneParticipantRoleUnknown; + } else if (((mgr == marie.getCMgr()) || !found) && (current_role == LinphoneParticipantRoleUnknown)) { + role = LinphoneParticipantRoleSpeaker; + } else { + role = current_role; + } + add_participant_info_to_list(&participants_info3, address, role, sequence); + } + check_conference_info_in_db( + mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info3, 0, 0, initialSubject, ((accept && send_ics) || (mgr == marie.getCMgr())) ? description : NULL, 0, - LinphoneConferenceInfoStateNew, (accept) ? security_level : LinphoneConferenceSecurityLevelNone); + LinphoneConferenceInfoStateNew, (accept) ? security_level : LinphoneConferenceSecurityLevelNone, FALSE); + bctbx_list_free_with_data(participants_info3, (bctbx_list_free_func)linphone_participant_info_unref); } // wait bit more to detect side effect if any @@ -792,6 +828,7 @@ static void create_conference_dial_out_base(bool_t send_ics, return false; }); + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); linphone_address_unref(confAddr); bctbx_list_free(coresList); } @@ -934,10 +971,12 @@ static void create_simple_conference_dial_out_organizer_codec_mismatch(void) { const char *description = "To the Goutier mountain hut!!!! :-)"; LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : participants) { - participantList.insert(std::make_pair(p, role)); + participantList.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker; } @@ -957,6 +996,7 @@ static void create_simple_conference_dial_out_organizer_codec_mismatch(void) { LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr); BC_ASSERT_PTR_NULL(fconference); + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); if (confAddr) linphone_address_unref(confAddr); bctbx_list_free(coresList); } @@ -1027,10 +1067,12 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp const char *description = "Having fun!!!! :-)"; LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : participants) { - participantList.insert(std::make_pair(p, role)); + participantList.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker; } @@ -1093,9 +1135,21 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp } if (confAddr) { + add_participant_info_to_list(&participants_info, marie.getCMgr()->identity, LinphoneParticipantRoleSpeaker, + -1); for (auto mgr : participants) { - check_conference_info(mgr, confAddr, marie.getCMgr(), 5, 0, 0, initialSubject, NULL, 0, - LinphoneConferenceInfoStateNew, security_level); + bctbx_list_t *participants_info2 = NULL; + for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) { + LinphoneParticipantInfo *participant_info_el = + (LinphoneParticipantInfo *)bctbx_list_get_data(info_it); + LinphoneParticipantRole role = LinphoneParticipantRoleUnknown; + const LinphoneAddress *address = linphone_participant_info_get_address(participant_info_el); + add_participant_info_to_list(&participants_info2, address, role, -1); + } + + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info2, 0, 0, + initialSubject, NULL, 0, LinphoneConferenceInfoStateNew, security_level, + FALSE); LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr); BC_ASSERT_PTR_NOT_NULL(pcall); @@ -1109,6 +1163,8 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp linphone_call_decline(pcall, reason); } } + + bctbx_list_free_with_data(participants_info2, (bctbx_list_free_func)linphone_participant_info_unref); } } @@ -1125,11 +1181,11 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1, liblinphone_tester_sip_timeout)); - BC_ASSERT_TRUE( - wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_NotifyFullStateReceived, 1, + liblinphone_tester_sip_timeout)); - check_conference_info(mgr, confAddr, marie.getCMgr(), 5, 0, 0, initialSubject, NULL, 0, - LinphoneConferenceInfoStateNew, security_level); + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, 0, 0, + initialSubject, NULL, 0, LinphoneConferenceInfoStateNew, security_level, TRUE); LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr); BC_ASSERT_PTR_NOT_NULL(pcall); @@ -1138,28 +1194,7 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log)); LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log); if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) { - BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_conference_info_get_organizer(call_log_info), - marie.getCMgr()->identity)); - BC_ASSERT_TRUE( - linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr)); - - const bctbx_list_t *info_participants = - linphone_conference_info_get_participant_infos(call_log_info); - // Original participants + Marie who joined the conference - BC_ASSERT_EQUAL(bctbx_list_size(info_participants), 5, size_t, "%zu"); - - BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(call_log_info), 0, - long long, "%lld"); - const int duration_m = linphone_conference_info_get_duration(call_log_info); - BC_ASSERT_EQUAL(duration_m, 0, int, "%d"); - BC_ASSERT_EQUAL((int)linphone_conference_info_get_security_level(call_log_info), - (int)security_level, int, "%0d"); - if (initialSubject) { - BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_subject(call_log_info), initialSubject); - } else { - BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(call_log_info)); - } - BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(call_log_info)); + check_conference_info_against_db(mgr, confAddr, call_log_info); } } } @@ -1241,20 +1276,8 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr); BC_ASSERT_PTR_NOT_NULL(fconference); - std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList; - for (const auto &member : all_active_participants) { - try { - const auto &participantInfo = participantList.at(member); - memberList.insert(std::make_pair(member, participantInfo)); - } catch (std::out_of_range &) { - if (member == marie.getCMgr()) { - memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker)); - } else { - ms_fatal("Unable to find active participant %s in the participant list", - linphone_core_get_identity(member->lc)); - } - } - } + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList = + fill_memmber_list(all_active_participants, participantList, marie.getCMgr(), participants_info); wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conference_members, focus.getCMgr(), memberList, confAddr, TRUE); @@ -1369,6 +1392,23 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp if (devices) { bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref); } + + if (mgr != focus.getCMgr()) { + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, 0, 0, + initialSubject, NULL, 0, LinphoneConferenceInfoStateNew, security_level, + TRUE); + + LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr); + BC_ASSERT_PTR_NOT_NULL(pcall); + if (pcall) { + LinphoneCallLog *call_log = linphone_call_get_call_log(pcall); + BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log)); + LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log); + if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) { + check_conference_info_against_db(mgr, confAddr, call_log_info); + } + } + } } } @@ -1528,12 +1568,45 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp for (bctbx_list_t *it = mgr_focus_call_log; it; it = bctbx_list_next(it)) { LinphoneCallLog *call_log = (LinphoneCallLog *)it->data; BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log)); + LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log); + if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) { + check_conference_info_against_db(mgr, confAddr, call_log_info); + } } bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref); } - check_conference_info(mgr, confAddr, marie.getCMgr(), 5, 0, 0, initialSubject, - (mgr == marie.getCMgr()) ? description : NULL, 0, LinphoneConferenceInfoStateNew, - security_level); + + bool mgr_declining_call = false; + for (auto declining_mgr : declining_participants) { + mgr_declining_call |= !!linphone_address_weak_equal(mgr->identity, declining_mgr->identity); + } + + bctbx_list_t *participants_info2 = NULL; + for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) { + LinphoneParticipantInfo *participant_info_el = (LinphoneParticipantInfo *)bctbx_list_get_data(info_it); + const LinphoneAddress *address = linphone_participant_info_get_address(participant_info_el); + bool declining_call = false; + for (auto declining_mgr : declining_participants) { + declining_call |= !!linphone_address_weak_equal(address, declining_mgr->identity); + } + + LinphoneParticipantRole role = LinphoneParticipantRoleUnknown; + int sequence = -1; + if (mgr_declining_call || (declining_call && (mgr != marie.getCMgr()))) { + role = LinphoneParticipantRoleUnknown; + sequence = -1; + } else { + role = linphone_participant_info_get_role(participant_info_el); + sequence = linphone_participant_info_get_sequence_number(participant_info_el); + } + add_participant_info_to_list(&participants_info2, address, role, sequence); + } + check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info2, 0, 0, + initialSubject, (mgr == marie.getCMgr()) ? description : NULL, 0, + LinphoneConferenceInfoStateNew, security_level, + !((mgr == marie.getCMgr()) || mgr_declining_call)); + + bctbx_list_free_with_data(participants_info2, (bctbx_list_free_func)linphone_participant_info_unref); } // wait bit more to detect side effect if any @@ -1541,6 +1614,7 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp return false; }); + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); linphone_address_unref(confAddr); bctbx_list_free(coresList); } @@ -1627,10 +1701,12 @@ static void simple_dial_out_conference_with_no_payloads(void) { const char *description = "To the top of the Mont Blanc!!!! :-)"; LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : participants) { - participantList.insert(std::make_pair(p, role)); + participantList.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker; } @@ -1768,6 +1844,7 @@ static void simple_dial_out_conference_with_no_payloads(void) { BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1, liblinphone_tester_sip_timeout)); + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); linphone_address_unref(confAddr); bctbx_list_free(coresList); } @@ -1788,9 +1865,8 @@ static test_t local_conference_inpromptu_conference_tests[] = { TEST_NO_TAG("Create simple dial out conference with many late participant additions", LinphoneTest::create_simple_conference_dial_out_with_many_late_participant_additions), TEST_NO_TAG("Create simple conference by merging calls", LinphoneTest::create_simple_conference_merging_calls), - TEST_ONE_TAG("Create simple conference by merging calls with video toggling", - LinphoneTest::create_simple_conference_merging_calls_with_video_toggling, - "LeaksMemory"), /* because of aborted calls*/ + TEST_NO_TAG("Create simple conference by merging calls with video toggling", + LinphoneTest::create_simple_conference_merging_calls_with_video_toggling), TEST_NO_TAG("Create dial out conference with active call", LinphoneTest::create_dial_out_conference_with_active_call), TEST_NO_TAG("Organizer creates 2 dialout conferences", LinphoneTest::organizer_creates_two_dialout_conferences), diff --git a/tester/local_scheduled_conference_tester.cpp b/tester/local_scheduled_conference_tester.cpp index ac760308c3..f5809aec54 100644 --- a/tester/local_scheduled_conference_tester.cpp +++ b/tester/local_scheduled_conference_tester.cpp @@ -83,16 +83,14 @@ static void create_conference_on_unresponsive_server(void) { LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelEndToEnd; - bctbx_list_t *participant_infos = NULL; + bctbx_list_t *participants_info = NULL; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; const char *domain = linphone_address_get_domain(marie.getCMgr()->identity); char user_address[100]; for (int idx = 0; idx < 180; idx++) { snprintf(user_address, sizeof(user_address), "sip:happyuser%0d@%s", idx, domain); LinphoneAddress *user = linphone_factory_create_address(linphone_factory_get(), user_address); - LinphoneParticipantInfo *participant_info = linphone_participant_info_new(user); - linphone_participant_info_set_role(participant_info, role); - participant_infos = bctbx_list_append(participant_infos, participant_info); + add_participant_info_to_list(&participants_info, user, role, -1); if (role == LinphoneParticipantRoleSpeaker) { role = LinphoneParticipantRoleListener; } else if (role == LinphoneParticipantRoleListener) { @@ -124,7 +122,7 @@ static void create_conference_on_unresponsive_server(void) { linphone_account_get_params(default_account))) : linphone_address_new(linphone_core_get_identity(marie.getLc())); linphone_conference_info_set_organizer(conf_info, organizer_address); - linphone_conference_info_set_participant_infos(conf_info, participant_infos); + linphone_conference_info_set_participant_infos(conf_info, participants_info); linphone_conference_info_set_duration( conf_info, (int)((end_time - start_time) / 60)); // duration is expected to be set in minutes linphone_conference_info_set_date_time(conf_info, start_time); @@ -155,7 +153,7 @@ static void create_conference_on_unresponsive_server(void) { marie_stat.number_of_ConferenceSchedulerStateError + 2, request_timeout_wait)); linphone_conference_info_unref(conf_info); - bctbx_list_free_with_data(participant_infos, (bctbx_list_free_func)linphone_participant_info_unref); + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); if (organizer_address) linphone_address_unref(organizer_address); linphone_conference_scheduler_unref(conference_scheduler); bctbx_list_free(coresList); @@ -284,16 +282,18 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen ClientConference marie("marie_rc", focus.getIdentity()); ClientConference pauline("pauline_rc", focus.getIdentity()); ClientConference laure("laure_tcp_rc", focus.getIdentity()); + ClientConference berthe("berthe_rc", focus.getIdentity()); focus.registerAsParticipantDevice(marie); focus.registerAsParticipantDevice(pauline); focus.registerAsParticipantDevice(laure); + focus.registerAsParticipantDevice(berthe); setup_conference_info_cbs(marie.getCMgr()); bctbx_list_t *coresList = NULL; - for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) { + for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), berthe.getCMgr()}) { LinphoneVideoActivationPolicy *pol = linphone_factory_create_video_activation_policy(linphone_factory_get()); linphone_video_activation_policy_set_automatically_accept(pol, TRUE); @@ -323,13 +323,19 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen const char *initialSubject = "Test characters: ^ :) ¤ çà @"; const char *description = "Chamrousse Pub"; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; LinphoneParticipantRole role = LinphoneParticipantRoleUnknown; for (auto &p : participants) { - participantList.insert(std::make_pair(p, role)); - role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener - : LinphoneParticipantRoleSpeaker; + participantList.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); + role = (role == LinphoneParticipantRoleListener) ? LinphoneParticipantRoleSpeaker + : LinphoneParticipantRoleListener; } + participantList.insert(std::make_pair( + berthe.getCMgr(), add_participant_info_to_list(&participants_info, berthe.getCMgr()->identity, + LinphoneParticipantRoleSpeaker, -1))); + LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time, initialSubject, description, TRUE, security_level); @@ -378,10 +384,8 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, no_streams_running, liblinphone_tester_sip_timeout)); - // Update to add to conference. - // If ICE is enabled, the addition to a conference may go through a resume of the call BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated, - ((mgr == marie.getCMgr()) ? 3 : 2), liblinphone_tester_sip_timeout)); + ((mgr == marie.getCMgr()) ? 4 : 2), liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE( wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1, 5000)); BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1, 5000)); @@ -400,8 +404,6 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning, focus_stat.number_of_LinphoneCallStreamsRunning + focus_no_streams_running, liblinphone_tester_sip_timeout)); - // Update to add to conference. - // If ICE is enabled, the addition to a conference may go through a resume of the call BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated, focus_stat.number_of_LinphoneConferenceStateCreated + 1, liblinphone_tester_sip_timeout)); @@ -419,25 +421,9 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen focus_stat.number_of_participant_devices_joined + 3, liblinphone_tester_sip_timeout)); - std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList; - for (const auto &member : members) { - try { - const auto &participantInfo = participantList.at(member); - auto role = participantInfo; - if (role == LinphoneParticipantRoleUnknown) { - role = LinphoneParticipantRoleSpeaker; - } - memberList.insert(std::make_pair(member, role)); - } catch (std::out_of_range &) { - if (member == marie.getCMgr()) { - memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker)); - } else { - ms_fatal("Unable to find active participant %s in the participant list", - linphone_core_get_identity(member->lc)); - } - } - } - wait_for_conference_streams({focus, marie, pauline, laure}, conferenceMgrs, focus.getCMgr(), memberList, + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList = + fill_memmber_list(members, participantList, marie.getCMgr(), participants_info); + wait_for_conference_streams({focus, marie, pauline, laure, berthe}, conferenceMgrs, focus.getCMgr(), memberList, confAddr, TRUE); LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr); @@ -529,6 +515,153 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen } } + focus_stat = focus.getStats(); + + LinphoneCallParams *new_params = linphone_core_create_call_params(berthe.getCMgr()->lc, nullptr); + linphone_call_params_enable_video(new_params, FALSE); + linphone_call_params_set_conference_video_layout(new_params, LinphoneConferenceLayoutActiveSpeaker); + ms_message("%s is calling conference %s", linphone_core_get_identity(berthe.getCMgr()->lc), + conference_address_str); + linphone_core_invite_address_with_params_2(berthe.getCMgr()->lc, confAddr, new_params, NULL, nullptr); + linphone_call_params_unref(new_params); + + BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getCMgr()->stat.number_of_LinphoneCallOutgoingProgress, 1, + liblinphone_tester_sip_timeout)); + int no_streams_running = 2; + BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getCMgr()->stat.number_of_LinphoneCallUpdating, + (no_streams_running - 1), liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getCMgr()->stat.number_of_LinphoneCallStreamsRunning, + no_streams_running, liblinphone_tester_sip_timeout)); + // Update to add to conference. + // If ICE is enabled, the addition to a conference may go through a resume of the call + BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getCMgr()->stat.number_of_LinphoneConferenceStateCreated, 2, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE( + wait_for_list(coresList, &berthe.getCMgr()->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1, 5000)); + BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getCMgr()->stat.number_of_LinphoneSubscriptionActive, 1, 5000)); + BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getCMgr()->stat.number_of_NotifyFullStateReceived, 1, + liblinphone_tester_sip_timeout)); + + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived, + focus_stat.number_of_LinphoneCallIncomingReceived + 1, + liblinphone_tester_sip_timeout)); + focus_no_streams_running = 2; + // Update to end ICE negotiations + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote, + focus_stat.number_of_LinphoneCallUpdatedByRemote + (focus_no_streams_running - 1), + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning, + focus_stat.number_of_LinphoneCallStreamsRunning + focus_no_streams_running, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived, + focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 1, 5000)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive, + focus_stat.number_of_LinphoneSubscriptionActive + 1, 5000)); + + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added, + focus_stat.number_of_participants_added + 1, liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added, + focus_stat.number_of_participant_devices_added + 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined, + focus_stat.number_of_participant_devices_joined + 1, + liblinphone_tester_sip_timeout)); + + participants.push_back(berthe.getCMgr()); + members.push_back(berthe.getCMgr()); + conferenceMgrs.push_back(berthe.getCMgr()); + + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList2 = + fill_memmber_list(members, participantList, marie.getCMgr(), participants_info); + wait_for_conference_streams({focus, marie, pauline, laure, berthe}, conferenceMgrs, focus.getCMgr(), + memberList2, confAddr, TRUE); + + // wait bit more to detect side effect if any + CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; }); + + for (auto mgr : conferenceMgrs) { + LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr); + BC_ASSERT_PTR_NOT_NULL(pconference); + if (pconference) { + const LinphoneConferenceParams *conference_params = linphone_conference_get_current_params(pconference); + int no_participants = 0; + if (start_time >= 0) { + BC_ASSERT_EQUAL((long long)linphone_conference_params_get_start_time(conference_params), + (long long)start_time, long long, "%lld"); + } + BC_ASSERT_EQUAL((long long)linphone_conference_params_get_end_time(conference_params), + (long long)end_time, long long, "%lld"); + bctbx_list_t *participant_device_list = linphone_conference_get_participant_device_list(pconference); + BC_ASSERT_EQUAL(bctbx_list_size(participant_device_list), 4, size_t, "%zu"); + bctbx_list_free_with_data(participant_device_list, (void (*)(void *))linphone_participant_device_unref); + + if (mgr == focus.getCMgr()) { + no_participants = 4; + BC_ASSERT_FALSE(linphone_conference_is_in(pconference)); + } else { + no_participants = 3; + BC_ASSERT_TRUE(linphone_conference_is_in(pconference)); + LinphoneCall *current_call = linphone_core_get_current_call(mgr->lc); + BC_ASSERT_PTR_NOT_NULL(current_call); + if (current_call) { + BC_ASSERT_EQUAL((int)linphone_call_get_state(current_call), + (int)LinphoneCallStateStreamsRunning, int, "%0d"); + } + + size_t no_streams_audio = 0; + size_t no_streams_video = 0; + size_t no_active_streams_video = 0; + size_t no_streams_text = 0; + + LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr); + BC_ASSERT_PTR_NOT_NULL(pcall); + if (pcall) { + no_streams_audio = compute_no_audio_streams(pcall, pconference); + _linphone_call_check_nb_streams(pcall, no_streams_audio, no_streams_video, no_streams_text); + _linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_active_streams_video, + no_streams_text); + const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall); + BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_lparams)); + const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall); + BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_rparams)); + const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall); + BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_cparams)); + } + LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity); + BC_ASSERT_PTR_NOT_NULL(ccall); + if (ccall) { + _linphone_call_check_nb_streams(ccall, no_streams_audio, no_streams_video, no_streams_text); + _linphone_call_check_nb_active_streams(ccall, no_streams_audio, no_active_streams_video, + no_streams_text); + const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall); + BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_lparams)); + const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(ccall); + BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_rparams)); + const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall); + BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_cparams)); + } + } + BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int, "%0d"); + BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject); + LinphoneParticipant *me = linphone_conference_get_me(pconference); + BC_ASSERT_TRUE(linphone_participant_is_admin(me) == + ((mgr == marie.getCMgr()) || (mgr == focus.getCMgr()))); + BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity)); + bctbx_list_t *participants = linphone_conference_get_participant_list(pconference); + for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) { + LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp); + BC_ASSERT_TRUE( + linphone_participant_is_admin(p) == + linphone_address_weak_equal(linphone_participant_get_address(p), marie.getCMgr()->identity)); + } + bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref); + + if (mgr != focus.getCMgr()) { + check_conference_ssrc(fconference, pconference); + } + } + } + // Everybody adds video std::list<LinphoneCoreManager *> withVideo{}; int mCnt = 0; @@ -596,16 +729,21 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen (int)bctbx_list_size(linphone_core_get_calls(pauline.getLc())); const int total_laure_calls = laure.getStats().number_of_LinphoneCallEnd + (int)bctbx_list_size(linphone_core_get_calls(laure.getLc())); + const int total_berthe_calls = + berthe.getStats().number_of_LinphoneCallEnd + (int)bctbx_list_size(linphone_core_get_calls(berthe.getLc())); linphone_core_terminate_all_calls(pauline.getLc()); linphone_core_terminate_all_calls(laure.getLc()); linphone_core_terminate_all_calls(marie.getLc()); + linphone_core_terminate_all_calls(berthe.getLc()); // Wait for calls to be terminated BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallEnd, total_marie_calls, 30000)); BC_ASSERT_TRUE( wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallEnd, total_pauline_calls, 30000)); BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallEnd, total_laure_calls, 30000)); + BC_ASSERT_TRUE( + wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallEnd, total_berthe_calls, 30000)); BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd, total_focus_calls, 40000)); BC_ASSERT_TRUE( @@ -614,6 +752,8 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallReleased, total_pauline_calls, 30000)); BC_ASSERT_TRUE( wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallReleased, total_laure_calls, 30000)); + BC_ASSERT_TRUE( + wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallReleased, total_berthe_calls, 30000)); BC_ASSERT_TRUE( wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased, total_focus_calls, 40000)); @@ -621,7 +761,7 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen linphone_conference_terminate(fconference); } - for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) { + for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), berthe.getCMgr()}) { // Wait for all conferences to be terminated BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminationPending, 1, @@ -632,7 +772,7 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, - (mgr == focus.getCMgr()) ? 3 : 1, liblinphone_tester_sip_timeout)); + (mgr == focus.getCMgr()) ? 4 : 1, liblinphone_tester_sip_timeout)); if (mgr && (mgr != focus.getCMgr())) { LinphoneCall *participant_call = @@ -658,6 +798,7 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen } } + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); ms_free(conference_address_str); linphone_address_unref(confAddr); bctbx_list_free(coresList); @@ -741,14 +882,19 @@ static void create_conference_with_codec_mismatch_base(bool_t organizer_codec_mi const char *description = "Paris Baker"; LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; - LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; + LinphoneParticipantRole role = LinphoneParticipantRoleUnknown; for (auto &p : participants) { - participantList.insert(std::make_pair(p, role)); + participantList.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker; } - participantList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleListener)); + participantList.insert( + std::make_pair(marie.getCMgr(), add_participant_info_to_list(&participants_info, marie.getCMgr()->identity, + LinphoneParticipantRoleListener, -1))); + LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time, initialSubject, description, TRUE, security_level); BC_ASSERT_PTR_NOT_NULL(confAddr); @@ -792,10 +938,11 @@ static void create_conference_with_codec_mismatch_base(bool_t organizer_codec_mi participantList.erase(m); } - for (auto [mgr, role] : participantList) { + for (auto [mgr, info] : participantList) { BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1, liblinphone_tester_sip_timeout)); - int no_streams_running = (role == LinphoneParticipantRoleSpeaker) ? 3 : 2; + int no_streams_running = + (linphone_participant_info_get_role(info) == LinphoneParticipantRoleSpeaker) ? 3 : 2; BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating, (no_streams_running - 1), liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, no_streams_running, @@ -864,20 +1011,8 @@ static void create_conference_with_codec_mismatch_base(bool_t organizer_codec_mi liblinphone_tester_sip_timeout)); } - std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList; - for (const auto &member : members) { - try { - const auto &participantInfo = participantList.at(member); - memberList.insert(std::make_pair(member, participantInfo)); - } catch (std::out_of_range &) { - if (member == marie.getCMgr()) { - memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker)); - } else { - ms_fatal("Unable to find active participant %s in the participant list", - linphone_core_get_identity(member->lc)); - } - } - } + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList = + fill_memmber_list(members, participantList, marie.getCMgr(), participants_info); wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(), memberList, confAddr, TRUE); @@ -1060,6 +1195,7 @@ static void create_conference_with_codec_mismatch_base(bool_t organizer_codec_mi return false; }); + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); ms_free(conference_address_str); linphone_address_unref(confAddr); bctbx_list_free(coresList); @@ -1120,14 +1256,18 @@ static void create_conference_with_server_restart_base(bool_t organizer_first) { const char *description = "London Pub"; LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : participants) { - participantList.insert(std::make_pair(p, role)); + participantList.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker; } - participantList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker)); + participantList.insert( + std::make_pair(marie.getCMgr(), add_participant_info_to_list(&participants_info, marie.getCMgr()->identity, + LinphoneParticipantRoleSpeaker, -1))); LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time, initialSubject, description, TRUE, security_level); @@ -1230,20 +1370,8 @@ static void create_conference_with_server_restart_base(bool_t organizer_first) { focus_stat.number_of_participant_devices_joined + 3, liblinphone_tester_sip_timeout)); - std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList; - for (const auto &member : members) { - try { - const auto &participantInfo = participantList.at(member); - memberList.insert(std::make_pair(member, participantInfo)); - } catch (std::out_of_range &) { - if (member == marie.getCMgr()) { - memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker)); - } else { - ms_fatal("Unable to find active participant %s in the participant list", - linphone_core_get_identity(member->lc)); - } - } - } + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList = + fill_memmber_list(members, participantList, marie.getCMgr(), participants_info); wait_for_conference_streams({focus, marie, pauline, laure}, conferenceMgrs, focus.getCMgr(), memberList, confAddr, TRUE); @@ -1411,6 +1539,7 @@ static void create_conference_with_server_restart_base(bool_t organizer_first) { } } + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); ms_free(conference_address_str); linphone_address_unref(confAddr); bctbx_list_free(coresList); @@ -1477,10 +1606,12 @@ static void create_simple_conference_with_update_deferred(void) { const char *description = "Paris Baker"; LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : participants) { - participantList.insert(std::make_pair(p, role)); + participantList.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker; } @@ -1887,6 +2018,7 @@ static void create_simple_conference_with_update_deferred(void) { // wait bit more to detect side effect if any CoreManagerAssert({focus, marie, pauline, laure, michelle}).waitUntil(chrono::seconds(2), [] { return false; }); + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); linphone_address_unref(confAddr); bctbx_list_free(coresList); } @@ -1944,10 +2076,12 @@ static void change_active_speaker(void) { const char *description = "hello"; LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : invitesList) { - participantList.insert(std::make_pair(p, role)); + participantList.insert( + std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); } LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time, initialSubject, description, TRUE, security_level); @@ -2156,6 +2290,7 @@ static void change_active_speaker(void) { } } + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); linphone_address_unref(confAddr); bctbx_list_free(coresList); } @@ -2208,10 +2343,11 @@ static void conference_with_participant_added_outside_valid_time_slot (bool_t be const char *initialSubject = "Colleagues"; const char *description = "Tom Black"; - std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList; + bctbx_list_t *participants_info = NULL; + std::map<LinphoneCoreManager *, LinphoneParticipantInfo*> participantList; LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker; for (auto &p : participants) { - participantList.insert(std::make_pair(p, role)); + participantList.insert(std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1))); role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker; } LinphoneAddress* confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time, initialSubject, description, TRUE, security_level); @@ -2237,6 +2373,7 @@ static void conference_with_participant_added_outside_valid_time_slot (bool_t be return false; }); + bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); linphone_address_unref(confAddr); bctbx_list_free(coresList); diff --git a/tester/tester.c b/tester/tester.c index 482e275833..17f11c20eb 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -702,6 +702,13 @@ conference_participant_device_media_capability_changed(LinphoneConference *confe manager->stat.number_of_participant_devices_media_capability_changed++; } +static void conference_participant_role_changed(LinphoneConference *conference, + BCTBX_UNUSED(const LinphoneParticipant *participant)) { + LinphoneCore *core = linphone_conference_get_core(conference); + LinphoneCoreManager *manager = (LinphoneCoreManager *)linphone_core_get_user_data(core); + manager->stat.number_of_participant_role_changed++; +} + static void conference_participant_admin_status_changed(LinphoneConference *conference, BCTBX_UNUSED(const LinphoneParticipant *participant)) { LinphoneCore *core = linphone_conference_get_core(conference); @@ -747,6 +754,7 @@ void core_conference_state_changed(BCTBX_UNUSED(LinphoneCore *core), linphone_conference_cbs_set_state_changed(cbs, conference_state_changed); linphone_conference_cbs_set_available_media_changed(cbs, conference_available_media_changed); linphone_conference_cbs_set_subject_changed(cbs, conference_subject_changed); + linphone_conference_cbs_set_participant_role_changed(cbs, conference_participant_role_changed); linphone_conference_cbs_set_participant_admin_status_changed(cbs, conference_participant_admin_status_changed); linphone_conference_cbs_set_participant_device_media_capability_changed( cbs, conference_participant_device_media_capability_changed); -- GitLab