Created
April 20, 2022 02:53
-
-
Save anhtuank7c/b543fe4a59a801fa5c5547ccedd2d6e8 to your computer and use it in GitHub Desktop.
AudioCue class, let initial this class to call speakOut function to speech the text.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example; | |
import android.content.Context | |
import android.content.Context.AUDIO_SERVICE | |
import android.media.AudioAttributes | |
import android.media.AudioFocusRequest | |
import android.media.AudioManager | |
import android.os.Build | |
import android.os.Bundle | |
import android.speech.tts.TextToSpeech | |
import android.speech.tts.UtteranceProgressListener | |
import com.facebook.react.bridge.UiThreadUtil.runOnUiThread | |
import java.math.RoundingMode | |
import java.util.* | |
import kotlin.math.floor | |
class AudioCue(context: Context): TextToSpeech.OnInitListener, UtteranceProgressListener() { | |
private val settings = AudioCueSetting.getSavedSetting() | |
private var textToSpeech: TextToSpeech = TextToSpeech(context, this, "com.google.android.tts") | |
private val audioManager = context.getSystemService(AUDIO_SERVICE) as AudioManager | |
private var focusRequest: AudioFocusRequest? = null | |
private var ttsReady: Boolean = false | |
private var mContext: Context = context | |
companion object { | |
val supportedLanguages = listOf("ar", "da", "de", "en", "es", "fr", "it", "ja", "nb", "nl", "pl_PL", "pt", "sv") | |
} | |
init { | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | |
val playbackAttributes = AudioAttributes.Builder() | |
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) | |
.setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT) | |
.build() | |
focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) | |
.setAudioAttributes(playbackAttributes) | |
.setAcceptsDelayedFocusGain(false) | |
.setWillPauseWhenDucked(false) | |
.setOnAudioFocusChangeListener { focusChange -> | |
when (focusChange) { | |
AudioManager.AUDIOFOCUS_LOSS -> { | |
textToSpeech.stop() | |
} | |
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { | |
textToSpeech.stop() | |
} | |
} | |
} | |
.build() | |
} | |
} | |
override fun onInit(status: Int) { | |
if (status == TextToSpeech.SUCCESS) { | |
val result = textToSpeech.setLanguage(getCurrentLocale()) | |
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { | |
Logger.nonFatal(Throwable("The Language specified is not supported!")) | |
return | |
} | |
textToSpeech.setOnUtteranceProgressListener(this@AudioCue) | |
ttsReady = true | |
return | |
} | |
Logger.nonFatal(Throwable("Failed to initialization Text To Speech!")) | |
} | |
/** | |
* get default locale | |
* fallback to the English if current locale is not in supported languages list | |
*/ | |
private fun getCurrentLocale(): Locale { | |
val language = Util.getLocale().toLowerCase() | |
if (supportedLanguages.contains(language)) { | |
return Locale(language) | |
} | |
return Locale.ENGLISH | |
} | |
private fun speakOut(message: String) { | |
if (!ttsReady) return | |
runOnUiThread { | |
val params = Bundle() | |
params.putInt(TextToSpeech.Engine.KEY_PARAM_STREAM, AudioManager.STREAM_MUSIC) | |
val request = focusRequest | |
val result: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && request != null) { | |
audioManager.requestAudioFocus(request) | |
} else { | |
audioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) | |
} | |
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { | |
textToSpeech.speak(message, TextToSpeech.QUEUE_ADD, params, Date().time.toString()) | |
} | |
} | |
} | |
private var mCallback: (() -> Unit)? = null | |
fun finish(callback: () -> Unit) { | |
mCallback = callback | |
textToSpeech.stop() | |
} | |
override fun onStop(utteranceId: String?, interrupted: Boolean) { | |
super.onStop(utteranceId, interrupted) | |
} | |
override fun onStart(utteranceId: String?) { | |
} | |
override fun onDone(utteranceId: String?) { | |
val request = focusRequest | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && request != null) { | |
audioManager.abandonAudioFocusRequest(request) | |
} else { | |
audioManager.abandonAudioFocus(null) | |
} | |
mCallback?.let { it() } | |
} | |
override fun onError(utteranceId: String?) { | |
mCallback?.let { it() } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage example: