[目录]
本文引用自
这篇的内容都不是我写的,我只是把例子自己用 MVC3 做了一遍,主要是下面这位大神实现的
源码 Demo
见附件
HZRecorder.js
(function (window) {//兼容window.URL = window.URL || window.webkitURL;navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;var HZRecorder = function (stream, config) {config = config || {};config.sampleBits = config.sampleBits || 8; //采样数位 8, 16config.sampleRate = config.sampleRate || (44100 / 6); //采样率(1/6 44100)var context = new (window.webkitAudioContext || window.AudioContext)();var audioInput = context.createMediaStreamSource(stream);var createScript = context.createScriptProcessor || context.createJavaScriptNode;var recorder = createScript.apply(context, [4096, 1, 1]);var audioData = {size: 0 //录音文件长度, buffer: [] //录音缓存, inputSampleRate: context.sampleRate //输入采样率, inputSampleBits: 16 //输入采样数位 8, 16, outputSampleRate: config.sampleRate //输出采样率, oututSampleBits: config.sampleBits //输出采样数位 8, 16, input: function (data) {this.buffer.push(new Float32Array(data));this.size += data.length;}, compress: function () { //合并压缩//合并var data = new Float32Array(this.size);var offset = 0;for (var i = 0; i < this.buffer.length; i++) {data.set(this.buffer[i], offset);offset += this.buffer[i].length;}//压缩var compression = parseInt(this.inputSampleRate / this.outputSampleRate);var length = data.length / compression;var result = new Float32Array(length);var index = 0, j = 0;while (index < length) {result[index] = data[j];j += compression;index++;}return result;}, encodeWAV: function () {var sampleRate = Math.min(this.inputSampleRate, this.outputSampleRate);var sampleBits = Math.min(this.inputSampleBits, this.oututSampleBits);var bytes = this.compress();var dataLength = bytes.length * (sampleBits / 8);var buffer = new ArrayBuffer(44 + dataLength);var data = new DataView(buffer);var channelCount = 1;//单声道var offset = 0;var writeString = function (str) {for (var i = 0; i < str.length; i++) {data.setUint8(offset + i, str.charCodeAt(i));}}// 资源交换文件标识符writeString('RIFF'); offset += 4;// 下个地址开始到文件尾总字节数,即文件大小-8data.setUint32(offset, 36 + dataLength, true); offset += 4;// WAV文件标志writeString('WAVE'); offset += 4;// 波形格式标志writeString('fmt '); offset += 4;// 过滤字节,一般为 0x10 = 16data.setUint32(offset, 16, true); offset += 4;// 格式类别 (PCM形式采样数据)data.setUint16(offset, 1, true); offset += 2;// 通道数data.setUint16(offset, channelCount, true); offset += 2;// 采样率,每秒样本数,表示每个通道的播放速度data.setUint32(offset, sampleRate, true); offset += 4;// 波形数据传输率 (每秒平均字节数) 单声道×每秒数据位数×每样本数据位/8data.setUint32(offset, channelCount * sampleRate * (sampleBits / 8), true); offset += 4;// 快数据调整数 采样一次占用字节数 单声道×每样本的数据位数/8data.setUint16(offset, channelCount * (sampleBits / 8), true); offset += 2;// 每样本数据位数data.setUint16(offset, sampleBits, true); offset += 2;// 数据标识符writeString('data'); offset += 4;// 采样数据总数,即数据总大小-44data.setUint32(offset, dataLength, true); offset += 4;// 写入采样数据if (sampleBits === 8) {for (var i = 0; i < bytes.length; i++, offset++) {var s = Math.max(-1, Math.min(1, bytes[i]));var val = s < 0 ? s * 0x8000 : s * 0x7FFF;val = parseInt(255 / (65535 / (val + 32768)));data.setInt8(offset, val, true);}} else {for (var i = 0; i < bytes.length; i++, offset += 2) {var s = Math.max(-1, Math.min(1, bytes[i]));data.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);}}return new Blob([data], { type: 'audio/wav' });}};//开始录音this.start = function () {audioInput.connect(recorder);recorder.connect(context.destination);}//停止this.stop = function () {recorder.disconnect();}//获取音频文件this.getBlob = function () {this.stop();return audioData.encodeWAV();}//回放this.play = function (audio) {audio.src = window.URL.createObjectURL(this.getBlob());}//上传this.upload = function (url, callback) {var fd = new FormData();fd.append("audioData", this.getBlob());var xhr = new XMLHttpRequest();if (callback) {xhr.upload.addEventListener("progress", function (e) {callback('uploading', e);}, false);xhr.addEventListener("load", function (e) {callback('ok', e);}, false);xhr.addEventListener("error", function (e) {callback('error', e);}, false);xhr.addEventListener("abort", function (e) {callback('cancel', e);}, false);}xhr.open("POST", url);xhr.send(fd);}//音频采集recorder.onaudioprocess = function (e) {audioData.input(e.inputBuffer.getChannelData(0));//record(e.inputBuffer.getChannelData(0));}};//抛出异常HZRecorder.throwError = function (message) {alert(message);throw new function () { this.toString = function () { return message; } }}//是否支持录音HZRecorder.canRecording = (navigator.getUserMedia != null);//获取录音机HZRecorder.get = function (callback, config) {if (callback) {if (navigator.getUserMedia) {navigator.getUserMedia({ audio: true } //只启用音频, function (stream) {var rec = new HZRecorder(stream, config);callback(rec);}, function (error) {switch (error.code || error.name) {case 'PERMISSION_DENIED':case 'PermissionDeniedError':HZRecorder.throwError('用户拒绝提供信息。');break;case 'NOT_SUPPORTED_ERROR':case 'NotSupportedError':HZRecorder.throwError('浏览器不支持硬件设备。');break;case 'MANDATORY_UNSATISFIED_ERROR':case 'MandatoryUnsatisfiedError':HZRecorder.throwError('无法发现指定的硬件设备。');break;default:HZRecorder.throwError('无法打开麦克风。异常信息:' + (error.code || error.name));break;}});} else {HZRecorder.throwErr('当前浏览器不支持录音功能。'); return;}}}window.HZRecorder = HZRecorder;})(window);
HTML
@{Layout = null;}<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>HZRecorder</title></head><body><div><audio controls autoplay></audio><input onclick="startRecording()" type="button" value="录音" /><input onclick="stopRecording()" type="button" value="停止" /><input onclick="playRecording()" type="button" value="播放" /><input onclick="uploadAudio()" type="button" value="提交" /></div><script type="text/javascript" src="@Url.Content("~/HZRecorder/HZRecorder.js")"></script><script>var recorder;var audio = document.querySelector('audio');function startRecording() {HZRecorder.get(function (rec) {recorder = rec;recorder.start();});}function stopRecording() {recorder.stop();}function playRecording() {recorder.play(audio);}function uploadAudio() {recorder.upload("@Url.Action("SaveFile","Default")", function (state, e) {switch (state) {case 'uploading'://var percentComplete = Math.round(e.loaded * 100 / e.total) + '%';break;case 'ok':debugger//alert(e.target.responseText);alert("上传成功");alert(e.target.responseText.AudioSrc);break;case 'error':alert("上传失败");break;case 'cancel':alert("上传被取消");break;}});}</script></body></html>
Controller
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;namespace RecordDemo.Controllers{public class DefaultController : Controller{public ActionResult Index(){return View();}public ActionResult HZRecorder(){return View();}[HttpPost]public JsonResult SaveFile(HttpPostedFileBase f){var files = Request.Files;if (files.Count == 0)return Json(new { Success = false, Message = "提示:没有要上传的文件!" }, JsonRequestBehavior.AllowGet);string savePath = "/Content/Audio/";string audioUrl = "http://" + Request.Url.Authority + savePath;foreach (string file in files){//获取文件信息var curFile = Request.Files[file];string fileName = "1.wav";//保存文件到服务器磁盘curFile.SaveAs(Server.MapPath("~" + savePath) + fileName);audioUrl += fileName;}return Json(new { Success = true, AudioSrc = audioUrl }, JsonRequestBehavior.AllowGet);}}}