diff --git a/limelight-common/Connection.c b/limelight-common/Connection.c
index f6e94c8..75d5e3d 100644
--- a/limelight-common/Connection.c
+++ b/limelight-common/Connection.c
@@ -3,7 +3,7 @@
static int stage = STAGE_NONE;
static CONNECTION_LISTENER_CALLBACKS listenerCallbacks;
-static CONNECTION_LISTENER_CALLBACKS originalCallbacks;
+static ConnListenerConnectionTerminated originalTerminationCallback;
// This is used for debug prints so it's not declared static
PLATFORM_CALLBACKS platformCallbacks;
@@ -101,26 +101,6 @@ void LiStopConnection(void) {
LC_ASSERT(stage == STAGE_NONE);
}
-static void ClInternalStageStarting(int stage)
-{
- originalCallbacks.stageStarting(stage);
-}
-
-static void ClInternalStageComplete(int stage)
-{
- originalCallbacks.stageComplete(stage);
-}
-
-static void ClInternalStageFailed(int stage, long errorCode)
-{
- originalCallbacks.stageFailed(stage, errorCode);
-}
-
-static void ClInternalConnectionStarted(void)
-{
- originalCallbacks.connectionStarted();
-}
-
static void ClInternalConnectionTerminated(long errorCode)
{
// Avoid recursion and issuing multiple callbacks
@@ -129,17 +109,7 @@ static void ClInternalConnectionTerminated(long errorCode)
}
alreadyTerminated = 1;
- originalCallbacks.connectionTerminated(errorCode);
-}
-
-void ClInternalDisplayMessage(char* message)
-{
- originalCallbacks.displayMessage(message);
-}
-
-void ClInternalDisplayTransientMessage(char* message)
-{
- originalCallbacks.displayTransientMessage(message);
+ originalTerminationCallback(errorCode);
}
void LiCompleteThreadStart(void)
@@ -155,16 +125,15 @@ int LiStartConnection(IP_ADDRESS host, PSTREAM_CONFIGURATION streamConfig, PCONN
serverMajorVersion = _serverMajorVersion;
- memcpy(&originalCallbacks, clCallbacks, sizeof(originalCallbacks));
+ // Replace missing callbacks with placeholders
+ fixupMissingCallbacks(&drCallbacks, &arCallbacks, &clCallbacks, &plCallbacks);
memcpy(&platformCallbacks, plCallbacks, sizeof(platformCallbacks));
-
- listenerCallbacks.stageStarting = ClInternalStageStarting;
- listenerCallbacks.stageComplete = ClInternalStageComplete;
- listenerCallbacks.stageFailed = ClInternalStageFailed;
- listenerCallbacks.connectionStarted = ClInternalConnectionStarted;
+
+ // Hook the termination callback so we can avoid issuing a termination callback
+ // after LiStopConnection() is called
+ originalTerminationCallback = clCallbacks->connectionTerminated;
+ memcpy(&listenerCallbacks, clCallbacks, sizeof(listenerCallbacks));
listenerCallbacks.connectionTerminated = ClInternalConnectionTerminated;
- listenerCallbacks.displayMessage = ClInternalDisplayMessage;
- listenerCallbacks.displayTransientMessage = ClInternalDisplayTransientMessage;
alreadyTerminated = 0;
diff --git a/limelight-common/FakeCallbacks.c b/limelight-common/FakeCallbacks.c
new file mode 100644
index 0000000..3b8205d
--- /dev/null
+++ b/limelight-common/FakeCallbacks.c
@@ -0,0 +1,140 @@
+#include "Limelight-internal.h"
+
+static void fakeDrSetup(int width, int height, int redrawRate, void* context, int drFlags) {}
+static void fakeDrStart(void) {}
+static void fakeDrStop(void) {}
+static void fakeDrRelease(void) {}
+static int fakeDrSubmitDecodeUnit(PDECODE_UNIT decodeUnit) { return DR_OK; }
+
+static DECODER_RENDERER_CALLBACKS fakeDrCallbacks = {
+ .setup = fakeDrSetup,
+ .start = fakeDrStart,
+ .stop = fakeDrStop,
+ .release = fakeDrRelease,
+ .submitDecodeUnit = fakeDrSubmitDecodeUnit,
+};
+
+static void fakeArInit(void) {}
+static void fakeArStart(void) {}
+static void fakeArStop(void) {}
+static void fakeArRelease(void) {}
+static void fakeArDecodeAndPlaySample(char* sampleData, int sampleLength) {}
+
+AUDIO_RENDERER_CALLBACKS fakeArCallbacks = {
+ .init = fakeArInit,
+ .start = fakeArStart,
+ .stop = fakeArStop,
+ .release = fakeArRelease,
+ .decodeAndPlaySample = fakeArDecodeAndPlaySample,
+};
+
+static void fakeClStageStarting(int stage) {}
+static void fakeClStageComplete(int stage) {}
+static void fakeClStageFailed(int stage, long errorCode) {}
+static void fakeClConnectionStarted(void) {}
+static void fakeClConnectionTerminated(long errorCode) {}
+static void fakeClDisplayMessage(char* message) {}
+static void fakeClDisplayTransientMessage(char* message) {}
+
+static CONNECTION_LISTENER_CALLBACKS fakeClCallbacks = {
+ .stageStarting = fakeClStageStarting,
+ .stageComplete = fakeClStageComplete,
+ .stageFailed = fakeClStageFailed,
+ .connectionStarted = fakeClConnectionStarted,
+ .connectionTerminated = fakeClConnectionTerminated,
+ .displayMessage = fakeClDisplayMessage,
+ .displayTransientMessage = fakeClDisplayTransientMessage,
+};
+
+static void fakePlThreadStart(void) {}
+static void fakePlDebugPrint(char* string) {}
+
+static PLATFORM_CALLBACKS fakePlCallbacks = {
+ .threadStart = fakePlThreadStart,
+ .debugPrint = fakePlDebugPrint,
+};
+
+void fixupMissingCallbacks(PDECODER_RENDERER_CALLBACKS *drCallbacks, PAUDIO_RENDERER_CALLBACKS *arCallbacks,
+ PCONNECTION_LISTENER_CALLBACKS *clCallbacks, PPLATFORM_CALLBACKS *plCallbacks)
+{
+ if (*drCallbacks == NULL) {
+ *drCallbacks = &fakeDrCallbacks;
+ }
+ else {
+ if ((*drCallbacks)->setup == NULL) {
+ (*drCallbacks)->setup = fakeDrSetup;
+ }
+ if ((*drCallbacks)->start == NULL) {
+ (*drCallbacks)->start = fakeDrStart;
+ }
+ if ((*drCallbacks)->stop == NULL) {
+ (*drCallbacks)->stop = fakeDrStop;
+ }
+ if ((*drCallbacks)->release == NULL) {
+ (*drCallbacks)->release = fakeDrRelease;
+ }
+ if ((*drCallbacks)->submitDecodeUnit == NULL) {
+ (*drCallbacks)->submitDecodeUnit = fakeDrSubmitDecodeUnit;
+ }
+ }
+
+ if (*arCallbacks == NULL) {
+ *arCallbacks = &fakeArCallbacks;
+ }
+ else {
+ if ((*arCallbacks)->init == NULL) {
+ (*arCallbacks)->init = fakeArInit;
+ }
+ if ((*arCallbacks)->start == NULL) {
+ (*arCallbacks)->start = fakeArStart;
+ }
+ if ((*arCallbacks)->stop == NULL) {
+ (*arCallbacks)->stop = fakeArStop;
+ }
+ if ((*arCallbacks)->release == NULL) {
+ (*arCallbacks)->release = fakeArRelease;
+ }
+ if ((*arCallbacks)->decodeAndPlaySample == NULL) {
+ (*arCallbacks)->decodeAndPlaySample = fakeArDecodeAndPlaySample;
+ }
+ }
+
+ if (*clCallbacks == NULL) {
+ *clCallbacks = &fakeClCallbacks;
+ }
+ else {
+ if ((*clCallbacks)->stageStarting == NULL) {
+ (*clCallbacks)->stageStarting = fakeClStageStarting;
+ }
+ if ((*clCallbacks)->stageComplete == NULL) {
+ (*clCallbacks)->stageComplete = fakeClStageComplete;
+ }
+ if ((*clCallbacks)->stageFailed == NULL) {
+ (*clCallbacks)->stageFailed = fakeClStageFailed;
+ }
+ if ((*clCallbacks)->connectionStarted == NULL) {
+ (*clCallbacks)->connectionStarted = fakeClConnectionStarted;
+ }
+ if ((*clCallbacks)->connectionTerminated == NULL) {
+ (*clCallbacks)->connectionTerminated = fakeClConnectionTerminated;
+ }
+ if ((*clCallbacks)->displayMessage == NULL) {
+ (*clCallbacks)->displayMessage = fakeClDisplayMessage;
+ }
+ if ((*clCallbacks)->displayTransientMessage == NULL) {
+ (*clCallbacks)->displayTransientMessage = fakeClDisplayTransientMessage;
+ }
+ }
+
+ if (*plCallbacks == NULL) {
+ *plCallbacks = &fakePlCallbacks;
+ }
+ else {
+ if ((*plCallbacks)->threadStart == NULL) {
+ (*plCallbacks)->threadStart = fakePlThreadStart;
+ }
+ if ((*plCallbacks)->debugPrint == NULL) {
+ (*plCallbacks)->debugPrint = fakePlDebugPrint;
+ }
+ }
+}
\ No newline at end of file
diff --git a/limelight-common/Limelight-internal.h b/limelight-common/Limelight-internal.h
index dfa8466..e1d322d 100644
--- a/limelight-common/Limelight-internal.h
+++ b/limelight-common/Limelight-internal.h
@@ -8,6 +8,9 @@
extern int serverMajorVersion;
+void fixupMissingCallbacks(PDECODER_RENDERER_CALLBACKS *drCallbacks, PAUDIO_RENDERER_CALLBACKS *arCallbacks,
+ PCONNECTION_LISTENER_CALLBACKS *clCallbacks, PPLATFORM_CALLBACKS *plCallbacks);
+
char* getSdpPayloadForStreamConfig(PSTREAM_CONFIGURATION streamConfig, struct in_addr targetAddress,
int rtspClientVersion, int *length);
diff --git a/limelight-common/limelight-common.vcxproj b/limelight-common/limelight-common.vcxproj
index ad60caf..85c6aa3 100644
--- a/limelight-common/limelight-common.vcxproj
+++ b/limelight-common/limelight-common.vcxproj
@@ -135,6 +135,7 @@
+
diff --git a/limelight-common/limelight-common.vcxproj.filters b/limelight-common/limelight-common.vcxproj.filters
index ec4a1b9..672f0bc 100644
--- a/limelight-common/limelight-common.vcxproj.filters
+++ b/limelight-common/limelight-common.vcxproj.filters
@@ -63,6 +63,9 @@
Source Files\OpenAES
+
+ Source Files
+