From 412c301f985772ae60c34674694fa4e02c24eae5 Mon Sep 17 00:00:00 2001 From: Nicolas Vengeon <nicolas.vengeon@savoirfairelinux.com> Date: Tue, 25 Oct 2022 17:38:13 -0400 Subject: [PATCH] call: add media transport information https://git.jami.net/savoirfairelinux/jami-client-qt/-/issues/510#510 Change-Id: Ie09ebd95ba161559c5c08b7e0618d6e87ecca1ee --- src/jami/call_const.h | 4 ++ src/media/video/video_rtp_session.cpp | 6 ++ src/media/video/video_rtp_session.h | 2 + src/sip/sipcall.cpp | 44 +++++++++++---- test/unitTest/call/call.cpp | 80 ++++++++++++++++++++++++++- 5 files changed, 125 insertions(+), 11 deletions(-) diff --git a/src/jami/call_const.h b/src/jami/call_const.h index 0088c6b383..541e184530 100644 --- a/src/jami/call_const.h +++ b/src/jami/call_const.h @@ -60,6 +60,10 @@ constexpr static char VIDEO_SOURCE[] = "VIDEO_SOURCE"; constexpr static char AUDIO_ONLY[] = "AUDIO_ONLY"; constexpr static char AUDIO_CODEC[] = "AUDIO_CODEC"; constexpr static char VIDEO_CODEC[] = "VIDEO_CODEC"; +constexpr static char SOCKETS[] = "SOCKETS"; +constexpr static char VIDEO_MIN_BITRATE[] = "VIDEO_MIN_BITRATE"; +constexpr static char VIDEO_BITRATE[] = "VIDEO_BITRATE"; +constexpr static char VIDEO_MAX_BITRATE[] = "VIDEO_MAX_BITRATE"; } // namespace Details diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp index b59e8a0d48..2957f77727 100644 --- a/src/media/video/video_rtp_session.cpp +++ b/src/media/video/video_rtp_session.cpp @@ -78,6 +78,12 @@ VideoRtpSession::~VideoRtpSession() JAMI_DBG("[%p] Video RTP session destroyed", this); } +const VideoBitrateInfo& +VideoRtpSession::getVideoBitrateInfo() +{ + return videoBitrateInfo_; +} + /// Setup internal VideoBitrateInfo structure from media descriptors. /// void diff --git a/src/media/video/video_rtp_session.h b/src/media/video/video_rtp_session.h index 8071d0546a..4a7f2f0629 100644 --- a/src/media/video/video_rtp_session.h +++ b/src/media/video/video_rtp_session.h @@ -100,6 +100,8 @@ public: void initRecorder(std::shared_ptr<MediaRecorder>& rec) override; void deinitRecorder(std::shared_ptr<MediaRecorder>& rec) override; + const VideoBitrateInfo& getVideoBitrateInfo(); + bool hasConference() { return conference_; } std::shared_ptr<VideoInput>& getVideoLocal() { return videoLocal_; } diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp index d7df507bae..07eab27079 100644 --- a/src/sip/sipcall.cpp +++ b/src/sip/sipcall.cpp @@ -2977,19 +2977,39 @@ SIPCall::getDetails() const details.emplace(libjami::Call::Details::PEER_HOLDING, peerHolding_ ? TRUE_STR : FALSE_STR); -#ifdef ENABLE_VIDEO for (auto const& stream : rtpStreams_) { - if (stream.mediaAttribute_->type_ != MediaType::MEDIA_VIDEO) - continue; - details.emplace(libjami::Call::Details::VIDEO_SOURCE, stream.mediaAttribute_->sourceUri_); - if (auto const& rtpSession = stream.rtpSession_) { - if (auto codec = rtpSession->getCodec()) - details.emplace(libjami::Call::Details::VIDEO_CODEC, codec->systemCodecInfo.name); - else - details.emplace(libjami::Call::Details::VIDEO_CODEC, ""); + if (stream.mediaAttribute_->type_ == MediaType::MEDIA_VIDEO) { + details.emplace(libjami::Call::Details::VIDEO_SOURCE, + stream.mediaAttribute_->sourceUri_); + if (auto const& rtpSession = stream.rtpSession_) { + if (auto codec = rtpSession->getCodec()) { + details.emplace(libjami::Call::Details::VIDEO_CODEC, + codec->systemCodecInfo.name); + details.emplace(libjami::Call::Details::VIDEO_MIN_BITRATE, + std::to_string(codec->systemCodecInfo.minBitrate)); + details.emplace(libjami::Call::Details::VIDEO_MAX_BITRATE, + std::to_string(codec->systemCodecInfo.maxBitrate)); + const auto& curvideoRtpSession + = std::static_pointer_cast<video::VideoRtpSession>(rtpSession); + if (curvideoRtpSession) { + auto curBitrate = curvideoRtpSession->getVideoBitrateInfo() + .videoBitrateCurrent; + details.emplace(libjami::Call::Details::VIDEO_BITRATE, + std::to_string(curBitrate)); + } + } else + details.emplace(libjami::Call::Details::VIDEO_CODEC, ""); + } + } else if (stream.mediaAttribute_->type_ == MediaType::MEDIA_AUDIO) { + if (auto const& rtpSession = stream.rtpSession_) { + if (auto codec = rtpSession->getCodec()) { + details.emplace(libjami::Call::Details::AUDIO_CODEC, + codec->systemCodecInfo.name); + } else + details.emplace(libjami::Call::Details::AUDIO_CODEC, ""); + } } } -#endif #if HAVE_RINGNS if (not peerRegisteredName_.empty()) @@ -3023,6 +3043,10 @@ SIPCall::getDetails() const } } #endif + if (auto transport = getIceMedia()) { + if (transport && transport->isRunning()) + details.emplace(libjami::Call::Details::SOCKETS, transport->link().c_str()); + } return details; } diff --git a/test/unitTest/call/call.cpp b/test/unitTest/call/call.cpp index f282a5af53..8a76962510 100644 --- a/test/unitTest/call/call.cpp +++ b/test/unitTest/call/call.cpp @@ -32,10 +32,12 @@ #include "../../test_runner.h" #include "jami.h" #include "account_const.h" - +#include "media_const.h" +#include "call_const.h" #include "common.h" using namespace libjami::Account; +using namespace libjami::Call::Details; namespace jami { namespace test { @@ -65,6 +67,7 @@ private: void testStopSearching(); void testDeclineMultiDevice(); void testTlsInfosPeerCertificate(); + void testSocketInfos(); CPPUNIT_TEST_SUITE(CallTest); CPPUNIT_TEST(testCall); @@ -72,6 +75,7 @@ private: CPPUNIT_TEST(testStopSearching); CPPUNIT_TEST(testDeclineMultiDevice); CPPUNIT_TEST(testTlsInfosPeerCertificate); + CPPUNIT_TEST(testSocketInfos); CPPUNIT_TEST_SUITE_END(); }; @@ -359,6 +363,80 @@ CallTest::testTlsInfosPeerCertificate() CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&] { return callStopped == 2; })); } +void +CallTest::testSocketInfos() +{ + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + auto bobUri = bobAccount->getUsername(); + auto aliceUri = aliceAccount->getUsername(); + + std::mutex mtx; + std::unique_lock<std::mutex> lk {mtx}; + std::condition_variable cv; + std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; + std::atomic<int> callStopped {0}; + std::string bobCallId; + std::string aliceCallState; + // Watch signals + confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::IncomingCallWithMedia>( + [&](const std::string& accountId, + const std::string& callId, + const std::string&, + const std::vector<std::map<std::string, std::string>>&) { + if (accountId == bobId) + bobCallId = callId; + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::StateChange>( + [&](const std::string& accountId, const std::string&, const std::string& state, signed) { + if (accountId == aliceId) + aliceCallState = state; + if (state == "OVER") { + callStopped += 1; + if (callStopped == 2) + cv.notify_one(); + } + })); + auto mediaReady = false; + confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::MediaNegotiationStatus>( + [&](const std::string& callId, + const std::string& event, + const std::vector<std::map<std::string, std::string>>&) { + if (event == libjami::Media::MediaNegotiationStatusEvents::NEGOTIATION_SUCCESS) { + mediaReady = true; + cv.notify_one(); + } + })); + libjami::registerSignalHandlers(confHandlers); + + JAMI_INFO("Start call between alice and Bob"); + auto callId = libjami::placeCallWithMedia(aliceId, bobUri, {}); + + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&] { return !bobCallId.empty(); })); + + Manager::instance().answerCall(bobId, bobCallId); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&] { + return aliceCallState == "CURRENT" && mediaReady; + })); + + JAMI_INFO("Detail debug"); + auto details = libjami::getCallDetails(aliceId, callId); + for (auto i = details.begin(); i != details.end(); i++) { + JAMI_INFO("%s : %s", i->first.c_str(), i->second.c_str()); + } + auto call = std::dynamic_pointer_cast<SIPCall>(aliceAccount->getCall(callId)); + auto transport = call->getIceMedia(); + CPPUNIT_ASSERT(transport); + CPPUNIT_ASSERT(transport->isRunning()); + CPPUNIT_ASSERT(transport->link().c_str() == details[libjami::Call::Details::SOCKETS]); + + JAMI_INFO("Stop call between alice and Bob"); + callStopped = 0; + Manager::instance().hangupCall(aliceId, callId); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&] { return callStopped == 2; })); +} + } // namespace test } // namespace jami -- GitLab