Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What are the problem?

posted at

updated at

Reactでブラウザから音声を録音してFirebaseにアップロードしてみた(iOS未対応)

経緯

最近は音声を投稿するSNSが増えてきているなぁと感じてきており、私が知っている限りでも10個は直ぐに思い出せます。
そこで、いつか音声サービスを作ってみたくなるかもしれないので、興味本位で調べてみました。

動作確認

WindowsのChrome

開発情報

  • react
  • firebase
  • react-audio-player

デモ動画

YouTubeで確認できます。
https://youtu.be/zHmhcu2CANs

コード

App.js
import React, { useEffect, useState, useRef } from "react";
import firebase from "firebase";
import ReactAudioPlayer from "react-audio-player";

// configは、自分のfirebaseの設定を指定してください。
const config = {
  apiKey: "",
  authDomain: "",
  databaseURL: "",
  storageBucket: "",
};

const App = () => {
  const [file, setFile] = useState([]);
  const [audioState, setAudioState] = useState(true);
  const audioRef = useRef();

  useEffect(() => {
    if (firebase.apps.length === 0) {
      firebase.initializeApp(config);
    }
    // マイクへのアクセス権を取得
    navigator.getUserMedia =
      navigator.getUserMedia || navigator.webkitGetUserMedia;
    //audioのみtrue
    navigator.getUserMedia(
      {
        audio: true,
        video: false,
      },
      handleSuccess,
      hancleError
    );
  }, []);

  const handleSuccess = (stream) => {
    // レコーディングのインスタンスを作成
    audioRef.current = new MediaRecorder(stream, {
      mimeType: "video/webm;codecs=vp9",
    });
    // 音声データを貯める場所
    var chunks = [];
    // 録音が終わった後のデータをまとめる
    audioRef.current.addEventListener("dataavailable", (ele) => {
      if (ele.data.size > 0) {
        chunks.push(ele.data);
      }
      // 音声データをセット
      setFile(chunks);
    });
    // 録音を開始したら状態を変える
    audioRef.current.addEventListener("start", () => setAudioState(false));
    // 録音がストップしたらchunkを空にして、録音状態を更新
    audioRef.current.addEventListener("stop", () => {
      setAudioState(true);
      chunks = [];
    });
  };
  // 録音開始
  const handleStart = () => {
    audioRef.current.start();
  };

  // 録音停止
  const handleStop = () => {
    audioRef.current.stop();
  };
  // firebaseに音声ファイルを送信
  const handleSubmit = () => {
    // firebaseのrefを作成
    var storageRef = firebase.storage().ref();
    var metadata = {
      contentType: "audio/mp3",
    };
    // ファイル名を付けてBlobからファイルを作成して送信
    var mountainsRef = storageRef.child(new Date() + "test.mp3");
    mountainsRef.put(new Blob(file), metadata).then(function () {
      console.log("アップロード完了!");
    });
  };
  const handleRemove = () => {
    setAudioState(true);
    setFile([]);
  };

  const hancleError = () => {
    alert("エラーです。");
  };

  return (
    <div>
      <button onClick={handleStart}>録音</button>
      <button onClick={handleStop} disabled={audioState}>
        ストップ
      </button>
      <button onClick={handleSubmit} disabled={file.length === 0}>
        送信
      </button>
      <button onClick={handleRemove}>削除</button>
      <ReactAudioPlayer src={URL.createObjectURL(new Blob(file))} controls />
    </div>
  );
};

export default App;

所感

ほぼ参考サイトのコピペですが、それをReactで実装してみました。
Webで音声を録音することも案外できるものだなぁと感じました。
また、音声の再生には「react-audio-player」というライブラリが直感的に使えて助かりました。
音声を録音と変換が簡単にできるreactのライブラリがあればよかったのですが...

また、iOSのブラウザではWeb Audio APIを使用する必要があるみたいで、この実装だと動きません。
実装し終えてから気づきました。。。

次はiOSに対応するバージョンと、ReactNativeでの音声の録音と保存にも挑戦してみようと思います。

最後に

※発言は個人の見解で所属組織とは無関係です

参考にした記事

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
2
Help us understand the problem. What are the problem?