赵梦欢
赵梦欢
  • 发布:2016-08-17 13:37
  • 更新:2020-07-09 17:15
  • 阅读:57346

录音文件与Base64编码相互转换的方法

分类:HTML5+

前言

最近有几个朋友一直在问语音文件怎么转base64字符串进行发送上传,base64字符串又如何转成文件,论坛中已经有多篇问题的帖子有介绍,这里只是稍微整理,方便大家可以更加方便的使用,首先看效果:

录音文件转成base64字符串

hello mui 演示app中im-chat.html有演示案例,通过hold和release控制录音的长度,即长按按钮开始录音,释放就停止录音,上拉取消发送录音。

html部分

<button id="recorder" type="button" class="mui-btn mui-btn-blue mui-btn-block">录制语音文件转base64字符串</button>

js部分

mui.init中首先需要配置手势事件

mui.init({  
	gestureConfig: {  
		tap: true, //默认为true  
		doubletap: true, //默认为false  
		longtap: true, //默认为false  
		swipe: true, //默认为true  
		drag: true, //默认为true  
		hold: true, //默认为false,不监听  
		release: true //默认为false,不监听  
	}  
});

录音逻辑控制,按住按钮弹出录音提示框,并且对录音时长进行控制,录音时间太短取消操作,手指上划,取消发送。

var MIN_SOUND_TIME = 800;  
var recorder = null;  
var startTimestamp = null;  
var stopTimestamp = null;  
var stopTimer = null;  
var recordCancel = false;  
  
var soundAlert = document.getElementById("sound-alert");  
var audioTips = document.getElementById("audio-tips");  
  
// 控制录音弹出框是否播放  
var setSoundAlertVisable=function(show){  
	if(show){  
		soundAlert.style.display = 'block';  
		soundAlert.style.opacity = 1;  
	}else{  
		soundAlert.style.opacity = 0;  
		//  完成再真正隐藏  
		setTimeout(function(){  
			soundAlert.style.display = 'none';  
		},200);  
	}  
};  
  
mui.plusReady(function () {  
	/**  
	 * 录制语音文件转base64字符串  
	 */  
	// 按住录音(长按开始录音)  
    document.querySelector('#recorder').addEventListener('hold',function () {  
    	recordCancel = false;  
	if(stopTimer)clearTimeout(stopTimer);  
					  
	audioTips.innerHTML = "手指上划,取消发送";  
	soundAlert.classList.remove('rprogress-sigh');  
	setSoundAlertVisable(true);  
		  
	// 获取当前设备的录音对象  
        recorder = plus.audio.getRecorder();  
        startTimestamp = (new Date()).getTime();  
      	recorder.record({  
      		filename:"_doc/audio/",  
      		format:"amr" //iOS平台支持"wav"、"aac"、"amr"格式,默认为"wav"  
      	}, function (path) {  
      		if (recordCancel) return;  
			console.log("path:"+path);  
			Audio2dataURL(path);  
		}, function ( e ) {  
			mui.toast("录音出现异常: " + e.message );  
		});  
    })  
      
    // 释放保存(松手保存)  
    document.querySelector('#recorder').addEventListener('release',function () {  
    	if (audioTips.classList.contains("cancel")) {  
			audioTips.classList.remove("cancel");  
			audioTips.innerHTML = "手指上划,取消发送";  
		}  
		// 判断录音时间  
		stopTimestamp = (new Date()).getTime();  
		if (stopTimestamp - startTimestamp < 800) {  
			audioTips.innerHTML = "录音时间太短";  
			soundAlert.classList.add('rprogress-sigh');  
			recordCancel = true;  
			stopTimer=setTimeout(function(){  
				setSoundAlertVisable(false);  
			},800);  
		}else{  
			setSoundAlertVisable(false);  
		}  
		recorder.stop();  
    })  
      
    // 拖动屏幕(手指上划,取消发送)  
    document.body.addEventListener('drag', function(event) {  
		if (Math.abs(event.detail.deltaY) > 50) {  
			if (!recordCancel) {  
				recordCancel = true;  
				if (!audioTips.classList.contains("cancel")) {  
					audioTips.classList.add("cancel");  
				}  
				audioTips.innerHTML = "松开手指,取消发送";  
			}  
		} else {  
			if (recordCancel) {  
				recordCancel = false;  
				if (audioTips.classList.contains("cancel")) {  
					audioTips.classList.remove("cancel");  
				}  
				audioTips.innerHTML = "手指上划,取消发送";  
			}  
		}  
      }, false);  
})

当录音成功后,我们可以将录音文件转成base64字符串,用于网络传输。

/**  
 * 录音语音文件转base64字符串  
 * @param {Object} path  
 */  
function Audio2dataURL (path) {  
	plus.io.resolveLocalFileSystemURL(path, function(entry){  
		entry.file(function(file){  
			var reader = new plus.io.FileReader();  
			reader.onloadend = function (e) {  
				console.log(e.target.result);  
			};  
			reader.readAsDataURL(file);  
		},function(e){  
			mui.toast("读写出现异常: " + e.message );  
		})  
	})  
}

至此我们完成了录音语音文件转base64字符串,反过来我们需要将base64字符串转成语音文件。

base64字符串转成语音文件

我们可以封装如下方法:

/**  
 * base64字符串转成语音文件(参考http://ask.dcloud.net.cn/question/16935)  
 * @param {Object} base64Str  
 * @param {Object} callback  
 */  
function dataURL2Audio (base64Str, callback) {  
	var base64Str = base64Str.replace('data:audio/amr;base64,','');  
	var audioName = (new Date()).valueOf() + '.amr';  
	  
	plus.io.requestFileSystem(plus.io.PRIVATE_DOC,function(fs){  
		fs.root.getFile(audioName,{create:true},function(entry){  
			// 获得平台绝对路径  
			var fullPath = entry.fullPath;  
			if(mui.os.android){    
    			// 读取音频  
	            var Base64 = plus.android.importClass("android.util.Base64");  
	            var FileOutputStream = plus.android.importClass("java.io.FileOutputStream");  
	            try{  
		            var out = new FileOutputStream(fullPath);  
	                var bytes = Base64.decode(base64Str, Base64.DEFAULT);  
	                out.write(bytes);   
	                out.close();  
	                // 回调  
	                callback && callback(entry);  
        		}catch(e){  
          			console.log(e.message);  
        		}  
        	}else if(mui.os.ios){  
	    		var NSData = plus.ios.importClass('NSData');  
				var nsData = new NSData();  
				nsData = nsData.initWithBase64EncodedStringoptions(base64Str,0);  
				if (nsData) {  
				    nsData.plusCallMethod({writeToFile: fullPath,atomically:true});  
				    plus.ios.deleteObject(nsData);  
				}  
				// 回调  
	      		callback && callback(entry);  
        	}  
		})  
	})  
}

调用方法如下:

html部分:

<button id="player" type="button" class="mui-btn mui-btn-blue mui-btn-block">base64字符串转成语音文件播放</button>

js部分:

/**  
 * base64字符串转成语音文件播放  
 */  
document.querySelector('#player').addEventListener('tap',function () {  
        // 语音文件Base64编码(由于编码过长影响阅读体验,请查看工程验证)  
	 var base64Str = ' '   
  
        // 转成.amr文件播放  
	dataURL2Audio(base64Str, function(entry){  
		var toURL = entry.toURL();  
		// 播放音频  
	    playAudio(toURL);  
	})  
})  
  
/**  
 * 播放音频  
 * @param {Object} path  
 */  
function playAudio (path) {  
	var player = plus.audio.createPlayer(path);  
	player.play(function(){  
		mui.toast("播放成功");  
	}, function(e) {  
		mui.toast("播放失败");  
	});	  
}

写在后面

本文以语音文件为例说明5+中语音文件与Base64编码的相互转换,对于图片与Base64编码的转换方法请参考nativeObj Bitmap: 原生图片对象,可以通过loadBase64Data方法加载Base64编码格式图片到Bitmap对象,通过toBase64Data方法获取图片的Base64编码数据。对于一般性文件,建议使用h5 File API,详细可以参考我这篇文章:
JavaScript进阶学习(三)—— 基于html5 File API的文件操作

本文详细代码请查看附件工程。

