如何使用从浏览器发送到 Nodejs 服务器的 Blob 进行 Google Speech-to-Text

Ali*_*ron 9 audio-streaming node.js socket.io getusermedia google-speech-api

我正在尝试设置服务器以使用 接收来自客户端浏览器的音频SocketIO,然后通过 Google Speech-to-Text 对其进行处理,最后将文本回复给客户端。

最初和理想情况下,我想设置得有点像此页面上的工具:https : //cloud.google.com/speech-to-text/

我尝试使用getUserMedia和流式传输它SocketIO-Stream,但我不知道如何“管道” MediaStream

相反,现在我决定MediaRecorder在客户端使用,然后将数据作为 blob 一起发送(见本示例)。

然后我申请toString('base64')blob 并在 blob 上调用 google-cloud/speech client.recognize()

客户端(我正在使用 VueJS):

        new Vue({
            el: '#app',
            data: function () {
                return ({
                    msgs: [],
                    socket: null,
                    recorder: null,
                    : []
                })
            },
            mounted: function () {
                this.socket = io.connect('localhost:3000/user');
                console.log('Connected!')
                this.socket.on('text', function (text) {
                    this.msgs.push(text)
                })
            },
            methods: {
                startRecording: function () {
                    if (this.recorder && this.recorder.state == 'recording') {
                        console.log("Stopping!")
                        this.recorder.stop()
                    } else {
                        console.log("Starting!")
                        navigator.mediaDevices.getUserMedia({ audio: true, video: false })
                            .then(this.handleSuccess);
                    }
                },
                handleSuccess: function (stream) {
                    this.recorder = new MediaRecorder(stream)
                    this.recorder.start(10000)
                    this.recorder.ondataavailable = (e) => {
                        this.chunks.push(e.data)
                        console.log(e.data)
                    }
                    this.recorder.onstop = (e) => {
                        const blob = new Blob(this.chunks, { 'type': 'audio/webm; codecs=opus' })
                        this.socket.emit('audio', blob)
                    }
                }
            }
        })
Run Code Online (Sandbox Code Playgroud)

服务器端:

        new Vue({
            el: '#app',
            data: function () {
                return ({
                    msgs: [],
                    socket: null,
                    recorder: null,
                    : []
                })
            },
            mounted: function () {
                this.socket = io.connect('localhost:3000/user');
                console.log('Connected!')
                this.socket.on('text', function (text) {
                    this.msgs.push(text)
                })
            },
            methods: {
                startRecording: function () {
                    if (this.recorder && this.recorder.state == 'recording') {
                        console.log("Stopping!")
                        this.recorder.stop()
                    } else {
                        console.log("Starting!")
                        navigator.mediaDevices.getUserMedia({ audio: true, video: false })
                            .then(this.handleSuccess);
                    }
                },
                handleSuccess: function (stream) {
                    this.recorder = new MediaRecorder(stream)
                    this.recorder.start(10000)
                    this.recorder.ondataavailable = (e) => {
                        this.chunks.push(e.data)
                        console.log(e.data)
                    }
                    this.recorder.onstop = (e) => {
                        const blob = new Blob(this.chunks, { 'type': 'audio/webm; codecs=opus' })
                        this.socket.emit('audio', blob)
                    }
                }
            }
        })
Run Code Online (Sandbox Code Playgroud)

main()服务器端函数的日志总是:

“转录:”

——这是空的!

它应该包含来自发送的音频的文本。先感谢您!

O. *_*nes 8

您的 nodejs 应用程序要求处理原始音频数据,以'LINEAR16'16k 样本/秒 ( 16000)的速率记录为 16 位有符号整数 ( )数组。由于在古代电话知识中丢失的原因,这种音频表示被称为脉冲编码调制 (PCM)

但是您从客户端代码发送的 Blob 并非如此。它是一个具有 content-type 的媒体对象audio/webm; codecs=opus。这意味着音轨使用Opus 编解码器压缩并以 webm (Matroska, ebml) 容器格式装箱(多路复用)。云文本转语音代码试图将其解释为原始音频数据,但失败并举手并返回一个空的转录字符串。这类似于尝试在文本编辑器中查看 zip 文件:这只是胡言乱语。

要使文本转语音与媒体对象一起使用,您必须首先从中提取 PCM 音频。这是在服务器上设置的一项臭名昭著的痛苦;你必须使用 ffmpeg。在 text-to-speech 文档中有一个关于它教程。本教程提到从视频文件中抓取音频。你的 Blob 基本上是一个没有视频轨道的视频文件,所以同样的技术也能工作。

但是,您最好返回第一种方法,使用MediaStream 浏览器 javascript API。特别是,您的浏览器代码应该使用Web Audio API 的元素来拦截原始 PCM 音频数据并将其发送到您的服务器或直接从您的浏览器发送到文本到语音。

解释所有这些超出了 StackOverflow 答案的范围。这里有一些提示。如何使用网络音频 api 获取原始 pcm 音频?