Last active
April 6, 2017 17:29
-
-
Save microwavePC/0d82a9c9be147d682180b3da2accec27 to your computer and use it in GitHub Desktop.
【Xamarin.Forms】音声認識の使い方 ref: http://qiita.com/microwavePC/items/40b1016cf84ea89c4ed1
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
using System.ComponentModel; | |
namespace VoiceRecognitionSample.Models | |
{ | |
// 音声認識用のdependency service。 | |
// プロパティの変更をViewModelで捕まえるため、INotifyPropertyChangedを継承している。 | |
public interface IVoiceRecognitionService : INotifyPropertyChanged | |
{ | |
// 音声認識が実行中かどうか(実行中の間のみtrueを返す) | |
bool IsRecognizing { get; } | |
// 音声認識の結果テキスト(iOSの場合、認識結果をリアルタイムで取得できる) | |
string RecognizedText { get; } | |
// 音声認識の開始と停止 | |
void StartRecognizing(); | |
void StopRecognizing(); | |
} | |
} |
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
using System; | |
using Android.App; | |
using Android.Content; | |
using Android.Content.PM; | |
using Android.OS; | |
using Microsoft.Practices.Unity; | |
using Prism.Unity; | |
// ↓追加 | |
using Android.Preferences; | |
namespace VoiceRecognitionSample.Droid | |
{ | |
[Activity(Label = "VoiceRecognitionSample.Droid", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] | |
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity | |
{ | |
// ↓追加 | |
public event EventHandler<PreferenceManager.ActivityResultEventArgs> ActivityResult = delegate {}; | |
protected override void OnCreate(Bundle bundle) | |
{ | |
base.OnCreate(bundle); | |
global::Xamarin.Forms.Forms.Init(this, bundle); | |
LoadApplication(new App(new AndroidInitializer())); | |
} | |
// ↓追加 | |
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) | |
{ | |
base.OnActivityResult(requestCode, resultCode, data); | |
var resultEventArgs = new PreferenceManager.ActivityResultEventArgs(true, requestCode, resultCode, data); | |
ActivityResult(this, resultEventArgs); | |
} | |
} | |
public class AndroidInitializer : IPlatformInitializer | |
{ | |
public void RegisterTypes(IUnityContainer container) | |
{ | |
} | |
} | |
} |
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
(省略) | |
<Label Text="{Binding RecognizedText}" /> | |
<Button Text="{Binding VoiceRecognitionButtonText}" | |
Command="{Binding VoiceRecognitionCommand}" /> | |
(省略) | |
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
(省略) | |
// コンストラクタ | |
public MainPageViewModel(IVoiceRecognitionService voiceRecognitionService) | |
{ | |
_voiceRecognitionService = voiceRecognitionService; | |
// 音声認識サービスのプロパティが変更されたときに実行する処理を設定する。 | |
_voiceRecognitionService.PropertyChanged += voiceRecognitionServicePropertyChanged; | |
// 音声認識サービスの処理本体をコマンドに紐付ける。 | |
VoiceRecognitionCommand = new DelegateCommand(executeVoiceRecognition); | |
} | |
(省略) | |
// 音声認識サービスのプロパティ変更時にトリガーされるイベントの実処理 | |
private void voiceRecognitionServicePropertyChanged(object sender, PropertyChangedEventArgs args) | |
{ | |
if (args.PropertyName == "RecognizedText") | |
{ | |
// 音声の認識結果テキストの変更がトリガーになった場合、そのテキストをViewModelに取得する。 | |
RecognizedText = _voiceRecognitionService.RecognizedText; | |
// | |
// 音声の認識結果テキストを使って何か処理をしたい場合、 | |
// ここに処理(または処理の呼び出し)を書けばOK。 | |
// | |
} | |
if (args.PropertyName == "IsRecognizing") | |
{ | |
// 音声認識の実行状況変更がトリガーになった場合、その実行状況をViewModelに取得する。 | |
IsRecognizing = _voiceRecognitionService.IsRecognizing; | |
} | |
} | |
// 音声認識サービス呼び出し用ボタンのコマンドの実処理 | |
private void executeVoiceRecognition() | |
{ | |
if (IsRecognizing) | |
{ | |
// 音声認識を実行中の場合、「停止」ボタンとして機能させる。 | |
_voiceRecognitionService.StopRecognizing(); | |
} | |
else | |
{ | |
// 音声認識が停止中の場合、「開始」ボタンとして機能させる。 | |
_voiceRecognitionService.StartRecognizing(); | |
} | |
} | |
(省略) | |
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
// プロパティの変更をバインドで捉えられるようにするため、BindableBaseを継承する。 | |
public class VoiceRecognitionService : BindableBase, IVoiceRecognitionService | |
{ | |
#region Properties | |
// 音声認識の実行状況(実行中の間のみtrueを返す) | |
private bool _isRecognizing; | |
public bool IsRecognizing | |
{ | |
get { return _isRecognizing; } | |
set { SetProperty(ref _isRecognizing, value); } | |
} | |
// 音声認識の結果テキスト | |
private string _recognizedText; | |
public string RecognizedText | |
{ | |
get | |
{ | |
if (_recognizedText != null) | |
return _recognizedText; | |
else | |
return string.Empty; | |
} | |
set { SetProperty(ref _recognizedText, value); } | |
} | |
#endregion | |
#region Constant, MainActivity | |
// 定数・MainActivity | |
private readonly int REQUEST_CODE_VOICE = 10; // 音声認識のリクエストコード | |
private readonly int INTERVAL_1500_MILLISEC = 1500; // 1.5秒(ミリ秒単位) | |
private MainActivity mainActivity; // MainActivity | |
#endregion | |
#region Constructor | |
// コンストラクタ | |
public VoiceRecognitionService() | |
{ | |
// 音声認識のアクティビティで取得した結果をハンドルする処理をMainActivityに付ける。 | |
mainActivity = Forms.Context as MainActivity; | |
mainActivity.ActivityResult += HandleActivityResult; | |
} | |
#endregion | |
#region Handler | |
// 音声認識のアクティビティで取得した結果をハンドルする処理の本体 | |
private void HandleActivityResult(object sender, PreferenceManager.ActivityResultEventArgs args) | |
{ | |
if (args.RequestCode == REQUEST_CODE_VOICE) | |
{ | |
IsRecognizing = false; | |
if (args.ResultCode == Result.Ok) | |
{ | |
// 認識が成功した場合、認識結果の文字列を引き出し、RecognizedTextに入れる。 | |
var matches = args.Data.GetStringArrayListExtra(RecognizerIntent.ExtraResults); | |
if (matches.Count != 0) | |
{ | |
RecognizedText = matches[0]; | |
} | |
} | |
} | |
} | |
#endregion | |
#region Public Methods | |
// 音声認識の開始処理 | |
public void StartRecognizing() | |
{ | |
RecognizedText = string.Empty; | |
IsRecognizing = true; | |
try | |
{ | |
// 音声認識のアクティビティを呼び出すためのインテントを用意する。 | |
var voiceIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech); | |
// 諸々のプロパティを設定する。 | |
voiceIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm); | |
voiceIntent.PutExtra(RecognizerIntent.ExtraPrompt, "音声認識ダイアログにこの文字列が表示される。"); | |
voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, INTERVAL_1500_MILLISEC); | |
voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, INTERVAL_1500_MILLISEC); | |
voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, INTERVAL_1500_MILLISEC); | |
voiceIntent.PutExtra(RecognizerIntent.ExtraMaxResults, 1); | |
// 認識言語の指定。端末の設定言語(Java.Util.Locale.Default)で音声認識を行う。 | |
voiceIntent.PutExtra(RecognizerIntent.ExtraLanguage, Java.Util.Locale.Default); | |
// 音声認識のアクティビティを開始する。 | |
mainActivity.StartActivityForResult(voiceIntent, REQUEST_CODE_VOICE); | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine(ex.Message); | |
} | |
} | |
// 音声認識の停止処理 | |
public void StopRecognizing() | |
{ | |
// Androidでは実装は不要。 | |
} | |
#endregion | |
} | |
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
// プロパティの変更をバインドで捉えられるようにするため、BindableBaseを継承する。 | |
public class VoiceRecognitionService : BindableBase, IVoiceRecognitionService | |
{ | |
#region Properties | |
// 音声認識の実行状況(実行中の間のみtrueを返す) | |
private bool _isRecognizing; | |
public bool IsRecognizing | |
{ | |
get { return _isRecognizing; } | |
set { SetProperty(ref _isRecognizing, value); } | |
} | |
// 音声認識の結果テキスト | |
private string _recognizedText; | |
public string RecognizedText | |
{ | |
get | |
{ | |
if (_recognizedText != null) | |
return _recognizedText; | |
else | |
return string.Empty; | |
} | |
set { SetProperty(ref _recognizedText, value); } | |
} | |
#endregion | |
#region Variables | |
// 音声認識に必要な諸々のクラスのインスタンス。 | |
private AVAudioEngine audioEngine; | |
private SFSpeechRecognizer speechRecognizer; | |
private SFSpeechAudioBufferRecognitionRequest recognitionRequest; | |
private SFSpeechRecognitionTask recognitionTask; | |
#endregion | |
#region Public Methods | |
// 音声認識の開始処理 | |
public void StartRecognizing() | |
{ | |
RecognizedText = string.Empty; | |
IsRecognizing = true; | |
// 音声認識の許可をユーザーに求める。 | |
SFSpeechRecognizer.RequestAuthorization((SFSpeechRecognizerAuthorizationStatus status) => | |
{ | |
switch (status) | |
{ | |
case SFSpeechRecognizerAuthorizationStatus.Authorized: | |
// 音声認識がユーザーに許可された場合、必要なインスタンスを生成した後に音声認識の本処理を実行する。 | |
// SFSpeechRecognizerのインスタンス生成時、コンストラクタの引数でlocaleを指定しなくても、 | |
// 端末の標準言語が日本語なら日本語は問題なく認識される。 | |
audioEngine = new AVAudioEngine(); | |
speechRecognizer = new SFSpeechRecognizer(); | |
recognitionRequest = new SFSpeechAudioBufferRecognitionRequest(); | |
startRecognitionSession(); | |
break; | |
default: | |
// 音声認識がユーザーに許可されなかった場合、処理を終了する。 | |
return; | |
} | |
} | |
); | |
} | |
// 音声認識の停止処理 | |
public void StopRecognizing() | |
{ | |
try | |
{ | |
audioEngine?.Stop(); | |
recognitionTask?.Cancel(); | |
recognitionRequest?.EndAudio(); | |
IsRecognizing = false; | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine(ex.Message); | |
} | |
} | |
#endregion | |
#region Private Methods | |
// 音声認識の本処理 | |
private void startRecognitionSession() | |
{ | |
// 音声認識のパラメータ設定と認識開始。ここのパラメータはおまじない。 | |
audioEngine.InputNode.InstallTapOnBus( | |
bus: 0, | |
bufferSize: 1024, | |
format: audioEngine.InputNode.GetBusOutputFormat(0), | |
tapBlock: (buffer, when) => { recognitionRequest?.Append(buffer); } | |
); | |
audioEngine?.Prepare(); | |
NSError error = null; | |
audioEngine?.StartAndReturnError(out error); | |
if (error != null) | |
{ | |
Console.WriteLine(error); | |
return; | |
} | |
try | |
{ | |
if (recognitionTask?.State == SFSpeechRecognitionTaskState.Running) | |
{ | |
// 音声認識が実行中に音声認識開始処理が呼び出された場合、実行中だった音声認識を中断する。 | |
recognitionTask.Cancel(); | |
} | |
recognitionTask = speechRecognizer.GetRecognitionTask(recognitionRequest, | |
(SFSpeechRecognitionResult result, NSError err) => | |
{ | |
if (result == null) | |
{ | |
// iOS Simulator等、端末が音声認識に対応していない場合はここに入る。 | |
StopRecognizing(); | |
return; | |
} | |
if (err != null) | |
{ | |
Console.WriteLine(err); | |
StopRecognizing(); | |
return; | |
} | |
if ((result.BestTranscription != null) && (result.BestTranscription.FormattedString != null)) | |
{ | |
// 音声を認識できた場合、認識結果を更新する。 | |
RecognizedText = result.BestTranscription.FormattedString; | |
} | |
if (result.Final) | |
{ | |
// 音声が認識されなくなって時間が経ったら音声認識を打ち切る。 | |
StopRecognizing(); | |
return; | |
} | |
} | |
); | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine(ex.Message); | |
} | |
} | |
#endregion | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment