음성 (뉴톤)

카카오에서는 모바일 상에서 손쉽게 사용할 수 있는 음성 API를 제공합니다. 사용자는 모바일 기기에 장착되어 있는 마이크와 스피커를 이용해 사람의 음성 언어를 인식하거나 합성할 수 있습니다.

  • 시작하기 전에
    카카오 음성 API를 연동하기 전에 필요한 앱 설정 항목과 특징을 설명합니다.

현재 카카오 SDK에서 제공하는 음성 API 기능은 다음과 같습니다.

  • 음성 인식 (뉴톤)
    사람이 말하는 음성 언어를 컴퓨터가 해석해 그 내용을 문자 데이터로 변환하는 음성-문자 변환 시스템 (Speech-to-Text system) 입니다.
  • 음성 합성 (뉴톤톡)
    앞의 기능과 반대로 문자 데이타를 사람이 이해할 수 있는 음성 언어로 변환하는 문자-음성 변환 시스템 (Text-to-Speech system)입니다.

시작하기 전에

요구 사항
  • minimum OS 버전 : android 4.0 (API Level 14)
  • target OS 버전 : android 6.0 (API Level 23)
  • 개발툴 : android studio (IntelliJ)

SDK import하기
  • Gradle 환경에서 사용하기를 참고하여 카카오의Gradle repository를 추가합니다.
  • 사용할 앱의 build.gradle 파일에 아래와 같이 카카오 음성 SDK를 추가하여import합니다.
dependencies {
    compile group: 'com.kakao.sdk', name: 'newtone', version: project.KAKAO_SPEECH_VERSION
}

카카오 음성 SDK 샘플앱을 다운받으셔서 샘플앱의 코드를 참고해 보세요.

앱 생성 및 설정
  • 앱 생성키해시 등록을 참고하여 빠진 부분이 없는지 확인합니다.
  • 내 애플리케이션 > [앱] > 설정 > 음성 메뉴로 들어가서 음성 사용을 활성화 합니다. enable_speech.png

카카오 이미지 표시 의무

개인 또는 법인이 상업적 용도로 사용시 아래 카카오(powered by kakao) 이미지를 음성 인식 라이브러리를 사용하고 있을때 표시하여야 한다. 폰 화면 상에서 위치는 상하 좌우측 또는 중간에 표시한다. 이미지 사이즈는 최소 가로 102 픽셀, 세로 15 픽셀 이상이어야 한다. (더 크게 표시할 경우 가로 세로 배율 유지)

Kakao.png

음성 인식 (뉴톤)

사람이 말하는 음성 언어를 컴퓨터가 해석해 그 내용을 문자 데이터로 변환하는 음성-문자 변환 시스템(Speech-to-Text system)입니다. 아래 순서대로 음성 인식 기능을 사용하기 위한 절차를 설명합니다.

권한 설정

카카오스피치 SDK는 RECORD_AUDIO, WRITE_EXTERNAL_STORAGE, ACCESS_NETWORK_STATE 권한을 필요로 합니다. 위 권한들을 다음과 같이 앱의 AndroidManifest.xml 파일에 설정해 줍니다.

[AndroidManifest.xml]

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

<application
    ...
    <meta-data
       android:name="com.kakao.sdk.AppKey"
       android:value="@string/kakao_app_key" />
    ...
 </application>

안드로이드 M (API level 23) 부터 RECORD_AUDIOWRITE_EXTERNAL_STORAGE 권한은 위험 권한으로 분류되어 AndroidManifest.xml에 권한을 명시하더라도 동적으로 유저에게 권한 요청을 거쳐야 합니다. 앱의 flow에 맞게 두개의 권한을 동적으로 획득하세요.

// 동적 권한 코드

...
public void onCreate(Bundle savedInstanceState) {

  if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO) && ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
      ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_AUDIO_AND_WRITE_EXTERNAL_STORAGE);
    } else {
      // 유저가 거부하면서 다시 묻지 않기를 클릭.. 권한이 없다고 유저에게 직접 알림.
    }
  } else {
    startUsingSpeechSDK();
  }
}

...
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case REQUEST_CODE_AUDIO_AND_WRITE_EXTERNAL_STORAGE:
            if (grantResults.length > 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                startUsingSpeechSDK();
            } else {
                finish();
            }
            break;
        default:
            break;
    }
}

시작하기

