Created
January 2, 2020 18:43
-
-
Save zion830/d045325ec84b7cb1a545f31f65ff966c to your computer and use it in GitHub Desktop.
[Android] TTS Player 예제
This file contains 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
<?xml version="1.0" encoding="utf-8"?> | |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:orientation="vertical" | |
tools:context=".MainActivity"> | |
<LinearLayout | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content"> | |
<Button | |
android:id="@+id/btn_play" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_weight="1" | |
android:text="PLAY" /> | |
<Button | |
android:id="@+id/btn_pause" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_weight="1" | |
android:text="WAIT" /> | |
<Button | |
android:id="@+id/btn_stop" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_weight="1" | |
android:text="STOP" /> | |
</LinearLayout> | |
<EditText | |
android:id="@+id/et_input" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:text="안녕하세요!! 만나서 반갑습니다!" | |
android:hint="재생할 텍스트 입력" | |
android:maxLines="3" /> | |
<TextView | |
android:id="@+id/tv_content" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:padding="10dp" | |
android:scrollbars="vertical" | |
android:text="입력한 텍스트가 출력되는 영역입니다." | |
android:textColor="@android:color/black" | |
android:textSize="16sp" /> | |
</LinearLayout> |
This file contains 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.ttsplayer; | |
import android.graphics.Color; | |
import android.os.Bundle; | |
import android.speech.tts.TextToSpeech; | |
import android.speech.tts.UtteranceProgressListener; | |
import android.text.Spannable; | |
import android.text.SpannableString; | |
import android.text.style.BackgroundColorSpan; | |
import android.view.View; | |
import android.widget.Button; | |
import android.widget.EditText; | |
import android.widget.TextView; | |
import android.widget.Toast; | |
import androidx.appcompat.app.AppCompatActivity; | |
import java.util.Locale; | |
public class MainActivity extends AppCompatActivity implements TextPlayer, View.OnClickListener { | |
private final Bundle params = new Bundle(); | |
private final BackgroundColorSpan colorSpan = new BackgroundColorSpan(Color.YELLOW); | |
private TextToSpeech tts; | |
private Button playBtn; | |
private Button pauseBtn; | |
private Button stopBtn; | |
private EditText inputEditText; | |
private TextView contentTextView; | |
private PlayState playState = PlayState.STOP; | |
private Spannable spannable; | |
private int standbyIndex = 0; | |
private int lastPlayIndex = 0; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
initTTS(); | |
initView(); | |
} | |
private void initView() { | |
playBtn = findViewById(R.id.btn_play); | |
pauseBtn = findViewById(R.id.btn_pause); | |
stopBtn = findViewById(R.id.btn_stop); | |
inputEditText = findViewById(R.id.et_input); | |
contentTextView = findViewById(R.id.tv_content); | |
playBtn.setOnClickListener(this); | |
pauseBtn.setOnClickListener(this); | |
stopBtn.setOnClickListener(this); | |
} | |
private void initTTS() { | |
params.putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, null); | |
tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { | |
@Override | |
public void onInit(int state) { | |
if (state == TextToSpeech.SUCCESS) { | |
tts.setLanguage(Locale.KOREAN); | |
} else { | |
showState("TTS 객체 초기화 중 문제가 발생했습니다."); | |
} | |
} | |
}); | |
tts.setOnUtteranceProgressListener(new UtteranceProgressListener() { | |
@Override | |
public void onStart(String s) { | |
} | |
@Override | |
public void onDone(String s) { | |
clearAll(); | |
} | |
@Override | |
public void onError(String s) { | |
showState("재생 중 에러가 발생했습니다."); | |
} | |
@Override | |
public void onRangeStart(String utteranceId, int start, int end, int frame) { | |
changeHighlight(standbyIndex + start, standbyIndex + end); | |
lastPlayIndex = start; | |
} | |
}); | |
} | |
@Override | |
public void onClick(View view) { | |
switch (view.getId()) { | |
case R.id.btn_play: | |
startPlay(); | |
break; | |
case R.id.btn_pause: | |
pausePlay(); | |
break; | |
case R.id.btn_stop: | |
stopPlay(); | |
break; | |
} | |
showState(playState.getState()); | |
} | |
@Override | |
public void startPlay() { | |
String content = inputEditText.getText().toString(); | |
if (playState.isStopping() && !tts.isSpeaking()) { | |
setContentFromEditText(content); | |
startSpeak(content); | |
} else if (playState.isWaiting()) { | |
standbyIndex += lastPlayIndex; | |
startSpeak(content.substring(standbyIndex)); | |
} | |
playState = PlayState.PLAY; | |
} | |
@Override | |
public void pausePlay() { | |
if (playState.isPlaying()) { | |
playState = PlayState.WAIT; | |
tts.stop(); | |
} | |
} | |
@Override | |
public void stopPlay() { | |
tts.stop(); | |
clearAll(); | |
} | |
private void changeHighlight(final int start, final int end) { | |
runOnUiThread(new Runnable() { | |
@Override | |
public void run() { | |
spannable.setSpan(colorSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); | |
} | |
}); | |
} | |
private void setContentFromEditText(String content) { | |
contentTextView.setText(content, TextView.BufferType.SPANNABLE); | |
spannable = (SpannableString) contentTextView.getText(); | |
} | |
private void startSpeak(final String text) { | |
tts.speak(text, TextToSpeech.QUEUE_ADD, params, text); | |
} | |
private void clearAll() { | |
playState = PlayState.STOP; | |
standbyIndex = 0; | |
lastPlayIndex = 0; | |
if (spannable != null) { | |
changeHighlight(0, 0); // remove highlight | |
} | |
} | |
private void showState(final String msg) { | |
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show(); | |
} | |
@Override | |
protected void onPause() { | |
if (playState.isPlaying()) { | |
pausePlay(); | |
} | |
super.onPause(); | |
} | |
@Override | |
protected void onResume() { | |
if (playState.isWaiting()) { | |
startPlay(); | |
} | |
super.onResume(); | |
} | |
@Override | |
protected void onDestroy() { | |
tts.stop(); | |
tts.shutdown(); | |
super.onDestroy(); | |
} | |
} |
This file contains 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.ttsplayer; | |
public enum PlayState { | |
PLAY("재생 중"), WAIT("일시정지"), STOP("멈춤"); | |
private String state; | |
PlayState(String state) { | |
this.state = state; | |
} | |
public String getState() { | |
return state; | |
} | |
public boolean isStopping() { | |
return this == STOP; | |
} | |
public boolean isWaiting() { | |
return this == WAIT; | |
} | |
public boolean isPlaying() { | |
return this == PLAY; | |
} | |
} |
This file contains 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.ttsplayer; | |
public interface TextPlayer { | |
void startPlay(); | |
void pausePlay(); | |
void stopPlay(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment