Problem with Libburn and writing CD

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!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.