[英]Speech recognition with Microsoft Cognitive Speech API and non-microphone real-time audio stream
我的项目包括一个实时录制音频的桌面应用程序,我打算接收来自 API 的实时识别反馈。 使用麦克风,使用 Microsoft 新的 Speech-to-Text API 的实时实现是微不足道的,我的场景与我的场景的不同之处仅在于我的数据写入MemoryStream
对象。
本文解释了如何使用自定义音频流实现 API 的Recognizer
( 链接),这总是需要实现抽象类PullAudioInputStream
( 链接),以便使用CreatePullStream
方法( 链接)创建所需的AudioConfig
对象。 换句话说,要实现我的要求,必须实现回调接口。
由于我的数据被写入 MemoryStream(我使用的库只会记录到文件或 Stream 对象),在下面的代码中,我只是将缓冲区复制到实现的类(可能是草率的方式? )解决分歧在方法签名中。
class AudioInputCallback : PullAudioInputStreamCallback
{
private readonly MemoryStream memoryStream;
public AudioInputCallback(MemoryStream stream)
{
this.memoryStream = stream;
}
public override int Read(byte[] dataBuffer, uint size)
{
return this.Read(dataBuffer, 0, dataBuffer.Length);
}
private int Read(byte[] buffer, int offset, int count)
{
return memoryStream.Read(buffer, offset, count);
}
public override void Close()
{
memoryStream.Close();
base.Close();
}
}
Recognizer
实现如下:
private SpeechRecognizer CreateMicrosoftSpeechRecognizer(MemoryStream memoryStream)
{
var recognizerConfig = SpeechConfig.FromSubscription(SubscriptionKey, @"westus");
recognizerConfig.SpeechRecognitionLanguage =
_programInfo.CurrentSourceCulture.TwoLetterISOLanguageName;
// Constants are used as constructor params)
var format = AudioStreamFormat.GetWaveFormatPCM(
samplesPerSecond: SampleRate, bitsPerSample: BitsPerSample, channels: Channels);
// Implementation of PullAudioInputStreamCallback
var callback = new AudioInputCallback(memoryStream);
AudioConfig audioConfig = AudioConfig.FromStreamInput(callback, format);
//Actual recognizer is created with the required objects
SpeechRecognizer recognizer = new SpeechRecognizer(recognizerConfig, audioConfig);
// Event subscriptions. Most handlers are implemented for debugging purposes only.
// A log window outputs the feedback from the event handlers.
recognizer.Recognized += MsRecognizer_Recognized;
recognizer.Recognizing += MsRecognizer_Recognizing;
recognizer.Canceled += MsRecognizer_Canceled;
recognizer.SpeechStartDetected += MsRecognizer_SpeechStartDetected;
recognizer.SpeechEndDetected += MsRecognizer_SpeechEndDetected;
recognizer.SessionStopped += MsRecognizer_SessionStopped;
recognizer.SessionStarted += MsRecognizer_SessionStarted;
return recognizer;
}
如何将数据提供给识别器(使用 CSCore):
MemoryStream memoryStream = new MemoryStream(_finalSource.WaveFormat.BytesPerSecond / 2);
byte[] buffer = new byte[_finalSource.WaveFormat.BytesPerSecond / 2];
_soundInSource.DataAvailable += (s, e) =>
{
int read;
_programInfo.IsDataAvailable = true;
// Writes to MemoryStream as event fires
while ((read = _finalSource.Read(buffer, 0, buffer.Length)) > 0)
memoryStream.Write(buffer, 0, read);
};
// Creates MS recognizer from MemoryStream
_msRecognizer = CreateMicrosoftSpeechRecognizer(memoryStream);
//Initializes loopback capture instance
_soundIn.Start();
await Task.Delay(1000);
// Starts recognition
await _msRecognizer.StartContinuousRecognitionAsync();
当应用程序运行时,我没有收到任何异常,也没有来自 API 的任何响应,除了SessionStarted
和SessionStopped
,如下面我的应用程序的日志窗口所示。
我可以使用不同方法的建议来实现我的实现,因为我怀疑将记录的DataAvailable
事件与实际向 API 发送数据相关联时存在一些时间问题,这使得它过早地丢弃会话。 由于没有关于我的请求为何不成功的详细反馈,我只能猜测原因。
如果没有立即可用的数据, PullAudioInputStream
的Read()
回调应该阻塞。 只有当流到达末尾时, Read()
返回 0。 然后,在Read()
返回 0 后,SDK 将关闭流Read()
在此处找到 API 参考文档)。
但是,C# MemoryStream 的 Read() 的行为不同:如果缓冲区中没有可用数据,则返回 0。 这就是为什么您只看到SessionStart
和SessionStop
事件,而看不到识别事件的原因。
为了解决这个问题,您需要在PullAudioInputStream::Read()
和MemoryStream::Write()
之间添加某种同步,以确保PullAudioInputStream::Read()
将等到MemoryStream::Write()
将一些数据写入缓冲区。
或者,我建议使用PushAudioInputStream
,它允许您直接将数据写入流。 对于你的情况,在_soundSource.DataAvailable
事件,而不是将数据写入MemoryStream
,你可以直接把它写到PushAudioInputStream
。 您可以在此处找到PushAudioInputStream
示例。
我们将更新文档以提供有关如何使用 Pull 和 Push AudioInputStream
的最佳实践。 带来不便敬请谅解。
谢谢!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.