From f7b624ba819036b9ebfb3f4d0517fd45e01919b2 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Mon, 7 May 2018 17:30:27 +0200 Subject: [PATCH 1/3] API names, and conversion from/to API identifier --- RtAudio.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++++ RtAudio.h | 15 ++++++++ tests/CMakeLists.txt | 3 ++ tests/Makefile.am | 5 ++- tests/apinames.cpp | 75 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 tests/apinames.cpp diff --git a/RtAudio.cpp b/RtAudio.cpp index b091e15..db3b7cb 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -133,6 +134,92 @@ void RtAudio :: getCompiledApi( std::vector &apis ) #endif } +const std::string &RtAudio :: getCompiledApiName( RtAudio::Api api ) +{ +#if defined(__UNIX_JACK__) + if ( api == UNIX_JACK ) { + static std::string name( "JACK" ); + return name; + } +#endif +#if defined(__LINUX_PULSE__) + if ( api == LINUX_PULSE ) { + static std::string name( "PulseAudio" ); + return name; + } +#endif +#if defined(__LINUX_ALSA__) + if ( api == LINUX_ALSA ) { + static std::string name( "ALSA" ); + return name; + } +#endif +#if defined(__LINUX_OSS__) + if ( api == LINUX_OSS ) { + static std::string name( "OSS" ); + return name; + } +#endif +#if defined(__WINDOWS_ASIO__) + if ( api == WINDOWS_ASIO ) { + static std::string name( "ASIO" ); + return name; + } +#endif +#if defined(__WINDOWS_WASAPI__) + if ( api == WINDOWS_WASAPI ) { + static std::string name( "WASAPI" ); + return name; + } +#endif +#if defined(__WINDOWS_DS__) + if ( api == WINDOWS_DS ) { + static std::string name( "DirectSound" ); + return name; + } +#endif +#if defined(__MACOSX_CORE__) + if ( api == MACOSX_CORE ) { + static std::string name( "CoreAudio" ); + return name; + } +#endif +#if defined(__RTAUDIO_DUMMY__) + if ( api == RTAUDIO_DUMMY ) { + static std::string name( "Dummy" ); + return name; + } +#endif + static std::string name; + return name; +} + +RtAudio::Api RtAudio :: getCompiledApiByName( const std::string &name ) +{ + unsigned int api_number = RtAudio::UNSPECIFIED; + size_t nameLength = name.size(); + + if ( nameLength == 0 ) + return RtAudio::UNSPECIFIED; + + while ( api_number <= RtAudio::RTAUDIO_DUMMY ) { + const std::string &otherName = + getCompiledApiName((RtAudio::Api)api_number); + + bool equal = nameLength == otherName.size(); + for ( size_t i = 0; equal && i < nameLength; ++i ) + equal = tolower((unsigned char)name[i]) == + tolower((unsigned char)otherName[i]); + + if ( equal ) + return (RtAudio::Api)api_number; + + ++api_number; + } + + return RtAudio::UNSPECIFIED; +} + void RtAudio :: openRtApi( RtAudio::Api api ) { if ( rtapi_ ) diff --git a/RtAudio.h b/RtAudio.h index 34a2534..91124cf 100644 --- a/RtAudio.h +++ b/RtAudio.h @@ -397,6 +397,21 @@ class RTAUDIO_DLL_PUBLIC RtAudio */ static void getCompiledApi( std::vector &apis ); + //! Return the name of a specified compiled audio API. + /*! + If the API is unknown or not compiled, this function will return + the empty string. + */ + static const std::string &getCompiledApiName( 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/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0fb028f..f611d51 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,6 +18,9 @@ target_link_libraries(record rtaudio_static ${LINKLIBS}) add_executable(duplex duplex.cpp) target_link_libraries(duplex rtaudio_static ${LINKLIBS}) +add_executable(apinames apinames.cpp) +target_link_libraries(apinames rtaudio_static ${LINKLIBS}) + add_executable(testall testall.cpp) target_link_libraries(testall rtaudio_static ${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..b915ad0 --- /dev/null +++ b/tests/apinames.cpp @@ -0,0 +1,75 @@ +/******************************************/ +/* + 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 +#include +#include + +int main() { + std::vector apis; + RtAudio::getCompiledApi( apis ); + + // ensure the known APIs return valid names + std::cout << "API names by identifier:\n"; + for ( size_t i = 0; i < apis.size() ; ++i ) { + const std::string &name = RtAudio::getCompiledApiName(apis[i]); + if (name.empty()) { + std::cerr << "Invalid name for API " << (int)apis[i] << "\n"; + exit(1); + } + std::cout << "* " << (int)apis[i] << ": '" << name << "'\n"; + } + + // ensure unknown APIs return the empty string + { + const std::string &name = RtAudio::getCompiledApiName((RtAudio::Api)-1); + if (!name.empty()) { + std::cerr << "Bad string for invalid API\n"; + exit(1); + } + } + + // try getting API identifier by case-insensitive name + std::cout << "API identifiers by name:\n"; + for ( size_t i = 0; i < apis.size() ; ++i ) { + std::string name = RtAudio::getCompiledApiName(apis[i]); + if ( RtAudio::getCompiledApiByName(name) != apis[i] ) { + std::cerr << "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]); + if ( RtAudio::getCompiledApiByName(name) != apis[i] ) { + std::cerr << "Bad identifier for API '" << name << "'\n"; + exit( 1 ); + } + std::cout << "* '" << name << "': " << (int)apis[i] << "\n"; + } + + // try getting an API identifier by unknown name + { + RtAudio::Api api; + api = RtAudio::getCompiledApiByName("ALSO"); + if ( api != RtAudio::UNSPECIFIED ) { + std::cerr << "Bad identifier for unknown API name\n"; + exit( 1 ); + } + api = RtAudio::getCompiledApiByName(""); + if ( api != RtAudio::UNSPECIFIED ) { + std::cerr << "Bad identifier for unknown API name\n"; + exit( 1 ); + } + } + + return 0; +} From ee6fd4b4609a1c05a3f4ded4c8022b5ba84d7afd Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Tue, 7 Aug 2018 22:12:06 +0200 Subject: [PATCH 2/3] Add the C interface for the name API --- rtaudio_c.cpp | 13 +++++++++++++ rtaudio_c.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/rtaudio_c.cpp b/rtaudio_c.cpp index 699d2ce..f831655 100644 --- a/rtaudio_c.cpp +++ b/rtaudio_c.cpp @@ -50,6 +50,19 @@ const char *rtaudio_version() { return RTAUDIO_VERSION; } const rtaudio_api_t *rtaudio_compiled_api() { return compiled_api; } +const char *rtaudio_compiled_api_name(rtaudio_api_t api) { + const std::string &name = RtAudio::getCompiledApiName((RtAudio::Api)api); + return name.empty() ? NULL : name.c_str(); +} + +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) { return audio->errmsg; diff --git a/rtaudio_c.h b/rtaudio_c.h index 05015a9..589994a 100644 --- a/rtaudio_c.h +++ b/rtaudio_c.h @@ -102,6 +102,8 @@ typedef struct rtaudio *rtaudio_t; RTAUDIOAPI const char *rtaudio_version(void); RTAUDIOAPI const rtaudio_api_t *rtaudio_compiled_api(void); +RTAUDIOAPI const char *rtaudio_compiled_api_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); From 021928773bfbf9b25505677451ee197b1fe006b6 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Wed, 8 Aug 2018 00:36:22 +0200 Subject: [PATCH 3/3] Use short lower-case names as API identifiers --- RtAudio.cpp | 74 +++++++++++++++++++++++++++++++++++++++------- RtAudio.h | 10 +++++++ rtaudio_c.cpp | 6 ++++ rtaudio_c.h | 1 + tests/apinames.cpp | 28 +++++++++++------- 5 files changed, 98 insertions(+), 21 deletions(-) diff --git a/RtAudio.cpp b/RtAudio.cpp index db3b7cb..82c78bd 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -45,7 +45,6 @@ #include #include #include -#include #include #include @@ -136,6 +135,66 @@ void RtAudio :: getCompiledApi( std::vector &apis ) const std::string &RtAudio :: getCompiledApiName( RtAudio::Api api ) { +#if defined(__UNIX_JACK__) + if ( api == UNIX_JACK ) { + static std::string name( "jack" ); + return name; + } +#endif +#if defined(__LINUX_PULSE__) + if ( api == LINUX_PULSE ) { + static std::string name( "pulse" ); + return name; + } +#endif +#if defined(__LINUX_ALSA__) + if ( api == LINUX_ALSA ) { + static std::string name( "alsa" ); + return name; + } +#endif +#if defined(__LINUX_OSS__) + if ( api == LINUX_OSS ) { + static std::string name( "oss" ); + return name; + } +#endif +#if defined(__WINDOWS_ASIO__) + if ( api == WINDOWS_ASIO ) { + static std::string name( "asio" ); + return name; + } +#endif +#if defined(__WINDOWS_WASAPI__) + if ( api == WINDOWS_WASAPI ) { + static std::string name( "wasapi" ); + return name; + } +#endif +#if defined(__WINDOWS_DS__) + if ( api == WINDOWS_DS ) { + static std::string name( "ds" ); + return name; + } +#endif +#if defined(__MACOSX_CORE__) + if ( api == MACOSX_CORE ) { + static std::string name( "core" ); + return name; + } +#endif +#if defined(__RTAUDIO_DUMMY__) + if ( api == RTAUDIO_DUMMY ) { + static std::string name( "dummy" ); + return name; + } +#endif + static std::string name; + return name; +} + +const std::string &RtAudio :: getCompiledApiDisplayName( RtAudio::Api api ) +{ #if defined(__UNIX_JACK__) if ( api == UNIX_JACK ) { static std::string name( "JACK" ); @@ -180,13 +239,13 @@ const std::string &RtAudio :: getCompiledApiName( RtAudio::Api api ) #endif #if defined(__MACOSX_CORE__) if ( api == MACOSX_CORE ) { - static std::string name( "CoreAudio" ); + static std::string name( "Core Audio" ); return name; } #endif #if defined(__RTAUDIO_DUMMY__) if ( api == RTAUDIO_DUMMY ) { - static std::string name( "Dummy" ); + static std::string name( "RtAudio Dummy" ); return name; } #endif @@ -206,18 +265,13 @@ RtAudio::Api RtAudio :: getCompiledApiByName( const std::string &name ) const std::string &otherName = getCompiledApiName((RtAudio::Api)api_number); - bool equal = nameLength == otherName.size(); - for ( size_t i = 0; equal && i < nameLength; ++i ) - equal = tolower((unsigned char)name[i]) == - tolower((unsigned char)otherName[i]); - - if ( equal ) + if ( name == otherName ) return (RtAudio::Api)api_number; ++api_number; } - return RtAudio::UNSPECIFIED; + return RtAudio::UNSPECIFIED; } void RtAudio :: openRtApi( RtAudio::Api api ) diff --git a/RtAudio.h b/RtAudio.h index 91124cf..449e0d7 100644 --- a/RtAudio.h +++ b/RtAudio.h @@ -399,11 +399,21 @@ class RTAUDIO_DLL_PUBLIC RtAudio //! 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 or not compiled, this function will return the empty string. */ static const std::string &getCompiledApiName( 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 or not compiled, this function will return + the empty string. + */ + static const std::string &getCompiledApiDisplayName( RtAudio::Api api ); + //! Return the compiled audio API having the given name. /*! A case insensitive comparison will check the specified name diff --git a/rtaudio_c.cpp b/rtaudio_c.cpp index f831655..ec84941 100644 --- a/rtaudio_c.cpp +++ b/rtaudio_c.cpp @@ -55,6 +55,12 @@ const char *rtaudio_compiled_api_name(rtaudio_api_t api) { return name.empty() ? NULL : name.c_str(); } +const char *rtaudio_compiled_api_display_name(rtaudio_api_t api) +{ + const std::string &name = RtAudio::getCompiledApiDisplayName((RtAudio::Api)api); + return name.empty() ? NULL : name.c_str(); +} + rtaudio_api_t rtaudio_compiled_api_by_name(const char *name) { RtAudio::Api api = RtAudio::UNSPECIFIED; if (name) { diff --git a/rtaudio_c.h b/rtaudio_c.h index 589994a..893917c 100644 --- a/rtaudio_c.h +++ b/rtaudio_c.h @@ -103,6 +103,7 @@ typedef struct rtaudio *rtaudio_t; RTAUDIOAPI const char *rtaudio_version(void); RTAUDIOAPI const rtaudio_api_t *rtaudio_compiled_api(void); RTAUDIOAPI const char *rtaudio_compiled_api_name(rtaudio_api_t api); +RTAUDIOAPI const char *rtaudio_compiled_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/apinames.cpp b/tests/apinames.cpp index b915ad0..db7a258 100644 --- a/tests/apinames.cpp +++ b/tests/apinames.cpp @@ -10,8 +10,8 @@ /******************************************/ #include "RtAudio.h" -#include #include +#include #include int main() { @@ -26,7 +26,12 @@ int main() { std::cerr << "Invalid name for API " << (int)apis[i] << "\n"; exit(1); } - std::cout << "* " << (int)apis[i] << ": '" << name << "'\n"; + const std::string &displayName = RtAudio::getCompiledApiDisplayName(apis[i]); + if (displayName.empty()) { + std::cerr << "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 @@ -36,9 +41,14 @@ int main() { std::cerr << "Bad string for invalid API\n"; exit(1); } + const std::string &displayName = RtAudio::getCompiledApiDisplayName((RtAudio::Api)-1); + if (!displayName.empty()) { + std::cerr << "Bad display string for invalid API\n"; + exit(1); + } } - // try getting API identifier by case-insensitive name + // try getting API identifier by name std::cout << "API identifiers by name:\n"; for ( size_t i = 0; i < apis.size() ; ++i ) { std::string name = RtAudio::getCompiledApiName(apis[i]); @@ -47,23 +57,19 @@ int main() { 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]); - if ( RtAudio::getCompiledApiByName(name) != apis[i] ) { - std::cerr << "Bad identifier for API '" << name << "'\n"; + RtAudio::Api api = RtAudio::getCompiledApiByName(name); + if ( api != RtAudio::UNSPECIFIED ) { + std::cerr << "Identifier " << (int)api << " for invalid API '" << name << "'\n"; exit( 1 ); } - std::cout << "* '" << name << "': " << (int)apis[i] << "\n"; } // try getting an API identifier by unknown name { RtAudio::Api api; - api = RtAudio::getCompiledApiByName("ALSO"); - if ( api != RtAudio::UNSPECIFIED ) { - std::cerr << "Bad identifier for unknown API name\n"; - exit( 1 ); - } api = RtAudio::getCompiledApiByName(""); if ( api != RtAudio::UNSPECIFIED ) { std::cerr << "Bad identifier for unknown API name\n";