# -*- coding: utf-8 -*- from __future__ import print_function # C Bindings import os, sys, ctypes.util, functools as ft from ctypes import * force_str = lambda s, errors='strict': s.decode('utf-8', errors) if isinstance(s, bytes) else s force_bytes = lambda s, errors='strict': s.encode('utf-8', errors) if isinstance(s, unicode) else s if sys.version_info.major >= 3: class c_str_p_type(object): c_type = c_char_p def __call__(self, val): return force_str(val) def from_param(self, val): # int will be interpreted as pointer and segfault in py3 if isinstance(val, int): raise ArgumentError(type(val)) return force_bytes(val) unicode, c_str_p = str, c_str_p_type() import time mono_time = time.monotonic else: c_str_p = c_char_p def mono_time(): if not hasattr(mono_time, 'ts'): class timespec(Structure): _fields_ = [('tv_sec', c_long), ('tv_nsec', c_long)] librt = CDLL('librt.so.1', use_errno=True) mono_time.get = librt.clock_gettime mono_time.get.argtypes = [c_int, POINTER(timespec)] mono_time.ts = timespec ts = mono_time.ts() if mono_time.get(4, pointer(ts)) != 0: err = get_errno() raise OSError(err, os.strerror(err)) return ts.tv_sec + ts.tv_nsec * 1e-9 PA_INVALID = 2**32-1 PA_VOLUME_NORM = 0x10000 PA_VOLUME_MAX = (2**32-1) // 2 # was different before pulseaudio-1.0, see 179b291b there PA_VOLUME_INVALID = 2**32-1 pa_sw_volume_from_dB = lambda db:\ min(PA_VOLUME_MAX, int(round(((10.0 ** (db / 20.0)) ** (1/3)) * PA_VOLUME_NORM))) PA_VOLUME_UI_MAX = 99957 # pa_sw_volume_from_dB(+11.0) PA_CHANNELS_MAX = 32 PA_USEC_T = c_uint64 PA_CONTEXT_NOAUTOSPAWN = 0x0001 PA_CONTEXT_NOFAIL = 0x0002 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_SUBSCRIPTION_MASK_NULL = 0x0000 PA_SUBSCRIPTION_MASK_SINK = 0x0001 PA_SUBSCRIPTION_MASK_SOURCE = 0x0002 PA_SUBSCRIPTION_MASK_SINK_INPUT = 0x0004 PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 0x0008 PA_SUBSCRIPTION_MASK_MODULE = 0x0010 PA_SUBSCRIPTION_MASK_CLIENT = 0x0020 PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 0x0040 PA_SUBSCRIPTION_MASK_SERVER = 0x0080 PA_SUBSCRIPTION_MASK_AUTOLOAD = 0x0100 PA_SUBSCRIPTION_MASK_CARD = 0x0200 PA_SUBSCRIPTION_MASK_ALL = 0x02ff PA_SUBSCRIPTION_EVENT_SINK = 0x0000 PA_SUBSCRIPTION_EVENT_SOURCE = 0x0001 PA_SUBSCRIPTION_EVENT_SINK_INPUT = 0x0002 PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 0x0003 PA_SUBSCRIPTION_EVENT_MODULE = 0x0004 PA_SUBSCRIPTION_EVENT_CLIENT = 0x0005 PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 0x0006 PA_SUBSCRIPTION_EVENT_SERVER = 0x0007 PA_SUBSCRIPTION_EVENT_AUTOLOAD = 0x0008 PA_SUBSCRIPTION_EVENT_CARD = 0x0009 PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 0x000F PA_SUBSCRIPTION_EVENT_NEW = 0x0000 PA_SUBSCRIPTION_EVENT_CHANGE = 0x0010 PA_SUBSCRIPTION_EVENT_REMOVE = 0x0020 PA_SUBSCRIPTION_EVENT_TYPE_MASK = 0x0030 PA_SAMPLE_FLOAT32LE = 5 PA_SAMPLE_FLOAT32BE = 6 PA_SAMPLE_FLOAT32NE = dict( little=PA_SAMPLE_FLOAT32LE, big=PA_SAMPLE_FLOAT32BE )[sys.byteorder] PA_STREAM_DONT_MOVE = 0x0200 PA_STREAM_PEAK_DETECT = 0x0800 PA_STREAM_ADJUST_LATENCY = 0x2000 PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND = 0x8000 def c_enum_map(**values): return dict((v, force_str(k)) for k,v in values.items()) _globals = globals().copy() _pa_ev_type = dict( (force_str(k), _globals['PA_SUBSCRIPTION_EVENT_{}'.format(k.upper())]) for k in 'new change remove'.split() ) _pa_ev_fac, _pa_ev_mask = dict(), dict() for k, n in _globals.items(): if k.startswith('PA_SUBSCRIPTION_EVENT_'): if k.endswith('_MASK'): continue k = force_str(k[22:].lower()) if k in _pa_ev_type: continue assert n & PA_SUBSCRIPTION_EVENT_FACILITY_MASK == n, [k, n] _pa_ev_fac[k] = n elif k.startswith('PA_SUBSCRIPTION_MASK_'): _pa_ev_mask[force_str(k[21:].lower())] = n PA_EVENT_TYPE_MAP = c_enum_map(**_pa_ev_type) PA_EVENT_FACILITY_MAP = c_enum_map(**_pa_ev_fac) PA_EVENT_MASK_MAP = c_enum_map(**_pa_ev_mask) del _globals, _pa_ev_type, _pa_ev_fac, _pa_ev_mask PA_UPDATE_MAP = c_enum_map(set=0, merge=1, replace=2) PA_PORT_AVAILABLE_MAP = c_enum_map(unknown=0, no=1, yes=2) PA_DIRECTION_MAP = c_enum_map(unknown=0, output=1, input=2) # These are defined separately as # pa_sink_state / pa_source_state, but seem to match. PA_OBJ_STATE_MAP = c_enum_map(invalid=-1, running=0, idle=1, suspended=2) class PA_MAINLOOP(Structure): pass class PA_STREAM(Structure): pass class PA_MAINLOOP_API(Structure): pass class PA_CONTEXT(Structure): pass class PA_PROPLIST(Structure): pass class PA_OPERATION(Structure): pass class PA_SIGNAL_EVENT(Structure): pass class PA_IO_EVENT(Structure): pass class PA_SAMPLE_SPEC(Structure): _fields_ = [ ('format', c_int), ('rate', c_uint32), ('channels', c_uint32) ] class PA_CHANNEL_MAP(Structure): _fields_ = [ ('channels', c_uint8), ('map', c_int * PA_CHANNELS_MAX) ] class PA_CVOLUME(Structure): _fields_ = [ ('channels', c_uint8), ('values', c_uint32 * PA_CHANNELS_MAX) ] class PA_PORT_INFO(Structure): _fields_ = [ ('name', c_char_p), ('description', c_char_p), ('priority', c_uint32), ('available', c_int), ] class PA_SINK_INPUT_INFO(Structure): _fields_ = [ ('index', c_uint32), ('name', c_char_p), ('owner_module', c_uint32), ('client', c_uint32), ('sink', c_uint32), ('sample_spec', PA_SAMPLE_SPEC), ('channel_map', PA_CHANNEL_MAP), ('volume', PA_CVOLUME), ('buffer_usec', PA_USEC_T), ('sink_usec', PA_USEC_T), ('resample_method', c_char_p), ('driver', c_char_p), ('mute', c_int), ('proplist', POINTER(PA_PROPLIST)), ('corked', c_int), ('has_volume', c_int), ('volume_writable', c_int), ] class PA_SINK_INFO(Structure): _fields_ = [ ('name', c_char_p), ('index', c_uint32), ('description', c_char_p), ('sample_spec', PA_SAMPLE_SPEC), ('channel_map', PA_CHANNEL_MAP), ('owner_module', c_uint32), ('volume', PA_CVOLUME), ('mute', c_int), ('monitor_source', c_uint32), ('monitor_source_name', c_char_p), ('latency', PA_USEC_T), ('driver', c_char_p), ('flags', c_int), ('proplist', POINTER(PA_PROPLIST)), ('configured_latency', PA_USEC_T), ('base_volume', c_uint32), ('state', c_int), ('n_volume_steps', c_int), ('card', c_uint32), ('n_ports', c_uint32), ('ports', POINTER(POINTER(PA_PORT_INFO))), ('active_port', POINTER(PA_PORT_INFO)), ] class PA_SOURCE_OUTPUT_INFO(Structure): _fields_ = [ ('index', c_uint32), ('name', c_char_p), ('owner_module', c_uint32), ('client', c_uint32), ('source', c_uint32), ('sample_spec', PA_SAMPLE_SPEC), ('channel_map', PA_CHANNEL_MAP), ('buffer_usec', PA_USEC_T), ('source_usec', PA_USEC_T), ('resample_method', c_char_p), ('driver', c_char_p), ('proplist', POINTER(PA_PROPLIST)), ('corked', c_int), ('volume', PA_CVOLUME), ('mute', c_int), ('has_volume', c_int), ('volume_writable', c_int), ] class PA_SOURCE_INFO(Structure): _fields_ = [ ('name', c_char_p), ('index', c_uint32), ('description', c_char_p), ('sample_spec', PA_SAMPLE_SPEC), ('channel_map', PA_CHANNEL_MAP), ('owner_module', c_uint32), ('volume', PA_CVOLUME), ('mute', c_int), ('monitor_of_sink', c_uint32), ('monitor_of_sink_name', c_char_p), ('latency', PA_USEC_T), ('driver', c_char_p), ('flags', c_int), ('proplist', POINTER(PA_PROPLIST)), ('configured_latency', PA_USEC_T), ('base_volume', c_uint32), ('state', c_int), ('n_volume_steps', c_int), ('card', c_uint32), ('n_ports', c_uint32), ('ports', POINTER(POINTER(PA_PORT_INFO))), ('active_port', POINTER(PA_PORT_INFO)), ] class PA_CLIENT_INFO(Structure): _fields_ = [ ('index', c_uint32), ('name', c_char_p), ('owner_module', c_uint32), ('driver', c_char_p), ('proplist', POINTER(PA_PROPLIST)), ] class PA_SERVER_INFO(Structure): _fields_ = [ ('user_name', c_char_p), ('host_name', c_char_p), ('server_version', c_char_p), ('server_name', c_char_p), ('sample_spec', PA_SAMPLE_SPEC), ('default_sink_name', c_char_p), ('default_source_name', c_char_p), ('cookie', c_uint32), ('channel_map', PA_CHANNEL_MAP), ] class PA_CARD_PROFILE_INFO(Structure): _fields_ = [ ('name', c_char_p), ('description', c_char_p), ('n_sinks', c_uint32), ('n_sources', c_uint32), ('priority', c_uint32), ('available', c_int), ] # Extends PA_PORT_INFO with a few card-specific things class PA_CARD_PORT_INFO(Structure): _fields_ = [ ('name', c_char_p), ('description', c_char_p), ('priority', c_uint32), ('available', c_int), ('direction', c_int), ('n_profiles', c_uint32), ('profiles', c_void_p), # use profiles2 ('proplist', POINTER(PA_PROPLIST)), ('latency_offset', c_int64), ('profiles2', POINTER(POINTER(PA_CARD_PROFILE_INFO))), ] class PA_CARD_INFO(Structure): _fields_ = [ ('index', c_uint32), ('name', c_char_p), ('owner_module', c_uint32), ('driver', c_char_p), ('n_profiles', c_uint32), ('profiles', c_void_p), # use profiles2 / active_profile2 ('active_profile', c_void_p), ('proplist', POINTER(PA_PROPLIST)), ('n_ports', c_uint32), ('ports', POINTER(POINTER(PA_CARD_PORT_INFO))), ('profiles2', POINTER(POINTER(PA_CARD_PROFILE_INFO))), ('active_profile2', POINTER(PA_CARD_PROFILE_INFO)), ] class PA_MODULE_INFO(Structure): _fields_ = [ ('index', c_uint32), ('name', c_char_p), ('argument', c_char_p), ('n_used', c_uint32), ('auto_unload', c_int), ('proplist', POINTER(PA_PROPLIST)), ] class PA_EXT_STREAM_RESTORE_INFO(Structure): _fields_ = [ ('name', c_char_p), ('channel_map', PA_CHANNEL_MAP), ('volume', PA_CVOLUME), ('device', c_char_p), ('mute', c_int), ] class PA_BUFFER_ATTR(Structure): _fields_ = [ ('maxlength', c_uint32), ('tlength', c_uint32), ('prebuf', c_uint32), ('minreq', c_uint32), ('fragsize', c_uint32), ] class POLLFD(Structure): _fields_ = [ ('fd', c_int), ('events', c_short), ('revents', c_short), ] PA_POLL_FUNC_T = CFUNCTYPE(c_int, POINTER(POLLFD), c_ulong, c_int, c_void_p) PA_SIGNAL_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_MAINLOOP_API), POINTER(c_int), c_int, c_void_p) PA_STATE_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_CONTEXT), c_void_p) PA_CLIENT_INFO_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_CONTEXT), POINTER(PA_CLIENT_INFO), c_int, c_void_p) PA_SERVER_INFO_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_CONTEXT), POINTER(PA_SERVER_INFO), c_void_p) PA_SINK_INPUT_INFO_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_CONTEXT), POINTER(PA_SINK_INPUT_INFO), c_int, c_void_p) PA_SINK_INFO_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_CONTEXT), POINTER(PA_SINK_INFO), c_int, c_void_p) PA_SOURCE_OUTPUT_INFO_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_CONTEXT), POINTER(PA_SOURCE_OUTPUT_INFO), c_int, c_void_p) PA_SOURCE_INFO_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_CONTEXT), POINTER(PA_SOURCE_INFO), c_int, c_void_p) PA_CONTEXT_DRAIN_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_CONTEXT), c_void_p) PA_CONTEXT_INDEX_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_CONTEXT), c_uint32, c_void_p) PA_CONTEXT_SUCCESS_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_CONTEXT), c_int, c_void_p) PA_EXT_STREAM_RESTORE_TEST_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_CONTEXT), c_uint32, c_void_p) PA_EXT_STREAM_RESTORE_READ_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_CONTEXT), POINTER(PA_EXT_STREAM_RESTORE_INFO), c_int, c_void_p) PA_CARD_INFO_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_CONTEXT), POINTER(PA_CARD_INFO), c_int, c_void_p) PA_MODULE_INFO_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_CONTEXT), POINTER(PA_MODULE_INFO), c_int, c_void_p) PA_SUBSCRIBE_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_CONTEXT), c_int, c_int, c_void_p) PA_STREAM_REQUEST_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_STREAM), c_int, c_void_p) PA_STREAM_NOTIFY_CB_T = CFUNCTYPE(c_void_p, POINTER(PA_STREAM), c_void_p) class LibPulse(object): # func_def ::= arg_types_list | (arg_types_list, res_spec) | (res_spec, arg_types_list) # res_spec ::= ctypes_restype # | res_proc_func | (ctypes_restype, res_proc_func) # | res_spec_name_str | (ctypes_restype, res_spec_name_str) # res_spec_name_str ::= 'int_check_ge0' | 'pa_op' | ... func_defs = dict( pa_strerror=([c_int], c_str_p), pa_runtime_path=([c_str_p], (c_char_p, 'not_null')), pa_operation_unref=[POINTER(PA_OPERATION)], pa_mainloop_new=(POINTER(PA_MAINLOOP)), pa_mainloop_get_api=([POINTER(PA_MAINLOOP)], POINTER(PA_MAINLOOP_API)), pa_mainloop_run=([POINTER(PA_MAINLOOP), POINTER(c_int)], c_int), pa_mainloop_prepare=([POINTER(PA_MAINLOOP), c_int], 'int_check_ge0'), pa_mainloop_poll=([POINTER(PA_MAINLOOP)], 'int_check_ge0'), pa_mainloop_dispatch=([POINTER(PA_MAINLOOP)], 'int_check_ge0'), pa_mainloop_iterate=([POINTER(PA_MAINLOOP), c_int, POINTER(c_int)], 'int_check_ge0'), pa_mainloop_wakeup=[POINTER(PA_MAINLOOP)], pa_mainloop_set_poll_func=[POINTER(PA_MAINLOOP), PA_POLL_FUNC_T, c_void_p], pa_mainloop_quit=([POINTER(PA_MAINLOOP), c_int]), pa_mainloop_free=[POINTER(PA_MAINLOOP)], pa_signal_init=([POINTER(PA_MAINLOOP_API)], 'int_check_ge0'), pa_signal_new=([c_int, PA_SIGNAL_CB_T, POINTER(PA_SIGNAL_EVENT)]), pa_signal_done=None, pa_context_errno=([POINTER(PA_CONTEXT)], c_int), pa_context_new=([POINTER(PA_MAINLOOP_API), c_str_p], POINTER(PA_CONTEXT)), pa_context_set_state_callback=([POINTER(PA_CONTEXT), PA_STATE_CB_T, c_void_p]), pa_context_connect=([POINTER(PA_CONTEXT), c_str_p, c_int, POINTER(c_int)], 'int_check_ge0'), pa_context_get_state=([POINTER(PA_CONTEXT)], c_int), pa_context_disconnect=[POINTER(PA_CONTEXT)], pa_context_unref=[POINTER(PA_CONTEXT)], pa_context_drain=( 'pa_op', [POINTER(PA_CONTEXT), PA_CONTEXT_DRAIN_CB_T, c_void_p] ), pa_context_set_default_sink=( 'pa_op', [POINTER(PA_CONTEXT), c_str_p, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_set_default_source=( 'pa_op', [POINTER(PA_CONTEXT), c_str_p, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_get_sink_input_info_list=( 'pa_op', [POINTER(PA_CONTEXT), PA_SINK_INPUT_INFO_CB_T, c_void_p] ), pa_context_get_sink_input_info=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, PA_SINK_INPUT_INFO_CB_T, c_void_p] ), pa_context_get_sink_info_list=( 'pa_op', [POINTER(PA_CONTEXT), PA_SINK_INFO_CB_T, c_void_p] ), pa_context_get_sink_info_by_name=( 'pa_op', [POINTER(PA_CONTEXT), c_str_p, PA_SINK_INFO_CB_T, c_void_p] ), pa_context_get_sink_info_by_index=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, PA_SINK_INFO_CB_T, c_void_p] ), pa_context_set_sink_mute_by_index=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, c_int, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_suspend_sink_by_index=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, c_int, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_set_sink_port_by_index=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, c_str_p, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_set_sink_input_mute=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, c_int, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_set_sink_volume_by_index=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, POINTER(PA_CVOLUME), PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_set_sink_input_volume=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, POINTER(PA_CVOLUME), PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_move_sink_input_by_index=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, c_uint32, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_get_source_output_info=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, PA_SOURCE_OUTPUT_INFO_CB_T, c_void_p] ), pa_context_get_source_output_info_list=( 'pa_op', [POINTER(PA_CONTEXT), PA_SOURCE_OUTPUT_INFO_CB_T, c_void_p] ), pa_context_move_source_output_by_index=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, c_uint32, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_set_source_output_volume=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, POINTER(PA_CVOLUME), PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_set_source_output_mute=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, c_int, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_kill_source_output=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_get_source_info_list=( 'pa_op', [POINTER(PA_CONTEXT), PA_SOURCE_INFO_CB_T, c_void_p] ), pa_context_get_source_info_by_name=( 'pa_op', [POINTER(PA_CONTEXT), c_str_p, PA_SOURCE_INFO_CB_T, c_void_p] ), pa_context_get_source_info_by_index=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, PA_SOURCE_INFO_CB_T, c_void_p] ), pa_context_set_source_volume_by_index=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, POINTER(PA_CVOLUME), PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_set_source_mute_by_index=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, c_int, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_suspend_source_by_index=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, c_int, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_set_source_port_by_index=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, c_str_p, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_get_client_info_list=( 'pa_op', [POINTER(PA_CONTEXT), PA_CLIENT_INFO_CB_T, c_void_p] ), pa_context_get_client_info=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, PA_CLIENT_INFO_CB_T, c_void_p] ), pa_context_get_server_info=( 'pa_op', [POINTER(PA_CONTEXT), PA_SERVER_INFO_CB_T, c_void_p] ), pa_context_get_card_info_by_index=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, PA_CARD_INFO_CB_T, c_void_p] ), pa_context_get_card_info_by_name=( 'pa_op', [POINTER(PA_CONTEXT), c_str_p, PA_CARD_INFO_CB_T, c_void_p] ), pa_context_get_card_info_list=( 'pa_op', [POINTER(PA_CONTEXT), PA_CARD_INFO_CB_T, c_void_p] ), pa_context_set_card_profile_by_index=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, c_str_p, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_get_module_info=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, PA_MODULE_INFO_CB_T, c_void_p] ), pa_context_get_module_info_list=( 'pa_op', [POINTER(PA_CONTEXT), PA_MODULE_INFO_CB_T, c_void_p] ), pa_context_load_module=( 'pa_op', [POINTER(PA_CONTEXT), c_char_p, c_char_p, PA_CONTEXT_INDEX_CB_T, c_void_p] ), pa_context_unload_module=( 'pa_op', [POINTER(PA_CONTEXT), c_uint32, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_subscribe=( 'pa_op', [POINTER(PA_CONTEXT), c_int, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_set_subscribe_callback=[POINTER(PA_CONTEXT), PA_SUBSCRIBE_CB_T, c_void_p], pa_context_play_sample=( 'pa_op', [POINTER(PA_CONTEXT), c_str_p, c_str_p, c_uint32, PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_context_play_sample_with_proplist=( 'pa_op', [ POINTER(PA_CONTEXT), c_str_p, c_str_p, c_uint32, POINTER(PA_PROPLIST), PA_CONTEXT_SUCCESS_CB_T, c_void_p ] ), pa_ext_stream_restore_test=( 'pa_op', [POINTER(PA_CONTEXT), PA_EXT_STREAM_RESTORE_TEST_CB_T, c_void_p] ), pa_ext_stream_restore_read=( 'pa_op', [POINTER(PA_CONTEXT), PA_EXT_STREAM_RESTORE_READ_CB_T, c_void_p] ), pa_ext_stream_restore_write=( 'pa_op', [ POINTER(PA_CONTEXT), c_int, POINTER(PA_EXT_STREAM_RESTORE_INFO), c_uint, c_int, PA_CONTEXT_SUCCESS_CB_T, c_void_p ] ), pa_ext_stream_restore_delete=( 'pa_op', [POINTER(PA_CONTEXT), POINTER(c_char_p), PA_CONTEXT_SUCCESS_CB_T, c_void_p] ), pa_proplist_from_string=([c_str_p], POINTER(PA_PROPLIST)), pa_proplist_iterate=([POINTER(PA_PROPLIST), POINTER(c_void_p)], c_str_p), pa_proplist_gets=([POINTER(PA_PROPLIST), c_str_p], c_str_p), pa_proplist_free=[POINTER(PA_PROPLIST)], pa_channel_map_init_mono=( [POINTER(PA_CHANNEL_MAP)], (POINTER(PA_CHANNEL_MAP), 'not_null') ), pa_channel_map_init_stereo=( [POINTER(PA_CHANNEL_MAP)], (POINTER(PA_CHANNEL_MAP), 'not_null') ), pa_channel_map_snprint=([c_str_p, c_int, POINTER(PA_CHANNEL_MAP)], c_str_p), pa_channel_map_parse=( [POINTER(PA_CHANNEL_MAP), c_str_p], (POINTER(PA_CHANNEL_MAP), 'not_null') ), pa_channel_position_to_string=([c_int], c_str_p), pa_stream_new_with_proplist=( [ POINTER(PA_CONTEXT), c_str_p, POINTER(PA_SAMPLE_SPEC), POINTER(PA_CHANNEL_MAP), POINTER(PA_PROPLIST) ], POINTER(PA_STREAM) ), pa_stream_set_monitor_stream=([POINTER(PA_STREAM), c_uint32], 'int_check_ge0'), pa_stream_set_read_callback=[POINTER(PA_STREAM), PA_STREAM_REQUEST_CB_T, c_void_p], pa_stream_connect_record=( [POINTER(PA_STREAM), c_str_p, POINTER(PA_BUFFER_ATTR), c_int], 'int_check_ge0' ), pa_stream_unref=[POINTER(PA_STREAM)], pa_stream_peek=( [POINTER(PA_STREAM), POINTER(c_void_p), POINTER(c_int)], 'int_check_ge0' ), pa_stream_drop=([POINTER(PA_STREAM)], 'int_check_ge0'), pa_stream_disconnect=([POINTER(PA_STREAM)], 'int_check_ge0') ) class CallError(Exception): pass def __init__(self): p = CDLL(ctypes.util.find_library('libpulse') or 'libpulse.so.0') self.funcs = dict() for k, spec in self.func_defs.items(): func, args, res_proc = getattr(p, k), None, None if spec: if not isinstance(spec, tuple): spec = (spec,) for v in spec: assert v, [k, spec, v] if isinstance(v, list): args = v else: res_proc = v func_k = k if not k.startswith('pa_') else k[3:] self.funcs[func_k] = self._func_wrapper(k, func, args, res_proc) def _func_wrapper(self, func_name, func, args=list(), res_proc=None): func.restype, func.argtypes = None, args if isinstance(res_proc, tuple): func.restype, res_proc = res_proc if isinstance(res_proc, str): if res_proc.startswith('int_check_'): func.restype = c_int elif res_proc == 'pa_op': func.restype = POINTER(PA_OPERATION) elif not func.restype and hasattr(res_proc, 'c_type'): func.restype = res_proc.c_type elif not func.restype: func.restype, res_proc = res_proc, None def _wrapper(*args): # print('libpulse call:', func_name, args, file=sys.stderr) # sys.stderr.flush() res = func(*args) if isinstance(res_proc, str): assert res_proc in ['int_check_ge0', 'pa_op', 'not_null'] if (res_proc == 'int_check_ge0' and res < 0)\ or (res_proc == 'pa_op' and not res)\ or (res_proc == 'not_null' and not res): err = [func_name, args, res] if args and isinstance(getattr(args[0], 'contents', None), PA_CONTEXT): errno_ = self.context_errno(args[0]) err.append('{} [pulse errno {}]'.format(self.strerror(errno_), errno_)) else: err.append('Return value check failed: {}'.format(res_proc)) raise self.CallError(*err) elif res_proc: res = res_proc(res) return res _wrapper.__name__ = 'libpulse.{}'.format(func_name) return _wrapper def __getattr__(self, k): return self.funcs[k] def return_value(self): return pointer(c_int()) pa = LibPulse()