2025-04-01 21:45:25 -05:00

289 lines
7.6 KiB
C++

#pragma once
#include <QSemaphore>
#include <QWindow>
#include <Limelight.h>
#include <opus_multistream.h>
#include "settings/streamingpreferences.h"
#include "input/input.h"
#include "video/decoder.h"
#include "audio/renderers/renderer.h"
#include "video/overlaymanager.h"
class SupportedVideoFormatList : public QList<int>
{
public:
operator int() const
{
int value = 0;
for (const int & v : *this) {
value |= v;
}
return value;
}
void
removeByMask(int mask)
{
int i = 0;
while (i < this->length()) {
if (this->value(i) & mask) {
this->removeAt(i);
}
else {
i++;
}
}
}
void
deprioritizeByMask(int mask)
{
QList<int> deprioritizedList;
int i = 0;
while (i < this->length()) {
if (this->value(i) & mask) {
deprioritizedList.append(this->takeAt(i));
}
else {
i++;
}
}
this->append(std::move(deprioritizedList));
}
int maskByServerCodecModes(int serverCodecModes)
{
int mask = 0;
const QMap<int, int> mapping = {
{SCM_H264, VIDEO_FORMAT_H264},
{SCM_H264_HIGH8_444, VIDEO_FORMAT_H264_HIGH8_444},
{SCM_HEVC, VIDEO_FORMAT_H265},
{SCM_HEVC_MAIN10, VIDEO_FORMAT_H265_MAIN10},
{SCM_HEVC_REXT8_444, VIDEO_FORMAT_H265_REXT8_444},
{SCM_HEVC_REXT10_444, VIDEO_FORMAT_H265_REXT10_444},
{SCM_AV1_MAIN8, VIDEO_FORMAT_AV1_MAIN8},
{SCM_AV1_MAIN10, VIDEO_FORMAT_AV1_MAIN10},
{SCM_AV1_HIGH8_444, VIDEO_FORMAT_AV1_HIGH8_444},
{SCM_AV1_HIGH10_444, VIDEO_FORMAT_AV1_HIGH10_444},
};
for (QMap<int, int>::const_iterator it = mapping.cbegin(); it != mapping.cend(); ++it) {
if (serverCodecModes & it.key()) {
mask |= it.value();
serverCodecModes &= ~it.key();
}
}
// Make sure nobody forgets to update this for new SCM values
SDL_assert(serverCodecModes == 0);
int val = *this;
return val & mask;
}
};
class Session : public QObject
{
Q_OBJECT
friend class SdlInputHandler;
friend class DeferredSessionCleanupTask;
friend class AsyncConnectionStartThread;
friend class ExecThread;
public:
explicit Session(NvComputer* computer, NvApp& app, StreamingPreferences *preferences = nullptr);
// NB: This may not get destroyed for a long time! Don't put any cleanup here.
// Use Session::exec() or DeferredSessionCleanupTask instead.
virtual ~Session() {};
Q_INVOKABLE void exec(QWindow* qtWindow);
static
void getDecoderInfo(SDL_Window* window,
bool& isHardwareAccelerated, bool& isFullScreenOnly,
bool& isHdrSupported, QSize& maxResolution);
static Session* get()
{
return s_ActiveSession;
}
Overlay::OverlayManager& getOverlayManager()
{
return m_OverlayManager;
}
void flushWindowEvents();
signals:
void stageStarting(QString stage);
void stageFailed(QString stage, int errorCode, QString failingPorts);
void connectionStarted();
void displayLaunchError(QString text);
void displayLaunchWarning(QString text);
void quitStarting();
void sessionFinished(int portTestResult);
// Emitted after sessionFinished() when the session is ready to be destroyed
void readyForDeletion();
private:
void execInternal();
bool initialize();
bool startConnectionAsync();
bool validateLaunch(SDL_Window* testWindow);
void emitLaunchWarning(QString text);
bool populateDecoderProperties(SDL_Window* window);
IAudioRenderer* createAudioRenderer(const POPUS_MULTISTREAM_CONFIGURATION opusConfig);
bool initializeAudioRenderer();
bool testAudio(int audioConfiguration);
int getAudioRendererCapabilities(int audioConfiguration);
void getWindowDimensions(int& x, int& y,
int& width, int& height);
void toggleFullscreen();
void notifyMouseEmulationMode(bool enabled);
void updateOptimalWindowDisplayMode();
enum class DecoderAvailability {
None,
Software,
Hardware
};
static
DecoderAvailability getDecoderAvailability(SDL_Window* window,
StreamingPreferences::VideoDecoderSelection vds,
int videoFormat, int width, int height, int frameRate);
static
bool chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
SDL_Window* window, int videoFormat, int width, int height,
int frameRate, bool enableVsync, bool enableFramePacing,
bool testOnly,
IVideoDecoder*& chosenDecoder);
static
void clStageStarting(int stage);
static
void clStageFailed(int stage, int errorCode);
static
void clConnectionTerminated(int errorCode);
static
void clLogMessage(const char* format, ...);
static
void clRumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsigned short highFreqMotor);
static
void clConnectionStatusUpdate(int connectionStatus);
static
void clSetHdrMode(bool enabled);
static
void clRumbleTriggers(uint16_t controllerNumber, uint16_t leftTrigger, uint16_t rightTrigger);
static
void clSetMotionEventState(uint16_t controllerNumber, uint8_t motionType, uint16_t reportRateHz);
static
void clSetControllerLED(uint16_t controllerNumber, uint8_t r, uint8_t g, uint8_t b);
static
void clSetAdaptiveTriggers(uint16_t controllerNumber, uint8_t eventFlags, uint8_t typeLeft, uint8_t typeRight, uint8_t *left, uint8_t *right);
static
int arInit(int audioConfiguration,
const POPUS_MULTISTREAM_CONFIGURATION opusConfig,
void* arContext, int arFlags);
static
void arCleanup();
static
void arDecodeAndPlaySample(char* sampleData, int sampleLength);
static
int drSetup(int videoFormat, int width, int height, int frameRate, void*, int);
static
void drCleanup();
static
int drSubmitDecodeUnit(PDECODE_UNIT du);
StreamingPreferences* m_Preferences;
bool m_IsFullScreen;
SupportedVideoFormatList m_SupportedVideoFormats; // Sorted in order of descending priority
STREAM_CONFIGURATION m_StreamConfig;
DECODER_RENDERER_CALLBACKS m_VideoCallbacks;
AUDIO_RENDERER_CALLBACKS m_AudioCallbacks;
NvComputer* m_Computer;
NvApp m_App;
SDL_Window* m_Window;
IVideoDecoder* m_VideoDecoder;
SDL_SpinLock m_DecoderLock;
bool m_AudioDisabled;
bool m_AudioMuted;
Uint32 m_FullScreenFlag;
QWindow* m_QtWindow;
bool m_ThreadedExec;
bool m_UnexpectedTermination;
SdlInputHandler* m_InputHandler;
int m_MouseEmulationRefCount;
int m_FlushingWindowEventsRef;
QList<QString> m_LaunchWarnings;
bool m_AsyncConnectionSuccess;
int m_PortTestResults;
int m_ActiveVideoFormat;
int m_ActiveVideoWidth;
int m_ActiveVideoHeight;
int m_ActiveVideoFrameRate;
OpusMSDecoder* m_OpusDecoder;
IAudioRenderer* m_AudioRenderer;
OPUS_MULTISTREAM_CONFIGURATION m_ActiveAudioConfig;
OPUS_MULTISTREAM_CONFIGURATION m_OriginalAudioConfig;
int m_AudioSampleCount;
Uint32 m_DropAudioEndTime;
Overlay::OverlayManager m_OverlayManager;
static CONNECTION_LISTENER_CALLBACKS k_ConnCallbacks;
static Session* s_ActiveSession;
static QSemaphore s_ActiveSessionSemaphore;
};