PageRenderTime 60ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/broken_gtk2_interface/alsaplayer/input/cdda/cdda_engine.c

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