Added a basic play queue

This commit is contained in:
2025-10-25 23:20:10 +10:00
parent 62c95a5de8
commit 496c5e9acf
5 changed files with 127 additions and 29 deletions

View File

@@ -20,8 +20,10 @@
extern configHandler_config_t* configObj; extern configHandler_config_t* configObj;
bool bLikedSongsShow = false; bool bLikedSongsShow = false;
bool bAudioSettingsShow = false; bool bAudioSettingsShow = false;
bool bPlayQueueShow = false;
void showLikedSongs(); void showLikedSongs();
void showAudioSettings(); void showAudioSettings();
void showPlayQueue();
int gui_entry() { int gui_entry() {
// Initialize SDL // Initialize SDL
@@ -104,6 +106,12 @@ int gui_entry() {
bAudioSettingsShow = true; bAudioSettingsShow = true;
} }
ImGui::SameLine();
if (ImGui::Button("Play Queue")) {
bPlayQueueShow = true;
}
ImGui::End(); ImGui::End();
} }
@@ -115,6 +123,10 @@ int gui_entry() {
showAudioSettings(); showAudioSettings();
} }
if (bPlayQueueShow) {
showPlayQueue();
}
// Render // Render
ImGui::Render(); ImGui::Render();
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
@@ -186,9 +198,10 @@ void showLikedSongs() {
} }
if (selectedSong != -1) { if (selectedSong != -1) {
printf("Song: %s (%s)\n", starredStruct->songs[selectedSong].title, OSSPlayer_QueueAppend(starredStruct->songs[selectedSong].title,
starredStruct->songs[selectedSong].id); starredStruct->songs[selectedSong].artist,
OSSPlayer_QueueAppend(starredStruct->songs[selectedSong].id); starredStruct->songs[selectedSong].id,
starredStruct->songs[selectedSong].duration);
selectedSong = -1; selectedSong = -1;
} }
@@ -231,3 +244,22 @@ void showAudioSettings() {
ImGui::End(); 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();
}

View File

@@ -5,29 +5,82 @@
* Info: Gstreamer Queue Handler * 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 <cstddef>
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <deque> #include <deque>
#include "playQueue.hpp" #include "playQueue.hpp"
// NOTE: Acronym is OpenSubsonicPlayerQueue // C++ interface for storing song queue data (C interface is in the header)
std::deque<std::string> OSSPQ_Items; 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<SongObject> 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); 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; return 0;
} }
char* internal_OSSPQ_PopFromFront() { OSSPQ_SongStruct* internal_OSSPQ_PopFromFront() {
if (OSSPQ_Items.empty()) { if (OSSPQ_Items.empty()) {
// No items in play queue // No items in play queue
return NULL; 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(); 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() { int internal_OSSPQ_GetItemCount() {

View File

@@ -11,8 +11,18 @@
extern "C" { extern "C" {
#endif // __cplusplus #endif // __cplusplus
int internal_OSSPQ_AppendToEnd(char* id); // C interface for sending song queue data (C++ interface is in the C++ file)
char* internal_OSSPQ_PopFromFront(); 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(); int internal_OSSPQ_GetItemCount();
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -10,16 +10,14 @@
#include <math.h> #include <math.h>
#include <stdbool.h> #include <stdbool.h>
#include <pthread.h> #include <pthread.h>
#include <unistd.h>
#include "../configHandler.h" #include "../configHandler.h"
#include "../discordrpc.h" #include "../discordrpc.h"
#include "../libopensubsonic/logger.h" #include "../libopensubsonic/logger.h"
#include "../libopensubsonic/endpoint_getSong.h" #include "../libopensubsonic/endpoint_getSong.h"
#include "../libopensubsonic/httpclient.h" #include "../libopensubsonic/httpclient.h"
#include "playQueue.hpp"
#include "player.h" #include "player.h"
#include <unistd.h> // For worse sleep TODO
extern configHandler_config_t* configObj; extern configHandler_config_t* configObj;
static int rc = 0; static int rc = 0;
GstElement *pipeline, *playbin, *filter_bin, *conv_in, *conv_out, *in_volume, *equalizer, *pitch, *reverb, *out_volume; 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) { if (internal_OSSPQ_GetItemCount() != 0 && isPlaying == false) {
printf("IS VALID\n"); printf("IS VALID\n");
// Player is not playing and a song is in the song queue // Player is not playing and a song is in the song queue
char* id = OSSPlayer_QueuePopFront(); OSSPQ_SongStruct* pq = OSSPlayer_QueuePopFront();
if (id == NULL) { if (pq == NULL) {
printf("FUCK\n"); printf("FUCK\n");
// TODO: this // 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 // NOTE: Using a few strdup()'s because the cleanup/deinit functions perform free's and to avoid UAFs/Double frees
// Fetch song information // Fetch song information
@@ -168,7 +169,7 @@ void* OSSPlayer_ThrdInit(void*) {
isPlaying = true; isPlaying = true;
gst_element_set_state(pipeline, GST_STATE_PLAYING); 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 // Initialize equalizer
if (configObj->audio_equalizer_enable) { 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 // Dynamically append settings to the equalizer to match the config file
for (int i = 0; i < configObj->audio_equalizer_graphCount; i++) { for (int i = 0; i < configObj->audio_equalizer_graphCount; i++) {
char* ftl_name = NULL; char* ftl_name = NULL;
@@ -335,20 +334,22 @@ int OSSPlayer_GstDeInit() {
/* /*
* Player Queue Control Functions * Player Queue Control Functions
*/ */
int OSSPlayer_QueueAppend(char* id) { int OSSPlayer_QueueAppend(char* title, char* artist, char* id, long duration) {
// Call to C++ function // 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 // Call to C++ function
// NOTE: 'id' is heap-allocated from C++
char* id = internal_OSSPQ_PopFromFront(); OSSPQ_SongStruct* songObject = internal_OSSPQ_PopFromFront();
if (id == NULL) {
if (songObject == NULL) {
// Queue is empty TODO // Queue is empty TODO
printf("FUCKFUCKFUCK\n"); printf("FUCKFUCKFUCK\n");
} }
return id; return songObject;
} }
/* /*

View File

@@ -11,11 +11,13 @@
extern "C" { extern "C" {
#endif #endif
#include "playQueue.hpp"
void* OSSPlayer_GMainLoop(void*); void* OSSPlayer_GMainLoop(void*);
void* OSSPlayer_ThrdInit(void*); void* OSSPlayer_ThrdInit(void*);
int OSSPlayer_GstInit(); int OSSPlayer_GstInit();
int OSSPlayer_QueueAppend(char* id); int OSSPlayer_QueueAppend(char* title, char* artist, char* id, long duration);
char* OSSPlayer_QueuePopFront(); OSSPQ_SongStruct* OSSPlayer_QueuePopFront();
float OSSPlayer_GstECont_InVolume_Get(); float OSSPlayer_GstECont_InVolume_Get();
void OSSPlayer_GstECont_InVolume_set(float val); void OSSPlayer_GstECont_InVolume_set(float val);