[Android] STT
🙋♀️ STT(Speech To Text)
STT란 무엇일까?? 이는 Speech To Text의 줄임말로 말 그대로 음성을 텍스트로 전환하는 것을 말한다.
안드로이드에서는 Speach API를 활용해 STT 기능을 구현할 수 있다.
🙋♀️ Speech API 사용법
➡️ 필요한 권한 획득
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
➡️ STT 작업 진행
우선 stt를 적용하기 위해서 버전과 퍼미션 체크를 진행해야 한다.
private fun isPermissionGranted(): Boolean {
return !(Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED)
}
private val requestAudioLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()) { isGranted ->
if (!isGranted) {
val error = resources.getString(R.string.dialog_permission)
val dialog = AudioPermissionDialog(error)
dialog.show(requireActivity().supportFragmentManager, "AudioPermissionDialog")
}
}
ActivityReusltContract의 RequestPermission을 통해 Audio 권한을 요청한다.
ActivityContract에 대한 자세한 설명은 다음 게시글을 참고하길 바란다.
음성 인식 서비스에 접근하려면 SpeechRecognizer
클래스를 사용해야 한다. 해당 클래스를 사용하기 위해서는 createSpeechRecognizer
를 통해서 SpeechRecognizer 클래스를 생성해야 한다.
또한, 음성 인식을 실행하려면 intent를 생성해야 하는데 RecognizerIntent
를 사용한다.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val speechRecognizer = SpeechRecognizer.createSpeechRecognizer(context)
val speechRecognizerIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
//음성 인식의 음성 모델 정보 설정
speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
//음성 인식의 인식되는 언어 설정
speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "ko-KR")
...
다음으로 listener를 정의해 음성 인식 과정을 처리한다.
이때 사용하는 것이 RecognitionListener
이다.
private val recognitionListener: RecognitionListener = object: RecognitionListener {
//말하기 시작할 준비가 될 때 호출
override fun onReadyForSpeech(p0: Bundle?) {
TODO("Not yet implemented")
}
//말하기 시작할 때 호출
override fun onBeginningOfSpeech() {
TODO("Not yet implemented")
}
//사운드 크기가 달라졌을 때 호출
override fun onRmsChanged(p0: Float) {
TODO("Not yet implemented")
}
//말하기 시작하고 더 많은 단어들이 인식되었을 때 호출
override fun onBufferReceived(p0: ByteArray?) {
TODO("Not yet implemented")
}
//말하기가 끝났을 때 호출
override fun onEndOfSpeech() {
TODO("Not yet implemented")
}
//에러가 발생했을 때 호출
override fun onError(p0: Int) {
TODO("Not yet implemented")
}
//인식 결과가 준비되면 호출
override fun onResults(p0: Bundle?) {
TODO("Not yet implemented")
}
//부분적으로 인식된 결과를 사용할 수 있을 때 호출
override fun onPartialResults(p0: Bundle?) {
TODO("Not yet implemented")
}
//향후 이벤트를 예약
override fun onEvent(p0: Int, p1: Bundle?) {
TODO("Not yet implemented")
}
}
이렇게 작성한 리스너를 이제 SpeechRecognizer
에 설정하면 된다.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
...
speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "ko-KR")
//리스너 설정
speechRecognizer.setRecognitionListener(recognitionListener)
이렇게 하면 stt를 사용할 준비가 되었다!!!
이제 직접 사용해보자!!
//음성 인식 시작
speechRecognizer.startListening(speechRecognizerIntent)
//음성 인식 종료
speechRecognizer.stopListening()
위의 시작/종료 코드를 버튼 리스너 속에 작성하는 등 필요한 부분에서 사용하면 된다!
➡️ 전체 코드
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val speechRecognizer = SpeechRecognizer.createSpeechRecognizer(context)
val speechRecognizerIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "ko-KR")
speechRecognizer.setRecognitionListener(recognitionListener)
binding.btnRadioPlay.setOnClickListener {
if (isPermissionGranted()) {
speechRecognizer.startListening(speechRecognizerIntent)
} else{
requestAudioLauncher.launch(Manifest.permission.RECORD_AUDIO)
}
}
binding.btnRadioStop.setOnClickListener {
speechRecognizer.stopListening()
}
}
private fun isPermissionGranted(): Boolean {
return !(Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED)
}
private val requestAudioLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()) { isGranted ->
if (!isGranted) {
val error = resources.getString(R.string.dialog_permission)
val dialog = AudioPermissionDialog(error)
dialog.show(requireActivity().supportFragmentManager, "AudioPermissionDialog")
}
}
private val recognitionListener: RecognitionListener = object: RecognitionListener {
override fun onReadyForSpeech(p0: Bundle?) {}
override fun onBeginningOfSpeech() {
binding.btnRadioPlay.visibility = View.GONE
binding.btnRadioStop.visibility = View.VISIBLE
}
override fun onRmsChanged(p0: Float) {}
override fun onBufferReceived(p0: ByteArray?) {}
override fun onEndOfSpeech() {
binding.btnRadioStop.visibility = View.GONE
binding.btnRadioPlay.visibility = View.VISIBLE
}
override fun onError(p0: Int) {
val message = when (p0) {
SpeechRecognizer.ERROR_AUDIO -> resources.getString(R.string.stt_audio_error)
SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS -> resources.getString(R.string.stt_permission_error)
SpeechRecognizer.ERROR_NETWORK -> resources.getString(R.string.stt_network_error)
SpeechRecognizer.ERROR_SPEECH_TIMEOUT -> resources.getString(R.string.stt_time_error)
else -> resources.getString(R.string.stt_default_error)
}
//메세지 처리
Log.d("error", message)
}
override fun onResults(p0: Bundle?) {
p0?.let {
val content: ArrayList<String>? =
p0.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)
content.let {
//결과값 처리
Log.d("result", content!!)
}
}
}
override fun onPartialResults(p0: Bundle?) {}
override fun onEvent(p0: Int, p1: Bundle?) {}
}
🙇♀️ 부족한 부분이 있다면 말씀해주세요! 감사합니다!
📃참고
- 공식 문서
- 그 외
댓글남기기