⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xiph.c

📁 linux下网络收音机的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2003, 2004 Jean-Yves Lefort * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include <string.h>#include <stdlib.h>#include <glib/gi18n.h>#include <libxml/parser.h>#include "streamtuner.h"/*** cpp *********************************************************************/#define XIPH_HOME		"http://dir.xiph.org/"#define XIPH_XML		"http://dir.xiph.org/yp.xml"#define PARSER_STATE_IS_IN_DIRECTORY(state) \  ((state)->tags && ! (state)->tags->next && ! strcmp((state)->tags->data, "directory"))#define PARSE_ERROR		st_handler_notice(xiph_handler, _("parse error at %s"), G_STRLOC)/*** types *******************************************************************/typedef struct{  STStream	stream;    char		*server_name;  char		*listen_url;  char		*server_type;  char		*bitrate;  int		channels;  int		samplerate;  char		*genre;  char		*current_song;} XiphStream;enum {  FIELD_SERVER_NAME,  FIELD_LISTEN_URL,  FIELD_SERVER_TYPE,  FIELD_BITRATE,  FIELD_CHANNELS,  FIELD_SAMPLERATE,  FIELD_GENRE,  FIELD_CURRENT_SONG,  FIELD_AUDIO		/* meta field (bitrate, channels and samplerate) */};enum {  TAG_ROOT,  TAG_DIRECTORY,  TAG_ENTRY,  TAG_SERVER_NAME,  TAG_LISTEN_URL,  TAG_SERVER_TYPE,  TAG_BITRATE,  TAG_CHANNELS,  TAG_SAMPLERATE,  TAG_GENRE,  TAG_CURRENT_SONG,  TAG_UNSUPPORTED};typedef struct{  GSList		*tags;  GHashTable		*stream_properties;  GList			*streams;  char			*error;} ParserState;  /*** variables ***************************************************************/static STPlugin *xiph_plugin = NULL;static STHandler *xiph_handler = NULL;static struct{  char		*name;  char		*label;  char		*re;  regex_t	compiled_re;} stock_genres[] = {  { "__alternative",	N_("Alternative"),	"alternative|indie|goth|college|industrial|punk|hardcore|ska" },  { "__classical",	N_("Classical"),	"classical|opera|symphonic" },  { "__country",	N_("Country"),		"country|swing" },  { "__electronic",	N_("Electronic"),	"electronic|ambient|drum.*bass|trance|techno|house|downtempo|breakbeat|jungle|garage" },  { "__rap",		N_("Hip-Hop/Rap"),	"hip ?hop|rap|turntabl|old school|new school" },  { "__jazz",		N_("Jazz"),		"jazz|swing|big ?band" },  { "__oldies",		N_("Oldies"),		"oldies|disco|50s|60s|70s|80s|90s" },  { "__rock",		N_("Pop/Rock"),		"pop|rock|top ?40|metal" },  { "__soul",		N_("R&B/Soul"),		"r ?(&|'? ?n ?'?) ?b|funk|soul|urban" },  { "__spiritual",	N_("Spiritual"),	"spiritual|gospel|christian|muslim|jewish|religio" },  { "__spoken",		N_("Spoken"),		"spoken|talk|comedy" },  { "__world",		N_("World"),		"world|reggae|island|african|european|middle ?east|asia" },  { "__other",		N_("Other"),		"various|mixed|misc|eclectic|film|show|instrumental" },  { NULL }};static char *search_token = NULL;/*** functions ***************************************************************/static XiphStream *stream_new_cb (gpointer data);static void stream_field_get_cb (XiphStream *stream,				 STHandlerField *field,				 GValue *value,				 gpointer data);static void stream_field_set_cb (XiphStream *stream,				 STHandlerField *field,				 const GValue *value,				 gpointer data);static void stream_stock_field_get_cb (XiphStream *stream,				       STHandlerStockField stock_field,				       GValue *value,				       gpointer data);static void stream_free_cb (XiphStream *stream, gpointer data);static XiphStream *stream_copy (XiphStream *stream);static char *stream_get_audio (XiphStream *stream);static gboolean stream_tune_in_cb (XiphStream *stream,				   gpointer data,				   GError **err);static gboolean stream_record_cb (XiphStream *stream,				  gpointer data,				  GError **err);static GList *streams_match_genre (GList *streams, regex_t *regexp);static GList *streams_match_any (GList *streams, const char *token);static gboolean utf8_strcasecontains (const char *big, const char *little);static gboolean reload_streams (GList **streams, GError **err);static char *parser_state_get_stream_property_string (ParserState *state,						      const char *name);static int parser_state_get_stream_property_int (ParserState *state,						 const char *name);static xmlEntityPtr reload_streams_get_entity_cb (gpointer user_data,						  const xmlChar *name);static void reload_streams_start_element_cb (gpointer user_data,					     const xmlChar *name,					     const xmlChar **atts);static void reload_streams_end_element_cb (gpointer user_data,					   const xmlChar *name);static void reload_streams_characters_cb (gpointer user_data,					  const xmlChar *ch, int len);static void reload_streams_warning_cb (gpointer user_data,				       const char *format,				       ...) G_GNUC_PRINTF(2, 3);static void reload_streams_error_cb (gpointer user_data,				     const char *format,				     ...) G_GNUC_PRINTF(2, 3);static gboolean search_url_cb (STCategory *category);static gboolean check_api_version (GError **err);static void init_handler (void);/*** implementation **********************************************************/static XiphStream *stream_new_cb (gpointer data){  return g_new0(XiphStream, 1);}static voidstream_field_get_cb (XiphStream *stream,		     STHandlerField *field,		     GValue *value,		     gpointer data){  switch (field->id)    {    case FIELD_SERVER_NAME:      g_value_set_string(value, stream->server_name);      break;          case FIELD_LISTEN_URL:      g_value_set_string(value, stream->listen_url);      break;    case FIELD_SERVER_TYPE:      g_value_set_string(value, stream->server_type);      break;    case FIELD_BITRATE:      g_value_set_string(value, stream->bitrate);      break;    case FIELD_CHANNELS:      g_value_set_int(value, stream->channels);      break;    case FIELD_SAMPLERATE:      g_value_set_int(value, stream->samplerate);      break;    case FIELD_GENRE:      g_value_set_string(value, stream->genre);      break;    case FIELD_CURRENT_SONG:      g_value_set_string(value, stream->current_song);      break;    case FIELD_AUDIO:      g_value_take_string(value, stream_get_audio(stream));      break;    default:      g_assert_not_reached();    }}static voidstream_field_set_cb (XiphStream *stream,		     STHandlerField *field,		     const GValue *value,		     gpointer data){  switch (field->id)    {    case FIELD_SERVER_NAME:      stream->server_name = g_value_dup_string(value);      break;    case FIELD_LISTEN_URL:      stream->listen_url = g_value_dup_string(value);      break;    case FIELD_SERVER_TYPE:      stream->server_type = g_value_dup_string(value);      break;    case FIELD_BITRATE:      stream->bitrate = g_value_dup_string(value);      break;    case FIELD_CHANNELS:      stream->channels = g_value_get_int(value);      break;    case FIELD_SAMPLERATE:      stream->samplerate = g_value_get_int(value);      break;    case FIELD_GENRE:      stream->genre = g_value_dup_string(value);      break;    case FIELD_CURRENT_SONG:      stream->current_song = g_value_dup_string(value);      break;    default:      g_assert_not_reached();    }}static voidstream_stock_field_get_cb (XiphStream *stream,			   STHandlerStockField stock_field,			   GValue *value,			   gpointer data){  switch (stock_field)    {    case ST_HANDLER_STOCK_FIELD_NAME:      g_value_set_string(value, stream->server_name);      break;    case ST_HANDLER_STOCK_FIELD_GENRE:      g_value_set_string(value, stream->genre);      break;    case ST_HANDLER_STOCK_FIELD_DESCRIPTION:    case ST_HANDLER_STOCK_FIELD_HOMEPAGE:      /* nop */      break;    case ST_HANDLER_STOCK_FIELD_URI_LIST:      {	GValueArray *value_array;	GValue uri_value = { 0, };	value_array = g_value_array_new(1);	g_value_init(&uri_value, G_TYPE_STRING);	g_value_set_string(&uri_value, stream->listen_url);	g_value_array_append(value_array, &uri_value);	g_value_unset(&uri_value);	g_value_take_boxed(value, value_array);	break;      }    }}static voidstream_free_cb (XiphStream *stream, gpointer data){  g_free(stream->server_name);  g_free(stream->listen_url);  g_free(stream->server_type);  g_free(stream->bitrate);  g_free(stream->genre);  g_free(stream->current_song);  st_stream_free((STStream *) stream);}static XiphStream *stream_copy (XiphStream *stream){  XiphStream *copy;  copy = stream_new_cb(NULL);  ((STStream *) copy)->name = g_strdup(((STStream *) stream)->name);  copy->server_name = g_strdup(stream->server_name);  copy->listen_url = g_strdup(stream->listen_url);  copy->server_type = g_strdup(stream->server_type);  copy->bitrate = g_strdup(stream->bitrate);  copy->channels = stream->channels;  copy->samplerate = stream->samplerate;  copy->genre = g_strdup(stream->genre);  copy->current_song = g_strdup(stream->current_song);  return copy;}static char *stream_get_audio (XiphStream *stream){  GString *audio;  char *str;  g_return_val_if_fail(stream != NULL, NULL);  audio = g_string_new(NULL);  if (stream->bitrate)    {      if (g_str_has_prefix(stream->bitrate, "Quality"))	g_string_append(audio, stream->bitrate);      else if (st_str_like(stream->bitrate, ST_NUMERIC))	{	  int bitrate = atoi(stream->bitrate);	  if (bitrate > 0 && bitrate < 1000000) /* avoid bogus bitrates */	    {	      /*	       * Some bitrates are given in bps. To properly convert	       * bps to kbps, we consider that if the bitrate is	       * superior to 1000, the unit is bps.	       *	       * Also, bitrates such as "16000" probably mean	       * "16kbps", so we use a kilo of 1000, not 1024.	       */	      if (bitrate > 1000)		bitrate /= 1000;	      str = st_format_bitrate(bitrate);	      g_string_append(audio, str);	      g_free(str);	    }	}    }  if (stream->samplerate > 0)    {      if (*audio->str)	g_string_append(audio, ", ");      str = st_format_samplerate(stream->samplerate);      g_string_append(audio, str);      g_free(str);    }  if (stream->channels > 0)    {      if (*audio->str)	g_string_append(audio, ", ");      str = st_format_channels(stream->channels);      g_string_append(audio, str);      g_free(str);    }    if (*audio->str)    return g_string_free(audio, FALSE);  else    {      g_string_free(audio, TRUE);      return NULL;    }}static gbooleanstream_tune_in_cb (XiphStream *stream,		   gpointer data,		   GError **err){  return st_action_run("play-stream", stream->listen_url, err);}static gbooleanstream_record_cb (XiphStream *stream,		  gpointer data,		  GError **err){  return st_action_run("record-stream", stream->listen_url, err);}static GList *streams_match_genre (GList *streams, regex_t *regexp){  GList *matching = NULL;  GList *l;  for (l = streams; l; l = l->next)    {      XiphStream *stream = l->data;      if (st_re_match(regexp, stream->genre))	matching = g_list_append(matching, stream_copy(stream));    }  return matching;}static GList *streams_match_any (GList *streams, const char *token){  GList *matching = NULL;  GList *l;  for (l = streams; l; l = l->next)    {      XiphStream *stream = l->data;      if (utf8_strcasecontains(stream->server_name, token)	  || utf8_strcasecontains(stream->listen_url, token)	  || utf8_strcasecontains(stream->server_type, token)	  || utf8_strcasecontains(stream->genre, token)	  || utf8_strcasecontains(stream->current_song, token))	matching = g_list_append(matching, stream_copy(stream));    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -