Search code examples
c#audiodirectshowdirectshow.net

(c#) Playing and controlling multiple sound files using DirectShow


I have very little experience with DirectShow, so far I have managed paly a .wav file over a particular output device while being able to control its volume and get/set its track-position. Basically I’m able to create a very simple sound player application.

Here is the code I’m currently using:

    //select an output device          
    DsDevice[] devices = DsDevice.GetDevicesOfCat(FilterCategory.AudioRendererCategory 
    DsDevice device = (DsDevice)devices[xxx];

  
    //define a source          
    Guid iid = typeof(IBaseFilter).GUID; 
    object source = null;            
    device.Mon.BindToObject(null, null, ref iid, out source);          
           
    //build a basic graph to play the sound
    IGraphBuilder player_gra = (IGraphBuilder)new FilterGraph();                
    player_gra.AddFilter((IBaseFilter)source, "Audio Render");            
    player_gra.RenderFile(@"test.wav", "");                         
            
    //start the sound
    (player_gra as IMediaControl).Run();          
            
    //control the volume          
    (player_gra as IBasicAudio).put_Volume(volume);

    //get/set position on the track
    (player_gra as IMediaPosition).get_Duration(out out1);//how long the track is
    (player_gra as IMediaPosition).get_CurrentPosition(out out2);
    (player_gra as IMediaPosition).put_CurrentPosition(yyy);

What I would like to do now is to play several .wav files simultaneously while being able to control the volume and track-position of each file at runtime.

My first attempt was to create several IGraphBuilder instances and run them at the same time but it seem that only one can play at the same time while the others wait until the currently playing one is terminated via:

Marshal.ReleaseComObject(player_gra);  

My second attempt was to give the IGraphBuilder several Files to render before starting it.

…
player_gra.RenderFile(@"testA.wav", "");            
player_gra.RenderFile(@"testB.wav", "");            
player_gra.RenderFile(@"testC.wav", "");            
…

This way the files are played simultaneously but I see no way to control the volume of each individual sound, much less its position on the audio track.

Thank you in advance ;-)


Solution

  • In these lines

    DsDevice[] devices = DsDevice.GetDevicesOfCat(FilterCategory.AudioRendererCategory);
    DsDevice device = (DsDevice)devices[0];
    

    you enumerate audio output devices and pick the first "random" device which appears to be Default WaveOut Device or one of its instances.

    It has a legacy behavior that only one active instance is actually sending data to playback. There is no fundamental limitation in the system to prevent from simultaneous plyback, it is just legacy behavior.

    That is, you have both graph playing but audio from the second is muted.

    Audio mixing is disabled in the waveOut Audio Renderer, so if you need to mix multiple audio streams during playback, use the DirectSound renderer.

    If you use Default DirectSound Device instead (which you can quickly pick up by using different index in device[NNN] in code) you'll hear what you expect to hear.

    DirectShow.NET does the enumeration somehow confusingly, Default DirectSound Device normally has highest merit and is listed first and you seem to be given devices in different order.