@mentra/bluetooth-sdk 0.1.9 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/README.md +116 -18
  2. package/android/build.gradle +289 -16
  3. package/android/gradle.properties.example +9 -0
  4. package/android/lc3Lib/build.gradle +95 -6
  5. package/android/settings.gradle +3 -0
  6. package/android/silero/LICENSE.md +17 -0
  7. package/android/silero/build.gradle +42 -0
  8. package/android/silero/proguard-rules.pro +24 -0
  9. package/android/silero/src/androidTest/assets/hello.wav +0 -0
  10. package/android/silero/src/androidTest/java/com/konovalov/vad/silero/VadSileroTest.kt +79 -0
  11. package/android/silero/src/main/assets/LICENSE +21 -0
  12. package/android/silero/src/main/assets/silero_vad.onnx +0 -0
  13. package/android/silero/src/main/java/com/konovalov/vad/silero/Vad.kt +160 -0
  14. package/android/silero/src/main/java/com/konovalov/vad/silero/VadSilero.kt +449 -0
  15. package/android/silero/src/main/java/com/konovalov/vad/silero/config/FrameSize.kt +15 -0
  16. package/android/silero/src/main/java/com/konovalov/vad/silero/config/Mode.kt +14 -0
  17. package/android/silero/src/main/java/com/konovalov/vad/silero/config/SampleRate.kt +12 -0
  18. package/android/silero/src/main/java/com/konovalov/vad/silero/utils/AudioUtils.kt +47 -0
  19. package/android/silero/src/main/java/com/konovalov/vad/silero/utils/TensorMap.kt +41 -0
  20. package/android/silero/src/test/java/com/konovalov/vad/silero/utils/AudioUtilsTest.kt +44 -0
  21. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkDefaults.kt +6 -0
  22. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +165 -27
  23. package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +89 -21
  24. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +189 -16
  25. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +22 -2
  26. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +787 -85
  27. package/android/src/main/java/com/mentra/bluetoothsdk/audio/AudioModels.kt +6 -2
  28. package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +123 -10
  29. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +12 -2
  30. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +8 -2
  31. package/android/src/main/java/com/mentra/bluetoothsdk/debug/BleTraceLogger.kt +33 -17
  32. package/android/src/main/java/com/mentra/bluetoothsdk/events/BluetoothEvents.kt +101 -0
  33. package/android/src/main/java/com/mentra/bluetoothsdk/internal/MapParsing.kt +8 -0
  34. package/android/src/main/java/com/mentra/bluetoothsdk/photoreceiver/LocalPhotoReceiverRegistry.java +108 -0
  35. package/android/src/main/java/com/mentra/bluetoothsdk/photoreceiver/LocalPhotoUploadServer.kt +399 -74
  36. package/android/src/main/java/com/mentra/bluetoothsdk/photoreceiver/MentraPhotoReceiverModule.kt +100 -17
  37. package/android/src/main/java/com/mentra/bluetoothsdk/requests/DisplayRequests.kt +17 -0
  38. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +2 -2
  39. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +569 -220
  40. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +2 -2
  41. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +271 -66
  42. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +176 -104
  43. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraosBle.java +12753 -27036
  44. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +54 -2
  45. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +16 -4
  46. package/android/src/main/java/com/mentra/bluetoothsdk/status/DeviceStatus.kt +60 -3
  47. package/android/src/main/java/com/mentra/bluetoothsdk/streaming/StreamModels.kt +12 -3
  48. package/android/src/main/java/com/mentra/bluetoothsdk/stt/STTTools.kt +87 -36
  49. package/android/src/main/java/com/mentra/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +13 -4
  50. package/android/src/main/java/com/mentra/bluetoothsdk/stt/VadGateSpeechPolicy.kt +229 -0
  51. package/android/src/main/java/com/mentra/bluetoothsdk/tts/TTSTools.kt +180 -0
  52. package/android/src/main/java/com/mentra/bluetoothsdk/utils/AvifExifStripper.java +573 -0
  53. package/android/src/main/java/com/mentra/bluetoothsdk/utils/BlePhotoUploadService.java +488 -50
  54. package/android/src/main/java/com/mentra/bluetoothsdk/utils/HeifExifTagReader.java +199 -0
  55. package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunkReassembler.java +18 -1
  56. package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunker.java +64 -18
  57. package/android/src/main/java/com/mentra/bluetoothsdk/utils/NexSGCUtils.kt +48 -39
  58. package/android/src/test/java/com/mentra/bluetoothsdk/camera/PhotoRequestTest.kt +23 -0
  59. package/android/src/test/java/com/mentra/bluetoothsdk/photoreceiver/LocalPhotoReceiverRegistryTest.java +75 -0
  60. package/android/src/test/java/com/mentra/bluetoothsdk/utils/AvifExifStripperTest.java +30 -0
  61. package/android/src/test/java/com/mentra/bluetoothsdk/utils/BlePhotoUploadServiceTest.java +98 -0
  62. package/android/src/test/resources/avif_with_exif.avif +0 -0
  63. package/build/BluetoothSdk.types.d.ts +241 -43
  64. package/build/BluetoothSdk.types.d.ts.map +1 -1
  65. package/build/BluetoothSdk.types.js +11 -10
  66. package/build/BluetoothSdk.types.js.map +1 -1
  67. package/build/_private/BluetoothSdkModule.d.ts +36 -23
  68. package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
  69. package/build/_private/BluetoothSdkModule.js +30 -52
  70. package/build/_private/BluetoothSdkModule.js.map +1 -1
  71. package/build/_private/photoRequestPayload.d.ts +4 -0
  72. package/build/_private/photoRequestPayload.d.ts.map +1 -0
  73. package/build/_private/photoRequestPayload.js +25 -0
  74. package/build/_private/photoRequestPayload.js.map +1 -0
  75. package/build/index.d.ts +1 -1
  76. package/build/index.d.ts.map +1 -1
  77. package/build/index.js +23 -0
  78. package/build/index.js.map +1 -1
  79. package/build/react/useMentraBluetooth.d.ts +2 -2
  80. package/build/react/useMentraBluetooth.d.ts.map +1 -1
  81. package/build/react/useMentraBluetooth.js +3 -3
  82. package/build/react/useMentraBluetooth.js.map +1 -1
  83. package/ios/BluetoothSdkModule.swift +174 -70
  84. package/ios/LocalPhotoUploadServer.swift +370 -105
  85. package/ios/MentraBluetoothSDK.podspec +3 -1
  86. package/ios/MentraPhotoReceiverModule.swift +62 -10
  87. package/ios/Packages/CoreObjC/include/PcmConverter.h +22 -0
  88. package/ios/Packages/SherpaOnnx/SherpaOnnx.swift +668 -26
  89. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Info.plist +13 -9
  90. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/Headers/sherpa-onnx/c-api/c-api.h +4551 -0
  91. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/Headers/sherpa-onnx/c-api/cxx-api.h +1745 -0
  92. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/libsherpa-onnx.a +0 -0
  93. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/Headers/sherpa-onnx/c-api/c-api.h +4551 -0
  94. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/Headers/sherpa-onnx/c-api/cxx-api.h +1745 -0
  95. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/libsherpa-onnx.a +0 -0
  96. package/ios/Source/BluetoothSdkDefaults.swift +6 -0
  97. package/ios/Source/Bridge.swift +58 -19
  98. package/ios/Source/DeviceManager.swift +149 -17
  99. package/ios/Source/DeviceStore.swift +16 -6
  100. package/ios/Source/MentraBluetoothSDK.swift +803 -47
  101. package/ios/Source/ObservableStore.swift +6 -0
  102. package/ios/Source/{Audio → audio}/AudioModels.swift +9 -7
  103. package/ios/Source/{Camera → camera}/CameraModels.swift +225 -16
  104. package/ios/Source/controllers/ControllerManager.swift +4 -3
  105. package/ios/Source/controllers/R1.swift +3 -3
  106. package/ios/Source/{Events → events}/BluetoothEvents.swift +183 -1
  107. package/ios/Source/{Internal → internal}/ValueParsing.swift +10 -1
  108. package/ios/Source/{Requests → requests}/DisplayRequests.swift +28 -4
  109. package/ios/Source/services/PhoneMic.swift +1 -0
  110. package/ios/Source/sgcs/G1.swift +2 -2
  111. package/ios/Source/sgcs/G2.swift +645 -403
  112. package/ios/Source/sgcs/Mach1.swift +2 -2
  113. package/ios/Source/sgcs/MentraLive.swift +812 -319
  114. package/ios/Source/sgcs/MentraNex.swift +412 -182
  115. package/ios/Source/sgcs/SGCManager.swift +57 -3
  116. package/ios/Source/sgcs/Simulated.swift +7 -3
  117. package/ios/Source/sgcs/mentraos_ble.pb.swift +3073 -3134
  118. package/ios/Source/status/DeviceStatus.swift +974 -0
  119. package/ios/Source/{Status → status}/WifiHotspotStatus.swift +4 -4
  120. package/ios/Source/{Streaming → streaming}/StreamModels.swift +24 -9
  121. package/ios/Source/stt/STTTools.swift +27 -12
  122. package/ios/Source/stt/SherpaOnnxTranscriber.swift +31 -8
  123. package/ios/Source/tts/TTSTools.swift +164 -0
  124. package/ios/Source/utils/JSCExperiment.swift +7 -7
  125. package/ios/Source/utils/MessageChunkReassembler.swift +20 -1
  126. package/ios/Source/utils/MessageChunker.swift +78 -21
  127. package/ios/Source/utils/TarBz2Extractor.swift +53 -2
  128. package/package.json +1 -1
  129. package/plugin/build/withAndroid.js +68 -4
  130. package/src/BluetoothSdk.types.ts +331 -59
  131. package/src/_private/BluetoothSdkModule.ts +113 -102
  132. package/src/_private/photoRequestPayload.ts +28 -0
  133. package/src/index.ts +58 -15
  134. package/src/react/useMentraBluetooth.ts +6 -4
  135. package/android/.project +0 -28
  136. package/android/lc3Lib/.project +0 -28
  137. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/cargs.h +0 -162
  138. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/c-api.h +0 -1852
  139. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/cxx-api.h +0 -674
  140. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/sherpa-onnx.a +0 -0
  141. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/sherpa-onnx.a +0 -0
  142. package/ios/Source/Status/DeviceStatus.swift +0 -471
  143. /package/ios/Source/{Connection → connection}/ScanSession.swift +0 -0
  144. /package/ios/Source/{Errors → errors}/BluetoothError.swift +0 -0
  145. /package/ios/Source/{Internal → internal}/BluetoothAvailability.swift +0 -0
  146. /package/ios/Source/{Status → status}/RuntimeState.swift +0 -0
  147. /package/ios/Source/{Types → types}/DeviceModels.swift +0 -0