음성 인식 기능을 이용하려면 먼저 SDK 초기화를 해줘야 합니다. 음성 인식 기능을 이용하는 Activity의 onCreate()에서 라이브러리를 초기화하는 함수인 SpeechRecognizerManager의 initializeLibrary() 를 호출합니다. 그 후 SpeechRecognizerClient.Builder를 통하여 다음과 같이 SpeechRecognizerClient를 생성합니다.

  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

      // SDK 초기화
      SpeechRecognizerManager.getInstance().initializeLibrary(this);

      // 클라이언트 생성
      SpeechRecognizerClient.Builder builder = new SpeechRecognizerClient.Builder().
            setServiceType(SpeechRecognizerClient.SERVICE_TYPE_WEB).
            setUserDictionary(userdict);  // optional

      SpeechRecognizerClient client = builder.build();
  }

  // ...

  public void onDestroy() {
      super.onDestroy();

      SpeechRecognizerManager.getInstance().finalizeLibrary();
  }
설정 Key 설명
setServiceType(String) [optional] 음성 인식에서 지원하는 서비스 타입으로 웹검색/연속어/지도/고립어 인식을 제공.
- SpeechRecognizerClient.SERVICE_TYPE_WEB : 웹 검색 키워드 검색어 인식에 최적화. 포탈 검색에 많이 사용되는 텍스트들에 인식 최적화.(default)
- SpeechRecognizerClient.SERVICE_TYPE_LOCAL : 지도 검색으로 장소명 검색어 인식에 최적화.
- SpeechRecognizerClient.SERVICE_TYPE_DICTATION : 연속어 인식으로 문장 인식에 최적화. 15초 이내의 한 문장 정도 인식에 사용.
- ServiceRecognizerClient.SERVICE_TYPE_WORD : 고립어 인식으로 단어 인식에 최적화. UserDictionary 에 설정된 단어들 중에서만 인식.
setGlobalTimeOut(int) [optional] 녹음에서 인식까지의 전체 세션 타임 아웃으로 default는 30초(sec).
setUserDictionary(String) [optional] 사용자 사전을 정의. 구분자는 '\n'(newline). 예) "다음\n카카오\n음성인식"

결과값 및 오류 처리

음성 인식 중에 발생하는 다양한 이벤트를 callback 메서드를 구현하여 처리할 수 있습니다.

callback 메서드를 받기 위해서는 SpeechRecognizeListener 인터페이스를 구현해야 합니다.

SpeechRecognizeListener는 결과값을 받거나 에러가 발생하는 등의 이벤트가 발생했을 때 해당 상태에 맞는 callback 메서드를 호출해 줍니다.

SpeechRecognizeListener를 추가하는 방법은 SpeechRecognizerClient의 setSpeechRecognizeListener() 메서드를 이용하면 됩니다.

client.setSpeechRecognizeListener(new SpeechRecognizeListener() {
   @Override
   public void onReady() {
       //To change body of implemented methods use File | Settings | File Templates.
   }
 // ...
});

SpeechRecognizeListener를 구현하려면 총 7개의 메서드를 구현해야 합니다.

모든 callback 함수는 UI thread가 아닌 background thread에서 호출될 수 있기 때문에, UI와 관련된 작업은 Activity.runOnUiThread(Runnable) 이나 Handler.post(Runnable)을 통해 비동기로 호출해야 합니다. 우선 startRecording()이 실행된 이후에 음성 입력을 감지하면 감지된 음성에 대한 결과를 경우에 따라 두가지 callback을 통해 얻을 수 있습니다.

onPartialResult

onPartialResult는 완전히 음성이 종료되기 이전에 현재까지 인식된 음성데이터 문자열을 알려줍니다.

이 데이터는 서버에 질의해 데이터를 보정하는 과정을 거치지 않으므로, 다소 부정확할 수 있습니다.

중간 인식 결과에 대한 결과가 발생할 때마다 호출되므로 여러번 호출될 수 있습니다.

@Override
public void onPartialResult(String text) {
   //TODO implement interface SpeechRecognizeListener method
}

on_partial_results2.png

onResults

onResults는 음성 입력이 종료된 것으로 판단하거나 stopRecording()을 호출한 후에 서버에 질의하는 과정까지 마치고 나면 호출됩니다.

인식된 문자열은 신뢰도가 높은 값부터 순서대로 Bundle의 SpeechRecognizerClient.KEY_RECOGNITION_RESULTS 값을 통해 ArrayList로 얻을 수 있습니다.

신뢰도는 Bundle의 SpeechRecognizerClient.KEY_CONFIDENCE_VALUES 값을 통해 ArrayList로 얻을 수 있으며 높은 값부터 순서대로 입니다.

