Accéder à PulseAudio avec Python2 est un peu délicat, mais cela fonctionne à l’aide de ctypes. Le problème est que le même code ne fonctionne pas avec Python3. Apparemment, quelque chose a été changé dans les types, mais je ne peux pas savoir quoi exactement.
Voici l'exemple de code, qui répertoriera tous les périphériques sources. Cela fonctionne en Python2, mais segfaults horriblement en Python3.
# PulseAudio Source list:
import time
from ctypes import *
PA = CDLL('libpulse.so.0')
PA_CONTEXT_UNCONNECTED = 0
PA_CONTEXT_CONNECTING = 1
PA_CONTEXT_AUTHORIZING = 2
PA_CONTEXT_SETTING_NAME = 3
PA_CONTEXT_READY = 4
PA_CONTEXT_FAILED = 5
PA_CONTEXT_TERMINATED = 6
PA_OPERATION_RUNNING = 0
PA_OPERATION_DONE = 1
PA_OPERATION_CANCELLED = 2
STRING = c_char_p
size_t = c_ulong
uint32_t = c_uint32
uint8_t = c_uint8
class pa_mainloop_api(Structure):
pass
class pa_threaded_mainloop(Structure):
pass
pa_threaded_mainloop._fields_ = []
pa_threaded_mainloop_new = PA.pa_threaded_mainloop_new
pa_threaded_mainloop_new.restype = POINTER(pa_threaded_mainloop)
pa_threaded_mainloop_new.argtypes = []
pa_threaded_mainloop_free = PA.pa_threaded_mainloop_free
pa_threaded_mainloop_free.restype = None
pa_threaded_mainloop_free.argtypes = [POINTER(pa_threaded_mainloop)]
pa_threaded_mainloop_start = PA.pa_threaded_mainloop_start
pa_threaded_mainloop_start.restype = c_int
pa_threaded_mainloop_start.argtypes = [POINTER(pa_threaded_mainloop)]
pa_threaded_mainloop_stop = PA.pa_threaded_mainloop_stop
pa_threaded_mainloop_stop.restype = None
pa_threaded_mainloop_stop.argtypes = [POINTER(pa_threaded_mainloop)]
pa_threaded_mainloop_get_api = PA.pa_threaded_mainloop_get_api
pa_threaded_mainloop_get_api.restype = POINTER(pa_mainloop_api)
pa_threaded_mainloop_get_api.argtypes = [POINTER(pa_threaded_mainloop)]
class pa_context(Structure):
pass
pa_context._fields_ = []
class pa_spawn_api(Structure):
pass
class pa_stream(Structure):
pass
pa_stream._fields_ = []
class pa_operation(Structure):
pass
class pa_source_info(Structure):
pass
pa_source_info._fields_ = [
('name', STRING),
('index', uint32_t),
('description', STRING),
]
pa_context_flags = c_int
pa_context_flags_t = pa_context_flags
pa_context_state = c_int
pa_context_state_t = pa_context_state
pa_context_notify_cb_t = CFUNCTYPE(None, POINTER(pa_context), c_void_p)
pa_context_success_cb_t = CFUNCTYPE(None, POINTER(pa_context), c_int, c_void_p)
pa_stream_success_cb_t = CFUNCTYPE(None, POINTER(pa_stream), c_int, c_void_p)
pa_stream_request_cb_t = CFUNCTYPE(None, POINTER(pa_stream), size_t, c_void_p)
pa_stream_notify_cb_t = CFUNCTYPE(None, POINTER(pa_stream), c_void_p)
pa_source_info_cb_t = CFUNCTYPE(None, POINTER(pa_context), POINTER(pa_source_info), c_int, c_void_p)
pa_context_new = PA.pa_context_new
pa_context_new.restype = POINTER(pa_context)
pa_context_new.argtypes = [POINTER(pa_mainloop_api), STRING]
pa_context_connect = PA.pa_context_connect
pa_context_connect.restype = c_int
pa_context_connect.argtypes = [POINTER(pa_context), STRING, pa_context_flags_t, POINTER(pa_spawn_api)]
pa_context_set_state_callback = PA.pa_context_set_state_callback
pa_context_set_state_callback.restype = None
pa_context_set_state_callback.argtypes = [POINTER(pa_context), pa_context_notify_cb_t, c_void_p]
pa_context_get_state = PA.pa_context_get_state
pa_context_get_state.restype = pa_context_state_t
pa_context_get_state.argtypes = [POINTER(pa_context)]
pa_stream_set_state_callback = PA.pa_stream_set_state_callback
pa_stream_set_state_callback.restype = None
pa_stream_set_state_callback.argtypes = [POINTER(pa_stream), pa_stream_notify_cb_t, c_void_p]
pa_context_get_source_info_list = PA.pa_context_get_source_info_list
pa_context_get_source_info_list.restype = POINTER(pa_operation)
pa_context_get_source_info_list.argtypes = [POINTER(pa_context), pa_source_info_cb_t, c_void_p]
def pa_state_cb(context, userdata):
global pa_state
state = pa_context_get_state(context)
if state in [PA_CONTEXT_UNCONNECTED, PA_CONTEXT_CONNECTING, PA_CONTEXT_AUTHORIZING,
PA_CONTEXT_SETTING_NAME]:
pa_state = 0
Elif state == PA_CONTEXT_FAILED:
pa_state = 2
Elif state == PA_CONTEXT_READY:
pa_state = 1
return 0
def pa_sourcelist_cb(context, source_info, eol, userdata):
if eol==0:
print("IDX:", source_info.contents.index, " ", source_info.contents.name, "--", source_info.contents.description)
return 0
pa_ml = pa_threaded_mainloop_new()
pa_mlapi = pa_threaded_mainloop_get_api(pa_ml)
pa_ctx = pa_context_new(pa_mlapi, b"kazam-Pulse")
error = -1
pa_state = 0
if pa_context_connect(pa_ctx, None, 0, None)!=0:
print("cannot connect..")
sys.exit(1)
pa_context_set_state_callback(pa_ctx, pa_context_notify_cb_t(pa_state_cb), None)
ret = pa_threaded_mainloop_start(pa_ml)
ctc = pa_context_get_state(pa_ctx)
time.sleep(1)
pa_context_get_source_info_list(pa_ctx, pa_source_info_cb_t(pa_sourcelist_cb), None);
time.sleep(1)
Et voici la trace:
#0 0x00007ffff7e11fc1 in ?? ()
#1 0x00007ffff5e82d27 in pa_context_set_state (st=PA_CONTEXT_AUTHORIZING, c=0xae7d40) at Pulse/context.c:291
#2 pa_context_set_state (c=0xae7d40, st=PA_CONTEXT_AUTHORIZING) at Pulse/context.c:279
#3 0x00007ffff5e85691 in setup_context (io=0x7fffe8000910, c=0xae7d40) at Pulse/context.c:561
#4 on_connection (client=<optimized out>, io=0x7fffe8000910, userdata=0xae7d40) at Pulse/context.c:890
#5 0x00007ffff5a440e6 in do_call (c=0x9976c0) at pulsecore/socket-client.c:161
#6 0x00007ffff5e96ba7 in dispatch_defer (m=0x9ce180) at Pulse/mainloop.c:704
#7 pa_mainloop_dispatch (m=0x9ce180) at Pulse/mainloop.c:920
#8 0x00007ffff5e96de5 in pa_mainloop_iterate (m=0x9ce180, block=<optimized out>, retval=0x0) at Pulse/mainloop.c:960
#9 0x00007ffff5e96e90 in pa_mainloop_run (m=0x9ce180, retval=0x0) at Pulse/mainloop.c:975
#10 0x00007ffff5ea530f in thread (userdata=0x9a64a0) at Pulse/thread-mainloop.c:88
#11 0x00007ffff5a4ed18 in internal_thread_func (userdata=0xa66840) at pulsecore/thread-posix.c:83
#12 0x00007ffff7bc4e9a in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0
#13 0x00007ffff65844bd in clone () from /lib/x86_64-linux-gnu/libc.so.6
#14 0x0000000000000000 in ?? ()
Juste un suivi. Ce problème a été résolu. En utilisant Python 3.2.3 dans Precise Pangolin, le code envoyé fonctionne comme prévu.