@@ -818,7 +818,7 @@ def query_hostapis(index=None):
818818 The dictionaries have the following keys:
819819
820820 ``'name'``
821- The name of the host API.
821+ The name of the host API and suitable for user display .
822822 ``'devices'``
823823 A list of device IDs belonging to the host API.
824824 Use `query_devices()` to get information about a device.
@@ -831,6 +831,16 @@ def query_hostapis(index=None):
831831 overwritten by assigning to `default.device` -- take(s)
832832 precedence over `default.hostapi` and the information in
833833 the abovementioned dictionaries.
834+ ``'apiname'``
835+ *apiname* is a string that is suitable for use as a Python
836+ identifier. Unlike *name*, *apiname* does not contain
837+ spaces or any other characters that are not suitable as a
838+ Python identifier. These strings are derived from
839+ PortAudio's PaHostApiTypeId enumeration and thus correspond
840+ on a one-to-one basis with that enumeration. These strings
841+ shall never be eubject to locale settings such as LANG,
842+ LC_ALL, or LC_MESSAGES. In short, these strings are safer
843+ than *name* for hard coding into an application.
834844 ``'api'``
835845 A namedtuple containing the platform-specific API from
836846 PortAudio. If a platform-specific API is unavailable, this
@@ -858,6 +868,7 @@ def query_hostapis(index=None):
858868 for i in range (info .deviceCount )],
859869 'default_input_device' : info .defaultInputDevice ,
860870 'default_output_device' : info .defaultOutputDevice ,
871+ 'apiname' : _get_host_apiname (info .type ),
861872 'api' : api ,
862873 }
863874
@@ -2353,6 +2364,48 @@ class CallbackAbort(Exception):
23532364# Host-API:
23542365
23552366
2367+ # Is there a way to query the names used in "enum PaHostApiTypeId"?
2368+ # If so, then I wouldn't bother with this dict, _typeid_to_apiname.
2369+ #
2370+ # Q: Should _typeid_to_apiname be brought out to global scope, with
2371+ # the leading underscore? I'm averse to relying upon converting the
2372+ # current .name field as an api identifier, since those strings are
2373+ # intended for user consumption. (For example, will Port Audio one
2374+ # day provide language translations of those names? If they did,
2375+ # these names could differ for each user purely based on locale
2376+ # settings, such as LANG, LC_ALL, or LC_MESSAGES!)
2377+ _typeid_to_apiname = {
2378+ _lib .paInDevelopment : str .lower ('InDevelopment' ),
2379+ _lib .paDirectSound : str .lower ('DirectSound' ),
2380+ _lib .paMME : str .lower ('MME' ),
2381+ _lib .paASIO : str .lower ('ASIO' ),
2382+ _lib .paSoundManager : str .lower ('SoundManager' ),
2383+ _lib .paCoreAudio : str .lower ('CoreAudio' ),
2384+ _lib .paOSS : str .lower ('OSS' ),
2385+ _lib .paALSA : str .lower ('ALSA' ),
2386+ _lib .paAL : str .lower ('AL' ),
2387+ _lib .paBeOS : str .lower ('BeOS' ),
2388+ _lib .paWDMKS : str .lower ('WDMKS' ),
2389+ _lib .paJACK : str .lower ('JACK' ),
2390+ _lib .paWASAPI : str .lower ('WASAPI' ),
2391+ _lib .paAudioScienceHPI : str .lower ('AudioScienceHPI' ),
2392+ }
2393+ def _get_host_apiname (hostapi_typeid ):
2394+ # Assume int for building '_hostapi###' strings.
2395+ assert isinstance (hostapi_typeid , int )
2396+ try :
2397+ # Pre-assigned name:
2398+ return _typeid_to_apiname [hostapi_typeid ]
2399+ except KeyError :
2400+ # Make up new names on the fly:
2401+ if hostapi_typeid >= 0 :
2402+ # 42 -> '_hostapi42'
2403+ return '_hostapi' + str (hostapi_typeid )
2404+ else :
2405+ # -37 -> '_hostapi_37'
2406+ return '_hostapi_' + str (- hostapi_typeid )
2407+
2408+
23562409_api_dicts = {}
23572410def _get_host_api (hostapi_typeid ):
23582411 """Lookup hostapi_typeid and return the results as a namedtuple.
@@ -2376,11 +2429,34 @@ def _get_host_api(hostapi_typeid):
23762429
23772430 """
23782431 api_dict = _api_dicts [hostapi_typeid ]
2379- API = _namedtuple ('_API_' + str (hostapi_typeid ), api_dict .keys ())
2432+ # Using .upper() to distinguish that we're using _get_host_apiname
2433+ # to name a type:
2434+ API = _namedtuple (_get_host_apiname (hostapi_typeid ).upper (),
2435+ api_dict .keys ())
23802436 api = API (** api_dict )
23812437 return api
23822438
23832439
2440+ # hostapis is an alternative interface to query_hostapis and populated during _initialize().
2441+ hostapis = None
2442+
2443+
2444+ def _populate_hostapis ():
2445+ global hostapis
2446+ # For now, just invoke query_hostapis() to get the list. Later if
2447+ # we deprecate query_hostapis, we can move its guts into here.
2448+ hostapi_list = query_hostapis ()
2449+ # There is one _HostAPI for each field in _HostAPIs:
2450+ _HostAPI = _namedtuple ('_HostAPI' , ('name' , 'devices' ,
2451+ 'default_input_device' ,
2452+ 'default_output_device' ,
2453+ 'apiname' , 'api' ))
2454+ class HostAPIs (_namedtuple ('HostAPIs' , (h ['apiname' ] for h in hostapi_list ))):
2455+ """Access to PortAudio Host API's"""
2456+ __slots__ = ()
2457+ hostapis = HostAPIs (* (_HostAPI (** h ) for h in hostapi_list ))
2458+
2459+
23842460# Host-API: ASIO
23852461
23862462
@@ -3176,6 +3252,7 @@ def _initialize():
31763252 global _initialized
31773253 _check (_lib .Pa_Initialize (), 'Error initializing PortAudio' )
31783254 _initialized += 1
3255+ _populate_hostapis ()
31793256
31803257
31813258def _terminate ():
0 commit comments