音频开发-小程序和H5

news2024/11/16 9:47:19

微信录音

1、引入sdk

 

 

2、录音操作

 

 

 

浏览器录音

 

参考文献:前端H5实现调用麦克风,录音功能_h5 录音_Darker丨峰神的博客-CSDN博客

function record() {

    window.navigator.mediaDevices.getUserMedia({

        audio: {

            sampleRate: 44100, // 采样率

            channelCount: 2,   // 声道

            volume: 2.0        // 音量

        }

    }).then(mediaStream => {

        console.log(mediaStream);

        window.mediaStream = mediaStream

        // beginRecord(window.mediaStream);

    }).catch(err => {

        // 如果用户电脑没有麦克风设备或者用户拒绝了,或者连接出问题了等

        // 这里都会抛异常,并且通过err.name可以知道是哪种类型的错误

        console.error(err);

    });

}

function beginRecord(mediaStream) {

    let audioContext = new (window.AudioContext || window.webkitAudioContext);

    let mediaNode = audioContext.createMediaStreamSource(mediaStream);

    console.log(mediaNode)

    window.mediaNode = mediaNode

    // 这里connect之后就会自动播放了

    // mediaNode.connect(audioContext.destination); //直接把录的音直接播放出来

    // 创建一个jsNode

    let jsNode = createJSNode(audioContext);

    window.jsNode = jsNode

    // 需要连到扬声器消费掉outputBuffer,process回调才能触发

    // 并且由于不给outputBuffer设置内容,所以扬声器不会播放出声音

    jsNode.connect(audioContext.destination);

    jsNode.onaudioprocess = onAudioProcess;

    // 把mediaNode连接到jsNode

    mediaNode.connect(jsNode);

}

function createJSNode(audioContext) {

    const BUFFER_SIZE = 4096; //4096

    const INPUT_CHANNEL_COUNT = 2;

    const OUTPUT_CHANNEL_COUNT = 2;

    // createJavaScriptNode已被废弃

    let creator = audioContext.createScriptProcessor || audioContext.createJavaScriptNode;

    creator = creator.bind(audioContext);

    return creator(BUFFER_SIZE,

        INPUT_CHANNEL_COUNT, OUTPUT_CHANNEL_COUNT);

}

let leftDataList = [],

    rightDataList = [];

function onAudioProcess(event) {

    // console.log(event.inputBuffer);

    let audioBuffer = event.inputBuffer;

    let leftChannelData = audioBuffer.getChannelData(0),

        rightChannelData = audioBuffer.getChannelData(1);

    // console.log(leftChannelData, rightChannelData);

    // 需要克隆一下

    leftDataList.push(leftChannelData.slice(0));

    rightDataList.push(rightChannelData.slice(0));

}

function bofangRecord() {

    // 播放录音

    let leftData = mergeArray(leftDataList),

        rightData = mergeArray(rightDataList);

    let allData = interleaveLeftAndRight(leftData, rightData);

    let wavBuffer = createWavFile(allData);

    playRecord(wavBuffer);

}

function playRecord(arrayBuffer) {

    let blob = new Blob([new Uint8Array(arrayBuffer)]);

    let blobUrl = URL.createObjectURL(blob);

    document.querySelector('.audio-node').src = blobUrl;

}

function stopRecord() {

    // 停止录音

    window.mediaNode.disconnect();

    window.jsNode.disconnect();

    console.log("已停止录音")

    // console.log(leftDataList, rightDataList);

}

function recordClose() {

    // 停止语音

    window.mediaStream.getAudioTracks()[0].stop();

    console.log("已停止语音")

}

function mergeArray(list) {

    let length = list.length * list[0].length;

    let data = new Float32Array(length),

        offset = 0;

    for (let i = 0; i < list.length; i++) {

        data.set(list[i], offset);

        offset += list[i].length;

    }

    return data;

}

function interleaveLeftAndRight(left, right) {

    // 交叉合并左右声道的数据

    let totalLength = left.length + right.length;

    let data = new Float32Array(totalLength);

    for (let i = 0; i < left.length; i++) {

        let k = i * 2;

        data[k] = left[i];

        data[k + 1] = right[i];

    }

    return data;

}

function createWavFile(audioData) {

    const WAV_HEAD_SIZE = 44;

    let buffer = new ArrayBuffer(audioData.length * 2 + WAV_HEAD_SIZE),

        // 需要用一个view来操控buffer

        view = new DataView(buffer);

    // 写入wav头部信息

    // RIFF chunk descriptor/identifier

    writeUTFBytes(view, 0, 'RIFF');

    // RIFF chunk length

    view.setUint32(4, 44 + audioData.length * 2, true);

    // RIFF type

    writeUTFBytes(view, 8, 'WAVE');

    // format chunk identifier

    // FMT sub-chunk

    writeUTFBytes(view, 12, 'fmt ');

    // format chunk length

    view.setUint32(16, 16, true);

    // sample format (raw)

    view.setUint16(20, 1, true);

    // stereo (2 channels)

    view.setUint16(22, 2, true);

    // sample rate

    view.setUint32(24, 44100, true);

    // byte rate (sample rate * block align)

    view.setUint32(28, 44100 * 2, true);

    // block align (channel count * bytes per sample)

    view.setUint16(32, 2 * 2, true);

    // bits per sample

    view.setUint16(34, 16, true);

    // data sub-chunk

    // data chunk identifier

    writeUTFBytes(view, 36, 'data');

    // data chunk length

    view.setUint32(40, audioData.length * 2, true);

    // 写入wav头部,代码同上

    // 写入PCM数据

    let length = audioData.length;

    let index = 44;

    let volume = 1;

    for (let i = 0; i < length; i++) {

        view.setInt16(index, audioData[i] * (0x7FFF * volume), true);

        index += 2;

    }

    return buffer;

}

function writeUTFBytes(view, offset, string) {

    var lng = string.length;

    for (var i = 0; i < lng; i++) {

        view.setUint8(offset + i, string.charCodeAt(i));

    }

}

  • 播放录音

1.使用audio标签

<audio src='audio_file.mp3'></audio>

2.使用audio对象(uni-app)

3.浏览器对象(js)

 var mp3 = null;

    function audioplay(url){

        console.log("播放录音---"+url);

        if(mp3 != null){

            mp3.pause();

            mp3 = new Audio(url);

            mp3.play();

        }else{

            mp3 = new Audio(url);

            mp3.play(); //播放 mp3这个音频对象

        }

    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/814903.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

游戏APP开发:创新设计的秘诀

在游戏 APP开发中&#xff0c;创新设计是游戏开发公司的一大追求&#xff0c;为了可以为用户带来更好的游戏体验&#xff0c;这就需要对游戏 APP开发进行创新设计。那么&#xff0c;游戏 APP开发中的创新设计是什么呢&#xff1f;接下来&#xff0c;我们就一起来看看吧。 想要…

一起学算法(递推篇)

前言&#xff1a;递推最通俗的理解就是数列&#xff0c;递推和数列的关系就好比算法和数据结构的关系&#xff0c;数列有点像数据结构中的顺序表&#xff0c;而递推就是一个循环或者迭代的过程的枚举过程 1.斐波那契数列 斐波那契数形成的序列称为斐波那契数列&#xff0c;该…

【Java|golang】143. 重排链表---快慢指针

给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff1a; L0 → L1 → … → Ln - 1 → Ln 请将其重新排列后变为&#xff1a; L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … 不能只是单纯的改变节点内部的值&#xff0c;而是需要实际的进行节点交换。 …

python中有哪些异常,怎么处理

目录 python报的错误怎么处理 1. 使用 try-except 语句块 2. 使用 finally 语句块 3. 主动引发异常 python中有哪些异常 不知道是什么异常时怎么操作 总结 python报的错误怎么处理 在Python中&#xff0c;当程序执行时遇到错误&#xff0c;Python会抛出异常。要处理Pyt…

孩子近视有必要用全光谱灯吗?全光谱led灯推荐

当然&#xff0c;有必要!全光谱LED灯的光源分布更加均匀&#xff0c;使空间更加美观舒适&#xff0c;而普通灯的光源分布可能会在一定范围内分布不均匀。全光谱它的使用寿命长达20-30万小时&#xff0c;而普通灯的使用寿命仅为1000-2000小时&#xff0c;因此在长期使用上&#…

list模拟

之前模拟了string,vector&#xff0c;再到现在的list&#xff0c;list的迭代器封装最让我影响深刻。本次模拟的list是双向带头节点的循环链表&#xff0c;该结构虽然看起来比较复杂&#xff0c;但是却非常有利于我们做删除节点的操作&#xff0c;结构图如下。 由于其节点结构特…

收发存和进销存有什么区别?

一、什么是收发存和进销存 1、收发存 收发存是供应链管理中的关键概念&#xff0c;用于描述企业在供应链中的物流和库存管理过程。 收发存代表了企业在采购、生产和销售过程中的物流活动和库存水平。 收&#xff08;Receiving&#xff09; 企业接收供应商送达的物料或产品…

归并排序算法

归并排序 算法说明与实现代码&#xff1a; 归并排序&#xff08;Merge Sort&#xff09;: 归并排序是一种分治算法&#xff0c;它将列表分成两个子列表&#xff0c;分别进行排序&#xff0c;然后将排序好的子列表合并成一个有序列表。 package mainimport "fmt"fu…

手机商城免费搭建之java商城 开源java电子商务Spring Cloud+Spring Boot+mybatis+MQ+VR全景+b2b2c

1. 涉及平台 平台管理、商家端&#xff08;PC端、手机端&#xff09;、买家平台&#xff08;H5/公众号、小程序、APP端&#xff08;IOS/Android&#xff09;、微服务平台&#xff08;业务服务&#xff09; 2. 核心架构 Spring Cloud、Spring Boot、Mybatis、Redis 3. 前端框…

微信小程序代码优化3个小技巧

抽取重复样式 样式复用 我们会发现很多时候在开发的过程中会存在多个页面中都用到了同样的样式&#xff0c;那么其实之前有提到过&#xff0c;公用样式可以放在app.wxss里面这样就可以直接复用。 如&#xff1a;flex布局的纵向排列&#xff0c;定义在app.wxss里面 .flex-co…

win10安装cygwin

参考 Cygwin简介及其下载安装卸载_cygwin是什么软件_徐晓康的博客的博客-CSDN博客https://blog.csdn.net/weixin_42837669/article/details/114381405这个文章写的非常好&#xff0c;不过现在如果想安装多个包的话&#xff0c;采用gui的方式可以不行了&#xff0c;我采用的方式…

JavaScript 简单实现观察者模式和发布-订阅模式

JavaScript 简单实现观察者模式和发布-订阅模式 1. 观察者模式1.1 什么是观察者模式1.2 代码实现 2. 发布-订阅模式2.1 什么是发布-订阅模式2.2 代码实现2.2.1 基础版2.2.2 取消订阅2.2.3 订阅一次 1. 观察者模式 1.1 什么是观察者模式 概念&#xff1a;观察者模式定义对象间…

【Windows11】家庭版开启组策略指南

目录 背景新建一个cmd文件运行运行结果 背景 Win11找不到gpedit.msc怎么办&#xff1f;有用户通过命令窗口想要去打开本地组策略的时候&#xff0c;系统突然弹出了一个错误提示&#xff0c;显示系统缺少了gpedit.msc导致无法开启本地组策略编辑器了。那么这个情况要怎么去进行…

【Web开发指南】如何用MyEclipse进行JavaScript开发?

由于MyEclipse中有高级语法高亮显示、智能内容辅助和准确验证等特性&#xff0c;进行JavaScript编码不再是一项繁琐的任务。 MyEclipse v2023.1.2离线版下载 JavaScript项目 在MyEclipse 2021及以后的版本中&#xff0c;大多数JavaScript支持都是开箱即用的JavaScript源代码…

【Minio怎么用】Minio上传图片并Vue回显

流程&#xff1a; 目录 1.文件服务器Minio的安装 1.1 下载Minio安装后&#xff0c;新建1个data文件夹。并在该安装目录cmd 敲命令。注意不要进错目录。依次输入 1.2 登录Minio网页端 1.3 先建1个桶&#xff08;buckets&#xff09;&#xff0c;点击create a bucket 2. Spr…

前端小练-仿掘金导航栏

文章目录 前言项目结构导航实现创作中心移动小球消息提示 完整代码 前言 闲的&#xff0c;你信嘛&#xff0c;还得开发一个基本的门户社区网站&#xff0c;来给到Hlang,不然我怕说工作量不够。那么这个的话&#xff0c;其实也很好办&#xff0c;主要是这个门户网站的UI写起来麻…

操作系统_进程与线程(三)

目录 3. 同步与互斥 3.1 同步与互斥的基本概念 3.1.1 临界资源 3.1.2 同步 3.1.3 互斥 3.2 实现临界区互斥的基本方法 3.2.1 软件实现方法 3.2.1.1 算法一&#xff1a;单标志法 3.2.1.2 算法二&#xff1a;双标志法先检查 3.2.1.3 算法三&#xff1a;双标志法后检查 …

HarmonyOS/OpenHarmony元服务开发-卡片使用自定义绘制能力

ArkTS卡片开放了自定义绘制的能力&#xff0c;在卡片上可以通过Canvas组件创建一块画布&#xff0c;然后通过CanvasRenderingContext2D对象在画布上进行自定义图形的绘制&#xff0c;如下示例代码实现了在画布的中心绘制了一个笑脸。 Entry Component struct Card { private c…

如何把几个视频合并在一起?视频合并方法分享

当我们需要制作一个比较长的视频时&#xff0c;将多个视频进行合并可以使得整个过程更加高效。此外&#xff0c;合并视频还可以避免出现“剪辑断层”的情况&#xff0c;使得视频内容更加连贯&#xff0c;更加容易被观众理解和接受。再有&#xff0c;合并视频还可以减少视频文件…

第三方电容笔支持随手写吗?性价比高的触控笔推荐

在日常生活中&#xff0c;电容笔的用途非常广泛&#xff0c;无论是配上笔记本&#xff0c;还是配上ipad&#xff0c;又或者是配上手机&#xff0c;都是非常好用的办公利器。首先要明确自己的需要&#xff0c;然后才能选择适合自己的产品。苹果Pencil因为具有特殊的重力压感&…