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