xref: /titanic_52/usr/src/cmd/cdrw/dae.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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