diff options
| author | Stephen Sinclair <radarsat1@gmail.com> | 2018-10-16 15:01:30 +0200 |
|---|---|---|
| committer | Stephen Sinclair <radarsat1@gmail.com> | 2018-10-16 15:01:30 +0200 |
| commit | 4690b26068191afa44dc8a872e250990acb1d175 (patch) | |
| tree | 0b6b1e4d752315423590e134f72e844760601540 | |
| parent | 154627e9e314bc99d5f29a1675bdbd7a7c80c612 (diff) | |
| parent | 6919d3578769202957d1ba320ff458e959935e05 (diff) | |
Merge remote-tracking branch 'upstream/pr/136'
| -rw-r--r-- | CMakeLists.txt | 1 | ||||
| -rw-r--r-- | Makefile.am | 1 | ||||
| -rw-r--r-- | RtAudio.cpp | 84 | ||||
| -rw-r--r-- | RtAudio.h | 32 | ||||
| -rw-r--r-- | rtaudio_c.cpp | 57 | ||||
| -rw-r--r-- | rtaudio_c.h | 8 | ||||
| -rw-r--r-- | tests/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | tests/Makefile.am | 5 | ||||
| -rw-r--r-- | tests/apinames.cpp | 157 |
9 files changed, 299 insertions, 49 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 77ffdb0..d220bc7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -216,6 +216,7 @@ if(BUILD_SHARED_LIBS) # Set compile-time definitions target_compile_definitions(rtaudio PRIVATE ${API_DEFS}) + target_compile_definitions(rtaudio PRIVATE RTAUDIO_EXPORT) target_link_libraries(rtaudio ${LINKLIBS}) endif() diff --git a/Makefile.am b/Makefile.am index f83007c..2a05035 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,6 +6,7 @@ endif AM_CXXFLAGS = @visibility@ lib_LTLIBRARIES = %D%/librtaudio.la +%C%_librtaudio_la_CXXFLAGS = -DRTAUDIO_EXPORT %C%_librtaudio_la_LDFLAGS = -no-undefined -export-dynamic -version-info @SO_VERSION@ %C%_librtaudio_la_SOURCES = \ %D%/RtAudio.cpp \ diff --git a/RtAudio.cpp b/RtAudio.cpp index 77bd4b6..5bc1055 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -98,39 +98,95 @@ std::string RtAudio :: getVersion( void ) return RTAUDIO_VERSION; } -void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis ) -{ - apis.clear(); +// Define API names and display names. +// Must be in same order as API enum. +extern "C" { +const char* rtaudio_api_names[][2] = { + { "unspecified" , "Unknown" }, + { "alsa" , "ALSA" }, + { "pulse" , "Pulse" }, + { "oss" , "OpenSoundSystem" }, + { "jack" , "Jack" }, + { "core" , "CoreAudio" }, + { "wasapi" , "WASAPI" }, + { "asio" , "ASIO" }, + { "ds" , "DirectSound" }, + { "dummy" , "Dummy" }, +}; +const unsigned int rtaudio_num_api_names = + sizeof(rtaudio_api_names)/sizeof(rtaudio_api_names[0]); - // The order here will control the order of RtAudio's API search in - // the constructor. +// The order here will control the order of RtAudio's API search in +// the constructor. +extern "C" const RtAudio::Api rtaudio_compiled_apis[] = { #if defined(__UNIX_JACK__) - apis.push_back( UNIX_JACK ); + RtAudio::UNIX_JACK, #endif #if defined(__LINUX_PULSE__) - apis.push_back( LINUX_PULSE ); + RtAudio::LINUX_PULSE, #endif #if defined(__LINUX_ALSA__) - apis.push_back( LINUX_ALSA ); + RtAudio::LINUX_ALSA, #endif #if defined(__LINUX_OSS__) - apis.push_back( LINUX_OSS ); + RtAudio::LINUX_OSS, #endif #if defined(__WINDOWS_ASIO__) - apis.push_back( WINDOWS_ASIO ); + RtAudio::WINDOWS_ASIO, #endif #if defined(__WINDOWS_WASAPI__) - apis.push_back( WINDOWS_WASAPI ); + RtAudio::WINDOWS_WASAPI, #endif #if defined(__WINDOWS_DS__) - apis.push_back( WINDOWS_DS ); + RtAudio::WINDOWS_DS, #endif #if defined(__MACOSX_CORE__) - apis.push_back( MACOSX_CORE ); + RtAudio::MACOSX_CORE, #endif #if defined(__RTAUDIO_DUMMY__) - apis.push_back( RTAUDIO_DUMMY ); + RtAudio::RTAUDIO_DUMMY, #endif + RtAudio::UNSPECIFIED, +}; +extern "C" const unsigned int rtaudio_num_compiled_apis = + sizeof(rtaudio_compiled_apis)/sizeof(rtaudio_compiled_apis[0])-1; +} + +// This is a compile-time check that rtaudio_num_api_names == RtAudio::NUM_APIS. +// If the build breaks here, check that they match. +template<bool b> class StaticAssert { private: StaticAssert() {} }; +template<> class StaticAssert<true>{ public: StaticAssert() {} }; +class StaticAssertions { StaticAssertions() { + StaticAssert<rtaudio_num_api_names == RtAudio::NUM_APIS>(); +}}; + +void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis ) +{ + apis = std::vector<RtAudio::Api>(rtaudio_compiled_apis, + rtaudio_compiled_apis + rtaudio_num_compiled_apis); +} + +std::string RtAudio :: getApiName( RtAudio::Api api ) +{ + if (api < 0 || api >= RtAudio::NUM_APIS) + return ""; + return rtaudio_api_names[api][0]; +} + +std::string RtAudio :: getApiDisplayName( RtAudio::Api api ) +{ + if (api < 0 || api >= RtAudio::NUM_APIS) + return "Unknown"; + return rtaudio_api_names[api][1]; +} + +RtAudio::Api RtAudio :: getCompiledApiByName( const std::string &name ) +{ + unsigned int i=0; + for (i = 0; i < rtaudio_num_compiled_apis; ++i) + if (name == rtaudio_api_names[rtaudio_compiled_apis[i]][0]) + return rtaudio_compiled_apis[i]; + return RtAudio::UNSPECIFIED; } void RtAudio :: openRtApi( RtAudio::Api api ) @@ -48,7 +48,11 @@ #define RTAUDIO_VERSION "5.0.0" #if defined _WIN32 || defined __CYGWIN__ - #define RTAUDIO_DLL_PUBLIC + #if defined(RTAUDIO_EXPORT) + #define RTAUDIO_DLL_PUBLIC __declspec(dllexport) + #else + #define RTAUDIO_DLL_PUBLIC + #endif #else #if __GNUC__ >= 4 #define RTAUDIO_DLL_PUBLIC __attribute__( (visibility( "default" )) ) @@ -285,7 +289,8 @@ class RTAUDIO_DLL_PUBLIC RtAudio WINDOWS_WASAPI, /*!< The Microsoft WASAPI API. */ WINDOWS_ASIO, /*!< The Steinberg Audio Stream I/O API. */ WINDOWS_DS, /*!< The Microsoft Direct Sound API. */ - RTAUDIO_DUMMY /*!< A compilable but non-functional API. */ + RTAUDIO_DUMMY, /*!< A compilable but non-functional API. */ + NUM_APIS /*!< Number of values in this enum. */ }; //! The public device information structure for returning queried values. @@ -397,6 +402,29 @@ class RTAUDIO_DLL_PUBLIC RtAudio */ static void getCompiledApi( std::vector<RtAudio::Api> &apis ); + //! Return the name of a specified compiled audio API. + /*! + This obtains a short lower-case name used for identification purposes. + This value is guaranteed to remain identical across library versions. + If the API is unknown, this function will return the empty string. + */ + static std::string getApiName( RtAudio::Api api ); + + //! Return the display name of a specified compiled audio API. + /*! + This obtains a long name used for display purposes. + If the API is unknown, this function will return the empty string. + */ + static std::string getApiDisplayName( RtAudio::Api api ); + + //! Return the compiled audio API having the given name. + /*! + A case insensitive comparison will check the specified name + against the list of compiled APIs, and return the one which + matches. On failure, the function returns UNSPECIFIED. + */ + static RtAudio::Api getCompiledApiByName( const std::string &name ); + //! The class constructor. /*! The constructor performs minor initialization tasks. An exception diff --git a/rtaudio_c.cpp b/rtaudio_c.cpp index 699d2ce..da3ab24 100644 --- a/rtaudio_c.cpp +++ b/rtaudio_c.cpp @@ -15,40 +15,33 @@ struct rtaudio { char errmsg[MAX_ERROR_MESSAGE_LENGTH]; }; -static const rtaudio_api_t compiled_api[] = { -#if defined(__UNIX_JACK__) - RTAUDIO_API_UNIX_JACK, -#endif -#if defined(__LINUX_ALSA__) - RTAUDIO_API_LINUX_ALSA, -#endif -#if defined(__LINUX_PULSE__) - RTAUDIO_API_LINUX_PULSE, -#endif -#if defined(__LINUX_OSS__) - RTAUDIO_API_LINUX_OSS, -#endif -#if defined(__WINDOWS_ASIO__) - RTAUDIO_API_WINDOWS_ASIO, -#endif -#if defined(__WINDOWS_WASAPI__) - RTAUDIO_API_WINDOWS_WASAPI, -#endif -#if defined(__WINDOWS_DS__) - RTAUDIO_API_WINDOWS_DS, -#endif -#if defined(__MACOSX_CORE__) - RTAUDIO_API_MACOSX_CORE, -#endif -#if defined(__RTAUDIO_DUMMY__) - RTAUDIO_API_DUMMY, -#endif - RTAUDIO_API_UNSPECIFIED, -}; - const char *rtaudio_version() { return RTAUDIO_VERSION; } -const rtaudio_api_t *rtaudio_compiled_api() { return compiled_api; } +extern "C" const rtaudio_api_t rtaudio_compiled_apis[]; // casting from RtAudio::Api[] +extern "C" const unsigned int rtaudio_num_compiled_apis; +const rtaudio_api_t *rtaudio_compiled_api() { return rtaudio_compiled_apis; } + +extern "C" const char* rtaudio_api_names[][2]; +const char *rtaudio_api_name(rtaudio_api_t api) { + if (api < 0 || api >= RTAUDIO_API_NUM) + return NULL; + return rtaudio_api_names[api][0]; +} + +const char *rtaudio_api_display_name(rtaudio_api_t api) +{ + if (api < 0 || api >= RTAUDIO_API_NUM) + return "Unknown"; + return rtaudio_api_names[api][1]; +} + +rtaudio_api_t rtaudio_compiled_api_by_name(const char *name) { + RtAudio::Api api = RtAudio::UNSPECIFIED; + if (name) { + api = RtAudio::getCompiledApiByName(name); + } + return (rtaudio_api_t)api; +} const char *rtaudio_error(rtaudio_t audio) { if (audio->has_error) { diff --git a/rtaudio_c.h b/rtaudio_c.h index 05015a9..a366117 100644 --- a/rtaudio_c.h +++ b/rtaudio_c.h @@ -2,8 +2,12 @@ #define RTAUDIO_C_H #if defined(RTAUDIO_EXPORT) +#if defined _WIN32 || defined __CYGWIN__ #define RTAUDIOAPI __declspec(dllexport) #else +#define RTAUDIOAPI __attribute__((visibility("default"))) +#endif +#else #define RTAUDIOAPI //__declspec(dllimport) #endif @@ -64,6 +68,7 @@ typedef enum rtaudio_api { RTAUDIO_API_WINDOWS_ASIO, RTAUDIO_API_WINDOWS_DS, RTAUDIO_API_DUMMY, + RTAUDIO_API_NUM, } rtaudio_api_t; #define NUM_SAMPLE_RATES 16 @@ -102,6 +107,9 @@ typedef struct rtaudio *rtaudio_t; RTAUDIOAPI const char *rtaudio_version(void); RTAUDIOAPI const rtaudio_api_t *rtaudio_compiled_api(void); +RTAUDIOAPI const char *rtaudio_api_name(rtaudio_api_t api); +RTAUDIOAPI const char *rtaudio_api_display_name(rtaudio_api_t api); +RTAUDIOAPI rtaudio_api_t rtaudio_compiled_api_by_name(const char *name); RTAUDIOAPI const char *rtaudio_error(rtaudio_t audio); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5c08f6d..5847027 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,6 +20,9 @@ target_link_libraries(record ${LIBRTAUDIO} ${LINKLIBS}) add_executable(duplex duplex.cpp) target_link_libraries(duplex ${LIBRTAUDIO} ${LINKLIBS}) +add_executable(apinames apinames.cpp) +target_link_libraries(apinames ${LIBRTAUDIO} ${LINKLIBS}) + add_executable(testall testall.cpp) target_link_libraries(testall ${LIBRTAUDIO} ${LINKLIBS}) diff --git a/tests/Makefile.am b/tests/Makefile.am index e39fdde..c8159da 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,5 +1,5 @@ -noinst_PROGRAMS = audioprobe playsaw playraw record duplex testall teststops +noinst_PROGRAMS = audioprobe playsaw playraw record duplex apinames testall teststops AM_CXXFLAGS = -Wall -I$(top_srcdir) @@ -18,6 +18,9 @@ record_LDADD = $(top_builddir)/librtaudio.la duplex_SOURCES = duplex.cpp duplex_LDADD = $(top_builddir)/librtaudio.la +apinames_SOURCES = apinames.cpp +apinames_LDADD = $(top_builddir)/librtaudio.la + testall_SOURCES = testall.cpp testall_LDADD = $(top_builddir)/librtaudio.la diff --git a/tests/apinames.cpp b/tests/apinames.cpp new file mode 100644 index 0000000..c270764 --- /dev/null +++ b/tests/apinames.cpp @@ -0,0 +1,157 @@ +/******************************************/ +/* + apinames.cpp + by Jean Pierre Cimalando, 2018. + + This program tests parts of RtAudio related + to API names, the conversion from name to API + and vice-versa. +*/ +/******************************************/ + +#include "RtAudio.h" +#include <cctype> +#include <cstdlib> +#include <iostream> + +int test_cpp() { + std::vector<RtAudio::Api> apis; + RtAudio::getCompiledApi( apis ); + + // ensure the known APIs return valid names + std::cout << "API names by identifier (C++):\n"; + for ( size_t i = 0; i < apis.size() ; ++i ) { + const std::string name = RtAudio::getApiName(apis[i]); + if (name.empty()) { + std::cout << "Invalid name for API " << (int)apis[i] << "\n"; + exit(1); + } + const std::string displayName = RtAudio::getApiDisplayName(apis[i]); + if (displayName.empty()) { + std::cout << "Invalid display name for API " << (int)apis[i] << "\n"; + exit(1); + } + std::cout << "* " << (int)apis[i] << " '" << name << "': '" << displayName << "'\n"; + } + + // ensure unknown APIs return the empty string + { + const std::string name = RtAudio::getApiName((RtAudio::Api)-1); + if (!name.empty()) { + std::cout << "Bad string for invalid API '" << name << "'\n"; + exit(1); + } + const std::string displayName = RtAudio::getApiDisplayName((RtAudio::Api)-1); + if (displayName!="Unknown") { + std::cout << "Bad display string for invalid API '" << displayName << "'\n"; + exit(1); + } + } + + // try getting API identifier by name + std::cout << "API identifiers by name (C++):\n"; + for ( size_t i = 0; i < apis.size() ; ++i ) { + std::string name = RtAudio::getApiName(apis[i]); + if ( RtAudio::getCompiledApiByName(name) != apis[i] ) { + std::cout << "Bad identifier for API '" << name << "'\n"; + exit( 1 ); + } + std::cout << "* '" << name << "': " << (int)apis[i] << "\n"; + + for ( size_t j = 0; j < name.size(); ++j ) + name[j] = (j & 1) ? toupper(name[j]) : tolower(name[j]); + RtAudio::Api api = RtAudio::getCompiledApiByName(name); + if ( api != RtAudio::UNSPECIFIED ) { + std::cout << "Identifier " << (int)api << " for invalid API '" << name << "'\n"; + exit( 1 ); + } + } + + // try getting an API identifier by unknown name + { + RtAudio::Api api; + api = RtAudio::getCompiledApiByName(""); + if ( api != RtAudio::UNSPECIFIED ) { + std::cout << "Bad identifier for unknown API name\n"; + exit( 1 ); + } + } + + return 0; +} + +#include "rtaudio_c.h" + +int test_c() { + const rtaudio_api_t *apis = rtaudio_compiled_api(); + + // ensure the known APIs return valid names + std::cout << "API names by identifier (C):\n"; + for ( size_t i = 0; apis[i] != RTAUDIO_API_UNSPECIFIED; ++i) { + const std::string name = rtaudio_api_name(apis[i]); + if (name.empty()) { + std::cout << "Invalid name for API " << (int)apis[i] << "\n"; + exit(1); + } + const std::string displayName = rtaudio_api_display_name(apis[i]); + if (displayName.empty()) { + std::cout << "Invalid display name for API " << (int)apis[i] << "\n"; + exit(1); + } + std::cout << "* " << (int)apis[i] << " '" << name << "': '" << displayName << "'\n"; + } + + // ensure unknown APIs return the empty string + { + const char *s = rtaudio_api_name((rtaudio_api_t)-1); + const std::string name(s?s:""); + if (!name.empty()) { + std::cout << "Bad string for invalid API '" << name << "'\n"; + exit(1); + } + s = rtaudio_api_display_name((rtaudio_api_t)-1); + const std::string displayName(s?s:""); + if (displayName!="Unknown") { + std::cout << "Bad display string for invalid API '" << displayName << "'\n"; + exit(1); + } + } + + // try getting API identifier by name + std::cout << "API identifiers by name (C):\n"; + for ( size_t i = 0; apis[i] != RTAUDIO_API_UNSPECIFIED ; ++i ) { + const char *s = rtaudio_api_name(apis[i]); + std::string name(s?s:""); + if ( rtaudio_compiled_api_by_name(name.c_str()) != apis[i] ) { + std::cout << "Bad identifier for API '" << name << "'\n"; + exit( 1 ); + } + std::cout << "* '" << name << "': " << (int)apis[i] << "\n"; + + for ( size_t j = 0; j < name.size(); ++j ) + name[j] = (j & 1) ? toupper(name[j]) : tolower(name[j]); + rtaudio_api_t api = rtaudio_compiled_api_by_name(name.c_str()); + if ( api != RTAUDIO_API_UNSPECIFIED ) { + std::cout << "Identifier " << (int)api << " for invalid API '" << name << "'\n"; + exit( 1 ); + } + } + + // try getting an API identifier by unknown name + { + rtaudio_api_t api; + api = rtaudio_compiled_api_by_name(""); + if ( api != RTAUDIO_API_UNSPECIFIED ) { + std::cout << "Bad identifier for unknown API name\n"; + exit( 1 ); + } + } + + return 0; +} + +int main() +{ + test_cpp(); + test_c(); +} |
