Search code examples
c#vlcaudio-streaming

C#+VideoLan.LibVLC Sample Audio Stream and save it to disk


I am using VideoLan.VLC to get 20 seconds of an audio stream every 30 seconds. I have a loop, something like

    private LibVLC libvlc = new LibVLC();
    private MediaPlayer mediaPlayer = null;
    private Media Media = null;

    private string AudioSampleFileName { get {
                return "audio_" + DateTime.Now.ToString("yyyyMMdd_HHmmss")+
                        ".ts";             
            } }

public void Start(){

     mediaPlayer = new MediaPlayer(libvlc);
     
     while(...){
             Get_20_seconds_audio_sample();
             Wait_30_Seconds();            
            }
          }



    public void Get_sample(Uri playPathUri, string FileName)
            {
                
                var currentDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
                var destination = Path.Combine(currentDirectory, FileName);
    
                var mediaOptions = new string[]
                {
                     ":sout=#file{dst=" + destination + ",channels=1,samplerate=16000}",
                     ":sout-keep"
                };
                
                if (Media == null)
                {
                    Media = new Media(libvlc, playPathUri, mediaOptions);
                    mediaPlayer.Media = Media;
                }
                else {
                    Media.AddOption(":sout=#file{dst=" + destination + ",channels=1,samplerate=16000}");
                }            
                mediaPlayer.Play();            
            }
            
    public void Get_20_seconds_audio_sample(){
        
            Get_sample(RadioURI,AudioSampleFileName);
            Wait_20_seconds();
            Stop();
    }
    
     public void Stop()
            {
                mediaPlayer.Stop();            
            }

The Problem is that radio streming ususally starts with a commercial that lasts about 25 seconds. Every sample plays the commercial. It seems that Stop() closes the stream until Play() is called again and it restart the stream. I tired to pause the audio but, well...it makes no much sense to pause and play.

I can accept to get the commercial only in the first sample but then I want the regular radio audio. Is there a way not to close the stream every time? I am not tied to VideoLan dll so I can start from scratch if you have a better way to do it.


Solution

  • Use Audio callbacks and save the audio stream yourself. Full sample:

    class Program
        {
            // This sample shows you how you can use SetAudioFormatCallback and SetAudioCallbacks. It does two things:
            // 1) Play the sound from the specified video using NAudio
            // 2) Extract the sound into a file using NAudio
    
            static void Main(string[] args)
            {
                Core.Initialize();
    
                using var libVLC = new LibVLC(enableDebugLogs: true);
                using var media = new Media(libVLC,
                    new Uri("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4"),
                    ":no-video");
                using var mediaPlayer = new MediaPlayer(media);
    
                using var outputDevice = new WaveOutEvent();
                var waveFormat = new WaveFormat(8000, 16, 1);
                var writer = new WaveFileWriter("sound.wav", waveFormat);
                var waveProvider = new BufferedWaveProvider(waveFormat);
                outputDevice.Init(waveProvider);
    
                mediaPlayer.SetAudioFormatCallback(AudioSetup, AudioCleanup);
                mediaPlayer.SetAudioCallbacks(PlayAudio, PauseAudio, ResumeAudio, FlushAudio, DrainAudio);
    
                mediaPlayer.Play();
                mediaPlayer.Time = 20_000; // Seek the video 20 seconds
                outputDevice.Play();
    
                Console.WriteLine("Press 'q' to quit. Press any other key to pause/play.");
                while (true)
                {
                    if (Console.ReadKey().KeyChar == 'q')
                        break;
    
                    if (mediaPlayer.IsPlaying)
                        mediaPlayer.Pause();
                    else
                        mediaPlayer.Play();
                }
    
                void PlayAudio(IntPtr data, IntPtr samples, uint count, long pts)
                {
                    int bytes = (int)count * 2; // (16 bit, 1 channel)
                    var buffer = new byte[bytes];
                    Marshal.Copy(samples, buffer, 0, bytes);
    
                    waveProvider.AddSamples(buffer, 0, bytes);
                    writer.Write(buffer, 0, bytes);
                }
    
                int AudioSetup(ref IntPtr opaque, ref IntPtr format, ref uint rate, ref uint channels)
                {
                    channels = (uint)waveFormat.Channels;
                    rate = (uint)waveFormat.SampleRate;
                    return 0;
                }
    
                void DrainAudio(IntPtr data)
                {
                    writer.Flush();
                }
    
                void FlushAudio(IntPtr data, long pts)
                {
                    writer.Flush();
                    waveProvider.ClearBuffer();
                }
    
                void ResumeAudio(IntPtr data, long pts)
                {
                    outputDevice.Play();
                }
    
                void PauseAudio(IntPtr data, long pts)
                {
                    outputDevice.Pause();
                }
    
                void AudioCleanup(IntPtr opaque) { }
            }
        }