6474
|
1 /*
|
|
2 * CDDB HTTP protocol
|
|
3 * by Bertrand Baudet <bertrand_baudet@yahoo.com>
|
|
4 * (C) 2002, MPlayer team.
|
|
5 *
|
|
6 * Implementation follow the freedb.howto1.06.txt specification
|
|
7 * from http://freedb.freedb.org
|
|
8 *
|
|
9 * discid computation by Jeremy D. Zawodny
|
|
10 * Copyright (c) 1998-2000 Jeremy D. Zawodny <Jeremy@Zawodny.com>
|
|
11 * Code release under GPL
|
|
12 *
|
|
13 * TODO:
|
|
14 * * do a xmcd parser
|
|
15 */
|
|
16
|
|
17 #include "config.h"
|
|
18
|
|
19 #if defined(HAVE_CDDA) && defined(STREAMING)
|
|
20
|
|
21 #include <stdio.h>
|
|
22 #include <stdlib.h>
|
|
23 #include <fcntl.h>
|
|
24 #include <stdarg.h>
|
|
25 #include <errno.h>
|
|
26 #include <netdb.h>
|
|
27 #include <unistd.h>
|
|
28 #include <string.h>
|
|
29 #include <sys/ioctl.h>
|
|
30 #include <sys/types.h>
|
|
31 #include <sys/stat.h>
|
|
32
|
|
33 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__)
|
|
34 #define SYS_BSD 1
|
|
35 #endif
|
|
36
|
|
37 #if defined(__linux__)
|
|
38 #include <linux/cdrom.h>
|
|
39 #elif defined(SYS_BSD)
|
|
40 #include <sys/cdio.h>
|
|
41 #endif
|
|
42
|
|
43 #include "../version.h"
|
|
44 #include "stream.h"
|
|
45 #include "network.h"
|
|
46
|
|
47 #define DEFAULT_FREEDB_SERVER "freedb.freedb.org"
|
|
48 #define DEFAULT_CACHE_DIR "/.cddb/"
|
|
49
|
|
50 stream_t* open_cdda(char *dev, char *track);
|
|
51
|
|
52 typedef struct {
|
|
53 char cddb_hello[1024];
|
|
54 unsigned long disc_id;
|
|
55 unsigned int tracks;
|
|
56 char *cache_dir;
|
|
57 char *freedb_server;
|
|
58 int freedb_proto_level;
|
|
59 char category[100];
|
|
60 char *xmcd_file;
|
|
61 size_t xmcd_file_size;
|
|
62 void *user_data;
|
|
63 } cddb_data_t;
|
|
64
|
|
65
|
|
66 struct toc {
|
|
67 int min, sec, frame;
|
|
68 } cdtoc[100];
|
|
69
|
|
70 #if defined(__linux__)
|
|
71 int
|
|
72 read_toc(void) {
|
|
73 int drive = open("/dev/cdrom", O_RDONLY | O_NONBLOCK);
|
|
74 struct cdrom_tochdr tochdr;
|
|
75 struct cdrom_tocentry tocentry;
|
|
76 int i;
|
|
77
|
|
78 ioctl(drive, CDROMREADTOCHDR, &tochdr);
|
|
79 for (i = tochdr.cdth_trk0; i <= tochdr.cdth_trk1; i++) {
|
|
80 tocentry.cdte_track = i;
|
|
81 tocentry.cdte_format = CDROM_MSF;
|
|
82 ioctl(drive, CDROMREADTOCENTRY, &tocentry);
|
|
83 cdtoc[i-1].min = tocentry.cdte_addr.msf.minute;
|
|
84 cdtoc[i-1].sec = tocentry.cdte_addr.msf.second;
|
|
85 cdtoc[i-1].frame = tocentry.cdte_addr.msf.frame;
|
|
86 cdtoc[i-1].frame += cdtoc[i-1].min*60*75;
|
|
87 cdtoc[i-1].frame += cdtoc[i-1].sec*75;
|
|
88 }
|
|
89 tocentry.cdte_track = 0xAA;
|
|
90 tocentry.cdte_format = CDROM_MSF;
|
|
91 ioctl(drive, CDROMREADTOCENTRY, &tocentry);
|
|
92 cdtoc[tochdr.cdth_trk1].min = tocentry.cdte_addr.msf.minute;
|
|
93 cdtoc[tochdr.cdth_trk1].sec = tocentry.cdte_addr.msf.second;
|
|
94 cdtoc[tochdr.cdth_trk1].frame = tocentry.cdte_addr.msf.frame;
|
|
95 cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].min*60*75;
|
|
96 cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].sec*75;
|
|
97 close(drive);
|
|
98 return tochdr.cdth_trk1;
|
|
99 }
|
|
100
|
|
101 #elif defined(SYS_BSD)
|
|
102 int
|
|
103 read_toc(void) {
|
|
104 int drive = open("/dev/acd0c", O_RDONLY | O_NONBLOCK);
|
|
105 struct ioc_toc_header tochdr;
|
|
106 struct ioc_read_toc_single_entry tocentry;
|
|
107 int i;
|
|
108
|
|
109 ioctl(drive, CDIOREADTOCHEADER, &tochdr);
|
|
110 for (i = tochdr.starting_track; i <= tochdr.ending_track; i++) {
|
|
111 tocentry.track = i;
|
|
112 tocentry.address_format = CD_MSF_FORMAT;
|
|
113 ioctl(drive, CDIOREADTOCENTRY, &tocentry);
|
|
114 cdtoc[i-1].min = tocentry.entry.addr.msf.minute;
|
|
115 cdtoc[i-1].sec = tocentry.entry.addr.msf.second;
|
|
116 cdtoc[i-1].frame = tocentry.entry.addr.msf.frame;
|
|
117 cdtoc[i-1].frame += cdtoc[i-1].min*60*75;
|
|
118 cdtoc[i-1].frame += cdtoc[i-1].sec*75;
|
|
119 }
|
|
120 tocentry.track = 0xAA;
|
|
121 tocentry.address_format = CD_MSF_FORMAT;
|
|
122 ioctl(drive, CDIOREADTOCENTRY, &tocentry);
|
|
123 cdtoc[tochdr.ending_track].min = tocentry.entry.addr.msf.minute;
|
|
124 cdtoc[tochdr.ending_track].sec = tocentry.entry.addr.msf.second;
|
|
125 cdtoc[tochdr.ending_track].frame = tocentry.entry.addr.msf.frame;
|
|
126 cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].min*60*75;
|
|
127 cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].sec*75;
|
|
128 close(drive);
|
|
129 return tochdr.ending_track;
|
|
130 }
|
|
131 #endif
|
|
132
|
|
133 unsigned int
|
|
134 cddb_sum(int n) {
|
|
135 unsigned int ret;
|
|
136
|
|
137 ret = 0;
|
|
138 while (n > 0) {
|
|
139 ret += (n % 10);
|
|
140 n /= 10;
|
|
141 }
|
|
142 return ret;
|
|
143 }
|
|
144
|
|
145 unsigned long
|
|
146 cddb_discid(int tot_trks) {
|
|
147 unsigned int i, t = 0, n = 0;
|
|
148
|
|
149 i = 0;
|
|
150 while (i < tot_trks) {
|
|
151 n = n + cddb_sum((cdtoc[i].min * 60) + cdtoc[i].sec);
|
|
152 i++;
|
|
153 }
|
|
154 t = ((cdtoc[tot_trks].min * 60) + cdtoc[tot_trks].sec) -
|
|
155 ((cdtoc[0].min * 60) + cdtoc[0].sec);
|
|
156 return ((n % 0xff) << 24 | t << 8 | tot_trks);
|
|
157 }
|
|
158
|
|
159
|
|
160
|
|
161 int
|
|
162 cddb_http_request(char *command, int (*reply_parser)(HTTP_header_t*,cddb_data_t*), cddb_data_t *cddb_data) {
|
|
163 char request[4096];
|
|
164 int fd, ret = 0;
|
|
165 URL_t *url;
|
|
166 HTTP_header_t *http_hdr;
|
|
167
|
|
168 if( reply_parser==NULL || command==NULL || cddb_data==NULL ) return -1;
|
|
169
|
|
170 sprintf( request, "http://%s/~cddb/cddb.cgi?cmd=%s%s&proto=%d", cddb_data->freedb_server, command, cddb_data->cddb_hello, cddb_data->freedb_proto_level );
|
|
171 printf("Request[%s]\n", request );
|
|
172
|
|
173 url = url_new(request);
|
|
174 if( url==NULL ) {
|
|
175 printf("Not a valid URL\n");
|
|
176 return -1;
|
|
177 }
|
|
178
|
|
179 fd = http_send_request(url);
|
|
180 if( fd<0 ) {
|
|
181 printf("failed to send the http request\n");
|
|
182 return -1;
|
|
183 }
|
|
184
|
|
185 http_hdr = http_read_response( fd );
|
|
186 if( http_hdr==NULL ) {
|
|
187 printf("Failed to read the http response\n");
|
|
188 return -1;
|
|
189 }
|
|
190
|
|
191 http_debug_hdr(http_hdr);
|
|
192 printf("body=[%s]\n", http_hdr->body );
|
|
193
|
|
194 switch(http_hdr->status_code) {
|
|
195 case 200:
|
|
196 ret = reply_parser(http_hdr, cddb_data);
|
|
197 break;
|
|
198 case 400:
|
|
199 printf("Not Found\n");
|
|
200 break;
|
|
201 default:
|
|
202 printf("Unknown Error code\n");
|
|
203 }
|
|
204
|
|
205 http_free( http_hdr );
|
|
206 url_free( url );
|
|
207
|
|
208 return ret;
|
|
209 }
|
|
210
|
|
211 int
|
|
212 cddb_read_cache(cddb_data_t *cddb_data) {
|
|
213 char file_name[100];
|
|
214 struct stat stats;
|
|
215 int file_fd, ret;
|
|
216 size_t file_size;
|
|
217
|
|
218 if( cddb_data==NULL || cddb_data->cache_dir==NULL ) return -1;
|
|
219
|
|
220 sprintf( file_name, "%s%08lx", cddb_data->cache_dir, cddb_data->disc_id);
|
|
221
|
|
222 file_fd = open(file_name, O_RDONLY);
|
|
223 if( file_fd<0 ) {
|
|
224 printf("No cache found\n");
|
|
225 return -1;
|
|
226 }
|
|
227
|
|
228 ret = fstat( file_fd, &stats );
|
|
229 if( ret<0 ) {
|
|
230 perror("fstat");
|
|
231 file_size = 4096;
|
|
232 } else {
|
|
233 file_size = stats.st_size;
|
|
234 }
|
|
235
|
|
236 cddb_data->xmcd_file = (char*)malloc(file_size);
|
|
237 if( cddb_data->xmcd_file==NULL ) {
|
|
238 printf("Memory allocation failed\n");
|
|
239 close(file_fd);
|
|
240 return -1;
|
|
241 }
|
|
242 cddb_data->xmcd_file_size = read(file_fd, cddb_data->xmcd_file, file_size);
|
|
243 if( cddb_data->xmcd_file_size!=file_size ) {
|
|
244 printf("Not all the xmcd file has been read\n");
|
|
245 close(file_fd);
|
|
246 return -1;
|
|
247 }
|
|
248
|
|
249 close(file_fd);
|
|
250
|
|
251 return 0;
|
|
252 }
|
|
253
|
|
254 int
|
|
255 cddb_write_cache(cddb_data_t *cddb_data) {
|
|
256 // We have the file, save it for cache.
|
|
257 char file_name[100];
|
|
258 int file_fd;
|
|
259 size_t wrote=0;
|
|
260
|
|
261 if( cddb_data==NULL || cddb_data->cache_dir==NULL ) return -1;
|
|
262
|
|
263 sprintf( file_name, "%s%08lx", cddb_data->cache_dir, cddb_data->disc_id);
|
|
264
|
|
265 file_fd = creat(file_name, S_IREAD|S_IWRITE);
|
|
266 if( file_fd<0 ) {
|
|
267 perror("open");
|
|
268 return -1;
|
|
269 }
|
|
270
|
|
271 wrote = write(file_fd, cddb_data->xmcd_file, cddb_data->xmcd_file_size);
|
|
272 if( wrote<0 ) {
|
|
273 perror("write");
|
|
274 close(file_fd);
|
|
275 return -1;
|
|
276 }
|
|
277 if( wrote!=cddb_data->xmcd_file_size ) {
|
|
278 printf("Not all the xmcd file has been written\n");
|
|
279 close(file_fd);
|
|
280 return -1;
|
|
281 }
|
|
282
|
|
283 close(file_fd);
|
|
284
|
|
285 return 0;
|
|
286 }
|
|
287
|
|
288 int
|
|
289 cddb_read_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
|
|
290 unsigned long disc_id;
|
|
291 char category[100];
|
|
292 char *ptr=NULL, *ptr2=NULL;
|
|
293 int ret, status;
|
|
294
|
|
295 if( http_hdr==NULL || cddb_data==NULL ) return -1;
|
|
296
|
|
297 ret = sscanf( http_hdr->body, "%d ", &status);
|
|
298 if( ret!=1 ) {
|
|
299 printf("Parse error\n");
|
|
300 return -1;
|
|
301 }
|
|
302
|
|
303 switch(status) {
|
|
304 case 210:
|
|
305 ret = sscanf( http_hdr->body, "%d %s %08lx", &status, category, &disc_id);
|
|
306 if( ret!=3 ) {
|
|
307 printf("Parse error\n");
|
|
308 return -1;
|
|
309 }
|
|
310 // Check if it's a xmcd database file
|
|
311 ptr = strstr(http_hdr->body, "# xmcd");
|
|
312 if( ptr==NULL ) {
|
|
313 printf("Invalid xmcd database file returned\n");
|
|
314 return -1;
|
|
315 }
|
|
316 // Ok found the beginning of the file
|
|
317 // look for the end
|
|
318 ptr2 = strstr(ptr, "\r\n.\r\n");
|
|
319 if( ptr2==NULL ) {
|
|
320 ptr2 = strstr(ptr, "\n.\n");
|
|
321 if( ptr2==NULL ) {
|
|
322 printf("Unable to find '.'\n");
|
|
323 return -1;
|
|
324 }
|
|
325 }
|
|
326 // Ok found the end
|
|
327 // do a sanity check
|
|
328 if( http_hdr->body_size<(ptr2-ptr) ) {
|
|
329 printf("Unexpected fix me\n");
|
|
330 return -1;
|
|
331 }
|
|
332 cddb_data->xmcd_file = ptr;
|
|
333 cddb_data->xmcd_file_size = ptr2-ptr+2;
|
|
334 cddb_data->xmcd_file[cddb_data->xmcd_file_size] = '\0';
|
|
335 // Avoid the http_free function to free the xmcd file...save a mempcy...
|
|
336 http_hdr->body = NULL;
|
|
337 http_hdr->body_size = 0;
|
|
338 return cddb_write_cache(cddb_data);
|
|
339 default:
|
|
340 printf("Unhandled code\n");
|
|
341 }
|
|
342 return 0;
|
|
343 }
|
|
344
|
|
345 int
|
|
346 cddb_request_titles(cddb_data_t *cddb_data) {
|
|
347 char command[1024];
|
|
348 sprintf( command, "cddb+read+%s+%08lx", cddb_data->category, cddb_data->disc_id);
|
|
349 return cddb_http_request(command, cddb_read_parse, cddb_data);
|
|
350 }
|
|
351
|
|
352 int
|
|
353 cddb_query_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
|
|
354 char album_title[100];
|
|
355 char *ptr = NULL;
|
|
356 int ret, status;
|
|
357
|
|
358 ret = sscanf( http_hdr->body, "%d ", &status);
|
|
359 if( ret!=1 ) {
|
|
360 printf("Parse error\n");
|
|
361 return -1;
|
|
362 }
|
|
363
|
|
364 switch(status) {
|
|
365 case 200:
|
|
366 // Found exact match
|
|
367 ret = sscanf(http_hdr->body, "%d %s %08lx %s", &status, cddb_data->category, &(cddb_data->disc_id), album_title);
|
|
368 if( ret!=4 ) {
|
|
369 printf("Parse error\n");
|
|
370 return -1;
|
|
371 }
|
|
372 ptr = strstr(http_hdr->body, album_title);
|
|
373 if( ptr!=NULL ) {
|
|
374 char *ptr2;
|
|
375 int len;
|
|
376 ptr2 = strstr(ptr, "\n");
|
|
377 if( ptr2==NULL ) {
|
|
378 len = (http_hdr->body_size)-(ptr-(http_hdr->body));
|
|
379 } else {
|
|
380 len = ptr2-ptr+1;
|
|
381 }
|
|
382 strncpy(album_title, ptr, len);
|
|
383 album_title[len-2]='\0';
|
|
384 }
|
|
385 printf("Parse OK, found: %s\n", album_title);
|
|
386 return cddb_request_titles(cddb_data);
|
|
387 case 202:
|
|
388 // No match found
|
|
389 printf("Album not found\n");
|
|
390 break;
|
|
391 case 210:
|
|
392 // Found exact matches, list follows
|
|
393 ptr = strstr(http_hdr->body, "\n");
|
|
394 if( ptr==NULL ) {
|
|
395 printf("Unable to find end of line\n");
|
|
396 return -1;
|
|
397 }
|
|
398 ptr++;
|
|
399 // We have a list of exact matches, so which one do
|
|
400 // we use? So let's take the first one.
|
|
401 ret = sscanf(ptr, "%s %08lx %s", cddb_data->category, &(cddb_data->disc_id), album_title);
|
|
402 if( ret!=3 ) {
|
|
403 printf("Parse error\n");
|
|
404 return -1;
|
|
405 }
|
|
406 ptr = strstr(http_hdr->body, album_title);
|
|
407 if( ptr!=NULL ) {
|
|
408 char *ptr2;
|
|
409 int len;
|
|
410 ptr2 = strstr(ptr, "\n");
|
|
411 if( ptr2==NULL ) {
|
|
412 len = (http_hdr->body_size)-(ptr-(http_hdr->body));
|
|
413 } else {
|
|
414 len = ptr2-ptr+1;
|
|
415 }
|
|
416 strncpy(album_title, ptr, len);
|
|
417 album_title[len-2]='\0';
|
|
418 }
|
|
419 printf("Parse OK, found: %s\n", album_title);
|
|
420 return cddb_request_titles(cddb_data);
|
|
421 /*
|
|
422 body=[210 Found exact matches, list follows (until terminating `.')
|
|
423 misc c711930d Santana / Supernatural
|
|
424 rock c711930d Santana / Supernatural
|
|
425 blues c711930d Santana / Supernatural
|
|
426 .]
|
|
427 */
|
|
428 case 211:
|
|
429 // Found inexact matches, list follows
|
|
430 printf("No exact matches found, list follows\n");
|
|
431 break;
|
|
432 default:
|
|
433 printf("Unhandled code\n");
|
|
434 }
|
|
435 return -1;
|
|
436 }
|
|
437
|
|
438 int
|
|
439 cddb_proto_level_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
|
|
440 int max;
|
|
441 int ret, status;
|
|
442 char *ptr;
|
|
443
|
|
444 ret = sscanf( http_hdr->body, "%d ", &status);
|
|
445 if( ret!=1 ) {
|
|
446 printf("Parse error\n");
|
|
447 return -1;
|
|
448 }
|
|
449
|
|
450 switch(status) {
|
|
451 case 210:
|
|
452 ptr = strstr(http_hdr->body, "max proto:");
|
|
453 if( ptr==NULL ) {
|
|
454 printf("Parse error\n");
|
|
455 return -1;
|
|
456 }
|
|
457 ret = sscanf(ptr, "max proto: %d", &max);
|
|
458 if( ret!=1 ) {
|
|
459 printf("Parse error\n");
|
|
460 return -1;
|
|
461 }
|
|
462 cddb_data->freedb_proto_level = max;
|
|
463 return 0;
|
|
464 default:
|
|
465 printf("Unhandled code\n");
|
|
466 }
|
|
467 return -1;
|
|
468 }
|
|
469
|
|
470 int
|
|
471 cddb_get_proto_level(cddb_data_t *cddb_data) {
|
|
472 return cddb_http_request("stat", cddb_proto_level_parse, cddb_data);
|
|
473 }
|
|
474
|
|
475 int
|
|
476 cddb_freedb_sites_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
|
|
477 int ret, status;
|
|
478
|
|
479 ret = sscanf( http_hdr->body, "%d ", &status);
|
|
480 if( ret!=1 ) {
|
|
481 printf("Parse error\n");
|
|
482 return -1;
|
|
483 }
|
|
484
|
|
485 switch(status) {
|
|
486 case 210:
|
|
487 // Parse the sites
|
|
488 return 0;
|
|
489 case 401:
|
|
490 printf("No sites information available\n");
|
|
491 break;
|
|
492 default:
|
|
493 printf("Unhandled code\n");
|
|
494 }
|
|
495 return -1;
|
|
496 }
|
|
497
|
|
498 int
|
|
499 cddb_get_freedb_sites(cddb_data_t *cddb_data) {
|
|
500 return cddb_http_request("sites", cddb_freedb_sites_parse, cddb_data);
|
|
501 }
|
|
502
|
|
503 void
|
|
504 cddb_create_hello(cddb_data_t *cddb_data) {
|
|
505 char host_name[51];
|
|
506 char *user_name;
|
|
507
|
|
508 if( gethostname(host_name, 50)<0 ) {
|
|
509 strcpy(host_name, "localhost");
|
|
510 }
|
|
511 user_name = getenv("LOGNAME");
|
|
512 sprintf( cddb_data->cddb_hello, "&hello=%s+%s+%s+%s", user_name, host_name, "MPlayer", VERSION );
|
|
513 }
|
|
514
|
|
515 int
|
|
516 cddb_retrieve(cddb_data_t *cddb_data) {
|
|
517 char offsets[1024], command[1024];
|
|
518 char *ptr;
|
|
519 int i, time_len;
|
|
520
|
|
521 ptr = offsets;
|
|
522 for( i=0; i<cddb_data->tracks ; i++ ) {
|
|
523 ptr += sprintf(ptr, "%d+", cdtoc[i].frame );
|
|
524 }
|
|
525 time_len = (cdtoc[cddb_data->tracks].frame)/75;
|
|
526
|
|
527 cddb_data->freedb_server = DEFAULT_FREEDB_SERVER;
|
|
528 cddb_data->freedb_proto_level = 1;
|
|
529 cddb_data->xmcd_file = NULL;
|
|
530
|
|
531 cddb_create_hello(cddb_data);
|
|
532 cddb_get_proto_level(cddb_data);
|
|
533
|
|
534 //cddb_get_freedb_sites(&cddb_data);
|
|
535
|
|
536 sprintf(command, "cddb+query+%08lx+%d+%s%d", cddb_data->disc_id, cddb_data->tracks, offsets, time_len );
|
|
537 i = cddb_http_request(command, cddb_query_parse, cddb_data);
|
|
538 if( i<0 ) return -1;
|
|
539
|
|
540 if( cddb_data->cache_dir!=NULL ) {
|
|
541 free(cddb_data->cache_dir);
|
|
542 }
|
|
543 return 0;
|
|
544 }
|
|
545
|
|
546 int
|
|
547 cddb_resolve(char *xmcd_file) {
|
|
548 char cddb_cache_dir[] = DEFAULT_CACHE_DIR;
|
|
549 char *home_dir = NULL;
|
|
550 cddb_data_t cddb_data;
|
|
551
|
|
552 cddb_data.tracks = read_toc();
|
|
553 cddb_data.disc_id = cddb_discid(cddb_data.tracks);
|
|
554
|
|
555 home_dir = getenv("HOME");
|
|
556 if( home_dir==NULL ) {
|
|
557 cddb_data.cache_dir = NULL;
|
|
558 } else {
|
|
559 cddb_data.cache_dir = (char*)malloc(strlen(home_dir)+strlen(cddb_cache_dir)+1);
|
|
560 if( cddb_data.cache_dir==NULL ) {
|
|
561 printf("Memory allocation failed\n");
|
|
562 return -1;
|
|
563 }
|
|
564 sprintf(cddb_data.cache_dir, "%s%s", home_dir, cddb_cache_dir );
|
|
565 }
|
|
566
|
|
567 // Check for a cached file
|
|
568 if( cddb_read_cache(&cddb_data)<0 ) {
|
|
569 // No Cache found
|
|
570 if( cddb_retrieve(&cddb_data)<0 ) {
|
|
571 return -1;
|
|
572 }
|
|
573 }
|
|
574
|
|
575 if( cddb_data.xmcd_file!=NULL ) {
|
|
576 printf("%s\n", cddb_data.xmcd_file );
|
|
577 xmcd_file = cddb_data.xmcd_file;
|
|
578 }
|
|
579
|
|
580 return 0;
|
|
581 }
|
|
582
|
|
583 stream_t*
|
|
584 cddb_open(char *dev, char *track) {
|
|
585 char *xmcd_file;
|
|
586 cddb_resolve(xmcd_file);
|
|
587
|
|
588 return open_cdda(dev, track);
|
|
589 }
|
|
590
|
|
591 #endif
|