11/*
2- Copyright 2023 Picovoice Inc.
2+ Copyright 2023-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.
6-
6+
77 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
88 an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
99 specific language governing permissions and limitations under the License.
1010*/
1111
1212#include <getopt.h>
1313#include <math.h>
14+ #include <stdbool.h>
1415#include <stdio.h>
1516#include <stdlib.h>
1617#include <sys/time.h>
@@ -87,17 +88,21 @@ static void print_dl_error(const char *message) {
8788}
8889
8990static struct option long_options [] = {
90- {"access_key" , required_argument , NULL , 'a' },
91- {"library_path" , required_argument , NULL , 'l' },
92- {"model_path" , required_argument , NULL , 'm' },
93- {"input_path" , required_argument , NULL , 'i' },
94- {"output_path" , required_argument , NULL , 'o' },
91+ {"access_key" , required_argument , NULL , 'a' },
92+ {"library_path" , required_argument , NULL , 'l' },
93+ {"model_path" , required_argument , NULL , 'm' },
94+ {"device" , required_argument , NULL , 'y' },
95+ {"input_path" , required_argument , NULL , 'i' },
96+ {"output_path" , required_argument , NULL , 'o' },
97+ {"show_inference_devices" , required_argument , NULL , 'z' },
9598};
9699
97100static void print_usage (const char * program_name ) {
98101 fprintf (
99102 stdout ,
100- "Usage: %s [-l LIBRARY_PATH -m MODEL_PATH -a ACCESS_KEY -i INPUT_PATH -o OUTPUT_PATH]\n" ,
103+ "Usage: %s -l LIBRARY_PATH [-m MODEL_PATH -a ACCESS_KEY -y DEVICE -i INPUT_PATH -o OUTPUT_PATH]\n"
104+ " %s [-z, --show_inference_devices] -l LIBRARY_PATH\n" ,
105+ program_name ,
101106 program_name );
102107}
103108
@@ -122,16 +127,94 @@ static void print_progress_bar(size_t num_total_samples, size_t num_processed_sa
122127 fflush (stdout );
123128}
124129
130+ static void print_inference_devices (const char * library_path ) {
131+ void * dl_handle = open_dl (library_path );
132+ if (!dl_handle ) {
133+ fprintf (stderr , "Failed to open library at '%s'.\n" , library_path );
134+ exit (EXIT_FAILURE );
135+ }
136+
137+ const char * (* pv_status_to_string_func )(pv_status_t ) = load_symbol (dl_handle , "pv_status_to_string" );
138+ if (!pv_status_to_string_func ) {
139+ print_dl_error ("Failed to load 'pv_status_to_string'" );
140+ exit (EXIT_FAILURE );
141+ }
142+
143+ pv_status_t (* pv_koala_list_hardware_devices_func )(char * * * , int32_t * ) =
144+ load_symbol (dl_handle , "pv_koala_list_hardware_devices" );
145+ if (!pv_koala_list_hardware_devices_func ) {
146+ print_dl_error ("failed to load `pv_koala_list_hardware_devices`" );
147+ exit (EXIT_FAILURE );
148+ }
149+
150+ pv_status_t (* pv_koala_free_hardware_devices_func )(char * * , int32_t ) =
151+ load_symbol (dl_handle , "pv_koala_free_hardware_devices" );
152+ if (!pv_koala_free_hardware_devices_func ) {
153+ print_dl_error ("failed to load `pv_koala_free_hardware_devices`" );
154+ exit (EXIT_FAILURE );
155+ }
156+
157+ pv_status_t (* pv_get_error_stack_func )(char * * * , int32_t * ) =
158+ load_symbol (dl_handle , "pv_get_error_stack" );
159+ if (!pv_get_error_stack_func ) {
160+ print_dl_error ("failed to load 'pv_get_error_stack_func'" );
161+ exit (EXIT_FAILURE );
162+ }
163+
164+ void (* pv_free_error_stack_func )(char * * ) =
165+ load_symbol (dl_handle , "pv_free_error_stack" );
166+ if (!pv_free_error_stack_func ) {
167+ print_dl_error ("failed to load 'pv_free_error_stack_func'" );
168+ exit (EXIT_FAILURE );
169+ }
170+
171+ char * * message_stack = NULL ;
172+ int32_t message_stack_depth = 0 ;
173+ pv_status_t error_status = PV_STATUS_RUNTIME_ERROR ;
174+
175+ char * * hardware_devices = NULL ;
176+ int32_t num_hardware_devices = 0 ;
177+ pv_status_t status = pv_koala_list_hardware_devices_func (& hardware_devices , & num_hardware_devices );
178+ if (status != PV_STATUS_SUCCESS ) {
179+ fprintf (
180+ stderr ,
181+ "Failed to list hardware devices with `%s`.\n" ,
182+ pv_status_to_string_func (status ));
183+ error_status = pv_get_error_stack_func (& message_stack , & message_stack_depth );
184+ if (error_status != PV_STATUS_SUCCESS ) {
185+ fprintf (
186+ stderr ,
187+ ".\nUnable to get Koala error state with '%s'.\n" ,
188+ pv_status_to_string_func (error_status ));
189+ exit (EXIT_FAILURE );
190+ }
191+
192+ if (message_stack_depth > 0 ) {
193+ fprintf (stderr , ":\n" );
194+ print_error_message (message_stack , message_stack_depth );
195+ pv_free_error_stack_func (message_stack );
196+ }
197+ exit (EXIT_FAILURE );
198+ }
199+
200+ for (int32_t i = 0 ; i < num_hardware_devices ; i ++ ) {
201+ fprintf (stdout , "%s\n" , hardware_devices [i ]);
202+ }
203+ pv_koala_free_hardware_devices_func (hardware_devices , num_hardware_devices );
204+ close_dl (dl_handle );
205+ }
125206
126207int picovoice_main (int argc , char * argv []) {
127208 const char * library_path = NULL ;
128209 const char * model_path = NULL ;
129210 const char * access_key = NULL ;
130211 const char * input_path = NULL ;
131212 const char * output_path = NULL ;
213+ const char * device = NULL ;
214+ bool show_inference_devices = false;
132215
133216 int c ;
134- while ((c = getopt_long (argc , argv , "l :m:a:i:o:" , long_options , NULL )) != -1 ) {
217+ while ((c = getopt_long (argc , argv , "zl :m:a:y :i:o:" , long_options , NULL )) != -1 ) {
135218 switch (c ) {
136219 case 'l' :
137220 library_path = optarg ;
@@ -148,16 +231,37 @@ int picovoice_main(int argc, char *argv[]) {
148231 case 'o' :
149232 output_path = optarg ;
150233 break ;
234+ case 'y' :
235+ device = optarg ;
236+ break ;
237+ case 'z' :
238+ show_inference_devices = true;
239+ break ;
151240 default :
152241 exit (EXIT_FAILURE );
153242 }
154243 }
155244
245+ if (show_inference_devices ) {
246+ if (!library_path ) {
247+ fprintf (stderr , "`library_path` is required to view available inference devices.\n" );
248+ print_usage (argv [0 ]);
249+ exit (EXIT_FAILURE );
250+ }
251+
252+ print_inference_devices (library_path );
253+ return EXIT_SUCCESS ;
254+ }
255+
156256 if (!library_path || !access_key || !input_path || !output_path ) {
157257 print_usage (argv [0 ]);
158258 exit (EXIT_FAILURE );
159259 }
160260
261+ if (device == NULL ) {
262+ device = "best" ;
263+ }
264+
161265 void * koala_library = open_dl (library_path );
162266 if (!koala_library ) {
163267 fprintf (stderr , "Failed to open library at '%s'.\n" , library_path );
@@ -177,7 +281,7 @@ int picovoice_main(int argc, char *argv[]) {
177281 exit (EXIT_FAILURE );
178282 }
179283
180- pv_status_t (* pv_koala_init_func )(const char * , const char * , pv_koala_t * * ) =
284+ pv_status_t (* pv_koala_init_func )(const char * , const char * , const char * , pv_koala_t * * ) =
181285 load_symbol (koala_library , "pv_koala_init" );
182286 if (!pv_koala_init_func ) {
183287 print_dl_error ("Failed to load 'pv_koala_init'" );
@@ -229,7 +333,7 @@ int picovoice_main(int argc, char *argv[]) {
229333 }
230334
231335 pv_koala_t * koala = NULL ;
232- pv_status_t koala_status = pv_koala_init_func (access_key , model_path , & koala );
336+ pv_status_t koala_status = pv_koala_init_func (access_key , model_path , device , & koala );
233337 if (koala_status != PV_STATUS_SUCCESS ) {
234338 fprintf (stderr , "Failed to init with '%s'" , pv_status_to_string_func (koala_status ));
235339 char * * message_stack = NULL ;
0 commit comments