Click here to Skip to main content
15,896,557 members
Articles / Web Development / HTML

nVLC

Rate me:
Please Sign up or sign in to vote.
4.94/5 (213 votes)
12 Feb 2018GPL316 min read 12.2M   69.9K   379  
A .NET API for the libVLC interface so the vast majority of VLC functionality could be utilized in managed applications
//    nVLC
//    
//    Author:  Roman Ginzburg
//
//    nVLC is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    nVLC is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//    GNU General Public License for more details.
//     
// ========================================================================

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Timers;
using Declarations;
using Declarations.Enums;
using LibVlcWrapper;

namespace Implementation
{
    internal unsafe sealed class AudioRenderer : DisposableBase, IAudioRenderer
    {
        private IntPtr m_hMediaPlayer;
        private AudioCallbacks m_callbacks = new AudioCallbacks();
        private Func<SoundFormat, SoundFormat> m_formatSetupCB;
        private SoundFormat m_format;
        private List<Delegate> m_callbacksDelegates = new List<Delegate>();
        private Action<Exception> m_excHandler;
        private IntPtr m_hSetup;
        private IntPtr m_hVolume;
        private IntPtr m_hSound;
        private IntPtr m_hPause;
        private IntPtr m_hResume;
        private IntPtr m_hFlush;
        private IntPtr m_hDrain;
        private Timer m_timer = new Timer();
        volatile int m_frameRate = 0;
        int m_latestFps;

        public AudioRenderer(IntPtr hMediaPlayer)
        {
            m_hMediaPlayer = hMediaPlayer;

            PlayCallbackEventHandler pceh = PlayCallback;
            VolumeCallbackEventHandler vceh = VolumeCallback;
            SetupCallbackEventHandler sceh = SetupCallback;
            AudioCallbackEventHandler pause = PauseCallback;
            AudioCallbackEventHandler resume = ResumeCallback;
            AudioCallbackEventHandler flush = FlushCallback;
            AudioDrainCallbackEventHandler drain = DrainCallback;

            m_hSound = Marshal.GetFunctionPointerForDelegate(pceh);
            m_hVolume = Marshal.GetFunctionPointerForDelegate(vceh);
            m_hSetup = Marshal.GetFunctionPointerForDelegate(sceh);
            m_hPause = Marshal.GetFunctionPointerForDelegate(pause);
            m_hResume = Marshal.GetFunctionPointerForDelegate(resume);
            m_hFlush = Marshal.GetFunctionPointerForDelegate(flush);
            m_hDrain = Marshal.GetFunctionPointerForDelegate(drain);

            m_callbacksDelegates.Add(pceh);
            m_callbacksDelegates.Add(vceh);
            m_callbacksDelegates.Add(sceh);
            m_callbacksDelegates.Add(pause);
            m_callbacksDelegates.Add(resume);
            m_callbacksDelegates.Add(flush);
            m_callbacksDelegates.Add(drain);

            m_timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            m_timer.Interval = 1000;
        }

        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            m_latestFps = m_frameRate;
            m_frameRate = 0;
        }

        public void SetCallbacks(VolumeChangedEventHandler volume, NewSoundEventHandler sound)
        {
            m_callbacks.VolumeCallback = volume;
            m_callbacks.SoundCallback = sound;
            LibVlcMethods.libvlc_audio_set_callbacks(m_hMediaPlayer, m_hSound, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
            LibVlcMethods.libvlc_audio_set_volume_callback(m_hMediaPlayer, m_hVolume);
        }

        public void SetCallbacks(AudioCallbacks callbacks)
        {
            if (callbacks.SoundCallback == null)
            {
                throw new ArgumentNullException("Sound playback callback must be set");
            }

            m_callbacks = callbacks;
            LibVlcMethods.libvlc_audio_set_callbacks(m_hMediaPlayer, m_hSound, m_hPause, m_hResume, m_hFlush, m_hDrain, IntPtr.Zero);
            LibVlcMethods.libvlc_audio_set_volume_callback(m_hMediaPlayer, m_hVolume);
        }

        public void SetFormat(SoundFormat format)
        {
            m_format = format;
            LibVlcMethods.libvlc_audio_set_format(m_hMediaPlayer, m_format.Format.ToUtf8(), m_format.Rate, m_format.Channels);
        }

        public void SetFormatCallback(Func<SoundFormat, SoundFormat> formatSetup)
        {
            m_formatSetupCB = formatSetup;
            LibVlcMethods.libvlc_audio_set_format_callbacks(m_hMediaPlayer, m_hSetup, IntPtr.Zero);
        }

        internal void StartTimer()
        {
            m_timer.Start();
        }

        private void PlayCallback(void* data, void* samples, uint count, long pts)
        {
            Sound s = new Sound();
            s.SamplesData = new IntPtr(samples);
            s.SamplesSize = (uint)(count * m_format.BlockSize);
            s.Pts = pts;

            if (m_callbacks.SoundCallback != null)
            {
                m_callbacks.SoundCallback(s);
            }
        }

        private void PauseCallback(void* data, long pts)
        {
            if (m_callbacks.PauseCallback != null)
            {
                m_callbacks.PauseCallback(pts);
            }
        }

        private void ResumeCallback(void* data, long pts)
        {
            if (m_callbacks.ResumeCallback != null)
            {
                m_callbacks.ResumeCallback(pts);
            }
        }

        private void FlushCallback(void* data, long pts)
        {
            if (m_callbacks.FlushCallback != null)
            {
                m_callbacks.FlushCallback(pts);
            }
        }

        private void DrainCallback(void* data)
        {
            if (m_callbacks.DrainCallback != null)
            {
                m_callbacks.DrainCallback();
            }
        }

        private void VolumeCallback(void* data, float volume, bool mute)
        {
            if (m_callbacks.VolumeCallback != null)
            {
                m_callbacks.VolumeCallback(volume, mute);
            }
        }

        private int SetupCallback(void** data, char* format, int* rate, int* channels)
        {
            IntPtr pFormat = new IntPtr(format);
            string formatStr = Marshal.PtrToStringAnsi(pFormat);

            SoundType sType;
            if (!Enum.TryParse<SoundType>(formatStr, out sType))
            {
                ArgumentException exc = new ArgumentException("Unsupported sound type " + formatStr);
                if (m_excHandler != null)
                {
                    m_excHandler(exc);
                    return 1;
                }
                else
                {
                    throw exc;
                }
            }

            m_format = new SoundFormat(sType, *rate, *channels);
            if (m_formatSetupCB != null)
            {
                m_format = m_formatSetupCB(m_format);
            }
            
            Marshal.Copy(m_format.Format.ToUtf8(), 0, pFormat, 4);
            *rate = m_format.Rate;
            *channels = m_format.Channels;

            return m_format.UseCustomAudioRendering == true ? 0 : 1;
        }

        protected override void Dispose(bool disposing)
        {
            LibVlcMethods.libvlc_audio_set_format_callbacks(m_hMediaPlayer, IntPtr.Zero, IntPtr.Zero);
            LibVlcMethods.libvlc_audio_set_callbacks(m_hMediaPlayer, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);

            if (disposing)
            {
                m_formatSetupCB = null;
                m_excHandler = null;
                m_callbacks = null;
                m_callbacksDelegates.Clear();
            }          
        }

        public void SetExceptionHandler(Action<Exception> handler)
        {
            m_excHandler = handler;
        }

        public int ActualFrameRate
        {
            get
            {
                return m_latestFps;
            }
        }
    }
}

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 GNU General Public License (GPLv3)


Written By
Software Developer (Senior)
Israel Israel
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions