Skip to content

Commit 7b2de12

Browse files
committed
v4.0 C Binding & Demo
1 parent cae2a8e commit 7b2de12

File tree

3 files changed

+224
-22
lines changed

3 files changed

+224
-22
lines changed

demo/c/rhino_demo_file.c

Lines changed: 104 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2018-2023 Picovoice Inc.
2+
Copyright 2018-2025 Picovoice Inc.
33
44
You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE"
55
file accompanying this source.
@@ -90,19 +90,21 @@ static struct option long_options[] = {
9090
{"access_key", required_argument, NULL, 'a'},
9191
{"library_path", required_argument, NULL, 'l'},
9292
{"model_path", required_argument, NULL, 'm'},
93+
{"device", required_argument, NULL, 'y'},
9394
{"context_path", required_argument, NULL, 'c'},
9495
{"wav_path", required_argument, NULL, 'w'},
9596
{"sensitivity", required_argument, NULL, 't'},
9697
{"endpoint_duration_sec", required_argument, NULL, 'u'},
9798
{"require_endpoint", required_argument, NULL, 'e'},
9899
{"performance_threshold_sec", optional_argument, NULL, 'p'}
100+
{"show_inference_devices", no_argument, NULL, 'i'},
99101
};
100102

101103
void print_usage(const char *program_name) {
102104
fprintf(
103105
stderr,
104-
"Usage : %s -a ACCESS_KEY -l LIBRARY_PATH -m MODEL_PATH -c CONTEXT_PATH -w WAV_PATH [-t SENSITIVITY] "
105-
"[-u, --endpoint_duration_sec] [-e, --require_endpoint (true,false)]\n",
106+
"Usage : %s -a ACCESS_KEY -l LIBRARY_PATH -m MODEL_PATH -y DEVICE -c CONTEXT_PATH -w WAV_PATH [-t SENSITIVITY] "
107+
"[-u, --endpoint_duration_sec] [-e, --require_endpoint (true,false)] [-i, --show_inference_devices]\n",
106108
program_name);
107109
}
108110

@@ -112,19 +114,98 @@ void print_error_message(char **message_stack, int32_t message_stack_depth) {
112114
}
113115
}
114116

