Skip to content

Instantly share code, notes, and snippets.

@haydenjameslee
Created January 19, 2016 00:07
Show Gist options
  • Save haydenjameslee/4b405cf5e08d227de318 to your computer and use it in GitHub Desktop.
Save haydenjameslee/4b405cf5e08d227de318 to your computer and use it in GitHub Desktop.
Gets PCM audio data from a CoherentUI browser in Unity3D and plays it through a Unity audio filter.
using UnityEngine;
using System.Collections;
using Coherent.UI;
using System.IO;
using System;
using System.Runtime.InteropServices;
[RequireComponent(typeof(CoherentUIView))]
[RequireComponent(typeof(AudioSource))]
unsafe public class CoherentAudioPlayerFilter : MonoBehaviour
{
public int BufferSize = 8192;
[Range(0, 2f)] public float gain = 1f;
View m_View;
UnityViewListener m_ViewListener;
new AudioSource audio;
int m_StreamId;
int m_BitDepth;
int m_Frequency;
int m_Channels;
bool isPlaying;
void Start ()
{
audio = GetComponent<AudioSource>();
GetComponent<CoherentUIView>().OnViewCreated += InitBrowser;
}
void InitBrowser(View view)
{
m_View = view;
m_ViewListener = GetComponent<CoherentUIView>().Listener;
m_ViewListener.AudioStreamCreated += this.OnAudioStreamCreated;
m_ViewListener.AudioStreamPlay += this.OnAudioStreamPlay;
m_ViewListener.AudioStreamPause += this.OnAudioStreamPause;
m_ViewListener.AudioStreamClose += this.OnAudioStreamClose;
}
void OnAudioFilterRead(float[] data, int channels)
{
if (!isPlaying) return;
int numBytes = data.Length * 2;
IntPtr m_AudioBuffer = Marshal.AllocHGlobal(numBytes);
// When you need more data to play for stream #streamID
int timeout = 0; // A zero timeout means block until data is received
int received = m_View.GetAudioData(m_StreamId, m_AudioBuffer, numBytes, timeout);
if (received <= 0)
{
// Negative values indicate an error; Zero is a valid return value if no data is present
return;
}
// Get a byte pointer from the unmanaged memory block.
byte* audioBufferBytePtr = (byte*)m_AudioBuffer.ToPointer();
UnmanagedMemoryStream readStream = new UnmanagedMemoryStream(audioBufferBytePtr, received, numBytes, FileAccess.Read);
// Create a byte array to hold data from unmanaged memory.
byte[] managedData = new byte[received];
// Read from unmanaged memory to the byte array.
readStream.Read(managedData, 0, received);
readStream.Close();
// You now have your data in *managedData* and you can set it to the audio clip.
//WriteToConsole("manageddata", ArrayToString(managedData));
float[] audioFloats = PCMBytesToFloats(managedData);
for (int i = 0; i < audioFloats.Length; i++)
{
data[i] = audioFloats[i] * gain;
}
}
public void OnAudioStreamCreated(int streamId, int channels, int bitDepth, int frequency)
{
Debug.Log("sid = " + streamId + " channels = " + channels + " bitdepth = " + bitDepth + " frequency = " + frequency);
m_StreamId = streamId;
m_Channels = channels;
m_BitDepth = bitDepth;
m_Frequency = frequency;
AudioClip audioClip = AudioClip.Create("browser-audio-" + streamId, BufferSize, m_Channels, 44000, false);
audio.clip = audioClip;
}
public void OnAudioStreamPlay(int streamId)
{
Debug.Log("on audio stream play");
isPlaying = true;
audio.Play();
}
public void OnAudioStreamPause(int streamId)
{
Debug.Log("on audio stream pause");
isPlaying = false;
audio.Pause();
}
public void OnAudioStreamClose(int streamId)
{
Debug.Log("on audio stream close");
isPlaying = false;
audio.Stop();
}
static float[] PCMBytesToFloats(byte[] bytes)
{
float[] floats = new float[bytes.Length / 2];
for (int i = 0; i < bytes.Length; i += 2)
{
short s = BitConverter.ToInt16(bytes, i); // convert 2 bytes to short
floats[i / 2] = ((float)s) / (float)32768; // convert short to float
}
return floats;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment