// -----------------------------------------------------------------------
//
// Photon Voice API Framework for Photon - Copyright (C) 2017 Exit Games GmbH
//
//
// Photon data streaming support.
//
// developer@photonengine.com
// ----------------------------------------------------------------------------
using System;
namespace Photon.Voice
{
///
/// Adapter base reading data from and pushing it to .
///
///
/// Use this with a LocalVoice of same T type.
///
public abstract class BufferReaderPushAdapterBase : IServiceable
{
protected IDataReader reader;
/// Do the actual data read/push.
/// LocalVoice instance to push data to.
public abstract void Service(LocalVoice localVoice);
/// Create a new BufferReaderPushAdapterBase instance
/// DataReader to read from.
public BufferReaderPushAdapterBase(IDataReader reader)
{
this.reader = reader;
}
/// Release resources associated with this instance.
public void Dispose()
{
this.reader.Dispose();
}
}
///
/// Simple implementation using a single buffer and synchronous
///
public class BufferReaderPushAdapter : BufferReaderPushAdapterBase
{
protected T[] buffer;
/// Create a new BufferReaderPushAdapter instance
/// LocalVoice instance to push data to.
/// DataReader to read from.
public BufferReaderPushAdapter(LocalVoice localVoice, IDataReader reader) : base(reader)
{
// any buffer will work but only of localVoice.FrameSize avoids additional processing
buffer = new T[((LocalVoiceFramed)localVoice).FrameSize];
}
public override void Service(LocalVoice localVoice)
{
while (this.reader.Read(this.buffer))
{
((LocalVoiceFramed)localVoice).PushData(this.buffer);
}
}
}
///
/// implementation using asynchronous .
///
///
/// Acquires a buffer from pool before each Read, releases buffer after last Read (brings Acquire/Release overhead).
/// Expects localVoice to be a of same T.
///
public class BufferReaderPushAdapterAsyncPool : BufferReaderPushAdapterBase
{
/// Create a new BufferReaderPushAdapter instance
/// LocalVoice instance to push data to.
/// DataReader to read from.
public BufferReaderPushAdapterAsyncPool(LocalVoice localVoice, IDataReader reader) : base(reader) { }
/// Do the actual data read/push.
/// LocalVoice instance to push data to. Must be a of same T.
public override void Service(LocalVoice localVoice)
{
var v = ((LocalVoiceFramed)localVoice);
T[] buf = v.BufferFactory.New();
while (this.reader.Read(buf))
{
v.PushDataAsync(buf);
buf = v.BufferFactory.New();
}
// release unused buffer
v.BufferFactory.Free(buf, buf.Length);
}
}
///
/// implementation using asynchronous and data copy.
///
///
/// Reads data to preallocated buffer, copies it to buffer from pool before pushing.
/// Compared with , this avoids one pool Acquire/Release cycle at the cost
/// of a buffer copy.
/// Expects localVoice to be a of same T.
///
public class BufferReaderPushAdapterAsyncPoolCopy : BufferReaderPushAdapterBase
{
protected T[] buffer;
/// Create a new BufferReaderPushAdapter instance
/// LocalVoice instance to push data to.
/// DataReader to read from.
public BufferReaderPushAdapterAsyncPoolCopy(LocalVoice localVoice, IDataReader reader) : base(reader)
{
buffer = new T[((LocalVoiceFramedBase)localVoice).FrameSize];
}
/// Do the actual data read/push.
/// LocalVoice instance to push data to. Must be a of same T.
public override void Service(LocalVoice localVoice)
{
while (this.reader.Read(buffer))
{
var v = ((LocalVoiceFramed)localVoice);
var buf = v.BufferFactory.New();
Array.Copy(buffer, buf, buffer.Length);
v.PushDataAsync(buf);
}
}
}
///
/// implementation using asynchronous , converting float samples to short.
///
///
/// This adapter works exactly like , but it converts float samples to short.
/// Acquires a buffer from pool before each Read, releases buffer after last Read.
///
/// Expects localVoice to be a of same T.
///
public class BufferReaderPushAdapterAsyncPoolFloatToShort : BufferReaderPushAdapterBase
{
float[] buffer;
/// Create a new BufferReaderPushAdapter instance
/// LocalVoice instance to push data to.
/// DataReader to read from.
public BufferReaderPushAdapterAsyncPoolFloatToShort(LocalVoice localVoice, IDataReader reader) : base(reader)
{
buffer = new float[((LocalVoiceFramed)localVoice).FrameSize];
}
/// Do the actual data read/push.
/// LocalVoice instance to push data to. Must be a of same T.
public override void Service(LocalVoice localVoice)
{
var v = ((LocalVoiceFramed)localVoice);
short[] buf = v.BufferFactory.New();
while (this.reader.Read(buffer))
{
AudioUtil.Convert(buffer, buf, buf.Length);
v.PushDataAsync(buf);
buf = v.BufferFactory.New();
}
// release unused buffer
v.BufferFactory.Free(buf, buf.Length);
}
}
///
/// implementation using asynchronous , converting short samples to float.
///
/// This adapter works exactly like , but it converts short samples to float.
/// Acquires a buffer from pool before each Read, releases buffer after last Read.
///
/// Expects localVoice to be a of same T.
public class BufferReaderPushAdapterAsyncPoolShortToFloat : BufferReaderPushAdapterBase
{
short[] buffer;
/// Create a new BufferReaderPushAdapter instance
/// LocalVoice instance to push data to.
/// DataReader to read from.
public BufferReaderPushAdapterAsyncPoolShortToFloat(LocalVoice localVoice, IDataReader reader) : base(reader)
{
buffer = new short[((LocalVoiceFramed)localVoice).FrameSize];
}
/// Do the actual data read/push.
/// LocalVoice instance to push data to. Must be a of same T.
public override void Service(LocalVoice localVoice)
{
var v = ((LocalVoiceFramed)localVoice);
float[] buf = v.BufferFactory.New();
while (this.reader.Read(buffer))
{
AudioUtil.Convert(buffer, buf, buf.Length);
v.PushDataAsync(buf);
buf = v.BufferFactory.New();
}
// release unused buffer
v.BufferFactory.Free(buf, buf.Length);
}
}
}