alphacep / alphacep/vosk-android-demo

Vosk stopped recognizing speech when started from background

Open
#223 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
1.1k
Forks
278
PR merge metrics
No merged PRs in 30d

Description

Good day and thanks for this solution

I implemented Vosk in a service in android.
when I start it from the foreground, it works fine in recognizing speech (even though for few minutes)
my main challenge now is that, it doesnt recognize any speech at all when I start the service from background using WorkManager
and all logs are the same (fore and back scenarios).

I have tried audiofocus, tried reset of speechservice and recognizer. none works

```
class VoiceRecognitionService : Service() {

private lateinit var model: Model
private lateinit var recognizer: Recognizer
private var speechService: SpeechService? = null
private lateinit var ei: MyExternalIntegrator
private lateinit var modelReadyDeferred: CompletableDeferred
private val serviceScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private val tag = "SpeechService"

private var audioManager: AudioManager? = null
private var focusRetryCount = 0
private val maxFocusRetries = 5

companion object {
private const val NOTIFICATION_ID = 1
private const val ACTION_STOP_SERVICE = "ACTION_STOP_SERVICE"
}

override fun onCreate() {
super.onCreate()
ei = MyExternalIntegrator(this)
Log.i(tag, "onCreate")
// Initialize audio manager
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
initializeVosk()
LibVosk.setLogLevel(LogLevel.INFO)
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)

Log.i(tag, "onStartCommand")
if (intent?.action == ACTION_STOP_SERVICE) {
stopSelf()
SharedPrefs(applicationContext).setPrefValue("listen_state", false)
return START_NOT_STICKY
}

// Ensure audio focus before starting the service
if (!requestAudioFocus()) {
Log.e(tag, "Failed to gain audio focus, retrying")
retryAudioFocus()
return START_NOT_STICKY
}

// Start foreground service
startForeground(NOTIFICATION_ID, createNotification())

serviceScope.launch {
modelReadyDeferred.await() // Ensure Vosk model is ready
startListening() // Start listening after model is ready
}

return START_STICKY
}

private fun requestAudioFocus(): Boolean {
Log.i(tag, "Requesting audio focus")
val focusRequest = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT

val result = audioManager?.requestAudioFocus(
audioFocusChangeListener,
AudioManager.STREAM_MUSIC,
focusRequest
)

return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
}

private val audioFocusChangeListener = AudioManager.OnAudioFocusChangeListener { focusChange ->
Log.i(tag, "audioFocusChangeListener: $focusChange")
when (focusChange) {
AudioManager.AUDIOFOCUS_LOSS -> {
Log.e(tag, "Audio focus lost. Stopping service.")
stopSelf()
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
Log.i(tag, "Audio focus lost temporarily. Pausing...")
speechService?.stop()
retryAudioFocus() // Try to regain audio focus
}
AudioManager.AUDIOFOCUS_GAIN -> {
Log.i(tag, "Audio focus gained. Resuming listening...")
startListening() // Resume listening when focus is gained
}
}
}

private fun retryAudioFocus() {
Log.i(tag, "Retrying audio focus")
serviceScope.launch {
var retries = 0
while (retries < maxFocusRetries) {
delay(2000) // Wait 2 seconds before trying again
if (requestAudioFocus()) {
Log.i(tag, "Audio focus regained after retry ($retries/$maxFocusRetries)")
focusRetryCount = 0
startListening() // Resume listening once focus is regained
break
} else {
retries++
Log.e(tag, "Retrying audio focus ($retries/$maxFocusRetries)")
}
}

if (retries == maxFocusRetries) {
Log.e(tag, "Failed to regain audio focus after max of $maxFocusRetries retries. Stopping service.")
stopSelf() // Stop service if we can't regain audio focus
}
}
}

private fun createNotification(): Notification {
...
}

private fun initializeVosk() {
Log.i(tag, "Initializing Vosk model")
modelReadyDeferred = CompletableDeferred()

serviceScope.launch {
var retries = 0
val maxRetries = 5

while (retries < maxRetries) {
try {
val modelPath = copyAssetFolder(applicationContext, "vosk-model-small-en-us-0.15", "${applicationContext.filesDir}/vosk")
model = Model(modelPath)
recognizer = Recognizer(model, 16000.0f)
modelReadyDeferred.complete(true)
Log.i(tag, "Vosk model initialized successfully")
break
} catch (e: Exception) {
retries++
Log.e(tag, "Failed to initialize Vosk model. Retrying ($retries/$maxRetries)...")
delay(2000)
}
}

if (retries == maxRetries) {
modelReadyDeferred.completeExceptionally(Exception("Failed to initialize Vosk model after $maxRetries retries"))
}
}
}

private fun startListening() {
Log.i(tag, "Starting listening")

if (!this::recognizer.isInitialized) {
Log.e(tag, "Recognizer not initialized. Attempting to initialize...")
serviceScope.launch {
try {
initializeVosk()
initializeSpeechService()
} catch (e: Exception) {
Log.e(tag, "Error initializing Vosk or starting listening: ${e.message}")
}
}
} else {
initializeSpeechService()
}
}

private fun initializeSpeechService() {
if (speechService == null) {
Log.i(tag, "Initializing speech service")
speechService = SpeechService(recognizer, 16000.0f)
}

speechService?.reset() //todo remove
if (speechService?.startListening(resultListener) == false) {
Log.i(tag, "Starting speech service listening...")
speechService?.startListening(resultListener)
} else {
Log.i(tag, "Speech service is already listening")
}
}

private val resultListener = object : RecognitionListener {
override fun onPartialResult(hypothesis: String?) {
// Handle partial results if needed
}

override fun onResult(hypothesis: String?) {
Log.i(tag, "Recognized speech: $hypothesis")

}

override fun onFinalResult(hypothesis: String?) {
// Handle final results if needed
}

override fun onError(e: Exception?) {
Log.e(tag, "Recognition error: ${e?.message}")
}

override fun onTimeout() {
Log.i(tag, "Listening timeout, restarting...")
startListening()
}
}

override fun onDestroy() {
Log.i(tag, "Service destroyed")
serviceScope.cancel() // Cancel all ongoing coroutines
audioManager?.abandonAudioFocus(audioFocusChangeListener) // Release audio focus
speechService?.stop() // Stop speech service
speechService?.shutdown()
if (this::recognizer.isInitialized) { recognizer?.close() }
super.onDestroy()
}

override fun onBind(intent: Intent?): IBinder? = null

override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
restartService()
}

```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.