You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

react-mic音频转换方案咨询:将weba转为MP3/MP4/WAV

Solutions for Converting react-mic's WebM Blob to MP3/WAV/MP4

Hey there! Let's tackle this audio format conversion problem you're facing. I've dealt with similar React + Rails audio workflows before, so here are practical frontend and backend solutions to get you past this hurdle:


Frontend JS Library Options (No Backend Dependencies)

Since you're looking to handle conversion on the frontend, these libraries will let you transform the WebM blob from react-mic directly into your desired format before uploading:

1. ffmpeg.wasm (Most Versatile)

This is a browser port of FFmpeg, supporting nearly all audio/video format conversions. It's powerful and straightforward once set up:

Step 1: Install Dependencies

npm install @ffmpeg/ffmpeg @ffmpeg/core

Step 2: Modify Your React Component's onStop and onUpload Methods

Update your onStop handler to convert the WebM blob to MP3 (or WAV/MP4) before uploading:

import React from 'react';
import { ReactMic } from 'react-mic';
import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg';

const ffmpeg = createFFmpeg({ log: true });

class AudioMic extends React.Component {
  constructor(props){
    super(props)
    this.state = { recordAudio: false, blobAudio: null, blobURL: null };
  };

  startRecording = () => {
    this.setState({ recordAudio: true });
  }

  stopRecording = () => {
    this.setState({ recordAudio: false });
  }

  onStart = () => {
    console.log('You can tap into the onStart callback');
  }

  onStop = async (blobAudio) => {
    // Load FFmpeg core first (only needs to happen once, but safe to call multiple times)
    if (!ffmpeg.isLoaded()) {
      await ffmpeg.load();
    }

    const inputFilename = 'recording.webm';
    const outputFilename = 'recording.mp3';

    // Write the WebM blob to FFmpeg's virtual file system
    ffmpeg.FS('writeFile', inputFilename, await fetchFile(blobAudio.blob));

    // Run conversion command (adjust output format by changing the extension: .wav, .mp4)
    await ffmpeg.run('-i', inputFilename, outputFilename);

    // Read the converted file back
    const convertedData = ffmpeg.FS('readFile', outputFilename);
    const convertedBlob = new Blob([convertedData.buffer], { type: 'audio/mp3' });

    // Update state with converted blob
    this.setState({
      blobAudio: { blob: convertedBlob, blobURL: URL.createObjectURL(convertedBlob) }
    }, () => this.onUpload());
  };

  onUpload = () => {
    const formData = new FormData();
    // Append the converted blob directly (no need for FileReader)
    formData.append('audio', this.state.blobAudio.blob, 'recording.mp3');

    fetch('/api/v1/user_response', {
      credentials: 'same-origin',
      method: 'POST',
      body: formData,
      headers: {
        'Accept': 'application/json, */*'
        // Don't set Content-Type here — the browser auto-handles multipart/form-data boundaries
      }
    })
    .then(response => {
      if (!response.ok) throw new Error(`${response.status} (${response.statusText})`);
      return response.json();
    })
    .then(body => console.log('Upload successful:', body))
    .catch(error => console.error('Upload error:', error.message));
  };

  componentDidMount = () => {
    const hasGetUserMedia = !!(navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
    if(!hasGetUserMedia) {
      alert('Your browser cannot stream from your audio. Please switch to Chrome or Firefox.');
    }
  };

  render() {
    return (
      <div>
        <ReactMic 
          className='oscilloscope' 
          record={ this.state.recordAudio } 
          backgroundColor='#FF4081' 
          visualSetting='sinewave' 
          audioBitsPerSecond= { 128000 } 
          onStop={ this.onStop } 
          onStart={ this.onStart } 
          strokeColor='#000000' 
        />
        <div>
          <audio ref='audioSource' controls='controls' src={ this.state.blobURL }></audio>
        </div>
        <button onClick={ this.startRecording }>
          <span>Start Recording</span>
          <span hidden>🎤</span>
        </button>
        <button onClick={ this.stopRecording }>
          <span>Stop Recording</span>
          <span hidden>⏹️</span>
        </button>
        <button onClick={ this.onUpload }>
          <span>Upload Response</span>
          <span hidden>☁️</span>
        </button>
      </div>
    );
  };
};

2. lamejs (Lightweight for WAV → MP3)

If you first convert WebM to WAV (using ffmpeg.wasm or another tool), lamejs is a tiny library dedicated to WAV-to-MP3 conversion:

import lamejs from 'lamejs';

// Assume you have a WAV ArrayBuffer from conversion
const convertWavToMp3 = (wavArrayBuffer) => {
  const wav = new Uint8Array(wavArrayBuffer);
  const wavHeader = lamejs.WavHeader.readHeader(new DataView(wav.buffer));
  const samples = new Int16Array(wav.buffer, wavHeader.dataOffset, wavHeader.dataLen / 2);

  const mp3Encoder = new lamejs.Mp3Encoder(1, wavHeader.sampleRate, 128); // 1 channel, 44.1kHz, 128kbps
  const mp3Data = [];
  const chunkSize = 1152;

  for (let i = 0; i < samples.length; i += chunkSize) {
    const chunk = samples.subarray(i, i + chunkSize);
    const mp3Buf = mp3Encoder.encodeBuffer(chunk);
    if (mp3Buf.length > 0) mp3Data.push(new Uint8Array(mp3Buf));
  }

  const finalBuf = mp3Encoder.flush();
  if (finalBuf.length > 0) mp3Data.push(new Uint8Array(finalBuf));

  return new Blob(mp3Data, { type: 'audio/mp3' });
};

Backend Solution (Alternative to sox)

If you prefer handling conversion on the Rails side, swap carrierwave-audio with streamio-ffmpeg — it's easier to set up and supports more formats:

Step 1: Add the Gem

# Gemfile
gem 'streamio-ffmpeg'

Run bundle install, then install FFmpeg on your server:

  • Ubuntu/Debian: sudo apt install ffmpeg
  • macOS: brew install ffmpeg

Step 2: Update Your CarrierWave Uploader

class UserResponseUploader < CarrierWave::Uploader::Base
  include CarrierWave::FFmpeg

  storage :file if Rails.env.test?
  storage :fog unless Rails.env.test?

  # Auto-convert uploaded files to MP3 (change to .wav or .mp4 as needed)
  process convert: 'mp3'

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  # Optional: Customize conversion settings
  def convert(format)
    manipulate! do |media|
      media.encoder = 'libmp3lame'
      media.audio_bitrate = 128
      media
    end
  end
end

Final Recommendations

  • Frontend conversion (ffmpeg.wasm) is great for reducing backend load and giving users immediate feedback. It's also easier to debug since you can test the conversion directly in the browser.
  • Backend conversion (streamio-ffmpeg) is better if you need to enforce consistent format standards or handle large files that might strain client devices.

内容的提问来源于stack exchange,提问作者nmadoug

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:44:53