Mercurial > audlegacy-plugins
view src/streambrowser/xiph.c @ 3176:dca77b467ea2
Fix a race condition which can occur when flushing the output buffer, causing
two locking g_conds to occur at unexpected order, halting the execution.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 05 Jun 2009 02:32:48 +0300 |
parents | 3134a0987162 |
children |
line wrap: on
line source
/* * Audacious Streambrowser Plugin * * Copyright (c) 2008 Calin Crisan <ccrisan@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; under version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses>. */ #include <string.h> #include <glib.h> #include <libxml/parser.h> #include <libxml/tree.h> #include <audlegacy/plugin.h> #include "streambrowser.h" #include "xiph.h" typedef struct { gchar name[DEF_STRING_LEN]; gchar url[DEF_STRING_LEN]; gchar current_song[DEF_STRING_LEN]; gchar genre[DEF_STRING_LEN]; } xiph_entry_t; static xiph_entry_t *xiph_entries = NULL; static int xiph_entry_count = 0; typedef struct { gchar *name; gchar *match_string; } xiph_category_t; /* inspired from streamtuner's xiph plugin */ static xiph_category_t xiph_categories[] = { { "Alternative", "alternative indie goth college industrial punk hardcore ska" }, { "Electronic", "electronic ambient drum trance techno house downtempo breakbeat jungle garage" }, { "Classical", "classical opera symphonic" }, { "Country", "country swing" }, { "Hip-Hop/Rap", "hip hop rap turntable" }, { "Jazz", "jazz swing" }, { "Oldies", "oldies disco 50s 60s 70s 80s 90s" }, { "Rop", "top pop" }, { "Rock", "rock metal" }, { "R&B/Soul", "r&b funk soul urban" }, { "Spiritual", "spiritual gospel christian muslim jewish religio" }, { "Spoken", "spoken talk comedy" }, { "World", "world reggae island african european east asia" }, { "Other", "various mixed misc eclectic film show instrumental" } }; static void refresh_streamdir(void); /* returns true if any of the words in string1 is present in string2 */ static gboolean genre_match(gchar *string1, gchar *string2); gboolean xiph_streaminfo_fetch(category_t *category, streaminfo_t *streaminfo) { gint entryno; refresh_streamdir(); /* find the corresponding xiph entry */ for (entryno = 0; entryno < xiph_entry_count; entryno++) { if (strcmp(xiph_entries[entryno].name, streaminfo->name) == 0) { strcpy(streaminfo->name, xiph_entries[entryno].name); strcpy(streaminfo->url, xiph_entries[entryno].url); strcpy(streaminfo->current_track, xiph_entries[entryno].current_song); break; } } return TRUE; } gboolean xiph_category_fetch(streamdir_t *streamdir, category_t *category) { refresh_streamdir(); gint entryno, categoryno; gint xiph_category_count = sizeof(xiph_categories) / sizeof(xiph_category_t); xiph_category_t *xiph_category = NULL; for (categoryno = 0; categoryno < xiph_category_count; categoryno++) if (strcmp(xiph_categories[categoryno].name, category->name) == 0) { xiph_category = xiph_categories + categoryno; break; } /* somehow we've got an invalid/unrecognized category */ if (xiph_category == NULL) { failure("xiph: got an unrecognized category: '%s'\n", category->name); return FALSE; } /* free/remove any existing streaminfos in this category */ while (streaminfo_get_count(category) > 0) streaminfo_remove(category, streaminfo_get_by_index(category, 0)); /* see what entries match this category */ for (entryno = 0; entryno < xiph_entry_count; entryno++) { if (genre_match(xiph_category->match_string, xiph_entries[entryno].genre)) { streaminfo_t *streaminfo = streaminfo_new(xiph_entries[entryno].name, "", xiph_entries[entryno].url, xiph_entries[entryno].current_song); streaminfo_add(category, streaminfo); } } /* if the requested category is the last one in the list ("other"), we fill it with all the entries that don't match the rest of categories */ if (xiph_category == &xiph_categories[xiph_category_count - 1]) { for (entryno = 0; entryno < xiph_entry_count; entryno++) { gboolean matched = FALSE; for (categoryno = 0; categoryno < xiph_category_count; categoryno++) if (genre_match(xiph_entries[entryno].genre, xiph_categories[categoryno].match_string)) { matched = TRUE; break; } if (!matched) { streaminfo_t *streaminfo = streaminfo_new(xiph_entries[entryno].name, "", xiph_entries[entryno].url, xiph_entries[entryno].current_song); streaminfo_add(category, streaminfo); } } } return TRUE; } streamdir_t* xiph_streamdir_fetch(void) { streamdir_t *streamdir = streamdir_new(XIPH_NAME); gint categno; refresh_streamdir(); for (categno = 0; categno < sizeof(xiph_categories) / sizeof(xiph_category_t); categno++) { category_t *category = category_new(xiph_categories[categno].name); category_add(streamdir, category); } return streamdir; } static void refresh_streamdir(void) { /* free any previously fetched streamdir data */ if (xiph_entries != NULL) { free(xiph_entries); xiph_entries = NULL; } xiph_entry_count = 0; debug("xiph: fetching streaming directory file '%s'\n", XIPH_STREAMDIR_URL); if (!fetch_remote_to_local_file(XIPH_STREAMDIR_URL, XIPH_TEMP_FILENAME)) { failure("xiph: stream directory file '%s' could not be downloaded to '%s'\n", XIPH_STREAMDIR_URL, XIPH_TEMP_FILENAME); return; } debug("xiph: stream directory file '%s' successfuly downloaded to '%s'\n", XIPH_STREAMDIR_URL, XIPH_TEMP_FILENAME); xmlDoc *doc = xmlReadFile(XIPH_TEMP_FILENAME, NULL, 0); if (doc == NULL) { failure("xiph: failed to read stream directory file\n"); return; } xmlNode *root_node = xmlDocGetRootElement(doc); xmlNode *node, *child; gchar *content; root_node = root_node->children; for (node = root_node; node != NULL; node = node->next) { if (node->type == XML_ELEMENT_NODE) { xiph_entries = realloc(xiph_entries, sizeof(xiph_entry_t) * (xiph_entry_count + 1)); for (child = node->children; child != NULL; child = child->next) { if (strcmp((gchar *)child->name, "server_name") == 0) { content = (gchar *) xmlNodeGetContent(child); strcpy(xiph_entries[xiph_entry_count].name, content); xmlFree(content); } else if (strcmp((gchar *)child->name, "listen_url") == 0) { content = (gchar *) xmlNodeGetContent(child); strcpy(xiph_entries[xiph_entry_count].url, content); xmlFree(content); } else if (strcmp((gchar *)child->name, "current_song") == 0) { content = (gchar *) xmlNodeGetContent(child); strcpy(xiph_entries[xiph_entry_count].current_song, content); xmlFree(content); } else if (strcmp((gchar *)child->name, "genre") == 0) { content = (gchar *) xmlNodeGetContent(child); strcpy(xiph_entries[xiph_entry_count].genre, content); xmlFree(content); } } xiph_entry_count++; } } xmlFreeDoc(doc); debug("xiph: streaming directory successfuly loaded\n"); } static gboolean genre_match(gchar *string1, gchar *string2) { gchar *saveptr = NULL, *token; gboolean matched = FALSE; gchar *temp1 = g_strdup(string1), *temp2 = g_strdup(string2); token = strtok_r(temp1, " ", &saveptr); while (token != NULL) { if (mystrcasestr(temp2, token)) matched = TRUE; token = strtok_r(NULL, " ", &saveptr); } return matched; }