Applied cleaned up patch originally by Ziusudra as part of ticket #3473:
* Changed the session module to create an extra session for existing audio tracks. * Let cdda also recognize "audio partitions" as published by the session module. * If there is only a single session, the session module now gives file system drivers the chance to play with the device directly. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41288 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -544,9 +544,9 @@ is_data_track(const scsi_toc_track& track)
|
|||||||
uint32
|
uint32
|
||||||
count_audio_tracks(scsi_toc_toc* toc)
|
count_audio_tracks(scsi_toc_toc* toc)
|
||||||
{
|
{
|
||||||
uint32 lastTrack = toc->last_track + 1 - toc->first_track;
|
uint32 trackCount = toc->last_track + 1 - toc->first_track;
|
||||||
uint32 count = 0;
|
uint32 count = 0;
|
||||||
for (uint32 i = 0; i < lastTrack; i++) {
|
for (uint32 i = 0; i < trackCount; i++) {
|
||||||
if (!is_data_track(toc->tracks[i]))
|
if (!is_data_track(toc->tracks[i]))
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@@ -1330,8 +1330,10 @@ Inode::RemoveAttribute(const char* name, bool checkNamespace)
|
|||||||
AttrCookieList::Iterator i = fAttrCookies.GetIterator();
|
AttrCookieList::Iterator i = fAttrCookies.GetIterator();
|
||||||
while (i.HasNext()) {
|
while (i.HasNext()) {
|
||||||
attr_cookie* cookie = i.Next();
|
attr_cookie* cookie = i.Next();
|
||||||
if (cookie->current == attribute)
|
if (cookie->current == attribute) {
|
||||||
cookie->current = attribute->GetDoublyLinkedListLink()->next;
|
cookie->current
|
||||||
|
= attribute->GetDoublyLinkedListLink()->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator.Remove();
|
iterator.Remove();
|
||||||
@@ -1378,11 +1380,41 @@ cdda_identify_partition(int fd, partition_data* partition, void** _cookie)
|
|||||||
|
|
||||||
status_t status = read_table_of_contents(fd, toc, 2048);
|
status_t status = read_table_of_contents(fd, toc, 2048);
|
||||||
|
|
||||||
// there has to be at least a single audio track
|
// If we succeeded in reading the toc, check the tracks in the
|
||||||
if (status == B_OK && count_audio_tracks(toc) == 0)
|
// partition, which may not be the whole CD, and if any are audio,
|
||||||
status = B_BAD_TYPE;
|
// claim the partition.
|
||||||
|
if (status == B_OK) {
|
||||||
|
uint32 trackCount = toc->last_track + (uint32)1 - toc->first_track;
|
||||||
|
uint64 sessionStartLBA = partition->offset / partition->block_size;
|
||||||
|
uint64 sessionEndLBA = sessionStartLBA
|
||||||
|
+ (partition->size / partition->block_size);
|
||||||
|
TRACE(("cdda_identify_partition: session at %lld-%lld\n",
|
||||||
|
sessionStartLBA, sessionEndLBA));
|
||||||
|
status = B_ENTRY_NOT_FOUND;
|
||||||
|
for (uint32 i = 0; i < trackCount; i++) {
|
||||||
|
// We have to get trackLBA from track.start.time since
|
||||||
|
// track.start.lba is useless for this.
|
||||||
|
// This is how session gets it.
|
||||||
|
uint64 trackLBA
|
||||||
|
= ((toc->tracks[i].start.time.minute * kFramesPerMinute)
|
||||||
|
+ (toc->tracks[i].start.time.second * kFramesPerSecond)
|
||||||
|
+ toc->tracks[i].start.time.frame - 150);
|
||||||
|
if (trackLBA >= sessionStartLBA && trackLBA < sessionEndLBA) {
|
||||||
|
if (is_data_track(toc->tracks[i])) {
|
||||||
|
TRACE(("cdda_identify_partition: track %ld at %lld is "
|
||||||
|
"data\n", i + 1, trackLBA));
|
||||||
|
status = B_BAD_TYPE;
|
||||||
|
} else {
|
||||||
|
TRACE(("cdda_identify_partition: track %ld at %lld is "
|
||||||
|
"audio\n", i + 1, trackLBA));
|
||||||
|
status = B_OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (status < B_OK) {
|
if (status != B_OK) {
|
||||||
free(toc);
|
free(toc);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -1740,7 +1772,8 @@ cdda_read_stat(fs_volume* _volume, fs_vnode* _node, struct stat* stat)
|
|||||||
Volume* volume = (Volume*)_volume->private_volume;
|
Volume* volume = (Volume*)_volume->private_volume;
|
||||||
Inode* inode = (Inode*)_node->private_node;
|
Inode* inode = (Inode*)_node->private_node;
|
||||||
|
|
||||||
TRACE(("cdda_read_stat: vnode %p (0x%Lx), stat %p\n", inode, inode->ID(), stat));
|
TRACE(("cdda_read_stat: vnode %p (0x%Lx), stat %p\n", inode, inode->ID(),
|
||||||
|
stat));
|
||||||
|
|
||||||
fill_stat_buffer(volume, inode, NULL, *stat);
|
fill_stat_buffer(volume, inode, NULL, *stat);
|
||||||
|
|
||||||
@@ -1819,7 +1852,8 @@ cdda_read_dir(fs_volume* _volume, fs_vnode* _node, void* _cookie,
|
|||||||
Volume* volume = (Volume*)_volume->private_volume;
|
Volume* volume = (Volume*)_volume->private_volume;
|
||||||
Inode* inode = (Inode*)_node->private_node;
|
Inode* inode = (Inode*)_node->private_node;
|
||||||
|
|
||||||
TRACE(("cdda_read_dir: vnode %p, cookie %p, buffer = %p, bufferSize = %ld, num = %p\n", _node, _cookie, dirent, bufferSize,_num));
|
TRACE(("cdda_read_dir: vnode %p, cookie %p, buffer = %p, bufferSize = %ld,"
|
||||||
|
" num = %p\n", _node, _cookie, buffer, bufferSize,_num));
|
||||||
|
|
||||||
if ((Inode*)_node->private_node != &volume->RootNode())
|
if ((Inode*)_node->private_node != &volume->RootNode())
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -1915,7 +1949,7 @@ cdda_free_dir_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie)
|
|||||||
{
|
{
|
||||||
dir_cookie* cookie = (dir_cookie*)_cookie;
|
dir_cookie* cookie = (dir_cookie*)_cookie;
|
||||||
|
|
||||||
TRACE(("cdda_freecookie: entry vnode %p, cookie %p\n", _vnode, cookie));
|
TRACE(("cdda_freecookie: entry vnode %p, cookie %p\n", _node, cookie));
|
||||||
|
|
||||||
free(cookie);
|
free(cookie);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2009, Haiku, Inc.
|
* Copyright 2003-2011, Haiku, Inc.
|
||||||
* Distributed under the terms of the MIT license.
|
* Distributed under the terms of the MIT license.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -86,9 +86,9 @@ public:
|
|||||||
|
|
||||||
off_t start_lba;
|
off_t start_lba;
|
||||||
uint8 control;
|
uint8 control;
|
||||||
//!< only used to give what are probably useless warnings
|
// Used to check for Yellow/Red Book mixed-mode CDs.
|
||||||
uint8 adr;
|
uint8 adr;
|
||||||
//!< only used to give what are probably useless warnings
|
// only used to give what are probably useless warnings
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -548,12 +548,13 @@ Disc::Disc(int fd)
|
|||||||
int count;
|
int count;
|
||||||
|
|
||||||
header = (cdrom_table_of_contents_header*)data;
|
header = (cdrom_table_of_contents_header*)data;
|
||||||
entries = (cdrom_full_table_of_contents_entry*)(data+4);
|
entries = (cdrom_full_table_of_contents_entry*)(data + 4);
|
||||||
header->length = B_BENDIAN_TO_HOST_INT16(header->length);
|
header->length = B_BENDIAN_TO_HOST_INT16(header->length);
|
||||||
|
|
||||||
count = (header->length - 2)
|
count = (header->length - 2)
|
||||||
/ sizeof(cdrom_full_table_of_contents_entry);
|
/ sizeof(cdrom_full_table_of_contents_entry);
|
||||||
|
|
||||||
|
count = _AdjustForYellowBook(entries, count);
|
||||||
error = _ParseTableOfContents(entries, count);
|
error = _ParseTableOfContents(entries, count);
|
||||||
// Dump();
|
// Dump();
|
||||||
if (!error) {
|
if (!error) {
|
||||||
@@ -696,6 +697,92 @@ Disc::Dump()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! \brief Checks for Yellow Book data tracks in audio sessions and if found
|
||||||
|
inserts them as a new data session.
|
||||||
|
*/
|
||||||
|
uint32
|
||||||
|
Disc::_AdjustForYellowBook(cdrom_full_table_of_contents_entry entries[],
|
||||||
|
uint32 count)
|
||||||
|
{
|
||||||
|
uint8 foundCount = 0;
|
||||||
|
uint8 endLBAEntry = 0;
|
||||||
|
uint8 trackTwo = 0;
|
||||||
|
|
||||||
|
// Make sure TOC has only one session and that it is audio.
|
||||||
|
bool sessionIsAudio = true;
|
||||||
|
for (uint32 i = 0; i < count; i++) {
|
||||||
|
if (entries[i].point == 0xa2) {
|
||||||
|
if ((entries[i].control & kControlDataTrack) != 0) {
|
||||||
|
sessionIsAudio = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
foundCount++;
|
||||||
|
endLBAEntry = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!sessionIsAudio || foundCount != 1)
|
||||||
|
return count;
|
||||||
|
|
||||||
|
TRACE(("%s: Single audio session, checking for data track\n",
|
||||||
|
kModuleDebugName));
|
||||||
|
|
||||||
|
// See if there are any data tracks.
|
||||||
|
for (uint32 i = 0; i < count; i++) {
|
||||||
|
if (entries[i].point > 0 && entries[i].point < 100
|
||||||
|
&& (entries[i].control & kControlDataTrack) != 0) {
|
||||||
|
if (entries[i].point == 1) {
|
||||||
|
// Create a new endLBA point for session one.
|
||||||
|
entries[count] = entries[endLBAEntry];
|
||||||
|
entries[count].control = entries[i].control;
|
||||||
|
|
||||||
|
// Get track two and use it's start as
|
||||||
|
// the end of our new session.
|
||||||
|
for (uint8 j = 0; j < count; j++) {
|
||||||
|
if (entries[j].point == 2) {
|
||||||
|
trackTwo = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entries[count].pminutes = entries[trackTwo].pminutes;
|
||||||
|
entries[count].pseconds = entries[trackTwo].pseconds;
|
||||||
|
entries[count].pframes = entries[trackTwo].pframes;
|
||||||
|
|
||||||
|
// Change the other points to session two.
|
||||||
|
for (uint32 j = 0; j < count; j++) {
|
||||||
|
entries[j].session = 2;
|
||||||
|
}
|
||||||
|
entries[i].session = 1;
|
||||||
|
|
||||||
|
count++;
|
||||||
|
TRACE(("%s: first track is data, adjusted TOC\n",
|
||||||
|
kModuleDebugName));
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// Change the track to session two.
|
||||||
|
entries[i].session = 2;
|
||||||
|
|
||||||
|
// Create a new endLBA point for session two.
|
||||||
|
entries[count] = entries[endLBAEntry];
|
||||||
|
entries[count].session = 2;
|
||||||
|
entries[count].control = entries[i].control;
|
||||||
|
|
||||||
|
// Use the beginning of the data track as the
|
||||||
|
// end of the previous session.
|
||||||
|
entries[endLBAEntry].pminutes = entries[i].pminutes;
|
||||||
|
entries[endLBAEntry].pseconds = entries[i].pseconds;
|
||||||
|
entries[endLBAEntry].pframes = entries[i].pframes;
|
||||||
|
|
||||||
|
count++;
|
||||||
|
TRACE(("%s: last track is data, adjusted TOC\n",
|
||||||
|
kModuleDebugName));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! \brief Reads through the given table of contents data and creates an
|
/*! \brief Reads through the given table of contents data and creates an
|
||||||
unsorted, unverified (i.e. non-error-checked) list of sessions and tracks.
|
unsorted, unverified (i.e. non-error-checked) list of sessions and tracks.
|
||||||
*/
|
*/
|
||||||
@@ -813,7 +900,7 @@ Disc::_ParseTableOfContents(cdrom_full_table_of_contents_entry entries[],
|
|||||||
session->track_list.Add(track);
|
session->track_list.Add(track);
|
||||||
} else {
|
} else {
|
||||||
WARN(("%s: warning: illegal point 0x%2x found in table of "
|
WARN(("%s: warning: illegal point 0x%2x found in table of "
|
||||||
"contents\n", kModuleDebugName, entries[i].point));
|
"contents\n", kModuleDebugName, point));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2009, Haiku, Inc.
|
* Copyright 2003-2011, Haiku, Inc.
|
||||||
* Distributed under the terms of the MIT license.
|
* Distributed under the terms of the MIT license.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -32,27 +32,33 @@ class Session;
|
|||||||
*/
|
*/
|
||||||
class Disc {
|
class Disc {
|
||||||
public:
|
public:
|
||||||
Disc(int fd);
|
Disc(int fd);
|
||||||
~Disc();
|
~Disc();
|
||||||
|
|
||||||
status_t InitCheck();
|
status_t InitCheck();
|
||||||
Session* GetSession(int32 index);
|
Session* GetSession(int32 index);
|
||||||
|
|
||||||
void Dump();
|
void Dump();
|
||||||
|
|
||||||
// CDs and DVDs are required to have a block size of 2K by
|
// CDs and DVDs are required to have a block size of 2K by
|
||||||
// the SCSI-3 standard
|
// the SCSI-3 standard
|
||||||
static const int kBlockSize = 2048;
|
static const int kBlockSize = 2048;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _ParseTableOfContents(
|
uint32 _AdjustForYellowBook(
|
||||||
cdrom_full_table_of_contents_entry entries[],
|
cdrom_full_table_of_contents_entry
|
||||||
uint32 count);
|
entries[],
|
||||||
void _SortAndRemoveDuplicates();
|
uint32 count);
|
||||||
status_t _CheckForErrorsAndWarnings();
|
status_t _ParseTableOfContents(
|
||||||
|
cdrom_full_table_of_contents_entry
|
||||||
|
entries[],
|
||||||
|
uint32 count);
|
||||||
|
void _SortAndRemoveDuplicates();
|
||||||
|
status_t _CheckForErrorsAndWarnings();
|
||||||
|
|
||||||
status_t fInitStatus;
|
private:
|
||||||
List* fSessionList;
|
status_t fInitStatus;
|
||||||
|
List* fSessionList;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -61,32 +67,35 @@ private:
|
|||||||
*/
|
*/
|
||||||
class Session {
|
class Session {
|
||||||
public:
|
public:
|
||||||
~Session();
|
~Session();
|
||||||
|
|
||||||
off_t Offset() { return fOffset; }
|
off_t Offset() { return fOffset; }
|
||||||
off_t Size() { return fSize; }
|
off_t Size() { return fSize; }
|
||||||
uint32 BlockSize() { return fBlockSize; }
|
uint32 BlockSize() { return fBlockSize; }
|
||||||
int32 Index() { return fIndex; }
|
int32 Index() { return fIndex; }
|
||||||
uint32 Flags() { return fFlags; }
|
uint32 Flags() { return fFlags; }
|
||||||
const char* Type() { return fType; }
|
const char* Type() { return fType; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Disc;
|
friend class Disc;
|
||||||
|
|
||||||
Session(off_t offset, off_t size, uint32 blockSize,
|
Session(off_t offset, off_t size,
|
||||||
int32 index, uint32 flags, const char* type);
|
uint32 blockSize, int32 index, uint32 flags,
|
||||||
|
const char* type);
|
||||||
|
|
||||||
Session(const Session& ref);
|
Session(const Session& other);
|
||||||
// not implemented
|
// not implemented
|
||||||
Session& operator=(const Session& ref);
|
Session& operator=(const Session& other);
|
||||||
// not implemented
|
// not implemented
|
||||||
|
|
||||||
off_t fOffset;
|
private:
|
||||||
off_t fSize;
|
off_t fOffset;
|
||||||
uint32 fBlockSize;
|
off_t fSize;
|
||||||
int32 fIndex;
|
uint32 fBlockSize;
|
||||||
uint32 fFlags;
|
int32 fIndex;
|
||||||
char* fType;
|
uint32 fFlags;
|
||||||
|
char* fType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // _DISC_H
|
#endif // _DISC_H
|
||||||
|
|||||||
@@ -52,12 +52,17 @@ identify_partition(int fd, partition_data *partition, void **cookie)
|
|||||||
&& geometry.device_type == B_CD) {
|
&& geometry.device_type == B_CD) {
|
||||||
Disc *disc = new(std::nothrow) Disc(fd);
|
Disc *disc = new(std::nothrow) Disc(fd);
|
||||||
if (disc != NULL && disc->InitCheck() == B_OK) {
|
if (disc != NULL && disc->InitCheck() == B_OK) {
|
||||||
|
// If we have only a single session then we can let the file system
|
||||||
|
// drivers play directly with the device.
|
||||||
|
if (disc->GetSession(1) != NULL)
|
||||||
|
result = 0.9f;
|
||||||
|
else
|
||||||
|
result = 0.1f;
|
||||||
*cookie = static_cast<void*>(disc);
|
*cookie = static_cast<void*>(disc);
|
||||||
result = 0.7;
|
|
||||||
} else
|
} else
|
||||||
delete disc;
|
delete disc;
|
||||||
}
|
}
|
||||||
PRINT(("returning %ld\n", int32(result * 10000)));
|
PRINT(("returning %g\n", result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user