Click here to Skip to main content
13,829,826 members
Click here to Skip to main content

Stats

730.2K views
29.9K downloads
281 bookmarked
Posted 14 Sep 2010
Licenced CPOL

PVS.AVPlayer - MCI Audio and Video Library

, 7 Aug 2018
Windows Media Control Interface (MCI) library with many added features
PVS.AVPlayer
PVS.AVPlayer .NET 2.0
PVS.AVPlayer.XML
PVS.AVPlayer .NET 3.0
PVS.AVPlayer.XML
PVS.AVPlayer .NET 3.5
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.0
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.5
PVS.AVPlayer .NET 4.5.1
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.5.2
PVS.AVPlayer.XML
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.6
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.6.1
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.6.2
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.7
PVS.AVPlayer .NET 4.7.1
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.7.2
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer All Source Code
AVPlayerExample
AVPlayerExample
AVPlayerExample.csproj.user
bin
Debug
PVS.AVPlayer.XML
Release
Dialogs
Display Overlays
obj
Debug
Release
x86
Debug
Release
Properties
Resources
Crystal Italic1.ttf
WingDings3a.ttf
Voice Recorder
FolderView
FolderView
bin
Debug
PVS.AVPlayer.XML
Release
FolderView.csproj.user
obj
Release
x86
Debug
Release
Properties
Resources
Crystal Italic1.ttf
PVS.AVPlayer
AVPlayerExample.csproj.user
PVS.AVPlayer.dll
PVS.AVPlayer.XML
Custom Items
Native Methods
Bob.png
Crystal Italic1.ttf
Dial Green 2.png
Dial Green 4.png
Dial Green.png
Dial Red 2.png
Dial Red.png
media7.ico
media7a.ico
Media8.ico
Media8a.ico
VU Meter.png
WingDings3a.ttf
Sound Recorder
Various
About Dialog
PVS.AVPlayer.dll
PVS.AVPlayer.XML
Custom Items
FolderView.csproj.user
Debug
Bob.png
Crystal Italic1.ttf
media7a.ico
media7b.ico
Media8a.ico
Media8b.ico
Subtitles Overlay
Various
How To (C#)
PVSAVPlayerHowTo
bin
Debug
PVS.AVPlayer.dll
PVS.AVPlayer.XML
Release
obj
Debug
Release
Properties
How To (VB.NET)
PVSAVPlayerHowToVB
bin
Debug
PVS.AVPlayer.dll
PVS.AVPlayer.XML
Release
My Project
Application.myapp
obj
Debug
Release
PVSAVPlayerHowTo.vbproj.user
PVS.AVPlayer Examples
AVPlayerExample.ex_
FolderView.ex_
AVPlayerExample.exe
FolderView.exe
PVS.AVPlayer.dll
/****************************************************************
    
    PVS.AVPlayer - Version 0.46
    September 2015, The Netherlands
    © Copyright 2015 PVS The Netherlands

    ****************

    The PVS.AVPlayer library source code is divided into 3 files:
    1. Player.cs - Player source code
    2. Recorder.cs - (this file) (Microphone) Recorder source code
    3. PlayerRecorder.cs - code used by both Player.cs and Recorder.cs

    Required references:
    System
    System.Drawing
    System.Windows.Forms

    ****************

    This file: Recorder.cs

    Recorder Class
    Uses file 'PlayerRecorder.cs'

    ****************

    About Media Control Interface (MCI)
    - for information about MCI, please see https://msdn.microsoft.com/en-us/library/windows/desktop/dd757151%28v=vs.85%29.aspx
    - you can find very many articles about mci on the internet, search examples: 'c# mci', 'mcicommandstring'
      or the subject of your question.

    The PVS.AVPlayer.Recorder 'operating steps':
    1. open recorder (mci device; e.g. 'open new type waveaudio alias myRecorder')
    2. set recorder properties (e.g. 'set myRecorder set ...' (please see Record() method))
    3. start recording (e.g. 'record myRecorder')
    4. stop recording (e.g. 'stop myRecorder')
    5. save recording (e.g. 'save myRecorder C:\MyRecording.wav')
    6. close recorder (mci device; e.g. 'close myRecorder')

    The 'open' and 'close' device commands are 'hidden' from the user:
    The user only has to use the 'record' and 'stop' commands.

    ****************

    Thanks!

    Many thanks to Microsoft (Windows, .NET Framework, Visual Studio Express, etc.), all the people
    writing about programming on the internet (a great source for ideas and solving problems),
    the websites publishing those or other writings about programming, the people responding
    to the PVS.AVPlayer article with comments and suggestions and, of course, The Code Project:
    thank you Deeksha, Smitha and Sean for the beautiful article and all!

    ****************************************************************/


#region Usings

using System;
using System.Text;
using System.Windows.Forms;

#endregion

namespace PVS.AVPlayer
{
    // ******************************** PVS.AVPlayer - Enumerations (Recorder)

    #region PVS.AVPlayer - Enumerations (Recorder) - Channels / Bits / SampleRate

    /// <summary>
    /// Specifies the recorder's number of input channels for recording.
    /// </summary>
    public enum Channels
    {
        /// <summary>
        /// The recorder uses one input channel (mono).
        /// </summary>
        Mono = 1,
        /// <summary>
        /// The recorder uses two input channels (stereo).
        /// </summary>
        Stereo = 2
    }

    /// <summary>
    /// Specifies the recorder's number of bits per sample for recording.
    /// </summary>
    public enum Bits
    {
        /// <summary>
        /// The recorder uses 8 bits per sample.
        /// </summary>
        Bits8 = 8,
        /// <summary>
        /// The recorder uses 16 bits per sample.
        /// </summary>
        Bits16 = 16
    }

    /// <summary>
    /// Specifies the recorder's number of samples per second for recording.
    /// </summary>
    public enum SampleRate
    {
        /// <summary>
        /// The recorder uses 11025 samples per second.
        /// </summary>
        Samples11025 = 11025,
        /// <summary>
        /// The recorder uses 22050 samples per second.
        /// </summary>
        Samples22050 = 22050,
        /// <summary>
        /// The recorder uses 44100 samples per second.
        /// </summary>
        Samples44100 = 44100
    }

    #endregion

    /// <summary>
    /// Represents a recorder that can be used to record audio using Microsoft Windows built-in Media Control Interface (MCI).
    /// </summary>
    [CLSCompliant(true)]
    public class Recorder : IDisposable
    {
        // ******************************** Event Declarations

        #region Event Declarations

        /// <summary>
        /// Occurs when recording has started.
        /// </summary>
        public event EventHandler RecorderStarted;

        /// <summary>
        /// Occurs when the recorder's pause mode is activated (recording is paused).
        /// </summary>
        public event EventHandler RecorderPaused;

        /// <summary>
        /// Occurs when the recorder's pause mode is deactivated (recording is resumed).
        /// </summary>
        public event EventHandler RecorderResumed;

        /// <summary>
        /// Occurs when recording has stopped by using the recorder's Stop function.
        /// </summary>
        public event EventHandler RecorderStopped;

        /// <summary>
        /// Occurs when recording has stopped and the recording can be saved to a file (length > 0).
        /// </summary>
        public event EventHandler RecorderSaveRequest;

        /// <summary>
        /// Occurs when the recording position of the recorder has changed.
        /// </summary>
        public event EventHandler RecorderPositionChanged;

        /// <summary>
        /// Occurs when the recording level of the recorder has changed.
        /// </summary>
        public event EventHandler RecorderLevelChanged;

        /// <summary>
        /// Occurs when the recorder's input channels setting has changed.
        /// </summary>
        public event EventHandler RecorderChannelsChanged;

        /// <summary>
        /// Occurs when the recorder's input bits per sample setting has changed.
        /// </summary>
        public event EventHandler RecorderBitsChanged;

        /// <summary>
        /// Occurs when the recorder's input samples per second setting has changed.
        /// </summary>
        public event EventHandler RecorderSampleRateChanged;

        #endregion

        // ******************************** Fields

        #region Fields

        // MCI Device
        private string      _deviceId;
        private bool        _hasTempDevice;

        // Status
        private int         _lastError;
        private bool        _hasDevice;
        private bool        _isRecording;
        private bool        _isPaused;
        private bool        _hasLevel;

        // Settings
        private Channels    _recChannels    = Channels.Mono;            // channels can be 1 (mono) or 2 (stereo)
        private Bits        _recBits        = Bits.Bits8;               // bits per sample can be 8 or 16
        private SampleRate  _recSampleRate  = SampleRate.Samples11025;  // samples per second can be 11025, 22050 or 44100

        private int         _recBytes       = 11025;                    // average bytes/sec calculate: recChannels * recBits * recSampleRate / 8
        private int         _recAlignment   = 1;                        // block alignment calculate: recChannels * recBits / 8

        // Settings 2
        private int         _inputDevice    = -1;

        // Timer used with position changed event
        private Timer       _timer;

        // Used with sending MCI command text and error text
        private StringBuilder _textBuffer;

        // Miscellaneous
        private int         _number;
        private int         _count;
        private bool        _disposed;

        #endregion


        // ******************************** Recorder Constructor / Dispose / Destructor / Version

        #region Recorder Constructor

        /// <summary>
        /// Initializes a new instance of the PVS.AVPlayer.Recorder class.
        /// </summary>
        public Recorder()
        {
            _deviceId = Global.RandomNumber.Next(10, 100000000) + "AVR";
            _textBuffer = new StringBuilder(Global.BUFFER_SIZE);

            _timer = new Timer { Interval = 200 };
            _timer.Tick += TimerTick;
        }

        #endregion

        #region Recorder Dispose / Destructor

        /// <summary>
        /// Remove the recorder and clean up any resources being used.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Remove the recorder and clean up any resources being used.
        /// </summary>
        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _timer.Dispose();
                    _timer = null;
                }

                if (_hasDevice)
                {
                    SafeNativeMethods.mciSendString("close " + _deviceId, null, 0, IntPtr.Zero);
                    _hasDevice = false;
                }
                _disposed = true;
            }
        }

        /// <summary>
        /// Remove the recorder and clean up any resources being used.
        /// </summary>
        ~Recorder()
        {
            Dispose(false);
        }

        #endregion

        #region PVS.AVPlayer Version

        /// <summary>
        /// Gets the version number of the PVS.AVPlayer library.
        /// </summary>
        public static float Version
        {
            get { return Global.VERSION; }
        }

        /// <summary>
        /// Gets the version string of the PVS.AVPlayer library.
        /// </summary>
        public static string VersionString
        {
            get { return Global.VERSION_STRING; }
        }

        #endregion

        // ******************************** Error Information

        #region Error Information

        /// <summary>
        /// Gets a value indicating whether an error has occured with the last recorder instruction.
        /// </summary>
        public bool LastError
        {
            get { return _lastError != Global.MCIERR_NO_ERROR; }
        }

        /// <summary>
        /// Gets the code of the recorder's last error that has occured (0 = no error).
        /// </summary>
        public int LastErrorCode
        {
            get { return _lastError; }
        }

        /// <summary>
        /// Gets a description of the recorder's last error that has occured.
        /// </summary>
        public string LastErrorString
        {
            get { return GetErrorString(_lastError); }
        }

        /// <summary>
        /// Returns a description of the specified errorcode.
        /// </summary>
        /// <param name="errorCode">The errorcode to get the description of.</param>
        public string GetErrorString(int errorCode)
        {
            SafeNativeMethods.mciGetErrorString(errorCode, _textBuffer, Global.BUFFER_SIZE);
            return _textBuffer.ToString();
        }

        #endregion

        // ******************************** Channels, Bits, SampleRate

        #region Channels, Bits, SampleRate

        /// <summary>
        /// Gets or sets the number of channels used for recording.
        /// </summary>
        public Channels Channels
        {
            get { return _recChannels; }
            set
            {
                if (value != _recChannels)
                {
                    _recChannels = value;
                    if (RecorderChannelsChanged != null) RecorderChannelsChanged(this, EventArgs.Empty);
                }
            }
        }

        /// <summary>
        /// Gets or sets the number of bits per sample used for recording.
        /// </summary>
        public Bits Bits
        {
            get { return _recBits; }
            set
            {
                if (value != _recBits)
                {
                    _recBits = value;
                    if (RecorderBitsChanged != null) RecorderBitsChanged(this, EventArgs.Empty);
                }
            }
        }

        /// <summary>
        /// Gets or sets the number of samples per second used for recording.
        /// </summary>
        public SampleRate SampleRate
        {
            get { return _recSampleRate; }
            set
            {
                if (value != _recSampleRate)
                {
                    _recSampleRate = value;
                    if (RecorderSampleRateChanged != null) RecorderSampleRateChanged(this, EventArgs.Empty);
                }
            }
        }

        #endregion

        // ******************************** Record / Recording / Pause / Paused / Resume / Stop

        #region Record / Recording / Pause / Paused / Resume / Stop

        /// <summary>
        /// Starts a new recording.
        /// </summary>
        public int Record()
        {
            int aliasRepeat = Global.ALIAS_REPEAT;

            if (_hasDevice) Stop();

            do // repeat in (very rare) case the device alias (= deviceID) already exists
            {
                _lastError = SafeNativeMethods.mciSendString("open new type waveaudio alias " + _deviceId, null, 0, IntPtr.Zero);
                Application.DoEvents();
                if (_lastError == Global.MCIERR_DUPLICATE_ALIAS) _deviceId = Global.RandomNumber.Next(10, 100000000) + "AVRD";
            }
            while (_lastError == Global.MCIERR_DUPLICATE_ALIAS && aliasRepeat-- > 0);

            if (_lastError != Global.MCIERR_NO_ERROR) return _lastError;
            _hasDevice = true;

            // calculate the bytes per second and alignment
            _recBytes = (int) _recChannels * (int) _recBits * (int) _recSampleRate / 8;
            _recAlignment = (int) _recChannels * (int) _recBits / 8;

            // apply settings
            _textBuffer.Length = 0;
            // this has to be set in one commandline and in this order
            _textBuffer.Append("set ").Append(_deviceId)
                .Append(" time format ms bitspersample ").Append((int) _recBits)
                .Append(" channels ").Append((int) _recChannels)
                .Append(" alignment ").Append(_recAlignment)
                .Append(" samplespersec ").Append((int) _recSampleRate)
                .Append(" bytespersec ").Append(_recBytes)
                .Append(" format tag pcm");

            _lastError = SafeNativeMethods.mciSendString(_textBuffer.ToString(), null, 0, IntPtr.Zero);
            if (_lastError == Global.MCIERR_NO_ERROR)
            {
                // start recording
                _lastError = SafeNativeMethods.mciSendString("record " + _deviceId, null, 0, IntPtr.Zero);
                if (_lastError == Global.MCIERR_NO_ERROR)
                {
                    _isRecording = true;
                    if (_isPaused) SafeNativeMethods.mciSendString("pause " + _deviceId, null, 0, IntPtr.Zero);

                    // set inputdevice
                    if (_inputDevice != -1) _lastError = SafeNativeMethods.mciSendString("set " + _deviceId + " input " + _inputDevice.ToString(), null, 0, IntPtr.Zero);
                    if (_lastError == Global.MCIERR_NO_ERROR)
                    {
                        if (Level > 0) _hasLevel = true;
                        else _lastError = Global.MCIERR_NO_ERROR;

                        if (!_isPaused)
                        {
                            if (RecorderPositionChanged != null || (_hasLevel && RecorderLevelChanged != null))
                            {
                                _timer.Start();
                            }
                        }
                        if (RecorderStarted != null) RecorderStarted(this, EventArgs.Empty);
                    }
                }
            }
            if (_lastError != Global.MCIERR_NO_ERROR)
            {
                SafeNativeMethods.mciSendString("close " + _deviceId + " wait", null, 0, IntPtr.Zero);
                _hasDevice = _isRecording = false;
            }
            return _lastError;
        }

        /// <summary>
        /// Gets a value indicating whether the recorder is recording (includes state paused).
        /// </summary>
        public bool Recording
        {
            get { return _isRecording; }
        }

        /// <summary>
        /// Activates the recorder's pause mode (pauses recording).
        /// </summary>
        public int Pause()
        {
            _lastError = Global.MCIERR_NO_ERROR;

            if (_isPaused) return _lastError;
            if (_isRecording)
            {
                _lastError = SafeNativeMethods.mciSendString("pause " + _deviceId, null, 0, IntPtr.Zero);
                _timer.Stop();
            }
            _isPaused = true;
            if (RecorderPaused != null) RecorderPaused(this, EventArgs.Empty);

            return _lastError;
        }

        /// <summary>
        /// Gets or sets a value indicating whether the player's pause mode is activated.
        /// </summary>
        public bool Paused
        {
            get { return _isPaused; }
            set
            {
                if (value) Pause();
                else Resume();
            }
        }

        /// <summary>
        /// Deactivates the recorder's pause mode (resumes recording).
        /// </summary>
        public int Resume()
        {
            _lastError = Global.MCIERR_NO_ERROR;

            if (!_isPaused) return _lastError;
            if (_isRecording)
            {
                _lastError = SafeNativeMethods.mciSendString("resume " + _deviceId, null, 0, IntPtr.Zero);
                if (RecorderPositionChanged != null || RecorderLevelChanged != null)
                {
                    _timer.Start();
                }
            }
            _isPaused = false;
            if (RecorderResumed != null) RecorderResumed(this, EventArgs.Empty);
            return _lastError;
        }

        /// <summary>
        /// Stops recording. The RecorderSaveRequest event can be used to save the recording to a file.
        /// </summary>
        public int Stop()
        {
            if (_hasDevice)
            {
                if (_isRecording)
                {
                    SafeNativeMethods.mciSendString("stop " + _deviceId + " wait", null, 0, IntPtr.Zero);
                    _timer.Stop();
                    _isRecording = false;
                    if (RecorderStopped != null) RecorderStopped(this, EventArgs.Empty);
                    if (Length > 0 && RecorderSaveRequest != null) RecorderSaveRequest(this, EventArgs.Empty);
                    if (RecorderPositionChanged != null) RecorderPositionChanged(this, EventArgs.Empty);
                }

                SafeNativeMethods.mciSendString("close " + _deviceId + " wait", null, 0, IntPtr.Zero);
                _hasDevice = _hasLevel = false;
            }
            _lastError = Global.MCIERR_NO_ERROR;
            return _lastError;
        }

        #endregion

        // ******************************** timer_Tick / Position / Length

        #region TimerTick / Position / Length

        private void TimerTick(object sender, EventArgs e)
        {
            if (RecorderPositionChanged != null) RecorderPositionChanged(this, EventArgs.Empty);
            if (_hasLevel && RecorderLevelChanged != null) RecorderLevelChanged(this, EventArgs.Empty);
        }

        /// <summary>
        /// Gets a value indicating the recorder's recording position.
        /// </summary>
        public TimeSpan Position
        {
            get
            {
                _textBuffer.Length = 0;
                if (_isRecording && SafeNativeMethods.mciSendString("status " + _deviceId + " position", _textBuffer, Global.BUFFER_SIZE, IntPtr.Zero) == Global.MCIERR_NO_ERROR)
                {
                    _number = 0;
                    for (_count = 0; _count < _textBuffer.Length; ++_count)
                    {
                        _number = 10 *_number + (_textBuffer[_count] - 48);
                    }
                    return TimeSpan.FromMilliseconds(_number);
                }
                return TimeSpan.Zero;
            }
        }

        /// <summary>
        /// Gets a value indicating the recorder's recording length (in bytes).
        /// </summary>
        public int Length
        {
            get
            {
                _textBuffer.Length = 0;
                return SafeNativeMethods.mciSendString("status " + _deviceId + " length", _textBuffer, Global.BUFFER_SIZE, IntPtr.Zero) == Global.MCIERR_NO_ERROR ? int.Parse(_textBuffer.ToString()) : 0;
            }
        }

        #endregion

        // ******************************** Save

        #region Save

        /// <summary>
        /// Saves the recording to a file (waveaudio (.wav) file format).
        /// </summary>
        public int Save(string fileName)
        {
            _lastError = Global.MCIERR_DEVICE_NOT_READY;
            if (Length > 0) _lastError = SafeNativeMethods.mciSendString("save " + _deviceId + " " + fileName, null, 0, IntPtr.Zero);
            return _lastError;
        }

        #endregion

        // ******************************** InputDevices

        #region InputDevices

        /// <summary>
        /// Gets a value indicating the total number of available input devices for recording.
        /// </summary>
        public int InputDeviceCount
        {
            get
            {
                OpenTempDevice();

                _textBuffer.Length = 0;
                _lastError = SafeNativeMethods.mciSendString("capability " + _deviceId + " inputs", _textBuffer, Global.BUFFER_SIZE, IntPtr.Zero);

                CloseTempDevice();
                return _lastError == Global.MCIERR_NO_ERROR ? int.Parse(_textBuffer.ToString()) : 0;
            }
        }

        /// <summary>
        /// Gets the description of the current input device. Returns "none" if an input device is not set.
        /// </summary>
        public string InputDeviceInfo
        {
            get
            {
                OpenTempDevice();

                _textBuffer.Length = 0;
                _lastError = SafeNativeMethods.mciSendString("info " + _deviceId + " input", _textBuffer, Global.BUFFER_SIZE, IntPtr.Zero);

                CloseTempDevice();
                return _lastError == Global.MCIERR_NO_ERROR ? _textBuffer.ToString() : string.Empty;
            }
        }

        /// <summary>
        /// Gets or sets the input device (by number (starting at 0 or -1 for the default input device)).
        /// </summary>
        public int InputDevice
        {
            get { return _inputDevice; }
            set
            {
                _lastError = Global.MCIERR_NO_ERROR;
                if (_isRecording)
                {
                    _lastError = value == -1 ? SafeNativeMethods.mciSendString("set " + _deviceId + " any input", null, 0, IntPtr.Zero) : SafeNativeMethods.mciSendString("set " + _deviceId + " input " + value, null, 0, IntPtr.Zero);
                }
                if (_lastError == Global.MCIERR_NO_ERROR) _inputDevice = value;
            }
        }

        #endregion

        // ******************************** Audio Level

        #region Audio Level

        /// <summary>
        /// Gets the current audio sample value (peak level) - if available and when recording (incl. paused) only. Value from 1 to 128: low-word: left volume (and mono), high-word: right volume (stereo).
        /// </summary>
        public int Level
        {
            get
            {
                _lastError = Global.MCIERR_DEVICE_NOT_READY;

                if (!_isRecording) return 0;
                _textBuffer.Length = 0;

                _lastError = SafeNativeMethods.mciSendString("status " + _deviceId + " level", _textBuffer, Global.BUFFER_SIZE, IntPtr.Zero);
                if (_lastError != Global.MCIERR_NO_ERROR) return 0;

                _number = 0;
                for (_count = 0; _count < _textBuffer.Length; ++_count)
                {
                    _number = 10 *_number + (_textBuffer[_count] - 48);
                }
                return _number;
            }
        }

        /// <summary>
        /// Gets a value indicating whether peak level values are available (when recording (incl. paused) only).
        /// </summary>
        public bool LevelPresent
        {
            get
            {
                if (_isRecording) return Level > 0;
                return false;
            }
        }

        #endregion

        // ******************************** Temporary Device (for Settings)

        #region Temporary Device

        private void OpenTempDevice()
        {
            if (_hasDevice || _hasTempDevice) return;
            if (SafeNativeMethods.mciSendString("open new type waveaudio alias " + _deviceId, null, 0, IntPtr.Zero) != Global.MCIERR_NO_ERROR) return;
            _hasTempDevice = true;

            // calculate the bytes per second and alignment
            _recBytes = (int) _recChannels * (int) _recBits * (int) _recSampleRate / 8;
            _recAlignment = (int) _recChannels * (int) _recBits / 8;

            // apply settings
            _textBuffer.Length = 0;
            // this has to be set in one commandline and in this order
            _textBuffer.Append("set ").Append(_deviceId)
                .Append(" time format ms bitspersample ").Append((int) _recBits)
                .Append(" channels ").Append((int) _recChannels)
                .Append(" alignment ").Append(_recAlignment)
                .Append(" samplespersec ").Append((int) _recSampleRate)
                .Append(" bytespersec ").Append(_recBytes)
                .Append(" format tag pcm");

            SafeNativeMethods.mciSendString(_textBuffer.ToString(), null, 0, IntPtr.Zero);
            if (_inputDevice != -1) SafeNativeMethods.mciSendString("set " + _deviceId + " input " + _inputDevice, null, 0, IntPtr.Zero);
        }

        private void CloseTempDevice()
        {
            if (_hasTempDevice)
            {
                SafeNativeMethods.mciSendString("close " + _deviceId + " wait", null, 0, IntPtr.Zero);
                _hasTempDevice = false;
            }
        }

        #endregion

        // ******************************** MCI Direct Access

        #region MCI Direct Access

        /// <summary>
        /// Sends a command to the MCI device associated with the recorder.
        /// </summary>
        /// <param name="command">String that specifies the MCI command.</param>
        /// <returns>Returns 0 if successful or an MCI errorcode otherwise (also available with LastErrorCode).</returns>
        public int MciCommand(string command)
        {
            _lastError = SafeNativeMethods.mciSendString(command.Trim() + " " + _deviceId, null, 0, IntPtr.Zero);
            return _lastError;
        }

        /// <summary>
        /// Sends a command to the MCI device associated with the recorder.
        /// </summary>
        /// <param name="command">String that specifies the MCI command.</param>
        /// <param name="parameters">String that specifies the MCI command parameters.</param>
        /// <returns>Returns 0 if successful or an MCI errorcode otherwise (also available with LastErrorCode).</returns>
        public int MciCommand(string command, string parameters)
        {
            parameters = parameters.Trim();
            _lastError = parameters.Length == 0 ? SafeNativeMethods.mciSendString(command.Trim() + " " + _deviceId, null, 0, IntPtr.Zero) : SafeNativeMethods.mciSendString(command.Trim() + " " + _deviceId + " " + parameters, null, 0, IntPtr.Zero);
            return _lastError;
        }

        /// <summary>
        /// Sends a request to the MCI device associated with the recorder.
        /// </summary>
        /// <param name="request">String that specifies the MCI request.</param>
        /// <param name="parameters">String that specifies the MCI request parameters.</param>
        /// <param name="result">A string that receives return information.</param>
        /// <returns>Returns 0 if successful or an MCI errorcode otherwise (also available with LastErrorCode).</returns>
        public int MciRequest(string request, string parameters, out string result)
        {
            _lastError = SafeNativeMethods.mciSendString(request.Trim() + " " + _deviceId + " " + parameters.Trim(), _textBuffer, Global.BUFFER_SIZE, IntPtr.Zero);
            result = _lastError == Global.MCIERR_NO_ERROR ? _textBuffer.ToString() : string.Empty;
            return _lastError;
        }

        #endregion

        // ******************************** Show System Audio Input Panel

        #region System Audio Input Panel

        // non-static methods by design

        /// <summary>
        /// Opens the System Sound Control Panel for user access to the default system audio input settings.
        /// </summary>
        /// <returns>Returns a value indicating whether opening the control has succeeded.</returns>
        public bool ShowAudioInputPanel()
        {
            return ShowAudioInputPanel(null);
        }

        /// <summary>
        /// Opens the System Sound Control Panel for user access to the default system audio input settings.
        /// </summary>
        /// <param name="centerForm">The control panel is centered on top of the specified form.</param>
        /// <returns>Returns a value indicating whether opening the control has succeeded.</returns>
        public bool ShowAudioInputPanel(Form centerForm)
        {
            return SafeNativeMethods.CenterSystemDialog("control", "mmsys.cpl,,1", centerForm);
        }

        #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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Peter Vegter
United States United States
No Biography provided

You may also be interested in...

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web03 | 2.8.190114.1 | Last Updated 7 Aug 2018
Article Copyright 2010 by Peter Vegter
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid