Restructured Socket Handling, and fixed some memory leaks in it

This commit is contained in:
2026-03-21 11:06:43 +10:00
parent b4351b8f48
commit af8f359759
5 changed files with 219 additions and 170 deletions
+2 -1
View File
@@ -22,7 +22,8 @@ add_executable(ossp MACOSX_BUNDLE
discordrpc.c
localRadioDBHandler.c
localMusicHandler.cpp
socket.c
socket/socket.c
socket/socketActions.c
gui/gui_entry.cpp
player/player.c
player/playQueue.cpp
+24 -153
View File
@@ -21,15 +21,13 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "external/cJSON.h"
#include "configHandler.h"
#include "player/player.h"
#include "player/playQueue.hpp"
#include "libopensubsonic/utils.h"
#include "libopensubsonic/httpclient.h"
#include "libopensubsonic/endpoint_getStarred.h"
#include "libopensubsonic/endpoint_getSong.h"
#include "../external/cJSON.h"
#include "../configHandler.h"
#include "../player/player.h"
#include "../player/playQueue.hpp"
#include "../libopensubsonic/utils.h"
#include "socket.h"
#include "socketActions.h"
static int server_fd = -1;
static int client_fd = -1;
@@ -160,95 +158,14 @@ void socketHandler_cleanup() {
void socketHandler_performAction(int id, char** retDataStr, cJSON** cliReqJson) {
switch (id) {
case OSSP_SOCKET_ACTION_GETSTARREDSONGS:
printf("[SocketHandler] Client requested Starred Songs.\n");
// Fetch /getStarred endpoint
opensubsonic_httpClient_URL_t* url = malloc(sizeof(opensubsonic_httpClient_URL_t));
opensubsonic_httpClient_URL_prepare(&url);
url->endpoint = OPENSUBSONIC_ENDPOINT_GETSTARRED;
opensubsonic_httpClient_formUrl(&url);
opensubsonic_getStarred_struct* getStarredStruct;
opensubsonic_httpClient_fetchResponse(&url, (void**)&getStarredStruct);
opensubsonic_httpClient_URL_cleanup(&url); // Free URL
// Format into JSON
cJSON* retData = cJSON_CreateObject();
cJSON_AddItemToObject(retData, "songCount", cJSON_CreateNumber(getStarredStruct->songCount));
cJSON* songArray = cJSON_CreateArray();
cJSON_AddItemToObject(retData, "songs", songArray);
for (int i = 0; i < getStarredStruct->songCount; i++) {
// NOTE: For anything the client isn't directly accessing, only pass IDs
// Client uses cover art directly, so it needs a URL, but it only needs to pass a song ID back
cJSON* song = cJSON_CreateObject();
cJSON_AddItemToObject(song, "title", cJSON_CreateString(getStarredStruct->songs[i].title));
cJSON_AddItemToObject(song, "album", cJSON_CreateString(getStarredStruct->songs[i].album));
cJSON_AddItemToObject(song, "artist", cJSON_CreateString(getStarredStruct->songs[i].artist));
cJSON_AddItemToObject(song, "id", cJSON_CreateString(getStarredStruct->songs[i].id));
cJSON_AddItemToObject(song, "size", cJSON_CreateNumber(getStarredStruct->songs[i].size));
cJSON_AddItemToObject(song, "duration", cJSON_CreateNumber(getStarredStruct->songs[i].duration));
cJSON_AddItemToObject(song, "albumId", cJSON_CreateString(getStarredStruct->songs[i].albumId));
cJSON_AddItemToObject(song, "artistId", cJSON_CreateString(getStarredStruct->songs[i].artistId));
// Convert cover art ID to URL
opensubsonic_httpClient_URL_t* coverArtUrl = malloc(sizeof(opensubsonic_httpClient_URL_t));
opensubsonic_httpClient_URL_prepare(&coverArtUrl);
coverArtUrl->endpoint = OPENSUBSONIC_ENDPOINT_GETCOVERART;
coverArtUrl->id = strdup(getStarredStruct->songs[i].coverArt);
opensubsonic_httpClient_formUrl(&coverArtUrl);
cJSON_AddItemToObject(song, "coverArtUrl", cJSON_CreateString(coverArtUrl->formedUrl));
cJSON_AddItemToArray(songArray, song);
opensubsonic_httpClient_URL_cleanup(&coverArtUrl); // Free Cover Art URL
}
*retDataStr = cJSON_PrintUnformatted(retData);
cJSON_Delete(retData);
opensubsonic_getStarred_struct_free(&getStarredStruct); // Free Struct
case OSSP_SOCKET_ACTION_GET_STARRED_SONGS:
printf("[SocketHandler] Client requested OSSP_SOCKET_ACTION_GET_STARRED_SONGS.\n");
OSSPS_SocketAction_Get_Starred_Songs(retDataStr, cliReqJson);
break;
case OSSP_SOCKET_ACTION_NOW_PLAYING:
printf("[SocketHandler] Client requested Now Playing.\n");
cJSON* retDatab = cJSON_CreateObject();
int currentPos = OSSPQ_getCurrentPos();
if (currentPos == 0) {
// No songs added to queue yet
cJSON_AddItemToObject(retDatab, "totalQueueCount", cJSON_CreateNumber(0));
} else {
// At least a single song has been added to the queue
OSSPQ_SongStruct* nowPlaying = OSSPQ_getAtPos(currentPos);
if (nowPlaying == NULL) {
// Could not pull queue item
printf("[SocketHandler] --\n");
}
cJSON_AddItemToObject(retDatab, "songTitle", cJSON_CreateString(nowPlaying->title));
cJSON_AddItemToObject(retDatab, "songAlbum", cJSON_CreateString(nowPlaying->album));
cJSON_AddItemToObject(retDatab, "songArtist", cJSON_CreateString(nowPlaying->artist));
//cJSON_AddItemToObject(retData, "duration", cJSON_CreateString());
cJSON_AddItemToObject(retDatab, "coverArtUrl", cJSON_CreateString(nowPlaying->coverArtUrl));
}
printf("%s\n", cJSON_PrintUnformatted(retDatab));
printf("[SocketHandler] Client requested OSSP_SOCKET_ACTION_NOW_PLAYING.\n");
OSSPS_SocketAction_Now_Playing(retDataStr, cliReqJson);
break;
case OSSP_SOCKET_ACTION_ADD_TO_QUEUE:
printf("[SocketHandler] Client requested OSSP_SOCKET_ACTION_ADD_TO_QUEUE.\n");
OSSPS_SocketAction_Add_To_Queue(retDataStr, cliReqJson);
@@ -257,28 +174,26 @@ void socketHandler_performAction(int id, char** retDataStr, cJSON** cliReqJson)
case OSSP_SOCKET_ACTION_OSSPP_PREV:
//
OSSPlayer_GstECont_Playbin3_Prev();
*retDataStr = strdup("OK");
break;
case OSSP_SOCKET_ACTION_OSSPP_PLAYPAUSE:
OSSPlayer_GstECont_Playbin3_PlayPause();
*retDataStr = strdup("OK");
break;
case OSSP_SOCKET_ACTION_OSSPP_NEXT:
OSSPlayer_GstECont_Playbin3_Stop();
OSSPlayer_GstECont_Playbin3_Next();
*retDataStr = strdup("OK");
break;
case OSSP_SOCKET_ACTION_OSSPP_OUTVOLUME:
printf("OUT VOL CHANGED!\n");
int vol = 0;
OSS_Pioj(&vol, *cliReqJson, "vol");
printf("New vol: %d\n", vol);
float f_vol = (float)vol / 100.0f;
printf("New f_vol: %f\n", f_vol);
OSSPlayer_GstECont_OutVolume_set(f_vol);
*retDataStr = strdup("OK");
// New OutVolume set from client
printf("[SocketHandler] Client requested OSSP_SOCKET_ACTION_OSSPP_OUTVOLUME.\n");
OSSPS_SocketAction_OSSPP_OutVolume(retDataStr, cliReqJson);
break;
case OSSP_SOCKET_ACTION_OSSPP_INVOLUME:
// New InVolume set from client
printf("[SocketHandler] Client requested OSSP_SOCKET_ACTION_OSSPP_INVOLUME.\n");
OSSPS_SocketAction_OSSPP_InVolume(retDataStr, cliReqJson);
break;
@@ -291,58 +206,14 @@ void socketHandler_performAction(int id, char** retDataStr, cJSON** cliReqJson)
void OSSPS_SocketAction_Add_To_Queue(char** retDataStr, cJSON** cliReqJson) {
// Pull ID from request JSON
char* id = NULL;
OSS_Psoj(&id, *cliReqJson, "songId");
if (id == NULL) {
printf("[SocketHandler] OSSP_SOCKET_ACTION_ADD_TO_QUEUE failed - 'id' is null.\n");
*retDataStr = strdup("NOTOK");
return;
}
// Create Stream URL from ID
opensubsonic_httpClient_URL_t* streamUrl = malloc(sizeof(opensubsonic_httpClient_URL_t));
opensubsonic_httpClient_URL_prepare(&streamUrl);
streamUrl->endpoint = OPENSUBSONIC_ENDPOINT_STREAM;
streamUrl->id = strdup(id);
opensubsonic_httpClient_formUrl(&streamUrl);
// Contact the /getSong endpoint
opensubsonic_httpClient_URL_t* songUrl = malloc(sizeof(opensubsonic_httpClient_URL_t));
opensubsonic_httpClient_URL_prepare(&songUrl);
songUrl->endpoint = OPENSUBSONIC_ENDPOINT_GETSONG;
songUrl->id = strdup(id);
opensubsonic_httpClient_formUrl(&songUrl);
opensubsonic_getSong_struct* getSongStruct;
opensubsonic_httpClient_fetchResponse(&songUrl, (void**)&getSongStruct);
// Create Cover Art URL from ID
opensubsonic_httpClient_URL_t* coverartUrl = (opensubsonic_httpClient_URL_t*)malloc(sizeof(opensubsonic_httpClient_URL_t));
opensubsonic_httpClient_URL_prepare(&coverartUrl);
coverartUrl->endpoint = OPENSUBSONIC_ENDPOINT_GETCOVERART;
coverartUrl->id = strdup(id);
opensubsonic_httpClient_formUrl(&coverartUrl);
// Append to queue
OSSPQ_AppendToEnd(getSongStruct->title,
getSongStruct->album,
getSongStruct->artist,
id,
streamUrl->formedUrl,
coverartUrl->formedUrl,
getSongStruct->duration,
OSSPQ_MODE_OPENSUBSONIC);
// Free memory
opensubsonic_getSong_struct_free(&getSongStruct);
opensubsonic_httpClient_URL_cleanup(&songUrl);
opensubsonic_httpClient_URL_cleanup(&streamUrl);
opensubsonic_httpClient_URL_cleanup(&coverartUrl);
*retDataStr = strdup("OK");
return;
}
-16
View File
@@ -1,17 +1,6 @@
#ifndef _SOCKET_H
#define _SOCKET_H
#include <stdint.h>
#include "external/cJSON.h"
#define OSSP_SOCKET_ACTION_GETSTARREDSONGS 101
#define OSSP_SOCKET_ACTION_NOW_PLAYING 201
#define OSSP_SOCKET_ACTION_STATS 202
#define OSSP_SOCKET_ACTION_ADD_TO_QUEUE 203
#define OSSP_SOCKET_ACTION_OSSPP_PREV 301 // (OSSPP -> OSSP Player)
#define OSSP_SOCKET_ACTION_OSSPP_PLAYPAUSE 302
#define OSSP_SOCKET_ACTION_OSSPP_NEXT 303
#define OSSP_SOCKET_ACTION_OSSPP_OUTVOLUME 304
typedef struct {
uint32_t signature;
@@ -43,9 +32,4 @@ int socketHandler_sendJson(char* json, int size);
uint32_t socketHandlerUtil_byteArrToUint32BE(uint8_t buf[]);
uint32_t socketHandlerUtil_byteArrToUint32LE(uint8_t buf[]);
// Testing
void OSSPS_SocketAction_Add_To_Queue(char** retDataStr, cJSON** cliReqJson);
#endif
+164
View File
@@ -0,0 +1,164 @@
/*
* OpenSubsonicPlayer
* Goldenkrew3000 2025
* License: GNU General Public License 3.0
* Info: Socket Actions
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "socketActions.h"
#include "../player/player.h"
#include "../player/playQueue.hpp"
#include "../libopensubsonic/utils.h"
#include "../libopensubsonic/httpclient.h"
#include "../libopensubsonic/endpoint_getStarred.h"
#include "../libopensubsonic/endpoint_getSong.h"
#include "../external/cJSON.h"
void OSSPS_SocketAction_Get_Starred_Songs(char** retDataStr, cJSON** cliReqJson) {
// Fetch /getStarred endpoint
opensubsonic_httpClient_URL_t* starredUrl = malloc(sizeof(opensubsonic_httpClient_URL_t));
opensubsonic_httpClient_URL_prepare(&starredUrl);
starredUrl->endpoint = OPENSUBSONIC_ENDPOINT_GETSTARRED;
opensubsonic_httpClient_formUrl(&starredUrl);
opensubsonic_getStarred_struct* getStarredStruct;
opensubsonic_httpClient_fetchResponse(&starredUrl, (void**)&getStarredStruct);
opensubsonic_httpClient_URL_cleanup(&starredUrl);
// Filter out the starred songs only
cJSON* retPayload = cJSON_CreateObject();
cJSON_AddItemToObject(retPayload, "songCount", cJSON_CreateNumber(getStarredStruct->songCount));
cJSON* songArray = cJSON_CreateArray();
cJSON_AddItemToObject(retPayload, "songs", songArray);
for (int i = 0; i < getStarredStruct->songCount; i++) {
// NOTE: For anything the client isn't directly accessing, only pass IDs
// Client uses cover art directly, so it needs a URL, but it only needs to pass a song ID back
opensubsonic_httpClient_URL_t* coverArtUrl = malloc(sizeof(opensubsonic_httpClient_URL_t));
opensubsonic_httpClient_URL_prepare(&coverArtUrl);
coverArtUrl->endpoint = OPENSUBSONIC_ENDPOINT_GETCOVERART;
coverArtUrl->id = strdup(getStarredStruct->songs[i].coverArt);
opensubsonic_httpClient_formUrl(&coverArtUrl);
cJSON* songObj = cJSON_CreateObject();
cJSON_AddItemToObject(songObj, "title", cJSON_CreateString(getStarredStruct->songs[i].title));
cJSON_AddItemToObject(songObj, "album", cJSON_CreateString(getStarredStruct->songs[i].album));
cJSON_AddItemToObject(songObj, "artist", cJSON_CreateString(getStarredStruct->songs[i].artist));
cJSON_AddItemToObject(songObj, "id", cJSON_CreateString(getStarredStruct->songs[i].id));
cJSON_AddItemToObject(songObj, "size", cJSON_CreateNumber(getStarredStruct->songs[i].size));
cJSON_AddItemToObject(songObj, "duration", cJSON_CreateNumber(getStarredStruct->songs[i].duration));
cJSON_AddItemToObject(songObj, "albumId", cJSON_CreateString(getStarredStruct->songs[i].albumId));
cJSON_AddItemToObject(songObj, "artistId", cJSON_CreateString(getStarredStruct->songs[i].artistId));
cJSON_AddItemToObject(songObj, "coverArtUrl", cJSON_CreateString(coverArtUrl->formedUrl));
cJSON_AddItemToArray(songArray, songObj);
opensubsonic_httpClient_URL_cleanup(&coverArtUrl);
}
// Create return payload string and free memory
opensubsonic_getStarred_struct_free(&getStarredStruct);
*retDataStr = cJSON_PrintUnformatted(retPayload);
cJSON_Delete(retPayload);
return;
}
void OSSPS_SocketAction_Now_Playing(char** retDataStr, cJSON** cliReqJson) {
cJSON* retPayload = cJSON_CreateObject();
int currentPos = OSSPQ_getCurrentPos();
if (currentPos == 0) {
// No songs added to queue yet
cJSON_AddItemToObject(retPayload, "totalQueueCount", cJSON_CreateNumber(0));
} else {
// At least a single song has been added to the queue
OSSPQ_SongStruct* nowPlaying = OSSPQ_getAtPos(currentPos);
if (nowPlaying == NULL) {
// Could not pull queue item
// TODO
printf("[SocketHandler] --\n");
}
cJSON_AddItemToObject(retPayload, "songTitle", cJSON_CreateString(nowPlaying->title));
cJSON_AddItemToObject(retPayload, "songAlbum", cJSON_CreateString(nowPlaying->album));
cJSON_AddItemToObject(retPayload, "songArtist", cJSON_CreateString(nowPlaying->artist));
//cJSON_AddItemToObject(retData, "duration", cJSON_CreateString());
cJSON_AddItemToObject(retPayload, "coverArtUrl", cJSON_CreateString(nowPlaying->coverArtUrl));
}
*retDataStr = cJSON_PrintUnformatted(retPayload);
cJSON_Delete(retPayload);
return;
}
void OSSPS_SocketAction_Add_To_Queue(char** retDataStr, cJSON** cliReqJson) {
// Pull ID from request JSON
char* id = NULL;
OSS_Psoj(&id, *cliReqJson, "songId");
if (id == NULL) {
printf("[SocketHandler] OSSP_SOCKET_ACTION_ADD_TO_QUEUE failed - 'id' is null.\n");
*retDataStr = strdup("NOTOK");
return;
}
// Create Stream URL from ID
opensubsonic_httpClient_URL_t* streamUrl = malloc(sizeof(opensubsonic_httpClient_URL_t));
opensubsonic_httpClient_URL_prepare(&streamUrl);
streamUrl->endpoint = OPENSUBSONIC_ENDPOINT_STREAM;
streamUrl->id = strdup(id);
opensubsonic_httpClient_formUrl(&streamUrl);
// Contact the /getSong endpoint
opensubsonic_httpClient_URL_t* songUrl = malloc(sizeof(opensubsonic_httpClient_URL_t));
opensubsonic_httpClient_URL_prepare(&songUrl);
songUrl->endpoint = OPENSUBSONIC_ENDPOINT_GETSONG;
songUrl->id = strdup(id);
opensubsonic_httpClient_formUrl(&songUrl);
opensubsonic_getSong_struct* getSongStruct;
opensubsonic_httpClient_fetchResponse(&songUrl, (void**)&getSongStruct);
// Create Cover Art URL from ID
opensubsonic_httpClient_URL_t* coverartUrl = (opensubsonic_httpClient_URL_t*)malloc(sizeof(opensubsonic_httpClient_URL_t));
opensubsonic_httpClient_URL_prepare(&coverartUrl);
coverartUrl->endpoint = OPENSUBSONIC_ENDPOINT_GETCOVERART;
coverartUrl->id = strdup(id);
opensubsonic_httpClient_formUrl(&coverartUrl);
// Append to queue
OSSPQ_AppendToEnd(getSongStruct->title,
getSongStruct->album,
getSongStruct->artist,
id,
streamUrl->formedUrl,
coverartUrl->formedUrl,
getSongStruct->duration,
OSSPQ_MODE_OPENSUBSONIC);
// Free memory
opensubsonic_getSong_struct_free(&getSongStruct);
opensubsonic_httpClient_URL_cleanup(&songUrl);
opensubsonic_httpClient_URL_cleanup(&streamUrl);
opensubsonic_httpClient_URL_cleanup(&coverartUrl);
*retDataStr = strdup("OK");
return;
}
// NOTE: Could refactor OSSPS_SocketAction_OSSPP_OutVolume and OSSPS_SocketAction_OSSPP_InVolume into a single function,
// but at this point, I don't think it's worth it. This might change later
void OSSPS_SocketAction_OSSPP_OutVolume(char** retDataStr, cJSON** cliReqJson) {
int vol = 0;
OSS_Pioj(&vol, *cliReqJson, "vol");
float f_vol = (float)vol / 100.0f;
OSSPlayer_GstECont_OutVolume_set(f_vol);
*retDataStr = strdup("OK");
}
void OSSPS_SocketAction_OSSPP_InVolume(char** retDataStr, cJSON** cliReqJson) {
int vol = 0;
OSS_Pioj(&vol, *cliReqJson, "vol");
float f_vol = (float)vol / 100.0f;
OSSPlayer_GstECont_InVolume_set(f_vol);
*retDataStr = strdup("OK");
}
+29
View File
@@ -0,0 +1,29 @@
/*
* OpenSubsonicPlayer
* Goldenkrew3000 2025
* License: GNU General Public License 3.0
* Info: Socket Actions
*/
#ifndef _SOCKETACTIONS_H
#define _SOCKETACTIONS_H
#include "../external/cJSON.h"
#define OSSP_SOCKET_ACTION_GET_STARRED_SONGS 101
#define OSSP_SOCKET_ACTION_NOW_PLAYING 201
#define OSSP_SOCKET_ACTION_STATS 202
#define OSSP_SOCKET_ACTION_ADD_TO_QUEUE 203
#define OSSP_SOCKET_ACTION_OSSPP_PREV 301
#define OSSP_SOCKET_ACTION_OSSPP_PLAYPAUSE 302
#define OSSP_SOCKET_ACTION_OSSPP_NEXT 303
#define OSSP_SOCKET_ACTION_OSSPP_OUTVOLUME 304
#define OSSP_SOCKET_ACTION_OSSPP_INVOLUME 305
void OSSPS_SocketAction_Get_Starred_Songs(char** retDataStr, cJSON** cliReqJson);
void OSSPS_SocketAction_Now_Playing(char** retDataStr, cJSON** cliReqJson);
void OSSPS_SocketAction_Add_To_Queue(char** retDataStr, cJSON** cliReqJson);
void OSSPS_SocketAction_OSSPP_OutVolume(char** retDataStr, cJSON** cliReqJson);
void OSSPS_SocketAction_OSSPP_InVolume(char** retDataStr, cJSON** cliReqJson);
#endif