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