Android 熄屏一段时间后TTS停止朗读

Android TTS stops reading aloud after the screen is turned off for a while

我正在开发一个需要在屏幕关闭后继续大声朗读文本的应用程序。为了达到这个目的,我把文字转语音(TTS)的代码放在了Foreground Service中,这样TTS可以在屏幕关闭时保持运行。

它之前在我的 phone 上运行良好。但是我把我的phone从Android11升级到Android12后,TTS会在屏幕关闭一段时间后停止工作,通常是几分钟后。

一般情况下,TTS说完一句话后,会调用UtteranceProgressListeneronDone方法,这样我就可以让TTS在那里说下一句了。 TTS 停止工作的原因是 onDone 方法在屏幕关闭一段时间后停止调用。它不会立即停止,而是在几分钟后停止,有时更长,有时更短。

我猜是新的AndroidOS的电池优化导致了这个问题。但是我关闭系统电池优化后,它也不起作用。我还注意到一些类似的应用程序有同样的问题,但有些应用程序没有。我该如何解决这个问题?

此代码在 Android 12 中运行,即使应用程序在后台运行

class TTS:服务(),OnInitListener {

private var tts: TextToSpeech? = null
private lateinit var spokenText: String
private var isInit: Boolean = false

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    if(intent?.extras != null) {
        spokenText = intent.getStringExtra("text").toString()
    }
    else {
        spokenText = ""
    }
    Log.d(TAG, "onStartCommand: $spokenText")
    return START_NOT_STICKY
}

override fun onCreate() {
    tts = TextToSpeech(this, this)
    Log.d(TAG, "onCreate: CREATING AGAIN !!")
}

override fun onInit(status: Int) {
    if (status == TextToSpeech.SUCCESS) {
        Log.d(TAG, "onInit: TextToSpeech Success")
        val result = tts!!.setLanguage(Locale("hi", "IN"))
        if (result != TextToSpeech.LANG_MISSING_DATA && result != TextToSpeech.LANG_NOT_SUPPORTED) {
            Log.d(TAG, "onInit: speaking........")
            addAudioAttributes()
            isInit = true
        }
    }
    else {
        Log.d(TAG, "onInit: TTS initialization failed")
        Toast.makeText(
            applicationContext,
            "Your device don't support text to speech.\n Visit app to download!!",
            Toast.LENGTH_SHORT
        ).show()
    }
}

private fun addAudioAttributes() {
    val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        val audioAttributes = AudioAttributes.Builder()
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
            .build()
        tts?.setAudioAttributes(audioAttributes)
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val focusRequest =
            AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
                .setAudioAttributes(
                    AudioAttributes.Builder()
                        .setUsage(AudioAttributes.USAGE_MEDIA)
                        .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                        .build()
                )
                .setAcceptsDelayedFocusGain(true)
                .setOnAudioFocusChangeListener { focus ->
                    when (focus) {
                        AudioManager.AUDIOFOCUS_GAIN -> {
                        }
                        else -> stopSelf()
                    }
                }.build()

        when (audioManager.requestAudioFocus(focusRequest)) {
            AudioManager.AUDIOFOCUS_REQUEST_GRANTED -> speak(audioManager, focusRequest)
            AudioManager.AUDIOFOCUS_REQUEST_DELAYED -> stopSelf()
            AudioManager.AUDIOFOCUS_REQUEST_FAILED -> stopSelf()
        }

    } else {
        val result = audioManager.requestAudioFocus( { focusChange: Int ->
            when(focusChange) {
                AudioManager.AUDIOFOCUS_GAIN -> {
                }
                else -> stopSelf()
            }
        },
            AudioManager.STREAM_MUSIC,
            AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
        )

        if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
            speak(audioManager, null)
        }
    }
}

private fun speak(audioManager: AudioManager, focusRequest: AudioFocusRequest?) {
    val speechListener = object : UtteranceProgressListener() {
        override fun onStart(utteranceId: String?) {
            Log.d(TAG, "onStart: Started syntheses.....")
        }

        override fun onDone(utteranceId: String?) {
            Log.d(TAG, "onDone: Completed synthesis ")
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && focusRequest != null) {
                audioManager.abandonAudioFocusRequest(focusRequest)
            }
            stopSelf()
        }

        override fun onError(utteranceId: String?) {
            Log.d(TAG, "onError: Error synthesis")
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && focusRequest != null) {
                audioManager.abandonAudioFocusRequest(focusRequest)
            }
            stopSelf()
        }
    }
    val paramsMap: HashMap<String, String> = HashMap()
    paramsMap[TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID] = "tts_service"

    tts?.speak(spokenText, TextToSpeech.QUEUE_ADD, paramsMap)
    tts?.setOnUtteranceProgressListener(speechListener)
}

override fun onDestroy() {
    if (tts != null) {
        Log.d(TAG, "onDestroy: destroyed tts")
        tts?.stop()
        tts?.shutdown()
    }
    super.onDestroy()
}

override fun onBind(arg0: Intent?): IBinder? {
    return null
}

companion object {
    private const val TAG = "TTS_Service"
}

}