>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>欢迎转载,转载请注明出处-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设备的应用实例的更多相关文章

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

    转:https://blog.csdn.net/holybin/article/details/38637381 一.对于IDE接口的硬盘的两种表示方法: 1.IDE接口硬盘,对于整块硬盘的两种表示方 ...

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

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

  3. 使用SetupDI* API列举系统中的设备

    原文链接地址:https://blog.csdn.net/clteng/article/details/801012?utm_source=blogxgwz8 在Windows系统中提供一组有用的函数 ...

  4. 如何在施工物料管理Web系统中处理大量数据并显示

    最近在开发施工物料管理系统,其中涉及大量的物料信息需要管理和汇总,数据量非常庞大.之前尝试自己通过将原始数据,加工处理建模,在后台代码中通过分组.转置再显示到 Web 页面中,但自己编写的代码量非常大 ...

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

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

  6. JAVA WEB项目中生成验证码及验证实例(附源码及目录结构)

    [我是一个初学者,自己总结和网上搜索资料,代码是自己敲了一遍,亲测有效,现将所有的目录结构和代码贴出来分享给像我一样的初学者] 作用 验证码为全自动区分计算机和人类的图灵测试的缩写,是一种区分用户是计 ...

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

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

  8. java web系统中时间比sql server中的日期少2天的解决办法

    系统环境 jdk:1.7 数据库:sql server 2008 问题描述 升级1.7之后查询出来的日期就比数据库中的少2天,降回1.6版本的jdk就正常了. 问题原因及解决办法 国内网站有很多不靠谱 ...

  9. 重新指派usb转串口模块在linux系统中的设备调用名称

    How to remap /dev/ttyUSB* to a specific name to be called by my program. How to map /dev/ttyUSB* to ...

随机推荐

  1. win 10 dpi:150% 与 win 7 dpi:150% 的不同之处

    由于 win 7 和 win 10 的 dpi 处理方式不同,导致我们写的客户端程序在 win 7 上运行正常,在 win 10(dpi:150%)上运行不正常了. 具体的描述,可参考:解决win10 ...

  2. Number和toString中的坑

    在之前的一篇文章 JavaScript中的大数相加 中,在做大数相加时, 突然想到 数字.toString方法 会报错,但是作为函数参数传进来,直接调用 toString 方法却不会报错 上网搜了看看 ...

  3. 用js提取字符串中的某一段字符

    String.prototype.getQuery = function(name){var reg = new RegExp("(^|&)"+ name +"= ...

  4. Day057--django

    1. http协议 请求的格式(request ---浏览器向服务器发送的消息) 请求方式: URL HTTP/1.1\r\n K1:V1\r\n K2:V2\r\n \r\n 请求正文/请求体(ge ...

  5. Javascript介绍(了解)

    Web前端有三层: HTML:从语义的角度,描述页面结构 CSS:从审美的角度,描述样式(美化页面) JavaScript:从交互的角度,描述行为(提升用户体验) JavaScript的历史 1992 ...

  6. 前端安全类——CSRF/XSS

    CSRF 概念:跨站请求伪造 全称:Cross-site request forgery 攻击原理:网站中某一个接口存在漏洞,用户在注册网站登录过 防御措施: 1.Token验证:引诱链接只会自动携带 ...

  7. Hadoop记录-切换NN

    一.第一种方法 重启namenode(1.1.1.1 1.1.1.2)重启standby节点:1.1hadoop-daemon.sh stop zkfchadoop-daemon.sh stop na ...

  8. [译]Ocelot - Rate Limiting

    原文 Ocelot支持对上游做访问限流,这样就可以保证下游不要负载太大了. 如果要启用访问限流,需要做如下配置: "RateLimitOptions": { "Clien ...

  9. API设计中响应数据格式用json的优点

    通常我们再设计api返回时,都使用json格式返回,相比xml,他又有什么优点呢? 更直观易懂 占用空间更小 能与JavaScript跟好的兼容.js通过eval()进行Json读取. 支持多种语言. ...

  10. Navicat连接阿里云服务器Linux下的Mysql

    用Navicat连接阿里云ECS服务器上的MySQL数据库   今天用navtive连接阿里云服务器(Linux)的数据库时,老是连接不上,并且报10060错误,要通过以下两个步骤解决: 1.先进入l ...