微信小程序实现录音及播放功能

使用的是: RecorderManager 全局唯一的录音管理器InnerAudioContext 实例

以下为实现代码:

WXML
         <view class="bg-white fs14 pb-32">
          <view class="label gray-2">录音</view>
          <view class="w100 audio">
            <view class="bg-1 w100 radius-10 center pd-40 flex-column">
              <image src="../../../assets/imgs/playAudio.png" mode="" class="audioImg" data-type="1" bindtap="playRecord" wx:if="{{recorderType == '0'}}" />
              <block wx:if="{{recorderType == '1'}}">
                <view class="auditBox w100 mb-20">
                  <view class="auditItem" wx:for="{{31}}" wx:key="index"></view>
                </view>
                <view class="p">{{ recorderCount }}</view>
                <image src="../../../assets/imgs/pauseAudio.png" mode="" class="audioImg" data-type="2" bindtap="playRecord" />
              </block>
              <block wx:if="{{recorderType == '2'}}">
                <view class="w100 flex">
                  <van-icon name="play-circle" color="{{colorStyle}}" size="28px" data-type="3" bindtap="playRecord" wx:if="{{audioType == '4'}}" />
                  <van-icon name="stop-circle" color="{{colorStyle}}" size="28px" data-type="4" bindtap="playRecord" wx:if="{{audioType == '3'}}" />
                  <view class="flex-1 plr-20">
                    <progress percent="{{audioCurrentLength}}" stroke-width="3" activeColor="{{colorStyle}}" />
                  </view>
                  <view class="mr-20">{{audioLength}}</view>
                  <van-icon name="delete-o" data-type="0" bindtap="playRecord" color="#ff0000" size="24px" wx:if="{{isAdd}}" />
                </view>
                <view class="center w100 mt-20">
                  <view class="bg-blue white radius-10 ptb-16 plr-60 size-30" data-type="3" bindtap="playRecord" wx:if="{{audioType == '4'}}">播放</view>
                  <view class="bg-blue white radius-10 ptb-16 plr-60 size-30" data-type="4" bindtap="playRecord" wx:if="{{audioType == '3'}}">暂停</view>
                </view>
              </block>
            </view>
          </view>
        </view>
