/// <summary> /// Sends a pseudo-random sample to replicate white noise. /// </summary> private void SendNoiseSample(object state) { lock (_audioStreamTimer) { int bufferSize = SAMPLE_RATE / 1000 * AUDIO_SAMPLE_PERIOD_MILLISECONDS; float[] linear = new float[bufferSize]; _signalGenerator.Read(linear, 0, bufferSize); byte[] encodedSample = new byte[bufferSize]; short[] pcm = linear.Select(x => (short)(x * 32767f)).ToArray(); if (_sendingFormat.FormatCodec == SDPMediaFormatsEnum.G722) { _g722Codec.Encode(_g722CodecState, encodedSample, pcm, bufferSize); } else { for (int index = 0; index < bufferSize; index++) { if (_sendingFormat.FormatCodec == SDPMediaFormatsEnum.PCMA) { encodedSample[index] = ALawEncoder.LinearToALawSample(pcm[index]); } else { encodedSample[index] = MuLawEncoder.LinearToMuLawSample(pcm[index]); } } } SendAudioFrame((uint)bufferSize, (int)_sendingFormat.FormatCodec, encodedSample); } }
public byte[] EncodeAudio(short[] pcm, AudioFormat format) { if (format.Codec == AudioCodecsEnum.G722) { if (_g722Codec == null) { _g722Codec = new G722Codec(); _g722CodecState = new G722CodecState(G722_BIT_RATE, G722Flags.None); } int outputBufferSize = pcm.Length / 2; byte[] encodedSample = new byte[outputBufferSize]; int res = _g722Codec.Encode(_g722CodecState, encodedSample, pcm, pcm.Length); return(encodedSample); } else if (format.Codec == AudioCodecsEnum.PCMA) { return(pcm.Select(x => ALawEncoder.LinearToALawSample(x)).ToArray()); } else if (format.Codec == AudioCodecsEnum.PCMU) { return(pcm.Select(x => MuLawEncoder.LinearToMuLawSample(x)).ToArray()); } else if (format.Codec == AudioCodecsEnum.L16) { // When netstandard2.1 can be used. //return MemoryMarshal.Cast<short, byte>(pcm) // Put on the wire in network byte order (big endian). return(pcm.SelectMany(x => new byte[] { (byte)(x >> 8), (byte)(x) }).ToArray()); } else if (format.Codec == AudioCodecsEnum.PCM_S16LE) { // Put on the wire as little endian. return(pcm.SelectMany(x => new byte[] { (byte)(x), (byte)(x >> 8) }).ToArray()); } else { throw new ApplicationException($"Audio format {format.Codec} cannot be encoded."); } }
/// <summary> /// Event handler for audio sample being supplied by local capture device. /// </summary> private void LocalAudioSampleAvailable(object sender, WaveInEventArgs args) { byte[] sample = new byte[args.Buffer.Length / 2]; int sampleIndex = 0; if (_sendingAudioFormat.FormatCodec == SDPMediaFormatsEnum.PCMA || _sendingAudioFormat.FormatCodec == SDPMediaFormatsEnum.PCMU) { for (int index = 0; index < args.BytesRecorded; index += 2) { if (_sendingAudioFormat.FormatCodec == SDPMediaFormatsEnum.PCMU) { var ulawByte = NAudio.Codecs.MuLawEncoder.LinearToMuLawSample(BitConverter.ToInt16(args.Buffer, index)); sample[sampleIndex++] = ulawByte; } else if (_sendingAudioFormat.FormatCodec == SDPMediaFormatsEnum.PCMA) { var alawByte = NAudio.Codecs.ALawEncoder.LinearToALawSample(BitConverter.ToInt16(args.Buffer, index)); sample[sampleIndex++] = alawByte; } } base.SendAudioFrame(_rtpAudioTimestampPeriod, Convert.ToInt32(_sendingAudioFormat.FormatID), sample); } else if (_sendingAudioFormat.FormatCodec == SDPMediaFormatsEnum.G722) { // NAudio provides 16 Bit PCM little endian samples. Each sample consists of two bytes. short[] inBuffer = new short[args.Buffer.Length / 2]; for (int index = 0; index < args.BytesRecorded; index += 2) { inBuffer[sampleIndex++] = BitConverter.ToInt16(args.Buffer, index); } byte[] outBuffer = new byte[inBuffer.Length / 2]; int encodedSamples = _g722Encode.Encode(_g722EncodeState, outBuffer, inBuffer, inBuffer.Length); //Log.LogDebug($"g722 encode input samples {args.Buffer.Length}, encoded samples {encodedSamples}, output buffer length {outBuffer.Length}."); base.SendAudioFrame(_rtpAudioTimestampPeriod, Convert.ToInt32(_sendingAudioFormat.FormatID), outBuffer); } }
/// <summary> /// Encodes a 16 bit PCM sample and sends to the remote party. /// </summary> /// <param name="sample">The PCM 16 bit *=8KHz sample to send.</param> /// <param name="sampleLength">The length of the sample</param> /// <param name="sampleRate">The sample rate of either 8 or 16 KHz for the supplied sample.</param> private void EncodeAndSendAudioSample(byte[] sample, int sampleLength, AudioSamplingRatesEnum sampleRate) { byte[] encodedSample = null; // Convert buffer into a PCM sample (array of signed shorts) that's // suitable for input into the chosen encoder. short[] pcm = new short[sampleLength / 2]; for (int i = 0; i < pcm.Length; i++) { pcm[i] = BitConverter.ToInt16(sample, i * 2); } if (_sendingFormat.FormatCodec == SDPMediaFormatsEnum.G722) { if (sampleRate == AudioSamplingRatesEnum.SampleRate16KHz) { // No up sampling required. int outputBufferSize = pcm.Length / 2; encodedSample = new byte[outputBufferSize]; int res = _g722Codec.Encode(_g722CodecState, encodedSample, pcm, pcm.Length); } else { // Up sample the supplied PCM signal by doubling each sample. int outputBufferSize = pcm.Length; encodedSample = new byte[outputBufferSize]; short[] pcmUpsampled = new short[pcm.Length * 2]; for (int i = 0; i < pcm.Length; i++) { pcmUpsampled[i * 2] = pcm[i]; pcmUpsampled[i * 2 + 1] = pcm[i]; } _g722Codec.Encode(_g722CodecState, encodedSample, pcmUpsampled, pcmUpsampled.Length); } } else { Func <short, byte> encode = (_sendingFormat.FormatCodec == SDPMediaFormatsEnum.PCMA) ? (Func <short, byte>)ALawEncoder.LinearToALawSample : MuLawEncoder.LinearToMuLawSample; if (sampleRate == AudioSamplingRatesEnum.SampleRate8KHz) { // No down sampling required. int outputBufferSize = pcm.Length; encodedSample = new byte[outputBufferSize]; for (int index = 0; index < pcm.Length; index++) { encodedSample[index] = encode(pcm[index]); } } else { // Down sample the supplied PCM signal by skipping every second sample. int outputBufferSize = pcm.Length / 2; encodedSample = new byte[outputBufferSize]; int encodedIndex = 0; // Skip every second sample. for (int index = 0; index < pcm.Length; index += 2) { encodedSample[encodedIndex++] = encode(pcm[index]); } } } int sampleRateTicks = (sampleRate == AudioSamplingRatesEnum.SampleRate8KHz) ? 8000 : 16000; int durationMilliseconds = (sample.Length * 1000) / (sampleRateTicks * 2); int rtpTimestampDuration = _sendingAudioRtpRate / 1000 * durationMilliseconds; //Log.LogDebug($"send audio frame sample rate {sampleRateTicks}, duration ms {durationMilliseconds}, rtp timestamp duration {rtpTimestampDuration}."); SendAudioFrame((uint)rtpTimestampDuration, (int)_sendingFormat.FormatCodec, encodedSample); }
public byte[] EncodeAudio(short[] pcm, AudioCodecsEnum codec, AudioSamplingRatesEnum sampleRate) { byte[] encodedSample = null; if (codec == AudioCodecsEnum.G722) { if (_g722Codec == null) { _g722Codec = new G722Codec(); _g722CodecState = new G722CodecState(G722_BIT_RATE, G722Flags.None); } if (sampleRate == AudioSamplingRatesEnum.Rate16KHz) { // No up sampling required. int outputBufferSize = pcm.Length / 2; encodedSample = new byte[outputBufferSize]; int res = _g722Codec.Encode(_g722CodecState, encodedSample, pcm, pcm.Length); } else { // Up sample the supplied PCM signal by doubling each sample. int outputBufferSize = pcm.Length; encodedSample = new byte[outputBufferSize]; short[] pcmUpsampled = new short[pcm.Length * 2]; for (int i = 0; i < pcm.Length; i++) { pcmUpsampled[i * 2] = pcm[i]; pcmUpsampled[i * 2 + 1] = pcm[i]; } _g722Codec.Encode(_g722CodecState, encodedSample, pcmUpsampled, pcmUpsampled.Length); } return(encodedSample); } else if (codec == AudioCodecsEnum.PCMA || codec == AudioCodecsEnum.PCMU) { Func <short, byte> encode = (codec == AudioCodecsEnum.PCMA) ? (Func <short, byte>)ALawEncoder.LinearToALawSample : MuLawEncoder.LinearToMuLawSample; if (sampleRate == AudioSamplingRatesEnum.Rate8KHz) { // No down sampling required. int outputBufferSize = pcm.Length; encodedSample = new byte[outputBufferSize]; for (int index = 0; index < pcm.Length; index++) { encodedSample[index] = encode(pcm[index]); } } else { // Down sample the supplied PCM signal by skipping every second sample. int outputBufferSize = pcm.Length / 2; encodedSample = new byte[outputBufferSize]; int encodedIndex = 0; // Skip every second sample. for (int index = 0; index < pcm.Length; index += 2) { encodedSample[encodedIndex++] = encode(pcm[index]); } } return(encodedSample); } else { throw new ApplicationException($"Audio format {codec} cannot be encoded."); } }