신뢰도값은 항상 0보다 크거나 같은 정수이며, 문자열 목록과 같은 개수입니다.

on_suggest2.png

@Override
public void onResults(Bundle results) {
   //TODO implement interface SpeechRecognizeListener method
   ArrayList<String/> texts =  results.getStringArrayList(SpeechRecognizerClient.KEY_RECOGNITION_RESULTS);
   ArrayList<Integer/> confs =   results.getIntegerArrayList(SpeechRecognizerClient.KEY_CONFIDENCE_VALUES);
}
onError

결과를 얻기 위한 callback 말고도 다양한 callback 메서드가 존재합니다.

onError callback은 이름에서 알 수 있듯이 에러가 발생했을 때 호출됩니다.

SpeechRecognizerClient 에서 다양한 에러 코드에 대응하는 ERROR_ 로 시작하는 code 값들을 확인할 수 있습니다.

@Override
public void onError(int errorCode, String errorMsg) {
   //TODO implement interface SpeechRecognizeListener method
}
음성 인식 에러코드

음성 인식 API는 아래와 같은 에러코드를 전달합니다. SpeechRecognizerClient에서 ERROR_ 로 시작하는 static int 값들입니다.

Error Code 설명
ERROR_AUDIO_FAIL 음성입력이 불가능하거나 마이크 접근이 허용되지 않았을 경우.
ERROR_AUTH_FAIL apikey 인증이 실패한 경우.
ERROR_AUTH_TROUBLE apikey 인증 과정 중 내부 문제가 발생한 경우.
ERROR_NETWORK_FAIL 네트워크 오류가 발생한 경우.
ERROR_NETWORK_TIMEOUT 네트워크 타임아웃이 발생한 경우.
ERROR_SERVER_FAIL 서버에서 오류가 발생한 경우.
ERROR_SERVER_TIMEOUT 서버 응답 시간이 초과한 경우.
ERROR_NO_RESULT 인식된 결과 목록이 없는 경우.
ERROR_CLIENT 클라이언트 내부 로직에서 오류가 발생한 경우.
ERROR_RECOGNITION_TIMEOUT 전체 소요시간에 대한 타임아웃이 발생한 경우.
ERROR_SERVER_UNSUPPORT_SERVICE 제공하지 않는 서비스 타입이 지정됐을 경우.
ERROR_SERVER_USERDICT_EMPTY 입력된 사용자 사전에 내용이 없는 경우.
ERROR_SERVER_ALLOWED_REQUESTS_EXCESS 요청 허용 횟수 초과.
기타 이벤트

onReady callback은 SpeechRecognizerClient의 startRecording이 수행된 후에 단말기의 마이크 하드웨어와 OS의 오디오 서비스 등에 대한 초기화 등이 모두 준비되었을 때 호출됩니다.

여러가지 초기화 작업을 성공적으로 마치고 나면 가장 먼저 호출되는 callback입니다.

onBeginningOfSpeech callback은 사용자가 말하기 시작하는 것으로 판단될 때 호출되는 callback입니다.

사용자가 말을 하지 않은 상태에서 에러가 발생하면 이 callback은 호출되지 않습니다.

onEndOfSpeech callback은 사용자가 말하는 것을 끝마친 것으로 판단될 때 호출되는 callback입니다.

사용자가 너무 오랜 시간을 말하여 앱이 지정한 시간 내에 음성을 인식하지 못하였거나 인식 중에 오류가 발생했을 때는 호출되지 않습니다.

onEndOfSpeech 이후에는 음성데이터를 서버에 전송하여 값을 보정하고 후보 인식 목록과 신뢰도를 조회하는 과정을 거칩니다.

on_end_of_speech2.png

onAudioLevel callback은 음성이 입력되는 도중에 입력되는 음성의 크기를 dB(데시벨)로 판별한 후 재가공을 거친 상대값을 알려줍니다. 0과 1 사이의 float 값입니다. onFinished callback은 인식 종료 후 사용하던 리소스를 모두 해제한 후에 호출됩니다. 음성인식이 성공적으로 종료되었을 때만 호출되며, onError가 발생했을 때는 호출되지 않습니다.

@Override
public void onReady() {
   //TODO implement interface SpeechRecognizeListener method
}

@Override
public void onBeginningOfSpeech() {
   //TODO implement interface SpeechRecognizeListener method
}

@Override
public void onEndOfSpeech() {
 //TODO implement interface SpeechRecognizeListener method
}

@Override
public void onAudioLevel(float v) {
   //TODO implement interface SpeechRecognizeListener method
}

@Override
public void onFinished() {
   //TODO implement interface SpeechRecognizeListener method
}

음성 인식 실행하기

음성 인식을 시작하는 방법은 간단합니다.

아래와 같이 SpeechRecognizerClient의 startRecording() 메서드를 호출합니다.

파라미터로 입력하는 boolean 값은 현재 재생되고 있는 음악 등 배경 소리를 음소거(mute)할지 지정하는 값입니다. 값이 true면 음소거를 합니다.

음소거를 했을 경우 음성 인식이 종료되면 음소거가 종료됩니다.

client.startRecording(true);

음성 인식을 중지하는 방법은 cancelRecording() 메서드와 stopRecording() 메서드, 두가지가 있습니다.

cancelRecording() 은 음성 인식을 취소하며 이후로 진행되는 동작은 없습니다.

stopRecording() 은 음성 인식을 멈추지만, startRecording()을 실행한 이후부터 stopRecording()을 실행할 때까지의 음성데이터를 이용해 음성 인식을 진행합니다.

따라서, stopRecording() 은 실행된 이후에 SpeechRecognizeListener의 onResults 또는 onError가 호출되게 됩니다.

client.cancelRecording();
// or
client.stopRecording();

SDK에서 제공하는 기본 UI 사용하기

SpeechRecognizerClient와 SpeechRecognizeListener를 직접 이용하는 방법 말고도 제공되는 기본 UI를 통해 간편하게 사용자에게 UI를 제공할 수 있습니다.

간결하게 UI를 구성할 수 있도록 샘플 프로젝트의 리소스와 예제 코드를 이용할 수 있습니다. 기본 UI에서 많은 커스터마이징이 필요하다면 별도로 제작하는 것이 바람직합니다.

UI와 관련된 파일 복사하기

기본 UI로 이용할 수 있는 음성 인식 기능은 샘플 프로젝트의 VoiceRecoActivity를 이용합니다.

VoiceRecoActivity은 카카오 스피치 SDK의 SpeechRecognizerActivity를 상속받아 구현하였습니다.

가장 먼저 할 작업은 압축파일에 포함된 기본 UI를 구현한 VoiceRecoActivity.java를 필요한 프로젝트에 복사합니다.

java 파일을 복사한 후에 package name은 그에 맞게 변경합니다.

copy_voicerecoactivity.png

그리고 activity에서 이용하는 리소스들을 프로젝트의 리소스 경로 위치로 복사합니다. 복사하는 것으로 인해 기존 프로젝트의 리소스를 덮어쓰지 않도록 파일 이름들이 설정되어 있습니다. res/ 밑에 anim, drawable, drawable-xhdpi 를 모두 복사합니다. res/layout/ 밑에 com_kakao_sdk_asr 로 시작하는 xml 파일들을 모두 복사합니다. res/values/ 밑에 com_kakao_sdk_asr_strings.xml 파일을 복사합니다.

copy_resources.png

AndroidManifest.xml 에 activity 등록하기

이제 AndroidManifest.xml에 activity를 등록만 하면 VoiceRecoActivity의 이용을 위한 준비는 끝납니다.

<!-- package 이름은 적절히 변경합니다. -->
<activity android:name="com.kakao.sdk.speech.sample.VoiceRecoActivity" />
activity 호출하기

VoiceRecoActivity를 이용하여 호출하기 전에 Intent로 한가지 정보는 꼭 넘겨주어야 합니다. 바로 APIKey 입니다.

APIKey 이외에 설정할 수 있는 값이나, 자세한 내용은 javadoc을 참고하면 됩니다.

Intent i = new Intent(getApplicationContext(), VoiceRecoActivity.class);

i.putExtra(SpeechRecognizerActivity.EXTRA_KEY_API_KEY, apikey);
// apiKey는 신청과정을 통해 package와 매치되도록 발급받은 APIKey 문자열 값.

startActivityForResult(i, 0);
이벤트 처리 - onActivityResult 이용

제공된 샘플의 SpeechSampleActivity의 onActivityResult method를 참고하여 성공과 실패에 대한 결과를 처리할 수 있습니다.

성공시에는 resultCode 가 RESULT_OK 이며, 에러가 발생하는 등의 실패가 발생했을 땐 RESULT_CANCELED 입니다.

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
   if (resultCode == RESULT_OK) { // 성공
       ArrayList<String> results = data.getStringArrayListExtra(VoiceRecoActivity.EXTRA_KEY_RESULT_ARRAY);
       // ....
   }
   else if (requestCode == RESULT_CANCELED) { // 실패
       int errorCode = data.getIntExtra(VoiceRecoActivity.EXTRA_KEY_ERROR_CODE, -1);
       String errorMsg = data.getStringExtra(VoiceRecoActivity.EXTRA_KEY_ERROR_MESSAGE);
       // ....
   }
}

Intent의 extra 값은 VoiceRecoActivity.java의 상단에서 알 수 있듯이 다음과 같은 key 들로 조회할 수 있습니다.

  public static String EXTRA_KEY_RESULT_ARRAY = "result_array"; // 결과값 목록.  ArrayList<String>
  public static String EXTRA_KEY_MARKED = "marked"; // 첫번째 값의 신뢰도가 현저하게 높은 경우 true. 아니면 false. Boolean
  public static String EXTRA_KEY_ERROR_CODE = "error_code"; // 에러가 발생했을 때 코드값. 코드값은   SpeechRecognizerClient를 참조. Integer
  public static String EXTRA_KEY_ERROR_MESSAGE = "error_msg"; // 에러 메시지. String
이벤트 처리 - VoiceRecoActivity의 Override methods

onResourcesWillInitialize 메서드는 UI를 변경하지 않고 이용한다면 sample의 내용을 그대로 이용할 수 있습니다.

일부 리소스를 변경하고자 할 때는 SpeechRecognizerClient의 RES_STRINGS와 RES_VIEWID enum 과 관련된 문서를 참고하여 어떤 리소스의 ID가 어떤 상황에서 표시되는지 알 수 있습니다.

제공되는 기본 UI에서 리소스나 레이아웃을 변경할 때는 이미지 파일이나 strings 파일, layout xml을 직접 변경하는 것을 권장합니다.

@Override
protected void onResourcesWillInitialize() {
// ....
}

onRecognitionSuccess 메서드는 VoiceRecoActivity를 통해 음성 인식을 성공했을 때 호출되는 메서드입니다.

샘플 프로젝트에서 오버라이드한 onRecognitionSuccess 메서드는 결과 목록을 호출한 Activity로 값을 전달하도록 하였습니다.

메서드의 marked 파라미터는 결과목록의 첫번째 값이 신뢰도가 높은 값인지 알려줍니다. 결과 목록에서 첫번째 값의 신뢰도가 SpeechRecognizerClient.CONFIDENCE_PASSING_MARKED(int = 10) 보다 같거나 높으면 높은 신뢰도를 가지는 값으로 간주할 수 있습니다.

이와 별도로 결과 목록의 첫번째 값의 신뢰도가 낮으면 결과 목록을 UI에서 표시하고, 이 목록에서 사용자가 말한 단어를 선택할 수 있도록 도와줍니다.

이 단계를 거쳐서 값이 선택될 때도 marked 값은 true 입니다. marked 값이 false가 되는 경우는 후보단어 목록 표시 생략하기에서 알 수 있습니다.

@Override
protected void onRecognitionSuccess(List<String> result, boolean marked) {
   // ....
}

onRecognitionFailed 메서드는 VoiceRecoActivity를 통해 수행한 음성 인식이 실패하거나 에러가 발생했을 때 호출되는 메서드입니다. sample에서의 기본 동작은 에러코드와 에러 메시지를 호출한 Activity로 전달합니다.

@Override
protected void onRecognitionFailed(int errorCode, String errorMsg) {
   // ....
}
후보단어 목록 표시 생략하기

기본 UI를 통한 구현은 기본적으로 높은 신뢰도를 가지지 못한 결과 목록을 얻었을 때 사용자에게 말한 내용을 판단하도록 거치는 과정이 있습니다.

이 과정을 생략하거나 다른 방법으로 안내를 하려면 SpeechRecognizerActivity 를 호출할 때 Intent의 extra 값으로 SpeechRecognizerActivity.EXTRA_KEY_SHOW_SUGGEST_LIST 키값을 설정하면 됩니다.

설정하지 않으면 기본값은 true이며, false면 후보단어 목록 표시를 생략하고 true면 후보단어 목록을 표시합니다.

후보단어 표시를 생략한 채로 onRecognitionSuccess callback 메서드가 호출되면 신뢰도가 높은 결과값인지 판단할 근거가 부족해집니다.

그래서 후보단어 표시를 생략하고 결과 목록의 신뢰도가 낮을 때만 onRecognitionSuccess 메서드의 marked 파라미터 값이 false가 됩니다.

  Intent i = new Intent(getApplicationContext(), VoiceRecoActivity.class);

  i.putExtra(SpeechRecognizerActivity.EXTRA_KEY_API_KEY, apikey);
  i.putExtra(SpeechRecognizerActivity.EXTRA_KEY_SHOW_SUGGEST_LIST, false); // 후보단어 목록 표시 생략

  startActivityForResult(i, 0);

추가 설명

서비스 모드 설명

서비스 모드란 음성인식 도메인이고, 각 도메인에 더 특화되어 있다.

서비스 모드 도메인 종류
서비스 모드 도메인 설명
Dictation 받아쓰기 모드이며 일반적인 문장, 대화체 인식에 사용
Local 주소, 지역명 인식에 사용(예 : 카카오맵 앱 음성 인식)
Web or Search 웹 검색에 사용 (예 : 다음 앱 음성 인식)
Word 명령어 인식에 사용
Word 모드에서 User Dict (사용자 사전) 설명

user dict (사용자 사전) 에 단어들을 넣어놓고 인식하면 그 단어들중에서만 인식 된다. user dict 에는 한단어 이상 반드시 들어가야 한다. (user dict 가 비워져있으면 에러 반환된다.) 그외 서비스 모드에서는 사용자 사전 안에 있는 텍스트들을 좀 더 가중치를 줘서 인식한다. 최대 허용 사이즈 : 약 3000 단어 정도

api 사용 방식
비동기 구현

message queue, event handler 등을 사용해 비동기적으로 처리하고 onPartialResult, onError 등의 이벤트 호출 함수 안에서 또 다시 음성 api 함수를 재호출하지 않는다.

예 : onInactive (ios 라이브러리 경우 onFinished) 호출 안에서 startListening 재 호출 하는 경우 지양

stop (stopRecording 또는 stopListening) 과 cancel 호출 의 차이

stop : stop 이 호출된 시점까지 인식된다. (서버의 인식 결과를 기다림) cancel : cancel 이 호촐되면 바로 취소된다. (서버의 인식 결과를 기다리지 않고 취소됨)

종료시 마지막으로 호출되는 이벤트 함수

에러 발생시 : onError 정상 종료시 : onInacitive

이중 실행 금지

ios, android 음성 라이브러리는 기본적으로 이중 또는 다중 실행을 지원하지 않는다. 중복 실행시 여러 버그의 원인이 된다.

음성 합성 (뉴톤톡)

권한 설정

앱의 AndroidManifest.xml 파일에는 다음과 같은 권한들을 설정합니다. (bluetooth는 선택사항입니다.)

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

음성 인식 기능과 마찬가지로 targetSdkVersion이 23 (Android M) 이상일 경우에는 동적으로 유저에게 권한을 받아야 합니다. 음성 인식 권한 설정을 참고하여 유저에게 동적 권한을 획득하세요.

시작하기

음성 합성 기능을 이용하려면 먼저 라이브러리 초기화를 해줘야 합니다.

음성 합성 기능을 이용하는 곳에서 라이브러리를 초기화 하는 함수인 initializeLibrary()를 아래와 같이 호출합니다.

public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   TextToSpeechManager.getInstance().initializeLibrary(getApplicationContext());
}

// 더 이상 쓰지 않는 경우에는 다음과 같이 해제
public void onDestroy() {
   super.onDestroy();
   TextToSpeechManager.getInstance().finalizeLibrary();
}

라이브러리 초기화 후에는 TextToSpeechClient.Builder를 사용하여 클라이언트를 생성합니다.

private TextToSpeechClient ttsClient;

...

ttsClient = new TextToSpeechClient.Builder()
        .setSpeechMode(TextToSpeechClient.NEWTONE_TALK_1)     // 음성합성방식
        .setSpeechSpeed(1.0)            // 발음 속도(0.5~4.0)
        .setSpeechVoice(TextToSpeechClient.VOICE_WOMAN_READ_CALM)  //TTS 음색 모드 설정(여성 차분한 낭독체)
        .setListener(this)
        .build();