@@ -7,12 +7,81 @@ plugins {
7
7
  }
8
8
 
9
9
  def packageJson = new JsonSlurper().parse(file("../../package.json"))
10
+ def mavenGroupId = 'com.mentraglass'
11
+ def mavenPublishVersion = (findProperty('mentraMavenVersion') ?: System.getenv('MENTRA_MAVEN_VERSION') ?: packageJson.version).toString()
10
12
 
11
- group = 'com.mentra'
12
- version = packageJson.version
13
+ group = mavenGroupId
14
+ version = mavenPublishVersion
13
15
 
14
- def isPublishTask = {
15
- gradle.taskGraph.allTasks.any { it.name.toLowerCase().contains("publish") }
16
+ def credentialValue = { List<String> propertyNames, List<String> envNames ->
17
+ for (propertyName in propertyNames) {
18
+ def value = findProperty(propertyName)
19
+ if (value != null && value.toString().trim()) {
20
+ return value.toString()
21
+ }
22
+ }
23
+ for (envName in envNames) {
24
+ def value = System.getenv(envName)
25
+ if (value != null && value.trim()) {
26
+ return value
27
+ }
28
+ }
29
+ return null
30
+ }
31
+
32
+ def centralTokenParts = { boolean failOnInvalid = false ->
33
+ def token = credentialValue(['sonatypeTokenBase64', 'mavenCentralTokenBase64'], ['SONATYPE_TOKEN_BASE64', 'MAVEN_CENTRAL_TOKEN_BASE64'])
34
+ if (!token) {
35
+ return null
36
+ }
37
+ def decoded
38
+ try {
39
+ decoded = new String(token.decodeBase64(), 'UTF-8')
40
+ } catch (Exception e) {
41
+ if (failOnInvalid) {
42
+ throw new GradleException('Sonatype token must be valid base64 for username:password', e)
43
+ }
44
+ return null
45
+ }
46
+ def separator = decoded.indexOf(':')
47
+ if (separator <= 0) {
48
+ if (failOnInvalid) {
49
+ throw new GradleException('Sonatype token must decode to username:password')
50
+ }
51
+ return null
52
+ }
53
+ return [decoded.substring(0, separator), decoded.substring(separator + 1)]
54
+ }
55
+
56
+ def centralUsername = { boolean failOnInvalidToken = false ->
57
+ credentialValue(['sonatypeUsername', 'mavenCentralUsername'], ['SONATYPE_USERNAME', 'MAVEN_CENTRAL_USERNAME']) ?: centralTokenParts(failOnInvalidToken)?.get(0)
58
+ }
59
+
60
+ def centralPassword = { boolean failOnInvalidToken = false ->
61
+ credentialValue(['sonatypePassword', 'mavenCentralPassword'], ['SONATYPE_PASSWORD', 'MAVEN_CENTRAL_PASSWORD']) ?: centralTokenParts(failOnInvalidToken)?.get(1)
62
+ }
63
+
64
+ def signingKey = {
65
+ credentialValue(['signingKey'], ['SIGNING_KEY'])
66
+ }
67
+
68
+ def signingPassword = {
69
+ credentialValue(['signingPassword'], ['SIGNING_PASSWORD'])
70
+ }
71
+
72
+ def shouldUseGpgCmd = {
73
+ (credentialValue(['signing.useGpgCmd'], ['SIGNING_USE_GPG_CMD']) ?: 'false').toBoolean()
74
+ }
75
+
76
+ def isCentralPublishTask = {
77
+ gradle.taskGraph.allTasks.any { it.name.toLowerCase().contains('sonatypecentral') }
78
+ }
79
+
80
+ gradle.taskGraph.whenReady {
81
+ if (isCentralPublishTask()) {
82
+ centralUsername(true)
83
+ centralPassword(true)
84
+ }
16
85
  }
17
86
 
18
87
  android {
@@ -67,7 +136,7 @@ afterEvaluate {
67
136
  publishing {
68
137
  publications {
69
138
  release(MavenPublication) {
70
- groupId = 'com.mentra'
139
+ groupId = mavenGroupId
71
140
  artifactId = 'lc3Lib'
72
141
  version = project.version
73
142
 
@@ -98,12 +167,32 @@ afterEvaluate {
98
167
  }
99
168
  }
100
169
  }
170
+ repositories {
171
+ maven {
172
+ name = 'sonatypeCentral'
173
+ url = uri('https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/')
174
+ credentials {
175
+ username = centralUsername()
176
+ password = centralPassword()
177
+ }
178
+ }
179
+ }
101
180
  }
102
181
 
103
182
  signing {
183
+ def inMemorySigningKey = signingKey()
184
+ if (inMemorySigningKey) {
185
+ useInMemoryPgpKeys(inMemorySigningKey, signingPassword())
186
+ } else if (shouldUseGpgCmd()) {
187
+ useGpgCmd()
188
+ }
104
189
  required {
105
- isPublishTask() && (findProperty("signing.keyId") || findProperty("signingKey"))
190
+ isCentralPublishTask()
106
191
  }
107
192
  sign publishing.publications.release
108
193
  }
109
194
  }
195
+
196
+ tasks.withType(Sign).configureEach {
197
+ onlyIf { isCentralPublishTask() }
198
+ }
@@ -1 +1,4 @@
1
1
  include ':lc3Lib'
2
+
3
+ include ':silero'
4
+ project(':silero').projectDir = new File(rootDir, 'silero')
@@ -0,0 +1,17 @@
1
+ Copyright 2023 Georgiy Konovalov
2
+
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
5
+ associated documentation files (the "Software"), to deal in the Software without restriction,
6
+ including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
+ and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all copies or substantial
11
+ portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
14
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
16
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,42 @@
1
+ // Vendored from https://github.com/gkonovalov/android-vad (silero module, v2.0.10)
2
+ // Consumed in-place by the bluetooth-sdk so we can pin ORT to a version that
3
+ // matches our other ORT consumer (sherpa-onnx) without depending on a Jitpack
4
+ // AAR whose prebuilt JNI was built against a different ORT.
5
+ plugins {
6
+ id 'com.android.library'
7
+ id 'kotlin-android'
8
+ }
9
+
10
+ android {
11
+ namespace "com.konovalov.vad.silero"
12
+ compileSdk 36
13
+
14
+ defaultConfig {
15
+ minSdkVersion 24
16
+ targetSdkVersion 36
17
+
18
+ ndk {
19
+ abiFilters "armeabi-v7a", "x86", "x86_64", "arm64-v8a"
20
+ }
21
+ }
22
+
23
+ aaptOptions {
24
+ noCompress "onnx"
25
+ }
26
+
27
+ compileOptions {
28
+ sourceCompatibility JavaVersion.VERSION_17
29
+ targetCompatibility JavaVersion.VERSION_17
30
+ }
31
+
32
+ kotlinOptions {
33
+ jvmTarget = '17'
34
+ }
35
+ }
36
+
37
+ dependencies {
38
+ // 1.24.3 matches the ORT version sherpa-onnx 1.13.2 was built against, so
39
+ // both consumers can share a single libonnxruntime.so (same versioned
40
+ // OrtGetApiBase@@VERS_1.24.3 symbol). Keep these versions in lockstep.
41
+ implementation 'com.microsoft.onnxruntime:onnxruntime-android:1.24.3'
42
+ }
@@ -0,0 +1,24 @@
1
+ # Add project specific ProGuard rules here.
2
+ # You can control the set of applied configuration files using the
3
+ # proguardFiles setting in build.gradle.
4
+ #
5
+ # For more details, see
6
+ # http://developer.android.com/guide/developing/tools/proguard.html
7
+
8
+ # If your project uses WebView with JS, uncomment the following
9
+ # and specify the fully qualified class name to the JavaScript interface
10
+ # class:
11
+ #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12
+ # public *;
13
+ #}
14
+
15
+ # Uncomment this to preserve the line number information for
16
+ # debugging stack traces.
17
+ #-keepattributes SourceFile,LineNumberTable
18
+
19
+ # If you keep the line number information, uncomment this to
20
+ # hide the original source file name.
21
+ #-renamesourcefileattribute SourceFile
22
+ -keep class ai.onnxruntime.** {*;}
23
+ -keep class com.konovalov.vad.** {*;}
24
+ -dontwarn com.google.**
@@ -0,0 +1,79 @@
1
+ package com.konovalov.silero
2
+
3
+ import android.content.Context
4
+ import androidx.test.ext.junit.runners.AndroidJUnit4
5
+ import androidx.test.platform.app.InstrumentationRegistry
6
+ import com.konovalov.vad.silero.Vad
7
+ import com.konovalov.vad.silero.VadSilero
8
+ import com.konovalov.vad.silero.config.FrameSize
9
+ import com.konovalov.vad.silero.config.Mode
10
+ import com.konovalov.vad.silero.config.SampleRate
11
+ import junit.framework.TestCase.assertEquals
12
+ import org.junit.After
13
+ import org.junit.Before
14
+ import org.junit.Test
15
+ import org.junit.runner.RunWith
16
+
17
+
18
+ /**
19
+ * Created by Georgiy Konovalov on 12/22/2023.
20
+ *
21
+ * Instrumented test for VadSilero class.
22
+ */
23
+ @RunWith(AndroidJUnit4::class)
24
+ class VadSileroTest {
25
+
26
+ private lateinit var vad: VadSilero
27
+ private lateinit var testContext: Context
28
+
29
+ @Before
30
+ fun setUp() {
31
+ this.testContext = InstrumentationRegistry.getInstrumentation().context
32
+
33
+ this.vad = Vad.builder()
34
+ .setContext(testContext)
35
+ .setSampleRate(SampleRate.SAMPLE_RATE_16K)
36
+ .setFrameSize(FrameSize.FRAME_SIZE_512)
37
+ .setMode(Mode.VERY_AGGRESSIVE)
38
+ .build()
39
+ }
40
+
41
+ @After
42
+ fun shutdown() {
43
+ vad.close()
44
+ }
45
+
46
+ @Test
47
+ fun testIsSpeech() {
48
+ // List for VAD results
49
+ val actualResult = mutableListOf<Boolean>()
50
+
51
+ // List with expected VAD results
52
+ val expectedResult = listOf(
53
+ false, false, false, false, false,
54
+ false, true, true, true, true,
55
+ true, true, true, true, true,
56
+ true, true, true, false, false
57
+ )
58
+
59
+ // Buffer size should be 2x for ByteArray
60
+ val chunkSize = vad.frameSize.value * 2
61
+
62
+ // Reading audio data from test file
63
+ testContext.assets.open("hello.wav").buffered().use { input ->
64
+ // Skip WAV Header
65
+ input.skip(44)
66
+
67
+ while (input.available() > 0) {
68
+ // Read audio Frame
69
+ val frameChunk = ByteArray(chunkSize).apply { input.read(this) }
70
+
71
+ // Save interference result
72
+ actualResult.add(vad.isSpeech(frameChunk))
73
+ }
74
+ }
75
+
76
+ // Compare expectedResult with actualResult
77
+ assertEquals(expectedResult, actualResult)
78
+ }
79
+ }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020-present Silero Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,160 @@
1
+ package com.konovalov.vad.silero
2
+
3
+ import android.content.Context
4
+ import com.konovalov.vad.silero.config.FrameSize
5
+ import com.konovalov.vad.silero.config.Mode
6
+ import com.konovalov.vad.silero.config.SampleRate
7
+
8
+ /**
9
+ * Created by Georgiy Konovalov on 6/26/2023.
10
+ *
11
+ * The Silero VAD algorithm, based on DNN, analyzes the audio signal to determine whether it
12
+ * contains speech or non-speech segments. It offers higher accuracy in differentiating speech from
13
+ * background noise compared to the WebRTC VAD algorithm.
14
+ *
15
+ * The Silero VAD supports the following parameters:
16
+ *
17
+ * Sample Rates:
18
+ *
19
+ * 8000Hz,
20
+ * 16000Hz
21
+ *
22
+ * Frame Sizes (per sample rate):
23
+ *
24
+ * For 8000Hz: 80, 160, 240
25
+ * For 16000Hz: 160, 320, 480
26
+ *
27
+ * Mode:
28
+ *
29
+ * NORMAL,
30
+ * LOW_BITRATE,
31
+ * AGGRESSIVE,
32
+ * VERY_AGGRESSIVE
33
+ *
34
+ * Please note that the VAD class supports these specific combinations of sample
35
+ * rates and frame sizes, and the classifiers determine the aggressiveness of the voice
36
+ * activity detection algorithm.
37
+ *
38
+ * @param context is required for reading the model file from file system.
39
+ * @param sampleRate is required for processing audio input.
40
+ * @param frameSize is required for processing audio input.
41
+ * @param mode is required for the VAD model.
42
+ * @param speechDurationMs is minimum duration in milliseconds for speech segments (optional).
43
+ * @param silenceDurationMs is minimum duration in milliseconds for silence segments (optional).
44
+ */
45
+ class Vad private constructor() {
46
+ private lateinit var context: Context
47
+ private lateinit var sampleRate: SampleRate
48
+ private lateinit var frameSize: FrameSize
49
+ private lateinit var mode: Mode
50
+ private var speechDurationMs = 0
51
+ private var silenceDurationMs = 0
52
+
53
+ /**
54
+ * Set Context for Vad Model.
55
+ *
56
+ * @param context is required for accessing the model file.
57
+ */
58
+ fun setContext(context: Context): Vad = apply {
59
+ this.context = context.applicationContext ?: context
60
+ }
61
+
62
+ /**
63
+ * Set, retrieve and validate sample rate for Vad Model.
64
+ *
65
+ * Valid Sample Rates:
66
+ *
67
+ * 8000Hz,
68
+ * 16000Hz
69
+ *
70
+ * @param sampleRate is required for processing audio input.
71
+ */
72
+ fun setSampleRate(sampleRate: SampleRate): Vad = apply {
73
+ this.sampleRate = sampleRate
74
+ }
75
+
76
+ /**
77
+ * Set, retrieve and validate frame size for Vad Model.
78
+ *
79
+ * Valid Frame Sizes (per sample rate):
80
+ *
81
+ * For 8000Hz: 256, 512, 768
82
+ * For 16000Hz: 512, 1024, 1536
83
+ *
84
+ * @param frameSize is required for processing audio input.
85
+ */
86
+ fun setFrameSize(frameSize: FrameSize): Vad = apply {
87
+ this.frameSize = frameSize
88
+ }
89
+
90
+ /**
91
+ * Set and retrieve detection mode for Vad model.
92
+ *
93
+ * Mode:
94
+ *
95
+ * NORMAL,
96
+ * LOW_BITRATE,
97
+ * AGGRESSIVE,
98
+ * VERY_AGGRESSIVE
99
+ *
100
+ * @param mode is required for the VAD model.
101
+ */
102
+ fun setMode(mode: Mode): Vad = apply {
103
+ this.mode = mode
104
+ }
105
+
106
+ /**
107
+ * Set the minimum duration in milliseconds for speech segments.
108
+ * The value of this parameter will define the necessary and sufficient duration of positive
109
+ * results to recognize result as speech. This parameter is optional.
110
+ *
111
+ * Permitted range (0ms >= speechDurationMs <= 300000ms).
112
+ *
113
+ * Parameters used for {@link VadSilero.isSpeech}.
114
+ *
115
+ * @param speechDurationMs minimum duration in milliseconds for speech segments.
116
+ */
117
+ fun setSpeechDurationMs(speechDurationMs: Int): Vad = apply {
118
+ this.speechDurationMs = speechDurationMs
119
+ }
120
+
121
+ /**
122
+ * Set the minimum duration in milliseconds for silence segments.
123
+ * The value of this parameter will define the necessary and sufficient duration of
124
+ * negative results to recognize it as silence. This parameter is optional.
125
+ *
126
+ * Permitted range (0ms >= silenceDurationMs <= 300000ms).
127
+ *
128
+ * Parameters used in {@link VadSilero.isSpeech}.
129
+ *
130
+ * @param silenceDurationMs minimum duration in milliseconds for silence segments.
131
+ */
132
+ fun setSilenceDurationMs(silenceDurationMs: Int): Vad = apply {
133
+ this.silenceDurationMs = silenceDurationMs
134
+ }
135
+
136
+ /**
137
+ * Builds and returns a VadModel instance based on the specified parameters.
138
+ *
139
+ * @return constructed VadSilero model.
140
+ * @throws IllegalArgumentException if invalid parameters have been set for the model.
141
+ * @throws OrtException if the model failed to parse, wasn't compatible or caused an error.
142
+ */
143
+ fun build(): VadSilero {
144
+ return VadSilero(
145
+ context,
146
+ sampleRate,
147
+ frameSize,
148
+ mode,
149
+ speechDurationMs,
150
+ silenceDurationMs
151
+ )
152
+ }
153
+
154
+ companion object {
155
+ @JvmStatic
156
+ fun builder(): Vad {
157
+ return Vad()
158
+ }
159
+ }
160
+ }