Tuesday, June 5, 2012

c# Service Play Sound with NAudio example by Moshe

windows server 2008 or vista forword if u host a service W/O a user loggon the system wont start the audio devices.
to solve this u can use the dear NAudio Dll from http://naudio.codeplex.com/ - its open source.
but its a damn long (and helpful) code while u wont a simple service with only 1 CS page, so my Dear Team Chief and IT man Moshe reduced that to a single CS page just to play the sounds and here u go:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NAudio.Wave;
using NAudio.CoreAudioApi;
using System.ComponentModel.Composition;
using NAudio.Wave.SampleProviders;

namespace CallAndRead
{
   
public interface IInputFileFormatPlugin
   {
      
string Name { get; }
       string Extension { get; }
       WaveStream CreateWaveStream(string fileName);
   }
   

   [Export(typeof(IInputFileFormatPlugin))]
   class WaveInputFilePlugin : IInputFileFormatPlugin
   {
       public string Name
      { get { return "WAV file"; } }
       public string Extension
      { get { return ".wav"; } }

       public WaveStream CreateWaveStream(string fileName)
       {
             WaveStream readerStream = new WaveFileReader(fileName);
             if (readerStream.WaveFormat.Encoding != WaveFormatEncoding.Pcm
                   && readerStream.WaveFormat.Encoding != WaveFormatEncoding.IeeeFloat)
            {
                  readerStream =
WaveFormatConversionStream.CreatePcmStream(readerStream);
                  readerStream = new BlockAlignReductionStream(readerStream);
            }
            return readerStream;
      }
   }
   

   class WASAPI
   {
        public static void Concatenate(string outputFile, IEnumerable<string> sourceFiles)
        {
             byte[] buffer = new byte[1024];
             WaveFileWriter waveFileWriter = null;
             try
            {
                 foreach (string sourceFile in sourceFiles)
                 {
                        using (WaveFileReader reader = new WaveFileReader(sourceFile))
                        {
                               if (waveFileWriter == null)
                                   waveFileWriter = new WaveFileWriter(outputFile, reader.WaveFormat);
                               else
                              {
                                     if (!reader.WaveFormat.Equals(waveFileWriter.WaveFormat))
                                     throw new InvalidOperationException(
                                              "Can't concatenate WAV Files that don't share the same format");
                              }
                              int read;
                              while ((read = reader.Read(buffer, 0, buffer.Length)) > 0)
                             {
                                   waveFileWriter.WriteData(buffer, 0, read);
                             }
                      }
                }
            }
           
finally
           {
                if (waveFileWriter != null)
                     waveFileWriter.Dispose();
           }
      }

      private IWavePlayer waveOut = new WasapiOut(NAudio.CoreAudioApi.AudioClientShareMode.Shared, 300);
      WaveStream fileWaveStream;
      Action<float> setVolumeDelegate;

     [ImportMany(typeof(IInputFileFormatPlugin))]
     public IEnumerable<IInputFileFormatPlugin> InputFileFormats { get; set; }

     void OnPreVolumeMeter(object sender, NAudio.Wave.SampleProviders.StreamVolumeEventArgs e)
     {
          // we know it is stereo
          //w aveformPainter1.AddMax(e.MaxSampleValues[0]);
          //waveformPainter2.AddMax(e.MaxSampleValues[1]);
     }

      public ISampleProvider CreateInputStream(string fileName)
     {
  
        var plugin = new WaveInputFilePlugin();
           if (plugin == null)
                  throw new InvalidOperationException("Unsupported file extension");
           fileWaveStream = plugin.CreateWaveStream(fileName);
           var waveChannel = new NAudio.Wave.SampleProviders.SampleChannel(fileWaveStream);
           setVolumeDelegate = (vol) => waveChannel.Volume = vol;
           waveChannel.PreVolumeMeter += OnPreVolumeMeter;
           var postVolumeMeter = new MeteringSampleProvider(waveChannel);
           postVolumeMeter.StreamVolume += OnPostVolumeMeter;
           return postVolumeMeter;
     }

     
void OnPostVolumeMeter(object sender, StreamVolumeEventArgs e)
     {
           // we know it is stereo
           //volumeMeter1.Amplitude = e.MaxSampleValues[0];
          //volumeMeter2.Amplitude = e.MaxSampleValues[1];
      }

      public WASAPI(string fileName)
     {
            ISampleProvider sampleProvider = null;
            sampleProvider = CreateInputStream(fileName);
            waveOut.Init(
new SampleToWaveProvider(sampleProvider));
            waveOut.Play();
            return;
      }
   }
}


and what u need to do in ur app is simply this:
WASAPI Player = new WASAPI(path);
(advised to do sleep for it to finish and maybe player = null if ur the saving resources type)

ENJOY!

4 comments:

  1. does not worth to write this much of code to simply play a sound

    ReplyDelete
  2. Hello
    i am looking for someone for a small developing/programming project with IVR
    please contact me i pay for it
    asherdan@gmail.com

    ReplyDelete
  3. Excellent!
    I needed a way to play a sound in a windows service and this resolve that :D

    ReplyDelete