首页 > 解决方案 > 使用 Microsoft Cognitive Speech API 和非麦克风实时音频流进行语音识别

问题描述

问题

我的项目包含一个实时录制音频的桌面应用程序,我打算为此接收来自 API 的实时识别反馈。使用麦克风,使用 Microsoft 新的 Speech-to-Text API 的实时实现是微不足道的,我的场景与此不同,仅在我的数据被写入MemoryStream对象的意义上。

API 支持

本文解释了如何使用自定义音频流Recognizer实现 API (链接),这总是需要实现抽象类(链接),以便使用方法(链接)创建所需的对象。也就是说,要实现我所要求的,必须实现一个回调接口。PullAudioInputStreamAudioConfigCreatePullStream

实施尝试

由于我的数据被写入 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 的实际数据发送联系起来存在一些时间问题,这使它过早地丢弃了会话。由于没有详细反馈我的请求为何不成功,我只能猜测原因。

标签: c#audiospeech-recognitionmicrosoft-cognitivecscore

解决方案


如果没有立即可用的数据,则应该阻塞的Read()回调。PullAudioInputStream并且Read()仅当流到达末尾时才返回 0。SDK 将在返回 0 后关闭流(在此处Read()查找 API 参考文档)。

但是,C# MemoryStream 的 Read() 的行为不同:如果缓冲区中没有可用数据,则返回 0。这就是为什么你只看到SessionStartSessionStop事件,但没有识别事件。

为了解决这个问题,您需要在PullAudioInputStream::Read()and之间添加某种同步MemoryStream::Write(),以确保PullAudioInputStream::Read()将等到MemoryStream::Write()将一些数据写入缓冲区。

或者,我建议使用PushAudioInputStream,它允许您直接将数据写入流。对于您的情况,_soundSource.DataAvailable如果不将数据写入MemoryStream,您可以直接将其写入PushAudioInputStream. PushAudioInputStream 你可以在这里找到样品。

我们将更新文档以提供有关如何使用 Pull 和 Push 的最佳实践AudioInputStream。带来不便敬请谅解。

谢谢!


推荐阅读