Click here to Skip to main content
14,027,936 members
Click here to Skip to main content

Stats

747.6K views
30.2K 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.91
    August 2018, The Netherlands
    © Copyright 2018 PVS The Netherlands - Free to Use

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

    For use with Microsoft .NET Framework version 2.0 or higher and any CPU.
    Created with Microsoft Visual Studio.

    Articles on CodeProject with information on the use of the PVS.AVPlayer library:
    About the Player: http://www.codeproject.com/Articles/109714/PVS-AVPlayer-MCI-Audio-and-Video-Library
    About the Sound Recorder: http://www.codeproject.com/Articles/1116698/PVS-AVPlayer-MCI-Sound-Recorder

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

    The PVS.AVPlayer library source code is divided into 10 files:

    1. Player.cs            - Player source code
    2. MouseEvents.cs       - extension source code of Player.cs, provides player display mouse events
    3. PeakMeter.cs         - extension source code of Player.cs, provides player audio peak level values
    4. DisplayClones.cs     - extension source code of Player.cs, provides player multiple video displays 
    5. Subtitles.cs         - extension source code of Player.cs, provides player SubRip (.srt) subtitles
    6. Signals.cs           - extension source code of Player.cs, provides player media position signaling
    7. CursorHide.cs        - extension source code of Player.cs, hides the mouse cursor during inactivity
    8. Recorder.cs          - Sound Recorder source code
    9. PlayerRecorder.cs    - code used by both Player.cs (and its extension files) and Recorder.cs
    10. Infolabel.cs         - Info Label (custom ToolTip) source code

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

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

    This file: PeakMeter.cs

    Player Class
    Extension to file 'Player.cs'.

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

    About Media Control Interface (MCI)
    - for information about MCI, please see https://msdn.microsoft.com/en-us/library/vs/alm/dd757151(v=vs.85).aspx
    - you can find many articles about mci on the internet, search examples: 'c# mci', 'vb mci', 'mcisendstring'
    or the subject of your question.
    - the PVS.AVPlayer library also provides 'direct access' to MCI (e.g. 'Mci.MciSendString').

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

    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 articles with comments and suggestions and, of course, CodeProject:
    thank you Deeksha, Smitha and Sean Ewington for the beautiful articles and all!

    Special thanks to Sean Ewington of CodeProject who also took care of publishing the many code
    updates and changes in the PVS.AVPlayer articles in a friendly, fast, and highly competent manner.
    Thank you very much, Sean!

    Peter Vegter
    August 2018, The Netherlands

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

#region Usings

using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;

#endregion

namespace PVS.AVPlayer
{
    public partial class Player
    {
        /*
            Peak Meter
            Provides audio peak values by subscribing to the Player.Events.MediaPeakLevelChanged event.
        */

        // ******************************** Peak Meter - Fields

        #region Peak Meter - Fields

        private static Guid                     IID_IAudioMeterInformation  = new Guid("C02216F6-8C67-4B5B-9D00-D008E73E0064");
        private static Guid                     IID_IAudioEndpointVolume    = new Guid("5CDF2C82-841E-4546-9722-0CF74078229A");
        private const string                    PM_REGISTRY_KEYNAME         = @"HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\SWD\MMDEVAPI\";
        private const string                    PM_REGISTRY_VALUENAME       = "FriendlyName";
        private const int                       PM_VALUES_LENGTH            = 16;

        private static bool                     pm_HasPeakMeter;
        private static IAudioMeterInformation   pm_PeakMeterInfo;
        private static string                   pm_PeakMeterId              = string.Empty;
        private static string                   pm_PeakMeterName            = string.Empty;
        private static float                    pm_PeakMeterMasterValue;
        private static float[]                  pm_PeakMeterValues;
        private static float[]                  pm_PeakMeterValuesStop;
        private static int                      pm_PeakMeterChannelCount;
        private static object                   pm_PeakMeterLock            = new object();
        private static object                   pm_PeakMeterLock2           = new object();
        private static PeakMeterClient          pm_PeakMeterCallback;

        #endregion


        // ******************************** Peak Meter - Open / Close / Reset / GetValues

        #region Peak Meter - Open / Close / Reset / GetValues

        private static bool PeakMeter_Open()
        {
            lock (pm_PeakMeterLock)
            {
                if (!pm_HasPeakMeter)
                {
                    IMMDeviceEnumerator deviceEnumerator    = null;
                    IMMDevice           levelDevice         = null;
                    object              levelDeviceInfo     = null;

                    try
                    {
                        deviceEnumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());

                        if (pm_PeakMeterCallback == null)
                        {
                            pm_PeakMeterCallback = new PeakMeterClient();
                            deviceEnumerator.RegisterEndpointNotificationCallback(pm_PeakMeterCallback);
                        }

                        deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out levelDevice);

                        if (levelDevice != null)
                        {
                            levelDevice.Activate(ref IID_IAudioMeterInformation, 3, IntPtr.Zero, out levelDeviceInfo);
                            pm_PeakMeterInfo = (IAudioMeterInformation)levelDeviceInfo;

                            levelDevice.GetId(out pm_PeakMeterId);
                            try { pm_PeakMeterName = (string)Registry.GetValue(PM_REGISTRY_KEYNAME + pm_PeakMeterId, PM_REGISTRY_VALUENAME, string.Empty); }
                            catch { /* ignore */ }

                            if (pm_PeakMeterValues == null)
                            {
                                pm_PeakMeterValues     = new float[PM_VALUES_LENGTH];
                                pm_PeakMeterValuesStop = new float[PM_VALUES_LENGTH];
                                for (int i = 0; i < PM_VALUES_LENGTH; i++)
                                {
                                    //_peakMeterValues[i]     = 0;
                                    pm_PeakMeterValuesStop[i] = -1;
                                }
                            }

                            pm_HasPeakMeter = true;
                        }
                    }
                    catch { /* ignore */ }

                    if (levelDevice != null) Marshal.ReleaseComObject(levelDevice);
                    if (deviceEnumerator != null) Marshal.ReleaseComObject(deviceEnumerator);
                }

