1 /* 2 * cdda - CD Digital Audio support 3 * 4 * Copyright (C) 1993-2004 Ti Kan 5 * E-mail: xmcd@amb.org 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 */ 21 22 /* 23 * HP-UX audio driver support 24 */ 25 #ifndef lint 26 static char *_wr_hpux_c_ident_ = "@(#)wr_hpux.c 7.66 04/03/24"; 27 #endif 28 29 #include "common_d/appenv.h" 30 #include "common_d/util.h" 31 #include "libdi_d/libdi.h" 32 #include "cdda_d/cdda.h" 33 #include "cdda_d/common.h" 34 35 #if defined(CDDA_WR_HPUX) && defined(CDDA_SUPPORTED) 36 37 #include <sys/audio.h> 38 #include "cdda_d/wr_gen.h" 39 #include "cdda_d/wr_hpux.h" 40 41 42 extern appdata_t app_data; 43 extern FILE *errfp; 44 45 STATIC int hpux_wsemid, /* Semaphores identifier */ 46 hpux_outport = 0, /* Output port */ 47 hpux_vol_max, /* Max volume */ 48 hpux_vol_half, /* Half volume */ 49 hpux_vol_offset, /* Volume offset */ 50 hpux_curr_vol0, /* Previous ch0 volume */ 51 hpux_curr_vol1; /* Previous ch1 volume */ 52 STATIC pid_t hpux_pipe_pid = -1; /* Pipe to program pid */ 53 STATIC cd_state_t *hpux_wcd; /* Shared memory pointer */ 54 STATIC bool_t hpux_write_dev, /* Write to audio device */ 55 hpux_write_file, /* Write to output file */ 56 hpux_write_pipe, /* Pipe to program */ 57 hpux_file_be = FALSE; /* Big endian output file */ 58 STATIC gen_desc_t *hpux_audio_desc = NULL,/* Audio device desc */ 59 *hpux_file_desc = NULL, /* Output file desc */ 60 *hpux_pipe_desc = NULL; /* Pipe to program desc */ 61 STATIC unsigned int hpux_file_mode; /* Output file mode */ 62 63 64 /* 65 * hpuxaud_scale_vol 66 * Scale volume from xmcd 0-100 to HP-UX audio device values 67 * 68 * Args: 69 * vol - xmcd volume 0-100 70 * 71 * Return: 72 * HP-UX volume value 73 */ 74 STATIC int 75 hpuxaud_scale_vol(int vol) 76 { 77 int n; 78 79 n = ((vol * hpux_vol_max) / 100); 80 if (((vol * hpux_vol_max) % 100) >= 50) 81 n++; 82 83 /* Range checking */ 84 if (n > hpux_vol_max) 85 n = hpux_vol_max; 86 87 return (n - hpux_vol_offset); 88 } 89 90 91 /* 92 * hpuxaud_unscale_vol 93 * Scale volume from HP-UX audio device values to xmcd 0-100 94 * 95 * Args: 96 * vol - HP-UX volume value 97 * 98 * Return: 99 * xmcd volume 0-100 100 */ 101 STATIC int 102 hpuxaud_unscale_vol(int vol) 103 { 104 int n; 105 106 n = ((vol + hpux_vol_offset) * 100) / hpux_vol_max; 107 if (((vol * 100) % hpux_vol_max) >= hpux_vol_half) 108 n++; 109 110 /* Range checking */ 111 if (n < 0) 112 n = 0; 113 else if (n > 100) 114 n = 100; 115 116 return (n); 117 } 118 119 120 /* 121 * hpuxaud_open_dev 122 * Opens the audio device. 123 * 124 * Args: 125 * None. 126 * 127 * Return: 128 * FALSE - failure 129 * TRUE - success 130 */ 131 STATIC bool_t 132 hpuxaud_open_dev(void) 133 { 134 char *cp; 135 struct stat stbuf; 136 137 if (!gen_set_eid(hpux_wcd)) 138 return FALSE; 139 140 /* Use environment variable if set */ 141 if ((cp = getenv("AUDIODEV")) == NULL) 142 cp = DEFAULT_DEV_AUDIO; 143 144 /* Check to make sure it's a device */ 145 if (stat(cp, &stbuf) < 0 || !S_ISCHR(stbuf.st_mode)) { 146 (void) sprintf(hpux_wcd->i->msgbuf, 147 "hpuxaud_open_dev: " 148 "%s is not a character device", 149 cp); 150 DBGPRN(DBG_SND)(errfp, "%s\n", hpux_wcd->i->msgbuf); 151 (void) gen_reset_eid(hpux_wcd); 152 return FALSE; 153 } 154 155 /* Open audio device */ 156 hpux_audio_desc = gen_open_file( 157 hpux_wcd, cp, O_RDWR, 0, FILEFMT_RAW, 0 158 ); 159 if (hpux_audio_desc == NULL) { 160 (void) sprintf(hpux_wcd->i->msgbuf, 161 "hpuxaud_open_dev: open of %s failed (errno=%d)", 162 cp, errno); 163 DBGPRN(DBG_SND)(errfp, "%s\n", hpux_wcd->i->msgbuf); 164 (void) gen_reset_eid(hpux_wcd); 165 return FALSE; 166 } 167 168 (void) gen_reset_eid(hpux_wcd); 169 return TRUE; 170 } 171 172 173 /* 174 * hpuxaud_close_dev 175 * Closes the audio device. 176 * 177 * Args: 178 * None. 179 * 180 * Return: 181 * FALSE - failure 182 * TRUE - success 183 */ 184 STATIC bool_t 185 hpuxaud_close_dev(void) 186 { 187 if (!gen_set_eid(hpux_wcd)) 188 return FALSE; 189 190 /* Close audio device */ 191 (void) gen_close_file(hpux_audio_desc); 192 hpux_audio_desc = NULL; 193 194 (void) gen_reset_eid(hpux_wcd); 195 return TRUE; 196 } 197 198 199 /* 200 * hpuxaud_gethw_vol 201 * Query hardware volume settings and update structures. 202 * 203 * Args: 204 * None. 205 * 206 * Return: 207 * TRUE - success 208 * FALSE - failure 209 */ 210 STATIC bool_t 211 hpuxaud_gethw_vol(void) 212 { 213 int vol0, 214 vol1, 215 val; 216 struct audio_gain again; 217 218 /* Retrieve current gain settings */ 219 (void) memset(&again, 0, sizeof(again)); 220 again.channel_mask = AUDIO_CHANNEL_0 | AUDIO_CHANNEL_1; 221 222 if (!gen_ioctl(hpux_audio_desc, AUDIO_GET_GAINS, &again)) { 223 (void) sprintf(hpux_wcd->i->msgbuf, 224 "hpuxaud_set_info: " 225 "AUDIO_GET_GAINS failed (errno=%d)", 226 errno); 227 DBGPRN(DBG_SND)(errfp, "%s\n", hpux_wcd->i->msgbuf); 228 return FALSE; 229 } 230 231 vol0 = hpuxaud_unscale_vol(again.cgain[0].transmit_gain); 232 vol1 = hpuxaud_unscale_vol(again.cgain[1].transmit_gain); 233 234 if (vol0 == hpux_curr_vol0 && vol1 == hpux_curr_vol1) 235 /* No change */ 236 return TRUE; 237 238 hpux_curr_vol0 = vol0; 239 hpux_curr_vol1 = vol1; 240 241 /* Update volume and balance */ 242 if (vol0 == vol1) { 243 hpux_wcd->i->vol = util_untaper_vol(vol0); 244 hpux_wcd->i->vol_left = 100; 245 hpux_wcd->i->vol_right = 100; 246 } 247 else if (vol0 > vol1) { 248 hpux_wcd->i->vol = util_untaper_vol(vol0); 249 hpux_wcd->i->vol_left = 100; 250 hpux_wcd->i->vol_right = (vol1 * 100) / vol0; 251 val = vol0 >> 1; 252 if (((vol1 * 100) % vol0) >= val) 253 hpux_wcd->i->vol_right++; 254 } 255 else { 256 hpux_wcd->i->vol = util_untaper_vol(vol1); 257 hpux_wcd->i->vol_right = 100; 258 hpux_wcd->i->vol_left = (vol0 * 100) / vol1; 259 val = vol1 >> 1; 260 if (((vol0 * 100) % vol1) >= val) 261 hpux_wcd->i->vol_left++; 262 } 263 264 return TRUE; 265 } 266 267 268 /* 269 * hpuxaud_set_outport 270 * Set CDDA playback output port. 271 * 272 * Args: 273 * outport - New output port selector bitmap CDDA_OUT_XXX 274 * 275 * Return: 276 * Nothing. 277 */ 278 STATIC void 279 hpuxaud_set_outport(int outport) 280 { 281 int val; 282 283 if (outport != 0 && outport != hpux_outport) { 284 val = 0; 285 if ((outport & CDDA_OUT_SPEAKER) != 0) 286 val |= AUDIO_OUT_SPEAKER; 287 if ((outport & CDDA_OUT_HEADPHONE) != 0) 288 val |= AUDIO_OUT_HEADPHONE; 289 if ((outport & CDDA_OUT_LINEOUT) != 0) 290 val |= AUDIO_OUT_LINE; 291 292 if (!gen_ioctl(hpux_audio_desc, AUDIO_SET_OUTPUT, 293 (void *) val)) { 294 (void) sprintf(hpux_wcd->i->msgbuf, 295 "hpuxaud_set_outport: " 296 "AUDIO_SET_OUTPUT (0x%x) " 297 "failed (errno=%d)", 298 val, errno); 299 DBGPRN(DBG_SND)(errfp, "%s\n", hpux_wcd->i->msgbuf); 300 } 301 302 hpux_outport = outport; 303 } 304 } 305 306 307 /* 308 * hpuxaud_config 309 * Sets up audio device for playing CD quality audio. 310 * 311 * Args: 312 * None. 313 * 314 * Return: 315 * FALSE - failure 316 * TRUE - success 317 */ 318 STATIC bool_t 319 hpuxaud_config(void) 320 { 321 struct audio_limits alimits; 322 struct audio_describe adesc; 323 324 /* Set data format */ 325 if (!gen_ioctl(hpux_audio_desc, AUDIO_SET_DATA_FORMAT, 326 (void *) AUDIO_FORMAT_LINEAR16BIT)) { 327 (void) sprintf(hpux_wcd->i->msgbuf, 328 "hpuxaud_config: " 329 "AUDIO_SET_DATA_FORMAT failed (errno=%d)", 330 errno); 331 DBGPRN(DBG_SND)(errfp, "%s\n", hpux_wcd->i->msgbuf); 332 return FALSE; 333 } 334 335 /* Set number of channels */ 336 if (!gen_ioctl(hpux_audio_desc, AUDIO_SET_CHANNELS, (void *) 2)) { 337 (void) sprintf(hpux_wcd->i->msgbuf, 338 "hpuxaud_config: " 339 "AUDIO_SET_CHANNELS failed (errno=%d)", 340 errno); 341 DBGPRN(DBG_SND)(errfp, "%s\n", hpux_wcd->i->msgbuf); 342 return FALSE; 343 } 344 345 /* Set sampling rate */ 346 if (!gen_ioctl(hpux_audio_desc, AUDIO_SET_SAMPLE_RATE, 347 (void *) 44100)) { 348 (void) sprintf(hpux_wcd->i->msgbuf, 349 "hpuxaud_config: " 350 "AUDIO_SET_SAMPLE_RATE failed (errno=%d)", 351 errno); 352 DBGPRN(DBG_SND)(errfp, "%s\n", hpux_wcd->i->msgbuf); 353 return FALSE; 354 } 355 356 /* Get volume control range */ 357 (void) memset(&adesc, 0, sizeof(adesc)); 358 if (!gen_ioctl(hpux_audio_desc, AUDIO_DESCRIBE, &adesc)) { 359 (void) sprintf(hpux_wcd->i->msgbuf, 360 "hpuxaud_set_info: " 361 "AUDIO_GET_GAINS failed (errno=%d)", 362 errno); 363 DBGPRN(DBG_SND)(errfp, "%s\n", hpux_wcd->i->msgbuf); 364 365 hpux_vol_max = HPUX_MAX_VOL; 366 hpux_vol_half = HPUX_HALF_VOL; 367 hpux_vol_offset = HPUX_VOL_OFFSET; 368 } 369 else { 370 hpux_vol_max = 371 adesc.max_transmit_gain - adesc.min_transmit_gain; 372 hpux_vol_half = hpux_vol_max >> 1; 373 hpux_vol_offset = 0 - adesc.min_transmit_gain; 374 } 375 376 /* Set audio output port */ 377 hpuxaud_set_outport(hpux_wcd->i->outport); 378 379 /* Check buffer sizes - informational only */ 380 (void) memset(&alimits, 0, sizeof(alimits)); 381 if (!gen_ioctl(hpux_audio_desc, AUDIO_GET_LIMITS, &alimits)) { 382 (void) sprintf(hpux_wcd->i->msgbuf, 383 "hpuxaud_config: " 384 "AUDIO_GET_LIMITS failed (errno=%d)", 385 errno); 386 DBGPRN(DBG_SND)(errfp, "%s\n", hpux_wcd->i->msgbuf); 387 } 388 else { 389 DBGPRN(DBG_SND)(errfp, "recv_bufs=%d xmit_bufs=%d\n", 390 alimits.max_receive_buffer_size, 391 alimits.max_transmit_buffer_size); 392 } 393 394 /* Query current volume settings */ 395 hpux_curr_vol0 = hpux_curr_vol1 = -1; 396 if (!hpuxaud_gethw_vol()) 397 return FALSE; 398 399 return TRUE; 400 } 401 402 403 /* 404 * hpuxaud_update 405 * Updates hardware volume and balance settings from GUI settings. 406 * 407 * Args: 408 * None. 409 * 410 * Return: 411 * Nothing. 412 */ 413 STATIC void 414 hpuxaud_update(void) 415 { 416 int vol0, 417 vol1, 418 val; 419 struct audio_gain again; 420 static int curr_vol0 = -1, 421 curr_vol1 = -1; 422 423 app_data.vol_taper = hpux_wcd->i->vol_taper; 424 425 /* Set audio output port */ 426 hpuxaud_set_outport(hpux_wcd->i->outport); 427 428 (void) memset(&again, 0, sizeof(again)); 429 430 if (hpux_wcd->i->vol_left == hpux_wcd->i->vol_right) { 431 vol0 = util_taper_vol(hpux_wcd->i->vol); 432 vol1 = vol0; 433 again.cgain[0].transmit_gain = hpuxaud_scale_vol(vol0); 434 again.cgain[1].transmit_gain = again.cgain[0].transmit_gain; 435 } 436 else if (hpux_wcd->i->vol_left > hpux_wcd->i->vol_right) { 437 val = (hpux_wcd->i->vol * hpux_wcd->i->vol_right) / 100; 438 if (((hpux_wcd->i->vol * hpux_wcd->i->vol_right) % 100) >= 50) 439 val++; 440 vol0 = util_taper_vol(hpux_wcd->i->vol); 441 vol1 = util_taper_vol(val); 442 again.cgain[0].transmit_gain = hpuxaud_scale_vol(vol0); 443 again.cgain[1].transmit_gain = hpuxaud_scale_vol(vol1); 444 } 445 else { 446 val = (hpux_wcd->i->vol * hpux_wcd->i->vol_left) / 100; 447 if (((hpux_wcd->i->vol * hpux_wcd->i->vol_left) % 100) >= 50) 448 val++; 449 vol0 = util_taper_vol(val); 450 vol1 = util_taper_vol(hpux_wcd->i->vol); 451 again.cgain[0].transmit_gain = hpuxaud_scale_vol(vol0); 452 again.cgain[1].transmit_gain = hpuxaud_scale_vol(vol1); 453 } 454 455 if (vol0 == curr_vol0 && vol1 == curr_vol1) 456 /* No change */ 457 return; 458 459 curr_vol0 = vol0; 460 curr_vol1 = vol1; 461 462 /* Apply new settings */ 463 again.channel_mask = AUDIO_CHANNEL_0 | AUDIO_CHANNEL_1; 464 465 if (!gen_ioctl(hpux_audio_desc, AUDIO_SET_GAINS, &again)) { 466 (void) sprintf(hpux_wcd->i->msgbuf, 467 "hpuxaud_set_info: " 468 "AUDIO_SET_GAINS failed (errno=%d)", 469 errno); 470 DBGPRN(DBG_SND)(errfp, "%s\n", hpux_wcd->i->msgbuf); 471 } 472 } 473 474 475 /* 476 * hpuxaud_status 477 * Updates volume and balance settings from audio device. 478 * 479 * Args: 480 * None. 481 * 482 * Return: 483 * Nothing. 484 */ 485 STATIC void 486 hpuxaud_status(void) 487 { 488 (void) hpuxaud_gethw_vol(); 489 } 490 491 492 /* 493 * hpuxaud_write 494 * Function responsible for writing from the buffer to the audio 495 * device (and file if saving). 496 * 497 * Args: 498 * s - Pointer to the curstat_t structure 499 * 500 * Return: 501 * FALSE - failure 502 * TRUE - success 503 */ 504 STATIC bool_t 505 hpuxaud_write(curstat_t *s) 506 { 507 byte_t *in_data, 508 *sw_data, 509 *le_data, 510 *be_data, 511 *dev_data, 512 *file_data, 513 *pipe_data; 514 char *fname = NULL; 515 int trk_idx = -1, 516 hbcnt = 1; 517 time_t start_time, 518 tot_time; 519 bool_t ret; 520 521 /* Get memory for audio device write buffer */ 522 le_data = (byte_t *) MEM_ALLOC("le_data", hpux_wcd->cds->chunk_bytes); 523 if (le_data == NULL) { 524 (void) sprintf(hpux_wcd->i->msgbuf, 525 "hpuxaud_write: out of memory"); 526 DBGPRN(DBG_GEN)(errfp, "%s\n", hpux_wcd->i->msgbuf); 527 return FALSE; 528 } 529 530 /* Get memory for audio file write buffer */ 531 be_data = (byte_t *) MEM_ALLOC("be_data", hpux_wcd->cds->chunk_bytes); 532 if (be_data == NULL) { 533 MEM_FREE(le_data); 534 (void) sprintf(hpux_wcd->i->msgbuf, 535 "hpuxaud_write: out of memory"); 536 DBGPRN(DBG_GEN)(errfp, "%s\n", hpux_wcd->i->msgbuf); 537 return FALSE; 538 } 539 540 (void) memset(le_data, 0, hpux_wcd->cds->chunk_bytes); 541 (void) memset(be_data, 0, hpux_wcd->cds->chunk_bytes); 542 543 in_data = app_data.cdda_bigendian ? be_data : le_data; 544 sw_data = app_data.cdda_bigendian ? le_data : be_data; 545 546 /* Start time */ 547 start_time = time(NULL); 548 549 /* While not stopped */ 550 ret = TRUE; 551 while (hpux_wcd->i->state != CDSTAT_COMPLETED) { 552 /* Get lock */ 553 cdda_waitsem(hpux_wsemid, LOCK); 554 555 /* End if finished and nothing in the buffer */ 556 if (hpux_wcd->cdb->occupied == 0 && hpux_wcd->i->cdda_done) { 557 hpux_wcd->i->state = CDSTAT_COMPLETED; 558 cdda_postsem(hpux_wsemid, LOCK); 559 break; 560 } 561 562 /* Wait until there is something there */ 563 while (hpux_wcd->cdb->occupied <= 0 && 564 hpux_wcd->i->state != CDSTAT_COMPLETED) { 565 cdda_postsem(hpux_wsemid, LOCK); 566 cdda_waitsem(hpux_wsemid, DATA); 567 cdda_waitsem(hpux_wsemid, LOCK); 568 } 569 570 /* Break if stopped */ 571 if (hpux_wcd->i->state == CDSTAT_COMPLETED) { 572 cdda_postsem(hpux_wsemid, LOCK); 573 break; 574 } 575 576 /* Set the current track and track length info */ 577 cdda_wr_setcurtrk(hpux_wcd); 578 579 /* Copy a chunk from the nextout slot into the data buffers */ 580 (void) memcpy( 581 in_data, 582 &hpux_wcd->cdb->b[ 583 hpux_wcd->cds->chunk_bytes * hpux_wcd->cdb->nextout 584 ], 585 hpux_wcd->cds->chunk_bytes 586 ); 587 588 /* Update pointers */ 589 hpux_wcd->cdb->nextout++; 590 hpux_wcd->cdb->nextout %= hpux_wcd->cds->buffer_chunks; 591 hpux_wcd->cdb->occupied--; 592 593 /* Set heartbeat and interval, update stats */ 594 if (--hbcnt == 0) { 595 cdda_heartbeat(&hpux_wcd->i->writer_hb,CDDA_HB_WRITER); 596 597 tot_time = time(NULL) - start_time; 598 if (tot_time > 0 && hpux_wcd->i->frm_played > 0) { 599 hpux_wcd->i->frm_per_sec = (int) 600 ((float) hpux_wcd->i->frm_played / 601 (float) tot_time) + 0.5; 602 } 603 604 hbcnt = cdda_heartbeat_interval( 605 hpux_wcd->i->frm_per_sec 606 ); 607 } 608 609 /* Signal room available */ 610 cdda_postsem(hpux_wsemid, ROOM); 611 612 /* Release lock */ 613 cdda_postsem(hpux_wsemid, LOCK); 614 615 /* Change channel routing and attenuation if necessary */ 616 gen_chroute_att(hpux_wcd->i->chroute, 617 hpux_wcd->i->att, 618 (sword16_t *)(void *) in_data, 619 (size_t) hpux_wcd->cds->chunk_bytes); 620 621 /* Prepare byte-swapped version of the data */ 622 gen_byteswap(in_data, sw_data, 623 (size_t) hpux_wcd->cds->chunk_bytes); 624 625 /* Write to device */ 626 if (hpux_write_dev) { 627 /* Always feed HP-UX audio driver big endian data */ 628 dev_data = be_data; 629 630 if (!gen_write_chunk(hpux_audio_desc, dev_data, 631 (size_t) hpux_wcd->cds->chunk_bytes)) { 632 hpux_wcd->i->state = CDSTAT_COMPLETED; 633 cdda_postsem(hpux_wsemid, LOCK); 634 ret = FALSE; 635 break; 636 } 637 638 /* Update volume and balance settings */ 639 hpuxaud_update(); 640 641 if ((hpux_wcd->i->frm_played % FRAME_PER_SEC) == 0) 642 hpuxaud_status(); 643 } 644 645 /* Write to file */ 646 if (hpux_write_file) { 647 file_data = hpux_file_be ? be_data : le_data; 648 649 /* Open new track file if necessary */ 650 if (!app_data.cdda_trkfile) { 651 fname = s->trkinfo[0].outfile; 652 } 653 else if (trk_idx != hpux_wcd->i->trk_idx) { 654 trk_idx = hpux_wcd->i->trk_idx; 655 656 if (hpux_file_desc != NULL && 657 !gen_close_file(hpux_file_desc)) { 658 hpux_wcd->i->state = CDSTAT_COMPLETED; 659 cdda_postsem(hpux_wsemid, LOCK); 660 ret = FALSE; 661 break; 662 } 663 664 fname = s->trkinfo[trk_idx].outfile; 665 hpux_file_desc = gen_open_file( 666 hpux_wcd, 667 fname, 668 O_WRONLY | O_TRUNC | O_CREAT, 669 (mode_t) hpux_file_mode, 670 app_data.cdda_filefmt, 671 hpux_wcd->i->trk_len 672 ); 673 if (hpux_file_desc == NULL) { 674 hpux_wcd->i->state = CDSTAT_COMPLETED; 675 cdda_postsem(hpux_wsemid, LOCK); 676 ret = FALSE; 677 break; 678 } 679 } 680 681 if (!gen_write_chunk(hpux_file_desc, file_data, 682 (size_t) hpux_wcd->cds->chunk_bytes)) { 683 hpux_wcd->i->state = CDSTAT_COMPLETED; 684 cdda_postsem(hpux_wsemid, LOCK); 685 ret = FALSE; 686 break; 687 } 688 } 689 690 /* Pipe to program */ 691 if (hpux_write_pipe) { 692 pipe_data = hpux_file_be ? be_data : le_data; 693 694 if (!gen_write_chunk(hpux_pipe_desc, pipe_data, 695 (size_t) hpux_wcd->cds->chunk_bytes)) { 696 hpux_wcd->i->state = CDSTAT_COMPLETED; 697 cdda_postsem(hpux_wsemid, LOCK); 698 ret = FALSE; 699 break; 700 } 701 } 702 703 hpux_wcd->i->frm_played += hpux_wcd->cds->chunk_blocks; 704 705 while (hpux_wcd->i->state == CDSTAT_PAUSED) 706 util_delayms(400); 707 708 /* Update debug level */ 709 app_data.debug = hpux_wcd->i->debug; 710 } 711 712 /* Wake up reader */ 713 cdda_postsem(hpux_wsemid, ROOM); 714 715 /* Free memory */ 716 MEM_FREE(le_data); 717 MEM_FREE(be_data); 718 719 return (ret); 720 } 721 722 723 /* 724 * hpux_winit 725 * Pre-playback support check function 726 * 727 * Args: 728 * None. 729 * 730 * Return: 731 * Bitmask of supported features 732 */ 733 word32_t 734 hpux_winit(void) 735 { 736 return (CDDA_WRITEDEV | CDDA_WRITEFILE | CDDA_WRITEPIPE); 737 } 738 739 740 /* 741 * hpux_write 742 * Opens audio device/file, attaches shared memory and semaphores. 743 * Continuously reads data from shared memory and writes it 744 * to the audio device/file. 745 * 746 * Args: 747 * s - Pointer to the curstat_t structure 748 * 749 * Return: 750 * FALSE - failure 751 * TRUE - success 752 */ 753 bool_t 754 hpux_write(curstat_t *s) 755 { 756 size_t estlen; 757 758 if (!PLAYMODE_IS_CDDA(app_data.play_mode)) { 759 (void) fprintf(errfp, "hpux_write: Nothing to do.\n"); 760 return FALSE; 761 } 762 763 hpux_write_dev = (bool_t) ((app_data.play_mode & PLAYMODE_CDDA) != 0); 764 hpux_write_file = (bool_t) ((app_data.play_mode & PLAYMODE_FILE) != 0); 765 hpux_write_pipe = (bool_t) ((app_data.play_mode & PLAYMODE_PIPE) != 0); 766 767 /* Generic services initialization */ 768 gen_write_init(); 769 770 /* Allocate memory */ 771 hpux_wcd = (cd_state_t *) MEM_ALLOC("cd_state_t", sizeof(cd_state_t)); 772 if (hpux_wcd == NULL) { 773 (void) fprintf(errfp, "hpux_write: out of memory\n"); 774 return FALSE; 775 } 776 (void) memset(hpux_wcd, 0, sizeof(cd_state_t)); 777 778 /* Initialize shared memory and semaphores */ 779 if ((hpux_wsemid = cdda_initipc(hpux_wcd)) < 0) 780 return FALSE; 781 782 (void) sscanf(app_data.cdinfo_filemode, "%o", &hpux_file_mode); 783 /* Make sure file is at least accessible by user */ 784 hpux_file_mode |= S_IRUSR | S_IWUSR; 785 hpux_file_mode &= ~(S_ISUID | S_ISGID | S_IWGRP | S_IWOTH); 786 787 estlen = (hpux_wcd->i->end_lba - hpux_wcd->i->start_lba + 1) * 788 CDDA_BLKSZ; 789 790 /* Set heartbeat */ 791 cdda_heartbeat(&hpux_wcd->i->writer_hb, CDDA_HB_WRITER); 792 793 if (hpux_write_file || hpux_write_pipe) { 794 /* Open file and/or pipe */ 795 if (!app_data.cdda_trkfile && hpux_write_file) { 796 hpux_file_desc = gen_open_file( 797 hpux_wcd, 798 s->trkinfo[0].outfile, 799 O_WRONLY | O_TRUNC | O_CREAT, 800 (mode_t) hpux_file_mode, 801 app_data.cdda_filefmt, 802 estlen 803 ); 804 if (hpux_file_desc == NULL) 805 return FALSE; 806 } 807 808 if (hpux_write_pipe) { 809 hpux_pipe_desc = gen_open_pipe( 810 hpux_wcd, 811 app_data.pipeprog, 812 &hpux_pipe_pid, 813 app_data.cdda_filefmt, 814 estlen 815 ); 816 if (hpux_pipe_desc == NULL) 817 return FALSE; 818 819 DBGPRN(DBG_SND)(errfp, 820 "\nhpuxaud_write: Pipe to [%s]: " 821 "chunk_blks=%d\n", 822 app_data.pipeprog, 823 hpux_wcd->cds->chunk_blocks); 824 } 825 826 /* Set endian */ 827 hpux_file_be = gen_filefmt_be(app_data.cdda_filefmt); 828 } 829 830 if (hpux_write_dev) { 831 /* Open audio device */ 832 if (!hpuxaud_open_dev()) 833 return FALSE; 834 835 /* Configure audio */ 836 if (!hpuxaud_config()) 837 return FALSE; 838 839 /* Initial settings */ 840 hpuxaud_update(); 841 } 842 843 /* Do the writing */ 844 if (!hpuxaud_write(s)) 845 return FALSE; 846 847 return TRUE; 848 } 849 850 851 /* 852 * hpux_wdone 853 * Post-playback cleanup function 854 * 855 * Args: 856 * killreader - whether to terminate the reader thread or process 857 * 858 * Return: 859 * Nothing. 860 */ 861 void 862 hpux_wdone(bool_t killreader) 863 { 864 DBGPRN(DBG_GEN)(errfp, "\nhpux_wdone: Cleaning up writer\n"); 865 866 if (hpux_audio_desc != NULL) 867 (void) hpuxaud_close_dev(); 868 869 if (hpux_file_desc != NULL) { 870 (void) gen_close_file(hpux_file_desc); 871 hpux_file_desc = NULL; 872 } 873 874 if (hpux_pipe_desc != NULL) { 875 (void) gen_close_pipe(hpux_pipe_desc); 876 hpux_pipe_desc = NULL; 877 } 878 879 cdda_yield(); 880 881 if (hpux_pipe_pid > 0) { 882 (void) kill(hpux_pipe_pid, SIGTERM); 883 hpux_pipe_pid = -1; 884 } 885 886 if (hpux_wcd != NULL) { 887 if (hpux_wcd->i != NULL) { 888 if (killreader && hpux_wcd->i->reader != (thid_t) 0) { 889 cdda_kill(hpux_wcd->i->reader, SIGTERM); 890 hpux_wcd->i->state = CDSTAT_COMPLETED; 891 } 892 893 /* Reset frames played counter */ 894 hpux_wcd->i->frm_played = 0; 895 } 896 897 MEM_FREE(hpux_wcd); 898 hpux_wcd = NULL; 899 } 900 901 hpux_write_dev = hpux_write_file = hpux_write_pipe = FALSE; 902 } 903 904 905 /* 906 * hpux_winfo 907 * Append method identification to informational string. 908 * 909 * Args: 910 * str - The informational string 911 * 912 * Return: 913 * Nothing. 914 */ 915 void 916 hpux_winfo(char *str) 917 { 918 (void) strcat(str, "HP-UX audio driver\n"); 919 } 920 921 #endif /* CDDA_WR_HPUX CDDA_SUPPORTED */ 922 923