栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > PHP

小程序、录音、TP5、转码、silk

PHP 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

小程序、录音、TP5、转码、silk

本篇文章主要介绍一下以下功能:

用小程序实现录音功能,在本地播放,提交服务端,服务端播放。

中间遇到了一些坑,找到了一些解决方法,如果有更优的解决方案希望你能在评论留言,一起加油。

1.小程序端

前端展示页面,小程序采用数据绑定方式,这里正在录音和正在播放的状态切换,用两张图根据录音状态和播放状态切换,这里就不多说了。

长按开始录音,触发录音事件,松手执行录音结束,将录音结果保存在本地。

    
    startRecord: function () {
 var that = this
 that.setData({
     isRecording: true,
 });

 whisper.startRecord({
     success(result) {
  that.setData({
      isRecording: false,
  });
  console.log('录音成功:', result);
  console.log('录音成功:', result.tempFilePath);
  //提交录音
  var src = result.tempFilePath;
  var name = 'record'
  repair.uploadRecord(src, name, (res) => {

      that.data.recordObj.record = res;
  });
     },
     fail(error) {
  console.log('录音失败:', error);
     },
     process() {
  that.setData({
      duration: whisper.getRecordDuration(),
  });
     },
     compelete() {

     },
 });
    },

    
    stopRecord: function () {
 var that = this;
 whisper.stopRecord({
     success(result) {
  that.setData({
      isRecording: false,
  });

  console.log('停止录音:', result);
     },
     fail(error) {
  console.log('停止录音失败:', error);
     }
 });

    },

    
    play: function () {
 var that = this
 that.setData({
     isPlaying: true,
 });
 whisper.playRecord({
     src: whisper.getRecordSrc(),
     success(result) {
  that.setData({
      isPlaying: false,
  });
  console.log('播放/暂停成功:', result);
     },
     fail(error) {
  that.setData({
      isPlaying: false,
  });
  console.log('播放/暂停失败:', error);
     }
 });
    },

在录音结束后,执行success的回调函数,上传录音文件到服务器,注意微信小程序的录音文件是silk格式,这是一大坑,在服务端需要处理一下,后面再说。

具体的上传在model层。

    //上传录音
    uploadRecord(src, name, callback){
 var params = {
     url:'repair/record',
     filePath: src,
     name: name,
     formdata: {
  'name': name
     },
     sCallback: function (data) {
  callback && callback(data);
     }
 };
 this.upload(params);
    }

录音类也贴一下

var noop = function noop() { };
var recorder = {

};


var RecordError = (function () {
    function RecordError(message) {
 Error.call(this, message);
 this.message = message;
    }

    RecordError.prototype = new Error();
    RecordError.prototype.constructor = RecordError;

    return RecordError;
})();

function startRecord(options) {
    if (typeof options !== 'object') {
 var message = '请求传参应为 object 类型,但实际传了 ' + (typeof options) + ' 类型';
 throw new RecordError(message);
    }

    var process = options.process;
    var success = options.success || noop;
    var fail = options.fail || noop;
    var complete = options.complete || noop;

    if (typeof process !== 'function') {
 var message = '刷新Ui函数不存在';
 throw new RecordError(message);
    }

    // 成功回调
    var callSuccess = function () {
 success.apply(null, arguments);
 complete.apply(null, arguments);
    };

    // 失败回调
    var callFail = function (error) {
 fail.call(null, error);
 complete.call(null, error);
    };

    // 初始化录音器
    initRecorder();
    // 实际进行请求的方法
    doRecord();

    // 实际进行请求的方法
    function doRecord() {
 console.log("开始录音")
 recorder.timer = setInterval(function () {
     recorder.duration += 1;
     process();
     if (recorder.duration >= recorder.maxDuration && recorder.timer) {
  clearInterval(recorder.timer);
     }
 }, 1000);
 wx.startRecord({
     success: function (res) {
  if (res.tempFilePath) {
      recorder.src = res.tempFilePath;
      callSuccess.apply(null, arguments);
      return ;
  } else {
      message = '录音文件保存失败';
      var error = new RecordError(message);
      options.fail(error);
  }
  callFail(error);
     },

     fail: callFail,
     complete: complete,
 });

    };

    // 初始化录音器
    function initRecorder() {
 recorder = {
     maxDuration: 60,
     duration: 0,
     src: null,
     timer: null,
 };
    }

};

