00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <glib.h>
00023
00024 #include "xmmspriv/xmms_xform.h"
00025 #include "xmms/xmms_log.h"
00026 #include "xmms/xmms_object.h"
00027
00028
00029 struct xmms_stream_type_St {
00030 xmms_object_t obj;
00031 gint priority;
00032 gchar *name;
00033 GList *list;
00034 };
00035
00036 typedef enum xmms_stream_type_val_type_E {
00037 STRING,
00038 INT,
00039 } xmms_stream_type_val_type_t;
00040
00041 typedef struct xmms_stream_type_val_St {
00042 xmms_stream_type_key_t key;
00043 xmms_stream_type_val_type_t type;
00044 union {
00045 char *string;
00046 int num;
00047 } d;
00048 } xmms_stream_type_val_t;
00049
00050
00051 static void
00052 xmms_stream_type_destroy (xmms_object_t *obj)
00053 {
00054 xmms_stream_type_t *st = (xmms_stream_type_t *)obj;
00055 GList *n;
00056
00057 g_free (st->name);
00058
00059 for (n = st->list; n; n = g_list_next (n)) {
00060 xmms_stream_type_val_t *val = n->data;
00061 if (val->type == STRING) {
00062 g_free (val->d.string);
00063 }
00064 g_free (val);
00065 }
00066
00067 g_list_free (st->list);
00068 }
00069
00070 xmms_stream_type_t *
00071 xmms_stream_type_parse (va_list ap)
00072 {
00073 xmms_stream_type_t *res;
00074
00075 res = xmms_object_new (xmms_stream_type_t, xmms_stream_type_destroy);
00076 if (!res) {
00077 return NULL;
00078 }
00079
00080 res->priority = -1;
00081 res->name = NULL;
00082
00083 for (;;) {
00084 xmms_stream_type_val_t *val;
00085 xmms_stream_type_key_t key;
00086
00087 key = va_arg (ap, int);
00088 if (key == XMMS_STREAM_TYPE_END)
00089 break;
00090
00091 if (key == XMMS_STREAM_TYPE_NAME) {
00092 res->name = g_strdup (va_arg (ap, char *));
00093 continue;
00094 }
00095
00096 if (key == XMMS_STREAM_TYPE_PRIORITY) {
00097 res->priority = va_arg (ap, int);
00098 continue;
00099 }
00100
00101 val = g_new0 (xmms_stream_type_val_t, 1);
00102 val->key = key;
00103
00104 switch (val->key) {
00105 case XMMS_STREAM_TYPE_MIMETYPE:
00106 case XMMS_STREAM_TYPE_URL:
00107 val->type = STRING;
00108 val->d.string = g_strdup (va_arg (ap, char *));
00109 break;
00110 case XMMS_STREAM_TYPE_FMT_FORMAT:
00111 case XMMS_STREAM_TYPE_FMT_CHANNELS:
00112 case XMMS_STREAM_TYPE_FMT_SAMPLERATE:
00113 val->type = INT;
00114 val->d.num = va_arg (ap, int);
00115 break;
00116 default:
00117 XMMS_DBG ("UNKNOWN TYPE!!");
00118 g_free (val);
00119 xmms_object_unref (res);
00120 return NULL;
00121 }
00122 res->list = g_list_append (res->list, val);
00123 }
00124
00125 if (!res->name) {
00126 const gchar *mime = xmms_stream_type_get_str (res, XMMS_STREAM_TYPE_MIMETYPE);
00127 const gchar *url = xmms_stream_type_get_str (res, XMMS_STREAM_TYPE_URL);
00128
00129 if (mime && url) {
00130 res->name = g_strconcat (mime, ":", url, NULL);
00131 } else if (mime) {
00132 res->name = g_strdup (mime);
00133 } else {
00134 g_assert_not_reached ();
00135 }
00136
00137 g_strdelimit (res->name, ".", '_');
00138 }
00139
00140 if (res->priority < 0) {
00141 res->priority = XMMS_STREAM_TYPE_PRIORITY_DEFAULT;
00142 }
00143
00144 return res;
00145 }
00146
00147 const char *
00148 xmms_stream_type_get_str (const xmms_stream_type_t *st, xmms_stream_type_key_t key)
00149 {
00150 GList *n;
00151
00152 if (key == XMMS_STREAM_TYPE_NAME) {
00153 return st->name;
00154 }
00155
00156 for (n = st->list; n; n = g_list_next (n)) {
00157 xmms_stream_type_val_t *val = n->data;
00158 if (val->key == key) {
00159 if (val->type != STRING) {
00160 XMMS_DBG ("Key passed to get_str is not string");
00161 return NULL;
00162 }
00163 return val->d.string;
00164 }
00165 }
00166 return NULL;
00167 }
00168
00169
00170 gint
00171 xmms_stream_type_get_int (const xmms_stream_type_t *st, xmms_stream_type_key_t key)
00172 {
00173 GList *n;
00174
00175 if (key == XMMS_STREAM_TYPE_PRIORITY) {
00176 return st->priority;
00177 }
00178
00179 for (n = st->list; n; n = g_list_next (n)) {
00180 xmms_stream_type_val_t *val = n->data;
00181 if (val->key == key) {
00182 if (val->type != INT) {
00183 XMMS_DBG ("Key passed to get_int is not int");
00184 return -1;
00185 }
00186 return val->d.num;
00187 }
00188 }
00189 return -1;
00190 }
00191
00192
00193
00194
00195 static gboolean
00196 match_val (xmms_stream_type_val_t *vin, xmms_stream_type_val_t *vout)
00197 {
00198 if (vin->type != vout->type)
00199 return FALSE;
00200 switch (vin->type) {
00201 case STRING:
00202 return g_pattern_match_simple (vin->d.string, vout->d.string);
00203 case INT:
00204 return vin->d.num == vout->d.num;
00205 }
00206 return FALSE;
00207 }
00208
00209 gboolean
00210 xmms_stream_type_match (const xmms_stream_type_t *in_type, const xmms_stream_type_t *out_type)
00211 {
00212 GList *in;
00213
00214 for (in = in_type->list; in; in = g_list_next (in)) {
00215 xmms_stream_type_val_t *inval = in->data;
00216 GList *n;
00217
00218 for (n = out_type->list; n; n = g_list_next (n)) {
00219 xmms_stream_type_val_t *outval = n->data;
00220 if (inval->key == outval->key) {
00221 if (!match_val (inval, outval))
00222 return FALSE;
00223 break;
00224 }
00225
00226 }
00227 if (!n) {
00228
00229 return FALSE;
00230 }
00231 }
00232
00233 return TRUE;
00234 }
00235
00236
00237
00238
00239 xmms_stream_type_t *
00240 xmms_stream_type_coerce (const xmms_stream_type_t *in, const GList *goal_types)
00241 {
00242 xmms_stream_type_t *best = NULL;
00243 const GList *on;
00244
00245 gint bestscore = 100000;
00246 gint format, samplerate, channels;
00247 gint gformat, gsamplerate, gchannels;
00248 const gchar *gmime;
00249
00250 format = xmms_stream_type_get_int (in, XMMS_STREAM_TYPE_FMT_FORMAT);
00251 samplerate = xmms_stream_type_get_int (in, XMMS_STREAM_TYPE_FMT_SAMPLERATE);
00252 channels = xmms_stream_type_get_int (in, XMMS_STREAM_TYPE_FMT_CHANNELS);
00253
00254 if (format == -1 || samplerate == -1 || channels == -1) {
00255 xmms_log_info ("In-type lacks format, samplerate or channels");
00256 return NULL;
00257 }
00258
00259 for (on = goal_types ; on; on = g_list_next (on)) {
00260 xmms_stream_type_t *goal = on->data;
00261 const gchar *mime;
00262 gint score = 0;
00263
00264 mime = xmms_stream_type_get_str (goal, XMMS_STREAM_TYPE_MIMETYPE);
00265 if (strcmp (mime, "audio/pcm") != 0) {
00266 continue;
00267 }
00268
00269 gformat = xmms_stream_type_get_int (goal, XMMS_STREAM_TYPE_FMT_FORMAT);
00270 gsamplerate = xmms_stream_type_get_int (goal, XMMS_STREAM_TYPE_FMT_SAMPLERATE);
00271 gchannels = xmms_stream_type_get_int (goal, XMMS_STREAM_TYPE_FMT_CHANNELS);
00272 if (gsamplerate == -1) {
00273 gsamplerate = samplerate;
00274 }
00275 if (gformat == -1 || gchannels == -1) {
00276 continue;
00277 }
00278
00279
00280 if (gchannels > channels) {
00281
00282 score += gchannels - channels;
00283 } else if (gchannels < channels) {
00284
00285 score += 10 * (channels - gchannels);
00286 }
00287
00288
00289
00290 if (gformat > format) {
00291
00292 score += gformat - format;
00293 } else if (gformat < format) {
00294
00295 score += 10 * (format - gformat);
00296 }
00297
00298
00299 if (gsamplerate > samplerate) {
00300
00301 score += 2 * gsamplerate / samplerate;
00302 } else if (gsamplerate < samplerate) {
00303
00304 score += 20 * samplerate / gsamplerate;
00305 }
00306
00307 if (score < bestscore) {
00308 best = goal;
00309 bestscore = score;
00310 }
00311
00312 }
00313
00314 if (!best) {
00315 xmms_log_error ("Couldn't convert sample format to any of the %d goal formats",
00316 g_list_length ((GList *)goal_types));
00317 return NULL;
00318 }
00319
00320 gmime = xmms_stream_type_get_str (best, XMMS_STREAM_TYPE_MIMETYPE);
00321 gformat = xmms_stream_type_get_int (best, XMMS_STREAM_TYPE_FMT_FORMAT);
00322 gchannels = xmms_stream_type_get_int (best, XMMS_STREAM_TYPE_FMT_CHANNELS);
00323 gsamplerate = xmms_stream_type_get_int (best, XMMS_STREAM_TYPE_FMT_SAMPLERATE);
00324
00325
00326 if (gsamplerate == -1) {
00327 gsamplerate = samplerate;
00328 }
00329
00330 best = _xmms_stream_type_new ("dummy",
00331 XMMS_STREAM_TYPE_MIMETYPE, gmime,
00332 XMMS_STREAM_TYPE_FMT_FORMAT, gformat,
00333 XMMS_STREAM_TYPE_FMT_CHANNELS, gchannels,
00334 XMMS_STREAM_TYPE_FMT_SAMPLERATE, gsamplerate,
00335 XMMS_STREAM_TYPE_END);
00336
00337 return best;
00338 }
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361 xmms_stream_type_t *
00362 _xmms_stream_type_new (void *dumb, ...)
00363 {
00364 xmms_stream_type_t *res;
00365 va_list ap;
00366
00367 va_start (ap, dumb);
00368 res = xmms_stream_type_parse (ap);
00369 va_end (ap);
00370
00371 return res;
00372 }