【问题标题】:Android speech recognition pass data back to Xamarin FormsAndroid 语音识别将数据传回 Xamarin Forms
【发布时间】:2017-03-29 14:07:56
【问题描述】:

我现在真的卡住了,我对 Xamarin 很陌生。 我使用 Xamarin Forms 开发具有语音识别功能的应用程序。

我只创建了一个带有按钮和输入框的简单 UI。

工作:

  • 按下按钮并显示带有语音识别的弹出窗口
  • 将口语读入 var

不工作:

  • 将数据传回 Xamarin Forms UI(条目)

StartPage.xaml.cs:

    private void BtnRecord_OnClicked(object sender, EventArgs e)
    {
        WaitForSpeechToText();
    } 

    private async void WaitForSpeechToText()
    {
        EntrySpeech.Text = await DependencyService.Get<Listener.ISpeechToText>().SpeechToTextAsync();
    }

ISpeechToText.cs:

public interface ISpeechToText
{
    Task<string> SpeechToTextAsync();
}

调用本机代码。

SpeechToText_Android.cs:

    public class SpeechToText_Android : ISpeechToText
    {
    private const int VOICE = 10;

    public SpeechToText_Android() { }

    public Task<string> SpeechToTextAsync()
    {
        var tcs = new TaskCompletionSource<string>();

        try
        {
            var voiceIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
            voiceIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
            voiceIntent.PutExtra(RecognizerIntent.ExtraPrompt, "Sprechen Sie jetzt");
            voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, 1500);
            voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, 1500);
            voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, 15000);
            voiceIntent.PutExtra(RecognizerIntent.ExtraMaxResults, 1);
            voiceIntent.PutExtra(RecognizerIntent.ExtraLanguage, Java.Util.Locale.Default);

            try
            {
                ((Activity)Forms.Context).StartActivityForResult(voiceIntent, VOICE);

            }
            catch (ActivityNotFoundException a)
            {
                tcs.SetResult("Device doesn't support speech to text");
            }
        }
        catch (Exception ex)
        {

            tcs.SetException(ex);
        }

        return tcs.Task;
    }
}

MainActivity.cs:

    protected override void OnActivityResult(int requestCode, Result resultVal, Intent data)
    {  
        if (requestCode == VOICE)
        {
            if (resultVal == Result.Ok)
            {
                var matches = data.GetStringArrayListExtra(RecognizerIntent.ExtraResults);
                if (matches.Count != 0)
                {
                    string textInput = matches[0].ToString();
                    if (textInput.Length > 500)
                        textInput = textInput.Substring(0, 500);
                }
                // RETURN 
            }
        }
        base.OnActivityResult(requestCode, resultVal, data);
    }

首先我认为我可以通过

return tcs.Task;

回到 ui,但后来我注意到这个返回发生在 语音识别的弹出窗口已完成渲染。这一刻,一句话也没说。

口语在 OnActivityResult 函数中的字符串“textInput”中, 但是我怎样才能将此字符串传递回 Xamarin.Forms UI?

谢谢大家!

【问题讨论】:

  • SpeechToTextAsync 需要用 async 关键字标记。

标签: c# android xamarin xamarin.android xamarin.forms


【解决方案1】:

我会使用 AutoResetEvent 暂停返回,直到调用 OnActivityResult,直到用户记录某些内容、取消或您在 AutoResetEvent 中超时他们的操作。

从您的 SpeechToTextAsync 方法返回一个 Task&lt;string&gt;

public interface ISpeechToText
{
    Task<string> SpeechToTextAsync();
}

AutoResetEvent 添加到暂停执行:

注意:包裹AutoResetEvent.WaitOne以防止挂起应用程序循环

public class SpeechToText_Android : Listener.ISpeechToText
{
    public static AutoResetEvent autoEvent = new AutoResetEvent(false);
    public static string SpeechText;
    const int VOICE = 10;

    public async Task<string> SpeechToTextAsync()
    {
        var voiceIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
        voiceIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
        voiceIntent.PutExtra(RecognizerIntent.ExtraPrompt, "Sprechen Sie jetzt");
        voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, 1500);
        voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, 1500);
        voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, 15000);
        voiceIntent.PutExtra(RecognizerIntent.ExtraMaxResults, 1);
        voiceIntent.PutExtra(RecognizerIntent.ExtraLanguage, Java.Util.Locale.Default);

        SpeechText = "";
        autoEvent.Reset();
        ((Activity)Forms.Context).StartActivityForResult(voiceIntent, VOICE);
        await Task.Run(() => { autoEvent.WaitOne(new TimeSpan(0, 2, 0)); });
        return SpeechText;
    }
}

MainActivity OnActivityResult:

    const int VOICE = 10;
    protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
    {
        base.OnActivityResult(requestCode, resultCode, data);
        if (requestCode == VOICE)
        {
            if (resultCode == Result.Ok)
            {
                var matches = data.GetStringArrayListExtra(RecognizerIntent.ExtraResults);
                if (matches.Count != 0)
                {
                    var textInput = matches[0];
                    if (textInput.Length > 500)
                        textInput = textInput.Substring(0, 500);
                    SpeechToText_Android.SpeechText = textInput;
                }
            }
            SpeechToText_Android.autoEvent.Set();
        }
    }

注意:这是使用几个静态变量来简化此示例的实现...有些开发人员会说这是代码异味,我半同意,但您不能拥有多个 Google语音识别器一次运行....

Hello World 示例:

public class App : Application
{
    public App()
    {
        var speechTextLabel = new Label
        {
            HorizontalTextAlignment = TextAlignment.Center,
            Text = "Waiting for text"
        };

        var speechButton = new Button();
        speechButton.Text = "Fetch Speech To Text Results";
        speechButton.Clicked += async (object sender, EventArgs e) =>
        {
            var speechText = await WaitForSpeechToText();
            speechTextLabel.Text = string.IsNullOrEmpty(speechText) ? "Nothing Recorded" : speechText;
        };

        var content = new ContentPage
        {
            Title = "Speech",
            Content = new StackLayout
            {
                VerticalOptions = LayoutOptions.Center,
                Children = {
                    new Label {
                        HorizontalTextAlignment = TextAlignment.Center,
                        Text = "Welcome to Xamarin Forms!"
                    },
                    speechButton,
                    speechTextLabel
                }
            }
        };
        MainPage = new NavigationPage(content);
    }

    async Task<string> WaitForSpeechToText()
    {
        return await DependencyService.Get<Listener.ISpeechToText>().SpeechToTextAsync();
    }
}

【讨论】:

  • 非常感谢@SushiHangover!它就像一个魅力。如果我做对了,那么您创建了一个最多等待 2 分钟的线程(autoEvent)。它阻止函数的返回。然后你通过“autoEvent.Set()”发信号通知线程在你得到语音输入后继续,我做对了吗?
  • @user3769192 完全正确,此方法有效,但并不完美....您可能会超时,而当您超时时,您将无法取消 Google 识别器。 “正确”方法是创建一个SpeechRecognizer(通过SpeechRecognizer.CreateSpeechRecognizer),构建您自己的用户界面,设置一个RecognitionListener作为您的回调,从而处理发送到的任何单词您的侦听器在另一个线程中可以取消/停止识别器,在超时或用户取消后,然后拆除您的自定义 UI ....
  • 我尝试了使用 SpeechRecognizer 创建自己的界面的方式,但我认为我失败了。所以我决定回到标准实现。感谢您的解释和您的帮助!
  • @SushiHangover 我可以与您联系以获取有关此主题的后续问题吗?
猜你喜欢
  • 1970-01-01
  • 2020-11-14
  • 1970-01-01
  • 1970-01-01
  • 2020-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多