Skip to content

Commit 49d85d7

Browse files
committed
v4.0 dotnet Binding & Demo
1 parent 7659500 commit 49d85d7

File tree

9 files changed

+199
-41
lines changed

9 files changed

+199
-41
lines changed

.github/workflows/dotnet-demos.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ jobs:
2525

2626
strategy:
2727
matrix:
28+
device: [cpu, cpu:1]
2829
os: [ubuntu-latest, windows-latest, macos-latest]
2930
include:
3031
- os: ubuntu-latest
@@ -52,13 +53,14 @@ jobs:
5253
run: dotnet build -c FileDemo.Release
5354

5455
- name: Run Dotnet filedemo
55-
run: dotnet run -c FileDemo.Release -- --input_audio_path ../../../resources/audio_samples/test_within_context.wav --access_key ${{secrets.PV_VALID_ACCESS_KEY}} --context_path ../../../resources/contexts/${{ matrix.platform }}/coffee_maker_${{ matrix.platform }}.rhn
56+
run: dotnet run -c FileDemo.Release -- --input_audio_path ../../../resources/audio_samples/test_within_context.wav --access_key ${{secrets.PV_VALID_ACCESS_KEY}} --device ${{ matrix.device }} --context_path ../../../resources/contexts/${{ matrix.platform }}/coffee_maker_${{ matrix.platform }}.rhn
5657

5758
build-self-hosted:
5859
runs-on: ${{ matrix.machine }}
5960

6061
strategy:
6162
matrix:
63+
device: [best]
6264
machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-64, pv-windows-arm64]
6365
include:
6466
- machine: rpi3-32
@@ -87,4 +89,4 @@ jobs:
8789
run: dotnet build -c FileDemo.Release
8890

8991
- name: Run Dotnet filedemo
90-
run: dotnet run -c FileDemo.Release -- --input_audio_path ../../../resources/audio_samples/test_within_context.wav --access_key ${{secrets.PV_VALID_ACCESS_KEY}} --context_path ../../../resources/contexts/${{ matrix.platform }}/coffee_maker_${{ matrix.platform }}.rhn
92+
run: dotnet run -c FileDemo.Release -- --input_audio_path ../../../resources/audio_samples/test_within_context.wav --access_key ${{secrets.PV_VALID_ACCESS_KEY}} --device ${{ matrix.device }} --context_path ../../../resources/contexts/${{ matrix.platform }}/coffee_maker_${{ matrix.platform }}.rhn

.github/workflows/dotnet.yml

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,48 +49,40 @@ jobs:
4949

5050
strategy:
5151
matrix:
52+
device: [cpu, cpu:1]
5253
os: [ubuntu-latest, macos-latest, macos-13, windows-latest]
53-
dotnet-version: [2.1.x, 3.0.x, 3.1.x, 5.0.x, 6.0.x, 8.0.x]
54+
dotnet-version: [2.1.x, 3.1.x, 6.0.x, 8.0.x, 10.0.x]
5455
include:
5556
- dotnet-version: 2.1.x
5657
binding-framework: netstandard2.0
5758
test-framework: netcoreapp2.1
58-
- dotnet-version: 3.0.x
59-
binding-framework: netcoreapp3.0
60-
test-framework: netcoreapp3.0
6159
- dotnet-version: 3.1.x
62-
binding-framework: netcoreapp3.0
60+
binding-framework: netstandard2.0
6361
test-framework: netcoreapp3.1
64-
- dotnet-version: 5.0.x
65-
binding-framework: netcoreapp3.0
66-
test-framework: net5.0
6762
- dotnet-version: 6.0.x
6863
binding-framework: net6.0
6964
test-framework: net6.0
7065
- dotnet-version: 8.0.x
7166
binding-framework: net8.0
7267
test-framework: net8.0
68+
- dotnet-version: 10.0.x
69+
binding-framework: net8.0
70+
test-framework: net10.0
7371
exclude:
7472
- os: ubuntu-latest
7573
dotnet-version: 2.1.x
76-
- os: ubuntu-latest
77-
dotnet-version: 3.0.x
7874
- os: ubuntu-latest
7975
dotnet-version: 3.1.x
80-
- os: ubuntu-latest
81-
dotnet-version: 5.0.x
8276
- os: macos-latest
8377
dotnet-version: 2.1.x
84-
- os: macos-latest
85-
dotnet-version: 3.0.x
8678
- os: macos-latest
8779
dotnet-version: 3.1.x
88-
- os: macos-latest
89-
dotnet-version: 5.0.x
9080
- os: macos-latest
9181
dotnet-version: 6.0.x
9282
- os: macos-13
9383
dotnet-version: 8.0.x
84+
- os: macos-13
85+
dotnet-version: 10.0.x
9486

