// ----------------------------------------------------------------------- // // 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); } } }