설정 Key 설명
setSpeechMode(String) TextToSpeechClient.NEWTONE_TALK_1 : 통계적 합성 방식 (기존)
- 기존에 뉴톤톡 API로 제공되던 통계적 합성 방식은 음성의 통계적 특성을 분석하여 모델을 만들고 이를 이용하여 합성하는 방식으로, 녹음된 데이터에 없는 합성음을 안정적으로 합성해 낼 수 있어서 다양한 분야에 적용되어도 일관된 품질의 합성음을 생성해 낼 수 있고 음색 변환 등 다양한 응용에 적용할 수 있습니다. 일반적으로 편집 합성 방식에 비해 음질이 떨어집니다.
TextToSpeechClient.NEWTONE_TALK_2 : 편집 합성 방식
- 새롭게 추가된 편집 합성 방식은 통계적 특성을 이용하는 것이 아니라 녹음된 음성 데이터 자체를 이용하여 필요한 음소들을 발췌하여 합성하는 방식입니다. 장점으로는 데이터 자체를 이용하므로 녹음에 사용된 문장과 동일한 영역의 문장들에 대해서는 통계적 합성 방식보다 자연스러운 음성을 만들어 낼 수 있습니다. 단점으로는 녹음 데이터에 없는 영역의 문장에서는 음질이 저하되는 단점이 있습니다. (예를 들어 대화체 음색을 이용하여 낭독체 문장을 합성하는 경우). 편집 합성 방식에서는 통계적 합성 방식과 달리 합성 속도 변경 기능은 제공하지 않습니다.
setSpeechSpeed(double) 발음속도 0.5 ~ 4.0 (1이 보통속도, 크면 빠르게, 작으면 느리게)
setSpeechVoice(String) TextToSpeechClient.VOICE_WOMAN_READ_CALM : 여성 차분한 낭독체
TextToSpeechClient.VOICE_MAN_READ_CALM : 남성 차분한 낭독체
TextToSpeechClient.VOICE_WOMAN_DIALOG_BRIGHT : 여성 밝은 대화체
TextToSpeechClient.VOICE_MAN_DIALOG_BRIGHT : 남성 밝은 대화체

음성 합성 실행하기

음성합성은 multi thread 기반으로 동작하며 음성합성이 진행되는 과정에 따라 이벤트들이 호출되고 그에 따른 동작들을 구현해주면 됩니다. 음성인식과 달리 음성합성은 중간 결과가 없기 때문에, onFinished와 onError이벤트 밖에 없어서 비교적 구현이 간단합니다.

음성합성의 callback을 받기위해서 TextToSpeechListener를 구현해 줍니다.

모든 callback 함수는 UI thread가 아닌 background thread에서 호출될 수 있기 때문에, UI와 관련된 작업은 Activity.runOnUiThread(Runnable) 이나 Handler.post(Runnable)을 통해 비동기로 호출해야 합니다.

onError는 뉴톤톡 중에 에러가 발생한 경우 호출됩니다.

onFinished는 음성합성이 완료된 뒤에 호출됩니다.

//com.kakao.sdk.newtoneapi.TextToSpeechListener
@Override
public void onError(int code, String message) { //에러처리
    handleError(code);
}

@Override
public void onFinished() { //음성합성이 종료될 때 호출된다.
    int intSentSize = ttsClient.getSentDataSize();      //세션 중에 전송한 데이터 사이즈
    int intRecvSize = ttsClient.getReceivedDataSize();  //세션 중에 전송받은 데이터 사이즈

    final String strInacctiveText = "handleFinished() SentSize : " + intSentSize + "  RecvSize : " + intRecvSize;

    Log.i(TAG, strInacctiveText);
}

음성합성을 위한 텍스트를 넣고 play() 시키면 동작됩니다.

play 함수에 텍스트를 파라미터로 전달하거나 미리 텍스트를 세팅한 후 플레이 할 수도 있습니다.

//boolean com.kakao.sdk.newtoneapi.TextToSpeechClient.play(String)
//boolean com.kakao.sdk.newtoneapi.TextToSpeechClient.play()
//boolean com.kakao.sdk.newtoneapi.TextToSpeechClient.setSpeechText(String)

예)
String strText = "안녕하세요"
ttsClient.play(strText);

// 또는
ttsClient.setSpeechText(strText);   //뉴톤톡 하고자 하는 문자열을 미리 세팅.
ttsClient.play();       //세팅된 문자열을 합성하여 재생.

합성된 음성이 재생되는 것을 중지시키려면 stop()을 사용합니다.

//void com.kakao.sdk.newtoneapi.TextToSpeechClient.stop()

예)
ttsClient.stop();
합성된 음성이 재생중인지 확인하려면 isPlaying()을 사용합니다. 반환값이 True이면 재생중입니다.
//boolean com.kakao.sdk.newtoneapi.TextToSpeechClient.isPlaying()

예)
ttsClient.isPlaying();

결과값 및 오류 처리

onError

onError callback은 이름에서 알 수 있듯이 에러가 발생했을 때 호출됩니다.

