Compare commits

..

No commits in common. "611a2e7f8f6583d6d6aad30f0c8a02d6c07ab085" and "2d984f4b0dfab5ea2cff0f262abe1a056946a7c1" have entirely different histories.

14 changed files with 86 additions and 283 deletions

2
enet

@ -1 +1 @@
Subproject commit 78cc9b4b03bdd4f95c277391cac6e0951407072b
Subproject commit dea6fb5414b180908b58c0293c831105b5d124dd

View file

@ -377,19 +377,6 @@ int LiStartConnection(PSERVER_INFORMATION serverInfo, PSTREAM_CONFIGURATION stre
ListenerCallbacks.stageFailed(STAGE_NAME_RESOLUTION, err);
goto Cleanup;
}
// Resolve LocalAddr by RemoteAddr.
{
SOCKADDR_LEN localAddrLen;
err = getLocalAddressByUdpConnect(&RemoteAddr, AddrLen, RtspPortNumber, &LocalAddr, &localAddrLen);
if (err != 0) {
Limelog("failed to resolve local addr: %d\n", err);
ListenerCallbacks.stageFailed(STAGE_NAME_RESOLUTION, err);
goto Cleanup;
}
LC_ASSERT(localAddrLen == AddrLen);
}
stage++;
LC_ASSERT(stage == STAGE_NAME_RESOLUTION);
ListenerCallbacks.stageComplete(STAGE_NAME_RESOLUTION);

View file

