Search code examples
c#uwpnaudio

Playback of multiple Audiofiles with NAudio in UWP


I'm developing an universal app where several audio streams are played simultaneously. I'd need the ability to change the volume for each of my streams seperately. I tried to use the MixinSampleProvider, as is shown in Mark Heath's blog entry but I get a com exception when starting playback (in MediaFoundationReaderUniversal). I'm fairly new to NAudio so I'm a bit lost here. I researched already quite a bit but samples concerning UWP are pretty rare. Below is what I have already. What is the correct way/which class should I use?

This is what I have so far:

IStorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(path, UriKind.Absolute));
var stream = await file.OpenAsync(FileAccessMode.Read);
var player = new WasapiOutRT(AudioClientShareMode.Shared, 200);
player.Init(() => { return new MediaFoundationReaderUniversal(stream); });
player.Play();

Can I do what I want in an UWP-compatible way?

edit:

this is the exception I get, it's half in german but the important parts are in english. The last part says "interface not supported":

Unable to cast COM object of type 'System.__ComObject' to interface type 'NAudio.MediaFoundation.IMFSourceReader'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{70AE66F2-C809-4E4F-8915-BDCB406B7993}' failed due to the following error: Schnittstelle nicht unterstützt (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

in MediaFoundationReader.Read pReader.ReadSample(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, out actualStreamIndex, out dwFlags, out timestamp, out pSample);


Solution

  • Ok, I solved it myself, the problem is when I use a closure for the player.Init() Function, like this:

    IStorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(path, UriKind.Absolute));
    var stream = await file.OpenAsync(FileAccessMode.Read);
    var waveChannel32 = new WaveChannel32(new MediaFoundationReaderUniversal(stream));
    var mixer = new MixingSampleProvider(new ISampleProvider[] { waveChannel32.ToSampleProvider() });
    
    _audioOutput = new WasapiOutRT(AudioClientShareMode.Shared, 200);
    _audioOutput.Init(() =>
    {
        return mixer.ToWaveProvider();
    });
    _audioOutput.Play();
    

    when I change above code to this, no COM Exception is thrown and the code runs just fine:

    IStorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(path, UriKind.Absolute));
    var stream = await file.OpenAsync(FileAccessMode.Read);
    
    _audioOutput = new WasapiOutRT(AudioClientShareMode.Shared, 200);
    _audioOutput.Init(() =>
    {
        var waveChannel32 = new WaveChannel32(new MediaFoundationReaderUniversal(stream));
        var mixer = new MixingSampleProvider(new ISampleProvider[] { waveChannel32.ToSampleProvider() });
        return mixer.ToWaveProvider();
    });
    _audioOutput.Play();