-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
346 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
#include "rtp/FakeKeyframeGeneratorHandler.h" | ||
|
||
#include <algorithm> | ||
#include <string> | ||
|
||
#include "./MediaDefinitions.h" | ||
#include "./MediaStream.h" | ||
#include "./RtpUtils.h" | ||
|
||
namespace erizo { | ||
|
||
DEFINE_LOGGER(FakeKeyframeGeneratorHandler, "rtp.FakeKeyframeGeneratorHandler"); | ||
|
||
constexpr uint64_t kPliPeriodMs = 300; | ||
|
||
FakeKeyframeGeneratorHandler::FakeKeyframeGeneratorHandler() : | ||
stream_{nullptr}, enabled_{true}, first_keyframe_received_{false}, plis_scheduled_{false}, | ||
video_source_ssrc_{0}, video_sink_ssrc_{0} { | ||
} | ||
|
||
void FakeKeyframeGeneratorHandler::enable() { | ||
enabled_ = true; | ||
} | ||
|
||
void FakeKeyframeGeneratorHandler::disable() { | ||
enabled_ = false; | ||
} | ||
|
||
void FakeKeyframeGeneratorHandler::notifyUpdate() { | ||
auto pipeline = getContext()->getPipelineShared(); | ||
if (pipeline && !stream_) { | ||
stream_ = pipeline->getService<MediaStream>().get(); | ||
} | ||
if (stream_) { | ||
video_source_ssrc_ = stream_->getVideoSourceSSRC(); | ||
video_sink_ssrc_ = stream_->getVideoSinkSSRC(); | ||
} | ||
} | ||
|
||
void FakeKeyframeGeneratorHandler::read(Context *ctx, std::shared_ptr<DataPacket> packet) { | ||
ctx->fireRead(std::move(packet)); | ||
} | ||
|
||
void FakeKeyframeGeneratorHandler::write(Context *ctx, std::shared_ptr<DataPacket> packet) { | ||
RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(packet->data); | ||
if (enabled_) { | ||
if (!first_keyframe_received_ && packet->type == VIDEO_PACKET && !chead->isRtcp()) { | ||
if (!packet->is_keyframe) { | ||
if (!plis_scheduled_) { | ||
plis_scheduled_ = true; | ||
ELOG_DEBUG("Scheduling PLIs"); | ||
sendPLI(); | ||
schedulePLI(); | ||
} | ||
ELOG_DEBUG("Building a black keyframe from packet"); | ||
auto keyframe_packet = transformIntoKeyframePacket(packet); | ||
ctx->fireWrite(keyframe_packet); | ||
return; | ||
} else { | ||
ELOG_DEBUG("First part of a keyframe received, stop rewriting packets"); | ||
first_keyframe_received_ = true; | ||
} | ||
} | ||
} | ||
ctx->fireWrite(std::move(packet)); | ||
} | ||
|
||
std::shared_ptr<DataPacket> FakeKeyframeGeneratorHandler::transformIntoKeyframePacket | ||
(std::shared_ptr<DataPacket> packet) { | ||
if (packet->codec == "VP8") { | ||
auto keyframe_packet = RtpUtils::makeVP8BlackKeyframePacket(packet); | ||
return keyframe_packet; | ||
} else { | ||
ELOG_DEBUG("Generate keyframe packet is not available for codec %s", packet->codec); | ||
return packet; | ||
} | ||
} | ||
void FakeKeyframeGeneratorHandler::sendPLI() { | ||
getContext()->fireRead(RtpUtils::createPLI(video_sink_ssrc_, video_source_ssrc_)); | ||
} | ||
void FakeKeyframeGeneratorHandler::schedulePLI() { | ||
std::weak_ptr<FakeKeyframeGeneratorHandler> weak_this = shared_from_this(); | ||
stream_->getWorker()->scheduleEvery([weak_this] { | ||
if (auto this_ptr = weak_this.lock()) { | ||
if (!this_ptr->first_keyframe_received_) { | ||
ELOG_DEBUG("Sending PLI in FakeGenerator, scheduling another"); | ||
this_ptr->sendPLI(); | ||
return true; | ||
} else { | ||
ELOG_DEBUG("Stop sending scheduled PLI packets"); | ||
return false; | ||
} | ||
} | ||
return false; | ||
}, std::chrono::milliseconds(kPliPeriodMs)); | ||
} | ||
} // namespace erizo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#ifndef ERIZO_SRC_ERIZO_RTP_FAKEKEYFRAMEGENERATORHANDLER_H_ | ||
#define ERIZO_SRC_ERIZO_RTP_FAKEKEYFRAMEGENERATORHANDLER_H_ | ||
|
||
#include <string> | ||
|
||
#include "./logger.h" | ||
#include "pipeline/Handler.h" | ||
#include "lib/Clock.h" | ||
#include "lib/TokenBucket.h" | ||
#include "thread/Worker.h" | ||
#include "rtp/SequenceNumberTranslator.h" | ||
#include "rtp/RtpVP8Parser.h" | ||
#include "./Stats.h" | ||
|
||
namespace erizo { | ||
|
||
class MediaStream; | ||
|
||
class FakeKeyframeGeneratorHandler: public Handler, public std::enable_shared_from_this<FakeKeyframeGeneratorHandler> { | ||
DECLARE_LOGGER(); | ||
|
||
public: | ||
FakeKeyframeGeneratorHandler(); | ||
void enable() override; | ||
void disable() override; | ||
|
||
std::string getName() override { | ||
return "fake-keyframe-generator"; | ||
} | ||
|
||
void read(Context *ctx, std::shared_ptr<DataPacket> packet) override; | ||
void write(Context *ctx, std::shared_ptr<DataPacket> packet) override; | ||
void notifyUpdate() override; | ||
|
||
private: | ||
std::shared_ptr<DataPacket> transformIntoKeyframePacket(std::shared_ptr<DataPacket> packet); | ||
void sendPLI(); | ||
void schedulePLI(); | ||
|
||
private: | ||
MediaStream* stream_; | ||
bool enabled_; | ||
bool first_keyframe_received_; | ||
bool plis_scheduled_; | ||
uint32_t video_source_ssrc_; | ||
uint32_t video_sink_ssrc_; | ||
RtpVP8Parser vp8_parser_; | ||
std::shared_ptr<ScheduledTaskReference> scheduled_task_; | ||
}; | ||
|
||
} // namespace erizo | ||
|
||
#endif // ERIZO_SRC_ERIZO_RTP_FAKEKEYFRAMEGENERATORHANDLER_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
128 changes: 128 additions & 0 deletions
128
erizo/src/test/rtp/FakeKeyframeGeneratorHandlerTest.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
#include <gmock/gmock.h> | ||
#include <gtest/gtest.h> | ||
|
||
#include <rtp/FakeKeyframeGeneratorHandler.h> | ||
#include <rtp/RtpHeaders.h> | ||
#include <MediaDefinitions.h> | ||
#include <WebRtcConnection.h> | ||
#include <stats/StatNode.h> | ||
|
||
#include <queue> | ||
#include <string> | ||
#include <vector> | ||
|
||
#include "../utils/Mocks.h" | ||
#include "../utils/Tools.h" | ||
#include "../utils/Matchers.h" | ||
|
||
using ::testing::_; | ||
using ::testing::IsNull; | ||
using ::testing::Args; | ||
using ::testing::Return; | ||
using ::testing::AtLeast; | ||
using ::testing::Not; | ||
using erizo::DataPacket; | ||
using erizo::packetType; | ||
using erizo::AUDIO_PACKET; | ||
using erizo::VIDEO_PACKET; | ||
using erizo::MovingIntervalRateStat; | ||
using erizo::IceConfig; | ||
using erizo::RtpMap; | ||
using erizo::FakeKeyframeGeneratorHandler; | ||
using erizo::WebRtcConnection; | ||
using erizo::Pipeline; | ||
using erizo::InboundHandler; | ||
using erizo::OutboundHandler; | ||
using erizo::Worker; | ||
using std::queue; | ||
|
||
|
||
class FakeKeyframeGeneratorHandlerTest : public erizo::HandlerTest { | ||
public: | ||
FakeKeyframeGeneratorHandlerTest() {} | ||
|
||
protected: | ||
void setHandler() { | ||
keyframe_generator = std::make_shared<FakeKeyframeGeneratorHandler>(); | ||
pipeline->addBack(keyframe_generator); | ||
} | ||
std::shared_ptr<FakeKeyframeGeneratorHandler> keyframe_generator; | ||
}; | ||
|
||
TEST_F(FakeKeyframeGeneratorHandlerTest, basicBehaviourShouldReadPackets) { | ||
auto packet = erizo::PacketTools::createDataPacket(erizo::kArbitrarySeqNumber, AUDIO_PACKET); | ||
|
||
EXPECT_CALL(*reader.get(), read(_, _)). | ||
With(Args<1>(erizo::RtpHasSequenceNumber(erizo::kArbitrarySeqNumber))).Times(1); | ||
pipeline->read(packet); | ||
} | ||
|
||
TEST_F(FakeKeyframeGeneratorHandlerTest, basicBehaviourShouldWritePackets) { | ||
auto packet = erizo::PacketTools::createDataPacket(erizo::kArbitrarySeqNumber, AUDIO_PACKET); | ||
|
||
EXPECT_CALL(*writer.get(), write(_, _)). | ||
With(Args<1>(erizo::RtpHasSequenceNumber(erizo::kArbitrarySeqNumber))).Times(1); | ||
pipeline->write(packet); | ||
} | ||
|
||
TEST_F(FakeKeyframeGeneratorHandlerTest, shouldNotChangePacketsWhenDisabled) { | ||
keyframe_generator->disable(); | ||
|
||
auto packet = erizo::PacketTools::createVP8Packet(erizo::kArbitrarySeqNumber, false, false); | ||
int length = packet->length; | ||
EXPECT_CALL(*writer.get(), write(_, _)). | ||
With(Args<1>(erizo::PacketLengthIs(length))).Times(1); | ||
pipeline->write(packet); | ||
} | ||
|
||
TEST_F(FakeKeyframeGeneratorHandlerTest, shouldTransformVP8Packet) { | ||
keyframe_generator->enable(); | ||
EXPECT_CALL(*writer.get(), write(_, _)). | ||
With(Args<1>(erizo::PacketIsKeyframe())).Times(1); | ||
pipeline->write(erizo::PacketTools::createVP8Packet(erizo::kArbitrarySeqNumber, false, false)); | ||
} | ||
|
||
TEST_F(FakeKeyframeGeneratorHandlerTest, shouldNotTransformVP8Keyframes) { | ||
auto packet = erizo::PacketTools::createVP8Packet(erizo::kArbitrarySeqNumber, true, true); | ||
int length = packet->length; | ||
EXPECT_CALL(*writer.get(), write(_, _)). | ||
With(Args<1>(erizo::PacketLengthIs(length))).Times(1); | ||
pipeline->write(packet); | ||
} | ||
|
||
TEST_F(FakeKeyframeGeneratorHandlerTest, shouldNotTransformUnsupportedCodecPackets) { | ||
auto packet = erizo::PacketTools::createVP9Packet(erizo::kArbitrarySeqNumber, false, false); | ||
int length = packet->length; | ||
EXPECT_CALL(*writer.get(), write(_, _)). | ||
With(Args<1>(erizo::PacketLengthIs(length))).Times(1); | ||
pipeline->write(packet); | ||
} | ||
|
||
TEST_F(FakeKeyframeGeneratorHandlerTest, shouldSendPLIInmediatelyIfNoKeyframeIsReceived) { | ||
auto packet = erizo::PacketTools::createVP8Packet(erizo::kArbitrarySeqNumber, false, false); | ||
EXPECT_CALL(*reader.get(), read(_, _)).With(Args<1>(erizo::IsPLI())).Times(1); | ||
pipeline->write(packet); | ||
} | ||
|
||
TEST_F(FakeKeyframeGeneratorHandlerTest, shouldNotSendPLIIfKeyframeIsFirstPacket) { | ||
auto packet = erizo::PacketTools::createVP8Packet(erizo::kArbitrarySeqNumber, true, true); | ||
EXPECT_CALL(*reader.get(), read(_, _)).With(Args<1>(erizo::IsPLI())).Times(0); | ||
pipeline->write(packet); | ||
} | ||
|
||
TEST_F(FakeKeyframeGeneratorHandlerTest, shouldSendPLIsPeriodically) { | ||
auto packet = erizo::PacketTools::createVP8Packet(erizo::kArbitrarySeqNumber, false, false); | ||
EXPECT_CALL(*reader.get(), read(_, _)).With(Args<1>(erizo::IsPLI())).Times(2); | ||
pipeline->write(packet); | ||
executeTasksInNextMs(350); | ||
} | ||
|
||
TEST_F(FakeKeyframeGeneratorHandlerTest, shouldNotSendPeriodicPLISIfKeyframeIsReceived) { | ||
auto packet = erizo::PacketTools::createVP8Packet(erizo::kArbitrarySeqNumber, false, false); | ||
auto keyframe_packet = erizo::PacketTools::createVP8Packet(erizo::kArbitrarySeqNumber, true, true); | ||
EXPECT_CALL(*reader.get(), read(_, _)).With(Args<1>(erizo::IsPLI())).Times(1); | ||
pipeline->write(packet); | ||
pipeline->write(keyframe_packet); | ||
executeTasksInNextMs(350); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.