Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions .github/workflows/c-demos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:

strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ ubuntu-latest, windows-latest, macos-latest ]
include:
- os: ubuntu-latest
pv_recorder_platform: "linux"
Expand All @@ -62,7 +62,7 @@ jobs:

strategy:
matrix:
machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-64, pv-windows-arm64]
machine: [ rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-64, pv-windows-arm64 ]
include:
- machine: rpi3-32
make_file: "Unix Makefiles"
Expand Down Expand Up @@ -99,7 +99,8 @@ jobs:

strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
device: [ cpu, cpu:1 ]
os: [ ubuntu-latest, windows-latest, macos-latest ]
include:
- os: ubuntu-latest
platform: linux
Expand Down Expand Up @@ -131,14 +132,15 @@ jobs:
run: cmake --build ./build --target koala_demo_file

- name: Test
run: python test/test_koala_c.py ${{secrets.PV_VALID_ACCESS_KEY}} ${{ matrix.platform }} ${{ matrix.arch }}
run: python test/test_koala_c.py ${{secrets.PV_VALID_ACCESS_KEY}} ${{ matrix.device }} ${{ matrix.platform }} ${{ matrix.arch }}

build-filedemo-self-hosted:
runs-on: ${{ matrix.machine }}

strategy:
matrix:
machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-64]
device: [ best ]
machine: [ rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-64, pv-windows-arm64 ]
include:
- machine: rpi3-32
platform: raspberry-pi
Expand Down Expand Up @@ -170,6 +172,24 @@ jobs:
arch: arm64
make_file: "MinGW Makefiles"
pv_recorder_platform: "windows-arm64"
- device: gpu
machine: pv-linux
platform: linux
arch: x86_64
make_file: "Unix Makefiles"
pv_recorder_platform: "linux"
- device: gpu
machine: pv-windows
platform: windows
arch: amd64
make_file: "MinGW Makefiles"
pv_recorder_platform: "windows-amd64"
- device: gpu
machine: pv-ios
platform: mac
arch: arm64
make_file: "Unix Makefiles"
pv_recorder_platform: "mac-arm64"

steps:
- uses: actions/checkout@v3
Expand All @@ -183,4 +203,4 @@ jobs:
run: cmake --build ./build --target koala_demo_file

