Web系统中Mic设备的应用实例
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>欢迎转载,转载请注明出处-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 onclick='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)
@ResponseBody
public 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)
@ResponseBody
public 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)
@ResponseBody
public 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>
Web系统中Mic设备的应用实例的更多相关文章
- Linux系统中存储设备的两种表示方法
转:https://blog.csdn.net/holybin/article/details/38637381 一.对于IDE接口的硬盘的两种表示方法: 1.IDE接口硬盘,对于整块硬盘的两种表示方 ...
- VLC在web系统中应用(x-vlc-plugin 即如何把VLC嵌入HTML中)第一篇
VLC毫无疑问是优秀的一款播放软件,子B/S机构的web项目中,如果能把它嵌入页面,做页面预览或者其他,是非常棒的. 第一步:下载VLC安装程序:(推荐1.0.3或者是1.0.5版本,比较稳定) ht ...
- 使用SetupDI* API列举系统中的设备
原文链接地址:https://blog.csdn.net/clteng/article/details/801012?utm_source=blogxgwz8 在Windows系统中提供一组有用的函数 ...
- 如何在施工物料管理Web系统中处理大量数据并显示
最近在开发施工物料管理系统,其中涉及大量的物料信息需要管理和汇总,数据量非常庞大.之前尝试自己通过将原始数据,加工处理建模,在后台代码中通过分组.转置再显示到 Web 页面中,但自己编写的代码量非常大 ...
- B/S(WEB)系统中使用Activex插件调用扫描仪实现连续扫描并上传图像(IE文件扫描并自动上传)
IE浏览器下使用Activex插件调用客户端扫描仪扫描文件并山传,可以将纸质档案(如合同.文件.资料等)扫描并将扫描图像保存到服务器,可以用于合同管理.档案管理等. 通过插件方式调用扫描仪扫描并获取图 ...
- JAVA WEB项目中生成验证码及验证实例(附源码及目录结构)
[我是一个初学者,自己总结和网上搜索资料,代码是自己敲了一遍,亲测有效,现将所有的目录结构和代码贴出来分享给像我一样的初学者] 作用 验证码为全自动区分计算机和人类的图灵测试的缩写,是一种区分用户是计 ...
- web开发中不同设备浏览器的区分
通常区分不同设备浏览器是用JavaScript中的navigator.userAgent.toLowerCase()方式获取浏览器的userAgent信息 //使用javascript判断是否是iPh ...
- java web系统中时间比sql server中的日期少2天的解决办法
系统环境 jdk:1.7 数据库:sql server 2008 问题描述 升级1.7之后查询出来的日期就比数据库中的少2天,降回1.6版本的jdk就正常了. 问题原因及解决办法 国内网站有很多不靠谱 ...
- 重新指派usb转串口模块在linux系统中的设备调用名称
How to remap /dev/ttyUSB* to a specific name to be called by my program. How to map /dev/ttyUSB* to ...
随机推荐
- LOJ#2244 起床困难综合症
解:m = 0的部分分,直接模拟.有and 0的部分分,直接模拟.<=1000的部分分,枚举攻击力之后模拟.所有操作相同的部分分,可以合并成只有一个操作.然后枚举m或者逐位贪心. 正解是逐位贪心 ...
- Sublime Text3—自带快捷键介绍
摘要: Sublime Text是个小巧便捷的编辑器,除了众多好用的插件外,还有它自带的快捷键,打代码事半功倍,不会用的赶紧看看吧! 其实菜单上都有,看不懂可以汉化,Key Bindings-Defa ...
- 虚拟机 模拟centos 7 系统安装
Cnetos 服务器安装过程 1.制作U盘启动器 网上有很多制作U盘启动的教程,这里就不详细说了 2.用U盘启动电脑进入安装界面 3.开始安装 等待片刻后,正常的应该会进入语言选择界面了. 选择中文 ...
- CMakeList.txt(1):cmake error
cmake_symlink_library: System Error: Operation not supported 1/创建链接不成功,要确认当前帐户下是否有权限在编译的目录中有创建链接的权限 ...
- 对于Sobel算子的学习
本来想说很多目前对于 Sobel 算子的认识,但最终还是觉得对于其掌握程度太低,没有一个系统的理解,远不足以写博客,但为了12月不至于零输出,还是决定把自己学习过程中找到的相关资料进行分享. 等到一月 ...
- E. Vanya and Balloons Codeforces Round #355 (Div. 2)
http://codeforces.com/contest/677/problem/E 题意:有n*n矩形,每个格子有一个值(0.1.2.3),你可以在矩形里画一个十字(‘+’形或‘x’形),十字的四 ...
- xin
测试文件 行内公式 y = x 独立公式 limx → 0x = 0
- Exp5 MSF基础应用 20164314
一.实践内容 本实践目标是掌握metasploit的基本应用方式,重点常用的三种攻击方式的思路.具体需要完成: 1.一个主动攻击实践,如ms08_067; (成功) 2.一个针对浏览器的攻击,如ms1 ...
- parallels desktop for mac安装虚拟机 之parallelsdesktop密钥 以及 parallels desktop安装win10的办公推荐可以提高办公效率
大家好我是一个老程序员了. 用惯了 mac , 平时工作都是在 mac安装虚拟机,之后就是mac 安装 win10. 因为很多办公软件 mac 都不好用,主要是跟同事沟通不方便,当然mac 的软件还 ...
- patchwork.ffmpeg.org 里面未被选中的优秀代码
很多程序员为 FFMpeg 增加新功能写出代码, 把写好的代码 git send-email 邮件方式提交 patch 文件 发送给 patchwork.ffmpeg.org; 一直认为 FFMpeg ...