Commit acd22269 authored by Ghislain MARY's avatar Ghislain MARY
Browse files

Add state of conference participant device.

parent bccf926b
......@@ -20,6 +20,10 @@
#ifndef _L_SERVER_GROUP_CHAT_ROOM_P_H_
#define _L_SERVER_GROUP_CHAT_ROOM_P_H_
#include <chrono>
#include <queue>
#include <unordered_map>
#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<Participant> addParticipant (const IdentityAddress &participantAddress);
void removeParticipant (const std::shared_ptr<const Participant> &participant);
std::shared_ptr<Participant> findRemovedParticipant (const std::shared_ptr<const CallSession> &session) const;
std::shared_ptr<Participant> findFilteredParticipant (const std::shared_ptr<const CallSession> &session) const;
std::shared_ptr<Participant> findFilteredParticipant (const IdentityAddress &participantAddress) const;
void confirmCreation ();
void confirmJoining (SalCallOp *op);
void confirmRecreation (SalCallOp *op);
void dispatchQueuedMessages ();
IdentityAddress generateConferenceAddress (const std::shared_ptr<Participant> &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> &message, const std::string &uri);
void finalizeCreation ();
void inviteDevice (const std::shared_ptr<ParticipantDevice> &device);
bool isAdminLeft () const;
void queueMessage (const std::shared_ptr<Message> &message);
void queueMessage (const std::shared_ptr<Message> &msg, const IdentityAddress &deviceAddress);
void onParticipantDeviceLeft (const std::shared_ptr<const CallSession> &session);
// ChatRoomListener
void onChatRoomInsertRequested (const std::shared_ptr<AbstractChatRoom> &chatRoom) override;
......@@ -80,11 +94,11 @@ private:
const std::string &message
) override;
std::list<std::shared_ptr<Participant>> removedParticipants;
std::list<std::shared_ptr<Participant>> filteredParticipants;
ChatRoomListener *chatRoomListener = this;
ServerGroupChatRoom::CapabilitiesMask capabilities = ServerGroupChatRoom::Capabilities::Conference;
bool joiningPendingAfterCreation = false;
std::list<Message> queuedMessages;
std::unordered_map<std::string, std::queue<std::shared_ptr<Message>>> queuedMessages;
L_DECLARE_PUBLIC(ServerGroupChatRoom);
};
......
......@@ -34,9 +34,11 @@ shared_ptr<Participant> ServerGroupChatRoomPrivate::addParticipant (const Identi
void ServerGroupChatRoomPrivate::removeParticipant (const shared_ptr<const Participant> &) {}
shared_ptr<Participant> ServerGroupChatRoomPrivate::findRemovedParticipant (
const shared_ptr<const CallSession> &
) const {
shared_ptr<Participant> ServerGroupChatRoomPrivate::findFilteredParticipant (const shared_ptr<const CallSession> &session) const {
return nullptr;
}
shared_ptr<Participant> 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<Participant> &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> &message, const std::string &uri) {}
void ServerGroupChatRoomPrivate::finalizeCreation () {}
void ServerGroupChatRoomPrivate::inviteDevice (const std::shared_ptr<ParticipantDevice> &device) {}
bool ServerGroupChatRoomPrivate::isAdminLeft () const {
return false;
}
void ServerGroupChatRoomPrivate::queueMessage (const std::shared_ptr<Message> &message) {}
void ServerGroupChatRoomPrivate::queueMessage (const std::shared_ptr<Message> &msg, const IdentityAddress &deviceAddress) {}
// -----------------------------------------------------------------------------
void ServerGroupChatRoomPrivate::onParticipantDeviceLeft (const std::shared_ptr<const CallSession> &session) {}
// -----------------------------------------------------------------------------
void ServerGroupChatRoomPrivate::onChatRoomInsertRequested (const shared_ptr<AbstractChatRoom> &chatRoom) {}
......@@ -189,4 +201,6 @@ void ServerGroupChatRoom::join () {}
void ServerGroupChatRoom::leave () {}
void ServerGroupChatRoom::onFirstNotifyReceived (const IdentityAddress &addr) {}
LINPHONE_END_NAMESPACE
......@@ -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);
......
......@@ -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<std::string> &keywords) {}
virtual void onConferenceTerminated (const IdentityAddress &addr) = 0;
virtual void onFirstNotifyReceived (const IdentityAddress &addr) = 0;
virtual void onParticipantAdded (const std::shared_ptr<ConferenceParticipantEvent> &event, bool isFullState) = 0;
virtual void onParticipantRemoved (const std::shared_ptr<ConferenceParticipantEvent> &event, bool isFullState) = 0;
virtual void onParticipantSetAdmin (const std::shared_ptr<ConferenceParticipantEvent> &event, bool isFullState) = 0;
virtual void onSubjectChanged (const std::shared_ptr<ConferenceSubjectEvent> &event, bool isFullState) = 0;
virtual void onParticipantDeviceAdded (const std::shared_ptr<ConferenceParticipantDeviceEvent> &event, bool isFullState) = 0;
virtual void onParticipantDeviceRemoved (const std::shared_ptr<ConferenceParticipantDeviceEvent> &event, bool isFullState) = 0;
virtual void onConferenceTerminated (const IdentityAddress &addr) {}
virtual void onFirstNotifyReceived (const IdentityAddress &addr) {}
virtual void onParticipantAdded (const std::shared_ptr<ConferenceParticipantEvent> &event, bool isFullState) {}
virtual void onParticipantRemoved (const std::shared_ptr<ConferenceParticipantEvent> &event, bool isFullState) {}
virtual void onParticipantSetAdmin (const std::shared_ptr<ConferenceParticipantEvent> &event, bool isFullState) {}
virtual void onSubjectChanged (const std::shared_ptr<ConferenceSubjectEvent> &event, bool isFullState) {}
virtual void onParticipantDeviceAdded (const std::shared_ptr<ConferenceParticipantDeviceEvent> &event, bool isFullState) {}
virtual void onParticipantDeviceRemoved (const std::shared_ptr<ConferenceParticipantDeviceEvent> &event, bool isFullState) {}
};
LINPHONE_END_NAMESPACE
......
......@@ -83,8 +83,7 @@ shared_ptr<Participant> Conference::getMe () const {
}
int Conference::getParticipantCount () const {
L_D();
return static_cast<int>(d->participants.size());
return static_cast<int>(getParticipants().size());
}
const list<shared_ptr<Participant>> &Conference::getParticipants () const {
......
......@@ -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;
......
......@@ -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 &notify, const std::shared_ptr<Participant> &participant);
......
......@@ -62,51 +62,6 @@ void LocalConferenceEventHandlerPrivate::notifyAll (const string &notify) {
notifyParticipant(notify, participant);
}
void LocalConferenceEventHandlerPrivate::notifyParticipant (const string &notify, const shared_ptr<Participant> &participant) {
for (const auto &device : participant->getPrivate()->getDevices())
notifyParticipantDevice(notify, device);
}
void LocalConferenceEventHandlerPrivate::notifyParticipantDevice (const string &notify, const shared_ptr<ParticipantDevice> &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<unsigned int>(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<long>(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<ConferenceParticipantEvent> setAdminEvent = static_pointer_cast<ConferenceParticipantEvent>(eventLog);
body = createNotifyParticipantAdmined(
body = createNotifyParticipantAdminStatusChanged(
setAdminEvent->getParticipantAddress(),
true,
eventNotifyId
......@@ -186,7 +141,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyMultipart (int notifyId)
case EventLog::Type::ConferenceParticipantUnsetAdmin: {
shared_ptr<ConferenceParticipantEvent> unsetAdminEvent = static_pointer_cast<ConferenceParticipantEvent>(eventLog);
body = createNotifyParticipantAdmined(
body = createNotifyParticipantAdminStatusChanged(
unsetAdminEvent->getParticipantAddress(),
false,
eventNotifyId
......@@ -263,51 +218,37 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const A
return createNotify(confInfo, notifyId);
}
string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const Address &addr, int notifyId) {
string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdminStatusChanged (const Address &addr, bool isAdmin, int notifyId) {
string entity = conf->getConferenceAddress().asString();
ConferenceType confInfo = ConferenceType(entity);
UsersType users;
confInfo.setUsers(users);
UserType user = UserType();
UserRolesType roles;
user.setRoles(roles);
user.setEntity(addr.asStringUriOnly());
user.setState(StateType::deleted);
user.getRoles()->getEntry().push_back(isAdmin ? "admin" : "participant");
user.setState(StateType::partial);
confInfo.getUsers()->getUser().push_back(user);
return createNotify(confInfo, notifyId);
}
string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const Address &addr, bool isAdmin, int 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();
UserRolesType roles;
user.setRoles(roles);
user.setEntity(addr.asStringUriOnly());
user.getRoles()->getEntry().push_back(isAdmin ? "admin" : "participant");
user.setState(StateType::partial);
user.setState(StateType::deleted);
confInfo.getUsers()->getUser().push_back(user);
return createNotify(confInfo, notifyId);
}
string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged (int notifyId) {
return createNotifySubjectChanged(conf->getSubject(), notifyId);
}
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);
}
string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceAdded (const Address &addr, const Address &gruu, int notifyId) {
string entity = conf->getConferenceAddress().asString();
ConferenceType confInfo = ConferenceType(entity);
......@@ -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<LocalConferenceEventHandlerPrivate *>(
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<unsigned int>(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<long>(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 &notify, const shared_ptr<Participant> &participant) {
for (const auto &device : participant->getPrivate()->getDevices())
notifyParticipantDevice(notify, device);
}
void LocalConferenceEventHandlerPrivate::notifyParticipantDevice (const string &notify, const shared_ptr<ParticipantDevice> &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<ConferenceParticipantEvent> LocalConferenceEventHandler::notifyPartic
shared_ptr<ConferenceParticipantEvent> LocalConferenceEventHandler::notifyParticipantSetAdmin (const Address &addr, bool isAdmin) {
L_D();
d->notifyAll(d->createNotifyParticipantAdmined(addr, isAdmin));
d->notifyAll(d->createNotifyParticipantAdminStatusChanged(addr, isAdmin));
shared_ptr<ConferenceParticipantEvent> event = make_shared<ConferenceParticipantEvent>(
isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin,
time(nullptr),
......
......@@ -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<CallSession> getSession () const { return mSession; }
inline void setSession (std::shared_ptr<CallSession> 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<CallSession> mSession;
LinphoneEvent *mConferenceSubscribeEvent = nullptr;
State mState = State::Joining;
L_DISABLE_COPY(ParticipantDevice);
};
......
......@@ -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:
......
......@@ -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");
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment