Roman Inflianskas
Committed by GitHub

SherpaOnnxVadAsr: Offload runSecondPass to background thread for improved real-t…

…ime audio processing (#1638)

This change ensures that the main audio processing loop is not blocked by
long-running operations in `runSecondPass`, improving responsiveness and
reducing the risk of missing parts of input speech.
@@ -19,6 +19,11 @@ import com.k2fsa.sherpa.onnx.Vad @@ -19,6 +19,11 @@ import com.k2fsa.sherpa.onnx.Vad
19 import com.k2fsa.sherpa.onnx.getFeatureConfig 19 import com.k2fsa.sherpa.onnx.getFeatureConfig
20 import com.k2fsa.sherpa.onnx.getOfflineModelConfig 20 import com.k2fsa.sherpa.onnx.getOfflineModelConfig
21 import com.k2fsa.sherpa.onnx.getVadModelConfig 21 import com.k2fsa.sherpa.onnx.getVadModelConfig
  22 +import kotlinx.coroutines.CoroutineScope
  23 +import kotlinx.coroutines.Dispatchers
  24 +import kotlinx.coroutines.cancel
  25 +import kotlinx.coroutines.launch
  26 +import kotlinx.coroutines.withContext
22 import kotlin.concurrent.thread 27 import kotlin.concurrent.thread
23 28
24 29
@@ -166,6 +171,8 @@ class MainActivity : AppCompatActivity() { @@ -166,6 +171,8 @@ class MainActivity : AppCompatActivity() {
166 171
167 val bufferSize = 512 // in samples 172 val bufferSize = 512 // in samples
168 val buffer = ShortArray(bufferSize) 173 val buffer = ShortArray(bufferSize)
  174 + val coroutineScope = CoroutineScope(Dispatchers.IO)
  175 +
169 176
170 while (isRecording) { 177 while (isRecording) {
171 val ret = audioRecord?.read(buffer, 0, buffer.size) 178 val ret = audioRecord?.read(buffer, 0, buffer.size)
@@ -175,11 +182,15 @@ class MainActivity : AppCompatActivity() { @@ -175,11 +182,15 @@ class MainActivity : AppCompatActivity() {
175 vad.acceptWaveform(samples) 182 vad.acceptWaveform(samples)
176 while(!vad.empty()) { 183 while(!vad.empty()) {
177 var segment = vad.front() 184 var segment = vad.front()
178 - val text = runSecondPass(segment.samples)  
179 -  
180 - if (text.isNotBlank()) {  
181 - lastText = "${lastText}\n${idx}: ${text}"  
182 - idx += 1 185 + coroutineScope.launch {
  186 + val text = runSecondPass(segment.samples)
  187 + if (text.isNotBlank()) {
  188 + withContext(Dispatchers.Main) {
  189 + lastText = "${lastText}\n${idx}: ${text}"
  190 + idx += 1
  191 + textView.text = lastText.lowercase()
  192 + }
  193 + }
183 } 194 }
184 195
185 vad.pop(); 196 vad.pop();
@@ -192,6 +203,9 @@ class MainActivity : AppCompatActivity() { @@ -192,6 +203,9 @@ class MainActivity : AppCompatActivity() {
192 } 203 }
193 } 204 }
194 } 205 }
  206 +
  207 + // Clean up the coroutine scope when done
  208 + coroutineScope.cancel()
195 } 209 }
196 210
197 private fun initOfflineRecognizer() { 211 private fun initOfflineRecognizer() {