Skip to content

Commit

Permalink
Multiple instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
dchansen06 committed Dec 21, 2024
1 parent f419fa9 commit cbee56a
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 55 deletions.
6 changes: 3 additions & 3 deletions src/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
17 changes: 14 additions & 3 deletions src/client_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -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();
Expand All @@ -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)) {
Expand All @@ -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;
}

Expand Down
11 changes: 5 additions & 6 deletions src/client_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ You should have received a copy of the GNU General Public License along with thi

#include <string>

#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);
8 changes: 4 additions & 4 deletions src/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
58 changes: 46 additions & 12 deletions src/server_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,29 @@ 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;
default_random_engine rand_eng(rand_dev());
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;
Expand All @@ -48,27 +58,34 @@ 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<fspath> of locations to not look through
vector<fspath> findNoMedia(fspath path, string pattern)
{
vector<fspath> nomediadir;

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++;
}

return nomediadir;
}

// Configures the valid extensions of music to include in a music_list
// Precondition: None
// Postcondition: Returns a vector<string> containing the given valid extensions
vector<string> validExtensionTypes()
{
vector<string> 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])
Expand All @@ -79,43 +96,54 @@ vector<string> 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<fspath> nomediadirs = findNoMedia(path, ".nomedia");
vector<fspath> nomediadirs = findNoMedia(path, ".nomedia"); // Any directory containing a file named ".nomedia" will not have files inside of it added
vector<string> 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;
}
}

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++;
}

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());
Expand Down Expand Up @@ -152,36 +180,42 @@ 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);
cout << "Opened audio at " << audio_rate << " Hz, "
<< (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;

playSong(song, fadeMS);
}

/* Clean up */
Mix_CloseAudio();
Mix_Quit();
SDL_Quit();
Expand Down
32 changes: 15 additions & 17 deletions src/server_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,21 @@ You should have received a copy of the GNU General Public License along with thi
#include <vector>
#include <SDL2/SDL_mixer.h>

#ifndef SERVER_FUNCTIONS_H
#define SERVER_FUNCTIONS_H
#pragma once

typedef std::vector<std::filesystem::path> music_list;
typedef std::filesystem::path fspath;
typedef std::vector<std::filesystem::path> 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);
20 changes: 10 additions & 10 deletions src/signals.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ You should have received a copy of the GNU General Public License along with thi

#include <csignal>

#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
};

0 comments on commit cbee56a

Please # to comment.