function stopRecord(options) {
    if (typeof options !== 'object') {
 var message = '请求传参应为 object 类型,但实际传了 ' + (typeof options) + ' 类型';
 throw new RecordError(message);
    }

    var success = options.success || noop;
    var fail = options.fail || noop;
    var complete = options.complete || noop;

    // 成功回调
    var callSuccess = function () {
 success.apply(null, arguments);
 complete.apply(null, arguments);
    };

    // 失败回调
    var callFail = function (error) {
 fail.call(null, error);
 complete.call(null, error);
    };

    doStopRecord();

    // 实际进行请求的方法
    function doStopRecord() {
 wx.stopRecord({
     success: function (res) {
  if (recorder.timer) {
      clearInterval(recorder.timer);
  }
  callSuccess.apply(null, arguments);
     },
     fail: callFail,
     complete: complete,
 });
    };
};

function getRecordDuration() {
    return recorder.duration || 0;
}

function getRecordSrc() {
    return recorder.src || null;
}

module.exports = {
    RecordError: RecordError,
    startRecord: startRecord,
    stopRecord: stopRecord,
    getRecordDuration: getRecordDuration,
    getRecordSrc: getRecordSrc,
};

播放类

var noop = function noop() { };
var player = {
    src: null,
};


var PlayError = (function () {
    function PlayError(message) {
 Error.call(this, message);
 this.message = message;
    }

    PlayError.prototype = new Error();
    PlayError.prototype.constructor = PlayError;

    return PlayError;
})();

function play(options) {
    if (typeof options !== 'object') {
 var message = '请求传参应为 object 类型,但实际传了 ' + (typeof options) + ' 类型';
 throw new PlayError(message);
    }

    if (!options.src) {
 var message = '无资源';
 var error = new PlayError(message);
 options.fail(error);
 return;
    }

    var process = options.process || noop;
    var success = options.success || noop;
    var fail = options.fail || noop;
    var complete = options.complete || noop;

    // 成功回调
    var callSuccess = function () {
 success.apply(null, arguments);
 complete.apply(null, arguments);
    };

    // 失败回调
    var callFail = function (error) {
 fail.call(null, error);
 complete.call(null, error);
    };

    if (!player.src || player.src != options.src) {
 if (player.src) {
     doStop(false);
 }
 doPlay();
    } else {
 doStop(true);
    }

    // 实际进行请求的方法
    function doPlay() {
 player.src = options.src;
 console.log("开始播放" + player.src);
 wx.playVoice({
     filePath: player.src,
     success: function (res) {
  // success
  console.log("播放结束" + player.src);
  player.src = null,
      callSuccess.apply(null, arguments);
     },
     fail: callFail,
     complete: complete,
 })
    };

    // 实际进行请求的方法
    function doStop(isCallbackOn) {
 wx.stopVoice({
     success: function () {
  console.log("停止播放" + player.src);
  player.src = null;
  isCallbackOn ? callSuccess.apply(null, arguments) : noop();
     },
     fail: isCallbackOn ? callFail : noop,
     complete: isCallbackOn ? complete : noop,
 });
    };
};

module.exports = {
    PlayError: PlayError,
    playRecord: play,
};

ok,前端完成,转向服务端

2.服务端

后端用的是PHP的TP5框架,接收到的silk文件想要在浏览器上播放,我刚开始是想的转码MP3,在网上找了些资料,基本都指向了kn007大神的博客,写了个demo,Silk v3编码格式转码MP3终于实现了,结果发现小程序的silk不是silk V3,哭晕在厕所,这里可能有我没理解的,有人实现了希望可以留言。

然后,我一同事提醒我webm格式的可以直接播放的,囧。那就没的说了,直接base64解码成webm格式。

   
    public function uploadRecord()
    {
 $name = input('post.name');
 if($_FILES[$name]["error"] > 0){
     throw new Exception("Error: " . $_FILES[$name]["error"]);
 }else{
     $file = request()->file($name);
     $info = $file->move(ROOT_PATH . 'public' . DS . 'record/'.$this->mainID);
     $path = $info->getSaveName();

     $base = ROOT_PATH . 'public' . DS;
     $silk = $base . 'record/' . $this->mainID . '/' . $path;
     $webm = str_replace("silk","webm",$silk);
     $returnWebm = str_replace("silk","webm",$path);

     $content = file_get_contents($silk);
     $baseSilk = base64_decode(str_replace("data:audio/webm;base64,", '', $content));
     file_put_contents($webm,$baseSilk);

 }

 return $returnWebm;
    }

也贴一下wins环境下,用silk_v3_decoder.exe转码MP3的测试代码吧,具体的可以看下kn007大神的博客。

    public function test()
    {

 $base = ROOT_PATH . 'public' . DS;

 $file = $base.'record\song1.silk';
 $type = $base.'record\song.pcm';

 $res  = $base.'record\song.mp3';
 $cmd = "{$base}silk\windows\silk_v3_decoder.exe $file $type" ;
 exec($cmd, $out);

 $cmd1 = "{$base}silk\windows\ffmpeg.exe -y -f s16le -ar 24000 -ac 1 -i  $type $res";
 exec($cmd1,$out1);
    }

就这吧。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/228415.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号