Agora Go Real

{{ page_meta.name }}|{{ group.public_title }}|{{ site_settings.logo_alt }}

作成者: ブイキューブ|May 13, 2022 6:34:27 AM

実装

1.AudioRawDataObserver を登録し、コールバックを設定する

今回は自身の音声データを使うので、複数あるコールバックのうち
SetOnRecordAudioFrameCallback を設定します。

TestHelloUnityVideo.cs
    public void setUpRawAudioData() {
            mAudioManager = AudioRawDataManager.GetInstance(mRtcEngine);
    
            // Registers the audio observer.
            mAudioManager.RegisterAudioRawDataObserver();
    
            // Listens for the OnRecordAudioFrameHandler delegate.
            mAudioManager.SetOnRecordAudioFrameCallback(OnRecordAudioFrameHandler);
        }
    

RegisterAudioRawDataObserver は JoinChannel 前にコールしておく必要があります。

TestHelloUnityVideo.cs
    public void join(string channel)
        {
            ... 
    
            setUpRawAudioData();
    
            // join channel
            mRtcEngine.JoinChannel(channel, null, 0);
    
            ... 
        }
    

2.コールバックを実装する

コールバックを設定すると、定期的に AudioFrame が引数で渡されてきます。AudioFrame はサンプリングされた音声データを含むオブジェクトで、これを一時的にためておくキューをクラス内に用意しておきます。今回、キューに格納されたデータは描画のタイミングで 1 個ずつ順番に取り出す実装にしますが、万が一描画のタイミングが遅いなどしてデータが増えすぎてしまわないよう、キューに格納できる上限を設けておきます。

TestHelloUnityVideo.cs
    public void OnRecordAudioFrameHandler(AudioFrame audioFrame) {  
            if(audioFrameQueue.Count <= 3) {
                audioFrameQueue.Enqueue(audioFrame);
            }
        }
    

3.オーディオデータ取得のインターフェースを実装する

今回、音声波形の描画は TestHome.cs に任せるため、AudioFrame オブジェクトを返すメソッドを用意します。

TestHelloUnityVideo.cs
    public AudioFrame getAudioFrame() {
            return (audioFrameQueue.Count > 0) ? (AudioFrame)audioFrameQueue.Dequeue() : new AudioFrame();
        }
    

4.描画ロジックを実装する

LineRenderer を使って音声波形を描画します。先ずは、線の色・太さを設定します。

TestHome.cs
    void Start()
        {
            ...
    
            LineRenderer lineRenderer = gameObject.AddComponent<LineRenderer>();
    
            float lineWidth = 0.1f;
            lineRenderer.startWidth = lineWidth;
            lineRenderer.endWidth = lineWidth;
    
            Color lineColor = new Color(0.9f, 0.9f, 0.5f);
            lineRenderer.startColor = lineColor;
            lineRenderer.endColor = lineColor;
    
            lineRenderer.material = new Material(Shader.Find("Sprites/Default"));
        }
    

次に Update() メソッドに描画ロジックを追加します。AudioFrame オブジェクトを扱うので、次の一行をファイルに追加しておきます:

TestHome.cs
using agora_gaming_rtc;
    

AudioFrame に含まれるサンプル数と同じサイズの Vector3 配列 (頂点リスト)を用意し、各頂点の座標を計算していきます。サンプル一つ一つは 16 bit PCM 方式で格納されているため、復号してから Y 座標を計算していきます。

TestHome.cs
    void Update()
        {
            ...
    
            if(app != null) {
                AudioFrame audioFrame = app.getAudioFrame();
                LineRenderer lineRenderer = GetComponent<LineRenderer>();
    
                lineRenderer.positionCount = audioFrame.samples;
                Vector3[] points = new Vector3[lineRenderer.positionCount];
    
                float xStretch = 8.0f;
                float yAmp = 2.0f;
                float yOffset = 4.0f;
    
                for(int i = 0, idx = 0; i < lineRenderer.positionCount; i++, idx+=2) {
                    // AudioFrame type is PCM 16bit little endian.
                    short audioLevel = (short) ( (audioFrame.buffer[idx+1] << 8) | audioFrame.buffer[idx] ); 
    
                    points[i] = new Vector3(
                        xStretch * (2.0f * i / (lineRenderer.positionCount - 1.0f) - 1.0f), 
                        yAmp * (audioLevel / 32768f) + yOffset, 
                        0.0f
                    );
                }
    
                lineRenderer.SetPositions(points);
            }
        }
    

実行結果