Skip to content

[WIP] Add read speed option - #60

Open
strict-flower wants to merge 6 commits into
Bloomca:mainfrom
strict-flower:dev-speed-option
Open

[WIP] Add read speed option#60
strict-flower wants to merge 6 commits into
Bloomca:mainfrom
strict-flower:dev-speed-option

Conversation

@strict-flower

Copy link
Copy Markdown

Under development

Description

Background discussion is #59

Adds an option to request to set the read speed of the tracks.

@Bloomca Bloomca left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this API looks good! I left a few comments for the implementation, also there a few typos in the comments but we can fix it later.

I think we should an example of "slow_read_track" which would read the first track from the default drive at 10x.

@strict-flower One question I am curious about and forgot to ask in the issue. If custom multiplier does persist (we'll need to test it), do you think we should set speed back to optimal in the drive destructor?

Comment thread src/data_reader/read_speed.rs Outdated
/// By MMC-3 specification, It can be set to the optimal speed of the drive when it executes SET CD SPEED command with read speed (KB/s) = 0xFFFF.
/// On the Linux, the read speed will selected by the CDROM_SELECT_SPEED ioctl with speed = 0. It'll set the speed automatically and highest speed that supported by the drive.
Optimal,
/// Use the custom speed with specified multiplier.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add some inline documentation that it is 176KB/s * multiplier. Also maybe give an example that 10x is usually slow enough.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to add that. Is this what you had in mind?

#include <IOKit/storage/IOCDMediaBSDClient.h>

Boolean request_cd_read_speed(int fd, uint16_t target_speed_kbs) {
int ret = ioctl(fd, DKIOCCDSETSPEED, target_speed_kbs);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to pass a pointer there (I remember it from your example in the issue and here it dereferences

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just typo. I've fixed that.

let target_speed_kbs = if multiplier == 0 {
0xffff
} else {
multiplier * 176400 / 1000

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can overflow. With u16, it is not that hard to do, however, generally seems that audio CD can max out at ~52.

So maybe we can clamp the multiplier to 100x?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed CustomMultiplier(u16) to CustomMultiplier(u8) since u8 is sufficient to it I think. This change will fix it.

Comment thread src/platform/macos/speed.rs Outdated
multiplier * 176400 / 1000
};
if target_speed_kbs > u16::MAX.into() {
// TODO: Implement error handle (CdReaderError?)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to before, I think it might be easier to clamp the multiplier and this way we will never overflow

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

@strict-flower

Copy link
Copy Markdown
Author

@Bloomca Thanks for the quick review. I've fixed them. I'll write & testing the Linux implementation today.

One question I am curious about and forgot to ask in the issue. If custom multiplier does persist (we'll need to test it), do you think we should set speed back to optimal in the drive destructor?

I tested that.

The DKIOCCDSETSPEED ioctl seems to set the drive speed until the disc is ejected. Below is my experiment summary.

  1. Read with Unchanged -> corrupted and 24x
  2. Read with CustomMultiplier(10) -> success and 10x
  3. Read with Unchanged -> success and 10x
  4. Eject and re-insert the disc
  5. Read with Unchanged -> corrupted and 24x

... and the default state seems to be Optimal, but we can't confirm that because DKIOCCDGETSPEED only returns the current speed1, according to my experiments.

Footnotes

  1. I also tested that. I inserted eprintln! in the read loop to print the return value of the DKIOCCDGETSPEED ioctl, and it changed between 10x and 24x depending on the actual read speed. This means that it returns the current speed.

@strict-flower

strict-flower commented Aug 16, 2026

Copy link
Copy Markdown
Author

I think it's difficult to restore the original state. At least, macOS doesn't seem to provide a way to get the original state.

Moreover, we could get the read speed performance data of the drive, but we can't get the current speed policy of the drive. In other words, even if the current speed is 10x, we can't determine whether the value was set by another program, is the default value of the drive, or was selected automatically.

Therefore, I think just setting Optimal is the best way to implement the destructor. (deleted, please read the next comment)

@strict-flower

strict-flower commented Aug 16, 2026

Copy link
Copy Markdown
Author

I wrote the implementation for Linux and tested. It seems to work correctly.

Also I tested Optimal / Unchanged / CustomMultiplier with the USB-connected drive that I used for the macOS test, and it doesn't behave the same way as on macOS. I didn't retrieve the read speed, but I only observed whether the read succeeded or returned corrupted data (It could probably be obtained using GET PERFORMANCE, but I haven't implemented that yet).

  1. Read with CustomMultiplier(10) -> success
  2. Read with Unchanged -> success
  3. Read with Optimal -> corrupted
  4. Read with Unchanged -> success
  5. Read with CustomMultiplier(1) -> success

Although I didn't eject the CD during the above procedure, the speed setting did not persist. On Linux, it seems to be reset on each open(2).

Additionally, I tested this on an internal disc drive (ASUS BC-12D2HT). This drive seems to ignore the requested speed with the SET CD SPEED command1. Nevertheless, this behaviour doesn't necessarily violate MMC-3, because MMC-3 specifies that The Logical Unit is to select the Logical Unit Read Speed specified or any higher rate.

Thus, unlike my earlier comments, I think the best destructor behaviour may be OS-dependent. However, there is also the possibility that we don't need to restore the policy at all.

  • macOS: Optimal (?)
  • Linux: Nothing to do.
  • Windows: ?

Footnotes

  1. Unlike the USB-connected drive, it could read the disc correctly with all settings I tested. However, the USB-connected drive could read most discs correctly at 24x, so there may still be some hidden hardware-specific issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants