Commit a25acbc9 authored by Eric Wong's avatar Eric Wong

rewrite statefile code for audio devices

In the words of the original author, it was 'crappy'. I tend to agree :) The code has also been broken for at least the past few months, and nobody bothered fixing it The previous format it was overly complex: 5 lines to describe each device. The new format is one-line per-device: audio_device_state:%d:%s %d - 0 for disabled, any integer for enabled %s - name of the device as specified in the config file, whitespace and all Incompatibilities: * Output names are now _required_ to be unique. This is required because the new format relies solely on the name of the audio device. Relying on the device IDs internal to MPD was a bad idea anyways since the user usually has none or very little idea how they're generated, and adding a new device or removing one from a config would throw things off completely. This is also just a Good Idea(TM) because it makes things less confusing to users when they see it in their clients. * Output states are not preserved from the previous format. Not a big deal, since the previous code was never officially released. Also, it's been broken for months now, so I doubt anybody would notice :) git-svn-id: https://svn.musicpd.org/mpd/trunk@3928 09075e82-0dd4-0310-85a5-a0d7c8717e4f
parent 6dadabea
...@@ -34,18 +34,10 @@ ...@@ -34,18 +34,10 @@
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#define AUDIO_DEVICE_STATE "audio_device_state:"
/* crappy code by qball */ #define AUDIO_DEVICE_STATE_LEN 19 /* strlen(AUDIO_DEVICE_STATE) */
#define AUDIO_STATE_FILE_DEVICE_START "audio_device_start"
#define AUDIO_STATE_FILE_DEVICE_ID "audio_device_id: "
#define AUDIO_STATE_FILE_DEVICE_ENABLED "audio_device_enabled: "
#define AUDIO_STATE_FILE_DEVICE_NAME "audio_device_name: "
#define AUDIO_STATE_FILE_DEVICE_END "audio_device_end"
#define AUDIO_BUFFER_SIZE 2*MAXPATHLEN #define AUDIO_BUFFER_SIZE 2*MAXPATHLEN
/* /crappy code */ static void saveAudioDevicesState();
static AudioFormat audio_format; static AudioFormat audio_format;
...@@ -104,6 +96,9 @@ void initAudioDriver() { ...@@ -104,6 +96,9 @@ void initAudioDriver() {
param = getNextConfigParam(CONF_AUDIO_OUTPUT, param); param = getNextConfigParam(CONF_AUDIO_OUTPUT, param);
do { do {
AudioOutput *output;
int j;
if(audioOutputArraySize == AUDIO_MAX_DEVICES) { if(audioOutputArraySize == AUDIO_MAX_DEVICES) {
ERROR("only up to 255 audio output devices are " ERROR("only up to 255 audio output devices are "
"supported"); "supported");
...@@ -114,14 +109,25 @@ void initAudioDriver() { ...@@ -114,14 +109,25 @@ void initAudioDriver() {
audioOutputArray = realloc(audioOutputArray, audioOutputArray = realloc(audioOutputArray,
audioOutputArraySize*sizeof(AudioOutput *)); audioOutputArraySize*sizeof(AudioOutput *));
audioOutputArray[i] = newAudioOutput(param);
if(!audioOutputArray[i] && param) { output = newAudioOutput(param);
if(!output && param) {
ERROR("problems configuring output device defined at " ERROR("problems configuring output device defined at "
"line %i\n", param->line); "line %i\n", param->line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* require output names to be unique: */
for (j = i - 1; j >= 0; --j) {
if ( !strcmp( output->name,
audioOutputArray[j]->name) ) {
ERROR("output devices with identical "
"names: %s\n",
output->name);
exit(EXIT_FAILURE);
}
}
audioOutputArray[i] = output;
} while((param = getNextConfigParam(CONF_AUDIO_OUTPUT, param))); } while((param = getNextConfigParam(CONF_AUDIO_OUTPUT, param)));
} }
...@@ -221,6 +227,7 @@ void finishAudioConfig() { ...@@ -221,6 +227,7 @@ void finishAudioConfig() {
void finishAudioDriver() { void finishAudioDriver() {
int i; int i;
saveAudioDevicesState();
for(i = 0; i < audioOutputArraySize; i++) { for(i = 0; i < audioOutputArraySize; i++) {
finishAudioOutput(audioOutputArray[i]); finishAudioOutput(audioOutputArray[i]);
} }
...@@ -415,115 +422,97 @@ void printAudioDevices(FILE * fp) { ...@@ -415,115 +422,97 @@ void printAudioDevices(FILE * fp) {
} }
} }
/* more qball crappy code */
static char * getStateFile() { static char * getStateFile() {
ConfigParam * param = parseConfigFilePath(CONF_STATE_FILE, 0); ConfigParam * param = parseConfigFilePath(CONF_STATE_FILE, 0);
if(!param) return NULL; if(!param) return NULL;
return param->value; return param->value;
} }
static void saveAudioDevicesState() {
char *stateFile;
FILE *fp;
int i;
if (!(stateFile = getStateFile()))
return;
void saveAudioDevicesState() { while(!(fp = fopen(stateFile,"a")) && errno==EINTR);
int i; if(!fp) {
char * stateFile = getStateFile(); ERROR("problems opening state file \"%s\" for "
"writing: %s\n", stateFile, strerror(errno));
if(stateFile) { return;
FILE * fp; }
while(!(fp = fopen(stateFile,"a")) && errno==EINTR); assert(audioOutputArraySize != 0);
if(!fp) { for (i = audioOutputArraySize - 1; i >= 0; --i) {
ERROR("problems opening state file \"%s\" for " myfprintf(fp, AUDIO_DEVICE_STATE "%d:%s\n",
"writing: %s\n", stateFile, (int)pdAudioDevicesEnabled[i],
strerror(errno)); audioOutputArray[i]->name);
return;
}
for(i = 0; i < audioOutputArraySize; i++) {
myfprintf(fp, "%s\n", AUDIO_STATE_FILE_DEVICE_START);
myfprintf(fp, "%s%i\n", AUDIO_STATE_FILE_DEVICE_ID, i);
myfprintf(fp, "%s%s\n", AUDIO_STATE_FILE_DEVICE_NAME, audioOutputArray[i]->name);
myfprintf(fp, "%s%i\n", AUDIO_STATE_FILE_DEVICE_ENABLED,(int)pdAudioDevicesEnabled[i]);
myfprintf(fp, "%s\n", AUDIO_STATE_FILE_DEVICE_END);
}
while(fclose(fp) && errno==EINTR);
} }
while(fclose(fp) && errno==EINTR);
} }
void readAudioDevicesState() { static void parse_audio_device_state(FILE *fp)
char * stateFile = getStateFile(); {
FILE *fp; char buffer[AUDIO_BUFFER_SIZE];
struct stat st; int i;
if(stateFile) {
char buffer[AUDIO_BUFFER_SIZE];
assert(audioOutputArraySize != 0);
while (myFgets(buffer,AUDIO_BUFFER_SIZE,fp)) {
char *c, *name;
if (strncmp(buffer,AUDIO_DEVICE_STATE,AUDIO_DEVICE_STATE_LEN))
continue;
if(stat(stateFile,&st)<0) { c = strchr(buffer,':');
DEBUG("failed to stat state file\n"); if (!c || !(++c))
return; goto errline;
}
if(!S_ISREG(st.st_mode)) {
ERROR("state file \"%s\" is not a regular "
"file\n",stateFile);
exit(EXIT_FAILURE);
}
fp = fopen(stateFile,"r"); name = strchr(c,':');
if(!fp) { if (!name || !(++name))
ERROR("problems opening state file \"%s\" for " goto errline;
"reading: %s\n", stateFile,
strerror(errno));
exit(EXIT_FAILURE);
}
while(myFgets(buffer,AUDIO_BUFFER_SIZE,fp)) { for (i = audioOutputArraySize - 1; i >= 0; --i) {
if(strncmp(buffer,AUDIO_STATE_FILE_DEVICE_START, strlen(AUDIO_STATE_FILE_DEVICE_START))==0) { if (!strcmp(name, audioOutputArray[i]->name)) {
char *name = NULL; pdAudioDevicesEnabled[i] = atoi(c);
int id = -1; break;
int enabled = 1;
if(!myFgets(buffer,AUDIO_BUFFER_SIZE,fp)) {
ERROR("error parsing state file \"%s\"\n", stateFile);
exit(EXIT_FAILURE);
}
while(strcmp(buffer,AUDIO_STATE_FILE_DEVICE_END)) {
if(strncmp(buffer,AUDIO_STATE_FILE_DEVICE_ID, strlen(AUDIO_STATE_FILE_DEVICE_ID)) == 0 ) {
if(strlen(buffer) > strlen(AUDIO_STATE_FILE_DEVICE_ID))
{
id = atoi(&buffer[strlen(AUDIO_STATE_FILE_DEVICE_ID)]);
}
}
if(strncmp(buffer,AUDIO_STATE_FILE_DEVICE_ENABLED, strlen(AUDIO_STATE_FILE_DEVICE_ENABLED)) == 0 ) {
if(strlen(buffer) > strlen(AUDIO_STATE_FILE_DEVICE_ENABLED))
{
enabled = atoi(&buffer[strlen(AUDIO_STATE_FILE_DEVICE_ENABLED)]);
}
}
if(!myFgets(buffer,AUDIO_BUFFER_SIZE,fp)) {
ERROR("error parsing state file \"%s\"\n", stateFile);
exit(EXIT_FAILURE);
}
}
if(id != -1)
{
/* search for same name here, can we trust id? */
if(id < audioOutputArraySize)
{
pdAudioDevicesEnabled[id] = enabled;
}
}
if(name != NULL)
{
free(name);
}
} }
} }
continue;
errline:
/* nonfatal */
ERROR("invalid line in state_file: %s\n", buffer);
}
}
void readAudioDevicesState() {
char *stateFile;
FILE *fp;
struct stat st;
fclose(fp); if (!(stateFile = getStateFile()))
return;
if(stat(stateFile,&st)<0) {
DEBUG("failed to stat state file\n");
return;
}
if(!S_ISREG(st.st_mode)) {
ERROR("state file \"%s\" is not a regular file\n",
stateFile);
exit(EXIT_FAILURE);
}
fp = fopen(stateFile,"r");
if(!fp) {
ERROR("problems opening state file \"%s\" for "
"reading: %s\n", stateFile,
strerror(errno));
exit(EXIT_FAILURE);
} }
parse_audio_device_state(fp);
fclose(fp);
} }
...@@ -75,8 +75,6 @@ int disableAudioDevice(FILE * fp, int device); ...@@ -75,8 +75,6 @@ int disableAudioDevice(FILE * fp, int device);
void printAudioDevices(FILE * fp); void printAudioDevices(FILE * fp);
/* qball's crappy code */
void readAudioDevicesState(); void readAudioDevicesState();
void saveAudioDevicesState();
#endif #endif
...@@ -300,7 +300,6 @@ void startMainProcess() { ...@@ -300,7 +300,6 @@ void startMainProcess() {
if(pid>0) { if(pid>0) {
initInputStream(); initInputStream();
initReplayGainState(); initReplayGainState();
/* qball crappy code */
readAudioDevicesState(); readAudioDevicesState();
/* free stuff we don't need */ /* free stuff we don't need */
...@@ -317,9 +316,6 @@ void startMainProcess() { ...@@ -317,9 +316,6 @@ void startMainProcess() {
finishAudioConfig(); finishAudioConfig();
finishAudioDriver(); finishAudioDriver();
/* qball crappy code */
saveAudioDevicesState();
finishPaths(); finishPaths();
kill(mainPid, SIGTERM); kill(mainPid, SIGTERM);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment