Fala do Android

Este artigo aborda os conceitos básicos do uso do namespace Android.Speech muito poderoso. Desde a sua criação, o Android tem sido capaz de reconhecer a fala e produzi-la como texto. É um processo relativamente simples. Para texto para fala, no entanto, o processo é mais envolvido, pois não só o mecanismo de fala deve ser levado em conta, mas também os idiomas disponíveis e instalados a partir do sistema Text To Speech (TTS).

Visão geral da fala

Ter um sistema que "entenda" a fala humana e enuncia o que está sendo digitado – Speech to Text e Text to Speech – é uma área cada vez maior dentro do desenvolvimento móvel à medida que a demanda por comunicação natural com nossos dispositivos aumenta. Há muitos casos em que ter um recurso que converte texto em fala, ou vice-versa, é uma ferramenta muito útil para incorporar em seu aplicativo Android.

Por exemplo, com a repressão ao uso do celular durante a condução, os usuários querem uma maneira mãos-livres de operar seus dispositivos. A infinidade de diferentes fatores de forma do Android — como o Android Wear — e a inclusão cada vez maior daqueles capazes de usar dispositivos Android (como tablets e blocos de notas), criaram um foco maior em ótimos aplicativos TTS.

O Google fornece ao desenvolvedor um rico conjunto de APIs no namespace Android.Speech para cobrir a maioria das instâncias de tornar um dispositivo "consciente de fala" (como software projetado para cegos). O namespace inclui a facilidade de permitir que o texto seja traduzido em fala através Android.Speech.Ttsdo , controle sobre o mecanismo usado para executar a tradução, bem como um número de RecognizerIntents que permitem que a fala seja convertida em texto.

Embora as facilidades existam para que a fala seja compreendida, há limitações com base no hardware usado. É improvável que o dispositivo interprete com sucesso tudo o que lhe é falado em todos os idiomas disponíveis.

Requisitos

Não há requisitos especiais para este guia, além de seu dispositivo ter um microfone e alto-falante.

O núcleo de um dispositivo Android interpretando a fala é o uso de um Intent com um OnActivityResultcorrespondente . É importante, porém, reconhecer que o discurso não é compreendido – mas interpretado em texto. A diferença é importante.

A diferença entre compreender e interpretar

Uma definição simples de compreensão é que você é capaz de determinar pelo tom e contexto o real significado do que está sendo dito. Interpretar significa apenas pegar as palavras e produzi-las de outra forma.

Considere o seguinte exemplo simples que é usado em conversas diárias:

Olá, tudo bem?

Sem flexão (ênfase colocada em palavras específicas ou partes de palavras), é uma pergunta simples. No entanto, se um ritmo lento for aplicado à linha, a pessoa que está ouvindo detectará que o asker não está muito feliz e talvez precise se animar ou que o asker não está bem. Se a ênfase é colocada em "são", a pessoa que pergunta geralmente está mais interessada na resposta.

Sem um processamento de áudio bastante poderoso para fazer uso da inflexão e um grau de inteligência artificial (IA) para entender o contexto, o software não consegue nem começar a entender o que foi dito — o melhor que um simples telefone pode fazer é converter a fala em texto.

Configurando

Antes de usar o sistema de fala, é sempre aconselhável verificar se o dispositivo tem um microfone. De pouco adiantaria tentar executar seu aplicativo em um bloco de notas do Kindle ou do Google sem um microfone instalado.

O exemplo de código abaixo demonstra como consultar se um microfone está disponível e, se não, para criar um alerta. Se nenhum microfone estiver disponível neste momento, você encerrará a atividade ou desabilitará a capacidade de gravar a fala.

string rec = Android.Content.PM.PackageManager.FeatureMicrophone;
if (rec != "android.hardware.microphone")
{
    var alert = new AlertDialog.Builder(recButton.Context);
    alert.SetTitle("You don't seem to have a microphone to record with");
    alert.SetPositiveButton("OK", (sender, e) =>
    {
        return;
    });
    alert.Show();
}

Criando a intenção

A intenção para o sistema de fala usa um tipo particular de intenção chamado RecognizerIntent. Essa intenção controla um grande número de parâmetros, incluindo quanto tempo esperar com silêncio até que a gravação seja considerada encerrada, quaisquer idiomas adicionais para reconhecer e produzir, e qualquer texto para incluir no Intentdiálogo modal do como meio de instrução. Neste trecho, VOICE é um readonly int usado para reconhecimento em OnActivityResult.

var voiceIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
voiceIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
voiceIntent.PutExtra(RecognizerIntent.ExtraPrompt, Application.Context.GetString(Resource.String.messageSpeakNow));
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);
StartActivityForResult(voiceIntent, VOICE);

Conversão do discurso

O texto interpretado a partir da fala será entregue dentro do , que é retornado quando a atividade foi concluída e é acessado Intentvia GetStringArrayListExtra(RecognizerIntent.ExtraResults). Isso retornará um IList<string>, do qual o índice pode ser usado e exibido, dependendo do número de idiomas solicitados na intenção do chamador (e especificados no RecognizerIntent.ExtraMaxResults). Como em qualquer lista, porém, vale a pena verificar se há dados a serem exibidos.

Ao ouvir o valor de retorno de um StartActivityForResult, o OnActivityResult método deve ser fornecido.

No exemplo abaixo, textBox é um TextBox usado para emitir o que foi ditado. Ele também pode ser usado para passar o texto para alguma forma de intérprete e, a partir daí, o aplicativo pode comparar o texto e a ramificação com outra parte do aplicativo.

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 = textBox.Text + matches[0];
                textBox.Text = textInput;
                switch (matches[0].Substring(0, 5).ToLower())
                {
                    case "north":
                        MovePlayer(0);
                        break;
                    case "south":
                        MovePlayer(1);
                        break;
                }
            }
            else
            {
                textBox.Text = "No speech was recognised";
            }
        }
        base.OnActivityResult(requestCode, resultVal, data);
    }
}

Conversão de Texto em Fala

Texto para fala não é exatamente o inverso de fala para texto e depende de dois componentes principais; um mecanismo de conversão de texto em fala sendo instalado no dispositivo e um idioma sendo instalado.

Em grande parte, os dispositivos Android vêm com o serviço padrão do Google TTS instalado e pelo menos um idioma. Isso é estabelecido quando o dispositivo é configurado pela primeira vez e será baseado em onde o dispositivo está no momento (por exemplo, um telefone configurado na Alemanha instalará o idioma alemão, enquanto um na América terá inglês americano).

Etapa 1 - Instanciando o TextToSpeech

TextToSpeech pode levar até 3 parâmetros, os dois primeiros são necessários com o terceiro sendo opcional (AppContext, IOnInitListener, engine). O ouvinte é usado para vincular ao serviço e testar se há falha com o mecanismo sendo qualquer número de mecanismos de texto para fala disponíveis no Android. No mínimo, o dispositivo terá o próprio motor do Google.

Passo 2 - Encontrar os idiomas disponíveis

A Java.Util.Locale classe contém um método útil chamado GetAvailableLocales(). Essa lista de idiomas suportados pelo mecanismo de fala pode então ser testada em relação aos idiomas instalados.

É uma questão trivial gerar a lista de línguas "compreendidas". Sempre haverá um idioma padrão (o idioma que o usuário definiu quando configurou seu dispositivo pela primeira vez), portanto, neste exemplo, o List<string> tem "Padrão" como o primeiro parâmetro, o restante da lista será preenchido dependendo do resultado do textToSpeech.IsLanguageAvailable(locale).

var langAvailable = new List<string>{ "Default" };
var localesAvailable = Java.Util.Locale.GetAvailableLocales().ToList();
foreach (var locale in localesAvailable)
{
    var res = textToSpeech.IsLanguageAvailable(locale);
    switch (res)
    {
        case LanguageAvailableResult.Available:
          langAvailable.Add(locale.DisplayLanguage);
          break;
        case LanguageAvailableResult.CountryAvailable:
          langAvailable.Add(locale.DisplayLanguage);
          break;
        case LanguageAvailableResult.CountryVarAvailable:
          langAvailable.Add(locale.DisplayLanguage);
          break;
    }
}
langAvailable = langAvailable.OrderBy(t => t).Distinct().ToList();

Esse código chama TextToSpeech.IsLanguageAvailable para testar se o pacote de idioma de uma determinada localidade já está presente no dispositivo. Esse método retorna um LanguageAvailableResult, que indica se o idioma da localidade passada está disponível. Se LanguageAvailableResult indicar que o idioma é NotSupported, então não há nenhum pacote de voz disponível (mesmo para download) para esse idioma. Se LanguageAvailableResult estiver definido como MissingData, é possível baixar um novo pacote de idiomas, conforme explicado abaixo na Etapa 4.

Passo 3 - Definindo a velocidade e o pitch

O Android permite que o usuário altere o som da fala alterando o SpeechRate e Pitch (a taxa de velocidade e o tom da fala). Isso vai de 0 a 1, com a fala "normal" sendo 1 para ambos.

Etapa 4 - Testando e carregando novos idiomas

O download de um novo idioma é realizado usando um Intentarquivo . O resultado dessa intenção faz com que o método OnActivityResult seja invocado. Ao contrário do exemplo de fala para texto (que usou o RecognizerIntent como um PutExtra parâmetro para o Intent), o teste e o carregamento Intents são Actionbaseados em:

O exemplo de código a seguir ilustra como usar essas ações para testar recursos de idioma e baixar um novo idioma:

var checkTTSIntent = new Intent();
checkTTSIntent.SetAction(TextToSpeech.Engine.ActionCheckTtsData);
StartActivityForResult(checkTTSIntent, NeedLang);
//
protected override void OnActivityResult(int req, Result res, Intent data)
{
    if (req == NeedLang)
    {
        var installTTS = new Intent();
        installTTS.SetAction(TextToSpeech.Engine.ActionInstallTtsData);
        StartActivity(installTTS);
    }
}

TextToSpeech.Engine.ActionCheckTtsData testes de disponibilidade de recursos linguísticos. OnActivityResult é invocado quando este teste é concluído. Se os recursos de idioma precisarem ser baixados, OnActivityResult disparará a TextToSpeech.Engine.ActionInstallTtsData ação para iniciar uma atividade que permita ao usuário baixar os idiomas necessários. Observe que essa OnActivityResult implementação não verifica o Result código porque, neste exemplo simplificado, já foi determinada que o pacote de idioma precisa ser baixado.

A TextToSpeech.Engine.ActionInstallTtsData ação faz com que a atividade de dados de voz do Google TTS seja apresentada ao usuário para escolher os idiomas a serem baixados:

Atividade de dados de voz TTS do Google

Como exemplo, o usuário pode escolher francês e clicar no ícone de download para baixar dados de voz em francês:

Exemplo de download do idioma francês

A instalação desses dados acontece automaticamente após a conclusão do download.

Passo 5 - O IOnInitListener

Para que uma atividade possa converter o texto em fala, o método OnInit de interface precisa ser implementado (este é o segundo parâmetro especificado para a instanciação da TextToSpeech classe). Isso inicializa o ouvinte e testa o resultado.

O ouvinte deve testar para ambos OperationResult.Success e OperationResult.Failure no mínimo. O exemplo a seguir mostra exatamente isso:

void TextToSpeech.IOnInitListener.OnInit(OperationResult status)
{
    // if we get an error, default to the default language
    if (status == OperationResult.Error)
        textToSpeech.SetLanguage(Java.Util.Locale.Default);
    // if the listener is ok, set the lang
    if (status == OperationResult.Success)
        textToSpeech.SetLanguage(lang);
}

Resumo

Neste guia, analisamos os conceitos básicos de conversão de texto em fala e fala em texto e possíveis métodos de como incluí-los em seus próprios aplicativos. Embora eles não abranjam todos os casos específicos, agora você deve ter uma compreensão básica de como a fala é interpretada, como instalar novos idiomas e como aumentar a inclusão de seus aplicativos.