diff --git a/coreapi/chat.c b/coreapi/chat.c index daf9b7bb6..b453892eb 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -138,6 +138,7 @@ LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, LinphoneChatRoom *_linphone_core_join_client_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr) { LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); + _linphone_core_add_group_chat_room(lc, L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceAddress()->asStringUriOnly().c_str(), linphone_chat_room_ref(cr)); lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); return cr; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 4948d1d5f..7dedc0672 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -45,6 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mediastreamer2/msjpegwriter.h" #include "mediastreamer2/msogl.h" #include "mediastreamer2/msvolume.h" +#include "chat/client-group-chat-room-p.h" #include "conference/remote-conference-event-handler.h" // For migration purpose. @@ -2115,11 +2116,13 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve ms_message("Notify presence for list %p", list); linphone_friend_list_notify_presence_received(list, lev, body); } - } else if (strcmp(notified_event, "Conference") == 0) { - LinphonePrivate::RemoteConferenceEventHandler *handler = - reinterpret_cast(linphone_event_get_user_data(lev)); - if (handler) - handler->notifyReceived(reinterpret_cast(linphone_content_get_buffer(body))); + } else if (strcmp(notified_event, "conference") == 0) { + const LinphoneAddress *resource = linphone_event_get_resource(lev); + char *resourceUri = linphone_address_as_string_uri_only(resource); + LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, resourceUri); + bctbx_free(resourceUri); + if (cr) + L_GET_PRIVATE_FROM_C_OBJECT(cr, ClientGroupChatRoom)->notifyReceived(linphone_content_get_string_buffer(body)); } } @@ -2251,6 +2254,7 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL); } // else linphone_core_start will be called after the remote provisioning (see linphone_core_iterate) lc->bw_controller = ms_bandwidth_controller_new(); + lc->group_chat_rooms = bctbx_mmap_cchar_new(); } LinphoneCore *_linphone_core_new_with_config(LinphoneCoreCbs *cbs, struct _LpConfig *config, void *userdata) { @@ -5946,6 +5950,8 @@ static void linphone_core_uninit(LinphoneCore *lc) } lc->chatrooms = bctbx_list_free_with_data(lc->chatrooms, (MSIterateFunc)linphone_chat_room_release); + if (lc->group_chat_rooms) + bctbx_mmap_cchar_delete_with_data(lc->group_chat_rooms, (void (*)(void *))linphone_chat_room_unref); linphone_core_set_state(lc,LinphoneGlobalShutdown,"Shutting down"); #ifdef VIDEO_ENABLED @@ -7077,6 +7083,32 @@ const char * linphone_core_get_conference_factory_uri(const LinphoneCore *lc) { return lp_config_get_string(linphone_core_get_config(lc), "misc", "conference_factory_uri", nullptr); } +bool_t _linphone_core_has_group_chat_room(const LinphoneCore *lc, const char *id) { + bool_t result; + bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, id); + bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); + result = !bctbx_iterator_cchar_equals(it, endit); + bctbx_iterator_cchar_delete(endit); + bctbx_iterator_cchar_delete(it); + return result; +} + +void _linphone_core_add_group_chat_room(LinphoneCore *lc, const char *id, LinphoneChatRoom *cr) { + bctbx_pair_t *pair = reinterpret_cast(bctbx_pair_cchar_new(id, linphone_chat_room_ref(cr))); + bctbx_map_cchar_insert_and_delete(lc->group_chat_rooms, pair); +} + +LinphoneChatRoom *_linphone_core_find_group_chat_room(const LinphoneCore *lc, const char *id) { + LinphoneChatRoom *result = nullptr; + bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, id); + bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); + if (!bctbx_iterator_cchar_equals(it, endit)) + result = reinterpret_cast(bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it))); + bctbx_iterator_cchar_delete(endit); + bctbx_iterator_cchar_delete(it); + return result; +} + void linphone_core_set_tls_cert(LinphoneCore *lc, const char *tls_cert) { if (lc->tls_cert) { ms_free(lc->tls_cert); diff --git a/coreapi/private.h b/coreapi/private.h index 31bbda276..74a551576 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -449,6 +449,8 @@ bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription extern LinphonePrivate::Sal::Callbacks linphone_sal_callbacks; LINPHONE_PUBLIC bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LINPHONE_PUBLIC bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc); +bool_t _linphone_core_has_group_chat_room(const LinphoneCore *lc, const char *id); +void _linphone_core_add_group_chat_room(LinphoneCore *lc, const char *id, LinphoneChatRoom *cr); void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); @@ -832,6 +834,7 @@ struct _LinphoneCore MSList *queued_calls; /* used by the autoreplier */ MSList *call_logs; MSList *chatrooms; + bctbx_map_t *group_chat_rooms; int max_call_logs; int missed_calls; VideoPreview *previewstream; diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h index ccb993246..0431d80de 100644 --- a/coreapi/tester_utils.h +++ b/coreapi/tester_utils.h @@ -94,6 +94,7 @@ LINPHONE_PUBLIC mblk_t *_linphone_call_stats_get_received_rtcp (const LinphoneCa LINPHONE_PUBLIC LinphoneQualityReporting *linphone_call_log_get_quality_reporting(LinphoneCallLog *call_log); LINPHONE_PUBLIC reporting_session_report_t **linphone_quality_reporting_get_reports(LinphoneQualityReporting *qreporting); +LINPHONE_PUBLIC LinphoneChatRoom *_linphone_core_find_group_chat_room(const LinphoneCore *lc, const char *id); LINPHONE_PUBLIC bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc, LinphoneFriendList *list); diff --git a/src/chat/client-group-chat-room-p.h b/src/chat/client-group-chat-room-p.h index 7bc90bac5..54e8f9b60 100644 --- a/src/chat/client-group-chat-room-p.h +++ b/src/chat/client-group-chat-room-p.h @@ -38,6 +38,7 @@ public: virtual ~ClientGroupChatRoomPrivate () = default; std::shared_ptr createSession (); + void notifyReceived (std::string body); private: L_DECLARE_PUBLIC(ClientGroupChatRoom); diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 3b98f9448..b5637602b 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -50,6 +50,11 @@ shared_ptr ClientGroupChatRoomPrivate::createSession () { return session; } +void ClientGroupChatRoomPrivate::notifyReceived (string body) { + L_Q(); + q->eventHandler->notifyReceived(body); +} + // ============================================================================= ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, const string &uri, const string &subject) @@ -169,6 +174,7 @@ void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { L_D(); conferenceAddress = addr; d->setState(ChatRoom::State::Created); + _linphone_core_add_group_chat_room(d->core, addr.asStringUriOnly().c_str(), L_GET_C_BACK_PTR(this)); } void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 9794b706c..2b271e2d1 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -189,9 +189,11 @@ shared_ptr Conference::findParticipant (const shared_ptrgetAddress(); - cleanedAddress.setPort(0); - return addr.equal(cleanedAddress); + Address cleanedMe = me->getAddress(); + cleanedMe.setPort(0); + Address cleanedAddr = addr; + cleanedAddr.setPort(0); + return cleanedAddr.equal(cleanedMe); } LINPHONE_END_NAMESPACE diff --git a/src/conference/conference.h b/src/conference/conference.h index 1d30d0b80..57a4cdb44 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -46,6 +46,9 @@ public: LinphoneCore * getCore () const { return core; } + std::shared_ptr findParticipant (const Address &addr) const; + std::shared_ptr findParticipant (const std::shared_ptr &session) const; + public: /* ConferenceInterface */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; @@ -81,8 +84,6 @@ private: 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) const; bool isMe (const Address &addr) const ; protected: diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 8d5896229..2e216e5c2 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -18,7 +18,7 @@ */ #include "conference/local-conference.h" -#include "conference/participant.h" +#include "conference/participant-p.h" #include "local-conference-event-handler.h" #include "object/object-p.h" @@ -78,15 +78,15 @@ void LocalConferenceEventHandlerPrivate::notifyFullState (string notify, Linphon void LocalConferenceEventHandlerPrivate::notifyAllExcept (string notify, const Address &addr) { for (const auto &participant : conf->getParticipants()) { - if (addr != participant->getAddress()) { - this->sendNotify(notify, addr); - } + if (participant->getPrivate()->isSubscribedToConferenceEventPackage() && (addr != participant->getAddress())) + sendNotify(notify, addr); } } void LocalConferenceEventHandlerPrivate::notifyAll (string notify) { for (const auto &participant : conf->getParticipants()) { - this->sendNotify(notify, participant->getAddress()); + if (participant->getPrivate()->isSubscribedToConferenceEventPackage()) + sendNotify(notify, participant->getAddress()); } } @@ -199,7 +199,17 @@ LocalConferenceEventHandler::~LocalConferenceEventHandler () { void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { L_D(); - d->notifyFullState(d->createNotifyFullState(), lev); + const LinphoneAddress *lAddr = linphone_event_get_from(lev); + char *addrStr = linphone_address_as_string(lAddr); + shared_ptr participant = d->conf->findParticipant(Address(addrStr)); + bctbx_free(addrStr); + if (participant) { + if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionActive) { + participant->getPrivate()->subscribeToConferenceEventPackage(true); + d->notifyFullState(d->createNotifyFullState(), lev); + } else if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionTerminated) + participant->getPrivate()->subscribeToConferenceEventPackage(false); + } } void LocalConferenceEventHandler::notifyParticipantAdded (const Address &addr) { diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index 363820f9b..f862c54a4 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -41,12 +41,15 @@ public: std::shared_ptr createSession (const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener); std::shared_ptr getSession () const { return session; } + bool isSubscribedToConferenceEventPackage () const { return _isSubscribedToConferenceEventPackage; } + void subscribeToConferenceEventPackage (bool value) { _isSubscribedToConferenceEventPackage = value; } void removeSession () { session = nullptr; } void setAddress (const Address &newAddr) { addr = newAddr; } private: Address addr; bool isAdmin = false; + bool _isSubscribedToConferenceEventPackage = false; std::shared_ptr session; L_DECLARE_PUBLIC(Participant); diff --git a/src/conference/participant.h b/src/conference/participant.h index dd5de40ad..7b092bb7f 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -39,6 +39,8 @@ class Participant : public Object { friend class ClientGroupChatRoomPrivate; friend class Conference; friend class LocalConference; + friend class LocalConferenceEventHandler; + friend class LocalConferenceEventHandlerPrivate; friend class MediaSessionPrivate; friend class RemoteConference;