From 10711cbd8751316fecaf9f568f3db57f543d49f4 Mon Sep 17 00:00:00 2001 From: Arda Cinar Date: Wed, 4 Oct 2023 17:37:01 +0000 Subject: [PATCH] Add a media handler to respond to intra frame requests This introduces a PLIResponder class, which can be used for responding back with an intra frame after the receiver requests one with an FIR (Full Intra Request) or a PLI (Picture Loss Indicator) message. This is useful when a video is being streamed live and we can control the behavior of the video encoder. PLIResponder simply notifies its caller when a new intra frame is requested, which passes this request onto its video frame source. --- CMakeLists.txt | 2 ++ include/rtc/pliresponder.hpp | 31 ++++++++++++++++++++++++++++ src/pliresponder.cpp | 40 ++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 include/rtc/pliresponder.hpp create mode 100644 src/pliresponder.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d4d29eb1f..b4169d54b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,6 +92,7 @@ set(LIBDATACHANNEL_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpnackresponder.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/rtp.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/capi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/pliresponder.cpp ) set(LIBDATACHANNEL_HEADERS @@ -132,6 +133,7 @@ set(LIBDATACHANNEL_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/mediahandlerrootelement.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtcpnackresponder.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/utils.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/pliresponder.hpp ) set(LIBDATACHANNEL_IMPL_SOURCES diff --git a/include/rtc/pliresponder.hpp b/include/rtc/pliresponder.hpp new file mode 100644 index 000000000..172dd6204 --- /dev/null +++ b/include/rtc/pliresponder.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2023 Arda Cinar + * + * 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_PLI_RESPONDER_H +#define RTC_PLI_RESPONDER_H + +#include "mediahandlerelement.hpp" +#include + +namespace rtc { + +/// Responds to PLI and FIR messages sent by the receiver. The sender should respond to these +/// messages by sending an intra. +class RTC_CPP_EXPORT PliResponder final : public MediaHandlerElement { + std::function onPli; + +public: + /// Constructs the PLIResponder object to notify whenever a new intra frame is requested + /// @param onPli The callback that gets called whenever an intra frame is requested by the receiver + PliResponder(std::function onPli); + ChainedIncomingControlProduct processIncomingControlMessage(message_ptr) override; +}; + +} + +#endif // RTC_PLI_RESPONDER_H diff --git a/src/pliresponder.cpp b/src/pliresponder.cpp new file mode 100644 index 000000000..157632b9c --- /dev/null +++ b/src/pliresponder.cpp @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2023 Arda Cinar + * + * 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 "pliresponder.hpp" + +namespace rtc { + +ChainedIncomingControlProduct PliResponder::processIncomingControlMessage(message_ptr message) { + size_t offset = 0; + + while ((sizeof(RtcpHeader) + offset) <= message->size()) { + auto header = reinterpret_cast(message->data() + offset); + uint8_t payload_type = header->payloadType(); + + if (payload_type == 196) { + // FIR message, call pli handler anyway + onPli(); + break; + } else if (payload_type == 206) { + // On a payload specific fb message, there is a "feedback message type" (FMT) in the + // header instead of a report count. PT = 206, FMT = 1 means a PLI message + uint8_t feedback_message_type = header->reportCount(); + if (feedback_message_type == 1) { + onPli(); + break; + } + } + offset += header->lengthInBytes(); + } + return { message, std::nullopt }; +} + +PliResponder::PliResponder(std::function onPli) : onPli(onPli) { } + +} \ No newline at end of file