티스토리 뷰

반응형

speech to text와 text to speech의 예제입니다.

 

 

 

먼저 Manifest에 권한을 추가해줍니다.

// AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>

 

 

 

아래는 권한을 확인하는 코드입니다.

// MainActivity.kt

private val REQUEST_CODE = 1

if (Build.VERSION.SDK_INT >= 23)
    ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.INTERNET, Manifest.permission.RECORD_AUDIO), REQUEST_CODE)

 

 

 

 

STT

STT는 두 가지 예제로 준비했습니다.

 

 

 

 

 

첫 번째는, onActivityResult를 통해 STT를 받는 전체 코드입니다.

class MainActivity : AppCompatActivity() {

    private var speechRecognizer: SpeechRecognizer? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // STTButton 클릭시 onActivityResult를 이용한 startSTT() 함수 실행
        UseActivityResultSTTButton.setOnClickListener { startSTTUseActivityResult() }
    }

    // onActivityResult 사용한 예제
    private fun startSTTUseActivityResult() {
        speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this)

        val speechRecognizerIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
            putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, packageName)
            //putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
            putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault())
        }

        startActivityForResult(speechRecognizerIntent, 100)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if (resultCode == Activity.RESULT_OK && requestCode == 100) {
            viewText.text = data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)!![0]
        }
    }

    override fun onDestroy() {
    
        if (speechRecognizer != null) {
            speechRecognizer!!.stopListening()
        }

        super.onDestroy()
    }
}

 

speechRecognizer에 SpeechRecognizer.createSpeechRecognizer를 통해 현재 context를 넣어주고

 

 

speechRecognizerIntent에는 RecognizerIntent의 속성을 넣어주고, packageName과 언어를 선택해줍니다.

언어는 getDefault로 골랐지만 KOREA으로 명시적으로 골라줘도 됩니다.

 

그리고 startActivityForResult를 통해 speechRecognizerIntent와 requestCode를 보냈습니다.

 

따라서 onActivityResult를 통해 viewText라는 id를 가진 TextView에 getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)를 통해 값을 가져옵니다.

 

배열의 0번 값이 제일 정확하므로 0번 배열의 값을 가져옵니다.

 

 

 

 

 

두 번째로, RecognitionListener를 사용한 STT 전체 코드입니다.

class MainActivity : AppCompatActivity() {

    private var speechRecognizer: SpeechRecognizer? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // STTButton 클릭시 startSTT() 함수 실행
        STTButton.setOnClickListener { startSTT() }
    }


    // RecognitionListener 사용한 예제
    private  fun startSTT() {
        val speechRecognizerIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
            putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, packageName)
            putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault())
        }

        speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this).apply {
            setRecognitionListener(recognitionListener())
            startListening(speechRecognizerIntent)
        }

    }

    private fun recognitionListener() = object : RecognitionListener {
        override fun onReadyForSpeech(params: Bundle?) = Toast.makeText(this@MainActivity, "음성인식 시작", Toast.LENGTH_SHORT).show()

        override fun onRmsChanged(rmsdB: Float) {}

        override fun onBufferReceived(buffer: ByteArray?) {}

        override fun onPartialResults(partialResults: Bundle?) {}

        override fun onEvent(eventType: Int, params: Bundle?) {}

        override fun onBeginningOfSpeech() {}

        override fun onEndOfSpeech() {}

        override fun onError(error: Int) {
            when(error) {
                SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS -> Toast.makeText(this@MainActivity, "퍼미션 없음", Toast.LENGTH_SHORT).show()
            }
        }

        override fun onResults(results: Bundle) {
            viewText.text = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)!![0]
        }
    }

    override fun onDestroy() {

        if (speechRecognizer != null) {
            speechRecognizer!!.stopListening()
        }

        super.onDestroy()
    }
}

 

전체 코드 구조는 첫 번째 코드와 비슷하지만 speechRecognizer에 SpeechRecognizer.createSpeechRecognizer를 통해 현재 context를 넣을 뿐만 아니라 setRecognitionListener로 RecognitionListener를 선언한 함수를 넣어주고 startListening에 speechRecognizerIntent를 넣습니다.

 

위와 같이 함수로 선언하여 넣어도 되고 아래와 같이 변수로 선언해서 넣어도 됩니다.

 

private  fun startSTT() {

   ...

    speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this).apply {
        setRecognitionListener(recognitionListener)
        startListening(speechRecognizerIntent)
    }

}

private val recognitionListener = object : RecognitionListener {
       
   ...
}

 

RecognitionListener 안에 오버라이드된 함수들의 역할은 아래 문서를 확인하면 됩니다.

https://developer.android.com/reference/android/speech/RecognitionListener

 

RecognitionListener  |  Android 개발자  |  Android Developers

RecognitionListener public interface RecognitionListener android.speech.RecognitionListener Used for receiving notifications from the SpeechRecognizer when the recognition related events occur. All the callbacks are executed on the Application main thread.

developer.android.com

 

결과적으로 onResults를 통해 값을 받아오면 됩니다.

 

 

 

 

TTS

 

