diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 0000000000..e69de29bb2 diff --git a/native_client/java/.gitignore b/native_client/java/.gitignore old mode 100644 new mode 100755 index fd45b12f05..7661a22379 --- a/native_client/java/.gitignore +++ b/native_client/java/.gitignore @@ -1,11 +1,22 @@ -*.iml -.gradle -/local.properties -/.idea/caches/build_file_checksums.ser -/.idea/libraries -/.idea/modules.xml -/.idea/workspace.xml -.DS_Store -/build -/captures -.externalNativeBuild +#Native libs +libdeepspeech_android/libs/* +!libdeepspeech_android/libs/.gitignore +libdeepspeech_android/*.so + +#Gradle +.gradle/ + +#Make/CMake +Makefile/ + +#SWIG +jni/*.cpp +jni/*.o + +#Collected files by make +build/ + +#Autogenerated java files by SWIG +libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech/*.java +!libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechModel.java +!libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechStreamingState.java \ No newline at end of file diff --git a/native_client/java/.idea/codeStyles/Project.xml b/native_client/java/.idea/codeStyles/Project.xml deleted file mode 100644 index 30aa626c23..0000000000 --- a/native_client/java/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/native_client/java/.idea/gradle.xml b/native_client/java/.idea/gradle.xml deleted file mode 100644 index 6e2e5ce632..0000000000 --- a/native_client/java/.idea/gradle.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/native_client/java/.idea/misc.xml b/native_client/java/.idea/misc.xml deleted file mode 100644 index b0c7b20c87..0000000000 --- a/native_client/java/.idea/misc.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/native_client/java/.idea/runConfigurations.xml b/native_client/java/.idea/runConfigurations.xml deleted file mode 100644 index 7f68460d8b..0000000000 --- a/native_client/java/.idea/runConfigurations.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/native_client/java/Makefile b/native_client/java/Makefile index 904936215a..cc40ae7406 100644 --- a/native_client/java/Makefile +++ b/native_client/java/Makefile @@ -1,31 +1,73 @@ -.PHONY: clean apk-clean +.PHONY: clean android-clean jre jre-prepare jre-libdeepspeech-jni jre-gradle jre-collect jre-clean android-prepare include ../definitions.mk -ARCHS := $(shell grep 'ABI_FILTERS' libdeepspeech/gradle.properties | cut -d'=' -f2 | sed -e 's/;/ /g') +ARCHS := $(shell grep 'ABI_FILTERS' libdeepspeech_android/gradle.properties | cut -d'=' -f2 | sed -e 's/;/ /g') GRADLE ?= ./gradlew -all: apk +all: android jre +standalone: jre -clean: apk-clean +clean: android-clean jre-clean rm -rf *.java jni/deepspeech_wrap.cpp -apk-clean: +android-clean: $(GRADLE) clean + rm -rf settings.gradle -libs-clean: - rm -fr libdeepspeech/libs/*/libdeepspeech.so +jre-clean: + rm -f build.gradle + rm -f jni/deepspeech_wrap.cpp jni/deepspeech_wrap.o + rm -rf libdeepspeech_jre/cmake_install.cmake libdeepspeech_jre/CMakeCache.txt libdeepspeech_jre/Makefile libdeepspeech_jre/CMakeFiles/ + rm -rf libdeepspeech_jre/build/ + rm -rf settings.gradle -libdeepspeech/libs/%/libdeepspeech.so: - -mkdir libdeepspeech/libs/$*/ - cp ${TFDIR}/bazel-out/$*-*/bin/native_client/libdeepspeech.so libdeepspeech/libs/$*/ +libdeepspeech_jre/libs/%/libdeepspeech.so: + -mkdir libdeepspeech_jre/libs/$*/ + cp ${TFDIR}/bazel-out/$*-*/bin/native_client/libdeepspeech.so libdeepspeech_jre/libs/$*/ -apk: apk-clean bindings $(patsubst %,libdeepspeech/libs/%/libdeepspeech.so,$(ARCHS)) +libdeepspeech_android/libs/%/libdeepspeech.so: + -mkdir libdeepspeech_android/libs/$*/ + cp ${TFDIR}/bazel-out/$*-*/bin/native_client/libdeepspeech.so libdeepspeech_android/libs/$*/ + +android-prepare: + cp build.gradle.android build.gradle + cp libdeepspeech_android/settings.gradle settings.gradle + +android: android-prepare android-clean bindings $(patsubst %,libdeepspeech/libs/%/libdeepspeech.so,$(ARCHS)) + $(GRADLE) build + +jre: jre-prepare jre-collect jre-restore-makefile jre-clean +jre-prepare: $(patsubst %,libdeepspeech_jre/libs/%/libdeepspeech.so,$(ARCHS)) + cp Makefile Makefile.original + cp build.gradle.standalone build.gradle + cp libdeepspeech_jre/settings.gradle ./settings.gradle + sed -i 's|__JAVA_HOME__|'${JAVA_HOME}'|g' libdeepspeech_jre/CMakeLists.txt + +jre-libdeepspeech-jni: bindings + cd libdeepspeech_jre; \ + cmake .; \ + $(MAKE) + +jre-gradle: jre-libdeepspeech-jni $(GRADLE) build -maven-bundle: apk +jre-collect: jre-gradle + mkdir -p build + mv libdeepspeech_jre/libdeepspeech-jni.so build/ + cp libdeepspeech_jre/libs/x86_64/libdeepspeech.so build/ + cp libdeepspeech_jre/build/libs/libdeepspeech_jre.jar build/ + +jre-restore-makefile: + mv Makefile.original Makefile + +maven-bundle: android $(GRADLE) uploadArchives $(GRADLE) zipMavenArtifacts -bindings: clean ds-swig - $(DS_SWIG_ENV) swig -c++ -java -package org.deepspeech.libdeepspeech -outdir libdeepspeech/src/main/java/org/deepspeech/libdeepspeech/ -o jni/deepspeech_wrap.cpp jni/deepspeech.i +bindings: ds-swig + mkdir -p ./tmp + $(DS_SWIG_ENV) swig -c++ -java -package org.deepspeech.libdeepspeech -outdir ./tmp -o jni/deepspeech_wrap.cpp jni/deepspeech.i + cp ./tmp/* libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech/ + cp ./tmp/* libdeepspeech_jre/src/main/java/org/deepspeech/libdeepspeech/ + rm -rf ./tmp \ No newline at end of file diff --git a/native_client/java/README.md b/native_client/java/README.md old mode 100644 new mode 100755 index 89ebc59431..ea79b5c4a2 --- a/native_client/java/README.md +++ b/native_client/java/README.md @@ -1 +1,17 @@ +# Java bindings Full project description and documentation on GitHub: [https://github.com/mozilla/DeepSpeech](https://github.com/mozilla/DeepSpeech). + +## Android bindings +For use with Android + +``make android`` + +>Note: The current example app in `./App` is not up to date with the latest changes to the bindings! + +## Standalone Java Bindings for DeepSpeech +For use with standalone Java + +``make standalone`` + +### Usage information: +See [standalone.md](standalone.md) \ No newline at end of file diff --git a/native_client/java/build.gradle b/native_client/java/build.gradle.android similarity index 100% rename from native_client/java/build.gradle rename to native_client/java/build.gradle.android diff --git a/native_client/java/build.gradle.standalone b/native_client/java/build.gradle.standalone new file mode 100755 index 0000000000..80234950fc --- /dev/null +++ b/native_client/java/build.gradle.standalone @@ -0,0 +1,29 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + + repositories { + google() + jcenter() + } + dependencies { + } +} + + +allprojects { + repositories { + jcenter() + } +} + +dependencies { +} + +task clean(type: Delete) { + delete rootProject.buildDir +} + +ext { + dsVersionString = rootProject.file('../../VERSION').text.trim() +} diff --git a/native_client/java/gradle.properties b/native_client/java/gradle.properties old mode 100644 new mode 100755 diff --git a/native_client/java/gradle/wrapper/gradle-wrapper.jar b/native_client/java/gradle/wrapper/gradle-wrapper.jar old mode 100644 new mode 100755 index f6b961fd5a..62d4c05355 Binary files a/native_client/java/gradle/wrapper/gradle-wrapper.jar and b/native_client/java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/native_client/java/gradle/wrapper/gradle-wrapper.properties b/native_client/java/gradle/wrapper/gradle-wrapper.properties old mode 100644 new mode 100755 index 9a4163a4f5..bb8b2fc26b --- a/native_client/java/gradle/wrapper/gradle-wrapper.properties +++ b/native_client/java/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/native_client/java/gradlew b/native_client/java/gradlew index cccdd3d517..fbd7c51583 100755 --- a/native_client/java/gradlew +++ b/native_client/java/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# 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. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -66,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -109,10 +126,11 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -138,19 +156,19 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -159,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/native_client/java/gradlew.bat b/native_client/java/gradlew.bat old mode 100644 new mode 100755 index e95643d6a2..a9f778a7a9 --- a/native_client/java/gradlew.bat +++ b/native_client/java/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -13,8 +29,11 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -65,6 +84,7 @@ set CMD_LINE_ARGS=%* set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% diff --git a/native_client/java/jni/deepspeech.i b/native_client/java/jni/deepspeech.i old mode 100644 new mode 100755 diff --git a/native_client/java/libdeepspeech/.gitignore b/native_client/java/libdeepspeech_android/.gitignore similarity index 100% rename from native_client/java/libdeepspeech/.gitignore rename to native_client/java/libdeepspeech_android/.gitignore diff --git a/native_client/java/libdeepspeech/CMakeLists.txt b/native_client/java/libdeepspeech_android/CMakeLists.txt similarity index 100% rename from native_client/java/libdeepspeech/CMakeLists.txt rename to native_client/java/libdeepspeech_android/CMakeLists.txt diff --git a/native_client/java/libdeepspeech/build.gradle b/native_client/java/libdeepspeech_android/build.gradle similarity index 100% rename from native_client/java/libdeepspeech/build.gradle rename to native_client/java/libdeepspeech_android/build.gradle diff --git a/native_client/java/libdeepspeech/gradle.properties b/native_client/java/libdeepspeech_android/gradle.properties similarity index 100% rename from native_client/java/libdeepspeech/gradle.properties rename to native_client/java/libdeepspeech_android/gradle.properties diff --git a/native_client/java/libdeepspeech/libs/.gitignore b/native_client/java/libdeepspeech_android/libs/.gitignore similarity index 100% rename from native_client/java/libdeepspeech/libs/.gitignore rename to native_client/java/libdeepspeech_android/libs/.gitignore diff --git a/native_client/java/libdeepspeech/proguard-rules.pro b/native_client/java/libdeepspeech_android/proguard-rules.pro similarity index 100% rename from native_client/java/libdeepspeech/proguard-rules.pro rename to native_client/java/libdeepspeech_android/proguard-rules.pro diff --git a/native_client/java/libdeepspeech_android/settings.gradle b/native_client/java/libdeepspeech_android/settings.gradle new file mode 100644 index 0000000000..8b67f5a445 --- /dev/null +++ b/native_client/java/libdeepspeech_android/settings.gradle @@ -0,0 +1 @@ +include ':libdeepspeech_android' diff --git a/native_client/java/libdeepspeech/src/androidTest/java/org/deepspeech/libdeepspeech/test/BasicTest.java b/native_client/java/libdeepspeech_android/src/androidTest/java/org/deepspeech/libdeepspeech/test/BasicTest.java similarity index 100% rename from native_client/java/libdeepspeech/src/androidTest/java/org/deepspeech/libdeepspeech/test/BasicTest.java rename to native_client/java/libdeepspeech_android/src/androidTest/java/org/deepspeech/libdeepspeech/test/BasicTest.java diff --git a/native_client/java/libdeepspeech/src/main/AndroidManifest.xml b/native_client/java/libdeepspeech_android/src/main/AndroidManifest.xml similarity index 100% rename from native_client/java/libdeepspeech/src/main/AndroidManifest.xml rename to native_client/java/libdeepspeech_android/src/main/AndroidManifest.xml diff --git a/native_client/java/libdeepspeech/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechModel.java b/native_client/java/libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechModel.java similarity index 100% rename from native_client/java/libdeepspeech/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechModel.java rename to native_client/java/libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechModel.java diff --git a/native_client/java/libdeepspeech/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechStreamingState.java b/native_client/java/libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechStreamingState.java similarity index 100% rename from native_client/java/libdeepspeech/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechStreamingState.java rename to native_client/java/libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechStreamingState.java diff --git a/native_client/java/libdeepspeech/src/main/java/org/deepspeech/libdeepspeech_doc/CandidateTranscript.java b/native_client/java/libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech_doc/CandidateTranscript.java similarity index 100% rename from native_client/java/libdeepspeech/src/main/java/org/deepspeech/libdeepspeech_doc/CandidateTranscript.java rename to native_client/java/libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech_doc/CandidateTranscript.java diff --git a/native_client/java/libdeepspeech/src/main/java/org/deepspeech/libdeepspeech_doc/DeepSpeech_Error_Codes.java b/native_client/java/libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech_doc/DeepSpeech_Error_Codes.java similarity index 100% rename from native_client/java/libdeepspeech/src/main/java/org/deepspeech/libdeepspeech_doc/DeepSpeech_Error_Codes.java rename to native_client/java/libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech_doc/DeepSpeech_Error_Codes.java diff --git a/native_client/java/libdeepspeech/src/main/java/org/deepspeech/libdeepspeech_doc/Metadata.java b/native_client/java/libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech_doc/Metadata.java similarity index 100% rename from native_client/java/libdeepspeech/src/main/java/org/deepspeech/libdeepspeech_doc/Metadata.java rename to native_client/java/libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech_doc/Metadata.java diff --git a/native_client/java/libdeepspeech/src/main/java/org/deepspeech/libdeepspeech_doc/README.rst b/native_client/java/libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech_doc/README.rst similarity index 100% rename from native_client/java/libdeepspeech/src/main/java/org/deepspeech/libdeepspeech_doc/README.rst rename to native_client/java/libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech_doc/README.rst diff --git a/native_client/java/libdeepspeech/src/main/java/org/deepspeech/libdeepspeech_doc/TokenMetadata.java b/native_client/java/libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech_doc/TokenMetadata.java similarity index 100% rename from native_client/java/libdeepspeech/src/main/java/org/deepspeech/libdeepspeech_doc/TokenMetadata.java rename to native_client/java/libdeepspeech_android/src/main/java/org/deepspeech/libdeepspeech_doc/TokenMetadata.java diff --git a/native_client/java/libdeepspeech/src/main/res/values/strings.xml b/native_client/java/libdeepspeech_android/src/main/res/values/strings.xml similarity index 100% rename from native_client/java/libdeepspeech/src/main/res/values/strings.xml rename to native_client/java/libdeepspeech_android/src/main/res/values/strings.xml diff --git a/native_client/java/libdeepspeech/src/test/java/org/deepspeech/libdeepspeech/ExampleUnitTest.java b/native_client/java/libdeepspeech_android/src/test/java/org/deepspeech/libdeepspeech/ExampleUnitTest.java similarity index 100% rename from native_client/java/libdeepspeech/src/test/java/org/deepspeech/libdeepspeech/ExampleUnitTest.java rename to native_client/java/libdeepspeech_android/src/test/java/org/deepspeech/libdeepspeech/ExampleUnitTest.java diff --git a/native_client/java/libdeepspeech_jre/.gitignore b/native_client/java/libdeepspeech_jre/.gitignore new file mode 100644 index 0000000000..e4a37c9bbd --- /dev/null +++ b/native_client/java/libdeepspeech_jre/.gitignore @@ -0,0 +1,13 @@ +src/main/java/org/deepspeech/libdeepspeech/*.java +!src/main/java/org/deepspeech/libdeepspeech/DeepSpeechModel.java +!src/main/java/org/deepspeech/libdeepspeech/DeepSpeechStreamingState.java + +CMakeFiles/ +cmake_install.cmake +CMakeCache.txt +Makefile + +build/ + +libs/* +*.so \ No newline at end of file diff --git a/native_client/java/libdeepspeech_jre/CMakeLists.txt b/native_client/java/libdeepspeech_jre/CMakeLists.txt new file mode 100755 index 0000000000..63d460bcef --- /dev/null +++ b/native_client/java/libdeepspeech_jre/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.10) + +set(JAVA_AWT_INCLUDE_PATH NotNeeded) + +set(JAVA_HOME /usr/lib/jvm/java-1.11.0-openjdk-amd64) + +find_package(Java REQUIRED) +find_package(JNI REQUIRED) +include(UseJava) + +include_directories( ${CMAKE_JAVA_} /usr/lib/jvm/java-1.11.0-openjdk-amd64/include /usr/lib/jvm/java-1.11.0-openjdk-amd64/include/linux ) + +add_library( deepspeech-jni SHARED ../jni/deepspeech_wrap.cpp ) + +find_library(deepspeech-lib NAMES deepspeech PATHS ${CMAKE_SOURCE_DIR}/libs/x86_64/ REQUIRED) +message(STATUS ${deepspeech-lib}) + +add_custom_command( TARGET deepspeech-jni POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/libs/x86_64/libdeepspeech.so ${CMAKE_SOURCE_DIR}/libdeepspeech.so ) + +target_link_libraries( deepspeech-jni ${deepspeech-lib} ) \ No newline at end of file diff --git a/native_client/java/libdeepspeech_jre/build.gradle b/native_client/java/libdeepspeech_jre/build.gradle new file mode 100755 index 0000000000..c213aaa98f --- /dev/null +++ b/native_client/java/libdeepspeech_jre/build.gradle @@ -0,0 +1,83 @@ +apply plugin: 'maven' +apply plugin: 'java' + +allprojects { + sourceSets { + main.java.srcDirs = [ 'src/main/java/org/deepspeech/libdeepspeech/' ] + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + testImplementation 'junit:junit:4.12' +} + +task printABIs { + print ABI_FILTERS.split(';').join(" ") +} + +task sourcesJar(type: Jar) { + from sourceSets.main.output + classifier = 'sources' +} + +artifacts { + archives sourcesJar +} + +uploadArchives { + repositories { + mavenDeployer { + pom.packaging = 'aar' + pom.name = 'libdeepspeech' + pom.groupId = 'org.deepspeech' + pom.artifactId = 'libdeepspeech' + pom.version = dsVersionString + (project.hasProperty('snapshot') ? '-SNAPSHOT' : '') + + pom.project { + description 'Speech recognition library' + url 'https://github.com/mozilla/DeepSpeech' + + licenses { + license { + name 'MPL-2.0' + url 'https://www.mozilla.org/en-US/MPL/2.0/' + distribution 'repo' + } + } + + developers { + developer { + id 'deepspeech' + name 'DeepSpeech authors' + email 'deepspeechs@lists.mozilla.org' + } + } + + scm { + connection 'https://github.com/mozilla/DeepSpeech.git' + developerConnection 'https://github.com/mozilla/DeepSpeech.git' + url 'https://github.com/mozilla/DeepSpeech' + } + } + + repository(url: "file://${project.buildDir}/maven") + } + } +} + +task zipMavenArtifacts(type: Zip) { + from "${project.buildDir}/maven" + + include '**/*.aar' + include '**/*.jar' + include '**/*.pom' + include '**/*.md5' + include '**/*.sha1' + include '**/*maven-metadata.xml*' + + archiveName "${archivesBaseName}.maven.zip" + includeEmptyDirs = false + destinationDir(file("${project.buildDir}")) +} diff --git a/native_client/java/libdeepspeech_jre/docs/standalone.md b/native_client/java/libdeepspeech_jre/docs/standalone.md new file mode 100755 index 0000000000..731a6d5794 --- /dev/null +++ b/native_client/java/libdeepspeech_jre/docs/standalone.md @@ -0,0 +1,193 @@ +# DeepSpeech for standalone Java + +### Adding DeepSpeech to your Java project +>Note: You can do this on your own way too, but this works with the example usage code provided below. +1. Copy `libdeepspeech.jar` from `./build/` into `{YOUR PROJECT ROOT}/libs/` +2. Copy '*.so' from `./build/` into `{YOUR PROJECT ROOT}/src/main/resources/jni/x86_64/` +3. Modify your `build.gradle` file to include: +```groovy +plugins { + id 'com.github.johnrengelman.shadow' version '5.0.0' +} + +repositories { + flatDir { + dirs 'libs' + } +} + +dependencies { + compile ':libdeepspeech' +} +``` +4. You can now compile your project with `./gradlew shadowJar`. + +### Notes +- At this moment, this will only run on x86-64 Linux. + +### Example usage +`LibDeepSpeech.java` example +```java +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; + +import org.deepspeech.libdeepspeech.DeepSpeechModel; + +//This class facilitates the loading of the native libraries. +//The implementation in here works with the Gradle guide provided in the README.md document. +//However you can modify this to whatever you wish. +public class LibDeepSpeech extends DeepSpeechModel { + + public LibDeepSpeech(String modelPath) { + loadNativeLibs(); + super.loadModel(modelPath); + } + + @Override + public void loadNativeLibs() { + String jniName = "libdeepspeech-jni.so"; + String libName = "libdeepspeech.so"; + + System.out.println("Setting up DeepSpeech..."); + + URL jniUrl = DeepSpeechModel.class.getResource("/jni/x86_64/" + jniName); + URL libUrl = DeepSpeechModel.class.getResource("/jni/x86_64/" + libName); + File tmpDir = null; + try { + tmpDir = Files.createTempDirectory("libdeepspeech").toFile(); + } catch (IOException e) { + e.printStackTrace(); + } + tmpDir.deleteOnExit(); + + File jniTmpFile = new File(tmpDir, jniName); + jniTmpFile.deleteOnExit(); + File libTmpFile = new File(tmpDir, libName); + libTmpFile.deleteOnExit(); + + try ( + InputStream jniIn = jniUrl.openStream(); + InputStream libIn = libUrl.openStream(); + ) { + Files.copy(jniIn, jniTmpFile.toPath()); + Files.copy(libIn, libTmpFile.toPath()); + } catch (IOException e) { + e.printStackTrace(); + } + + System.load(jniTmpFile.getAbsolutePath()); + System.load(libTmpFile.getAbsolutePath()); + } +} +``` + +`DeepSpeechExample.java` +```java +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class DeepSpeechExample { + private LibDeepSpeech deepSpeechModel = null + + private final String TF_MODEL = "PATH_TO_YOUR_TENSORFLOW_MODEL"; + private final int BEAM_WIDTH = 50; + + public void createModel(String tensorFlowModel) { + if(this.deepSpeechModel == null) { + this.deepSpeechModel = new LibDeepSpeech(tensorFlowModel); + this.deepSpeechModel.setBeamWidth(BEAM_WIDTH); + } + } + + //The format we want is a 16Khz 16 bit mono .WAV file! + public void doInfer(String audioFile) { + long inferenceExecTime = 0L; + + //Create a new model to use during the inference + this.newModel(this.TF_MODEL); + + System.out.println("Extracting audio features..."); + + try { + RandomAccessFile wave = new RandomAccessFile(audioFile, "r"); + + //Assert that the audio format is PCM + wave.seek(20); + char audioFormat = this.readLEChar(wave); + assert (audioFormat == 1); // 1 is PCM + + //Assert that the amount of channels is 1, meaning mono audio + wave.seek(22); + char numChannels = this.readLEChar(wave); + assert (numChannels == 1); // MONO + + //Assert that the sample rate is the sample rate expected by the model + //This can vary per model! + wave.seek(24); + int sampleRate = this.readLEInt(wave); + assert (sampleRate == this.deepSpeechModel.sampleRate()); // desired sample rate + + //Assert that the bits per sample is 16 + wave.seek(34); + char bitsPerSample = this.readLEChar(wave); + assert (bitsPerSample == 16); // 16 bits per sample + + //Assert that the buffer size is more than 0 + wave.seek(40); + int bufferSize = this.readLEInt(wave); + assert (bufferSize > 0); + + //Read the actual contents of the audio + wave.seek(44); + byte[] bytes = new byte[bufferSize]; + wave.readFully(bytes); + + //Turn the byte[] into a short[] and set the correct byte order + short[] shorts = new short[bytes.length/2]; + ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts); + + System.out.println("Running inference..."); + + //current time. Used later on to calculate the time the inference took + long inferenceStartTime = System.currentTimeMillis(); + + //This is where we actually do the inference + String decoded = this.deepSpeechModel.stt(shorts, shorts.length); + + //Calculate how long it took to run the inference + inferenceExecTime = System.currentTimeMillis() - inferenceStartTime; + + System.out.println(decoded); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + System.out.println("Finished! Took " + inferenceExecTime); + } + + //Helper function to read a char from a RandomAccessFile in little endian + private char readLEChar(RandomAccessFile f) throws IOException { + byte b1 = f.readByte(); + byte b2 = f.readByte(); + return (char)((b2 << 8) | b1); + } + + //Helper function to read an integer from a RandomAccessFile in little endian + private int readLEInt(RandomAccessFile f) throws IOException { + byte b1 = f.readByte(); + byte b2 = f.readByte(); + byte b3 = f.readByte(); + byte b4 = f.readByte(); + return (int)((b1 & 0xFF) | (b2 & 0xFF) << 8 | (b3 & 0xFF) << 16 | (b4 & 0xFF) << 24); + } +} +``` \ No newline at end of file diff --git a/native_client/java/libdeepspeech_jre/gradle.properties b/native_client/java/libdeepspeech_jre/gradle.properties new file mode 100755 index 0000000000..9051129674 --- /dev/null +++ b/native_client/java/libdeepspeech_jre/gradle.properties @@ -0,0 +1 @@ +ABI_FILTERS = x86_64 diff --git a/native_client/java/libdeepspeech_jre/proguard-rules.pro b/native_client/java/libdeepspeech_jre/proguard-rules.pro new file mode 100644 index 0000000000..f1b424510d --- /dev/null +++ b/native_client/java/libdeepspeech_jre/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/native_client/java/libdeepspeech_jre/settings.gradle b/native_client/java/libdeepspeech_jre/settings.gradle new file mode 100644 index 0000000000..764791a121 --- /dev/null +++ b/native_client/java/libdeepspeech_jre/settings.gradle @@ -0,0 +1 @@ +include ':libdeepspeech_jre' \ No newline at end of file diff --git a/native_client/java/libdeepspeech_jre/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechModel.java b/native_client/java/libdeepspeech_jre/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechModel.java new file mode 100755 index 0000000000..778a9971cb --- /dev/null +++ b/native_client/java/libdeepspeech_jre/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechModel.java @@ -0,0 +1,272 @@ +package org.deepspeech.libdeepspeech; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; + +/** + * @brief Exposes a DeepSpeech model in Java + **/ +public class DeepSpeechModel { + + /** + * Create a new DeepSpeechModel object and load the native libraries.
+ * Use on: Android + */ + public DeepSpeechModel() { + System.loadLibrary("deepspeech-jni"); + System.loadLibrary("deepspeech"); + } + + /** + * Create a new DeepSpeechModel object.
+ * Use on: Android, Standalone + * @param loadNativeLibrariesManually if true, the native libraries will not be loaded. The developer must do this manually then. + */ + public DeepSpeechModel(boolean loadNativeLibrariesManually) { + if(!loadNativeLibrariesManually) { + System.loadLibrary("deepspeech-jni"); + System.loadLibrary("deepspeech"); + } + } + + // FIXME: We should have something better than those SWIGTYPE_* + private SWIGTYPE_p_p_ModelState _mspp; + private SWIGTYPE_p_ModelState _msp; + + private void evaluateErrorCode(int errorCode) { + DeepSpeech_Error_Codes code = DeepSpeech_Error_Codes.swigToEnum(errorCode); + if (code != DeepSpeech_Error_Codes.ERR_OK) { + throw new RuntimeException("Error: " + impl.ErrorCodeToErrorMessage(errorCode) + " (0x" + Integer.toHexString(errorCode) + ")."); + } + } + + /** + * @brief An object providing an interface to a trained DeepSpeech model. + * + * @constructor + * + * @param modelPath The path to the frozen model graph. + * + * @throws RuntimeException on failure. + */ + public void loadModel(String modelPath) { + this._mspp = impl.new_modelstatep(); + evaluateErrorCode(impl.CreateModel(modelPath, this._mspp)); + this._msp = impl.modelstatep_value(this._mspp); + } + + /** + * @brief Get beam width value used by the model. If setModelBeamWidth was not + * called before, will return the default value loaded from the model file. + * + * @return Beam width value used by the model. + */ + public long beamWidth() { + return impl.GetModelBeamWidth(this._msp); + } + + /** + * @brief Set beam width value used by the model. + * + * @param aBeamWidth The beam width used by the model. A larger beam width value + * generates better results at the cost of decoding time. + * + * @throws RuntimeException on failure. + */ + public void setBeamWidth(long beamWidth) { + evaluateErrorCode(impl.SetModelBeamWidth(this._msp, beamWidth)); + } + + /** + * @brief Return the sample rate expected by the model. + * + * @return Sample rate. + */ + public int sampleRate() { + return impl.GetModelSampleRate(this._msp); + } + + /** + * @brief Frees associated resources and destroys model object. + */ + public void freeModel() { + impl.FreeModel(this._msp); + } + + /** + * @brief Enable decoding using an external scorer. + * + * @param scorer The path to the external scorer file. + * + * @throws RuntimeException on failure. + */ + public void enableExternalScorer(String scorer) { + evaluateErrorCode(impl.EnableExternalScorer(this._msp, scorer)); + } + + /** + * @brief Disable decoding using an external scorer. + * + * @throws RuntimeException on failure. + */ + public void disableExternalScorer() { + evaluateErrorCode(impl.DisableExternalScorer(this._msp)); + } + + /** + * @brief Enable decoding using beam scoring with a KenLM language model. + * + * @param alpha The alpha hyperparameter of the decoder. Language model weight. + * @param beta The beta hyperparameter of the decoder. Word insertion weight. + * + * @throws RuntimeException on failure. + */ + public void setScorerAlphaBeta(float alpha, float beta) { + evaluateErrorCode(impl.SetScorerAlphaBeta(this._msp, alpha, beta)); + } + + /** + * @brief Use the DeepSpeech model to perform Speech-To-Text. + * + * @param buffer A 16-bit, mono raw audio signal at the appropriate + * sample rate (matching what the model was trained on). + * @param buffer_size The number of samples in the audio signal. + * + * @return The STT result. + */ + public String stt(short[] buffer, int buffer_size) { + return impl.SpeechToText(this._msp, buffer, buffer_size); + } + + /** + * @brief Use the DeepSpeech model to perform Speech-To-Text and output metadata + * about the results. + * + * @param buffer A 16-bit, mono raw audio signal at the appropriate + * sample rate (matching what the model was trained on). + * @param buffer_size The number of samples in the audio signal. + * @param num_results Maximum number of candidate transcripts to return. Returned list might be smaller than this. + * + * @return Metadata struct containing multiple candidate transcripts. Each transcript + * has per-token metadata including timing information. + */ + public Metadata sttWithMetadata(short[] buffer, int buffer_size, int num_results) { + return impl.SpeechToTextWithMetadata(this._msp, buffer, buffer_size, num_results); + } + + /** + * @brief Create a new streaming inference state. The streaming state returned + * by this function can then be passed to feedAudioContent() + * and finishStream(). + * + * @return An opaque object that represents the streaming state. + * + * @throws RuntimeException on failure. + */ + public DeepSpeechStreamingState createStream() { + SWIGTYPE_p_p_StreamingState ssp = impl.new_streamingstatep(); + evaluateErrorCode(impl.CreateStream(this._msp, ssp)); + return new DeepSpeechStreamingState(impl.streamingstatep_value(ssp)); + } + + /** + * @brief Feed audio samples to an ongoing streaming inference. + * + * @param cctx A streaming state pointer returned by createStream(). + * @param buffer An array of 16-bit, mono raw audio samples at the + * appropriate sample rate (matching what the model was trained on). + * @param buffer_size The number of samples in @p buffer. + */ + public void feedAudioContent(DeepSpeechStreamingState ctx, short[] buffer, int buffer_size) { + impl.FeedAudioContent(ctx.get(), buffer, buffer_size); + } + + /** + * @brief Compute the intermediate decoding of an ongoing streaming inference. + * + * @param ctx A streaming state pointer returned by createStream(). + * + * @return The STT intermediate result. + */ + public String intermediateDecode(DeepSpeechStreamingState ctx) { + return impl.IntermediateDecode(ctx.get()); + } + + /** + * @brief Compute the intermediate decoding of an ongoing streaming inference. + * + * @param ctx A streaming state pointer returned by createStream(). + * @param num_results Maximum number of candidate transcripts to return. Returned list might be smaller than this. + * + * @return The STT intermediate result. + */ + public Metadata intermediateDecodeWithMetadata(DeepSpeechStreamingState ctx, int num_results) { + return impl.IntermediateDecodeWithMetadata(ctx.get(), num_results); + } + + /** + * @brief Compute the final decoding of an ongoing streaming inference and return + * the result. Signals the end of an ongoing streaming inference. + * + * @param ctx A streaming state pointer returned by createStream(). + * + * @return The STT result. + * + * @note This method will free the state pointer (@p ctx). + */ + public String finishStream(DeepSpeechStreamingState ctx) { + return impl.FinishStream(ctx.get()); + } + + /** + * @brief Compute the final decoding of an ongoing streaming inference and return + * the results including metadata. Signals the end of an ongoing streaming + * inference. + * + * @param ctx A streaming state pointer returned by createStream(). + * @param num_results Maximum number of candidate transcripts to return. Returned list might be smaller than this. + * + * @return Metadata struct containing multiple candidate transcripts. Each transcript + * has per-token metadata including timing information. + * + * @note This method will free the state pointer (@p ctx). + */ + public Metadata finishStreamWithMetadata(DeepSpeechStreamingState ctx, int num_results) { + return impl.FinishStreamWithMetadata(ctx.get(), num_results); + } + /** + * @brief Add a hot-word + * + * @param word + * @param boost + * + * @throws RuntimeException on failure. + * + */ + public void addHotWord(String word, float boost) { + evaluateErrorCode(impl.AddHotWord(this._msp, word, boost)); + } + /** + * @brief Erase a hot-word + * + * @param word + * + * @throws RuntimeException on failure. + * + */ + public void eraseHotWord(String word) { + evaluateErrorCode(impl.EraseHotWord(this._msp, word)); + } + /** + * @brief Clear all hot-words. + * + * @throws RuntimeException on failure. + * + */ + public void clearHotWords() { + evaluateErrorCode(impl.ClearHotWords(this._msp)); + } +} diff --git a/native_client/java/libdeepspeech_jre/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechStreamingState.java b/native_client/java/libdeepspeech_jre/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechStreamingState.java new file mode 100755 index 0000000000..cd9aafe42c --- /dev/null +++ b/native_client/java/libdeepspeech_jre/src/main/java/org/deepspeech/libdeepspeech/DeepSpeechStreamingState.java @@ -0,0 +1,13 @@ +package org.deepspeech.libdeepspeech; + +public final class DeepSpeechStreamingState { + private SWIGTYPE_p_StreamingState _sp; + + public DeepSpeechStreamingState(SWIGTYPE_p_StreamingState sp) { + this._sp = sp; + } + + public SWIGTYPE_p_StreamingState get() { + return this._sp; + } +} diff --git a/native_client/java/settings.gradle b/native_client/java/settings.gradle deleted file mode 100644 index a31d5636a1..0000000000 --- a/native_client/java/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include ':app', ':libdeepspeech'