PageRenderTime 61ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/Release-0.99.80/input/cdda/cdda_engine.c

#
C | 1355 lines | 1005 code | 184 blank | 166 comment | 213 complexity | f4b0e28568d8f23d50ca6502ed34c5c2 MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0
  1. /*
  2. * cdda_engine.c (C) 1999-2003 by Andy Lo A Foe <andy@alsaplayer.org>
  3. * CDDB lookup code by Anders Rune Jensen
  4. *
  5. * Based on code from dagrab 0.3 by Marcello Urbani <murbani@numerica.it>
  6. *
  7. * This plugin reads music CD's in digital form, allowing for exceptional
  8. * quality playback of CD audio. It is used in the alsaplayer project
  9. * by Andy Lo A Foe. If you use use this please be so kind as to put a
  10. * pointer to the web page at http://www.alsa-project.org/~andy
  11. *
  12. * This file is part of AlsaPlayer.
  13. *
  14. * AlsaPlayer is free software; you can redistribute it and/or modify
  15. * it under the terms of the GNU General Public License as published by
  16. * the Free Software Foundation; either version 3 of the License, or
  17. * (at your option) any later version.
  18. *
  19. * AlsaPlayer is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, see <http://www.gnu.org/licenses/>.
  26. *
  27. */
  28. #include "config.h"
  29. #include "cdda.h"
  30. #include "prefs.h"
  31. #include <assert.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <unistd.h>
  35. #include <fcntl.h>
  36. #include <time.h>
  37. #include <string.h>
  38. #include <dirent.h>
  39. #include <pwd.h>
  40. #include <endian.h>
  41. #include <inttypes.h>
  42. #ifdef HAVE_LINUX_CDROM_H
  43. #include <linux/cdrom.h>
  44. #endif
  45. #include <sys/ioctl.h>
  46. #include <sys/time.h>
  47. #include <sys/vfs.h>
  48. #include <sys/stat.h>
  49. #include <sys/types.h>
  50. #include <sys/param.h>
  51. #include <pthread.h>
  52. #include "input_plugin.h"
  53. #include "alsaplayer_error.h"
  54. #include "AlsaPlayer.h"
  55. #include "control.h"
  56. #include "prefs.h"
  57. #include "utilities.h"
  58. #define MAX_TRACKS 128
  59. #define BUFFER_SIZE 4096
  60. #define DEFAULT_DEVICE "/dev/cdrom"
  61. #define FRAME_LEN 4
  62. #define N_BUF 8
  63. #define OVERLAY 3
  64. #define KEYLEN 12
  65. #define OFS 12
  66. #define RETRYS 20
  67. #define IFRAMESIZE (CD_FRAMESIZE_RAW/sizeof(int))
  68. #define BLEN 255
  69. /* global variables */
  70. static char *REAL_PATH = NULL;
  71. typedef struct
  72. {
  73. char *artist;
  74. char *album;
  75. char *track;
  76. } track;
  77. struct cd_trk_list {
  78. int min;
  79. int max;
  80. int *l_min;
  81. int *l_sec;
  82. int *l_frame;
  83. int *starts;
  84. char *types;
  85. };
  86. struct cdda_local_data {
  87. track tracks[MAX_TRACKS];
  88. char device_path[1024];
  89. struct cd_trk_list tl;
  90. int cdrom_fd;
  91. int samplerate;
  92. int track_length;
  93. int track_start;
  94. int rel_pos;
  95. int track_nr;
  96. };
  97. //static cd_trk_list tl, old_tl;
  98. typedef unsigned short Word;
  99. typedef unsigned char unchar;
  100. int cddb_sum (int n);
  101. static int cd_get_tochdr(int cdrom_fd, struct cdrom_tochdr *Th)
  102. {
  103. return ioctl(cdrom_fd, CDROMREADTOCHDR,Th);
  104. }
  105. static int cd_get_tocentry(int cdrom_fd, int trk, struct cdrom_tocentry *Te, int mode)
  106. {
  107. Te->cdte_track=trk;
  108. Te->cdte_format=mode;
  109. return ioctl(cdrom_fd,CDROMREADTOCENTRY,Te);
  110. }
  111. static int cd_read_audio(int cdrom_fd, int lba, int num, unsigned char *buf)
  112. {
  113. struct cdrom_read_audio ra;
  114. ra.addr.lba = lba;
  115. ra.addr_format = CDROM_LBA;
  116. ra.nframes = num;
  117. ra.buf = buf;
  118. if (ioctl(cdrom_fd, CDROMREADAUDIO, &ra)) {
  119. alsaplayer_error("CDDA: read raw ioctl failed at lba %d length %d",
  120. lba, num);
  121. perror("CDDA");
  122. return 1;
  123. }
  124. return 0;
  125. }
  126. /*
  127. static char *resttime(int sec)
  128. {
  129. static char buf[BLEN+1];
  130. snprintf(buf, BLEN, "%02d:%02d:%02d", sec/3600, (sec/60)%60, sec%60);
  131. return buf;
  132. }
  133. */
  134. void toc_fail(struct cd_trk_list *tl)
  135. {
  136. free(tl->starts);
  137. free(tl->types);
  138. free(tl->l_min);
  139. free(tl->l_sec);
  140. free(tl->l_frame);
  141. tl->starts = NULL;
  142. tl->types = NULL;
  143. tl->l_min = NULL;
  144. tl->l_sec = NULL;
  145. tl->l_frame = NULL;
  146. }
  147. static int cd_getinfo(int *cdrom_fd, char *cd_dev, struct cd_trk_list *tl)
  148. {
  149. int i;
  150. struct cdrom_tochdr Th;
  151. struct cdrom_tocentry Te;
  152. if ((*cdrom_fd=open(cd_dev,O_RDONLY | O_NONBLOCK))==-1){
  153. alsaplayer_error("CDDA: error opening device %s",cd_dev);
  154. return 1;
  155. }
  156. if(cd_get_tochdr(*cdrom_fd, &Th)){
  157. alsaplayer_error("CDDA: read TOC ioctl failed");
  158. return 1;
  159. }
  160. tl->min=Th.cdth_trk0; /* first track */
  161. tl->max=Th.cdth_trk1; /* last track */
  162. if((tl->starts=(int *)malloc((tl->max-tl->min+2)*sizeof(int)))==NULL){
  163. alsaplayer_error("CDDA: list data allocation failed");
  164. return 1;
  165. }
  166. if((tl->types=(char *)malloc(tl->max-tl->min+2))==NULL){
  167. alsaplayer_error("CDDA: list data allocation failed");
  168. return 1;
  169. }
  170. /* length */
  171. if((tl->l_min=(int *)malloc((tl->max-tl->min+2)*sizeof(int)))==NULL){
  172. alsaplayer_error("CDDA: list data allocation failed");
  173. return 1;
  174. }
  175. if((tl->l_sec=(int *)malloc((tl->max-tl->min+2)*sizeof(int)))==NULL){
  176. alsaplayer_error("CDDA: list data allocation failed");
  177. return 1;
  178. }
  179. if((tl->l_frame=(int *)malloc((tl->max-tl->min+2)*sizeof(int)))==NULL){
  180. alsaplayer_error("CDDA: list data allocation failed");
  181. return 1;
  182. }
  183. i=CDROM_LEADOUT;
  184. if(cd_get_tocentry(*cdrom_fd, i,&Te,CDROM_LBA)){
  185. alsaplayer_error("CDDA: read TOC entry ioctl failed");
  186. toc_fail(tl);
  187. return 1;
  188. }
  189. tl->starts[tl->max]=Te.cdte_addr.lba;
  190. tl->types[tl->max]=Te.cdte_ctrl&CDROM_DATA_TRACK;
  191. if(cd_get_tocentry(*cdrom_fd, i,&Te,CDROM_MSF)){
  192. alsaplayer_error("CDDA: read TOC entry ioctl failed");
  193. toc_fail(tl);
  194. return 1;
  195. }
  196. /* length info */
  197. tl->l_min[tl->max] = Te.cdte_addr.msf.minute;
  198. tl->l_sec[tl->max] = Te.cdte_addr.msf.second;
  199. tl->l_frame[tl->max] = Te.cdte_addr.msf.frame;
  200. for (i=tl->max;i>=tl->min;i--)
  201. {
  202. if(cd_get_tocentry(*cdrom_fd, i,&Te,CDROM_LBA)){
  203. alsaplayer_error("CDDA: read TOC entry ioctl failed");
  204. toc_fail(tl);
  205. return 1;
  206. }
  207. tl->starts[i-1]=Te.cdte_addr.lba;
  208. tl->types[i-1]=Te.cdte_ctrl&CDROM_DATA_TRACK;
  209. if(cd_get_tocentry(*cdrom_fd, i,&Te,CDROM_MSF)){
  210. alsaplayer_error("CDDA: read TOC entry ioctl failed");
  211. toc_fail(tl);
  212. return 1;
  213. }
  214. /* length info */
  215. tl->l_min[i-1] = Te.cdte_addr.msf.minute;
  216. tl->l_sec[i-1] = Te.cdte_addr.msf.second;
  217. tl->l_frame[i-1] = Te.cdte_addr.msf.frame;
  218. }
  219. return 0;
  220. }
  221. /*
  222. * create_socket - create a socket to communicate with the remote server
  223. * return the fd' int on success, or -1 on error.
  224. */
  225. int create_socket (unchar *unchar_address, int int_port)
  226. {
  227. int sock, len;
  228. struct hostent *remote;
  229. struct sockaddr_in server;
  230. ushort port = (ushort) (int_port);
  231. ulong address, temp;
  232. /* get the "remote" server information */
  233. remote = gethostbyname (unchar_address);
  234. if (! remote)
  235. {
  236. alsaplayer_error("%s\n", strerror (errno));
  237. return (-1);
  238. }
  239. bcopy ((char *) remote->h_addr, (char *) &temp, remote->h_length);
  240. /* convert the 32bit long value from *network byte order* to the *host byte order* */
  241. address = ntohl (temp);
  242. /* create the address of the CDDB server, filling the server's mem_area with 0 values */
  243. len = sizeof (struct sockaddr_in);
  244. memset (&server, 0, len);
  245. server.sin_family = AF_INET; /* set the address as being in the internet domain */
  246. server.sin_port = htons (port); /* set the port address of the server */
  247. server.sin_addr.s_addr = htonl (address);
  248. /* create a socket in the INET domain */
  249. sock = socket (AF_INET, SOCK_STREAM, 0);
  250. if (sock < 0)
  251. {
  252. alsaplayer_error("socket error\n");
  253. return (-1);
  254. }
  255. /* connect to the server */
  256. if (connect (sock, (struct sockaddr *) &server, sizeof (server)) < 0)
  257. {
  258. alsaplayer_error("%s\n", strerror (errno));
  259. return (-1);
  260. }
  261. return (sock);
  262. }
  263. /*
  264. * sent_to_server - send a message to the server, and return the server response
  265. * on success, or NULL on error
  266. */
  267. char * send_to_server (int server_fd, char *message)
  268. {
  269. ssize_t total, i;
  270. int len = BUFFER_SIZE;
  271. char *response, *temp;
  272. temp = (char *) malloc(BUFFER_SIZE);
  273. /* write 'message' to the server */
  274. if (send (server_fd, message, strlen (message), MSG_DONTWAIT) < 0)
  275. {
  276. alsaplayer_error("%s: %s\n", message, strerror (errno));
  277. free (temp);
  278. return (NULL);
  279. }
  280. if (global_verbose) {
  281. /* print the message sent to the server */
  282. alsaplayer_error("-> %s", message);
  283. }
  284. /* read the response from the server */
  285. total = 0;
  286. do
  287. {
  288. i = read (server_fd, temp + total, BUFFER_SIZE);
  289. if (i < 0)
  290. {
  291. alsaplayer_error("%s\n", strerror (errno));
  292. free (temp);
  293. return (NULL);
  294. }
  295. total += i;
  296. if (total + BUFFER_SIZE > len)
  297. {
  298. temp = (char *) realloc(temp, len + BUFFER_SIZE);
  299. len += BUFFER_SIZE;
  300. }
  301. }
  302. while (total > 2 && temp[total - 2] != '\r' && i != 0);
  303. if (total < 2)
  304. {
  305. free (temp);
  306. return (NULL);
  307. }
  308. temp[total-2] = '\0'; /* temp[total-1] == \r; temp[total] == \n */
  309. response = strdup (temp); /* duplicate the response from the server */
  310. free(temp);
  311. if (global_verbose) {
  312. /* print the message sent to the server */
  313. alsaplayer_error("<- %s", response);
  314. }
  315. return (response);
  316. }
  317. /*
  318. * cddb_disc_id - generate the disc ID from the total music time
  319. * (routine token from the cddb.howto)
  320. */
  321. unsigned int cddb_disc_id (struct cd_trk_list *tl)
  322. {
  323. int i, t = 0, n = 0;
  324. /* n == total music time in seconds */
  325. i = 0;
  326. while (i < tl->max)
  327. {
  328. n += cddb_sum((tl->l_min[i] * 60) + tl->l_sec[i]);
  329. i++;
  330. }
  331. /* t == lead-out offset seconds - 1st music total time, in seconds */
  332. t = ((tl->l_min[tl->max] * 60) + tl->l_sec[tl->max])
  333. - ((tl->l_min[0] * 60) + tl->l_sec[0]);
  334. /*
  335. * mod 'n' with FFh and left-shift it by 24. 't' is left-shifted by 8.
  336. * the disc_id is then returned as these operations + total tracks
  337. * 'OR'ed together.
  338. */
  339. return ((n % 0xff) << 24 | t << 8 | tl->max);
  340. }
  341. /*
  342. * cddb_sum - adds the value of each digit in the decimal string representation
  343. * of the number. (routine token from the cddb.howto)
  344. */
  345. int cddb_sum (int n)
  346. {
  347. int ret = 0;
  348. while (n > 0)
  349. {
  350. ret = ret + (n % 10);
  351. n = n/10;
  352. }
  353. return (ret);
  354. }
  355. /*
  356. * save_to_disk - receive the subdir, cdID and the message, and save the
  357. * information into the cddb directory. This function returns the filename on
  358. * success, or NULL on error.
  359. */
  360. char * cddb_save_to_disk(char *subdir, int cdID, char *message)
  361. {
  362. FILE *destination;
  363. DIR *thedir;
  364. char *path, *retval;
  365. char new[strlen (message)], *filename;
  366. int i = 0, j = 0;
  367. /* check if we already have the subdir created */
  368. path = (char *) malloc ((strlen (subdir) + strlen (REAL_PATH) + 2) * sizeof (char));
  369. /* print the message sent to the server */
  370. sprintf(path, "%s", REAL_PATH);
  371. if (! (thedir=opendir(path))) { /* No cddb directory yet! */
  372. if ((mkdir(path, 0744)) < 0) {
  373. perror("mkdir");
  374. free(path);
  375. return (NULL);
  376. }
  377. } else {
  378. closedir(thedir);
  379. }
  380. /* cddb directory should be there at this point */
  381. sprintf (path, "%s/%s", REAL_PATH, subdir);
  382. if (global_verbose)
  383. alsaplayer_error("path = %s", path);
  384. /* check if we have the directory in the disk */
  385. if (! (thedir = opendir (path))) {
  386. /* given directory doesn't exist */
  387. if (global_verbose)
  388. printf ("directory %s doesn't exist, trying to create it.\n", path);
  389. /* try to create it.. */
  390. if ((mkdir (path, 0744)) < 0) {
  391. perror ("mkdir");
  392. free(path);
  393. return (NULL);
  394. } else {
  395. if (global_verbose)
  396. printf ("directory created successfully\n");
  397. }
  398. } else {
  399. closedir(thedir);
  400. }
  401. while (message[i] != '\n')
  402. i++;
  403. i++;
  404. for (; i < (int)strlen (message); i++, j++)
  405. new[j] = message[i];
  406. /* save it into the disc */
  407. filename = (char *) malloc ((strlen (subdir) + strlen (REAL_PATH) + 11) * sizeof (char));
  408. sprintf (filename, "%s/%s/%08x", REAL_PATH, subdir, cdID);
  409. retval = strdup (filename);
  410. if (global_verbose)
  411. alsaplayer_error("filename = %s", filename);
  412. /* create the file */
  413. destination = fopen (filename, "w");
  414. free(filename);
  415. if (! destination)
  416. {
  417. alsaplayer_error("error creating file");
  418. free(path);
  419. return (NULL);
  420. }
  421. /* copy the new string content into the file */
  422. for (i = 0; i < (int)strlen (new); i++)
  423. fputc (new[i], destination);
  424. /* free path's memory */
  425. free (path);
  426. /* close the file */
  427. fclose (destination);
  428. return (retval);
  429. }
  430. /*
  431. * search for the CD info in the hard disk CDDB, returning NULL on error or the
  432. * filename on success.
  433. */
  434. char * cddb_local_lookup (char *path, unsigned int cd_id)
  435. {
  436. int i, number, fd;
  437. char *name;
  438. char cdrom_id[9];
  439. struct dirent **directory;
  440. if (global_verbose)
  441. alsaplayer_error ("Searching for CDDB entries on %s ... ", path);
  442. /* try to open the given directory */
  443. if (! (opendir (path)))
  444. {
  445. return (NULL);
  446. }
  447. /* get the number of subdirectories in the 'path' dir */
  448. number = scandir (path, &directory, 0, alphasort);
  449. if (number < 0)
  450. {
  451. alsaplayer_error("scandir\n");
  452. return (NULL);
  453. }
  454. /* set the cdrom_id */
  455. sprintf (cdrom_id, "%08x", cd_id);
  456. cdrom_id[8] = '\0';
  457. for (i = 0; i < number; i++)
  458. {
  459. /* ignore '.' and '..' directories */
  460. if ((strcmp (directory[i]->d_name, ".")) && (strcmp (directory[i]->d_name, "..")))
  461. {
  462. name = malloc((strlen (path) + strlen (directory[i]->d_name) + 15) * sizeof(char));
  463. sprintf (name, "%s", path);
  464. strcat (name, "/");
  465. strncat (name, directory[i]->d_name, strlen (directory[i]->d_name));
  466. strcat (name, "/");
  467. strncat (name, cdrom_id, 8);
  468. if ((fd = open (name, O_RDONLY)) >= 0)
  469. {
  470. if (global_verbose)
  471. printf ("OK\n");
  472. close (fd);
  473. return (name);
  474. }
  475. free (name);
  476. }
  477. }
  478. if (global_verbose)
  479. printf ("not found\n");
  480. return (NULL);
  481. }
  482. char*
  483. cut_html_head(char *answer)
  484. {
  485. if(!answer)
  486. return NULL;
  487. char *new_answer;
  488. int counter = 0, i = 0;
  489. for (i = 0; i < strlen(answer); i++) {
  490. if (*(answer+i) == '\n') {
  491. if (counter < 3) {
  492. new_answer = strdup(answer+i+1);
  493. free(answer);
  494. return new_answer;
  495. }
  496. counter = 0;
  497. }
  498. counter++;
  499. }
  500. free(answer);
  501. return NULL;
  502. }
  503. /*
  504. * search for the song in the CDDB given address/port, returning it's name, or
  505. * NULL if not found.
  506. */
  507. char * cddb_lookup (char *address, char *char_port, int discID, struct cd_trk_list *tl)
  508. {
  509. int port = atoi (char_port);
  510. int server_fd, i, j;
  511. int total_secs = 0, counter = 0;
  512. char *answer = NULL, *username, *filename, categ[20], newID[9];
  513. char msg[BUFFER_SIZE], offsets[BUFFER_SIZE], tmpbuf[BUFFER_SIZE];
  514. char hostname[MAXHOSTNAMELEN], separator='+';
  515. /* try to create a socket to the server */
  516. if (global_verbose)
  517. alsaplayer_error ("Opening Connection to %s:%d ... ", address, port);
  518. /* get the server fd from the create_socket function */
  519. server_fd = create_socket ((unchar *) address, port);
  520. if (server_fd < 0)
  521. return (NULL);
  522. else
  523. if (global_verbose)
  524. printf ("OK\n");
  525. /* get the initial message from the server */
  526. if (port > 80) {
  527. answer = send_to_server (server_fd, "");
  528. if (global_verbose) {
  529. printf ("Saying HELLO to CDDB server ...\n");
  530. }
  531. free (answer);
  532. }
  533. /* set some settings before saying HELLO to the CDDB server */
  534. username = getlogin ();
  535. if ((gethostname (hostname, sizeof (hostname))) < 0)
  536. snprintf (hostname, sizeof (hostname), "unknown");
  537. if (port > 80) {
  538. snprintf (msg, sizeof (msg), "cddb hello %s %s %s %s\r\n\r\n", username, hostname,PACKAGE, VERSION);
  539. answer = send_to_server (server_fd, msg);
  540. if (! answer)
  541. {
  542. alsaplayer_error("bad response from the server\n");
  543. close (server_fd);
  544. return (NULL);
  545. }
  546. separator=' ';
  547. }
  548. /* set another settings before querying the CDDB database */
  549. tmpbuf[0] = '\0';
  550. for (i = 0; i < tl->max; i++)
  551. {
  552. /* put the frame offset of the starting location of each track in a string */
  553. //snprintf (offsets, sizeof (offsets), "%s %d ", tmpbuf,
  554. snprintf (offsets, sizeof (offsets), "%s%c%d", tmpbuf, separator,
  555. tl->l_frame[i] + (75 * (tl->l_sec[i] + (60 * tl->l_min[i]))));
  556. strcpy (tmpbuf, offsets);
  557. counter += tl->l_frame[i] + (75 * tl->l_sec[i] + (60 * tl->l_min[i]));
  558. }
  559. total_secs = tl->l_sec[tl->max] + (tl->l_min[tl->max] * 60);
  560. /* send it */
  561. if (port > 80)
  562. snprintf (msg, sizeof (msg), "cddb query %08x %d %s %d\r\n", discID, tl->max, offsets, total_secs);
  563. else
  564. snprintf (msg, sizeof (msg), "GET /~cddb/cddb.cgi?cmd=cddb+query+%08x+%d%s+%d&hello=%s+%s+%s+%s&proto=6 HTTP/1.0\r\n\r\n", discID, tl->max, offsets, total_secs, username, hostname,PACKAGE, VERSION);
  565. if (answer)
  566. free(answer);
  567. answer = send_to_server (server_fd, msg);
  568. if (! answer)
  569. {
  570. alsaplayer_error("bad response from the server\n");
  571. close (server_fd);
  572. return (NULL);
  573. }
  574. /*
  575. * if answer == "200...", found exact match
  576. * if answer == "211...", found too many matches
  577. * if answer == "202...", found no matches
  578. */
  579. if (port <= 80)
  580. answer = cut_html_head(answer);
  581. if (!answer)
  582. return NULL;
  583. i = 0;
  584. if (! (strncmp (answer, "211", 3)))
  585. {
  586. /* seek the 2nd line */
  587. while (answer[i] != '\n') {
  588. if (! answer[i])
  589. goto error;
  590. ++i;
  591. }
  592. /* copy the 1st match to the category */
  593. j = 0;
  594. i++;
  595. while (j < 19 && answer[i] != ' ') {
  596. if (! answer[i])
  597. goto error;
  598. categ[j++] = answer[i++];
  599. }
  600. categ[j++] = '\0';
  601. while (answer[i] != ' ') {
  602. if (! answer[i])
  603. goto error;
  604. i++;
  605. }
  606. /* get the new cdID given from the CDDB */
  607. j = 0;
  608. i++;
  609. while (j < 8 && answer[i] != ' ') {
  610. if (! answer[i])
  611. goto error;
  612. newID[j++] = answer[i++];
  613. }
  614. newID[j++] = '\0';
  615. while (answer[i] != ' ') {
  616. if (! answer[i])
  617. goto error;
  618. i++;
  619. }
  620. }
  621. else if (! (strncmp (answer, "200", 3)))
  622. {
  623. /* get it from the 1st line */
  624. while (answer[i] != ' ') {
  625. if (! answer[i])
  626. goto error;
  627. i++;
  628. }
  629. i++;
  630. /* copy the match to the category */
  631. j = 0;
  632. while (j < 19 && answer[i] != ' ') {
  633. if (! answer[i])
  634. goto error;
  635. categ[j++] = answer[i++];
  636. }
  637. categ[j++] = '\0';
  638. while (answer[i] != ' ') {
  639. if (! answer[i])
  640. goto error;
  641. i++;
  642. }
  643. /* copy the new cdID */
  644. j = 0;
  645. i++;
  646. while (j < 8 && answer[i] != ' ') {
  647. if (! answer[i])
  648. goto error;
  649. newID[j++] = answer[i++];
  650. }
  651. newID[j++] = '\0';
  652. while (answer[i] != ' ') {
  653. if (! answer[i])
  654. goto error;
  655. i++;
  656. }
  657. }
  658. else
  659. {
  660. error:
  661. alsaplayer_error("Could not find any matches for %08x\n\n", discID);
  662. close (server_fd);
  663. free(answer);
  664. return (NULL);
  665. }
  666. /* read from the server */
  667. if (port > 80)
  668. sprintf (msg, "cddb read %s %s\r\n", categ, newID);
  669. else {
  670. server_fd = create_socket ((unchar *) address, port);
  671. snprintf (msg, sizeof (msg), "GET /~cddb/cddb.cgi?cmd=cddb+read+%s+%s&hello=%s+%s+%s+%s&proto=6 HTTP/1.0\r\n\r\n", categ, newID, username, hostname,PACKAGE, VERSION);
  672. }
  673. free(answer);
  674. answer = send_to_server(server_fd, msg);
  675. if (! answer)
  676. {
  677. alsaplayer_error("could not receive the informations from %s\n", address);
  678. close (server_fd);
  679. return (NULL);
  680. }
  681. /* save the output into the disc */
  682. if (global_verbose)
  683. {
  684. printf ("Saving CDDB information into %s/%s ...\n", REAL_PATH, newID);
  685. printf ("save_to_disk(%s)\n", answer);
  686. }
  687. filename = cddb_save_to_disk(categ, discID, answer);
  688. if (! filename)
  689. {
  690. alsaplayer_error("could not create the file %s/%s, check permission\n", categ, newID);
  691. close (server_fd);
  692. return (NULL);
  693. }
  694. if (global_verbose)
  695. puts ("");
  696. /* close the fd */
  697. close (server_fd);
  698. free(answer);
  699. return (filename);
  700. }
  701. /*
  702. * open the filename and put music title's into the global variable
  703. */
  704. void cddb_read_file (char *file, struct cdda_local_data *data)
  705. {
  706. char line[BUFFER_SIZE], name[BUFFER_SIZE];
  707. char *token = NULL, *tmp, *divider, *s, *post;
  708. char album[BUFFER_SIZE];
  709. int i, index = 1;
  710. FILE *f;
  711. /* try to open the file */
  712. f = fopen (file, "r");
  713. if (! f) {
  714. alsaplayer_error("couldn't open file");
  715. return;
  716. }
  717. /* read it line by line */
  718. while (!feof (f)) {
  719. if ((fgets (line, sizeof (line), f))) {
  720. if (! (strstr (line, "DTITLE="))) {
  721. /* check if is the music name.. */
  722. if ((strstr (line, "TTITLE"))) {
  723. token = strtok (line, "=");
  724. if (!token) {
  725. alsaplayer_error("error: TTITLE has no arguments");
  726. continue;
  727. }
  728. token = strtok (NULL, "=");
  729. if (!token) {
  730. alsaplayer_error("TTITLE has no arguments");
  731. continue;
  732. }
  733. /* seek for the \r character */
  734. for (i = 0; i < (int)strlen (token); i++) {
  735. if ((token[i] == '\n') || (token[i] == '\r'))
  736. break;
  737. }
  738. if (sscanf(line, "TTITLE%d=", &index)) {
  739. //alsaplayer_error("Found index %d", index);
  740. index++;
  741. } else {
  742. index = 1;
  743. alsaplayer_error("Error reading index number!");
  744. }
  745. token[i] = '\0';
  746. sprintf (name, "%s", token);
  747. if (data->tracks[index].track) {
  748. post = (char *)malloc(strlen(data->tracks[index].track) + strlen(name) + 1);
  749. *post = '\0';
  750. strcat(post, data->tracks[index].track);
  751. strcat(post, name);
  752. free(data->tracks[index].track);
  753. data->tracks[index].track = strdup(post);
  754. free(post);
  755. } else {
  756. data->tracks[index].track = strdup (name);
  757. }
  758. }
  759. continue;
  760. } else {
  761. // workaround album name on multiple lines, need improvment
  762. if (data->tracks[1].album)
  763. continue;
  764. /* print the album name */
  765. tmp = strtok (line, "=");
  766. if (!tmp) {
  767. alsaplayer_error ("error: no arguments given on %s", line);
  768. continue;
  769. }
  770. tmp = strtok (NULL, "=");
  771. if (!tmp) {
  772. alsaplayer_error ("error: no arguments given on %s", line);
  773. continue;
  774. }
  775. divider = strstr (tmp, " / ");
  776. if (!divider) {
  777. alsaplayer_error("No divider found in DTITLE");
  778. data->tracks[1].artist = strdup(tmp);
  779. data->tracks[1].album = strdup(tmp);
  780. } else {
  781. data->tracks[1].album = strdup (divider+3);
  782. tmp[strlen(tmp)-strlen(data->tracks[1].album)-3] = '\0';
  783. data->tracks[1].artist = strdup (tmp);
  784. }
  785. if ((s = strstr(data->tracks[1].artist, "\r"))) {
  786. *s = '\0';
  787. }
  788. if ((s = strstr(data->tracks[1].artist, "\n"))) {
  789. *s = '\0';
  790. }
  791. if ((s = strstr(data->tracks[1].album, "\r"))) {
  792. *s = '\0';
  793. }
  794. if ((s = strstr(data->tracks[1].album, "\n"))) {
  795. *s = '\0';
  796. }
  797. if (data->tracks[1].album[strlen(data->tracks[1].album)-1] == ' ') {
  798. data->tracks[1].album[strlen(data->tracks[1].album)-1] = '\0';
  799. }
  800. if (data->tracks[1].artist[strlen(data->tracks[1].artist)-1] == ' ') {
  801. data->tracks[1].artist[strlen(data->tracks[1].artist)-1] = '\0';
  802. }
  803. if (global_verbose) {
  804. alsaplayer_error ("Artist: %s", data->tracks[1].artist);
  805. alsaplayer_error ("Album name: %s", data->tracks[1].album);
  806. }
  807. }
  808. } /* if */
  809. } /* while */
  810. }
  811. void cddb_update_info(struct cdda_local_data *data)
  812. {
  813. char *file_name = NULL;
  814. char *cddb_servername = NULL;
  815. char *cddb_serverport = NULL;
  816. struct cd_trk_list *tl;
  817. int index;
  818. unsigned int cd_id;
  819. if (!data)
  820. return;
  821. tl = &data->tl;
  822. cd_id = cddb_disc_id(tl);
  823. /* try to get the audio info from the hard disk.. */
  824. file_name = cddb_local_lookup(REAL_PATH, cd_id);
  825. if (file_name)
  826. {
  827. /* open the 'file_name' and search for album information */
  828. cddb_read_file (file_name, data);
  829. }
  830. else
  831. {
  832. /* if could not, try to get it from the internet connection.. */
  833. cddb_servername = prefs_get_string(ap_prefs, "cdda", "cddb_servername", "freedb.freedb.org");
  834. cddb_serverport = prefs_get_string(ap_prefs, "cdda", "cddb_serverport", "80");
  835. if (global_verbose)
  836. alsaplayer_error("CDDB server: %s:%s", cddb_servername, cddb_serverport);
  837. file_name = cddb_lookup(cddb_servername, cddb_serverport, cd_id, tl);
  838. if (file_name) {
  839. /* fine, now we have the hard disk access! so, let's use it's information */
  840. free(file_name);
  841. file_name = cddb_local_lookup(REAL_PATH, cd_id);
  842. if (file_name)
  843. cddb_read_file (file_name, data);
  844. else {
  845. for (index = 1; index <= tl->max; index++)
  846. data->tracks[index].track = strdup ("unrecognized song");
  847. }
  848. } else {
  849. for (index = 1; index <= tl->max; index++)
  850. data->tracks[index].track = strdup ("unrecognized song");
  851. }
  852. }
  853. }
  854. static int cdda_init(void)
  855. {
  856. char *prefsdir;
  857. prefsdir = get_prefsdir();
  858. REAL_PATH = (char *)malloc((strlen(prefsdir) + 8) * sizeof(char));
  859. if (REAL_PATH) {
  860. sprintf(REAL_PATH, "%s/cddb", prefsdir);
  861. return 1;
  862. }
  863. return 0;
  864. }
  865. static float cdda_can_handle(const char *name)
  866. {
  867. char *ext;
  868. ext = strrchr(name, '.');
  869. if (ext)
  870. if ((strcasecmp(ext, ".cdda") == 0)) {
  871. return 1.0;
  872. }
  873. return 0.0;
  874. }
  875. void cd_adder(void *data) {
  876. int i;
  877. intptr_t nr_tracks;
  878. char track_name[1024];
  879. if (!data)
  880. return;
  881. nr_tracks = (intptr_t)data;
  882. for (i=1;i <= nr_tracks;i++) {
  883. sprintf(track_name, "Track %02d.cdda", i);
  884. ap_add_path(global_session_id, track_name);
  885. }
  886. pthread_exit(NULL);
  887. }
  888. static int cdda_open(input_object *obj, const char *name)
  889. {
  890. struct cdda_local_data *data;
  891. const char *fname;
  892. char device_name[1024];
  893. if (!obj)
  894. return 0;
  895. fname = strrchr(name, '/');
  896. if (!fname)
  897. fname = name;
  898. else fname++; // Ignore '/'
  899. if (ap_prefs) {
  900. strcpy(device_name, prefs_get_string(ap_prefs, "cdda", "device", DEFAULT_DEVICE));
  901. } else {
  902. strcpy(device_name, DEFAULT_DEVICE);
  903. }
  904. #ifdef DEBUG
  905. alsaplayer_error("device = %s, name = %s\n", device_name, fname);
  906. #endif
  907. obj->local_data = malloc(sizeof(struct cdda_local_data));
  908. if (!obj->local_data) {
  909. return 0;
  910. }
  911. data = (struct cdda_local_data *)obj->local_data;
  912. memset(data->tracks, 0, sizeof(data->tracks));
  913. if(cd_getinfo(&data->cdrom_fd, device_name, &data->tl)) {
  914. free(obj->local_data);
  915. obj->local_data = NULL;
  916. return 0;
  917. }
  918. #ifdef DEBUG
  919. cd_disp_TOC(&data->tl);
  920. alsaplayer_error("IFRAMESIZE = %d\n", IFRAMESIZE);
  921. #endif
  922. obj->nr_channels = 2;
  923. data->samplerate = 44100;
  924. data->track_length = 0;
  925. data->track_start = 0;
  926. data->rel_pos = 0;
  927. data->track_nr = 0;
  928. strcpy(data->device_path, device_name);
  929. if (prefs_get_bool(ap_prefs, "cdda", "do_cddb_lookup", 1)) {
  930. /* look up cd in cddb */
  931. cddb_update_info(data);
  932. }
  933. if (strcmp(fname, "CD.cdda") == 0) {
  934. pthread_t cd_add;
  935. pthread_create(&cd_add, NULL, (void *(*)(void *))cd_adder, (void *)(intptr_t)data->tl.max);
  936. pthread_detach(cd_add);
  937. return 1;
  938. } else if (sscanf(fname, "Track %02d.cdda", &data->track_nr) != 1 ||
  939. sscanf(fname, "Track%02d.cdda", &data->track_nr) != 1) {
  940. alsaplayer_error("Failed to read track number (%s)", fname);
  941. free(obj->local_data);
  942. obj->local_data = NULL;
  943. return 0;
  944. } else {
  945. #ifdef DEBUG
  946. alsaplayer_error("Found track number %d (%s)\n", data->track_nr, fname);
  947. #endif
  948. data->track_start = data->tl.starts[data->track_nr-1];
  949. data->track_length = data->tl.starts[data->track_nr] -
  950. data->tl.starts[data->track_nr-1];
  951. data->rel_pos = 0;
  952. }
  953. obj->flags = P_SEEK;
  954. return 1;
  955. }
  956. static void cdda_close(input_object *obj)
  957. {
  958. struct cdda_local_data *data;
  959. int i = 0;
  960. #ifdef DEBUG
  961. alsaplayer_error("In cdda_close()\n");
  962. #endif
  963. if (!obj)
  964. return;
  965. data = (struct cdda_local_data *)obj->local_data;
  966. if (!data) {
  967. return;
  968. }
  969. for (i = 0; i < MAX_TRACKS;i++) {
  970. if (data->tracks[i].album) {
  971. free(data->tracks[i].album);
  972. }
  973. if (data->tracks[i].artist) {
  974. free(data->tracks[i].artist);
  975. }
  976. if (data->tracks[i].track) {
  977. free(data->tracks[i].track);
  978. }
  979. }
  980. close(data->cdrom_fd);
  981. if (data->tl.starts) free(data->tl.starts);
  982. data->tl.starts = NULL;
  983. if (data->tl.types) free(data->tl.types);
  984. data->tl.types = NULL;
  985. /* length */
  986. if (data->tl.l_min) free(data->tl.l_min);
  987. data->tl.l_min = NULL;
  988. if (data->tl.l_sec) free(data->tl.l_sec);
  989. data->tl.l_sec = NULL;
  990. if (data->tl.l_frame) free(data->tl.l_frame);
  991. data->tl.l_frame = NULL;
  992. free(obj->local_data);
  993. obj->local_data = NULL;
  994. }
  995. static int cdda_play_frame(input_object *obj, char *buf)
  996. {
  997. struct cdda_local_data *data;
  998. unsigned char bla[CD_FRAMESIZE_RAW*FRAME_LEN];
  999. if (!obj)
  1000. return 0;
  1001. data = (struct cdda_local_data *)obj->local_data;
  1002. if (!data) {
  1003. return 0;
  1004. }
  1005. if (!data->track_length ||
  1006. (data->rel_pos > data->track_length)) {
  1007. #ifdef DEBUG
  1008. alsaplayer_error("rel_pos = %d, start = %d, end = %d\n",
  1009. data->rel_pos, data->track_start,
  1010. data->track_start + data->track_length);
  1011. #endif
  1012. return 0;
  1013. }
  1014. memset(bla, 0, sizeof(bla));
  1015. if (cd_read_audio(data->cdrom_fd, data->track_start + data->rel_pos, FRAME_LEN, bla)) {
  1016. return 0;
  1017. }
  1018. data->rel_pos += FRAME_LEN;
  1019. if (buf) {
  1020. memcpy(buf, bla, (CD_FRAMESIZE_RAW * FRAME_LEN));
  1021. #ifdef __BYTE_ORDER
  1022. #if __BYTE_ORDER == __BIG_ENDIAN
  1023. swab (buf, buf, (CD_FRAMESIZE_RAW * FRAME_LEN));
  1024. #endif
  1025. #endif
  1026. }
  1027. return 1;
  1028. }
  1029. static int cdda_frame_seek(input_object *obj, int index)
  1030. {
  1031. struct cdda_local_data *data;
  1032. if (!obj)
  1033. return 0;
  1034. data = (struct cdda_local_data *)obj->local_data;
  1035. if (data)
  1036. data->rel_pos = (index * FRAME_LEN);
  1037. return 1;
  1038. }
  1039. static int cdda_frame_size(input_object *obj)
  1040. {
  1041. int size = (CD_FRAMESIZE_RAW * FRAME_LEN);
  1042. return size;
  1043. }
  1044. static int cdda_nr_frames(input_object *obj)
  1045. {
  1046. struct cdda_local_data *data;
  1047. int nr_frames = 0;
  1048. if (!obj)
  1049. return 0;
  1050. data = (struct cdda_local_data *)obj->local_data;
  1051. if (data)
  1052. nr_frames = data->track_length >> 2;
  1053. return nr_frames;
  1054. }
  1055. static long cdda_frame_to_sec(input_object *obj, int frame)
  1056. {
  1057. unsigned long byte_count = FRAME_LEN * frame * CD_FRAMESIZE_RAW;
  1058. return (byte_count / 1764); /* 44Khz stereo 16 bit, fixed */
  1059. /* 1764 = 176400 / 100 voor de 100ste seconden representatie */
  1060. }
  1061. static int cdda_sample_rate(input_object *obj)
  1062. {
  1063. struct cdda_local_data *data;
  1064. if (!obj)
  1065. return 0;
  1066. data = (struct cdda_local_data *)obj->local_data;
  1067. return (data ? data->samplerate : 0);
  1068. }
  1069. static int cdda_channels(input_object *obj)
  1070. {
  1071. if (!obj)
  1072. return 0;
  1073. return obj->nr_channels;
  1074. }
  1075. static int cdda_stream_info(input_object *obj, stream_info *info)
  1076. {
  1077. struct cdda_local_data *data;
  1078. struct cd_trk_list *tl;
  1079. assert(obj);
  1080. assert(info);
  1081. data = (struct cdda_local_data *)obj->local_data;
  1082. tl = &data->tl;
  1083. sprintf(info->stream_type, "CD Audio, 44KHz, stereo");
  1084. if (data->tracks[1].artist)
  1085. sprintf(info->artist, "%s", data->tracks[1].artist);
  1086. if (data->tracks[1].album)
  1087. sprintf(info->album, "%s", data->tracks[1].album);
  1088. info->status[0] = 0;
  1089. if (data->track_nr < 0)
  1090. info->title[0] = 0;
  1091. else if (data->track_nr == 0)
  1092. sprintf(info->title, "Full CD length playback");
  1093. else if (data->tracks[data->track_nr].track)
  1094. sprintf(info->title, "%s", data->tracks[data->track_nr].track);
  1095. //alsaplayer_error("title = %s\nalbum = %s\nartist = %s",
  1096. // info->title, info->album, info->artist);
  1097. return 1;
  1098. }
  1099. static int cdda_nr_tracks(input_object *obj)
  1100. {
  1101. struct cdda_local_data *data;
  1102. if (!obj)
  1103. return 0;
  1104. data = (struct cdda_local_data *)obj->local_data;
  1105. if (!data)
  1106. return 0;
  1107. return data->tl.max;
  1108. }
  1109. static void cdda_shutdown(void)
  1110. {
  1111. return;
  1112. }
  1113. static int cdda_track_seek(input_object *obj, int track)
  1114. {
  1115. return 1;
  1116. }
  1117. static input_plugin cdda_plugin;
  1118. /*
  1119. = {
  1120. INPUT_PLUGIN_VERSION,
  1121. 0,
  1122. "CDDA player v1.1",
  1123. "Andy Lo A Foe <andy@alsaplayer.org>",
  1124. NULL,
  1125. cdda_init,
  1126. cdda_shutdown,
  1127. NULL,
  1128. cdda_can_handle,
  1129. cdda_open,
  1130. cdda_close,
  1131. cdda_play_frame,
  1132. cdda_frame_seek,
  1133. cdda_frame_size,
  1134. cdda_nr_frames,
  1135. cdda_frame_to_sec,
  1136. cdda_sample_rate,
  1137. cdda_channels,
  1138. cdda_stream_info,
  1139. cdda_nr_tracks,
  1140. cdda_track_seek
  1141. };
  1142. */
  1143. #ifdef __cplusplus
  1144. extern "C" {
  1145. #endif
  1146. input_plugin *input_plugin_info(void)
  1147. {
  1148. memset(&cdda_plugin, 0, sizeof(input_plugin));
  1149. cdda_plugin.version = INPUT_PLUGIN_VERSION;
  1150. cdda_plugin.name = "CDDA player v1.2";
  1151. cdda_plugin.author = "Andy Lo A Foe <andy@alsaplayer.org>";
  1152. cdda_plugin.init = cdda_init;
  1153. cdda_plugin.shutdown = cdda_shutdown;
  1154. cdda_plugin.can_handle = cdda_can_handle;
  1155. cdda_plugin.open = cdda_open;
  1156. cdda_plugin.close = cdda_close;
  1157. cdda_plugin.play_frame = cdda_play_frame;
  1158. cdda_plugin.frame_seek = cdda_frame_seek;
  1159. cdda_plugin.frame_size = cdda_frame_size;
  1160. cdda_plugin.nr_frames = cdda_nr_frames;
  1161. cdda_plugin.frame_to_sec = cdda_frame_to_sec;
  1162. cdda_plugin.sample_rate = cdda_sample_rate;
  1163. cdda_plugin.channels = cdda_channels;
  1164. cdda_plugin.stream_info = cdda_stream_info;
  1165. cdda_plugin.nr_tracks = cdda_nr_tracks;
  1166. cdda_plugin.track_seek = cdda_track_seek;
  1167. return &cdda_plugin;
  1168. }
  1169. #ifdef __cplusplus
  1170. }
  1171. #endif