Skip to content

Commit ec9f9e8

Browse files
feat: add Java support and example usage to README and new Java files (#74)
* feat: add Java support and example usage to README and new Java files - Updated README.md to include Java usage section and updated platform support for Java. - Added TestTenVad.java as an example of using the TEN VAD library in Java. - Introduced TenVad.java as a Java wrapper for the TEN VAD native library, enabling voice activity detection in Java applications. * refactor: enhance TenVad library with improved error handling and debug information - Updated TenVad.java to use Pointer for vadHandle and improved library loading error messages. - Refactored getLibraryPath method for better platform detection and library path management. - Added printDebugInfo method to assist in diagnosing library loading issues. - Modified TestTenVad.java to print debug information instead of library version. * refactor: streamline TenVad implementation and enhance error handling - Simplified the initialization of the VAD instance in TenVad.java by using the CLib interface for native method calls. - Removed unnecessary debug information printing from TestTenVad.java. - Improved error messages for VAD creation and processing failures. - Updated library path retrieval logic for better clarity and maintainability.
1 parent 1be1959 commit ec9f9e8

File tree

3 files changed

+354
-5
lines changed

3 files changed

+354
-5
lines changed

README.md

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
- [Linux](#1-linux--macos--windows)
4747
- [JS Usage](#js-usage)
4848
- [Web](#1-web)
49+
- [Java Usage](#java-usage)
4950
- [C Usage](#c-usage)
5051
- [Linux](#1-linux)
5152
- [Windows](#2-windows)
@@ -254,22 +255,22 @@ The project supports five major platforms with dynamic library linking.
254255
<th align="center"> Linux </th>
255256
<td align="center"> libten_vad.so </td>
256257
<td align="center"> x64 </td>
257-
<td align="center"> Python, C </td>
258-
<td rowspan="6">ten_vad.h <br> ten_vad.py <br> ten_vad.js</td>
258+
<td align="center"> Python, C, Java </td>
259+
<td rowspan="6">ten_vad.h <br> ten_vad.py <br> ten_vad.js <br> TenVad.java</td>
259260
<td> </td>
260261
</tr>
261262
<tr>
262263
<th align="center"> Windows </th>
263264
<td align="center"> ten_vad.dll </td>
264265
<td align="center"> x64, x86 </td>
265-
<td align="center"> C </td>
266+
<td align="center"> C, Java </td>
266267
<td> </td>
267268
</tr>
268269
<tr>
269270
<th align="center"> macOS </th>
270271
<td align="center"> ten_vad.framework </td>
271272
<td align="center"> arm64, x86_64 </td>
272-
<td align="center"> C </td>
273+
<td align="center"> C, Java </td>
273274
<td> </td>
274275
</tr>
275276
<tr>
@@ -283,7 +284,7 @@ The project supports five major platforms with dynamic library linking.
283284
<th align="center"> Android </th>
284285
<td align="center"> libten_vad.so </td>
285286
<td align="center"> arm64-v8a, armeabi-v7a </td>
286-
<td align="center"> C </td>
287+
<td align="center"> C, Java </td>
287288
<td> </td>
288289
</tr>
289290
<tr>
@@ -392,6 +393,83 @@ from ten_vad import TenVad
392393

393394
<br>
394395

396+
### **Java Usage**
397+
398+
TEN VAD provides comprehensive Java support with JNI (Java Native Interface) bindings for all major platforms.
399+
400+
#### **Requirements**
401+
402+
- Java 8 or higher
403+
- Native libraries in `lib/` directory
404+
- JNI headers
405+
406+
#### **Compilation**
407+
408+
```bash
409+
# Compile Java source
410+
javac -cp . include/TenVad.java examples/TestTenVad.java
411+
412+
# Run example
413+
java -cp . -Djava.library.path=lib TestTenVad s0724-s0730.wav out.txt
414+
```
415+
416+
#### **Example Code**
417+
418+
```java
419+
import com.ten.vad.TenVad;
420+
421+
public class VADExample {
422+
public static void main(String[] args) {
423+
// Create VAD instance
424+
TenVad vad = new TenVad(256, 0.5f);
425+
426+
// Process audio frame
427+
short[] audioFrame = new short[256]; // 16ms at 16kHz
428+
// ... fill audioFrame with audio data ...
429+
430+
TenVad.VadResult result = vad.process(audioFrame);
431+
System.out.println("Probability: " + result.getProbability());
432+
System.out.println("Voice detected: " + result.isVoiceDetected());
433+
434+
// Clean up
435+
vad.destroy();
436+
}
437+
}
438+
```
439+
440+
#### **Platform-Specific Notes**
441+
442+
- **Linux**: Requires `libc++1` package
443+
- **Windows**: Ensure Visual C++ Redistributable is installed
444+
- **macOS**: No additional requirements
445+
- **Android**: Use Android NDK for native library integration
446+
447+
#### **API Reference**
448+
449+
```java
450+
public class TenVad {
451+
// Constructor
452+
public TenVad(int hopSize, float threshold)
453+
454+
// Process audio frame
455+
public VadResult process(short[] audioData)
456+
457+
// Get library version
458+
public static String getVersion()
459+
460+
// Cleanup
461+
public void destroy()
462+
}
463+
464+
public static class VadResult {
465+
public float getProbability() // [0.0, 1.0]
466+
public int getFlag() // 0 or 1
467+
public boolean isVoiceDetected() // true if voice detected
468+
}
469+
```
470+
471+
<br>
472+
395473
### **C Usage**
396474

397475
#### **Build Scripts**

examples/TestTenVad.java

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
//
2+
// Copyright © 2025 Agora
3+
// This file is part of TEN Framework, an open source project.
4+
// Licensed under the Apache License, Version 2.0, with certain conditions.
5+
// Refer to the "LICENSE" file in the root directory for more information.
6+
//
7+
8+
9+
// import com.ten.vad.TenVad; // Uncomment when using package structure
10+
import javax.sound.sampled.*;
11+
import java.io.*;
12+
import java.nio.ByteBuffer;
13+
import java.nio.ByteOrder;
14+
15+
/**
16+
* Example usage of TEN VAD Java interface.
17+
*
18+
* This example demonstrates how to use the TEN VAD library in Java
19+
* for real-time voice activity detection.
20+
*
21+
* Usage: java TestTenVad <input_wav_file> <output_txt_file>
22+
*
23+
* @author TEN Framework Team
24+
* @version 1.0
25+
*/
26+
public class TestTenVad {
27+
28+
private static final int HOP_SIZE = 256; // 16 ms per frame at 16kHz
29+
private static final float THRESHOLD = 0.5f;
30+
31+
public static void main(String[] args) {
32+
if (args.length != 2) {
33+
System.err.println("Usage: java TestTenVad <input_wav_file> <output_txt_file>");
34+
System.exit(1);
35+
}
36+
37+
String inputFile = args[0];
38+
String outputFile = args[1];
39+
40+
try {
41+
42+
// Create VAD instance
43+
TenVad vad = new TenVad(HOP_SIZE, THRESHOLD);
44+
System.out.println("TEN VAD initialized with hop_size=" + vad.getHopSize() +
45+
", threshold=" + vad.getThreshold());
46+
47+
// Load and process audio file
48+
processAudioFile(vad, inputFile, outputFile);
49+
50+
// Clean up
51+
vad.destroy();
52+
System.out.println("Processing completed successfully!");
53+
54+
} catch (Exception e) {
55+
System.err.println("Error: " + e.getMessage());
56+
e.printStackTrace();
57+
System.exit(1);
58+
}
59+
}
60+
61+
/**
62+
* Process audio file and write VAD results to output file.
63+
*/
64+
private static void processAudioFile(TenVad vad, String inputFile, String outputFile)
65+
throws IOException, UnsupportedAudioFileException {
66+
67+
// Load WAV file
68+
AudioInputStream audioStream = AudioSystem.getAudioInputStream(new File(inputFile));
69+
AudioFormat format = audioStream.getFormat();
70+
71+
// Verify audio format
72+
if (format.getSampleRate() != 16000) {
73+
throw new IllegalArgumentException("Audio sample rate must be 16kHz, got: " +
74+
format.getSampleRate());
75+
}
76+
77+
if (format.getSampleSizeInBits() != 16) {
78+
throw new IllegalArgumentException("Audio sample size must be 16-bit, got: " +
79+
format.getSampleSizeInBits());
80+
}
81+
82+
if (format.getChannels() != 1) {
83+
throw new IllegalArgumentException("Audio must be mono, got: " +
84+
format.getChannels() + " channels");
85+
}
86+
87+
System.out.println("Audio format: " + format);
88+
89+
// Read audio data
90+
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
91+
byte[] data = new byte[4096];
92+
int bytesRead;
93+
94+
while ((bytesRead = audioStream.read(data)) != -1) {
95+
buffer.write(data, 0, bytesRead);
96+
}
97+
98+
audioStream.close();
99+
byte[] audioBytes = buffer.toByteArray();
100+
101+
// Convert to short array
102+
short[] audioSamples = bytesToShorts(audioBytes, format.isBigEndian());
103+
System.out.println("Loaded " + audioSamples.length + " audio samples");
104+
105+
// Process audio in frames
106+
int numFrames = audioSamples.length / HOP_SIZE;
107+
System.out.println("Processing " + numFrames + " frames...");
108+
109+
try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {
110+
for (int i = 0; i < numFrames; i++) {
111+
// Extract frame
112+
short[] frame = new short[HOP_SIZE];
113+
System.arraycopy(audioSamples, i * HOP_SIZE, frame, 0, HOP_SIZE);
114+
115+
// Process frame
116+
TenVad.VadResult result = vad.process(frame);
117+
118+
// Write result
119+
String line = String.format("[%d] %.6f, %d", i,
120+
result.getProbability(), result.getFlag());
121+
System.out.println(line);
122+
writer.println(line);
123+
}
124+
}
125+
}
126+
127+
/**
128+
* Convert byte array to short array.
129+
*/
130+
private static short[] bytesToShorts(byte[] bytes, boolean bigEndian) {
131+
short[] shorts = new short[bytes.length / 2];
132+
ByteBuffer.wrap(bytes).order(bigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN)
133+
.asShortBuffer().get(shorts);
134+
return shorts;
135+
}
136+
137+
/**
138+
* Example of real-time audio processing from microphone.
139+
*/
140+
public static void processMicrophoneInput() {
141+
try {
142+
TenVad vad = new TenVad(HOP_SIZE, THRESHOLD);
143+
144+
// Set up audio capture
145+
AudioFormat format = new AudioFormat(16000, 16, 1, true, false);
146+
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
147+
148+
if (!AudioSystem.isLineSupported(info)) {
149+
System.err.println("Microphone input not supported");
150+
return;
151+
}
152+
153+
TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info);
154+
line.open(format);
155+
line.start();
156+
157+
System.out.println("Recording from microphone... Press Ctrl+C to stop");
158+
159+
byte[] buffer = new byte[HOP_SIZE * 2]; // 16-bit samples
160+
short[] frame = new short[HOP_SIZE];
161+
162+
while (true) {
163+
int bytesRead = line.read(buffer, 0, buffer.length);
164+
if (bytesRead == buffer.length) {
165+
// Convert to short array
166+
ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN)
167+
.asShortBuffer().get(frame);
168+
169+
// Process frame
170+
TenVad.VadResult result = vad.process(frame);
171+
172+
// Print result
173+
System.out.printf("VAD: %.3f, %s%n",
174+
result.getProbability(),
175+
result.isVoiceDetected() ? "VOICE" : "SILENCE");
176+
}
177+
}
178+
179+
} catch (Exception e) {
180+
System.err.println("Error in microphone processing: " + e.getMessage());
181+
e.printStackTrace();
182+
}
183+
}
184+
}

0 commit comments

Comments
 (0)