LoginSignup
10
13

More than 3 years have passed since last update.

【Unity(C#)×PUN2】OculusQuestでのボイスチャット実装方法

Posted at

ボイスチャット

ボイスチャットの実装に当たっていろいろなライブラリがありますが、
メジャーどころで情報が多そうなPhotonを使うことにしました。

しかしながらPhoton2のボイスチャットの実装方法に関する記事
見つけることができませんでした。

公式のドキュメント読めば余裕かな?と思ってましたが、
実際に繋がっているかどうかのテストとかも面倒で意外と時間使ったのでメモします。

下準備

まずはPhoton Voice 2というアセットの導入です。
アセットストアからインポートします。

PUN2もインポートします。

次にアプリケーションIDを作成する必要があります。
アカウント作成後に下記のようにPhotonVoiceという種類の
アプリケーションを作成します。

PUN2Voice.PNG

Photonアプリケーションの作成

設定

下記パスのPhotonServerSettingsのアプリケーションIDを設定します。
Assets\Photon\PhotonUnityNetworking\Resources\PhotonServerSettings

先ほど作成したPhotonVoiceという種類のアプリケーションIDを入力します。
PUN2VoiceSettings.png


次にHierarchyに必要なコンポーネントを用意します。
PhotonVoiceNetworkRecorderが必要です。

適当なオブジェクトにアタッチして、
赤枠で囲った箇所が合ってればだいたい問題ないです。
VoiceConnectionAndRecorder.png

AvatarというPrefabをアタッチしている箇所にはPhotonNetwork経由で生成する
アバター(同期オブジェクト)を設定しています。

【参考リンク】:【Unity(C#),PUN2】OculusQuestのハンドトラッキング同期実装


Avatar側にも設定が必要なので見ていきます。

SpeakerPhotonVoiceViewが必要です。
AudioSourceは自動で追加されます。

SpeakerSettings.png

赤枠で囲った箇所を設定します。
SpeakerInUseは自身のオブジェクトからアタッチします。

これでおおよその設定が完了しました。

音声を口の動きに反映、通信同期

今回利用したアバターは下記画像のものです。
NormcoreAvatar.PNG

球体が頭部で口は独立したオブジェクトとして頭部の子階層に配置されています。

NormcoreというVR/ARの通信同期実装のためのライブラリから拝借しました。

今回はこの口のオブジェクトを声に合わせてパクパクさせたいと思います。

もともとNormcoreのライブラリで口をパクパクさせるコードが
ドキュメントに公開されていますのでそれをPUN2用に利用してみます。

Normcoreのドキュメントのコード
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Normal.Realtime;

public class MouthMove : MonoBehaviour {
    public Transform mouth;

    private RealtimeAvatarVoice _voice;
    private float _mouthSize;

    void Awake() {
        // Get a reference to the RealtimeAvatarVoice component
        _voice = GetComponent<RealtimeAvatarVoice>();
    }

    void Update() {
        // Use the current voice volume (a value between 0 - 1) to calculate the target mouth size (between 0.1 and 1.0)
        float targetMouthSize = Mathf.Lerp(0.1f, 1.0f, _voice.voiceVolume);

        // Animate the mouth size towards the target mouth size to keep the open / close animation smooth
        _mouthSize = Mathf.Lerp(_mouthSize, targetMouthSize, 30.0f * Time.deltaTime);

        // Apply the mouth size to the scale of the mouth geometry
        Vector3 localScale = mouth.localScale;
        localScale.y = _mouthSize;
        mouth.localScale = localScale;
    }
} 

コード

実際のコード全文が下記です。

using Photon.Pun;
using Photon.Voice.PUN;
using UniRx;
using UniRx.Triggers;
using UnityEngine;

/// <summary>
/// しゃべると口が動く機能
/// </summary>
public class MouthSyncVoice : MonoBehaviourPun
{
    [SerializeField] private Transform _mouth;

    private PhotonVoiceView _voice;
    private float _mouthSize;

    void Start() 
    {
        if (photonView.IsMine)
        {
            _voice = GetComponent<PhotonVoiceView>();
            _voice.RecorderInUse.TransmitEnabled = true;

            this.UpdateAsObservable()
                .Subscribe(_ =>
                {
                    //口のオブジェクトのY軸のスケールをLerpで滑らかに動かす
                    float targetMouthSize = Mathf.Lerp(0.1f, 1.0f,100 * _voice.RecorderInUse.LevelMeter.CurrentAvgAmp);
                    _mouthSize = Mathf.Lerp(_mouthSize, targetMouthSize, 30.0f * Time.deltaTime);

                    //口の動きを同期通信させる
                    photonView.RPC(nameof(SyncMouth),RpcTarget.All,_mouthSize);
                })
                .AddTo(this);
        }
    }

    /// <summary>
    /// 口の動きの変化を送信
    /// </summary>
    /// <param name="mouthSize">口の大きさ</param>
    [PunRPC]
    private void SyncMouth(float mouthSize)
    {
        Vector3 localScale = _mouth.localScale;
        localScale.y = mouthSize;
        _mouth.localScale = localScale;
    }
}

_voice.RecorderInUse.TransmitEnabled = true;
の箇所で音声のやり取りを開始しています。

_voice.RecorderInUse.LevelMeter.CurrentAvgAmp
で直前の0.5秒間の平均した音の波形を取得しています。

この波形を利用して口のオブジェクトのY軸方向のスケールを変化させています。

最後のSyncMouthメソッドの中で口のオブジェクトの大きさの変化を双方のクライアントで同期しています。

デモ

GIFなので音はありませんが、相手の音がHMDから聞こえてきて
口がパクパクしているのを確認できました。

SignLanguageInVRMouthSync.gif

最後に

繋がったり、繋がらなかったり、音声が極端に小さかったりと
不具合まみれだったので原因がわかり次第追記していこうと思います。

10
13
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
10
13