Streaming dell’input a System.Speech.Recognition.SpeechRecognitionEngine

Sto cercando di eseguire il riconoscimento vocale “streaming” in C # da un socket TCP. Il problema che sto avendo è che SpeechRecognitionEngine.SetInputToAudioStream () sembra richiedere un stream di una lunghezza definita che può cercare. In questo momento l’unico modo in cui posso pensare di far funzionare questo è quello di eseguire ripetutamente il riconoscimento su un MemoryStream con l’arrivo di più input.

Ecco un codice per illustrare:

SpeechRecognitionEngine appRecognizer = new SpeechRecognitionEngine(); System.Speech.AudioFormat.SpeechAudioFormatInfo formatInfo = new System.Speech.AudioFormat.SpeechAudioFormatInfo(8000, System.Speech.AudioFormat.AudioBitsPerSample.Sixteen, System.Speech.AudioFormat.AudioChannel.Mono); NetworkStream stream = new NetworkStream(socket,true); appRecognizer.SetInputToAudioStream(stream, formatInfo); // At the line above a "NotSupportedException" complaining that "This stream does not support seek operations." 

Qualcuno sa come aggirare questo? Deve supportare input di streaming di qualche tipo, dal momento che funziona bene con il microfono utilizzando SetInputToDefaultAudioDevice ().

Grazie, Sean

Ho ottenuto il riconoscimento vocale dal vivo lavorando ignorando la class stream:

 class SpeechStreamer : Stream { private AutoResetEvent _writeEvent; private List _buffer; private int _buffersize; private int _readposition; private int _writeposition; private bool _reset; public SpeechStreamer(int bufferSize) { _writeEvent = new AutoResetEvent(false); _buffersize = bufferSize; _buffer = new List(_buffersize); for (int i = 0; i < _buffersize;i++ ) _buffer.Add(new byte()); _readposition = 0; _writeposition = 0; } public override bool CanRead { get { return true; } } public override bool CanSeek { get { return false; } } public override bool CanWrite { get { return true; } } public override long Length { get { return -1L; } } public override long Position { get { return 0L; } set { } } public override long Seek(long offset, SeekOrigin origin) { return 0L; } public override void SetLength(long value) { } public override int Read(byte[] buffer, int offset, int count) { int i = 0; while (i= _writeposition) { _writeEvent.WaitOne(100, true); continue; } buffer[i] = _buffer[_readposition+offset]; _readposition++; if (_readposition == _buffersize) { _readposition = 0; _reset = false; } i++; } return count; } public override void Write(byte[] buffer, int offset, int count) { for (int i = offset; i < offset+count; i++) { _buffer[_writeposition] = buffer[i]; _writeposition++; if (_writeposition == _buffersize) { _writeposition = 0; _reset = true; } } _writeEvent.Set(); } public override void Close() { _writeEvent.Close(); _writeEvent = null; base.Close(); } public override void Flush() { } } 

... e utilizzando un'istanza di questo come input di stream per il metodo SetInputToAudioStream. Non appena il stream restituisce una lunghezza o il conteggio restituito è inferiore a quello richiesto, il motore di riconoscimento pensa che l'input sia terminato. Questo imposta un buffer circolare che non finisce mai.

Hai provato a completare lo streaming di rete in un System.IO.BufferedStream?

 NetworkStream netStream = new NetworkStream(socket,true); BufferedStream buffStream = new BufferedStream(netStream, 8000*16*1); // buffers 1 second worth of data appRecognizer.SetInputToAudioStream(buffStream, formatInfo); 

Ho finito con il buffering dell’input e poi l’ho inviato al motore di riconoscimento vocale in blocchi sempre più grandi. Ad esempio, potrei inviare prima i primi 0,25 secondi, poi i primi 0,5 secondi, poi i primi 0,75 secondi e così via fino a ottenere un risultato. Non sono sicuro che questo sia il modo più efficace per farlo, ma mi dà risultati soddisfacenti.

Buona fortuna, Sean

Apparentemente non può essere fatto (“Per disegno”!). Vedi http://social.msdn.microsoft.com/Forums/en/netfxbcl/thread/fcf62d6d-19df-4ca9-9f1f-17724441f84e

Questa è la mia soluzione.

 class FakeStreamer : Stream { public bool bExit = false; Stream stream; TcpClient client; public FakeStreamer(TcpClient client) { this.client = client; this.stream = client.GetStream(); this.stream.ReadTimeout = 100; //100ms } public override bool CanRead { get { return stream.CanRead; } } public override bool CanSeek { get { return false; } } public override bool CanWrite { get { return stream.CanWrite; } } public override long Length { get { return -1L; } } public override long Position { get { return 0L; } set { } } public override long Seek(long offset, SeekOrigin origin) { return 0L; } public override void SetLength(long value) { stream.SetLength(value); } public override int Read(byte[] buffer, int offset, int count) { int len = 0, c = count; while (c > 0 && !bExit) { try { len = stream.Read(buffer, offset, c); } catch (Exception e) { if (e.HResult == -2146232800) // Timeout { continue; } else { //Exit read loop break; } } if (!client.Connected || len == 0) { //Exit read loop return 0; } offset += len; c -= len; } return count; } public override void Write(byte[] buffer, int offset, int count) { stream.Write(buffer,offset,count); } public override void Close() { stream.Close(); base.Close(); } public override void Flush() { stream.Flush(); } } 

Come usare:

 //client connect in TcpClient clientSocket = ServerSocket.AcceptTcpClient(); FakeStreamer buffStream = new FakeStreamer(clientSocket); ... //recognizer init m_recognizer.SetInputToAudioStream(buffStream , audioFormat); ... //recognizer end if (buffStream != null) buffStream.bExit = true;