diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5438cb2..f547f67 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -69,7 +69,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") include_directories(${GSTREAMER_INCLUDE_DIRS} ${AVFORMAT_INCLUDE_DIR} ${AVUTIL_INCLUDE_DIRS} /usr/X11R7/include /usr/pkg/include/ffmpeg8) elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") message("--- Detected macOS ---") - target_link_directories(ossp PRIVATE /opt/ossp/lib /opt/homebrew/lib) + target_link_directories(ossp PRIVATE /opt/ossp/lib) pkg_check_modules(AVFORMAT REQUIRED libavformat) pkg_check_modules(AVUTIL REQUIRED libavutil) pkg_check_modules(BZ2 REQUIRED bzip2) diff --git a/src/discordrpc.c b/src/discordrpc.c index dad0847..4700d26 100644 --- a/src/discordrpc.c +++ b/src/discordrpc.c @@ -66,21 +66,23 @@ void discordrpc_update(discordrpc_data** discordrpc_struct) { if ((*discordrpc_struct)->state == DISCORDRPC_STATE_IDLE) { asprintf(&detailsString, "Idle"); presence.details = detailsString; - } else if ((*discordrpc_struct)->state == DISCORDRPC_STATE_PLAYING_OPENSUBSONIC) { - // Playing a song + } else if ((*discordrpc_struct)->state == DISCORDRPC_STATE_PLAYING_OPENSUBSONIC || + ((*discordrpc_struct)->state == DISCORDRPC_STATE_PLAYING_LOCALFILE)) { + // Playing a song from an OpenSubsonic server time_t currentTime = time(NULL); asprintf(&detailsString, "%s", (*discordrpc_struct)->songTitle); asprintf(&stateString, "by %s", (*discordrpc_struct)->songArtist); presence.details = detailsString; presence.state = stateString; - presence.largeImageKey = (*discordrpc_struct)->coverArtUrl; + if ((*discordrpc_struct)->state == DISCORDRPC_STATE_PLAYING_OPENSUBSONIC) { + // TODO As of now, local file playback does NOT deal with cover art + presence.largeImageKey = (*discordrpc_struct)->coverArtUrl; + } presence.startTimestamp = (long)currentTime; presence.endTimestamp = (long)currentTime + (*discordrpc_struct)->songLength; if (configObj->discordrpc_showSysDetails) { presence.largeImageText = discordrpc_osString; } - } else if ((*discordrpc_struct)->state == DISCORDRPC_STATE_PLAYING_LOCALFILE) { - // } else if ((*discordrpc_struct)->state == DISCORDRPC_STATE_PLAYING_INTERNETRADIO) { // Playing an internet radio station time_t currentTime = time(NULL); diff --git a/src/gui/gui_entry.cpp b/src/gui/gui_entry.cpp index 6f8e24b..0faf6e4 100644 --- a/src/gui/gui_entry.cpp +++ b/src/gui/gui_entry.cpp @@ -5,6 +5,11 @@ * Info: Debug / Prototype graphical interface */ +/* + * THIS IS SPECIFICALLY THE DEVELOPMENT INTERFACE + * IT IS HORRIFICIALLY UNOPTIMIZED BUT IT WORKS + */ + #include "../external/imgui/imgui.h" #include "../external/imgui/backends/imgui_impl_sdl2.h" #include "../external/imgui/backends/imgui_impl_opengl2.h" @@ -15,15 +20,25 @@ #include "../configHandler.h" #include "../libopensubsonic/httpclient.h" #include "../libopensubsonic/endpoint_getStarred.h" +#include "../libopensubsonic/endpoint_getAlbum.h" #include "../player/player.h" +#include "../libopensubsonic/endpoint_getInternetRadioStations.h" extern configHandler_config_t* configObj; bool bLikedSongsShow = false; bool bAudioSettingsShow = false; bool bPlayQueueShow = false; +bool bShowRadioStations = false; +bool bShowNowPlaying = false; +bool bShowLikedAlbums = false; +bool bShowLocalSongs = false; void showLikedSongs(); void showAudioSettings(); void showPlayQueue(); +void showRadioStations(); +void showNowPlaying(); +void showLikedAlbums(); +void showLocalSongs(); int gui_entry() { // Initialize SDL @@ -112,6 +127,26 @@ int gui_entry() { bPlayQueueShow = true; } + if (ImGui::Button("Radio")) { + bShowRadioStations = true; + } + + ImGui::SameLine(); + + if (ImGui::Button("Now Playing")) { + bShowNowPlaying = true; + } + + ImGui::SameLine(); + + if (ImGui::Button("Liked Albums")) { + bShowLikedAlbums = true; + } + + if (ImGui::Button("Local Songs")) { + bShowLocalSongs = true; + } + ImGui::End(); } @@ -127,6 +162,22 @@ int gui_entry() { showPlayQueue(); } + if (bShowRadioStations) { + showRadioStations(); + } + + if (bShowNowPlaying) { + showNowPlaying(); + } + + if (bShowLikedAlbums) { + showLikedAlbums(); + } + + if (bShowLocalSongs) { + showLocalSongs(); + } + // Render ImGui::Render(); glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); @@ -198,10 +249,30 @@ void showLikedSongs() { } if (selectedSong != -1) { - OSSPlayer_QueueAppend(starredStruct->songs[selectedSong].title, - starredStruct->songs[selectedSong].artist, - starredStruct->songs[selectedSong].id, - starredStruct->songs[selectedSong].duration); + // Form URL + opensubsonic_httpClient_URL_t* song_url = (opensubsonic_httpClient_URL_t*)malloc(sizeof(opensubsonic_httpClient_URL_t)); + opensubsonic_httpClient_URL_prepare(&song_url); + song_url->endpoint = OPENSUBSONIC_ENDPOINT_STREAM; + song_url->id = strdup(starredStruct->songs[selectedSong].id); + opensubsonic_httpClient_formUrl(&song_url); + + opensubsonic_httpClient_URL_t* coverart_url = (opensubsonic_httpClient_URL_t*)malloc(sizeof(opensubsonic_httpClient_URL_t)); + opensubsonic_httpClient_URL_prepare(&coverart_url); + coverart_url->endpoint = OPENSUBSONIC_ENDPOINT_GETCOVERART; + coverart_url->id = strdup(starredStruct->songs[selectedSong].coverArt); + opensubsonic_httpClient_formUrl(&coverart_url); + + OSSPQ_AppendToEnd(starredStruct->songs[selectedSong].title, + starredStruct->songs[selectedSong].album, + starredStruct->songs[selectedSong].artist, + starredStruct->songs[selectedSong].id, + song_url->formedUrl, + coverart_url->formedUrl, + starredStruct->songs[selectedSong].duration, + OSSPQ_MODE_OPENSUBSONIC); + + opensubsonic_httpClient_URL_cleanup(&song_url); + opensubsonic_httpClient_URL_cleanup(&coverart_url); selectedSong = -1; } @@ -242,6 +313,10 @@ void showAudioSettings() { OSSPlayer_GstECont_Pitch_Set(pitch_val * 100.0f); // Convert semitones to cents } + if(ImGui::Button("Skip")) { + OSSPlayer_GstECont_Playbin3_Stop(); + } + ImGui::End(); } @@ -263,3 +338,289 @@ void showPlayQueue() { ImGui::End(); } + + + +bool haveRadioStations = false; +opensubsonic_getInternetRadioStations_struct* irsStruct; +opensubsonic_httpClient_URL_t* radioUrl; + +void getRadioStations() { + radioUrl = (opensubsonic_httpClient_URL_t*)malloc(sizeof(opensubsonic_httpClient_URL_t)); + opensubsonic_httpClient_URL_prepare(&radioUrl); + radioUrl->endpoint = OPENSUBSONIC_ENDPOINT_GETINTERNETRADIOSTATIONS; + opensubsonic_httpClient_formUrl(&radioUrl); + opensubsonic_httpClient_fetchResponse(&radioUrl, (void**)&irsStruct); + + if (irsStruct->errorCode != 0) { + // Error happened + } + + haveRadioStations = true; +} + +void showRadioStations() { + if (!haveRadioStations) { getRadioStations(); } + + ImGui::Begin("Radio Stations"); + + static int selectedSong = -1; + if (haveRadioStations) { + if (ImGui::BeginChild("Radio Stations", ImVec2(0, 200), ImGuiChildFlags_Border)) { + for (int i = 0; i < irsStruct->radioStationCount; i++) { + if (ImGui::Selectable(irsStruct->radioStations[i].name, selectedSong == i)) { + selectedSong = i; + } + } + ImGui::EndChild(); + } + } + + + if (selectedSong != -1) { + //OSSPlayer_QueueAppend_Radio(irsStruct->radioStations[selectedSong].name, + // irsStruct->radioStations[selectedSong].id, + // irsStruct->radioStations[selectedSong].streamUrl); + selectedSong = -1; + } + + ImGui::End(); +} + +void showNowPlaying() { + ImGui::Begin("Now Playing"); + + /* + * Okay so I need: + * - Current and final position of song + * - Play, Pause, Next buttons (Needs DiscordRPC expansion) + */ + + ImGui::End(); +} + + +void showAlbum(char* id); + +int likedAlbumsSelectedSong = -1; +void showLikedAlbums() { + // /getStarred is all of the liked info, not just songs + if (!haveLikedSongsInfo) { getLikedSongsInfo(); } + + ImGui::Begin("Liked Albums"); + + ImGui::Text("Liked Albums"); + + if (ImGui::Button("Close")) { + bShowLikedAlbums = false; + } + + if (ImGui::Button("Refresh")) { + opensubsonic_getStarred_struct_free(&starredStruct); + opensubsonic_httpClient_URL_cleanup(&starredUrl); + haveLikedSongsInfo = false; + } + + if (haveLikedSongsInfo) { + if (ImGui::BeginChild("Liked Albums", ImVec2(0, 200), ImGuiChildFlags_Border)) { + for (int i = 0; i < starredStruct->albumCount; i++) { + if (ImGui::Selectable(starredStruct->albums[i].title, likedAlbumsSelectedSong == i)) { + likedAlbumsSelectedSong = i; + } + } + ImGui::EndChild(); + } + } + + if (likedAlbumsSelectedSong != -1) { + showAlbum(starredStruct->albums[likedAlbumsSelectedSong].id); + } + + ImGui::End(); +} + +bool hasAlbum = false; +opensubsonic_getAlbum_struct* getAlbumStruct; +void getAlbum(char* id) { + opensubsonic_httpClient_URL_t* url = (opensubsonic_httpClient_URL_t*)malloc(sizeof(opensubsonic_httpClient_URL_t)); + opensubsonic_httpClient_URL_prepare(&url); + url->endpoint = OPENSUBSONIC_ENDPOINT_GETALBUM; + url->id = strdup(id); + opensubsonic_httpClient_formUrl(&url); + + opensubsonic_httpClient_fetchResponse(&url, (void**)&getAlbumStruct); + + //opensubsonic_getAlbum_struct_free(&getAlbumStruct); + //opensubsonic_httpClient_URL_cleanup(&url); + + hasAlbum = true; +} + +static int rand_int(int n) { + int limit = RAND_MAX - RAND_MAX % n; + int rnd; + + do { + rnd = rand(); + } while (rnd >= limit); + return rnd % n; +} + +void shuffle(int *array, int n) { + int i, j, tmp; + + for (i = n - 1; i > 0; i--) { + j = rand_int(i + 1); + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + } +} + +void shuffleAlbum() { + int n = getAlbumStruct->songCount; + + int arr[1] = { 0 }; + for (int i = 0; i < n; i++) { + arr[i] = i; + } + + shuffle(arr, n); + + for (int i = 0; i < n; i++) { + //OSSPlayer_QueueAppend_Song(getAlbumStruct->songs[arr[i]].title, + // getAlbumStruct->songs[arr[i]].artist, + // getAlbumStruct->songs[arr[i]].id, + // getAlbumStruct->songs[arr[i]].duration); + } +} + +#include +void showAlbum(char* id) { + ImGui::Begin("Album"); + + if (!hasAlbum) { getAlbum(id); } + + ImGui::Text("Album"); + + if (ImGui::Button("Close")) { + likedAlbumsSelectedSong = -1; + hasAlbum = false; + } + + ImGui::SameLine(); + + if (ImGui::Button("Play all")) { + for (int i = 0; i < getAlbumStruct->songCount; i++) { + /* + // Form URL + opensubsonic_getAlbum_struct* + + opensubsonic_httpClient_URL_t* song_url = (opensubsonic_httpClient_URL_t*)malloc(sizeof(opensubsonic_httpClient_URL_t)); + opensubsonic_httpClient_URL_prepare(&song_url); + song_url->endpoint = OPENSUBSONIC_ENDPOINT_STREAM; + song_url->id = strdup(starredStruct->songs[selectedSong].id); + opensubsonic_httpClient_formUrl(&song_url); + + opensubsonic_httpClient_URL_t* coverart_url = (opensubsonic_httpClient_URL_t*)malloc(sizeof(opensubsonic_httpClient_URL_t)); + opensubsonic_httpClient_URL_prepare(&coverart_url); + coverart_url->endpoint = OPENSUBSONIC_ENDPOINT_GETCOVERART; + coverart_url->id = strdup(starredStruct->songs[selectedSong].coverArt); + opensubsonic_httpClient_formUrl(&coverart_url); + + OSSPQ_AppendToEnd(starredStruct->songs[selectedSong].title, + starredStruct->songs[selectedSong].album, + starredStruct->songs[selectedSong].artist, + starredStruct->songs[selectedSong].id, + song_url->formedUrl, + coverart_url->formedUrl, + starredStruct->songs[selectedSong].duration, + OSSPQ_MODE_OPENSUBSONIC); + + opensubsonic_httpClient_URL_cleanup(&song_url); + opensubsonic_httpClient_URL_cleanup(&coverart_url); + selectedSong = -1; getAlbumStruct->songs[i].duration); + */ + } + } + + ImGui::SameLine(); + + if (ImGui::Button("Shuffle")) { + srand(time(NULL)); + shuffleAlbum(); + } + + static int selectedSong = -1; + if (hasAlbum) { + if (ImGui::BeginChild("Album", ImVec2(0, 200), ImGuiChildFlags_Border)) { + for (int i = 0; i < getAlbumStruct->songCount; i++) { + if (ImGui::Selectable(getAlbumStruct->songs[i].title, selectedSong == i)) { + selectedSong = i; + } + } + ImGui::EndChild(); + } + } + + ImGui::End(); +} + + + + + + + +#include "../localMusicHandler.hpp" + +bool hasLocalSongs = false; +localMusicHandler_songReq_t* songReq; + +void getLocalSongs() { + songReq = localMusicHandler_test(); + hasLocalSongs = true; +} + +void showLocalSongs() { + + + ImGui::Begin("Local Songs"); + + if (!hasLocalSongs) { getLocalSongs(); } + + ImGui::Text("Local Songs"); + + static int selectedSong = -1; + if (hasLocalSongs) { + if (ImGui::BeginChild("LocalSongs", ImVec2(0, 200), ImGuiChildFlags_Border)) { + for (int i = 0; i < songReq->songCount; i++) { + if (ImGui::Selectable(songReq->songs[i].title, selectedSong == i)) { + selectedSong = i; + } + } + ImGui::EndChild(); + } + } + + if (selectedSong != -1) { + // Treat it as radio station for testing + char* newPath = NULL; + asprintf(&newPath, "file://%s", songReq->songs[selectedSong].path); + + //OSSPlayer_QueueAppend_Radio(songReq->songs[selectedSong].title, + // songReq->songs[selectedSong].uid, + // newPath); + OSSPQ_AppendToEnd(songReq->songs[selectedSong].title, + NULL, + NULL, + songReq->songs[selectedSong].uid, + newPath, + NULL, + 0, + OSSPQ_MODE_LOCALFILE); + selectedSong = -1; + } + + ImGui::End(); +} diff --git a/src/localMusicHandler.cpp b/src/localMusicHandler.cpp index 4290ff3..fe4f52d 100644 --- a/src/localMusicHandler.cpp +++ b/src/localMusicHandler.cpp @@ -84,6 +84,9 @@ void localMusicHandler_scan() { } else if (rc == 1) { // Table was already made, assume songs were loaded in before } + + + //localMusicHandler_test(); } void localMusicHandler_scanDirectory(char* directory) { @@ -255,3 +258,65 @@ void localMusicHandler_moveSongsToDatabase(int idx) { sqlite3_finalize(sqlite_stmt); } + + + + + + + + +// P.S. Sqlite searching directly is fucking useless +// Have to use something on top, and just load base shit into memory completely I think +// Plus how many fucking songs would it take to actually become an issue? +std::deque localMusicHandler_songReqDeque; +localMusicHandler_songReq_t* localMusicHandler_test() { + // Test + sqlite3_stmt* sqlite_stmt; + //const char* sqlQuery = "SELECT * FROM local_songs WHERE artistTitle LIKE ?;"; + const char* sqlQuery = "SELECT * FROM local_songs;"; + + if (sqlite3_prepare_v2(sqlite_db, sqlQuery, -1, &sqlite_stmt, NULL) != SQLITE_OK) { + printf("fuck\n"); + //return; + } + //sqlite3_bind_text(sqlite_stmt, 1, "ch", -1, SQLITE_STATIC); + + // %text% to prevent SQL injection --> %% for % with asprintf, %%%s%%. fucking ridiculous but its it + // Also rename these fuckass fields. 'artistTitle' what am I high?? + + static int rc = 0; + while ((rc = sqlite3_step(sqlite_stmt)) == SQLITE_ROW) { + printf("here\n"); + localMusicHandler_AudioObject audioObject; + // TODO THIS IS NOT SAFE HOLY FUCK TESTING ONLY LIKE MEGA ONLY + // Could load directly into struct if I know how many songs there will be + // Seems to be only able to do that by issuing yet another SQL request + audioObject.path = (char*)sqlite3_column_text(sqlite_stmt, 6); + audioObject.songTitle = (char*)sqlite3_column_text(sqlite_stmt, 1); + audioObject.uid = (char*)sqlite3_column_text(sqlite_stmt, 0); + localMusicHandler_songReqDeque.push_back(audioObject); + } + + if (sqlite3_step(sqlite_stmt) != SQLITE_DONE) { + printf("[LocalMusicHandler] Execution error: %s\n", sqlite3_errmsg(sqlite_db)); + } + + sqlite3_finalize(sqlite_stmt); + + // Load into actual struct + int songCount = localMusicHandler_songReqDeque.size(); + localMusicHandler_songReq_t* songReq = (localMusicHandler_songReq_t*)malloc(sizeof(localMusicHandler_songReq_t)); + songReq->songCount = songCount; + songReq->songs = (localMusicHandler_songReq_songs_t*)malloc(sizeof(localMusicHandler_songReq_songs_t) * songCount); + for (int i = 0; i < songCount; i++) { + localMusicHandler_AudioObject audioObject; + audioObject = localMusicHandler_songReqDeque.front(); + localMusicHandler_songReqDeque.pop_front(); + songReq->songs[i].uid = strdup(audioObject.uid.c_str()); + songReq->songs[i].title = strdup(audioObject.songTitle.c_str()); + songReq->songs[i].path = strdup(audioObject.path.c_str()); + } + + return songReq; +} diff --git a/src/localMusicHandler.hpp b/src/localMusicHandler.hpp index 1eb2ec8..d1a0abb 100644 --- a/src/localMusicHandler.hpp +++ b/src/localMusicHandler.hpp @@ -19,6 +19,25 @@ void localMusicHandler_generateUid(int idx); int localMusicHandler_initDatabase(); void localMusicHandler_moveSongsToDatabase(int idx); + + + + +typedef struct { + char* uid; + char* title; + char* album; + char* artist; + char* path; +} localMusicHandler_songReq_songs_t; + +typedef struct { + int songCount; + localMusicHandler_songReq_songs_t* songs; +} localMusicHandler_songReq_t; + +localMusicHandler_songReq_t* localMusicHandler_test(); + #ifdef __cplusplus } #endif // __cplusplus diff --git a/src/localRadioDBHandler.c b/src/localRadioDBHandler.c new file mode 100644 index 0000000..23abb9d --- /dev/null +++ b/src/localRadioDBHandler.c @@ -0,0 +1,61 @@ +/* + * OpenSubsonicPlayer + * Goldenkrew3000 2026 + * License: GNU General Public License 3.0 + * Info: Local (Not from OpenSubsonic server) Internet Radio Sqlite3 Database Handler + */ + +#include +#include +#include +#include +#include "external/sqlite3/sqlite3.h" + +#include "localRadioDBHandler.h" + +static sqlite3* db = NULL; +static int rc = 0; +static char* errorMsg = NULL; + +int localRadioDBHandler_CreateDB(char* dbPath); + +int localRadioDBHandler_Init() { + // Form path + char* homePath = getenv("HOME"); + char* dbPath = NULL; + rc = asprintf(&dbPath, "%s/.config/ossp/radio.db", homePath); + if (rc == -1) { printf("asprintf() failed.\n"); return 1; } + + // Check if file exists + struct stat st; + if (stat(dbPath, &st) == 0) { + printf("[LocalRadio] Database found, is %ld bytes.\n", st.st_size); + } else { + printf("[LocalRadio] Database does not exist, creating.\n"); + localRadioDBHandler_CreateDB(dbPath); + } +} + +int localRadioDBHandler_CreateDB(char* dbPath) { + // Create database + rc = sqlite3_open(dbPath, &db); + if (rc) { + printf("Could not create database: %s\n", sqlite3_errmsg(db)); + } else { printf("Created database.\n"); } + + // Create table 'stations' + char* sqlQuery = "CREATE TABLE stations(id INT, name TEXT, url TEXT)"; + rc = sqlite3_exec(db, sqlQuery, NULL, 0, &errorMsg); + if (rc != SQLITE_OK) { + printf("could not make table: %s\n", errorMsg); + sqlite3_free(errorMsg); + } else { + printf("made table\n"); + } + + sqlite3_close(db); +} + +int localRadioDBHandler_AddStation(char* name, char* url) { + // +} diff --git a/src/localRadioDBHandler.h b/src/localRadioDBHandler.h new file mode 100644 index 0000000..ad5c83f --- /dev/null +++ b/src/localRadioDBHandler.h @@ -0,0 +1,6 @@ +#ifndef _LOCAL_RADIO_DB_HANDLER_H +#define _LOCAL_RADIO_DB_HANDLER_H + +int localRadioDBHandler_Init(); + +#endif diff --git a/src/main.c b/src/main.c index 2269c68..36cda22 100644 --- a/src/main.c +++ b/src/main.c @@ -17,12 +17,20 @@ #include "player/player.h" #include "discordrpc.h" +#include "localRadioDBHandler.h" +#include "libopensubsonic/endpoint_getInternetRadioStations.h" +#include "libopensubsonic/httpclient.h" +#include "socket.h" +#include "localMusicHandler.hpp" + static int rc = 0; configHandler_config_t* configObj = NULL; int checkConfigFile(); int validateConnection(); int main(int argc, char** argv) { + //localRadioDBHandler_Init(); + // Read config file rc = configHandler_Read(&configObj); if (rc != 0) { @@ -67,8 +75,11 @@ int main(int argc, char** argv) { discordrpc_update(&discordrpc); discordrpc_struct_deinit(&discordrpc); + //localMusicHandler_scan(); + // Launch QT frontend gui_entry(); + //socketHandler_init(); // Cleanup and exit configHandler_Free(&configObj); diff --git a/src/player/player.c b/src/player/player.c index 0b6dc39..2994f2f 100644 --- a/src/player/player.c +++ b/src/player/player.c @@ -44,7 +44,7 @@ static gboolean gst_bus_call(GstBus* bus, GstMessage* message, gpointer data) { case GST_MESSAGE_BUFFERING: { gint percent = 0; gst_message_parse_buffering(message, &percent); - printf("Buffering (%d%%)...\n", (int)percent); + //printf("Buffering (%d%%)...\n", (int)percent); break; } case GST_MESSAGE_ERROR: { @@ -57,7 +57,7 @@ static gboolean gst_bus_call(GstBus* bus, GstMessage* message, gpointer data) { break; } case GST_MESSAGE_STATE_CHANGED: - printf("State changed\n"); + //printf("State changed\n"); break; case GST_MESSAGE_NEW_CLOCK: // @@ -361,6 +361,8 @@ int OSSPlayer_GstInit() { } // Initialize reverb + + } int OSSPlayer_GstDeInit() { @@ -432,6 +434,19 @@ void OSSPlayer_GstECont_Playbin3_Stop() { isPlaying = false; // Notify player thread to attempt to load next song } +void OSSPlayer_GstECont_Playbin3_PlayPause() { + GstState state; + gst_element_get_state (pipeline, &state, NULL, 0); + + if (state == GST_STATE_PLAYING) { + gst_element_set_state (pipeline, GST_STATE_PAUSED); + g_print ("Paused\n"); + } else { + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_print ("Playing\n"); + } +} + /* * Utility Functions */ diff --git a/src/player/player.h b/src/player/player.h index dad8979..4aa59e7 100644 --- a/src/player/player.h +++ b/src/player/player.h @@ -13,10 +13,11 @@ extern "C" { #include "playQueue.hpp" -void* OSSPlayer_GMainLoop(void*); -void* OSSPlayer_ThrdInit(void*); +void* OSSPlayer_GMainLoop(void* arg); +void* OSSPlayer_ThrdInit(void* arg); int OSSPlayer_GstInit(); -int OSSPlayer_QueueAppend(char* title, char* artist, char* id, long duration); +int OSSPlayer_QueueAppend_Song(char* title, char* artist, char* id, long duration); +int OSSPlayer_QueueAppend_Radio(char* name, char* id, char* radioUrl); OSSPQ_SongStruct* OSSPlayer_QueuePopFront(); float OSSPlayer_GstECont_InVolume_Get(); @@ -25,6 +26,8 @@ float OSSPlayer_GstECont_OutVolume_Get(); void OSSPlayer_GstECont_OutVolume_set(float val); float OSSPlayer_GstECont_Pitch_Get(); void OSSPlayer_GstECont_Pitch_Set(float cents); +void OSSPlayer_GstECont_Playbin3_Stop(); +void OSSPlayer_GstECont_Playbin3_PlayPause(); float OSSPlayer_DbLinMul(float db); float OSSPlayer_PitchFollow(float freq, float semitone);