Allow loopback without having to define output parameters
[rtaudio-cdist.git] / rtaudio_c.cpp
1 #include "rtaudio_c.h"
2 #include "RtAudio.h"
3
4 #include <cstring>
5
6 #define MAX_ERROR_MESSAGE_LENGTH 512
7
8 struct rtaudio {
9   RtAudio *audio;
10
11   rtaudio_cb_t cb;
12   void *userdata;
13
14   int has_error;
15   char errmsg[MAX_ERROR_MESSAGE_LENGTH];
16 };
17
18 const char *rtaudio_version() { return RTAUDIO_VERSION; }
19
20 extern "C" const RtAudio::Api rtaudio_compiled_apis[];
21 const rtaudio_api_t *rtaudio_compiled_api() {
22   return (rtaudio_api_t *) &rtaudio_compiled_apis[0];
23 }
24
25 extern "C" const char* rtaudio_api_names[][2];
26 const char *rtaudio_api_name(rtaudio_api_t api) {
27     if (api < 0 || api >= RTAUDIO_API_NUM)
28         return NULL;
29     return rtaudio_api_names[api][0];
30 }
31
32 const char *rtaudio_api_display_name(rtaudio_api_t api)
33 {
34     if (api < 0 || api >= RTAUDIO_API_NUM)
35         return "Unknown";
36     return rtaudio_api_names[api][1];
37 }
38
39 rtaudio_api_t rtaudio_compiled_api_by_name(const char *name) {
40     RtAudio::Api api = RtAudio::UNSPECIFIED;
41     if (name) {
42         api = RtAudio::getCompiledApiByName(name);
43     }
44     return (rtaudio_api_t)api;
45 }
46
47 const char *rtaudio_error(rtaudio_t audio) {
48   if (audio->has_error) {
49     return audio->errmsg;
50   }
51   return NULL;
52 }
53
54 rtaudio_t rtaudio_create(rtaudio_api_t api) {
55   rtaudio_t audio = new struct rtaudio();
56   try {
57     audio->audio = new RtAudio((RtAudio::Api)api);
58   } catch (RtAudioError &err) {
59     audio->has_error = 1;
60     strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
61   }
62   return audio;
63 }
64
65 void rtaudio_destroy(rtaudio_t audio) { delete audio->audio; }
66
67 rtaudio_api_t rtaudio_current_api(rtaudio_t audio) {
68   return (rtaudio_api_t)audio->audio->getCurrentApi();
69 }
70
71 int rtaudio_device_count(rtaudio_t audio) {
72   return audio->audio->getDeviceCount();
73 }
74
75 rtaudio_device_info_t rtaudio_get_device_info(rtaudio_t audio, int i) {
76   rtaudio_device_info_t result;
77   std::memset(&result, 0, sizeof(result));
78   try {
79     audio->has_error = 0;
80     RtAudio::DeviceInfo info = audio->audio->getDeviceInfo(i);
81     result.probed = info.probed;
82     result.output_channels = info.outputChannels;
83     result.input_channels = info.inputChannels;
84     result.duplex_channels = info.duplexChannels;
85     result.is_default_output = info.isDefaultOutput;
86     result.is_default_input = info.isDefaultInput;
87     result.native_formats = info.nativeFormats;
88     result.preferred_sample_rate = info.preferredSampleRate;
89     strncpy(result.name, info.name.c_str(), sizeof(result.name) - 1);
90     for (unsigned int j = 0; j < info.sampleRates.size(); j++) {
91       if (j < sizeof(result.sample_rates) / sizeof(result.sample_rates[0])) {
92         result.sample_rates[j] = info.sampleRates[j];
93       }
94     }
95   } catch (RtAudioError &err) {
96     audio->has_error = 1;
97     strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
98   }
99   return result;
100 }
101
102 unsigned int rtaudio_get_default_output_device(rtaudio_t audio) {
103   return audio->audio->getDefaultOutputDevice();
104 }
105
106 unsigned int rtaudio_get_default_input_device(rtaudio_t audio) {
107   return audio->audio->getDefaultInputDevice();
108 }
109
110 static int proxy_cb_func(void *out, void *in, unsigned int nframes, double time,
111                          RtAudioStreamStatus status, void *userdata) {
112   rtaudio_t audio = (rtaudio_t)userdata;
113   return audio->cb(out, in, nframes, time, (rtaudio_stream_status_t)status,
114                    audio->userdata);
115 }
116
117 int rtaudio_open_stream(rtaudio_t audio,
118                         rtaudio_stream_parameters_t *output_params,
119                         rtaudio_stream_parameters_t *input_params,
120                         rtaudio_format_t format, unsigned int sample_rate,
121                         unsigned int *buffer_frames, rtaudio_cb_t cb,
122                         void *userdata, rtaudio_stream_options_t *options,
123                         rtaudio_error_cb_t /*errcb*/) {
124   try {
125     audio->has_error = 0;
126     RtAudio::StreamParameters *in = NULL;
127     RtAudio::StreamParameters *out = NULL;
128     RtAudio::StreamOptions *opts = NULL;
129
130     RtAudio::StreamParameters inparams;
131     RtAudio::StreamParameters outparams;
132     RtAudio::StreamOptions stream_opts;
133
134     if (input_params != NULL) {
135       inparams.deviceId = input_params->device_id;
136       inparams.nChannels = input_params->num_channels;
137       inparams.firstChannel = input_params->first_channel;
138       in = &inparams;
139     }
140     if (output_params != NULL) {
141       outparams.deviceId = output_params->device_id;
142       outparams.nChannels = output_params->num_channels;
143       outparams.firstChannel = output_params->first_channel;
144       out = &outparams;
145     }
146
147     if (options != NULL) {
148       stream_opts.flags = (RtAudioStreamFlags)options->flags;
149       stream_opts.numberOfBuffers = options->num_buffers;
150       stream_opts.priority = options->priority;
151       if (strlen(options->name) > 0) {
152         stream_opts.streamName = std::string(options->name);
153       }
154       opts = &stream_opts;
155     }
156     audio->cb = cb;
157     audio->userdata = userdata;
158     audio->audio->openStream(out, in, (RtAudioFormat)format, sample_rate,
159                              buffer_frames, proxy_cb_func, (void *)audio, opts,
160                              NULL);
161     return 0;
162   } catch (RtAudioError &err) {
163     audio->has_error = 1;
164     strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
165     return -1;
166   }
167 }
168
169 void rtaudio_close_stream(rtaudio_t audio) { audio->audio->closeStream(); }
170
171 int rtaudio_start_stream(rtaudio_t audio) {
172   try {
173     audio->has_error = 0;
174     audio->audio->startStream();
175   } catch (RtAudioError &err) {
176     audio->has_error = 1;
177     strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
178   }
179   return 0;
180 }
181
182 int rtaudio_stop_stream(rtaudio_t audio) {
183   try {
184     audio->has_error = 0;
185     audio->audio->stopStream();
186   } catch (RtAudioError &err) {
187     audio->has_error = 1;
188     strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
189   }
190   return 0;
191 }
192
193 int rtaudio_abort_stream(rtaudio_t audio) {
194   try {
195     audio->has_error = 0;
196     audio->audio->abortStream();
197   } catch (RtAudioError &err) {
198     audio->has_error = 1;
199     strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
200   }
201   return 0;
202 }
203
204 int rtaudio_is_stream_open(rtaudio_t audio) {
205   return !!audio->audio->isStreamOpen();
206 }
207
208 int rtaudio_is_stream_running(rtaudio_t audio) {
209   return !!audio->audio->isStreamRunning();
210 }
211
212 double rtaudio_get_stream_time(rtaudio_t audio) {
213   try {
214     audio->has_error = 0;
215     return audio->audio->getStreamTime();
216   } catch (RtAudioError &err) {
217     audio->has_error = 1;
218     strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
219     return 0;
220   }
221 }
222
223 void rtaudio_set_stream_time(rtaudio_t audio, double time) {
224   try {
225     audio->has_error = 0;
226     audio->audio->setStreamTime(time);
227   } catch (RtAudioError &err) {
228     audio->has_error = 1;
229     strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
230   }
231 }
232
233 int rtaudio_get_stream_latency(rtaudio_t audio) {
234   try {
235     audio->has_error = 0;
236     return audio->audio->getStreamLatency();
237   } catch (RtAudioError &err) {
238     audio->has_error = 1;
239     strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
240     return -1;
241   }
242 }
243
244 unsigned int rtaudio_get_stream_sample_rate(rtaudio_t audio) {
245   try {
246     return audio->audio->getStreamSampleRate();
247   } catch (RtAudioError &err) {
248     audio->has_error = 1;
249     strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
250     return -1;
251   }
252 }
253
254 void rtaudio_show_warnings(rtaudio_t audio, int show) {
255   audio->audio->showWarnings(!!show);
256 }