static int xrun_recovery (snd_pcm_t * handle, int err) { if (err == -EPIPE) { /* under-run */ err = snd_pcm_prepare (handle); if (err < 0) alsaplayer_error ("Can't recovery from underrun, prepare failed: %s", snd_strerror (err)); return 0; } else if (err == -ESTRPIPE) { while ((err = snd_pcm_resume (handle)) == -EAGAIN) sleep (1); /* wait until the suspend flag is released */ if (err < 0) { err = snd_pcm_prepare (handle); if (err < 0) alsaplayer_error ("Can't recovery from suspend, prepare failed: %s", snd_strerror (err)); } return 0; } return err; }
void load_scope_addons() { char path[1024]; struct stat buf; scope_plugin *tmp; scope_plugin_info_type scope_plugin_info; snprintf(path, sizeof(path)-1, "%s/scopes2", addon_dir); DIR *dir = opendir(path); dirent *entry; if (dir) { while ((entry = readdir(dir)) != NULL) { // For each file in scopes if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } snprintf(path, sizeof (path), "%s/scopes2/%s", addon_dir, entry->d_name); //alsaplayer_error(path); if (stat(path, &buf)) continue; if (S_ISREG(buf.st_mode)) { void *handle; char *ext = strrchr(path, '.'); if (!ext) continue; ext++; if (strcasecmp(ext, "so")) continue; if ((handle = dlopen(path, RTLD_NOW |RTLD_GLOBAL))) { scope_plugin_info = (scope_plugin_info_type) dlsym(handle, "scope_plugin_info"); if (scope_plugin_info) { #ifdef DEBUG alsaplayer_error("Loading scope addon: %s\n", path); #endif tmp = scope_plugin_info(); if (tmp) { tmp->handle = handle; if (apRegisterScopePlugin(tmp) == -1) { alsaplayer_error("%s is deprecated", path); } } } else { dlclose(handle); } } else { printf("%s\n", dlerror()); } } } closedir(dir); } }
/* Receive response head. */ static int get_response_head (int sock, char *response, int max) { int len = 0; while (len < 4 || memcmp (response + len - 4, "\r\n\r\n", 4)) { /* check for overflow */ if (len >= max) { alsaplayer_error ("HTTP: Response is too long."); return 1; } /* wait for data */ if (sleep_for_data (sock)) return 1; /* read */ if (read (sock, response + len, 1) <=0 ) break; len += 1; } /* terminate string */ response [len] = '\0'; return 0; } /* end of: get_response_head */
static int mad_stream_info(input_object *obj, stream_info *info) { struct mad_local_data *data; unsigned len; char metadata[256]; char *s, *p; if (!obj || !info) return 0; data = (struct mad_local_data *)obj->local_data; if (data) { if (!data->parse_id3) { sprintf(data->sinfo.title, "%s", data->filename); } else if (!data->parsed_id3) { if (reader_seekable(data->mad_fd)) { parse_id3 (data->path, &data->sinfo); if ((len = strlen(data->sinfo.title))) { s = data->sinfo.title + (len - 1); while (s != data->sinfo.title && *s == ' ') *(s--) = '\0'; } if ((len = strlen(data->sinfo.artist))) { s = data->sinfo.artist + (len - 1); while (s != data->sinfo.artist && *s == ' ') *(s--) = '\0'; } } strncpy (data->sinfo.path, data->path, sizeof(data->sinfo.path)); data->parsed_id3 = 1; } memset(metadata, 0, sizeof(metadata)); if ((len = reader_metadata(data->mad_fd, sizeof(metadata), metadata))) { //alsaplayer_error("Metadata: %s", metadata); if ((s = strstr(metadata, "StreamTitle='"))) { s += 13; if ((p = strstr(s, "'"))) { *p = '\0'; snprintf(data->sinfo.title, 128, "%s", s); } else { alsaplayer_error("Malformed metadata: \"%s\"", metadata); } } } /* Restore permanently filled info */ memcpy (info, &data->sinfo, sizeof (data->sinfo)); /* Compose path, stream_type and status fields */ sprintf(info->stream_type, "MP3 %dKHz %s %-3ldkbit", data->frame.header.samplerate / 1000, obj->nr_channels == 2 ? "stereo" : "mono", data->frame.header.bitrate / 1000); if (data->seeking) sprintf(info->status, "Seeking..."); } return 1; }
static void oglspectrum_start(void) { if (pthread_mutex_trylock(&scope_mutex) != 0) { alsaplayer_error("spectrum already running"); return; } start_display(); }
void exit_sighandler(int x) { static int sigcount = 0; ++sigcount; if (sigcount == 1) { alsaplayer_error("alsaplayer interrupted by signal %d", x); exit(1); } if (sigcount > 5) { kill(getpid(), SIGKILL); } }
static void wait_for_vsync(void) { #ifdef NVIDIA_SYNC static int init = 0; static int fd = -1; static struct pollfd pollfds; if (!init) { fd = open("/dev/nvidia0", O_RDONLY); if (fd == -1) { alsaplayer_error("Error opening NVIDIA device /dev/nvidia0"); } else { pollfds.fd = fd; pollfds.events = 0xffff; pollfds.revents = 0xffff; alsaplayer_error("Using NVIDIA poll method for vsync"); } init = 1; } poll (&pollfds, 1, -1); #else dosleep(10000); #endif }
int interface_gtk_start(Playlist *playlist, int argc, char **argv) { char path[256]; char *home; the_coreplayer = playlist->GetCorePlayer(); g_thread_init(NULL); if (!g_thread_supported()) { alsaplayer_error("Sorry - this interface requires working threads.\n"); return 1; } // Scope functions scopes = new AlsaSubscriber(); scopes->Subscribe(the_coreplayer->GetNode(), POS_END); scopes->EnterStream(scope_feeder_func, the_coreplayer); gtk_set_locale(); gtk_init(&argc, &argv); gdk_rgb_init(); home = getenv("HOME"); if (home) { snprintf(path, 255, "%s/.gtkrc", home); gtk_rc_parse(path); } if (playlist->Length()) playlist->UnPause(); // Scope addons gdk_flush(); GDK_THREADS_ENTER(); init_main_window(playlist); load_scope_addons(); gdk_flush(); gtk_main(); gdk_flush(); GDK_THREADS_LEAVE(); unload_scope_addons(); destroy_scopes_window(); GDK_THREADS_ENTER(); gdk_flush(); GDK_THREADS_LEAVE(); playlist->Pause(); dl_close_scopes(); return 0; }
interface_plugin_info_type load_interface(const char *name) { void *handle; char path[1024]; const char *pluginroot; struct stat statbuf; interface_plugin_info_type plugin_info; interface_plugin *ui; if (!global_pluginroot) pluginroot = ADDON_DIR; else pluginroot = global_pluginroot; if (!name) return NULL; if (strchr(name, '.')) ap_strlcpy(path, name, sizeof(path)); else snprintf(path, sizeof(path), "%s/interface/lib%s_interface.so", pluginroot, name); #ifdef DEBUG alsaplayer_error("Loading interface plugin: %s\n", path); #endif if (stat(path, &statbuf) != 0) // Error reading object return NULL; handle = dlopen(path, RTLD_LAZY | RTLD_GLOBAL); if (!handle) { alsaplayer_error("%s\n", dlerror()); return NULL; } plugin_info = (interface_plugin_info_type) dlsym(handle, "interface_plugin_info"); if (!plugin_info) { alsaplayer_error("symbol error in shared object: %s", path); dlclose(handle); return NULL; } interface_plugin *plugin = plugin_info(); if (plugin) plugin->handle = handle; ui = plugin_info(); if (ui->version != INTERFACE_PLUGIN_VERSION) { alsaplayer_error("Wrong interface plugin version (v%d, wanted v%d)", ui->version, INTERFACE_PLUGIN_VERSION - INTERFACE_PLUGIN_BASE_VERSION); alsaplayer_error("Error loading %s", path); alsaplayer_error("Please remove this file from your system"); return NULL; } return plugin_info; }
/* Sleep for data. */ static int sleep_for_data (int sock) { fd_set set; struct timeval tv; tv.tv_sec = 5; tv.tv_usec = 0; FD_ZERO (&set); FD_SET (sock, &set); if (select (sock+1, &set, NULL, NULL, &tv) < 1) { alsaplayer_error ("HTTP: Connection is too slow."); return 1; } return 0; } /* end of: sleep_for_data */
/* Parse URI. */ static int parse_uri (const char *uri, char **host, int *port, char **path) { char *slash, *colon; int l; *port = 80; /* Trying to find end of a host part */ slash = strchr (uri+7, '/'); colon = strchr (uri+7, ':'); if ((slash && colon && slash > colon) || (!slash && colon)) { /* As I see, there is port specified */ char *s; *port = (int)strtol (colon+1, &s, 10); /* Test, port should be digit */ if ((slash && s!=slash) || (!slash && *s!='\0')) { alsaplayer_error ("\nHTTP: Couldn't open %s: Port -- parse error.", uri); return -1; } /* Calculate host part length */ l = colon - uri - 7; } else { /* Calculate host part length */ l = slash ? slash - uri - 7 : (int) strlen (uri+7); } /* Reset port if URI looks like 'foo.bar:/aaa.mp3' */ if (colon && slash && slash==colon+1) *port = 80; /* Split URI */ //if (*host) // free(*host); *host = malloc (l+1); ap_strlcpy (*host, uri+7, l+1); //if (*path) // free(*path); *path = strdup (slash ? slash : "/"); return 0; } /* end of: parse_uri */
static ssize_t find_initial_frame(uint8_t *buf, int size) { uint8_t *data = buf; int ext_header = 0; int pos = 0; ssize_t header_size = 0; while (pos < (size - 10)) { if (pos == 0 && data[pos] == 0x0d && data[pos+1] == 0x0a) pos += 2; if (data[pos] == 0xff && (data[pos+1] == 0xfb || data[pos+1] == 0xfa || data[pos+1] == 0xf3 || data[pos+1] == 0xf2 || data[pos+1] == 0xe2 || data[pos+1] == 0xe3)) { return pos; } if (pos == 0 && data[pos] == 0x0d && data[pos+1] == 0x0a) { return -1; /* Let MAD figure this out */ } if (pos == 0 && (data[pos] == 'I' && data[pos+1] == 'D' && data[pos+2] == '3')) { header_size = (data[pos + 6] << 21) + (data[pos + 7] << 14) + (data[pos + 8] << 7) + data[pos + 9]; /* syncsafe integer */ if (data[pos + 5] & 0x10) { ext_header = 1; header_size += 10; /* 10 byte extended header */ } /* printf("ID3v2.%c detected with header size %d (at pos %d)\n", 0x30 + data[pos + 3], header_size, pos); */ if (ext_header) { /* printf("Extended header detected\n"); */ } header_size += 10; if (header_size > STREAM_BUFFER_SIZE) { //alsaplayer_error("Header larger than 32K (%d)", header_size); return header_size; } return header_size; } else if (data[pos] == 'R' && data[pos+1] == 'I' && data[pos+2] == 'F' && data[pos+3] == 'F') { pos+=4; /* alsaplayer_error("Found a RIFF header"); */ while (pos < size) { if (data[pos] == 'd' && data[pos+1] == 'a' && data[pos+2] == 't' && data[pos+3] == 'a') { pos += 8; /* skip 'data' and ignore size */ return pos; } else pos++; } puts("MAD debug: invalid header"); return -1; } else if (pos == 0 && data[pos] == 'T' && data[pos+1] == 'A' && data[pos+2] == 'G') { return 128; /* TAG is fixed 128 bytes, we assume! */ } else { pos++; } } alsaplayer_error( "MAD debug: potential problem file or unhandled info block\n" "next 4 bytes = %x %x %x %x (index = %d, size = %d)\n", data[header_size], data[header_size+1], data[header_size+2], data[header_size+3], (int)header_size, size); return -1; }
// Thread which performs an insert to playlist void insert_looper(void *data) { std::set<PlaylistInterface *>::const_iterator i; std::set<playlist_interface *>::const_iterator j; PlInsertItems * items = (PlInsertItems *)data; Playlist *playlist = items->playlist; // Stop the list being changed while we add these items playlist->Lock(); // First vetting of the list, and recurse through directories std::vector<std::string> vetted_items; std::vector<std::string>::const_iterator k = items->items.begin(); while(k != items->items.end() && playlist->active) { additems(&(vetted_items), *k++, MAXRECURSEDEPTH); } std::vector<PlayItem> newitems; if(vetted_items.size() > 0) { char cwd[PATH_MAX + 1]; std::vector<std::string>::const_iterator path; if (!getcwd(cwd, PATH_MAX)) { alsaplayer_error("Failed to get current working directory"); cwd[0] = 0; } // Check items for adding to list for(path = vetted_items.begin(); path != vetted_items.end() && playlist->active; path++) { // Check that item is valid if(!playlist->CanPlay(*path)) { //alsaplayer_error("Can't find a player for `%s'\n", path->c_str()); } else { newitems.push_back(PlayItem(*path)); } } } // Check position is valid if(playlist->queue.size() < items->position) { items->position = playlist->queue.size(); } // Add to list playlist->queue.insert(playlist->queue.begin() + items->position, newitems.begin(), newitems.end()); if(playlist->curritem > items->position) playlist->curritem += newitems.size(); if(playlist->curritem == 0) { playlist->curritem = 1; } // Tell the subscribing interfaces about the changes playlist->LockInterfaces(); if(playlist->interfaces.size() > 0) { for(i = playlist->interfaces.begin(); i != playlist->interfaces.end(); i++) { (*i)->CbInsert(newitems, items->position); (*i)->CbSetCurrent(playlist->curritem); } } if (playlist->cinterfaces.size() > 0) { for (j = playlist->cinterfaces.begin(); j != playlist->cinterfaces.end(); j++) { (*j)->cbinsert((*j)->data, newitems, items->position); (*j)->cbsetcurrent((*j)->data, playlist->curritem); } } playlist->UnlockInterfaces(); // Free the list again /* Metadate gathering is disabled for now. It completely * breaks streaming and it was never very efficient. A complete * reimplementation will follow shortly */ if (playlist->active) info_looper(playlist); playlist->Unlock(); delete items; }
int main(int argc, char **argv) { const char *device_param = default_pcm_device; char *prefsdir; char thefile[1024]; char str[1024]; float start_vol = 1.0; int ap_result = 0; int use_fragsize = -1; // Initialized int use_fragcount = -1; // later int do_loopsong = 0; int do_looplist = 0; int do_enqueue = 0; int do_replace = 0; int do_realtime = 0; int do_remote_control = 0; int do_shuffle = 0; int do_start = 0; int do_stop = 0; int do_prev = 0; int do_next = 0; int do_pause = 0; int do_jump = -1; int do_clear = 0; int do_seek = -1; int do_relative = 0; int do_setvol = 0; int do_quit = 0; int do_status = 0; int do_speed = 0; float speed_val = 0.0; int do_onebyone = 0; int use_freq = OUTPUT_RATE; float use_vol = 1.0; int use_session = 0; int do_crossfade = 0; int do_save = 1; int bool_val = 0; const char *use_output = NULL; char *use_interface = NULL; char *use_config = NULL; char *use_loopsong = NULL; char *use_onebyone = NULL; char *use_looplist = NULL; int opt; int option_index; const char *options = "Cc:d:eEf:F:g:hi:J:I:l:n:NMp:qrs:vRSQVxo:"; struct option long_options[] = { /* { "long_option", take_argument, 0, 'short_option' }, */ { "config", 1, 0, 'c' }, { "device", 1, 0, 'd' }, { "enqueue", 0, 0, 'e' }, { "replace", 0, 0, 'E' }, { "fragsize", 1, 0, 'f' }, { "frequency", 1, 0, 'F' }, { "fragcount", 1, 0, 'g' }, { "help", 0, 0, 'h' }, { "interface", 1, 0, 'i' }, { "volume", 1, 0, 'Y' }, { "session", 1, 0, 'n' }, { "nosave", 0, 0, 'N' }, { "path", 1, 0, 'p' }, { "quiet", 0, 0, 'q' }, { "realtime", 0, 0, 'r' }, { "script", 1, 0, 'I'}, { "session-name", 1, 0, 's' }, { "version", 0, 0, 'v' }, { "verbose", 0, 0, 'V' }, { "reverb", 0, 0, 'R' }, { "loopsong", 1, 0, 'L' }, { "looplist", 1, 0, 'P' }, { "crossfade", 0, 0, 'x' }, { "output", 1, 0, 'o' }, { "stop", 0, 0, 'U' }, { "pause", 0, 0, 'O' }, { "start", 0, 0, 'T' }, { "shuffle", 0, 0, 'S' }, { "prev", 0, 0, 'Q' }, { "next", 0, 0, 'M' }, { "jump", 1, 0, 'J' }, { "seek", 1, 0, 'X' }, { "relative", 1, 0, 'Z' }, { "speed", 1, 0, 'H' }, { "clear", 0, 0, 'C' }, { "startvolume", 1, 0, 'l' }, { "quit", 0, 0, 'A' }, { "status", 0, 0, 'B' }, { "onebyone", 1, 0, 't' }, // Options that we want to be able to pass on to gtk_init(). See man // gtk-options(7). // Give all of these an option number of 128 because we're going to // ignore them option switch statement anyway. { "gtk-module", 1, 0, 128 }, { "gtk-debug", 1, 0, 128 }, { "gtk-no-debug", 1, 0, 128 }, { "g-fatal-warnings", 0, 0, 128 }, { "display", 1, 0, 128 }, { "screen", 1, 0, 128 }, { "sync", 0, 0, 128 }, { "no-xshm", 0, 0, 128 }, { "name", 1, 0, 128 }, { "class", 1, 0, 128 }, { "gxid_host", 1, 0, 128 }, { "gxid_port", 1, 0, 128 }, { "xim-preedit", 0, 0, 128 }, { "xim-status", 0, 0, 128 }, { "gdk-debug", 1, 0, 128 }, { "gdk-no-debug", 1, 0, 128 }, // End of list marker. { 0, 0, 0, 0 } }; // First setup signal handler signal(SIGPIPE, nonfatal_sighandler); // PIPE (socket control) signal(SIGTERM, exit_sighandler); // kill signal(SIGHUP, exit_sighandler); // kill -HUP / xterm closed signal(SIGINT, exit_sighandler); // Interrupt from keyboard signal(SIGQUIT, exit_sighandler); // Quit from keyboard // fatal errors signal(SIGBUS, exit_sighandler); // bus error //signal(SIGSEGV, exit_sighandler); // segfault signal(SIGILL, exit_sighandler); // illegal instruction signal(SIGFPE, exit_sighandler); // floating point exc. signal(SIGABRT, exit_sighandler); // abort() // Enable locale support #ifdef ENABLE_NLS setlocale (LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); bind_textdomain_codeset (PACKAGE, "UTF-8"); #endif // Init global mutexes pthread_mutex_init(&playlist_sort_seq_mutex, NULL); #if !defined(EMBEDDED) init_effects(); #endif while ((opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) { switch(opt) { case 'A': do_remote_control = 1; do_quit = 1; break; case 'B': do_remote_control = 1; do_status = 1; break; case 'c': if (strlen(optarg) < 1023) { use_config = optarg; } else { alsaplayer_error("config file path too long"); return 1; } break; case 'd': device_param = optarg; break; case 'E': do_replace = 1; case 'e': do_enqueue = 1; break; case 'f': use_fragsize = atoi(optarg); if (!use_fragsize) { alsaplayer_error("invalid fragment size"); return 1; } if (use_fragsize > 32768) { alsaplayer_error("fragment size (%d) out of range (0-32768)", use_fragsize); return 1; } break; case 'F': use_freq = atoi(optarg); if (use_freq < 8000 || use_freq > 48000) { alsaplayer_error("frequency (%d) out of range (8000-48000)", use_freq); return 1; } break; case 'g': use_fragcount = atoi(optarg); if (use_fragcount < 2 || use_fragcount > 128) { alsaplayer_error("fragcount (%d) out of range (2-128)", use_fragcount); return 1; } break; case 'h': help(); return 0; case 'H': if ((sscanf(optarg, "%f", &speed_val))) { do_remote_control = 1; do_speed = 1; } break; case 'i': use_interface = optarg; break; case 'l': start_vol = atof(optarg); if (start_vol < 0.0 || start_vol > 1.0) { alsaplayer_error("volume (%.3f) out of range: using 1.0", start_vol); start_vol = 1.0; } break; case 'L': do_remote_control = 1; do_loopsong = 1; use_loopsong = optarg; break; case 'Y': do_remote_control = 1; do_setvol = 1; use_vol = atof(optarg); if (use_vol < 0.0 || use_vol > 1.0) { alsaplayer_error("volume (%.3f) out of range: using 1.0", use_vol); use_vol = 1.0; } break; case 'n': use_session = atoi(optarg); break; case 'N': do_save = 0; break; case 'O': do_remote_control = 1; do_pause = 1; break; case 'p': global_pluginroot = optarg; break; case 'q': global_quiet = 1; break; case 'r': do_realtime = 1; break; case 's': if (strlen(optarg) < 32) { global_session_name = strdup(optarg); } else { alsaplayer_error("max 32 char session name, ignoring"); } break; case 'v': version(); return 0; case 'V': global_verbose = 1; break; case 'R': break; case 'P': do_remote_control = 1; do_looplist = 1; use_looplist = optarg; break; case 'x': do_crossfade = 1; break; case 'o': use_output = optarg; break; case '?': return 1; case 'I': global_interface_script = optarg; break; case 'U': do_remote_control = 1; do_stop = 1; break; case 'T': do_remote_control = 1; do_start = 1; break; case 'S': do_remote_control = 1; do_shuffle = 1; break; case 'Q': do_remote_control = 1; do_prev = 1; break; case 'M': do_remote_control = 1; do_next = 1; break; case 'J': do_remote_control = 1; do_jump = atoi(optarg); break; case 'C': do_remote_control = 1; do_clear = 1; break; case 'X': do_remote_control = 1; do_seek = atoi(optarg); break; case 'Z': do_remote_control = 1; do_relative = 1; do_seek = atoi(optarg); break; case 't': do_remote_control = 1; do_onebyone = 1; use_onebyone = optarg; break; case 128: // Gtk-option which we ignore. break; default: alsaplayer_error("Unknown option '%c'", opt); break; } } prefsdir = get_prefsdir(); mkdir(prefsdir, 0700); /* XXX We don't do any error checking here */ snprintf(thefile, sizeof(thefile)-21, "%s/config", prefsdir); if (use_config) ap_prefs = prefs_load(use_config); else ap_prefs = prefs_load(thefile); if (!ap_prefs) { alsaplayer_error("Invalid config file %s\n", use_config ? use_config : thefile); return 1; } /* Initialize some settings (and populate the prefs system if needed */ if (use_fragsize < 0) use_fragsize = prefs_get_int(ap_prefs, "main", "period_size", 4096); if (use_fragcount < 0) use_fragcount = prefs_get_int(ap_prefs, "main", "period_count", 8); if (global_verbose) puts(copyright_string); if (!global_pluginroot) { global_pluginroot = strdup (ADDON_DIR); } if (use_session == 0) { for (; use_session < MAX_REMOTE_SESSIONS+1; use_session++) { ap_result = ap_session_running(use_session); if (ap_result) break; } if (use_session == (MAX_REMOTE_SESSIONS+1)) { //alsaplayer_error("No remote session found"); if (do_remote_control) { alsaplayer_error("No active sessions"); return 1; } do_enqueue = 0; } else { //alsaplayer_error("Found session %d", use_session); if (prefs_get_bool(ap_prefs, "main", "multiopen", 1) == 0) { // We should not spawn another alsaplayer //alsaplayer_error("Using session %d, not doing multiopen", use_session); do_enqueue = 1; do_replace = 1; } } } // Check if we're in remote control mode if (do_remote_control) { if (do_quit) { ap_quit(use_session); return 0; } else if (do_status) { char res[1024]; float fres; int ires; fprintf(stdout, "---------------- Session ----------------\n"); if (ap_get_session_name(use_session, res) && strlen(res)) fprintf(stdout, "name: %s\n", res); if (ap_get_playlist_length(use_session, &ires)) fprintf(stdout, "playlist_length: %d\n", ires); if (ap_get_volume(use_session, &fres)) fprintf(stdout, "volume: %.2f\n", fres); if (ap_get_speed(use_session, &fres)) fprintf(stdout, "speed: %d%%\n", (int)(fres * 100)); fprintf(stdout, "-------------- Current Track ------------\n"); if (ap_get_artist(use_session, res) && strlen(res)) fprintf(stdout, "artist: %s\n", res); if (ap_get_title(use_session, res) && strlen(res)) fprintf(stdout, "title: %s\n", res); if (ap_get_album(use_session, res) && strlen(res)) fprintf(stdout, "album: %s\n", res); if (ap_get_genre(use_session, res) && strlen(res)) fprintf(stdout, "genre: %s\n", res); if (ap_get_file_path(use_session, res) && strlen(res)) fprintf(stdout, "path: %s\n", res); if (ap_get_blocks(use_session, &ires)) fprintf(stdout, "blocks: %d\n", ires); if (ap_get_length(use_session, &ires)) fprintf(stdout, "length: %d second%s\n", ires, (ires == 1) ? "": "s"); if (ap_get_position(use_session, &ires)) fprintf(stdout, "position: %d\n", ires); fprintf(stdout, "-----------------------------------------\n"); return 0; } else if (do_setvol) { ap_set_volume(use_session, use_vol); return 0; } else if (do_shuffle) { ap_shuffle_playlist(use_session); return 0; } else if (do_start) { ap_play(use_session); return 0; } else if (do_stop) { ap_stop(use_session); return 0; } else if (do_pause) { if (ap_is_paused(use_session, &bool_val)) { if (bool_val) ap_unpause(use_session); else ap_pause(use_session); } return 0; } else if (do_next) { ap_next(use_session); return 0; } else if (do_prev) { ap_prev(use_session); return 0; } else if (do_jump >= 0) { ap_jump_to(use_session, do_jump); return 0; } else if (do_clear) { ap_clear_playlist(use_session); return 0; } else if (do_relative) { if (do_seek != 0) ap_set_position_relative(use_session, do_seek); return 0; } else if (do_speed) { if (speed_val < -10.0 || speed_val > 10.0) { alsaplayer_error("Speed out of range, must be between -10.00 and 10.00"); return 1; } ap_set_speed(use_session, speed_val); return 0; } else if (do_seek >= 0) { ap_set_position(use_session, do_seek); return 0; } else if (do_loopsong) { if (strcasecmp(use_loopsong, "on") != 0) { do_loopsong = false; } ap_set_looping(use_session, do_loopsong); return 0; } else if (do_onebyone) { if (strcasecmp(use_onebyone, "on") != 0) { do_onebyone = false; } ap_set_onebyone(use_session, do_onebyone); return 0; } else if (do_looplist) { if (strcasecmp(use_looplist, "on") != 0) { do_looplist = false; } ap_set_playlist_looping(use_session, do_looplist); return 0; } else alsaplayer_error("No remote control command executed."); } // Check if we need to enqueue the files if (do_enqueue) { char queue_name[2048]; int count = 0; int was_playing = 0; int playlist_length = 0; count = optind; ap_result = 1; if (do_replace && count < argc) { ap_is_playing(use_session, &was_playing); if (was_playing) { ap_stop(use_session); } ap_clear_playlist(use_session); } else { ap_get_playlist_length(use_session, &playlist_length); if (!playlist_length) { // Empty list so fire up after add was_playing = 1; } } while (count < argc && ap_result) { if (is_playlist(argv[count])) { ap_add_playlist(use_session, argv[count]); count++; continue; } if (argv[count][0] != '/' && strncmp(argv[count], "http://", 7) != 0 && strncmp(argv[count], "ftp://", 6) != 0) { // Not absolute so append cwd if (getcwd(queue_name, 1024) == NULL) { alsaplayer_error("error getting cwd"); return 1; } ap_strlcat(queue_name, "/", sizeof(queue_name)); ap_strlcat(queue_name, argv[count], sizeof(queue_name)); } else ap_strlcpy(queue_name, argv[count], sizeof(queue_name)); count++; //alsaplayer_error("Adding %s", queue_name); ap_result = ap_add_path(use_session, queue_name); //alsaplayer_error("ap_result = %d", ap_result); } if (was_playing) ap_jump_to(use_session, 1); if (ap_result) return 0; } AlsaNode *node; // Check if we want jack if (strcmp(argv[0], "jackplayer") == 0) { use_output = "jack"; } // Check the output option if (use_output == NULL) { use_output = prefs_get_string(ap_prefs, "main", "default_output", "alsa"); } // Else do the usual plugin based thing node = new AlsaNode(use_output, device_param, do_realtime); if (!node->RegisterPlugin(use_output)) { alsaplayer_error("Failed to load output plugin \"%s\". Trying defaults.", use_output); if (!node->RegisterPlugin()) return 1; } int output_is_ok = 0; int output_alternate = 0; do { if (!node || !node->ReadyToRun()) { alsaplayer_error ("failed to load output plugin (%s). exitting...", use_output ? use_output: "alsa,etc."); return 1; } if (!node->SetSamplingRate(use_freq) || !node->SetStreamBuffers(use_fragsize, use_fragcount, 2)) { alsaplayer_error ("failed to configure output device...trying OSS"); /* Special case for OSS, since it's easiest to get going, so try it */ if (!output_alternate) { output_alternate = 1; node->RegisterPlugin("oss"); continue; } else { return 1; } } output_is_ok = 1; /* output device initialized */ } while (!output_is_ok); // Initialise reader reader_init (); // Initialise playlist - must be done before things try to register with it playlist = new Playlist(node); if (!prefs_get_bool(ap_prefs, "main", "play_on_start", false)) playlist->Pause(); else playlist->UnPause(); if (!playlist) { alsaplayer_error("Failed to create Playlist object"); return 1; } // Add any command line arguments to the playlist if (optind < argc) { std::vector < std::string > newitems; while (optind < argc) { if (is_playlist(argv[optind])) { if (global_verbose) alsaplayer_error("Loading playlist (%s)", argv[optind]); playlist->Load(std::string(argv[optind++]), playlist->Length(), false); } else { newitems.push_back(std::string(argv[optind++])); } } playlist->Insert(newitems, playlist->Length()); } else { prefsdir = get_prefsdir(); snprintf(thefile, sizeof(thefile)-28, "%s/alsaplayer.m3u", prefsdir); playlist->Load(thefile, playlist->Length(), false); } // Loop song if (do_loopsong) { playlist->LoopSong(); } // Loop Playlist if (do_looplist) { playlist->LoopPlaylist(); } // Play songs one by one if (do_onebyone) { playlist->SetOneByOne(); } // Cross fading if (do_crossfade) { playlist->Crossfade(); } // Set start volume playlist->GetCorePlayer()->SetVolume(start_vol); interface_plugin_info_type interface_plugin_info; interface_plugin *ui; if (get_interface_from_argv0 (argv[0], str)) use_interface = str; if (use_interface && *use_interface) { if (!(interface_plugin_info = load_interface(use_interface))) { alsaplayer_error("Failed to load interface %s\n", use_interface); goto _fatal_err; } } else { const char *interface = prefs_get_string (ap_prefs, "main", "default_interface", "gtk2"); // if we're trying to use the old gtk-1 interface, use gtk-2 instead if (strcmp (interface, "gtk") == 0) interface = "gtk2"; // if we're trying to use the gtk interface, but we have no // $DISPLAY, use the text interface instead if (strcmp (interface, "gtk2") == 0 && !getenv("DISPLAY")) interface = "text"; if (!(interface_plugin_info = load_interface(interface))) { if (!(interface_plugin_info = load_interface(prefs_get_string (ap_prefs, "main", "fallback_interface", "text")))) { alsaplayer_error("Failed to load text interface. This is bad (%s,%s,%s)", interface, interface, global_pluginroot); goto _fatal_err; } } } if (interface_plugin_info) { ui = interface_plugin_info(); if (global_verbose) printf("Interface plugin: %s\n", ui->name); if (!ui->init()) { alsaplayer_error("Failed to load interface plugin. Should fall back to text\n"); } else { control_socket_start(playlist, ui); ui->start(playlist, argc, argv); ui->close(); // Unfortunately gtk+ is a pig when it comes to // cleaning up its resources; it doesn't! // so we can never safely dlclose gtk+ based // user interfaces, bah! //dlclose(ui->handle); control_socket_stop(); } } // Save playlist before exit prefsdir = get_prefsdir(); snprintf(thefile, sizeof(thefile)-25, "%s/alsaplayer", prefsdir); playlist->Save(thefile, PL_FORMAT_M3U); // Save preferences if (ap_prefs && do_save) { if (prefs_save(ap_prefs) < 0) { alsaplayer_error("failed to save preferences."); } } _fatal_err: delete playlist; //delete p; delete node; if (global_session_name) free(global_session_name); return 0; }
prefs_handle_t *prefs_load(const char *filename) { FILE *fd; prefs_handle_t *prefs; char buf[1024]; char *val; char *key; int error_count = 0; if (!filename) return NULL; prefs = malloc(sizeof(prefs_handle_t)); if (!prefs) return NULL; memset(prefs, 0, sizeof(prefs_handle_t)); if ((fd = fopen(filename, "r")) == NULL) { if ((fd = fopen(filename, "w")) == NULL) { free(prefs); return NULL; } } while (fgets(buf, 1023, fd) && error_count < 5) { buf[1023] = 0; if (strlen(buf) < 1024) buf[strlen(buf)-1] = 0; /* get rid of '\n' */ else { error_count++; continue; } if (buf[0] == '#') continue; if ((val = strchr(buf, '='))) { *val = 0; /* replace value separator with 0 */ val++; if ((key = strchr(buf, '.'))) { *key = 0; /* replace section separator with 0 */ key++; prefs_set_string(prefs, buf, key, val); } else { alsaplayer_error("Found old prefs format (%s), ignoring", buf); continue; } } else { error_count++; } } fclose(fd); if (error_count >= 5) { /* too many errors */ fprintf(stderr, "*** WARNING: Too many errors in %s\n" "*** WARNING: It is probably corrupted! Please remove it.\n", filename); return NULL; } prefs->filename = strdup(filename); return prefs; }
static void * draw_thread_func(void * UNUSED (arg)) { Bool configured = FALSE; window_w = prefs_get_int(ap_prefs, "opengl_spectrum", "width", DEFAULT_W); window_h = prefs_get_int(ap_prefs, "opengl_spectrum", "height", DEFAULT_H); if ((window = create_window(window_w, window_h)) == 0) { alsaplayer_error("unable to create window"); pthread_exit(NULL); } XMapWindow(dpy, window); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1, 1, -1, 1, 1.5, 10); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); while(going) { while(XPending(dpy)) { XEvent event; KeySym keysym; char buf[16]; XNextEvent(dpy, &event); switch(event.type) { case ConfigureNotify: glViewport(0,0,event.xconfigure.width, event.xconfigure.height); window_w = event.xconfigure.width; window_h = event.xconfigure.height; prefs_set_int(ap_prefs, "opengl_spectrum", "width", window_w); prefs_set_int(ap_prefs, "opengl_spectrum", "height", window_h); configured = TRUE; break; case KeyPress: XLookupString (&event.xkey, buf, 16, &keysym, NULL); switch(keysym) { case XK_Escape: going = FALSE; break; case XK_z: /*xmms_remote_playlist_prev(oglspectrum_vp.xmms_session); */ break; case XK_x: /*xmms_remote_play(oglspectrum_vp.xmms_session); */ break; case XK_c: /*xmms_remote_pause(oglspectrum_vp.xmms_session); */ break; case XK_v: /*xmms_remote_stop(oglspectrum_vp.xmms_session); */ break; case XK_b: /* xmms_remote_playlist_next(oglspectrum_vp.xmms_session); */ break; case XK_Up: x_speed -= 0.1; if(x_speed < -3.0) x_speed = -3.0; break; case XK_Down: x_speed += 0.1; if(x_speed > 3.0) x_speed = 3.0; break; case XK_Left: y_speed -= 0.1; if(y_speed < -3.0) y_speed = -3.0; break; case XK_Right: y_speed += 0.1; if(y_speed > 3.0) y_speed = 3.0; break; case XK_w: z_speed -= 0.1; if(z_speed < -3.0) z_speed = -3.0; break; case XK_q: z_speed += 0.1; if(z_speed > 3.0) z_speed = 3.0; break; case XK_Return: x_speed = 0.0; y_speed = 0.5; z_speed = 0.0; x_angle = 20.0; y_angle = 45.0; z_angle = 0.0; break; } break; case ClientMessage: if ((Atom)event.xclient.data.l[0] == wm_delete_window_atom) { going = FALSE; } break; } } if(configured) { x_angle += x_speed; if(x_angle >= 360.0) x_angle -= 360.0; y_angle += y_speed; if(y_angle >= 360.0) y_angle -= 360.0; z_angle += z_speed; if(z_angle >= 360.0) z_angle -= 360.0; draw_bars(); } } if (glxcontext) { glXMakeCurrent(dpy, 0, NULL); glXDestroyContext(dpy, glxcontext); glxcontext = NULL; } if (window) { if (grabbed_pointer) { XUngrabPointer(dpy, CurrentTime); grabbed_pointer = FALSE; } XDestroyWindow(dpy, window); window = 0; } pthread_mutex_unlock(&scope_mutex); stop_display(0); /* Close down display */ pthread_exit(NULL); }
static int mad_play_frame(input_object *obj, char *buf) { struct mad_local_data *data; struct mad_pcm *pcm; mad_fixed_t const *left_ch; mad_fixed_t const *right_ch; int16_t *output; int nsamples; int nchannels; if (!obj) return 0; data = (struct mad_local_data *)obj->local_data; if (!data) return 0; if (data->bytes_avail < 3072) { /* alsaplayer_error("Filling buffer = %d,%d", data->bytes_avail, data->map_offset + MAD_BUFSIZE - data->bytes_avail); */ fill_buffer(data, -1); /* data->map_offset + MAD_BUFSIZE - data->bytes_avail); */ mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail); } else { /* alsaplayer_error("bytes_avail = %d", data->bytes_avail); */ } if (mad_frame_decode(&data->frame, &data->stream) == -1) { if (!MAD_RECOVERABLE(data->stream.error)) { /* alsaplayer_error("MAD error: %s (%d). fatal", error_str(data->stream.error, data->str), data->bytes_avail); */ mad_frame_mute(&data->frame); return 0; } else { if (reader_eof(data->mad_fd)) { return 0; } //alsaplayer_error("MAD error: %s (not fatal)", error_str(data->stream.error, data->str)); memset(buf, 0, obj->frame_size); return 1; } } data->current_frame++; if (data->seekable && data->current_frame < (obj->nr_frames + FRAME_RESERVE)) { data->frames[data->current_frame] = data->map_offset + data->stream.this_frame - data->mad_map; if (data->current_frame > 3 && (data->frames[data->current_frame] - data->frames[data->current_frame-3]) < 6) { return 0; } if (data->highest_frame < data->current_frame) data->highest_frame = data->current_frame; } mad_synth_frame (&data->synth, &data->frame); { pcm = &data->synth.pcm; output = (int16_t *)buf; nsamples = pcm->length; nchannels = pcm->channels; if (nchannels != obj->nr_channels) { alsaplayer_error("ERROR: bad data stream! (channels: %d != %d, frame %d)", nchannels, obj->nr_channels, data->current_frame); mad_frame_mute(&data->frame); memset(buf, 0, obj->frame_size); return 1; } obj->nr_channels = nchannels; if (data->samplerate != data->frame.header.samplerate) { alsaplayer_error("ERROR: bad data stream! (samplerate: %d != %d, frame %d)", data->samplerate, data->frame.header.samplerate, data->current_frame); mad_frame_mute(&data->frame); memset(buf, 0, obj->frame_size); return 1; } data->samplerate = data->frame.header.samplerate; left_ch = pcm->samples[0]; right_ch = pcm->samples[1]; while (nsamples--) { *output++ = my_scale(*(left_ch++)); if (nchannels == 1) { *output++ = my_scale(*(left_ch-1)); } else { /* nchannels == 2 */ *output++ = my_scale(*(right_ch++)); } } } data->bytes_avail = data->stream.bufend - data->stream.next_frame; return 1; }
void playlist_looper(void *data) { #ifdef DEBUG printf("THREAD-%d=playlist thread\n", getpid()); #endif /* DEBUG */ Playlist *pl = (Playlist *)data; CorePlayer *coreplayer; if(!pl) return; while(pl->active) { if (!pl->IsPaused()) { if (!(coreplayer = (CorePlayer *)(pl->coreplayer))) return; if (!coreplayer->IsActive()) { if (pl->Length()) { if (pl->LoopingSong()) { pl->Play(pl->GetCurrent()); } else { pl->Next(); if(pl->IsOneByOne()) { pl->Stop(); } } // TODO? set a flag to skip the dosleep() } } if (pl->Crossfading() && pl->Length() && pl->coreplayer->GetSpeed() >= 0.0) { // Cross example // Calc the block to sec value int nr_blocks = coreplayer->GetBlocks(); int totaltime = coreplayer->GetCurrentTime(nr_blocks); float blocktime = (float)totaltime / (float)nr_blocks; float xstart = 300; // 3.0 seconds float xblock = xstart / blocktime; //alsaplayer_error("xblock = %.2f", xblock); if ((coreplayer->GetBlocks() - coreplayer->GetPosition()) < (int)xblock) { if (pl->player1->IsActive() && pl->player2->IsActive()) { alsaplayer_error("Stopping players in playlist_looper"); pl->player1->Stop(); pl->player2->Stop(); } if (pl->player1->IsActive()) { pl->player2->SetSpeed(pl->coreplayer->GetSpeed()); pl->coreplayer = pl->player2; } else { pl->player1->SetSpeed(pl->coreplayer->GetSpeed()); pl->coreplayer = pl->player1; } pl->Next(); // TODO? set a flag to skip the dosleep() } } } // Update the position: notifier information pl->coreplayer->PositionUpdate(); dosleep(200000); } }
/* follow redirect URLs if encountered */ static int reconnect (http_desc_t *desc, char *redirect) { char request [2048]; char response [10240]; char *s; int error; socklen_t error_len; struct hostent *hp; struct sockaddr_in address; fd_set set; struct timeval tv; int flags; int rc = 0; /* Clear error status */ desc->error = 0; /* Stop filling thread */ if (desc->going) { desc->going = 0; desc->dont_wait = 10; pthread_cond_signal (&desc->dont_wait_signal); pthread_join (desc->buffer_thread, NULL); } /* Close connection */ if (desc->sock) { close (desc->sock); desc->sock = 0; } /* Free buffer */ if (desc->buffer) { free (desc->buffer); desc->buffer = NULL; } desc->begin = 0; desc->len = 0; /* Look up for host IP */ if (!(hp = gethostbyname (desc->host))) { alsaplayer_error ("HTTP: Couldn't look up host %s.", desc->host); return 1; } /* Open socket */ desc->sock = socket (AF_INET, SOCK_STREAM, 0); if (desc->sock==-1) { alsaplayer_error ("HTTP: Couldn't open socket."); return 1; } flags = fcntl (desc->sock, F_GETFL, 0); fcntl (desc->sock, F_SETFL, flags | O_NONBLOCK); /* Fill address struct */ address.sin_family = AF_INET; address.sin_port = htons (desc->port); memcpy (&address.sin_addr.s_addr, *(hp->h_addr_list), sizeof (address.sin_addr.s_addr)); /* Start connection */ if (connect (desc->sock, (struct sockaddr *) &address, sizeof (struct sockaddr_in)) == -1) { if (errno != EINPROGRESS) { alsaplayer_error ("HTTP: Couldn't connect to host %s:%u", desc->host, desc->port); return 1; } } /* Wait for connection */ tv.tv_sec = 10; tv.tv_usec = 0; FD_ZERO (&set); FD_SET (desc->sock, &set); if (select (desc->sock+1, NULL, &set, NULL, &tv) < 1) { alsaplayer_error ("HTTP: Connection is too slow."); return 1; } /* Test for errors while connected */ error_len = sizeof (error); getsockopt (desc->sock, SOL_SOCKET, SO_ERROR, &error, &error_len); if (error) { alsaplayer_error ("HTTP: Couldn't connect to host %s:%u", desc->host, desc->port); return 1; } /* Send request for remote file */ snprintf (request, 2048, "GET %s HTTP/1.1\r\n" "Host: %s\r\n" "Connection: close\r\n" "User-Agent: %s/%s\r\n" "Range: bytes=%ld-\r\n" "Icy-Metadata: 1\r\n" "\r\n", desc->path, desc->host, PACKAGE, VERSION, desc->pos); //alsaplayer_error("%s", request); write (desc->sock, request, strlen (request)); desc->begin = desc->buffer_pos = desc->pos; /* Get response */ if (get_response_head (desc->sock, response, 10240)) return 1; /* Check protocol */ if (!strncmp (response, "HTTP/1.0 ", 9)) { desc->seekable = 0; } else if (!strncmp (response, "HTTP/1.1 ", 9)) { desc->seekable = 1; } else if (!strncmp (response, "ICY 200 OK", 10)) { desc->seekable = 0; rc = 200; //alsaplayer_error("%s", response); } else if (!strncmp (response, "ICY 400 Server Full", 19)) { rc = 400; } else if (!strncmp (response, "ICY 404", 7)) { rc = 404; } else { if (strlen(response)) { alsaplayer_error ("HTTP: Wrong server protocol for http://%s:%u%s", desc->host, desc->port, desc->path); alsaplayer_error("ERROR:\n\"%s\"", response); } return 1; } /* Check return code */ if (strstr(response, "HTTP")) rc = atoi (response + 9); if (rc != 200 && rc != 206) { /* Wrong code */ if (rc == 404) { /* 404 */ alsaplayer_error ("HTTP: File not found: http://%s:%u%s", desc->host, desc->port, desc->path); return 1; } else if (rc == 302) { s = strstr(response, "302"); if (s) { //alsaplayer_error("%s", s); s = strstr(response, "Location: "); if (s && redirect) { /* Parse redirect */ if (sscanf(s, "Location: %[^\r]", redirect)) { /* alsaplayer_error("Redirection: %s", redirect); */ } } return 1; } } else if (rc == 400) { if (desc->status) { desc->status(desc->data, "Server is full"); } if (redirect) redirect[0] = 0; return 1; } else if (rc == 401) { if (desc->status) { desc->status(desc->data, "Unauthorized access"); } if (redirect) redirect[0] = 0; return 1; } else if (rc == 404) { if (desc->status) { desc->status(desc->data, "Resource not found"); } if (redirect) redirect[0] = 0; return 1; } else { /* unknown */ alsaplayer_error ("HTTP: We don't support %d response code: http://%s:%u%s", rc, desc->host, desc->port, desc->path); if (redirect) redirect[0] = 0; return 1; } } /* Looking for size */ s = strstr (response, "\r\nContent-Length: "); if (s) { /* Set size only once */ if (!desc->size) desc->size = atol (s+18); } else { desc->seekable = 0; } /* Look for icy-metaint */ s = strstr (response, "\r\nicy-metaint:"); if (s) { desc->icy_metaint = atoi(s+14); //alsaplayer_error("Found metaint: %d", desc->icy_metaint); } else { desc->icy_metaint = 0; } /* Setup played parts */ desc->played_parts = desc->seekable ? 5 : 0; /* Attach thread to fill a buffer */ desc->going = 1; pthread_create (&desc->buffer_thread, NULL, (void* (*)(void *)) buffer_thread, desc); return 0; } /* end of: reconnect */
/* Trying to fill info from id3 tagged file */ static void parse_id3 (const char *path, stream_info *info) { void *fd; unsigned char buf [2024]; unsigned char g; /* Open stream */ fd = reader_open (path, NULL, NULL); if (!fd) return; /* --------------------------------------------------- */ /* Trying to load id3v2 tags */ if (reader_read (buf, 10, fd) != 10) { reader_close (fd); return; } if (memcmp(buf, "ID3", 3) == 0) { /* Parse id3v2 tags */ /* Header */ unsigned char major_version = buf [3]; int f_unsynchronization = buf [5] & (1<<7); int f_extended_header = buf [5] & (1<<6); int f_experimental = buf [5] & (1<<5); int header_size = from_synchsafe4 (buf + 6); int name_size = buf [3] == 2 ? 3 : 4; int ext_size = 0; if (f_extended_header) { // alsaplayer_error ("FIXME: Extended header found in mp3." // "Please contact alsaplayer team.\n" // "Filename: %s", path); // reader_close (fd); // return; ext_size = 1; //stupid but should do } if (f_unsynchronization) { alsaplayer_error ("FIXME: f_unsynchronization is set." "Please contact alsaplayer team.\n" "Filename: %s", path); reader_close (fd); return; } if (f_experimental) { alsaplayer_error ("FIXME: f_experimental is set." "Please contact alsaplayer team.\n" "Filename: %s", path); reader_close (fd); return; } if (ext_size) { char b[4]; if (reader_read (b, 4, fd) != 4) { reader_close(fd); return; } if (major_version == 2) ext_size = from_synchsafe3 (b); else ext_size = from_synchsafe4 (b); if (reader_seek (fd, ext_size - 4, SEEK_CUR) < 0) { reader_close (fd); return; } } /* -- -- read frames -- -- */ while (reader_tell (fd) <= header_size + 10) { unsigned int size; /* Get name of this frame */ if (reader_read (buf, name_size, fd) != (unsigned)name_size) { reader_close (fd); return; } if (buf [0] == '\0') break; if (buf [0] < 'A') break; if (buf [0] > 'Z') break; /* Get size */ if (major_version == 2) { char sb [3]; if (reader_read (sb, 3, fd) != 3) { reader_close (fd); return; } size = from_synchsafe3 (sb); } else { char sb [4]; if (reader_read (sb, 4, fd) != 4) { reader_close (fd); return; } size = from_synchsafe4 (sb); } /* skip frame flags */ // if (reader_seek (fd, 1, SEEK_CUR) == -1) { // reader_close (fd); // return; // } int start = 0; // read them char b[2]; if (reader_read (b, 2, fd) != 2) { reader_close (fd); return; } else { if (b[1] & (1 << 6)) { // printf ("Grouping added\n"); start++; } if (b[1] & (1 << 3)) { // printf ("Compression added\n"); } if (b[1] & (1 << 2)) { // printf ("Encryption added\n"); } if (b[1] & (1 << 1)) { // printf ("Unsynch added\n"); } if (b[1] & (1 << 0)) { // printf ("Length added\n"); start+=4; } } if (size>=1024) { /* I will not support such long tags... * Only if someone ask for it... * not now... */ if (reader_seek (fd, size, SEEK_CUR) == -1) { reader_close (fd); return; } continue; } /* read info */ if (reader_read (buf + name_size, size, fd) != size) { reader_close (fd); return; } /* !!! Ok. There we have frame name and data. */ /* Lets use it. */ if (name_size == 4) { if (memcmp (buf, "TIT2", 4)==0) fill_from_id3v2 (info->title, buf + name_size + start, sizeof (info->title), size - start); else if (memcmp (buf, "TPE1", 4)==0) fill_from_id3v2 (info->artist, buf + name_size + start, sizeof (info->artist), size - start); else if (memcmp (buf, "TALB", 4)==0) fill_from_id3v2 (info->album, buf + name_size + start, sizeof (info->album), size - start); else if (memcmp (buf, "TYER", 4)==0) fill_from_id3v2 (info->year, buf + name_size + start, sizeof (info->year), size - start); else if (memcmp (buf, "COMM", 4)==0) fill_from_id3v2 (info->comment, buf + name_size + start, sizeof (info->comment), size - start); else if (memcmp (buf, "TRCK", 4)==0) fill_from_id3v2 (info->track, buf + name_size + start, sizeof (info->track), size - start); else if (memcmp (buf, "TCON", 4)==0) { /* Genre */ /* TODO: Optimize duplicated code */ unsigned int gindex; if (sscanf (buf + name_size + start +1, "(%u)", &gindex)==1) { if (gindex==255) *info->genre = '\0'; else if (sizeof (genres)/sizeof(char*) <= gindex) snprintf (info->genre, sizeof (info->genre), "(%u)", gindex); else snprintf (info->genre, sizeof (info->genre), "%s", genres[gindex]); } else fill_from_id3v2 (info->genre, buf + name_size + start, sizeof (info->genre), size - start); } } /* end of 'if name_size == 4' */ } /* end of frames read */ /* end parsing */ reader_close (fd); return; } /* end of id3v2 parsing */ /* --------------------------------------------------- */ /* Trying to load id3v1 tags */ if (reader_seek (fd, -128, SEEK_END) == -1) { reader_close (fd); return; } if (reader_read (buf, 128, fd) != 128) { reader_close (fd); return; } if (memcmp(buf, "TAG", 3) == 0) { /* ID3v1 frame found */ /* title */ strncpy (info->title, buf + 3, 30); rstrip (info->title); /* artist */ strncpy (info->artist, buf + 33, 30); rstrip (info->artist); /* album */ strncpy (info->album, buf + 63, 30); rstrip (info->album); /* year */ strncpy (info->year, buf + 93, 4); rstrip (info->year); /* comment */ strncpy (info->comment, buf + 97, 28); rstrip (info->comment); /* track number */ if (buf [125] == '\0') snprintf (info->track, sizeof (info->track), "%u", buf [126]); /* genre */ g = buf [127]; if (g==255) *info->genre = '\0'; else if (sizeof (genres)/sizeof(char*) <= g) snprintf (info->genre, sizeof (info->genre), "(%u)", g); else snprintf (info->genre, sizeof (info->genre), "%s", genres[g]); } /* end of id3v1 parsing */ reader_close (fd); }
/* Buffer filling thread. */ static void buffer_thread (http_desc_t *desc) { pthread_mutex_t mut; /* Temporary mutex. */ int BLOCK_SIZE = HTTP_BLOCK_SIZE; void *ibuffer; int rest = 0; int metasize = 0, metapos = 0, extra_read = 0; char *p; /* Init */ pthread_mutex_init (&mut, NULL); if (desc->icy_metaint) { BLOCK_SIZE = (HTTP_BLOCK_SIZE > desc->icy_metaint) ? desc->icy_metaint : HTTP_BLOCK_SIZE; } ibuffer = malloc (BLOCK_SIZE << 1); /* Process while main thread allow it. */ while (desc->going) { void *newbuf; int readed; #ifdef DEBUG_HTTP_BUFFERING print_debug_info (desc); #endif rest = metasize = 0; /* trying to shrink buffer */ pthread_mutex_lock (&desc->buffer_lock); shrink_buffer (desc); pthread_mutex_unlock (&desc->buffer_lock); /* let them know about our state, heh */ status_notify (desc); /* check for overflow */ if (desc->len > http_buffer_size) { /* Notice waiting function that the new block of data has arrived */ desc->new_datablock = 1; pthread_cond_signal (&desc->new_datablock_signal); /* Make pause */ if (!desc->dont_wait) { pthread_mutex_lock (&mut); cond_timedwait_relative (&desc->dont_wait_signal, &mut, calc_time_to_wait (desc)); pthread_mutex_unlock (&mut); } else { desc->dont_wait--; } continue; } /* read to internal buffer */ readed = read_data (desc->sock, ibuffer, BLOCK_SIZE); /* reasons to stop */ if (readed == 0) { desc->going = 0; } else if (readed <0) { desc->error = 1; desc->going = 0; } else { /* Something readed */ /* Metadata stuff */ if (desc->icy_metaint > 0 && (desc->buffer_pos+readed) > desc->icy_metaint) { /* Metadata block is next! */ rest = (desc->buffer_pos+readed) - desc->icy_metaint; p = ((char *)ibuffer); p += (readed-rest); metapos = (readed-rest); if (rest) { metasize = *(int8_t *)p; metasize <<= 4; if (rest < metasize) { /* Uh oh, big trouble ahead, or maybe not? */ extra_read = read_data (desc->sock, ibuffer+readed, metasize); readed += extra_read; rest += extra_read; } if (metasize > 4080) { alsaplayer_error("Invalid metasize (%d)", metasize); } else if (metasize > 0) { p++; p[metasize] = '\0'; pthread_mutex_lock (&desc->meta_lock); if (desc->metadata) { free(desc->metadata); } desc->metadata = malloc(strlen(p)+1); memcpy(desc->metadata, p, strlen(p)); pthread_mutex_unlock (&desc->meta_lock); } else { /* Metadata is zero length */ } } else { alsaplayer_error("Rest = 0???"); } metasize++; /* Length byte */ } else { desc->buffer_pos += readed; } /* These operations are fast. -> doesn't break reader_read */ /* ---------------- lock buffer ( */ pthread_mutex_lock (&desc->buffer_lock); /* enlarge buffer */ newbuf = malloc (desc->len + (BLOCK_SIZE * 2)); /* HTTP_BLOCK_SIZE */ memcpy (newbuf, desc->buffer, desc->len); if (metasize) { memcpy(newbuf + desc->len, ibuffer, metapos); memcpy(newbuf + desc->len + metapos, ibuffer+metapos+metasize, rest - metasize); readed -= metasize; desc->buffer_pos = rest - metasize; } else { memcpy (newbuf + desc->len, ibuffer, readed); } /* switch buffers */ free (desc->buffer); desc->buffer = newbuf; desc->len += readed; /* unlock buffer ) */ pthread_mutex_unlock (&desc->buffer_lock); } /* Notice waiting function that the new block of data has arrived */ desc->new_datablock = 1; pthread_cond_signal (&desc->new_datablock_signal); /* Do wait */ if (desc->going && !desc->dont_wait) { pthread_mutex_lock (&mut); cond_timedwait_relative (&desc->dont_wait_signal, &mut, calc_time_to_wait (desc)); pthread_mutex_unlock (&mut); } if (desc->dont_wait) desc->dont_wait--; } free (ibuffer); pthread_exit (NULL); } /* end of: buffer_thread */
static int mad_open(input_object *obj, const char *path) { struct mad_local_data *data; char *p; int mode; if (!obj) return 0; obj->local_data = malloc(sizeof(struct mad_local_data)); if (!obj->local_data) { puts("failed to allocate local data"); return 0; } data = (struct mad_local_data *)obj->local_data; memset(data, 0, sizeof(struct mad_local_data)); if ((data->mad_fd = reader_open(path, &reader_status, obj)) == NULL) { fprintf(stderr, "mad_open(obj, %s) failed\n", path); free(obj->local_data); obj->local_data = NULL; return 0; } obj->flags = 0; if (strncasecmp(path, "http://", 7) == 0) { obj->flags |= P_STREAMBASED; strcpy(data->sinfo.status, "Prebuffering"); } else { obj->flags |= P_FILEBASED; } if (!reader_seekable(data->mad_fd)) { data->seekable = 0; } else { obj->flags |= P_SEEK; obj->flags |= P_PERFECTSEEK; data->seekable = 1; } obj->flags |= P_REENTRANT; mad_init_decoder(data); memset(&data->xing, 0, sizeof(struct xing)); xing_init (&data->xing); data->mad_init = 1; fill_buffer(data, -1); //alsaplayer_error("initial bytes_avail = %d", data->bytes_avail); if (obj->flags & P_PERFECTSEEK) { data->offset = find_initial_frame(data->mad_map, data->bytes_avail < STREAM_BUFFER_SIZE ? data->bytes_avail : STREAM_BUFFER_SIZE); } else { data->offset = 0; } data->highest_frame = 0; if (data->offset < 0) { //fprintf(stderr, "mad_open() couldn't find valid MPEG header\n"); data->offset = 0; } //alsaplayer_error("data->offset = %d", data->offset); if (data->offset > data->bytes_avail) { data->seekable = 1; //alsaplayer_error("Need to refill buffer (data->offset = %d)", data->offset); fill_buffer(data, 0); mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail); } else { mad_stream_buffer(&data->stream, data->mad_map + data->offset, data->bytes_avail - data->offset); data->bytes_avail -= data->offset; } first_frame: if ((mad_header_decode(&data->frame.header, &data->stream) == -1)) { switch (data->stream.error) { case MAD_ERROR_BUFLEN: return 0; case MAD_ERROR_LOSTSYNC: case MAD_ERROR_BADEMPHASIS: case MAD_ERROR_BADBITRATE: case MAD_ERROR_BADLAYER: case MAD_ERROR_BADSAMPLERATE: //alsaplayer_error("Error %x (frame %d)", data->stream.error, data->current_frame); data->bytes_avail-=(data->stream.next_frame - data->stream.this_frame); goto first_frame; break; case MAD_ERROR_BADBITALLOC: return 0; case MAD_ERROR_BADCRC: alsaplayer_error("MAD_ERROR_BADCRC: %s", error_str(data->stream.error, data->str)); case MAD_ERROR_BADBIGVALUES: case MAD_ERROR_BADDATAPTR: break; default: alsaplayer_error("ERROR: %s", error_str(data->stream.error, data->str)); alsaplayer_error("No valid frame found at start (pos: %d, error: 0x%x --> %x %x %x %x) (%s)", data->offset, data->stream.error, data->stream.this_frame[0], data->stream.this_frame[1], data->stream.this_frame[2], data->stream.this_frame[3],path); return 0; } } mad_frame_decode(&data->frame, &data->stream); /* alsaplayer_error("xing parsing...%x %x %x %x (%x %d)", data->stream.this_frame[0], data->stream.this_frame[1], data->stream.this_frame[2], data->stream.this_frame[3], data->stream.anc_ptr, data->stream.anc_bitlen); */ if (xing_parse(&data->xing, data->stream.anc_ptr, data->stream.anc_bitlen) == 0) { // We use the xing data later on } mode = (data->frame.header.mode == MAD_MODE_SINGLE_CHANNEL) ? 1 : 2; data->samplerate = data->frame.header.samplerate; data->bitrate = data->frame.header.bitrate; mad_synth_frame (&data->synth, &data->frame); { struct mad_pcm *pcm = &data->synth.pcm; obj->nr_channels = pcm->channels; //alsaplayer_error("nr_channels = %d", obj->nr_channels); } //alsaplayer_error("Initial: %d, %d, %d", data->samplerate, data->bitrate, obj->nr_channels); /* Calculate some values */ data->bytes_avail = data->stream.bufend - data->stream.next_frame; { int64_t time; int64_t samples; int64_t frames; long oldpos = reader_tell(data->mad_fd); reader_seek(data->mad_fd, 0, SEEK_END); data->filesize = reader_tell(data->mad_fd); data->filesize -= data->offset; reader_seek(data->mad_fd, oldpos, SEEK_SET); if (data->bitrate) time = (data->filesize * 8) / (data->bitrate); else time = 0; samples = 32 * MAD_NSBSAMPLES(&data->frame.header); obj->frame_size = (int) samples << 2; /* Assume 16-bit stereo */ frames = data->samplerate * (time+1) / samples; if (data->xing.flags & XING_FRAMES) { obj->nr_frames = data->xing.frames; } else { obj->nr_frames = (int) frames; } obj->nr_tracks = 1; } /* Determine if nr_frames makes sense */ if (!(obj->flags & P_SEEK) && (obj->flags & P_STREAMBASED)) { obj->nr_frames = -1; } /* Allocate frame index */ if (!data->seekable || obj->nr_frames > 1000000 || (data->frames = (ssize_t *)malloc((obj->nr_frames + FRAME_RESERVE) * sizeof(ssize_t))) == NULL) { data->seekable = 0; // Given really } else { data->seekable = 1; data->frames[0] = 0; } data->mad_init = 1; p = strrchr(path, '/'); if (p) { strcpy(data->filename, ++p); } else { strcpy(data->filename, path); } strcpy(data->path, path); data->parse_id3 = prefs_get_bool(ap_prefs, "mad", "parse_id3", 1); return 1; }
void nonfatal_sighandler(int x) { alsaplayer_error("Warning: alsaplayer interrupted by signal %d", x); }
static int flac_open (input_object * obj, const char * name) { if (!obj) return 0; if (!name) return 0; reader_type * rdr = reader_open (name, NULL, NULL); if (!rdr) { alsaplayer_error ("flac_open: reader_open failed"); return 0; } obj->flags = 0; Flac::FlacStream * f = 0; try { if (Flac::FlacStream::isFlacStream (name)) { if (reader_seekable (rdr)) { f = new Flac::FlacSeekableStream (name, rdr); obj->flags |= P_SEEK | P_PERFECTSEEK; } else f = new Flac::FlacStream (name, rdr); } #ifdef HAVE_LIBOGGFLC else { f = new Flac::OggFlacStream (name, rdr); } #endif } catch (...) { alsaplayer_error ("flac_open: unable to allocate memory for plugin."); delete f; reader_close (rdr); return 0; } if (f && f->open ()) { obj->block_size = f->engine ()->apBlockSize (); // attach a song info tag if (Flac::FlacTag::hasTag (f->name ())) { Flac::FlacTag * t = Flac::FlacTag::newTag (f->name ()); f->setTag (t); } if (strncasecmp (name, "http://", 7) == 0) obj->flags |= P_STREAMBASED; else obj->flags |= P_FILEBASED; obj->nr_channels = f->engine ()->apChannels (); obj->flags |= P_REENTRANT; obj->nr_blocks = f->engine ()->apBlocks (); obj->nr_tracks = 1; obj->ready = 1; obj->local_data = (void *) f; return 1; } else { alsaplayer_error ("flac_open: unable to open flac stream or " "unsupported flac stream (%s)", name); delete f; obj->block_size = 0; obj->nr_channels = 0; obj->flags = 0; obj->nr_blocks = 0; obj->nr_tracks = 0; obj->ready = 0; obj->local_data = 0; return 0; } }