Skip to content

Commit 78e0db2

Browse files
Merge pull request #276 from microsoft/pete-dev
Network MIDI 2.0 abstraction scaffolding
2 parents c374e8f + 0dc531a commit 78e0db2

22 files changed

+690
-178
lines changed

build/staging/version/BundleInfo.wxi

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
<Include>
22
<?define SetupVersionName="Developer Preview 5" ?>
3-
<?define SetupVersionNumber="1.0.24044.1942" ?>
3+
<?define SetupVersionNumber="1.0.24044.2146" ?>
44
</Include>

docs/developer-docs/Windows.Devices.Midi2/service/MidiService.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Loopback endpoints created by the user and stored in the configuration file will
3838

3939
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.
4040

41-
> Note: In version 1 of the API, only transports can be configured at runtime. We're working on enabling configuration of message processing plugins.
41+
> 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.
4242
4343
## Static Functions : Service Health
4444

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License
3+
// ============================================================================
4+
// This is part of the Windows MIDI Services App API and should be used
5+
// in your Windows application via an official binary distribution.
6+
// Further information: https://github.com/microsoft/MIDI/
7+
// ============================================================================
8+
9+
#include "pch.h"
10+
11+
12+
AbstractionState::AbstractionState() = default;
13+
AbstractionState::~AbstractionState() = default;
14+
15+
AbstractionState& AbstractionState::Current()
16+
{
17+
// explanation: http://www.modernescpp.com/index.php/thread-safe-initialization-of-data/
18+
19+
static AbstractionState current;
20+
21+
return current;
22+
}
23+
24+
25+
26+
HRESULT
27+
AbstractionState::ConstructEndpointManager()
28+
{
29+
RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize<CMidi2NetworkMidiEndpointManager>(&m_endpointManager));
30+
31+
return S_OK;
32+
}
33+
34+
35+
HRESULT
36+
AbstractionState::ConstructConfigurationManager()
37+
{
38+
RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize<CMidi2NetworkMidiConfigurationManager>(&m_configurationManager));
39+
40+
return S_OK;
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License
3+
// ============================================================================
4+
// This is part of the Windows MIDI Services App API and should be used
5+
// in your Windows application via an official binary distribution.
6+
// Further information: https://github.com/microsoft/MIDI/
7+
// ============================================================================
8+
9+
10+
#pragma once
11+
12+
// singleton
13+
class AbstractionState
14+
{
15+
16+
public:
17+
static AbstractionState& Current();
18+
19+
// no copying
20+
AbstractionState(_In_ const AbstractionState&) = delete;
21+
AbstractionState& operator=(_In_ const AbstractionState&) = delete;
22+
23+
24+
wil::com_ptr<CMidi2NetworkMidiEndpointManager> GetEndpointManager()
25+
{
26+
return m_endpointManager;
27+
}
28+
29+
wil::com_ptr<CMidi2NetworkMidiConfigurationManager> GetConfigurationManager()
30+
{
31+
return m_configurationManager;
32+
}
33+
34+
std::shared_ptr<MidiNetworkDeviceTable> GetEndpointTable()
35+
{
36+
return m_endpointTable;
37+
}
38+
39+
40+
HRESULT Cleanup()
41+
{
42+
m_endpointManager.reset();
43+
m_configurationManager.reset();
44+
45+
return S_OK;
46+
}
47+
48+
49+
HRESULT ConstructEndpointManager();
50+
HRESULT ConstructConfigurationManager();
51+
52+
53+
private:
54+
AbstractionState();
55+
~AbstractionState();
56+
57+
58+
wil::com_ptr<CMidi2NetworkMidiEndpointManager> m_endpointManager;
59+
wil::com_ptr<CMidi2NetworkMidiConfigurationManager> m_configurationManager;
60+
61+
std::shared_ptr<MidiNetworkDeviceTable> m_endpointTable = std::make_shared<MidiNetworkDeviceTable>();
62+
};

src/api/Abstraction/NetworkMidiAbstraction/Midi2.NetworkMidiAbstraction.cpp

+41-8
Original file line numberDiff line numberDiff line change
@@ -58,33 +58,66 @@ CMidi2NetworkMidiAbstraction::Activate(
5858

5959
TraceLoggingWrite(
6060
MidiNetworkMidiAbstractionTelemetryProvider::Provider(),
61-
__FUNCTION__ "- Midi BiDi",
61+
__FUNCTION__ "- IMidiBiDi",
6262
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
63-
TraceLoggingValue(__FUNCTION__),
63+
TraceLoggingWideString(L"IMidiBiDi", "requested interface"),
6464
TraceLoggingPointer(this, "this")
6565
);
6666

6767
wil::com_ptr_nothrow<IMidiBiDi> midiBiDi;
6868
RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize<CMidi2NetworkMidiBiDi>(&midiBiDi));
6969
*Interface = midiBiDi.detach();
7070
}
71+
72+
7173
else if (__uuidof(IMidiEndpointManager) == Riid)
7274
{
7375
TraceLoggingWrite(
7476
MidiNetworkMidiAbstractionTelemetryProvider::Provider(),
75-
__FUNCTION__ "- Midi Endpoint Manager",
77+
__FUNCTION__ "- IMidiEndpointManager",
7678
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
77-
TraceLoggingValue(__FUNCTION__),
79+
TraceLoggingWideString(L"IMidiEndpointManager", "requested interface"),
80+
TraceLoggingPointer(this, "this")
81+
);
82+
83+
// check to see if this is the first time we're creating the endpoint manager. If so, create it.
84+
if (AbstractionState::Current().GetEndpointManager() == nullptr)
85+
{
86+
AbstractionState::Current().ConstructEndpointManager();
87+
}
88+
89+
RETURN_IF_FAILED(AbstractionState::Current().GetEndpointManager()->QueryInterface(Riid, Interface));
90+
}
91+
92+
93+
else if (__uuidof(IMidiAbstractionConfigurationManager) == Riid)
94+
{
95+
TraceLoggingWrite(
96+
MidiNetworkMidiAbstractionTelemetryProvider::Provider(),
97+
__FUNCTION__,
98+
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
99+
TraceLoggingWideString(L"IMidiAbstractionConfigurationManager", "requested interface"),
78100
TraceLoggingPointer(this, "this")
79101
);
80102

81-
wil::com_ptr_nothrow<IMidiEndpointManager> midiEndpointManager;
82-
RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize<CMidi2NetworkMidiEndpointManager>(&midiEndpointManager));
83-
*Interface = midiEndpointManager.detach();
103+
// check to see if this is the first time we're creating the configuration manager. If so, create it.
104+
if (AbstractionState::Current().GetConfigurationManager() == nullptr)
105+
{
106+
AbstractionState::Current().ConstructConfigurationManager();
107+
}
108+
109+
RETURN_IF_FAILED(AbstractionState::Current().GetConfigurationManager()->QueryInterface(Riid, Interface));
84110
}
111+
85112
else
86113
{
87-
OutputDebugString(L"" __FUNCTION__ " Returning E_NOINTERFACE. Was an interface added that isn't handled in the Abstraction?");
114+
TraceLoggingWrite(
115+
MidiNetworkMidiAbstractionTelemetryProvider::Provider(),
116+
__FUNCTION__,
117+
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
118+
TraceLoggingWideString(L"Unknown or invalid interface request", "message"),
119+
TraceLoggingPointer(this, "this")
120+
);
88121

89122
return E_NOINTERFACE;
90123
}

src/api/Abstraction/NetworkMidiAbstraction/Midi2.NetworkMidiAbstraction.vcxproj

+7
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,10 @@
274274
</Midl>
275275
</ItemDefinitionGroup>
276276
<ItemGroup>
277+
<ClCompile Include="AbstractionState.cpp" />
277278
<ClCompile Include="dllmain.cpp" />
278279
<ClCompile Include="Midi2.NetworkMidiAbstraction.cpp" />
280+
<ClCompile Include="Midi2.NetworkMidiConfigurationManager.cpp" />
279281
<ClCompile Include="Midi2.NetworkMidiEndpointManager.cpp" />
280282
<ClCompile Include="Midi2.NetworkMidiBidi.cpp" />
281283
<ClCompile Include="Midi2.NetworkMidiIn.cpp" />
@@ -291,13 +293,18 @@
291293
<None Include="packages.config" />
292294
</ItemGroup>
293295
<ItemGroup>
296+
<ClInclude Include="AbstractionState.h" />
294297
<ClInclude Include="abstraction_defs.h" />
295298
<ClInclude Include="dllmain.h" />
296299
<ClInclude Include="Midi2.NetworkMidiAbstraction.h" />
300+
<ClInclude Include="Midi2.NetworkMidiConfigurationManager.h" />
297301
<ClInclude Include="Midi2.NetworkMidiEndpointManager.h" />
298302
<ClInclude Include="Midi2.NetworkMidiBidi.h" />
299303
<ClInclude Include="Midi2.NetworkMidiIn.h" />
300304
<ClInclude Include="Midi2.NetworkMidiOut.h" />
305+
<ClInclude Include="MidiNetworkDevice.h" />
306+
<ClInclude Include="MidiNetworkDeviceDefinition.h" />
307+
<ClInclude Include="MidiNetworkDeviceTable.h" />
301308
<ClInclude Include="pch.h" />
302309
<ClInclude Include="Resource.h" />
303310
</ItemGroup>

src/api/Abstraction/NetworkMidiAbstraction/Midi2.NetworkMidiAbstraction.vcxproj.filters

+21
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@
3636
<ClCompile Include="Midi2.NetworkMidiOut.cpp">
3737
<Filter>Source Files</Filter>
3838
</ClCompile>
39+
<ClCompile Include="Midi2.NetworkMidiConfigurationManager.cpp">
40+
<Filter>Source Files</Filter>
41+
</ClCompile>
42+
<ClCompile Include="AbstractionState.cpp">
43+
<Filter>Source Files</Filter>
44+
</ClCompile>
3945
</ItemGroup>
4046
<ItemGroup>
4147
<Midl Include="Midi2NetworkMidiAbstraction.idl">
@@ -79,6 +85,21 @@
7985
<ClInclude Include="abstraction_defs.h">
8086
<Filter>Header Files</Filter>
8187
</ClInclude>
88+
<ClInclude Include="Midi2.NetworkMidiConfigurationManager.h">
89+
<Filter>Header Files</Filter>
90+
</ClInclude>
91+
<ClInclude Include="AbstractionState.h">
92+
<Filter>Header Files</Filter>
93+
</ClInclude>
94+
<ClInclude Include="MidiNetworkDeviceDefinition.h">
95+
<Filter>Header Files</Filter>
96+
</ClInclude>
97+
<ClInclude Include="MidiNetworkDeviceTable.h">
98+
<Filter>Header Files</Filter>
99+
</ClInclude>
100+
<ClInclude Include="MidiNetworkDevice.h">
101+
<Filter>Header Files</Filter>
102+
</ClInclude>
82103
</ItemGroup>
83104
<ItemGroup>
84105
<ResourceCompile Include="Midi2.NetworkMidiAbstraction.rc">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License
3+
// ============================================================================
4+
// This is part of the Windows MIDI Services App API and should be used
5+
// in your Windows application via an official binary distribution.
6+
// Further information: https://github.com/microsoft/MIDI/
7+
// ============================================================================
8+
9+
#include "pch.h"
10+
11+
12+
_Use_decl_annotations_
13+
HRESULT
14+
CMidi2NetworkMidiConfigurationManager::Initialize(
15+
GUID AbstractionId,
16+
IUnknown* MidiDeviceManager
17+
)
18+
{
19+
TraceLoggingWrite(
20+
MidiNetworkMidiAbstractionTelemetryProvider::Provider(),
21+
__FUNCTION__,
22+
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
23+
TraceLoggingPointer(this, "this")
24+
);
25+
26+
RETURN_HR_IF_NULL(E_INVALIDARG, MidiDeviceManager);
27+
RETURN_IF_FAILED(MidiDeviceManager->QueryInterface(__uuidof(IMidiDeviceManagerInterface), (void**)&m_MidiDeviceManager));
28+
29+
m_abstractionId = AbstractionId;
30+
31+
return S_OK;
32+
}
33+
34+
_Use_decl_annotations_
35+
HRESULT
36+
CMidi2NetworkMidiConfigurationManager::UpdateConfiguration(
37+
LPCWSTR ConfigurationJsonSection,
38+
BOOL IsFromConfigurationFile,
39+
BSTR* Response
40+
)
41+
{
42+
TraceLoggingWrite(
43+
MidiNetworkMidiAbstractionTelemetryProvider::Provider(),
44+
__FUNCTION__,
45+
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
46+
TraceLoggingPointer(this, "this"),
47+
TraceLoggingWideString(ConfigurationJsonSection, "json")
48+
);
49+
50+
UNREFERENCED_PARAMETER(IsFromConfigurationFile);
51+
52+
53+
54+
// if we're passed a null or empty json, we just quietly exit
55+
if (ConfigurationJsonSection == nullptr) return S_OK;
56+
57+
json::JsonObject jsonObject;
58+
59+
// default to failure
60+
auto responseObject = internal::BuildConfigurationResponseObject(false);
61+
62+
63+
// TODO: All your json parsing config stuff. Build any device table entries from it, etc.
64+
// See Midi2.LoopbackMidiAbstraction for an example
65+
66+
// The runtime json sent up from the client in the case of network MIDI may include
67+
// an IP address, port, password, etc. You can assume there can be a UI on the client
68+
// for gathering that information and then sending it up. The API just needs to know
69+
// what is needed.
70+
71+
72+
// the response object should include anything the client needs to be able to use
73+
// the endpoint, if the creation was successful. Typically, this is just an SWD
74+
// interface id
75+
internal::JsonStringifyObjectToOutParam(responseObject, &Response);
76+
77+
return S_OK;
78+
79+
}
80+
81+
82+
HRESULT
83+
CMidi2NetworkMidiConfigurationManager::Cleanup()
84+
{
85+
TraceLoggingWrite(
86+
MidiNetworkMidiAbstractionTelemetryProvider::Provider(),
87+
__FUNCTION__,
88+
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
89+
TraceLoggingPointer(this, "this")
90+
);
91+
92+
93+
94+
95+
return S_OK;
96+
}
97+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License
3+
// ============================================================================
4+
// This is part of the Windows MIDI Services App API and should be used
5+
// in your Windows application via an official binary distribution.
6+
// Further information: https://github.com/microsoft/MIDI/
7+
// ============================================================================
8+
9+
#pragma once
10+
11+
12+
class CMidi2NetworkMidiConfigurationManager :
13+
public Microsoft::WRL::RuntimeClass<
14+
Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
15+
IMidiAbstractionConfigurationManager>
16+
17+
{
18+
public:
19+
STDMETHOD(Initialize(_In_ GUID AbstractionId, _In_ IUnknown* MidiDeviceManager));
20+
STDMETHOD(UpdateConfiguration(_In_ LPCWSTR ConfigurationJsonSection, _In_ BOOL IsFromConfigurationFile, _Out_ BSTR* Response));
21+
STDMETHOD(Cleanup)();
22+
23+
private:
24+
wil::com_ptr_nothrow<IMidiDeviceManagerInterface> m_MidiDeviceManager;
25+
26+
GUID m_abstractionId; // kept for convenience
27+
};

0 commit comments

Comments
 (0)