private static void PlayWithoutStreaming(IWaveSource waveSource) { using (var xaudio2 = XAudio2.CreateXAudio2()) using (var masteringVoice = xaudio2.CreateMasteringVoice()) //ALWAYS create at least one masteringVoice. using (var sourceVoice = xaudio2.CreateSourceVoice(waveSource.WaveFormat)) { var buffer = waveSource.ToByteArray(); using (var sourceBuffer = new XAudio2Buffer(buffer.Length)) { using (var stream = sourceBuffer.GetStream()) { stream.Write(buffer, 0, buffer.Length); } sourceVoice.SubmitSourceBuffer(sourceBuffer); } sourceVoice.Start(); Console.WriteLine("Press any key to exit."); Console.ReadKey(); sourceVoice.Stop(); } }
/// <summary> /// Initializes a new instance of the <see cref="StreamingSourceVoice" /> class. /// </summary> /// <param name="ptr">Pointer to a <see cref="XAudio2SourceVoice" /> object.</param> /// <param name="voiceCallback"> /// <see cref="VoiceCallback" /> instance which receives notifications from the /// <see cref="XAudio2SourceVoice" /> which got passed as a pointer (see the <paramref name="ptr" /> argument). /// </param> /// <param name="waveSource"><see cref="IWaveSource" /> which provides the audio data to stream.</param> /// <param name="bufferSize"> /// Buffersize of the internal used buffers in milliseconds. Values in the range from 70ms to /// 200ms are recommended. /// </param> /// <remarks>It is recommended to use the <see cref="Create" /> method instead of the this constructor.</remarks> public StreamingSourceVoice(IntPtr ptr, VoiceCallback voiceCallback, IWaveSource waveSource, int bufferSize) { BasePtr = ptr; _voiceCallback = voiceCallback; _waveSource = waveSource; var maxBufferBytes = (int) waveSource.WaveFormat.MillisecondsToBytes(bufferSize); _buffer = new byte[maxBufferBytes]; for (int i = 0; i < _buffers.Length; i++) { var buffer = new XAudio2Buffer(maxBufferBytes); _buffers[i] = buffer; } InitializeForStreaming(); }
internal StreamingSourceVoice(XAudio2 xaudio2, IWaveSource waveSource, VoiceCallback voiceCallback, int bufferSize) : base(CreateSourceVoice(xaudio2, waveSource, voiceCallback), xaudio2.Version) { _voiceCallback = voiceCallback; _waveSource = waveSource; var maxBufferBytes = (int)waveSource.WaveFormat.MillisecondsToBytes(bufferSize); _buffer = new byte[maxBufferBytes]; for (int i = 0; i < _buffers.Length; i++) { var buffer = new XAudio2Buffer(maxBufferBytes); _buffers[i] = buffer; } InitializeForStreaming(); }
/// <summary> /// Initializes a new instance of the <see cref="StreamingSourceVoice" /> class. /// </summary> /// <param name="ptr">Pointer to a <see cref="XAudio2SourceVoice" /> object.</param> /// <param name="voiceCallback"> /// <see cref="VoiceCallback" /> instance which receives notifications from the /// <see cref="XAudio2SourceVoice" /> which got passed as a pointer (see the <paramref name="ptr" /> argument). /// </param> /// <param name="waveSource"><see cref="IWaveSource" /> which provides the audio data to stream.</param> /// <param name="bufferSize"> /// Buffersize of the internal used buffers in milliseconds. Values in the range from 70ms to /// 200ms are recommended. /// </param> /// <remarks>It is recommended to use the <see cref="Create(XAudio2,IWaveSource,int)" /> method instead of the this constructor.</remarks> internal StreamingSourceVoice(IntPtr ptr, VoiceCallback voiceCallback, IWaveSource waveSource, int bufferSize) { BasePtr = ptr; _voiceCallback = voiceCallback; _waveSource = waveSource; var maxBufferBytes = (int)waveSource.WaveFormat.MillisecondsToBytes(bufferSize); _buffer = new byte[maxBufferBytes]; for (int i = 0; i < _buffers.Length; i++) { var buffer = new XAudio2Buffer(maxBufferBytes); _buffers[i] = buffer; } InitializeForStreaming(); }
/// <summary> /// Notifies the <see cref="StreamingSourceVoice" /> class that new data got requested. If there are any buffers which /// are currently not queued and the underlying <see cref="IWaveSource" /> holds any more data, this data refills the /// internal used buffers and provides audio data to play. /// </summary> public virtual void Refill() { lock (_lockObj) //make sure that nothing gets disposed while anything is still in use. { if (_disposed) { _waitHandle.Close(); return; } int buffersQueued = GetState(GetVoiceStateFlags.NoSamplesPlayed).BuffersQueued; if (buffersQueued >= MaxBufferCount) { return; } int read = _waveSource.Read(_buffer, 0, _buffer.Length); if (read == 0) { return; } XAudio2Buffer nbuffer = _buffers[_currentBufferIndex]; nbuffer.AudioBytes = read; //bug: could be critical since some wave sources don't provide length and position nbuffer.Flags = _waveSource.Position >= _waveSource.Length ? XAudio2BufferFlags.EndOfStream : XAudio2BufferFlags.None; using (var stream = nbuffer.GetStream()) { stream.Write(_buffer, 0, read); } Debug.WriteLine(String.Format("Submit: {0};{1}", nbuffer.Flags, nbuffer.AudioBytes)); SubmitSourceBuffer(nbuffer); _currentBufferIndex++; _currentBufferIndex %= MaxBufferCount; } }
public void CanSubmitSourceBuffer() { const int lengthInSeconds = 2; using (var masteringVoice = _xaudio2.CreateMasteringVoice()) using (var sourceVoice = _xaudio2.CreateSourceVoice(_source.WaveFormat)) { byte[] rawBuffer = new byte[_source.WaveFormat.BytesPerSecond * lengthInSeconds]; int read = _source.Read(rawBuffer, 0, rawBuffer.Length); var buffer = new XAudio2Buffer(read); using (var stream = buffer.GetStream()) { stream.Write(rawBuffer, 0, read); } sourceVoice.SubmitSourceBuffer(buffer); sourceVoice.Start(); Thread.Sleep(lengthInSeconds * 1000 + 500); } }
public void CanRegisterSourceVoiceCallback() { const int lengthInSeconds = 2; bool b0 = false, b1 = false; var callback = new VoiceCallback(); using (var masteringVoice = _xaudio2.CreateMasteringVoice()) using (var sourceVoice = _xaudio2.CreateSourceVoice(_source.WaveFormat, VoiceFlags.None, CSCore.XAudio2.XAudio2.DefaultFrequencyRatio, callback, null, null)) { callback.BufferStart += (s,e) => b0 = true; callback.BufferEnd += (s,e) => b1 = true; byte[] rawBuffer = new byte[_source.WaveFormat.BytesPerSecond * lengthInSeconds]; int read = _source.Read(rawBuffer, 0, rawBuffer.Length); var buffer = new XAudio2Buffer(read); using (var stream = buffer.GetStream()) { stream.Write(rawBuffer, 0, read); } sourceVoice.SubmitSourceBuffer(buffer); sourceVoice.Start(); Thread.Sleep(lengthInSeconds * 1000 + 2000); Assert.IsTrue(b0, "No BufferStart."); Assert.IsTrue(b1, "No BufferEnd."); } }
public void CanRegisterEngineCallback() { const int lengthInSeconds = 2; bool b0 = false, b1 = false; XAudio2EngineCallback engineCallback = new XAudio2EngineCallback(); engineCallback.ProcessingPassStart += (s, e) => b0 = true; engineCallback.ProcessingPassEnd += (s, e) => b1 = true; _xaudio2.RegisterForCallbacks(engineCallback); using (var masteringVoice = _xaudio2.CreateMasteringVoice()) using (var sourceVoice = _xaudio2.CreateSourceVoice(_source.WaveFormat)) { byte[] rawBuffer = new byte[_source.WaveFormat.BytesPerSecond * lengthInSeconds]; int read = _source.Read(rawBuffer, 0, rawBuffer.Length); var buffer = new XAudio2Buffer(read); using (var stream = buffer.GetStream()) { stream.Write(rawBuffer, 0, read); } sourceVoice.SubmitSourceBuffer(buffer); sourceVoice.Start(); Thread.Sleep((lengthInSeconds * 1000 + 500) / 2); Assert.IsTrue(b0 || b1); Console.WriteLine("Unregistered"); _xaudio2.UnregisterForCallbacks(engineCallback); b0 = b1 = false; Thread.Sleep((lengthInSeconds * 1000 + 500) / 4); Assert.IsFalse(b0 && b1); Console.WriteLine("Register"); _xaudio2.RegisterForCallbacks(engineCallback); Thread.Sleep((lengthInSeconds * 1000 + 500) / 4); Assert.IsTrue(b0 || b1); } _xaudio2.UnregisterForCallbacks(engineCallback); }
/// <summary> /// Adds a new audio buffer to the voice queue. /// </summary> /// <param name="buffer"><see cref="XAudio2Buffer" /> structure to queue.</param> /// <remarks> /// See /// http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.ixaudio2sourcevoice.ixaudio2sourcevoice.submitsourcebuffer(v=vs.85).aspx. /// </remarks> public unsafe void SubmitSourceBuffer(XAudio2Buffer buffer) { XAudio2Exception.Try(SubmitSourceBufferNative(new IntPtr(&buffer), IntPtr.Zero), N, "SubmitSourceBuffer"); }