2009-11-05 7 views
5

Ich versuche, "Streaming" Spracherkennung in C# von einem TCP-Socket zu tun. Das Problem, das ich habe, ist, dass SpeechRecognitionEngine.SetInputToAudioStream() scheint, einen Stream einer definierten Länge zu verlangen, die suchen kann. Im Augenblick ist die einzige Möglichkeit, die ich denken kann, diese Arbeit zu machen, ist immer wieder die Erkennungs auf einem Memorystream läuft als mehr Input kommtStreaming-Eingang zu System.Speech.Recognition.SpeechRecognitionEngine

Hier einige Code sind zu veranschaulichen.

  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." 

Weiß jemand, wie man um das herum? Es muss Streaming-Eingaben anderer Art unterstützen, da es mit dem Mikrofon funktioniert, das SetInputToDefaultAudioDevice() verwendet.

Danke, Sean

+0

Vielleicht 'SetInputToDefaultAudioDevice()' ist Microsoft "schwarze Magie" (häufig), oder es führt eine Art der Dosierung wie Sie vorgeschlagen. –

Antwort

2

Haben Sie versucht, in einem System.IO.BufferedStream die Netzwerk-Stream Verpackung?

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

Ich habe es gerade versucht, und ich habe den gleichen Fehler. – spurserh

+0

Haben Sie überprüft, ob der gepufferte Stream die Suche unterstützt? I.e., im obigen Code, gibt buffStream.CanSeek() true zurück? –

1

Ich beendete die Pufferung der Eingabe und dann an die Spracherkennungsmaschine in sukzessive größere Stücke zu senden. Zum Beispiel könnte ich zuerst die ersten 0,25 Sekunden, dann die ersten 0,5 Sekunden, dann die ersten 0,75 Sekunden usw. senden, bis ich ein Ergebnis erhalte. Ich bin mir nicht sicher, ob dies der effizienteste Weg ist, um dies zu erreichen, aber es liefert zufriedenstellende Ergebnisse für mich.

Best of luck, Sean

+0

Ich habe auch Probleme mit SAPI und MemoryStreams..just kann es nicht funktionieren, obwohl alles funktioniert von Standardeingabe oder Datei. Wenn Sie sagten, dass Sie mit einem Puffer arbeiten, meinen Sie, dass Sie den BufferStream-Ansatz verwenden, den Serguei vorgeschlagen hat, oder halten Sie einfach die Erkennung zurück, bis der MemoryStream größer ist? Ich habe beides ohne Erfolg versucht. Verwenden Sie die SpeechHypothesized-, SpeechRecognized-Ereignisse oder zwingen Sie RecognitionResult rr = recognizer.Recognize() gelegentlich? Kannst du noch mehr Code posten, um zu helfen? Würde sehr geschätzt werden. – timemirror

9

ich durch Überschreiben der Stream-Klasse Live-Spracherkennung arbeitet bekam:

class SpeechStreamer : Stream 
{ 
    private AutoResetEvent _writeEvent; 
    private List<byte> _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<byte>(_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<count && _writeEvent!=null) 
     { 
      if (!_reset && _readposition >= _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() 
    { 

    } 
} 

... und mit einer Instanz, dass als Stromeingang zu dem SetInputToAudioStream Verfahren. Sobald der Stream eine Länge zurückgibt oder die zurückgegebene Anzahl kleiner als die angeforderte ist, denkt die Erkennungs-Engine, dass die Eingabe beendet wurde. Dies richtet einen Ringpuffer ein, der niemals endet.

+0

Hallo Sean, ich habe versucht, deine Lösung zur Arbeit zu bringen, aber es bisher nicht geschafft. Wie bei anderen oben funktioniert alles gut von der Festplatte, funktioniert aber nicht mit MemoryStream. Gibt es gelegentlich eine Erkennungsanfrage, oder können Sie die SpeechHypothesized-, SpeechRecognized-Ereignisse verwenden? Könntest du noch mehr Code posten, um zu helfen? Vielen Dank! – timemirror

+0

Sorry, verpasste deine Frage, da gehst du. Damit bin ich in der Lage, Spracherkennung in Echtzeit zu machen und das Audio-Feed über das Netzwerk zu streamen (Teil meines Open-Source-Projekts ispy - http://www.ispyconnect.com) – Sean

+0

Danke Sean ... großartig aussehendes Projekt . – timemirror

1

Das ist meine Lösung.

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(); 
    } 
} 

So verwenden:

//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;