Click here to Skip to main content
15,867,568 members
Articles / Multimedia / Audio

Code to stream or convert MP3/WMA to PCM/WAV in Windows 8 (VB)

Rate me:
Please Sign up or sign in to vote.
4.70/5 (7 votes)
25 Sep 2012Public Domain6 min read 68.2K   2K   20   8
VB code to convert MP3 to WAV in Windows 8 using MediaFoundation

Introduction 

This code converts audio from MP3 or WMA into PCM or WAV format, on Windows 8. It's written in VB but the same techniques apply to C#. It can convert file:/// files stored locally on the hard disk, and also works with http:// files from the internet, and also mms:// streams.  

It uses the Media Foundation Source Reader API. 

Windows comes with built-in decoders for MP3 and WMA formats. It exposes these decoders through several APIs:  

  • MediaElement -  All UI frameworks have a MediaElement control - XAML for Windows 8, WPF, Silverlight, WinForms. They let you play audio and video. But they don't offer a way to get at the raw audio data.
     
  • MediaTranscoder - This API was introduced in Windows 8. It lets you transcode audio and video, e.g. changing video resolution, but its only audio target formats are MP3 and WMA: no WAV. There's an SDK-sample showing how to use it.
     
  • Audio Compression Manager - This legacy C++ API exposes decoding of MP3 files, but it's not allowed in Windows Store apps.
     
  • Windows Media Format SDK - This C++/COM API is for all things WMA-related, but it's not allowed in Windows Store apps.
     
  • Media Foundation Source Reader - The Media Foundation C++/COM API, introduced in Vista, is the successor to the old DirectShow. "Source Reader" is a standalone decoding part of it. Microsoft have a C++ sample showing how to use it to convert to WAV; this current article is largely based on that sample. Tamir Khason wrote a great article about using some parts of Media Foundation from C#: http://www.codeproject.com/Articles/239378/Video-encoder-and-metadata-reading-by-using-Window
     
  • XAudio2 - This C++/COM API is the successor to the old DirectSound. It's aimed at game developers.

NAudio. As a .NET developer, if you want audio, your first port of call should normally be http://naudio.codeplex.com/. NAudio is a high quality library, available through NuGet, licensed under MS-Pl, for adding audio to VB and C# apps. 

I wrote this article because (as of September 2012) NAudio is built on the Audio Compression Manager and Windows Media Format APIs,  neither of which are allowed in Windows Store apps. I needed to find a different solution. 

Using the Code 

COM interop and getting started

The IMFSourceReader COM object is the entry point into the Media Foundation Source Reader API. The APIs are only exposed by Microsoft to C++/COM. If you want to use them from VB or C# you need a lot of COM PInvoke interop.

VB
<MTAThread> 
Sub Main() 
    MFStartup(MF_VERSION) 
    Dim pReader As IMFSourceReader = Nothing
    MFCreateSourceReaderFromURL(source, Nothing, pReader) 

    ... 

    Runtime.InteropServices.Marshal.ReleaseComObject(pReader) : pReader = Nothing
    MFShutdown() 
End Sub     

In an audio application, you deal with large quantities of data, and it's important to release resources in a timely fashion. VB and C# use the IDispose mechanism for this, and rely on .NET garbage collection for everything else. C++/COM uses IUnknown.Release and reference-counting instead. It's difficult to bridge the gap between the two. For background information I suggest this MSDN article "Improving Interop Performance" and this C++ Team Blog article "Mixing deterministic and non-deterministic cleanup" and this blog by Lim Bio Liong "RCW Internal Reference Count". 

We will be concerned with the COM object created in the above code, which maintains an reference count, and the .NET Runtime Callable Wrapper (RCW) for it which has its own internal reference count. There's a one-to-one relationship between an RCW and a COM object's IUnknown IntPtr. The first time the IUnknown IntPtr enters managed code (e.g. through allocating a new COM object, or Marshal.ObjectFromIUnknown) then the RCW is created, its internal reference count is set to 1, and it calls IUnknown.AddRef just once. On subsequent times that the same IUnknown IntPtr enters managed code, then the RCW's internal reference count is incremented, but it doesn't call IUnknown.AddRef. The RCW's internal reference count gets decremented through natural garbage collection; you can also decrement it manually with Marshal.ReleaseComObject, or force it straight to 0 with Marshal.FinalReleaseComObject. When the RCW's internal reference count drops to 0 then it calls IUnknown.Release just once. Any further methods on it will fail with the message "COM object that has been separated from its underlying RCW cannot be used". 

