Many informative comments courtesy of Peter J. Creath.

External accessible routines renamed to their libcdio name.
This commit is contained in:
rocky
2005-10-14 01:20:55 +00:00
parent 1d52037d81
commit 8c04ca8e04

View File

@@ -1,5 +1,5 @@
/* /*
$Id: paranoia.c,v 1.16 2005/10/08 09:08:10 rocky Exp $ $Id: paranoia.c,v 1.17 2005/10/14 01:20:55 rocky Exp $
Copyright (C) 2004, 2005 Rocky Bernstein <rocky@panix.com> Copyright (C) 2004, 2005 Rocky Bernstein <rocky@panix.com>
Copyright (C) 1998 Monty xiphmont@mit.edu Copyright (C) 1998 Monty xiphmont@mit.edu
@@ -235,7 +235,7 @@ do_const_sync(c_block_t *A,
ret=i_paranoia_overlap(cv(A), iv(B), posA, posB, ret=i_paranoia_overlap(cv(A), iv(B), posA, posB,
cs(A), is(B), begin, end); cs(A), is(B), begin, end);
else else
if((flagB[posB]&2)==0) if((flagB[posB]&FLAGS_UNREAD)==0)
ret=i_paranoia_overlap2(cv(A), iv(B), flagA, flagB, ret=i_paranoia_overlap2(cv(A), iv(B), flagA, flagB,
posA, posB, cs(A), is(B), posA, posB, cs(A), is(B),
begin, end); begin, end);
@@ -857,7 +857,7 @@ i_stage2_each(root_block *root, v_fragment_t *v,
free_v_fragment(v); free_v_fragment(v);
return(1); return(1);
}else{ } else {
/* D'oh. No match. What to do with the fragment? */ /* D'oh. No match. What to do with the fragment? */
if(fe(v)+dynoverlap<re(root) && !root->silenceflag){ if(fe(v)+dynoverlap<re(root) && !root->silenceflag){
/* It *should* have matched. No good; free it. */ /* It *should* have matched. No good; free it. */
@@ -1162,7 +1162,40 @@ paranoia_seek(cdrom_paranoia_t *p, off_t seek, int mode)
return(ret); return(ret);
} }
/* returns last block read, -1 on error */
/* ===========================================================================
* read_c_block() (internal)
*
* This funtion reads many (p->readahead) sectors, encompassing at least
* the requested words.
*
* It returns a c_block which encapsulates these sectors' data and sector
* number. The sectors come come from multiple low-level read requests.
*
* This function reads many sectors in order to exhaust any caching on the
* drive itself, as caching would simply return the same incorrect data
* over and over. Paranoia depends on truly re-reading portions of the
* disc to make sure the reads are accurate and correct any inaccuracies.
*
* Which precise sectors are read varies ("jiggles") between calls to
* read_c_block, to prevent consistent errors across multiple reads
* from being misinterpreted as correct data.
*
* The size of each low-level read is determined by the underlying driver
* (p->d->nsectors), which allows the driver to specify how many sectors
* can be read in a single request. Historically, the Linux kernel could
* only read 8 sectors at a time, with likely dropped samples between each
* read request. Other operating systems may have different limitations.
*
* This function is called by paranoia_read_limited(), which breaks the
* c_block of read data into runs of samples that are likely to be
* contiguous, verifies them and stores them in verified fragments, and
* eventually merges the fragments into the verified root.
*
* This function returns the last c_block read or NULL on error.
*/
static c_block_t * static c_block_t *
i_read_c_block(cdrom_paranoia_t *p,long beginword,long endword, i_read_c_block(cdrom_paranoia_t *p,long beginword,long endword,
void(*callback)(long, paranoia_cb_mode_t)) void(*callback)(long, paranoia_cb_mode_t))
@@ -1186,6 +1219,16 @@ i_read_c_block(cdrom_paranoia_t *p,long beginword,long endword,
long dynoverlap=(p->dynoverlap+CD_FRAMEWORDS-1)/CD_FRAMEWORDS; long dynoverlap=(p->dynoverlap+CD_FRAMEWORDS-1)/CD_FRAMEWORDS;
long anyflag=0; long anyflag=0;
/* Calculate the first sector to read. This calculation takes
* into account the need to jitter the starting point of the read
* to reveal consistent errors as well as the low reliability of
* the edge words of a read.
*
* ???: Document more clearly how dynoverlap and MIN_SECTOR_BACKUP
* are calculated and used.
*/
/* What is the first sector to read? want some pre-buffer if /* What is the first sector to read? want some pre-buffer if
we're not at the extreme beginning of the disc */ we're not at the extreme beginning of the disc */
@@ -1200,7 +1243,7 @@ i_read_c_block(cdrom_paranoia_t *p,long beginword,long endword,
if(target+MIN_SECTOR_BACKUP>p->lastread && target<=p->lastread) if(target+MIN_SECTOR_BACKUP>p->lastread && target<=p->lastread)
target=p->lastread-MIN_SECTOR_BACKUP; target=p->lastread-MIN_SECTOR_BACKUP;
/* we want to jitter the read alignment boundary, as some /* we want to jitter the read alignment boundary, as some
drives, beginning from a specific point, will tend to drives, beginning from a specific point, will tend to
lose bytes between sectors in the same place. Also, as lose bytes between sectors in the same place. Also, as
@@ -1232,13 +1275,29 @@ i_read_c_block(cdrom_paranoia_t *p,long beginword,long endword,
buffer=calloc(totaltoread*CDIO_CD_FRAMESIZE_RAW, 1); buffer=calloc(totaltoread*CDIO_CD_FRAMESIZE_RAW, 1);
sofar=0; sofar=0;
firstread=-1; firstread=-1;
/* Issue each of the low-level reads until we've read enough sectors
* to exhaust the drive's cache.
*
* p->readahead = total number of sectors to read
* p->d->nsectors = number of sectors to read per request
*
* The driver determines this latter number, which is the maximum
* number of sectors the kernel can reliably read per request. In
* old Linux kernels, there was a hard limit of 8 sectors per read.
* While this limit has since been removed, certain motherboards
* can't handle DMA requests larger than 64K. And other operating
* systems may have similar limitations. So the method of splitting
* up reads is still useful.
*/
/* actual read loop */ /* actual read loop */
while(sofar<totaltoread){ while(sofar<totaltoread){
long secread=sectatonce; long secread=sectatonce; /* number of sectors to read this request */
long adjread=readat; long adjread=readat; /* first sector to read for this request */
long thisread; long thisread; /* how many sectors were read this request */
/* don't under/overflow the audio session */ /* don't under/overflow the audio session */
if(adjread<p->current_firstsector){ if(adjread<p->current_firstsector){
@@ -1254,8 +1313,21 @@ i_read_c_block(cdrom_paranoia_t *p,long beginword,long endword,
if (firstread<0) firstread = adjread; if (firstread<0) firstread = adjread;
/* Issue the low-level read to the driver.
*/
thisread = cdda_read(p->d, buffer+sofar*CD_FRAMEWORDS, adjread, secread); thisread = cdda_read(p->d, buffer+sofar*CD_FRAMEWORDS, adjread, secread);
/* If the low-level read returned too few sectors, pad the result
* with null data and mark it as invalid (FLAGS_UNREAD). We pad
* because we're going to be appending further reads to the current
* c_block.
*
* ???: Why not re-read? It might be to keep you from getting
* hung up on a bad sector. Or it might be to avoid interrupting
* the streaming as much as possible.
*/
if ( thisread < secread) { if ( thisread < secread) {
if (thisread<0) thisread=0; if (thisread<0) thisread=0;
@@ -1272,7 +1344,21 @@ i_read_c_block(cdrom_paranoia_t *p,long beginword,long endword,
CD_FRAMEWORDS*(secread-thisread)); CD_FRAMEWORDS*(secread-thisread));
} }
if(thisread!=0)anyflag=1; if(thisread!=0)anyflag=1;
/* Because samples are likely to be dropped between read requests,
* mark the samples near the the boundaries of the read requests
* as suspicious (FLAGS_EDGE). This means that any span of samples
* against which these adjacent read requests are compared must
* overlap beyond the edges and into the more trustworthy data.
* Such overlapping spans are accordingly at least MIN_WORDS_OVERLAP
* words long (and naturally longer if any samples were dropped
* between the read requests).
*
* (EEEEE...overlapping span...EEEEE)
* (read 1 ...........EEEEE) (EEEEE...... read 2 ......EEEEE) ...
* dropped samples --^
*/
if(flags && sofar!=0){ if(flags && sofar!=0){
/* Don't verify across overlaps that are too close to one /* Don't verify across overlaps that are too close to one
another */ another */
@@ -1281,6 +1367,12 @@ i_read_c_block(cdrom_paranoia_t *p,long beginword,long endword,
flags[sofar*CD_FRAMEWORDS+i]|=FLAGS_EDGE; flags[sofar*CD_FRAMEWORDS+i]|=FLAGS_EDGE;
} }
/* Move the read cursor ahead by the number of sectors we attempted
* to read.
*
* ???: Again, why not move it ahead by the number actually read?
*/
p->lastread=adjread+secread; p->lastread=adjread+secread;
if(adjread+secread-1==p->current_lastsector) if(adjread+secread-1==p->current_lastsector)
@@ -1290,13 +1382,24 @@ i_read_c_block(cdrom_paranoia_t *p,long beginword,long endword,
sofar+=secread; sofar+=secread;
readat=adjread+secread; readat=adjread+secread;
} else } else /* secread <= 0 */
if(readat<p->current_firstsector) if(readat<p->current_firstsector)
readat+=sectatonce; /* due to being before the readable area */ readat+=sectatonce; /* due to being before the readable area */
else else
break; /* due to being past the readable area */ break; /* due to being past the readable area */
}
/* Keep issuing read requests until we've read enough sectors to
* exhaust the drive's cache.
*/
} /* end while */
/* If we managed to read any sectors at all (anyflag), create a new
* c_block containing the read data. Otherwise, free our buffers and
* return NULL.
*/
if (anyflag) { if (anyflag) {
new->vector=buffer; new->vector=buffer;
new->begin=firstread*CD_FRAMEWORDS-p->dyndrift; new->begin=firstread*CD_FRAMEWORDS-p->dyndrift;
@@ -1311,11 +1414,20 @@ i_read_c_block(cdrom_paranoia_t *p,long beginword,long endword,
return(new); return(new);
} }
/* The returned buffer is *not* to be freed by the caller. It will
persist only until the next call to paranoia_read() for this p */ /** ==========================================================================
* cdio_paranoia_read(), cdio_paranoia_read_limited()
*
* These functions "read" the next sector of audio data and returns
* a pointer to a full sector of verified samples (2352 bytes).
*
* The returned buffer is *not* to be freed by the caller. It will
* persist only until the next call to paranoia_read() for this p
*/
int16_t * int16_t *
paranoia_read(cdrom_paranoia_t *p, void(*callback)(long, paranoia_cb_mode_t)) cdio_paranoia_read(cdrom_paranoia_t *p,
void(*callback)(long, paranoia_cb_mode_t))
{ {
return paranoia_read_limited(p, callback, 20); return paranoia_read_limited(p, callback, 20);
} }
@@ -1324,9 +1436,9 @@ paranoia_read(cdrom_paranoia_t *p, void(*callback)(long, paranoia_cb_mode_t))
breaking any old apps using the nerw libs. cdparanoia 9.8 will breaking any old apps using the nerw libs. cdparanoia 9.8 will
need the updated libs, but nothing else will require it. */ need the updated libs, but nothing else will require it. */
int16_t * int16_t *
paranoia_read_limited(cdrom_paranoia_t *p, cdio_paranoia_read_limited(cdrom_paranoia_t *p,
void(*callback)(long int, paranoia_cb_mode_t), void(*callback)(long int, paranoia_cb_mode_t),
int max_retries) int max_retries)
{ {
long int beginword = p->cursor*(CD_FRAMEWORDS); long int beginword = p->cursor*(CD_FRAMEWORDS);
long int endword = beginword+CD_FRAMEWORDS; long int endword = beginword+CD_FRAMEWORDS;
@@ -1337,6 +1449,16 @@ paranoia_read_limited(cdrom_paranoia_t *p,
if (beginword > p->root.returnedlimit) if (beginword > p->root.returnedlimit)
p->root.returnedlimit=beginword; p->root.returnedlimit=beginword;
lastend=re(root); lastend=re(root);
/* Since paranoia reads and verifies chunks of data at a time
* (which it needs to counteract dropped samples and inaccurate
* seeking), the requested samples may already be in memory,
* in the verified "root".
*
* The root is where paranoia stores samples that have been
* verified and whose position has been accurately determined.
*/
/* First, is the sector we want already in the root? */ /* First, is the sector we want already in the root? */
while(rv(root)==NULL || while(rv(root)==NULL ||
@@ -1346,35 +1468,83 @@ paranoia_read_limited(cdrom_paranoia_t *p,
re(root)<endword){ re(root)<endword){
/* Nope; we need to build or extend the root verified range */ /* Nope; we need to build or extend the root verified range */
/* We may have already read the necessary samples and placed
* them into verified fragments, but not yet merged them into
* the verified root. We'll check that before we actually
* try to read data from the drive.
*/
if(p->enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)){ if(p->enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)){
/* We need to make sure our memory consumption doesn't grow
* to the size of the whole CD. But at the same time, we
* need to hang onto some of the verified data (even perhaps
* data that's already been returned by paranoia_read()) in
* order to verify and accurately position future samples.
*
* Therefore, we free some of the verified data that we
* no longer need.
*/
i_paranoia_trim(p,beginword,endword); i_paranoia_trim(p,beginword,endword);
recover_cache(p); recover_cache(p);
if(rb(root)!=-1 && p->root.lastsector) if(rb(root)!=-1 && p->root.lastsector)
i_end_case(p, endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS), i_end_case(p, endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS),
callback); callback);
else else
/* Merge as many verified fragments into the verified root
* as we need to satisfy the pending request. We may
* not have all the fragments we need, in which case we'll
* read data from the CD further below.
*/
i_stage2(p, beginword, i_stage2(p, beginword,
endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS), endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS),
callback); callback);
}else }else
i_end_case(p,endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS), i_end_case(p,endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS),
callback); /* only trips if we're already done */ callback); /* only trips if we're already done */
/* If we were able to fill the verified root with data already
* in memory, we don't need to read any more data from the drive.
*/
if(!(rb(root)==-1 || rb(root)>beginword || if(!(rb(root)==-1 || rb(root)>beginword ||
re(root)<endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS))) re(root)<endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS)))
break; break;
/* Hmm, need more. Read another block */ /* Hmm, need more. Read another block */
{ {
/* Read many sectors, encompassing at least the requested words.
*
* The returned c_block encapsulates these sectors' data and
* sector number. The sectors come come from multiple low-level
* read requests, and words which were near the boundaries of
* those read requests are marked with FLAGS_EDGE.
*/
c_block_t *new=i_read_c_block(p,beginword,endword,callback); c_block_t *new=i_read_c_block(p,beginword,endword,callback);
if(new){ if(new){
if(p->enable&(PARANOIA_MODE_OVERLAP|PARANOIA_MODE_VERIFY)){ if(p->enable&(PARANOIA_MODE_OVERLAP|PARANOIA_MODE_VERIFY)){
/* If we need to verify these samples, send them to
* stage 1 verification, which will add verified samples
* to the set of verified fragments. Verified fragments
* will be merged into the verified root during stage 2
* overlap analysis.
*/
if(p->enable&PARANOIA_MODE_VERIFY) if(p->enable&PARANOIA_MODE_VERIFY)
i_stage1(p,new,callback); i_stage1(p,new,callback);
/* If we're only doing overlapping reads (no stage 1
* verification), consider each low-level read in the
* c_block to be a verified fragment. We exclude the
* edges from these fragments to enforce the requirement
* that we overlap the reads by the minimum amount.
* These fragments will be merged into the verified
* root during stage 2 overlap analysis.
*/
else{ else{
/* just make v_fragments from the boundary information. */ /* just make v_fragments from the boundary information. */
long begin=0,end=0; long begin=0,end=0;
@@ -1394,6 +1564,11 @@ paranoia_read_limited(cdrom_paranoia_t *p,
}else{ }else{
/* If we're not doing any overlapping reads or verification
* of data, skip over the stage 1 and stage 2 verification and
* promote this c_block directly to the current "verified" root.
*/
if(p->root.vector)i_cblock_destructor(p->root.vector); if(p->root.vector)i_cblock_destructor(p->root.vector);
free_elem(new->e,0); free_elem(new->e,0);
p->root.vector=new; p->root.vector=new;
@@ -1406,7 +1581,10 @@ paranoia_read_limited(cdrom_paranoia_t *p,
} }
/* Are we doing lots of retries? **************************************/ /* Are we doing lots of retries? **************************************/
/* ???: To be studied
*/
/* Check unaddressable sectors first. There's no backoff here; /* Check unaddressable sectors first. There's no backoff here;
jiggle and minimum backseek handle that for us */ jiggle and minimum backseek handle that for us */
@@ -1438,15 +1616,25 @@ paranoia_read_limited(cdrom_paranoia_t *p,
} }
} }
} }
}
/* Having read data from the drive and placed it into verified
* fragments, we now loop back to try to extend the root with
* the newly loaded data. Alternatively, if the root already
* contains the needed data, we'll just fall through.
*/
} /* end while */
p->cursor++; p->cursor++;
/* Return a pointer into the verified root. Thus, the caller
* must NOT free the returned pointer!
*/
return(rv(root)+(beginword-rb(root))); return(rv(root)+(beginword-rb(root)));
} }
/* a temporary hack */ /* a temporary hack */
void void
paranoia_overlapset(cdrom_paranoia_t *p, long int overlap) cdio_paranoia_overlapset(cdrom_paranoia_t *p, long int overlap)
{ {
p->dynoverlap=overlap*CD_FRAMEWORDS; p->dynoverlap=overlap*CD_FRAMEWORDS;
p->stage1.offpoints=-1; p->stage1.offpoints=-1;