You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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<Boolean>
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()
}
The text was updated successfully, but these errors were encountered:
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
The text was updated successfully, but these errors were encountered: