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

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

## 動作確認
WindowsのChrome

### 開発情報
- react
- firebase
- react-audio-player

## デモ動画
YouTubeで確認できます。
https://youtu.be/zHmhcu2CANs

## コード
```react: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](https://developer.mozilla.org/ja/docs/Web/API/Web_Audio_API)を使用する必要があるみたいで、この実装だと動きません。
実装し終えてから気づきました。。。

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

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

## 参考にした記事
- [ブラウザで録音してwavで保存](https://qiita.com/optimisuke/items/f1434d4a46afd667adc6)
- [JavaScriptのWeb Audio APIで録音してみる](https://saitodev.co/article/JavaScript%E3%81%AEWeb_Audio_API%E3%81%A7%E9%8C%B2%E9%9F%B3%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B)
- [Blob または File からアップロードする](https://firebase.google.com/docs/storage/web/upload-files?hl=ja#upload_from_a_blob_or_file)