Line data Source code
1 : /*
2 : * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 : #pragma once
18 :
19 : #include "media/rtp_session.h"
20 : #include "media/media_device.h"
21 :
22 : #include "media_stream.h"
23 : #include "threadloop.h"
24 :
25 : #include <string>
26 : #include <memory>
27 :
28 : namespace jami {
29 : class CongestionControl;
30 : class Conference;
31 : class MediaRecorder;
32 : } // namespace jami
33 :
34 : namespace jami {
35 : namespace video {
36 :
37 : class VideoInput;
38 : class VideoMixer;
39 : class VideoSender;
40 : class VideoReceiveThread;
41 :
42 : struct RTCPInfo
43 : {
44 : float packetLoss;
45 : unsigned int jitter;
46 : unsigned int nb_sample;
47 : float latency;
48 : };
49 :
50 : struct VideoBitrateInfo
51 : {
52 : unsigned videoBitrateCurrent;
53 : unsigned videoBitrateMin;
54 : unsigned videoBitrateMax;
55 : unsigned videoQualityCurrent;
56 : unsigned videoQualityMin;
57 : unsigned videoQualityMax;
58 : unsigned cptBitrateChecking;
59 : unsigned maxBitrateChecking;
60 : float packetLostThreshold;
61 : };
62 :
63 : class VideoRtpSession : public RtpSession, public std::enable_shared_from_this<VideoRtpSession>
64 : {
65 : public:
66 : using BaseType = RtpSession;
67 :
68 : VideoRtpSession(const std::string& callId,
69 : const std::string& streamId,
70 : const DeviceParams& localVideoParams,
71 : const std::shared_ptr<MediaRecorder>& rec);
72 : ~VideoRtpSession();
73 :
74 : void setRequestKeyFrameCallback(std::function<void(void)> cb);
75 :
76 : void updateMedia(const MediaDescription& send, const MediaDescription& receive) override;
77 :
78 : void start(std::unique_ptr<dhtnet::IceSocket> rtp_sock, std::unique_ptr<dhtnet::IceSocket> rtcp_sock) override;
79 : void restartSender() override;
80 : void stop() override;
81 : void setMuted(bool mute, Direction dir = Direction::SEND) override;
82 :
83 : /**
84 : * Set video orientation
85 : *
86 : * Send to the receive thread rotation to apply to the video (counterclockwise)
87 : *
88 : * @param rotation Rotation in degrees (counterclockwise)
89 : */
90 : void setRotation(int rotation);
91 : void forceKeyFrame();
92 : void bindMixer(VideoMixer* mixer);
93 : void unbindMixer();
94 : void enterConference(Conference& conference);
95 : void exitConference();
96 :
97 : void setChangeOrientationCallback(std::function<void(int)> cb);
98 : void initRecorder() override;
99 : void deinitRecorder() override;
100 :
101 : const VideoBitrateInfo& getVideoBitrateInfo();
102 :
103 351 : bool hasConference() { return conference_; }
104 :
105 462 : std::shared_ptr<VideoInput>& getVideoLocal() { return videoLocal_; }
106 :
107 : std::shared_ptr<VideoMixer>& getVideoMixer() { return videoMixer_; }
108 :
109 497 : std::shared_ptr<VideoReceiveThread>& getVideoReceive() { return receiveThread_; }
110 :
111 : private:
112 : void setupConferenceVideoPipeline(Conference& conference, Direction dir);
113 : void setupVideoPipeline();
114 : void startSender();
115 : void stopSender(bool forceStopSocket = false);
116 : void startReceiver();
117 : void stopReceiver(bool forceStopSocket = false);
118 : using clock = std::chrono::steady_clock;
119 : using time_point = clock::time_point;
120 :
121 : DeviceParams localVideoParams_;
122 :
123 : std::unique_ptr<VideoSender> sender_;
124 : std::shared_ptr<VideoReceiveThread> receiveThread_;
125 : Conference* conference_ {nullptr};
126 : std::shared_ptr<VideoMixer> videoMixer_;
127 : std::shared_ptr<VideoInput> videoLocal_;
128 : uint16_t initSeqVal_ = 0;
129 :
130 : std::function<void(void)> requestKeyFrameCallback_;
131 :
132 : bool check_RCTP_Info_RR(RTCPInfo&);
133 : bool check_RCTP_Info_REMB(uint64_t*);
134 : void adaptQualityAndBitrate();
135 : void storeVideoBitrateInfo();
136 : void setupVideoBitrateInfo();
137 : void checkReceiver();
138 : float getPonderateLoss(float lastLoss);
139 : void delayMonitor(int gradient, int deltaT);
140 : void dropProcessing(RTCPInfo* rtcpi);
141 : void delayProcessing(int br);
142 : void setNewBitrate(unsigned int newBR);
143 :
144 : // no packet loss can be calculated as no data in input
145 : static constexpr float NO_INFO_CALCULATED {-1.0};
146 : // bitrate and quality info struct
147 : VideoBitrateInfo videoBitrateInfo_;
148 : std::list<std::pair<time_point, float>> histoLoss_;
149 :
150 : // 5 tries in a row
151 : static constexpr unsigned MAX_ADAPTATIVE_BITRATE_ITERATION {5};
152 : // packet loss threshold
153 : static constexpr float PACKET_LOSS_THRESHOLD {1.0};
154 :
155 : InterruptedThreadLoop rtcpCheckerThread_;
156 : void processRtcpChecker();
157 :
158 : std::function<void(int)> changeOrientationCallback_;
159 :
160 : std::function<void(bool)> recordingStateCallback_;
161 :
162 : // interval in seconds between RTCP checkings
163 301 : std::chrono::seconds rtcp_checking_interval {4};
164 :
165 : time_point lastMediaRestart_ {time_point::min()};
166 : time_point last_REMB_inc_ {time_point::min()};
167 : time_point last_REMB_dec_ {time_point::min()};
168 : time_point lastBitrateDecrease {time_point::min()};
169 :
170 : unsigned remb_dec_cnt_ {0};
171 :
172 : std::unique_ptr<CongestionControl> cc;
173 :
174 : std::function<void(void)> cbKeyFrameRequest_;
175 :
176 : std::atomic<int> rotation_ {0};
177 :
178 : void attachRemoteRecorder(const MediaStream& ms);
179 : void attachLocalRecorder(const MediaStream& ms);
180 : };
181 :
182 : } // namespace video
183 : } // namespace jami
|