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

录音文件与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