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 ...
随机推荐
- js实现一个长页面中的图片懒加载即滚动到其位置才加载
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 转载:Linux命令之查看文件占用空间大小-du,df
转载自:<du命令>-linux命令五分钟系列之三 du(disk usage),顾名思义,查看目录/文件占用空间大小 #查看当前目录下的所有目录以及子目录的大小$ du -h $ du ...
- IDEA+Maven配置MyBatis的初体验(坑点总结)
起因 在老师的推荐下,我跟着这篇文章https://www.jb51.net/article/70923.htm尝试MyBatis的初次调试运行.途中困难重重,由于教程中的开发环境是eclipse,项 ...
- 爬一下国家统计局行政区划代码C#
目前NBS上有2015-2018四个年度的代码信息,写一个控制台程序爬一下县级行政区下的代码. 使用HttpWebRequest+HttpWebResponse获取html,使用HtmlAgility ...
- <HTML> 模块
一些元素 <q>元素 用于引用, quote 浏览器一般会负责加上双引号,但是不是所有的浏览器都会在<q>元素的内容两边加双引号. <blockquote>元素 用 ...
- Idea主题下载
http://www.riaway.com/ 将jar导入
- solr7.5--win10--部署使用
2018年8月份学习使用solr,当时下载的版本是solr7.5,写这篇博文的时候是2019年3月份,solr此时已经出到了8.0版本.一个大版本的变迁肯定有很多的改动,暂时还未研究就不赘述了. 此篇 ...
- python2x和python3的区别
1,源码的区别 py2x:源码比较混乱,重复代码较多,冗余 py3x: 源码崇尚优美,代码清晰简单 2,用户交互的区别: py2x:python2中input的到的数据类型为int型,Python2x ...
- tomcat去掉ContextPath
众所周知,项目打成war包直接放到webapps下启动tomcat后访问项目需要带上ContextPath,也就是war包的文件名,需要去除掉这玩意最简单的办法是将war包重命名为ROOT.war,为 ...
- 使用Mac下的sequel Pro链接数据库时提示错误(已解决)
使用Mac下的sequel Pro链接数据库时,出现如下问题: ? 1 MySQL said: Authentication plugin 'caching_sha2_password' cannot ...