소스 검색

Add a media handler to respond to remb bitrate

Vladimir Voronin 1 년 전
부모
커밋
f6c8073a31
8개의 변경된 파일108개의 추가작업 그리고 0개의 파일을 삭제
  1. 2 0
      CMakeLists.txt
  2. 35 0
      include/rtc/rembhandler.hpp
  3. 4 0
      include/rtc/rtc.h
  4. 1 0
      include/rtc/rtc.hpp
  5. 2 0
      include/rtc/rtp.hpp
  6. 12 0
      src/capi.cpp
  7. 44 0
      src/rembhandler.cpp
  8. 8 0
      src/rtp.cpp

+ 2 - 0
CMakeLists.txt

@@ -87,6 +87,7 @@ set(LIBDATACHANNEL_SOURCES
 	${CMAKE_CURRENT_SOURCE_DIR}/src/capi.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/plihandler.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/pacinghandler.cpp
+	${CMAKE_CURRENT_SOURCE_DIR}/src/rembhandler.cpp
 )
 
 set(LIBDATACHANNEL_HEADERS
@@ -123,6 +124,7 @@ set(LIBDATACHANNEL_HEADERS
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/utils.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/plihandler.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/pacinghandler.hpp
+	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rembhandler.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/version.h
 )
 

+ 35 - 0
include/rtc/rembhandler.hpp

@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2024 Vladimir Voronin
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef RTC_REMB_RESPONDER_H
+#define RTC_REMB_RESPONDER_H
+
+#if RTC_ENABLE_MEDIA
+
+#include "mediahandler.hpp"
+#include "utils.hpp"
+
+namespace rtc {
+
+/// Responds to REMB messages sent by the receiver.
+class RTC_CPP_EXPORT RembHandler final : public MediaHandler {
+    rtc::synchronized_callback<unsigned int, unsigned int> mOnRemb;
+
+public:
+	/// Constructs the RembResponder object to notify whenever a bitrate
+	/// @param onRemb The callback that gets called whenever a bitrate by the receiver
+    RembHandler(std::function<void(unsigned int, unsigned int)> onRemb);
+
+	void incoming(message_vector &messages, const message_callback &send) override;
+};
+
+}
+
+#endif // RTC_ENABLE_MEDIA
+
+#endif // RTC_REMB_RESPONDER_H

+ 4 - 0
include/rtc/rtc.h

@@ -170,6 +170,7 @@ typedef void *(RTC_API *rtcInterceptorCallbackFunc)(int pc, const char *message,
 typedef void(RTC_API *rtcBufferedAmountLowCallbackFunc)(int id, void *ptr);
 typedef void(RTC_API *rtcAvailableCallbackFunc)(int id, void *ptr);
 typedef void(RTC_API *rtcPliHandlerCallbackFunc)(int tr, void *ptr);
+typedef void(RTC_API *rtcRembHandlerCallbackFunc)(int tr, unsigned int numSSRC, unsigned int bitrate, void *ptr);
 
 // Log
 
@@ -409,6 +410,9 @@ RTC_C_EXPORT int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPackets
 // Chain PliHandler on track
 RTC_C_EXPORT int rtcChainPliHandler(int tr, rtcPliHandlerCallbackFunc cb);
 
+// Chain RembHandler on track
+RTC_C_EXPORT int rtcChainRembHandler(int tr, rtcRembHandlerCallbackFunc cb);
+
 // Transform seconds to timestamp using track's clock rate, result is written to timestamp
 RTC_C_EXPORT int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp);
 

+ 1 - 0
include/rtc/rtc.hpp

@@ -34,6 +34,7 @@
 #include "h265rtppacketizer.hpp"
 #include "mediahandler.hpp"
 #include "plihandler.hpp"
+#include "rembhandler.hpp"
 #include "pacinghandler.hpp"
 #include "rtcpnackresponder.hpp"
 #include "rtcpreceivingsession.hpp"

+ 2 - 0
include/rtc/rtp.hpp

@@ -274,6 +274,8 @@ struct RTC_CPP_EXPORT RtcpRemb {
 	void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int in_bitrate);
 	void setBitrate(unsigned int numSSRC, unsigned int in_bitrate);
 	void setSsrc(int iterator, SSRC newSssrc);
+	unsigned int getNumSSRC();
+	unsigned int getBitrate();
 };
 
 struct RTC_CPP_EXPORT RtcpPli {

+ 12 - 0
src/capi.cpp

@@ -1331,6 +1331,18 @@ int rtcChainPliHandler(int tr, rtcPliHandlerCallbackFunc cb) {
 	});
 }
 
+int rtcChainRembHandler(int tr, rtcRembHandlerCallbackFunc cb) {
+	return wrap([&] {
+		auto track = getTrack(tr);
+		auto handler = std::make_shared<RembHandler>([tr, cb](unsigned int numSSRC, unsigned int bitrate) {
+			if (auto ptr = getUserPointer(tr))
+				cb(tr, numSSRC, bitrate, *ptr);
+		});
+		track->chainMediaHandler(handler);
+		return RTC_ERR_SUCCESS;
+	});
+}
+
 int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp) {
 	return wrap([&] {
 		auto config = getRtpConfig(id);

+ 44 - 0
src/rembhandler.cpp

@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2024 Vladimir Voronin
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#include "rembhandler.hpp"
+#include "rtp.hpp"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <arpa/inet.h>
+#endif
+
+#if RTC_ENABLE_MEDIA
+
+namespace rtc {
+
+RembHandler::RembHandler(std::function<void(unsigned int, unsigned int)> onRemb) : mOnRemb(onRemb) {}
+
+void RembHandler::incoming(message_vector &messages, [[maybe_unused]] const message_callback &send) {
+	for (const auto &message : messages) {
+		size_t offset = 0;
+		while ((sizeof(RtcpHeader) + offset) <= message->size()) {
+			auto header = reinterpret_cast<RtcpHeader *>(message->data() + offset);
+			uint8_t payload_type = header->payloadType();
+
+			if (payload_type == 206 && header->reportCount() == 15) {
+                auto remb = reinterpret_cast<RtcpRemb *>(message->data() + offset);
+                mOnRemb(remb->getNumSSRC(), remb->getBitrate());
+                break;
+			}
+
+			offset += header->lengthInBytes();
+		}
+	}
+}
+
+} // namespace rtc
+
+#endif // RTC_ENABLE_MEDIA

+ 8 - 0
src/rtp.cpp

@@ -558,6 +558,14 @@ void RtcpRemb::setBitrate(unsigned int numSSRC, unsigned int in_bitrate) {
 
 void RtcpRemb::setSsrc(int iterator, SSRC newSssrc) { _ssrc[iterator] = htonl(newSssrc); }
 
+unsigned int RtcpRemb::getNumSSRC() { return ntohl(_bitrate) >> 24u; }
+
+unsigned int RtcpRemb::getBitrate() {
+	uint32_t br = ntohl(_bitrate);
+	uint8_t exp = (br << 8u) >> 26u;
+	return (br & 0x3FFFF) * (unsigned int)pow(exp, 2);
+}
+
 unsigned int RtcpPli::Size() { return sizeof(RtcpFbHeader); }
 
 void RtcpPli::preparePacket(SSRC messageSSRC) {