From acd22269faadbb17cd7df6e3c125f9b5e64297d9 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 9 Feb 2018 15:44:44 +0100 Subject: [PATCH] Add state of conference participant device. --- src/chat/chat-room/server-group-chat-room-p.h | 24 ++- .../chat-room/server-group-chat-room-stub.cpp | 26 ++- src/chat/chat-room/server-group-chat-room.h | 3 + src/conference/conference-listener.h | 18 +- src/conference/conference.cpp | 3 +- src/conference/conference.h | 2 + .../local-conference-event-handler-p.h | 6 +- .../local-conference-event-handler.cpp | 170 ++++++++++-------- src/conference/participant-device.h | 10 ++ src/conference/remote-conference.h | 3 +- tester/conference-event-tester.cpp | 4 +- 11 files changed, 170 insertions(+), 99 deletions(-) diff --git a/src/chat/chat-room/server-group-chat-room-p.h b/src/chat/chat-room/server-group-chat-room-p.h index 1aeb4cff2..6b9ef0da0 100644 --- a/src/chat/chat-room/server-group-chat-room-p.h +++ b/src/chat/chat-room/server-group-chat-room-p.h @@ -20,6 +20,10 @@ #ifndef _L_SERVER_GROUP_CHAT_ROOM_P_H_ #define _L_SERVER_GROUP_CHAT_ROOM_P_H_ +#include +#include +#include + #include "chat-room-p.h" #include "server-group-chat-room.h" @@ -27,15 +31,20 @@ LINPHONE_BEGIN_NAMESPACE +class ParticipantDevice; + class ServerGroupChatRoomPrivate : public ChatRoomPrivate { public: std::shared_ptr addParticipant (const IdentityAddress &participantAddress); void removeParticipant (const std::shared_ptr &participant); - std::shared_ptr findRemovedParticipant (const std::shared_ptr &session) const; + + std::shared_ptr findFilteredParticipant (const std::shared_ptr &session) const; + std::shared_ptr findFilteredParticipant (const IdentityAddress &participantAddress) const; void confirmCreation (); void confirmJoining (SalCallOp *op); void confirmRecreation (SalCallOp *op); + void dispatchQueuedMessages (); IdentityAddress generateConferenceAddress (const std::shared_ptr &me) const; @@ -60,13 +69,18 @@ private: IdentityAddress fromAddr; Content content; + std::chrono::system_clock::time_point timestamp = std::chrono::system_clock::now(); }; void designateAdmin (); - void dispatchMessage (const Message &message); - void dispatchQueuedMessages (); + void dispatchMessage (const std::shared_ptr &message, const std::string &uri); void finalizeCreation (); + void inviteDevice (const std::shared_ptr &device); bool isAdminLeft () const; + void queueMessage (const std::shared_ptr &message); + void queueMessage (const std::shared_ptr &msg, const IdentityAddress &deviceAddress); + + void onParticipantDeviceLeft (const std::shared_ptr &session); // ChatRoomListener void onChatRoomInsertRequested (const std::shared_ptr &chatRoom) override; @@ -80,11 +94,11 @@ private: const std::string &message ) override; - std::list> removedParticipants; + std::list> filteredParticipants; ChatRoomListener *chatRoomListener = this; ServerGroupChatRoom::CapabilitiesMask capabilities = ServerGroupChatRoom::Capabilities::Conference; bool joiningPendingAfterCreation = false; - std::list queuedMessages; + std::unordered_map>> queuedMessages; L_DECLARE_PUBLIC(ServerGroupChatRoom); }; diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index 1fa4c58f5..0e59145ab 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -34,9 +34,11 @@ shared_ptr ServerGroupChatRoomPrivate::addParticipant (const Identi void ServerGroupChatRoomPrivate::removeParticipant (const shared_ptr &) {} -shared_ptr ServerGroupChatRoomPrivate::findRemovedParticipant ( - const shared_ptr & -) const { +shared_ptr ServerGroupChatRoomPrivate::findFilteredParticipant (const shared_ptr &session) const { + return nullptr; +} + +shared_ptr ServerGroupChatRoomPrivate::findFilteredParticipant (const IdentityAddress &participantAddress) const { return nullptr; } @@ -48,6 +50,8 @@ void ServerGroupChatRoomPrivate::confirmJoining (SalCallOp *) {} void ServerGroupChatRoomPrivate::confirmRecreation (SalCallOp *) {} +void ServerGroupChatRoomPrivate::dispatchQueuedMessages () {} + // ----------------------------------------------------------------------------- IdentityAddress ServerGroupChatRoomPrivate::generateConferenceAddress (const shared_ptr &me) const { @@ -76,16 +80,24 @@ LinphoneReason ServerGroupChatRoomPrivate::onSipMessageReceived (SalOp *, const void ServerGroupChatRoomPrivate::designateAdmin () {} -void ServerGroupChatRoomPrivate::dispatchMessage (const Message &message) {} - -void ServerGroupChatRoomPrivate::dispatchQueuedMessages () {} +void ServerGroupChatRoomPrivate::dispatchMessage (const std::shared_ptr &message, const std::string &uri) {} void ServerGroupChatRoomPrivate::finalizeCreation () {} +void ServerGroupChatRoomPrivate::inviteDevice (const std::shared_ptr &device) {} + bool ServerGroupChatRoomPrivate::isAdminLeft () const { return false; } +void ServerGroupChatRoomPrivate::queueMessage (const std::shared_ptr &message) {} + +void ServerGroupChatRoomPrivate::queueMessage (const std::shared_ptr &msg, const IdentityAddress &deviceAddress) {} + +// ----------------------------------------------------------------------------- + +void ServerGroupChatRoomPrivate::onParticipantDeviceLeft (const std::shared_ptr &session) {} + // ----------------------------------------------------------------------------- void ServerGroupChatRoomPrivate::onChatRoomInsertRequested (const shared_ptr &chatRoom) {} @@ -189,4 +201,6 @@ void ServerGroupChatRoom::join () {} void ServerGroupChatRoom::leave () {} +void ServerGroupChatRoom::onFirstNotifyReceived (const IdentityAddress &addr) {} + LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-room/server-group-chat-room.h b/src/chat/chat-room/server-group-chat-room.h index bd480533c..fa4fd0ab4 100644 --- a/src/chat/chat-room/server-group-chat-room.h +++ b/src/chat/chat-room/server-group-chat-room.h @@ -85,6 +85,9 @@ public: void join () override; void leave () override; + /* ConferenceListener */ + void onFirstNotifyReceived (const IdentityAddress &addr) override; + private: L_DECLARE_PRIVATE(ServerGroupChatRoom); L_DISABLE_COPY(ServerGroupChatRoom); diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h index e90c00760..e4da1bd7b 100644 --- a/src/conference/conference-listener.h +++ b/src/conference/conference-listener.h @@ -36,16 +36,16 @@ class IdentityAddress; class ConferenceListener { public: - virtual void onConferenceCreated (const IdentityAddress &addr) = 0; + virtual void onConferenceCreated (const IdentityAddress &addr) {} virtual void onConferenceKeywordsChanged (const std::vector &keywords) {} - virtual void onConferenceTerminated (const IdentityAddress &addr) = 0; - virtual void onFirstNotifyReceived (const IdentityAddress &addr) = 0; - virtual void onParticipantAdded (const std::shared_ptr &event, bool isFullState) = 0; - virtual void onParticipantRemoved (const std::shared_ptr &event, bool isFullState) = 0; - virtual void onParticipantSetAdmin (const std::shared_ptr &event, bool isFullState) = 0; - virtual void onSubjectChanged (const std::shared_ptr &event, bool isFullState) = 0; - virtual void onParticipantDeviceAdded (const std::shared_ptr &event, bool isFullState) = 0; - virtual void onParticipantDeviceRemoved (const std::shared_ptr &event, bool isFullState) = 0; + virtual void onConferenceTerminated (const IdentityAddress &addr) {} + virtual void onFirstNotifyReceived (const IdentityAddress &addr) {} + virtual void onParticipantAdded (const std::shared_ptr &event, bool isFullState) {} + virtual void onParticipantRemoved (const std::shared_ptr &event, bool isFullState) {} + virtual void onParticipantSetAdmin (const std::shared_ptr &event, bool isFullState) {} + virtual void onSubjectChanged (const std::shared_ptr &event, bool isFullState) {} + virtual void onParticipantDeviceAdded (const std::shared_ptr &event, bool isFullState) {} + virtual void onParticipantDeviceRemoved (const std::shared_ptr &event, bool isFullState) {} }; LINPHONE_END_NAMESPACE diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index b3127d89d..1aa3459e6 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -83,8 +83,7 @@ shared_ptr Conference::getMe () const { } int Conference::getParticipantCount () const { - L_D(); - return static_cast(d->participants.size()); + return static_cast(getParticipants().size()); } const list> &Conference::getParticipants () const { diff --git a/src/conference/conference.h b/src/conference/conference.h index 733c1360e..9891240ea 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -23,6 +23,7 @@ #include "linphone/types.h" #include "conference/conference-interface.h" +#include "conference/conference-listener.h" #include "core/core-accessor.h" // ============================================================================= @@ -36,6 +37,7 @@ class ConferencePrivate; class LINPHONE_PUBLIC Conference : public ConferenceInterface, + public ConferenceListener, public CoreAccessor { friend class CallSessionPrivate; diff --git a/src/conference/handlers/local-conference-event-handler-p.h b/src/conference/handlers/local-conference-event-handler-p.h index 6fce0ddb3..a4ad08b2a 100644 --- a/src/conference/handlers/local-conference-event-handler-p.h +++ b/src/conference/handlers/local-conference-event-handler-p.h @@ -40,11 +40,11 @@ public: std::string createNotifyFullState (int notifyId = -1, bool oneToOne = false); std::string createNotifyMultipart (int notifyId); std::string createNotifyParticipantAdded (const Address &addr, int notifyId = -1); + std::string createNotifyParticipantAdminStatusChanged (const Address &addr, bool isAdmin, int notifyId = -1); std::string createNotifyParticipantRemoved (const Address &addr, int notifyId = -1); - std::string createNotifyParticipantAdmined (const Address &addr, bool isAdmin, int notifyId = -1); - std::string createNotifySubjectChanged (int notifyId = -1); std::string createNotifyParticipantDeviceAdded (const Address &addr, const Address &gruu, int notifyId = -1); std::string createNotifyParticipantDeviceRemoved (const Address &addr, const Address &gruu, int notifyId = -1); + std::string createNotifySubjectChanged (int notifyId = -1); inline unsigned int getLastNotify () const { return lastNotify; }; @@ -54,6 +54,8 @@ private: LocalConference *conf = nullptr; unsigned int lastNotify = 1; + static void notifyResponseCb (const LinphoneEvent *ev); + std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo, int notifyId = -1, bool isFullState = false); std::string createNotifySubjectChanged (const std::string &subject, int notifyId = -1); void notifyParticipant (const std::string ¬ify, const std::shared_ptr &participant); diff --git a/src/conference/handlers/local-conference-event-handler.cpp b/src/conference/handlers/local-conference-event-handler.cpp index 7b3989b72..d02280dc7 100644 --- a/src/conference/handlers/local-conference-event-handler.cpp +++ b/src/conference/handlers/local-conference-event-handler.cpp @@ -62,51 +62,6 @@ void LocalConferenceEventHandlerPrivate::notifyAll (const string ¬ify) { notifyParticipant(notify, participant); } -void LocalConferenceEventHandlerPrivate::notifyParticipant (const string ¬ify, const shared_ptr &participant) { - for (const auto &device : participant->getPrivate()->getDevices()) - notifyParticipantDevice(notify, device); -} - -void LocalConferenceEventHandlerPrivate::notifyParticipantDevice (const string ¬ify, const shared_ptr &device, bool multipart) { - if (device->isSubscribedToConferenceEventPackage() && !notify.empty()) { - LinphoneEvent *ev = device->getConferenceSubscribeEvent(); - LinphoneContent *content = linphone_core_create_content(ev->lc); - linphone_content_set_buffer(content, (const uint8_t *)notify.c_str(), strlen(notify.c_str())); - if (multipart) { - linphone_content_set_type(content, "multipart"); - linphone_content_set_subtype(content, "mixed;boundary=---------------------------14737809831466499882746641449"); - } else { - linphone_content_set_type(content, "application"); - linphone_content_set_subtype(content, "conference-info"); - } - linphone_event_notify(ev, content); - linphone_content_unref(content); - } -} - -string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo, int notifyId, bool isFullState) { - if (notifyId == -1) { - lastNotify = lastNotify + 1; - confInfo.setVersion(lastNotify); - } else { - confInfo.setVersion(static_cast(notifyId)); - } - confInfo.setState(isFullState ? StateType::full : StateType::partial); - if (!confInfo.getConferenceDescription()) { - ConferenceDescriptionType description = ConferenceDescriptionType(); - confInfo.setConferenceDescription(description); - } - - time_t result = time(nullptr); - confInfo.getConferenceDescription()->setFreeText(Utils::toString(static_cast(result))); - - stringstream notify; - Xsd::XmlSchema::NamespaceInfomap map; - map[""].name = "urn:ietf:params:xml:ns:conference-info"; - serializeConferenceInfo(notify, confInfo, map); - return notify.str(); -} - string LocalConferenceEventHandlerPrivate::createNotifyFullState (int notifyId, bool oneToOne) { string entity = conf->getConferenceAddress().asString(); string subject = conf->getSubject(); @@ -177,7 +132,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyMultipart (int notifyId) case EventLog::Type::ConferenceParticipantSetAdmin: { shared_ptr setAdminEvent = static_pointer_cast(eventLog); - body = createNotifyParticipantAdmined( + body = createNotifyParticipantAdminStatusChanged( setAdminEvent->getParticipantAddress(), true, eventNotifyId @@ -186,7 +141,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyMultipart (int notifyId) case EventLog::Type::ConferenceParticipantUnsetAdmin: { shared_ptr unsetAdminEvent = static_pointer_cast(eventLog); - body = createNotifyParticipantAdmined( + body = createNotifyParticipantAdminStatusChanged( unsetAdminEvent->getParticipantAddress(), false, eventNotifyId @@ -263,21 +218,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const A return createNotify(confInfo, notifyId); } -string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const Address &addr, int notifyId) { - string entity = conf->getConferenceAddress().asString(); - ConferenceType confInfo = ConferenceType(entity); - UsersType users; - confInfo.setUsers(users); - - UserType user = UserType(); - user.setEntity(addr.asStringUriOnly()); - user.setState(StateType::deleted); - confInfo.getUsers()->getUser().push_back(user); - - return createNotify(confInfo, notifyId); -} - -string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const Address &addr, bool isAdmin, int notifyId) { +string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdminStatusChanged (const Address &addr, bool isAdmin, int notifyId) { string entity = conf->getConferenceAddress().asString(); ConferenceType confInfo = ConferenceType(entity); UsersType users; @@ -294,16 +235,16 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const return createNotify(confInfo, notifyId); } -string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged (int notifyId) { - return createNotifySubjectChanged(conf->getSubject(), notifyId); -} - -string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged (const string &subject, int notifyId) { +string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const Address &addr, int notifyId) { string entity = conf->getConferenceAddress().asString(); ConferenceType confInfo = ConferenceType(entity); - ConferenceDescriptionType confDescr = ConferenceDescriptionType(); - confDescr.setSubject(subject); - confInfo.setConferenceDescription((const ConferenceDescriptionType)confDescr); + UsersType users; + confInfo.setUsers(users); + + UserType user = UserType(); + user.setEntity(addr.asStringUriOnly()); + user.setState(StateType::deleted); + confInfo.getUsers()->getUser().push_back(user); return createNotify(confInfo, notifyId); } @@ -350,6 +291,93 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved return createNotify(confInfo, notifyId); } +string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged (int notifyId) { + return createNotifySubjectChanged(conf->getSubject(), notifyId); +} + +// ----------------------------------------------------------------------------- + +void LocalConferenceEventHandlerPrivate::notifyResponseCb (const LinphoneEvent *ev) { + LinphoneEventCbs *cbs = linphone_event_get_callbacks(ev); + LocalConferenceEventHandlerPrivate *handler = reinterpret_cast( + linphone_event_cbs_get_user_data(cbs) + ); + linphone_event_cbs_set_user_data(cbs, nullptr); + linphone_event_cbs_set_notify_response(cbs, nullptr); + + if (linphone_event_get_reason(ev) != LinphoneReasonNone) + return; + + for (const auto &p : handler->conf->getParticipants()) { + for (const auto &d : p->getPrivate()->getDevices()) { + if ((d->getConferenceSubscribeEvent() == ev) && (d->getState() == ParticipantDevice::State::Joining)) { + handler->conf->onFirstNotifyReceived(d->getAddress()); + return; + } + } + } +} + +// ----------------------------------------------------------------------------- + +string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo, int notifyId, bool isFullState) { + if (notifyId == -1) { + lastNotify = lastNotify + 1; + confInfo.setVersion(lastNotify); + } else { + confInfo.setVersion(static_cast(notifyId)); + } + confInfo.setState(isFullState ? StateType::full : StateType::partial); + if (!confInfo.getConferenceDescription()) { + ConferenceDescriptionType description = ConferenceDescriptionType(); + confInfo.setConferenceDescription(description); + } + + time_t result = time(nullptr); + confInfo.getConferenceDescription()->setFreeText(Utils::toString(static_cast(result))); + + stringstream notify; + Xsd::XmlSchema::NamespaceInfomap map; + map[""].name = "urn:ietf:params:xml:ns:conference-info"; + serializeConferenceInfo(notify, confInfo, map); + return notify.str(); +} + +string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged (const string &subject, int notifyId) { + string entity = conf->getConferenceAddress().asString(); + ConferenceType confInfo = ConferenceType(entity); + ConferenceDescriptionType confDescr = ConferenceDescriptionType(); + confDescr.setSubject(subject); + confInfo.setConferenceDescription((const ConferenceDescriptionType)confDescr); + + return createNotify(confInfo, notifyId); +} + +void LocalConferenceEventHandlerPrivate::notifyParticipant (const string ¬ify, const shared_ptr &participant) { + for (const auto &device : participant->getPrivate()->getDevices()) + notifyParticipantDevice(notify, device); +} + +void LocalConferenceEventHandlerPrivate::notifyParticipantDevice (const string ¬ify, const shared_ptr &device, bool multipart) { + if (device->isSubscribedToConferenceEventPackage() && !notify.empty()) { + LinphoneEvent *ev = device->getConferenceSubscribeEvent(); + LinphoneEventCbs *cbs = linphone_event_get_callbacks(ev); + linphone_event_cbs_set_user_data(cbs, this); + linphone_event_cbs_set_notify_response(cbs, notifyResponseCb); + LinphoneContent *content = linphone_core_create_content(ev->lc); + linphone_content_set_buffer(content, (const uint8_t *)notify.c_str(), strlen(notify.c_str())); + if (multipart) { + linphone_content_set_type(content, "multipart"); + linphone_content_set_subtype(content, "mixed;boundary=---------------------------14737809831466499882746641449"); + } else { + linphone_content_set_type(content, "application"); + linphone_content_set_subtype(content, "conference-info"); + } + linphone_event_notify(ev, content); + linphone_content_unref(content); + } +} + // ============================================================================= LocalConferenceEventHandler::LocalConferenceEventHandler (LocalConference *localConference, unsigned int notify) : @@ -434,7 +462,7 @@ shared_ptr LocalConferenceEventHandler::notifyPartic shared_ptr LocalConferenceEventHandler::notifyParticipantSetAdmin (const Address &addr, bool isAdmin) { L_D(); - d->notifyAll(d->createNotifyParticipantAdmined(addr, isAdmin)); + d->notifyAll(d->createNotifyParticipantAdminStatusChanged(addr, isAdmin)); shared_ptr event = make_shared( isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin, time(nullptr), diff --git a/src/conference/participant-device.h b/src/conference/participant-device.h index c4ee94e62..09fa3101c 100644 --- a/src/conference/participant-device.h +++ b/src/conference/participant-device.h @@ -34,6 +34,13 @@ class CallSession; class ParticipantDevice { public: + enum class State { + Joining, + Present, + Leaving, + Left + }; + ParticipantDevice (); explicit ParticipantDevice (const IdentityAddress &gruu); virtual ~ParticipantDevice (); @@ -43,6 +50,8 @@ public: inline const IdentityAddress &getAddress () const { return mGruu; } inline std::shared_ptr getSession () const { return mSession; } inline void setSession (std::shared_ptr session) { mSession = session; } + inline State getState () const { return mState; } + inline void setState (State newState) { mState = newState; } inline bool isSubscribedToConferenceEventPackage () const { return mConferenceSubscribeEvent != nullptr; } LinphoneEvent *getConferenceSubscribeEvent () const { return mConferenceSubscribeEvent; } @@ -54,6 +63,7 @@ private: IdentityAddress mGruu; std::shared_ptr mSession; LinphoneEvent *mConferenceSubscribeEvent = nullptr; + State mState = State::Joining; L_DISABLE_COPY(ParticipantDevice); }; diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index 95f1bee8f..1dd2b5931 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -20,7 +20,6 @@ #ifndef _L_REMOTE_CONFERENCE_H_ #define _L_REMOTE_CONFERENCE_H_ -#include "conference-listener.h" #include "conference.h" #include "core/core-accessor.h" @@ -30,7 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class RemoteConferencePrivate; -class LINPHONE_PUBLIC RemoteConference : public Conference, public ConferenceListener { +class LINPHONE_PUBLIC RemoteConference : public Conference { friend class ClientGroupChatRoomPrivate; public: diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 8f531974f..ecde1d4ab 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -1023,7 +1023,7 @@ void send_admined_notify() { BC_ASSERT_TRUE(!tester->participants.find(bobAddr.asString())->second); BC_ASSERT_TRUE(tester->participants.find(aliceAddr.asString())->second); - notify = localHandlerPrivate->createNotifyParticipantAdmined(bobAddr, true); + notify = localHandlerPrivate->createNotifyParticipantAdminStatusChanged(bobAddr, true); tester->handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester->participants.size(), 2, int, "%d"); @@ -1078,7 +1078,7 @@ void send_unadmined_notify() { BC_ASSERT_TRUE(!tester->participants.find(bobAddr.asString())->second); BC_ASSERT_TRUE(tester->participants.find(aliceAddr.asString())->second); - notify = localHandlerPrivate->createNotifyParticipantAdmined(aliceAddr, false); + notify = localHandlerPrivate->createNotifyParticipantAdminStatusChanged(aliceAddr, false); tester->handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester->participants.size(), 2, int, "%d");