欧美三级国产三级日韩三级_亚洲熟妇丰满大屁股熟妇_欧美亚洲成人一区二区三区_国产精品久久久久久模特

【微信小程序】小程序端錄音、播放踩坑日記 - 新聞資訊 - 云南小程序開發(fā)|云南軟件開發(fā)|云南網(wǎng)站建設(shè)-昆明葵宇信息科技有限公司

159-8711-8523

云南網(wǎng)建設(shè)/小程序開發(fā)/軟件開發(fā)

知識

不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價(jià)值,我們在追求其視覺表現(xiàn)的同時(shí),更側(cè)重于功能的便捷,營銷的便利,運(yùn)營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實(shí)提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序?yàn)楹笃谏壧峁┍憬莸闹С郑?

您當(dāng)前位置>首頁 » 新聞資訊 » 小程序相關(guān) >

【微信小程序】小程序端錄音、播放踩坑日記

發(fā)表時(shí)間:2021-1-5

發(fā)布人:葵宇科技

瀏覽次數(shù):171

一、前言
  • 開發(fā)背景:首次嘗試小程序中實(shí)現(xiàn)錄音、播放功能。
  • 開發(fā)框架:
    • taro 2.2.6
    • taro-ui 2.3.4
  • 難點(diǎn)描述:
    • 實(shí)現(xiàn)小程序錄音、上傳到后臺
    • PC、IOS 和安卓端音頻播放資源的地址,支持 mp3 下載鏈接

溫馨提示:這篇文章重點(diǎn)介紹小程序的音頻在各種環(huán)境錄音和播放實(shí)踐。適用對象:遇到小程序在 IOS 端無法播放音頻的同學(xué)們和對小程序兼容性感興趣的同學(xué)。

二、小程序錄音、上傳

2.1 注冊事件監(jiān)聽

首先,介紹一下錄音的部分。這里主要用到了小程序中的 wx.getRecorderManager() 模塊部分。

直接放代碼,感興趣的可以去微信開發(fā)文檔就了解下各種配置。

import Taro, { Component } from '@tarojs/taro'

export default class Index extends Component {
  ...
  // 聲明錄音管理器模塊
  recorderManager = wx.getRecorderManager()

  componentDidMount() {
    // 拋出錯(cuò)誤
    recorderManager.onError(() => {
      Taro.showToast({
        title: '錄音失??!',
        duration: 1000,
        icon: 'none'
      })
    })
    // 錄音結(jié)束時(shí)的處理
    recorderManager.onStop(res => {
      if (res.duration < 1000) {
        Taro.showToast({
          title: '錄音時(shí)間太短',
          duration: 1000,
          icon: 'none'
        })
      } else {
        // content 是存儲錄音結(jié)束后的數(shù)據(jù)結(jié)構(gòu),用于調(diào)試
        this.setState({ content: res })
        wx.saveFile({
          tempFilePath: res.tempFilePath,
          success: result => {
            // 這里會調(diào)用一個(gè)文件上傳的接口
            this.fileUpload(result.savedFilePath)
          }
        })
      }
    })
  }
  
  fileUpload(tempFilePath) {
    Taro.uploadFile({
      url: XXXApi,
      filePath: tempFilePath,
      name: 'file',
      header: {
        'content-type': 'multipart/form-data',
        cookie: Taro.getStorageSync('cookie') // 上傳需要單獨(dú)處理 cookie
      },
      formData: {
        method: 'POST' // 請求方式
      },
      success: res => {
        // 錄音上傳成功之后的處理
      }
    })
  }
}
復(fù)制代碼

梳理一下:

  • componentDidMount 生命周期中,注冊幾個(gè)重要的事件。包括:監(jiān)聽錄音錯(cuò)誤事件監(jiān)聽錄音結(jié)束事件
  • 在錄音結(jié)束時(shí),用 wx.savefile 將文件保存到本地
  • wx.savefile 成功的回調(diào)中,調(diào)用文件上傳的接口,將文件上傳到服務(wù)器。

2.2 實(shí)現(xiàn)錄音事件處理函數(shù)

先看下 dom 節(jié)點(diǎn)部分:

<Text>上傳語音</Text>
<Text
  onLongPress={this.handleRecordStart}
  onTouchend={this.handleRecordStop}
>
  長按說話
</Text>
復(fù)制代碼

其中就兩個(gè)事件:handleRecordStarthandleRecordStop。他們分別是長按時(shí)觸發(fā)和手指松開時(shí)觸發(fā)。

簡單實(shí)現(xiàn):

// longpress (長按)時(shí)觸發(fā)
handleRecordStart(e) {
  this.setState({
    record: {
      // 修改錄音數(shù)據(jù)結(jié)構(gòu),此時(shí)錄音按鈕樣式會發(fā)生變化。
      text: '松開保存',
      type: 'recording'
    }
  })
  // 開始錄音
  this.recorderManager.start({
    duration: 60000,
    sampleRate: 44100,
    numberOfChannels: 1,
    encodeBitRate: 192000,
    format: 'mp3',
    frameSize: 50
  }) 
  Taro.showToast({
    title: '正在錄音',
    duration: 60000,
    icon: 'none'
  })
}

// touchend (手指松開)時(shí)觸發(fā)
handleRecordStop() {
  // 復(fù)原在 start 方法中修改的錄音的數(shù)據(jù)結(jié)構(gòu)
  this.setState({
    record: {
      text: '長按錄音',
      type: 'record'
    }
  })
  // 結(jié)束錄音、隱藏 Toast 提示框
  wx.hideToast() 
  // 結(jié)束錄音
  this.recorderManager.stop() 
}
復(fù)制代碼

這里用了一個(gè) record 對象來記錄錄音的狀態(tài)。

注意 recorderManager.start 方法的參數(shù)中, duration 指錄音時(shí)長,這里設(shè)置為 60000 msformat 值為 mp3,意思錄音得到的音頻文件為 mp3 格式。

溫馨提示:最初開發(fā)沒有設(shè)置成格式化為 mp3,導(dǎo)致后臺同事增加了工作量(將 m4a 轉(zhuǎn)換成 mp3),這里建議前端直接處理,很方便。


三、小程序端錄音的播放

3.1 錄音播放

說到音頻播放,大家第一時(shí)間可能想到的是 Audio 標(biāo)簽,然后給其中的 src 屬性動態(tài)賦值就好了。沒錯(cuò),PC 端確實(shí)是這樣。但是小程序比較坑,如下圖:

音頻播放這里,我們選用了 wx.createInnerAudioContext() 接口。

溫馨提示:如果音頻上傳到后臺之后可以返回 .mp3 結(jié)尾的 url 鏈接(例如:http://47.104.167.164/faceVideo/result_2020_07_21_12_33_43.mp3),可以考慮直接利用 wx.createInnerAudioContext()play() 方法實(shí)現(xiàn)播放。

由于部分原因,我們后臺上傳音頻文件后,返回的鏈接是一個(gè)云文件 ID(指瀏覽器打開可以下載此 mp3 文件)。而且經(jīng)過測試發(fā)現(xiàn),安卓端可以直接播放,IOS 端直接播放沒有聲音。

然后,請教了一下我們組的架構(gòu)師,決定將文件先下載下來,然后保存到手機(jī)本地,最后播放(經(jīng)過測試方案可行)。

我們直接看代碼:

// 小程序音頻播放 api
innerAudioContext = wx.createInnerAudioContext()

// 下載音頻文件
downloadFile() {
  const FileSystemManager = wx.getFileSystemManager()
  const { voiceUrl } = this.state
  wx.downloadFile({
    url: voiceUrl,
    header: { 'Content-type': 'audio/mp3' },
    success: res => {
      // 只要服務(wù)器有響應(yīng)數(shù)據(jù),就會把響應(yīng)內(nèi)容寫入文件并進(jìn)入 success 回調(diào),業(yè)務(wù)需要自行判斷是否下載到了想要的內(nèi)容
      if (res.statusCode === 200) {
        FileSystemManager.saveFile({
          tempFilePath: res.tempFilePath,
          // 文件地址為手機(jī)本地
          filePath: `${wx.env.USER_DATA_PATH}/${new Date().getTime()}.mp3`,
          success: result => {
            if (result.errMsg == 'saveFile:ok') {
              this.registerAudioContext(result.savedFilePath)
            }
          }
        })
      }
    }
  })
}

// 注冊音頻控件
registerAudioContext(path) {
  this.innerAudioContext.src = http://www.wxapp-union.com/path
  this.innerAudioContext.play()
  // 避開 IOS 端靜音狀態(tài)沒法播放的問題
  this.innerAudioContext.obeyMuteSwitch = false
  this.innerAudioContext.onEnded(res => {
    // isPlaying 記錄是否在播放中
    this.setState({ isPlaying: false })
    this.innerAudioContext.stop()
  })
  this.innerAudioContext.onError(res => {
    // 播放音頻失敗的回調(diào)
  })
  this.innerAudioContext.onPlay(res => {
    // 開始播放音頻的回調(diào)
  })
  this.innerAudioContext.onStop(res => {
    // 播放音頻停止的回調(diào)
  })
}
復(fù)制代碼

這里做了兩件事情:

  • wx.downloadFile() 接口將文件下載下來,注意參數(shù)中 header 屬性, Content-type 值為 audio/mp3。即將此文件識別為音頻類文件。這里用到微信里的文件管理器 wx.getFileSystemManager() ,接口中的 saveFile() 方法可以把文件保存到本地
  • wx.createInnerAudioContext()play() 方法播放存在本地的音樂 mp3 文件

3.2 性能優(yōu)化

這里考慮到播放完之后,存在手機(jī)的錄音文件會越來越多。我們想想辦法,做一做性能優(yōu)化工作。也就是在恰當(dāng)?shù)臅r(shí)機(jī)清楚多余文件。

