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>
0 commit comments