16 关注 分享
lhyh mfan hanni 小手真黑 5***@qq.com sdsdsdsds huangijn 1***@qq.com 崔大人 3***@qq.com l***@163.com 1***@163.com Mike132 菜鸡 5***@qq.com 木头哥

要回复文章请先登录注册

2***@qq.com

2***@qq.com

视频文件可以吗
2020-07-09 17:15
小权

小权

我的base64在.net服务端转成文件可以播放的。现在base64传到前端,用android.util.Base64.decode解码返回null到底是什么原因?如何解决?
2020-04-12 15:30
喜欢技术的前端

喜欢技术的前端

回复 大海的凡夫俗子 :
是是,ios不支持amr,怎么解决呢
2019-11-29 17:30
大海的凡夫俗子

大海的凡夫俗子

回复 大海的凡夫俗子 :
PS: ios正常,安卓不行, 音频文件是amr格式
2019-09-11 15:05
大海的凡夫俗子

大海的凡夫俗子

从后台读取base64音频文件字符串到前端播放失败,提示: {"code":-5,"message":"setDataSourceFD failed.: status=0x80000000"} 有遇到的吗?
2019-09-11 15:04
8***@qq.com

8***@qq.com

mark,之前都没有注意到plus.io.fileReader,一直用window.fileReader(),一直转不了文件
2019-05-09 15:52
3***@qq.com

3***@qq.com

回复 3***@qq.com :
ry {
var myatb, bstr;
var out = new FileOutputStream(fullPath);
var mystr = atob(mv);
var mlen = mystr.length;
var sstr = '';
while(mlen > 0) {
mysub = mystr.substr(0, 1000);
mystr = mystr.substr(1000);
mlen = mystr.length;
myatb = new Str(mysub);
bstr = myatb.getBytes("ISO8859-1");
out.write(bstr);
}
out.close();
callback && callback(entry); // 回调
} catch(ex) {
console.log('写入失败');

}
2018-12-18 10:25
3***@qq.com

3***@qq.com

function dataURL2Audio (base64Str, callback) {
var base64Str = base64Str.replace('data:audio/amr;base64,','');
var audioName = (new Date()).valueOf() + '.amr';
var Base64 = plus.android.importClass("android.util.Base64");

。。。


var Base64 = plus.android.importClass("android.util.Base64");

Base64 转码部分在部分手机机型上会返回null.

附:解决方法

function dataURL2Audio(fname, base64Str, callback) { //base64转amr文件
var mv = base64Str || '';
if(typeof callback != 'function' || mv == '') return;
fname = fname || ((new Date()).getTime());
fname = (fname.indexOf('.amr') == fname.length - 4) ? fname : fname + '.amr';
var audioName = '_doc/audio/' + fname;
plus.io.requestFileSystem(plus.io.PRIVATE_DOC, function(fs) {
fs.root.getFile(audioName, {
create: true
}, function(entry) {
var fullPath = entry.fullPath;
if(mui.os.android) {
var etStr = plus.android.importClass("java.lang.String");//替换
var FileOutputStream = plus.android.importClass("java.io.FileOutputStream");
try {
var out = new FileOutputStream(fullPath);
var etby = new etStr (atob(mv)); //BASE64解码 源编码如使有 ISO8859-1字符集
var bstr = myatb.etby ("ISO8859-1");//不同系统编码会不一样,需指定与源编码一致
out.write(bstr);
out.close();
callback && callback(entry); // 回调
} catch(ex) {
console.log('写入失败');
}
} else if(mui.os.ios) {
var NSData = plus.ios.importClass('NSData');
var nsData = new NSData();
nsData = nsData.initWithBase64EncodedStringoptions(mv, 0);
if(nsData) {
nsData.plusCallMethod({
writeToFile: fullPath,
atomically: true
});
plus.ios.deleteObject(nsData);
}
callback && callback(entry); // 回调
}
})
})
}
2018-12-16 09:21
1***@163.com

1***@163.com

回复 b***@163.com :
你这个解决了吗?如果解决了可以发一份解决方案到我的邮箱吗?18839127530@163.com
2018-11-07 11:29
1***@163.com

1***@163.com

hbuilder真机测试没问题,但是打包app,安卓出错,ios正常
在录音r.record({filename:'_doc/audio/',format:"amr"} 这个时候存储文件最后没有.amr
2018-11-07 11:27