Tong Li
Committed by GitHub

push to maven center (#2463)

正在显示 90 个修改的文件 包含 891 行增加12 行删除
  1 +[win.env]
  2 +set JAVA_HOME=D:\java\jdk1.8.0_121
  3 +
  4 +[win.build]
  5 +mvn clean install -DskipTests -Dgpg.skip=true
  6 +
  7 +[linux.env]
  8 +export JAVA_HOME=/usr/java/jdk1.8.0_121
  9 +
  10 +[linux.build]
  11 +mvn clean install -DskipTests -Dgpg.skip=true
  12 +
  13 +[mac.env]
  14 +export JAVA_HOME=~/java/jdk1.8.0_121
  15 +
  16 +[mac.build]
  17 +mvn clean install -DskipTests -Dgpg.skip=true
1 -.idea  
2 -java-api.iml  
3 -out  
4 -META-INF  
5 -build  
6 -*.jar 1 +### Eclipse template
  2 +*.pydevproject
  3 +.metadata
  4 +.gradle*
  5 +classes/
  6 +bin/
  7 +tmp/
  8 +*.tmp
  9 +*.bak
  10 +*.swp
  11 +*~.nib
  12 +local.properties
  13 +.settings/
  14 +.loadpath
  15 +rebel.xml
  16 +
  17 +# Eclipse Core
  18 +.project
  19 +
  20 +generatedsources
  21 +
  22 +# External tool builders
  23 +.externalToolBuilders/
  24 +
  25 +# Locally stored "Eclipse launch configurations"
  26 +*.launch
  27 +
  28 +# CDT-specific
  29 +.cproject
  30 +
  31 +# JDT-specific (Eclipse Java Development Tools)
  32 +.classpath
  33 +
  34 +# PDT-specific
  35 +.buildpath
  36 +
  37 +# sbteclipse plugin
  38 +.target
  39 +
  40 +# TeXlipse plugin
  41 +.texlipse
  42 +
  43 +
  44 +
  45 +### JetBrains template
  46 +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
  47 +
  48 +*.iml
  49 +.flattened-pom.xml
  50 +## Directory-based project format:
  51 +.idea/
  52 +# if you remove the above rule, at least ignore the following:
  53 +
  54 +# User-specific stuff:
  55 +# .idea/workspace.xml
  56 +# .idea/tasks.xml
  57 +# .idea/dictionaries
  58 +
  59 +# Sensitive or high-churn files:
  60 +# .idea/dataSources.ids
  61 +# .idea/dataSources.xml
  62 +# .idea/sqlDataSources.xml
  63 +# .idea/dynamic.xml
  64 +# .idea/uiDesigner.xml
  65 +
  66 +# Gradle:
  67 +# .idea/gradle.xml
  68 +# .idea/libraries
  69 +
  70 +# Mongo Explorer plugin:
  71 +# .idea/mongoSettings.xml
  72 +
  73 +## File-based project format:
  74 +*.ipr
  75 +*.iws
  76 +
  77 +## Plugin-specific files:
  78 +
  79 +# IntelliJ
  80 +/out/
  81 +
  82 +# mpeltonen/sbt-idea plugin
  83 +.idea_modules/
  84 +
  85 +# JIRA plugin
  86 +atlassian-ide-plugin.xml
  87 +
  88 +# Crashlytics plugin (for Android Studio and IntelliJ)
  89 +com_crashlytics_export_strings.xml
  90 +crashlytics.properties
  91 +crashlytics-build.properties
  92 +
  93 +build/
  94 +
  95 +# Ignore Gradle GUI config
  96 +gradle-app.setting
  97 +
  98 +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
  99 +!gradle-wrapper.jar
  100 +
  101 +db
  102 +
  103 +### Java template
  104 +*.class
  105 +
  106 +# Mobile Tools for Java (J2ME)
  107 +.mtj.tmp/
  108 +
  109 +# Package Files #
  110 +#*.jar
  111 +
  112 +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
  113 +hs_err_pid*
  114 +
  115 +
  116 +### Leiningen template
  117 +classes/
  118 +target/
  119 +logs/
  120 +checkouts/
  121 +.lein-deps-sum
  122 +.lein-repl-history
  123 +.lein-plugins/
  124 +.lein-failures
  125 +.nrepl-port
  126 +
  127 +querydsl/
  128 +
  129 +.DS_Store
  130 +
  131 +*.exe
  132 +*.out
  133 +
  134 +*.log
  135 +node_modules/
  136 +dist/
  137 +dist.zip
  138 +package-lock.json
  139 +*.lock
  140 +local.properties
  141 +.cxx
  142 +.externalNativeBuild
  143 +/captures
  144 +/build
  145 +__pycache__/
  146 +*.pyc
  147 +
  148 +
  149 +cmake-build-debug/
  150 +cmake-build-debug-mingw/
  151 +venv/
  152 +.vs/
  153 +Debug/
  154 +vcpkg_installed/
  155 +.env
  156 +.next/
  157 +app.zip
  158 +secrets.txt
  159 +src.zip
@@ -101,7 +101,7 @@ java_files += OfflineSpeechDenoiser.java @@ -101,7 +101,7 @@ java_files += OfflineSpeechDenoiser.java
101 101
102 class_files := $(java_files:%.java=%.class) 102 class_files := $(java_files:%.java=%.class)
103 103
104 -java_files := $(addprefix src/$(package_dir)/,$(java_files)) 104 +java_files := $(addprefix src/main/java/$(package_dir)/,$(java_files))
105 class_files := $(addprefix $(out_dir)/$(package_dir)/,$(class_files)) 105 class_files := $(addprefix $(out_dir)/$(package_dir)/,$(class_files))
106 106
107 $(info -- java files $(java_files)) 107 $(info -- java files $(java_files))
@@ -119,6 +119,6 @@ $(out_jar): $(class_files) @@ -119,6 +119,6 @@ $(out_jar): $(class_files)
119 clean: 119 clean:
120 $(RM) -rfv $(out_dir) 120 $(RM) -rfv $(out_dir)
121 121
122 -$(class_files): $(out_dir)/$(package_dir)/%.class: src/$(package_dir)/%.java 122 +$(class_files): $(out_dir)/$(package_dir)/%.class: src/main/java/$(package_dir)/%.java
123 mkdir -p build 123 mkdir -p build
124 javac -d $(out_dir) -cp $(out_dir) $< 124 javac -d $(out_dir) -cp $(out_dir) $<
  1 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  2 + <modelVersion>4.0.0</modelVersion>
  3 + <groupId>com.litongjava</groupId>
  4 + <artifactId>sherpa-onnx-java-api</artifactId>
  5 + <version>1.0.1</version>
  6 + <packaging>jar</packaging>
  7 + <name>sherpa-onnx-java-api</name>
  8 + <description>sherpa-onnx-java-api</description>
  9 + <url>https://github.com/k2-fsa/sherpa-onnx/tree/master/sherpa-onnx/java-api</url>
  10 + <properties>
  11 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  12 + <java.version>1.8</java.version>
  13 + <maven.compiler.source>${java.version}</maven.compiler.source>
  14 + <maven.compiler.target>${java.version}</maven.compiler.target>
  15 + </properties>
  16 +
  17 + <licenses>
  18 + <license>
  19 + <name>The Apache Software License, Version 2.0</name>
  20 + <url>http://apache.org/licenses/LICENSE-2.0.txt</url>
  21 + </license>
  22 + </licenses>
  23 +
  24 + <developers>
  25 + <developer>
  26 + <id>litongjava</id>
  27 + <name>Tong Li</name>
  28 + <email>litongjava001@gmail.com</email>
  29 + <url>https://github.com/litongjava</url>
  30 + </developer>
  31 + </developers>
  32 +
  33 + <scm>
  34 + <connection>scm:git:git@github.com:k2-fsa/sherpa-onnx.git</connection>
  35 + <developerConnection>scm:git:git@github.com:k2-fsa/sherpa-onnx.git</developerConnection>
  36 + <url>git@github.com:k2-fsa/sherpa-onnx.git</url>
  37 + </scm>
  38 +
  39 + <build>
  40 + <plugins>
  41 + <!-- Source -->
  42 + <plugin>
  43 + <groupId>org.apache.maven.plugins</groupId>
  44 + <artifactId>maven-source-plugin</artifactId>
  45 + <version>2.2.1</version>
  46 + <executions>
  47 + <execution>
  48 + <phase>package</phase>
  49 + <goals>
  50 + <goal>jar-no-fork</goal>
  51 + </goals>
  52 + </execution>
  53 + </executions>
  54 + </plugin>
  55 + <!-- Javadoc -->
  56 + <plugin>
  57 + <groupId>org.apache.maven.plugins</groupId>
  58 + <artifactId>maven-javadoc-plugin</artifactId>
  59 + <version>2.9.1</version>
  60 + <configuration>
  61 + <!-- 添加这个压制JavaDoc检查 -->
  62 + <additionalparam>-Xdoclint:none</additionalparam>
  63 + </configuration>
  64 + <executions>
  65 + <execution>
  66 + <phase>package</phase>
  67 + <goals>
  68 + <goal>jar</goal>
  69 + </goals>
  70 + </execution>
  71 + </executions>
  72 + </plugin>
  73 + <!-- GPG mvn clean deploy -Dgpg.passphrase=YourPassphase -->
  74 + <plugin>
  75 + <groupId>org.apache.maven.plugins</groupId>
  76 + <artifactId>maven-gpg-plugin</artifactId>
  77 + <version>1.5</version>
  78 + <executions>
  79 + <execution>
  80 + <id>sign-artifacts</id>
  81 + <phase>verify</phase>
  82 + <goals>
  83 + <goal>sign</goal>
  84 + </goals>
  85 + </execution>
  86 + </executions>
  87 + </plugin>
  88 + <plugin>
  89 + <groupId>org.sonatype.central</groupId>
  90 + <artifactId>central-publishing-maven-plugin</artifactId>
  91 + <version>0.7.0</version>
  92 + <extensions>true</extensions>
  93 + <configuration>
  94 + <publishingServerId>central</publishingServerId>
  95 + </configuration>
  96 + </plugin>
  97 + </plugins>
  98 + </build>
  99 +</project>
  1 +# User Guide
  2 +
  3 +*Applicable to Windows / macOS / Linux (using Windows as an example for dynamic library loading)*
  4 +
  5 +## 1. Prerequisites
  6 +
  7 +* Java 1.8+ environment
  8 +* Download and prepare the following:
  9 +
  10 + * Sherpa-ONNX Java API (Maven dependency)
  11 + * Kokoro TTS model files (including `model.onnx`, etc.)
  12 +
  13 +---
  14 +
  15 +## 2. Add Maven Dependency
  16 +
  17 +In your `pom.xml`, add:
  18 +
  19 +```xml
  20 +<dependency>
  21 + <groupId>com.litongjava</groupId>
  22 + <artifactId>sherpa-onnx-java-api</artifactId>
  23 + <version>1.0.1</version>
  24 +</dependency>
  25 +```
  26 +
  27 +---
  28 +
  29 +## 3. Obtain and Configure Native Dynamic Libraries (JNI)
  30 +
  31 +### 3.1 Install ONNX Runtime
  32 +
  33 +#### Windows 10
  34 +
  35 +Starting from Windows 10 v1809 and all versions of Windows 11, the system comes with built-in ONNX Runtime as part of Windows ML (WinRT API), exposed through Windows.AI.MachineLearning.dll. You can directly use WinML to load and run ONNX models without additional downloads or installations.
  36 +[run-onnx-models](https://learn.microsoft.com/en-us/windows/ai/new-windows-ml/run-onnx-models)
  37 +
  38 +#### Linux
  39 +
  40 +Sherpa-ONNX does **not** bundle ONNX Runtime. To install it manually:
  41 +
  42 +1. Download the Linux x64 binary from Microsoft’s GitHub Releases:
  43 +
  44 + ```bash
  45 + wget https://github.com/microsoft/onnxruntime/releases/download/v1.17.1/onnxruntime-linux-x64-1.17.1.tgz
  46 + tar -xzf onnxruntime-linux-x64-1.17.1.tgz
  47 + ```
  48 +
  49 +2. Copy and symlink the library into a system directory:
  50 +
  51 + ```bash
  52 + sudo cp onnxruntime-linux-x64-1.17.1/lib/libonnxruntime.so* /usr/local/lib/
  53 + sudo ln -sf /usr/local/lib/libonnxruntime.so.1.17.1 /usr/local/lib/libonnxruntime.so
  54 + ```
  55 +
  56 +3. Update the shared-library cache and verify:
  57 +
  58 + ```bash
  59 + sudo ldconfig
  60 + ldconfig -p | grep onnxruntime
  61 + ```
  62 +
  63 +#### macOS
  64 +
  65 +Sherpa-ONNX also requires you to install ONNX Runtime on macOS:
  66 +
  67 +1. Download the macOS ARM64 binary:
  68 +
  69 + ```bash
  70 + wget https://github.com/microsoft/onnxruntime/releases/download/v1.17.1/onnxruntime-osx-arm64-1.17.1.tgz
  71 + tar -xzf onnxruntime-osx-arm64-1.17.1.tgz
  72 + ```
  73 +
  74 +2. Copy the dylib into `/usr/local/lib`:
  75 +
  76 + ```bash
  77 + sudo cp onnxruntime-osx-arm64-1.17.1/lib/libonnxruntime.1.17.1.dylib /usr/local/lib/
  78 + ```
  79 +
  80 +3. Add `/usr/local/lib` to `dyld`’s search path:
  81 +
  82 + ```bash
  83 + export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH
  84 + ```
  85 +
  86 +4. Verify with `otool`:
  87 +
  88 + ```bash
  89 + otool -L /Users/ping/lib/darwin_arm64/libsherpa-onnx-jni.dylib
  90 + ```
  91 +
  92 +---
  93 +
  94 +### 3.2 Common Errors & Troubleshooting
  95 +
  96 +**Error Example:**
  97 +
  98 +```text
  99 +Exception in thread "main" java.lang.UnsatisfiedLinkError: no sherpa-onnx-jni in java.library.path: ...
  100 +```
  101 +
  102 +This means the JVM couldn’t locate the native library in `java.library.path`.
  103 +
  104 +**Troubleshooting steps:**
  105 +
  106 +1. Ensure you downloaded the build matching your OS and architecture (e.g. win-x64 vs. arm64).
  107 +
  108 +2. Test with an absolute path:
  109 +
  110 + ```bash
  111 + java -Djava.library.path=C:\full\path\to\jni -jar your-app.jar
  112 + ```
  113 +
  114 +3. Print or inspect `java.library.path` at runtime (e.g. `System.out.println(System.getProperty("java.library.path"));`).
  115 +
  116 +4. **Do not** hack the internal `sys_paths` via reflection (it may throw `NoSuchFieldException`). Use `-Djava.library.path` instead.
  117 +
  118 +---
  119 +
  120 +## 4. Download & Prepare the Kokoro Model
  121 +
  122 +Fetch the model package from the official release (example: Kokoro v0.19 English):
  123 +
  124 +```
  125 +https://k2-fsa.github.io/sherpa/onnx/tts/pretrained_models/kokoro.html
  126 +```
  127 +
  128 +```bash
  129 +# Download (manually or via script)
  130 +wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kokoro-en-v0_19.tar.bz2
  131 +
  132 +# Extract
  133 +tar -xjf kokoro-en-v0_19.tar.bz2
  134 +
  135 +# Inspect
  136 +ls -lh kokoro-en-v0_19/
  137 +```
  138 +
  139 +You should see:
  140 +
  141 +```
  142 +LICENSE
  143 +README.md
  144 +espeak-ng-data/ # speech data directory
  145 +model.onnx # TTS model
  146 +tokens.txt # token mapping
  147 +voices.bin # voice embeddings
  148 +```
  149 +
  150 +Make sure your Java code points to these files (using either relative or absolute paths).
  151 +
  152 +---
  153 +
  154 +## 5. Test Code (Java Example)
  155 +
  156 +```java
  157 +package com.litongjava.linux.tts;
  158 +
  159 +import com.k2fsa.sherpa.onnx.GeneratedAudio;
  160 +import com.k2fsa.sherpa.onnx.OfflineTts;
  161 +import com.k2fsa.sherpa.onnx.OfflineTtsConfig;
  162 +import com.k2fsa.sherpa.onnx.OfflineTtsKokoroModelConfig;
  163 +import com.k2fsa.sherpa.onnx.OfflineTtsModelConfig;
  164 +
  165 +public class NonStreamingTtsKokoroEn {
  166 + public static void main(String[] args) {
  167 + String model = "./kokoro-en-v0_19/model.onnx";
  168 + String voices = "./kokoro-en-v0_19/voices.bin";
  169 + String tokens = "./kokoro-en-v0_19/tokens.txt";
  170 + String dataDir = "./kokoro-en-v0_19/espeak-ng-data";
  171 + String text = "Today as always, men fall into two groups: slaves and free men. Whoever does not have"
  172 + + " two-thirds of his day for himself, is a slave, whatever he may be: a statesman, a"
  173 + + " businessman, an official, or a scholar.";
  174 +
  175 + OfflineTtsKokoroModelConfig kokoroConfig = OfflineTtsKokoroModelConfig.builder()
  176 + .setModel(model)
  177 + .setVoices(voices)
  178 + .setTokens(tokens)
  179 + .setDataDir(dataDir)
  180 + .build();
  181 +
  182 + OfflineTtsModelConfig modelConfig = OfflineTtsModelConfig.builder()
  183 + .setKokoro(kokoroConfig)
  184 + .setNumThreads(2)
  185 + .setDebug(true)
  186 + .build();
  187 +
  188 + OfflineTtsConfig config = OfflineTtsConfig.builder()
  189 + .setModel(modelConfig)
  190 + .build();
  191 +
  192 + OfflineTts tts = new OfflineTts(config);
  193 +
  194 + int sid = 0;
  195 + float speed = 1.0f;
  196 + long start = System.currentTimeMillis();
  197 + GeneratedAudio audio = tts.generate(text, sid, speed);
  198 + long stop = System.currentTimeMillis();
  199 +
  200 + float elapsed = (stop - start) / 1000.0f;
  201 + float duration = audio.getSamples().length / (float) audio.getSampleRate();
  202 + float rtf = elapsed / duration;
  203 +
  204 + String outFile = "tts-kokoro-en.wav";
  205 + audio.save(outFile);
  206 +
  207 + System.out.printf("-- elapsed : %.3f seconds%n", elapsed);
  208 + System.out.printf("-- audio duration : %.3f seconds%n", duration);
  209 + System.out.printf("-- real-time factor : %.3f%n", rtf);
  210 + System.out.printf("-- text : %s%n", text);
  211 + System.out.printf("-- Saved to : %s%n", outFile);
  212 +
  213 + tts.release();
  214 + }
  215 +}
  216 +```
  217 +
  218 +### Output Explanation
  219 +
  220 +After successful execution, you should see something like:
  221 +
  222 +```
  223 +-- elapsed : 6.739 seconds
  224 +-- audio duration : 6.739 seconds
  225 +-- real-time factor : 0.563
  226 +-- text : ...
  227 +-- Saved to : tts-kokoro-en.wav
  228 +```
  229 +
  230 +A file named `tts-kokoro-en.wav` will appear in the current directory—play it with any audio player to verify.
  1 +# 使用指南
  2 +
  3 +*适用于 Windows / macOS / Linux(以 Windows 为例说明动态库加载)*
  4 +
  5 +## 1. 前提条件
  6 +
  7 +* Java 1.8+ 环境
  8 +* 下载并准备好以下内容:
  9 + * Sherpa-ONNX Java API(Maven 依赖)
  10 + * Kokoro TTS 模型文件(包含 `model.onnx` 等)
  11 +
  12 +---
  13 +
  14 +## 2. 添加 Maven 依赖
  15 +
  16 +在你的 `pom.xml` 中添加如下依赖:
  17 +
  18 +```xml
  19 +<dependency>
  20 + <groupId>com.litongjava</groupId>
  21 + <artifactId>sherpa-onnx-java-api</artifactId>
  22 + <version>1.0.1</version>
  23 +</dependency>
  24 +```
  25 +
  26 +---
  27 +
  28 +## 3. 获取并配置本地动态链接库(JNI)
  29 +
  30 +### 3.1 安装 ONNX Runtime
  31 +
  32 +#### 1. Windows 11
  33 +
  34 +Starting from Windows 10 v1809 and all versions of Windows 11, the system comes with built-in ONNX Runtime as part of Windows ML (WinRT API), exposed through Windows.AI.MachineLearning.dll. You can directly use WinML to load and run ONNX models without additional downloads or installations.
  35 +(run-onnx-models)[https://learn.microsoft.com/en-us/windows/ai/new-windows-ml/run-onnx-models]
  36 +
  37 +#### 2. Linux
  38 +
  39 +Sherpa-ONNX 并不包含 ONNX Runtime,需要手动下载并配置:
  40 +
  41 +1. 从微软官方 GitHub Releases 下载 Linux 64 位二进制包:
  42 +
  43 + ```bash
  44 + wget https://github.com/microsoft/onnxruntime/releases/download/v1.17.1/onnxruntime-linux-x64-1.17.1.tgz
  45 + tar -xzf onnxruntime-linux-x64-1.17.1.tgz
  46 + ```
  47 +2. 将解压后的 `libonnxruntime.so` 文件复制到系统库目录,并创建软链接:
  48 +
  49 + ```bash
  50 + sudo cp onnxruntime-linux-x64-1.17.1/lib/libonnxruntime.so* /usr/local/lib/
  51 + sudo ln -sf /usr/local/lib/libonnxruntime.so.1.17.1 /usr/local/lib/libonnxruntime.so
  52 + ```
  53 +3. 更新共享库缓存并验证安装:
  54 +
  55 + ```bash
  56 + sudo ldconfig
  57 + ldconfig -p | grep onnxruntime
  58 + ```
  59 +
  60 +#### 3. macOS
  61 +
  62 +Sherpa-ONNX 同样不包含 ONNX Runtime,需要从官方获取并配置:
  63 +
  64 +1. 下载 macOS ARM64 版本二进制包:
  65 +
  66 + ```bash
  67 + wget https://github.com/microsoft/onnxruntime/releases/download/v1.17.1/onnxruntime-osx-arm64-1.17.1.tgz
  68 + tar -xzf onnxruntime-osx-arm64-1.17.1.tgz
  69 + ```
  70 +2.`libonnxruntime.1.17.1.dylib` 复制到 `/usr/local/lib`
  71 +
  72 + ```bash
  73 + sudo cp onnxruntime-osx-arm64-1.17.1/lib/libonnxruntime.1.17.1.dylib /usr/local/lib/
  74 + ```
  75 +3.`/usr/local/lib` 添加到 `dyld` 的搜索路径:
  76 +
  77 + ```bash
  78 + export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH
  79 + ```
  80 +4. 使用 `otool` 验证:
  81 +
  82 + ```bash
  83 + otool -L /Users/ping/lib/darwin_arm64/libsherpa-onnx-jni.dylib
  84 + ```
  85 +---
  86 +
  87 +
  88 +### 3.2 常见错误与排查
  89 +
  90 +**错误示例:**
  91 +
  92 +```text
  93 +Exception in thread "main" java.lang.UnsatisfiedLinkError: no sherpa-onnx-jni in java.library.path: ...
  94 +```
  95 +
  96 +说明 JVM 没有在 `java.library.path` 中找到本地库。
  97 +
  98 +排查步骤:
  99 +
  100 +1. 确认下载的是与你操作系统与架构匹配的版本(如 win-x64 vs arm64 等)。
  101 +2. 用绝对路径测试:将 `.dll` 放在某个目录并运行:
  102 +
  103 + ```sh
  104 + java -Djava.library.path=C:\full\path\to\jni -jar your-app.jar
  105 + ```
  106 +3. 打印或检查 `java.library.path` 内容(示例代码里可输出 `System.getProperty("java.library.path")`)。
  107 +4. 避免通过反射修改 `sys_paths`(不要尝试 hack `java.library.path` 的内部字段,容易引发 `NoSuchFieldException: sys_paths`,建议直接用 `-Djava.library.path`)。
  108 +
  109 +---
  110 +
  111 +## 4. 下载并准备 Kokoro 模型
  112 +
  113 +从官方 release 获取模型包(以英文 Kokoro v0.19 为例):
  114 +```
  115 +https://k2-fsa.github.io/sherpa/onnx/tts/pretrained_models/kokoro.html
  116 +```
  117 +
  118 +```sh
  119 +# 下载(手工或脚本)
  120 +# 例如从 GitHub releases:
  121 +wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kokoro-en-v0_19.tar.bz2
  122 +
  123 +# 解压
  124 +tar -xjf kokoro-en-v0_19.tar.bz2
  125 +
  126 +# 查看结构
  127 +ls -lh kokoro-en-v0_19/
  128 +```
  129 +
  130 +该目录结构示例(解压后应包含):
  131 +
  132 +```
  133 +LICENSE
  134 +README.md
  135 +espeak-ng-data/ # 语音数据目录
  136 +model.onnx # TTS 模型
  137 +tokens.txt # token 映射
  138 +voices.bin # voice embedding
  139 +```
  140 +
  141 +确保这些路径在你的 Java 程序中指向正确的位置(相对或绝对皆可)。
  142 +
  143 +---
  144 +
  145 +## 5. 测试代码(Java 示例)
  146 +
  147 +```java
  148 +package com.litongjava.linux.tts;
  149 +
  150 +import com.k2fsa.sherpa.onnx.GeneratedAudio;
  151 +import com.k2fsa.sherpa.onnx.OfflineTts;
  152 +import com.k2fsa.sherpa.onnx.OfflineTtsConfig;
  153 +import com.k2fsa.sherpa.onnx.OfflineTtsKokoroModelConfig;
  154 +import com.k2fsa.sherpa.onnx.OfflineTtsModelConfig;
  155 +
  156 +public class NonStreamingTtsKokoroEn {
  157 + public static void main(String[] args) {
  158 + String model = "./kokoro-en-v0_19/model.onnx";
  159 + String voices = "./kokoro-en-v0_19/voices.bin";
  160 + String tokens = "./kokoro-en-v0_19/tokens.txt";
  161 + String dataDir = "./kokoro-en-v0_19/espeak-ng-data";
  162 + String text = "Today as always, men fall into two groups: slaves and free men. Whoever does not have"
  163 + + " two-thirds of his day for himself, is a slave, whatever he may be: a statesman, a"
  164 + + " businessman, an official, or a scholar.";
  165 +
  166 + OfflineTtsKokoroModelConfig kokoroModelConfig = OfflineTtsKokoroModelConfig.builder()
  167 + .setModel(model)
  168 + .setVoices(voices)
  169 + .setTokens(tokens)
  170 + .setDataDir(dataDir)
  171 + .build();
  172 +
  173 + OfflineTtsModelConfig modelConfig = OfflineTtsModelConfig.builder()
  174 + .setKokoro(kokoroModelConfig)
  175 + .setNumThreads(2)
  176 + .setDebug(true)
  177 + .build();
  178 +
  179 + OfflineTtsConfig config = OfflineTtsConfig.builder()
  180 + .setModel(modelConfig)
  181 + .build();
  182 +
  183 + OfflineTts tts = new OfflineTts(config);
  184 +
  185 + int sid = 0;
  186 + float speed = 1.0f;
  187 + long start = System.currentTimeMillis();
  188 + GeneratedAudio audio = tts.generate(text, sid, speed);
  189 + long stop = System.currentTimeMillis();
  190 +
  191 + float timeElapsedSeconds = (stop - start) / 1000.0f;
  192 + float audioDuration = audio.getSamples().length / (float) audio.getSampleRate();
  193 + float real_time_factor = timeElapsedSeconds / audioDuration;
  194 +
  195 + String waveFilename = "tts-kokoro-en.wav";
  196 + audio.save(waveFilename);
  197 + System.out.printf("-- elapsed : %.3f seconds\n", timeElapsedSeconds);
  198 + System.out.printf("-- audio duration: %.3f seconds\n", audioDuration);
  199 + System.out.printf("-- real-time factor (RTF): %.3f\n", real_time_factor);
  200 + System.out.printf("-- text: %s\n", text);
  201 + System.out.printf("-- Saved to %s\n", waveFilename);
  202 +
  203 + tts.release();
  204 + }
  205 +}
  206 +```
  207 +
  208 +### 输出说明
  209 +
  210 +成功执行后会输出类似:
  211 +
  212 +```
  213 +-- elapsed : 6.739 seconds
  214 +-- audio duration: 6.739 seconds
  215 +-- real-time factor (RTF): 0.563
  216 +-- text: ...
  217 +-- Saved to tts-kokoro-en.wav
  218 +```
  219 +
  220 +并在当前目录生成 `tts-kokoro-en.wav`,可以用任意音频播放器播放验证。
  221 +
  222 +---
@@ -63,7 +63,7 @@ public class EndpointConfig { @@ -63,7 +63,7 @@ public class EndpointConfig {
63 return this; 63 return this;
64 } 64 }
65 65
66 - public Builder setRul3(EndpointRule rule) { 66 + public Builder setRule3(EndpointRule rule) {
67 this.rule3 = rule; 67 this.rule3 = rule;
68 return this; 68 return this;
69 } 69 }
1 package com.k2fsa.sherpa.onnx; 1 package com.k2fsa.sherpa.onnx;
2 2
  3 +import com.k2fsa.sherpa.onnx.utils.LibraryUtils;
  4 +
3 public class LibraryLoader { 5 public class LibraryLoader {
4 private static volatile boolean autoLoadEnabled = true; 6 private static volatile boolean autoLoadEnabled = true;
5 private static volatile boolean isLoaded = false; 7 private static volatile boolean isLoaded = false;
6 8
7 static synchronized void loadLibrary() { 9 static synchronized void loadLibrary() {
8 if (!isLoaded) { 10 if (!isLoaded) {
9 - System.loadLibrary("sherpa-onnx-jni"); 11 + LibraryUtils.load();
10 isLoaded = true; 12 isLoaded = true;
11 } 13 }
12 } 14 }
@@ -16,6 +16,9 @@ public class OnlineRecognizer { @@ -16,6 +16,9 @@ public class OnlineRecognizer {
16 } 16 }
17 17
18 public void decode(OnlineStream[] ss) { 18 public void decode(OnlineStream[] ss) {
  19 + if (ss == null || ss.length == 0) {
  20 + throw new IllegalArgumentException("Stream array must be non-empty");
  21 + }
19 long[] streamPtrs = new long[ss.length]; 22 long[] streamPtrs = new long[ss.length];
20 for (int i = 0; i < ss.length; ++i) { 23 for (int i = 0; i < ss.length; ++i) {
21 streamPtrs[i] = ss[i].getPtr(); 24 streamPtrs[i] = ss[i].getPtr();
@@ -46,7 +49,7 @@ public class OnlineRecognizer { @@ -46,7 +49,7 @@ public class OnlineRecognizer {
46 } 49 }
47 50
48 // You'd better call it manually if it is not used anymore 51 // You'd better call it manually if it is not used anymore
49 - public void release() { 52 + protected void close() {
50 if (this.ptr == 0) { 53 if (this.ptr == 0) {
51 return; 54 return;
52 } 55 }
@@ -54,6 +57,10 @@ public class OnlineRecognizer { @@ -54,6 +57,10 @@ public class OnlineRecognizer {
54 this.ptr = 0; 57 this.ptr = 0;
55 } 58 }
56 59
  60 + public void release() {
  61 + this.close();
  62 + }
  63 +
57 public OnlineRecognizerResult getResult(OnlineStream s) { 64 public OnlineRecognizerResult getResult(OnlineStream s) {
58 Object[] arr = getResult(ptr, s.getPtr()); 65 Object[] arr = getResult(ptr, s.getPtr());
59 String text = (String) arr[0]; 66 String text = (String) arr[0];
@@ -32,6 +32,10 @@ public class OnlineStream { @@ -32,6 +32,10 @@ public class OnlineStream {
32 } 32 }
33 33
34 public void release() { 34 public void release() {
  35 + close();
  36 + }
  37 +
  38 + public void close() {
35 // stream object must be release after used 39 // stream object must be release after used
36 if (this.ptr == 0) { 40 if (this.ptr == 0) {
37 return; 41 return;
@@ -42,7 +46,7 @@ public class OnlineStream { @@ -42,7 +46,7 @@ public class OnlineStream {
42 46
43 @Override 47 @Override
44 protected void finalize() throws Throwable { 48 protected void finalize() throws Throwable {
45 - release(); 49 + close();
46 super.finalize(); 50 super.finalize();
47 } 51 }
48 52
  1 +package com.k2fsa.sherpa.onnx.core;
  2 +
  3 +public interface Core {
  4 + String NATIVE_LIBRARY_NAME = "sherpa-onnx-jni";
  5 +}
  1 +package com.k2fsa.sherpa.onnx.utils;
  2 +
  3 +import java.io.File;
  4 +import java.io.IOException;
  5 +import java.io.InputStream;
  6 +import java.nio.file.Files;
  7 +import java.nio.file.StandardCopyOption;
  8 +import java.util.Locale;
  9 +
  10 +import com.k2fsa.sherpa.onnx.core.Core;
  11 +
  12 +public class LibraryUtils {
  13 + // System property to override native library path
  14 + private static final String NATIVE_PATH_PROP = "sherpa_onnx.native.path";
  15 +
  16 + public static void load() {
  17 + String libFileName = System.mapLibraryName(Core.NATIVE_LIBRARY_NAME);
  18 +
  19 + // 1. Try loading from external directory if provided
  20 + String nativePath = System.getProperty(NATIVE_PATH_PROP);
  21 + if (nativePath != null) {
  22 + File nativeDir = new File(nativePath);
  23 + File libInDir = new File(nativeDir, libFileName);
  24 + if (nativeDir.isDirectory() && libInDir.exists()) {
  25 + System.out.println("Loading native lib from external directory: " + libInDir.getAbsolutePath());
  26 + System.load(libInDir.getAbsolutePath());
  27 + return;
  28 + }
  29 + }
  30 +
  31 + // 2. Fallback to extracting and loading from the JAR
  32 + File libFile = init(libFileName);
  33 + System.out.println("Loading native lib from: " + libFile.getAbsolutePath());
  34 + System.load(libFile.getAbsolutePath());
  35 + }
  36 +
  37 + /* Computes and initializes OS_ARCH_STR (such as linux-x64) */
  38 + private static String initOsArch() {
  39 + String detectedOS = null;
  40 + String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH);
  41 + if (os.contains("mac") || os.contains("darwin")) {
  42 + detectedOS = "osx";
  43 + } else if (os.contains("win")) {
  44 + detectedOS = "win";
  45 + } else if (os.contains("nux")) {
  46 + detectedOS = "linux";
  47 + } else {
  48 + throw new IllegalStateException("Unsupported os:" + os);
  49 + }
  50 + String detectedArch = null;
  51 + String arch = System.getProperty("os.arch", "generic").toLowerCase(Locale.ENGLISH);
  52 + if (arch.startsWith("amd64") || arch.startsWith("x86_64")) {
  53 + detectedArch = "x64";
  54 + } else if (arch.startsWith("x86")) {
  55 + // 32-bit x86 is not supported by the Java API
  56 + detectedArch = "x86";
  57 + } else if (arch.startsWith("aarch64")) {
  58 + detectedArch = "aarch64";
  59 + } else {
  60 + throw new IllegalStateException("Unsupported arch:" + arch);
  61 + }
  62 + return detectedOS + '-' + detectedArch;
  63 + }
  64 +
  65 + private static File init(String libFileName) {
  66 + String osName = System.getProperty("os.name").toLowerCase();
  67 + String osArch = System.getProperty("os.arch").toLowerCase();
  68 + String userHome = System.getProperty("user.home");
  69 + System.out.printf("Detected OS=%s, ARCH=%s, HOME=%s%n", osName, osArch, userHome);
  70 +
  71 + String archName = initOsArch();
  72 +
  73 + // Prepare destination directory under ~/lib/<archName>/
  74 + String dstDir = userHome + File.separator + "lib" + File.separator + archName;
  75 + File libFile = new File(dstDir, libFileName);
  76 + File parentDir = libFile.getParentFile();
  77 + if (!parentDir.exists() && !parentDir.mkdirs()) {
  78 + throw new RuntimeException("Unable to create directory: " + parentDir);
  79 + }
  80 +
  81 + // Extract the native library from JAR
  82 + extractResource("/native/" + archName + "/" + libFileName, libFile);
  83 + return libFile;
  84 + }
  85 +
  86 + /**
  87 + * Copies a resource file from the jar to the specified destination.
  88 + *
  89 + * @param resourcePath The resource path inside the jar, e.g.:
  90 + * /native/linux_x64/libonnxruntime.so
  91 + * @param destination The destination file on disk
  92 + */
  93 + private static void extractResource(String resourcePath, File destination) {
  94 + try (InputStream in = LibraryUtils.class.getResourceAsStream(resourcePath)) {
  95 + if (in == null) {
  96 + throw new RuntimeException("Resource not found: " + resourcePath);
  97 + }
  98 + Files.copy(in, destination.toPath(), StandardCopyOption.REPLACE_EXISTING);
  99 + } catch (IOException e) {
  100 + throw new RuntimeException("Failed to extract resource " + resourcePath + " to " + destination.getAbsolutePath(),
  101 + e);
  102 + }
  103 + }
  104 +}
  1 +please downlaod file and put in folder
  2 +[donwload link](https://huggingface.co/csukuangfj/sherpa-onnx-libs/tree/main/jni)
  3 +
  4 +- sherpa-onnx-v1.12.7-linux-aarch64-jni.tar.bz2
  5 +- sherpa-onnx-v1.12.7-linux-x64-jni.tar.bz2
  6 +- sherpa-onnx-v1.12.7-osx-arm64-jni.tar.bz2
  7 +- sherpa-onnx-v1.12.7-osx-x86_64-jni.tar.bz2
  8 +- sherpa-onnx-v1.12.7-win-x64-jni.tar.bz2
  9 +
  10 +
  11 +- linux_arm64
  12 +- linux_x64
  13 +- darwin_arm64
  14 +- darwin_x64
  15 +- windows_x64
  16 +
  17 +
  18 +add to src/main/resources
  19 +
  20 +```
  21 +.
  22 +├── native
  23 +│ ├── linux-aarch64
  24 +│ │ ├── libsherpa-onnx-jni.so
  25 +│ ├── linux-x64
  26 +│ │ ├── libsherpa-onnx-jni.so
  27 +│ ├── osx-aarch64
  28 +│ │ ├── libsherpa-onnx-jni.dylib
  29 +│ ├── osx-x64
  30 +│ │ ├── libsherpa-onnx-jni.dylib
  31 +│ ├── win-x64
  32 +│ │ ├── sherpa-onnx-jni.dll
  33 +```
  34 +