/* Initialize the script playlist handler */ int ices_playlist_script_initialize (playlist_module_t* pm) { ices_log_debug ("Initializing script playlist handler..."); if (!pm->module) { ices_log_error ("No playlist script defined"); return 0; } cmd = pm->module; /* make path relative to module dir */ if (cmd[0] != '/' && !(cmd[0] == '.' && (cmd[1] == '/' || (cmd[1] == '.' && cmd[2] == '/')))) { cmd = malloc (strlen(pm->module) + strlen(ICES_MODULEDIR) + 2); if (cmd) sprintf (cmd, "%s/%s", ICES_MODULEDIR, pm->module); } else cmd = strdup(pm->module); if (!cmd) { ices_log_error("Could not allocate memory for playlist path"); return 0; } pm->get_next = playlist_script_get_next; pm->get_metadata = playlist_script_get_metadata; pm->get_lineno = NULL; pm->shutdown = playlist_script_shutdown; return 1; }
int ices_playlist_perl_initialize(playlist_module_t* pm) { char *str; int ret = -1; pm->get_next = playlist_perl_get_next; pm->get_metadata = playlist_perl_get_metadata; pm->get_lineno = playlist_perl_get_lineno; pm->shutdown = playlist_perl_shutdown; pm->reload = playlist_perl_reload; if (pl_perl_init_perl() < 0) return -1; if (!pl_init_hook) return 1; if ((str = pl_perl_eval(pl_init_hook))) { ret = atoi(str); ices_util_free(str); } if (ret <= 0) ices_log_error("Execution of 'ices_init' failed"); return ret; }
/* Call python function to initialize the python script */ int ices_playlist_python_initialize (playlist_module_t* pm) { PyObject* res; int rc = 1; pm->get_next = playlist_python_get_next; pm->get_metadata = playlist_python_get_metadata; pm->get_lineno = playlist_python_get_lineno; pm->reload = playlist_python_reload; pm->shutdown = playlist_python_shutdown; if (python_init () < 0) return -1; if (pl_init_hook) { if ((res = python_eval (pl_init_hook)) && PyInt_Check (res)) rc = PyInt_AsLong (res); else ices_log_error ("ices_init failed"); Py_XDECREF (res); } return rc; }
/* Call python function to get next file to play */ char * interpreter_playlist_python_get_next (void) { PyObject *res = (PyObject *)interpreter_python_eval_function ("ices_python_get_next"); if (res && PyString_Check (res)) return ices_util_strdup (PyString_AsString (res)); ices_log_error ("Execution of 'ices_python_get_next()' in ices.py failed"); return NULL; }
/* Call python function to shutdown the script */ int interpreter_playlist_python_shutdown (ices_config_t *ices_config) { PyObject *res = (PyObject *)interpreter_python_eval_function ("ices_python_shutdown"); if (res && PyInt_Check (res)) return PyInt_AsLong (res); ices_log_error ("Execution of 'ices_python_shutdown()' in ices.py failed"); return 0; }
/* Call the python function to get the current line number */ int interpreter_playlist_python_get_current_lineno (void) { PyObject *res = (PyObject *)interpreter_python_eval_function ("ices_python_get_current_lineno"); if (res && PyInt_Check (res)) return PyInt_AsLong (res); ices_log_error ("Execution of 'ices_python_get_current_lineno()' in ices.py failed"); return 0; }
/* Call python function to shutdown the script */ static void playlist_python_shutdown(void) { PyObject* res; if (pl_shutdown_hook) { if (!((res = python_eval(pl_shutdown_hook)) && PyInt_Check(res))) ices_log_error("ices_shutdown failed"); Py_XDECREF(res); } python_shutdown(); }
/* Call python function to get next file to play */ static char *playlist_python_get_next(void) { PyObject* res; char* rc = NULL; if ((res = python_eval(pl_get_next_hook)) && PyString_Check(res)) rc = ices_util_strdup(PyString_AsString(res)); else ices_log_error("ices_get_next failed"); Py_XDECREF(res); return rc; }
static void metadata_update(int delay) { ices_stream_t* stream; shout_metadata_t* metadata; char song[1024]; char* playlist_metadata; char* value; int rc; if (delay) usleep(delay); if (!(playlist_metadata = ices_playlist_get_metadata())) { if (Title) { if (Artist) snprintf(song, sizeof(song), "%s - %s", Artist, Title); else snprintf(song, sizeof(song), "%s", Title); } else snprintf(song, sizeof(song), "%s", Filename); value = song; } else value = playlist_metadata; if (!(metadata = shout_metadata_new())) { ices_log_error("Error allocating metadata structure"); ices_util_free(playlist_metadata); return; } if (shout_metadata_add(metadata, "song", value) != SHOUTERR_SUCCESS) { ices_log_error_output("Error adding info to metadata structure"); ices_util_free(playlist_metadata); shout_metadata_free(metadata); return; } for (stream = ices_config.streams; stream; stream = stream->next) { rc = shout_set_metadata(stream->conn, metadata); if (rc != SHOUTERR_SUCCESS) ices_log_error_output("Updating metadata on %s failed.", stream->mount); else ices_log_debug("Updated metadata on %s to: %s", stream->mount, value); } ices_util_free(playlist_metadata); shout_metadata_free(metadata); }
/* Attempt to reload the playlist module */ static int playlist_python_reload(void) { PyObject* new_module; if (!(new_module = PyImport_ReloadModule(python_module))) { ices_log_error("Playlist module reload failed"); PyErr_Print(); return -1; } python_module = new_module; ices_log_debug("Playlist module reloaded"); return 0; }
/* Call the python function to get the current line number */ static int playlist_python_get_lineno(void) { PyObject* res; int rc = 0; if (pl_get_lineno_hook) { if ((res = python_eval(pl_get_lineno_hook)) && PyInt_Check(res)) rc = PyInt_AsLong(res); else ices_log_error("ices_get_lineno failed"); Py_XDECREF(res); } return rc; }
/* private functions */ static int cf_init(void) { if (!(FL = malloc(FadeSamples * 2))) goto err; if (!(FR = malloc(FadeSamples * 2))) goto err; if (!(Swap = malloc(FadeSamples * 2))) goto err; ices_log_debug("Crossfading %d seconds between tracks", Fadelen); return 0; err: ices_log_error("Crossfader could not allocate memory"); cf_shutdown(); return -1; }
/* Force the python interpreter to look in our module path * and in the current directory for modules */ static int python_setup_path(void) { char *oldpath = getenv("PYTHONPATH"); if (oldpath && (python_path = (char*) malloc(strlen(oldpath) + strlen(ICES_MODULEDIR) + 15))) sprintf(python_path, "PYTHONPATH=%s:%s:.", oldpath, ICES_MODULEDIR); else if ((python_path = (char*) malloc(strlen(ICES_MODULEDIR) + 14))) sprintf(python_path, "PYTHONPATH=%s:.", ICES_MODULEDIR); else { ices_log_error("Could not allocate memory for python environment"); return -1; } putenv(python_path); return 0; }
static int ices_vorbis_readpcm (input_stream_t* self, size_t olen, int16_t* left, int16_t* right) { ices_vorbis_in_t* vorbis_data = (ices_vorbis_in_t*) self->data; int pos; int len; int i; /* refill buffer if necessary */ if (! vorbis_data->samples) { vorbis_data->offset = 0; do { if ((len = ov_read (vorbis_data->vf, (char*) vorbis_data->buf, sizeof (vorbis_data->buf), ICES_OV_BE, SAMPLESIZE, 1, &pos)) <= 0) { if (len == OV_HOLE) { ices_log_error ("Skipping bad vorbis data"); } else return len; } } while (len <= 0); vorbis_data->samples = len / SAMPLESIZE; if (vorbis_data->info->channels > 1) vorbis_data->samples /= vorbis_data->info->channels; self->bytes_read = ov_raw_tell (vorbis_data->vf); } len = 0; while (vorbis_data->samples && olen) { if (vorbis_data->info->channels == 1) { *left = *right = vorbis_data->buf[vorbis_data->offset++]; left++; right++; } else { *left++ = vorbis_data->buf[vorbis_data->offset++]; *right++ = vorbis_data->buf[vorbis_data->offset++]; } for (i = 0; i < vorbis_data->info->channels - 2; i++) vorbis_data->offset++; vorbis_data->samples--; olen -= SAMPLESIZE; len++; } return len; }
/* Return the current cue filename, and create it if * necessary */ const char * ices_cue_get_filename (void) { static char buf[1024]; if (ices_cue_filename) return ices_cue_filename; if (! ices_config.base_directory) { ices_log_error ("Base directory is invalid"); return NULL; } snprintf (buf, sizeof (buf), "%s/ices.cue", ices_config.base_directory); return buf; }
static int pl_perl_init_perl(void) { static char *my_argv[4] = { "", "-I" ICES_MODULEDIR, "-e", NULL }; static char module_space[255]; if ((my_perl = perl_alloc()) == NULL) { ices_log_debug("perl_alloc() error: (no memory!)"); return -1; } snprintf(module_space, sizeof(module_space), "use %s", ices_config.pm.module); my_argv[3] = module_space; perl_construct(my_perl); ices_log_debug("Importing perl module: %s", my_argv[3] + 4); if (perl_parse(my_perl, xs_init, 4, my_argv, NULL)) { ices_log_debug("perl_parse() error: parse problem"); return -1; } if (!(pl_init_hook = pl_find_func("ices_init"))) pl_init_hook = pl_find_func("ices_perl_initialize"); if (!(pl_shutdown_hook = pl_find_func("ices_shutdown"))) pl_shutdown_hook = pl_find_func("ices_perl_shutdown"); if (!(pl_get_next_hook = pl_find_func("ices_get_next"))) pl_get_next_hook = pl_find_func("ices_perl_get_next"); if (!(pl_get_metadata_hook = pl_find_func("ices_get_metadata"))) pl_get_metadata_hook = pl_find_func("ices_perl_get_metadata"); if (!(pl_get_lineno_hook = pl_find_func("ices_get_lineno"))) pl_get_lineno_hook = pl_find_func("ices_perl_get_current_lineno"); if (!pl_get_next_hook) { ices_log_error("The playlist module must define at least the ices_get_next method"); return -1; } return 0; }
/* Function to initialize the python interpreter */ static int python_init (void) { /* For some reason, python refuses to look in the * current directory for modules */ if (python_setup_path () < 0) return -1; Py_Initialize (); ices_log_debug ("Importing %s.py module...", ices_config.pm.module); /* Call the python api code to import the module */ if (!(python_module = PyImport_ImportModule (ices_config.pm.module))) { ices_log ("Error: Could not import module %s", ices_config.pm.module); PyErr_Print(); return -1; } /* Find defined methods */ pl_init_hook = python_find_attr (python_module, "ices_init", "ices_python_initialize"); pl_shutdown_hook = python_find_attr (python_module, "ices_shutdown", "ices_python_shutdown"); pl_get_next_hook = python_find_attr (python_module, "ices_get_next", "ices_python_get_next"); pl_get_metadata_hook = python_find_attr (python_module, "ices_get_metadata", "ices_python_get_metadata"); pl_get_lineno_hook = python_find_attr (python_module, "ices_get_lineno", "ices_python_get_current_lineno"); if (! pl_get_next_hook) { ices_log_error ("The playlist module must define at least the ices_get_next method"); return -1; } return 0; }
static void metadata_update (input_stream_t* source, int delay) { ices_stream_t* stream; char song[1024]; char* playlist_metadata; char* metadata; int rc; if (delay) usleep (delay); if (! (playlist_metadata = ices_playlist_get_metadata ())) { if (Title) { if (Artist) snprintf (song, sizeof (song), "%s - %s", Artist, Title); else snprintf (song, sizeof (song), "%s", Title); } else metadata_clean_filename (source->path, song, sizeof (song)); metadata = song; } else metadata = playlist_metadata; for (stream = ices_config.streams; stream; stream = stream->next) { rc = shout_update_metadata (&stream->conn, metadata); if (rc != 1) ices_log_error ("Updating metadata on %s failed.", stream->mount); else ices_log_debug ("Updated metadata on %s to: %s", stream->mount, metadata); } ices_util_free (playlist_metadata); }
static char * playlist_script_get_next (void) { char *filename = NULL, *metadata = NULL; FILE *pipe; int i = 0; filename = malloc(STR_BUFFER); metadata = malloc(STR_BUFFER); pipe = popen(cmd, "r"); if (!pipe) { ices_log_error ("Couldn't open pipe to program \"%s\"", cmd); return NULL; } if (fgets(filename, STR_BUFFER, pipe) == NULL) { ices_log_error ("Couldn't read filename from pipe to program \"%s\"", cmd); free(filename); filename = NULL; free(metadata); metadata = NULL; pclose(pipe); return NULL; } if (fgets(metadata, STR_BUFFER, pipe) == NULL) { /* This is non-fatal. */ ices_log_debug ("No metadata received from pipe to program \"%s\"", cmd); free(metadata); metadata = NULL; } pclose(pipe); if (filename[0] == '\n' || (filename[0] == '\r' && filename[1] == '\n')) { ices_log_error ("Got newlines instead of filename from program \"%s\"", cmd); free(filename); filename = NULL; free(metadata); metadata = NULL; pclose(pipe); return NULL; } /* Remove linefeeds etc. */ i = 0; while (filename[i]) { if (filename[i] == '\r' || filename[i] == '\n') { filename[i] = '\0'; break; } i++; } i = 0; while (metadata && metadata[i]) { if (metadata[i] == '\r' || metadata[i] == '\n') { metadata[i] = '\0'; break; } i++; } if (playlist_metadata) free(playlist_metadata); if (metadata) playlist_metadata = metadata; else playlist_metadata = NULL; ices_log_debug ("Script playlist handler serving: %s [%s]", ices_util_nullcheck (filename), ices_util_nullcheck(playlist_metadata)); return filename; }
/* try to open a vorbis file for decoding. Returns: * 0: success * 1: not a vorbis file * -1: error opening */ int ices_vorbis_open (input_stream_t* self, char* buf, size_t len) { ices_vorbis_in_t* vorbis_data; OggVorbis_File* vf; FILE* fin; char errbuf[128]; int rc; if (! (fin = fdopen (self->fd, "rb"))) { ices_util_strerror (errno, errbuf, sizeof (errbuf)); ices_log_error ("Error opening %s: %s", self->path, errbuf); return -1; } if (! (vf = (OggVorbis_File*) malloc (sizeof (OggVorbis_File)))) { ices_log_error ("Malloc failed in ices_vorbis_open"); return -1; } if ((rc = ov_open (fin, vf, buf, len)) != 0) { free (vf); fclose (fin); if (rc == OV_ENOTVORBIS) return 1; if (rc == OV_EREAD) ices_log_error ("Read error opening vorbis file"); else if (rc == OV_EVERSION) ices_log_error ("Vorbis version mismatch"); else if (rc == OV_EBADHEADER) ices_log_error ("Invalid vorbis header"); else ices_log_error ("Error in ov_open: %d", rc); return -1; } if (!(vorbis_data = (ices_vorbis_in_t*)malloc (sizeof (ices_vorbis_in_t)))) { ices_log_error ("Malloc failed in ices_vorbis_open"); ov_clear (vf); free (vf); return -1; } if (!(vorbis_data->info = ov_info(vf, -1))) { ices_log_error ("Vorbis: error reading vorbis info"); ices_vorbis_close (self); return -1; } if (vorbis_data->info->channels < 1) { ices_log_error ("Vorbis: Cannot decode, %d channels of audio data!", vorbis_data->info->channels); ices_vorbis_close (self); return -1; } self->bitrate = vorbis_data->info->bitrate_nominal / 1000; if (! self->bitrate) self->bitrate = ov_bitrate (vf, -1) / 1000; self->samplerate = (unsigned int) vorbis_data->info->rate; ices_log_debug("Ogg vorbis file found, version %d, %d kbps, %d channels, %ld Hz", vorbis_data->info->version, self->bitrate, vorbis_data->info->channels, self->samplerate); vorbis_data->vf = vf; vorbis_data->samples = 0; self->type = ICES_INPUT_VORBIS; self->data = vorbis_data; self->read = NULL; self->readpcm = ices_vorbis_readpcm; self->close = ices_vorbis_close; in_vorbis_set_metadata (vorbis_data); return 0; }