File indexing completed on 2024-05-05 09:08:27
0001 /* 0002 * This file is part of WorkMan, the civilized CD player library 0003 * Copyright (C) Alexander Kern <alex.kern@gmx.de> 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Library General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2 of the License, or (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Library General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Library General Public 0016 * License along with this library; if not, write to the Free 0017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0018 */ 0019 0020 #include <string.h> 0021 #include <sys/poll.h> 0022 #include <sys/wait.h> 0023 #include <arpa/inet.h> /* For htonl(3) */ 0024 #include <stdio.h> 0025 #include <unistd.h> 0026 #include "include/wm_config.h" 0027 #include "include/wm_struct.h" 0028 #include "include/wm_cdda.h" 0029 #include "include/wm_cdrom.h" 0030 #include "include/wm_helpers.h" 0031 #include "include/wm_scsi.h" 0032 #include "audio/audio.h" 0033 0034 #include <pthread.h> 0035 0036 static pthread_t thread_read; 0037 static pthread_t thread_play; 0038 0039 /* CDDABLKSIZE give us the 588 samples 4 bytes each(16 bit x 2 channel) 0040 by rate 44100 HZ, 588 samples are 1/75 sec 0041 if we read 15 frames(8820 samples), we get in each block, data for 1/5 sec */ 0042 #define COUNT_CDDA_FRAMES_PER_BLOCK 15 0043 0044 /* Only Linux and Sun define the number of blocks explicitly; assume all 0045 other systems are like Linux and have 10 blocks. 0046 */ 0047 #ifndef COUNT_CDDA_BLOCKS 0048 #define COUNT_CDDA_BLOCKS 10 0049 #endif 0050 0051 static struct wm_cdda_block blks[COUNT_CDDA_BLOCKS]; 0052 static pthread_mutex_t blks_mutex[COUNT_CDDA_BLOCKS]; 0053 static pthread_cond_t wakeup_audio; 0054 0055 /* 0056 * This is non-null if we're saving audio to a file. 0057 */ 0058 static FILE *output = NULL; 0059 0060 /* 0061 * These are driverdependent oops 0062 * 0063 */ 0064 static struct audio_oops *oops = NULL; 0065 0066 /* 0067 * Audio file header format. 0068 */ 0069 typedef unsigned long u_32; 0070 struct auheader { 0071 u_32 magic; 0072 u_32 hdr_size; 0073 u_32 data_size; 0074 u_32 encoding; 0075 u_32 sample_rate; 0076 u_32 channels; 0077 }; 0078 0079 static int cdda_status(struct wm_drive *d, int oldmode, 0080 int *mode, int *frame, int *track, int *ind) 0081 { 0082 if (d->cddax) { 0083 if(d->status) 0084 *mode = d->status; 0085 else 0086 *mode = oldmode; 0087 0088 if (*mode == WM_CDM_PLAYING) { 0089 *track = d->track; 0090 *ind = d->index; 0091 *frame = d->frame; 0092 } else if (*mode == WM_CDM_CDDAERROR) { 0093 /* 0094 * An error near the end of the CD probably 0095 * just means we hit the end. 0096 */ 0097 *mode = WM_CDM_TRACK_DONE; 0098 } 0099 0100 return 0; 0101 } 0102 0103 return -1; 0104 } 0105 0106 static int cdda_play(struct wm_drive *d, int start, int end) 0107 { 0108 if (d->cddax) { 0109 d->command = WM_CDM_STOPPED; 0110 oops->wmaudio_stop(); 0111 0112 /* wait before reader, stops */ 0113 while(d->status != d->command) 0114 wm_susleep(1000); 0115 0116 d->current_position = start; 0117 d->ending_position = end; 0118 0119 d->track = -1; 0120 d->index = 0; 0121 d->frame = start; 0122 d->status = d->command = WM_CDM_PLAYING; 0123 0124 return 0; 0125 } 0126 0127 return -1; 0128 } 0129 0130 static int cdda_pause(struct wm_drive *d) 0131 { 0132 if (d->cddax) { 0133 if(WM_CDM_PLAYING == d->command) { 0134 d->command = WM_CDM_PAUSED; 0135 if(oops->wmaudio_pause) 0136 oops->wmaudio_pause(); 0137 } else { 0138 d->command = WM_CDM_PLAYING; 0139 } 0140 0141 return 0; 0142 } 0143 0144 return -1; 0145 } 0146 0147 static int cdda_stop(struct wm_drive *d) 0148 { 0149 if (d->cddax) { 0150 d->command = WM_CDM_STOPPED; 0151 oops->wmaudio_stop(); 0152 return 0; 0153 } 0154 0155 return -1; 0156 } 0157 0158 static int cdda_set_volume(struct wm_drive *d, int left, int right) 0159 { 0160 if (d->cddax) { 0161 if(oops->wmaudio_balvol && !oops->wmaudio_balvol(1, &left, &right)) 0162 return 0; 0163 } 0164 0165 return -1; 0166 } 0167 0168 static int cdda_get_volume(struct wm_drive *d, int *left, int *right) 0169 { 0170 if (d->cddax) { 0171 if(oops->wmaudio_balvol && !oops->wmaudio_balvol(0, left, right)) 0172 return 0; 0173 } 0174 0175 return -1; 0176 } 0177 0178 #if 0 0179 /* 0180 * Tell the CDDA slave to start (or stop) saving to a file. 0181 */ 0182 void 0183 cdda_save(struct wm_drive *, char *) 0184 { 0185 0186 int len; 0187 0188 if (filename == NULL || filename[0] == '\0') 0189 len = 0; 0190 else 0191 len = strlen(filename); 0192 write(d->cdda_slave, "F", 1); 0193 write(d->cdda_slave, &len, sizeof(len)); 0194 if (len) 0195 write(d->cdda_slave, filename, len); 0196 0197 0198 read(0, &namelen, sizeof(namelen)); 0199 if (output != NULL) { 0200 fclose(output); 0201 output = NULL; 0202 } 0203 if (namelen) { 0204 filename = malloc(namelen + 1); 0205 if (filename == NULL) { 0206 perror("cddas"); 0207 wmcdda_close(cdda_device); 0208 oops->wmaudio_close(); 0209 exit(1); 0210 } 0211 0212 read(0, filename, namelen); 0213 filename[namelen] = '\0'; 0214 output = fopen(filename, "w"); 0215 if (output == NULL) { 0216 perror(filename); 0217 } else { 0218 /* Write an .au file header. */ 0219 hdr.magic = htonl(0x2e736e64); 0220 hdr.hdr_size = htonl(sizeof(hdr) + 28); 0221 hdr.data_size = htonl(~0); 0222 hdr.encoding = htonl(3); /* linear-16 */ 0223 hdr.sample_rate = htonl(44100); 0224 hdr.channels = htonl(2); 0225 0226 fwrite(&hdr, sizeof(hdr), 1, output); 0227 fwrite("Recorded from CD by WorkMan", 28, 1, output); 0228 } 0229 free(filename); 0230 0231 } 0232 #endif 0233 0234 static int get_next_block(int x) 0235 { 0236 int y = ++x; 0237 return (y < COUNT_CDDA_BLOCKS)?y:0; 0238 } 0239 0240 static void *cdda_fct_read(void* arg) 0241 { 0242 struct wm_drive *d = (struct wm_drive *)arg; 0243 int i, j, wakeup; 0244 long result; 0245 0246 while (d->blocks) { 0247 while(d->command != WM_CDM_PLAYING) { 0248 d->status = d->command; 0249 wm_susleep(1000); 0250 } 0251 0252 i = 0; 0253 (void) pthread_mutex_lock(&blks_mutex[i]); 0254 wakeup = 1; 0255 0256 while(d->command == WM_CDM_PLAYING) { 0257 result = gen_cdda_read(d, &blks[i]); 0258 if (result <= 0 && blks[i].status != WM_CDM_TRACK_DONE) { 0259 ERRORLOG("cdda: wmcdda_read failed, stop playing\n"); 0260 d->command = WM_CDM_STOPPED; 0261 break; 0262 } else { 0263 if (output) 0264 fwrite(blks[i].buf, blks[i].buflen, 1, output); 0265 } 0266 0267 j = get_next_block(i); 0268 (void) pthread_mutex_lock(&blks_mutex[j]); 0269 0270 if(wakeup) { 0271 wakeup = 0; 0272 pthread_cond_signal(&wakeup_audio); 0273 } 0274 0275 (void) pthread_mutex_unlock(&blks_mutex[i]); 0276 /* audio can start here */ 0277 0278 i = j; 0279 } 0280 0281 (void) pthread_mutex_unlock(&blks_mutex[i]); 0282 } 0283 0284 return 0; 0285 } 0286 0287 static void *cdda_fct_play(void* arg) 0288 { 0289 struct wm_drive *d = (struct wm_drive *)arg; 0290 int i = 0; 0291 0292 while (d->blocks) { 0293 if(d->command != WM_CDM_PLAYING) { 0294 i = 0; 0295 (void) pthread_mutex_lock(&blks_mutex[i]); 0296 pthread_cond_wait(&wakeup_audio, &blks_mutex[i]); 0297 } else { 0298 i = get_next_block(i); 0299 (void) pthread_mutex_lock(&blks_mutex[i]); 0300 } 0301 0302 if (oops->wmaudio_play(&blks[i])) { 0303 oops->wmaudio_stop(); 0304 ERRORLOG("cdda: wmaudio_play failed\n"); 0305 d->command = WM_CDM_STOPPED; 0306 } 0307 if (oops->wmaudio_state) 0308 oops->wmaudio_state(&blks[i]); 0309 0310 d->frame = blks[i].frame; 0311 d->track = blks[i].track; 0312 d->index = blks[i].index; 0313 if ((d->status = blks[i].status) == WM_CDM_TRACK_DONE) 0314 d->command = WM_CDM_STOPPED; 0315 0316 (void) pthread_mutex_unlock(&blks_mutex[i]); 0317 } 0318 0319 return 0; 0320 } 0321 0322 /* 0323 * Try to initialize the CDDA slave. Returns 0 on success. 0324 */ 0325 int wm_cdda_init(struct wm_drive *d) 0326 { 0327 int ret = 0; 0328 0329 if (d->cddax) { 0330 wm_cdda_destroy(d); 0331 0332 wm_susleep(1000); 0333 d->blocks = 0; 0334 wm_susleep(1000); 0335 } 0336 0337 memset(blks, 0, sizeof(blks)); 0338 0339 d->blocks = blks; 0340 d->frames_at_once = COUNT_CDDA_FRAMES_PER_BLOCK; 0341 d->numblocks = COUNT_CDDA_BLOCKS; 0342 d->status = WM_CDM_UNKNOWN; 0343 0344 if ((ret = gen_cdda_init(d))) 0345 return ret; 0346 0347 if ((ret = gen_cdda_open(d))) 0348 return ret; 0349 0350 wm_scsi_set_speed(d, 4); 0351 0352 oops = setup_soundsystem(d->soundsystem, d->sounddevice, d->ctldevice); 0353 if (!oops) { 0354 ERRORLOG("cdda: setup_soundsystem failed\n"); 0355 gen_cdda_close(d); 0356 return -1; 0357 } 0358 0359 if(pthread_create(&thread_read, NULL, cdda_fct_read, d)) { 0360 ERRORLOG("error by create pthread"); 0361 oops->wmaudio_close(); 0362 gen_cdda_close(d); 0363 return -1; 0364 } 0365 0366 if(pthread_create(&thread_play, NULL, cdda_fct_play, d)) { 0367 ERRORLOG("error by create pthread"); 0368 oops->wmaudio_close(); 0369 gen_cdda_close(d); 0370 return -1; 0371 } 0372 0373 d->proto.get_drive_status = cdda_status; 0374 d->proto.pause = cdda_pause; 0375 d->proto.resume = NULL; 0376 d->proto.stop = cdda_stop; 0377 d->proto.play = cdda_play; 0378 d->proto.set_volume = cdda_set_volume; 0379 d->proto.get_volume = cdda_get_volume; 0380 d->proto.scale_volume = NULL; 0381 d->proto.unscale_volume = NULL; 0382 0383 d->cddax = (void *)1; 0384 0385 return 0; 0386 } 0387 0388 int wm_cdda_destroy(struct wm_drive *d) 0389 { 0390 if (d->cddax) { 0391 wm_scsi_set_speed(d, -1); 0392 0393 d->command = WM_CDM_STOPPED; 0394 oops->wmaudio_stop(); 0395 wm_susleep(2000); 0396 gen_cdda_close(d); 0397 oops->wmaudio_close(); 0398 0399 d->numblocks = 0; 0400 d->blocks = NULL; 0401 wait(NULL); 0402 d->cddax = NULL; 0403 } 0404 return 0; 0405 }