TTS의 전체 코드이다.

class MainActivity : AppCompatActivity(), TextToSpeech.OnInitListener {

    private var tts: TextToSpeech? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // tts에 TextToSpeech 값 넣어줌
        tts = TextToSpeech(this, this)

        // TTSButton 클릭시 startTTS() 함수 실행
        TTSButton.setOnClickListener { startTTS() }
    }

    // TTS 예제
    private fun startTTS() {
        tts!!.speak(viewText.text.toString(), TextToSpeech.QUEUE_FLUSH, null, "")
    }

    // TextToSpeech override 함수
    override fun onInit(status: Int) {
        if (status == TextToSpeech.SUCCESS) {
            // set US English as language for tts
            val result = tts!!.setLanguage(Locale.KOREA)

            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                //doSomething
            } else {
                //doSomething
            }
        } else {
            //doSomething
        }

    }


    override fun onDestroy() {

        if (tts != null) {
            tts!!.stop()
            tts!!.shutdown()
        }

        super.onDestroy()
    }
}

 

 

 

전체 예제 코드

github

 

Im-Tae/Blog_Example

Contribute to Im-Tae/Blog_Example development by creating an account on GitHub.

github.com

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:text=""
        android:id="@+id/viewText" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center"
        android:layout_marginTop="30dp">

        <Button
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:text="STT"
            android:id="@+id/STTButton"/>

        <Button
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:text="TTS"
            android:id="@+id/TTSButton"/>
    </LinearLayout>

    <Button
        android:layout_width="250dp"
        android:layout_height="wrap_content"
        android:text="STT(activityResult 사용)"
        android:id="@+id/UseActivityResultSTTButton"/>

</androidx.appcompat.widget.LinearLayoutCompat>

 

MainActivity.kt

class MainActivity : AppCompatActivity(), TextToSpeech.OnInitListener {

    private var tts: TextToSpeech? = null
    private var speechRecognizer: SpeechRecognizer? = null
    private val REQUEST_CODE = 1

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // permission 확인
        if (Build.VERSION.SDK_INT >= 23)
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.INTERNET, Manifest.permission.RECORD_AUDIO), REQUEST_CODE)

        // tts에 TextToSpeech 값 넣어줌
        tts = TextToSpeech(this, this)

        // TTSButton 클릭시 startTTS() 함수 실행
        TTSButton.setOnClickListener { startTTS() }

        // STTButton 클릭시 onActivityResult를 이용한 startSTT() 함수 실행
        UseActivityResultSTTButton.setOnClickListener { startSTTUseActivityResult() }

        // STTButton 클릭시 startSTT() 함수 실행
        STTButton.setOnClickListener { startSTT() }
    }


    // RecognitionListener 사용한 예제
    private  fun startSTT() {
        val speechRecognizerIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
            putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, packageName)
            putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault())
        }

        speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this).apply {
            setRecognitionListener(recognitionListener())
            startListening(speechRecognizerIntent)
        }

    }

    private fun recognitionListener() = object : RecognitionListener {

        override fun onReadyForSpeech(params: Bundle?) = Toast.makeText(this@MainActivity, "음성인식 시작", Toast.LENGTH_SHORT).show()

        override fun onRmsChanged(rmsdB: Float) {}

        override fun onBufferReceived(buffer: ByteArray?) {}

        override fun onPartialResults(partialResults: Bundle?) {}

        override fun onEvent(eventType: Int, params: Bundle?) {}

        override fun onBeginningOfSpeech() {}

        override fun onEndOfSpeech() {}

        override fun onError(error: Int) {
            when(error) {
                SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS -> Toast.makeText(this@MainActivity, "퍼미션 없음", Toast.LENGTH_SHORT).show()
            }
        }

        override fun onResults(results: Bundle) {
            viewText.text = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)!![0]
        }
    }



    // onActivityResult 사용한 예제
    private fun startSTTUseActivityResult() {
        speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this)

        val speechRecognizerIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
            putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, packageName)
            //putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
            putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault())
        }

        startActivityForResult(speechRecognizerIntent, 100)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if (resultCode == Activity.RESULT_OK && requestCode == 100) {
            viewText.text = data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)!![0]
        }
    }



    // TTS 예제
    private fun startTTS() {
        tts!!.speak(viewText.text.toString(), TextToSpeech.QUEUE_FLUSH, null, "")
    }

    // TextToSpeech override 함수
    override fun onInit(status: Int) {
        if (status == TextToSpeech.SUCCESS) {
            // set US English as language for tts
            val result = tts!!.setLanguage(Locale.KOREA)

            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                //doSomething
            } else {
                //doSomething
            }
        } else {
            //doSomething
        }

    }


    override fun onDestroy() {

        if (tts != null) {
            tts!!.stop()
            tts!!.shutdown()
        }

        if (speechRecognizer != null) {
            speechRecognizer!!.stopListening()
        }

        super.onDestroy()
    }
}

 

예제 코드

https://github.com/Im-Tae/Blog_Example/tree/master/Android/Android_STT_TTS_Example

반응형
댓글