Click here to Skip to main content
12,252,860 members (62,418 online)
Click here to Skip to main content
Articles » Languages » C# » General » Downloads

Stats

20.9K views
1.4K downloads
22 bookmarked
Posted

Using OpenTK/OpenAL to Develop Cross Platform DIS VOIP Application

, 15 Mar 2010 BSD
Application allows voice communications (VOIP) utilizing the Distributed Interactive Simulation protocol (IEEE 1278.1)
MonoDISRadioTransmitter
AudioIN
bin
Properties
StyleCop.Cache
AudioOUT
bin
Properties
DISNET
bin
DataStreams
DISPDU
Enumerations
Properties
Utilities
OpenDISRadioTransmitterExample
AudioCodecs
bin
OpenDISRadioTransmitter.csproj.user
OpenTK
OpenTK.Compatibility.dll
OpenTK.dll
OpenTK.GLControl.dll
Properties
StyleCop.Cache
OpenDISRadioTransmitterSolution.suo
RadioFeatureSelection
bin
Properties
Sockets
bin
Properties
// Copyright (c) 2010, Peter Smith
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, 
// are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this list 
// of conditions and the following disclaimer. 
//
// Redistributions in binary form must reproduce the above copyright notice, this 
// list of conditions and the following disclaimer in the documentation and/or 
// other materials provided with the distribution. 
//
// Neither the name of the  Author nor the names of its contributors may be used to 
// endorse or promote products derived from this software without specific prior 
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
// OF THE POSSIBILITY OF SUCH DAMAGE.

namespace AudioIN
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;

    using OpenTK;
    using OpenTK.Audio;
    using OpenTK.Audio.OpenAL;

    public class Microphone
    {
        #region Fields

        /// <summary>
        /// Boolean value indicating if microphone intialized correctly
        /// </summary>
        public bool isMicrophoneValid = false;

        AudioCapture audio_capture;
        private byte[] buffer = new byte[1024];
        private bool continuePolling = false;
        private Queue<byte[]> microphoneData = new Queue<byte[]>();
        Thread pollMicrophone = null;
        private int SampleToByte = 2;
        private int src;

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Initialize the microphone
        /// </summary>
        /// <param name="samplingRate">Sample rate used during capture</param>
        /// <param name="gain">Gain of the microphone</param>
        /// <param name="deviceCaptureName">Name of the Device used for capturing audio</param>
        /// <param name="format">One of the openAL formats</param>
        /// <param name="bufferSize">Size of the buffer</param>
        public Microphone(int samplingRate, float gain, string deviceCaptureName, ALFormat format, int bufferSize)
        {
            isMicrophoneValid = SetUpMicrophone(samplingRate, gain, deviceCaptureName, format, bufferSize);
        }

        #endregion Constructors

        #region Properties

        /// <summary>
        /// Queue used to hold the incoming data from the microphone.
        /// </summary>
        public Queue<byte[]> MicrophoneData
        {
            get
            {
                return microphoneData;
            }

            set
            {
                microphoneData = value;
            }
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// Start recording from the Microphone
        /// </summary>
        public void StartRecording()
        {
            if (isMicrophoneValid == true)
            {
                audio_capture.Start();
                continuePolling = true;

                if (pollMicrophone == null ||pollMicrophone.IsAlive == false)
                {
                    pollMicrophone = new Thread(PollMicrophoneForData);
                    pollMicrophone.Start();
                }
            }
        }

        /// <summary>
        /// Stop recording from the Microphone
        /// </summary>
        public void StopRecording()
        {
            if (isMicrophoneValid == true)
            {
                continuePolling = false;
                audio_capture.Stop();
                ClearBuffers(0);
                MicrophoneData.Clear();
            }
        }

        /// <summary>
        /// Clears the Microphone buffers
        /// </summary>
        /// <param name="input">Which buffer</param>
        private void ClearBuffers(int input)
        {
            int[] freedbuffers;
            if (input == 0)
            {
                int BuffersProcessed;
                AL.GetSource(src, ALGetSourcei.BuffersProcessed, out BuffersProcessed);
                if (BuffersProcessed == 0)
                    return;
                freedbuffers = AL.SourceUnqueueBuffers(src, BuffersProcessed);
            }
            else
            {
                freedbuffers = AL.SourceUnqueueBuffers(src, input);
            }
            AL.DeleteBuffers(freedbuffers);
        }

        private bool InitializeMicrophone(int samplingRate, float gain, string deviceCaptureName, ALFormat format, int bufferSize)
        {
            AL.Listener(ALListenerf.Gain, gain);

            src = AL.GenSource();

            SampleToByte = NumberOfBytesPerSample(format);

            buffer = new byte[bufferSize];

            try
            {
                audio_capture = new AudioCapture(deviceCaptureName, samplingRate, format, bufferSize);
            }
            catch (AudioDeviceException ade)
            {
                audio_capture = null;
            }

            if (audio_capture == null)
                return false;

            return true;
        }

        private int NumberOfBytesPerSample(ALFormat format)
        {
            int bytesPerSample = 2;

            switch (format)
            {
                case ALFormat.Mono16:
                    bytesPerSample = 2;
                    break;
                case ALFormat.Mono8:
                    bytesPerSample = 1;
                    break;
                case ALFormat.MonoALawExt:
                    bytesPerSample = 1;
                    break;
                case ALFormat.MonoDoubleExt:
                    bytesPerSample = 8;
                    break;
                case ALFormat.MonoFloat32Ext:
                    bytesPerSample = 4;
                    break;
                case ALFormat.MonoIma4Ext:
                    bytesPerSample = 4;
                    break;
                case ALFormat.MonoMuLawExt:
                    bytesPerSample = 1;
                    break;
                case ALFormat.Mp3Ext:
                    bytesPerSample = 2; //Guessed might not be correct
                    break;
                case ALFormat.Multi51Chn16Ext:
                    bytesPerSample = 6 * 2;
                    break;
                case ALFormat.Multi51Chn32Ext:
                    bytesPerSample = 6 * 4;
                    break;
                case ALFormat.Multi51Chn8Ext:
                    bytesPerSample = 6 * 1;
                    break;
                case ALFormat.Multi61Chn16Ext:
                    bytesPerSample = 7 * 2;
                    break;
                case ALFormat.Multi61Chn32Ext:
                    bytesPerSample = 7 * 4;
                    break;
                case ALFormat.Multi61Chn8Ext:
                    bytesPerSample = 7 * 1;
                    break;
                case ALFormat.Multi71Chn16Ext:
                    bytesPerSample = 7 * 2;
                    break;
                case ALFormat.Multi71Chn32Ext:
                    bytesPerSample = 7 * 4;
                    break;
                case ALFormat.Multi71Chn8Ext:
                    bytesPerSample = 7 * 1;
                    break;
                case ALFormat.MultiQuad16Ext:
                    bytesPerSample = 4 * 2;
                    break;
                case ALFormat.MultiQuad32Ext:
                    bytesPerSample = 4 * 4;
                    break;
                case ALFormat.MultiQuad8Ext:
                    bytesPerSample = 4 * 1;
                    break;
                case ALFormat.MultiRear16Ext:
                    bytesPerSample = 1 * 2;
                    break;
                case ALFormat.MultiRear32Ext:
                    bytesPerSample =  1 * 4;
                    break;
                case ALFormat.MultiRear8Ext:
                    bytesPerSample = 1 * 1;
                    break;
                case ALFormat.Stereo16:
                    bytesPerSample = 2 * 2;
                    break;
                case ALFormat.Stereo8:
                    bytesPerSample = 2 * 1;
                    break;
                case ALFormat.StereoALawExt:
                    bytesPerSample = 2 * 1;
                    break;
                case ALFormat.StereoDoubleExt:
                    bytesPerSample = 2 * 8;
                    break;
                case ALFormat.StereoFloat32Ext:
                    bytesPerSample = 2 * 4;
                    break;
                case ALFormat.StereoIma4Ext:
                    bytesPerSample = 1; //Guessed
                    break;
                case ALFormat.StereoMuLawExt:
                    bytesPerSample = 2 * 1;
                    break;
                case ALFormat.VorbisExt:
                    bytesPerSample = 2; //Guessed
                    break;
                default:
                    break;
            }

            return bytesPerSample;
        }

        /// <summary>
        /// Used to poll the Microphone for data
        /// </summary>
        private void PollMicrophoneForData()
        {
            while (continuePolling)
            {
                Thread.Sleep(1); //Allow GUI some time

                if (audio_capture.AvailableSamples * SampleToByte >= buffer.Length)
                {
                    UpdateSamples();
                }
            }
        }

        private bool SetUpMicrophone(int samplingRate, float gain, string deviceCaptureName, ALFormat format, int bufferSize)
        {
            //return InitializeMicrophone(8000, 4.0f, AudioCapture.DefaultDevice, ALFormat.Mono16, 1024, codec);
            return InitializeMicrophone(samplingRate, gain, deviceCaptureName, format, bufferSize);
        }

        private void UpdateSamples()
        {
            buffer = new byte[buffer.Length];
            audio_capture.ReadSamples(buffer, buffer.Length / SampleToByte); //Need to divide as the readsamples expects the value to be in 2 bytes.

            //Queue raw data, let receiving application determine if it needs to compress
            this.microphoneData.Enqueue(buffer);
            ClearBuffers(0);
        }

        #endregion Methods
    }
}

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 BSD License

Share

About the Author

pesmith
Software Developer
United States United States
No Biography provided

You may also be interested in...

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160426.1 | Last Updated 15 Mar 2010
Article Copyright 2010 by pesmith
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid