Некоторое время назад я пытался заставить Google Speech Recognition работать в Xamarin (часть Android).К сожалению, пока у меня нет успеха.Примеры / фрагменты, которые я использую: Plugin.AudioRecorder , GrpcXamarinSamples и Пример распознавания Google .
Цель этого приложения - получитьпотоковый голос с микрофона на платформе Android, попросить Google обработать звук и вернуть строку для дальнейшего использования в проекте.Пример проекта работает, но как только я пытаюсь перенести его в свой собственный проект и заменить NAudio.WaveIn на код Plugin.AudioRecorder, он не работает должным образом.Я пробовал несколько способов сделать это, но ни один из них не работает, и мы всегда получаем какую-то ошибку.(прямо сейчас исключение NullPointerException, которое я не могу разместить)
В настоящее время я застрял в следующем классе, где Listen () - это метод, который вызывается, когда мы хотим получить единственное прослушивание-распознавание-возвратпетля.Когда я вызываю эту функцию, в консоли я получаю следующие результаты:
using System;
using System.Threading.Tasks;
using System.Reflection;
using System.IO;
using System.Threading;
using Android.App;
using Google.Apis.Auth.OAuth2;
using Google.Cloud.Speech.V1;
using Grpc.Core;
using Grpc.Auth;
using Xamarin.Forms;
using MyApp.Droid;
using Plugin.AudioRecorder;
[assembly: Dependency(typeof(GoogleSpeechRecognition))]
namespace MyApp.Droid
{
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
class GoogleSpeechRecognition : ISpeechRecognition
{
Editor logEditor;
AudioRecorderService recorder;
Assembly assembly = typeof(MainActivity).GetTypeInfo().Assembly;
Stream authStream = global::Android.App.Application.Context.Assets.Open("authenticateGoogle.json");
string resultString = null;
GoogleCredential credential;
Channel channel;
SpeechClient speech;
SpeechClient.StreamingRecognizeStream streamingCall;
private void Log(string logText)
{
//logEditor.Text += String.Format("{0}: {1}\n", DateTime.Now.ToString("HH:mm:ss.fff"), logText);
Console.WriteLine(String.Format("{0}: {1}\n", DateTime.Now.ToString("HH:mm:ss.fff"), logText));
}
public async Task<string> Listen()
{
PrepareSpeechRecognition();
WriteInitialPackage();
string result = await StreamingMicRecognizeAsync();
return result;
}
public void PrepareSpeechRecognition(Editor editor = null)
{
if (editor != null)
{
logEditor = editor;
}
recorder = new AudioRecorderService
{
StopRecordingOnSilence = true, //will stop recording after max seconds of silence (defined below)
AudioSilenceTimeout = TimeSpan.FromSeconds(0.5), //will stop recording after x seconds of silence, default is 2
//SilenceThreshold = 1.0F, //indicates the threshold that determines silence. Between 0 and 1, default is .15
StopRecordingAfterTimeout = true, //stop recording after a max timeout (defined below)
//TotalAudioTimeout = TimeSpan.FromSeconds(60) //audio will stop recording after x seconds, default is 30
};
// required to protect against a System.ArgumentNullException on Xamarin.Android during initialization of type
// Microsoft.Extensions.PlatformAbstractions.ApplicationEnvironment in the dependency from Google.Api.Gax (see https://github.com/aspnet/PlatformAbstractions/blob/rel/1.1.0/src/Microsoft.Extensions.PlatformAbstractions/ApplicationEnvironment.cs).
// The field initializer for "ApplicationBasePath" calls GetApplicationBasePath() which calls Path.GetFullPath(basePath)
// where basePath is AppContext.BaseDirectory which returns null on Xamarin by default (see https://github.com/mono/mono/blob/mono-5.10.0.140/mcs/class/referencesource/mscorlib/system/AppContext/AppContext.cs)
AppDomain.CurrentDomain.SetData("APP_CONTEXT_BASE_DIRECTORY", Path.DirectorySeparatorChar.ToString());
using (var reader = new StreamReader(authStream))
{
resultString = reader.ReadToEnd();
}
credential = GoogleCredential.FromJson(resultString);
if (credential.IsCreateScopedRequired)
{
credential = credential.CreateScoped(new[] { "https://www.googleapis.com/auth/cloud-platform" });
}
channel = new Channel(SpeechClient.DefaultEndpoint.Host,
credential.ToChannelCredentials());
speech = SpeechClient.Create(channel, new SpeechSettings());
streamingCall = speech.StreamingRecognize();
}
public async void WriteInitialPackage()
{
streamingCall = speech.StreamingRecognize();
// Write the initial request with the config.
await streamingCall.WriteAsync(
new StreamingRecognizeRequest()
{
StreamingConfig = new StreamingRecognitionConfig()
{
Config = new RecognitionConfig()
{
Encoding = RecognitionConfig.Types.AudioEncoding.Flac,
SampleRateHertz = 16000,
LanguageCode = "en",
},
InterimResults = true,
SingleUtterance = true,
}
}
);
}
public async Task<string> StreamingMicRecognizeAsync()
{
string callResult = "";
// Print responses as they arrive.
Task printResponses = Task.Run(async () =>
{
while (await streamingCall.ResponseStream.MoveNext(
default(CancellationToken)))
{
foreach (var result in streamingCall.ResponseStream
.Current.Results)
{
foreach (var alternative in result.Alternatives)
{
if (result.IsFinal)
{
Console.WriteLine("FINAL: ");
Console.WriteLine(alternative.Transcript);
callResult = alternative.Transcript;
}
Console.WriteLine(alternative.Transcript);
}
}
}
});
byte[] buffer = new byte[32 * 1024];
var audioRecordTask = await recorder.StartRecording();
int bytesRead = 0;
Log("STARTED RECORDING");
using (var _stream = recorder.GetAudioFileStream())
{
Log("Using");
while (recorder.IsRecording)
{
Log("Read bytes");
// [THIS IS WHERE IT ERRORS OUT]
try
{
bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length);
}
catch(Exception e)
{
Log("Exception: " + e.Message);
}
// [/THIS IS WHERE IT ERRORS OUT]
Log("Write");
streamingCall.WriteAsync(
new StreamingRecognizeRequest()
{
AudioContent = Google.Protobuf.ByteString.CopyFrom(buffer, 0, bytesRead)
}
).Wait();
Log("Delay?");
//await Task.Delay(500);
};
Log("FINISHED RECORDING");
await streamingCall.WriteCompleteAsync();
}
Log("STOP _STREAM");
await streamingCall.WriteCompleteAsync();
await printResponses;
return callResult;
}
}
}
12-08 09: 45: 23.721 I / mono-stdout (19951): 09: 45: 23.605:ЗАПУСК ЗАПИСИ 12-08 09: 45: 23.728 I / mon-stdout (19951): 09: 45: 23.605: ЗАПУСК ЗАПИСИ
09: 45: 23.734: Использование 12-08 09: 45: 23.734 I /mono-stdout (19951): 09: 45: 23.734: использование 12-08 09: 45: 23.734 I / mon-stdout (19951): 09: 45: 23.738: чтение байтов
12-08 09:45: 23.738 I / mon-stdout (19951): 09: 45: 23.738: считанные байты 12-08 09: 45: 23.739 I / mon-stdout (19951): 12-08 09: 45: 23.795 I / хореограф (19951): Пропущено 43 кадра!Приложение может выполнять слишком много работы в своем основном потоке.Необработанное исключение:
System.NullReferenceException: ссылка на объект не установлена для экземпляра объекта.
Извините за грязный код и все, это учебный проект, который имеет много итераций.
Аутентификация Google работает, мы проверили это с примером проекта.
Редактировать: По запросу полный журнал: https://pastebin.com/q3G62ByT