JS(其中 msToTime 秒数转换成时间方法, uploadWx 简单封装微信请求, 方法写在最后
  data: {
    // 全局唯一的录音管理器
    recorderManager: null,
    recorderType: '0', // 0-开始录音 1-停止录音
    // recorderCount: 60, // 剩余秒数
    recorderCount: '00:00', // 已经录制秒数
    recCount: 0, // 已经录制秒数
    timer: null,
    soundRecordPath: '', // 录音资源
    // 播放器
    innerAudioContext: null,
    audioCurrentLength: 0,
    audioLength: "00:00",
    duration: 0, //音频时长
    audioType: "4", //3-开始播放 4-暂停播放
  },
  //定时器方法
  audioTimer() {
    let that = this
    let { recCount } = this.data
    that.data.timer = setInterval(function () {
      if (++recCount == 600) {
        clearInterval(that.data.timer);
        that.stop();
        that.setData({ recCount: 0, recorderCount: "00:00", recorderType: "2" })
      } else {
        console.log(recCount, msToTime(recCount * 1000));
        that.setData({ recorderCount: msToTime(recCount * 1000) })
      }
    }, 1000)
    // that.data.timer = setInterval(function () {
    //   console.log(recorderCount);
    //   if (--recorderCount == 0) {
    //     clearInterval(that.data.timer);
    //     that.stop();
    //     that.setData({ recorderCount: 600, recorderType: "2" })
    //   } else {
    //     that.setData({ recorderCount: recorderCount })
    //   }
    // }, 1000)
  },
  // 开始录音
  playRecord(e) {
    let { type } = e.currentTarget.dataset
    if (type == '3' || type == '4') {
      this.setData({ audioType: type })
    } else if (type == 2) {
      // 停止录音操作
      this.stop();
    } else {
      this.setData({ recorderType: type })
    }
    if (type == '1') {
      // 开始录音操作      
      this.start();
    } else if (type == '0') {
      //重新录制操作
      this.setData({ soundRecordPath: "", audioCurrentLength: 0, audioType: '4', duration: 0 })
      this.audioPause() // 暂停
      this.audioDestroy() // 释放音频资源
      this.stop();
    } else if (type == '3') {
      // 播放音频操作
      this.audioPlay();
    } else if (type == '4') {
      // 暂停音频操作
      this.audioPause();
    }

  },
  // 录音start
  start() {
    const options = {
      duration: 600000,
      sampleRate: 44100,
      numberOfChannels: 1,
      encodeBitRate: 192000,
      format: 'mp3',
      frameSize: 50
    }
    this.data.recorderManager.start(options)
    this.data.recorderManager.onStart(() => {
      this.audioTimer();
      wx.showToast({ title: '录音开始', icon: 'none' });
      console.log('录音开始')
    })
  },
  // 录音stop
  stop() {
    let that = this
    this.data.recorderManager.stop();
    this.data.recorderManager.onStop((res) => {
      clearInterval(that.data.timer);
      console.log('recorder stop', res)

      const { tempFilePath, duration } = res
      console.log(tempFilePath, duration, 'duration');
      that.setData({ audioLength: msToTime(duration), duration: duration })
      wx.showLoading({
        title: '上传中',
      })
      uploadWx(tempFilePath).then(response => {
        if (response.statusCode == 200 && JSON.parse(response.data).code == 200) { //相当于success回调
          let resp = JSON.parse(response.data)
          if (resp.code == 200) {
            console.log(resp, 'resp');
            that.setData({ soundRecordPath: resp.url, recorderType: '2', recCount: 0, recorderCount: "00:00", duration: duration });
            that.playRecorder(resp.url)
            wx.showToast({ title: '上传成功' });
          } else {
            that.uploadError();
          }
          wx.hideLoading();
        } else {
          wx.hideLoading();
          that.uploadError();
        }
      }).catch(() => {
        wx.hideLoading();
        that.uploadError();
      })
    })
  },
  uploadError(){
    this.setData({ soundRecordPath: "", recorderType: '0', duration: 0, recCount: 0, recorderCount: "00:00", duration: duration });
    wx.showToast({
      title: "上传失败,请重新录制",
      icon: 'none',
      duration: 2000
    })
  },
  // 录音器
  getRecorder() {
    const recorderManager = wx.getRecorderManager()

    recorderManager.onPause(() => {
      console.log('recorder pause')
    })

    recorderManager.onFrameRecorded((res) => {
      const { frameBuffer } = res
      console.log('frameBuffer.byteLength', frameBuffer.byteLength)
    })
    this.setData({ recorderManager: recorderManager });
  },
  // 播放器
  playRecorder(url) {
    const innerAudioContext = wx.createInnerAudioContext({
      useWebAudioImplement: false // 是否使用 WebAudio 作为底层音频驱动,默认关闭。对于短音频、播放频繁的音频建议开启此选项,开启后将获得更优的性能表现。由于开启此选项后也会带来一定的内存增长,因此对于长音频建议关闭此选项
    })
    let that = this
    this.setData({ innerAudioContext: innerAudioContext })
    this.data.innerAudioContext.src = url
    this.data.innerAudioContext.onTimeUpdate(() => {
      let prop = (this.data.innerAudioContext.currentTime / (that.data.duration / 1000)) * 100
      console.log(prop, this.data.innerAudioContext.currentTime, that.data.duration);
      that.setData({ audioCurrentLength: prop })
    })
    this.data.innerAudioContext.onEnded(() => {
      console.log('自然结束了');
      that.setData({ audioCurrentLength: 0, audioType: '4' })
    })
  },
  // 播放play
  audioPlay() {
    this.data.innerAudioContext.play() // 播放
  },
  // 暂停pause
  audioPause() {
    this.data.innerAudioContext.pause() // 暂停
  },
  // 播放stop
  audioDestroy() {
    this.data.innerAudioContext.destroy() // 释放
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    this.getRecorder();
  },
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {
    if (this.data.innerAudioContext) {
      this.audioPause() // 暂停
      this.audioDestroy() // 释放音频资源
    }
  },
WXSS
/* -------------语音音阶------------- */
.auditBox {
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.auditBox .auditItem {
  display: block;
  background: #333333;
  width: 1px;
  height: 10%;
  margin-right: 2.5px;
  float: left;
}

.auditBox .auditItem:last-child {
  margin-right: 0px;
}

.auditBox .auditItem:nth-child(1) {
  animation: load 2.5s 3.0s infinite linear;
}

.auditBox .auditItem:nth-child(2) {
  animation: load 2.5s 2.8s infinite linear;
}

.auditBox .auditItem:nth-child(3) {
  animation: load 2.5s 2.6s infinite linear;
}

.auditBox .auditItem:nth-child(4) {
  animation: load 2.5s 2.4s infinite linear;
}

.auditBox .auditItem:nth-child(5) {
  animation: load 2.5s 2.2s infinite linear;
}

.auditBox .auditItem:nth-child(6) {
  animation: load 2.5s 2.0s infinite linear;
}

.auditBox .auditItem:nth-child(7) {
  animation: load 2.5s 1.8s infinite linear;
}

.auditBox .auditItem:nth-child(8) {
  animation: load 2.5s 1.6s infinite linear;
}

.auditBox .auditItem:nth-child(9) {
  animation: load 2.5s 1.4s infinite linear;
}

.auditBox .auditItem:nth-child(10) {
  animation: load 2.5s 1.2s infinite linear;
}

.auditBox .auditItem:nth-child(11) {
  animation: load 2.5s 1s infinite linear;
}

.auditBox .auditItem:nth-child(12) {
  animation: load 2.5s 0.8s infinite linear;
}

.auditBox .auditItem:nth-child(13) {
  animation: load 2.5s 0.6s infinite linear;
}

.auditBox .auditItem:nth-child(14) {
  animation: load 2.5s 0.4s infinite linear;
}

.auditBox .auditItem:nth-child(15) {
  animation: load 2.5s 0.2s infinite linear;
}

.auditBox .auditItem:nth-child(16) {
  animation: load 2.5s 0s infinite linear;
}

.auditBox .auditItem:nth-child(17) {
  animation: load 2.5s 0.2s infinite linear;
}

.auditBox .auditItem:nth-child(18) {
  animation: load 2.5s 0.4s infinite linear;
}

.auditBox .auditItem:nth-child(19) {
  animation: load 2.5s 0.6s infinite linear;
}

.auditBox .auditItem:nth-child(20) {
  animation: load 2.5s 0.8s infinite linear;
}

.auditBox .auditItem:nth-child(21) {
  animation: load 2.5s 1s infinite linear;
}

.auditBox .auditItem:nth-child(22) {
  animation: load 2.5s 1.2s infinite linear;
}

.auditBox .auditItem:nth-child(23) {
  animation: load 2.5s 1.4s infinite linear;
}

.auditBox .auditItem:nth-child(24) {
  animation: load 2.5s 1.6s infinite linear;
}

.auditBox .auditItem:nth-child(25) {
  animation: load 2.5s 1.8s infinite linear;
}

.auditBox .auditItem:nth-child(26) {
  animation: load 2.5s 2.0s infinite linear;
}

.auditBox .auditItem:nth-child(27) {
  animation: load 2.5s 2.2s infinite linear;
}

.auditBox .auditItem:nth-child(28) {
  animation: load 2.5s 2.4s infinite linear;
}

.auditBox .auditItem:nth-child(29) {
  animation: load 2.5s 2.6s infinite linear;
}

.auditBox .auditItem:nth-child(30) {
  animation: load 2.5s 2.8s infinite linear;
}

.auditBox .auditItem:nth-child(31) {
  animation: load 2.5s 3.0s infinite linear;
}


@keyframes load {
  0% {
    height: 10%;
  }

  25% {
    height: 100%;
  }

  50% {
    height: 20%;
  }

  75% {
    height: 100%;
  }

  100% {
    height: 10%;
  }
}
方法
// msToTime
export const msToTime = (duration) => {
  var milliseconds = parseInt((duration % 1000) / 100)
    , seconds = parseInt((duration / 1000) % 60)
    , minutes = parseInt((duration / (1000 * 60)) % 60);

  minutes = minutes < 10 ? "0" + minutes : minutes;
  seconds = seconds < 10 ? "0" + seconds : seconds;

  return minutes + ":" + seconds;
}

// uploadWx
export const uploadWx = (tempFilePath) => {
  return wxp.uploadFile({
    url: 'yourApi',
    filePath: tempFilePath,
    name: 'file',
    formData: {
      file: tempFilePath,
    },
    header: {
      'Content-Type': 'multipart/form-data',
      // token: wx.getStorageSync('token'), // 看后台需要哪种 header
      Authorization: "Bearer " + wx.getStorageSync('token'),
    }
  })
}
  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
当然可以!微信小程序录音机的代码可以分为前端和后端两部分。下面是一个简单的示例代码: 前端代码(WXML): ```html <view class="container"> <button bindtap="startRecord">开始录音</button> <button bindtap="stopRecord">停止录音</button> </view> ``` 前端代码(JS): ```javascript Page({ data: { recorderManager: null, tempFilePath: '' }, onLoad: function () { this.setData({ recorderManager: wx.getRecorderManager() }); this.data.recorderManager.onStart(() => { console.log('录音开始'); }); this.data.recorderManager.onStop((res) => { console.log('录音结束', res.tempFilePath); this.setData({ tempFilePath: res.tempFilePath }); }); }, startRecord: function () { this.data.recorderManager.start({ duration: 60000, // 录音时长,单位为毫秒 format: 'mp3' // 录音格式,支持 mp3 和 aac }); }, stopRecord: function () { this.data.recorderManager.stop(); } }); ``` 后端代码(Node.js): ```javascript const express = require('express'); const multer = require('multer'); const upload = multer({ dest: 'uploads/' }); const app = express(); app.post('/upload', upload.single('file'), (req, res) => { console.log(req.file); // 处理上传的录音文件 // ... res.send('上传成功'); }); app.listen(3000, () => { console.log('服务器已启动'); }); ``` 以上代码实现了一个简单的微信小程序录音机,点击开始录音按钮后开始录音,点击停止录音按钮后停止录音,并将录音文件上传到后端服务器。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值