代碼如下:

componentWillUnmount() {
  this.clearDir()
}

// 刪除下載的音頻文件
clearDir() {
  const FileSystemManager = wx.getFileSystemManager()
  const __dirPath = wx.env.USER_DATA_PATH
  FileSystemManager.readdir({
    dirPath: __dirPath,
    success: res => {
      const { errMsg, files } = res
      if (errMsg == 'readdir:ok') {
        files.forEach(item => {
          FileSystemManager.unlink({
            filePath: `${__dirPath}/${item}`
          })
        })
      }
    }
  })
}
復(fù)制代碼

梳理一下:

wx.getFileSystemManager() 接口中 readdir() 方法讀取到指定目錄(wx.env.USER_DATA_PATH)的所有文件。在其讀取成功的回調(diào)中做一個(gè) forEach 循環(huán),然后用 unlink() 刪除文件。最后將此方法放在生命周期 componentWillUnmount 中調(diào)用。


四、PC 端音頻播放

小程序的錄音和播放都簡單的介紹了,這里也拓展一下。說一說 PC 端比較原始的音頻播放方法。

項(xiàng)目中沒有引用播放器插件,這里直接用 audio 標(biāo)簽來實(shí)現(xiàn)。 html 的部分如下:

const { voice_url, isPlaying } = this.state;

return (
  <>
    <p>
      <span>音頻:</span>
      <Button onClick={this.onBtnClick}>{isPlaying ? '停止' : '播放'}</Button>
    </p>

    <audio
      id={`audio`}
      src={voice_url}
      autoPlay={true}
      ref={this.audioRef}
      preload={'auto'}
      onCanPlay={() => {}}
      onTimeUpdate={() => {}}>
      <track src={voice_url} kind='captions' />
    </audio>
  </>
)
復(fù)制代碼

然后看下 PC 端解析播放部分,和小程序原理差不多,先下載,后播放。代碼如下:

// 播放或者暫停
onBtnClick = () => {
  const { isPlaying } = this.state;
  // 區(qū)分播放還是暫停
  if (isPlaying) {
    this.audioRef.current.pause();
  } else {
    this.downloadFile();
  }
  this.setState({ isPlaying: !isPlaying });
};

// 下載文件
downloadFile = () => {
  const { download_url } = this.state;
  axios.get(download_url as string, { responseType: 'blob' }).then((res: any) => {
    const reader = new FileReader();
    const data = http://www.wxapp-union.com/res.data;
    reader.onload = e => {
      this.executeDownload(data);
    };
    reader.readAsText(data);
  });
};

// 在瀏覽器上預(yù)覽音頻文件
executeDownload = (data: any) => {
  if (!data) {
    return;
  }
  // 將文件轉(zhuǎn)化音頻流的鏈接
  const url = window.URL.createObjectURL(new Blob([data], { type: 'audio/mp3' }));
  // 前端存儲這個(gè)鏈接
  this.setState({ voice_url: url });
};
復(fù)制代碼

梳理:

  • 創(chuàng)建 audio 標(biāo)簽作為音頻播放的容器
  • 點(diǎn)擊頁面的播放按鈕觸發(fā)文件下載方法
  • 通過 axios 下載資源文件,用 new FileReader() 讀取文件,并且在文件完全加載時(shí),利用 window.URL.createObjectURL() 方法生成可以在瀏覽器上預(yù)覽音頻文件的鏈接
  • audio 監(jiān)聽到 src 屬性的變化時(shí),會自動播放出聲音

相關(guān)案例查看更多