Suggested practice: Make a wrapper class which implements IDisposable and which has a private field for the COM object (or more precisely, for its RCW). Never let your clients have direct access to the COM object. It's fine for local variables in your wrapper-class to reference the same RCW if needed. In IDisposable.Dispose, call Marshal.ReleaseComObject, set the field to Nothing, and make sure that your wrapper never accesses methods or fields of that field again. I haven't done that for this current article: I wanted to show how to use the Media Foundation APIs themselves, and leave it to a COM expert to write a good wrapper.  

 

Permissions to read local files on Windows 8 

In desktop apps, the above call to MFCreateSourceReaderFromURL will work fine for file:/// URLs, and for http:// and mms:// URLs, and you can also pass it relative or absolute filenames.

On Windows 8 app-store apps, MFCreateSourceReaderFromURL will work for internet http:// and mms:// URLs (if you have Internet Client privileges), and for ms-appx:/// URLs. But if you try it on filenames or file:/// URLs you'll get an access-denied error, even for files that you have access permissions to. Instead for local files you have to use MFCreateMFByteStreamOnStreamEx

VB.NET
Dim pReader As IMFSourceReader = Nothing
Dim src_file = Await Windows.Storage.StorageFile.GetFileFromPathAsync(src_uri.LocalPath)
Using src_stream = Await src_file.OpenAsync(Windows.Storage.FileAccessMode.Read)
    Dim src_bytestream As IMFByteStream = Nothing
    MFCreateMFByteStreamOnStreamEx(src_stream, src_bytestream)
    MFCreateSourceReaderFromByteStream(src_bytestream, Nothing, pReader)
    Runtime.InteropServices.Marshal.ReleaseComObject(src_bytestream)
End Using 

...

Runtime.InteropServices.Marshal.ReleaseComObject(pReader) : pReader = Nothing 

Picking the right audio format

We request the IMFSourceReader if it's able to give us decoded audio in the format we want (PCM data, 44100Hz, 2 channels, 16 bits per sample). It then tells us which media format it ended up picking for us.

VB
pReader.SetStreamSelection(MF_SOURCE_READER_ALL_STREAMS, False)
pReader.SetStreamSelection(MF_SOURCE_READER_FIRST_AUDIO_STREAM, True)
Dim pRequestedType As IMFMediaType = Nothing : MFCreateMediaType(pRequestedType)
pRequestedType.SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio)
pRequestedType.SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM)
pRequestedType.SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, 2)
pRequestedType.SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16)
pRequestedType.SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100)
pReader.SetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, Nothing, pRequestedType)
Runtime.InteropServices.Marshal.ReleaseComObject(pRequestedType) : pRequestedType = Nothing

Dim pAudioType As IMFMediaType = Nothing : pReader.GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, pAudioType)
Dim cbBlockSize = 0 : pAudioType.GetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, cbBlockSize)
Dim cbBytesPerSecond = 0 : pAudioType.GetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, cbBytesPerSecond)
Dim pWav As IntPtr, cbFormat As Integer : MFCreateWaveFormatExFromMFMediaType(pAudioType, pWav, cbFormat)
Dim wfx = New Byte(cbFormat - 1) {} : Runtime.InteropServices.Marshal.Copy(pWav, wfx, 0, cbFormat)
pReader.SetStreamSelection(MF_SOURCE_READER_FIRST_AUDIO_STREAM, True)
Runtime.InteropServices.Marshal.ReleaseComObject(pAudioType) : pAudioType = Nothing 

Writing the WAV file. Wav files have a straightforward format: a simple header, followed by the raw PCM data. 

VB
Dim header As Byte() =
     {CByte(AscW("R"c)), CByte(AscW("I"c)), CByte(AscW("F"c)), CByte(AscW("F"c)), 0, 0, 0, 0,
      CByte(AscW("W"c)), CByte(AscW("A"c)), CByte(AscW("V"c)), CByte(AscW("E"c)),
      CByte(AscW("f"c)), CByte(AscW("m"c)), CByte(AscW("t"c)), CByte(AscW(" "c)),
      CByte(cbFormat And 255), CByte((cbFormat >> 8) And 255),
      CByte((cbFormat >> 16) And 255), CByte((cbFormat >> 24) And 255)}
Dim dataHeader As Byte() =
     {CByte(AscW("d"c)), CByte(AscW("a"c)), _
      CByte(AscW("t"c)), CByte(AscW("a"c)), 0, 0, 0, 0}

Await dest.WriteAsync(header, 0, header.Length)
Await dest.WriteAsync(wfx, 0, wfx.Length)
Await dest.WriteAsync(dataHeader, 0, dataHeader.Length)
Runtime.InteropServices.Marshal.FreeCoTaskMem(pWav)
Dim cbHeader = header.Length + cbFormat + dataHeader.Length
Dim cbAudioData = 0


' Now a loop to get buffer after buffer from the MFSourceReader, and write it to disk:
' ...


' Some fields in the WAV file header need to be patched up, now that we know the correct sizes
Dim cbRiffFileSize = cbHeader + cbAudioData - 8
dest.Seek(4, IO.SeekOrigin.Begin) : Await dest.WriteAsync(BitConverter.GetBytes(cbRiffFileSize), 0, 4) 
dest.Seek(cbHeader - 4, IO.SeekOrigin.Begin) : Await dest.WriteAsync(BitConverter.GetBytes(cbAudioData), 0, 4)

Getting PCM Data out of IMFSourceReader

All that remains is the loop to get audio data out of IMFSourceReader

VB
Do
    Dim pSample As IMFSample = Nothing, dwFlags As Integer : _
        pReader.ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, 0, dwFlags, 0, pSample)
    If dwFlags <> 0 Then pSample = Nothing : Exit Do

    Dim pBuffer As IMFMediaBuffer = Nothing : pSample.ConvertToContiguousBuffer(pBuffer)
    Dim pAudioData As IntPtr, cbBuffer As Integer : pBuffer.Lock(pAudioData, Nothing, cbBuffer)
    Dim buf = New Byte(cbBuffer - 1) {} : Runtime.InteropServices.Marshal.Copy(pAudioData, buf, 0, cbBuffer)

    Await dest.WriteAsync(buf, 0, cbBuffer) : cbAudioData += cbBuffer

    pBuffer.Unlock()
    Runtime.InteropServices.Marshal.ReleaseComObject(pBuffer) : pBuffer = Nothing
    Runtime.InteropServices.Marshal.ReleaseComObject(pSample) : pSample = Nothing
Loop 

Invoke interop libraries for Media Foundation

All that's left is a huge pinvoke interop library. It took me several days to piece all this together.

I'm not a pinvoke expert by any means. I bet there are bugs in this definitions, and I'm sure they don't embody best-practice.

VB
Module Interop

    <Runtime.InteropServices.DllImport("mfplat.dll", ExactSpelling:=True, PreserveSig:=False)>
    Sub MFStartup(Version As Integer, Optional dwFlags As Integer = 0)
    End Sub

    <Runtime.InteropServices.DllImport("mfplat.dll", ExactSpelling:=True, PreserveSig:=False)>
    Public Sub MFShutdown()
    End Sub

    <Runtime.InteropServices.DllImport("mfplat.dll", ExactSpelling:=True, PreserveSig:=False)>
    Public Sub MFCreateMediaType(ByRef ppMFType As IMFMediaType)
    End Sub

    <Runtime.InteropServices.DllImport("mfplat.dll", ExactSpelling:=True, PreserveSig:=False)>
    Public Sub MFCreateWaveFormatExFromMFMediaType(pMFType As IMFMediaType, _
           ByRef ppWF As IntPtr, ByRef pcbSize As Integer, Optional Flags As Integer = 0)
    End Sub

    <Runtime.InteropServices.DllImport("mfreadwrite.dll", ExactSpelling:=True, PreserveSig:=False)>
    Public Sub MFCreateSourceReaderFromURL(<Runtime.InteropServices.MarshalAs( _
       Runtime.InteropServices.UnmanagedType.LPWStr)> pwszURL As String, _
       pAttributes As IntPtr, ByRef ppSourceReader As IMFSourceReader)
    End Sub

    <Runtime.InteropServices.DllImport("mfreadwrite.dll", ExactSpelling:=True, PreserveSig:=False)>
    Public Sub MFCreateSourceReaderFromByteStream(pByteStream As IMFByteStream, _
       pAttributes As IntPtr, ByRef ppSourceReader As IMFSourceReader)
    End Sub

    <Runtime.InteropServices.DllImport("mfplat.dll", ExactSpelling:=True, PreserveSig:=False)>
    Public Sub MFCreateMFByteStreamOnStreamEx(<Runtime.InteropServices.MarshalAs( _
       Runtime.InteropServices.UnmanagedType.IUnknown)> punkStream As Object, _
       ByRef ppByteStream As IMFByteStream)
    End Sub


    Public Const MF_SOURCE_READER_ALL_STREAMS As Integer = &HFFFFFFFE
    Public Const MF_SOURCE_READER_FIRST_AUDIO_STREAM As Integer = &HFFFFFFFD
    Public Const MF_SDK_VERSION As Integer = &H2
    Public Const MF_API_VERSION As Integer = &H70
    Public Const MF_VERSION As Integer = (MF_SDK_VERSION << 16) Or MF_API_VERSION
    Public ReadOnly MF_MT_MAJOR_TYPE As New Guid("48eba18e-f8c9-4687-bf11-0a74c9f96a8f")
    Public ReadOnly MF_MT_SUBTYPE As New Guid("f7e34c9a-42e8-4714-b74b-cb29d72c35e5")
    Public ReadOnly MF_MT_AUDIO_BLOCK_ALIGNMENT As New Guid("322de230-9eeb-43bd-ab7a-ff412251541d")
    Public ReadOnly MF_MT_AUDIO_AVG_BYTES_PER_SECOND As New Guid("1aab75c8-cfef-451c-ab95-ac034b8e1731")
    Public ReadOnly MF_MT_AUDIO_NUM_CHANNELS As New Guid("37e48bf5-645e-4c5b-89de-ada9e29b696a")
    Public ReadOnly MF_MT_AUDIO_SAMPLES_PER_SECOND As New Guid("5faeeae7-0290-4c31-9e8a-c534f68d9dba")
    Public ReadOnly MF_MT_AUDIO_BITS_PER_SAMPLE As New Guid("f2deb57f-40fa-4764-aa33-ed4f2d1ff669")
    Public ReadOnly MFMediaType_Audio As New Guid("73647561-0000-0010-8000-00AA00389B71")
    Public ReadOnly MFAudioFormat_PCM As New Guid("00000001-0000-0010-8000-00AA00389B71")

    <Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType( _
       Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), _
       Runtime.InteropServices.Guid("70ae66f2-c809-4e4f-8915-bdcb406b7993")>
    Public Interface IMFSourceReader
        Sub GetStreamSelection(<Runtime.InteropServices.In> _
            dwStreamIndex As Integer, <Runtime.InteropServices.Out> ByRef pSelected As Boolean)
        Sub SetStreamSelection(<Runtime.InteropServices.In> _
            dwStreamIndex As Integer, <Runtime.InteropServices.In> pSelected As Boolean)
        Sub GetNativeMediaType(<Runtime.InteropServices.In> dwStreamIndex As Integer, _
            <Runtime.InteropServices.In> dwMediaTypeIndex As Integer, _
            <Runtime.InteropServices.Out> ByRef ppMediaType As IntPtr)
        Sub GetCurrentMediaType(<Runtime.InteropServices.In> dwStreamIndex As Integer, _
            <Runtime.InteropServices.Out> ByRef ppMediaType As IMFMediaType)
        Sub SetCurrentMediaType(<Runtime.InteropServices.In> dwStreamIndex _
            As Integer, pdwReserved As IntPtr, <Runtime.InteropServices.In> pMediaType As IMFMediaType)
        Sub SetCurrentPosition(<Runtime.InteropServices.In, _
            Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
            guidTimeFormat As Guid, <Runtime.InteropServices.In> varPosition As Object)
        Sub ReadSample(<Runtime.InteropServices.In> dwStreamIndex As Integer, _
            <Runtime.InteropServices.In> dwControlFlags As Integer, _
            <Runtime.InteropServices.Out> ByRef pdwActualStreamIndex As Integer, _
            <Runtime.InteropServices.Out> ByRef pdwStreamFlags As Integer, _
            <Runtime.InteropServices.Out> ByRef pllTimestamp As UInt64, _
            <Runtime.InteropServices.Out> ByRef ppSample As IMFSample)
        Sub Flush(<Runtime.InteropServices.In> dwStreamIndex As Integer)
        Sub GetServiceForStream(<Runtime.InteropServices.In> dwStreamIndex As Integer, _
            <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidService As Guid, _
            <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> riid As Guid, _
            <Runtime.InteropServices.Out> ByRef ppvObject As IntPtr)
        Sub GetPresentationAttribute(<Runtime.InteropServices.In> _
            dwStreamIndex As Integer, <Runtime.InteropServices.In, _
            Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
            guidAttribute As Guid, <Runtime.InteropServices.Out> pvarAttribute As IntPtr)
    End Interface


    <Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType( _
       Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), _
       Runtime.InteropServices.Guid("2CD2D921-C447-44A7-A13C-4ADABFC247E3")>
    Public Interface IMFAttributes
        Sub GetItem(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, pValue As IntPtr)
        Sub GetItemType(<Runtime.InteropServices.In, _
            Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
            guidKey As Guid, ByRef pType As Integer)
        Sub CompareItem(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
            Value As IntPtr, <Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.Bool)> ByRef pbResult As Boolean)
        Sub Compare(<Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.Interface)> _
            pTheirs As IMFAttributes, MatchType As Integer, _
            <Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.Bool)> ByRef pbResult As Boolean)
        Sub GetUINT32(<Runtime.InteropServices.In, _
            Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
            guidKey As Guid, ByRef punValue As Integer)
        Sub GetUINT64(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef punValue As Long)
        Sub GetDouble(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pfValue As Double)
        Sub GetGUID(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pguidValue As Guid)
        Sub GetStringLength(<Runtime.InteropServices.In, _
            Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
            guidKey As Guid, ByRef pcchLength As Integer)
        Sub GetString(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
            <Runtime.InteropServices.Out, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPWStr)> pwszValue As Text.StringBuilder, _
            cchBufSize As Integer, ByRef pcchLength As Integer)
        Sub GetAllocatedString(<Runtime.InteropServices.In, _
            Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
            guidKey As Guid, <Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPWStr)> ByRef ppwszValue As String, ByRef pcchLength As Integer)
        Sub GetBlobSize(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pcbBlobSize As Integer)
        Sub GetBlob(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
            <Runtime.InteropServices.Out, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPArray)> pBuf As Byte(), _
            cbBufSize As Integer, ByRef pcbBlobSize As Integer)
        Sub GetAllocatedBlob(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef ip As IntPtr, ByRef pcbSize As Integer)
        Sub GetUnknown(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
            <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> riid As Guid, _
            <Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.IUnknown)> ByRef ppv As Object)
        Sub SetItem(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, Value As IntPtr)
        Sub DeleteItem(<Runtime.InteropServices.In, _
            Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid)
        Sub DeleteAllItems()
        Sub SetUINT32(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, unValue As Integer)
        Sub SetUINT64(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, unValue As Long)
        Sub SetDouble(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, fValue As Double)
        Sub SetGUID(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
            <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidValue As Guid)
        Sub SetString(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
            <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPWStr)> wszValue As String)
        Sub SetBlob(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
            <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.LPArray, SizeParamIndex:=2)> pBuf As Byte(), cbBufSize As Integer)
        Sub SetUnknown(<Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
            guidKey As Guid, <Runtime.InteropServices.In, _
            Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.IUnknown)> pUnknown As Object)
        Sub LockStore()
        Sub UnlockStore()
        Sub GetCount(ByRef pcItems As Integer)
        Sub GetItemByIndex(unIndex As Integer, ByRef pguidKey As Guid, pValue As IntPtr)
        Sub CopyAllItems(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
            Runtime.InteropServices.UnmanagedType.Interface)> pDest As IMFAttributes)
    End Interface


    <Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType( _
        Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), _
        Runtime.InteropServices.Guid("44AE0FA8-EA31-4109-8D2E-4CAE4997C555")>
    Public Interface IMFMediaType
        Inherits IMFAttributes
        Overloads Sub GetItem(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, pValue As IntPtr)
        Overloads Sub GetItemType(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, ByRef pType As Integer)
        Overloads Sub CompareItem(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, Value As IntPtr, <Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.Bool)> ByRef pbResult As Boolean)
        Overloads Sub Compare(<Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.Interface)> _
                  pTheirs As IMFAttributes, MatchType As Integer, _
                  <Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.Bool)> ByRef pbResult As Boolean)
        Overloads Sub GetUINT32(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, ByRef punValue As Integer)
        Overloads Sub GetUINT64(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef punValue As Long)
        Overloads Sub GetDouble(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pfValue As Double)
        Overloads Sub GetGUID(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pguidValue As Guid)
        Overloads Sub GetStringLength(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pcchLength As Integer)
        Overloads Sub GetString(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
                  <Runtime.InteropServices.Out, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPWStr)> pwszValue _
                  As Text.StringBuilder, cchBufSize As Integer, ByRef pcchLength As Integer)
        Overloads Sub GetAllocatedString(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, <Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPWStr)> _
                  ByRef ppwszValue As String, ByRef pcchLength As Integer)
        Overloads Sub GetBlobSize(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pcbBlobSize As Integer)
        Overloads Sub GetBlob(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, <Runtime.InteropServices.Out, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPArray)> pBuf As Byte(), _
                  cbBufSize As Integer, ByRef pcbBlobSize As Integer)
        Overloads Sub GetAllocatedBlob(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, ByRef ip As IntPtr, ByRef pcbSize As Integer)
        Overloads Sub GetUnknown(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> riid As Guid, _
                  <Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.IUnknown)> ByRef ppv As Object)
        Overloads Sub SetItem(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, Value As IntPtr)
        Overloads Sub DeleteItem(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid)
        Overloads Sub DeleteAllItems()
        Overloads Sub SetUINT32(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, unValue As Integer)
        Overloads Sub SetUINT64(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, unValue As Long)
        Overloads Sub SetDouble(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, fValue As Double)
        Overloads Sub SetGUID(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
                  <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidValue As Guid)
        Overloads Sub SetString(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
                  <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPWStr)> wszValue As String)
        Overloads Sub SetBlob(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
                  <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPArray, SizeParamIndex:=2)> pBuf As Byte(), cbBufSize As Integer)
        Overloads Sub SetUnknown(<Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
                  <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.IUnknown)> pUnknown As Object)
        Overloads Sub LockStore()
        Overloads Sub UnlockStore()
        Overloads Sub GetCount(ByRef pcItems As Integer)
        Overloads Sub GetItemByIndex(unIndex As Integer, ByRef pguidKey As Guid, pValue As IntPtr)
        Overloads Sub CopyAllItems(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.Interface)> pDest As IMFAttributes)
        '
        Sub GetMajorType(ByRef pguidMajorType As Guid)
        Sub IsCompressedFormat(<Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.Bool)> ByRef pfCompressed As Boolean)
        <Runtime.InteropServices.PreserveSig> Function IsEqual(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.Interface)> _
                  pIMediaType As IMFMediaType, ByRef pdwFlags As Integer) As Integer
        Sub GetRepresentation(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.Struct)> guidRepresentation As Guid, _
                  ByRef ppvRepresentation As IntPtr)
        Sub FreeRepresentation(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.Struct)> _
                  guidRepresentation As Guid, <Runtime.InteropServices.In> pvRepresentation As IntPtr)
    End Interface


    <Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType( _
                  Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), _
                  Runtime.InteropServices.Guid("c40a00f2-b93a-4d80-ae8c-5a1c634f58e4")>
    Public Interface IMFSample
        Inherits IMFAttributes
        Overloads Sub GetItem(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, pValue As IntPtr)
        Overloads Sub GetItemType(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pType As Integer)
        Overloads Sub CompareItem(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
                  Value As IntPtr, <Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.Bool)> ByRef pbResult As Boolean)
        Overloads Sub Compare(<Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.Interface)> _
                  pTheirs As IMFAttributes, MatchType As Integer, _
                  <Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.Bool)> ByRef pbResult As Boolean)
        Overloads Sub GetUINT32(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, ByRef punValue As Integer)
        Overloads Sub GetUINT64(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, ByRef punValue As Long)
        Overloads Sub GetDouble(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, ByRef pfValue As Double)
        Overloads Sub GetGUID(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pguidValue As Guid)
        Overloads Sub GetStringLength(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pcchLength As Integer)
        Overloads Sub GetString(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
                  <Runtime.InteropServices.Out, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPWStr)> _
                  pwszValue As Text.StringBuilder, cchBufSize As Integer, ByRef pcchLength As Integer)
        Overloads Sub GetAllocatedString(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, <Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPWStr)> _
                  ByRef ppwszValue As String, ByRef pcchLength As Integer)
        Overloads Sub GetBlobSize(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, ByRef pcbBlobSize As Integer)
        Overloads Sub GetBlob(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
                  <Runtime.InteropServices.Out, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPArray)> pBuf As Byte(), _
                  cbBufSize As Integer, ByRef pcbBlobSize As Integer)
        Overloads Sub GetAllocatedBlob(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, ByRef ip As IntPtr, ByRef pcbSize As Integer)
        Overloads Sub GetUnknown(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
                  <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> riid As Guid, _
                  <Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.IUnknown)> ByRef ppv As Object)
        Overloads Sub SetItem(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, Value As IntPtr)
        Overloads Sub DeleteItem(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid)
        Overloads Sub DeleteAllItems()
        Overloads Sub SetUINT32(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, unValue As Integer)
        Overloads Sub SetUINT64(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, unValue As Long)
        Overloads Sub SetDouble(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, fValue As Double)
        Overloads Sub SetGUID(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
                  <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidValue As Guid)
        Overloads Sub SetString(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> _
                  guidKey As Guid, <Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPWStr)> _
                  wszValue As String)
        Overloads Sub SetBlob(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
                  <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPArray, SizeParamIndex:=2)> pBuf As Byte(), cbBufSize As Integer)
        Overloads Sub SetUnknown(<Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
                  <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.IUnknown)> pUnknown As Object)
        Overloads Sub LockStore()
        Overloads Sub UnlockStore()
        Overloads Sub GetCount(ByRef pcItems As Integer)
        Overloads Sub GetItemByIndex(unIndex As Integer, ByRef pguidKey As Guid, pValue As IntPtr)
        Overloads Sub CopyAllItems(<Runtime.InteropServices.In, _
                  Runtime.InteropServices.MarshalAs( _
                  Runtime.InteropServices.UnmanagedType.Interface)> pDest As IMFAttributes)
        '
        Sub GetSampleFlags(ByRef pdwSampleFlags As Integer)
        Sub SetSampleFlags(dwSampleFlags As Integer)
        Sub GetSampleTime(ByRef phnsSampletime As Long)
        Sub SetSampleTime(hnsSampleTime As Long)
        Sub GetSampleDuration(ByRef phnsSampleDuration As Long)
        Sub SetSampleDuration(hnsSampleDuration As Long)
        Sub GetBufferCount(ByRef pdwBufferCount As Integer)
        Sub GetBufferByIndex(dwIndex As Integer, ByRef ppBuffer As IMFMediaBuffer)
        Sub ConvertToContiguousBuffer(ByRef ppBuffer As IMFMediaBuffer)
        Sub AddBuffer(pBuffer As IMFMediaBuffer)
        Sub RemoveBuferByindex(dwIndex As Integer)
        Sub RemoveAllBuffers()
        Sub GetTotalLength(ByRef pcbTotalLength As Integer)
        Sub CopyToByffer(pBuffer As IMFMediaBuffer)
    End Interface


    <Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType( _
                  Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), _
                  Runtime.InteropServices.Guid("045FA593-8799-42b8-BC8D-8968C6453507")>
    Public Interface IMFMediaBuffer
        Sub Lock(ByRef ppbBuffer As IntPtr, ByRef pcbMaxLength As Integer, ByRef pcbCurrentLength As Integer)
        Sub Unlock()
        Sub GetCurrentLength(ByRef pcbCurrentLength As Integer)
        Sub SetCurrentLength(cbCurrentLength As Integer)
        Sub GetMaxLength(ByRef pcbMaxLength As Integer)
    End Interface

    <Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType( _
                  Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), _
                  Runtime.InteropServices.Guid("ad4c1b00-4bf7-422f-9175-756693d9130d")>
    Public Interface IMFByteStream
        Sub GetCapabilities(ByRef pdwCapabiities As Integer)
        Sub GetLength(ByRef pqwLength As Long)
        Sub SetLength(qwLength As Long)
        Sub GetCurrentPosition(ByRef pqwPosition As Long)
        Sub SetCurrentPosition(qwPosition As Long)
        Sub IsEndOfStream(<Runtime.InteropServices.MarshalAs( _
              Runtime.InteropServices.UnmanagedType.Bool)> ByRef pfEndOfStream As Boolean)
        Sub Read(pb As IntPtr, cb As Integer, ByRef pcbRead As Integer)
        Sub BeginRead(pb As IntPtr, cb As Integer, pCallback As IntPtr, punkState As IntPtr)
        Sub EndRead(pResult As IntPtr, ByRef pcbRead As Integer)
        Sub Write(pb As IntPtr, cb As Integer, ByRef pcbWritten As Integer)
        Sub BeginWrite(pb As IntPtr, cb As Integer, pCallback As IntPtr, punkState As IntPtr)
        Sub EndWrite(pResult As IntPtr, ByRef pcbWritten As Integer)
        Sub Seek(SeekOrigin As Integer, llSeekOffset As Long, dwSeekFlags As Integer, ByRef pqwCurrentPosition As Long)
        Sub Flush()
        Sub Close()
    End Interface

End Module             

Notes

Using Await with MediaElement

In the accompanying code, I provide a Windows 8 app-store app that demonstrates IMFSourceReader. It uses a MediaElement to play the WAV file that we produce. Normally you deal with MediaElements by signing up event-handlers for their Completed events. I don't like callbacks or event-handlers. I much prefer to Await a MediaElement. So I created my own helper function:

Await MediaElement.EndedAsync()

VB.NET
MediaElement1.SetSource(stream, "audio/wav")
MediaElement1.Play()
Await MediaElement1.EndedAsync() 

The new VB/C# Await and Async keywords, in Visual Studio 2012, let you make any type awaitable even if it isn't already awaitable itself through you providing a helper function. Here's mine: 

VBScript
<Extension>
Function EndedAsync(m As MediaElement) As Task
    Dim tcs As New TaskCompletionSource(Of Object)
    Dim handlerEnded As RoutedEventHandler = Nothing
    Dim handlerChanged As RoutedEventHandler = Nothing
    Dim handlerFailed As ExceptionRoutedEventHandler = Nothing
    handlerEnded =
        Sub(s, e)
            RemoveHandler m.MediaEnded, handlerEnded
            RemoveHandler m.CurrentStateChanged, handlerChanged
            RemoveHandler m.MediaFailed, handlerFailed
            tcs.TrySetResult(Nothing)
        End Sub
    handlerChanged =
        Sub(s, e)
            If m.CurrentState <> MediaElementState.Closed AndAlso m.CurrentState _
                  <> MediaElementState.Stopped Then Return
            RemoveHandler m.MediaEnded, handlerEnded
            RemoveHandler m.CurrentStateChanged, handlerChanged
            RemoveHandler m.MediaFailed, handlerFailed
            tcs.TrySetResult(Nothing)
        End Sub
    handlerFailed = 
        Sub(s, e)
            RemoveHandler m.MediaEnded, handlerEnded
            RemoveHandler m.CurrentStateChanged, handlerChanged
            RemoveHandler m.MediaFailed, handlerFailed
            tcs.TrySetException(New Exception(e.ErrorMessage))
        End Sub
    AddHandler m.MediaEnded, handlerEnded
    AddHandler m.CurrentStateChanged, handlerChanged
    AddHandler m.MediaFailed, handlerFailed
    If m.CurrentState = MediaElementState.Closed OrElse m.CurrentState = _
                  MediaElementState.Stopped Then tcs.TrySetResult(Nothing)
    Return tcs.Task