                return pm_HasPeakMeter;
            }
        }

        private static void PeakMeter_Close()
        {
            lock (pm_PeakMeterLock)
            {
                if (pm_HasPeakMeter)
                {
                    pm_HasPeakMeter = false;

                    try { Marshal.ReleaseComObject(pm_PeakMeterInfo); }
                    catch { /* ignore */ }

                    for (int i = 0; i < PM_VALUES_LENGTH; i++) { pm_PeakMeterValues[i] = 0; }

                    pm_PeakMeterInfo  = null;
                    pm_PeakMeterId    = string.Empty;
                    pm_PeakMeterName  = string.Empty;
                }
            }
        }

        private static void PeakMeter_Reset()
        {
            lock (pm_PeakMeterLock)
            {
                if (pm_HasPeakMeter)
                {
                    PeakMeter_Close();
                    PeakMeter_Open();
                }
            }
        }

        private static void PeakMeter_GetValues()
        {
            lock (pm_PeakMeterLock)
            {
                if (pm_HasPeakMeter)
                {
                    GCHandle values = GCHandle.Alloc(pm_PeakMeterValues, GCHandleType.Pinned);
                    pm_PeakMeterInfo.GetMeteringChannelCount(out pm_PeakMeterChannelCount);
                    pm_PeakMeterInfo.GetChannelsPeakValues(pm_PeakMeterChannelCount, values.AddrOfPinnedObject());
                    pm_PeakMeterInfo.GetPeakValue(out pm_PeakMeterMasterValue);
                    values.Free();
                }
            }
        }

        #endregion


        // ******************************** Peak Meter - Master Volume / Name

        #region Peak Meter - Master Volume / Name

        internal static int PeakMeter_GetMasterVolume()
        {
            lock (pm_PeakMeterLock2)
            {
                IMMDeviceEnumerator deviceEnumerator    = null;
                IMMDevice           levelDevice         = null;
                object              levelDeviceInfo     = null;
                float               volume              = 0;

                try
                {
                    deviceEnumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
                    deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out levelDevice);

                    levelDevice.Activate(ref IID_IAudioEndpointVolume, 3, IntPtr.Zero, out levelDeviceInfo);
                    ((IAudioEndpointVolume)levelDeviceInfo).GetMasterVolumeLevelScalar(out volume);
                }
                catch { volume = -0.001f; }

                if (levelDeviceInfo != null) Marshal.ReleaseComObject(levelDeviceInfo);
                if (levelDevice != null) Marshal.ReleaseComObject(levelDevice);
                if (deviceEnumerator != null) Marshal.ReleaseComObject(deviceEnumerator);

                return (int)(volume * 1000);
            }
        }

        internal static bool PeakMeter_SetMasterVolume(int volume)
        {
            lock (pm_PeakMeterLock2)
            {
                IMMDeviceEnumerator deviceEnumerator    = null;
                IMMDevice           levelDevice         = null;
                object              levelDeviceInfo     = null;
                float               vol;
                bool                result              = true;

                if (volume <= 0) vol = 0;
                else if (volume >= 1000) vol = 1;
                else vol = (float)volume / 1000;

                try
                {
                    deviceEnumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
                    deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out levelDevice);

                    levelDevice.Activate(ref IID_IAudioEndpointVolume, 3, IntPtr.Zero, out levelDeviceInfo);
                    ((IAudioEndpointVolume)levelDeviceInfo).SetMasterVolumeLevelScalar(vol, Guid.Empty);
                }
                catch { result = false; }

                if (levelDeviceInfo != null) Marshal.ReleaseComObject(levelDeviceInfo);
                if (levelDevice != null) Marshal.ReleaseComObject(levelDevice);
                if (deviceEnumerator != null) Marshal.ReleaseComObject(deviceEnumerator);

                return result;
            }
        }

        internal static string PeakMeter_GetName()
        {
            lock (pm_PeakMeterLock2)
            {
                if (pm_HasPeakMeter) return pm_PeakMeterName;
                else
                {
                    IMMDeviceEnumerator deviceEnumerator = null;
                    IMMDevice levelDevice = null;
                    string levelDeviceId;
                    string deviceName = string.Empty;

                    try
                    {
                        deviceEnumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
                        deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out levelDevice);

                        if (levelDevice != null)
                        {
                            levelDevice.GetId(out levelDeviceId);
                            try { deviceName = (string)Registry.GetValue(PM_REGISTRY_KEYNAME + levelDeviceId, PM_REGISTRY_VALUENAME, string.Empty); }
                            catch { /* ignore - try/catch not necessary? */ }
                        }
                    }
                    catch { /* ignore */ }

                    if (levelDevice != null) Marshal.ReleaseComObject(levelDevice);
                    if (deviceEnumerator != null) Marshal.ReleaseComObject(deviceEnumerator);

                    return deviceName;
                }
            }
        }

        #endregion


        // ******************************** Peak Meter - PeakMeterClient (IMMNotificationClient)

        #region Peak Meter - PeakMeterClient (IMMNotificationClient)

        private class PeakMeterClient : IMMNotificationClient
        {
            public void OnDefaultDeviceChanged(EDataFlow dataFlow, ERole deviceRole, string defaultDeviceId)
            {
                if (deviceRole == ERole.eMultimedia)
                {
                    if (pm_HasPeakMeter)
                    {
                        if (defaultDeviceId == null) PeakMeter_Close();
                        else PeakMeter_Reset();
                    }
                    else
                    {
                        if (defaultDeviceId != null) PeakMeter_Open();
                    }
                }
            }

            public void OnDeviceAdded(string deviceId)
            {
            }

            public void OnDeviceRemoved(string deviceId)
            {
            }

            public void OnDeviceStateChanged(string deviceId, DeviceState newState)
            {
                if (newState == DeviceState.Disabled)
                {
                    if (pm_HasPeakMeter && deviceId == pm_PeakMeterId)
                    {
                        PeakMeter_Close();
                    }
                }
                else if (newState == DeviceState.Active)
                {
                    if (!pm_HasPeakMeter)
                    {
                        PeakMeter_Open();
                    }
                }
            }

            public void OnPropertyValueChanged(string deviceId, PropertyKey propertyKey)
            {
            }
        }

        #endregion


        // ******************************** Peak Meter - Windows Core Audio API

        #region Peak Meter - Windows Core Audio API

        private enum ERole
        {
            eConsole,
            eMultimedia,
            eCommunications,
            ERole_enum_count
        }

        [Flags]
        private enum DeviceState
        {
            Active      = 0x00000001,
            Disabled    = 0x00000002,
            NotPresent  = 0x00000004,
            Unplugged   = 0x00000008,
            All         = 0x0000000F
        }

        private enum EDataFlow
        {
            eRender,
            eCapture,
            eAll,
            EDataFlow_enum_count
        };

        private struct PropertyKey
        {
            public Guid fmtid;
            public int  pid;
        };

        [ComImport]
        [Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
        private class MMDeviceEnumerator
        {
        }

        [Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IMMDeviceEnumerator
        {
            int NotImpl1();
            [PreserveSig]
            int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMMDevice endpoint);
            [PreserveSig]
            int GetDevice(string id, out IMMDevice deviceName);
            [PreserveSig]
            int RegisterEndpointNotificationCallback(IMMNotificationClient client);
            [PreserveSig]
            int UnregisterEndpointNotificationCallback(IMMNotificationClient client);
        }

        [Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IMMDevice
        {
            [PreserveSig]
            int Activate(ref Guid iid, int dwClsCtx, IntPtr pActivationParams, [MarshalAs(UnmanagedType.IUnknown)] out object ppInterface);
            int NotImpl1();
            int GetId([MarshalAs(UnmanagedType.LPWStr)] out string id);
            int GetState(out DeviceState state);
        }

        [Guid("C02216F6-8C67-4B5B-9D00-D008E73E0064"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IAudioMeterInformation
        {
            [PreserveSig]
            int GetPeakValue(out float pfPeak);
            [PreserveSig]
            int GetMeteringChannelCount(out int pnChannelCount);
            [PreserveSig]
            int GetChannelsPeakValues(int u32ChannelCount, [In] IntPtr afPeakValues);
            [PreserveSig]
            int QueryHardwareSupport(out int pdwHardwareSupportMask);
        };

        [Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IAudioEndpointVolume
        {
            [PreserveSig]
            int NotImpl1();
            [PreserveSig]
            int NotImpl2();
            [PreserveSig]
            int GetChannelCount([Out] [MarshalAs(UnmanagedType.U4)] out UInt32 channelCount);
            [PreserveSig]
            int SetMasterVolumeLevel([In] [MarshalAs(UnmanagedType.R4)] float level, [In] [MarshalAs(UnmanagedType.LPStruct)] Guid eventContext);
            [PreserveSig]
            int SetMasterVolumeLevelScalar([In] [MarshalAs(UnmanagedType.R4)] float level, [In] [MarshalAs(UnmanagedType.LPStruct)] Guid eventContext);
            [PreserveSig]
            int GetMasterVolumeLevel([Out] [MarshalAs(UnmanagedType.R4)] out float level);
            [PreserveSig]
            int GetMasterVolumeLevelScalar([Out] [MarshalAs(UnmanagedType.R4)] out float level);
        }

        [Guid("7991EEC9-7E89-4D85-8390-6C703CEC60C0"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IMMNotificationClient
        {
            void OnDeviceStateChanged([MarshalAs(UnmanagedType.LPWStr)] string deviceId, [MarshalAs(UnmanagedType.I4)] DeviceState newState);
            void OnDeviceAdded([MarshalAs(UnmanagedType.LPWStr)] string pwstrDeviceId);
            void OnDeviceRemoved([MarshalAs(UnmanagedType.LPWStr)] string deviceId);
            void OnDefaultDeviceChanged(EDataFlow flow, ERole role, [MarshalAs(UnmanagedType.LPWStr)] string defaultDeviceId);
            void OnPropertyValueChanged([MarshalAs(UnmanagedType.LPWStr)] string pwstrDeviceId, PropertyKey key);
        }
    }

    #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.190419.4 | Last Updated 7 Aug 2018
Article Copyright 2010 by Peter Vegter
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid