androidで音声認識をするために以下のようなプログラムを書いたのですが、音声認識が始まった後の文章も途中からしか認識しなかったり、文章の読み上げが途中から聞こえたりします。そのタイミングもまちまちです。
そもそもこんな方法で良いのかも含め教えていただけたら幸いです。
Bluetoothを使わない状態での音声認識、読み上げは上手くいきます。
動作は、
Bluetoothヘッドセットのボタンを押す
→ BroadcastReceiverで受け取りbluetoothHeadset.startVoiceRecognitionを行う
→ mHeadsetBroadcastReceiverでbluetoothがAUDIO_CONNECTEDを受け取り
音声認識を開始
→ 音声認識が成功したらTextToSpeechを実行
→ bluetoothHeadset.stopVoiceRecognitionでヘッドセットとの接続を終了
private SpeechRecognizer sr;
private TextToSpeech tts;
private String ttsString;
private BluetoothHeadset mBluetoothHeadset;
private boolean isBluetoothConnected;
private BluetoothDevice bluetoothDevice;
public static MediaButtonIntentReceiver AMButtonReciever = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
//TTS初期化
tts = new TextToSpeech(this, this);
tts.setOnUtteranceProgressListener(new UtteranceProgressListener() {
@Override
public void onDone(String utteranceId) {
mBluetoothHeadset.stopVoiceRecognition(bluetoothDevice);
}
@Override
public void onError(String utteranceId) {}
@Override
public void onStart(String utteranceId) {}
});
// Bluetoothヘッドセットのボタンイベント
if(AMButtonReciever != null){
unregisterReceiver(AMButtonReciever);
AMButtonReciever = null;
}
AMButtonReciever = new MediaButtonIntentReceiver();
IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
MediaButtonIntentReceiver r = new MediaButtonIntentReceiver();
filter.setPriority(1000);
registerReceiver(AMButtonReciever, filter);
// Bluetoothの接続状況
registerReceiver(mHeadsetBroadcastReceiver, new IntentFilter(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED));
registerReceiver(mHeadsetBroadcastReceiver, new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED));
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
bluetoothAdapter.getProfileProxy(this, mProfileListener, BluetoothProfile.HEADSET);
}//onCreate
private BroadcastReceiver mHeadsetBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
int state;
if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
BluetoothHeadset.STATE_DISCONNECTED);
if (state == BluetoothHeadset.STATE_CONNECTED) {
} else if (state == BluetoothHeadset.STATE_DISCONNECTED) {}
} else {
state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
try{
Intent intentSR = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intentSR.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intentSR.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
intentSR.putExtra(RecognizerIntent.EXTRA_PROMPT, "話してください");
intentSR.putExtra(RecognizerIntent.EXTRA_PREFER_OFFLINE, true);
sr.startListening(intentSR);
}catch(Exception ex){
Toast.makeText(getApplicationContext(), "error",
Toast.LENGTH_LONG).show();
}
} else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
}
}
}
};
private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
mBluetoothHeadset = (BluetoothHeadset) proxy;
List<BluetoothDevice> devices = mBluetoothHeadset.getConnectedDevices();
if(devices.size() > 0){
isBluetoothConnected = true;
bluetoothDevice = devices.get(0);
}
}
}
public void onServiceDisconnected(int profile) {
if (profile == BluetoothProfile.HEADSET) {
mBluetoothHeadset = null;
}
}
};
// メディアボタンが押された時
public class MediaButtonIntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String intentAction = intent.getAction();
if (!Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
return;
}
KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (event == null) {
return;
}
int action = event.getAction();
if (action == KeyEvent.ACTION_DOWN) {
if (sr == null) {
sr = SpeechRecognizer.createSpeechRecognizer(this);
sr.setRecognitionListener(new listener());
}
if (tts.isSpeaking()) {
tts.stop(); // 読み上げ中なら止める
}
mBluetoothHeadset.startVoiceRecognition(bluetoothDevice);
abortBroadcast();
}
}
// TextToSpeech
@Override
public void onInit(int status) {
if (TextToSpeech.SUCCESS == status) {
Locale locale = Locale.JAPANESE;
if (tts.isLanguageAvailable(locale) >= TextToSpeech.LANG_AVAILABLE) {
tts.setLanguage(locale);
} else {
}
} else {
}
}
private void speechText() {
if (0 < string.length()) {
if (tts.isSpeaking()) {
tts.stop();// 読み上げ中なら止める
}
Bundle bundle = new Bundle();
bundle.putString(TextToSpeech.Engine.KEY_PARAM_STREAM, String.valueOf(AudioManager.STREAM_VOICE_CALL));
tts.speak(ttsString, TextToSpeech.QUEUE_FLUSH, bundle, utteranceId);
}
}
// 音声認識を終了する
protected void stopListening() {
if (sr != null) sr.destroy();
sr = null;
}
// 音声認識を再開する
public void restartListeningService() {
stopListening();
startListening();
}
// RecognitionListenerの定義
class listener implements RecognitionListener {
public void onBeginningOfSpeech() {}
public void onBufferReceived(byte[] buffer) {}
public void onEndOfSpeech() {}
public void onError(int error) {
mBluetoothHeadset.stopVoiceRecognition(bluetoothDevice);
stopListening();
}
public void onEvent(int eventType, Bundle params) {}
public void onPartialResults(Bundle partialResults) {}
public void onReadyForSpeech(Bundle params) {
Toast.makeText(getApplicationContext(), "話してください",
Toast.LENGTH_SHORT).show();
}
public void onResults(Bundle results) {
stopListening();
ArrayList results_array = results.getStringArrayList(
SpeechRecognizer.RESULTS_RECOGNITION);
String resultsString = "";
for (int i = 0; i < results_array.size(); i++) {
resultsString += results_array.get(i) + ";";
}
ttsString = resultsString;
speechText();
}
public void onRmsChanged(float rmsdB) {}
}
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
check解決した方法
0
ネット上の記事ではaudioManagerの以下のものよりも
audioManager.startBluetoothSco();
audioManager.setBluetoothScoOn(true);
bluetoothHeadset.startVoiceRecognitionの方が上手くいくという話があった。
(http://android.roof-balcony.com/bluetooth/sip_bluetooth/)
実際、参考サイトにもあるように
APIレベル11以上だとstartVoiceRecognitionで良いように思える。
しかし、実験した環境では、startVoiceRecognitionでは
音質が突然良くなったり悪くなったりと定まらなかったりした。
一方で、audioManager.startBluetoothScoでは(SCOだから当然)音質が低いモードであるが、
確実に接続することができた。
こちらは最新のAPIレベルでも使えるので、startVoiceRecognitionが上手くいかない場合は
こちらを使ってみると良いかもしれません。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.23%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる