Skip to content

Commit

Permalink
Merge pull request #276 from microsoft/pete-dev
Browse files Browse the repository at this point in the history
Network MIDI 2.0 abstraction scaffolding
  • Loading branch information
Psychlist1972 authored Feb 14, 2024
2 parents c374e8f + 0dc531a commit 78e0db2
Show file tree
Hide file tree
Showing 22 changed files with 690 additions and 178 deletions.
2 changes: 1 addition & 1 deletion build/staging/version/BundleInfo.wxi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Include>
<?define SetupVersionName="Developer Preview 5" ?>
<?define SetupVersionNumber="1.0.24044.1942" ?>
<?define SetupVersionNumber="1.0.24044.2146" ?>
</Include>
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Loopback endpoints created by the user and stored in the configuration file will

For plugins which support updates at runtime, developers of those plugins should create configuration WinRT types which implement the required configuration interfaces, and create the JSON that is used in the service. In this way, third-party service transport and message processing plugins can be created and configured without changes to the API.

> Note: In version 1 of the API, only transports can be configured at runtime. We're working on enabling configuration of message processing plugins.
> Note: In version 1 of the API, only transports can be configured at runtime. We're working on enabling configuration of message processing plugins. The API is a no-op.
## Static Functions : Service Health

Expand Down
41 changes: 41 additions & 0 deletions src/api/Abstraction/NetworkMidiAbstraction/AbstractionState.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License
// ============================================================================
// This is part of the Windows MIDI Services App API and should be used
// in your Windows application via an official binary distribution.
// Further information: https://github.com/microsoft/MIDI/
// ============================================================================

#include "pch.h"


AbstractionState::AbstractionState() = default;
AbstractionState::~AbstractionState() = default;

AbstractionState& AbstractionState::Current()
{
// explanation: http://www.modernescpp.com/index.php/thread-safe-initialization-of-data/

static AbstractionState current;

return current;
}



HRESULT
AbstractionState::ConstructEndpointManager()
{
RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize<CMidi2NetworkMidiEndpointManager>(&m_endpointManager));

return S_OK;
}


HRESULT
AbstractionState::ConstructConfigurationManager()
{
RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize<CMidi2NetworkMidiConfigurationManager>(&m_configurationManager));

return S_OK;
}
62 changes: 62 additions & 0 deletions src/api/Abstraction/NetworkMidiAbstraction/AbstractionState.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License
// ============================================================================
// This is part of the Windows MIDI Services App API and should be used
// in your Windows application via an official binary distribution.
// Further information: https://github.com/microsoft/MIDI/
// ============================================================================


#pragma once

// singleton
class AbstractionState
{

public:
static AbstractionState& Current();

// no copying
AbstractionState(_In_ const AbstractionState&) = delete;
AbstractionState& operator=(_In_ const AbstractionState&) = delete;


wil::com_ptr<CMidi2NetworkMidiEndpointManager> GetEndpointManager()
{
return m_endpointManager;
}

wil::com_ptr<CMidi2NetworkMidiConfigurationManager> GetConfigurationManager()
{
return m_configurationManager;
}

std::shared_ptr<MidiNetworkDeviceTable> GetEndpointTable()
{
return m_endpointTable;
}


HRESULT Cleanup()
{
m_endpointManager.reset();
m_configurationManager.reset();

return S_OK;
}


HRESULT ConstructEndpointManager();
HRESULT ConstructConfigurationManager();


private:
AbstractionState();
~AbstractionState();


wil::com_ptr<CMidi2NetworkMidiEndpointManager> m_endpointManager;
wil::com_ptr<CMidi2NetworkMidiConfigurationManager> m_configurationManager;

std::shared_ptr<MidiNetworkDeviceTable> m_endpointTable = std::make_shared<MidiNetworkDeviceTable>();
};
Original file line number Diff line number Diff line change
Expand Up @@ -58,33 +58,66 @@ CMidi2NetworkMidiAbstraction::Activate(

TraceLoggingWrite(
MidiNetworkMidiAbstractionTelemetryProvider::Provider(),
__FUNCTION__ "- Midi BiDi",
__FUNCTION__ "- IMidiBiDi",
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
TraceLoggingValue(__FUNCTION__),
TraceLoggingWideString(L"IMidiBiDi", "requested interface"),
TraceLoggingPointer(this, "this")
);

wil::com_ptr_nothrow<IMidiBiDi> midiBiDi;
RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize<CMidi2NetworkMidiBiDi>(&midiBiDi));
*Interface = midiBiDi.detach();
}


else if (__uuidof(IMidiEndpointManager) == Riid)
{
TraceLoggingWrite(
MidiNetworkMidiAbstractionTelemetryProvider::Provider(),
__FUNCTION__ "- Midi Endpoint Manager",
__FUNCTION__ "- IMidiEndpointManager",
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
TraceLoggingValue(__FUNCTION__),
TraceLoggingWideString(L"IMidiEndpointManager", "requested interface"),
TraceLoggingPointer(this, "this")
);

// check to see if this is the first time we're creating the endpoint manager. If so, create it.
if (AbstractionState::Current().GetEndpointManager() == nullptr)
{
AbstractionState::Current().ConstructEndpointManager();
}

RETURN_IF_FAILED(AbstractionState::Current().GetEndpointManager()->QueryInterface(Riid, Interface));
}


else if (__uuidof(IMidiAbstractionConfigurationManager) == Riid)
{
TraceLoggingWrite(
MidiNetworkMidiAbstractionTelemetryProvider::Provider(),
__FUNCTION__,
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
TraceLoggingWideString(L"IMidiAbstractionConfigurationManager", "requested interface"),
TraceLoggingPointer(this, "this")
);

wil::com_ptr_nothrow<IMidiEndpointManager> midiEndpointManager;
RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize<CMidi2NetworkMidiEndpointManager>(&midiEndpointManager));
*Interface = midiEndpointManager.detach();
// check to see if this is the first time we're creating the configuration manager. If so, create it.
if (AbstractionState::Current().GetConfigurationManager() == nullptr)
{
AbstractionState::Current().ConstructConfigurationManager();
}

RETURN_IF_FAILED(AbstractionState::Current().GetConfigurationManager()->QueryInterface(Riid, Interface));
}

else
{
OutputDebugString(L"" __FUNCTION__ " Returning E_NOINTERFACE. Was an interface added that isn't handled in the Abstraction?");
TraceLoggingWrite(
MidiNetworkMidiAbstractionTelemetryProvider::Provider(),
__FUNCTION__,
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
TraceLoggingWideString(L"Unknown or invalid interface request", "message"),
TraceLoggingPointer(this, "this")
);

return E_NOINTERFACE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,10 @@
</Midl>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="AbstractionState.cpp" />
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="Midi2.NetworkMidiAbstraction.cpp" />
<ClCompile Include="Midi2.NetworkMidiConfigurationManager.cpp" />
<ClCompile Include="Midi2.NetworkMidiEndpointManager.cpp" />
<ClCompile Include="Midi2.NetworkMidiBidi.cpp" />
<ClCompile Include="Midi2.NetworkMidiIn.cpp" />
Expand All @@ -291,13 +293,18 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AbstractionState.h" />
<ClInclude Include="abstraction_defs.h" />
<ClInclude Include="dllmain.h" />
<ClInclude Include="Midi2.NetworkMidiAbstraction.h" />
<ClInclude Include="Midi2.NetworkMidiConfigurationManager.h" />
<ClInclude Include="Midi2.NetworkMidiEndpointManager.h" />
<ClInclude Include="Midi2.NetworkMidiBidi.h" />
<ClInclude Include="Midi2.NetworkMidiIn.h" />
<ClInclude Include="Midi2.NetworkMidiOut.h" />
<ClInclude Include="MidiNetworkDevice.h" />
<ClInclude Include="MidiNetworkDeviceDefinition.h" />
<ClInclude Include="MidiNetworkDeviceTable.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="Resource.h" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@
<ClCompile Include="Midi2.NetworkMidiOut.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Midi2.NetworkMidiConfigurationManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AbstractionState.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Midl Include="Midi2NetworkMidiAbstraction.idl">
Expand Down Expand Up @@ -79,6 +85,21 @@
<ClInclude Include="abstraction_defs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Midi2.NetworkMidiConfigurationManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AbstractionState.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MidiNetworkDeviceDefinition.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MidiNetworkDeviceTable.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MidiNetworkDevice.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Midi2.NetworkMidiAbstraction.rc">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License
// ============================================================================
// This is part of the Windows MIDI Services App API and should be used
// in your Windows application via an official binary distribution.
// Further information: https://github.com/microsoft/MIDI/
// ============================================================================

#include "pch.h"


_Use_decl_annotations_
HRESULT
CMidi2NetworkMidiConfigurationManager::Initialize(
GUID AbstractionId,
IUnknown* MidiDeviceManager
)
{
TraceLoggingWrite(
MidiNetworkMidiAbstractionTelemetryProvider::Provider(),
__FUNCTION__,
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
TraceLoggingPointer(this, "this")
);

RETURN_HR_IF_NULL(E_INVALIDARG, MidiDeviceManager);
RETURN_IF_FAILED(MidiDeviceManager->QueryInterface(__uuidof(IMidiDeviceManagerInterface), (void**)&m_MidiDeviceManager));

m_abstractionId = AbstractionId;

return S_OK;
}

_Use_decl_annotations_
HRESULT
CMidi2NetworkMidiConfigurationManager::UpdateConfiguration(
LPCWSTR ConfigurationJsonSection,
BOOL IsFromConfigurationFile,
BSTR* Response
)
{
TraceLoggingWrite(
MidiNetworkMidiAbstractionTelemetryProvider::Provider(),
__FUNCTION__,
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
TraceLoggingPointer(this, "this"),
TraceLoggingWideString(ConfigurationJsonSection, "json")
);

UNREFERENCED_PARAMETER(IsFromConfigurationFile);



// if we're passed a null or empty json, we just quietly exit
if (ConfigurationJsonSection == nullptr) return S_OK;

json::JsonObject jsonObject;

// default to failure
auto responseObject = internal::BuildConfigurationResponseObject(false);


// TODO: All your json parsing config stuff. Build any device table entries from it, etc.
// See Midi2.LoopbackMidiAbstraction for an example

// The runtime json sent up from the client in the case of network MIDI may include
// an IP address, port, password, etc. You can assume there can be a UI on the client
// for gathering that information and then sending it up. The API just needs to know
// what is needed.


// the response object should include anything the client needs to be able to use
// the endpoint, if the creation was successful. Typically, this is just an SWD
// interface id
internal::JsonStringifyObjectToOutParam(responseObject, &Response);

return S_OK;

}


HRESULT
CMidi2NetworkMidiConfigurationManager::Cleanup()
{
TraceLoggingWrite(
MidiNetworkMidiAbstractionTelemetryProvider::Provider(),
__FUNCTION__,
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
TraceLoggingPointer(this, "this")
);




return S_OK;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License
// ============================================================================
// This is part of the Windows MIDI Services App API and should be used
// in your Windows application via an official binary distribution.
// Further information: https://github.com/microsoft/MIDI/
// ============================================================================

#pragma once


class CMidi2NetworkMidiConfigurationManager :
public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
IMidiAbstractionConfigurationManager>

{
public:
STDMETHOD(Initialize(_In_ GUID AbstractionId, _In_ IUnknown* MidiDeviceManager));
STDMETHOD(UpdateConfiguration(_In_ LPCWSTR ConfigurationJsonSection, _In_ BOOL IsFromConfigurationFile, _Out_ BSTR* Response));
STDMETHOD(Cleanup)();

private:
wil::com_ptr_nothrow<IMidiDeviceManagerInterface> m_MidiDeviceManager;

GUID m_abstractionId; // kept for convenience
};
Loading

0 comments on commit 78e0db2

Please sign in to comment.