9587
steps:
9688
- uses: actions/checkout@v3
@@ -111,6 +103,8 @@ jobs:
111103

112104
- name: Test
113105
run: dotnet test --framework ${{ matrix.test-framework }} -v n
106+
env:
107+
DEVICE: ${{ matrix.device }}
114108

115109
build-self-hosted:
116110
runs-on: ${{ matrix.machine }}
@@ -120,6 +114,7 @@ jobs:
120114
strategy:
121115
matrix:
122116
machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-64, pv-windows-arm64]
117+
device: [best]
123118

124119
steps:
125120
- uses: actions/checkout@v3
@@ -129,3 +124,5 @@ jobs:
129124

130125
- name: Test
131126
run: dotnet test --framework net8.0 -v n
127+
env:
128+
DEVICE: ${{ matrix.device }}

binding/dotnet/Rhino/Rhino.cs

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2020-2023 Picovoice Inc.
2+
Copyright 2020-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.
@@ -68,7 +68,7 @@ public class Rhino : IDisposable
6868
static Rhino()
6969
{
7070

71-
#if NETCOREAPP3_0_OR_GREATER
71+
#if NET6_0_OR_GREATER
7272

7373
NativeLibrary.SetDllImportResolver(typeof(Rhino).Assembly, ImportResolver);
7474

@@ -77,7 +77,7 @@ static Rhino()
7777
DEFAULT_MODEL_PATH = Utils.PvModelPath();
7878
}
7979

80-
#if NETCOREAPP3_0_OR_GREATER
80+
#if NET6_0_OR_GREATER
8181

