C# 流式输入到System.Speech.Recognition.SpeechRecognitionEngine
我正在尝试用C#从TCP套接字进行“流式”语音识别。我遇到的问题是SpeechRecognitionEngine.setInputOAudioStream()似乎需要一个定义长度的流,该流可以搜索。现在,我能想到的唯一方法是,当更多的输入进来时,在MemoryStream上重复运行识别器 下面是一些代码来说明:C# 流式输入到System.Speech.Recognition.SpeechRecognitionEngine,c#,sockets,streaming,speech-recognition,sapi,C#,Sockets,Streaming,Speech Recognition,Sapi,我正在尝试用C#从TCP套接字进行“流式”语音识别。我遇到的问题是SpeechRecognitionEngine.setInputOAudioStream()似乎需要一个定义长度的流,该流可以搜索。现在,我能想到的唯一方法是,当更多的输入进来时,在MemoryStream上重复运行识别器 下面是一些代码来说明: SpeechRecognitionEngine appRecognizer = new SpeechRecognitionEngine();
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."
有人知道怎么避开这件事吗?它必须支持某种类型的流式输入,因为它可以使用setInputOdeFaultAudioDevice()与麦克风配合使用
谢谢,Sean您是否尝试过将网络流包装到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);
我最终缓冲了输入,然后将其以连续较大的块发送到语音识别引擎。例如,我可能先发送0.25秒,然后发送0.5秒,然后发送0.75秒,依此类推,直到得到结果。我不确定这是否是最有效的方法,但它会给我带来令人满意的结果
祝你好运,肖恩(Sean)显然这是不可能的(“故意的”!)。请参见我通过覆盖流类实现了实时语音识别:
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()
{
}
}
class SpeechStreamer:Stream
{
私人自动存储事件_writeEvent;
私有列表缓冲区;
私有int_缓冲区大小;
私人内部位置;
私人int_写入位置;
私人楼宇重置;
公共演讲拖缆(int bufferSize)
{
_writeEvent=新的自动重置事件(false);
_缓冲大小=缓冲大小;
_缓冲区=新列表(_buffersize);
对于(int i=0;i<\u buffersize;i++)
_Add(新字节());
_readposition=0;
_writeposition=0;
}
公共覆盖布尔可读取
{
获取{return true;}
}
公共覆盖布尔搜索
{
获取{return false;}
}
公共覆盖布尔可写
{
获取{return true;}
}
公共覆盖长长度
{
获取{return-1L;}
}
公众优先多头仓位
{
获取{return 0L;}
集合{}
}
公共覆盖长寻道(长偏移,参见原始坐标系)
{
返回0升;
}
公共覆盖无效设置长度(长值)
{
}
公共重写整型读取(字节[]缓冲区、整型偏移量、整型计数)
{
int i=0;
while(i=_writeposition)
{
_writeEvent.WaitOne(100,true);
继续;
}
缓冲区[i]=_缓冲区[_读取位置+偏移量];
_readposition++;
如果(_readposition==_buffersize)
{
_readposition=0;
_重置=错误;
}
i++;
}
返回计数;
}
公共重写无效写入(字节[]缓冲区、整数偏移量、整数计数)
{
对于(int i=offset;i
。。。并使用该实例作为SetInputOAudioStream方法的流输入。一旦流返回的长度或返回的计数小于请求的长度或计数,识别引擎就会认为输入已完成。这将设置一个永不结束的循环缓冲区。这是我的解决方案
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();
}
}
如何使用:
//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;
可能
setInputOdeFaultAudioDevice()
是Microsoft的“黑魔法”(常见),或者它按照您的建议执行某种批处理。您是否验证缓冲流支持查找?也就是说,在上面的代码中,buffStream.CanSeek()是否返回true?嗨,Sean,我一直在尝试让您的解决方案工作,但到目前为止还没有成功。正如上面提到的其他方法一样,磁盘文件中的所有内容都可以正常工作,但MemoryStream不起作用。您是否偶尔发出识别请求,或者您是否能够使用SpeechAssociated、SpeechReceigned事件?你能发布更多的代码来帮助我吗?谢谢对不起,没有回答你的问题,好了。有了它,我可以进行实时语音识别,也可以通过网络传输音频(我的开源项目ispy的一部分)谢谢Sean…非常好看的项目。你是个天才Sean!您的代码的最新版本工作完美!捕获Skype的输出并针对SAPI运行以进行语音识别。非常感谢您的帮助…您好timemirror您有使用skype的SpeechStreamer的示例代码吗?我在SAPI和MemoryStream方面也有问题。只是无法让它工作,尽管从默认输入或文件中一切都正常。当你说你使用缓冲区工作时,你是说你使用Serguei建议的BufferStream方法,还是说你只是在MemoryStream变大之前停止识别?我两个都试过了,都没有成功。您是否经常使用SpeechResponsized、SpeechRecognited事件或强制识别结果rr=recognizer.recognizer()?您是否可以发布更多代码来提供帮助?非常感谢。