mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2025-08-17 08:55:48 +00:00
Initial RTSP implementation for GFE 2.1.1
This commit is contained in:
parent
fb40201672
commit
5a97188197
@ -1,26 +1,94 @@
|
||||
#include "Limelight-internal.h"
|
||||
#include "Rtsp.h"
|
||||
|
||||
static SOCKET sock = INVALID_SOCKET;
|
||||
static IP_ADDRESS remoteAddr;
|
||||
static int currentSeqNumber = 1;
|
||||
static char* rtspTargetUrl;
|
||||
static char sessionIdString[16];
|
||||
|
||||
// GFE 2.1.1
|
||||
#define RTSP_CLIENT_VERSION 10
|
||||
#define RTSP_CLIENT_VERSION_S "10"
|
||||
|
||||
#define RTSP_MAX_RESP_SIZE 1024
|
||||
|
||||
// FIXME defs
|
||||
static void* transactRtspMessage(IP_ADDRESS addr, void* message) {
|
||||
int err;
|
||||
static POPTION_ITEM createOptionItem(char* option, char* content)
|
||||
{
|
||||
POPTION_ITEM item = malloc(sizeof(*item));
|
||||
if (item == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
item->option = malloc(strlen(option) + 1);
|
||||
if (item->option == NULL) {
|
||||
free(item);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(item->option, option);
|
||||
|
||||
item->content = malloc(strlen(content) + 1);
|
||||
if (item->content == NULL) {
|
||||
free(item->option);
|
||||
free(item);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(item->content, content);
|
||||
|
||||
item->next = NULL;
|
||||
item->flags = FLAG_ALLOCATED_OPTION_FIELDS;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static int addOption(PRTSP_MESSAGE msg, char* option, char* content)
|
||||
{
|
||||
POPTION_ITEM item = createOptionItem(option, content);
|
||||
if (item == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
insertOption(&msg->options, item);
|
||||
msg->flags |= FLAG_ALLOCATED_OPTION_ITEMS;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int initializeRtspRequest(PRTSP_MESSAGE msg, char* command, char* target)
|
||||
{
|
||||
createRtspRequest(msg, NULL, 0, command, target, "RTSP/1.0",
|
||||
currentSeqNumber++, NULL, NULL);
|
||||
|
||||
if (!addOption(msg, "X-GS-ClientVersion", RTSP_CLIENT_VERSION_S)) {
|
||||
freeMessage(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Returns 1 on success, 0 otherwise */
|
||||
static int transactRtspMessage(PRTSP_MESSAGE request, PRTSP_MESSAGE response) {
|
||||
int err, ret = 0;
|
||||
char responseBuffer[RTSP_MAX_RESP_SIZE];
|
||||
int offset;
|
||||
void* responseMsg = NULL;
|
||||
char* serializedMessage;
|
||||
PRTSP_MESSAGE responseMsg = NULL;
|
||||
char* serializedMessage = NULL;
|
||||
int messageLen;
|
||||
|
||||
sock = connectTcpSocket(addr, 48010);
|
||||
sock = connectTcpSocket(remoteAddr, 48010);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
return NULL;
|
||||
return ret;
|
||||
}
|
||||
enableNoDelay(sock);
|
||||
|
||||
serializedMessage = NULL; // FIXME
|
||||
messageLen = 0; // FIXME
|
||||
serializedMessage = serializeRtspMessage(request, &messageLen);
|
||||
if (serializedMessage == NULL) {
|
||||
closesocket(sock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Send our message
|
||||
err = send(sock, serializedMessage, messageLen, 0);
|
||||
@ -40,17 +108,27 @@ static void* transactRtspMessage(IP_ADDRESS addr, void* message) {
|
||||
|
||||
// Warn if the RTSP message is too big
|
||||
if (offset == RTSP_MAX_RESP_SIZE) {
|
||||
Limelog("RTSP message too long");
|
||||
Limelog("RTSP message too long\n");
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
responseMsg = NULL; // FIXME
|
||||
if (parseRtspMessage(response, responseBuffer) == RTSP_ERROR_SUCCESS) {
|
||||
// Successfully parsed response
|
||||
ret = 1;
|
||||
}
|
||||
else {
|
||||
Limelog("Failed to parse RTSP response\n");
|
||||
}
|
||||
|
||||
Exit:
|
||||
if (serializedMessage != NULL) {
|
||||
free(serializedMessage);
|
||||
}
|
||||
|
||||
closesocket(sock);
|
||||
sock = INVALID_SOCKET;
|
||||
return responseMsg;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void terminateRtspHandshake(void) {
|
||||
@ -60,6 +138,252 @@ void terminateRtspHandshake(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static int requestOptions(PRTSP_MESSAGE response) {
|
||||
RTSP_MESSAGE request;
|
||||
int ret;
|
||||
|
||||
ret = initializeRtspRequest(&request, "OPTIONS", rtspTargetUrl);
|
||||
if (ret != 0) {
|
||||
ret = transactRtspMessage(&request, response);
|
||||
freeMessage(&request);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int requestDescribe(PRTSP_MESSAGE response) {
|
||||
RTSP_MESSAGE request;
|
||||
int ret;
|
||||
|
||||
ret = initializeRtspRequest(&request, "DESCRIBE", rtspTargetUrl);
|
||||
if (ret != 0) {
|
||||
if (addOption(&request, "Accept",
|
||||
"application/sdp") &&
|
||||
addOption(&request, "If-Modified-Since",
|
||||
"Thu, 01 Jan 1970 00:00:00 GMT")) {
|
||||
ret = transactRtspMessage(&request, response);
|
||||
}
|
||||
else {
|
||||
ret = 0;
|
||||
}
|
||||
freeMessage(&request);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int setupStream(PRTSP_MESSAGE response, char* target) {
|
||||
RTSP_MESSAGE request;
|
||||
int ret;
|
||||
|
||||
ret = initializeRtspRequest(&request, "SETUP", target);
|
||||
if (ret != 0) {
|
||||
if (sessionIdString[0] != 0) {
|
||||
if (!addOption(&request, "Session", sessionIdString)) {
|
||||
ret = 0;
|
||||
goto FreeMessage;
|
||||
}
|
||||
}
|
||||
|
||||
if (addOption(&request, "Transport", " ") &&
|
||||
addOption(&request, "If-Modified-Since",
|
||||
"Thu, 01 Jan 1970 00:00:00 GMT")) {
|
||||
ret = transactRtspMessage(&request, response);
|
||||
}
|
||||
else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
FreeMessage:
|
||||
freeMessage(&request);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int playStream(PRTSP_MESSAGE response, char* target) {
|
||||
RTSP_MESSAGE request;
|
||||
int ret;
|
||||
|
||||
ret = initializeRtspRequest(&request, "PLAY", target);
|
||||
if (ret != 0) {
|
||||
if (addOption(&request, "Session", sessionIdString)) {
|
||||
ret = transactRtspMessage(&request, response);
|
||||
}
|
||||
else {
|
||||
ret = 0;
|
||||
}
|
||||
freeMessage(&request);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sendVideoAnnounce(PRTSP_MESSAGE response, PSTREAM_CONFIGURATION streamConfig) {
|
||||
RTSP_MESSAGE request;
|
||||
int ret;
|
||||
int payloadLength;
|
||||
char payloadLengthStr[16];
|
||||
struct in_addr sdpAddr;
|
||||
|
||||
ret = initializeRtspRequest(&request, "ANNOUNCE", "streamid=video");
|
||||
if (ret != 0) {
|
||||
ret = 0;
|
||||
|
||||
if (!addOption(&request, "Session", sessionIdString) ||
|
||||
!addOption(&request, "Content-type", "application/sdp")) {
|
||||
goto FreeMessage;
|
||||
}
|
||||
|
||||
sdpAddr.S_un.S_addr = remoteAddr;
|
||||
request.payload = getSdpPayloadForStreamConfig(streamConfig, sdpAddr, &payloadLength);
|
||||
if (request.payload == NULL) {
|
||||
goto FreeMessage;
|
||||
}
|
||||
request.flags |= FLAG_ALLOCATED_PAYLOAD;
|
||||
|
||||
sprintf(payloadLengthStr, "%d", payloadLength);
|
||||
if (!addOption(&request, "Content-length", payloadLengthStr)) {
|
||||
goto FreeMessage;
|
||||
}
|
||||
|
||||
ret = transactRtspMessage(&request, response);
|
||||
|
||||
FreeMessage:
|
||||
freeMessage(&request);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int performRtspHandshake(IP_ADDRESS addr, PSTREAM_CONFIGURATION streamConfigPtr) {
|
||||
remoteAddr = addr;
|
||||
|
||||
{
|
||||
RTSP_MESSAGE response;
|
||||
|
||||
if (!requestOptions(&response)) {
|
||||
Limelog("RTSP OPTIONS request failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (response.message.response.statusCode != 200) {
|
||||
Limelog("RTSP OPTIONS request failed: %d\n",
|
||||
response.message.response.statusCode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeMessage(&response);
|
||||
}
|
||||
|
||||
{
|
||||
RTSP_MESSAGE response;
|
||||
|
||||
if (!requestDescribe(&response)) {
|
||||
Limelog("RTSP DESCRIBE request failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (response.message.response.statusCode != 200) {
|
||||
Limelog("RTSP DESCRIBE request failed: %d\n",
|
||||
response.message.response.statusCode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeMessage(&response);
|
||||
}
|
||||
|
||||
{
|
||||
RTSP_MESSAGE response;
|
||||
char* sessionId;
|
||||
|
||||
if (!setupStream(&response, "streamid=audio")) {
|
||||
Limelog("RTSP SETUP streamid=audio request failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (response.message.response.statusCode != 200) {
|
||||
Limelog("RTSP SETUP streamid=audio request failed: %d\n",
|
||||
response.message.response.statusCode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sessionId = getOptionContent(response.options, "Session");
|
||||
if (sessionId == NULL) {
|
||||
Limelog("RTSP SETUP streamid=audio is missing session attribute");
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeMessage(&response);
|
||||
}
|
||||
|
||||
{
|
||||
RTSP_MESSAGE response;
|
||||
|
||||
if (!setupStream(&response, "streamid=video")) {
|
||||
Limelog("RTSP SETUP streamid=video request failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (response.message.response.statusCode != 200) {
|
||||
Limelog("RTSP SETUP streamid=video request failed: %d\n",
|
||||
response.message.response.statusCode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeMessage(&response);
|
||||
}
|
||||
|
||||
{
|
||||
RTSP_MESSAGE response;
|
||||
|
||||
if (!sendVideoAnnounce(&response, streamConfigPtr)) {
|
||||
Limelog("RTSP ANNOUNCE request failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (response.message.response.statusCode != 200) {
|
||||
Limelog("RTSP ANNOUNCE request failed: %d\n",
|
||||
response.message.response.statusCode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeMessage(&response);
|
||||
}
|
||||
|
||||
{
|
||||
RTSP_MESSAGE response;
|
||||
|
||||
if (!playStream(&response, "streamid=video")) {
|
||||
Limelog("RTSP PLAY streamid=video request failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (response.message.response.statusCode != 200) {
|
||||
Limelog("RTSP PLAY streamid=video failed: %d\n",
|
||||
response.message.response.statusCode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeMessage(&response);
|
||||
}
|
||||
|
||||
{
|
||||
RTSP_MESSAGE response;
|
||||
|
||||
if (!playStream(&response, "streamid=audio")) {
|
||||
Limelog("RTSP PLAY streamid=audio request failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (response.message.response.statusCode != 200) {
|
||||
Limelog("RTSP PLAY streamid=audio failed: %d\n",
|
||||
response.message.response.statusCode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeMessage(&response);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user