@ -31,12 +31,11 @@ typedef struct _NVCTL_ENCRYPTED_PACKET_HEADER {
// encrypted NVCTL_ENET_PACKET_HEADER_V2 and payload data follow
} NVCTL_ENCRYPTED_PACKET_HEADER, *PNVCTL_ENCRYPTED_PACKET_HEADER;
typedef struct _QUEUED_REFERENCE_FRAME_CONTROL {
typedef struct _QUEUED_FRAME_INVALIDATION_TUPLE {
uint32_t startFrame;
uint32_t endFrame;
bool invalidate; // true: RFI(startFrame, endFrame); false: LTR_ACK(startFrame)
LINKED_BLOCKING_QUEUE_ENTRY entry;
} QUEUED_REFERENCE_FRAME_CONTROL, *PQUEUED_REFERENCE_FRAME_CONTROL;
} QUEUED_FRAME_INVALIDATION_TUPLE, *PQUEUED_FRAME_INVALIDATION_TUPLE;
typedef struct _QUEUED_FRAME_FEC_STATUS {
SS_FRAME_FEC_STATUS fecStatus;
@ -83,12 +82,6 @@ typedef struct _QUEUED_ASYNC_CALLBACK {
uint8_t left[DS_EFFECT_PAYLOAD_SIZE];
uint8_t right[DS_EFFECT_PAYLOAD_SIZE];
} dsAdaptiveTrigger;
struct {
uint8_t allowKeyboard;
uint8_t allowMouse;
uint8_t allowGamepad;
uint8_t reason;
} setInputPolicy;
} data;
LINKED_BLOCKING_QUEUE_ENTRY entry;
} QUEUED_ASYNC_CALLBACK, *PQUEUED_ASYNC_CALLBACK;
@ -120,7 +113,7 @@ static int lastConnectionStatusUpdate;
static uint32_t currentEnetSequenceNumber;
static uint64_t firstFrameTimeMs;
static LINKED_BLOCKING_QUEUE referenceFrameControlQueue;
static LINKED_BLOCKING_QUEUE invalidReferenceFrameTuples;
static LINKED_BLOCKING_QUEUE frameFecStatusQueue;
static LINKED_BLOCKING_QUEUE asyncCallbackQueue;
static PLT_EVENT idrFrameRequiredEvent;
@ -146,7 +139,6 @@ static PPLT_CRYPTO_CONTEXT decryptionCtx;
#define IDX_SET_MOTION_EVENT 10
#define IDX_SET_RGB_LED 11
#define IDX_DS_ADAPTIVE_TRIGGERS 12
#define IDX_SET_INPUT_POLICY 13
#define CONTROL_STREAM_TIMEOUT_SEC 10
#define CONTROL_STREAM_LINGER_TIMEOUT_SEC 2
@ -164,7 +156,6 @@ static const short packetTypesGen3[] = {
-1, // Rumble triggers (unused)
-1, // Set motion event (unused)
-1, // Set RGB LED (unused)
-1,
};
static const short packetTypesGen4[] = {
0x0606, // Request IDR frame
@ -179,7 +170,6 @@ static const short packetTypesGen4[] = {
-1, // Rumble triggers (unused)
-1, // Set motion event (unused)
-1, // Set RGB LED (unused)
-1,
};
static const short packetTypesGen5[] = {
0x0305, // Start A
@ -194,7 +184,6 @@ static const short packetTypesGen5[] = {
-1, // Rumble triggers (unused)
-1, // Set motion event (unused)
-1, // Set RGB LED (unused)
-1,
};
static const short packetTypesGen7[] = {
0x0305, // Start A
@ -209,7 +198,6 @@ static const short packetTypesGen7[] = {
-1, // Rumble triggers (unused)
-1, // Set motion event (unused)
-1, // Set RGB LED (unused)
-1,
};
static const short packetTypesGen7Enc[] = {
0x0302, // Request IDR frame
@ -225,7 +213,6 @@ static const short packetTypesGen7Enc[] = {
0x5501, // Set motion event (Sunshine protocol extension)
0x5502, // Set RGB LED (Sunshine protocol extension)
0x5503, // Set Adaptive Triggers (Sunshine protocol extension)
0x5504,
};
static const char requestIdrFrameGen3[] = { 0, 0 };
@ -313,7 +300,7 @@ static bool supportsIdrFrameRequest;
int initializeControlStream(void) {
stopping = false;
PltCreateEvent(&idrFrameRequiredEvent);
LbqInitializeLinkedBlockingQueue(&referenceFrameControlQueue, 20);
LbqInitializeLinkedBlockingQueue(&invalidReferenceFrameTuples, 20);
LbqInitializeLinkedBlockingQueue(&frameFecStatusQueue, 8); // Limits number of frame status reports per periodic ping interval
LbqInitializeLinkedBlockingQueue(&asyncCallbackQueue, 30);
PltCreateMutex(&enetMutex);
@ -388,7 +375,7 @@ void destroyControlStream(void) {
PltDestroyCryptoContext(encryptionCtx);
PltDestroyCryptoContext(decryptionCtx);
PltCloseEvent(&idrFrameRequiredEvent);
freeBasicLbqList(LbqDestroyLinkedBlockingQueue(&referenceFrameControlQueue));
freeBasicLbqList(LbqDestroyLinkedBlockingQueue(&invalidReferenceFrameTuples));
freeBasicLbqList(LbqDestroyLinkedBlockingQueue(&frameFecStatusQueue));
freeBasicLbqList(LbqDestroyLinkedBlockingQueue(&asyncCallbackQueue));
@ -399,15 +386,12 @@ static void queueFrameInvalidationTuple(uint32_t startFrame, uint32_t endFrame)
LC_ASSERT(startFrame <= endFrame);
if (isReferenceFrameInvalidationEnabled()) {
PQUEUED_REFERENCE_FRAME_CONTROL qfit;
PQUEUED_FRAME_INVALIDATION_TUPLE qfit;
qfit = malloc(sizeof(*qfit));
if (qfit != NULL) {
*qfit = (QUEUED_REFERENCE_FRAME_CONTROL){
.startFrame = startFrame,
.endFrame = endFrame,
.invalidate = true,
};
if (LbqOfferQueueItem(&referenceFrameControlQueue, qfit, &qfit->entry) == LBQ_BOUND_EXCEEDED) {
qfit->startFrame = startFrame;
qfit->endFrame = endFrame;
if (LbqOfferQueueItem(&invalidReferenceFrameTuples, qfit, &qfit->entry) == LBQ_BOUND_EXCEEDED) {
// Too many invalidation tuples, so we need an IDR frame now
Limelog("RFI range list reached maximum size limit\n");
free(qfit);
@ -427,7 +411,7 @@ static void queueFrameInvalidationTuple(uint32_t startFrame, uint32_t endFrame)
void LiRequestIdrFrame(void) {
// Any reference frame invalidation requests should be dropped now.
// We require a full IDR frame to recover.
freeBasicLbqList(LbqFlushQueueItems(&referenceFrameControlQueue));
freeBasicLbqList(LbqFlushQueueItems(&invalidReferenceFrameTuples));
// Request the IDR frame
PltSetEvent(&idrFrameRequiredEvent);
@ -439,29 +423,9 @@ void connectionDetectedFrameLoss(uint32_t startFrame, uint32_t endFrame) {
}
// When we receive a frame, update the number of our current frame
// and send ACK control message if the frame is LTR
void connectionReceivedCompleteFrame(uint32_t frameIndex, bool frameIsLTR) {
void connectionReceivedCompleteFrame(uint32_t frameIndex) {
lastGoodFrame = frameIndex;
intervalGoodFrameCount++;
if (frameIsLTR && IS_SUNSHINE() && isReferenceFrameInvalidationEnabled()) {
// Queue LTR frame ACK control message
PQUEUED_REFERENCE_FRAME_CONTROL qfit;
qfit = malloc(sizeof(*qfit));
if (qfit != NULL) {
*qfit = (QUEUED_REFERENCE_FRAME_CONTROL){
.startFrame = frameIndex,
.invalidate = false,
};
if (LbqOfferQueueItem(&referenceFrameControlQueue, qfit, &qfit->entry) == LBQ_BOUND_EXCEEDED) {
// This shouldn't happen and indicates that something has gone wrong with the queue
LC_ASSERT(false);
Limelog("Couldn't queue LTR ACK because the list has reached maximum size limit\n");
free(qfit);
LiRequestIdrFrame();
}
}
}
}
void connectionSendFrameFecStatus(PSS_FRAME_FEC_STATUS fecStatus) {
@ -1022,12 +986,6 @@ static void asyncCallbackThreadFunc(void* context) {
queuedCb->data.dsAdaptiveTrigger.left,
queuedCb->data.dsAdaptiveTrigger.right);
break;
case IDX_SET_INPUT_POLICY:
ListenerCallbacks.setInputPolicy(queuedCb->data.setInputPolicy.allowKeyboard,
queuedCb->data.setInputPolicy.allowMouse,
queuedCb->data.setInputPolicy.allowGamepad,
queuedCb->data.setInputPolicy.reason);
break;
default:
// Unhandled packet type from queueAsyncCallback()
LC_ASSERT(false);
@ -1044,8 +1002,7 @@ static bool needsAsyncCallback(unsigned short packetType) {
packetType == packetTypes[IDX_SET_MOTION_EVENT] ||
packetType == packetTypes[IDX_SET_RGB_LED] ||
packetType == packetTypes[IDX_HDR_INFO] ||
packetType == packetTypes[IDX_DS_ADAPTIVE_TRIGGERS] ||
packetType == packetTypes[IDX_SET_INPUT_POLICY];
packetType == packetTypes[IDX_DS_ADAPTIVE_TRIGGERS];
}
static void queueAsyncCallback(PNVCTL_ENET_PACKET_HEADER_V1 ctlHdr, int packetLength) {
@ -1106,13 +1063,6 @@ static void queueAsyncCallback(PNVCTL_ENET_PACKET_HEADER_V1 ctlHdr, int packetLe
BbGetBytes(&bb, queuedCb->data.dsAdaptiveTrigger.right, DS_EFFECT_PAYLOAD_SIZE);
queuedCb->typeIndex = IDX_DS_ADAPTIVE_TRIGGERS;
}
else if (ctlHdr->type == packetTypes[IDX_SET_INPUT_POLICY]) {
BbGet8(&bb, &queuedCb->data.setInputPolicy.allowKeyboard);
BbGet8(&bb, &queuedCb->data.setInputPolicy.allowMouse);
BbGet8(&bb, &queuedCb->data.setInputPolicy.allowGamepad);
BbGet8(&bb, &queuedCb->data.setInputPolicy.reason);
queuedCb->typeIndex = IDX_SET_INPUT_POLICY;
}
else {
// Unhandled packet type from needsAsyncCallback()
LC_ASSERT(false);
@ -1562,22 +1512,22 @@ static void requestIdrFrame(void) {
}
static void requestInvalidateReferenceFrames(uint32_t startFrame, uint32_t endFrame) {
int64_t payload[3];
LC_ASSERT(startFrame <= endFrame);
LC_ASSERT(isReferenceFrameInvalidationEnabled());
SS_RFI_REQUEST payload = {
.firstFrameIndex = LE32(startFrame),
.lastFrameIndex = LE32(endFrame),
};
payload[0] = LE64(startFrame);
payload[1] = LE64(endFrame);
payload[2] = 0;
// Send the reference frame invalidation request and read the response
if (!sendMessageAndDiscardReply(packetTypes[IDX_INVALIDATE_REF_FRAMES],
sizeof(payload),
&payload,
CTRL_CHANNEL_URGENT,
payload, CTRL_CHANNEL_URGENT,
ENET_PACKET_FLAG_RELIABLE,
false)) {
Limelog("Request Invalidate Reference Frames: Transaction failed: %d\n", (int)LastSocketError());
Limelog("Request Invaldiate Reference Frames: Transaction failed: %d\n", (int)LastSocketError());
ListenerCallbacks.connectionTerminated(LastSocketFail());
return;
}
@ -1585,65 +1535,32 @@ static void requestInvalidateReferenceFrames(uint32_t startFrame, uint32_t endFr
Limelog("Invalidate reference frame request sent (%d to %d)\n", startFrame, endFrame);
}
static void confirmLongtermReferenceFrame(uint32_t frameIndex) {
LC_ASSERT(isReferenceFrameInvalidationEnabled());
SS_LTR_FRAME_ACK payload = {
.frameIndex = LE32(frameIndex),
};
// Send LTR frame ACK and don't wait for response
if (!sendMessageAndForget(SS_LTR_FRAME_ACK_PTYPE,
sizeof(payload),
&payload,
CTRL_CHANNEL_URGENT,
ENET_PACKET_FLAG_RELIABLE,
false)) {
Limelog("LTR frame ACK: Transaction failed: %d\n", (int)LastSocketError());
ListenerCallbacks.connectionTerminated(LastSocketFail());
return;
}
}
static void referenceFrameControlFunc(void* context) {
static void invalidateRefFramesFunc(void* context) {
LC_ASSERT(isReferenceFrameInvalidationEnabled());
while (!PltIsThreadInterrupted(&invalidateRefFramesThread)) {
PQUEUED_REFERENCE_FRAME_CONTROL qfit;
uint32_t invalidateStartFrame;
uint32_t invalidateEndFrame;
bool invalidate = false;
PQUEUED_FRAME_INVALIDATION_TUPLE qfit;
uint32_t startFrame;
uint32_t endFrame;
// Wait for a reference frame control message or a request to shutdown
if (LbqWaitForQueueElement(&referenceFrameControlQueue, (void**)&qfit) != LBQ_SUCCESS) {
// Wait for a reference frame invalidation request or a request to shutdown
if (LbqWaitForQueueElement(&invalidReferenceFrameTuples, (void**)&qfit) != LBQ_SUCCESS) {
// Bail if we're stopping
return;
}
do {
if (qfit->invalidate) {
if (!invalidate) {
invalidateStartFrame = qfit->startFrame;
invalidateEndFrame = qfit->endFrame;
invalidate = true;
}
else {
// Aggregate all lost frames into one range
LC_ASSERT(qfit->endFrame >= invalidateEndFrame);
invalidateEndFrame = qfit->endFrame;
}
}
else {
// Send LTR frame ACK
confirmLongtermReferenceFrame(qfit->startFrame);
}
free(qfit);
} while (LbqPollQueueElement(&referenceFrameControlQueue, (void**)&qfit) == LBQ_SUCCESS);
startFrame = qfit->startFrame;
endFrame = qfit->endFrame;
if (invalidate) {
// Send the reference frame invalidation request
requestInvalidateReferenceFrames(invalidateStartFrame, invalidateEndFrame);
}
// Aggregate all lost frames into one range
do {
LC_ASSERT(qfit->endFrame >= endFrame);
endFrame = qfit->endFrame;
free(qfit);
} while (LbqPollQueueElement(&invalidReferenceFrameTuples, (void**)&qfit) == LBQ_SUCCESS);
// Send the reference frame invalidation request
requestInvalidateReferenceFrames(startFrame, endFrame);
}
}
@ -1657,8 +1574,8 @@ static void requestIdrFrameFunc(void* context) {
return;
}
// Any pending RFI requests and LTR frame ACK messages are now redundant
freeBasicLbqList(LbqFlushQueueItems(&referenceFrameControlQueue));
// Any pending reference frame invalidation requests are now redundant
freeBasicLbqList(LbqFlushQueueItems(&invalidReferenceFrameTuples));
// Request the IDR frame
requestIdrFrame();
@ -1668,7 +1585,7 @@ static void requestIdrFrameFunc(void* context) {
// Stops the control stream
int stopControlStream(void) {
stopping = true;
LbqSignalQueueShutdown(&referenceFrameControlQueue);
LbqSignalQueueShutdown(&invalidReferenceFrameTuples);
LbqSignalQueueShutdown(&frameFecStatusQueue);
LbqSignalQueueDrain(&asyncCallbackQueue);
PltSetEvent(&idrFrameRequiredEvent);
@ -1727,34 +1644,6 @@ int sendInputPacketOnControlStream(unsigned char* data, int length, uint8_t chan
return 0;
}
int LiSendSessionInputPolicy(bool allowKeyboard, bool allowMouse, bool allowGamepad, uint8_t reason) {
struct {
uint8_t allowKeyboard;
uint8_t allowMouse;
uint8_t allowGamepad;
uint8_t reason;
} payload;
if (!IS_SUNSHINE() || AppVersionQuad[0] < 7) {
return LI_ERR_UNSUPPORTED;
}
if (client == NULL || peer == NULL || stopping) {
return -2;
}
payload.allowKeyboard = allowKeyboard ? 1 : 0;
payload.allowMouse = allowMouse ? 1 : 0;
payload.allowGamepad = allowGamepad ? 1 : 0;
payload.reason = reason;
if (sendMessageAndForget(0x5504, sizeof(payload), &payload, CTRL_CHANNEL_GENERIC, ENET_PACKET_FLAG_RELIABLE, false) == 0) {
return -1;
}
return 0;
}
// Called by the input stream to flush queued packets before a batching wait
void flushInputOnControlStream(void) {
if (AppVersionQuad[0] >= 5) {
@ -1781,10 +1670,7 @@ bool isControlDataInTransit(void) {
bool LiGetEstimatedRttInfo(uint32_t* estimatedRtt, uint32_t* estimatedRttVariance) {
bool ret = false;
// We do not acquire enetMutex here because we're just reading metrics
// and observing a torn write every once in a while is totally fine.
// The peer pointer points to memory reserved inside the client object,
// so it's guaranteed that it will never go away underneath us.
PltLockMutex(&enetMutex);
if (peer != NULL && peer->state == ENET_PEER_STATE_CONNECTED) {
if (estimatedRtt != NULL) {
*estimatedRtt = peer->roundTripTime;
@ -1796,6 +1682,7 @@ bool LiGetEstimatedRttInfo(uint32_t* estimatedRtt, uint32_t* estimatedRttVarianc
ret = true;
}
PltUnlockMutex(&enetMutex);
return ret;
}
@ -2083,7 +1970,7 @@ int startControlStream(void) {
// Only create the reference frame invalidation thread if RFI is enabled
if (isReferenceFrameInvalidationEnabled()) {
err = PltCreateThread("InvRefFrames", referenceFrameControlFunc, NULL, &invalidateRefFramesThread);
err = PltCreateThread("InvRefFrames", invalidateRefFramesFunc, NULL, &invalidateRefFramesThread);
if (err != 0) {
stopping = true;
PltSetEvent(&idrFrameRequiredEvent);

View file

@ -41,7 +41,6 @@ static void fakeClRumbleTriggers(uint16_t controllerNumber, uint16_t leftTrigger
static void fakeClSetMotionEventState(uint16_t controllerNumber, uint8_t motionType, uint16_t reportRateHz) {}
static void fakeClSetAdaptiveTriggers(uint16_t controllerNumber, uint8_t eventFlags, uint8_t typeLeft, uint8_t typeRight, uint8_t *left, uint8_t *right) {};
static void fakeClSetControllerLED(uint16_t controllerNumber, uint8_t r, uint8_t g, uint8_t b) {}
static void fakeClSetInputPolicy(uint8_t allowKeyboard, uint8_t allowMouse, uint8_t allowGamepad, uint8_t reason) {}
static CONNECTION_LISTENER_CALLBACKS fakeClCallbacks = {
.stageStarting = fakeClStageStarting,
@ -57,7 +56,6 @@ static CONNECTION_LISTENER_CALLBACKS fakeClCallbacks = {
.setMotionEventState = fakeClSetMotionEventState,
.setControllerLED = fakeClSetControllerLED,
.setAdaptiveTriggers = fakeClSetAdaptiveTriggers,
.setInputPolicy = fakeClSetInputPolicy,
};
void fixupMissingCallbacks(PDECODER_RENDERER_CALLBACKS* drCallbacks, PAUDIO_RENDERER_CALLBACKS* arCallbacks,
@ -148,8 +146,5 @@ void fixupMissingCallbacks(PDECODER_RENDERER_CALLBACKS* drCallbacks, PAUDIO_REND
if ((*clCallbacks)->setAdaptiveTriggers == NULL) {
(*clCallbacks)->setAdaptiveTriggers = fakeClSetAdaptiveTriggers;
}
if ((*clCallbacks)->setInputPolicy == NULL) {
(*clCallbacks)->setInputPolicy = fakeClSetInputPolicy;
}
}
}

View file

@ -724,14 +724,9 @@ int LiSendMouseMoveEvent(short deltaX, short deltaY) {
// Queue a packet holder if this is the only pending relative mouse event
if (!currentRelativeMouseState.dirty) {
// Set the dirty flag to claim ownership of inserting the packet holder
// and unlock to allow other threads to enqueue or process input.
currentRelativeMouseState.dirty = true;
PltUnlockMutex(&batchedInputMutex);
holder = allocatePacketHolder(0);
if (holder == NULL) {
currentRelativeMouseState.dirty = false;
PltUnlockMutex(&batchedInputMutex);
return -1;
}
@ -752,21 +747,22 @@ int LiSendMouseMoveEvent(short deltaX, short deltaY) {
// Remaining fields are set in the input thread based on the latest currentRelativeMouseState values
err = LbqOfferQueueItem(&packetQueue, holder, &holder->entry);
if (err != LBQ_SUCCESS) {
if (err == LBQ_SUCCESS) {
currentRelativeMouseState.dirty = true;
}
else {
LC_ASSERT(err == LBQ_BOUND_EXCEEDED);
Limelog("Input queue reached maximum size limit\n");
freePacketHolder(holder);
// We weren't able to insert the entry, so let the next call try again
currentRelativeMouseState.dirty = false;
}
}
else {
// There's already a packet holder queued to send this event
PltUnlockMutex(&batchedInputMutex);
err = 0;
}
PltUnlockMutex(&batchedInputMutex);
return err;
}
@ -789,14 +785,9 @@ int LiSendMousePositionEvent(short x, short y, short referenceWidth, short refer
// Queue a packet holder if this is the only pending absolute mouse event
if (!currentAbsoluteMouseState.dirty) {
// Set the dirty flag to claim ownership of inserting the packet holder
// and unlock to allow other threads to enqueue or process input.
currentAbsoluteMouseState.dirty = true;
PltUnlockMutex(&batchedInputMutex);
holder = allocatePacketHolder(0);
if (holder == NULL) {
currentAbsoluteMouseState.dirty = false;
PltUnlockMutex(&batchedInputMutex);
return -1;
}
@ -812,21 +803,22 @@ int LiSendMousePositionEvent(short x, short y, short referenceWidth, short refer
// Remaining fields are set in the input thread based on the latest currentAbsoluteMouseState values
err = LbqOfferQueueItem(&packetQueue, holder, &holder->entry);
if (err != LBQ_SUCCESS) {
if (err == LBQ_SUCCESS) {
currentAbsoluteMouseState.dirty = true;
}
else {
LC_ASSERT(err == LBQ_BOUND_EXCEEDED);
Limelog("Input queue reached maximum size limit\n");
freePacketHolder(holder);
// We weren't able to insert the entry, so let the next call try again
currentAbsoluteMouseState.dirty = false;
}
}
else {
// There's already a packet holder queued to send this event
PltUnlockMutex(&batchedInputMutex);
err = 0;
}
PltUnlockMutex(&batchedInputMutex);
// This is not thread safe, but it's not a big deal because callers that want to
// use LiSendRelativeMotionAsMousePositionEvent() must not mix these function
// without synchronization (otherwise the state of the cursor on the host is
@ -1544,14 +1536,9 @@ int LiSendControllerMotionEvent(uint8_t controllerNumber, uint8_t motionType, fl
// Queue a packet holder if this is the only pending sensor event
if (!currentGamepadSensorState[controllerNumber][motionType - 1].dirty) {
// Set the dirty flag to claim ownership of inserting the packet holder
// and unlock to allow other threads to enqueue or process input.
currentGamepadSensorState[controllerNumber][motionType - 1].dirty = true;
PltUnlockMutex(&batchedInputMutex);
holder = allocatePacketHolder(0);
if (holder == NULL) {
currentGamepadSensorState[controllerNumber][motionType - 1].dirty = false;
PltUnlockMutex(&batchedInputMutex);
return -1;
}
@ -1567,21 +1554,22 @@ int LiSendControllerMotionEvent(uint8_t controllerNumber, uint8_t motionType, fl
// Remaining fields are set in the input thread based on the latest currentGamepadSensorState values
err = LbqOfferQueueItem(&packetQueue, holder, &holder->entry);
if (err != LBQ_SUCCESS) {
if (err == LBQ_SUCCESS) {
currentGamepadSensorState[controllerNumber][motionType - 1].dirty = true;
}
else {
LC_ASSERT(err == LBQ_BOUND_EXCEEDED);
Limelog("Input queue reached maximum size limit\n");
freePacketHolder(holder);
// We weren't able to insert the entry, so let the next call try again
currentGamepadSensorState[controllerNumber][motionType - 1].dirty = false;
}
}
else {
// There's already a packet holder queued to send this event
PltUnlockMutex(&batchedInputMutex);
err = 0;
}
PltUnlockMutex(&batchedInputMutex);
return err;
}

View file

@ -55,7 +55,7 @@ extern uint32_t EncryptionFeaturesEnabled;
// ENet channel ID values
#define CTRL_CHANNEL_GENERIC 0x00
#define CTRL_CHANNEL_URGENT 0x01 // IDR, LTR ACK and RFI
#define CTRL_CHANNEL_URGENT 0x01 // IDR and reference frame invalidation requests
#define CTRL_CHANNEL_KEYBOARD 0x02
#define CTRL_CHANNEL_MOUSE 0x03
#define CTRL_CHANNEL_PEN 0x04
@ -119,7 +119,7 @@ int startControlStream(void);
int stopControlStream(void);
void destroyControlStream(void);
void connectionDetectedFrameLoss(uint32_t startFrame, uint32_t endFrame);
void connectionReceivedCompleteFrame(uint32_t frameIndex, bool frameIsLTR);
void connectionReceivedCompleteFrame(uint32_t frameIndex);
void connectionSawFrame(uint32_t frameIndex);
void connectionSendFrameFecStatus(PSS_FRAME_FEC_STATUS fecStatus);
int sendInputPacketOnControlStream(unsigned char* data, int length, uint8_t channelId, uint32_t flags, bool moreData);

View file

@ -483,8 +483,6 @@ typedef void(*ConnListenerSetAdaptiveTriggers)(uint16_t controllerNumber, uint8_
// This callback is invoked to set a controller's RGB LED (if present).
typedef void(*ConnListenerSetControllerLED)(uint16_t controllerNumber, uint8_t r, uint8_t g, uint8_t b);
typedef void(*ConnListenerSetInputPolicy)(uint8_t allowKeyboard, uint8_t allowMouse, uint8_t allowGamepad, uint8_t reason);
typedef struct _CONNECTION_LISTENER_CALLBACKS {
ConnListenerStageStarting stageStarting;
ConnListenerStageComplete stageComplete;
@ -499,7 +497,6 @@ typedef struct _CONNECTION_LISTENER_CALLBACKS {
ConnListenerSetMotionEventState setMotionEventState;
ConnListenerSetControllerLED setControllerLED;
ConnListenerSetAdaptiveTriggers setAdaptiveTriggers;
ConnListenerSetInputPolicy setInputPolicy;
} CONNECTION_LISTENER_CALLBACKS, *PCONNECTION_LISTENER_CALLBACKS;
// Use this function to zero the connection callbacks when allocated on the stack or heap
@ -840,12 +837,6 @@ int LiSendHighResScrollEvent(short scrollAmount);
int LiSendHScrollEvent(signed char scrollClicks);
int LiSendHighResHScrollEvent(short scrollAmount);
#define LI_SESSION_INPUT_POLICY_REASON_STREAM_START 0x00
#define LI_SESSION_INPUT_POLICY_REASON_USER_TOGGLE 0x01
#define LI_SESSION_INPUT_POLICY_REASON_HOST_ACK 0x02
#define LI_SESSION_INPUT_POLICY_REASON_HOST_OVERRIDE 0x03
int LiSendSessionInputPolicy(bool allowKeyboard, bool allowMouse, bool allowGamepad, uint8_t reason);
// This function returns a time in microseconds with an implementation-defined epoch.
// It should only ever be compared with the return value from a previous call to itself.
uint64_t LiGetMicroseconds(void);

View file

@ -86,7 +86,9 @@ void* ThreadProc(void* context) {
ctx->entry(ctx->context);
free(ctx);
#if defined(__vita__)
free(ctx);
#endif
#if defined(LC_WINDOWS) || defined(__vita__) || defined(__WIIU__) || defined(__3DS__)
return 0;
@ -286,14 +288,11 @@ int PltCreateThread(const char* name, ThreadEntry entry, void* context, PLT_THRE
pthread_attr_init(&attr);
#ifdef __vita__
pthread_attr_setstacksize(&attr, 0x100000);
#endif
ctx->name = name;
int err = pthread_create(&thread->thread, &attr, ThreadProc, ctx);
pthread_attr_destroy(&attr);
if (err != 0) {
free(ctx);
return err;

View file

@ -568,40 +568,6 @@ Exit:
return s;
}
int getLocalAddressByUdpConnect(const struct sockaddr_storage* targetAddr, SOCKADDR_LEN targetAddrLen, unsigned short targetPort,
struct sockaddr_storage* localAddr, SOCKADDR_LEN* localAddrLen) {
SOCKET udpSocket;
LC_SOCKADDR connAddr;
LC_ASSERT(targetPort != 0);
udpSocket = createSocket(targetAddr->ss_family, SOCK_DGRAM, IPPROTO_UDP, false);
if (udpSocket == INVALID_SOCKET) {
return LastSocketError();
}
memcpy(&connAddr, targetAddr, targetAddrLen);
SET_PORT(&connAddr, RtspPortNumber);
if (connect(udpSocket, (struct sockaddr*)&connAddr, targetAddrLen) < 0) {
int err = LastSocketError();
Limelog("UDP connect() failed: %d\n", err);
closeSocket(udpSocket);
return err;
}
*localAddrLen = sizeof(*localAddr);
if (getsockname(udpSocket, (struct sockaddr*)localAddr, localAddrLen) < 0) {
int err = LastSocketError();
Limelog("getsockname() failed: %d\n", err);
closeSocket(udpSocket);
return err;
}
closeSocket(udpSocket);
return 0;
}
// See TCP_MAXSEG note in connectTcpSocket() above for more information.
// TCP_NODELAY must be enabled on the socket for this function to work!
int sendMtuSafe(SOCKET s, char* buffer, int size) {

View file

@ -107,8 +107,6 @@ void addrToUrlSafeString(struct sockaddr_storage* addr, char* string, size_t str
SOCKET createSocket(int addressFamily, int socketType, int protocol, bool nonBlocking);
SOCKET connectTcpSocket(struct sockaddr_storage* dstaddr, SOCKADDR_LEN addrlen, unsigned short port, int timeoutSec);
int getLocalAddressByUdpConnect(const struct sockaddr_storage* targetAddr, SOCKADDR_LEN targetAddrLen, unsigned short targetPort,
struct sockaddr_storage* localAddr, SOCKADDR_LEN* localAddrLen);
int sendMtuSafe(SOCKET s, char* buffer, int size);
SOCKET bindUdpSocket(int addressFamily, struct sockaddr_storage* localAddr, SOCKADDR_LEN addrLen, int bufferSize, int socketQosType);
int enableNoDelay(SOCKET s);

View file

@ -382,9 +382,9 @@ cleanup_packets:
// Check all NV_VIDEO_PACKET fields except FEC stuff which differs in the recovered packet
LC_ASSERT_VT(nvPacket->flags == droppedNvPacket->flags);
LC_ASSERT_VT(nvPacket->extraFlags == droppedNvPacket->extraFlags);
LC_ASSERT_VT(nvPacket->frameIndex == droppedNvPacket->frameIndex);
LC_ASSERT_VT(nvPacket->streamPacketIndex == droppedNvPacket->streamPacketIndex);
LC_ASSERT_VT(nvPacket->reserved == droppedNvPacket->reserved);
LC_ASSERT_VT(!queue->multiFecCapable || nvPacket->multiFecBlocks == droppedNvPacket->multiFecBlocks);
// Check the data itself - use memcmp() and only loop if an error is detected

View file

@ -477,6 +477,18 @@ static bool transactRtspMessageTcp(PRTSP_MESSAGE request, PRTSP_MESSAGE response
// Decrypt (if necessary) and deserialize the RTSP response
ret = unsealRtspMessage(responseBuffer, offset, response);
// Fetch the local address for this socket if it's not populated yet
if (LocalAddr.ss_family == 0) {
SOCKADDR_LEN addrLen = (SOCKADDR_LEN)sizeof(LocalAddr);
if (getsockname(sock, (struct sockaddr*)&LocalAddr, &addrLen) < 0) {
Limelog("Failed to get local address: %d\n", LastSocketError());
memset(&LocalAddr, 0, sizeof(LocalAddr));
}
else {
LC_ASSERT(addrLen == AddrLen);
}
}
Exit:
if (serializedMessage != NULL) {
free(serializedMessage);

View file

@ -22,13 +22,11 @@ typedef struct _ENC_VIDEO_HEADER {
#define FLAG_EOF 0x2
#define FLAG_SOF 0x4
#define NV_VIDEO_PACKET_EXTRA_FLAG_LTR_FRAME 0x1
typedef struct _NV_VIDEO_PACKET {
uint32_t streamPacketIndex;
uint32_t frameIndex;
uint8_t flags;
uint8_t extraFlags;
uint8_t reserved;
uint8_t multiFecFlags;
uint8_t multiFecBlocks;
uint32_t fecInfo;
@ -69,20 +67,4 @@ typedef struct _SS_FRAME_FEC_STATUS {
uint8_t multiFecBlockCount;
} SS_FRAME_FEC_STATUS, *PSS_FRAME_FEC_STATUS;
// Fields are little-endian
#define SS_LTR_FRAME_ACK_PTYPE 0x0350
typedef struct _SS_LTR_FRAME_ACK {
uint32_t frameIndex;
uint32_t reserved;
} SS_LTR_FRAME_ACK, *PSS_LTR_FRAME_ACK;
// Fields are little-endian
#define SS_RFI_REQUEST_PTYPE 0x0301
typedef struct _SS_RFI_REQUEST {
uint32_t firstFrameIndex;
uint32_t reserved1;
uint32_t lastFrameIndex;
uint32_t reserved2[3];
} SS_RFI_REQUEST, *PSS_RFI_REQUEST;
#pragma pack(pop)

View file

@ -466,7 +466,7 @@ static bool isIdrFrameStart(PBUFFER_DESC buffer) {
}
// Reassemble the frame with the given frame number
static void reassembleFrame(int frameNumber, bool frameIsLTR) {
static void reassembleFrame(int frameNumber) {
if (nalChainHead != NULL) {
QUEUED_DECODE_UNIT qduDS;
PQUEUED_DECODE_UNIT qdu;
@ -539,7 +539,7 @@ static void reassembleFrame(int frameNumber, bool frameIsLTR) {
}
// Notify the control connection
connectionReceivedCompleteFrame(frameNumber, frameIsLTR);
connectionReceivedCompleteFrame(frameNumber);
// Clear frame drops
consecutiveFrameDrops = 0;
@ -748,7 +748,6 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
BUFFER_DESC currentPos;
uint32_t frameIndex;
uint8_t flags;
uint8_t extraFlags;
bool firstPacket, lastPacket;
uint32_t streamPacketIndex;
uint8_t fecCurrentBlockNumber;
@ -766,7 +765,6 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
fecLastBlockNumber = (videoPacket->multiFecBlocks >> 6) & 0x3;
frameIndex = videoPacket->frameIndex;
flags = videoPacket->flags;
extraFlags = videoPacket->extraFlags;
firstPacket = isFirstPacket(flags, fecCurrentBlockNumber);
lastPacket = (flags & FLAG_EOF) && fecCurrentBlockNumber == fecLastBlockNumber;
@ -1121,7 +1119,7 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
}
}
reassembleFrame(frameIndex, extraFlags & NV_VIDEO_PACKET_EXTRA_FLAG_LTR_FRAME);
reassembleFrame(frameIndex);
}
}