Pulse-Eight / libcec

USB CEC Adapter communication Library http://libcec.pulse-eight.com/
Other
705 stars 282 forks source link

Python: unusable config.strDeviceLanguage #560

Open stefano-zanotti opened 3 years ago

stefano-zanotti commented 3 years ago

When creating a CEC configuration, you can set the device language as a 3-char code. See: https://github.com/Pulse-Eight/libcec/blob/76551ea1dd9a55f0ce1533e440dc12dbc594f7ba/include/cectypes.h#L1501

In the Python wrapper of the library, this field cannot be assigned, so it can't be changed from the default "eng".

This is a minimal repro:

import cec

cec_config = cec.libcec_configuration()

# this would correctly print "eng"
#print(cec_config.strDeviceLanguage)

# This throws an exception
#cec_config.strDeviceLanguage = "eng"
# Traceback (most recent call last):
#   File "test_cec.py", line 9, in <module>
#     cec_config.strDeviceLanguage = "eng"
#   File "/usr/local/lib/python3.7/dist-packages/cec.py", line 1088, in <lambda>
#     __setattr__ = lambda self, name, value: _swig_setattr(self, libcec_configuration, name, value)
#   File "/usr/local/lib/python3.7/dist-packages/cec.py", line 71, in _swig_setattr
#     return _swig_setattr_nondynamic(self, class_type, name, value, 0)
#   File "/usr/local/lib/python3.7/dist-packages/cec.py", line 60, in _swig_setattr_nondynamic
#     return method(self, value)
# TypeError: in method 'libcec_configuration_strDeviceLanguage_set', argument 2 of type 'char [3]'

# This works
cec_config.strDeviceLanguage = "en"
# this would correctly print "en"
#print(cec_config.strDeviceLanguage)

# Neither of these works
cec_config.strDeviceLanguage = b"eng"
cec_config.strDeviceLanguage = b"en"

The problem seems to be this: the C library uses a 3-char fixed-size string for this field (not NUL-terminated). When you try assigning it from Python, a 3-char string is actually converted to a C-style 4-char string (including the terminator), which doesn't fit into the library's 3-char buffer. On the other hand, a 2-char python string is converted to a 3-char C-style string, which fits. However, this is not a solution, since codes are supposed to be "3 character ISO 639-2 country codes".

This is the version info:

import cec
cec_config = cec.libcec_configuration()
cec_adapter = cec.ICECAdapter.Create(cec_config)
print(cec_adapter.VersionToString(cec_config.serverVersion))
print(cec_adapter.GetLibInfo())

6.0.2 git revision: libcec-6.0.2+1-76551ea, compiled on 2021-04-01 15:41:13 by pi@raspberrypi on Linux 5.4.83-v7l+ (armv7l), features: P8_USB, DRM, P8_detect, randr, RPi