c# - 使用 Microsoft Cognitive Speech API 和非麦克风实时音频流进行语音识别
问题描述
问题
我的项目包含一个实时录制音频的桌面应用程序,我打算为此接收来自 API 的实时识别反馈。使用麦克风,使用 Microsoft 新的 Speech-to-Text API 的实时实现是微不足道的,我的场景与此不同,仅在我的数据被写入MemoryStream
对象的意义上。
API 支持
本文解释了如何使用自定义音频流Recognizer
实现 API (链接),这总是需要实现抽象类(链接),以便使用方法(链接)创建所需的对象。也就是说,要实现我所要求的,必须实现一个回调接口。PullAudioInputStream
AudioConfig
CreatePullStream
实施尝试
由于我的数据被写入 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();
结果
SessionStarted
当应用程序运行时,除了和之外,我没有收到任何异常,也没有来自 API 的任何响应SessionStopped
,如下面我的应用程序的日志窗口所示。
我可以使用不同方法的建议来实现我的实现,因为我怀疑将记录的DataAvailable
事件与向 API 的实际数据发送联系起来存在一些时间问题,这使它过早地丢弃了会话。由于没有详细反馈我的请求为何不成功,我只能猜测原因。
解决方案
如果没有立即可用的数据,则应该阻塞的Read()
回调。PullAudioInputStream
并且Read()
仅当流到达末尾时才返回 0。SDK 将在返回 0 后关闭流(在此处Read()
查找 API 参考文档)。
但是,C# MemoryStream 的 Read() 的行为不同:如果缓冲区中没有可用数据,则返回 0。这就是为什么你只看到SessionStart
和SessionStop
事件,但没有识别事件。
为了解决这个问题,您需要在PullAudioInputStream::Read()
and之间添加某种同步MemoryStream::Write()
,以确保PullAudioInputStream::Read()
将等到MemoryStream::Write()
将一些数据写入缓冲区。
或者,我建议使用PushAudioInputStream
,它允许您直接将数据写入流。对于您的情况,_soundSource.DataAvailable
如果不将数据写入MemoryStream
,您可以直接将其写入PushAudioInputStream
. PushAudioInputStream
你可以在这里找到样品。
我们将更新文档以提供有关如何使用 Pull 和 Push 的最佳实践AudioInputStream
。带来不便敬请谅解。
谢谢!
推荐阅读
- javascript - 显示带有引号的 Javascript 变量
- f# - F# 序列行为
- javascript - 反应谷歌地图中的内容政策
- machine-learning - 字符串分类,如何逐字符编码并训练?
- c# - C# 使用 HtmlAgilityPack 从网站打印特定字符串
- javascript - 在输入字段上触发输入按钮
- laravel - 在laravel中提交excel文件时如何删除逗号和空格
- mongodb - 仅在嵌入文档 Mongodb 中使用 $ 时更新单个特定字段
- python - Google Colab 中的多个 GPU
- mongodb - mongodb如何存储和管理元数据?