Click here to Skip to main content
15,895,808 members
Articles / Programming Languages / C#

Sending and playing microphone audio over network

Rate me:
Please Sign up or sign in to vote.
4.92/5 (65 votes)
3 Aug 20072 min read 524.6K   42.9K   336  
Sending and playing microphone audio over network
using System;
using System.Collections.Generic;
using System.Text;

namespace LumiSoft.Net.RTP
{
    /// <summary>
    /// This class implements RTCP SDES packet 1 "chunk". 
    /// </summary>
    public class RTCP_Packet_SDES_Chunk
    {
        private uint   m_Source   = 0;
        private string m_CName    = null;
        private string m_Name     = null;
        private string m_Email    = null;
        private string m_Phone    = null;
        private string m_Location = null;
        private string m_Tool     = null;
        private string m_Note     = null;

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="source">SSRC or CSRC identifier.</param>
        /// <param name="cname">Canonical End-Point Identifier.</param>
        /// <exception cref="ArgumentException">Is raised when invalid value is passed.</exception>
        public RTCP_Packet_SDES_Chunk(uint source,string cname)
        {
            if(source == 0){
                throw new ArgumentException("Argument 'source' value must be > 0.");
            }
            if(string.IsNullOrEmpty(cname)){
                throw new ArgumentException("Argument 'cname' value may not be null or empty.");
            }

            m_Source = source;
            m_CName  = cname;
        }

        /// <summary>
        /// Parser constructor.
        /// </summary>
        internal RTCP_Packet_SDES_Chunk()
        {
        }


        #region method Parse

        /// <summary>
        /// Parses SDES chunk from the specified buffer.
        /// </summary>
        /// <param name="buffer">Buffer which contains SDES chunk.</param>
        /// <param name="offset">Offset in buffer.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>buffer</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public void Parse(byte[] buffer,ref int offset)
        {
            if(buffer == null){
                throw new ArgumentNullException("buffer");
            }
            if(offset < 0){
                throw new ArgumentException("Argument 'offset' value must be >= 0.");
            }
                        
            // Read SSRC/CSRC
            m_Source = (uint)(buffer[offset++] << 24 | buffer[offset++] << 16 | buffer[offset++] << 8 | buffer[offset++]);

            // Read SDES items while reach end of buffer or we get chunk terminator(\0).
            while(offset < buffer.Length && buffer[offset] != 0){
                int type   = buffer[offset++];
                int length = buffer[offset++];

                // CNAME
                if(type == 1){
                    m_CName = Encoding.UTF8.GetString(buffer,offset,length);
                }
                // NAME
                else if(type == 2){
                    m_Name = Encoding.UTF8.GetString(buffer,offset,length);
                }
                // EMAIL
                else if(type == 3){
                    m_Email = Encoding.UTF8.GetString(buffer,offset,length);
                }
                // PHONE
                else if(type == 4){
                    m_Phone = Encoding.UTF8.GetString(buffer,offset,length);
                }
                // LOC
                else if(type == 5){
                    m_Location = Encoding.UTF8.GetString(buffer,offset,length);
                }
                // TOOL
                else if(type == 6){
                    m_Tool = Encoding.UTF8.GetString(buffer,offset,length);
                }
                // NOTE
                else if(type == 7){
                    m_Note = Encoding.UTF8.GetString(buffer,offset,length);
                }
                // PRIV
                else if(type == 8){
                    // TODO:
                }
                offset += length;
            }
        }

        #endregion

        #region method ToByte

        /// <summary>
        /// Stores SDES junk to the specified buffer.
        /// </summary>
        /// <param name="buffer">Buffer where to store data.</param>
        /// <param name="offset">Offset in buffer.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>buffer</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public void ToByte(byte[] buffer,ref int offset)
        {
            if(buffer == null){
                throw new ArgumentNullException("buffer");
            }
            if(offset < 0){
                throw new ArgumentException("Argument 'offset' value must be >= 0.");
            }

            int startOffset = offset;

            // SSRC/SDES
            buffer[offset++] = (byte)((m_Source >> 24) | 0xFF);
            buffer[offset++] = (byte)((m_Source >> 16) | 0xFF);
            buffer[offset++] = (byte)((m_Source >>  8) | 0xFF);
            buffer[offset++] = (byte)((m_Source)       | 0xFF);

            //--- SDES items -----------------------------------
            if(!string.IsNullOrEmpty(m_CName)){
                byte[] b = Encoding.UTF8.GetBytes(m_CName);
                buffer[offset++] = 1;
                buffer[offset++] = (byte)b.Length;
                Array.Copy(b,0,buffer,offset,b.Length);
                offset += b.Length;
            }
            if(!string.IsNullOrEmpty(m_Name)){
                byte[] b = Encoding.UTF8.GetBytes(m_Name);
                buffer[offset++] = 2;
                buffer[offset++] = (byte)b.Length;
                Array.Copy(b,0,buffer,offset,b.Length);
                offset += b.Length;
            }
            if(!string.IsNullOrEmpty(m_Email)){
                byte[] b = Encoding.UTF8.GetBytes(m_Email);
                buffer[offset++] = 3;
                buffer[offset++] = (byte)b.Length;
                Array.Copy(b,0,buffer,offset,b.Length);
                offset += b.Length;
            }
            if(!string.IsNullOrEmpty(m_Phone)){
                byte[] b = Encoding.UTF8.GetBytes(m_Phone);
                buffer[offset++] = 4;
                buffer[offset++] = (byte)b.Length;
                Array.Copy(b,0,buffer,offset,b.Length);
                offset += b.Length;
            }
            if(!string.IsNullOrEmpty(m_Location)){
                byte[] b = Encoding.UTF8.GetBytes(m_Location);
                buffer[offset++] = 5;
                buffer[offset++] = (byte)b.Length;
                Array.Copy(b,0,buffer,offset,b.Length);
                offset += b.Length;
            }
            if(!string.IsNullOrEmpty(m_Tool)){
                byte[] b = Encoding.UTF8.GetBytes(m_Tool);
                buffer[offset++] = 6;
                buffer[offset++] = (byte)b.Length;
                Array.Copy(b,0,buffer,offset,b.Length);
                offset += b.Length;
            }
            if(!string.IsNullOrEmpty(m_Note)){
                byte[] b = Encoding.UTF8.GetBytes(m_Tool);
                buffer[offset++] = 7;
                buffer[offset++] = (byte)b.Length;
                Array.Copy(b,0,buffer,offset,b.Length);
                offset += b.Length;
            }
            // Terminate chunk
            buffer[offset++] = 0;

            // Pad 4 bytes boundary
            for(int i=0;i<((offset - startOffset) % 4);i++){
                buffer[offset++] = 0;
            }
        }

        #endregion


        #region method Set

        /// <summary>
        /// Gets all data from specified value and sets all values.
        /// </summary>
        /// <param name="description">Source description.</param>
        internal void Set(RTP_SourceDescription description)
        {
            m_Name     = description.Name;
            m_Email    = description.Email;
            m_Phone    = description.Phone;
            m_Location = description.Location;
            m_Tool     = description.Tool;
            m_Note     = description.Note;
        }

        #endregion


        #region Properties Implementation

        /// <summary>
        /// Gets SSRC or CSRC identifier.
        /// </summary>
        public uint Source
        {
            get{ return m_Source; }
        }

        /// <summary>
        /// Gets Canonical End-Point Identifier.
        /// </summary>
        public string CName
        {
            get{ return m_CName; }
        }

        /// <summary>
        /// Gets or sets the real name, eg. "John Doe". Value null means not specified.
        /// </summary>
        /// <exception cref="ArgumentException">Is raised when invalid value is passed.</exception>
        public string Name
        {
            get{ return m_Name; }

            set{
                if(Encoding.UTF8.GetByteCount(value) > 255){
                    throw new ArgumentException("Property 'Name' value must be <= 255 bytes.");
                }

                m_Name = value;
            }
        }

        /// <summary>
        /// Gets or sets email address. For example "John.Doe@example.com". Value null means not specified.
        /// </summary>
        /// <exception cref="ArgumentException">Is raised when invalid value is passed.</exception>
        public string Email
        {
            get{ return m_Email; }

            set{
                if(Encoding.UTF8.GetByteCount(value) > 255){
                    throw new ArgumentException("Property 'Email' value must be <= 255 bytes.");
                }

                m_Email = value;
            }
        }

        /// <summary>
        /// Gets or sets phone number. For example "+1 908 555 1212". Value null means not specified.
        /// </summary>
        /// <exception cref="ArgumentException">Is raised when invalid value is passed.</exception>
        public string Phone
        {
            get{ return m_Phone; }

            set{
                if(Encoding.UTF8.GetByteCount(value) > 255){
                    throw new ArgumentException("Property 'Phone' value must be <= 255 bytes.");
                }

                m_Phone = value;
            }
        }

        /// <summary>
        /// Gets gets location string. It may be geographic address or for example chat room name.
        /// Value null means not specified.
        /// </summary>
        /// <exception cref="ArgumentException">Is raised when invalid value is passed.</exception>
        public string Location
        {
            get{ return m_Location; }

            set{
                if(Encoding.UTF8.GetByteCount(value) > 255){
                    throw new ArgumentException("Property 'Location' value must be <= 255 bytes.");
                }

                m_Location = value;
            }
        }

        /// <summary>
        /// Gets or sets streaming application name/version.
        /// Value null means not specified.
        /// </summary>
        /// <exception cref="ArgumentException">Is raised when invalid value is passed.</exception>
        public string Tool
        {
            get{ return m_Tool; }

            set{
                if(Encoding.UTF8.GetByteCount(value) > 255){
                    throw new ArgumentException("Property 'Tool' value must be <= 255 bytes.");
                }

                m_Tool = value;
            }
        }

        /// <summary>
        /// Gets or sets note text. The NOTE item is intended for transient messages describing the current state
        /// of the source, e.g., "on the phone, can't talk".
        /// Value null means not specified.
        /// </summary>
        /// <exception cref="ArgumentException">Is raised when invalid value is passed.</exception>
        public string Note
        {
            get{ return m_Note; }

            set{
                if(Encoding.UTF8.GetByteCount(value) > 255){
                    throw new ArgumentException("Property 'Note' value must be <= 255 bytes.");
                }

                m_Note = value;
            }
        }

        /// <summary>
        /// Gets number of bytes needed for this SDES chunk.
        /// </summary>
        public int Size
        {
            get{
                int size = 4;
                if(m_CName != null){
                    size += Encoding.UTF8.GetByteCount(m_CName);
                }
                if(m_Name != null){
                    size += Encoding.UTF8.GetByteCount(m_Name);
                }
                if(m_Email != null){
                    size += Encoding.UTF8.GetByteCount(m_Email);
                }
                if(m_Phone != null){
                    size += Encoding.UTF8.GetByteCount(m_Phone);
                }
                if(m_Location != null){
                    size += Encoding.UTF8.GetByteCount(m_Location);
                }
                if(m_Tool != null){
                    size += Encoding.UTF8.GetByteCount(m_Tool);
                }
                if(m_Note != null){
                    size += Encoding.UTF8.GetByteCount(m_Note);
                }

                return size; 
            }
        }

        #endregion

    }
}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


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

Comments and Discussions