>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>欢迎转载,转载请注明出处-VirgoArt,www.cnblogs.com

感谢xiangyuecn同学在GitHub上提供的音频操作组件,点击传送!

一、客户端使用音频设备

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<html>
<head><title>HTML5采集麦克风音频</title><meta charset="UTF-8"><meta name="content-type" content="text/html; charset=UTF-8"><script src="http://static.runoob.com/assets/jquery-validation-1.14.0/lib/jquery.js"></script><script type="text/javascript" src="recorder-core.js"></script><script type="text/javascript" src="wav.js"></script><script type="text/javascript">var index = 1; //录音后行的索引(table)function hasGetUserMedia() {return !!(navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);}if (!hasGetUserMedia()) {alert('您的浏览器不支持录音');}// 录音配置
        set = {type: "wav" //输出类型:mp3,wav等,使用一个类型前需要先引入对应的编码引擎
            , bitRate: 16 //比特率 wav(位):16、8,MP3(单位kbps):8kbps时文件大小1k/s,16kbps 2k/s,录音文件很小
            , sampleRate: 16000 //采样率,wav格式文件大小=sampleRate*时间;mp3此项对低比特率文件大小有影响,高比特率几乎无影响。wav任意值,mp3取值范围:48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000
            , bufferSize: 4096 //AudioContext缓冲大小。会影响onProcess调用速度,相对于AudioContext.sampleRate=48000时,4096接近12帧/s
        }var rec = Recorder(set);function start() {//打开麦克风授权获得相关资源
            rec.open(function () {rec.start();//开始录音
setTimeout(function () {rec.stop(function (blob, duration) {//到达指定条件停止录音,拿到blob对象想干嘛就干嘛:立即播放、上传
                            addInfo(blob);rec.close();//释放录音资源
                        }, function (msg) {alert.log("录音失败:" + msg);});}, 1000 * $("#audiotime").val());}, function (msg) {//未授权或不支持
                    alert.log("无法录音:" + msg);});}var autioList = [];function addInfo(blob) {var table = $("#table");var ts = Date.parse(new Date());var dom = "<tr>";dom += "<td>" + index + "</td>";dom += "<td>" + ts + ".wav</td>";dom += "<td>" + "<video height='40px' width='300px' controls = 'controls' name = 'video' src = '" + URL.createObjectURL(blob) + "'></video>" + "</td>";dom += "<td>" + "<a download='audio' href='" + URL.createObjectURL(blob) + "'>下载</a>" + "</td>";dom += "<td>" + "<button οnclick='upload(this," + index + ")'>上传</button>" + "</td>";dom += "<td>未上传</td>";dom += "</tr>";table.append(dom);autioList.push({filename: ts + ".wav", blob: blob});index++;}function upload(my, index) {var formData = new FormData();formData.append("audioData", autioList[index - 1].blob, autioList[index - 1].filename);var xhr = new XMLHttpRequest();xhr.open("POST", "/upload");xhr.send(formData);xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {//若响应完成且请求成功
                    my.parentElement.nextElementSibling.textContent = xhr.responseText;}}}function recognition() {var xhr = new XMLHttpRequest();xhr.open("GET", "/recognition");xhr.send();xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {//若响应完成且请求成功
                    alert(xhr.responseText);}}}</script>
</head>
<body>
Web音频采集 <br>
<button id="start" onclick="start()"> 点击录音</button>
<span>录音时长,默认为三秒</span><input type="text" value="3" id="audiotime">
<button id="confirm" onclick="recognition()">确认</button>
<hr/>
<table id="table"><tr><td>序号</td><td>音频文件</td><td>播放</td><td>下载</td><td>上传</td><td>状态</td></tr>
</table>
</body>
</html>

  其中,项目需要引用xiangyuecn/Recorder工程中的recorder-core.js、wav.js(个人测试只用到Wav格式,如有其他需求,参见工程ReadMe)。

二、后端数据通信

package cn.virgo.audio.controller;import cn.virgo.audio.utils.RemoteShellExecutor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;@Controller
public class IndexController {@Value("${system.audiofile.path}")private  String AUDIO_FILES_PATH;@Value("${system.ffmpeg.path}")private  String AUDIO_FFMPEG_PATH;@Value("${system.ffmpeg.splittime}")private  String AUDIO_SPLIT_TIME;/*** 首页跳转** @param request* @return*/@RequestMapping(path = {"/index"}, method = RequestMethod.GET)public ModelAndView defaultPage1(HttpServletRequest request) throws IOException {ModelAndView modelAndView = new ModelAndView("/mic");return modelAndView;}/*** 音频文件上传** @param file* @return*/@RequestMapping(path = {"/upload"}, method = RequestMethod.POST)@ResponseBodypublic String upload1(@RequestParam("audioData") MultipartFile file) {if (file.isEmpty()) {return "Error";}try {Files.createDirectories(Paths.get(AUDIO_FILES_PATH));byte[] bytes = file.getBytes();Path path = Paths.get(AUDIO_FILES_PATH + file.getOriginalFilename());Files.write(path, bytes);} catch (IOException e) {e.printStackTrace();}return "Success";}/*** 音频文件上传** @param file* @return*/@RequestMapping(path = {"/upload2"}, method = RequestMethod.POST)@ResponseBodypublic String upload2(@RequestParam("audioData") MultipartFile file) {if (file.isEmpty()) {return "Error";}try {Files.createDirectories(Paths.get(AUDIO_FILES_PATH));byte[] bytes = file.getBytes();Path path = Paths.get(AUDIO_FILES_PATH + file.getOriginalFilename());Files.write(path, bytes);File srcFile = path.toFile();//TODO:上传完成后,调用FFMPEG将音频分片,并删除源文件run_exe(AUDIO_FFMPEG_PATH + "ffmpeg.exe -i " + AUDIO_FILES_PATH + file.getOriginalFilename() + " -f segment -segment_time " + AUDIO_SPLIT_TIME + " -c copy " + AUDIO_FILES_PATH + "out%03d.wav");srcFile.delete();} catch (IOException e) {e.printStackTrace();}return "Success";}/*** 准备就绪** @return*/@RequestMapping(path = {"/recognition"}, method = RequestMethod.GET)@ResponseBodypublic List<String> recognition1() {//TODO:return null;     }/*** 获取到项目路径** @return*/public static String getRootPath() {return ClassUtils.getDefaultClassLoader().getResource("").getPath();}/*** 调用EXE** @param cmd*/public static void run_exe(String cmd) {System.out.println("-------------Cmd info-------------");System.out.println("CMD:" + cmd);String s1;String s2;StringBuilder sb1 = new StringBuilder();sb1.append("ProcessInfo:");StringBuilder sb2 = new StringBuilder();sb2.append("ErrorInfo:");Process proc = null;try {// 使用绝对路径proc = Runtime.getRuntime().exec(cmd);InputStream pInfo = proc.getInputStream();BufferedReader bufferedReader1 = new BufferedReader(new InputStreamReader(pInfo));while ((s1 = bufferedReader1.readLine()) != null) {sb1.append(s1);}bufferedReader1.close();System.out.println(sb1.toString());InputStream pErr = proc.getErrorStream();BufferedReader bufferedReader2 = new BufferedReader(new InputStreamReader(pErr));while ((s2 = bufferedReader2.readLine()) != null) {sb2.append(s2);}bufferedReader2.close();System.out.println(sb2.toString());System.out.println("ExitCode:" + proc.waitFor());} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}
}

  其中,项目中upload1对上传的音频不做二次加工,upload2对上传的音频使用FFMPEG进行二次加工。

三、备注

  项目实例基于SpringBoot项目,需引用pom为:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>cn.study</groupId><artifactId>audio</artifactId><version>1.0-SNAPSHOT</version><name>audio</name><description>Demo project for audio</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.3.RELEASE</version><relativePath/></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><!--Spring Web 相关依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><!--排除默认的日志框架--><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!--第三方工具--><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.5</version></dependency><!--log4j2 日志框架--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><mainClass>com.audio.App</mainClass><layout>JAR</layout></configuration><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build>
</project>

转载于:https://www.cnblogs.com/virgoart/p/10569401.html

Web系统中Mic设备的应用实例相关推荐

  1. web系统中的结构化数据标记

    Web 系统的设计要点之一是内容和表示的分离,网站以HTML发布内容,对内容进行操作的服务也只能访问 HTML.随着表现形式各异的设备在大量地增加,也大大增加了网站针对不同表示格式的数量.同时,一些新 ...

  2. web系统中巧用word文档的html格式创建多样式的word文档,WEB系统中巧用WORD文档的HTML格式创建多样式的WORD文档...

    以计算机和现代网络技术为特征的现代信息技术极大地促进了社会经济的发展,基于各行各业的WEB系统的开发与应用也越来越多. >> WEB系统中巧用WORD文档的HTML格式创建多样式的WORD ...

  3. 在Linux系统中存储设备的两种表示方法

    作者:北南南北 来自:LinuxSir.Org 摘要: 硬盘和硬盘分区在Linux都表示为设备,按我们通俗的说法来说,就是怎么来表示或描述硬盘和或硬盘分区,但这种描述应该是科学和具体的:比如IDE硬盘 ...

  4. Vert.x(vertx) 认证和授权详解(包含认证和授权在Web系统中的使用)

    每个线上系统几乎都是离不开认证和授权的,Vert.x提供了灵活.简单.便捷的认证和授权的支持.Vert.x抽象出了两个核心的认证和授权的接口,一个是AuthProvider,另一个是User.通过这两 ...

  5. VLC在web系统中应用(x-vlc-plugin 即如何把VLC嵌入HTML中)第一篇

    VLC毫无疑问是优秀的一款播放软件,子B/S机构的web项目中,如果能把它嵌入页面,做页面预览或者其他,是非常棒的. 第一步:下载VLC安装程序:(推荐1.0.3或者是1.0.5版本,比较稳定) ht ...

  6. B/S(WEB)系统中使用websocket插件调用扫描仪实现连续扫描并上传图像(IE文件扫描并自动上传)

    浏览器下使用websocket插件调用客户端扫描仪扫描文件并山传,可以将纸质档案(如合同.文件.资料等)扫描并将扫描图像保存到服务器,可以用于合同管理.档案管理等. 通过插件方式调用扫描仪扫描并获取图 ...

  7. Web系统中出现 localhost 将您重定向的次数过多问题

    最新测试软件的时候,有个功能打开页面的时候就出现了如标题中提到的问题 然而通过查找资料,说一个代码中死循环了,导致一跳转到同一个页面多次. 下面来说明一下,为什么会出现上面的错误,为什么其他功能不会出 ...

  8. 5.3中断系统中的设备树——中断号的演变与irq_domain

    通过上一节我们知道,在内核中有一个irq_desc数组,数组里面的每一项对应一个中断,数组的下标就是对应中断的虚拟中断号(virq). 假设只有一个中断控制器,有32个中断,那么中断和irq_desc ...

  9. web开发中不同设备浏览器的区分

    通常区分不同设备浏览器是用JavaScript中的navigator.userAgent.toLowerCase()方式获取浏览器的userAgent信息 1 //使用javascript判断是否是i ...

最新文章

  1. 【Lucene4.8教程之三】搜索
  2. ionic4安卓真机调试
  3. Android选项切换条SHSegmentControl
  4. jvm分配内存_为JVM分配内存:一个案例研究
  5. Redis系列教程(九):Redis的内存回收原理,及内存过期淘汰策略详解
  6. iphone简单实例 (字体,弹出窗口) (实例)
  7. iis服务器udp协议,Win2003系统的IIS服务的w3wp.exe使用UDP的80端口发送大量的数据包,寻求帮助...
  8. How to learn Lua
  9. CTFHUB Web题解记录(信息泄露、弱口令部分)
  10. SQL server 表数据改变触发发送邮件
  11. r语言 生成等差序列_使用序列模型生成自然语言
  12. 【转载】身份证号码验证算法
  13. 有关js获取屏幕宽度问题
  14. 数据结构——中国邮递员问题
  15. win10+Ubuntu双系统设置默认系统启动项为win10
  16. vue将图片保存到相册_vue 图片下载到本地,图片保存到本地
  17. 【RL从入门到放弃】【二 表格型RL】
  18. 在win10里修改mysql的root密码
  19. 一起来捉妖找不到服务器,一起来捉妖妖怪分布大全 所有妖灵不同地点位置详解...
  20. 算法介绍 | 泛洪算法(Flood fill Algorithm)

热门文章

  1. 无线数据采集器与计算机系统的连接,WS5、WS6 WiFi无线数据采集器,如何与计算机实现无线远距离采集...
  2. 七猫php面试,七猫面试 - osc_2frv0wjp的个人空间 - OSCHINA - 中文开源技术交流社区...
  3. queue java 判断重复值_java集合类深入分析之Queue篇(Q,DQ)
  4. mysql have_mysql having用法解析
  5. linux手写数字识别opencv,opencv实现KNN手写数字的识别
  6. echarts 动态改变数据_Echarts的使用
  7. c语言全局变量符号,C语言中的 @ 符号是什么意思?
  8. htmljavascript 事件触发机制
  9. HDLBits 系列(22) Shift register
  10. DCM、PLL、PMCD、MMCM的区别与联系?