8282
private static IntPtr ImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
8383
{
@@ -92,6 +92,7 @@ private static IntPtr ImportResolver(string libraryName, Assembly assembly, DllI
9292
private static extern RhinoStatus pv_rhino_init(
9393
IntPtr accessKey,
9494
IntPtr modelPath,
95+
IntPtr device,
9596
IntPtr contextPath,
9697
float sensitivity,
9798
float endpointDurationSec,
@@ -143,6 +144,16 @@ private static extern RhinoStatus pv_rhino_context_info(
143144
[DllImport(LIBRARY, CallingConvention = CallingConvention.Cdecl)]
144145
private static extern int pv_rhino_frame_length();
145146

147+
[DllImport(LIBRARY, CallingConvention = CallingConvention.Cdecl)]
148+
private static extern PvStatus pv_rhino_list_hardware_devices(
149+
out IntPtr hardwareDevices,
150+
out int numHardwareDevices);
151+
152+
[DllImport(LIBRARY, CallingConvention = CallingConvention.Cdecl)]
153+
private static extern void pv_rhino_free_hardware_devices(
154+
IntPtr hardwareDevices,
155+
int numHardwareDevices);
156+
146157
[DllImport(LIBRARY, CallingConvention = CallingConvention.Cdecl)]
147158
private static extern void pv_set_sdk(string sdk);
148159

@@ -167,6 +178,13 @@ private static extern RhinoStatus pv_rhino_context_info(
167178
/// Absolute path to the file containing model parameters. If not set it will be set to the
168179
/// default location.
169180
/// </param>
181+
/// <param name="device">
182+
/// String representation of the device (e.g., CPU or GPU) to use. If set to `best`, the most
183+
/// suitable device is selected automatically. If set to `gpu`, the engine uses the first available GPU device. To select a specific
184+
/// GPU device, set this argument to `gpu:${GPU_INDEX}`, where `${GPU_INDEX}` is the index of the target GPU. If set to
185+
/// `cpu`, the engine will run on the CPU with the default number of threads. To specify the number of threads, set this
186+
/// argument to `cpu:${NUM_THREADS}`, where `${NUM_THREADS}` is the desired number of threads.
187+
/// </param>
170188
/// <param name="sensitivity">
171189
/// Inference sensitivity expressed as floating point value within [0,1]. A higher sensitivity value results in fewer misses
172190
/// at the cost of (potentially) increasing the erroneous inference rate.
@@ -187,11 +205,12 @@ public static Rhino Create(
187205
string accessKey,
188206
string contextPath,
189207
string modelPath = null,
208+
string device = null,
190209
float sensitivity = 0.5f,
191210
float endpointDurationSec = 1.0f,
192211
bool requireEndpoint = true)
193212
{
194-
return new Rhino(accessKey, modelPath ?? DEFAULT_MODEL_PATH, contextPath, sensitivity, endpointDurationSec, requireEndpoint);
213+
return new Rhino(accessKey, modelPath ?? DEFAULT_MODEL_PATH, contextPath, device, sensitivity, endpointDurationSec, requireEndpoint);
195214
}
196215

197216
/// <summary>
@@ -206,6 +225,13 @@ public static Rhino Create(
206225
/// Absolute path to the file containing model parameters. If not set it will be set to the
207226
/// default location.
208227
/// </param>
228+
/// <param name="device">
229+
/// String representation of the device (e.g., CPU or GPU) to use. If set to `best`, the most
230+
/// suitable device is selected automatically. If set to `gpu`, the engine uses the first available GPU device. To select a specific
231+
/// GPU device, set this argument to `gpu:${GPU_INDEX}`, where `${GPU_INDEX}` is the index of the target GPU. If set to
232+
/// `cpu`, the engine will run on the CPU with the default number of threads. To specify the number of threads, set this
233+
/// argument to `cpu:${NUM_THREADS}`, where `${NUM_THREADS}` is the desired number of threads.
234+
/// </param>
209235
/// <param name="sensitivity">
210236
/// Inference sensitivity expressed as floating point value within [0,1]. A higher sensitivity value results in fewer misses
211237
/// at the cost of (potentially) increasing the erroneous inference rate.
@@ -225,6 +251,7 @@ private Rhino(
225251
string accessKey,
226252
string modelPath,
227253
string contextPath,
254+
string device = null,
228255
float sensitivity = 0.5f,
229256
float endpointDurationSec = 1.0f,
230257
bool requireEndpoint = true)
@@ -244,6 +271,8 @@ private Rhino(
244271
throw new RhinoIOException($"Couldn't find context file at '{contextPath}'");
245272
}
246273

274+
device = device ?? "best";
275+
247276
if (sensitivity < 0 || sensitivity > 1)
248277
{
249278
throw new RhinoInvalidArgumentException("Sensitivity value should be within [0, 1].");
@@ -257,12 +286,14 @@ private Rhino(
257286
IntPtr accessKeyPtr = Utils.GetPtrFromUtf8String(accessKey);
258287
IntPtr modelPathPtr = Utils.GetPtrFromUtf8String(modelPath);
259288
IntPtr contextPathPtr = Utils.GetPtrFromUtf8String(contextPath);
289+
IntPtr devicePtr = Utils.GetPtrFromUtf8String(device);
260290

261291
pv_set_sdk("dotnet");
262292

263293
RhinoStatus status = pv_rhino_init(
264294
accessKeyPtr,
265295
modelPathPtr,
296+
devicePtr,
266297
contextPathPtr,
267298
sensitivity,
268299
endpointDurationSec,
@@ -271,6 +302,7 @@ private Rhino(
271302

272303
Marshal.FreeHGlobal(accessKeyPtr);
273304
Marshal.FreeHGlobal(modelPathPtr);
305+
Marshal.FreeHGlobal(devicePtr);
274306
Marshal.FreeHGlobal(contextPathPtr);
275307

276308
if (status != RhinoStatus.SUCCESS)
@@ -416,7 +448,6 @@ public Inference GetInference()
416448
/// <returns>Context information</returns>
417449
public string ContextInfo { get; private set; }
418450

419-
420451
/// <summary>
421452
/// Gets the version number of the Rhino library.
422453
/// </summary>
@@ -435,6 +466,37 @@ public Inference GetInference()
435466
/// <returns>Required sample rate.</returns>
436467
public int SampleRate { get; private set; }
437468

469+
/// <summary>
470+
/// Retrieves a list of hardware devices that can be specified when constructing the model.
471+
/// </summary>
472+
/// <returns>An array of available hardware devices.</returns>
473+
/// <exception cref="RhinoException">Thrown when an error occurs while retrieving the hardware devices.</exception>
474+
public static string[] GetAvailableDevices()
475+
{
476+
IntPtr hardwareDevicesPtr;
477+
int numDevices;
478+
PvStatus status = pv_rhino_list_hardware_devices(
479+
out hardwareDevicesPtr,
480+
out numDevices);
481+
if (status != PvStatus.SUCCESS)
482+
{
483+
throw PvStatusToException(
484+
status,
485+
"Get available devices failed",
486+
GetMessageStack());
487+
}
488+
489+
string[] devices = new string[numDevices];
490+
int elementSize = Marshal.SizeOf(typeof(IntPtr));
491+
for (int i = 0; i < numDevices; i++)
492+
{
493+
devices[i] = Utils.GetUtf8StringFromPtr(Marshal.ReadIntPtr(hardwareDevicesPtr, i * elementSize));
494+
}
495+
496+
pv_rhino_free_hardware_devices(hardwareDevicesPtr, numDevices);
497+
return devices;
498+
}
499+
438500
/// <summary>
439501
/// Coverts status codes to relevant .NET exceptions
440502
/// </summary>

binding/dotnet/Rhino/Rhino.csproj

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>net8.0;net6.0;netcoreapp3.0;netstandard2.0</TargetFrameworks>
5-
<Version>3.0.6</Version>
4+
<TargetFrameworks>net8.0;net6.0;netstandard2.0</TargetFrameworks>
5+
<Version>4.0.0</Version>
66
<Authors>Picovoice</Authors>
77
<Company />
88
<Product>Rhino Speech-to-Intent Engine</Product>
@@ -42,7 +42,6 @@
4242
</Content>
4343
<Content Include="Rhino.targets">
4444
<PackagePath>
45-
buildTransitive/netcoreapp3.0/Rhino.targets;
4645
buildTransitive/net6.0/Rhino.targets;
4746
buildTransitive/net8.0/Rhino.targets;
4847
</PackagePath>
@@ -55,18 +54,26 @@
5554
<Content Include="..\..\..\lib\windows\amd64\libpv_rhino.dll">
5655
<PackagePath>
5756
buildTransitive/netstandard2.0/libpv_rhino.dll;
58-
buildTransitive/netcoreapp3.0/lib/windows/amd64/libpv_rhino.dll;
5957
buildTransitive/net6.0/lib/windows/amd64/libpv_rhino.dll;
6058
buildTransitive/net8.0/lib/windows/amd64/libpv_rhino.dll;
6159
</PackagePath>
6260
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
6361
<Link>lib\windows\amd64\libpv_rhino.dll</Link>
6462
<Visible>false</Visible>
6563
</Content>
64+
<Content Include="..\..\..\lib\windows\amd64\pv_ypu_impl_cuda.dll">
65+
<PackagePath>
66+
buildTransitive/netstandard2.0/pv_ypu_impl_cuda.dll;
67+
buildTransitive/net6.0/lib/windows/amd64/pv_ypu_impl_cuda.dll;
68+
buildTransitive/net8.0/lib/windows/amd64/pv_ypu_impl_cuda.dll;
69+
</PackagePath>
70+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
71+
<Link>lib\windows\amd64\libpv_rhino.dll</Link>
72+
<Visible>false</Visible>
73+
</Content>
6674
<Content Include="..\..\..\lib\mac\x86_64\libpv_rhino.dylib">
6775
<PackagePath>
6876
buildTransitive/netstandard2.0/libpv_rhino.dylib;
69-
buildTransitive/netcoreapp3.0/lib/mac/x86_64/libpv_rhino.dylib;
7077
buildTransitive/net6.0/lib/mac/x86_64/libpv_rhino.dylib;
7178
buildTransitive/net8.0/lib/mac/x86_64/libpv_rhino.dylib;
7279
</PackagePath>
@@ -107,7 +114,6 @@
107114
</Content>
108115
<Content Include="..\..\..\lib\raspberry-pi\**\*" Exclude="..\..\..\lib\raspberry-pi\arm11\*">
109116
<PackagePath>
110-
buildTransitive/netcoreapp3.0/lib/raspberry-pi;
111117
buildTransitive/net6.0/lib/raspberry-pi;
112118
buildTransitive/net8.0/lib/raspberry-pi;
113119
</PackagePath>

binding/dotnet/Rhino/Rhino.netstandard2.0.targets

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
1111
<Visible>false</Visible>
1212
</Content>
13+
<Content Include="$(MSBuildThisFileDirectory)pv_ypu_impl_cuda.dll">
14+
<Link>pv_ypu_impl_cuda.dll</Link>
15+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
16+
<Visible>false</Visible>
17+
</Content>
1318
<Content Include="$(MSBuildThisFileDirectory)libpv_rhino.dylib">
1419
<Link>libpv_rhino.dylib</Link>
1520
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

0 commit comments

Comments
 (0)