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