public PlayAudio(VoiceService voices, int frameSize, RemoteVoice user) { Voices = voices; User = user; CallbackHandler = new WinMM.WaveDelegate(WaveCallback); FrameSize = frameSize; int sampleRate = 0; // if 20ms, at high quality (16khz) is 320 samples at 2 bytes each if (FrameSize == 320) { sampleRate = 16000; BufferSize = 320 * 2 * 2; // 2 bytes each frame, 2 channels SpeexMode = Speex.SPEEX_MODEID_WB; } else if (FrameSize == 160) { sampleRate = 8000; BufferSize = 160 * 2 * 2; SpeexMode = Speex.SPEEX_MODEID_NB; } else { Dispose(); return; } try { // init speex Speex.speex_bits_init(ref DecodeBits); IntPtr modePtr = Speex.speex_lib_get_mode(SpeexMode); SpeexDecoder = Speex.speex_decoder_init(modePtr); int tmp = 1; Speex.speex_decoder_ctl(SpeexDecoder, Speex.SPEEX_SET_ENH, ref tmp); // init wave Format = new WinMM.WaveFormat(sampleRate, 16, 2); WinMM.ErrorCheck(WinMM.waveOutOpen(out WaveHandle, Voices.PlaybackDevice, Format, CallbackHandler, 0, WinMM.CALLBACK_FUNCTION)); for (int i = 0; i < BufferCount; i++) { Buffers[i] = new PlayBuffer(i, WaveHandle, BufferSize); } } catch (Exception ex) { Dispose(); Voices.Core.Network.UpdateLog("Voice", "Error starting playing: " + ex.Message); } }
public void Dispose() { if (HeaderHandle.IsAllocated) { WinMM.ErrorCheck(WinMM.waveOutUnprepareHeader(WaveHandle, ref Header, Marshal.SizeOf(Header))); HeaderHandle.Free(); } if (DataHandle.IsAllocated) { DataHandle.Free(); } }
public PlayBuffer(int index, IntPtr handle, int size) { WaveHandle = handle; HeaderHandle = GCHandle.Alloc(Header, GCHandleType.Pinned); Data = new byte[size]; DataHandle = GCHandle.Alloc(Data, GCHandleType.Pinned); DataPtr = DataHandle.AddrOfPinnedObject(); //Header.dwUser = new IntPtr(index); //(IntPtr)GCHandle.Alloc(this); Header.lpData = DataHandle.AddrOfPinnedObject(); Header.dwBufferLength = size; WinMM.ErrorCheck(WinMM.waveOutPrepareHeader(WaveHandle, ref Header, Marshal.SizeOf(Header))); }
//public IntPtr EchoState; public RecordAudio(VoiceService voices) { Voices = voices; CallbackHandler = new WinMM.WaveDelegate(WaveCallback); // if 20ms, at high quality (16khz) is 320 samples at 2 bytes each if (HighQuality) { SampleRate = 16000; BufferSize = 320 * 2; SpeexMode = Speex.SPEEX_MODEID_WB; } else { SampleRate = 8000; BufferSize = 160 * 2; SpeexMode = Speex.SPEEX_MODEID_NB; } //LastBuffer = new byte[BufferSize]; try { InitSpeexEncoder(); Format = new WinMM.WaveFormat(SampleRate, 16, 1); WinMM.ErrorCheck(WinMM.waveInOpen(out WaveHandle, Voices.RecordingDevice, Format, CallbackHandler, 0, WinMM.CALLBACK_FUNCTION)); for (int i = 0; i < BufferCount; i++) { Buffers[i] = new RecordBuffer(i, WaveHandle, BufferSize); } WinMM.ErrorCheck(WinMM.waveInStart(WaveHandle)); } catch (Exception ex) { Dispose(); Voices.Core.Network.UpdateLog("Voice", "Error starting recording: " + ex.Message); } }
public void Dispose() { try { WinMM.ErrorCheck(WinMM.waveOutReset(WaveHandle)); // free buffers foreach (PlayBuffer buffer in Buffers) { buffer.Dispose(); } Buffers = null; // free speex Speex.speex_bits_destroy(ref DecodeBits); Speex.speex_decoder_destroy(SpeexDecoder); WinMM.ErrorCheck(WinMM.waveOutClose(WaveHandle)); } catch (Exception ex) { Voices.Core.Network.UpdateLog("Voice", "Error Disposing Player: " + ex.Message); } // remove wave out stream from user structure foreach (ulong routing in User.Streams.Keys) { if (User.Streams[routing] == this) { User.Streams.Remove(routing); break; } } Voices.Players.SafeRemove(this); }
public void ProcessBuffers() { try { while (FilledBuffers < BufferCount) { byte[] data = null; lock (AudioQueue) // either gets called from core, or system thread { if (AudioQueue.Count == 0) { return; } data = AudioQueue.Dequeue(); } // keep a log of received audio that user can back track through lock (History) { History.Enqueue(data); while (History.Count > HistoryLength) { History.Dequeue(); } } // decode Speex.speex_bits_reset(ref DecodeBits); Speex.speex_bits_read_from(ref DecodeBits, data, data.Length); byte[] mono = new byte[FrameSize * 2]; int success = Speex.speex_decode_int(SpeexDecoder, ref DecodeBits, mono); if (success != 0) { continue; } // cancel echo //if (Voices.Recorder != null && FrameSize == Voices.Recorder.FrameSize) // Speex.speex_echo_playback(Voices.Recorder.EchoState, mono); // get volume short maxVolume = 0; for (int i = 0; i < mono.Length / 2; i++) { short val = BitConverter.ToInt16(mono, i * 2); if (val > maxVolume) { maxVolume = val; } } if (maxVolume > User.VolumeIn) { User.VolumeIn = maxVolume; } // find out where audio should come out from, if at all // return down here so that even if user not listening, window shows volume bar AudioDirection direction = User.GetDirection(); if (direction == AudioDirection.None) { continue; } // shifting to one side PlayBuffer buffer = Buffers[NextBuffer]; for (int i = 0; i < mono.Length / 2; i++) { switch (direction) { case AudioDirection.Both: Buffer.BlockCopy(mono, i * 2, buffer.Data, i * 4, 2); // left Buffer.BlockCopy(mono, i * 2, buffer.Data, i * 4 + 2, 2); // right break; case AudioDirection.Left: Buffer.BlockCopy(mono, i * 2, buffer.Data, i * 4, 2); // left break; case AudioDirection.Right: Buffer.BlockCopy(mono, i * 2, buffer.Data, i * 4 + 2, 2); // right break; } } WinMM.ErrorCheck(WinMM.waveOutWrite(WaveHandle, ref buffer.Header, Marshal.SizeOf(buffer.Header))); FilledBuffers++; NextBuffer++; if (NextBuffer >= BufferCount) { NextBuffer = 0; } } } catch (Exception ex) { Voices.Core.RunInCoreAsync(() => { Dispose(); Voices.Core.Network.UpdateLog("Voice", "Error filling buffers: " + ex.Message); }); } }
public void ProcessBuffers() { try { while (AddedBuffers < BufferCount) { RecordBuffer buffer = Buffers[NextBuffer]; if (buffer.Added) { EncodeAudio(buffer); } /*if (!EncodeAudio(buffer) && LastBufferSet) * { * // no data sent - send last buffer so that audio doesnt snap, but fades out * // reverse - so waves match up * byte[] frame = new byte[2]; * int backpos = 0; * for (int i = 0; i < FrameSize / 2; i++) * { * backpos = LastBuffer.Length - 2 - i * 2; * Buffer.BlockCopy(LastBuffer, i * 2, frame, 0, 2); // front to temp * Buffer.BlockCopy(LastBuffer, backpos, LastBuffer, i * 2, 2); // back to front * Buffer.BlockCopy(frame, 0, LastBuffer, backpos, 2); // temp to back * } * * // fade so no sharp end to the sound * for (int i = 0; i < FrameSize; i++) * { * short value = BitConverter.ToInt16(LastBuffer, i * 2); * value = (short) (value * (FrameSize - i) / FrameSize); * BitConverter.GetBytes(value).CopyTo(LastBuffer, i * 2); * } * * LastBuffer.CopyTo(buffer.Data, 0); * * int tmp = 0; * Speex.speex_encoder_ctl(SpeexEncoder, Speex.SPEEX_SET_VAD, ref tmp); * Speex.speex_encoder_ctl(SpeexEncoder, Speex.SPEEX_SET_DTX, ref tmp); * * //EncodeAudio(buffer); * * tmp = 1; * Speex.speex_encoder_ctl(SpeexEncoder, Speex.SPEEX_SET_VAD, ref tmp); * Speex.speex_encoder_ctl(SpeexEncoder, Speex.SPEEX_SET_DTX, ref tmp); * * * LastBufferSet = false; * }*/ WinMM.ErrorCheck(WinMM.waveInAddBuffer(WaveHandle, ref buffer.Header, Marshal.SizeOf(buffer.Header))); buffer.Added = true; NextBuffer++; if (NextBuffer >= BufferCount) { NextBuffer = 0; } AddedBuffers++; } } catch (Exception ex) { Debug.Assert(false); Voices.Core.RunInCoreAsync(() => { Voices.Core.Network.UpdateLog("Voice", "Error in record thread: " + ex.Message); Dispose(); }); } }
public void WaveCallback(IntPtr hdrvr, int uMsg, int dwUser, ref WinMM.WaveHdr wavhdr, int dwParam2) { if (uMsg == WinMM.MM_WIM_DATA) { // use dwUser parameter of header to keep buffers in sync? // doesnt seem like buffers are getting out of sync at all AddedBuffers--; Voices.AudioEvent.Set(); } }
public void WaveCallback(IntPtr hdrvr, int uMsg, int dwUser, ref WinMM.WaveHdr wavhdr, int dwParam2) { if (uMsg == WinMM.MM_WOM_DONE) { FilledBuffers--; Voices.AudioEvent.Set(); } }