preface

During the development of the applets, there was a requirement to implement the recording function, play the recording, and upload the recording to the server. Taro framework is used in the development process, recording function is realized through Taro. GetRecorderManager () interface, upload recording to server through Taro. UploadFile interface. Play the tape use Taro. CreateInnerAudioContext () interface implementation. Here’s how the whole process is implemented in detail.

Applet recording

First get the recording Manager module:

const recorderManager = Taro.getRecorderManager();
Copy the code

Register a recording listening event when the component is mounted:

useEffect(() = > {
	// Listen for the recording
    recorderManager.onStart(() = > {
      console.log('Start recording');
    });
	// Listen recording paused
    recorderManager.onPause(() = > {
      console.log('Pause recording');
    });
	// Listen to the recording continue
    recorderManager.onResume(() = > {
      console.log('Continue recording');
    });
	// Stop listening
    recorderManager.onStop((res) = > {
      if (res.duration < 1000) {
        Taro.showToast({
          title: 'Recording time is too short'.duration: 1000.icon: 'none'}); }else {
        console.log('Stop recording'); fileUpload(res.tempFilePath); }}); recorderManager.onError(() = > {
      Taro.showToast({
        title: 'Recording failed! '.duration: 1000.icon: 'none'}); }); } []);Copy the code

In the callback function of recording onStop, we can obtain the temporary address of recording res.tempFilepath, but this address has an expiry date, so we need to upload the recording to the server background, save it, and then use it normally.

In the onStop callback function, fileUpload is called to upload files. The implementation of fileUpload is as follows:

const fileUpload = (tempFilePath) = > {
    Taro.uploadFile({
      url: 'http://127.0.0.1:7001/record'.// Server address
      filePath: tempFilePath,
      name: 'file'.// Fill this in freely
      header: {
        'content-type': 'multipart/form-data'.// The format must be this
        Authorization: Taro.getStorageSync('token'),},// formData is used to transfer information other than files
      formData: {
        record_name: 'Spoken work'.poem_id: poemInfo.id,
        category: poemInfo.category,
      },
      success: (res) = > {
        console.log(res);
        const url = res.data;
        playAudio(url); // Play the recording
      },
      fail: (error) = > {
        console.log('failed! ');
        console.error(error); }}); };Copy the code

Note that the content-type in the header must be multipart/form-data.

Handling recording events

Clicking handleClick for the first time triggers the recording to begin, which is then used to determine whether to pause or resume recording. HandleComplete is used to stop recording.

const handleClick = () = > {
    constcurPause = pause; setPause(! curPause);if (firstRecord) {
      setfirstRecord(false);

      recorderManager.start({
        duration: 60000.sampleRate: 44100.numberOfChannels: 1.encodeBitRate: 192000.format: 'mp3'.frameSize: 50}); Taro.showToast({title: 'Start recording'.duration: 1000.icon: 'none'}); }else {
      if (curPause) {
        recorderManager.pause(); // Pause the recording
      } else {
        recorderManager.resume(); // Continue recording}}};const handleComplete = () = > {
    recorderManager.stop(); // Stop recording
  };
Copy the code

The background realizes recording storage and returns recording address

Most blogs on the Internet are not involved in this content, the following is to introduce how to achieve the background framework I use Ali’s egg.js.

File uploads require configuration of something visible in the official documentation: egg.js file uploads. We use its first File mode here.

Because the Multipart plug-in is built into the egg.js framework, it can parse uploaded Multipart /form-data data.

First, now write the multipart configuration to the config file config.default.js:

module.exports = (app) = > {
  const config = (exports= {}); . config.multipart = {mode: 'file'.fileSize: '50mb',}...return{... config, ... userConfig, }; };Copy the code

Then, define the route in router.js:

// Submit the recording
router.post('/record', auth, controller.record.postRecord);
Copy the code

Define the record.js file in the Controller directory and write the following:

const Controller = require('egg').Controller;

class RecordController extends Controller {
  async postRecord() {
    const { ctx } = this;
    const file = ctx.request.files[0];
    const { record_name, poem_id, category } = ctx.request.body;
    
    const res = awaitctx.service.record.postRecord(file, record_name, poem_id, category); ctx.body = res; }}module.exports = RecordController;
Copy the code

Define record.js in the service directory and write the concrete implementation:

const Service = require('egg').Service;
let OSS = require('ali-oss');

let aliInfo = {
  // https://help.aliyun.com/document_detail/31837.html
  region: 'oss-cn-guangzhou'.bucket: 'poem-mini-program'.accessKeyId: 'xxx'.// Enter the accessKeyId of Ali Cloud
  accessKeySecret: 'xxx'.// Add accessKeySecret to aliyun
};

let client = new OSS(aliInfo);

class RecordService extends Service {
  async postRecord(file, record_name, poem_id, category) {
    const url = await this.uploadOSS(file);
    await this.updateRecord(url, record_name, poem_id, category);

    return url;
  }

  async uploadOSS(file) {
    const { ctx } = this;

    let result;
    try {
      // Process files, such as uploading to the cloud
      result = await client.put(file.filename, file.filepath);
    } finally {
      // Temporary files need to be deleted
      await ctx.cleanupRequestFiles();
    }
    return result.url;
  }

  async updateRecord(url, record_name, poem_id, category) {
    const { ctx } = this;

    console.log('Get openID from ctx.locals');
    console.log(ctx.locals.openid);
    const openid = ctx.locals.openid;

    // Record user information to the database
    const res = await ctx.model.Record.create({
      record_name: record_name,
      record_url: url,
      poem_id: poem_id,
      category: category,
      openid: openid, }); }}module.exports = RecordService;

Copy the code

Here are some things to note:

  • You need to register an Ali Cloud account, and create a bucket for storing audio in the object storage, which is the implementation of cloud storage.
  • You need to installali-ossNPM package, used to connect ali Cloud object storage. After receiving the temporary file uploaded by the front-end, the background will upload the audio to aliyun object storage (client.put).

Play the tape

UploadFile (tarono. uploadFile); playAudio (tarono. uploadFile); playAudio (tarono. uploadFile);

First, use Taro. CreateInnerAudioContext for audio context object:

const innerAudioText = Taro.createInnerAudioContext();
Copy the code

As with recording, register listening events when the component is mounted:

useEffect(() = > {
    innerAudioText.onPlay(() = > {
      console.log('Start playing');
    });

    innerAudioText.onError((e) = > {
      console.log('Playback exception');
      console.log(e); }); } []);Copy the code

After the recording file is uploaded successfully, call the playAudio method to play the recording:

const playAudio = (url) = > {
  innerAudioText.autoplay = true;
  innerAudioText.src = url;
};
Copy the code

When SRC is assigned a value, the recording starts playing.

conclusion

The above is the whole recording function and recording playback function to achieve the whole process, if you have any questions, welcome to communicate with us.