Frage Streaming-Eingabe für System.Speech.Recognition.SpeechRecognitionEngine


Ich versuche "Streaming" Spracherkennung in C # von einem TCP-Socket. Das Problem, das ich habe, ist, dass SpeechRecognitionEngine.SetInputToAudioStream () scheint, einen Stream einer definierten Länge zu verlangen, die suchen kann. Im Moment kann ich nur daran denken, das Recognizer auf einem MemoryStream laufen zu lassen, wenn mehr Input hereinkommt.

Hier ist ein Code zur Veranschaulichung:

            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 das schafft? Es muss Streaming-Eingaben anderer Art unterstützen, da es mit dem Mikrofon funktioniert, das SetInputToDefaultAudioDevice () verwendet.

Danke, Sean


7
2017-11-05 19:16


Ursprung


Antworten:


Ich habe Live-Spracherkennung durch Überschreiben der Stream-Klasse funktioniert:

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 eine Instanz davon als Stream-Eingabe für die SetInputToAudioStream-Methode verwenden. 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.


11
2017-08-05 01:29



Haben Sie versucht, den Netzwerkstream in einem System.IO.BufferedStream zu verpacken?

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

2
2017-11-05 19:24



Am Ende puffte ich die Eingabe und sendete sie dann in sukzessiv größeren Blöcken an die Spracherkennungsmaschine. 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.

Viel Glück, Sean


1
2018-01-09 13:17



Anscheinend kann es nicht gemacht werden ("By Design"!). Sehen http://social.msdn.microsoft.com/Forums/en/netfxbcl/thread/fcf62d6d-19df-4ca9-9f1f-17724441f84e 


1
2017-11-20 05:49



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

Wie benutzt man:

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

1
2018-06-09 06:04