LoginSignup
17
12

More than 3 years have passed since last update.

Clubhouseのような音声SNSアプリをWebRTCで作ってみる

Last updated at Posted at 2021-02-03

今年に入ってClubhouseという音声SNSが大ブームになっています。
技術のポイントとして、スピーカ同士が遅延なく通話が可能で、その通話を大勢のオーディエンスがリスニングできる点になります。

方法としてはスピーカ間はWebRTC、オーディエンスはHLSに変換されたデータを取得するという構成が考えられます。iOS/Androidアプリであれば独自プロトコルでの実装という事も考えられます。

今回はagora.ioの技術を用いてWeb版Clubhouseのようなアプリを作ってみようと思います。
WebアプリなのでベースはWebRTCとなります。又、agora.ioの技術を利用すれば大勢のオーディエンスもWebRTCで接続可能です。

サンプルはこちらに公開してます。

画面イメージ

スクリーンショット 0003-02-03 20.43.51.png
以下の機能が実装されています。
・ルームの作成
・他の人が作成されたルームの表示
・他の人のルームに入室
・退室

ルーム表示についてはサーバー側で管理する方法が一般的かもしれませんが、今回はAgoraRTMSDKを利用してリアルタイムメッセージで管理してみます。
AppIDはagora.ioにサインアップして取得する必要があります。

実装の詳細

JoinボタンをクリックしたタイミングでAgoraRTMにログインします。
全員共通の"main"というチャンネルに接続し、新規でルームが発生した際、入室ボタンを表示する実装になっています。

index.js
async function joinRtm() {
  rtmClient = AgoraRTM.createInstance(options.appid);
  rtmClient.login({ token: '', uid: options.accountName}).then(() => {
    console.log('AgoraRTM client login success');

    //rtm channel
    rtmChannel = rtmClient.createChannel(mainRtmChannel);
    rtmChannel.join().then(()=>{
        console.log("RTM Join Channel Success");

        rtmChannel.on('ChannelMessage', function (message, memberId) {
            console.log("Get channel message:"+memberId);
            console.dir(message);
            const information = JSON.parse(message.text);

            if(information.type == "new"){

              const room = $(
                <div id="player-wrapper-${memberId}" >
                  <button id="" type="submit" class="btn btn-primary btn-sm" onclick="join('${information.channelName}','','host')">Join Speaker(Host:${memberId})</button>
                  <button id="" type="submit" class="btn btn-primary btn-sm" onclick="join('${information.channelName}','','audience')">Join Audience(Host:${memberId})</button>
                  <button id="" type="submit" class="btn btn-primary btn-sm" onclick="leave()">Leave</button>
                </div>
                <br />
              );
              $("#remote-playerlist").append(room);
            }
        });
    });
  }, function (err) {
    console.log("AgoraRTC client init failed", err);
  });
}

次にRoomに入室処理する処理です。
・新規Room作成か既存Roomに入室か
・スピーカーかオーディエンスか
で処理を分岐しています。

新規Room作成の場合は、他のユーザにRoom作成の通知をRTMSDKで実施しています。
スピーカー入室の場合は、マイクを取得してサーバーへPublishする実装をします。

index.js
async function join(channelName,type,role) {
  console.log("channelName:" + channelName);
  // add event listener to play remote tracks when remote user publishs.
  client.on("user-published", handleUserPublished);
  client.on("user-unpublished", handleUserUnpublished);
  client.setClientRole(role);
  const uid = await client.join(options.appid, channelName, null, null);

  if(role == "host"){
    localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
    // Publish the local audio track to the channel.
    await client.publish([localAudioTrack]);
  }

  if(type == "new"){
    //新規ルームの通知
    var info = JSON.stringify({uid: options.accountName, channelName: channelName, type: type});
    rtmChannel.sendMessage({text: info});
    console.log("send new channel info");
  }
}

最後に他拠点からの音声取得部分になります。
こちらはスピーカーもオーディエンスも同様の処理になります。

index.js
async function subscribe(user, mediaType) {
  const uid = user.uid;
  // subscribe to a remote user
  await client.subscribe(user, mediaType);
  console.log("subscribe success");

  if (mediaType === 'audio') {
    user.audioTrack.play();
  }
}

agora.ioを利用すればClubhouseのようなリアルタイム音声SNSの構築が簡単にできます。
現時点ではミニマムなサンプルですが、段階的にClubhouseに近づけるサンプルを公開していきたいと思います。

参考リンク

agora.ioではiOS/Androidアプリ用のSDKも公開されています。より高性能な音声技術をアプリに組み込む事も可能です。
ボイスチャット/カラオケアプリにおける音声配信(VoIP)技術について
Raw Audio Data を使って自分の音声を可視化してみる

最後に

agora.ioに関するお問い合わせはこちらから
スクリーンショット 0001-08-15 13.41.56.png

17
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
12