- name: Test
run: python test/test_koala_c.py ${{secrets.PV_VALID_ACCESS_KEY}} ${{ matrix.platform }} ${{ matrix.arch }}
run: python3 test/test_koala_c.py ${{secrets.PV_VALID_ACCESS_KEY}} ${{ matrix.device }} ${{ matrix.platform }} ${{ matrix.arch }}
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,9 @@ When done be sure to explicitly release the resources using `koala.delete()`.
```c
pv_koala_t *handle = NULL;
const char *model_path = "${MODEL_PATH}";
pv_status_t status = pv_koala_init(${ACCESS_KEY}, model_path, &handle);
const char *device = "best";

pv_status_t status = pv_koala_init(${ACCESS_KEY}, model_path, device, &handle);
if (status != PV_STATUS_SUCCESS) {
// error handling logic
}
Expand Down Expand Up @@ -320,6 +322,13 @@ Replace `${ACCESS_KEY}` with yours obtained from [Picovoice Console](https://con

## Releases

### v3.0.0 - December 9th, 2025

- Improved engine performance
- Added support for running on GPU or multiple CPU cores
- Node.js min version bumped to Node 18
- iOS min version bumped to iOS 16

### v2.0.0 - November 24th, 2023

- Improvements to error reporting
Expand Down
126 changes: 115 additions & 11 deletions demo/c/koala_demo_file.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
/*
Copyright 2023 Picovoice Inc.
Copyright 2023-2025 Picovoice Inc.

You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE"
file accompanying this source.

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
*/

#include <getopt.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
Expand Down Expand Up @@ -87,17 +88,21 @@ static void print_dl_error(const char *message) {
}

static struct option long_options[] = {
{"access_key", required_argument, NULL, 'a'},
{"library_path", required_argument, NULL, 'l'},
{"model_path", required_argument, NULL, 'm'},
{"input_path", required_argument, NULL, 'i'},
{"output_path", required_argument, NULL, 'o'},
{"access_key", required_argument, NULL, 'a'},
{"library_path", required_argument, NULL, 'l'},
{"model_path", required_argument, NULL, 'm'},
{"device", required_argument, NULL, 'y'},
{"input_path", required_argument, NULL, 'i'},
{"output_path", required_argument, NULL, 'o'},
{"show_inference_devices", required_argument, NULL, 'z'},
};

static void print_usage(const char *program_name) {
fprintf(
stdout,
"Usage: %s [-l LIBRARY_PATH -m MODEL_PATH -a ACCESS_KEY -i INPUT_PATH -o OUTPUT_PATH]\n",
"Usage: %s -l LIBRARY_PATH [-m MODEL_PATH -a ACCESS_KEY -y DEVICE -i INPUT_PATH -o OUTPUT_PATH]\n"
" %s [-z, --show_inference_devices] -l LIBRARY_PATH\n",
program_name,
program_name);
}

Expand All @@ -122,16 +127,94 @@ static void print_progress_bar(size_t num_total_samples, size_t num_processed_sa
fflush(stdout);
}

static void print_inference_devices(const char *library_path) {
void *dl_handle = open_dl(library_path);
if (!dl_handle) {
fprintf(stderr, "Failed to open library at '%s'.\n", library_path);
exit(EXIT_FAILURE);
}

const char *(*pv_status_to_string_func)(pv_status_t) = load_symbol(dl_handle, "pv_status_to_string");
if (!pv_status_to_string_func) {
print_dl_error("Failed to load 'pv_status_to_string'");
exit(EXIT_FAILURE);
}

pv_status_t (*pv_koala_list_hardware_devices_func)(char ***, int32_t *) =
load_symbol(dl_handle, "pv_koala_list_hardware_devices");
if (!pv_koala_list_hardware_devices_func) {
print_dl_error("failed to load `pv_koala_list_hardware_devices`");
exit(EXIT_FAILURE);
}

pv_status_t (*pv_koala_free_hardware_devices_func)(char **, int32_t) =
load_symbol(dl_handle, "pv_koala_free_hardware_devices");
if (!pv_koala_free_hardware_devices_func) {
print_dl_error("failed to load `pv_koala_free_hardware_devices`");
exit(EXIT_FAILURE);
}

pv_status_t (*pv_get_error_stack_func)(char ***, int32_t *) =
load_symbol(dl_handle, "pv_get_error_stack");
if (!pv_get_error_stack_func) {
print_dl_error("failed to load 'pv_get_error_stack_func'");
exit(EXIT_FAILURE);
}

void (*pv_free_error_stack_func)(char **) =
load_symbol(dl_handle, "pv_free_error_stack");
if (!pv_free_error_stack_func) {
print_dl_error("failed to load 'pv_free_error_stack_func'");
exit(EXIT_FAILURE);
}

char **message_stack = NULL;
int32_t message_stack_depth = 0;
pv_status_t error_status = PV_STATUS_RUNTIME_ERROR;

char **hardware_devices = NULL;
int32_t num_hardware_devices = 0;
pv_status_t status = pv_koala_list_hardware_devices_func(&hardware_devices, &num_hardware_devices);
if (status != PV_STATUS_SUCCESS) {
fprintf(
stderr,
"Failed to list hardware devices with `%s`.\n",
pv_status_to_string_func(status));
error_status = pv_get_error_stack_func(&message_stack, &message_stack_depth);
if (error_status != PV_STATUS_SUCCESS) {
fprintf(
stderr,
".\nUnable to get Koala error state with '%s'.\n",
pv_status_to_string_func(error_status));
exit(EXIT_FAILURE);
}

if (message_stack_depth > 0) {
fprintf(stderr, ":\n");
print_error_message(message_stack, message_stack_depth);
pv_free_error_stack_func(message_stack);
}
exit(EXIT_FAILURE);
}

for (int32_t i = 0; i < num_hardware_devices; i++) {
fprintf(stdout, "%s\n", hardware_devices[i]);
}
pv_koala_free_hardware_devices_func(hardware_devices, num_hardware_devices);
close_dl(dl_handle);
}

int picovoice_main(int argc, char *argv[]) {
const char *library_path = NULL;
const char *model_path = NULL;
const char *access_key = NULL;
const char *input_path = NULL;
const char *output_path = NULL;
const char *device = NULL;
bool show_inference_devices = false;

int c;
while ((c = getopt_long(argc, argv, "l:m:a:i:o:", long_options, NULL)) != -1) {
while ((c = getopt_long(argc, argv, "zl:m:a:y:i:o:", long_options, NULL)) != -1) {
switch (c) {
case 'l':
library_path = optarg;
Expand All @@ -148,16 +231,37 @@ int picovoice_main(int argc, char *argv[]) {
case 'o':
output_path = optarg;
break;
case 'y':
device = optarg;
break;
case 'z':
show_inference_devices = true;
break;
default:
exit(EXIT_FAILURE);
}
}

if (show_inference_devices) {
if (!library_path) {
fprintf(stderr, "`library_path` is required to view available inference devices.\n");
print_usage(argv[0]);
exit(EXIT_FAILURE);
}

print_inference_devices(library_path);
return EXIT_SUCCESS;
}

if (!library_path || !access_key || !input_path || !output_path) {
print_usage(argv[0]);
exit(EXIT_FAILURE);
}

if (device == NULL) {
device = "best";
}

void *koala_library = open_dl(library_path);
if (!koala_library) {
fprintf(stderr, "Failed to open library at '%s'.\n", library_path);
Expand All @@ -177,7 +281,7 @@ int picovoice_main(int argc, char *argv[]) {
exit(EXIT_FAILURE);
}

pv_status_t (*pv_koala_init_func)(const char *, const char *, pv_koala_t **) =
pv_status_t (*pv_koala_init_func)(const char *, const char *, const char *, pv_koala_t **) =
load_symbol(koala_library, "pv_koala_init");
if (!pv_koala_init_func) {
print_dl_error("Failed to load 'pv_koala_init'");
Expand Down Expand Up @@ -229,7 +333,7 @@ int picovoice_main(int argc, char *argv[]) {
}

pv_koala_t *koala = NULL;
pv_status_t koala_status = pv_koala_init_func(access_key, model_path, &koala);
pv_status_t koala_status = pv_koala_init_func(access_key, model_path, device, &koala);
if (koala_status != PV_STATUS_SUCCESS) {
fprintf(stderr, "Failed to init with '%s'", pv_status_to_string_func(koala_status));
char **message_stack = NULL;
Expand Down
Loading