5+App 开发——录音文件与 Base64 编码相互转换的方法

前言

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

Alt text

录音文件转成 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 的文件操作

本文详细代码请查看这里:演示工程

写这些代码也许就一两个小时的事,写一篇大家好接受的文章需要几天的酝酿,如果文章对您有帮助请我喝杯咖啡吧!