Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Implementing Voice Recording and Playback with Dynamic Audio Visualization in WeChat Mini Programs

Tech May 15 1

Overview

This implementation demonstrates how to integrate voice recording, playback, and a dynamic audio wave effect into a WeChat Mini Program. It utilizes the RecorderManager for capturing audio and the InnerAudioContext for playback. The UI provides a hold-to-record button and a visualizer that animates during playback.

1. Structure (WXML)

The layout consists of a microphone icon for recording and a container for the playback interface. The playback container includes a dynamic wave indicator composed of bars and a timestamp display.


<view class="audio-container">
  <!-- Recording Trigger -->
  <image 
    class="mic-icon" 
    src="/assets/images/mic.png" 
    mode="aspectFit"
    catchtouchstart="onRecordStart" 
    catchtouchend="onRecordEnd" 
  />

  <!-- Playback Interface -->
  <view class="player-wrapper" wx:if="{{recordDuration > 0}}" bindtap="onPlayTap">
    <view class="wave-indicator">
      <view class="bar bar-1"></view>
      <view class="bar bar-2" style="opacity: {{visualizer.bar2Opacity}}"></view>
      <view class="bar bar-3" style="opacity: {{visualizer.bar3Opacity}}"></view>
    </view>
    <text class="duration-text">{{recordDuration}}s</text>
  </view>
</view>

<!-- Recording Status Overlay -->
<view class="recording-overlay" wx:if="{{isRecording}}">
  Recording...
</view>

2. Styling (WXSS)

The styles define the flex layout for the audio controls and the visual appearence of the waveform bars. The overlay is posisioned absolutely to indicate recording status.


.audio-container {
  display: flex;
  align-items: center;
  background-color: #ffffff;
  padding: 20rpx;
  box-sizing: border-box;
}

.mic-icon {
  width: 72rpx;
  height: 72rpx;
}

.player-wrapper {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-left: 32rpx;
  width: 160rpx;
  height: 68rpx;
  background-color: #2b7a7a;
  border-radius: 10rpx;
  padding: 0 12rpx;
  box-sizing: border-box;
}

.wave-indicator {
  display: flex;
  align-items: center;
  height: 100%;
}

.bar {
  width: 6rpx;
  background-color: #e0e0e0;
  margin-left: 8rpx;
}

.bar-1 { height: 12rpx; }
.bar-2 { height: 24rpx; }
.bar-3 { height: 36rpx; }

.duration-text {
  font-size: 24rpx;
  color: #e0e0e0;
}

.recording-overlay {
  position: fixed;
  bottom: 300rpx;
  left: 50%;
  transform: translateX(-50%);
  width: 200rpx;
  height: 200rpx;
  line-height: 200rpx;
  background-color: rgba(0, 0, 0, 0.7);
  color: white;
  text-align: center;
  border-radius: 10rpx;
}

3. Logic (JS)

The JavaScript handles the recording liefcycle, processes the audio file, and manages the playback animation loop. The animation loop creates a visual effect by toggling the opacity of the waveform bars.


const audioContext = wx.createInnerAudioContext();

Page({
  data: {
    isRecording: false,
    recordDuration: 0,
    visualizer: {
      bar2Opacity: 1,
      bar3Opacity: 1
    },
    tempFilePath: ''
  },

  onLoad() {
    this.recorderManager = wx.getRecorderManager();
    this.setupRecorderEvents();
    
    // Configure player
    audioContext.autoplay = false;
  },

  setupRecorderEvents() {
    this.recorderManager.onStop((res) => {
      const { tempFilePath } = res;
      const duration = Math.floor(res.duration / 1000);
      
      this.setData({
        recordDuration: duration,
        tempFilePath: tempFilePath,
        isRecording: false
      });
      
      // Prepare the player
      audioContext.src = tempFilePath;
      // Optional: Implement server upload logic here
    });
  },

  onRecordStart() {
    this.setData({ isRecording: true });
    const options = {
      duration: 60000 // Max duration 60s
    };
    this.recorderManager.start(options);
  },

  onRecordEnd() {
    this.setData({ isRecording: false });
    this.recorderManager.stop();
  },

  onPlayTap() {
    if (audioContext.src) {
      audioContext.play();
      this.startWaveAnimation();
    }
  },

  startWaveAnimation() {
    let remainingTime = this.data.recordDuration;
    let animInterval;
    
    // Cleanup any existing intervals
    if (this.playTimer) clearInterval(this.playTimer);
    if (this.waveTimer) clearInterval(this.waveTimer);

    const animateFrame = () => {
      // Animation Cycle: 1.2 seconds total
      this.setData({ visualizer: { bar2Opacity: 0, bar3Opacity: 0 } });
      
      setTimeout(() => {
        this.setData({ visualizer: { bar2Opacity: 1, bar3Opacity: 0 } });
      }, 300);

      setTimeout(() => {
        this.setData({ visualizer: { bar2Opacity: 1, bar3Opacity: 1 } });
      }, 600);

      setTimeout(() => {
        this.setData({ visualizer: { bar2Opacity: 0, bar3Opacity: 0 } });
      }, 900);
    };

    // Start animation immediately
    animateFrame();
    this.waveTimer = setInterval(animateFrame, 1200);

    // Countdown timer
    this.playTimer = setInterval(() => {
      remainingTime--;
      if (remainingTime <= 0) {
        this.stopAnimation();
      }
    }, 1000);
    
    // Ensure stop when audio ends naturally
    audioContext.onEnded(() => {
      this.stopAnimation();
    });
  },

  stopAnimation() {
    if (this.playTimer) clearInterval(this.playTimer);
    if (this.waveTimer) clearInterval(this.waveTimer);
    
    this.setData({
      visualizer: { bar2Opacity: 1, bar3Opacity: 1 }
    });
  }
});

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.