@@ -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() | |||
@@ -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 \ | |||
@@ -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 | |||
@@ -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) { | |||
@@ -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); | |||
@@ -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}) | |||
@@ -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 | |||
@@ -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(); | |||
} |