You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hololens 2中如何将WindowsMicrophoneStream接入Azure Speech SDK

解决方案:将Hololens 2 Room Capture麦克风流接入Azure Speech SDK

方案一:自定义PullAudioInputStreamCallback实现(优先推荐)

Speech SDK的Pull模式是SDK主动从回调拉取音频数据,刚好适配你已经初始化好的Room Capture流,步骤如下:

  1. 先确认你的Windows麦克风流(Room Capture类别)格式和Speech SDK要求一致:

    • 采样率:16000Hz(SDK默认强制要求)
    • 位深:16位
    • 声道:单声道
    • 编码:PCM原始格式
  2. 实现PullAudioInputStreamCallback核心类,重点完成Read()方法的音频数据读取逻辑:

    using Microsoft.CognitiveServices.Speech.Audio;
    using Windows.Media.Capture;
    using Windows.Media.MediaProperties;
    using Windows.Storage.Streams;
    
    public class RoomCaptureAudioCallback : PullAudioInputStreamCallback
    {
        private readonly MediaCapture _mediaCapture;
        private readonly AudioFrameInputNode _audioInputNode;
        private readonly byte[] _buffer;
        private bool _isStreaming = true;
    
        // 传入你已经初始化好的MediaCapture和对应的AudioFrameInputNode
        public RoomCaptureAudioCallback(MediaCapture mediaCapture, AudioFrameInputNode audioInputNode)
        {
            _mediaCapture = mediaCapture;
            _audioInputNode = audioInputNode;
            // 按10ms音频数据量初始化缓冲区(16000Hz*1声道*2字节/采样 = 320字节)
            _buffer = new byte[320];
        }
    
        public override int Read(byte[] dataBuffer, uint size)
        {
            if (!_isStreaming || _audioInputNode == null)
            {
                return 0; // 返回0告知SDK流已结束
            }
    
            uint bytesRead = 0;
            try
            {
                // 从Room Capture流中获取音频帧并读取PCM数据
                using (var frame = _audioInputNode.GetFrame())
                using (var audioBuffer = frame.LockBuffer(AudioBufferAccessMode.Read))
                using (var bufferRef = audioBuffer.CreateReference())
                {
                    var inputStream = bufferRef as IInputStream;
                    var readResult = inputStream.ReadAsync(_buffer.AsBuffer(), size, InputStreamOptions.None).AsTask().Wait();
                    bytesRead = (uint)_buffer.Length;
                    // 将读取到的数据复制到SDK要求的输出缓冲区
                    System.Buffer.BlockCopy(_buffer, 0, dataBuffer, 0, (int)bytesRead);
                }
            }
            catch
            {
                // 捕获流中断等异常,标记流停止
                _isStreaming = false;
                bytesRead = 0;
            }
    
            return (int)bytesRead;
        }
    
        public override void Close()
        {
            _isStreaming = false;
            _audioInputNode?.Dispose();
            base.Close();
        }
    }
    
  3. 关联回调与Speech SDK初始化:

    // 实例化自定义回调(传入你已初始化的MediaCapture和AudioFrameInputNode)
    var audioCallback = new RoomCaptureAudioCallback(yourMediaCapture, yourAudioInputNode);
    // 创建Pull模式音频输入流
    var audioInputStream = AudioInputStream.CreatePullStream(audioCallback);
    // 生成SDK可用的音频配置
    var audioConfig = AudioConfig.FromStreamInput(audioInputStream);
    // 初始化语音识别器
    var speechRecognizer = new SpeechRecognizer(yourSpeechConfig, audioConfig);
    

方案二:Push模式主动推送音频数据

如果更倾向于主动将麦克风数据推送给SDK,可以实现后台读取线程,把Room Capture流数据推送到PushAudioInputStream:

  1. 实现Push流处理类:

    using Microsoft.CognitiveServices.Speech.Audio;
    using Windows.Media.Capture;
    using Windows.Media.MediaProperties;
    using Windows.Storage.Streams;
    
    public class RoomCapturePushStreamHandler
    {
        private readonly PushAudioInputStream _pushStream;
        private readonly MediaCapture _mediaCapture;
        private readonly AudioFrameInputNode _audioInputNode;
        private bool _isRunning = true;
    
        public RoomCapturePushStreamHandler(MediaCapture mediaCapture, AudioFrameInputNode audioInputNode)
        {
            _mediaCapture = mediaCapture;
            _audioInputNode = audioInputNode;
            _pushStream = AudioInputStream.CreatePushStream();
            // 启动后台线程读取并推送数据
            _ = ReadAndPushAudioData();
        }
    
        private async Task ReadAndPushAudioData()
        {
            var buffer = new byte[320]; // 同10ms音频数据量
            while (_isRunning)
            {
                try
                {
                    using (var frame = _audioInputNode.GetFrame())
                    using (var audioBuffer = frame.LockBuffer(AudioBufferAccessMode.Read))
                    using (var bufferRef = audioBuffer.CreateReference())
                    {
                        var inputStream = bufferRef as IInputStream;
                        var readResult = await inputStream.ReadAsync(buffer.AsBuffer(), (uint)buffer.Length, InputStreamOptions.None);
                        if (readResult.Length > 0)
                        {
                            // 将PCM数据推送给SDK
                            _pushStream.Write(buffer, 0, (int)readResult.Length);
                        }
                    }
                    // 匹配音频采样频率控制读取间隔
                    await Task.Delay(10);
                }
                catch
                {
                    _isRunning = false;
                    break;
                }
            }
        }
    
        // 返回SDK可用的音频配置
        public AudioConfig GetAudioConfig()
        {
            return AudioConfig.FromStreamInput(_pushStream);
        }
    
        // 停止推送并释放资源
        public void Stop()
        {
            _isRunning = false;
            _pushStream.Close();
        }
    }
    
  2. 初始化Speech识别器:

    var pushHandler = new RoomCapturePushStreamHandler(yourMediaCapture, yourAudioInputNode);
    var audioConfig = pushHandler.GetAudioConfig();
    var speechRecognizer = new SpeechRecognizer(yourSpeechConfig, audioConfig);
    

关键注意事项

  • 必须保证Room Capture流的音频格式严格匹配SDK要求,否则会出现识别失败、杂音等问题。
  • Hololens 2端需要在Unity Player Settings中开启Microphone权限,同时在Package.appxmanifest中添加microphone和spatialPerception权限(Room Capture依赖空间感知)。
  • 场景退出或识别停止时,务必释放MediaCapture、AudioNode、Speech识别器等实例,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Leado

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 06:15:39