From 5c69780f4bf67e26ed370cea39418b2d82df119e Mon Sep 17 00:00:00 2001 From: Serge Zaitsev Date: Mon, 2 Oct 2017 16:20:13 +0300 Subject: [PATCH] add rtaudio c api wrappers (#98) add rtaudio c api wrappers --- CMakeLists.txt | 2 +- Makefile.am | 6 +- rtaudio_c.cpp | 261 +++++++++++++++++++++++++++++++++++++++++++++++++ rtaudio_c.h | 144 +++++++++++++++++++++++++++ 4 files changed, 410 insertions(+), 3 deletions(-) create mode 100644 rtaudio_c.cpp create mode 100644 rtaudio_c.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 812d4d3..54f8816 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,7 @@ if (CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") endif (CMAKE_COMPILER_IS_GNUCXX) -set(rtaudio_SOURCES RtAudio.cpp) +set(rtaudio_SOURCES RtAudio.cpp rtaudio_c.cpp) set(LINKLIBS) if (CMAKE_SYSTEM_NAME MATCHES "kNetBSD.*|NetBSD.*") diff --git a/Makefile.am b/Makefile.am index 00927e8..d4fa538 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,11 +6,13 @@ endif lib_LTLIBRARIES = %D%/librtaudio.la %C%_librtaudio_la_LDFLAGS = -no-undefined -export-dynamic -version-info @SO_VERSION@ %C%_librtaudio_la_SOURCES = \ - %D%/RtAudio.cpp + %D%/RtAudio.cpp \ + %D%/rtaudio_c.cpp rtaudio_incdir = $(includedir)/rtaudio rtaudio_inc_HEADERS = \ - %D%/RtAudio.h + %D%/RtAudio.h \ + %D%/rtaudio_c.h pkgconfigdatadir = $(libdir)/pkgconfig pkgconfigdata_DATA = rtaudio.pc diff --git a/rtaudio_c.cpp b/rtaudio_c.cpp new file mode 100644 index 0000000..090cbf9 --- /dev/null +++ b/rtaudio_c.cpp @@ -0,0 +1,261 @@ +#include "rtaudio_c.h" +#include "RtAudio.h" + +#include + +#define MAX_ERROR_MESSAGE_LENGTH 512 + +struct rtaudio { + RtAudio *audio; + + rtaudio_cb_t cb; + void *userdata; + + int has_error; + 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; } + +const char *rtaudio_error(rtaudio_t audio) { + if (audio->has_error) { + return audio->errmsg; + } + return NULL; +} + +rtaudio_t rtaudio_create(rtaudio_api_t api) { + rtaudio_t audio = new struct rtaudio(); + try { + audio->audio = new RtAudio((RtAudio::Api)api); + } catch (RtAudioError &err) { + audio->has_error = 1; + strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1); + } + return audio; +} + +void rtaudio_destroy(rtaudio_t audio) { delete audio->audio; } + +rtaudio_api_t rtaudio_current_api(rtaudio_t audio) { + return (rtaudio_api_t)audio->audio->getCurrentApi(); +} + +int rtaudio_device_count(rtaudio_t audio) { + return audio->audio->getDeviceCount(); +} + +rtaudio_device_info_t rtaudio_get_device_info(rtaudio_t audio, int i) { + rtaudio_device_info_t result = {}; + try { + audio->has_error = 0; + RtAudio::DeviceInfo info = audio->audio->getDeviceInfo(i); + result.probed = info.probed; + result.output_channels = info.outputChannels; + result.input_channels = info.inputChannels; + result.duplex_channels = info.duplexChannels; + result.is_default_output = info.isDefaultOutput; + result.is_default_input = info.isDefaultInput; + result.native_formats = info.nativeFormats; + result.preferred_sample_rate = info.preferredSampleRate; + strncpy(result.name, info.name.c_str(), sizeof(result.name) - 1); + for (unsigned int j = 0; j < info.sampleRates.size(); j++) { + if (j < sizeof(result.sample_rates) / sizeof(result.sample_rates[0])) { + result.sample_rates[j] = info.sampleRates[j]; + } + } + } catch (RtAudioError &err) { + audio->has_error = 1; + strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1); + } + return result; +} + +unsigned int rtaudio_get_default_output_device(rtaudio_t audio) { + return audio->audio->getDefaultOutputDevice(); +} + +unsigned int rtaudio_get_default_input_device(rtaudio_t audio) { + return audio->audio->getDefaultInputDevice(); +} + +static int proxy_cb_func(void *out, void *in, unsigned int nframes, double time, + RtAudioStreamStatus status, void *userdata) { + rtaudio_t audio = (rtaudio_t)userdata; + return audio->cb(out, in, nframes, time, (rtaudio_stream_status_t)status, + audio->userdata); +} + +int rtaudio_open_stream(rtaudio_t audio, + rtaudio_stream_parameters_t *output_params, + rtaudio_stream_parameters_t *input_params, + rtaudio_format_t format, unsigned int sample_rate, + unsigned int *buffer_frames, rtaudio_cb_t cb, + void *userdata, rtaudio_stream_options_t *options, + rtaudio_error_cb_t /*errcb*/) { + try { + audio->has_error = 0; + RtAudio::StreamParameters *in = NULL; + RtAudio::StreamParameters *out = NULL; + RtAudio::StreamOptions *opts = NULL; + + RtAudio::StreamParameters inparams; + RtAudio::StreamParameters outparams; + RtAudio::StreamOptions stream_opts; + + if (input_params != NULL) { + inparams.deviceId = input_params->device_id; + inparams.nChannels = input_params->num_channels; + inparams.firstChannel = input_params->first_channel; + in = &inparams; + } + if (output_params != NULL) { + outparams.deviceId = output_params->device_id; + outparams.nChannels = output_params->num_channels; + outparams.firstChannel = output_params->first_channel; + out = &outparams; + } + + if (options != NULL) { + stream_opts.flags = (RtAudioStreamFlags)options->flags; + stream_opts.numberOfBuffers = options->num_buffers; + stream_opts.priority = options->priority; + if (strlen(options->name) > 0) { + stream_opts.streamName = std::string(options->name); + } + opts = &stream_opts; + } + audio->cb = cb; + audio->userdata = userdata; + audio->audio->openStream(out, in, (RtAudioFormat)format, sample_rate, + buffer_frames, proxy_cb_func, (void *)audio, opts, + NULL); + return 0; + } catch (RtAudioError &err) { + audio->has_error = 1; + strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1); + return -1; + } +} + +void rtaudio_close_stream(rtaudio_t audio) { audio->audio->closeStream(); } + +int rtaudio_start_stream(rtaudio_t audio) { + try { + audio->has_error = 0; + audio->audio->startStream(); + } catch (RtAudioError &err) { + audio->has_error = 1; + strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1); + } + return 0; +} + +int rtaudio_stop_stream(rtaudio_t audio) { + try { + audio->has_error = 0; + audio->audio->stopStream(); + } catch (RtAudioError &err) { + audio->has_error = 1; + strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1); + } + return 0; +} + +int rtaudio_abort_stream(rtaudio_t audio) { + try { + audio->has_error = 0; + audio->audio->abortStream(); + } catch (RtAudioError &err) { + audio->has_error = 1; + strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1); + } + return 0; +} + +int rtaudio_is_stream_open(rtaudio_t audio) { + return !!audio->audio->isStreamOpen(); +} + +int rtaudio_is_stream_running(rtaudio_t audio) { + return !!audio->audio->isStreamRunning(); +} + +double rtaudio_get_stream_time(rtaudio_t audio) { + try { + audio->has_error = 0; + return audio->audio->getStreamTime(); + } catch (RtAudioError &err) { + audio->has_error = 1; + strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1); + return 0; + } +} + +void rtaudio_set_stream_time(rtaudio_t audio, double time) { + try { + audio->has_error = 0; + audio->audio->setStreamTime(time); + } catch (RtAudioError &err) { + audio->has_error = 1; + strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1); + } +} + +int rtaudio_get_stream_latency(rtaudio_t audio) { + try { + audio->has_error = 0; + return audio->audio->getStreamLatency(); + } catch (RtAudioError &err) { + audio->has_error = 1; + strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1); + return -1; + } +} + +unsigned int rtaudio_get_stream_sample_rate(rtaudio_t audio) { + try { + return audio->audio->getStreamSampleRate(); + } catch (RtAudioError &err) { + audio->has_error = 1; + strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1); + return -1; + } +} + +void rtaudio_show_warnings(rtaudio_t audio, int show) { + audio->audio->showWarnings(!!show); +} diff --git a/rtaudio_c.h b/rtaudio_c.h new file mode 100644 index 0000000..d92107e --- /dev/null +++ b/rtaudio_c.h @@ -0,0 +1,144 @@ +#ifndef RTAUDIO_C_H +#define RTAUDIO_C_H + +#if defined(RTAUDIO_EXPORT) +#define RTAUDIOAPI __declspec(dllexport) +#else +#define RTAUDIOAPI //__declspec(dllimport) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned long rtaudio_format_t; + +#define RTAUDIO_FORMAT_SINT8 0x01 +#define RTAUDIO_FORMAT_SINT16 0x02 +#define RTAUDIO_FORMAT_SINT24 0x04 +#define RTAUDIO_FORMAT_SINT32 0x08 +#define RTAUDIO_FORMAT_FLOAT32 0x10 +#define RTAUDIO_FORMAT_FLOAT64 0x20 + +typedef unsigned int rtaudio_stream_flags_t; + +#define RTAUDIO_FLAGS_NONINTERLEAVED 0x1 +#define RTAUDIO_FLAGS_MINIMIZE_LATENCY 0x2 +#define RTAUDIO_FLAGS_HOG_DEVICE 0x4 +#define RTAUDIO_FLAGS_SCHEDULE_REALTIME 0x8 +#define RTAUDIO_FLAGS_ALSA_USE_DEFAULT 0x10 + +typedef unsigned int rtaudio_stream_status_t; + +#define RTAUDIO_STATUS_INPUT_OVERFLOW 0x1 +#define RTAUDIO_STATUS_OUTPUT_UNDERFLOW 0x2 + +typedef int (*rtaudio_cb_t)(void *out, void *in, unsigned int nFrames, + double stream_time, rtaudio_stream_status_t status, + void *userdata); + +typedef enum rtaudio_error { + RTAUDIO_ERROR_WARNING, + RTAUDIO_ERROR_DEBUG_WARNING, + RTAUDIO_ERROR_UNSPECIFIED, + RTAUDIO_ERROR_NO_DEVICES_FOUND, + RTAUDIO_ERROR_INVALID_DEVICE, + RTAUDIO_ERROR_MEMORY_ERROR, + RTAUDIO_ERROR_INVALID_PARAMETER, + RTAUDIO_ERROR_INVALID_USE, + RTAUDIO_ERROR_DRIVER_ERROR, + RTAUDIO_ERROR_SYSTEM_ERROR, + RTAUDIO_ERROR_THREAD_ERROR, +} rtaudio_error_t; + +typedef void (*rtaudio_error_cb_t)(rtaudio_error_t err, const char *msg); + +typedef enum rtaudio_api { + RTAUDIO_API_UNSPECIFIED, + RTAUDIO_API_LINUX_ALSA, + RTAUDIO_API_LINUX_PULSE, + RTAUDIO_API_LINUX_OSS, + RTAUDIO_API_UNIX_JACK, + RTAUDIO_API_MACOSX_CORE, + RTAUDIO_API_WINDOWS_WASAPI, + RTAUDIO_API_WINDOWS_ASIO, + RTAUDIO_API_WINDOWS_DS, + RTAUDIO_API_DUMMY, +} rtaudio_api_t; + +#define NUM_SAMPLE_RATES 16 +#define MAX_NAME_LENGTH 512 +typedef struct rtaudio_device_info { + int probed; + unsigned int output_channels; + unsigned int input_channels; + unsigned int duplex_channels; + + int is_default_output; + int is_default_input; + + rtaudio_format_t native_formats; + + unsigned int preferred_sample_rate; + int sample_rates[NUM_SAMPLE_RATES]; + + char name[MAX_NAME_LENGTH]; +} rtaudio_device_info_t; + +typedef struct rtaudio_stream_parameters { + unsigned int device_id; + unsigned int num_channels; + unsigned int first_channel; +} rtaudio_stream_parameters_t; + +typedef struct rtaudio_stream_options { + rtaudio_stream_flags_t flags; + unsigned int num_buffers; + int priority; + char name[MAX_NAME_LENGTH]; +} rtaudio_stream_options_t; + +typedef struct rtaudio *rtaudio_t; + +RTAUDIOAPI const char *rtaudio_version(); +RTAUDIOAPI const rtaudio_api_t *rtaudio_compiled_api(); + +RTAUDIOAPI const char *rtaudio_error(rtaudio_t audio); + +RTAUDIOAPI rtaudio_t rtaudio_create(rtaudio_api_t api); +RTAUDIOAPI void rtaudio_destroy(rtaudio_t audio); + +RTAUDIOAPI rtaudio_api_t rtaudio_current_api(rtaudio_t audio); + +RTAUDIOAPI int rtaudio_device_count(rtaudio_t audio); +RTAUDIOAPI rtaudio_device_info_t rtaudio_get_device_info(rtaudio_t audio, + int i); +RTAUDIOAPI unsigned int rtaudio_get_default_output_device(rtaudio_t audio); +RTAUDIOAPI unsigned int rtaudio_get_default_input_device(rtaudio_t audio); + +RTAUDIOAPI int +rtaudio_open_stream(rtaudio_t audio, rtaudio_stream_parameters_t *output_params, + rtaudio_stream_parameters_t *input_params, + rtaudio_format_t format, unsigned int sample_rate, + unsigned int *buffer_frames, rtaudio_cb_t cb, + void *userdata, rtaudio_stream_options_t *options, + rtaudio_error_cb_t errcb); +RTAUDIOAPI void rtaudio_close_stream(rtaudio_t audio); +RTAUDIOAPI int rtaudio_start_stream(rtaudio_t audio); +RTAUDIOAPI int rtaudio_stop_stream(rtaudio_t audio); +RTAUDIOAPI int rtaudio_abort_stream(rtaudio_t audio); + +RTAUDIOAPI int rtaudio_is_stream_open(rtaudio_t audio); +RTAUDIOAPI int rtaudio_is_stream_running(rtaudio_t audio); + +RTAUDIOAPI double rtaudio_get_stream_time(rtaudio_t audio); +RTAUDIOAPI void rtaudio_set_stream_time(rtaudio_t audio, double time); +RTAUDIOAPI int rtaudio_get_stream_latency(rtaudio_t audio); +RTAUDIOAPI unsigned int rtaudio_get_stream_sample_rate(rtaudio_t audio); + +RTAUDIOAPI void rtaudio_show_warnings(rtaudio_t audio, int show); + +#ifdef __cplusplus +} +#endif +#endif /* RTAUDIO_C_H */ -- 2.30.2