Android RecognitionListener: onResults est appelé deux fois

10

J'ai un projet utilisant RecognitionListener écrit en Kotlin. La fonction de synthèse vocale a toujours été un succès et n'a jamais posé de problème.

Depuis la semaine dernière, sa fonction onResult a commencé à être appelée deux fois. Aucune modification n'a été apportée au projet. J'ai testé les anciennes versions du projet (il y a des mois) et celles-ci avaient le même problème.

Il existe trois cas différents:

  1. Petit texte (1 à 8 mots) et SpeechRecognizer arrêté automatiquement -> onResult () appelé deux fois;
  2. Gros texte (9 mots ou plus) et SpeechRecognizer arrêté automatiquement -> Comportement normal (onResult () appelé une fois);
  3. N'importe quelle taille de texte et fonction stopListening () de SpeechRecognizer appelée manuellement (à partir du code) -> Comportement normal.

Voici le code de classe de synthèse vocale VoiceRecognition:

class VoiceRecognition(private val activity: Activity, language: String = "pt_BR") : RecognitionListener {

    private val AudioLogTag = "AudioInput"

    var voiceRecognitionIntentHandler: VoiceRecognitionIntentHandler? = null
    var voiceRecognitionOnResultListener: VoiceRecognitionOnResultListener? = null //Must have this
    var voiceRecognitionLayoutChanger: VoiceRecognitionLayoutChanger? = null

    var isListening = false

    private val intent: Intent
    private var speech: SpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(activity)

    init {
        speech.setRecognitionListener(this)

        intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
        intent.putExtra(
            RecognizerIntent.EXTRA_LANGUAGE_MODEL,
            RecognizerIntent.LANGUAGE_MODEL_FREE_FORM
        )
        intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language)
    }

    //It is important to put this function inside a clickListener
    fun listen(): Boolean {
        if (ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.RECORD_AUDIO), 1)
            return false
        }

        speech.startListening(intent)

        Log.i(AudioLogTag, "startListening")

        return true
    }

    //Use this if you want to stop listening but still get recognition results
    fun endListening(){
        Log.i(AudioLogTag, "stopListening")

        speech.stopListening()
        isListening = false
    }

    fun cancelListening(){
        Log.i(AudioLogTag, "cancelListening")

        speech.cancel()
        voiceRecognitionLayoutChanger?.endListeningChangeLayout()
        isListening = false
    }

    override fun onReadyForSpeech(p0: Bundle?) {
        Log.i(AudioLogTag, "onReadyForSpeech")

        voiceRecognitionLayoutChanger?.startListeningChangeLayout()
        isListening = true
    }

    override fun onRmsChanged(p0: Float) {
//        Log.i(AudioLogTag, "onRmsChanged: $p0")
//        progressBar.setProgress((Int) p0)
    }

    override fun onBufferReceived(p0: ByteArray?) {
        Log.i(AudioLogTag, "onBufferReceived: $p0")
    }

    override fun onPartialResults(p0: Bundle?) {
        Log.i(AudioLogTag, "onPartialResults")
    }

    override fun onEvent(p0: Int, p1: Bundle?) {
        Log.i(AudioLogTag, "onEvent")
    }

    override fun onBeginningOfSpeech() {
        Log.i(AudioLogTag, "onBeginningOfSpeech")
    }

    override fun onEndOfSpeech() {
        Log.i(AudioLogTag, "onEndOfSpeech")

        voiceRecognitionLayoutChanger?.endListeningChangeLayout()
        isListening = false
    }

    override fun onError(p0: Int) {
        speech.cancel()
        val errorMessage = getErrorText(p0)
        Log.d(AudioLogTag, "FAILED: $errorMessage")
        voiceRecognitionLayoutChanger?.endListeningChangeLayout()
        isListening = false
    }

    override fun onResults(p0: Bundle?) {

        val results: ArrayList<String> = p0?.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION) as ArrayList<String>

        Log.i(AudioLogTag, "onResults -> ${results.size}")

        val voiceIntent: Int? = voiceRecognitionIntentHandler?.getIntent(results[0])
        if (voiceIntent != null && voiceIntent != 0) {
            voiceRecognitionIntentHandler?.handle(voiceIntent)
            return
        }

        voiceRecognitionOnResultListener!!.onResult(results[0])
    }

    private fun getErrorText(errorCode: Int): String {
        val message: String
        when (errorCode) {
            SpeechRecognizer.ERROR_AUDIO -> message = "Audio recording error"
            SpeechRecognizer.ERROR_CLIENT -> message = "Client side error"
            SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS -> message = "Insufficient permissions"
            SpeechRecognizer.ERROR_NETWORK -> message = "Network error"
            SpeechRecognizer.ERROR_NETWORK_TIMEOUT -> message = "Network timeout"
            SpeechRecognizer.ERROR_NO_MATCH -> message = "No match"
            SpeechRecognizer.ERROR_RECOGNIZER_BUSY -> message = "RecognitionService busy"
            SpeechRecognizer.ERROR_SERVER -> message = "Error from server"
            SpeechRecognizer.ERROR_SPEECH_TIMEOUT -> message = "No speech input"
            else -> message = "Didn't understand, please try again."
        }
        return message
    }

    //Use it in your overriden onPause function.
    fun onPause() {
        voiceRecognitionLayoutChanger?.endListeningChangeLayout()
        isListening = false

        speech.cancel()
        Log.i(AudioLogTag, "pause")
    }

    //Use it in your overriden onDestroy function.
    fun onDestroy() {
        speech.destroy()
    }

