forked from cgvr/DeltaVR
		
	
		
			
				
	
	
		
			153 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
namespace Oculus.Platform
 | 
						|
{
 | 
						|
  using UnityEngine;
 | 
						|
  using System;
 | 
						|
  using System.Collections.Generic;
 | 
						|
 | 
						|
  public class VoipAudioSourceHiLevel : MonoBehaviour
 | 
						|
  {
 | 
						|
    // This is a delegate that exists as a surface for OnAudioFilterRead
 | 
						|
    // It will be callled on unity's audio thread
 | 
						|
    public class FilterReadDelegate : MonoBehaviour
 | 
						|
    {
 | 
						|
      public VoipAudioSourceHiLevel parent;
 | 
						|
      float[] scratchBuffer;
 | 
						|
 | 
						|
      void Awake()
 | 
						|
      {
 | 
						|
        int bufferSizeElements = (int)CAPI.ovr_Voip_GetOutputBufferMaxSize();
 | 
						|
        scratchBuffer = new float[bufferSizeElements];
 | 
						|
      }
 | 
						|
 | 
						|
      void OnAudioFilterRead(float[] data, int channels)
 | 
						|
      {
 | 
						|
        int sizeToFetch = data.Length / channels;
 | 
						|
        int sourceBufferSize = sizeToFetch;
 | 
						|
        if (sourceBufferSize > scratchBuffer.Length)
 | 
						|
        {
 | 
						|
          Array.Clear(data, 0, data.Length);
 | 
						|
          throw new Exception(string.Format("Audio system tried to pull {0} bytes, max voip internal ring buffer size {1}", sizeToFetch, scratchBuffer.Length));
 | 
						|
        }
 | 
						|
 | 
						|
        int available = parent.pcmSource.PeekSizeElements();
 | 
						|
        if (available < sourceBufferSize)
 | 
						|
        {
 | 
						|
          if (verboseLogging)
 | 
						|
          {
 | 
						|
            Debug.LogFormat(
 | 
						|
              "Voip starved! Want {0}, but only have {1} available",
 | 
						|
              sourceBufferSize,
 | 
						|
              available);
 | 
						|
          }
 | 
						|
          return;
 | 
						|
        }
 | 
						|
 | 
						|
        int copied = parent.pcmSource.GetPCM(scratchBuffer, sourceBufferSize);
 | 
						|
        if (copied < sourceBufferSize)
 | 
						|
        {
 | 
						|
          Debug.LogWarningFormat(
 | 
						|
            "GetPCM() returned {0} samples, expected {1}",
 | 
						|
            copied,
 | 
						|
            sourceBufferSize);
 | 
						|
 | 
						|
          return;
 | 
						|
        }
 | 
						|
 | 
						|
        int dest = 0;
 | 
						|
        float tmpPeakAmp = -1;
 | 
						|
        for (int i = 0; i < sizeToFetch; i++)
 | 
						|
        {
 | 
						|
          float val = scratchBuffer[i];
 | 
						|
            
 | 
						|
          for (int j = 0; j < channels; j++)
 | 
						|
          {
 | 
						|
            data[dest++] = val;
 | 
						|
            if (val > tmpPeakAmp)
 | 
						|
            {
 | 
						|
              tmpPeakAmp = val;
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
        parent.peakAmplitude = tmpPeakAmp;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    int initialPlaybackDelayMS;
 | 
						|
    public UInt64 senderID
 | 
						|
    {
 | 
						|
      set
 | 
						|
      {
 | 
						|
        pcmSource.SetSenderID(value);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    public AudioSource audioSource;
 | 
						|
    public float peakAmplitude;
 | 
						|
 | 
						|
    protected IVoipPCMSource pcmSource;
 | 
						|
 | 
						|
    static int audioSystemPlaybackFrequency;
 | 
						|
    static bool verboseLogging = false;
 | 
						|
 | 
						|
    protected void Stop() {}
 | 
						|
 | 
						|
    VoipSampleRate SampleRateToEnum(int rate) {
 | 
						|
      switch(rate) {
 | 
						|
      case 48000:
 | 
						|
        return VoipSampleRate.HZ48000;
 | 
						|
      case 44100:
 | 
						|
        return VoipSampleRate.HZ44100;
 | 
						|
      case 24000:
 | 
						|
        return VoipSampleRate.HZ24000;
 | 
						|
      default:
 | 
						|
        return VoipSampleRate.Unknown;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    protected void Awake()
 | 
						|
    {
 | 
						|
      CreatePCMSource();
 | 
						|
      if(audioSource == null) {
 | 
						|
        audioSource = gameObject.AddComponent<AudioSource>();
 | 
						|
      }
 | 
						|
      audioSource.gameObject.AddComponent<FilterReadDelegate>();
 | 
						|
      var filterDelegate = audioSource.gameObject.GetComponent<FilterReadDelegate>();
 | 
						|
      filterDelegate.parent = this;
 | 
						|
 | 
						|
      initialPlaybackDelayMS = 40;
 | 
						|
 | 
						|
      audioSystemPlaybackFrequency = AudioSettings.outputSampleRate;
 | 
						|
      CAPI.ovr_Voip_SetOutputSampleRate(SampleRateToEnum(audioSystemPlaybackFrequency));
 | 
						|
      if(verboseLogging) {
 | 
						|
        Debug.LogFormat("freq {0}", audioSystemPlaybackFrequency);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    void Start() {
 | 
						|
      audioSource.Stop();
 | 
						|
    }
 | 
						|
 | 
						|
    protected virtual void CreatePCMSource()
 | 
						|
    {
 | 
						|
      pcmSource = new VoipPCMSourceNative();
 | 
						|
    }
 | 
						|
 | 
						|
    protected static int MSToElements(int ms) {
 | 
						|
      return ms * audioSystemPlaybackFrequency / 1000;
 | 
						|
    }
 | 
						|
      
 | 
						|
    void Update()
 | 
						|
    {
 | 
						|
      pcmSource.Update();
 | 
						|
 | 
						|
      if (!audioSource.isPlaying && pcmSource.PeekSizeElements() >= MSToElements(initialPlaybackDelayMS)) {
 | 
						|
        if(verboseLogging) {
 | 
						|
          Debug.LogFormat("buffered {0} elements, starting playback", pcmSource.PeekSizeElements());
 | 
						|
        }
 | 
						|
        audioSource.Play();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |