4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/types.h>
37 #include "misc_scsi.h"
42 #define BLOCK_SIZE 2352
43 #define READ_BURST_SIZE 200
44 #define SMALL_READ_BURST_SIZE 24 /* < 64K in all cases */
45 #define READ_OVERLAP 7
46 #define BLOCKS_COMPARE 3
48 static int abort_read
;
51 * These are routines for extracting audio from a cd. During
52 * extraction we will also convert the audio type from the
53 * CD to the audio type specified on the command line. This
54 * handles both newer CD drives which support the MMC2 standard
55 * and older Sun Toshiba drives which need jitter correction.
59 open_audio_for_extraction(char *fname
)
64 if (audio_type
== AUDIO_TYPE_NONE
) {
65 ext
= (char *)(strrchr(fname
, '.'));
69 if ((ext
== NULL
) || ((at
= get_audio_type(ext
)) == -1)) {
71 "Cannot understand file extension for %s\n"),
78 if (at
== AUDIO_TYPE_SUN
)
79 return (open_au_write_stream(fname
));
80 if (at
== AUDIO_TYPE_WAV
)
81 return (open_wav_write_stream(fname
));
82 if (at
== AUDIO_TYPE_CDA
)
83 return (open_file_write_stream(fname
));
84 if (at
== AUDIO_TYPE_AUR
)
85 return (open_aur_write_stream(fname
));
91 extract_signal_handler(int sig
, siginfo_t
*info
, void *context
)
97 * Older drives use different data buffer and m:s:f channels to transmit audio
98 * information. These channels may not be in sync with each other with the
99 * maximum disparity being the size of the data buffer. So handling is needed
100 * to keep these two channels in sync.
104 handle_jitter(uchar_t
*buf
, uchar_t
*last_end
)
107 for (i
= BLOCK_SIZE
*(READ_OVERLAP
- BLOCKS_COMPARE
); i
>= 0; i
-= 4) {
108 if (memcmp(last_end
- BLOCK_SIZE
* BLOCKS_COMPARE
, buf
+ i
,
109 BLOCK_SIZE
* BLOCKS_COMPARE
) == 0) {
110 return (i
+ (BLOCK_SIZE
* BLOCKS_COMPARE
));
113 for (i
= BLOCK_SIZE
*(READ_OVERLAP
- BLOCKS_COMPARE
);
114 i
< 2*READ_OVERLAP
*BLOCK_SIZE
; i
+= 4) {
115 if (memcmp(last_end
- BLOCK_SIZE
* BLOCKS_COMPARE
, buf
+ i
,
116 BLOCK_SIZE
* BLOCKS_COMPARE
) == 0) {
117 return (i
+ (BLOCK_SIZE
* BLOCKS_COMPARE
));
124 read_audio_track(cd_device
*dev
, struct track_info
*ti
, bstreamhandle h
)
126 uint32_t blocks_to_write
, blocks_to_read
, blks_to_overlap
;
127 uint32_t start_blk
, end_blk
, c_blk
;
128 uint32_t read_burst_size
;
129 uchar_t
*tmp
, *buf
, *prev
, *previous_end
;
132 struct sigaction oldsv
;
138 * It is good to do small sized I/Os as we have seen many devices
139 * choke with large I/Os. But if the device does not support
140 * reading accurate CDDA then we have to do overlapped I/Os
141 * and reducing size might affect performance. So use small
142 * I/O size if device supports accurate CDDA.
144 if (dev
->d_cap
& DEV_CAP_ACCURATE_CDDA
) {
145 read_burst_size
= SMALL_READ_BURST_SIZE
;
147 read_burst_size
= READ_BURST_SIZE
;
149 buf
= (uchar_t
*)my_zalloc(BLOCK_SIZE
* read_burst_size
);
150 prev
= (uchar_t
*)my_zalloc(BLOCK_SIZE
* read_burst_size
);
151 start_blk
= ti
->ti_start_address
;
152 end_blk
= ti
->ti_start_address
+ ti
->ti_track_size
- 1;
154 /* Even when we need jitter correction, this will be 0 1st time */
158 /* set up signal handler to write audio TOC if ^C is pressed */
159 sv
.sa_handler
= extract_signal_handler
;
160 (void) sigemptyset(&sv
.sa_mask
);
162 (void) sigaction(SIGINT
, &sv
, &oldsv
);
164 if ((dev
->d_cap
& DEV_CAP_EXTRACT_CDDA
) == 0) {
165 err_msg(gettext("Audio extraction method unknown for %s\n"),
166 dev
->d_name
? dev
->d_name
: gettext("CD drive"));
170 /* if the speed option given, try to change the speed */
171 if ((requested_speed
!= 0) && !cflag
) {
173 (void) printf(gettext("Trying to set speed to %dX.\n"),
175 if (dev
->d_speed_ctrl(dev
, SET_READ_SPEED
,
176 requested_speed
) == 0) {
178 err_msg(gettext("Unable to set speed.\n"));
183 speed
= dev
->d_speed_ctrl(dev
, GET_READ_SPEED
, 0);
184 if (speed
== requested_speed
) {
185 (void) printf(gettext("Speed set to %dX.\n"),
187 } else if (speed
== 0) {
188 (void) printf(gettext("Could not obtain "
189 "current Read Speed.\n"));
191 (void) printf(gettext("Speed set to "
192 "closest approximation of %dX allowed "
193 "by device (%dX).\n"),
194 requested_speed
, speed
);
200 gettext("Extracting audio from track %d..."), ti
->ti_track_no
);
204 (void) printf("\nStarting: %d Ending: %d\n",
209 for (c_blk
= start_blk
; c_blk
< end_blk
; c_blk
+= blocks_to_write
) {
210 /* update progress indicator */
211 (void) progress((end_blk
- start_blk
),
212 (int64_t)(c_blk
- start_blk
));
213 blocks_to_read
= end_blk
- c_blk
+ blks_to_overlap
;
216 * Make sure we don't read more blocks than the maximum
220 if (blocks_to_read
> read_burst_size
)
221 blocks_to_read
= read_burst_size
;
223 if (dev
->d_read_audio(dev
, c_blk
- blks_to_overlap
,
224 blocks_to_read
, buf
) == 0)
225 goto read_audio_track_done
;
228 * This drive supports accurate audio extraction don't
229 * do jitter correction.
231 if ((c_blk
== start_blk
) ||
232 (dev
->d_cap
& DEV_CAP_ACCURATE_CDDA
)) {
233 blocks_to_write
= blocks_to_read
;
234 previous_end
= buf
+ (blocks_to_write
* BLOCK_SIZE
);
235 goto skip_jitter_correction
;
238 if (c_blk
== start_blk
)
241 blks_to_overlap
= READ_OVERLAP
;
242 off
= handle_jitter(buf
, previous_end
);
246 "jitter control failed\n");
248 /* recover if jitter correction failed */
249 off
= BLOCK_SIZE
* BLOCKS_COMPARE
;
252 blocks_to_write
= blocks_to_read
- blks_to_overlap
;
254 while ((off
+ (blocks_to_write
*BLOCK_SIZE
)) >
255 (blocks_to_read
* BLOCK_SIZE
)) {
259 if ((blocks_to_write
+ c_blk
) > end_blk
) {
260 blocks_to_write
= end_blk
- c_blk
;
263 if (blocks_to_write
== 0) {
266 (void) memset(&buf
[off
], 0, off
% BLOCK_SIZE
);
269 previous_end
= buf
+ off
+ blocks_to_write
* BLOCK_SIZE
;
270 skip_jitter_correction
:
271 (void) memcpy(prev
, buf
, read_burst_size
* BLOCK_SIZE
);
272 if (h
->bstr_write(h
, &buf
[off
], blocks_to_write
*BLOCK_SIZE
)
274 goto read_audio_track_done
;
280 goto read_audio_track_done
;
284 (void) str_print(gettext("done.\n"), progress_pos
);
286 read_audio_track_done
:
287 (void) sigaction(SIGINT
, &oldsv
, (struct sigaction
*)0);
298 struct track_info
*ti
;
300 (void) check_device(target
, CHECK_NO_MEDIA
| CHECK_DEVICE_NOT_READY
|
301 EXIT_IF_CHECK_FAILED
);
303 ti
= (struct track_info
*)my_zalloc(sizeof (*ti
));
304 if (!build_track_info(target
, extract_track_no
, ti
)) {
305 err_msg(gettext("Cannot get track information for track %d\n"),
311 if ((ti
->ti_track_size
== 0) || ((ti
->ti_flags
& TI_NWA_VALID
) &&
312 (ti
->ti_start_address
== ti
->ti_nwa
))) {
313 err_msg(gettext("Track %d is empty\n"), extract_track_no
);
316 if (ti
->ti_track_mode
& 4) {
317 err_msg(gettext("Track %d is not an audio track\n"),
321 if (ti
->ti_data_mode
== 2) {
322 err_msg(gettext("Track format is not supported\n"));
326 h
= open_audio_for_extraction(extract_file
);
328 err_msg(gettext("Cannot open %s:%s\n"), extract_file
,
332 if (read_audio_track(target
, ti
, h
) == 0) {
333 err_msg(gettext("Extract audio failed\n"));
337 if (h
->bstr_close(h
) != 0) {
338 err_msg(gettext("Error closing audio stream : %s\n"),