// Copyright Epic Games, Inc. All Rights Reserved. #include "IPixelStreaming2Module.h" #include "IPixelStreaming2InputModule.h" #include "IPixelStreaming2Streamer.h" #include "Logging.h" #include "Misc/AutomationTest.h" #include "PixelStreaming2InputEnums.h" #include "Serialization/JsonReader.h" #include "Serialization/JsonSerializer.h" #include "Tests/AutomationCommon.h" #include "TestUtils.h" #if WITH_DEV_AUTOMATION_TESTS namespace UE::PixelStreaming2 { IMPLEMENT_SIMPLE_AUTOMATION_TEST(FPS2ProtocolTestAddMessage, "System.Plugins.PixelStreaming2.FPS2ProtocolTestAddMessage", EAutomationTestFlags::EditorContext | EAutomationTestFlags::ClientContext | EAutomationTestFlags::ProductFilter) bool FPS2ProtocolTestAddMessage::RunTest(const FString& Parameters) { // need to be able to accept codec to handshake otherwise setting local description fails when generating an answer SetCodec(EVideoCodec::VP8); int32 StreamerPort = TestUtils::NextStreamerPort(); int32 PlayerPort = TestUtils::NextPlayerPort(); TSharedPtr SignallingServer = CreateSignallingServer(StreamerPort, PlayerPort); FString StreamerName(FString::Printf(TEXT("MockStreamer%d"), StreamerPort)); TSharedPtr Streamer = CreateStreamer(StreamerName, StreamerPort); TSharedPtr InputHandler = Streamer->GetInputHandler().Pin(); const FString CustomMessageName = FString(TEXT("CustomMessage")); // Define our message and add it to the protocol TSharedPtr Message = InputHandler->GetToStreamerProtocol()->Add(CustomMessageName, { EPixelStreaming2MessageTypes::Uint16 }); // Define a handler function const TFunction Handler = [this](FString, FMemoryReader Ar) { /* Do nothing */ }; // Add it to the streamer InputHandler->RegisterMessageHandler(CustomMessageName, Handler); TSharedPtr Player = CreatePlayer(); Player->GetToStreamerProtocol()->Add(CustomMessageName, { EPixelStreaming2MessageTypes::Uint16 }); TSharedPtr VideoSink = Player->GetVideoSink(); TSharedPtr bComplete = MakeShared(false); TFunction&)> Callback = [bComplete, CustomMessageName](const TArray& RawBuffer) { const uint8 Type = RawBuffer[0]; if (Type == 255 && RawBuffer.Num() > 1) { const size_t DescriptorSize = (RawBuffer.Num() - 1) / sizeof(TCHAR); const TCHAR* DescPtr = reinterpret_cast(RawBuffer.GetData() + 1); const FString JsonRaw(DescriptorSize, DescPtr); TSharedPtr JsonParsed; TSharedRef> JsonReader = TJsonReaderFactory::Create(JsonRaw); if (FJsonSerializer::Deserialize(JsonReader, JsonParsed)) { double Direction = JsonParsed->GetNumberField(TEXT("Direction")); if (!(Direction == static_cast(EPixelStreaming2MessageDirection::ToStreamer))) { return; } if (JsonParsed->HasField(CustomMessageName)) { *bComplete.Get() = true; } else { UE_LOG(LogPixelStreaming2RTC, Error, TEXT("Expected custom message definition to be in the received protocol.")); } } } }; TSharedPtr bStreamingStarted = MakeShared(false); Streamer->OnStreamingStarted().AddLambda([bStreamingStarted](IPixelStreaming2Streamer*) { *(bStreamingStarted.Get()) = true; }); Player->OnMessageReceived.AddLambda(Callback); ADD_LATENT_AUTOMATION_COMMAND(FExecuteLambda([Streamer]() { Streamer->StartStreaming(); })) ADD_LATENT_AUTOMATION_COMMAND(FWaitAndCheckStreamerBool(TEXT("Check streaming started"), 5.0, Streamer, bStreamingStarted, true)) ADD_LATENT_AUTOMATION_COMMAND(FExecuteLambda([Player, PlayerPort]() { Player->Connect(PlayerPort); })) ADD_LATENT_AUTOMATION_COMMAND(FSubscribePlayerAfterStreamerConnectedOrTimeout(5.0, Streamer, Player, StreamerName)); ADD_LATENT_AUTOMATION_COMMAND(FWaitForDataChannelOrTimeout(5.0, Player)); ADD_LATENT_AUTOMATION_COMMAND(FSendCustomMessageToStreamer(Player, CustomMessageName, 1337)); ADD_LATENT_AUTOMATION_COMMAND(FWaitForDataChannelMessageOrTimeout(15.0, Player, Callback, bComplete)); ADD_LATENT_AUTOMATION_COMMAND(FCleanupAll(SignallingServer, Streamer, Player)); return true; } IMPLEMENT_SIMPLE_AUTOMATION_TEST(FPS2ProtocolTestUseCustomMessage, "System.Plugins.PixelStreaming2.FPS2ProtocolTestUseCustomMessage", EAutomationTestFlags::EditorContext | EAutomationTestFlags::ClientContext | EAutomationTestFlags::ProductFilter) bool FPS2ProtocolTestUseCustomMessage::RunTest(const FString& Parameters) { // need to be able to accept codec to handshake otherwise setting local description fails when generating an answer SetCodec(EVideoCodec::VP8); int32 StreamerPort = TestUtils::NextStreamerPort(); int32 PlayerPort = TestUtils::NextPlayerPort(); TSharedPtr SignallingServer = CreateSignallingServer(StreamerPort, PlayerPort); FString StreamerName(FString::Printf(TEXT("MockStreamer%d"), StreamerPort)); TSharedPtr Streamer = CreateStreamer(StreamerName, StreamerPort); TSharedPtr InputHandler = Streamer->GetInputHandler().Pin(); // Define our message and add it to the protocol const FString CustomMessageName = FString(TEXT("CustomMessage")); TSharedPtr Message = InputHandler->GetToStreamerProtocol()->Add(CustomMessageName, { EPixelStreaming2MessageTypes::Uint16 }); // Define a handler function TSharedPtr bComplete = MakeShared(false); const TFunction Handler = [this, bComplete](FString, FMemoryReader Ar) { *bComplete.Get() = true; uint16 Out; Ar << Out; TestTrue(TEXT("Expected message content to be 1337."), Out == 1337); }; // Add it to the streamer InputHandler->RegisterMessageHandler(CustomMessageName, Handler); TFunction&)> Callback = [](const TArray&) { /* Do nothing */ }; TSharedPtr Player = CreatePlayer(); Player->GetToStreamerProtocol()->Add(CustomMessageName, { EPixelStreaming2MessageTypes::Uint16 }); TSharedPtr VideoSink = Player->GetVideoSink(); TSharedPtr bStreamingStarted = MakeShared(false); Streamer->OnStreamingStarted().AddLambda([bStreamingStarted](IPixelStreaming2Streamer*) { *(bStreamingStarted.Get()) = true; }); ADD_LATENT_AUTOMATION_COMMAND(FExecuteLambda([Streamer]() { Streamer->StartStreaming(); })) ADD_LATENT_AUTOMATION_COMMAND(FWaitAndCheckStreamerBool(TEXT("Check streaming started"), 5.0, Streamer, bStreamingStarted, true)) ADD_LATENT_AUTOMATION_COMMAND(FExecuteLambda([Player, PlayerPort]() { Player->Connect(PlayerPort); })) ADD_LATENT_AUTOMATION_COMMAND(FSubscribePlayerAfterStreamerConnectedOrTimeout(5.0, Streamer, Player, StreamerName)); ADD_LATENT_AUTOMATION_COMMAND(FWaitForDataChannelOrTimeout(5.0, Player)); ADD_LATENT_AUTOMATION_COMMAND(FSendCustomMessageToStreamer(Player, CustomMessageName, 1337)); ADD_LATENT_AUTOMATION_COMMAND(FWaitForDataChannelMessageOrTimeout(15.0, Player, Callback, bComplete)); ADD_LATENT_AUTOMATION_COMMAND(FCleanupAll(SignallingServer, Streamer, Player)); return true; } } // namespace UE::PixelStreaming2 #endif // WITH_DEV_AUTOMATION_TESTS