diff --git a/src/client.cpp b/src/client.cpp index 0e90ed4..a47640c 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -14,12 +14,12 @@ int main(int argc, char* argv[]) { string path, directory; - int pidInput = getInformation(path, directory, argc, argv); + int pidInput = getInformation(path, directory, argc, argv); // Collects and parses arguments - if (pidInput == 0) + if (pidInput == 0) // No server given, must create one pidInput = setupServer(path, directory); - controlServer(pidInput); + controlServer(pidInput); // Loops until told to exit return 0; } diff --git a/src/client_functions.cpp b/src/client_functions.cpp index 32461ba..563e690 100644 --- a/src/client_functions.cpp +++ b/src/client_functions.cpp @@ -13,13 +13,16 @@ You should have received a copy of the GNU General Public License along with thi using namespace std; +// Reads information from the command line and gathers any missing information +// Precondition: A valid path, music directory, and command line arguments +// Postcondition: Returns the PID of the server to use or fills in the path and directory int getInformation(string& path, string& dir, int argc, char* argv[]) { - if (argc > 2 && ((string)argv[1]).find("-p") != string::npos) { + if (argc > 2 && ((string)argv[1]).find("-p") != string::npos) { // Must be in the form "command -p PID" return stoi(argv[2]); } - switch(argc) { + switch(argc) { // Gathers path and directory as provided, leaves off tail end case 3: path = argv[1]; dir = argv[2]; @@ -39,6 +42,9 @@ int getInformation(string& path, string& dir, int argc, char* argv[]) return 0; } +// Starts a new server as a detatched process and returns its PID to signal it +// Precondition: A valid path and directory for the server to use +// Postcondition: Returns the PID to signal the server on int setupServer(string path, string directory) { pid_t server = fork(); @@ -60,11 +66,14 @@ int setupServer(string path, string directory) return server; } +// Loop to control the server with signals and keyboard instructions, can close server or leave it running and stop controlling it +// Precondition: A valid PID of the server +// Postcondition: Kills the server or leaves it running as this exits on user input void controlServer(int server) { char input; cout << "Gained control of server " << server << "\nEnter instructions: [R]esume, [P]ause, re[W]ind, [S]kip, [E]xit (or Ctrl+C to close)\n"; - cin >> input; + cin >> input; // Reads one char at a time while (tolower(input) != 'e') { switch(tolower(input)) { @@ -84,6 +93,8 @@ void controlServer(int server) cout << "Misunderstood input, enter R, P, S, or E only:\n"; } + usleep(50000); // Allows inputting multiple instructions on the same line with minimal risk as long as >>fadeMS + cin >> input; } diff --git a/src/client_functions.h b/src/client_functions.h index 6c32347..8c0e189 100644 --- a/src/client_functions.h +++ b/src/client_functions.h @@ -6,9 +6,8 @@ You should have received a copy of the GNU General Public License along with thi #include -#ifndef CLIENT_FUNCTIONS_H - #define CLIENT_FUNCTIONS_H - int getInformation(std::string& path, std::string& dir, int argc, char* argv[]); - int setupServer(std::string path, std::string directory); - void controlServer(int server); -#endif +#pragma once + +int getInformation(std::string& path, std::string& dir, int argc, char* argv[]); +int setupServer(std::string path, std::string directory); +void controlServer(int server); diff --git a/src/server.cpp b/src/server.cpp index 0933e9c..4c2cca7 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -12,12 +12,12 @@ using namespace std; int main(int argc, char* argv[]) { - if (argc != 2) { + if (argc != 2) { // Requires directory path cerr << "Invalid option\n"; exit(-1); } - music_list validmusic = findMusicFiles(argv[1]); - shuffleMusic(validmusic); - playMusic(validmusic, 250); + music_list validmusic = findMusicFiles(argv[1]); // Find music + shuffleMusic(validmusic); // Shuffle + playMusic(validmusic, 250); // Play music with 250 ms fade in/out between songs } diff --git a/src/server_functions.cpp b/src/server_functions.cpp index 1c1aaeb..ff476b6 100644 --- a/src/server_functions.cpp +++ b/src/server_functions.cpp @@ -22,12 +22,19 @@ You should have received a copy of the GNU General Public License along with thi using namespace std; -sig_atomic_t signalStatus = RESUME; +sig_atomic_t signalStatus = RESUME; // Holds the signal that was most recently sent + +// Catches signals it is set up to catch and alters signalStatus accordingly +// Precondition: A valid signal +// Postcondition: Changes the signalStatus to match the signal void signal_handler(int signal) { signalStatus = signal; } +// Shuffles the music_list provided randomly +// Precondition: A valid music_list passed by reference +// Postcondition: The music_list is shuffled void shuffleMusic(music_list& songs) { random_device rand_dev; @@ -35,6 +42,9 @@ void shuffleMusic(music_list& songs) shuffle(songs.begin(), songs.end(), rand_eng); } +// Provides useful information about the currently playing song +// Precondition: A valid Mix_Music pointer +// Postcondition: Returns a filled out MusicInfo struct MusicInfo getInformation(const Mix_Music* m) { MusicInfo info; @@ -48,6 +58,9 @@ MusicInfo getInformation(const Mix_Music* m) return info; } +// Looks through the given path recursively for any directory containing a given file pattern and adds the directory containing it to a list +// Precondition: A valid path and pattern +// Postcondition: Returns a vector of locations to not look through vector findNoMedia(fspath path, string pattern) { vector nomediadir; @@ -55,9 +68,9 @@ vector findNoMedia(fspath path, string pattern) filesystem::recursive_directory_iterator rdi_itr = filesystem::recursive_directory_iterator(path, filesystem::directory_options::skip_permission_denied); filesystem::recursive_directory_iterator it_rdi = begin(rdi_itr); - while (it_rdi != end(rdi_itr)) { + while (it_rdi != end(rdi_itr)) { // Loops through until a given file is found if (it_rdi->path().filename() == pattern) - nomediadir.push_back(it_rdi->path().parent_path()); + nomediadir.push_back(it_rdi->path().parent_path()); // Adds parent to list it_rdi++; } @@ -65,10 +78,14 @@ vector findNoMedia(fspath path, string pattern) return nomediadir; } +// Configures the valid extensions of music to include in a music_list +// Precondition: None +// Postcondition: Returns a vector containing the given valid extensions vector validExtensionTypes() { vector validExtensionTypes = {".ogg", ".mp3", ".wav", ".flac"}; + /* Adds the capitalized version of any above extension */ for (size_t i = 0; i < (validExtensionTypes.size() + 1) / 2; i++) { string temp = ""; for (char c : validExtensionTypes[i]) @@ -79,28 +96,36 @@ vector validExtensionTypes() return validExtensionTypes; } +// Notes an empty path and configures $HOME correctly +// Precondition: A given fspath that can be changed +// Postcondition: A path with $HOME resolved or an error void checkAndCorrectPath(fspath path) { - if (path.empty()) + if (path.empty()) { + cerr << "Bad path!\n"; exit(-1); + } if (path.string()[0] == '~') path = getenv("HOME") + path.string().substr(1); } +// Recursively looks through a given path, adds all valid music files that do not mix with the findNoMedia pattern +// Precondition: A valid path +// Postcondition: A music_list containing all found songs music_list findMusicFiles(fspath path) { - checkAndCorrectPath(path); + checkAndCorrectPath(path); // Configures $HOME music_list validfiles; - vector nomediadirs = findNoMedia(path, ".nomedia"); + vector nomediadirs = findNoMedia(path, ".nomedia"); // Any directory containing a file named ".nomedia" will not have files inside of it added vector validExtensions = validExtensionTypes(); filesystem::recursive_directory_iterator rdi_itr = filesystem::recursive_directory_iterator(path, filesystem::directory_options::skip_permission_denied); filesystem::recursive_directory_iterator it_rdi = begin(rdi_itr); - while (it_rdi != end(rdi_itr)) { + while (it_rdi != end(rdi_itr)) { // Loops through recursively bool valid = true; - for (fspath nomediadir : nomediadirs) { + for (fspath nomediadir : nomediadirs) { // Confirms path does not violate nomediadir if (it_rdi->path().string().find(nomediadir.string()) != string::npos) { valid = false; break; @@ -108,7 +133,7 @@ music_list findMusicFiles(fspath path) } if (valid && find(begin(validExtensions), end(validExtensions), it_rdi->path().extension()) != end(validExtensions)) - validfiles.push_back(it_rdi->path()); + validfiles.push_back(it_rdi->path()); // Has valid extension it_rdi++; } @@ -116,6 +141,9 @@ music_list findMusicFiles(fspath path) return validfiles; } +// Plays a given song from a path and fades it in/out for given a time +// Precondition: A valid song path and positive fadeMS +// Postcondition: Plays the song if the SDL2 audio setup works, handles appropriate signals void playSong(fspath song, int fadeMS) { Mix_Music *music = Mix_LoadMUS(song.c_str()); @@ -152,22 +180,26 @@ void playSong(fspath song, int fadeMS) Mix_FreeMusic(music); } +// Plays a given music_list of songs, fades each in/out for fadeMS +// Precondition: A valid music_list and positive fadeMS +// Postcondition: Plays each song, handling provided signals correctly void playMusic(music_list songs, int fadeMS) { - if (songs.size() == 0) { + if (songs.size() == 0) { // Nothing to do return; } - if (SDL_Init(SDL_INIT_AUDIO) < 0) { + if (SDL_Init(SDL_INIT_AUDIO) < 0) { // Could not get audio control cerr << "Failed to init SDL: " << SDL_GetError() << endl; exit(1); } - if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, 4096) < 0) { + if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, 4096) < 0) { // Tries defaults cerr << "Could not open audio: " << SDL_GetError() << endl; exit(1); } + /* Collects information to present */ int audio_rate, audio_channels; SDL_AudioFormat audio_format; Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels); @@ -175,6 +207,7 @@ void playMusic(music_list songs, int fadeMS) << (audio_format&0xFF) << " bit" << (SDL_AUDIO_ISFLOAT(audio_format) ? " (float), " : ", ") << ((audio_channels > 2) ? "surround" : (audio_channels > 1) ? "stereo" : "mono") << endl; + /* Plays each song until told to exit or runs out of songs */ for (fspath song : songs) { if (signalStatus == EXIT) break; @@ -182,6 +215,7 @@ void playMusic(music_list songs, int fadeMS) playSong(song, fadeMS); } + /* Clean up */ Mix_CloseAudio(); Mix_Quit(); SDL_Quit(); diff --git a/src/server_functions.h b/src/server_functions.h index f6d710e..4d06469 100644 --- a/src/server_functions.h +++ b/src/server_functions.h @@ -9,23 +9,21 @@ You should have received a copy of the GNU General Public License along with thi #include #include -#ifndef SERVER_FUNCTIONS_H - #define SERVER_FUNCTIONS_H +#pragma once - typedef std::vector music_list; - typedef std::filesystem::path fspath; +typedef std::vector music_list; +typedef std::filesystem::path fspath; - struct MusicInfo { - std::string title; - std::string artist; - std::string album; - std::string copyright; - std::string type; - int numTracks; - }; +struct MusicInfo { + std::string title; + std::string artist; + std::string album; + std::string copyright; + std::string type; + int numTracks; +}; - void shuffleMusic(music_list& files); - MusicInfo getInformation(const Mix_Music* m); - music_list findMusicFiles(fspath path); - void playMusic(music_list path, int fadeMS); -#endif +void shuffleMusic(music_list& files); +MusicInfo getInformation(const Mix_Music* m); +music_list findMusicFiles(fspath path); +void playMusic(music_list path, int fadeMS); diff --git a/src/signals.h b/src/signals.h index 2a21f6b..30c6934 100644 --- a/src/signals.h +++ b/src/signals.h @@ -6,13 +6,13 @@ You should have received a copy of the GNU General Public License along with thi #include -#ifndef SIGNALS_H -#define SIGNALS_H - enum Control_Signals { - SKIP = SIGUSR1, - REWIND = SIGUSR2, - PAUSE = SIGTSTP, - RESUME = SIGCONT, - EXIT = SIGINT - }; -#endif +#pragma once + +/* Configures given signals so that they can be replaced easily */ +enum Control_Signals { + SKIP = SIGUSR1, + REWIND = SIGUSR2, + PAUSE = SIGTSTP, + RESUME = SIGCONT, + EXIT = SIGINT +};