Click here to Skip to main content
15,896,606 members
Articles / Programming Languages / C#

A Voice Chat Application in C#

Rate me:
Please Sign up or sign in to vote.
4.38/5 (64 votes)
5 Jul 2007CPOL2 min read 721.6K   43K   248  
In this article I will discuss a simple voice chat application. We will grab the audio from the microphone using DirectSound and transmit it in UDP packets.
using System;
using System.Collections.Generic;
using System.Text;

namespace g711audio
{
    /// <summary>
    /// Turns 16-bit linear PCM values into 8-bit �-law bytes.
    /// </summary>
    public class MuLawEncoder
    {
        public const int BIAS = 0x84; //aka 132, or 1000 0100
        public const int MAX = 32635; //32767 (max 15-bit integer) minus BIAS

        /// <summary>
        /// Sets whether or not all-zero bytes are encoded as 2 instead.
        /// The pcm values this concerns are in the range [32768,33924] (unsigned).
        /// </summary>
        public bool ZeroTrap
        {
            get { return (pcmToMuLawMap[33000] != 0); }
            set
            {
                byte val = (byte)(value ? 2 : 0);
                for (int i = 32768; i <= 33924; i++)
                    pcmToMuLawMap[i] = val;
            }
        }

        /// <summary>
        /// An array where the index is the 16-bit PCM input, and the value is
        /// the mu-law result.
        /// </summary>
        private static byte[] pcmToMuLawMap;

        static MuLawEncoder()
        {
            pcmToMuLawMap = new byte[65536];
            for (int i = short.MinValue; i <= short.MaxValue; i++)
                pcmToMuLawMap[(i & 0xffff)] = encode(i);
        }

        /// <summary>
        /// Encode one mu-law byte from a 16-bit signed integer. Internal use only.
        /// </summary>
        /// <param name="pcm">A 16-bit signed pcm value</param>
        /// <returns>A mu-law encoded byte</returns>
        private static byte encode(int pcm)
        {
            //Get the sign bit.  Shift it for later use without further modification
            int sign = (pcm & 0x8000) >> 8;
            //If the number is negative, make it positive (now it's a magnitude)
            if (sign != 0)
                pcm = -pcm;
            //The magnitude must be less than 32635 to avoid overflow
            if (pcm > MAX) pcm = MAX;
            //Add 132 to guarantee a 1 in the eight bits after the sign bit
            pcm += BIAS;

            /* Finding the "exponent"
             * Bits:
             * 1 2 3 4 5 6 7 8 9 A B C D E F G
             * S 7 6 5 4 3 2 1 0 . . . . . . .
             * We want to find where the first 1 after the sign bit is.
             * We take the corresponding value from the second row as the exponent value.
             * (i.e. if first 1 at position 7 -> exponent = 2) */
            int exponent = 7;
            //Move to the right and decrement exponent until we hit the 1
            for (int expMask = 0x4000; (pcm & expMask) == 0; exponent--, expMask >>= 1) { }

            /* The last part - the "mantissa"
             * We need to take the four bits after the 1 we just found.
             * To get it, we shift 0x0f :
             * 1 2 3 4 5 6 7 8 9 A B C D E F G
             * S 0 0 0 0 0 1 . . . . . . . . . (meaning exponent is 2)
             * . . . . . . . . . . . . 1 1 1 1
             * We shift it 5 times for an exponent of two, meaning
             * we will shift our four bits (exponent + 3) bits.
             * For convenience, we will actually just shift the number, then and with 0x0f. */
            int mantissa = (pcm >> (exponent + 3)) & 0x0f;

            //The mu-law byte bit arrangement is SEEEMMMM (Sign, Exponent, and Mantissa.)
            byte mulaw = (byte)(sign | exponent << 4 | mantissa);

            //Last is to flip the bits
            return (byte)~mulaw;
        }

        /// <summary>
        /// Encode a pcm value into a mu-law byte
        /// </summary>
        /// <param name="pcm">A 16-bit pcm value</param>
        /// <returns>A mu-law encoded byte</returns>
        public static byte MuLawEncode(int pcm)
        {
            return pcmToMuLawMap[pcm & 0xffff];
        }

        /// <summary>
        /// Encode a pcm value into a mu-law byte
        /// </summary>
        /// <param name="pcm">A 16-bit pcm value</param>
        /// <returns>A mu-law encoded byte</returns>
        public static byte MuLawEncode(short pcm)
        {
            return pcmToMuLawMap[pcm & 0xffff];
        }

        /// <summary>
        /// Encode an array of pcm values
        /// </summary>
        /// <param name="data">An array of 16-bit pcm values</param>
        /// <returns>An array of mu-law bytes containing the results</returns>
        public static byte[] MuLawEncode(int[] data)
        {
            int size = data.Length;
            byte[] encoded = new byte[size];
            for (int i = 0; i < size; i++)
                encoded[i] = MuLawEncode(data[i]);
            return encoded;
        }

        /// <summary>
        /// Encode an array of pcm values
        /// </summary>
        /// <param name="data">An array of 16-bit pcm values</param>
        /// <returns>An array of mu-law bytes containing the results</returns>
        public static byte[] MuLawEncode(short[] data)
        {
            int size = data.Length;
            byte[] encoded = new byte[size];
            for (int i = 0; i < size; i++)
                encoded[i] = MuLawEncode(data[i]);
            return encoded;
        }

        /// <summary>
        /// Encode an array of pcm values
        /// </summary>
        /// <param name="data">An array of bytes in Little-Endian format</param>
        /// <returns>An array of mu-law bytes containing the results</returns>
        public static byte[] MuLawEncode(byte[] data)
        {
            int size = data.Length / 2;
            byte[] encoded = new byte[size];
            for (int i = 0; i < size; i++)
                encoded[i] = MuLawEncode((data[2 * i + 1] << 8) | data[2 * i]);
            return encoded;
        }

        /// <summary>
        /// Encode an array of pcm values into a pre-allocated target array
        /// </summary>
        /// <param name="data">An array of bytes in Little-Endian format</param>
        /// <param name="target">A pre-allocated array to receive the mu-law bytes.  This array must be at least half the size of the source.</param>
        public static void MuLawEncode(byte[] data, byte[] target)
        {
            int size = data.Length / 2;
            for (int i = 0; i < size; i++)
                target[i] = MuLawEncode((data[2 * i + 1] << 8) | data[2 * i]);
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions