diff --git a/src/gui/gui_entry.cpp b/src/gui/gui_entry.cpp index 36d7e7e..6f8e24b 100644 --- a/src/gui/gui_entry.cpp +++ b/src/gui/gui_entry.cpp @@ -20,8 +20,10 @@ extern configHandler_config_t* configObj; bool bLikedSongsShow = false; bool bAudioSettingsShow = false; +bool bPlayQueueShow = false; void showLikedSongs(); void showAudioSettings(); +void showPlayQueue(); int gui_entry() { // Initialize SDL @@ -104,6 +106,12 @@ int gui_entry() { bAudioSettingsShow = true; } + ImGui::SameLine(); + + if (ImGui::Button("Play Queue")) { + bPlayQueueShow = true; + } + ImGui::End(); } @@ -115,6 +123,10 @@ int gui_entry() { showAudioSettings(); } + if (bPlayQueueShow) { + showPlayQueue(); + } + // Render ImGui::Render(); glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); @@ -186,9 +198,10 @@ void showLikedSongs() { } if (selectedSong != -1) { - printf("Song: %s (%s)\n", starredStruct->songs[selectedSong].title, - starredStruct->songs[selectedSong].id); - OSSPlayer_QueueAppend(starredStruct->songs[selectedSong].id); + OSSPlayer_QueueAppend(starredStruct->songs[selectedSong].title, + starredStruct->songs[selectedSong].artist, + starredStruct->songs[selectedSong].id, + starredStruct->songs[selectedSong].duration); selectedSong = -1; } @@ -231,3 +244,22 @@ void showAudioSettings() { ImGui::End(); } + +// TODO: go through abstraction +#include "../player/playQueue.hpp" + +void showPlayQueue() { + ImGui::Begin("Play Queue"); + + static int selectedSong = -1; + if (ImGui::BeginChild("Play Queue", ImVec2(0, 200), ImGuiChildFlags_Border)) { + for (int i = 0; i < internal_OSSPQ_GetItemCount(); i++) { + if (ImGui::Selectable(internal_OSSPQ_GetTitleAtIndex(i), selectedSong == i)) { + selectedSong = i; + } + } + ImGui::EndChild(); + } + + ImGui::End(); +} diff --git a/src/player/playQueue.cpp b/src/player/playQueue.cpp index 01aba3d..fd262d7 100644 --- a/src/player/playQueue.cpp +++ b/src/player/playQueue.cpp @@ -5,29 +5,82 @@ * Info: Gstreamer Queue Handler */ + /* + * Now you might ask why this even exists in this way, but I thought that it would be easier to jump to C++ + * to store a song queue with objects instead of some hacked together solution in C + * And I was right. + * Like yeah, you can store an array of structs easily in C, but to dynamically be able to move those around, no, + * std::deque makes that MUCH simpler. + */ + +#include #include #include #include #include "playQueue.hpp" -// NOTE: Acronym is OpenSubsonicPlayerQueue -std::deque OSSPQ_Items; +// C++ interface for storing song queue data (C interface is in the header) +class SongObject { + public: + std::string title; + std::string artist; + std::string id; + long duration; +}; -int internal_OSSPQ_AppendToEnd(char* id) { +// NOTE: Acronym is OpenSubsonicPlayerQueue +std::deque OSSPQ_Items; + +int internal_OSSPQ_AppendToEnd(char* title, char* artist, char* id, long duration) { + // Append a new song to the end of the queue + printf("Title: %s\nArtist: %s\nID: %s\nDuration: %ld\n", title, artist, id, duration); + // TODO: Find a neater way of converting a C string to a C++ string?? + std::string cpp_title(title); + std::string cpp_artist(artist); std::string cpp_id(id); - OSSPQ_Items.push_back(cpp_id); + SongObject songObject; + songObject.title = cpp_title; + songObject.artist = cpp_artist; + songObject.id = cpp_id; + songObject.duration = duration; + OSSPQ_Items.push_back(songObject); return 0; } -char* internal_OSSPQ_PopFromFront() { +OSSPQ_SongStruct* internal_OSSPQ_PopFromFront() { if (OSSPQ_Items.empty()) { // No items in play queue return NULL; } - char* id = strdup(OSSPQ_Items.front().c_str()); // Heap allocate id + // Pull the first song off the song queue + SongObject songObject = OSSPQ_Items.front(); OSSPQ_Items.pop_front(); - return id; + + // Move song data into a C readable format + // NOTE: I am initializing the variables to a known value just in case there is missing information in songObject + OSSPQ_SongStruct* playQueueObject = (OSSPQ_SongStruct*)malloc(sizeof(OSSPQ_SongStruct)); + playQueueObject->title = NULL; + playQueueObject->artist = NULL; + playQueueObject->id = NULL; + playQueueObject->duration = 0; + + playQueueObject->title = strdup(songObject.title.c_str()); + playQueueObject->artist = strdup(songObject.artist.c_str()); + playQueueObject->id = strdup(songObject.id.c_str()); + playQueueObject->duration = songObject.duration; + return playQueueObject; +} + +void internal_OSSPQ_FreeSongObject(OSSPQ_SongStruct* songObject) { + if (songObject->title != NULL) { free(songObject->title); } + if (songObject->artist != NULL) { free(songObject->artist); } + if (songObject->id != NULL) { free(songObject->id); } + if (songObject != NULL) { free(songObject); } +} + +char* internal_OSSPQ_GetTitleAtIndex(int idx) { + return (char*)OSSPQ_Items[idx].title.c_str(); } int internal_OSSPQ_GetItemCount() { diff --git a/src/player/playQueue.hpp b/src/player/playQueue.hpp index 1d1baf3..5809eda 100644 --- a/src/player/playQueue.hpp +++ b/src/player/playQueue.hpp @@ -11,8 +11,18 @@ extern "C" { #endif // __cplusplus -int internal_OSSPQ_AppendToEnd(char* id); -char* internal_OSSPQ_PopFromFront(); +// C interface for sending song queue data (C++ interface is in the C++ file) +typedef struct { + char* title; + char* artist; + char* id; + long duration; +} OSSPQ_SongStruct; + +int internal_OSSPQ_AppendToEnd(char* title, char* artist, char* id, long duration); +OSSPQ_SongStruct* internal_OSSPQ_PopFromFront(); +void internal_OSSPQ_FreeSongObject(OSSPQ_SongStruct* songObject); +char* internal_OSSPQ_GetTitleAtIndex(int idx); int internal_OSSPQ_GetItemCount(); #ifdef __cplusplus diff --git a/src/player/player.c b/src/player/player.c index 6ef69c5..d63c46c 100644 --- a/src/player/player.c +++ b/src/player/player.c @@ -10,16 +10,14 @@ #include #include #include +#include #include "../configHandler.h" #include "../discordrpc.h" #include "../libopensubsonic/logger.h" #include "../libopensubsonic/endpoint_getSong.h" #include "../libopensubsonic/httpclient.h" -#include "playQueue.hpp" #include "player.h" -#include // For worse sleep TODO - extern configHandler_config_t* configObj; static int rc = 0; GstElement *pipeline, *playbin, *filter_bin, *conv_in, *conv_out, *in_volume, *equalizer, *pitch, *reverb, *out_volume; @@ -118,12 +116,15 @@ void* OSSPlayer_ThrdInit(void*) { if (internal_OSSPQ_GetItemCount() != 0 && isPlaying == false) { printf("IS VALID\n"); // Player is not playing and a song is in the song queue - char* id = OSSPlayer_QueuePopFront(); - if (id == NULL) { + OSSPQ_SongStruct* pq = OSSPlayer_QueuePopFront(); + if (pq == NULL) { printf("FUCK\n"); // TODO: this } + char* id = strdup(pq->id); + //free(pq); + // NOTE: Using a few strdup()'s because the cleanup/deinit functions perform free's and to avoid UAFs/Double frees // Fetch song information @@ -168,7 +169,7 @@ void* OSSPlayer_ThrdInit(void*) { isPlaying = true; gst_element_set_state(pipeline, GST_STATE_PLAYING); } - usleep(200 * 1000); // Use futex and signals instead of this TODO + usleep(200 * 1000); } } @@ -254,8 +255,6 @@ int OSSPlayer_GstInit() { // Initialize equalizer if (configObj->audio_equalizer_enable) { - printf("Initializing %d equalizer bands...\n", configObj->audio_equalizer_graphCount); - // Dynamically append settings to the equalizer to match the config file for (int i = 0; i < configObj->audio_equalizer_graphCount; i++) { char* ftl_name = NULL; @@ -335,20 +334,22 @@ int OSSPlayer_GstDeInit() { /* * Player Queue Control Functions */ -int OSSPlayer_QueueAppend(char* id) { +int OSSPlayer_QueueAppend(char* title, char* artist, char* id, long duration) { // Call to C++ function - internal_OSSPQ_AppendToEnd(id); + // Note: I would receive a song struct instead of individual elements, but it would significantly slow down the GUI + internal_OSSPQ_AppendToEnd(title, artist, id, duration); } -char* OSSPlayer_QueuePopFront() { +OSSPQ_SongStruct* OSSPlayer_QueuePopFront() { // Call to C++ function - // NOTE: 'id' is heap-allocated from C++ - char* id = internal_OSSPQ_PopFromFront(); - if (id == NULL) { + + OSSPQ_SongStruct* songObject = internal_OSSPQ_PopFromFront(); + + if (songObject == NULL) { // Queue is empty TODO printf("FUCKFUCKFUCK\n"); } - return id; + return songObject; } /* diff --git a/src/player/player.h b/src/player/player.h index 2f7ef9d..dad8979 100644 --- a/src/player/player.h +++ b/src/player/player.h @@ -11,11 +11,13 @@ extern "C" { #endif +#include "playQueue.hpp" + void* OSSPlayer_GMainLoop(void*); void* OSSPlayer_ThrdInit(void*); int OSSPlayer_GstInit(); -int OSSPlayer_QueueAppend(char* id); -char* OSSPlayer_QueuePopFront(); +int OSSPlayer_QueueAppend(char* title, char* artist, char* id, long duration); +OSSPQ_SongStruct* OSSPlayer_QueuePopFront(); float OSSPlayer_GstECont_InVolume_Get(); void OSSPlayer_GstECont_InVolume_set(float val);