react框架下基于MQTT的实时喊话功能(录音+广播)

一、需求

不采用任何额外的插件服务,通过浏览器采集电脑麦克风声音,并实时播放

二、技术思路

1、通过浏览器采集电脑麦克风的声音,recorder.js

①完整示例参考:https://www.jb51.net/article/159849.htm
npm 安装js-audio-recorder插件版本
(1.x版本目前不支持边录边转,0.x版本支持)
1.x版本:https://github.com/2fps/recorder
0.x版本:https://gitee.com/davylw/recorder
1.x版本-在线测试:https://recorder.zhuyuntao.cn/

②如果上面的插件在参考本文做法后还是不能满足你的需求,可以尝试看下这个:https://github.com/xiangyuecn/Recorder
亲测可用,具体demo示例(uniapp)见:后期更新
在线demo测试:https://xiangyuecn.gitee.io/recorder/

③其他录音功能参考(其实我没用到,就当入门学习吧)
https://blog.csdn.net/qiao_1017/article/details/102609243
https://www.cnblogs.com/shihuc/p/9703508.html

2、采集的声音是WAV格式的,通过lamejs转成MP3 格式

参考:https://github.com/zhuker/lamejs

3、通过MQTT,把音频发布到后台
let payload ='';
await mp3Blob.arrayBuffer().then((arraybuffer) => {
    payload=new Uint8Array(arraybuffer)//8位无符号整型数组
});
//发送到后台
MQTT.publish('audiostream/'+streamid,payload,{qos:0}, () => {//消息发布
    console.log("音频消息发布")
});

三、实现步骤

1、npm安装录音插件npm i js-audio-recorder

//开始录音
startRecord = () => {
    this.clearPlay();

    const config = this.collectData();
    console.log(config)
    if (!recorder) {
        recorder = new Recorder(config);

        recorder.onprocess =(duration)=>{
            // this.setState({
            //     duration: duration.toFixed(5),
            // });
            // 推荐使用 onprogress
        }

        recorder.onprogress = (params) => {
            // console.log(recorder.duration);
            // console.log(recorder.fileSize);

            this.setState({
                duration: params.duration.toFixed(5),//录音时长
                fileSize: params.fileSize,//已录音文件大小(字节)
                vol: params.vol.toFixed(2)//录音音量百分比
            });
            // // 此处控制数据的收集频率
            // if (config.compiling) {
            //     // console.log('音频总数据:', params.data);
            // }
        }

        recorder.onplay = () => {
            console.log('%c回调监听,开始播放音频', 'color: #2196f3')
        }
        recorder.onpauseplay = () => {
            console.log('%c回调监听,暂停播放音频', 'color: #2196f3')
        }
        recorder.onresumeplay = () => {
            console.log('%c回调监听,恢复播放音频', 'color: #2196f3')
        }
        recorder.onstopplay = () => {
            console.log('%c回调监听,停止播放音频', 'color: #2196f3')
        }
        recorder.onplayend = () => {
            console.log('%c回调监听,音频已经完成播放', 'color: #2196f3')
            // 播放结束后,停止绘制canavs
            // this.stopDrawPlay();
        }

        // 定时获取录音的数据并播放
        config.compiling && (playTimer = setInterval(async() => {
            if (!recorder) {
                return;
            }

            let newData = recorder.getNextData();
            if (!newData.length) {
                return;
            }
            let byteLength = newData[0].byteLength
            let buffer = new ArrayBuffer(newData.length * byteLength)
            let dataView = new DataView(buffer)

            // 数据合并
            for (let i = 0, iLen = newData.length; i < iLen; ++i) {
                for (let j = 0, jLen = newData[i].byteLength; j < jLen; ++j) {
                    dataView.setInt8(i * byteLength + j, newData[i].getInt8(j))
                }
            }
            // 将录音数据转成WAV格式
            let a = encodeWAV(dataView, config.sampleRate, config.sampleRate, config.numChannels, config.sampleBits)
            let blob=new Blob([ a ], { type: 'audio/wav' });//一个专门用于支持文件操作的二进制对象
            let payload ='',payloadMp3='';
            await blob.arrayBuffer().then((arraybuffer) => {//一个通用的二进制缓冲区,类似数组,但在API和特性上有诸多不同
                payload=new Uint8Array(arraybuffer)//不懂为啥
            });
            // 将录音数据转成mp3格式(使用lamejs转成MP3)
            let mp3Blob = this.convertWavToMp30(a);//转成MP3格式
            await mp3Blob.arrayBuffer().then((arraybuffer) => {
            	//这里不清楚为啥要转成8位无符号整型数组
                payloadMp3=new Uint8Array(arraybuffer)
            });
            //0.x版本实现边转边播
            // Recorder.playAudio(blob);
            //1.x版本实现边转边播-暂未实现
            // blob.arrayBuffer().then((arraybuffer) => {
            //     Player.play(arraybuffer);
            // });
            //将录音转成MP3,并发送到后台
            MQTT.publish('wavstream/1',payloadMp3,{qos:0}, () => {//消息发布
                console.log("音频消息发布")
            });
            //end发送到后台
        }, 3000))
    } else {
        recorder.stop();
    }

    recorder.start().then(() => {
        console.log('开始录音');
    }, (error) => {
        console.log(`异常了,${error.name}:${error.message}`);
    });
    // 开始绘制canvas
    // this.drawRecord();

}

2、npm安装lamejsnpm install lamejs

//将录音数据转成mp3格式(使用lamejs转成MP3)
convertWavToMp30=(wavDataView)=> {
    const wav = lamejs.WavHeader.readHeader(wavDataView);
    const samples = new Int16Array(wavDataView.buffer, wav.dataOffset, wav.dataLen / 2);
    const { channels, sampleRate } = wav;
    const buffer = [];
    const mp3enc = new lamejs.Mp3Encoder(channels, sampleRate, 128);
    let remaining = samples.length;
    const maxSamples = 1152;
    for (let i = 0; remaining >= maxSamples; i += maxSamples) {
      const mono = samples.subarray(i, i + maxSamples);
      const mp3buf = mp3enc.encodeBuffer(mono);
      if (mp3buf.length > 0) {
        buffer.push(new Int8Array(mp3buf));
      }
      remaining -= maxSamples;
    }
    const d = mp3enc.flush();
    if (d.length > 0) {
      buffer.push(new Int8Array(d));
    }
    return new Blob(buffer, { type: 'audio/mp3' });
}

四、注意点

根据上述步骤完成后,发布到正式环境,会发现有几个问题:
1、录音功能只能localhost或者127.0.0.1时可用,输入地址时提示浏览器不支持
解决方案:
参考:新版chrome中非https无法打开摄像头、麦克风
https://www.jianshu.com/p/751a9cb93a43?tdsourcetag=s_pctim_aiomsg
步骤:
1、在浏览器地址栏中输入chrome://flags,
2、搜索栏中输入unsafely
3、如下图,将该选项置为Enabled,在输入框中输入需要访问的地址,多个地址使用“,”隔开;如果输入地址后,你测试依然无效,记得加上端口号试试
4、然后点击右下角弹出的Relaunch按钮,自动重启浏览器之后就可以在添加的http地址下调用摄像头和麦克风了。在这里插入图片描述
注意:如果输入地址后,你测试依然无效,记得加上端口号试试
在这里插入图片描述

网上其他解决方案(我测试下来好像没啥用,如果上面的方法不能解决,可以试试)

//不知道这几种行不行-没试http转成https
//有人用这个方法解决了,用了代理加上nginx,配置https,就可以了
https://blog.csdn.net/baiyunshi/article/details/98207952?utm_medium=distribute.pc_relevant_bbs_down.none-task--2~all~sobaiduend~default-2.nonecase&depth_1-utm_source=distribute.pc_relevant_bbs_down.none-task--2~all~sobaiduend~default-2.nonecase
https://blog.csdn.net/cswhl/article/details/110183132?utm_medium=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-1.nonecase&depth_1-utm_source=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-1.nonecase

2、录音语速变快。录制完语音后,播放倍率明显加快,导致录音时长变短
解决方案:
我发现录制歌曲时,明明时间相同,但是打印录制的时间总是变短。
然后找到node_modules/js-audio-recorder/dist/recorder.js中的initRecorder函数,把duration延长(这里是通过把缓存变大,使得时间变长,注意:缓冲区大小(12288)必须为0或256到16384之间的2的幂。)
在这里插入图片描述
这是我的解决方法,如果大家遇到同样的现象,可以试一下。

网上比较靠谱的其他方法(我没进行测试):

//原因--录制完语音后,播放倍率明显加快,导致录音时长变短
https://github.com/xiangyuecn/Recorder/issues/51
//解决方案--解决设备卡顿时接收到PCM缺失导致音频变短
https://github.com/xiangyuecn/Recorder/commit/cbd272bc725923c915c825983277f8766bdbc0a0
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Paho-MQTT是一个用于在React应用中连接和与MQTT服务器通信的库。下面是使用React Paho-MQTT连接MQTT并发送请求的步骤: 1. 首先,安装React Paho-MQTT库。可以使用npm或者yarn进行安装: ``` npm install react-paho-mqtt ``` 或者 ``` yarn add react-paho-mqtt ``` 2. 在React组件中导入所需的库: ```javascript import { MQTTProvider, useMQTT } from 'react-paho-mqtt';``` 3. 在组件中设置MQTT连接参数,并创建一个MQTT客户端实例: ```javascript const mqttConfig = { host: 'mqtt.example.com', // MQTT服务器地址 port: 1883, // MQTT服务器端口 clientId: 'myClientId', // 客户端ID username: 'myUsername', // 用户名(可选) password: 'myPassword', // 密码(可选) }; const mqttClient = new Paho.MQTT.Client(mqttConfig.host, mqttConfig.port, mqttConfig.clientId); ``` 4. 在组件中使用`MQTTProvider`组件包裹需要使用MQTT功能的子组件,并传递MQTT客户端实例和配置参数: ```javascript function App() { return ( <MQTTProvider client={mqttClient} config={mqttConfig}> <MyComponent /> </MQTTProvider> ); } ``` 5. 在子组件中使用`useMQTT`钩子来订阅主题和发送消息: ```javascript function MyComponent() { const { mqtt } = useMQTT(); // 订阅主题 useEffect(() => { mqtt.subscribe('myTopic'); return () => { mqtt.unsubscribe('myTopic'); }; }, []); // 发送消息 const sendMessage = () => { const message = new Paho.MQTT.Message('Hello, MQTT!'); message.destinationName = 'myTopic'; mqtt.send(message); }; return ( <div> <button onClick={sendMessage}>发送消息</button> </div> ); } ``` 这样,你就可以使用React Paho-MQTT库连接MQTT服务器并发送请求了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值