diff --git a/.github/workflows/c-demo.yml b/.github/workflows/c-demo.yml
index b74700d2..d7468f7b 100644
--- a/.github/workflows/c-demo.yml
+++ b/.github/workflows/c-demo.yml
@@ -31,7 +31,7 @@ jobs:
- os: ubuntu-latest
pv_recorder_platform: linux
- os: windows-latest
- pv_recorder_platform: windows
+ pv_recorder_platform: windows-amd64
- os: macos-latest
pv_recorder_platform: mac-arm64
@@ -53,7 +53,7 @@ jobs:
runs-on: ${{ matrix.machine }}
strategy:
matrix:
- machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64]
+ machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-windows-arm64]
include:
- machine: rpi3-32
pv_recorder_platform: raspberry-pi3
@@ -67,6 +67,9 @@ jobs:
pv_recorder_platform: raspberry-pi5
- machine: rpi5-64
pv_recorder_platform: raspberry-pi5-64
+ - machine: pv-windows-arm64
+ pv_recorder_platform: windows-arm64
+ shell: pwsh
steps:
- uses: actions/checkout@v3
diff --git a/.github/workflows/dotnet-demo.yml b/.github/workflows/dotnet-demo.yml
index 51e41f7f..4e0e05d4 100644
--- a/.github/workflows/dotnet-demo.yml
+++ b/.github/workflows/dotnet-demo.yml
@@ -53,7 +53,10 @@ jobs:
strategy:
matrix:
- machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64]
+ machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, pv-windows-arm64]
+ include:
+ - machine: pv-windows-arm64
+ shell: pwsh
steps:
- uses: actions/checkout@v3
diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index ab22afc4..f5072be3 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -31,22 +31,11 @@ jobs:
build-github-hosted:
runs-on: ${{ matrix.os }}
strategy:
+ fail-fast: false
matrix:
os: [ubuntu-latest]
- dotnet-version: [2.1.x, 3.0.x, 3.1.x, 5.0.x, 6.0.x, 8.0.x]
+ dotnet-version: [6.0.x, 8.0.x]
include:
- - dotnet-version: 2.1.x
- binding-framework: netstandard2.0
- test-framework: netcoreapp2.1.30
- - dotnet-version: 3.0.x
- binding-framework: netcoreapp3.0
- test-framework: netcoreapp3.0
- - dotnet-version: 3.1.x
- binding-framework: netcoreapp3.0
- test-framework: netcoreapp3.1
- - dotnet-version: 5.0.x
- binding-framework: netcoreapp3.0
- test-framework: net5.0
- dotnet-version: 6.0.x
binding-framework: net6.0
test-framework: net6.0
@@ -55,13 +44,19 @@ jobs:
test-framework: net8.0
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up .NET
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ matrix.dotnet-version }}
+ - name: Set up .NET (8)
+ if: ${{ matrix.os == 'ubuntu-latest' && matrix.dotnet-version == '6.0.x' }}
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+
- name: Build binding
run: dotnet build PvRecorder/PvRecorder.csproj --framework ${{ matrix.binding-framework }}
@@ -72,14 +67,39 @@ jobs:
runs-on: ${{ matrix.machine }}
strategy:
+ fail-fast: false
matrix:
- machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-windows, pv-ios]
+ machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-windows, pv-ios, pv-windows-arm64]
+ dotnet-version: [6.0.x, 8.0.x]
+ include:
+ - dotnet-version: 6.0.x
+ binding-framework: net6.0
+ test-framework: net6.0
+ - dotnet-version: 8.0.x
+ binding-framework: net8.0
+ test-framework: net8.0
+ - machine: pv-windows
+ dotnet-version: 2.1.x
+ binding-framework: netstandard2.0
+ test-framework: netcoreapp2.1
+ - machine: pv-windows
+ dotnet-version: 3.0.x
+ binding-framework: netcoreapp3.0
+ test-framework: netcoreapp3.0
+ - machine: pv-windows
+ dotnet-version: 3.1.x
+ binding-framework: netcoreapp3.0
+ test-framework: netcoreapp3.1
+ - machine: pv-windows
+ dotnet-version: 5.0.x
+ binding-framework: netcoreapp3.0
+ test-framework: net5.0
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Build binding
- run: dotnet build PvRecorder/PvRecorder.csproj --framework net8.0
+ run: dotnet build PvRecorder/PvRecorder.csproj --framework ${{ matrix.binding-framework }}
- name: Test
- run: dotnet test --framework net8.0 -v n
+ run: dotnet test --framework ${{ matrix.test-framework }} -v n
diff --git a/.github/workflows/go-demos.yml b/.github/workflows/go-demos.yml
index 2f9caf35..5c9567ce 100644
--- a/.github/workflows/go-demos.yml
+++ b/.github/workflows/go-demos.yml
@@ -58,7 +58,7 @@ jobs:
strategy:
matrix:
- machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-windows]
+ machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-windows, pv-windows-arm64]
steps:
- uses: actions/checkout@v3
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 26c179a2..7dd738a7 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -63,7 +63,7 @@ jobs:
strategy:
matrix:
- machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-windows, pv-ios]
+ machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-windows, pv-windows-arm64, pv-ios]
steps:
- uses: actions/checkout@v3
diff --git a/.github/workflows/nodejs-codestyle.yml b/.github/workflows/nodejs-codestyle.yml
index b075d18f..9c1ab6f8 100644
--- a/.github/workflows/nodejs-codestyle.yml
+++ b/.github/workflows/nodejs-codestyle.yml
@@ -27,9 +27,6 @@ jobs:
with:
node-version: lts/*
- - name: Pre-build dependencies
- run: npm install yarn
-
- name: Run Binding Linter
run: yarn && yarn lint
- working-directory: binding/nodejs
\ No newline at end of file
+ working-directory: binding/nodejs
diff --git a/.github/workflows/nodejs-demos.yml b/.github/workflows/nodejs-demos.yml
index 422a4e03..194b844d 100644
--- a/.github/workflows/nodejs-demos.yml
+++ b/.github/workflows/nodejs-demos.yml
@@ -38,6 +38,14 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
+ # ************ REMOVE AFTER RELEASE ***************
+ - name: build local binding
+ run: |
+ yarn install
+ yarn build
+ working-directory: binding/nodejs
+ # ************ REMOVE AFTER RELEASE ***************
+
- name: Install dependencies
run: yarn install
@@ -49,13 +57,21 @@ jobs:
strategy:
matrix:
- machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-windows, pv-ios]
+ machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-ios, pv-windows, pv-windows-arm64]
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
+ # ************ REMOVE AFTER RELEASE ***************
+ - name: build local binding
+ run: |
+ yarn install
+ yarn build
+ working-directory: binding/nodejs
+ # ************ REMOVE AFTER RELEASE ***************
+
- name: Install dependencies
run: yarn install
diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml
index b033ea22..a224ddd9 100644
--- a/.github/workflows/nodejs.yml
+++ b/.github/workflows/nodejs.yml
@@ -40,9 +40,6 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
- - name: Pre-build dependencies
- run: npm install yarn
-
- name: Install dependencies
run: yarn install
@@ -60,7 +57,7 @@ jobs:
strategy:
matrix:
- machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-windows, pv-ios]
+ machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-windows, pv-windows-arm64, pv-ios]
steps:
- uses: actions/checkout@v3
diff --git a/.github/workflows/python-demos.yml b/.github/workflows/python-demos.yml
index 685e22f2..f4190116 100644
--- a/.github/workflows/python-demos.yml
+++ b/.github/workflows/python-demos.yml
@@ -39,6 +39,14 @@ jobs:
- name: Pre-build dependencies
run: python -m pip install --upgrade pip
+ # ************ REMOVE AFTER RELEASE ***************
+ - name: build local binding
+ run: |
+ python3 -m pip install setuptools wheel
+ python3 -m setup sdist bdist_wheel
+ working-directory: binding/python
+ # ************ REMOVE AFTER RELEASE ***************
+
- name: Install dependencies
run: pip install -r requirements.txt
@@ -55,6 +63,13 @@ jobs:
steps:
- uses: actions/checkout@v3
+ # ************ REMOVE AFTER RELEASE ***************
+ - name: build local binding
+ run: |
+ python3 -m setup sdist bdist_wheel
+ working-directory: binding/python
+ # ************ REMOVE AFTER RELEASE ***************
+
- name: Install dependencies
run: |
python3 -m venv .venv
@@ -66,3 +81,27 @@ jobs:
python3 -m venv .venv
source .venv/bin/activate
python3 pv_recorder_demo.py --show_audio_devices
+
+ build-windows-arm64:
+ runs-on: ${{ matrix.machine }}
+
+ strategy:
+ matrix:
+ machine: [pv-windows-arm64]
+
+ steps:
+ - uses: actions/checkout@v3
+
+ # ************ REMOVE AFTER RELEASE ***************
+ - name: build local binding
+ run: |
+ python3 -m pip install setuptools wheel
+ python3 -m setup sdist bdist_wheel
+ working-directory: binding/python
+ # ************ REMOVE AFTER RELEASE ***************
+
+ - name: Install dependencies
+ run: pip3 install -r requirements.txt
+
+ - name: Run demo
+ run: python3 pv_recorder_demo.py --show_audio_devices
diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index 7e972f1a..81bb47fe 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -54,7 +54,7 @@ jobs:
strategy:
matrix:
- machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-windows, pv-ios]
+ machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-windows, pv-windows-arm64, pv-ios]
steps:
- uses: actions/checkout@v3
diff --git a/.github/workflows/rust-codestyle.yml b/.github/workflows/rust-codestyle.yml
index 8523b66c..2cea9779 100644
--- a/.github/workflows/rust-codestyle.yml
+++ b/.github/workflows/rust-codestyle.yml
@@ -43,11 +43,7 @@ jobs:
working-directory: binding/rust
- name: Install stable toolchain
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: stable
- override: true
+ uses: dtolnay/rust-toolchain@stable
- name: Run clippy
run: cargo clippy -- -D warnings
@@ -69,11 +65,7 @@ jobs:
working-directory: binding/rust
- name: Install stable toolchain
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: stable
- override: true
+ uses: dtolnay/rust-toolchain@stable
- name: Run clippy
run: cargo clippy -- -D warnings
diff --git a/.github/workflows/rust-demos.yml b/.github/workflows/rust-demos.yml
index df8a1c7c..f30a810c 100644
--- a/.github/workflows/rust-demos.yml
+++ b/.github/workflows/rust-demos.yml
@@ -43,11 +43,7 @@ jobs:
working-directory: binding/rust
- name: Install stable toolchain
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: stable
- override: true
+ uses: dtolnay/rust-toolchain@stable
- name: Rust build demo
run: cargo build --verbose
@@ -60,7 +56,7 @@ jobs:
strategy:
matrix:
- machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64]
+ machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-windows-arm64]
steps:
- uses: actions/checkout@v3
@@ -69,12 +65,6 @@ jobs:
run: bash copy.sh
working-directory: binding/rust
- - name: Install stable toolchain
- uses: actions-rs/toolchain@v1
- with:
- toolchain: stable
- override: true
-
- name: Rust build demo
run: cargo build --verbose
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index c94fc801..f91deadd 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -50,13 +50,6 @@ jobs:
- name: Rust pre-build
run: bash copy.sh
- - name: Install stable toolchain
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: stable
- override: true
-
- name: Build
run: cargo build --verbose
@@ -68,7 +61,7 @@ jobs:
strategy:
matrix:
- machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-windows, pv-ios]
+ machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, rpi5-32, rpi5-64, pv-windows, pv-windows-arm64, pv-ios]
steps:
- uses: actions/checkout@v3
@@ -76,22 +69,16 @@ jobs:
submodules: recursive
- name: Rust pre-build
- if: matrix.machine != 'pv-windows'
+ if: matrix.machine != 'pv-windows' && matrix.machine != 'pv-windows-arm64'
run: bash copy.sh
- name: Rust pre-build windows
- if: matrix.machine == 'pv-windows'
+ if: matrix.machine == 'pv-windows' || matrix.machine == 'pv-windows-arm64'
run: |
New-Item -Path "." -Name "data" -ItemType "directory"
New-Item -Path ".\data" -Name "lib" -ItemType "directory"
Copy-Item -Path "..\..\lib\windows" -Destination ".\data\lib" -Recurse
- - name: Install stable toolchain
- uses: actions-rs/toolchain@v1
- with:
- toolchain: stable
- override: true
-
- name: Build
run: cargo build --verbose
diff --git a/binding/dotnet/PvRecorder/PvRecorder.cs b/binding/dotnet/PvRecorder/PvRecorder.cs
index 9eec2810..044d7dda 100644
--- a/binding/dotnet/PvRecorder/PvRecorder.cs
+++ b/binding/dotnet/PvRecorder/PvRecorder.cs
@@ -1,5 +1,5 @@
/*
- Copyright 2021-2023 Picovoice Inc.
+ Copyright 2021-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.
@@ -61,7 +61,7 @@ private static IntPtr ImportResolver(string libraryName, Assembly assembly, DllI
#pragma warning disable IDE0059
IntPtr libHandle = IntPtr.Zero;
- NativeLibrary.TryLoad(GetLibraryPath(), out libHandle);
+ NativeLibrary.TryLoad(Utils.PvLibraryPath(libraryName), out libHandle);
return libHandle;
}
@@ -319,61 +319,6 @@ private static PvRecorderException PvRecorderStatusToException(PvRecorderStatus
}
}
- ///
- /// Helper function to get the library path of pv_recorder.
- ///
- /// A string representing the absolute path of the library.
- private static string GetLibraryPath()
- {
- string scriptPath;
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
- scriptPath = Path.Combine(AppContext.BaseDirectory, "scripts/platform.bat");
- }
- else
- {
- scriptPath = Path.Combine(AppContext.BaseDirectory, "scripts/platform.sh");
- }
-
- var process = new Process();
- var processStartInfo = new ProcessStartInfo()
- {
- FileName = scriptPath,
- UseShellExecute = false,
- RedirectStandardOutput = true,
- WindowStyle = ProcessWindowStyle.Hidden
- };
- process.StartInfo = processStartInfo;
- process.Start();
- process.WaitForExit();
-
- if (process.ExitCode != 0)
- {
- throw new SystemException("System is not supported.");
- }
-
- string[] output = process.StandardOutput.ReadToEnd().Split(' ');
- string osName = output[0];
- string cpu = output[1];
-
- string libName;
-
- if (osName == "windows")
- {
- libName = $"{LIBRARY}.dll";
- }
- else if (osName == "mac")
- {
- libName = $"{LIBRARY}.dylib";
- }
- else
- {
- libName = $"{LIBRARY}.so";
- }
-
- return Path.Combine(AppContext.BaseDirectory, $"lib/{osName}/{cpu}/{libName}");
- }
-
///
/// Frees memory used by PvRecorder instance.
///
diff --git a/binding/dotnet/PvRecorder/PvRecorder.csproj b/binding/dotnet/PvRecorder/PvRecorder.csproj
index a8526135..e1e01437 100644
--- a/binding/dotnet/PvRecorder/PvRecorder.csproj
+++ b/binding/dotnet/PvRecorder/PvRecorder.csproj
@@ -2,7 +2,7 @@
net8.0;net6.0;netcoreapp3.0;netstandard2.0
- 1.2.8
+ 1.2.9
Picovoice
PvRecorder
@@ -49,17 +49,6 @@
lib\windows\amd64\libpv_recorder.dll
false
-
-
- build/netstandard2.0/libpv_recorder.so;
- build/netcoreapp3.0/lib/linux/x86_64/libpv_recorder.so;
- build/net6.0/lib/linux/x86_64/libpv_recorder.so;
- build/net8.0/lib/linux/x86_64/libpv_recorder.so;
-
- PreserveNewest
- lib\linux\x86_64\libpv_recorder.so
- false
-
build/netstandard2.0/libpv_recorder.dylib;
@@ -73,22 +62,26 @@
-
+
-
+
- build/netcoreapp3.0/lib/raspberry-pi;
- build/net6.0/lib/raspberry-pi;
- build/net8.0/lib/raspberry-pi;
+ build/net6.0/lib/windows/arm64/libpv_recorder.dll;
+ build/net8.0/lib/windows/arm64/libpv_recorder.dll;
PreserveNewest
- lib\raspberry-pi\%(RecursiveDir)%(Filename)%(Extension)
+ lib\windows\arm64\libpv_recorder.dll
+ false
+
+
+
+ build/net6.0/lib/linux/x86_64/libpv_recorder.so;
+ build/net8.0/lib/linux/x86_64/libpv_recorder.so;
+
+ PreserveNewest
+ lib\linux\x86_64\libpv_recorder.so
false
-
-
-
-
build/net6.0/lib/mac/arm64/libpv_recorder.dylib;
@@ -98,22 +91,18 @@
lib\mac\arm64\libpv_recorder.dylib
false
-
-
-
-
-
+
- build/netstandard2.0/scripts;
- build/netcoreapp3.0/scripts;
- build/net6.0/scripts;
- build/net8.0/scripts;
+ build/net6.0/lib/raspberry-pi;
+ build/net8.0/lib/raspberry-pi;
PreserveNewest
- scripts\%(Filename)%(Extension)
- False
+ lib\raspberry-pi\%(RecursiveDir)%(Filename)%(Extension)
+ false
+
+
diff --git a/binding/dotnet/PvRecorder/PvRecorder.netstandard2.0.targets b/binding/dotnet/PvRecorder/PvRecorder.netstandard2.0.targets
index 8bde4cdc..7e677860 100644
--- a/binding/dotnet/PvRecorder/PvRecorder.netstandard2.0.targets
+++ b/binding/dotnet/PvRecorder/PvRecorder.netstandard2.0.targets
@@ -21,11 +21,4 @@
false
-
-
- scripts/%(Filename)%(Extension)
- PreserveNewest
- false
-
-
diff --git a/binding/dotnet/PvRecorder/PvRecorder.targets b/binding/dotnet/PvRecorder/PvRecorder.targets
index 5b6fb27a..06b1c75f 100644
--- a/binding/dotnet/PvRecorder/PvRecorder.targets
+++ b/binding/dotnet/PvRecorder/PvRecorder.targets
@@ -5,10 +5,5 @@
PreserveNewest
false
-
- scripts/%(Filename)%(Extension)
- PreserveNewest
- false
-
diff --git a/binding/dotnet/PvRecorder/Utils.cs b/binding/dotnet/PvRecorder/Utils.cs
new file mode 100644
index 00000000..8515b079
--- /dev/null
+++ b/binding/dotnet/PvRecorder/Utils.cs
@@ -0,0 +1,128 @@
+/*
+ Copyright 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.
+*/
+
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Pv
+{
+ public static class Utils
+ {
+ private static Architecture _arch => RuntimeInformation.ProcessArchitecture;
+
+ private static bool _isArm => _arch == Architecture.Arm || _arch == Architecture.Arm64;
+ private static string _env => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "mac" :
+ RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "windows" :
+ RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && _arch == Architecture.X64 ? "linux" :
+ RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && _isArm ? PvLinuxEnv() : "";
+
+ public static string PvLibraryPath(string libName)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && _arch == Architecture.X64)
+ {
+ return Path.Combine(AppContext.BaseDirectory, $"lib/{_env}/amd64/{libName}.dll");
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && _arch == Architecture.Arm64)
+ {
+ return Path.Combine(AppContext.BaseDirectory, $"lib/{_env}/arm64/{libName}.dll");
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && _arch == Architecture.X64)
+ {
+ return Path.Combine(AppContext.BaseDirectory, $"lib/{_env}/x86_64/{libName}.dylib");
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && _isArm)
+ {
+ return Path.Combine(AppContext.BaseDirectory, $"lib/{_env}/arm64/{libName}.dylib");
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ return Path.Combine(AppContext.BaseDirectory, $"lib/{_env}/{PvLinuxMachine()}/{libName}.so");
+ }
+ else
+ {
+ throw new PlatformNotSupportedException($"{RuntimeInformation.OSDescription} ({RuntimeInformation.OSArchitecture}) is not currently supported.");
+ }
+ }
+
+ public static string PvLinuxMachine()
+ {
+ string archInfo = "";
+ if (_arch == Architecture.X64)
+ return "x86_64";
+ else if (_arch == Architecture.Arm64)
+ archInfo = "-aarch64";
+
+ string cpuPart = GetCpuPart();
+ switch (cpuPart)
+ {
+ case "0xd03": return "cortex-a53" + archInfo;
+ case "0xd08": return "cortex-a72" + archInfo;
+ case "0xd0b": return "cortex-a76" + archInfo;
+ default:
+ throw new PlatformNotSupportedException($"This device (CPU part = {cpuPart}) is not supported by Picovoice.");
+ }
+ }
+
+ public static string PvLinuxEnv()
+ {
+ string cpuPart = GetCpuPart();
+ switch (cpuPart)
+ {
+ case "0xd03":
+ case "0xd08":
+ case "0xd0b": return "raspberry-pi";
+ default:
+ throw new PlatformNotSupportedException($"This device (CPU part = {cpuPart}) is not supported by Picovoice.");
+ }
+ }
+
+ public static IntPtr GetPtrFromUtf8String(string s)
+ {
+ byte[] utf8Bytes = Encoding.UTF8.GetBytes(s + '\0');
+ IntPtr p = Marshal.AllocHGlobal(utf8Bytes.Length);
+ Marshal.Copy(utf8Bytes, 0, p, utf8Bytes.Length);
+
+ return p;
+ }
+
+ public static string GetUtf8StringFromPtr(IntPtr p)
+ {
+ int i = 0;
+ List data = new List();
+ while (true)
+ {
+ byte b = Marshal.ReadByte(p, i++);
+ if (b == 0)
+ {
+ break;
+ }
+ data.Add(b);
+ }
+
+ return Encoding.UTF8.GetString(data.ToArray());
+ }
+
+ private static string GetCpuPart()
+ {
+ string cpuInfo = File.ReadAllText("/proc/cpuinfo");
+ string[] cpuPartList = cpuInfo.Split('\n').Where(x => x.Contains("CPU part")).ToArray();
+ if (cpuPartList.Length == 0)
+ throw new PlatformNotSupportedException($"Unsupported CPU.\n{cpuInfo}");
+
+ string cpuPart = cpuPartList[0].Split(' ').Last().ToLower();
+ return cpuPart;
+ }
+ }
+}
\ No newline at end of file
diff --git a/binding/dotnet/PvRecorderTest/PvRecorderTest.csproj b/binding/dotnet/PvRecorderTest/PvRecorderTest.csproj
index 1e0075f2..df8fd17c 100644
--- a/binding/dotnet/PvRecorderTest/PvRecorderTest.csproj
+++ b/binding/dotnet/PvRecorderTest/PvRecorderTest.csproj
@@ -6,8 +6,8 @@
-
-
+
+
diff --git a/binding/dotnet/README.md b/binding/dotnet/README.md
index 6a0e30b5..c4296710 100644
--- a/binding/dotnet/README.md
+++ b/binding/dotnet/README.md
@@ -1,6 +1,6 @@
# PvRecorder Binding for .NET
-# PvRecorder
+## PvRecorder
PvRecorder is an easy-to-use, cross-platform audio recorder designed for real-time speech audio processing. It allows developers access to an audio device's input stream, broken up into data frames of a given size.
@@ -16,19 +16,18 @@ Platform compatible with .NET Framework 4.6.1+:
Platforms compatible with .NET Core 2.0+:
-- Linux (x86_64)
- macOS (x86_64)
- Windows (x86_64)
-Platforms compatible with .NET Core 3.0+:
+Platform compatible with .NET 6.0+:
- Raspberry Pi:
- 3 (32 and 64 bit)
- 4 (32 and 64 bit)
- 5 (32 and 64 bit)
-Platform compatible with .NET 6.0+:
-
+- Linux (x86_64)
+- Windows (arm64)
- macOS (arm64)
## Installation
diff --git a/binding/go/README.md b/binding/go/README.md
index 24a608e2..d5679666 100644
--- a/binding/go/README.md
+++ b/binding/go/README.md
@@ -7,7 +7,7 @@ PvRecorder is an easy-to-use, cross-platform audio recorder designed for real-ti
## Compatibility
- Go 1.16+
-- Runs on Linux (x86_64), macOS (x86_64 and arm64), Windows (x86_64), and Raspberry Pi (Zero, 3, 4, 5).
+- Runs on Linux (x86_64), macOS (x86_64 and arm64), Windows (x86_64 and arm64), and Raspberry Pi (Zero, 3, 4, 5).
## Installation
diff --git a/binding/go/copy.sh b/binding/go/copy.sh
index 2f44e479..f129c1db 100755
--- a/binding/go/copy.sh
+++ b/binding/go/copy.sh
@@ -8,6 +8,7 @@ cp ../../lib/linux/x86_64/libpv_recorder.so ./embedded/lib/linux/x86_64/libpv_re
echo "Copying Windows lib..."
cp ../../lib/windows/amd64/libpv_recorder.dll ./embedded/lib/windows/amd64/libpv_recorder.dll
+cp ../../lib/windows/arm64/libpv_recorder.dll ./embedded/lib/windows/arm64/libpv_recorder.dll
echo "Copying macOS lib..."
cp ../../lib/mac/x86_64/libpv_recorder.dylib ./embedded/lib/mac/x86_64/libpv_recorder.dylib
diff --git a/binding/go/embedded/lib/windows/arm64/libpv_recorder.dll b/binding/go/embedded/lib/windows/arm64/libpv_recorder.dll
new file mode 100644
index 00000000..1201138b
Binary files /dev/null and b/binding/go/embedded/lib/windows/arm64/libpv_recorder.dll differ
diff --git a/binding/go/pv_recorder.go b/binding/go/pv_recorder.go
index 0e017820..480e92c3 100644
--- a/binding/go/pv_recorder.go
+++ b/binding/go/pv_recorder.go
@@ -1,4 +1,4 @@
-// Copyright 2021-2023 Picovoice Inc.
+// Copyright 2021-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.
@@ -115,6 +115,9 @@ type nativePvRecorderType struct{}
// private vars
var (
+ osName, cpu = getOS()
+ extractionDir = filepath.Join(os.TempDir(), "cheetah")
+
libName = extractLib()
nativePvRecorder = nativePvRecorderType{}
)
@@ -229,54 +232,95 @@ func GetAvailableDevices() ([]string, error) {
return deviceNames, nil
}
-func extractLib() string {
- extractionDir := filepath.Join(os.TempDir(), "pvRecorder")
+func getOS() (string, string) {
+ switch os := runtime.GOOS; os {
+ case "darwin":
+ return "mac", getMacArch()
+ case "linux":
+ osName, cpu := getLinuxDetails()
+ return osName, cpu
+ case "windows":
+ return "windows", getWinArch()
+ default:
+ log.Fatalf("%s is not a supported OS", os)
+ return "", ""
+ }
+}
- var scriptPath string
- if runtime.GOOS == "windows" {
- scriptPath = "embedded/scripts/platform.bat"
+func getMacArch() string {
+ if runtime.GOARCH == "arm64" {
+ return "arm64"
} else {
- scriptPath = "embedded/scripts/platform.sh"
+ return "x86_64"
}
+}
- script := extractFile(scriptPath, extractionDir)
- cmd := exec.Command(script)
- stdout, err := cmd.Output()
+func getWinArch() string {
+ if runtime.GOARCH == "arm64" {
+ return "arm64"
+ } else {
+ return "amd64"
+ }
+}
+
+func getLinuxDetails() (string, string) {
+ var archInfo = ""
+
+ if runtime.GOARCH == "amd64" {
+ return "linux", "x86_64"
+ } else if runtime.GOARCH == "arm64" {
+ archInfo = "-aarch64"
+ }
+
+ cmd := exec.Command("cat", "/proc/cpuinfo")
+ cpuInfo, err := cmd.Output()
if err != nil {
- log.Fatal("System is not supported.")
+ log.Fatalf("Failed to get CPU details: %s", err.Error())
}
- systemInfo := strings.Split(string(stdout), " ")
- osName := systemInfo[0]
- cpu := systemInfo[1]
-
- libFile := "libpv_recorder"
- if runtime.GOOS == "windows" {
- libFile += ".dll"
- } else if runtime.GOOS == "darwin" {
- libFile += ".dylib"
- } else if runtime.GOOS == "linux" {
- libFile += ".so"
- } else {
- log.Fatalf("OS: %s is not supported.", runtime.GOOS)
+ var cpuPart = ""
+ for _, line := range strings.Split(string(cpuInfo), "\n") {
+ if strings.Contains(line, "CPU part") {
+ split := strings.Split(line, " ")
+ cpuPart = strings.ToLower(split[len(split)-1])
+ break
+ }
}
- var srcPath string
- if cpu == "" {
- srcPath = fmt.Sprintf("embedded/lib/%s/%s", osName, libFile)
- } else {
- srcPath = fmt.Sprintf("embedded/lib/%s/%s/%s", osName, cpu, libFile)
+ switch cpuPart {
+ case "0xb76":
+ return "raspberry-pi", "arm11" + archInfo
+ case "0xd03":
+ return "raspberry-pi", "cortex-a53" + archInfo
+ case "0xd08":
+ return "raspberry-pi", "cortex-a72" + archInfo
+ case "0xd0b":
+ return "raspberry-pi", "cortex-a76" + archInfo
+ default:
+ log.Fatalf("Unsupported CPU:\n%s", cpuPart)
+ return "", ""
}
+}
- srcHash := sha256sum(srcPath)
- hashedExtractionDir := filepath.Join(extractionDir, srcHash)
- destPath := filepath.Join(hashedExtractionDir, srcPath)
- if _, err := os.Stat(destPath); errors.Is(err, os.ErrNotExist) {
- return extractFile(srcPath, hashedExtractionDir)
- } else {
- return destPath
+func extractLib() string {
+ var libPath string
+ switch os := runtime.GOOS; os {
+ case "darwin":
+ libPath = fmt.Sprintf("embedded/lib/%s/%s/libpv_cheetah.dylib", osName, cpu)
+ case "linux":
+ if cpu == "" {
+ libPath = fmt.Sprintf("embedded/lib/%s/libpv_cheetah.so", osName)
+ } else {
+ libPath = fmt.Sprintf("embedded/lib/%s/%s/libpv_cheetah.so", osName, cpu)
+ }
+ case "windows":
+ libPath = fmt.Sprintf("embedded/lib/%s/amd64/libpv_cheetah.dll", osName)
+ default:
+ log.Fatalf("%s is not a supported OS", os)
}
+
+ return extractFile(libPath, extractionDir)
}
func extractFile(srcFile string, dstDir string) string {
diff --git a/binding/nodejs/README.md b/binding/nodejs/README.md
index 4fbd5afe..542a8723 100644
--- a/binding/nodejs/README.md
+++ b/binding/nodejs/README.md
@@ -7,7 +7,7 @@ PvRecorder is an easy-to-use, cross-platform audio recorder designed for real-ti
## Compatibility
- Node.js 14+
-- Runs on Linux (x86_64), macOS (x86_64 and arm64), Windows (x86_64), and Raspberry Pi (3, 4, 5).
+- Runs on Linux (x86_64), macOS (x86_64 and arm64), Windows (x86_64 and arm64), and Raspberry Pi (3, 4, 5).
## Installation
diff --git a/binding/nodejs/copy.js b/binding/nodejs/copy.js
index d11b37f6..83e930f3 100644
--- a/binding/nodejs/copy.js
+++ b/binding/nodejs/copy.js
@@ -25,17 +25,3 @@ ncp(
console.log("Successfully copied library.");
}
)
-
-console.log("Copying scripts...");
-
-// Scripts
-ncp(
- "../../resources/scripts",
- "./scripts",
- function (err) {
- if (err) {
- return console.error(err);
- }
- console.log("Successfully copied scripts.")
- }
-)
diff --git a/binding/nodejs/package.json b/binding/nodejs/package.json
index 3b5a43f8..4ef1ac8e 100644
--- a/binding/nodejs/package.json
+++ b/binding/nodejs/package.json
@@ -1,6 +1,6 @@
{
"name": "@picovoice/pvrecorder-node",
- "version": "1.2.4",
+ "version": "1.2.5",
"description": "Audio recorder sdk for Nodejs.",
"main": "dist/index.js",
"types": "dist/types",
diff --git a/binding/nodejs/src/platforms.ts b/binding/nodejs/src/platforms.ts
new file mode 100644
index 00000000..d72eec11
--- /dev/null
+++ b/binding/nodejs/src/platforms.ts
@@ -0,0 +1,211 @@
+//
+// Copyright 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.
+//
+'use strict';
+
+import * as fs from 'fs';
+import * as os from 'os';
+import * as path from 'path';
+
+const SYSTEM_LINUX = 'linux';
+const SYSTEM_MAC = 'darwin';
+const SYSTEM_WINDOWS = 'win32';
+
+const X86_64 = 'x64';
+const ARM_32 = 'arm';
+const ARM_64 = 'arm64';
+
+const PLATFORM_LINUX = 'linux';
+const PLATFORM_MAC = 'mac';
+const PLATFORM_RASPBERRY_PI = 'raspberry-pi';
+const PLATFORM_WINDOWS = 'windows';
+
+const ARM_CPU_64 = '-aarch64';
+const ARM_CPU_CORTEX_A53 = 'cortex-a53';
+const ARM_CPU_CORTEX_A72 = 'cortex-a72';
+const ARM_CPU_CORTEX_A76 = 'cortex-a76';
+
+const SUPPORTED_NODEJS_SYSTEMS = new Set([
+ SYSTEM_LINUX,
+ SYSTEM_MAC,
+ SYSTEM_WINDOWS,
+]);
+
+const LIBRARY_PATH_PREFIX = '../lib/';
+const SYSTEM_TO_LIBRARY_PATH = new Map();
+SYSTEM_TO_LIBRARY_PATH.set(
+ `${SYSTEM_MAC}/${X86_64}`,
+ `${PLATFORM_MAC}/x86_64/pv_recorder.node`,
+);
+SYSTEM_TO_LIBRARY_PATH.set(
+ `${SYSTEM_MAC}/${ARM_64}`,
+ `${PLATFORM_MAC}/arm64/pv_recorder.node`,
+);
+SYSTEM_TO_LIBRARY_PATH.set(
+ `${SYSTEM_LINUX}/${X86_64}`,
+ `${PLATFORM_LINUX}/x86_64/pv_recorder.node`,
+);
+SYSTEM_TO_LIBRARY_PATH.set(
+ `${SYSTEM_LINUX}/${ARM_CPU_CORTEX_A53}`,
+ `${PLATFORM_RASPBERRY_PI}/${ARM_CPU_CORTEX_A53}/pv_recorder.node`,
+);
+SYSTEM_TO_LIBRARY_PATH.set(
+ `${SYSTEM_LINUX}/${ARM_CPU_CORTEX_A53}${ARM_CPU_64}`,
+ `${PLATFORM_RASPBERRY_PI}/${ARM_CPU_CORTEX_A53}${ARM_CPU_64}/pv_recorder.node`,
+);
+SYSTEM_TO_LIBRARY_PATH.set(
+ `${SYSTEM_LINUX}/${ARM_CPU_CORTEX_A72}`,
+ `${PLATFORM_RASPBERRY_PI}/${ARM_CPU_CORTEX_A72}/pv_recorder.node`,
+);
+SYSTEM_TO_LIBRARY_PATH.set(
+ `${SYSTEM_LINUX}/${ARM_CPU_CORTEX_A72}${ARM_CPU_64}`,
+ `${PLATFORM_RASPBERRY_PI}/${ARM_CPU_CORTEX_A72}${ARM_CPU_64}/pv_recorder.node`,
+);
+SYSTEM_TO_LIBRARY_PATH.set(
+ `${SYSTEM_LINUX}/${ARM_CPU_CORTEX_A76}`,
+ `${PLATFORM_RASPBERRY_PI}/${ARM_CPU_CORTEX_A76}/pv_recorder.node`,
+);
+SYSTEM_TO_LIBRARY_PATH.set(
+ `${SYSTEM_LINUX}/${ARM_CPU_CORTEX_A76}${ARM_CPU_64}`,
+ `${PLATFORM_RASPBERRY_PI}/${ARM_CPU_CORTEX_A76}${ARM_CPU_64}/pv_recorder.node`,
+);
+SYSTEM_TO_LIBRARY_PATH.set(
+ `${SYSTEM_WINDOWS}/${X86_64}`,
+ `${PLATFORM_WINDOWS}/amd64/pv_recorder.node`,
+);
+SYSTEM_TO_LIBRARY_PATH.set(
+ `${SYSTEM_WINDOWS}/${ARM_64}`,
+ `${PLATFORM_WINDOWS}/arm64/pv_recorder.node`,
+);
+
+function absoluteLibraryPath(libraryPath: string): string {
+ return path.resolve(__dirname, LIBRARY_PATH_PREFIX, libraryPath);
+}
+
+function getCpuPart(): string {
+ const cpuInfo = fs.readFileSync('/proc/cpuinfo', 'ascii');
+ for (const infoLine of cpuInfo.split('\n')) {
+ if (infoLine.includes('CPU part')) {
+ const infoLineSplit = infoLine.split(' ');
+ return infoLineSplit[infoLineSplit.length - 1].toLowerCase();
+ }
+ }
+ throw new Error(`Unsupported CPU.`);
+}
+
+function getLinuxPlatform(): string {
+ const cpuPart = getCpuPart();
+ switch (cpuPart) {
+ case '0xd03':
+ case '0xd08':
+ case '0xd0b':
+ return PLATFORM_RASPBERRY_PI;
+ default:
+ throw new Error(`Unsupported CPU: '${cpuPart}'`);
+ }
+}
+
+function getLinuxMachine(arch: string): string {
+ let archInfo = '';
+ if (arch === ARM_64) {
+ archInfo = ARM_CPU_64;
+ }
+
+ const cpuPart = getCpuPart();
+ switch (cpuPart) {
+ case '0xd03':
+ return ARM_CPU_CORTEX_A53 + archInfo;
+ case '0xd08':
+ return ARM_CPU_CORTEX_A72 + archInfo;
+ case '0xd0b':
+ return ARM_CPU_CORTEX_A76 + archInfo;
+ default:
+ throw new Error(`Unsupported CPU: '${cpuPart}'`);
+ }
+}
+
+export function getPlatform(): string {
+ const system = os.platform();
+ const arch = os.arch();
+
+ if (system === SYSTEM_MAC && (arch === X86_64 || arch === ARM_64)) {
+ return PLATFORM_MAC;
+ }
+
+ if (system === SYSTEM_WINDOWS && (arch === X86_64 || arch === ARM_64)) {
+ return PLATFORM_WINDOWS;
+ }
+
+ if (system === SYSTEM_LINUX) {
+ if (arch === X86_64) {
+ return PLATFORM_LINUX;
+ }
+ return getLinuxPlatform();
+ }
+
+ throw `System ${system}/${arch} is not supported by this library.`;
+}
+
+export function getSystemLibraryPath(): string {
+ const system = os.platform();
+ const arch = os.arch();
+
+ if (SUPPORTED_NODEJS_SYSTEMS.has(system)) {
+ switch (system) {
+ case SYSTEM_MAC: {
+ if (arch === X86_64) {
+ return absoluteLibraryPath(
+ SYSTEM_TO_LIBRARY_PATH.get(`${SYSTEM_MAC}/${X86_64}`),
+ );
+ } else if (arch === ARM_64) {
+ return absoluteLibraryPath(
+ SYSTEM_TO_LIBRARY_PATH.get(`${SYSTEM_MAC}/${ARM_64}`),
+ );
+ }
+ break;
+ }
+ case SYSTEM_LINUX: {
+ if (arch === X86_64) {
+ return absoluteLibraryPath(
+ SYSTEM_TO_LIBRARY_PATH.get(`${SYSTEM_LINUX}/${X86_64}`),
+ );
+ } else if (arch === ARM_32 || arch === ARM_64) {
+ const linuxMachine = getLinuxMachine(arch);
+ if (linuxMachine !== null) {
+ return absoluteLibraryPath(
+ SYSTEM_TO_LIBRARY_PATH.get(`${SYSTEM_LINUX}/${linuxMachine}`),
+ );
+ }
+ throw new Error(
+ `System ${system}/${arch} is not supported by this library for this CPU.`,
+ );
+ }
+ break;
+ }
+ case SYSTEM_WINDOWS: {
+ if (arch === X86_64 || arch === ARM_64) {
+ return absoluteLibraryPath(
+ SYSTEM_TO_LIBRARY_PATH.get(`${SYSTEM_WINDOWS}/${arch}`),
+ );
+ }
+ break;
+ }
+ default: {
+ throw new Error(
+ `System ${system}/${arch} is not supported by this library.`,
+ );
+ }
+ }
+ }
+
+ throw new Error(
+ `System ${system}/${arch} is not supported by this library.`,
+ );
+}
diff --git a/binding/nodejs/src/pv_recorder.ts b/binding/nodejs/src/pv_recorder.ts
index 98598f3f..e52e89c7 100644
--- a/binding/nodejs/src/pv_recorder.ts
+++ b/binding/nodejs/src/pv_recorder.ts
@@ -16,13 +16,14 @@ import * as path from "path";
import PvRecorderStatus from "./pv_recorder_status_t";
import pvRecorderStatusToException from "./errors";
+import { getSystemLibraryPath } from './platforms';
/**
* PvRecorder class for recording audio.
*/
class PvRecorder {
// eslint-disable-next-line
- private static _pvRecorder = require(PvRecorder._getLibraryPath());
+ private static _pvRecorder = require(getSystemLibraryPath());
private readonly _handle: number;
private readonly _frameLength: number;
@@ -181,20 +182,6 @@ class PvRecorder {
}
return devices;
}
-
- private static _getLibraryPath(): string {
- let scriptPath;
- if (os.platform() === "win32") {
- scriptPath = path.resolve(__dirname, "..", "scripts", "platform.bat");
- } else {
- scriptPath = path.resolve(__dirname, "..", "scripts", "platform.sh");
- }
-
- const output = execSync(`"${scriptPath}"`).toString();
- const [osName, cpu] = output.split(" ");
-
- return path.resolve(__dirname, "..", "lib", osName, cpu, "pv_recorder.node");
- }
}
export default PvRecorder;
diff --git a/binding/python/README.md b/binding/python/README.md
index 5359cdb9..a50b2277 100644
--- a/binding/python/README.md
+++ b/binding/python/README.md
@@ -7,7 +7,7 @@ PvRecorder is an easy-to-use, cross-platform audio recorder designed for real-ti
## Compatibility
- Python 3.8+
-- Runs on Linux (x86_64), macOS (x86_64 and arm64), Windows (x86_64), and Raspberry Pi (Zero, 3, 4, 5).
+- Runs on Linux (x86_64), macOS (x86_64 and arm64), Windows (x86_64 and arm64), and Raspberry Pi (Zero, 3, 4, 5).
## Installation
diff --git a/binding/python/_pvrecorder.py b/binding/python/_pvrecorder.py
index ee90e4b1..da43c36d 100644
--- a/binding/python/_pvrecorder.py
+++ b/binding/python/_pvrecorder.py
@@ -1,5 +1,5 @@
#
-# Copyright 2021-2023 Picovoice Inc.
+# Copyright 2021-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.
@@ -18,29 +18,64 @@
CALLBACK = CFUNCTYPE(None, POINTER(c_int16))
-
-def default_library_path(relative: str = ''):
- """A helper function to get the library path."""
-
- if platform.system() == "Windows":
- script_path = os.path.join(os.path.dirname(__file__), relative, "resources", "scripts", "platform.bat")
+_RASPBERRY_PI_MACHINES = {
+ "cortex-a53",
+ "cortex-a72",
+ "cortex-a76",
+ "cortex-a53-aarch64",
+ "cortex-a72-aarch64",
+ "cortex-a76-aarch64",
+}
+
+
+def _linux_machine() -> str:
+ machine = platform.machine()
+ if machine == "x86_64":
+ return machine
+ elif machine in ["aarch64", "armv7l"]:
+ arch_info = ("-" + machine) if '64bit' in platform.architecture()[0] else ""
else:
- script_path = os.path.join(os.path.dirname(__file__), relative, "resources", "scripts", "platform.sh")
-
- command = subprocess.run(script_path, stdout=subprocess.PIPE)
-
- if command.returncode != 0:
- raise RuntimeError("Current system is not supported.")
- os_name, cpu = str(command.stdout.decode("utf-8")).split(" ")
-
- if os_name == "windows":
- extension = "dll"
- elif os_name == "mac":
- extension = "dylib"
+ raise NotImplementedError("Unsupported CPU architecture: `%s`" % machine)
+
+ cpu_info = ""
+ try:
+ cpu_info = subprocess.check_output(["cat", "/proc/cpuinfo"]).decode("utf-8")
+ cpu_part_list = [x for x in cpu_info.split("\n") if "CPU part" in x]
+ cpu_part = cpu_part_list[0].split(" ")[-1].lower()
+ except Exception as e:
+ raise RuntimeError("Failed to identify the CPU with `%s`\nCPU info: `%s`" % (e, cpu_info))
+
+ if "0xd03" == cpu_part:
+ return "cortex-a53" + arch_info
+ elif "0xd08" == cpu_part:
+ return "cortex-a72" + arch_info
+ elif "0xd0b" == cpu_part:
+ return "cortex-a76" + arch_info
else:
- extension = "so"
+ raise NotImplementedError("Unsupported CPU: `%s`." % cpu_part)
+
- return os.path.join(os.path.dirname(__file__), relative, "lib", os_name, cpu, "libpv_recorder.%s" % extension)
+def default_library_path(relative: str = ''):
+ """A helper function to get the library path."""
+ if platform.system() == "Darwin":
+ if platform.machine() == "x86_64":
+ return os.path.join(os.path.dirname(__file__), relative, "lib/mac/x86_64/libpv_recorder.dylib")
+ elif platform.machine() == "arm64":
+ return os.path.join(os.path.dirname(__file__), relative, "lib/mac/arm64/libpv_recorder.dylib")
+ elif platform.system() == "Linux":
+ linux_machine = _linux_machine()
+ if linux_machine == "x86_64":
+ return os.path.join(os.path.dirname(__file__), relative, "lib/linux/x86_64/libpv_recorder.so")
+ elif linux_machine in _RASPBERRY_PI_MACHINES:
+ return os.path.join(
+ os.path.dirname(__file__), relative, "lib/raspberry-pi/%s/libpv_recorder.so" % linux_machine)
+ elif platform.system() == "Windows":
+ if platform.machine().lower() == "amd64":
+ return os.path.join(os.path.dirname(__file__), relative, "lib/windows/amd64/libpv_recorder.dll")
+ elif platform.machine().lower() == "arm64":
+ return os.path.join(os.path.dirname(__file__), relative, "lib/windows/arm64/libpv_recorder.dll")
+
+ raise NotImplementedError("Unsupported platform.")
class PvRecorder(object):
diff --git a/binding/python/setup.py b/binding/python/setup.py
index 3af1dc9f..6ff282ef 100644
--- a/binding/python/setup.py
+++ b/binding/python/setup.py
@@ -1,5 +1,5 @@
#
-# Copyright 2021-2024 Picovoice Inc.
+# Copyright 2021-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.
@@ -24,10 +24,6 @@
shutil.copy(os.path.join(os.path.dirname(__file__), '__init__.py'), os.path.join(package_folder, '__init__.py'))
shutil.copy(os.path.join(os.path.dirname(__file__), '_pvrecorder.py'), os.path.join(package_folder, '_pvrecorder.py'))
-shutil.copytree(
- os.path.join(os.path.dirname(__file__), '../../resources/scripts'),
- os.path.join(package_folder, 'resources/scripts'))
-
platforms = ('linux', 'mac', 'raspberry-pi', 'windows')
os.mkdir(os.path.join(package_folder, 'lib'))
@@ -45,6 +41,7 @@
include pvrecorder/lib/mac/arm64/libpv_recorder.dylib
recursive-include pvrecorder/lib/raspberry-pi *
include pvrecorder/lib/windows/amd64/libpv_recorder.dll
+include pvrecorder/lib/windows/arm64/libpv_recorder.dll
recursive-include pvrecorder/resources/scripts *
"""
@@ -56,7 +53,7 @@
setuptools.setup(
name="pvrecorder",
- version="1.2.3",
+ version="1.2.4",
author="Picovoice",
author_email="hello@picovoice.ai",
description="Recorder library for Picovoice.",
diff --git a/binding/rust/Cargo.toml b/binding/rust/Cargo.toml
index 8c589198..114001de 100644
--- a/binding/rust/Cargo.toml
+++ b/binding/rust/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "pv_recorder"
-version = "1.2.3"
+version = "1.2.4"
edition = "2018"
description = "Rust recorder library for Picovoice"
license = "Apache-2.0"
@@ -22,7 +22,7 @@ include = [
[lib]
name = "pv_recorder"
path = "src/lib.rs"
-crate_type = ["lib"]
+crate-type = ["lib"]
[dependencies]
libc = "0.2"
diff --git a/binding/rust/README.md b/binding/rust/README.md
index bda838f0..b8e0f296 100644
--- a/binding/rust/README.md
+++ b/binding/rust/README.md
@@ -12,7 +12,7 @@ PvRecorder is an easy-to-use, cross-platform audio recorder designed for real-ti
- Linux (x86_64)
- macOS (x86_64 and arm64)
-- Windows (x86_64)
+- Windows (x86_64 and arm64)
- Raspberry Pi:
- Zero
- 3 (32 and 64 bit)
diff --git a/binding/rust/src/util.rs b/binding/rust/src/util.rs
index 567daf75..b88740f5 100644
--- a/binding/rust/src/util.rs
+++ b/binding/rust/src/util.rs
@@ -1,5 +1,5 @@
/*
- Copyright 2021-2024 Picovoice Inc.
+ Copyright 2021-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.
@@ -59,11 +59,16 @@ fn base_library_path() -> PathBuf {
PathBuf::from("mac/arm64/libpv_recorder.dylib")
}
-#[cfg(target_os = "windows")]
+#[cfg(all(target_os = "windows", target_arch = "x86_64"))]
fn base_library_path() -> PathBuf {
PathBuf::from("windows/amd64/libpv_recorder.dll")
}
+#[cfg(all(target_os = "windows", target_arch = "aarch64"))]
+fn base_library_path() -> PathBuf {
+ PathBuf::from("windows/arm64/libpv_recorder.dll")
+}
+
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
fn base_library_path() -> PathBuf {
PathBuf::from("linux/x86_64/libpv_recorder.so")
diff --git a/demo/c/CMakeLists.txt b/demo/c/CMakeLists.txt
index b136de31..91693050 100644
--- a/demo/c/CMakeLists.txt
+++ b/demo/c/CMakeLists.txt
@@ -3,9 +3,9 @@ project(pv_recorder_demo VERSION 1.2.0 DESCRIPTION "Picovoice audio recorder lib
if(NOT PV_RECORDER_PLATFORM)
message(FATAL_ERROR "No `PV_RECORDER_PLATFORM` value was given. Valid platforms are: \n"
- "linux, mac-arm64, mac-x86_64, windows, raspberry-pi, raspberry-pi3-32, "
- "raspberry-pi3-64, raspberry-pi4-32, raspberry-pi4-64, raspberry-pi5-32, "
- "raspberry-pi5-64")
+ "linux, mac-arm64, mac-x86_64, windows-amd64, windows-arm64, "
+ "raspberry-pi, raspberry-pi3-32, raspberry-pi3-64, "
+ "raspberry-pi4-32, raspberry-pi4-64, raspberry-pi5-32, raspberry-pi5-64")
endif()
if (${PV_RECORDER_PLATFORM} STREQUAL "mac-arm64")
@@ -28,8 +28,10 @@ elseif (${PV_RECORDER_PLATFORM} STREQUAL "raspberry-pi5")
set(PV_RECORDER_LIB_DIR ${CMAKE_SOURCE_DIR}/../../lib/raspberry-pi/cortex-a76)
elseif (${PV_RECORDER_PLATFORM} STREQUAL "raspberry-pi5-64")
set(PV_RECORDER_LIB_DIR ${CMAKE_SOURCE_DIR}/../../lib/raspberry-pi/cortex-a76-aarch64)
-elseif (${PV_RECORDER_PLATFORM} STREQUAL "windows")
+elseif (${PV_RECORDER_PLATFORM} STREQUAL "windows-amd64")
set(PV_RECORDER_LIB_DIR ${CMAKE_SOURCE_DIR}/../../lib/windows/amd64)
+elseif (${PV_RECORDER_PLATFORM} STREQUAL "windows-arm64")
+ set(PV_RECORDER_LIB_DIR ${CMAKE_SOURCE_DIR}/../../lib/windows/arm64)
else ()
message(FATAL_ERROR "Unknown platform `${PV_RECORDER_PLATFORM}`.")
endif ()
diff --git a/demo/c/README.md b/demo/c/README.md
index 9e2ad382..f2feb039 100644
--- a/demo/c/README.md
+++ b/demo/c/README.md
@@ -16,7 +16,7 @@ PvRecorder is an easy-to-use, cross-platform audio recorder designed for real-ti
- Linux (x86_64)
- macOS (x86_64, arm64)
-- Windows (amd64)
+- Windows (amd64, arm64)
- Raspberry Pi (Zero, 3, 4, 5)
## Compiling
diff --git a/demo/dotnet/PvRecorderDemo/PvRecorderDemo.csproj b/demo/dotnet/PvRecorderDemo/PvRecorderDemo.csproj
index aa486930..59792f4d 100644
--- a/demo/dotnet/PvRecorderDemo/PvRecorderDemo.csproj
+++ b/demo/dotnet/PvRecorderDemo/PvRecorderDemo.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/demo/dotnet/README.md b/demo/dotnet/README.md
index 60f7b3ab..656b3b68 100644
--- a/demo/dotnet/README.md
+++ b/demo/dotnet/README.md
@@ -14,7 +14,7 @@ PvRecorder is an easy-to-use, cross-platform audio recorder designed for real-ti
- Linux (x86_64)
- macOS (x86_64, arm64)
-- Windows (x86_64)
+- Windows (x86_64, arm64)
- Raspberry Pi:
- 3 (32 and 64 bit)
- 4 (32 and 64 bit)
diff --git a/demo/go/README.md b/demo/go/README.md
index b38d7d45..36931b40 100644
--- a/demo/go/README.md
+++ b/demo/go/README.md
@@ -9,7 +9,7 @@ PvRecorder is an easy-to-use, cross-platform audio recorder designed for real-ti
## Compatibility
- Go 1.16+
-- Runs on Linux (x86_64), macOS (x86_64 and arm64), Windows (x86_64), and Raspberry Pi (Zero, 3, 4, 5).
+- Runs on Linux (x86_64), macOS (x86_64 and arm64), Windows (x86_64 and arm64), and Raspberry Pi (Zero, 3, 4, 5).
- **Windows**: The demo requires `cgo`, which means that you need to install a gcc compiler like [Mingw](http://mingw-w64.org/) to build it properly.
## Usage
diff --git a/demo/go/go.mod b/demo/go/go.mod
index bc9ac102..d86947f9 100644
--- a/demo/go/go.mod
+++ b/demo/go/go.mod
@@ -3,6 +3,6 @@ module pvrecorderdemo
go 1.16
require (
- github.com/Picovoice/pvrecorder/binding/go v1.2.3
+ github.com/Picovoice/pvrecorder/binding/go v1.2.4
github.com/go-audio/wav v1.0.0
)
diff --git a/demo/go/go.sum b/demo/go/go.sum
index f15f8c0f..50bc19f7 100644
--- a/demo/go/go.sum
+++ b/demo/go/go.sum
@@ -4,6 +4,10 @@ github.com/Picovoice/pvrecorder/binding/go v1.2.2 h1:UN0u60hVR+s8kYmVSITS4UbTihH
github.com/Picovoice/pvrecorder/binding/go v1.2.2/go.mod h1:gQdvBAjoKmRxMFh8W9cVKWcqHsWvu+d13sCPVFm7dhg=
github.com/Picovoice/pvrecorder/binding/go v1.2.3 h1:VU9cf4g3h7pazecoEsPINi21AHWgxIsn7jFWdRDpWZE=
github.com/Picovoice/pvrecorder/binding/go v1.2.3/go.mod h1:gQdvBAjoKmRxMFh8W9cVKWcqHsWvu+d13sCPVFm7dhg=
+github.com/Picovoice/pvrecorder/binding/go v1.2.4-0.20250114211217-3fe4c8533d85 h1:ASmJdY0qAFa1J/ETqAM8tjkwEieJTa1KBt0JS7vTSTg=
+github.com/Picovoice/pvrecorder/binding/go v1.2.4-0.20250114211217-3fe4c8533d85/go.mod h1:gQdvBAjoKmRxMFh8W9cVKWcqHsWvu+d13sCPVFm7dhg=
+github.com/Picovoice/pvrecorder/binding/go v1.2.4 h1:e98xV0Vj30Jo+ut/a68Fev2h1gU4+cOaHY2NdLws10s=
+github.com/Picovoice/pvrecorder/binding/go v1.2.4/go.mod h1:gQdvBAjoKmRxMFh8W9cVKWcqHsWvu+d13sCPVFm7dhg=
github.com/go-audio/audio v1.0.0 h1:zS9vebldgbQqktK4H0lUqWrG8P0NxCJVqcj7ZpNnwd4=
github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs=
github.com/go-audio/riff v1.0.0 h1:d8iCGbDvox9BfLagY94fBynxSPHO80LmZCaOsmKxokA=
diff --git a/demo/nodejs/README.md b/demo/nodejs/README.md
index 72d589b1..a049b0f4 100644
--- a/demo/nodejs/README.md
+++ b/demo/nodejs/README.md
@@ -9,7 +9,7 @@ PvRecorder is an easy-to-use, cross-platform audio recorder designed for real-ti
## Compatibility
- Node.js 14+
-- Runs on Linux (x86_64), macOS (x86_64 and arm64), Windows (x86_64), and Raspberry Pi (3, 4, 5).
+- Runs on Linux (x86_64), macOS (x86_64 and arm64), Windows (x86_64 and arm64), and Raspberry Pi (3, 4, 5).
## Installation:
diff --git a/demo/nodejs/package.json b/demo/nodejs/package.json
index 37fad21a..b3b0b477 100644
--- a/demo/nodejs/package.json
+++ b/demo/nodejs/package.json
@@ -1,6 +1,6 @@
{
"name": "@picovoice/pvrecorder-node-demo",
- "version": "1.2.4",
+ "version": "1.2.5",
"description": "Picovoice PvRecorder demo",
"scripts": {
"demo": "node demo.js"
@@ -14,7 +14,7 @@
"author": "Picovoice, Inc.",
"license": "Apache-2.0",
"dependencies": {
- "@picovoice/pvrecorder-node": "~1.2.4",
+ "@picovoice/pvrecorder-node": "=1.2.5",
"commander": "^6.1.0",
"wavefile": "^11.0.0"
},
diff --git a/demo/nodejs/yarn.lock b/demo/nodejs/yarn.lock
index 25624eb6..59e9b91b 100644
--- a/demo/nodejs/yarn.lock
+++ b/demo/nodejs/yarn.lock
@@ -2,10 +2,10 @@
# yarn lockfile v1
-"@picovoice/pvrecorder-node@~1.2.4":
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/@picovoice/pvrecorder-node/-/pvrecorder-node-1.2.4.tgz#1e67a1f82a144ad3c8e3f77c18fdbfe1ab5880cf"
- integrity sha512-s8l6LtJnTHZ+FfIgXJZ9d8pKONSWs04v5q83F2zmfRr9IV1m7SQ5RlsmL0FO7NsB0GjIar3qHndryAQCjgSInw==
+"@picovoice/pvrecorder-node@=1.2.5":
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/@picovoice/pvrecorder-node/-/pvrecorder-node-1.2.5.tgz#a47e11d347979ef0f1b083657ff69dd9bd2efe5c"
+ integrity sha512-bnid5oInf22JRdrZ75z8ooewOza0whYI9w/oSQSZbkDvddylPPrY6x+1L1qIyf5Tb8ZtzKQL+aQ9m8SazgRHFg==
commander@^6.1.0:
version "6.2.1"
diff --git a/demo/python/README.md b/demo/python/README.md
index f9d8fbb2..ff196be8 100644
--- a/demo/python/README.md
+++ b/demo/python/README.md
@@ -9,7 +9,7 @@ PvRecorder is an easy-to-use, cross-platform audio recorder designed for real-ti
## Compatibility
- Python 3.8+
-- Runs on Linux (x86_64), macOS (x86_64 and arm64), Windows (x86_64), and Raspberry Pi (Zero, 3, 4, 5).
+- Runs on Linux (x86_64), macOS (x86_64 and arm64), Windows (x86_64 and arm64), and Raspberry Pi (Zero, 3, 4, 5).
## Installation
diff --git a/demo/python/requirements.txt b/demo/python/requirements.txt
index 383e1372..fd40607b 100644
--- a/demo/python/requirements.txt
+++ b/demo/python/requirements.txt
@@ -1 +1 @@
-pvrecorder==1.2.3
+pvrecorder==1.2.4
diff --git a/demo/python/setup.py b/demo/python/setup.py
index d30409cf..64bf466d 100644
--- a/demo/python/setup.py
+++ b/demo/python/setup.py
@@ -23,7 +23,7 @@
setuptools.setup(
name="pvrecorderdemo",
- version="1.2.3",
+ version="1.2.4",
author="Picovoice",
author_email="hello@picovoice.ai",
description="Recorder library for Picovoice.",
@@ -31,7 +31,7 @@
long_description_content_type="text/markdown",
url="https://github.com/Picovoice/pvrecorder",
packages=["pvrecorderdemo"],
- install_requires=["pvrecorder==1.2.3"],
+ install_requires=["pvrecorder==1.2.4"],
include_package_data=True,
classifiers=[
"Development Status :: 5 - Production/Stable",
diff --git a/demo/rust/Cargo.toml b/demo/rust/Cargo.toml
index 65029fbd..48a2ed9c 100644
--- a/demo/rust/Cargo.toml
+++ b/demo/rust/Cargo.toml
@@ -7,4 +7,4 @@ edition = "2018"
clap = "4.3"
ctrlc = "3.4"
hound = "3.5"
-pv_recorder = "1.2.3"
+pv_recorder = "=1.2.4"
diff --git a/demo/rust/README.md b/demo/rust/README.md
index ba6e0c12..5a49e03e 100644
--- a/demo/rust/README.md
+++ b/demo/rust/README.md
@@ -14,7 +14,7 @@ PvRecorder is an easy-to-use, cross-platform audio recorder designed for real-ti
- Linux (x86_64)
- macOS (x86_64 and arm64)
-- Windows (x86_64)
+- Windows (x86_64 and arm64)
- Raspberry Pi:
- Zero
- 3 (32 and 64 bit)
diff --git a/lib/node/windows/arm64/pv_recorder.node b/lib/node/windows/arm64/pv_recorder.node
new file mode 100644
index 00000000..3ca44324
Binary files /dev/null and b/lib/node/windows/arm64/pv_recorder.node differ
diff --git a/lib/windows/arm64/libpv_recorder.dll b/lib/windows/arm64/libpv_recorder.dll
new file mode 100644
index 00000000..1201138b
Binary files /dev/null and b/lib/windows/arm64/libpv_recorder.dll differ