117+
void print_inference_devices(const char *library_path) {
118+
void *dl_handle = open_dl(library_path);
119+
if (!dl_handle) {
120+
fprintf(stderr, "Failed to open library at '%s'.\n", library_path);
121+
exit(EXIT_FAILURE);
122+
}
123+
124+
const char *(*pv_status_to_string_func)(pv_status_t) = load_symbol(dl_handle, "pv_status_to_string");
125+
if (!pv_status_to_string_func) {
126+
print_dl_error("Failed to load 'pv_status_to_string'");
127+
exit(EXIT_FAILURE);
128+
}
129+
130+
pv_status_t (*pv_rhino_list_hardware_devices_func)(char ***, int32_t *) =
131+
load_symbol(dl_handle, "pv_rhino_list_hardware_devices");
132+
if (!pv_eagle_list_hardware_devices_func) {
133+
print_dl_error("failed to load `pv_rhino_list_hardware_devices`");
134+
exit(EXIT_FAILURE);
135+
}
136+
137+
pv_status_t (*pv_rhino_free_hardware_devices_func)(char **, int32_t) =
138+
load_symbol(dl_handle, "pv_rhino_free_hardware_devices");
139+
if (!pv_eagle_free_hardware_devices_func) {
140+
print_dl_error("failed to load `pv_rhino_free_hardware_devices`");
141+
exit(EXIT_FAILURE);
142+
}
143+
144+
pv_status_t (*pv_get_error_stack_func)(char ***, int32_t *) =
145+
load_symbol(dl_handle, "pv_get_error_stack");
146+
if (!pv_get_error_stack_func) {
147+
print_dl_error("failed to load 'pv_get_error_stack_func'");
148+
exit(EXIT_FAILURE);
149+
}
150+
151+
void (*pv_free_error_stack_func)(char **) =
152+
load_symbol(dl_handle, "pv_free_error_stack");
153+
if (!pv_free_error_stack_func) {
154+
print_dl_error("failed to load 'pv_free_error_stack_func'");
155+
exit(EXIT_FAILURE);
156+
}
157+
158+
char **message_stack = NULL;
159+
int32_t message_stack_depth = 0;
160+
pv_status_t error_status = PV_STATUS_RUNTIME_ERROR;
161+
162+
char **hardware_devices = NULL;
163+
int32_t num_hardware_devices = 0;
164+
pv_status_t status = pv_rhino_list_hardware_devices_func(&hardware_devices, &num_hardware_devices);
165+
if (status != PV_STATUS_SUCCESS) {
166+
fprintf(
167+
stderr,
168+
"Failed to list hardware devices with `%s`.\n",
169+
pv_status_to_string_func(status));
170+
error_status = pv_get_error_stack_func(&message_stack, &message_stack_depth);
171+
if (error_status != PV_STATUS_SUCCESS) {
172+
fprintf(
173+
stderr,
174+
".\nUnable to get Rhino error state with '%s'.\n",
175+
pv_status_to_string_func(error_status));
176+
exit(EXIT_FAILURE);
177+
}
178+
179+
if (message_stack_depth > 0) {
180+
fprintf(stderr, ":\n");
181+
print_error_message(message_stack, message_stack_depth);
182+
pv_free_error_stack_func(message_stack);
183+
}
184+
exit(EXIT_FAILURE);
185+
}
186+
187+
for (int32_t i = 0; i < num_hardware_devices; i++) {
188+
fprintf(stdout, "%s\n", hardware_devices[i]);
189+
}
190+
pv_rhino_free_hardware_devices_func(hardware_devices, num_hardware_devices);
191+
close_dl(dl_handle);
192+
}
193+
115194
int picovoice_main(int argc, char *argv[]) {
116195
const char *access_key = NULL;
117196
const char *library_path = NULL;
118197
const char *model_path = NULL;
198+
const char *device = "best";
119199
const char *context_path = NULL;
120200
const char *wav_path = NULL;
121201
float sensitivity = 0.5f;
122202
float endpoint_duration_sec = 1.f;
123203
bool require_endpoint = true;
124204
double performance_threshold_sec = 0;
205+
bool show_inference_devices = false;
125206

126207
int c;
127-
while ((c = getopt_long(argc, argv, "a:l:m:c:w:t:u:e:p:", long_options, NULL)) != -1) {
208+
while ((c = getopt_long(argc, argv, "a:l:m:y:c:w:t:u:e:p:i", long_options, NULL)) != -1) {
128209
switch (c) {
129210
case 'a':
130211
access_key = optarg;
@@ -135,6 +216,9 @@ int picovoice_main(int argc, char *argv[]) {
135216
case 'm':
136217
model_path = optarg;
137218
break;
219+
case 'y':
220+
device = optarg;
221+
break;
138222
case 'c':
139223
context_path = optarg;
140224
break;
@@ -153,11 +237,25 @@ int picovoice_main(int argc, char *argv[]) {
153237
case 'p':
154238
performance_threshold_sec = strtod(optarg, NULL);
155239
break;
240+
case 'i':
241+
show_inference_devices = true;
242+
break;
156243
default:
157244
exit(1);
158245
}
159246
}
160247

248+
if (show_inference_devices) {
249+
if (!library_path) {
250+
fprintf(stderr, "`library_path` is required to view available inference devices.\n");
251+
print_usage(argv[0]);
252+
exit(1);
253+
}
254+
255+
print_inference_devices(library_path);
256+
return 0;
257+
}
258+
161259
if (!access_key || !library_path || !model_path || !context_path || !wav_path) {
162260
print_usage(argv[0]);
163261
exit(1);
@@ -185,6 +283,7 @@ int picovoice_main(int argc, char *argv[]) {
185283
const char *,
186284
const char *,
187285
const char *,
286+
const char *,
188287
float,
189288
float,
190289
bool,
@@ -303,6 +402,7 @@ int picovoice_main(int argc, char *argv[]) {
303402
pv_status_t status = pv_rhino_init_func(
304403
access_key,
305404
model_path,
405+
device,
306406
context_path,
307407
sensitivity,
308408
endpoint_duration_sec,

demo/c/rhino_demo_mic.c

Lines changed: 114 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -83,26 +83,34 @@ static void print_dl_error(const char *message) {
8383
}
8484

8585
static struct option long_options[] = {
86-
{"access_key", required_argument, NULL, 'a'},
87-
{"library_path", required_argument, NULL, 'l'},
88-
{"model_path", required_argument, NULL, 'm'},
89-
{"context_path", required_argument, NULL, 'c'},
90-
{"audio_device_index", required_argument, NULL, 'd'},
91-
{"sensitivity", required_argument, NULL, 't'},
92-
{"endpoint_duration_sec", required_argument, NULL, 'u'},
93-
{"require_endpoint", required_argument, NULL, 'e'},
94-
{"show_audio_devices", no_argument, NULL, 's'},
86+
{"access_key", required_argument, NULL, 'a'},
87+
{"library_path", required_argument, NULL, 'l'},
88+
{"model_path", required_argument, NULL, 'm'},
89+
{"device" , required_argument, NULL, 'y'},
90+
{"context_path", required_argument, NULL, 'c'},
91+
{"audio_device_index", required_argument, NULL, 'd'},
92+
{"sensitivity", required_argument, NULL, 't'},
93+
{"endpoint_duration_sec", required_argument, NULL, 'u'},
94+
{"require_endpoint", required_argument, NULL, 'e'},
95+
{"show_audio_devices", no_argument, NULL, 's'},
96+
{"show_inference_devices", no_argument, NULL, 'i'},
9597
};
9698

9799
static void print_usage(const char *program_name) {
98100
fprintf(stderr,
99-
"Usage : %s -a ACCESS_KEY -l LIBRARY_PATH -m MODEL_PATH -c CONTEXT_PATH [-d AUDIO_DEVICE_INDEX] "
101+
"Usage : %s -a ACCESS_KEY -l LIBRARY_PATH -m MODEL_PATH -y DEVICE -c CONTEXT_PATH [-d AUDIO_DEVICE_INDEX] "
100102
"[-t SENSITIVITY] [-u, --endpoint_duration_sec] [-e, --require_endpoint (true,false)]\n"
101103
" %s [-s, --show_audio_devices]\n",
102104
program_name,
103105
program_name);
104106
}
105107

108+
void print_error_message(char **message_stack, int32_t message_stack_depth) {
109+
for (int32_t i = 0; i < message_stack_depth; i++) {
110+
fprintf(stderr, " [%d] %s\n", i, message_stack[i]);
111+
}
112+
}
113+
106114
void interrupt_handler(int _) {
107115
(void) _;
108116
is_interrupted = true;
@@ -126,10 +134,81 @@ void show_audio_devices(void) {
126134
pv_recorder_free_available_devices(count, devices);
127135
}
128136

129-
void print_error_message(char **message_stack, int32_t message_stack_depth) {
130-
for (int32_t i = 0; i < message_stack_depth; i++) {
131-
fprintf(stderr, " [%d] %s\n", i, message_stack[i]);
137+
void print_inference_devices(const char *library_path) {
138+
void *dl_handle = open_dl(library_path);
139+
if (!dl_handle) {
140+
fprintf(stderr, "Failed to open library at '%s'.\n", library_path);
141+
exit(EXIT_FAILURE);
142+
}
143+
144+
const char *(*pv_status_to_string_func)(pv_status_t) = load_symbol(dl_handle, "pv_status_to_string");
145+
if (!pv_status_to_string_func) {
146+
print_dl_error("Failed to load 'pv_status_to_string'");
147+
exit(EXIT_FAILURE);
148+
}
149+
150+
pv_status_t (*pv_rhino_list_hardware_devices_func)(char ***, int32_t *) =
151+
load_symbol(dl_handle, "pv_rhino_list_hardware_devices");
152+
if (!pv_eagle_list_hardware_devices_func) {
153+
print_dl_error("failed to load `pv_rhino_list_hardware_devices`");
154+
exit(EXIT_FAILURE);
155+
}
156+
157+
pv_status_t (*pv_rhino_free_hardware_devices_func)(char **, int32_t) =
158+
load_symbol(dl_handle, "pv_rhino_free_hardware_devices");
159+
if (!pv_eagle_free_hardware_devices_func) {
160+
print_dl_error("failed to load `pv_rhino_free_hardware_devices`");
161+
exit(EXIT_FAILURE);
162+
}
163+
164+
pv_status_t (*pv_get_error_stack_func)(char ***, int32_t *) =
165+
load_symbol(dl_handle, "pv_get_error_stack");
166+
if (!pv_get_error_stack_func) {
167+
print_dl_error("failed to load 'pv_get_error_stack_func'");
168+
exit(EXIT_FAILURE);
169+
}
170+
171+
void (*pv_free_error_stack_func)(char **) =
172+
load_symbol(dl_handle, "pv_free_error_stack");
173+
if (!pv_free_error_stack_func) {
174+
print_dl_error("failed to load 'pv_free_error_stack_func'");
175+
exit(EXIT_FAILURE);
176+
}
177+
178+
char **message_stack = NULL;
179+
int32_t message_stack_depth = 0;
180+
pv_status_t error_status = PV_STATUS_RUNTIME_ERROR;
181+
182+
char **hardware_devices = NULL;
183+
int32_t num_hardware_devices = 0;
184+
pv_status_t status = pv_rhino_list_hardware_devices_func(&hardware_devices, &num_hardware_devices);
185+
if (status != PV_STATUS_SUCCESS) {
186+
fprintf(
187+
stderr,
188+
"Failed to list hardware devices with `%s`.\n",
189+
pv_status_to_string_func(status));
190+
error_status = pv_get_error_stack_func(&message_stack, &message_stack_depth);
191+
if (error_status != PV_STATUS_SUCCESS) {
192+
fprintf(
193+
stderr,
194+
".\nUnable to get Rhino error state with '%s'.\n",
195+
pv_status_to_string_func(error_status));
196+
exit(EXIT_FAILURE);
197+
}
198+
199+
if (message_stack_depth > 0) {
200+
fprintf(stderr, ":\n");
201+
print_error_message(message_stack, message_stack_depth);
202+
pv_free_error_stack_func(message_stack);
203+
}
204+
exit(EXIT_FAILURE);
205+
}
206+
207+
for (int32_t i = 0; i < num_hardware_devices; i++) {
208+
fprintf(stdout, "%s\n", hardware_devices[i]);
132209
}
210+
pv_rhino_free_hardware_devices_func(hardware_devices, num_hardware_devices);
211+
close_dl(dl_handle);
133212
}
134213

135214
int picovoice_main(int argc, char *argv[]) {
@@ -138,14 +217,16 @@ int picovoice_main(int argc, char *argv[]) {
138217
const char *access_key = NULL;
139218
const char *library_path = NULL;
140219
const char *model_path = NULL;
220+
const char *device = "best";
141221
const char *context_path = NULL;
142222
int32_t device_index = -1;
143223
float sensitivity = 0.5f;
144224
float endpoint_duration_sec = 1.f;
145225
bool require_endpoint = true;
226+
bool show_inference_devices = false;
146227

147228
int c;
148-
while ((c = getopt_long(argc, argv, "a:l:m:c:d:t:u:e:s", long_options, NULL)) != -1) {
229+
while ((c = getopt_long(argc, argv, "a:l:m:y:c:d:t:u:e:si", long_options, NULL)) != -1) {
149230
switch (c) {
150231
case 'a':
151232
access_key = optarg;
@@ -156,6 +237,9 @@ int picovoice_main(int argc, char *argv[]) {
156237
case 'm':
157238
model_path = optarg;
158239
break;
240+
case 'y':
241+
device = optarg;
242+
break;
159243
case 'c':
160244
context_path = optarg;
161245
break;
@@ -174,11 +258,25 @@ int picovoice_main(int argc, char *argv[]) {
174258
case 's':
175259
show_audio_devices();
176260
return 0;
261+
case 'i':
262+
show_inference_devices = true;
263+
break;
177264
default:
178265
exit(1);
179266
}
180267
}
181268

269+
if (show_inference_devices) {
270+
if (!library_path) {
271+
fprintf(stderr, "`library_path` is required to view available inference devices.\n");
272+
print_usage(argv[0]);
273+
exit(1);
274+
}
275+
276+
print_inference_devices(library_path);
277+
return 0;
278+
}
279+
182280
if (!access_key || !library_path || !model_path || !context_path) {
183281
print_usage(argv[0]);
184282
exit(1);
@@ -206,6 +304,7 @@ int picovoice_main(int argc, char *argv[]) {
206304
const char *,
207305
const char *,
208306
const char *,
307+
const char *,
209308
float,
210309
float,
211310
bool,
@@ -296,6 +395,7 @@ int picovoice_main(int argc, char *argv[]) {
296395
pv_status_t status = pv_rhino_init_func(
297396
access_key,
298397
model_path,
398+
device,
299399
context_path,
300400
sensitivity,
301401
endpoint_duration_sec,

0 commit comments

Comments
 (0)