TextToSpeechClient 에서 다양한 에러 코드에 대응하는 ERROR_ 로 시작하는 code 값들을 확인할 수 있습니다.

  @Override
  public void onError(int errorCode, String errorMsg) {
      //TODO implement interface TextToSpeechListener method
  }
음성 합성 에러코드

음성 합성 API는 아래와 같은 에러코드를 전달합니다. TextToSpeechClient에서 ERROR_ 로 시작하는 static int 값들을 참고할 수 있습니다.

Error Code 설명
ERROR_NONE 정상 (오류가 아님.)
ERROR_NETWORK 네트워크 오류가 발생한 경우.
ERROR_NETWORK_TIMEOUT 네트워크 타임아웃이 발생한 경우. (클라이언트에서 SOCKET READ TIMEOUT 5초 초과)
ERROR_CLIENT_INETRNAL 클라이언트 내부 오류가 발생한 경우.
ERROR_SERVER_INTERNAL 서버에서 오류가 발생한 경우.
ERROR_SERVER_TIMEOUT 서버 최대 접속시간 초과.(세션 30초 초과 또는 서버에서 SOCKET READ TIMEOUT 5초 초과)
ERROR_SERVER_AUTHENTICATION APPID 또는 APPKEY가 틀려서 인증이 실패한 경우.
ERROR_SERVER_SPEECH_TEXT_BAD 뉴톤톡 텍스트 오류 (처리과정을 거친 후 문자열의 길이가 0 또는 문자열의 길이가 0이상이지만 발음할 수 없는 문자로 구성된 경우. (^^, ----, (), [], !!!!! ) 등.)
ERROR_SERVER_SPEECH_TEXT_EXCESS 뉴톤톡 최대 허용 길이 초과.(합성 길이가 30초 이상이거나 100byte이상 길이의 단어가 포함되어 있는 경우.)
ERROR_SERVER_SPEECH_TEXT_FORBIDDEN 뉴톤톡 금칙어 오류.
ERROR_SERVER_ALLOWED_REQUESTS_EXCESS 뉴톤톡 서비스 최대 허용 횟수 초과.
ERROR_UNSUPPORTED_SERVICE 음성합성 서비스 모드 오류.
ERROR_UNKNOWN 알 수 없는 오류.
기타 이벤트

onFinished 메서드는 TextToSpeechClient의 합성된 음성의 재생이 종료된 이후에 호출됩니다.

여러가지 합성음 작업을 성공적으로 마치고 나면 가장 마지막에 호출되는 메서드입니다.

  @Override
  public void onFinished() {
      //TODO implement interface TextToSpeechListener method
  }

카카오 음성 합성 기본 내부 규칙

1. 표준어 및 한글 사용
  • "카카오 음성 합성 엔진"은 한국어 문장 합성기로, 영어 문장은 합성이 불가능합니다.
    • 다만 흔히 사용하는 영어 단어, 약어, 유명인 이름, 기업명 등은 예외적으로 한국식 발음으로 읽습니다.
  • 사투리나 은어, 비속어, 오타등은 합성음이 부자연스러울 수 있습니다.
  • URL -> "링크", 이메일 주소->"이메일 주소" 라는 발음으로 변환됩니다.
  • 미리 정의된 "ㅋㅋ", "ㅎㅎ" 등의 대화체 단어는 아래와 같이 합성됩니다.
단어 합성음
ㅎㅎ 흐흐 (3개 이상부터 "흐흐흐"로 통일)
ㅋㅋ 크크 (3개 이상부터 "크크크"로 통일)
ㅇㅋ 오케이
ㅇㅇ
ㄴㄴ
ㅃㅇ 빠이
ㅎㅇ 하이
2. 적절한 문장 부호 사용
  • 쉼표, 마침표, 느낌표, 물음표 등의 문장부호를 적절하게 사용합니다.
  • 특히 쉼표를 이용하여, 합성음에서의 인위적인 끊어읽기를 유도할 수 있습니다.
3. 특수기호
  • 흔히 쓰이는 특수기호를 제외하고는, 합성시 무시됩니다.
  • 마침표(.), 물음표(?), 탭(\t). 뉴라인(\n)을 기준으로 문장을 분리합니다.
  • 한글 자소, 한자 및 외래어등은 합성시 무시됩니다.
  • 흔히 사용되는 특수기호는 다음과 같습니다.
특수기호 합성음
$ 달러
¥
£ 파운드
유로
°
섭씨
화씨
4. 허용하지 않는 문장
  • 피싱에 사용될 가능성이 높은 문장
  • 음란성 문장

Last Modified : 2017-08-03