listen (), endListening () et cancelListening () sont tous appelés à partir d'un bouton.

Pedro Henrique Flores
la source
J'ai le même problème, le problème ne concerne que le Samsung s8 avec l'api 9 - ici, je peux également voir des résultats partiels lorsque la reconnaissance est en cours. Sur les appareils plus anciens, je n'en vis pas.
marcinj
J'ai vu ce problème depuis Android 7 et au-dessus ... Je n'ai même pas changé mon projet .. il a juste commencé à se produire.
Pedro Henrique Flores
"le problème est uniquement sur Samsung s8 avec api 9" - j'entendais par là dans mes tests sur les appareils que j'ai
marcinj
1
même problème sur Pocophone F1, ma solution était de vérifier si les résultats sont identiques, puis d'ignorer le deuxième résultat s'ils le sont
Lotan
Hier, cela vient de se produire dans l'une de mes applications. J'ai ajouté un booléen pour permettre au code de ne s'exécuter qu'une seule fois, mais j'aimerais une explication pour expliquer pourquoi il a soudainement commencé à faire cela. Les mises à jour?
Gavin Wright

Réponses:

3

J'ai trouvé ce problème ouvert: https://issuetracker.google.com/issues/152628934

Comme je l'ai commenté, je suppose que c'est un problème avec le "service de reconnaissance vocale" et non avec la classe Android RecognitionListener.

Al-Punk
la source
Ouais, je crois aussi que c'est le problème ..
Pedro Henrique Flores
1

Hier, cela a commencé à se produire dans l'une de mes applications. J'ai ajouté un booléen pour permettre au code de ne s'exécuter qu'une seule fois, mais j'aimerais une explication pour expliquer pourquoi il a soudainement commencé à faire cela. Les mises à jour?

Gavin Wright
la source
0

J'ai eu le même problème et je viens d'ajouter un drapeau booléen dans mon code, mais bien sûr, c'est une solution temporaire et je ne connais pas la source de ce problème.

object : RecognitionListener {

        var singleResult = true

        override fun onResults(results: Bundle?) {
            if (singleResult) {
                results?.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION).let {
                    // do something with result
                }
                // next result will be ignored
                singleResult = false
            }
        }
    }
Grobocop12
la source
Veuillez ajouter un exemple de code.
m02ph3u5 Il y a