Click here to Skip to main content
15,896,111 members
Articles / Web Development / ASP.NET

Your First Step to the Silverlight Voice/Video Chatting Client/Server

Rate me:
Please Sign up or sign in to vote.
4.85/5 (44 votes)
15 Dec 2013CPOL5 min read 343.6K   22.6K   188  
What you should to do to create your own Silverlight Voice/Video chatting system
using System;
using System.Collections.Generic;
using System.Text;

namespace VoiceEncoder
{
    #region G.711 Encoder Classes

    namespace G711Audio
    {
        /// <summary>
        /// Turns 16-bit linear PCM values into 8-bit A-law bytes.
        /// </summary>
        public class ALawEncoder
        {
            public const int MAX = 0x7fff; //maximum that can be held in 15 bits

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

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

            /// <summary>
            /// Encode one a-law byte from a 16-bit signed integer. protected use only.
            /// </summary>
            /// <param name="pcm">A 16-bit signed pcm value</param>
            /// <returns>A a-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 fit in 15 bits to avoid overflow
                if (pcm > MAX) pcm = MAX;

                /* 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 0 0 0 0 0 0 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)
                 * The exponent is 0 if the 1 is not found in bits 2 through 8.
                 * This means the exponent is 0 even if the "first 1" doesn't exist.
                 */
                int exponent = 7;
                //Move to the right and decrement exponent until we hit the 1 or the exponent hits 0
                for (int expMask = 0x4000; (pcm & expMask) == 0 && exponent > 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 . . . . . . . . . (say that 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. 
                 * 
                 * NOTE: If the exponent is 0:
                 * 1 2 3 4 5 6 7 8 9 A B C D E F G
                 * S 0 0 0 0 0 0 0 Z Y X W V U T S (we know nothing about bit 9)
                 * . . . . . . . . . . . . 1 1 1 1
                 * We want to get ZYXW, which means a shift of 4 instead of 3
                 */
                int mantissa = (pcm >> ((exponent == 0) ? 4 : (exponent + 3))) & 0x0f;

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

                //Last is to flip every other bit, and the sign bit (0xD5 = 1101 0101)
                return (byte)(alaw ^ 0xD5);
            }

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

            /// <summary>
            /// Encode a pcm value into a a-law byte
            /// </summary>
            /// <param name="pcm">A 16-bit pcm value</param>
            /// <returns>A a-law encoded byte</returns>
            public static byte ALawEncode(short pcm)
            {
                return pcmToALawMap[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 a-law bytes containing the results</returns>
            public static byte[] ALawEncode(int[] data)
            {
                int size = data.Length;
                byte[] encoded = new byte[size];
                for (int i = 0; i < size; i++)
                    encoded[i] = ALawEncode(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 a-law bytes containing the results</returns>
            public static byte[] ALawEncode(short[] data)
            {
                int size = data.Length;
                byte[] encoded = new byte[size];
                for (int i = 0; i < size; i++)
                    encoded[i] = ALawEncode(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 a-law bytes containing the results</returns>
            public static byte[] ALawEncode(byte[] data)
            {
                int size = data.Length / 2;
                byte[] encoded = new byte[size];
                for (int i = 0; i < size; i++)
                    encoded[i] = ALawEncode((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 A-law bytes.  This array must be at least half the size of the source.</param>
            public static void ALawEncode(byte[] data, byte[] target)
            {
                int size = data.Length / 2;
                for (int i = 0; i < size; i++)
                    target[i] = ALawEncode((data[2 * i + 1] << 8) | data[2 * i]);
            }
        }


        /// <summary>
        /// Turns 8-bit A-law bytes back into 16-bit PCM values.
        /// </summary>
        public static class ALawDecoder
        {
            /// <summary>
            /// An array where the index is the a-law input, and the value is
            /// the 16-bit PCM result.
            /// </summary>
            private static short[] aLawToPcmMap;

            static ALawDecoder()
            {
                aLawToPcmMap = new short[256];
                for (byte i = 0; i < byte.MaxValue; i++)
                    aLawToPcmMap[i] = decode(i);
            }

            /// <summary>
            /// Decode one a-law byte. For protected use only.
            /// </summary>
            /// <param name="alaw">The encoded a-law byte</param>
            /// <returns>A short containing the 16-bit result</returns>
            private static short decode(byte alaw)
            {
                //Invert every other bit, and the sign bit (0xD5 = 1101 0101)
                alaw ^= 0xD5;

                //Pull out the value of the sign bit
                int sign = alaw & 0x80;
                //Pull out and shift over the value of the exponent
                int exponent = (alaw & 0x70) >> 4;
                //Pull out the four bits of data
                int data = alaw & 0x0f;

                //Shift the data four bits to the left
                data <<= 4;
                //Add 8 to put the result in the middle of the range (like adding a half)
                data += 8;

                //If the exponent is not 0, then we know the four bits followed a 1,
                //and can thus add this implicit 1 with 0x100.
                if (exponent != 0)
                    data += 0x100;
                /* Shift the bits to where they need to be: left (exponent - 1) places
                 * Why (exponent - 1) ?
                 * 1 2 3 4 5 6 7 8 9 A B C D E F G
                 * . 7 6 5 4 3 2 1 . . . . . . . . <-- starting bit (based on exponent)
                 * . . . . . . . Z x x x x 1 0 0 0 <-- our data (Z is 0 only when exponent is 0)
                 * We need to move the one under the value of the exponent,
                 * which means it must move (exponent - 1) times
                 * It also means shifting is unnecessary if exponent is 0 or 1.
                 */
                if (exponent > 1)
                    data <<= (exponent - 1);

                return (short)(sign == 0 ? data : -data);
            }

            /// <summary>
            /// Decode one a-law byte
            /// </summary>
            /// <param name="alaw">The encoded a-law byte</param>
            /// <returns>A short containing the 16-bit result</returns>
            public static short ALawDecode(byte alaw)
            {
                return aLawToPcmMap[alaw];
            }

            /// <summary>
            /// Decode an array of a-law encoded bytes
            /// </summary>
            /// <param name="data">An array of a-law encoded bytes</param>
            /// <returns>An array of shorts containing the results</returns>
            public static short[] ALawDecode(byte[] data)
            {
                int size = data.Length;
                short[] decoded = new short[size];
                for (int i = 0; i < size; i++)
                    decoded[i] = aLawToPcmMap[data[i]];
                return decoded;
            }

            /// <summary>
            /// Decode an array of a-law encoded bytes
            /// </summary>
            /// <param name="data">An array of a-law encoded bytes</param>
            /// <param name="decoded">An array of shorts containing the results</param>
            /// <remarks>Same as the other method that returns an array of shorts</remarks>
            public static void ALawDecode(byte[] data, out short[] decoded)
            {
                int size = data.Length;
                decoded = new short[size];
                for (int i = 0; i < size; i++)
                    decoded[i] = aLawToPcmMap[data[i]];
            }

            /// <summary>
            /// Decode an array of a-law encoded bytes
            /// </summary>
            /// <param name="data">An array of a-law encoded bytes</param>
            /// <param name="decoded">An array of bytes in Little-Endian format containing the results</param>
            public static void ALawDecode(byte[] data, out byte[] decoded)
            {
                int size = data.Length;
                decoded = new byte[size * 2];
                for (int i = 0; i < size; i++)
                {
                    //First byte is the less significant byte
                    decoded[2 * i] = (byte)(aLawToPcmMap[data[i]] & 0xff);
                    //Second byte is the more significant byte
                    decoded[2 * i + 1] = (byte)(aLawToPcmMap[data[i]] >> 8);
                }
            }
        }
    }
    #endregion G.711 Encoding
}

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
Systems Engineer SocketCoder.Com
Jordan Jordan
Fadi Abdelqader
WebSite: http://www.SocketCoder.com
Facebook Group: http://www.facebook.com/groups/socketcoder/
Facebook Page: http://www.facebook.com/socketcoders/

Last Published Book:
-Professional Network, Distributed Systems & TCP/IP Programming In .NET Framework 1.1 & 2.0 (2006 Release)

Last Published eBook:
- The SocketCoder e-Reference For Network, Distributed Systems And TCP/IP Programming In .NET, Arabic (SocketCoder.Com 2010)

Last Projects:
- Silverlight Based Projects For Web Video Conferencing (WCS,WMS,WCS Plus..)
-(SocketCoder) RTP Multicasting VOIP Library
-(SocketCoder) Remote Controlling Systems

Last SocketCoder RSS: http://www.socketcoder.com/feed/

http://www.socketcoder.com

Comments and Discussions