1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 30*7c478bd9Sstevel@tonic-gate #include <string.h> 31*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 32*7c478bd9Sstevel@tonic-gate #include <libintl.h> 33*7c478bd9Sstevel@tonic-gate #include <signal.h> 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate #include "bstream.h" 36*7c478bd9Sstevel@tonic-gate #include "util.h" 37*7c478bd9Sstevel@tonic-gate #include "misc_scsi.h" 38*7c478bd9Sstevel@tonic-gate #include "device.h" 39*7c478bd9Sstevel@tonic-gate #include "main.h" 40*7c478bd9Sstevel@tonic-gate #include "msgs.h" 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate #define BLOCK_SIZE 2352 43*7c478bd9Sstevel@tonic-gate #define READ_BURST_SIZE 200 44*7c478bd9Sstevel@tonic-gate #define SMALL_READ_BURST_SIZE 24 /* < 64K in all cases */ 45*7c478bd9Sstevel@tonic-gate #define READ_OVERLAP 7 46*7c478bd9Sstevel@tonic-gate #define BLOCKS_COMPARE 3 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate static int abort_read; 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate /* 51*7c478bd9Sstevel@tonic-gate * These are routines for extracting audio from a cd. During 52*7c478bd9Sstevel@tonic-gate * extraction we will also convert the audio type from the 53*7c478bd9Sstevel@tonic-gate * CD to the audio type specified on the command line. This 54*7c478bd9Sstevel@tonic-gate * handles both newer CD drives which support the MMC2 standard 55*7c478bd9Sstevel@tonic-gate * and older Sun Toshiba drives which need jitter correction. 56*7c478bd9Sstevel@tonic-gate */ 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate static bstreamhandle 59*7c478bd9Sstevel@tonic-gate open_audio_for_extraction(char *fname) 60*7c478bd9Sstevel@tonic-gate { 61*7c478bd9Sstevel@tonic-gate int at; 62*7c478bd9Sstevel@tonic-gate char *ext; 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate if (audio_type == AUDIO_TYPE_NONE) { 65*7c478bd9Sstevel@tonic-gate ext = (char *)(strrchr(fname, '.')); 66*7c478bd9Sstevel@tonic-gate if (ext) { 67*7c478bd9Sstevel@tonic-gate ext++; 68*7c478bd9Sstevel@tonic-gate } 69*7c478bd9Sstevel@tonic-gate if ((ext == NULL) || ((at = get_audio_type(ext)) == -1)) { 70*7c478bd9Sstevel@tonic-gate err_msg(gettext( 71*7c478bd9Sstevel@tonic-gate "Cannot understand file extension for %s\n"), 72*7c478bd9Sstevel@tonic-gate fname); 73*7c478bd9Sstevel@tonic-gate exit(1); 74*7c478bd9Sstevel@tonic-gate } 75*7c478bd9Sstevel@tonic-gate } else { 76*7c478bd9Sstevel@tonic-gate at = audio_type; 77*7c478bd9Sstevel@tonic-gate } 78*7c478bd9Sstevel@tonic-gate if (at == AUDIO_TYPE_SUN) 79*7c478bd9Sstevel@tonic-gate return (open_au_write_stream(fname)); 80*7c478bd9Sstevel@tonic-gate if (at == AUDIO_TYPE_WAV) 81*7c478bd9Sstevel@tonic-gate return (open_wav_write_stream(fname)); 82*7c478bd9Sstevel@tonic-gate if (at == AUDIO_TYPE_CDA) 83*7c478bd9Sstevel@tonic-gate return (open_file_write_stream(fname)); 84*7c478bd9Sstevel@tonic-gate if (at == AUDIO_TYPE_AUR) 85*7c478bd9Sstevel@tonic-gate return (open_aur_write_stream(fname)); 86*7c478bd9Sstevel@tonic-gate return (NULL); 87*7c478bd9Sstevel@tonic-gate } 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 90*7c478bd9Sstevel@tonic-gate static void 91*7c478bd9Sstevel@tonic-gate extract_signal_handler(int sig, siginfo_t *info, void *context) 92*7c478bd9Sstevel@tonic-gate { 93*7c478bd9Sstevel@tonic-gate abort_read = 1; 94*7c478bd9Sstevel@tonic-gate } 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate /* 97*7c478bd9Sstevel@tonic-gate * Older drives use different data buffer and m:s:f channels to transmit audio 98*7c478bd9Sstevel@tonic-gate * information. These channels may not be in sync with each other with the 99*7c478bd9Sstevel@tonic-gate * maximum disparity being the size of the data buffer. So handling is needed 100*7c478bd9Sstevel@tonic-gate * to keep these two channels in sync. 101*7c478bd9Sstevel@tonic-gate */ 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate static int 104*7c478bd9Sstevel@tonic-gate handle_jitter(uchar_t *buf, uchar_t *last_end) 105*7c478bd9Sstevel@tonic-gate { 106*7c478bd9Sstevel@tonic-gate int i; 107*7c478bd9Sstevel@tonic-gate for (i = BLOCK_SIZE*(READ_OVERLAP - BLOCKS_COMPARE); i >= 0; i -= 4) { 108*7c478bd9Sstevel@tonic-gate if (memcmp(last_end - BLOCK_SIZE * BLOCKS_COMPARE, buf + i, 109*7c478bd9Sstevel@tonic-gate BLOCK_SIZE * BLOCKS_COMPARE) == 0) { 110*7c478bd9Sstevel@tonic-gate return (i + (BLOCK_SIZE * BLOCKS_COMPARE)); 111*7c478bd9Sstevel@tonic-gate } 112*7c478bd9Sstevel@tonic-gate } 113*7c478bd9Sstevel@tonic-gate for (i = BLOCK_SIZE*(READ_OVERLAP - BLOCKS_COMPARE); 114*7c478bd9Sstevel@tonic-gate i < 2*READ_OVERLAP*BLOCK_SIZE; i += 4) { 115*7c478bd9Sstevel@tonic-gate if (memcmp(last_end - BLOCK_SIZE * BLOCKS_COMPARE, buf + i, 116*7c478bd9Sstevel@tonic-gate BLOCK_SIZE * BLOCKS_COMPARE) == 0) { 117*7c478bd9Sstevel@tonic-gate return (i + (BLOCK_SIZE * BLOCKS_COMPARE)); 118*7c478bd9Sstevel@tonic-gate } 119*7c478bd9Sstevel@tonic-gate } 120*7c478bd9Sstevel@tonic-gate return (-1); 121*7c478bd9Sstevel@tonic-gate } 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate int 124*7c478bd9Sstevel@tonic-gate read_audio_track(cd_device *dev, struct track_info *ti, bstreamhandle h) 125*7c478bd9Sstevel@tonic-gate { 126*7c478bd9Sstevel@tonic-gate uint32_t blocks_to_write, blocks_to_read, blks_to_overlap; 127*7c478bd9Sstevel@tonic-gate uint32_t start_blk, end_blk, c_blk; 128*7c478bd9Sstevel@tonic-gate uint32_t read_burst_size; 129*7c478bd9Sstevel@tonic-gate uchar_t *tmp, *buf, *prev, *previous_end; 130*7c478bd9Sstevel@tonic-gate int ret, off; 131*7c478bd9Sstevel@tonic-gate struct sigaction sv; 132*7c478bd9Sstevel@tonic-gate struct sigaction oldsv; 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate ret = 0; 135*7c478bd9Sstevel@tonic-gate abort_read = 0; 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate /* 138*7c478bd9Sstevel@tonic-gate * It is good to do small sized I/Os as we have seen many devices 139*7c478bd9Sstevel@tonic-gate * choke with large I/Os. But if the device does not support 140*7c478bd9Sstevel@tonic-gate * reading accurate CDDA then we have to do overlapped I/Os 141*7c478bd9Sstevel@tonic-gate * and reducing size might affect performance. So use small 142*7c478bd9Sstevel@tonic-gate * I/O size if device supports accurate CDDA. 143*7c478bd9Sstevel@tonic-gate */ 144*7c478bd9Sstevel@tonic-gate if (dev->d_cap & DEV_CAP_ACCURATE_CDDA) { 145*7c478bd9Sstevel@tonic-gate read_burst_size = SMALL_READ_BURST_SIZE; 146*7c478bd9Sstevel@tonic-gate } else { 147*7c478bd9Sstevel@tonic-gate read_burst_size = READ_BURST_SIZE; 148*7c478bd9Sstevel@tonic-gate } 149*7c478bd9Sstevel@tonic-gate buf = (uchar_t *)my_zalloc(BLOCK_SIZE * read_burst_size); 150*7c478bd9Sstevel@tonic-gate prev = (uchar_t *)my_zalloc(BLOCK_SIZE * read_burst_size); 151*7c478bd9Sstevel@tonic-gate start_blk = ti->ti_start_address; 152*7c478bd9Sstevel@tonic-gate end_blk = ti->ti_start_address + ti->ti_track_size - 1; 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate /* Even when we need jitter correction, this will be 0 1st time */ 155*7c478bd9Sstevel@tonic-gate blks_to_overlap = 0; 156*7c478bd9Sstevel@tonic-gate off = 0; 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate /* set up signal handler to write audio TOC if ^C is pressed */ 159*7c478bd9Sstevel@tonic-gate sv.sa_handler = extract_signal_handler; 160*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&sv.sa_mask); 161*7c478bd9Sstevel@tonic-gate sv.sa_flags = 0; 162*7c478bd9Sstevel@tonic-gate (void) sigaction(SIGINT, &sv, &oldsv); 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate if ((dev->d_cap & DEV_CAP_EXTRACT_CDDA) == 0) { 165*7c478bd9Sstevel@tonic-gate err_msg(gettext("Audio extraction method unknown for %s\n"), 166*7c478bd9Sstevel@tonic-gate dev->d_name ? dev->d_name : gettext("CD drive")); 167*7c478bd9Sstevel@tonic-gate exit(1); 168*7c478bd9Sstevel@tonic-gate } 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate /* if the speed option given, try to change the speed */ 171*7c478bd9Sstevel@tonic-gate if ((requested_speed != 0) && !cflag) { 172*7c478bd9Sstevel@tonic-gate if (verbose) 173*7c478bd9Sstevel@tonic-gate (void) printf(gettext("Trying to set speed to %dX.\n"), 174*7c478bd9Sstevel@tonic-gate requested_speed); 175*7c478bd9Sstevel@tonic-gate if (dev->d_speed_ctrl(dev, SET_READ_SPEED, 176*7c478bd9Sstevel@tonic-gate requested_speed) == 0) { 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate err_msg(gettext("Unable to set speed.\n")); 179*7c478bd9Sstevel@tonic-gate exit(1); 180*7c478bd9Sstevel@tonic-gate } 181*7c478bd9Sstevel@tonic-gate if (verbose) { 182*7c478bd9Sstevel@tonic-gate int speed; 183*7c478bd9Sstevel@tonic-gate speed = dev->d_speed_ctrl(dev, GET_READ_SPEED, 0); 184*7c478bd9Sstevel@tonic-gate if (speed == requested_speed) { 185*7c478bd9Sstevel@tonic-gate (void) printf(gettext("Speed set to %dX.\n"), 186*7c478bd9Sstevel@tonic-gate speed); 187*7c478bd9Sstevel@tonic-gate } else { 188*7c478bd9Sstevel@tonic-gate (void) printf(gettext( 189*7c478bd9Sstevel@tonic-gate "Speed set to closest approximation ")); 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate (void) printf(gettext( 192*7c478bd9Sstevel@tonic-gate "of %dX allowed by device (%dX).\n"), 193*7c478bd9Sstevel@tonic-gate requested_speed, speed); 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate } 196*7c478bd9Sstevel@tonic-gate } 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate print_n_flush( 199*7c478bd9Sstevel@tonic-gate gettext("Extracting audio from track %d..."), ti->ti_track_no); 200*7c478bd9Sstevel@tonic-gate init_progress(); 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate if (debug) 203*7c478bd9Sstevel@tonic-gate (void) printf("\nStarting: %d Ending: %d\n", 204*7c478bd9Sstevel@tonic-gate start_blk, end_blk); 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate blocks_to_write = 0; 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate for (c_blk = start_blk; c_blk < end_blk; c_blk += blocks_to_write) { 209*7c478bd9Sstevel@tonic-gate /* update progress indicator */ 210*7c478bd9Sstevel@tonic-gate (void) progress((void *) (end_blk - start_blk), 211*7c478bd9Sstevel@tonic-gate (int64_t)(c_blk - start_blk)); 212*7c478bd9Sstevel@tonic-gate blocks_to_read = end_blk - c_blk + blks_to_overlap; 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate /* 215*7c478bd9Sstevel@tonic-gate * Make sure we don't read more blocks than the maximum 216*7c478bd9Sstevel@tonic-gate * burst size. 217*7c478bd9Sstevel@tonic-gate */ 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate if (blocks_to_read > read_burst_size) 220*7c478bd9Sstevel@tonic-gate blocks_to_read = read_burst_size; 221*7c478bd9Sstevel@tonic-gate 222*7c478bd9Sstevel@tonic-gate if (dev->d_read_audio(dev, c_blk - blks_to_overlap, 223*7c478bd9Sstevel@tonic-gate blocks_to_read, buf) == 0) 224*7c478bd9Sstevel@tonic-gate goto read_audio_track_done; 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate /* 227*7c478bd9Sstevel@tonic-gate * This drive supports accurate audio extraction don't 228*7c478bd9Sstevel@tonic-gate * do jitter correction. 229*7c478bd9Sstevel@tonic-gate */ 230*7c478bd9Sstevel@tonic-gate if ((c_blk == start_blk) || 231*7c478bd9Sstevel@tonic-gate (dev->d_cap & DEV_CAP_ACCURATE_CDDA)) { 232*7c478bd9Sstevel@tonic-gate blocks_to_write = blocks_to_read; 233*7c478bd9Sstevel@tonic-gate previous_end = buf + (blocks_to_write * BLOCK_SIZE); 234*7c478bd9Sstevel@tonic-gate goto skip_jitter_correction; 235*7c478bd9Sstevel@tonic-gate } 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate if (c_blk == start_blk) 238*7c478bd9Sstevel@tonic-gate blks_to_overlap = 0; 239*7c478bd9Sstevel@tonic-gate else 240*7c478bd9Sstevel@tonic-gate blks_to_overlap = READ_OVERLAP; 241*7c478bd9Sstevel@tonic-gate off = handle_jitter(buf, previous_end); 242*7c478bd9Sstevel@tonic-gate if (off == -1) { 243*7c478bd9Sstevel@tonic-gate if (debug) 244*7c478bd9Sstevel@tonic-gate (void) printf( 245*7c478bd9Sstevel@tonic-gate "jitter control failed\n"); 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate /* recover if jitter correction failed */ 248*7c478bd9Sstevel@tonic-gate off = BLOCK_SIZE * BLOCKS_COMPARE; 249*7c478bd9Sstevel@tonic-gate } 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate blocks_to_write = blocks_to_read - blks_to_overlap; 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate while ((off + (blocks_to_write*BLOCK_SIZE)) > 254*7c478bd9Sstevel@tonic-gate (blocks_to_read * BLOCK_SIZE)) { 255*7c478bd9Sstevel@tonic-gate blocks_to_write--; 256*7c478bd9Sstevel@tonic-gate } 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate if ((blocks_to_write + c_blk) > end_blk) { 259*7c478bd9Sstevel@tonic-gate blocks_to_write = end_blk - c_blk; 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate if (blocks_to_write == 0) { 263*7c478bd9Sstevel@tonic-gate c_blk = end_blk - 1; 264*7c478bd9Sstevel@tonic-gate blocks_to_write = 1; 265*7c478bd9Sstevel@tonic-gate (void) memset(&buf[off], 0, off % BLOCK_SIZE); 266*7c478bd9Sstevel@tonic-gate } 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate previous_end = buf + off + blocks_to_write * BLOCK_SIZE; 269*7c478bd9Sstevel@tonic-gate skip_jitter_correction: 270*7c478bd9Sstevel@tonic-gate (void) memcpy(prev, buf, read_burst_size * BLOCK_SIZE); 271*7c478bd9Sstevel@tonic-gate if (h->bstr_write(h, &buf[off], blocks_to_write*BLOCK_SIZE) 272*7c478bd9Sstevel@tonic-gate < 0) 273*7c478bd9Sstevel@tonic-gate goto read_audio_track_done; 274*7c478bd9Sstevel@tonic-gate tmp = buf; 275*7c478bd9Sstevel@tonic-gate buf = prev; 276*7c478bd9Sstevel@tonic-gate prev = tmp; 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate if (abort_read == 1) 279*7c478bd9Sstevel@tonic-gate goto read_audio_track_done; 280*7c478bd9Sstevel@tonic-gate } 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate ret = 1; 283*7c478bd9Sstevel@tonic-gate (void) str_print(gettext("done.\n"), progress_pos); 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate read_audio_track_done: 286*7c478bd9Sstevel@tonic-gate (void) sigaction(SIGINT, &oldsv, (struct sigaction *)0); 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate free(buf); 289*7c478bd9Sstevel@tonic-gate free(prev); 290*7c478bd9Sstevel@tonic-gate return (ret); 291*7c478bd9Sstevel@tonic-gate } 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate void 294*7c478bd9Sstevel@tonic-gate extract_audio(void) 295*7c478bd9Sstevel@tonic-gate { 296*7c478bd9Sstevel@tonic-gate bstreamhandle h; 297*7c478bd9Sstevel@tonic-gate struct track_info *ti; 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate (void) check_device(target, CHECK_NO_MEDIA | CHECK_DEVICE_NOT_READY | 300*7c478bd9Sstevel@tonic-gate EXIT_IF_CHECK_FAILED); 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate ti = (struct track_info *)my_zalloc(sizeof (*ti)); 303*7c478bd9Sstevel@tonic-gate if (!build_track_info(target, extract_track_no, ti)) { 304*7c478bd9Sstevel@tonic-gate err_msg(gettext("Cannot get track information for track %d\n"), 305*7c478bd9Sstevel@tonic-gate extract_track_no); 306*7c478bd9Sstevel@tonic-gate exit(1); 307*7c478bd9Sstevel@tonic-gate } 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate /* Verify track */ 310*7c478bd9Sstevel@tonic-gate if ((ti->ti_track_size == 0) || ((ti->ti_flags & TI_NWA_VALID) && 311*7c478bd9Sstevel@tonic-gate (ti->ti_start_address == ti->ti_nwa))) { 312*7c478bd9Sstevel@tonic-gate err_msg(gettext("Track %d is empty\n"), extract_track_no); 313*7c478bd9Sstevel@tonic-gate exit(1); 314*7c478bd9Sstevel@tonic-gate } 315*7c478bd9Sstevel@tonic-gate if (ti->ti_track_mode & 4) { 316*7c478bd9Sstevel@tonic-gate err_msg(gettext("Track %d is not an audio track\n"), 317*7c478bd9Sstevel@tonic-gate extract_track_no); 318*7c478bd9Sstevel@tonic-gate exit(1); 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate if (ti->ti_data_mode == 2) { 321*7c478bd9Sstevel@tonic-gate err_msg(gettext("Track format is not supported\n")); 322*7c478bd9Sstevel@tonic-gate exit(1); 323*7c478bd9Sstevel@tonic-gate } 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate h = open_audio_for_extraction(extract_file); 326*7c478bd9Sstevel@tonic-gate if (h == NULL) { 327*7c478bd9Sstevel@tonic-gate err_msg(gettext("Cannot open %s:%s\n"), extract_file, 328*7c478bd9Sstevel@tonic-gate get_err_str()); 329*7c478bd9Sstevel@tonic-gate exit(1); 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate if (read_audio_track(target, ti, h) == 0) { 332*7c478bd9Sstevel@tonic-gate err_msg(gettext("Extract audio failed\n")); 333*7c478bd9Sstevel@tonic-gate h->bstr_close(h); 334*7c478bd9Sstevel@tonic-gate exit(1); 335*7c478bd9Sstevel@tonic-gate } 336*7c478bd9Sstevel@tonic-gate if (h->bstr_close(h) != 0) { 337*7c478bd9Sstevel@tonic-gate err_msg(gettext("Error closing audio stream : %s\n"), 338*7c478bd9Sstevel@tonic-gate get_err_str()); 339*7c478bd9Sstevel@tonic-gate exit(1); 340*7c478bd9Sstevel@tonic-gate } 341*7c478bd9Sstevel@tonic-gate exit(0); 342*7c478bd9Sstevel@tonic-gate } 343