Hi everyone!
I’m trying to write a basic Python code that write a single song on a CD-RW. Here is my code:
import os
import sys
import ctypes
from enum import IntEnum
from time import sleep
# Define libburn classes
class BurnDrive(ctypes.Structure):
pass
class BurnDisc(ctypes.Structure):
pass
class BurnSession(ctypes.Structure):
pass
class BurnTrack(ctypes.Structure):
pass
class BurnSource(ctypes.Structure):
pass
class BurnDriveInfo(ctypes.Structure):
_fields_ = [
("vendor", ctypes.c_char * 9),
("product", ctypes.c_char * 17),
("revision", ctypes.c_char * 5),
("location", ctypes.c_char * 17),
("read_dvdram", ctypes.c_uint, 1),
("read_dvdr", ctypes.c_uint, 1),
("read_dvdrom", ctypes.c_uint, 1),
("read_cdr", ctypes.c_uint, 1),
("read_cdrw", ctypes.c_uint, 1),
("write_dvdram", ctypes.c_uint, 1),
("write_dvdr", ctypes.c_uint, 1),
("write_cdr", ctypes.c_uint, 1),
("write_cdrw", ctypes.c_uint, 1),
("write_simulate", ctypes.c_uint, 1),
("c2_error", ctypes.c_uint, 1),
("buffer_size", ctypes.c_int),
("tao_block_types", ctypes.c_int),
("sao_block_types", ctypes.c_int),
("raw_block_types", ctypes.c_int),
("packet_block_types", ctypes.c_int),
("drive", ctypes.c_void_p)
]
class BurnProgress(ctypes.Structure):
_fields_ = [
("revision", ctypes.c_int),
("sessions", ctypes.c_int),
("session", ctypes.c_int),
("tracks", ctypes.c_int),
("track", ctypes.c_int),
("indices", ctypes.c_int),
("index", ctypes.c_int),
("start_sector", ctypes.c_int64),
("sectors", ctypes.c_int64),
("sector", ctypes.c_int64),
("buffer_capacity", ctypes.c_int64),
("buffer_available", ctypes.c_int64),
("buffered_bytes", ctypes.c_int64),
("buffer_min_fill", ctypes.c_int64)
]
class BurnDiscStatus(IntEnum):
UNREADY = 0
BLANK = 1
EMPTY = 2
APPENDABLE = 3
FULL = 4
UNGRABBED = 5
UNSUITABLE = 6
class BurnDriveStatus(IntEnum):
IDLE = 0
SPAWNING = 1
READING = 2
WRITING = 3
WRITING_LEADIN = 4
WRITING_LEADOUT = 5
ERASING = 6
GRABBING = 7
WRITING_PREGAP = 8
CLOSING_TRACK = 9
CLOSING_SESSION = 10
FORMATTING = 11
READING_SYNC = 12
WRITING_SYNC = 13
class BurnSourceStatus(IntEnum):
OK = 0
EOF = 1
FAILED = 2
class BurnWriteOpts(ctypes.Structure):
pass
# Main code
libburn = ctypes.CDLL("binaries/libburn.so.4")
libburn.burn_initialize.restype = ctypes.c_int
libburn.burn_initialize.argtypes = None
libburn.burn_initialize()
# libburn.burn_set_scsi_logging(3)
# libburn.burn_set_verbosity(2)
DriveInfoPtr = ctypes.POINTER(BurnDriveInfo)
libburn.burn_drive_scan.restype = ctypes.c_int
libburn.burn_drive_scan.argtypes = (
ctypes.POINTER(DriveInfoPtr),
ctypes.POINTER(ctypes.c_uint)
)
drives_info = DriveInfoPtr()
n_drives = ctypes.c_uint()
res = libburn.burn_drive_scan(
ctypes.byref(drives_info),
ctypes.byref(n_drives)
)
sleep(0.1)
print("Nombre de lecteurs/graveurs :", n_drives.value)
if n_drives.value == 0:
sys.exit(0)
drive_info = drives_info[0]
# Exemple de string : print(f"Vendor: [{drive_info.vendor.decode('utf-8')}]")
# Exemple de int : print(f"Read DVD-RAM: [{drive_info.read_dvdram}]")
burn_drive = drive_info.drive
# libburn.burn_drive_get_write_speed.restype = ctypes.c_int
# libburn.burn_drive_get_write_speed.argtypes = (ctypes.c_void_p, )
# burn_drive_write_speed = libburn.burn_drive_get_write_speed(burn_drive)
libburn.burn_drive_get_status_v2.restype = ctypes.c_int
libburn.burn_drive_get_status_v2.argtypes = (ctypes.c_void_p, ctypes.c_void_p)
# On donne None car on ne s'occupe pas de la progression
burn_drive_status = libburn.burn_drive_get_status_v2(burn_drive, None)
burn_drive_status = BurnDriveStatus(burn_drive_status)
print(f"Status du lecteur/graveur : {burn_drive_status.name}")
libburn.burn_drive_grab.restype = ctypes.c_int
libburn.burn_drive_grab.argtypes = (ctypes.c_void_p, ctypes.c_int)
res = libburn.burn_drive_grab(burn_drive, ctypes.c_int(0))
print(f"Lecteur/graveur disponible : {bool(res)}")
libburn.burn_disc_get_status.restype = ctypes.c_int
libburn.burn_disc_get_status.argtypes = (ctypes.c_void_p, )
status_result = libburn.burn_disc_get_status(burn_drive)
burn_disc_status = BurnDiscStatus(status_result)
print(f"Status du disque : {burn_disc_status.name}")
if burn_disc_status == BurnDiscStatus.EMPTY:
sys.exit(0)
libburn.burn_disc_get_profile.restype = ctypes.c_int
libburn.burn_disc_get_profile.argtypes = (
ctypes.c_void_p,
ctypes.POINTER(ctypes.c_int),
ctypes.POINTER(ctypes.c_char)
)
profile_number = ctypes.c_int()
profile_name = ctypes.create_string_buffer(80)
res = libburn.burn_disc_get_profile(
burn_drive,
ctypes.byref(profile_number),
profile_name
)
print(f"Type de disque : {profile_name.value.decode('utf-8')}")
libburn.burn_write_opts_new.restype = ctypes.POINTER(BurnWriteOpts)
libburn.burn_write_opts_new.argtypes = (ctypes.c_void_p, )
write_opts = libburn.burn_write_opts_new(burn_drive)
BURN_WRITE_TAO = 1
libburn.burn_write_opts_set_write_type.restype = ctypes.c_int
libburn.burn_write_opts_set_write_type.argtypes = (
ctypes.POINTER(BurnWriteOpts),
ctypes.c_int,
ctypes.c_int
)
libburn.burn_write_opts_set_write_type(
write_opts,
ctypes.c_int(BURN_WRITE_TAO),
ctypes.c_int(0)
)
libburn.burn_write_opts_set_multi.restype = None
libburn.burn_write_opts_set_multi.argtypes = (
ctypes.POINTER(BurnWriteOpts),
ctypes.c_int
)
libburn.burn_write_opts_set_multi(write_opts, 0)
libburn.burn_drive_set_speed.restype = None
libburn.burn_drive_set_speed.argtypes = (
ctypes.c_void_p,
ctypes.c_int,
ctypes.c_int
)
libburn.burn_drive_set_speed(burn_drive, 0, 0)
# ctypes.c_int64 est important pour les off_t car
# Libburn est compilé en 64 bits
libburn.burn_disc_available_space.restype = ctypes.c_int64
libburn.burn_disc_available_space.argtypes = (ctypes.c_void_p, ctypes.c_void_p)
disc_space = libburn.burn_disc_available_space(burn_drive, write_opts)
print(f"Place disponible : {disc_space / 10 ** 9} Go")
libburn.burn_disc_erasable.restype = ctypes.c_int
libburn.burn_disc_erasable.argtypes = (ctypes.c_void_p, )
is_erasable = libburn.burn_disc_erasable(burn_drive)
is_erasable = bool(is_erasable)
print(f"Disque effaçable : {is_erasable}")
# Create a virtual disc to write
libburn.burn_disc_create.restype = ctypes.POINTER(BurnDisc)
libburn.burn_disc_create.argtypes = ()
disc = libburn.burn_disc_create()
libburn.burn_session_create.restype = ctypes.POINTER(BurnSession)
libburn.burn_session_create.argtypes = ()
session = libburn.burn_session_create()
libburn.burn_track_create.restype = ctypes.POINTER(BurnTrack)
libburn.burn_track_create.argtypes = ()
track = libburn.burn_track_create()
BURN_AUDIO = 64
BURN_COPY = 256
libburn.burn_track_define_data.restype = None
libburn.burn_track_define_data.argtypes = (
ctypes.POINTER(BurnTrack),
ctypes.c_int,
ctypes.c_int,
ctypes.c_int,
ctypes.c_int
)
libburn.burn_track_define_data(
track,
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_int(1),
ctypes.c_int(BURN_AUDIO | BURN_COPY)
)
libburn.burn_file_source_new.restype = ctypes.POINTER(BurnSource)
libburn.burn_file_source_new.argtypes = (
ctypes.c_char_p,
ctypes.c_char_p
)
source = libburn.burn_file_source_new(
ctypes.c_char_p(b"/home/eric/Projects/tests-libburn/audio.raw"),
None
)
libburn.burn_track_set_source.restype = ctypes.c_int
libburn.burn_track_set_source.argtypes = (
ctypes.POINTER(BurnTrack),
ctypes.POINTER(BurnSource)
)
source_status = libburn.burn_track_set_source(track, source)
source_status = BurnSourceStatus(source_status).name
print(f"Source accessible : {source_status}")
file_size = os.path.getsize("/home/eric/Projects/tests-libburn/audio.raw")
libburn.burn_track_set_size.restype = ctypes.c_int
libburn.burn_track_set_size.argtypes = (
ctypes.POINTER(BurnTrack),
ctypes.c_int64
)
libburn.burn_track_set_size(track, ctypes.c_int64(file_size))
BURN_POS_END = 100
libburn.burn_session_add_track.restype = ctypes.c_int
libburn.burn_session_add_track.argtypes = (
ctypes.POINTER(BurnSession),
ctypes.POINTER(BurnTrack),
ctypes.c_uint
)
res = libburn.burn_session_add_track(
session,
track,
ctypes.c_uint(BURN_POS_END)
)
libburn.burn_disc_add_session.restype = ctypes.c_int
libburn.burn_disc_add_session.argtypes = (
ctypes.POINTER(BurnDisc),
ctypes.POINTER(BurnSession),
ctypes.c_uint
)
res = libburn.burn_disc_add_session(
disc,
session,
ctypes.c_uint(BURN_POS_END)
)
# Simulate disc writing
BURN_REASONS_LEN = 4096
reasons = ctypes.create_string_buffer(BURN_REASONS_LEN)
libburn.burn_precheck_write.restype = ctypes.c_int
libburn.burn_precheck_write.argtypes = (
ctypes.POINTER(BurnWriteOpts),
ctypes.POINTER(BurnDisc),
ctypes.c_char_p,
ctypes.c_int
)
res = libburn.burn_precheck_write(
write_opts,
disc,
reasons,
ctypes.c_int(0)
)
print(f"Gravure possible : {bool(res)}")
print(f"Raisons : \n{reasons.value.decode("utf-8")}")
if bool(res):
response = input("Do you want to start the burning test? Please answer 'yes' or 'no'.\n")
if (response == "no") or (response != "yes"):
sys.exit(0)
libburn.burn_disc_write.restype = None
libburn.burn_disc_write.argtypes = (
ctypes.POINTER(BurnWriteOpts),
ctypes.POINTER(BurnDisc)
)
libburn.burn_disc_write(write_opts, disc)
while True:
libburn.burn_drive_get_status_v2.restype = ctypes.c_int
libburn.burn_drive_get_status_v2.argtypes = (ctypes.c_void_p, ctypes.c_void_p)
status = libburn.burn_drive_get_status_v2(burn_drive, None)
status = BurnDriveStatus(status)
print(f"Statut actuel : {status.name}")
if status == BurnDriveStatus.IDLE:
break
sleep(1)
# Free all assigned resources
libburn.burn_write_opts_free.restype = None
libburn.burn_write_opts_free.argtypes = (ctypes.POINTER(BurnWriteOpts), )
libburn.burn_write_opts_free(write_opts)
libburn.burn_disc_free.restype = None
libburn.burn_disc_free.argtypes = (ctypes.POINTER(BurnDisc), )
libburn.burn_disc_free(disc)
libburn.burn_session_free.restype = None
libburn.burn_session_free.argtypes = (ctypes.POINTER(BurnSession), )
libburn.burn_session_free(session)
libburn.burn_track_free.restype = None
libburn.burn_track_free.argtypes = (ctypes.POINTER(BurnTrack), )
libburn.burn_track_free(track)
libburn.burn_source_free.restype = None
libburn.burn_source_free.argtypes = (ctypes.POINTER(BurnSource), )
libburn.burn_source_free(source)
libburn.burn_drive_release.restype = None
libburn.burn_drive_release.argtypes = (ctypes.c_void_p, ctypes.c_int)
libburn.burn_drive_release(burn_drive, ctypes.c_int(0))
libburn.burn_finish()
And here is my output:
Nombre de lecteurs/graveurs : 1
Status du lecteur/graveur : IDLE
Lecteur/graveur disponible : True
Status du disque : BLANK
Type de disque : CD-RW
Place disponible : 0.736966656 Go
Disque effaçable : True
Source accessible : OK
Gravure possible : True
Raisons :
CD-RW:
Do you want to start the burning test? Please answer 'yes' or 'no'.
yes
Statut actuel : IDLE
I’m mostly experiencing, but the burn_disc_write() function seems to do nothing.
And removing the ```status == BurnDriveStatus.IDLE``` condition just creates an infinite loop.
Can someone explain me why is nothing happening?
Thanks for your help!