End Function

Disclaimer: although I work at Microsoft on the VB/C# language team, this article is strictly an personal amateur effort based on public information and experimentation - it's not in my professional area of expertise, is written in my own free time not as a representative of Microsoft, and neither Microsoft nor I make any claims about its correctness.

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication


Written By
Technical Lead
United States United States
Lucian studied theoretical computer science in Cambridge and Bologna, and then moved into the computer industry. Since 2004 he's been paid to do what he loves -- designing and implementing programming languages! The articles he writes on CodeProject are entirely his own personal hobby work, and do not represent the position or guidance of the company he works for. (He's on the VB/C# language team at Microsoft).

Comments and Discussions

 
QuestionGreat Pin
jfriedman23-Jul-14 22:56
jfriedman23-Jul-14 22:56 
Question非常有价值 Pin
happyokok25-Dec-12 20:38
happyokok25-Dec-12 20:38 
SuggestionC# version. Pin
Member 962469923-Nov-12 2:59
Member 962469923-Nov-12 2:59 
QuestionAwesome Pin
Mark Heath22-Nov-12 22:15
Mark Heath22-Nov-12 22:15 
AnswerRe: Awesome Pin
ljw100423-Nov-12 5:13
ljw100423-Nov-12 5:13 
GeneralRe: Awesome Pin
Mark Heath23-Nov-12 5:15
Mark Heath23-Nov-12 5:15 
QuestionMy Vote of 5 Pin
atmonline17-Oct-12 14:35
atmonline17-Oct-12 14:35 
GeneralMy vote of 5 Pin
Kanasz Robert20-Sep-12 1:43
professionalKanasz Robert20-Sep-12 1:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.