amerkoleci / Vortice.Windows

.NET bindings for Direct3D12, Direct3D11, WIC, Direct2D1, XInput, XAudio, X3DAudio, DXC, Direct3D9 and DirectInput.
MIT License
1.02k stars 73 forks source link

[Question] IMMNotificationClient interface? #213

Closed SuRGeoNix closed 2 years ago

SuRGeoNix commented 2 years ago

Hi @amerkoleci, I'm trying to replace NAudio with Vortice, so far so good! I'm having some trouble to create a IMMNotificationClient to handle the events (confused with that IntPtr in the constructor). What am I missing?

amerkoleci commented 2 years ago

Can you show me how you create IMMNotificationClient using NAudio? So I can add the missini API.

Thanks

SuRGeoNix commented 2 years ago

I just implement the interface here and I'm good to go (with deviceEnum.RegisterEndpointNotificationCallback(this)))

https://github.com/naudio/NAudio/blob/fb35ce8367f30b8bc5ea84e7d2529e172cf4c381/NAudio.Wasapi/CoreAudioApi/Interfaces/IMMNotificationClient.cs

Here is my code https://github.com/SuRGeoNix/Flyleaf/blob/master/FlyleafLib/AudioMaster.cs

That's your generated code:

/// <unmanaged>IMMNotificationClient</unmanaged>
/// <unmanaged-short>IMMNotificationClient</unmanaged-short>
[System.Runtime.InteropServices.GuidAttribute("7991EEC9-7E89-4D85-8390-6C703CEC60C0")]
public partial class IMMNotificationClient : SharpGen.Runtime.ComObject
{
    public IMMNotificationClient(System.IntPtr nativePtr): base(nativePtr)
    {
    }

    public static explicit operator IMMNotificationClient(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IMMNotificationClient(nativePtr);
    /// <unmanaged>HRESULT IMMNotificationClient::OnDeviceStateChanged([In] const wchar_t* pwstrDeviceId, [In] DWORD dwNewState)</unmanaged>
    /// <unmanaged-short>IMMNotificationClient::OnDeviceStateChanged</unmanaged-short>
    public unsafe void OnDeviceStateChanged(string pwstrDeviceId, int newState)
    {
        SharpGen.Runtime.Result __result__;
        fixed (char* pwstrDeviceId_ = pwstrDeviceId)
            __result__ = ((delegate* unmanaged[Stdcall]<System.IntPtr, void*, int, int> )this[3U])(NativePointer, (void*)pwstrDeviceId_, newState);
        __result__.CheckError();
    }

    /// <unmanaged>HRESULT IMMNotificationClient::OnDeviceAdded([In] const wchar_t* pwstrDeviceId)</unmanaged>
    /// <unmanaged-short>IMMNotificationClient::OnDeviceAdded</unmanaged-short>
    public unsafe void OnDeviceAdded(string pwstrDeviceId)
    {
        SharpGen.Runtime.Result __result__;
        fixed (char* pwstrDeviceId_ = pwstrDeviceId)
            __result__ = ((delegate* unmanaged[Stdcall]<System.IntPtr, void*, int> )this[4U])(NativePointer, (void*)pwstrDeviceId_);
        __result__.CheckError();
    }

    /// <unmanaged>HRESULT IMMNotificationClient::OnDeviceRemoved([In] const wchar_t* pwstrDeviceId)</unmanaged>
    /// <unmanaged-short>IMMNotificationClient::OnDeviceRemoved</unmanaged-short>
    public unsafe void OnDeviceRemoved(string pwstrDeviceId)
    {
        SharpGen.Runtime.Result __result__;
        fixed (char* pwstrDeviceId_ = pwstrDeviceId)
            __result__ = ((delegate* unmanaged[Stdcall]<System.IntPtr, void*, int> )this[5U])(NativePointer, (void*)pwstrDeviceId_);
        __result__.CheckError();
    }

    /// <unmanaged>HRESULT IMMNotificationClient::OnDefaultDeviceChanged([In] EDataFlow flow, [In] ERole role, [In] const wchar_t* pwstrDefaultDeviceId)</unmanaged>
    /// <unmanaged-short>IMMNotificationClient::OnDefaultDeviceChanged</unmanaged-short>
    public unsafe void OnDefaultDeviceChanged(Vortice.MediaFoundation.DataFlow flow, Vortice.MediaFoundation.Role role, string pwstrDefaultDeviceId)
    {
        SharpGen.Runtime.Result __result__;
        fixed (char* pwstrDefaultDeviceId_ = pwstrDefaultDeviceId)
            __result__ = ((delegate* unmanaged[Stdcall]<System.IntPtr, int, int, void*, int> )this[6U])(NativePointer, unchecked((int)flow), unchecked((int)role), (void*)pwstrDefaultDeviceId_);
        __result__.CheckError();
    }

    /// <unmanaged>HRESULT IMMNotificationClient::OnPropertyValueChanged([In] const wchar_t* pwstrDeviceId, [In] const PROPERTYKEY key)</unmanaged>
    /// <unmanaged-short>IMMNotificationClient::OnPropertyValueChanged</unmanaged-short>
    public unsafe void OnPropertyValueChanged(string pwstrDeviceId, SharpGen.Runtime.Win32.PropertyKey key)
    {
        SharpGen.Runtime.Result __result__;
        fixed (char* pwstrDeviceId_ = pwstrDeviceId)
            __result__ = ((delegate* unmanaged[Stdcall]<System.IntPtr, void*, SharpGen.Runtime.Win32.PropertyKey, int> )this[7U])(NativePointer, (void*)pwstrDeviceId_, key);
        __result__.CheckError();
    }
}
amerkoleci commented 2 years ago

I see, thanks!

Commit https://github.com/amerkoleci/Vortice.Windows/commit/8d9be436e1a2b8bedf051f721ea6312dbc301964 maps IMMNotificationClient as callback interface

SuRGeoNix commented 2 years ago

Nice, I will try to build it and tested

SuRGeoNix commented 2 years ago

Currently failed but I'm still looking...

deviceEnum.RegisterEndpointNotificationCallback(this);

InvalidOperationException: Operation is not valid due to the current state of the object.

This exception was originally thrown at this call stack:
    SharpGen.Runtime.MarshallingHelpers.ToCallbackPtr<TCallback>(SharpGen.Runtime.ICallbackable)
    Vortice.MediaFoundation.IMMDeviceEnumerator.RegisterEndpointNotificationCallback(Vortice.MediaFoundation.IMMNotificationClient) in Interfaces.cs
    FlyleafLib.AudioMaster.AudioMaster() in AudioMaster.cs
    FlyleafLib.Master.Master() in Master.cs

Got also

TypeInitializationException: The type initializer for 'FlyleafLib.Master' threw an exception.
SwitchExpressionException: Non-exhaustive switch expression failed to match its input.
Unmatched value was FlyleafLib.AudioMaster.
SuRGeoNix commented 2 years ago

This line complains

client_ = SharpGen.Runtime.MarshallingHelpers.ToCallbackPtr<Vortice.MediaFoundation.IMMNotificationClient>(client);
amerkoleci commented 2 years ago

You have to include CallbackBase as well, similar to this example: https://github.com/amerkoleci/Vortice.Windows/blob/main/src/samples/HelloDirect3D12/ShaderIncludeHandler.cs#L13

SuRGeoNix commented 2 years ago

It would be great if we can avoid this somehow tho!

SuRGeoNix commented 2 years ago

It seems that it misses the AudioSessions as well?