PageRenderTime 55ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/Release-0-99-77/alsaplayer/input/cdda/cdda_engine.c

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