From: Stephen Sinclair Date: Wed, 8 Aug 2018 19:01:18 +0000 (-0400) Subject: Fix api name functions for C, replace map with array. X-Git-Url: https://git.carlh.net/gitweb/?a=commitdiff_plain;h=e92130e9e152a71da71264a610662e910b450ec0;hp=5f0720fef77af2b19abd684d0dc9eed1bca9a64d;p=rtaudio-cdist.git Fix api name functions for C, replace map with array. --- diff --git a/RtAudio.cpp b/RtAudio.cpp index 07a6314..c2c3760 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -98,57 +98,76 @@ std::string RtAudio :: getVersion( void ) return RTAUDIO_VERSION; } -// Define API names. -// TODO: replace with initializer list in C++11. +// 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. -// Have to maintain a separate list of API enum identifiers since map -// doesn't preserve insertion order. -static std::pair< RtAudio::ApiNameMap, std::vector > init_ApiNames() -{ - RtAudio::ApiNameMap names; - std::vector apis; +RtAudio::Api rtaudio_compiled_apis[] = { #if defined(__UNIX_JACK__) - names["jack"] = std::pair(RtAudio::UNIX_JACK, "Jack"); - apis.push_back(RtAudio::UNIX_JACK); + RtAudio::UNIX_JACK, #endif #if defined(__LINUX_PULSE__) - names["pulse"] = std::pair(RtAudio::LINUX_PULSE, "Pulse"); - apis.push_back(RtAudio::LINUX_PULSE); + RtAudio::LINUX_PULSE, #endif #if defined(__LINUX_ALSA__) - names["alsa"] = std::pair(RtAudio::LINUX_ALSA, "ALSA"); - apis.push_back(RtAudio::LINUX_ALSA); + RtAudio::LINUX_ALSA, #endif #if defined(__LINUX_OSS__) - names["oss"] = std::pair(RtAudio::LINUX_OSS, "OSS"); - apis.push_back(RtAudio::LINUX_OSS); + RtAudio::LINUX_OSS, #endif #if defined(__WINDOWS_ASIO__) - names["asio"] = std::pair(RtAudio::WINDOWS_ASIO, "ASIO"); - apis.push_back(RtAudio::WINDOWS_ASIO); + RtAudio::WINDOWS_ASIO, #endif #if defined(__WINDOWS_WASAPI__) - names["wasapi"] = std::pair(RtAudio::WINDOWS_WASAPI, "WASAPI"); - apis.push_back(RtAudio::WINDOWS_WASAPI); + RtAudio::WINDOWS_WASAPI, #endif #if defined(__WINDOWS_DS__) - names["ds"] = std::pair(RtAudio::WINDOWS_DS, "DirectSound"); - apis.push_back(RtAudio::WINDOWS_DS); + RtAudio::WINDOWS_DS, #endif #if defined(__MACOSX_CORE__) - names["core"] = std::pair(RtAudio::MACOSX_CORE, "CoreAudio"); - apis.push_back(RtAudio::MACOSX_CORE); + RtAudio::MACOSX_CORE, #endif #if defined(__RTAUDIO_DUMMY__) - names["dummy"] = std::pair(RtAudio::RTAUDIO_DUMMY, "Dummy"); - apis.push_back(RtAudio::RTAUDIO_DUMMY); + RtAudio::RTAUDIO_DUMMY, #endif - return std::make_pair(names, apis); + RtAudio::UNSPECIFIED, +}; +const unsigned int rtaudio_num_compiled_apis = + sizeof(rtaudio_compiled_apis)/sizeof(rtaudio_compiled_apis[0])-1; } -const RtAudio::ApiNameMap RtAudio::apiNames(init_ApiNames().first); -const std::vector RtAudio::compiledApis(init_ApiNames().second); +// TODO: replace this with something nicer (C++11) +static const std::vector init_compiledApis() { + std::vector apis; + for (unsigned int i=0; i RtAudio::compiledApis(init_compiledApis()); + +// This is a compile-time check that rtaudio_num_api_names == RtAudio::NUM_APIS. +// If the build breaks here, check that they match. +template class StaticAssert { private: StaticAssert() {} }; +template<> class StaticAssert{ public: StaticAssert() {} }; +class StaticAssertions { StaticAssertions() { + StaticAssert(); +}}; void RtAudio :: getCompiledApi( std::vector &apis ) { @@ -160,32 +179,32 @@ const std::vector& RtAudio :: getCompiledApi() return compiledApis; } -static const std::string unknown_api_name = ""; -static const std::string unknown_api_display_name = "Unknown"; - -const std::string& RtAudio :: getCompiledApiName( RtAudio::Api api ) +const std::string RtAudio :: getCompiledApiName( RtAudio::Api api ) { - ApiNameMap::const_iterator it; - for (it = apiNames.begin(); it != apiNames.end(); it++) - if (it->second.first == api) - return it->first; - return unknown_api_name; + if (api < 0 || api > RtAudio::NUM_APIS + || (std::find(RtAudio::compiledApis.begin(), + RtAudio::compiledApis.end(), api) == RtAudio::compiledApis.end())) + return ""; + return rtaudio_api_names[api][0]; } -const std::string& RtAudio :: getCompiledApiDisplayName( RtAudio::Api api ) +const std::string RtAudio :: getCompiledApiDisplayName( RtAudio::Api api ) { - ApiNameMap::const_iterator it; - for (it = apiNames.begin(); it != apiNames.end(); it++) - if (it->second.first == api) - return it->second.second; - return unknown_api_display_name; + if (api < 0 || api > RtAudio::NUM_APIS + || (std::find(RtAudio::compiledApis.begin(), + RtAudio::compiledApis.end(), api) == RtAudio::compiledApis.end())) + return "Unknown"; + return rtaudio_api_names[api][1]; } RtAudio::Api RtAudio :: getCompiledApiByName( const std::string &name ) { - if (apiNames.find(name) == apiNames.end()) - return RtAudio::UNSPECIFIED; - return apiNames.at(name).first; + unsigned int i=0; + std::vector::const_iterator it; + for (it = compiledApis.begin(); it != compiledApis.end(); ++it, ++i) + if (name == rtaudio_api_names[*it][0]) + return *it; + return RtAudio::UNSPECIFIED; } void RtAudio :: openRtApi( RtAudio::Api api ) diff --git a/RtAudio.h b/RtAudio.h index 3927ae1..976ada0 100644 --- a/RtAudio.h +++ b/RtAudio.h @@ -61,7 +61,6 @@ #include #include #include -#include /*! \typedef typedef unsigned long RtAudioFormat; \brief RtAudio data format type. @@ -286,12 +285,10 @@ 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. */ }; - //! Map string identifiers for APIs to enum identifiers and display names - typedef std::map< std::string, std::pair > ApiNameMap; - //! The public device information structure for returning queried values. struct DeviceInfo { bool probed; /*!< true if the device capabilities were successfully probed. */ @@ -407,7 +404,7 @@ class RTAUDIO_DLL_PUBLIC RtAudio the enumerated list values. Note that there can be more than one API compiled for certain operating systems. */ - static const std::vector& getCompiledApi(); + static const std::vector& getCompiledApis(); //! Return the name of a specified compiled audio API. /*! @@ -416,7 +413,7 @@ class RTAUDIO_DLL_PUBLIC RtAudio If the API is unknown or not compiled, this function will return the empty string. */ - static const std::string& getCompiledApiName( RtAudio::Api api ); + static const std::string getCompiledApiName( RtAudio::Api api ); //! Return the display name of a specified compiled audio API. /*! @@ -424,7 +421,7 @@ class RTAUDIO_DLL_PUBLIC RtAudio If the API is unknown or not compiled, this function will return the empty string. */ - static const std::string& getCompiledApiDisplayName( RtAudio::Api api ); + static const std::string getCompiledApiDisplayName( RtAudio::Api api ); //! Return the compiled audio API having the given name. /*! @@ -618,9 +615,6 @@ class RTAUDIO_DLL_PUBLIC RtAudio protected: - //! Storage for API name map - static const ApiNameMap apiNames; - //! Storage for compiled API list static const std::vector compiledApis; diff --git a/rtaudio_c.cpp b/rtaudio_c.cpp index ec84941..7ae1bec 100644 --- a/rtaudio_c.cpp +++ b/rtaudio_c.cpp @@ -15,50 +15,24 @@ 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" 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_compiled_api_name(rtaudio_api_t api) { - const std::string &name = RtAudio::getCompiledApiName((RtAudio::Api)api); - return name.empty() ? NULL : name.c_str(); + if (api < 0 || api >= RTAUDIO_API_NUM) + return NULL; + return rtaudio_api_names[api][0]; } 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(); + 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) { diff --git a/rtaudio_c.h b/rtaudio_c.h index a13ea79..550f480 100644 --- a/rtaudio_c.h +++ b/rtaudio_c.h @@ -68,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 diff --git a/tests/apinames.cpp b/tests/apinames.cpp index 81a3d7d..9dc634c 100644 --- a/tests/apinames.cpp +++ b/tests/apinames.cpp @@ -14,19 +14,19 @@ #include #include -int main() { +int test_cpp() { std::vector apis; RtAudio::getCompiledApi( apis ); // ensure the known APIs return valid names - std::cout << "API names by identifier:\n"; + std::cout << "API names by identifier (C++):\n"; for ( size_t i = 0; i < apis.size() ; ++i ) { - const std::string &name = RtAudio::getCompiledApiName(apis[i]); + const std::string name = RtAudio::getCompiledApiName(apis[i]); if (name.empty()) { std::cerr << "Invalid name for API " << (int)apis[i] << "\n"; exit(1); } - const std::string &displayName = RtAudio::getCompiledApiDisplayName(apis[i]); + const std::string displayName = RtAudio::getCompiledApiDisplayName(apis[i]); if (displayName.empty()) { std::cerr << "Invalid display name for API " << (int)apis[i] << "\n"; exit(1); @@ -36,12 +36,12 @@ int main() { // ensure unknown APIs return the empty string { - const std::string &name = RtAudio::getCompiledApiName((RtAudio::Api)-1); + const std::string name = RtAudio::getCompiledApiName((RtAudio::Api)-1); if (!name.empty()) { std::cerr << "Bad string for invalid API '" << name << "'\n"; exit(1); } - const std::string &displayName = RtAudio::getCompiledApiDisplayName((RtAudio::Api)-1); + const std::string displayName = RtAudio::getCompiledApiDisplayName((RtAudio::Api)-1); if (displayName!="Unknown") { std::cerr << "Bad display string for invalid API '" << displayName << "'\n"; exit(1); @@ -49,7 +49,7 @@ int main() { } // try getting API identifier by name - std::cout << "API identifiers by name:\n"; + std::cout << "API identifiers by name (C++):\n"; for ( size_t i = 0; i < apis.size() ; ++i ) { std::string name = RtAudio::getCompiledApiName(apis[i]); if ( RtAudio::getCompiledApiByName(name) != apis[i] ) { @@ -79,3 +79,79 @@ int main() { 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_compiled_api_name(apis[i]); + if (name.empty()) { + std::cerr << "Invalid name for API " << (int)apis[i] << "\n"; + exit(1); + } + const std::string displayName = rtaudio_compiled_api_display_name(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 + { + const char *s = rtaudio_compiled_api_name((rtaudio_api_t)-1); + const std::string name(s?s:""); + if (!name.empty()) { + std::cerr << "Bad string for invalid API '" << name << "'\n"; + exit(1); + } + s = rtaudio_compiled_api_display_name((rtaudio_api_t)-1); + const std::string displayName(s?s:""); + if (displayName!="Unknown") { + std::cerr << "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_compiled_api_name(apis[i]); + std::string name(s?s:""); + if ( rtaudio_compiled_api_by_name(name.c_str()) != 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]); + rtaudio_api_t api = rtaudio_compiled_api_by_name(name.c_str()); + if ( api != RTAUDIO_API_UNSPECIFIED ) { + std::cerr << "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::cerr << "Bad identifier for unknown API name\n"; + exit( 1 ); + } + } + + return 0; +} + +int main() +{ + test_cpp(); + test_c(); +}