diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index fe8af1023..ddadceb3e 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -289,6 +289,12 @@ LINPHONE_PUBLIC bctbx_list_t * linphone_chat_room_get_participants (const Linpho */ LINPHONE_PUBLIC const char * linphone_chat_room_get_subject (const LinphoneChatRoom *cr); +/** + * Leave a chat room. + * @param[in] cr A LinphoneChatRoom object + */ +LINPHONE_PUBLIC void linphone_chat_room_leave (LinphoneChatRoom *cr); + /** * Remove a participant of a chat room. * @param[in] cr A LinphoneChatRoom object diff --git a/include/linphone/enums/chat-room-enums.h b/include/linphone/enums/chat-room-enums.h index fd83868ae..8a4318aa8 100644 --- a/include/linphone/enums/chat-room-enums.h +++ b/include/linphone/enums/chat-room-enums.h @@ -27,6 +27,7 @@ F(Instantiated) \ F(CreationPending) \ F(Created) \ + F(TerminationPending) \ F(Terminated) \ F(CreationFailed) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 9df110d4e..26eb20ee9 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -248,6 +248,10 @@ const char * linphone_chat_room_get_subject (const LinphoneChatRoom *cr) { return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getSubject()); } +void linphone_chat_room_leave (LinphoneChatRoom *cr) { + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->leave(); +} + void linphone_chat_room_remove_participant (LinphoneChatRoom *cr, LinphoneParticipant *participant) { L_GET_CPP_PTR_FROM_C_OBJECT(cr)->removeParticipant(L_GET_CPP_PTR_FROM_C_OBJECT(participant)); } diff --git a/src/chat/basic-chat-room.cpp b/src/chat/basic-chat-room.cpp index 0ceccf09e..769abf5d9 100644 --- a/src/chat/basic-chat-room.cpp +++ b/src/chat/basic-chat-room.cpp @@ -69,6 +69,8 @@ const string &BasicChatRoom::getSubject () const { return d->subject; } +void BasicChatRoom::leave () {} + void BasicChatRoom::removeParticipant (const shared_ptr &participant) { lError() << "removeParticipant() is not allowed on a BasicChatRoom"; } diff --git a/src/chat/basic-chat-room.h b/src/chat/basic-chat-room.h index 361a972f6..62c15c849 100644 --- a/src/chat/basic-chat-room.h +++ b/src/chat/basic-chat-room.h @@ -41,6 +41,7 @@ public: int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; + void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; void setSubject (const std::string &subject) override; diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index c0cb30abe..5deeb9b26 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -59,11 +59,6 @@ ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, this->subject = subject; } -ClientGroupChatRoom::~ClientGroupChatRoom () { - shared_ptr session = focus->getPrivate()->getSession(); - session->terminate(); -} - // ----------------------------------------------------------------------------- void ClientGroupChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { @@ -119,6 +114,19 @@ const string &ClientGroupChatRoom::getSubject () const { return RemoteConference::getSubject(); } +void ClientGroupChatRoom::leave () { + L_D(); + eventHandler->unsubscribe(); + shared_ptr session = focus->getPrivate()->getSession(); + if (session) + session->terminate(); + else { + session = d->createSession(); + session->startInvite(nullptr, "", nullptr); + } + d->setState(ChatRoom::State::TerminationPending); +} + void ClientGroupChatRoom::removeParticipant (const shared_ptr &participant) { // TODO } @@ -219,18 +227,27 @@ void ClientGroupChatRoom::onSubjectChanged (const std::string &subject) { // ----------------------------------------------------------------------------- -void ClientGroupChatRoom::onCallSessionSetTerminated (const std::shared_ptr session) { +void ClientGroupChatRoom::onCallSessionSetReleased (const std::shared_ptr session) { if (session == focus->getPrivate()->getSession()) focus->getPrivate()->removeSession(); } void ClientGroupChatRoom::onCallSessionStateChanged (const std::shared_ptr session, LinphoneCallState state, const string &message) { + L_D(); if (state == LinphoneCallConnected) { - Address addr(session->getRemoteContact()); - addr.clean(); - onConferenceCreated(addr); - if (session->getRemoteContactAddress()->hasParam("isfocus")) - eventHandler->subscribe(conferenceAddress); + if (d->state == ChatRoom::State::CreationPending) { + Address addr(session->getRemoteContact()); + addr.clean(); + onConferenceCreated(addr); + if (session->getRemoteContactAddress()->hasParam("isfocus")) + eventHandler->subscribe(conferenceAddress); + } else if (d->state == ChatRoom::State::TerminationPending) { + focus->getPrivate()->getSession()->terminate(); + } + } else { + if ((state == LinphoneCallReleased) && (d->state == ChatRoom::State::TerminationPending)) { + onConferenceTerminated(conferenceAddress); + } } } diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index e5faf94d3..a535f751d 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -38,7 +38,7 @@ class ClientGroupChatRoomPrivate; class LINPHONE_PUBLIC ClientGroupChatRoom : public ChatRoom, public RemoteConference { public: ClientGroupChatRoom (LinphoneCore *core, const Address &me, const std::string &subject); - virtual ~ClientGroupChatRoom (); + virtual ~ClientGroupChatRoom () = default; public: /* ConferenceInterface */ @@ -49,6 +49,7 @@ public: int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; + void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; void setSubject (const std::string &subject) override; @@ -64,7 +65,7 @@ private: private: /* CallSessionListener */ - void onCallSessionSetTerminated (const std::shared_ptr session) override; + void onCallSessionSetReleased (const std::shared_ptr session) override; void onCallSessionStateChanged (const std::shared_ptr session, LinphoneCallState state, const std::string &message) override; private: diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 3046a40f1..f29a70fea 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -165,6 +165,8 @@ const string &RealTimeTextChatRoom::getSubject () const { return d->subject; } +void RealTimeTextChatRoom::leave () {} + void RealTimeTextChatRoom::removeParticipant (const shared_ptr &participant) { lError() << "removeParticipant() is not allowed on a RealTimeTextChatRoom"; } diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h index 511bb15cc..9eacb9e3d 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/real-time-text-chat-room.h @@ -51,6 +51,7 @@ public: int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; + void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; void setSubject (const std::string &subject) override; diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index a897ae4b2..0829df832 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -42,6 +42,7 @@ public: virtual int getNbParticipants () const = 0; virtual std::list> getParticipants () const = 0; virtual const std::string &getSubject () const = 0; + virtual void leave () = 0; virtual void removeParticipant (const std::shared_ptr &participant) = 0; virtual void removeParticipants (const std::list> &participants) = 0; virtual void setSubject (const std::string &subject) = 0; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 2d17c5010..eb274d158 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -76,6 +76,8 @@ const string &Conference::getSubject () const { return subject; } +void Conference::leave () {} + void Conference::removeParticipant (const shared_ptr &participant) { lError() << "Conference class does not handle removeParticipant() generically"; } @@ -171,6 +173,14 @@ shared_ptr Conference::findParticipant (const Address &addr) const return nullptr; } +shared_ptr Conference::findParticipant (const shared_ptr session) { + for (const auto &participant : participants) { + if (participant->getPrivate()->getSession() == session) + return participant; + } + return nullptr; +} + bool Conference::isMe (const Address &addr) const { Address cleanedAddress = me->getAddress(); cleanedAddress.setPort(0); diff --git a/src/conference/conference.h b/src/conference/conference.h index 43da4651a..5dafd55f2 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -55,6 +55,7 @@ public: int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; + void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; void setSubject (const std::string &subject) override; @@ -80,6 +81,7 @@ protected: explicit Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); std::shared_ptr findParticipant (const Address &addr) const; + std::shared_ptr findParticipant (const std::shared_ptr session); bool isMe (const Address &addr) const ; protected: diff --git a/src/conference/participant.h b/src/conference/participant.h index 9d5c01ce1..f0916fc1b 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -37,6 +37,7 @@ class Participant : public Object { friend class CallPrivate; friend class ClientGroupChatRoom; friend class ClientGroupChatRoomPrivate; + friend class Conference; friend class LocalConference; friend class MediaSessionPrivate; friend class RemoteConference;