From cb1aa52136557cb237c16840c93d772bfe8f22dc Mon Sep 17 00:00:00 2001 From: Pete Brown Date: Mon, 12 Feb 2024 14:24:56 -0500 Subject: [PATCH 1/3] Fix header comments --- src/api/Inc/MidiDefs.h | 9 ++++++++- src/api/Inc/MidiKS.h | 9 ++++++++- src/api/Inc/MidiKSCommon.h | 9 ++++++++- src/api/Inc/MidiKSDef.h | 9 ++++++++- src/api/Inc/MidiXProc.h | 9 ++++++++- src/api/Inc/loopback_ids.h | 8 ++++++++ src/api/Inc/midi_timestamp.h | 8 ++++++++ src/api/Inc/midi_ump.h | 8 ++++++++ 8 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/api/Inc/MidiDefs.h b/src/api/Inc/MidiDefs.h index e91c83491..af7bdb296 100644 --- a/src/api/Inc/MidiDefs.h +++ b/src/api/Inc/MidiDefs.h @@ -1,4 +1,11 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// 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 diff --git a/src/api/Inc/MidiKS.h b/src/api/Inc/MidiKS.h index 8939e1b65..601fd1466 100644 --- a/src/api/Inc/MidiKS.h +++ b/src/api/Inc/MidiKS.h @@ -1,4 +1,11 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// 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 // copied from wdm.h diff --git a/src/api/Inc/MidiKSCommon.h b/src/api/Inc/MidiKSCommon.h index 8f6844d1b..0d4029925 100644 --- a/src/api/Inc/MidiKSCommon.h +++ b/src/api/Inc/MidiKSCommon.h @@ -1,4 +1,11 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// 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 diff --git a/src/api/Inc/MidiKSDef.h b/src/api/Inc/MidiKSDef.h index 1ef1a141e..391b35699 100644 --- a/src/api/Inc/MidiKSDef.h +++ b/src/api/Inc/MidiKSDef.h @@ -1,4 +1,11 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// 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 diff --git a/src/api/Inc/MidiXProc.h b/src/api/Inc/MidiXProc.h index d3d5c5548..8855944d5 100644 --- a/src/api/Inc/MidiXProc.h +++ b/src/api/Inc/MidiXProc.h @@ -1,4 +1,11 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// 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 using unique_mmcss_handle = wil::unique_any; diff --git a/src/api/Inc/loopback_ids.h b/src/api/Inc/loopback_ids.h index 9fc12b843..1732aee3e 100644 --- a/src/api/Inc/loopback_ids.h +++ b/src/api/Inc/loopback_ids.h @@ -1,3 +1,11 @@ +// 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 #define MIDI_DIAGNOSTICS_LOOPBACK_BIDI_ID_A L"\\\\?\\SWD#MIDISRV#MIDIU_DIAG_LOOPBACK_A#{e7cce071-3c03-423f-88d3-f1045d02552b}" diff --git a/src/api/Inc/midi_timestamp.h b/src/api/Inc/midi_timestamp.h index 0f9fb2bda..bae87b53c 100644 --- a/src/api/Inc/midi_timestamp.h +++ b/src/api/Inc/midi_timestamp.h @@ -1,3 +1,11 @@ +// 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 #include diff --git a/src/api/Inc/midi_ump.h b/src/api/Inc/midi_ump.h index 6b5904e31..c8ff4c4fd 100644 --- a/src/api/Inc/midi_ump.h +++ b/src/api/Inc/midi_ump.h @@ -1,3 +1,11 @@ +// 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 #include From eb789025f1f4c4f2b22ac02107cce02c1955a075 Mon Sep 17 00:00:00 2001 From: Pete Brown Date: Mon, 12 Feb 2024 16:09:37 -0500 Subject: [PATCH 2/3] Update MidiServices.wprp --- diagnostics/trace-logging/MidiServices.wprp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/diagnostics/trace-logging/MidiServices.wprp b/diagnostics/trace-logging/MidiServices.wprp index 1246cd8b9..132724c0d 100644 --- a/diagnostics/trace-logging/MidiServices.wprp +++ b/diagnostics/trace-logging/MidiServices.wprp @@ -1,8 +1,4 @@ - From b6b9267867119ff1a512050d7df32325a817a118 Mon Sep 17 00:00:00 2001 From: Pete Brown Date: Tue, 13 Feb 2024 03:32:22 -0500 Subject: [PATCH 3/3] Config-file-defined loopbacks working. Service props refactor --- build/staging/version/BundleInfo.wxi | 2 +- docs/endpoints/virtual-loopback.md | 8 +- .../MidiSample.AppToAppMidi.csproj | 2 +- .../Midi2.BluetoothMidiEndpointManager.cpp | 424 +--------------- .../Midi2.BluetoothMidiEndpointManager.h | 68 +-- src/api/Abstraction/BleMidiAbstraction/pch.h | 1 - .../Midi2.DiagnosticsEndpointManager.cpp | 115 ++--- .../Abstraction/DiagnosticsAbstraction/pch.h | 1 - .../Midi2.KSMidiEndpointManager.cpp | 20 + .../AbstractionState.h | 4 +- .../Midi2.LoopbackMidiBidi.cpp | 74 ++- ...Midi2.LoopbackMidiConfigurationManager.cpp | 202 ++++++-- .../Midi2.LoopbackMidiEndpointManager.cpp | 126 +++-- .../MidiLoopbackDeviceTable.h | 2 +- .../Abstraction/LoopbackMidiAbstraction/pch.h | 12 +- .../Abstraction/NetworkMidiAbstraction/pch.h | 1 - src/api/Abstraction/SampleAbstraction/pch.h | 1 - .../Midi2.VirtualMidiAbstraction.vcxproj | 2 - ...di2.VirtualMidiAbstraction.vcxproj.filters | 6 - .../Midi2.VirtualMidiEndpointManager.cpp | 124 ++--- .../MidiEndpointTable.cpp | 8 +- .../Abstraction/VirtualMidiAbstraction/pch.h | 1 - .../VirtualMidiAbstraction/swd_shared.cpp | 62 --- .../VirtualMidiAbstraction/swd_shared.h | 17 - .../Midi2.VirtualPatchBayEndpointManager.cpp | 470 +----------------- .../Midi2.VirtualPatchBayEndpointManager.h | 67 +-- .../VirtualPatchBayAbstraction/pch.h | 1 - src/api/Client/Midi2Client/pch.h | 1 - src/api/Inc/MidiDefs.h | 11 - .../AbstractionUtilities.vcxproj | 3 +- .../AbstractionUtilities.vcxproj.filters | 5 +- .../inc/swd_property_builders.h | 20 - .../inc/swd_property_helpers.h | 47 -- .../AbstractionUtilities/inc/swd_shared.h | 24 + src/api/Libs/AbstractionUtilities/src/pch.h | 3 +- .../src/swd_property_builders.cpp | 48 -- .../src/swd_property_helpers.cpp | 75 +-- .../AbstractionUtilities/src/swd_shared.cpp | 66 +++ src/api/Service/Exe/MidiDeviceManager.cpp | 219 +++++++- src/api/Service/Exe/stdafx.h | 2 +- src/api/Service/Inc/MidiDeviceManager.h | 4 +- src/api/idl/MidiDeviceManagerInterface.idl | 43 +- 42 files changed, 784 insertions(+), 1608 deletions(-) delete mode 100644 src/api/Abstraction/VirtualMidiAbstraction/swd_shared.cpp delete mode 100644 src/api/Abstraction/VirtualMidiAbstraction/swd_shared.h delete mode 100644 src/api/Libs/AbstractionUtilities/inc/swd_property_helpers.h create mode 100644 src/api/Libs/AbstractionUtilities/inc/swd_shared.h create mode 100644 src/api/Libs/AbstractionUtilities/src/swd_shared.cpp diff --git a/build/staging/version/BundleInfo.wxi b/build/staging/version/BundleInfo.wxi index 9f4197301..ee1c9ca44 100644 --- a/build/staging/version/BundleInfo.wxi +++ b/build/staging/version/BundleInfo.wxi @@ -1,4 +1,4 @@ - + diff --git a/docs/endpoints/virtual-loopback.md b/docs/endpoints/virtual-loopback.md index 6ebf1303a..6390f9b38 100644 --- a/docs/endpoints/virtual-loopback.md +++ b/docs/endpoints/virtual-loopback.md @@ -44,13 +44,13 @@ That out of the way, here's an example configuration section for the Virtual Loo { "name": "Perm Loopback 1A", "description": "This is a loopback I created in the configuration file", - "uniqueId": "3263827" + "uniqueIdentifier": "3263827" }, "endpointB": { "name": "Perm Loopback 1B", "description": "This is the b-side of the loopback I created in the configuration file", - "uniqueId": "3263827" + "uniqueIdentifier": "3263827" } }, "{B21B4973-3F85-48A0-8BA3-B35F44683D36}": @@ -60,13 +60,13 @@ That out of the way, here's an example configuration section for the Virtual Loo { "name": "Perm Loopback 2A", "description": "This is a loopback I created in the configuration file", - "uniqueId": "5150-1984" + "uniqueIdentifier": "5150-1984" }, "endpointB": { "name": "Perm Loopback 2B", "description": "This is the b-side of the loopback I created in the configuration file", - "uniqueId": "OU812" + "uniqueIdentifier": "OU812" } } } diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi.csproj b/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi.csproj index e980fe6ea..9438a45d2 100644 --- a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi.csproj +++ b/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi.csproj @@ -29,7 +29,7 @@ - + diff --git a/src/api/Abstraction/BleMidiAbstraction/Midi2.BluetoothMidiEndpointManager.cpp b/src/api/Abstraction/BleMidiAbstraction/Midi2.BluetoothMidiEndpointManager.cpp index e7e5381c2..7ecd3ea4f 100644 --- a/src/api/Abstraction/BleMidiAbstraction/Midi2.BluetoothMidiEndpointManager.cpp +++ b/src/api/Abstraction/BleMidiAbstraction/Midi2.BluetoothMidiEndpointManager.cpp @@ -25,8 +25,6 @@ CMidi2BluetoothMidiEndpointManager::Initialize( IUnknown* /*midiEndpointProtocolManager*/ ) { - //OutputDebugString(L"" __FUNCTION__ " Enter"); - TraceLoggingWrite( MidiBluetoothMidiAbstractionTelemetryProvider::Provider(), __FUNCTION__, @@ -41,442 +39,24 @@ CMidi2BluetoothMidiEndpointManager::Initialize( m_TransportAbstractionId = AbstractionLayerGUID; // this is needed so MidiSrv can instantiate the correct transport m_ContainerId = m_TransportAbstractionId; // we use the transport ID as the container ID for convenience - RETURN_IF_FAILED(CreateParentDevice()); - - //if (ConfigurationJson != nullptr) - //{ - // try - // { - // std::wstring json{ ConfigurationJson }; - - // if (!json.empty()) - // { - // m_jsonObject = json::JsonObject::Parse(json); - - // LOG_IF_FAILED(CreateConfiguredEndpoints(json)); - // } - // } - // catch (...) - // { - // OutputDebugString(L"Exception processing json for virtual MIDI abstraction"); - - // // we return S_OK here because otherwise this prevents the service from starting up. - // return S_OK; - // } - - //} - //else - //{ - // // empty / null is fine. We just continue on. - - // OutputDebugString(L"Configuration json is null for virtual MIDI abstraction"); - - // return S_OK; - //} + //RETURN_IF_FAILED(CreateParentDevice()); return S_OK; } -void -SwMidiParentDeviceCreateCallback( - __in HSWDEVICE /*hSwDevice*/, - __in HRESULT CreationResult, - __in_opt PVOID pContext, - __in_opt PCWSTR pszDeviceInstanceId -) -{ - if (pContext == nullptr) - { - // TODO: Should log this. - - return; - } - - PPARENTDEVICECREATECONTEXT creationContext = (PPARENTDEVICECREATECONTEXT)pContext; - - - // interface registration has started, assume failure - creationContext->MidiParentDevice->SwDeviceState = SWDEVICESTATE::Failed; - - LOG_IF_FAILED(CreationResult); - - if (SUCCEEDED(CreationResult)) - { - // success, mark the port as created - creationContext->MidiParentDevice->SwDeviceState = SWDEVICESTATE::Created; - - // get the new device instance ID. This is usually modified from what we started with - creationContext->MidiParentDevice->InstanceId = std::wstring(pszDeviceInstanceId); - } - else - { - OutputDebugString(L"" __FUNCTION__ " - CreationResult FAILURE"); - } - - // success or failure, signal we have completed. - creationContext->CreationCompleted.SetEvent(); -} - HRESULT CMidi2BluetoothMidiEndpointManager::CreateParentDevice() { - // the parent device parameters are set by the transport (this) - - std::wstring parentDeviceName{ TRANSPORT_PARENT_DEVICE_NAME }; - std::wstring parentDeviceId{ TRANSPORT_PARENT_ID }; - - SW_DEVICE_CREATE_INFO CreateInfo = {}; - CreateInfo.cbSize = sizeof(CreateInfo); - CreateInfo.pszInstanceId = parentDeviceId.c_str(); - CreateInfo.CapabilityFlags = SWDeviceCapabilitiesNone; - CreateInfo.pszDeviceDescription = parentDeviceName.c_str(); - - SW_DEVICE_CREATE_INFO* createInfo = (SW_DEVICE_CREATE_INFO*)&CreateInfo; - - if (m_ParentDevice != nullptr) - { - return S_OK; - } - - m_ParentDevice = std::make_unique(); - - RETURN_IF_NULL_ALLOC(m_ParentDevice); - - PARENTDEVICECREATECONTEXT creationContext; - - // lambdas can only be converted to a function pointer if they - // don't do capture, so copy everything into the CREATECONTEXT - // to share with the SwDeviceCreate callback. - creationContext.MidiParentDevice = m_ParentDevice.get(); - - //creationContext.InterfaceDevProperties = (DEVPROPERTY*)InterfaceDevProperties; - //creationContext.IntPropertyCount = IntPropertyCount; - - m_ParentDevice->SwDeviceState = SWDEVICESTATE::CreatePending; - - //m_ParentDevice->InstanceId = createInfo->pszInstanceId; - - DEVPROP_BOOLEAN devPropTrue = DEVPROP_TRUE; - - DEVPROPERTY deviceDevProperties[] = { - {{DEVPKEY_Device_PresenceNotForDevice, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropTrue)), &devPropTrue}, - {{DEVPKEY_Device_NoConnectSound, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropTrue)),&devPropTrue} - }; - - - std::wstring rootDeviceId = LOOPBACK_PARENT_ROOT; - std::wstring enumeratorName = TRANSPORT_ENUMERATOR; - - createInfo->pContainerId = &m_ContainerId; - - RETURN_IF_FAILED(SwDeviceCreate( - enumeratorName.c_str(), // this really should come from the service - rootDeviceId.c_str(), // root device - createInfo, - ARRAYSIZE(deviceDevProperties), // count of properties - (DEVPROPERTY*)deviceDevProperties, // pointer to properties - SwMidiParentDeviceCreateCallback, // callback - &creationContext, - wil::out_param(m_ParentDevice->SwDevice))); - - // wait for creation to complete - creationContext.CreationCompleted.wait(); - - // confirm we were able to register the interface - RETURN_HR_IF(E_FAIL, m_ParentDevice->SwDeviceState != SWDEVICESTATE::Created); return S_OK; } -#define MIDI_VIRTUAL_ENDPOINTS_ARRAY_KEY L"endpoints" - -#define MIDI_VIRTUAL_ENDPOINT_PROPERTY_NAME L"name" -#define MIDI_VIRTUAL_ENDPOINT_PROPERTY_DESCRIPTION L"description" -#define MIDI_VIRTUAL_ENDPOINT_PROPERTY_SMALLIMAGE L"smallImagePath" -#define MIDI_VIRTUAL_ENDPOINT_PROPERTY_LARGEIMAGE L"largeImagePath" - -#define MIDI_JSON_UPDATE_NODE L"update" - - -//json::JsonObject GetAddNode(json::JsonObject parent) -//{ -// if (parent.HasKey(MIDI_JSON_ADD_NODE)) -// { -// return parent.GetNamedObject(MIDI_JSON_ADD_NODE); -// } -// else -// { -// return nullptr; -// } -//} -// -//winrt::hstring GetStringValue(json::JsonObject parent, winrt::hstring key, winrt::hstring default) -//{ -// if (parent.HasKey(key)) -// { -// return parent.GetNamedString(key); -// } -// else -// { -// return default; -// } -//} - -_Use_decl_annotations_ -HRESULT -CMidi2BluetoothMidiEndpointManager::CreateConfiguredEndpoints( - std::wstring ConfigurationJson -) -{ - //// if nothing to configure, that's ok - //if (ConfigurationJson.empty()) return S_OK; - - //try - //{ - // auto jsonObject = json::JsonObject::Parse(ConfigurationJson); - - - // // check to see if we have an "add" node. No point in checking for "update" or "remove" for initial configuration - // auto addNode = GetAddNode(jsonObject); - - // if (addNode != nullptr && addNode.HasKey(MIDI_VIRTUAL_ENDPOINTS_ARRAY_KEY)) - // { - // auto endpoints = addNode.GetNamedArray(MIDI_VIRTUAL_ENDPOINTS_ARRAY_KEY); - - // for (auto endpointElement : endpoints) - // { - // // GetObjectW here is because wingdi redefines it to GetObject. It's a stupid preprocessor conflict - // try - // { - // auto endpoint = endpointElement.GetObjectW(); - - // // auto key = endpoint.GetNamedString(MIDI_VIRTUAL_ENDPOINT_PROPERTY_KEY, L""); - // auto name = endpoint.GetNamedString(MIDI_VIRTUAL_ENDPOINT_PROPERTY_NAME, L""); - // auto uniqueIdentifier = endpoint.GetNamedString(MIDI_VIRTUAL_ENDPOINT_PROPERTY_UNIQUEID, L""); - // // auto supportsMultiClient = endpoint.GetNamedBoolean(MIDI_VIRTUAL_ENDPOINT_PROPERTY_MULTICLIENT, true); - - // auto instanceId = TRANSPORT_MNEMONIC L"_" + uniqueIdentifier; - - // auto description = GetStringValue(endpoint, MIDI_VIRTUAL_ENDPOINT_PROPERTY_DESCRIPTION, L""); - // auto smallImage = GetStringValue(endpoint, MIDI_VIRTUAL_ENDPOINT_PROPERTY_SMALLIMAGE, L""); - // auto largeImage = GetStringValue(endpoint, MIDI_VIRTUAL_ENDPOINT_PROPERTY_LARGEIMAGE, L""); - - // bool multiclient = true; // TODO - // bool virtualResponder = false; // TODO - - - // // TODO: Need to add this to the table for routing, and also add the other properties to the function - // CreateEndpoint( - // (std::wstring)instanceId, - // (std::wstring)uniqueIdentifier, - // multiclient, - // virtualResponder, - // (std::wstring)name, - // (std::wstring)largeImage, - // (std::wstring)smallImage, - // (std::wstring)description - // ); - // } - // catch (...) - // { - // // couldn't get an object. Garbage data - // OutputDebugString(L"" __FUNCTION__ " Exception getting endpoint properties from json"); - - // return E_FAIL; - // } - // } - // } - // else - // { - // // nothing to add - // } - - - //} - //catch (...) - //{ - // // exception parsing the json. It's likely empty or malformed - - // OutputDebugString(L"" __FUNCTION__ " Exception parsing JSON. Json string follows."); - // OutputDebugString(ConfigurationJson.c_str()); - - // TraceLoggingWrite( - // MidiBluetoothMidiAbstractionTelemetryProvider::Provider(), - // __FUNCTION__, - // TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - // TraceLoggingPointer(this, "this") - // ); - - // return E_FAIL; - //} - - return S_OK; -} - -// this will be called from the runtime endpoint creation interface - _Use_decl_annotations_ HRESULT CMidi2BluetoothMidiEndpointManager::CreateEndpoint( - std::wstring const InstanceId, - std::wstring const UniqueId, - bool const Multiclient, - bool const /*IsVirtualEndpointResponder*/, - std::wstring const Name, - std::wstring const LargeImagePath, - std::wstring const SmallImagePath, - std::wstring const Description ) { - //put all of the devproperties we want into arrays and pass into ActivateEndpoint: - - std::wstring mnemonic(TRANSPORT_MNEMONIC); - MidiFlow const flow = MidiFlow::MidiFlowBidirectional; - - DEVPROP_BOOLEAN devPropTrue = DEVPROP_TRUE; - //DEVPROP_BOOLEAN devPropFalse = DEVPROP_FALSE; - - DEVPROP_BOOLEAN devPropMulticlient = Multiclient ? DEVPROP_TRUE : DEVPROP_FALSE; - //DEVPROP_BOOLEAN devPropVirtualResponder = IsVirtualEndpointResponder ? DEVPROP_TRUE : DEVPROP_FALSE; - - BYTE nativeDataFormat = MIDI_PROP_NATIVEDATAFORMAT_BYTESTREAM; - - uint32_t endpointPurpose{}; - - endpointPurpose = (uint32_t)MidiEndpointDevicePurposePropertyValue::NormalMessageEndpoint; - - DEVPROPERTY interfaceDevProperties[] = { - {{DEVPKEY_DeviceInterface_FriendlyName, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_STRING, static_cast((Name.length() + 1) * sizeof(WCHAR)), (PVOID)Name.c_str()}, - - // essential to instantiate the right endpoint types - {{PKEY_MIDI_AbstractionLayer, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_GUID, static_cast(sizeof(GUID)), (PVOID)&AbstractionLayerGUID }, - - {{PKEY_MIDI_TransportMnemonic, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_STRING, static_cast((mnemonic.length() + 1) * sizeof(WCHAR)), (PVOID)mnemonic.c_str()}, - - {{PKEY_MIDI_NativeDataFormat, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_BYTE, static_cast(sizeof(BYTE)), (PVOID)&nativeDataFormat}, - - //{{PKEY_MIDI_UniqueIdentifier, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_STRING, static_cast((UniqueId.length() + 1) * sizeof(WCHAR)), (PVOID)UniqueId.c_str()}, - - {{PKEY_MIDI_SupportsMulticlient, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropMulticlient)), (PVOID)&devPropMulticlient}, - - {{PKEY_MIDI_TransportSuppliedEndpointName, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_STRING, static_cast((Name.length() + 1) * sizeof(WCHAR)), (PVOID)Name.c_str()}, - - {{PKEY_MIDI_EndpointDevicePurpose, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_UINT32, static_cast(sizeof(endpointPurpose)),(PVOID)&endpointPurpose}, - - - {{PKEY_MIDI_UserSuppliedLargeImagePath, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_STRING, static_cast((LargeImagePath.length() + 1) * sizeof(WCHAR)), (PVOID)LargeImagePath.c_str() }, - - {{PKEY_MIDI_UserSuppliedSmallImagePath, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_STRING, static_cast((SmallImagePath.length() + 1) * sizeof(WCHAR)), (PVOID)SmallImagePath.c_str() }, - - {{PKEY_MIDI_UserSuppliedDescription, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_STRING, static_cast((Description.length() + 1) * sizeof(WCHAR)), (PVOID)Description.c_str() }, - - {{PKEY_MIDI_UserSuppliedEndpointName, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_STRING, static_cast((Name.length() + 1) * sizeof(WCHAR)), (PVOID)Name.c_str() } - }; - - - - // Additional metadata properties added here to avoid having to add them in every transport -// and to ensure they are registered under the same identity that is creating the device -// Several of these are later updated through discovery, user-supplied json metadata, etc. - //DEVPROP_BOOLEAN devPropFalse = DEVPROP_FALSE; - //uint8_t zeroByte = 0; - - //std::wstring emptyString = L""; - - //interfaceProperties.push_back({ {PKEY_MIDI_SupportsMultiClient, DEVPROP_STORE_SYSTEM, nullptr }, - // DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropTrue)), &devPropTrue }); - - //// from endpoint discovery ============ - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointSupportsMidi2Protocol, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropFalse)), &devPropFalse }); - - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointSupportsMidi1Protocol, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropFalse)), &devPropFalse }); - - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointSupportsReceivingJRTimestamps, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropFalse)), &devPropFalse }); - - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointSupportsSendingJRTimestamps, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropFalse)), &devPropFalse }); - - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointUmpVersionMajor, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_BYTE, static_cast(sizeof(zeroByte)), &zeroByte }); - - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointUmpVersionMinor, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_BYTE, static_cast(sizeof(zeroByte)), &zeroByte }); - - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointProvidedName, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_STRING, static_cast((emptyString.length() + 1) * sizeof(WCHAR)), (PVOID)emptyString.c_str() }); - - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointProvidedProductInstanceId, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_STRING, static_cast((emptyString.length() + 1) * sizeof(WCHAR)), (PVOID)emptyString.c_str() }); - - //interfaceProperties.push_back({ {PKEY_MIDI_FunctionBlocksAreStatic, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropFalse)),&devPropFalse }); - - ////interfaceProperties.push_back({ {PKEY_MIDI_DeviceIdentification, DEVPROP_STORE_SYSTEM, nullptr}, - //// DEVPROP_TYPE_BINARY, static_cast(0), }); - - - //// from function block discovery ============================= - - ////interfaceProperties.push_back({ {PKEY_MIDI_FunctionBlocks, DEVPROP_STORE_SYSTEM, nullptr}, - //// DEVPROP_TYPE_BINARY, static_cast(0), &functionBlockCount }); - - - - - DEVPROPERTY deviceDevProperties[] = { - {{DEVPKEY_Device_PresenceNotForDevice, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropTrue)), &devPropTrue}, - {{DEVPKEY_Device_NoConnectSound, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropTrue)),&devPropTrue} - }; - - SW_DEVICE_CREATE_INFO createInfo = {}; - createInfo.cbSize = sizeof(createInfo); - - createInfo.pszInstanceId = InstanceId.c_str(); - createInfo.CapabilityFlags = SWDeviceCapabilitiesNone; - createInfo.pszDeviceDescription = Name.c_str(); - - - const ULONG deviceInterfaceIdMaxSize = 255; - wchar_t newDeviceInterfaceId[deviceInterfaceIdMaxSize]{ 0 }; - - RETURN_IF_FAILED(m_MidiDeviceManager->ActivateEndpoint( - std::wstring(m_ParentDevice->InstanceId).c_str(), // parent instance Id - true, // UMP-only - flow, // MIDI Flow - ARRAYSIZE(interfaceDevProperties), - ARRAYSIZE(deviceDevProperties), - (PVOID)interfaceDevProperties, - (PVOID)deviceDevProperties, - (PVOID)&createInfo, - (LPWSTR)&newDeviceInterfaceId, - deviceInterfaceIdMaxSize)); - - OutputDebugString(__FUNCTION__ L": Created device interface id:"); - OutputDebugString(newDeviceInterfaceId); - - // store the created device in the device table, along with the interface id - - return S_OK; } @@ -509,8 +89,6 @@ CMidi2BluetoothMidiEndpointManager::EnumCompatibleBluetoothDevices() HRESULT CMidi2BluetoothMidiEndpointManager::Cleanup() { - OutputDebugString(L"" __FUNCTION__ " Enter"); - TraceLoggingWrite( MidiBluetoothMidiAbstractionTelemetryProvider::Provider(), __FUNCTION__, diff --git a/src/api/Abstraction/BleMidiAbstraction/Midi2.BluetoothMidiEndpointManager.h b/src/api/Abstraction/BleMidiAbstraction/Midi2.BluetoothMidiEndpointManager.h index 3207d2e80..8ee84ba3b 100644 --- a/src/api/Abstraction/BleMidiAbstraction/Midi2.BluetoothMidiEndpointManager.h +++ b/src/api/Abstraction/BleMidiAbstraction/Midi2.BluetoothMidiEndpointManager.h @@ -8,58 +8,6 @@ #pragma once -typedef enum _SWDEVICESTATE -{ - NotCreated = 0, // SwDeviceCreate not yet called - CreatePending, // SwDeviceCreate called successfully, but creation callback not yet invoked - Created, // SwDeviceCreate creation callback has been invoked and device interface has been created - Failed -} SWDEVICESTATE; - - -using unique_hswdevice = wil::unique_any; -using unique_swd_string = wil::unique_any; - - -class MidiUmpEndpointInfo -{ -public: - std::wstring Id{}; // the filter InterfaceId - std::wstring InstanceId{}; // the MIDI instance id - std::wstring ParentInstanceId{}; // The instance id of the parent device - std::wstring Name{}; // friendly name for this device - MidiFlow Flow{ MidiFlowBidirectional }; - - // TODO: Pointer to the interface? - -}; - -class MidiEndpointParentDeviceInfo -{ -public: - GUID InterfaceCategory{}; - SWDEVICESTATE SwDeviceState{ SWDEVICESTATE::NotCreated }; // SWD creation state - unique_hswdevice SwDevice{}; // Handle to the SWD created for the MIDI port - unique_swd_string DeviceInterfaceId{}; // SWD interface ID for the MIDI port - std::wstring InstanceId{}; - std::wstring Name{}; // friendly name for this device - -}; - -typedef struct _PARENTDEVICECREATECONTEXT -{ - MidiEndpointParentDeviceInfo* MidiParentDevice{ nullptr }; - wil::unique_event CreationCompleted{ wil::EventOptions::None }; - DEVPROPERTY* InterfaceDevProperties{ nullptr }; - ULONG IntPropertyCount{}; -} PARENTDEVICECREATECONTEXT, * PPARENTDEVICECREATECONTEXT; - - -// TODO: This class can implement another interface which takes in the json parameters -// (or whatever we want) for naming the new endpoints. Then, the SDK can call that -// interface to do the setup of the device. Or, there can be a common "runtime creatable transport" -// interface that is called from the API. TBD. But can't break that interface with -// the SDK, since the SDK ships with apps and could be older. class CMidi2BluetoothMidiEndpointManager : @@ -78,14 +26,7 @@ class CMidi2BluetoothMidiEndpointManager : GUID m_TransportAbstractionId{}; HRESULT CreateEndpoint( - _In_ std::wstring const InstanceId, - _In_ std::wstring const UniqueId, - _In_ bool const Multiclient, - _In_ bool const IsVirtualEndpointResponder, - _In_ std::wstring const Name, - _In_ std::wstring const LargeImagePath, - _In_ std::wstring const SmallImagePath, - _In_ std::wstring const Description); +); HRESULT EnumCompatibleBluetoothDevices(); @@ -95,11 +36,4 @@ class CMidi2BluetoothMidiEndpointManager : HRESULT CreateParentDevice(); wil::com_ptr_nothrow m_MidiDeviceManager; - - // TBD if we need to keep this here as well. The MidiDeviceManager has its own vector of endpoints - std::vector> m_AvailableMidiUmpEndpoints; - - std::unique_ptr m_ParentDevice{ nullptr }; - - json::JsonObject m_JsonObject{ nullptr }; }; diff --git a/src/api/Abstraction/BleMidiAbstraction/pch.h b/src/api/Abstraction/BleMidiAbstraction/pch.h index ba8f194ca..92fc32a4a 100644 --- a/src/api/Abstraction/BleMidiAbstraction/pch.h +++ b/src/api/Abstraction/BleMidiAbstraction/pch.h @@ -69,7 +69,6 @@ namespace json = ::winrt::Windows::Data::Json; // AbstractionUtilities #include "endpoint_data_helpers.h" #include "swd_property_builders.h" -#include "swd_property_helpers.h" #include "json_helpers.h" #include "MidiDefs.h" diff --git a/src/api/Abstraction/DiagnosticsAbstraction/Midi2.DiagnosticsEndpointManager.cpp b/src/api/Abstraction/DiagnosticsAbstraction/Midi2.DiagnosticsEndpointManager.cpp index 2b4532251..deaeaede2 100644 --- a/src/api/Abstraction/DiagnosticsAbstraction/Midi2.DiagnosticsEndpointManager.cpp +++ b/src/api/Abstraction/DiagnosticsAbstraction/Midi2.DiagnosticsEndpointManager.cpp @@ -135,44 +135,6 @@ CMidi2DiagnosticsEndpointManager::CreateLoopbackEndpoint( std::wstring friendlyName = internal::CalculateEndpointDevicePrimaryName(endpointName, L"", L""); // all the standard properties we define for endpoints - if (internal::AddStandardEndpointProperties( - interfaceDeviceProperties, - m_TransportAbstractionId, - MidiEndpointDevicePurposePropertyValue::DiagnosticLoopback, - friendlyName, - mnemonic, - endpointName, - endpointDescription, - L"", - L"", - UniqueId, - MidiDataFormat::MidiDataFormat_UMP, - MIDI_PROP_NATIVEDATAFORMAT_UMP, - multiClient, - requiresMetadataHandler, - generateIncomingTimestamps - )) - { - // all good. Add additional properties - // additional properties for this abstraction - - // we clear this because it's not used for this abstraction. - interfaceDeviceProperties.push_back(internal::BuildEmptyDevProperty(PKEY_MIDI_AssociatedUMP)); - } - else - { - // unable to build properties - - TraceLoggingWrite( - MidiDiagnosticsAbstractionTelemetryProvider::Provider(), - __FUNCTION__, - TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - TraceLoggingPointer(this, "this"), - TraceLoggingWideString(L"Unable to build standard endpoint properties list", "message") - ); - - return E_FAIL; - } DEVPROPERTY deviceDevProperties[] = { {{DEVPKEY_Device_PresenceNotForDevice, DEVPROP_STORE_SYSTEM, nullptr}, @@ -193,10 +155,28 @@ CMidi2DiagnosticsEndpointManager::CreateLoopbackEndpoint( wchar_t newDeviceInterfaceId[deviceInterfaceIdMaxSize]{ 0 }; + MIDIENDPOINTCOMMONPROPERTIES commonProperties; + commonProperties.AbstractionLayerGuid = m_TransportAbstractionId; + commonProperties.EndpointPurpose = MidiEndpointDevicePurposePropertyValue::DiagnosticLoopback; + commonProperties.FriendlyName = friendlyName.c_str(); + commonProperties.TransportMnemonic = mnemonic.c_str(); + commonProperties.TransportSuppliedEndpointName = endpointName.c_str(); + commonProperties.TransportSuppliedEndpointDescription = endpointDescription.c_str(); + commonProperties.UserSuppliedEndpointName = L""; + commonProperties.UserSuppliedEndpointDescription = L""; + commonProperties.UniqueIdentifier = UniqueId.c_str(); + commonProperties.SupportedDataFormats = MidiDataFormat::MidiDataFormat_UMP; + commonProperties.NativeDataFormat = MIDI_PROP_NATIVEDATAFORMAT_UMP; + commonProperties.SupportsMultiClient = multiClient; + commonProperties.RequiresMetadataHandler = requiresMetadataHandler; + commonProperties.GenerateIncomingTimestamps = generateIncomingTimestamps; + + RETURN_IF_FAILED(m_MidiDeviceManager->ActivateEndpoint( (PCWSTR)m_parentDeviceId.c_str(), // parent instance Id true, // UMP-only Flow, // MIDI Flow + &commonProperties, (ULONG)interfaceDeviceProperties.size(), ARRAYSIZE(deviceDevProperties), (PVOID)interfaceDeviceProperties.data(), @@ -205,7 +185,6 @@ CMidi2DiagnosticsEndpointManager::CreateLoopbackEndpoint( (LPWSTR)&newDeviceInterfaceId, deviceInterfaceIdMaxSize)); - // now delete all the properties that have been discovered in-protocol // we have to do this because they end up cached by PNP and come back // when you recreate a device with the same Id. This is a real problem @@ -256,47 +235,6 @@ CMidi2DiagnosticsEndpointManager::CreatePingEndpoint( // no user or in-protocol data in this case std::wstring friendlyName = internal::CalculateEndpointDevicePrimaryName(endpointName, L"", L""); - // all the standard properties we define for endpoints - if (internal::AddStandardEndpointProperties( - interfaceDeviceProperties, - m_TransportAbstractionId, - MidiEndpointDevicePurposePropertyValue::DiagnosticPing, - friendlyName, - mnemonic, - endpointName, - endpointDescription, - L"", - L"", - UniqueId, - MidiDataFormat::MidiDataFormat_UMP, - MIDI_PROP_NATIVEDATAFORMAT_UMP, - multiClient, - requiresMetadataHandler, - generateIncomingTimestamps - )) - { - // all good. Add additional properties - // additional properties for this abstraction - - // we clear this because it's not used for this abstraction. - interfaceDeviceProperties.push_back(internal::BuildEmptyDevProperty(PKEY_MIDI_AssociatedUMP)); - - } - else - { - // unable to build properties - - TraceLoggingWrite( - MidiDiagnosticsAbstractionTelemetryProvider::Provider(), - __FUNCTION__, - TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - TraceLoggingPointer(this, "this"), - TraceLoggingWideString(L"Unable to build standard endpoint properties list", "message") - ); - - return E_FAIL; - } - DEVPROPERTY deviceDevProperties[] = { {{DEVPKEY_Device_PresenceNotForDevice, DEVPROP_STORE_SYSTEM, nullptr}, DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropTrue)), &devPropTrue}, @@ -315,10 +253,27 @@ CMidi2DiagnosticsEndpointManager::CreatePingEndpoint( const ULONG deviceInterfaceIdMaxSize = 255; wchar_t newDeviceInterfaceId[deviceInterfaceIdMaxSize]{ 0 }; + MIDIENDPOINTCOMMONPROPERTIES commonProperties; + commonProperties.AbstractionLayerGuid = m_TransportAbstractionId; + commonProperties.EndpointPurpose = MidiEndpointDevicePurposePropertyValue::DiagnosticPing; + commonProperties.FriendlyName = friendlyName.c_str(); + commonProperties.TransportMnemonic = mnemonic.c_str(); + commonProperties.TransportSuppliedEndpointName = endpointName.c_str(); + commonProperties.TransportSuppliedEndpointDescription = endpointDescription.c_str(); + commonProperties.UserSuppliedEndpointName = L""; + commonProperties.UserSuppliedEndpointDescription = L""; + commonProperties.UniqueIdentifier = UniqueId.c_str(); + commonProperties.SupportedDataFormats = MidiDataFormat::MidiDataFormat_UMP; + commonProperties.NativeDataFormat = MIDI_PROP_NATIVEDATAFORMAT_UMP; + commonProperties.SupportsMultiClient = multiClient; + commonProperties.RequiresMetadataHandler = requiresMetadataHandler; + commonProperties.GenerateIncomingTimestamps = generateIncomingTimestamps; + RETURN_IF_FAILED(m_MidiDeviceManager->ActivateEndpoint( m_parentDeviceId.c_str(), // parent instance Id true, // UMP-only Flow, // MIDI Flow + &commonProperties, (ULONG)interfaceDeviceProperties.size(), ARRAYSIZE(deviceDevProperties), (PVOID)interfaceDeviceProperties.data(), diff --git a/src/api/Abstraction/DiagnosticsAbstraction/pch.h b/src/api/Abstraction/DiagnosticsAbstraction/pch.h index 78cf4bebf..b717611cf 100644 --- a/src/api/Abstraction/DiagnosticsAbstraction/pch.h +++ b/src/api/Abstraction/DiagnosticsAbstraction/pch.h @@ -56,7 +56,6 @@ // AbstractionUtilities #include "endpoint_data_helpers.h" #include "swd_property_builders.h" -#include "swd_property_helpers.h" #include "json_helpers.h" #include "MidiDefs.h" diff --git a/src/api/Abstraction/KSAbstraction/Midi2.KSMidiEndpointManager.cpp b/src/api/Abstraction/KSAbstraction/Midi2.KSMidiEndpointManager.cpp index 82add44ac..34a9bf3ed 100644 --- a/src/api/Abstraction/KSAbstraction/Midi2.KSMidiEndpointManager.cpp +++ b/src/api/Abstraction/KSAbstraction/Midi2.KSMidiEndpointManager.cpp @@ -398,12 +398,32 @@ HRESULT CMidi2KSMidiEndpointManager::OnDeviceAdded(DeviceWatcher watcher, Device const ULONG deviceInterfaceIdMaxSize = 255; wchar_t newDeviceInterfaceId[deviceInterfaceIdMaxSize]{ 0 }; + // TODO: Move to this structure + // + PMIDIENDPOINTCOMMONPROPERTIES pCommonProperties = nullptr; + //MIDIENDPOINTCOMMONPROPERTIES commonProperties; + //commonProperties.AbstractionLayerGuid = m_TransportAbstractionId; + //commonProperties.EndpointPurpose = MidiEndpointDevicePurposePropertyValue::DiagnosticPing; + //commonProperties.FriendlyName = friendlyName.c_str(); + //commonProperties.TransportMnemonic = mnemonic.c_str(); + //commonProperties.TransportSuppliedEndpointName = endpointName.c_str(); + //commonProperties.TransportSuppliedEndpointDescription = endpointDescription.c_str(); + //commonProperties.UserSuppliedEndpointName = L""; + //commonProperties.UserSuppliedEndpointDescription = L""; + //commonProperties.UniqueIdentifier = UniqueId.c_str(); + //commonProperties.SupportedDataFormats = MidiDataFormat::MidiDataFormat_UMP; + //commonProperties.NativeDataFormat = MIDI_PROP_NATIVEDATAFORMAT_UMP; + //commonProperties.SupportsMultiClient = multiClient; + //commonProperties.RequiresMetadataHandler = requiresMetadataHandler; + //commonProperties.GenerateIncomingTimestamps = generateIncomingTimestamps; + // log telemetry in the event activating the SWD for this pin has failed, // but push forward with creation for other pins. LOG_IF_FAILED(MidiPin->SwdCreation = m_MidiDeviceManager->ActivateEndpoint( MidiPin->ParentInstanceId.c_str(), MidiPin->CreateUMPOnly, MidiPin->Flow, + pCommonProperties, (ULONG) interfaceDevProperties.size(), (ULONG) deviceDevProperties.size(), (PVOID)interfaceDevProperties.data(), diff --git a/src/api/Abstraction/LoopbackMidiAbstraction/AbstractionState.h b/src/api/Abstraction/LoopbackMidiAbstraction/AbstractionState.h index 78d89dd24..abc579021 100644 --- a/src/api/Abstraction/LoopbackMidiAbstraction/AbstractionState.h +++ b/src/api/Abstraction/LoopbackMidiAbstraction/AbstractionState.h @@ -31,7 +31,7 @@ class AbstractionState return m_configurationManager; } - std::shared_ptr GetEndpointTable() + std::shared_ptr GetEndpointTable() { return m_endpointTable; } @@ -58,5 +58,5 @@ class AbstractionState wil::com_ptr m_endpointManager; wil::com_ptr m_configurationManager; - std::shared_ptr m_endpointTable = std::make_shared(); + std::shared_ptr m_endpointTable = std::make_shared(); }; \ No newline at end of file diff --git a/src/api/Abstraction/LoopbackMidiAbstraction/Midi2.LoopbackMidiBidi.cpp b/src/api/Abstraction/LoopbackMidiAbstraction/Midi2.LoopbackMidiBidi.cpp index 1e46e4864..e587f6b28 100644 --- a/src/api/Abstraction/LoopbackMidiAbstraction/Midi2.LoopbackMidiBidi.cpp +++ b/src/api/Abstraction/LoopbackMidiAbstraction/Midi2.LoopbackMidiBidi.cpp @@ -31,6 +31,9 @@ CMidi2LoopbackMidiBiDi::Initialize( m_callbackContext = Context; m_endpointId = internal::NormalizeEndpointInterfaceIdWStringCopy(endpointId); + m_associationId = internal::GetSwdPropertyVirtualEndpointAssociationId(m_endpointId); + + HRESULT hr = S_OK; // TODO: This should use SWD properties and not a string search @@ -44,12 +47,14 @@ CMidi2LoopbackMidiBiDi::Initialize( TraceLoggingLevel(WINEVENT_LEVEL_INFO), TraceLoggingPointer(this, "this"), TraceLoggingWideString(L"Initializing Side-A BiDi", "message"), - TraceLoggingWideString(m_endpointId.c_str(), "endpoint id") + TraceLoggingWideString(m_endpointId.c_str(), "endpoint id"), + TraceLoggingWideString(m_associationId.c_str(), "association id") ); m_callback = Callback; m_isEndpointA = true; + } else if (internal::EndpointInterfaceIdContainsString(m_endpointId, MIDI_PERM_LOOP_INSTANCE_ID_B_PREFIX) || internal::EndpointInterfaceIdContainsString(m_endpointId, MIDI_TEMP_LOOP_INSTANCE_ID_B_PREFIX)) @@ -60,7 +65,8 @@ CMidi2LoopbackMidiBiDi::Initialize( TraceLoggingLevel(WINEVENT_LEVEL_INFO), TraceLoggingPointer(this, "this"), TraceLoggingWideString(L"Initializing Side-B BiDi", "message"), - TraceLoggingWideString(m_endpointId.c_str(), "endpoint id") + TraceLoggingWideString(m_endpointId.c_str(), "endpoint id"), + TraceLoggingWideString(m_associationId.c_str(), "association id") ); m_callback = Callback; @@ -77,10 +83,39 @@ CMidi2LoopbackMidiBiDi::Initialize( TraceLoggingLevel(WINEVENT_LEVEL_ERROR), TraceLoggingPointer(this, "this"), TraceLoggingWideString(L"We don't understand the endpoint Id", "message"), - TraceLoggingWideString(m_endpointId.c_str(), "endpoint id") - ); + TraceLoggingWideString(m_endpointId.c_str(), "endpoint id"), + TraceLoggingWideString(m_associationId.c_str(), "association id") + ); + + return E_FAIL; + } + + // register this endpoint as part of a loopback device - hr = E_FAIL; + auto device = AbstractionState::Current().GetEndpointTable()->GetDevice(m_associationId); + + if (device) + { + if (m_isEndpointA) + { + device->RegisterEndpointA(this); + } + else + { + device->RegisterEndpointB(this); + } + } + else + { + TraceLoggingWrite( + MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), + __FUNCTION__, + TraceLoggingLevel(WINEVENT_LEVEL_INFO), + TraceLoggingPointer(this, "this"), + TraceLoggingWideString(L"Unable to find matching device in device table", "message"), + TraceLoggingWideString(m_endpointId.c_str(), "endpoint id"), + TraceLoggingWideString(m_associationId.c_str(), "association id") + ); } return hr; @@ -115,7 +150,8 @@ CMidi2LoopbackMidiBiDi::SendMidiMessage( __FUNCTION__, TraceLoggingLevel(WINEVENT_LEVEL_INFO), TraceLoggingPointer(this, "this"), - TraceLoggingWideString(m_endpointId.c_str(), "endpoint id") + TraceLoggingWideString(m_endpointId.c_str(), "endpoint id"), + TraceLoggingBool(m_isEndpointA, "is endpoint A") ); RETURN_HR_IF_NULL(E_INVALIDARG, Message); @@ -130,6 +166,19 @@ CMidi2LoopbackMidiBiDi::SendMidiMessage( { return device->SendMessageAToB(Message, Size, Position, m_callbackContext); } + else + { + TraceLoggingWrite( + MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), + __FUNCTION__, + TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + TraceLoggingPointer(this, "this"), + TraceLoggingWideString(m_endpointId.c_str(), "endpoint id"), + TraceLoggingWideString(L"Send A to B : Unable to find endpoint device in table", "message") + ); + + return E_FAIL; + } } else { @@ -140,6 +189,19 @@ CMidi2LoopbackMidiBiDi::SendMidiMessage( { return device->SendMessageBToA(Message, Size, Position, m_callbackContext); } + else + { + TraceLoggingWrite( + MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), + __FUNCTION__, + TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + TraceLoggingPointer(this, "this"), + TraceLoggingWideString(m_endpointId.c_str(), "endpoint id"), + TraceLoggingWideString(L"Send B to A : Unable to find endpoint device in table", "message") + ); + + return E_FAIL; + } } return S_OK; diff --git a/src/api/Abstraction/LoopbackMidiAbstraction/Midi2.LoopbackMidiConfigurationManager.cpp b/src/api/Abstraction/LoopbackMidiAbstraction/Midi2.LoopbackMidiConfigurationManager.cpp index 843cee601..ca0de42a9 100644 --- a/src/api/Abstraction/LoopbackMidiAbstraction/Midi2.LoopbackMidiConfigurationManager.cpp +++ b/src/api/Abstraction/LoopbackMidiAbstraction/Midi2.LoopbackMidiConfigurationManager.cpp @@ -12,7 +12,7 @@ _Use_decl_annotations_ HRESULT CMidi2LoopbackMidiConfigurationManager::Initialize( - GUID AbstractionId, + GUID AbstractionId, IUnknown* MidiDeviceManager ) { @@ -82,13 +82,11 @@ CMidi2LoopbackMidiConfigurationManager::UpdateConfiguration( std::wstring instanceIdPrefixB = IsFromConfigurationFile ? MIDI_PERM_LOOP_INSTANCE_ID_B_PREFIX : MIDI_TEMP_LOOP_INSTANCE_ID_B_PREFIX; // we should probably set a property based on this as well. - - - auto createObject = internal::JsonGetObjectProperty(jsonObject, MIDI_CONFIG_JSON_ENDPOINT_LOOPBACK_DEVICES_CREATE_KEY, json::JsonObject{}); + auto createObject = jsonObject.GetNamedObject(MIDI_CONFIG_JSON_ENDPOINT_LOOPBACK_DEVICES_CREATE_KEY, nullptr); // Create ---------------------------------- - if (createObject.Size() > 0) + if (createObject != nullptr && createObject.Size() > 0) { auto o = createObject.First(); @@ -97,80 +95,162 @@ CMidi2LoopbackMidiConfigurationManager::UpdateConfiguration( std::shared_ptr definitionA = std::make_shared(); std::shared_ptr definitionB = std::make_shared(); - auto associationObj = o.Current().Value().as(); + // get the association string (GUID) name + auto associationKey = o.Current().Key(); + //json::JsonObject associationObj; - definitionA->AssociationId = o.Current().Key(); + auto associationObj = o.Current().Value().GetObject(); - auto endpointAObject = internal::JsonGetObjectProperty(associationObj, MIDI_CONFIG_JSON_ENDPOINT_LOOPBACK_DEVICE_ENDPOINT_A_KEY, nullptr); - auto endpointBObject = internal::JsonGetObjectProperty(associationObj, MIDI_CONFIG_JSON_ENDPOINT_LOOPBACK_DEVICE_ENDPOINT_B_KEY, nullptr); + //if (!o.Current().Value().try_as(associationObj)) + //{ + // TraceLoggingWrite( + // MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), + // __FUNCTION__, + // TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + // TraceLoggingPointer(this, "this"), + // TraceLoggingWideString(L"Unable to read the property as a json object", "message"), + // TraceLoggingWideString(associationKey.c_str(), "key") + // TraceLoggingWideString(o.Current().Value().Stringify(), "stringify") + // ); - if (endpointAObject != nullptr && endpointBObject != nullptr) - { - definitionA->EndpointName = internal::JsonGetWStringProperty(endpointAObject, MIDI_CONFIG_JSON_ENDPOINT_COMMON_NAME_PROPERTY, L""); - definitionA->EndpointName = internal::JsonGetWStringProperty(endpointAObject, MIDI_CONFIG_JSON_ENDPOINT_COMMON_DESCRIPTION_PROPERTY, L""); - definitionA->EndpointName = internal::JsonGetWStringProperty(endpointAObject, MIDI_CONFIG_JSON_ENDPOINT_COMMON_UNIQUE_ID_PROPERTY, L""); - definitionA->InstanceIdPrefix = instanceIdPrefixA; + // internal::JsonStringifyObjectToOutParam(responseObject, &Response); - definitionB->EndpointName = internal::JsonGetWStringProperty(endpointBObject, MIDI_CONFIG_JSON_ENDPOINT_COMMON_NAME_PROPERTY, L""); - definitionB->EndpointName = internal::JsonGetWStringProperty(endpointBObject, MIDI_CONFIG_JSON_ENDPOINT_COMMON_DESCRIPTION_PROPERTY, L""); - definitionB->EndpointName = internal::JsonGetWStringProperty(endpointBObject, MIDI_CONFIG_JSON_ENDPOINT_COMMON_UNIQUE_ID_PROPERTY, L""); - definitionB->InstanceIdPrefix = instanceIdPrefixB; + // return E_FAIL; + //} + + if (associationObj) + { + definitionA->AssociationId = associationKey; + definitionB->AssociationId = definitionA->AssociationId; - if (SUCCEEDED(AbstractionState::Current().GetEndpointManager()->CreateEndpointPair(definitionA, definitionB))) - { - TraceLoggingWrite( - MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), - __FUNCTION__, - TraceLoggingLevel(WINEVENT_LEVEL_INFO), - TraceLoggingPointer(this, "this"), - TraceLoggingWideString(L"Loopback endpoint pair created", "message") - ); - - // all good - - internal::JsonSetBoolProperty( - responseObject, - MIDI_CONFIG_JSON_ENDPOINT_LOOPBACK_DEVICE_RESPONSE_SUCCESS_PROPERTY_KEY, - true); - - // update the return json with the new Ids - internal::JsonSetWStringProperty( - responseObject, - MIDI_CONFIG_JSON_ENDPOINT_LOOPBACK_DEVICE_RESPONSE_CREATED_ENDPOINT_A_ID_KEY, - definitionA->CreatedEndpointInterfaceId); + auto endpointAObject = associationObj.GetNamedObject(MIDI_CONFIG_JSON_ENDPOINT_LOOPBACK_DEVICE_ENDPOINT_A_KEY, nullptr); + auto endpointBObject = associationObj.GetNamedObject(MIDI_CONFIG_JSON_ENDPOINT_LOOPBACK_DEVICE_ENDPOINT_B_KEY, nullptr); - internal::JsonSetWStringProperty( - responseObject, - MIDI_CONFIG_JSON_ENDPOINT_LOOPBACK_DEVICE_RESPONSE_CREATED_ENDPOINT_B_ID_KEY, - definitionB->CreatedEndpointInterfaceId); + if (endpointAObject != nullptr && endpointBObject != nullptr) + { + definitionA->EndpointName = endpointAObject.GetNamedString(MIDI_CONFIG_JSON_ENDPOINT_COMMON_NAME_PROPERTY, L""); + definitionA->EndpointDescription = endpointAObject.GetNamedString(MIDI_CONFIG_JSON_ENDPOINT_COMMON_DESCRIPTION_PROPERTY, L""); + definitionA->EndpointUniqueIdentifier = endpointAObject.GetNamedString(MIDI_CONFIG_JSON_ENDPOINT_COMMON_UNIQUE_ID_PROPERTY, L""); + definitionA->InstanceIdPrefix = instanceIdPrefixA; + + definitionB->EndpointName = endpointBObject.GetNamedString(MIDI_CONFIG_JSON_ENDPOINT_COMMON_NAME_PROPERTY, L""); + definitionB->EndpointDescription = endpointBObject.GetNamedString(MIDI_CONFIG_JSON_ENDPOINT_COMMON_DESCRIPTION_PROPERTY, L""); + definitionB->EndpointUniqueIdentifier = endpointBObject.GetNamedString(MIDI_CONFIG_JSON_ENDPOINT_COMMON_UNIQUE_ID_PROPERTY, L""); + definitionB->InstanceIdPrefix = instanceIdPrefixB; + + + if (definitionA->EndpointName.empty() || definitionB->EndpointName.empty()) + { + TraceLoggingWrite( + MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), + __FUNCTION__, + TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + TraceLoggingPointer(this, "this"), + TraceLoggingWideString(L"Endpoint name missing or empty", "message") + ); + + internal::JsonStringifyObjectToOutParam(responseObject, &Response); + + return E_FAIL; + } + + + if (definitionA->EndpointUniqueIdentifier.empty() || definitionB->EndpointUniqueIdentifier.empty()) + { + TraceLoggingWrite( + MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), + __FUNCTION__, + TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + TraceLoggingPointer(this, "this"), + TraceLoggingWideString(L"Unique identifier missing or empty", "message") + ); + + internal::JsonStringifyObjectToOutParam(responseObject, &Response); + + return E_FAIL; + } + + + if (SUCCEEDED(AbstractionState::Current().GetEndpointManager()->CreateEndpointPair(definitionA, definitionB))) + { + TraceLoggingWrite( + MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), + __FUNCTION__, + TraceLoggingLevel(WINEVENT_LEVEL_INFO), + TraceLoggingPointer(this, "this"), + TraceLoggingWideString(L"Loopback endpoint pair created", "message") + ); + + // all good + + internal::JsonSetBoolProperty( + responseObject, + MIDI_CONFIG_JSON_ENDPOINT_LOOPBACK_DEVICE_RESPONSE_SUCCESS_PROPERTY_KEY, + true); + + // update the return json with the new Ids + + internal::JsonSetWStringProperty( + responseObject, + MIDI_CONFIG_JSON_ENDPOINT_LOOPBACK_DEVICE_RESPONSE_CREATED_ENDPOINT_A_ID_KEY, + definitionA->CreatedEndpointInterfaceId); + + internal::JsonSetWStringProperty( + responseObject, + MIDI_CONFIG_JSON_ENDPOINT_LOOPBACK_DEVICE_RESPONSE_CREATED_ENDPOINT_B_ID_KEY, + definitionB->CreatedEndpointInterfaceId); + } + else + { + // we failed to create the endpoints. Exit and return a fail. + TraceLoggingWrite( + MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), + __FUNCTION__, + TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + TraceLoggingPointer(this, "this"), + TraceLoggingWideString(L"Failed to create endpoints", "message") + ); + + internal::JsonStringifyObjectToOutParam(responseObject, &Response); + + return E_FAIL; + } } else { - // we failed to create the endpoints. Exit and return a fail. + // couldn't get the endpointA or endpointB objects. Exit and return a fail + TraceLoggingWrite( MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), __FUNCTION__, TraceLoggingLevel(WINEVENT_LEVEL_ERROR), TraceLoggingPointer(this, "this"), - TraceLoggingWideString(L"Failed to create endpoints", "message") + TraceLoggingWideString(associationKey.c_str(), "association key"), + TraceLoggingWideString(L"Failed to get one or both endpoints from the JSON", "message") ); + internal::JsonStringifyObjectToOutParam(responseObject, &Response); + + return E_FAIL; + } } else { - // couldn't get the endpointA or endpointB objects. Exit and return a fail - TraceLoggingWrite( MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), __FUNCTION__, TraceLoggingLevel(WINEVENT_LEVEL_ERROR), TraceLoggingPointer(this, "this"), - TraceLoggingWideString(L"Failed to get one or both endpoints from the JSON", "message") + TraceLoggingWideString(associationKey.c_str(), "association key"), + TraceLoggingWideString(L"Unable to convert association id property to a JsonObject", "message") ); + internal::JsonStringifyObjectToOutParam(responseObject, &Response); + + return E_FAIL; } o.MoveNext(); @@ -210,6 +290,22 @@ CMidi2LoopbackMidiConfigurationManager::UpdateConfiguration( // // TODO : Update endpoints //} + internal::JsonStringifyObjectToOutParam(responseObject, &Response); + + return S_OK; + + } + catch (const std::exception& e) + { + TraceLoggingWrite( + MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), + __FUNCTION__, + TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + TraceLoggingPointer(this, "this"), + TraceLoggingWideString(L"std exception processing json", "message"), + TraceLoggingString(e.what(), "exception"), + TraceLoggingWideString(ConfigurationJsonSection, "json") + ); } catch (...) { @@ -218,13 +314,9 @@ CMidi2LoopbackMidiConfigurationManager::UpdateConfiguration( __FUNCTION__, TraceLoggingLevel(WINEVENT_LEVEL_ERROR), TraceLoggingPointer(this, "this"), - TraceLoggingWideString(L"Exception processing json", "message"), + TraceLoggingWideString(L"Other exception processing json", "message"), TraceLoggingWideString(ConfigurationJsonSection, "json") ); - - internal::JsonStringifyObjectToOutParam(responseObject, &Response); - - return E_FAIL; } // return the json with the information the client will need diff --git a/src/api/Abstraction/LoopbackMidiAbstraction/Midi2.LoopbackMidiEndpointManager.cpp b/src/api/Abstraction/LoopbackMidiAbstraction/Midi2.LoopbackMidiEndpointManager.cpp index a1d7b276f..dd9212b3f 100644 --- a/src/api/Abstraction/LoopbackMidiAbstraction/Midi2.LoopbackMidiEndpointManager.cpp +++ b/src/api/Abstraction/LoopbackMidiAbstraction/Midi2.LoopbackMidiEndpointManager.cpp @@ -159,8 +159,8 @@ CMidi2LoopbackMidiEndpointManager::CreateSingleEndpoint( TraceLoggingLevel(WINEVENT_LEVEL_INFO), TraceLoggingPointer(this, "this"), TraceLoggingWideString(definition->AssociationId.c_str(), "association id"), - TraceLoggingWideString(definition->EndpointUniqueIdentifier.c_str(), "unique identifier"), TraceLoggingWideString(definition->InstanceIdPrefix.c_str(), "prefix"), + TraceLoggingWideString(definition->EndpointUniqueIdentifier.c_str(), "unique identifier"), TraceLoggingWideString(definition->EndpointName.c_str(), "name"), TraceLoggingWideString(definition->EndpointDescription.c_str(), "description") ); @@ -183,52 +183,32 @@ CMidi2LoopbackMidiEndpointManager::CreateSingleEndpoint( std::vector interfaceDeviceProperties{}; - bool requiresMetadataHandler = false; - bool multiClient = true; - bool generateIncomingTimestamps = true; - // no user or in-protocol data in this case std::wstring friendlyName = internal::CalculateEndpointDevicePrimaryName(endpointName, L"", L""); - // all the standard properties we define for endpoints - if (internal::AddStandardEndpointProperties( - interfaceDeviceProperties, - m_TransportAbstractionId, - MidiEndpointDevicePurposePropertyValue::NormalMessageEndpoint, - friendlyName, - mnemonic, - endpointName, - endpointDescription, - L"", - L"", - definition->EndpointUniqueIdentifier, - MidiDataFormat::MidiDataFormat_UMP, - MIDI_PROP_NATIVEDATAFORMAT_UMP, - multiClient, - requiresMetadataHandler, - generateIncomingTimestamps - )) - { - // additional properties for this abstraction - // we clear this because it's not used for this abstraction. - interfaceDeviceProperties.push_back(internal::BuildEmptyDevProperty(PKEY_MIDI_AssociatedUMP)); + bool requiresMetadataHandler = false; + bool multiClient = true; + bool generateIncomingTimestamps = true; - // this is needed for the loopback endpoints to have a relationship with each other - interfaceDeviceProperties.push_back(internal::BuildWStringDevProperty(PKEY_MIDI_VirtualMidiEndpointAssociator, definition->AssociationId)); - } - else - { - TraceLoggingWrite( - MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), - __FUNCTION__, - TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - TraceLoggingPointer(this, "this"), - TraceLoggingWideString(L"Unable to build standard endpoint properties list", "message") - ); - return E_FAIL; - } + TraceLoggingWrite( + MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), + __FUNCTION__, + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), + TraceLoggingPointer(this, "this"), + TraceLoggingWideString(definition->AssociationId.c_str(), "association id"), + TraceLoggingWideString(definition->EndpointUniqueIdentifier.c_str(), "unique identifier"), + TraceLoggingWideString(L"Adding endpoint properties"), + TraceLoggingWideString(friendlyName.c_str(), "friendlyName"), + TraceLoggingWideString(mnemonic.c_str(), "mnemonic"), + TraceLoggingWideString(endpointName.c_str(), "endpointName"), + TraceLoggingWideString(endpointDescription.c_str(), "endpointName") + ); + + // this is needed for the loopback endpoints to have a relationship with each other + interfaceDeviceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_VirtualMidiEndpointAssociator, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_STRING, (ULONG)(sizeof(wchar_t) * (definition->AssociationId.size() + 1)), (PVOID)definition->AssociationId.c_str() }); // Device properties @@ -248,16 +228,45 @@ CMidi2LoopbackMidiEndpointManager::CreateSingleEndpoint( createInfo.pszInstanceId = instanceId.c_str(); createInfo.CapabilityFlags = SWDeviceCapabilitiesNone; - createInfo.pszDeviceDescription = endpointName.c_str(); + createInfo.pszDeviceDescription = friendlyName.c_str(); const ULONG deviceInterfaceIdMaxSize = 255; wchar_t newDeviceInterfaceId[deviceInterfaceIdMaxSize]{ 0 }; + TraceLoggingWrite( + MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), + __FUNCTION__, + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), + TraceLoggingPointer(this, "this"), + TraceLoggingWideString(definition->AssociationId.c_str(), "association id"), + TraceLoggingWideString(definition->EndpointUniqueIdentifier.c_str(), "unique identifier"), + TraceLoggingWideString(instanceId.c_str(), "instance id"), + TraceLoggingWideString(L"Activating endpoint") + ); + + MIDIENDPOINTCOMMONPROPERTIES commonProperties; + commonProperties.AbstractionLayerGuid = m_TransportAbstractionId; + commonProperties.EndpointPurpose = MidiEndpointDevicePurposePropertyValue::NormalMessageEndpoint; + commonProperties.FriendlyName = friendlyName.c_str(); + commonProperties.TransportMnemonic = mnemonic.c_str(); + commonProperties.TransportSuppliedEndpointName = endpointName.c_str(); + commonProperties.TransportSuppliedEndpointDescription = endpointDescription.c_str(); + commonProperties.UserSuppliedEndpointName = nullptr; + commonProperties.UserSuppliedEndpointDescription = nullptr; + commonProperties.UniqueIdentifier = definition->EndpointUniqueIdentifier.c_str(); + commonProperties.SupportedDataFormats = MidiDataFormat::MidiDataFormat_UMP; + commonProperties.NativeDataFormat = MIDI_PROP_NATIVEDATAFORMAT_UMP; + commonProperties.SupportsMultiClient = multiClient; + commonProperties.RequiresMetadataHandler = requiresMetadataHandler; + commonProperties.GenerateIncomingTimestamps = generateIncomingTimestamps; + + RETURN_IF_FAILED(m_MidiDeviceManager->ActivateEndpoint( (PCWSTR)m_parentDeviceId.c_str(), // parent instance Id true, // UMP-only MidiFlow::MidiFlowBidirectional, // MIDI Flow + &commonProperties, (ULONG)interfaceDeviceProperties.size(), ARRAYSIZE(deviceDevProperties), (PVOID)interfaceDeviceProperties.data(), @@ -267,6 +276,18 @@ CMidi2LoopbackMidiEndpointManager::CreateSingleEndpoint( deviceInterfaceIdMaxSize)); + TraceLoggingWrite( + MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), + __FUNCTION__, + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), + TraceLoggingPointer(this, "this"), + TraceLoggingWideString(definition->AssociationId.c_str(), "association id"), + TraceLoggingWideString(definition->EndpointUniqueIdentifier.c_str(), "unique identifier"), + TraceLoggingWideString(newDeviceInterfaceId, "new device interface id"), + TraceLoggingWideString(L"Endpoint activated") + ); + + // now delete all the properties that have been discovered in-protocol // we have to do this because they end up cached by PNP and come back // when you recreate a device with the same Id. This is a real problem @@ -276,12 +297,21 @@ CMidi2LoopbackMidiEndpointManager::CreateSingleEndpoint( // we need this for removal later definition->CreatedShortClientInstanceId = instanceId; - definition->CreatedEndpointInterfaceId = internal::NormalizeEndpointInterfaceIdWStringCopy(newDeviceInterfaceId); //MidiEndpointTable::Current().AddCreatedEndpointDevice(entry); //MidiEndpointTable::Current().AddCreatedClient(entry.VirtualEndpointAssociationId, entry.CreatedClientEndpointId); + TraceLoggingWrite( + MidiLoopbackMidiAbstractionTelemetryProvider::Provider(), + __FUNCTION__, + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), + TraceLoggingPointer(this, "this"), + TraceLoggingWideString(definition->AssociationId.c_str(), "association id"), + TraceLoggingWideString(definition->EndpointUniqueIdentifier.c_str(), "unique identifier"), + TraceLoggingWideString(L"Done") + ); + return S_OK; } @@ -308,8 +338,16 @@ CMidi2LoopbackMidiEndpointManager::CreateEndpointPair( { if (SUCCEEDED(CreateSingleEndpoint(definitionB))) { + // all good now. Create the device table entry. + + auto associationId = definitionA->AssociationId; + + auto device = MidiLoopbackDevice{}; + + device.DefinitionA = *definitionA; + device.DefinitionB = *definitionB; - // all good now + AbstractionState::Current().GetEndpointTable()->SetDevice(associationId, device); } else diff --git a/src/api/Abstraction/LoopbackMidiAbstraction/MidiLoopbackDeviceTable.h b/src/api/Abstraction/LoopbackMidiAbstraction/MidiLoopbackDeviceTable.h index a8b67b284..389ebacee 100644 --- a/src/api/Abstraction/LoopbackMidiAbstraction/MidiLoopbackDeviceTable.h +++ b/src/api/Abstraction/LoopbackMidiAbstraction/MidiLoopbackDeviceTable.h @@ -10,7 +10,7 @@ #pragma once -class MidiEndpointTable +class MidiLoopbackDeviceTable { public: diff --git a/src/api/Abstraction/LoopbackMidiAbstraction/pch.h b/src/api/Abstraction/LoopbackMidiAbstraction/pch.h index ca66d19ac..94f64b1fa 100644 --- a/src/api/Abstraction/LoopbackMidiAbstraction/pch.h +++ b/src/api/Abstraction/LoopbackMidiAbstraction/pch.h @@ -20,9 +20,6 @@ #include #include #include -//#include - -//namespace json = ::winrt::Windows::Data::Json; #include @@ -67,12 +64,19 @@ #include "strsafe.h" #include "wstring_util.h" +//#pragma push_macro("GetObject") +#undef GetObject +#include +namespace json = ::winrt::Windows::Data::Json; +//#pragma pop_macro("GetObject") + + // AbstractionUtilities #include "endpoint_data_helpers.h" #include "swd_property_builders.h" -#include "swd_property_helpers.h" #include "json_helpers.h" +#include "swd_shared.h" #include "MidiDefs.h" #include "MidiDataFormat.h" diff --git a/src/api/Abstraction/NetworkMidiAbstraction/pch.h b/src/api/Abstraction/NetworkMidiAbstraction/pch.h index 4e822a25b..d51457851 100644 --- a/src/api/Abstraction/NetworkMidiAbstraction/pch.h +++ b/src/api/Abstraction/NetworkMidiAbstraction/pch.h @@ -59,7 +59,6 @@ namespace json = ::winrt::Windows::Data::Json; // AbstractionUtilities #include "endpoint_data_helpers.h" #include "swd_property_builders.h" -#include "swd_property_helpers.h" #include "json_helpers.h" #include "MidiDefs.h" diff --git a/src/api/Abstraction/SampleAbstraction/pch.h b/src/api/Abstraction/SampleAbstraction/pch.h index 286ecad14..9f95eac36 100644 --- a/src/api/Abstraction/SampleAbstraction/pch.h +++ b/src/api/Abstraction/SampleAbstraction/pch.h @@ -41,7 +41,6 @@ // AbstractionUtilities #include "endpoint_data_helpers.h" #include "swd_property_builders.h" -#include "swd_property_helpers.h" #include "json_helpers.h" #include "MidiDefs.h" diff --git a/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiAbstraction.vcxproj b/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiAbstraction.vcxproj index b6a569dc9..7fef3cb1a 100644 --- a/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiAbstraction.vcxproj +++ b/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiAbstraction.vcxproj @@ -282,7 +282,6 @@ - @@ -303,7 +302,6 @@ - diff --git a/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiAbstraction.vcxproj.filters b/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiAbstraction.vcxproj.filters index 1c9c29dc9..0190308f7 100644 --- a/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiAbstraction.vcxproj.filters +++ b/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiAbstraction.vcxproj.filters @@ -33,9 +33,6 @@ Source Files - - Source Files - Source Files @@ -82,9 +79,6 @@ Header Files - - Header Files - Header Files diff --git a/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiEndpointManager.cpp b/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiEndpointManager.cpp index 0aef21ac0..c3382a443 100644 --- a/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiEndpointManager.cpp +++ b/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiEndpointManager.cpp @@ -246,48 +246,10 @@ CMidi2VirtualMidiEndpointManager::CreateClientVisibleEndpoint( // no user or in-protocol data in this case std::wstring friendlyName = internal::CalculateEndpointDevicePrimaryName(endpointName, L"", L""); - // all the standard properties we define for endpoints - if (internal::AddStandardEndpointProperties( - interfaceDeviceProperties, - m_TransportAbstractionId, - MidiEndpointDevicePurposePropertyValue::NormalMessageEndpoint, - friendlyName, - mnemonic, - endpointName, - endpointDescription, - L"", - L"", - entry.ShortUniqueId, - MidiDataFormat::MidiDataFormat_UMP, - MIDI_PROP_NATIVEDATAFORMAT_UMP, - multiClient, - requiresMetadataHandler, - generateIncomingTimestamps - )) - { - // all good. Add additional properties - // additional properties for this abstraction - - // we clear this because it's not used for this abstraction. - interfaceDeviceProperties.push_back(internal::BuildEmptyDevProperty(PKEY_MIDI_AssociatedUMP)); - - // this is needed for the loopback endpoints to have a relationship with each other - interfaceDeviceProperties.push_back(internal::BuildWStringDevProperty(PKEY_MIDI_VirtualMidiEndpointAssociator, entry.VirtualEndpointAssociationId)); - } - else - { - // unable to build properties + // this is needed for the loopback endpoints to have a relationship with each other + interfaceDeviceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_VirtualMidiEndpointAssociator, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_STRING, (ULONG)(sizeof(wchar_t) * (entry.VirtualEndpointAssociationId.size() + 1)), (PVOID)entry.VirtualEndpointAssociationId.c_str() }); - TraceLoggingWrite( - MidiVirtualMidiAbstractionTelemetryProvider::Provider(), - __FUNCTION__, - TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - TraceLoggingPointer(this, "this"), - TraceLoggingWideString(L"Unable to build standard endpoint properties list", "message") - ); - - return E_FAIL; - } DEVPROPERTY deviceDevProperties[] = { {{DEVPKEY_Device_PresenceNotForDevice, DEVPROP_STORE_SYSTEM, nullptr}, @@ -309,10 +271,28 @@ CMidi2VirtualMidiEndpointManager::CreateClientVisibleEndpoint( const ULONG deviceInterfaceIdMaxSize = 255; wchar_t newDeviceInterfaceId[deviceInterfaceIdMaxSize]{ 0 }; + + MIDIENDPOINTCOMMONPROPERTIES commonProperties; + commonProperties.AbstractionLayerGuid = m_TransportAbstractionId; + commonProperties.EndpointPurpose = MidiEndpointDevicePurposePropertyValue::NormalMessageEndpoint; + commonProperties.FriendlyName = friendlyName.c_str(); + commonProperties.TransportMnemonic = mnemonic.c_str(); + commonProperties.TransportSuppliedEndpointName = endpointName.c_str(); + commonProperties.TransportSuppliedEndpointDescription = endpointDescription.c_str(); + commonProperties.UserSuppliedEndpointName = L""; + commonProperties.UserSuppliedEndpointDescription = L""; + commonProperties.UniqueIdentifier = entry.ShortUniqueId.c_str(); + commonProperties.SupportedDataFormats = MidiDataFormat::MidiDataFormat_UMP; + commonProperties.NativeDataFormat = MIDI_PROP_NATIVEDATAFORMAT_UMP; + commonProperties.SupportsMultiClient = multiClient; + commonProperties.RequiresMetadataHandler = requiresMetadataHandler; + commonProperties.GenerateIncomingTimestamps = generateIncomingTimestamps; + RETURN_IF_FAILED(m_MidiDeviceManager->ActivateEndpoint( (PCWSTR)m_parentDeviceId.c_str(), // parent instance Id true, // UMP-only MidiFlow::MidiFlowBidirectional, // MIDI Flow + &commonProperties, (ULONG)interfaceDeviceProperties.size(), ARRAYSIZE(deviceDevProperties), (PVOID)interfaceDeviceProperties.data(), @@ -374,48 +354,10 @@ CMidi2VirtualMidiEndpointManager::CreateDeviceSideEndpoint( // no user or in-protocol data in this case std::wstring friendlyName = internal::CalculateEndpointDevicePrimaryName(endpointName, L"", L""); - // all the standard properties we define for endpoints - if (internal::AddStandardEndpointProperties( - interfaceDeviceProperties, - m_TransportAbstractionId, - MidiEndpointDevicePurposePropertyValue::VirtualDeviceResponder, - friendlyName, - mnemonic, - endpointName, - endpointDescription, - L"", - L"", - entry.ShortUniqueId, - MidiDataFormat::MidiDataFormat_UMP, - MIDI_PROP_NATIVEDATAFORMAT_UMP, - multiClient, - requiresMetadataHandler, - generateIncomingTimestamps - )) - { - // all good. Add additional properties - // additional properties for this abstraction - // we clear this because it's not used for this abstraction. - interfaceDeviceProperties.push_back(internal::BuildEmptyDevProperty(PKEY_MIDI_AssociatedUMP)); + interfaceDeviceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_VirtualMidiEndpointAssociator, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_STRING, (ULONG)(sizeof(wchar_t) * (entry.VirtualEndpointAssociationId.size() + 1)), (PVOID)entry.VirtualEndpointAssociationId.c_str() }); - // this is needed for the loopback endpoints to have a relationship with each other - interfaceDeviceProperties.push_back(internal::BuildWStringDevProperty(PKEY_MIDI_VirtualMidiEndpointAssociator, entry.VirtualEndpointAssociationId)); - } - else - { - // unable to build properties - - TraceLoggingWrite( - MidiVirtualMidiAbstractionTelemetryProvider::Provider(), - __FUNCTION__, - TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - TraceLoggingPointer(this, "this"), - TraceLoggingWideString(L"Unable to build standard endpoint properties list", "message") - ); - - return E_FAIL; - } DEVPROPERTY deviceDevProperties[] = { {{DEVPKEY_Device_PresenceNotForDevice, DEVPROP_STORE_SYSTEM, nullptr}, @@ -442,10 +384,30 @@ CMidi2VirtualMidiEndpointManager::CreateDeviceSideEndpoint( + + + MIDIENDPOINTCOMMONPROPERTIES commonProperties; + commonProperties.AbstractionLayerGuid = m_TransportAbstractionId; + commonProperties.EndpointPurpose = MidiEndpointDevicePurposePropertyValue::VirtualDeviceResponder; + commonProperties.FriendlyName = friendlyName.c_str(); + commonProperties.TransportMnemonic = mnemonic.c_str(); + commonProperties.TransportSuppliedEndpointName = endpointName.c_str(); + commonProperties.TransportSuppliedEndpointDescription = endpointDescription.c_str(); + commonProperties.UserSuppliedEndpointName = L""; + commonProperties.UserSuppliedEndpointDescription = L""; + commonProperties.UniqueIdentifier = entry.ShortUniqueId.c_str(); + commonProperties.SupportedDataFormats = MidiDataFormat::MidiDataFormat_UMP; + commonProperties.NativeDataFormat = MIDI_PROP_NATIVEDATAFORMAT_UMP; + commonProperties.SupportsMultiClient = multiClient; + commonProperties.RequiresMetadataHandler = requiresMetadataHandler; + commonProperties.GenerateIncomingTimestamps = generateIncomingTimestamps; + + RETURN_IF_FAILED(m_MidiDeviceManager->ActivateEndpoint( (PCWSTR)m_parentDeviceId.c_str(), // parent instance Id true, // UMP-only MidiFlow::MidiFlowBidirectional, // MIDI Flow + &commonProperties, (ULONG)interfaceDeviceProperties.size(), ARRAYSIZE(deviceDevProperties), (PVOID)interfaceDeviceProperties.data(), diff --git a/src/api/Abstraction/VirtualMidiAbstraction/MidiEndpointTable.cpp b/src/api/Abstraction/VirtualMidiAbstraction/MidiEndpointTable.cpp index 843f21ea3..e6bd523e2 100644 --- a/src/api/Abstraction/VirtualMidiAbstraction/MidiEndpointTable.cpp +++ b/src/api/Abstraction/VirtualMidiAbstraction/MidiEndpointTable.cpp @@ -72,7 +72,7 @@ MidiEndpointTable::OnClientConnected( // look up the association ID in SWD properties - auto associationId = GetSwdPropertyVirtualEndpointAssociationId(clientEndpointInterfaceId); + auto associationId = internal::GetSwdPropertyVirtualEndpointAssociationId(clientEndpointInterfaceId); if (associationId != L"") { @@ -126,7 +126,7 @@ MidiEndpointTable::OnClientDisconnected( try { - std::wstring associationId = GetSwdPropertyVirtualEndpointAssociationId(clientEndpointInterfaceId); + std::wstring associationId = internal::GetSwdPropertyVirtualEndpointAssociationId(clientEndpointInterfaceId); if (associationId != L"") { @@ -185,7 +185,7 @@ HRESULT MidiEndpointTable::OnDeviceConnected(std::wstring deviceEndpointInterfac try { // look up the association ID in SWD properties - auto associationId = GetSwdPropertyVirtualEndpointAssociationId(deviceEndpointInterfaceId); + auto associationId = internal::GetSwdPropertyVirtualEndpointAssociationId(deviceEndpointInterfaceId); if (associationId != L"") { @@ -290,7 +290,7 @@ HRESULT MidiEndpointTable::OnDeviceDisconnected(std::wstring deviceEndpointInter { if (AbstractionState::Current().GetEndpointManager() != nullptr) { - std::wstring associationId = GetSwdPropertyVirtualEndpointAssociationId(deviceEndpointInterfaceId); + std::wstring associationId = internal::GetSwdPropertyVirtualEndpointAssociationId(deviceEndpointInterfaceId); if (associationId != L"") { diff --git a/src/api/Abstraction/VirtualMidiAbstraction/pch.h b/src/api/Abstraction/VirtualMidiAbstraction/pch.h index 14dd5612b..5f908c1f2 100644 --- a/src/api/Abstraction/VirtualMidiAbstraction/pch.h +++ b/src/api/Abstraction/VirtualMidiAbstraction/pch.h @@ -70,7 +70,6 @@ // AbstractionUtilities #include "endpoint_data_helpers.h" #include "swd_property_builders.h" -#include "swd_property_helpers.h" #include "json_helpers.h" #include "MidiDefs.h" diff --git a/src/api/Abstraction/VirtualMidiAbstraction/swd_shared.cpp b/src/api/Abstraction/VirtualMidiAbstraction/swd_shared.cpp deleted file mode 100644 index 241723feb..000000000 --- a/src/api/Abstraction/VirtualMidiAbstraction/swd_shared.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// 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" - -#include "swd_shared.h" - -_Use_decl_annotations_ -std::wstring GetStringSwdProperty(std::wstring deviceInterfaceId, std::wstring propertyName, std::wstring defaultValue) -{ - auto propertyKey = winrt::to_hstring(propertyName.c_str()); - - auto additionalProperties = winrt::single_threaded_vector(); - additionalProperties.Append(propertyKey); - - - auto deviceInfo = winrt::Windows::Devices::Enumeration::DeviceInformation::CreateFromIdAsync( - winrt::to_hstring(deviceInterfaceId.c_str()), - additionalProperties, - winrt::Windows::Devices::Enumeration::DeviceInformationKind::DeviceInterface).get(); - - auto prop = deviceInfo.Properties().Lookup(propertyKey); - - if (prop) - { - OutputDebugString(__FUNCTION__ L" found property"); - - // this interface is pointing to a UMP interface, so use that instance id. - return (winrt::unbox_value(prop)).c_str(); - } - else - { - OutputDebugString(__FUNCTION__ L" didn't find property"); - // default to any - return defaultValue; - } - -} - - -_Use_decl_annotations_ -std::wstring GetSwdPropertyVirtualEndpointAssociationId(std::wstring deviceInterfaceId) -{ - std::wstring cleanId = internal::NormalizeEndpointInterfaceIdWStringCopy(deviceInterfaceId); - - return internal::ToUpperTrimmedWStringCopy(GetStringSwdProperty(cleanId, STRING_PKEY_MIDI_VirtualMidiEndpointAssociator, L"")); -} - - -_Use_decl_annotations_ -std::wstring GetSwdPropertyInstanceId(std::wstring deviceInterfaceId) -{ - std::wstring cleanId = internal::NormalizeEndpointInterfaceIdWStringCopy(deviceInterfaceId); - - return internal::NormalizeDeviceInstanceIdWStringCopy(GetStringSwdProperty(cleanId, L"System.Devices.DeviceInstanceId", L"")); -} diff --git a/src/api/Abstraction/VirtualMidiAbstraction/swd_shared.h b/src/api/Abstraction/VirtualMidiAbstraction/swd_shared.h deleted file mode 100644 index 379cf1978..000000000 --- a/src/api/Abstraction/VirtualMidiAbstraction/swd_shared.h +++ /dev/null @@ -1,17 +0,0 @@ -// 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/ -// ============================================================================ - -// TODO: Post-NAMM, move this to a lib that all projects share - -#pragma once - -std::wstring GetSwdStringProperty(_In_ std::wstring deviceInterfaceId, _In_ std::wstring propertyName, _In_ std::wstring defaultValue); - -std::wstring GetSwdPropertyVirtualEndpointAssociationId(_In_ std::wstring deviceInterfaceId); - -std::wstring GetSwdPropertyInstanceId(_In_ std::wstring deviceInterfaceId); diff --git a/src/api/Abstraction/VirtualPatchBayAbstraction/Midi2.VirtualPatchBayEndpointManager.cpp b/src/api/Abstraction/VirtualPatchBayAbstraction/Midi2.VirtualPatchBayEndpointManager.cpp index 932f49498..4aa7ba0f5 100644 --- a/src/api/Abstraction/VirtualPatchBayAbstraction/Midi2.VirtualPatchBayEndpointManager.cpp +++ b/src/api/Abstraction/VirtualPatchBayAbstraction/Midi2.VirtualPatchBayEndpointManager.cpp @@ -41,7 +41,7 @@ CMidi2VirtualPatchBayEndpointManager::Initialize( m_TransportAbstractionId = AbstractionLayerGUID; // this is needed so MidiSrv can instantiate the correct transport m_ContainerId = m_TransportAbstractionId; // we use the transport ID as the container ID for convenience - RETURN_IF_FAILED(CreateParentDevice()); +// RETURN_IF_FAILED(CreateParentDevice()); @@ -51,424 +51,11 @@ CMidi2VirtualPatchBayEndpointManager::Initialize( -void SwMidiParentDeviceCreateCallback( - __in HSWDEVICE /*hSwDevice*/, - __in HRESULT CreationResult, - __in_opt PVOID pContext, - __in_opt PCWSTR pszDeviceInstanceId) -{ - if (pContext == nullptr) - { - // TODO: Should log this. - - return; - } - - PPARENTDEVICECREATECONTEXT creationContext = (PPARENTDEVICECREATECONTEXT)pContext; - - - // interface registration has started, assume failure - creationContext->MidiParentDevice->SwDeviceState = SWDEVICESTATE::Failed; - - LOG_IF_FAILED(CreationResult); - - if (SUCCEEDED(CreationResult)) - { - // success, mark the port as created - creationContext->MidiParentDevice->SwDeviceState = SWDEVICESTATE::Created; - - // get the new device instance ID. This is usually modified from what we started with - creationContext->MidiParentDevice->InstanceId = std::wstring(pszDeviceInstanceId); - } - else - { - OutputDebugString(L"" __FUNCTION__ " - CreationResult FAILURE"); - } - - // success or failure, signal we have completed. - creationContext->CreationCompleted.SetEvent(); -} - - - -HRESULT -CMidi2VirtualPatchBayEndpointManager::CreateParentDevice() -{ - // the parent device parameters are set by the transport (this) - - std::wstring parentDeviceName{ TRANSPORT_PARENT_DEVICE_NAME }; - std::wstring parentDeviceId{ TRANSPORT_PARENT_ID }; - - SW_DEVICE_CREATE_INFO CreateInfo = {}; - CreateInfo.cbSize = sizeof(CreateInfo); - CreateInfo.pszInstanceId = parentDeviceId.c_str(); - CreateInfo.CapabilityFlags = SWDeviceCapabilitiesNone; - CreateInfo.pszDeviceDescription = parentDeviceName.c_str(); - - SW_DEVICE_CREATE_INFO* createInfo = (SW_DEVICE_CREATE_INFO*)&CreateInfo; - - if (m_ParentDevice != nullptr) - { - return S_OK; - } - - m_ParentDevice = std::make_unique(); - - RETURN_IF_NULL_ALLOC(m_ParentDevice); - - PARENTDEVICECREATECONTEXT creationContext; - - // lambdas can only be converted to a function pointer if they - // don't do capture, so copy everything into the CREATECONTEXT - // to share with the SwDeviceCreate callback. - creationContext.MidiParentDevice = m_ParentDevice.get(); - - //creationContext.InterfaceDevProperties = (DEVPROPERTY*)InterfaceDevProperties; - //creationContext.IntPropertyCount = IntPropertyCount; - - m_ParentDevice->SwDeviceState = SWDEVICESTATE::CreatePending; - - //m_ParentDevice->InstanceId = createInfo->pszInstanceId; - - DEVPROP_BOOLEAN devPropTrue = DEVPROP_TRUE; - - DEVPROPERTY deviceDevProperties[] = { - {{DEVPKEY_Device_PresenceNotForDevice, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropTrue)), &devPropTrue}, - {{DEVPKEY_Device_NoConnectSound, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropTrue)),&devPropTrue} - }; - - - std::wstring rootDeviceId = LOOPBACK_PARENT_ROOT; - std::wstring enumeratorName = TRANSPORT_ENUMERATOR; - - createInfo->pContainerId = &m_ContainerId; - - RETURN_IF_FAILED(SwDeviceCreate( - enumeratorName.c_str(), // this really should come from the service - rootDeviceId.c_str(), // root device - createInfo, - ARRAYSIZE(deviceDevProperties), // count of properties - (DEVPROPERTY*)deviceDevProperties, // pointer to properties - SwMidiParentDeviceCreateCallback, // callback - &creationContext, - wil::out_param(m_ParentDevice->SwDevice))); - - // wait for creation to complete - creationContext.CreationCompleted.wait(); - - // confirm we were able to register the interface - RETURN_HR_IF(E_FAIL, m_ParentDevice->SwDeviceState != SWDEVICESTATE::Created); - - return S_OK; -} - - -#define MIDI_VIRTUAL_ENDPOINTS_ARRAY_KEY L"endpoints" - -#define MIDI_VIRTUAL_ENDPOINT_PROPERTY_KEY L"key" -#define MIDI_VIRTUAL_ENDPOINT_PROPERTY_NAME L"name" -#define MIDI_VIRTUAL_ENDPOINT_PROPERTY_UNIQUEID L"uniqueIdentifier" -#define MIDI_VIRTUAL_ENDPOINT_PROPERTY_MULTICLIENT L"supportsMulticlient" -#define MIDI_VIRTUAL_ENDPOINT_PROPERTY_DESCRIPTION L"description" -#define MIDI_VIRTUAL_ENDPOINT_PROPERTY_SMALLIMAGE L"smallImagePath" -#define MIDI_VIRTUAL_ENDPOINT_PROPERTY_LARGEIMAGE L"largeImagePath" - - - - -#define MIDI_JSON_ADD_NODE L"add" -#define MIDI_JSON_UPDATE_NODE L"update" -#define MIDI_JSON_REMOVE_NODE L"remove" - - -json::JsonObject GetAddNode( - json::JsonObject Parent -) -{ - if (Parent.HasKey(MIDI_JSON_ADD_NODE)) - { - return Parent.GetNamedObject(MIDI_JSON_ADD_NODE); - } - else - { - return nullptr; - } -} - -winrt::hstring GetStringValue( - json::JsonObject Parent, - winrt::hstring Key, - winrt::hstring Default) -{ - if (Parent.HasKey(Key)) - { - return Parent.GetNamedString(Key); - } - else - { - return Default; - } -} - -_Use_decl_annotations_ -HRESULT -CMidi2VirtualPatchBayEndpointManager::CreateConfiguredEndpoints( - std::wstring ConfigurationJson -) -{ - // if nothing to configure, that's ok - if (ConfigurationJson.empty()) return S_OK; - - try - { - auto jsonObject = json::JsonObject::Parse(ConfigurationJson); - - - // check to see if we have an "add" node. No point in checking for "update" or "remove" for initial configuration - auto addNode = GetAddNode(jsonObject); - - if (addNode != nullptr && addNode.HasKey(MIDI_VIRTUAL_ENDPOINTS_ARRAY_KEY)) - { - auto endpoints = addNode.GetNamedArray(MIDI_VIRTUAL_ENDPOINTS_ARRAY_KEY); - - for (auto endpointElement : endpoints) - { - // GetObjectW here is because wingdi redefines it to GetObject. It's a stupid preprocessor conflict - try - { - auto endpoint = endpointElement.GetObjectW(); - - // auto key = endpoint.GetNamedString(MIDI_VIRTUAL_ENDPOINT_PROPERTY_KEY, L""); - auto name = endpoint.GetNamedString(MIDI_VIRTUAL_ENDPOINT_PROPERTY_NAME, L""); - auto uniqueIdentifier = endpoint.GetNamedString(MIDI_VIRTUAL_ENDPOINT_PROPERTY_UNIQUEID, L""); - // auto supportsMultiClient = endpoint.GetNamedBoolean(MIDI_VIRTUAL_ENDPOINT_PROPERTY_MULTICLIENT, true); - - auto instanceId = TRANSPORT_MNEMONIC L"_" + uniqueIdentifier; - - auto description = GetStringValue(endpoint, MIDI_VIRTUAL_ENDPOINT_PROPERTY_DESCRIPTION, L""); - auto smallImage = GetStringValue(endpoint, MIDI_VIRTUAL_ENDPOINT_PROPERTY_SMALLIMAGE, L""); - auto largeImage = GetStringValue(endpoint, MIDI_VIRTUAL_ENDPOINT_PROPERTY_LARGEIMAGE, L""); - - bool multiclient = true; // TODO - bool virtualResponder = false; // TODO - - - // TODO: Need to add this to the table for routing, and also add the other properties to the function - CreateEndpoint( - (std::wstring)instanceId, - (std::wstring)uniqueIdentifier, - multiclient, - virtualResponder, - (std::wstring)name, - (std::wstring)largeImage, - (std::wstring)smallImage, - (std::wstring)description - ); - } - catch (...) - { - // couldn't get an object. Garbage data - OutputDebugString(L"" __FUNCTION__ " Exception getting endpoint properties from json"); - - return E_FAIL; - } - } - } - else - { - // nothing to add - } - - - } - catch (...) - { - // exception parsing the json. It's likely empty or malformed - - OutputDebugString(L"" __FUNCTION__ " Exception parsing JSON. Json string follows."); - OutputDebugString(ConfigurationJson.c_str()); - - TraceLoggingWrite( - MidiVirtualPatchBayAbstractionTelemetryProvider::Provider(), - __FUNCTION__, - TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - TraceLoggingPointer(this, "this") - ); - - return E_FAIL; - } - - return S_OK; -} - -// this will be called from the runtime endpoint creation interface - _Use_decl_annotations_ HRESULT CMidi2VirtualPatchBayEndpointManager::CreateEndpoint( - std::wstring const InstanceId, - std::wstring const UniqueId, - bool const Multiclient, - bool const IsVirtualEndpointResponder, - std::wstring const Name, - std::wstring const LargeImagePath, - std::wstring const SmallImagePath, - std::wstring const Description ) { - //put all of the devproperties we want into arrays and pass into ActivateEndpoint: - - std::wstring mnemonic(TRANSPORT_MNEMONIC); - MidiFlow const flow = MidiFlow::MidiFlowBidirectional; - - DEVPROP_BOOLEAN devPropTrue = DEVPROP_TRUE; - //DEVPROP_BOOLEAN devPropFalse = DEVPROP_FALSE; - - DEVPROP_BOOLEAN devPropMulticlient = Multiclient ? DEVPROP_TRUE : DEVPROP_FALSE; - //DEVPROP_BOOLEAN devPropVirtualResponder = IsVirtualEndpointResponder ? DEVPROP_TRUE : DEVPROP_FALSE; - - uint32_t endpointPurpose{}; - - if (IsVirtualEndpointResponder) - { - endpointPurpose = (uint32_t)MidiEndpointDevicePurposePropertyValue::VirtualDeviceResponder; - } - else - { - endpointPurpose = (uint32_t)MidiEndpointDevicePurposePropertyValue::NormalMessageEndpoint; - } - - BYTE nativeDataFormat = MIDI_PROP_NATIVEDATAFORMAT_UMP; - - DEVPROPERTY interfaceDevProperties[] = { - {{DEVPKEY_DeviceInterface_FriendlyName, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_STRING, static_cast((Name.length() + 1) * sizeof(WCHAR)), (PVOID)Name.c_str()}, - - // essential to instantiate the right endpoint types - {{PKEY_MIDI_AbstractionLayer, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_GUID, static_cast(sizeof(GUID)), (PVOID)&AbstractionLayerGUID }, - - {{PKEY_MIDI_TransportMnemonic, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_STRING, static_cast((mnemonic.length() + 1) * sizeof(WCHAR)), (PVOID)mnemonic.c_str()}, - - {{PKEY_MIDI_NativeDataFormat, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_BYTE, static_cast(sizeof(BYTE)), (PVOID)&nativeDataFormat}, - - //{{PKEY_MIDI_UniqueIdentifier, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_STRING, static_cast((UniqueId.length() + 1) * sizeof(WCHAR)), (PVOID)UniqueId.c_str()}, - - {{PKEY_MIDI_SupportsMulticlient, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropMulticlient)), (PVOID)&devPropMulticlient}, - - {{PKEY_MIDI_TransportSuppliedEndpointName, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_STRING, static_cast((Name.length() + 1) * sizeof(WCHAR)), (PVOID)Name.c_str()}, - - {{PKEY_MIDI_EndpointDevicePurpose, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_UINT32, static_cast(sizeof(endpointPurpose)),(PVOID)&endpointPurpose}, - - - {{PKEY_MIDI_UserSuppliedLargeImagePath, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_STRING, static_cast((LargeImagePath.length() + 1) * sizeof(WCHAR)), (PVOID)LargeImagePath.c_str() }, - - {{PKEY_MIDI_UserSuppliedSmallImagePath, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_STRING, static_cast((SmallImagePath.length() + 1) * sizeof(WCHAR)), (PVOID)SmallImagePath.c_str() }, - - {{PKEY_MIDI_UserSuppliedDescription, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_STRING, static_cast((Description.length() + 1) * sizeof(WCHAR)), (PVOID)Description.c_str() }, - - {{PKEY_MIDI_UserSuppliedEndpointName, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_STRING, static_cast((Name.length() + 1) * sizeof(WCHAR)), (PVOID)Name.c_str() } - }; - - - - // Additional metadata properties added here to avoid having to add them in every transport -// and to ensure they are registered under the same identity that is creating the device -// Several of these are later updated through discovery, user-supplied json metadata, etc. - //DEVPROP_BOOLEAN devPropFalse = DEVPROP_FALSE; - //uint8_t zeroByte = 0; - - //std::wstring emptyString = L""; - - //interfaceProperties.push_back({ {PKEY_MIDI_SupportsMultiClient, DEVPROP_STORE_SYSTEM, nullptr }, - // DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropTrue)), &devPropTrue }); - - //// from endpoint discovery ============ - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointSupportsMidi2Protocol, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropFalse)), &devPropFalse }); - - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointSupportsMidi1Protocol, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropFalse)), &devPropFalse }); - - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointSupportsReceivingJRTimestamps, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropFalse)), &devPropFalse }); - - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointSupportsSendingJRTimestamps, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropFalse)), &devPropFalse }); - - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointUmpVersionMajor, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_BYTE, static_cast(sizeof(zeroByte)), &zeroByte }); - - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointUmpVersionMinor, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_BYTE, static_cast(sizeof(zeroByte)), &zeroByte }); - - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointProvidedName, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_STRING, static_cast((emptyString.length() + 1) * sizeof(WCHAR)), (PVOID)emptyString.c_str() }); - - //interfaceProperties.push_back({ {PKEY_MIDI_EndpointProvidedProductinstanceId, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_STRING, static_cast((emptyString.length() + 1) * sizeof(WCHAR)), (PVOID)emptyString.c_str() }); - - //interfaceProperties.push_back({ {PKEY_MIDI_FunctionBlocksAreStatic, DEVPROP_STORE_SYSTEM, nullptr}, - // DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropFalse)),&devPropFalse }); - - ////interfaceProperties.push_back({ {PKEY_MIDI_DeviceIdentification, DEVPROP_STORE_SYSTEM, nullptr}, - //// DEVPROP_TYPE_BINARY, static_cast(0), }); - - - //// from function block discovery ============================= - - ////interfaceProperties.push_back({ {PKEY_MIDI_FunctionBlocks, DEVPROP_STORE_SYSTEM, nullptr}, - //// DEVPROP_TYPE_BINARY, static_cast(0), &functionBlockCount }); - - - - - DEVPROPERTY deviceDevProperties[] = { - {{DEVPKEY_Device_PresenceNotForDevice, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropTrue)), &devPropTrue}, - {{DEVPKEY_Device_NoConnectSound, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropTrue)),&devPropTrue} - }; - - SW_DEVICE_CREATE_INFO createInfo = {}; - createInfo.cbSize = sizeof(createInfo); - - createInfo.pszInstanceId = InstanceId.c_str(); - createInfo.CapabilityFlags = SWDeviceCapabilitiesNone; - createInfo.pszDeviceDescription = Name.c_str(); - - - const ULONG deviceInterfaceIdMaxSize = 255; - wchar_t newDeviceInterfaceId[deviceInterfaceIdMaxSize]{ 0 }; - - RETURN_IF_FAILED(m_MidiDeviceManager->ActivateEndpoint( - std::wstring(m_ParentDevice->InstanceId).c_str(), // parent instance Id - true, // UMP-only - flow, // MIDI Flow - ARRAYSIZE(interfaceDevProperties), - ARRAYSIZE(deviceDevProperties), - (PVOID)interfaceDevProperties, - (PVOID)deviceDevProperties, - (PVOID)&createInfo, - (LPWSTR)&newDeviceInterfaceId, - deviceInterfaceIdMaxSize)); - - OutputDebugString(__FUNCTION__ L": Created device interface id:"); - OutputDebugString(newDeviceInterfaceId); - - // store the created device in the device table, along with the interface id @@ -476,48 +63,6 @@ CMidi2VirtualPatchBayEndpointManager::CreateEndpoint( } - -//_Use_decl_annotations_ -//HRESULT -//CMidi2VirtualPatchBayEndpointManager::UpdateConfiguration(LPCWSTR configurationJson) -//{ -// UNREFERENCED_PARAMETER(configurationJson); -// -// -// //if (ConfigurationJson != nullptr) -// //{ -// // try -// // { -// // std::wstring json{ ConfigurationJson }; -// -// // if (!json.empty()) -// // { -// // m_jsonObject = json::JsonObject::Parse(json); -// -// // LOG_IF_FAILED(CreateConfiguredEndpoints(json)); -// // } -// // } -// // catch (...) -// // { -// // OutputDebugString(L"Exception processing json for virtual MIDI abstraction"); -// -// // // we return S_OK here because otherwise this prevents the service from starting up. -// // return S_OK; -// // } -// -// //} -// //else -// //{ -// // // empty / null is fine. We just continue on. -// -// // OutputDebugString(L"Configuration json is null for virtual MIDI abstraction"); -// -// // return S_OK; -// //} -// -// return S_OK; -//} - HRESULT CMidi2VirtualPatchBayEndpointManager::Cleanup() { @@ -534,16 +79,3 @@ CMidi2VirtualPatchBayEndpointManager::Cleanup() return S_OK; } - -// -//_Use_decl_annotations_ -//HRESULT -//CMidi2VirtualPatchBayEndpointManager::ApplyConfiguration( -// LPCWSTR /*configurationJson*/, -// LPWSTR /*resultJson*/ -//) -//{ -// return E_NOTIMPL; -//} - - diff --git a/src/api/Abstraction/VirtualPatchBayAbstraction/Midi2.VirtualPatchBayEndpointManager.h b/src/api/Abstraction/VirtualPatchBayAbstraction/Midi2.VirtualPatchBayEndpointManager.h index 6d4e4d261..fd1ab7dad 100644 --- a/src/api/Abstraction/VirtualPatchBayAbstraction/Midi2.VirtualPatchBayEndpointManager.h +++ b/src/api/Abstraction/VirtualPatchBayAbstraction/Midi2.VirtualPatchBayEndpointManager.h @@ -8,51 +8,6 @@ #pragma once -typedef enum _SWDEVICESTATE -{ - NotCreated = 0, // SwDeviceCreate not yet called - CreatePending, // SwDeviceCreate called successfully, but creation callback not yet invoked - Created, // SwDeviceCreate creation callback has been invoked and device interface has been created - Failed -} SWDEVICESTATE; - - -using unique_hswdevice = wil::unique_any; -using unique_swd_string = wil::unique_any; - - -class MidiUmpEndpointInfo -{ -public: - std::wstring Id{}; // the filter InterfaceId - std::wstring InstanceId{}; // the MIDI instance id - std::wstring ParentInstanceId{}; // The instance id of the parent device - std::wstring Name{}; // friendly name for this device - MidiFlow Flow{ MidiFlowBidirectional }; - - // TODO: Pointer to the interface? - -}; - -class MidiEndpointParentDeviceInfo -{ -public: - GUID InterfaceCategory{}; - SWDEVICESTATE SwDeviceState{ SWDEVICESTATE::NotCreated }; // SWD creation state - unique_hswdevice SwDevice{}; // Handle to the SWD created for the MIDI port - unique_swd_string DeviceInterfaceId{}; // SWD interface ID for the MIDI port - std::wstring InstanceId{}; - std::wstring Name{}; // friendly name for this device - -}; - -typedef struct _PARENTDEVICECREATECONTEXT -{ - MidiEndpointParentDeviceInfo* MidiParentDevice{ nullptr }; - wil::unique_event CreationCompleted{ wil::EventOptions::None }; - DEVPROPERTY* InterfaceDevProperties{ nullptr }; - ULONG IntPropertyCount{}; -} PARENTDEVICECREATECONTEXT, * PPARENTDEVICECREATECONTEXT; // TODO: This class can implement another interface which takes in the json parameters @@ -72,36 +27,16 @@ class CMidi2VirtualPatchBayEndpointManager : STDMETHOD(Initialize(_In_ IUnknown*, _In_ IUnknown*)); STDMETHOD(Cleanup)(); - //STDMETHOD(ApplyConfiguration( - // _In_ LPCWSTR configurationJson, - // _Out_ LPWSTR resultJson - //)); - private: GUID m_ContainerId{}; GUID m_TransportAbstractionId{}; HRESULT CreateEndpoint( - _In_ std::wstring const InstanceId, - _In_ std::wstring const UniqueId, - _In_ bool const Multiclient, - _In_ bool const IsVirtualEndpointResponder, - _In_ std::wstring const Name, - _In_ std::wstring const LargeImagePath, - _In_ std::wstring const SmallImagePath, - _In_ std::wstring const Description ); - HRESULT CreateConfiguredEndpoints(_In_ std::wstring ConfigurationJson); - HRESULT CreateParentDevice(); + //HRESULT CreateParentDevice(); wil::com_ptr_nothrow m_MidiDeviceManager; - // TBD if we need to keep this here as well. The MidiDeviceManager has its own vector of endpoints - std::vector> m_AvailableMidiUmpEndpoints; - - std::unique_ptr m_ParentDevice{ nullptr }; - - json::JsonObject m_JsonObject{ nullptr }; }; diff --git a/src/api/Abstraction/VirtualPatchBayAbstraction/pch.h b/src/api/Abstraction/VirtualPatchBayAbstraction/pch.h index 133b72d9c..c159d2d14 100644 --- a/src/api/Abstraction/VirtualPatchBayAbstraction/pch.h +++ b/src/api/Abstraction/VirtualPatchBayAbstraction/pch.h @@ -67,7 +67,6 @@ namespace json = ::winrt::Windows::Data::Json; // AbstractionUtilities #include "endpoint_data_helpers.h" #include "swd_property_builders.h" -#include "swd_property_helpers.h" #include "json_helpers.h" #include "MidiDefs.h" diff --git a/src/api/Client/Midi2Client/pch.h b/src/api/Client/Midi2Client/pch.h index 05f123f2e..d49afd875 100644 --- a/src/api/Client/Midi2Client/pch.h +++ b/src/api/Client/Midi2Client/pch.h @@ -49,7 +49,6 @@ namespace json = ::winrt::Windows::Data::Json; // AbstractionUtilities #include "endpoint_data_helpers.h" #include "swd_property_builders.h" -#include "swd_property_helpers.h" #include "json_helpers.h" // shared diff --git a/src/api/Inc/MidiDefs.h b/src/api/Inc/MidiDefs.h index af7bdb296..32b22944f 100644 --- a/src/api/Inc/MidiDefs.h +++ b/src/api/Inc/MidiDefs.h @@ -160,17 +160,6 @@ DEFINE_MIDIDEVPROPKEY(PKEY_MIDI_SerialNumber, 53); // DEVPROP_TYPE_STRING // Major Known Endpoint Types ===================================================================== // Starts at 100 -// If you change these, you should also update -// the WinRT MidiEndpointDevicePurpose enum, which is projected through the API -enum MidiEndpointDevicePurposePropertyValue -{ - NormalMessageEndpoint = 0, - VirtualDeviceResponder = 100, - InBoxGeneralMidiSynth = 400, - DiagnosticLoopback = 500, - DiagnosticPing = 510, -}; - // Valid values are in MidiEndpointDevicePurposePropertyValue #define STRING_PKEY_MIDI_EndpointDevicePurpose MIDI_STRING_PKEY_GUID MIDI_STRING_PKEY_PID_SEPARATOR L"100" DEFINE_MIDIDEVPROPKEY(PKEY_MIDI_EndpointDevicePurpose, 100); // DEVPROP_TYPE_ uint32 diff --git a/src/api/Libs/AbstractionUtilities/AbstractionUtilities.vcxproj b/src/api/Libs/AbstractionUtilities/AbstractionUtilities.vcxproj index 0fe62fc4c..1b3209bf2 100644 --- a/src/api/Libs/AbstractionUtilities/AbstractionUtilities.vcxproj +++ b/src/api/Libs/AbstractionUtilities/AbstractionUtilities.vcxproj @@ -170,9 +170,9 @@ + - @@ -185,6 +185,7 @@ Create + diff --git a/src/api/Libs/AbstractionUtilities/AbstractionUtilities.vcxproj.filters b/src/api/Libs/AbstractionUtilities/AbstractionUtilities.vcxproj.filters index 8e128b2df..912f99c2f 100644 --- a/src/api/Libs/AbstractionUtilities/AbstractionUtilities.vcxproj.filters +++ b/src/api/Libs/AbstractionUtilities/AbstractionUtilities.vcxproj.filters @@ -27,7 +27,7 @@ Header Files - + Header Files @@ -47,5 +47,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/src/api/Libs/AbstractionUtilities/inc/swd_property_builders.h b/src/api/Libs/AbstractionUtilities/inc/swd_property_builders.h index c7a7b9d7d..6b3a456cc 100644 --- a/src/api/Libs/AbstractionUtilities/inc/swd_property_builders.h +++ b/src/api/Libs/AbstractionUtilities/inc/swd_property_builders.h @@ -17,26 +17,6 @@ namespace Windows::Devices::Midi2::Internal { - DEVPROPERTY BuildWStringDevProperty( - _In_ DEVPROPKEY const key, - _In_ std::wstring const& value); - - DEVPROPERTY BuildUInt32DevProperty( - _In_ DEVPROPKEY const key, - _In_ uint32_t const& value); - - DEVPROPERTY BuildByteDevProperty( - _In_ DEVPROPKEY const key, - _In_ uint8_t const& value); - - DEVPROPERTY BuildGuidDevProperty( - _In_ DEVPROPKEY const key, - _In_ GUID const& value); - - DEVPROPERTY BuildBooleanDevProperty( - _In_ DEVPROPKEY const key, - _In_ bool const& value); - DEVPROPERTY BuildEmptyDevProperty( _In_ DEVPROPKEY const key); diff --git a/src/api/Libs/AbstractionUtilities/inc/swd_property_helpers.h b/src/api/Libs/AbstractionUtilities/inc/swd_property_helpers.h deleted file mode 100644 index cae230ef7..000000000 --- a/src/api/Libs/AbstractionUtilities/inc/swd_property_helpers.h +++ /dev/null @@ -1,47 +0,0 @@ -// 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 - -#ifndef SWD_PROPERTY_HELPERS_H -#define SWD_PROPERTY_HELPERS_H - -#include "MidiDefs.h" -#include "MidiDataFormat.h" - -namespace Windows::Devices::Midi2::Internal -{ - bool AddStandardEndpointProperties( - _In_ std::vector& interfaceDeviceProperties, - - _In_ GUID const& abstractionLayerGuid, - _In_ MidiEndpointDevicePurposePropertyValue const& endpointPurpose, - - _In_ std::wstring const& friendlyName, - - _In_ std::wstring const& transportMnemonic, - _In_ std::wstring const& transportSuppliedEndpointName, - _In_ std::wstring const& transportSuppliedEndpointDescription, - - _In_ std::wstring const& userSuppliedEndpointName, - _In_ std::wstring const& userSuppliedEndpointDescription, - - _In_ std::wstring const& uniqueIdentifier, - - _In_ MidiDataFormat const& supportedDataFormats, - _In_ BYTE const& nativeDataFormat, - - _In_ bool const& supportsMultiClient, - _In_ bool const& requiresMetadataHandler, - _In_ bool const& generateIncomingTimestamps - ); - - -} - -#endif \ No newline at end of file diff --git a/src/api/Libs/AbstractionUtilities/inc/swd_shared.h b/src/api/Libs/AbstractionUtilities/inc/swd_shared.h new file mode 100644 index 000000000..1a100b146 --- /dev/null +++ b/src/api/Libs/AbstractionUtilities/inc/swd_shared.h @@ -0,0 +1,24 @@ +// 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 +#include + + +#pragma once + +namespace Windows::Devices::Midi2::Internal +{ + + std::wstring GetSwdStringProperty(_In_ std::wstring deviceInterfaceId, _In_ std::wstring propertyName, _In_ std::wstring defaultValue); + + std::wstring GetSwdPropertyVirtualEndpointAssociationId(_In_ std::wstring deviceInterfaceId); + + std::wstring GetSwdPropertyInstanceId(_In_ std::wstring deviceInterfaceId); +} \ No newline at end of file diff --git a/src/api/Libs/AbstractionUtilities/src/pch.h b/src/api/Libs/AbstractionUtilities/src/pch.h index d313325c4..b8fd2bd27 100644 --- a/src/api/Libs/AbstractionUtilities/src/pch.h +++ b/src/api/Libs/AbstractionUtilities/src/pch.h @@ -18,7 +18,6 @@ #include - #include #include @@ -53,8 +52,8 @@ namespace internal = ::Windows::Devices::Midi2::Internal; #include "endpoint_data_helpers.h" #include "swd_property_builders.h" -#include "swd_property_helpers.h" #include "json_helpers.h" +#include "swd_shared.h" #endif //PCH_H diff --git a/src/api/Libs/AbstractionUtilities/src/swd_property_builders.cpp b/src/api/Libs/AbstractionUtilities/src/swd_property_builders.cpp index fa51c4c5c..04647332d 100644 --- a/src/api/Libs/AbstractionUtilities/src/swd_property_builders.cpp +++ b/src/api/Libs/AbstractionUtilities/src/swd_property_builders.cpp @@ -10,49 +10,6 @@ namespace Windows::Devices::Midi2::Internal { - _Use_decl_annotations_ - DEVPROPERTY BuildWStringDevProperty(DEVPROPKEY const key, std::wstring const& value) - { - auto cleanValue = internal::TrimmedWStringCopy(value); - - return DEVPROPERTY{ {key, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_STRING, static_cast((cleanValue.length() + 1) * sizeof(WCHAR)), (PVOID)cleanValue.c_str() }; - } - - _Use_decl_annotations_ - DEVPROPERTY BuildUInt32DevProperty(DEVPROPKEY const key, uint32_t const& value) - { - - return DEVPROPERTY{ {key, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_UINT32, static_cast(sizeof(value)), (PVOID)&value }; - } - - _Use_decl_annotations_ - DEVPROPERTY BuildByteDevProperty(DEVPROPKEY const key, uint8_t const& value) - { - - return DEVPROPERTY{ {key, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_BYTE, static_cast(sizeof(value)), (PVOID)&value }; - } - - _Use_decl_annotations_ - DEVPROPERTY BuildGuidDevProperty(DEVPROPKEY const key, GUID const& value) - { - - return DEVPROPERTY{ {key, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_GUID, static_cast(sizeof(GUID)), (PVOID)&value }; - } - - _Use_decl_annotations_ - DEVPROPERTY BuildBooleanDevProperty(DEVPROPKEY const key, bool const& value) - { - DEVPROP_BOOLEAN propVal = value ? DEVPROP_TRUE : DEVPROP_FALSE; - - return DEVPROPERTY{ {key, DEVPROP_STORE_SYSTEM, nullptr}, - DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(propVal)), (PVOID)&propVal }; - - } - _Use_decl_annotations_ DEVPROPERTY BuildEmptyDevProperty(DEVPROPKEY const key) { @@ -60,9 +17,4 @@ namespace Windows::Devices::Midi2::Internal DEVPROP_TYPE_EMPTY, 0, nullptr }; } - - - - - } diff --git a/src/api/Libs/AbstractionUtilities/src/swd_property_helpers.cpp b/src/api/Libs/AbstractionUtilities/src/swd_property_helpers.cpp index 800d7c8dc..9d9cf050b 100644 --- a/src/api/Libs/AbstractionUtilities/src/swd_property_helpers.cpp +++ b/src/api/Libs/AbstractionUtilities/src/swd_property_helpers.cpp @@ -12,81 +12,48 @@ namespace Windows::Devices::Midi2::Internal { - - - - - - + // NOTE: The parameters in here are all passed to the API by ref, so the + // calling code needs to keep them around until the device creation returns. _Use_decl_annotations_ bool AddStandardEndpointProperties( - std::vector& interfaceDeviceProperties, - - GUID const& abstractionLayerGuid, - MidiEndpointDevicePurposePropertyValue const& endpointPurpose, - std::wstring const& friendlyName, - - std::wstring const& transportMnemonic, - std::wstring const& transportSuppliedEndpointName, - std::wstring const& transportSuppliedEndpointDescription, - - std::wstring const& userSuppliedEndpointName, - std::wstring const& userSuppliedEndpointDescription, - - std::wstring const& uniqueIdentifier, - - MidiDataFormat const& supportedDataFormats, - BYTE const& nativeDataFormat, - - bool const& supportsMultiClient, - bool const& requiresMetadataHandler, - bool const& generateIncomingTimestamps ) { try { - interfaceDeviceProperties.push_back(BuildGuidDevProperty(PKEY_MIDI_AbstractionLayer, abstractionLayerGuid)); - interfaceDeviceProperties.push_back(BuildUInt32DevProperty(PKEY_MIDI_EndpointDevicePurpose, endpointPurpose)); - - interfaceDeviceProperties.push_back(BuildWStringDevProperty(DEVPKEY_DeviceInterface_FriendlyName, friendlyName)); - - // transport information + //interfaceDeviceProperties.push_back(BuildGuidDevProperty(PKEY_MIDI_AbstractionLayer, abstractionLayerGuid)); + //interfaceDeviceProperties.push_back(BuildUInt32DevProperty(PKEY_MIDI_EndpointDevicePurpose, endpointPurpose)); - interfaceDeviceProperties.push_back(BuildWStringDevProperty(PKEY_MIDI_TransportMnemonic, transportMnemonic)); - interfaceDeviceProperties.push_back(BuildWStringDevProperty(PKEY_MIDI_TransportSuppliedEndpointName, transportSuppliedEndpointName)); - interfaceDeviceProperties.push_back(BuildWStringDevProperty(PKEY_MIDI_TransportSuppliedDescription, transportSuppliedEndpointDescription)); + //interfaceDeviceProperties.push_back(BuildWStringDevProperty(DEVPKEY_DeviceInterface_FriendlyName, friendlyName)); - interfaceDeviceProperties.push_back(BuildWStringDevProperty(PKEY_MIDI_SerialNumber, uniqueIdentifier)); + ////// transport information + //interfaceDeviceProperties.push_back(BuildWStringDevProperty(PKEY_MIDI_TransportMnemonic, transportMnemonic)); + //interfaceDeviceProperties.push_back(BuildWStringDevProperty(PKEY_MIDI_TransportSuppliedEndpointName, transportSuppliedEndpointName)); + //interfaceDeviceProperties.push_back(BuildWStringDevProperty(PKEY_MIDI_TransportSuppliedDescription, transportSuppliedEndpointDescription)); - // user-supplied information, if available + //interfaceDeviceProperties.push_back(BuildWStringDevProperty(PKEY_MIDI_SerialNumber, uniqueIdentifier)); - if (!userSuppliedEndpointName.empty()) - { - interfaceDeviceProperties.push_back(BuildWStringDevProperty(PKEY_MIDI_UserSuppliedEndpointName, userSuppliedEndpointName)); - } - if (!userSuppliedEndpointDescription.empty()) - { - interfaceDeviceProperties.push_back(BuildWStringDevProperty(PKEY_MIDI_UserSuppliedDescription, userSuppliedEndpointDescription)); - } + //// user-supplied information, if available + //interfaceDeviceProperties.push_back(BuildWStringDevProperty(PKEY_MIDI_UserSuppliedEndpointName, userSuppliedEndpointName)); + //interfaceDeviceProperties.push_back(BuildWStringDevProperty(PKEY_MIDI_UserSuppliedDescription, userSuppliedEndpointDescription)); - // data format. These each have different uses. Native format is the device's format. Supported - // format is how we talk to it from the service (the driver may translate to UMP, for example) - interfaceDeviceProperties.push_back(BuildByteDevProperty(PKEY_MIDI_NativeDataFormat, nativeDataFormat)); - interfaceDeviceProperties.push_back(BuildUInt32DevProperty(PKEY_MIDI_SupportedDataFormats, supportedDataFormats)); + //// data format. These each have different uses. Native format is the device's format. Supported + //// format is how we talk to it from the service (the driver may translate to UMP, for example) - // behavior + //interfaceDeviceProperties.push_back(BuildByteDevProperty(PKEY_MIDI_NativeDataFormat, nativeDataFormat)); + //interfaceDeviceProperties.push_back(BuildUInt32DevProperty(PKEY_MIDI_SupportedDataFormats, supportedDataFormats)); - interfaceDeviceProperties.push_back(BuildBooleanDevProperty(PKEY_MIDI_GenerateIncomingTimestamp, generateIncomingTimestamps)); - interfaceDeviceProperties.push_back(BuildBooleanDevProperty(PKEY_MIDI_EndpointRequiresMetadataHandler, requiresMetadataHandler)); + //// behavior + //interfaceDeviceProperties.push_back(BuildBooleanDevProperty(PKEY_MIDI_GenerateIncomingTimestamp, generateIncomingTimestamps)); + //interfaceDeviceProperties.push_back(BuildBooleanDevProperty(PKEY_MIDI_EndpointRequiresMetadataHandler, requiresMetadataHandler)); - interfaceDeviceProperties.push_back(BuildBooleanDevProperty(PKEY_MIDI_SupportsMulticlient, supportsMultiClient)); + //interfaceDeviceProperties.push_back(BuildBooleanDevProperty(PKEY_MIDI_SupportsMulticlient, supportsMultiClient)); return true; } diff --git a/src/api/Libs/AbstractionUtilities/src/swd_shared.cpp b/src/api/Libs/AbstractionUtilities/src/swd_shared.cpp new file mode 100644 index 000000000..385f46c51 --- /dev/null +++ b/src/api/Libs/AbstractionUtilities/src/swd_shared.cpp @@ -0,0 +1,66 @@ +// 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" + +#include "swd_shared.h" + +namespace Windows::Devices::Midi2::Internal +{ + + _Use_decl_annotations_ + std::wstring GetStringSwdProperty(std::wstring deviceInterfaceId, std::wstring propertyName, std::wstring defaultValue) + { + auto propertyKey = winrt::to_hstring(propertyName.c_str()); + + auto additionalProperties = winrt::single_threaded_vector(); + additionalProperties.Append(propertyKey); + + + auto deviceInfo = winrt::Windows::Devices::Enumeration::DeviceInformation::CreateFromIdAsync( + winrt::to_hstring(deviceInterfaceId.c_str()), + additionalProperties, + winrt::Windows::Devices::Enumeration::DeviceInformationKind::DeviceInterface).get(); + + auto prop = deviceInfo.Properties().Lookup(propertyKey); + + if (prop) + { + OutputDebugString(__FUNCTION__ L" found property"); + + // this interface is pointing to a UMP interface, so use that instance id. + return (winrt::unbox_value(prop)).c_str(); + } + else + { + OutputDebugString(__FUNCTION__ L" didn't find property"); + // default to any + return defaultValue; + } + + } + + + _Use_decl_annotations_ + std::wstring GetSwdPropertyVirtualEndpointAssociationId(std::wstring deviceInterfaceId) + { + std::wstring cleanId = internal::NormalizeEndpointInterfaceIdWStringCopy(deviceInterfaceId); + + return internal::ToUpperTrimmedWStringCopy(GetStringSwdProperty(cleanId, STRING_PKEY_MIDI_VirtualMidiEndpointAssociator, L"")); + } + + + _Use_decl_annotations_ + std::wstring GetSwdPropertyInstanceId(std::wstring deviceInterfaceId) + { + std::wstring cleanId = internal::NormalizeEndpointInterfaceIdWStringCopy(deviceInterfaceId); + + return internal::NormalizeDeviceInstanceIdWStringCopy(GetStringSwdProperty(cleanId, L"System.Devices.DeviceInstanceId", L"")); + } +} \ No newline at end of file diff --git a/src/api/Service/Exe/MidiDeviceManager.cpp b/src/api/Service/Exe/MidiDeviceManager.cpp index 5990cee5b..cbe03a219 100644 --- a/src/api/Service/Exe/MidiDeviceManager.cpp +++ b/src/api/Service/Exe/MidiDeviceManager.cpp @@ -344,9 +344,6 @@ CMidiDeviceManager::ActivateVirtualParentDevice return S_OK; } - - - _Use_decl_annotations_ HRESULT CMidiDeviceManager::ActivateEndpoint @@ -354,13 +351,14 @@ CMidiDeviceManager::ActivateEndpoint PCWSTR ParentInstanceId, BOOL UMPOnly, MidiFlow MidiFlow, + PMIDIENDPOINTCOMMONPROPERTIES CommonProperties, ULONG IntPropertyCount, ULONG DevPropertyCount, PVOID InterfaceDevProperties, PVOID DeviceDevProperties, PVOID CreateInfo, PWSTR CreatedDeviceInterfaceId, - ULONG CreatedDeviceInterfaceIdCharCount + ULONG CreatedDeviceInterfaceIdWCharCount ) { TraceLoggingWrite( @@ -385,9 +383,9 @@ CMidiDeviceManager::ActivateEndpoint return false; }) != m_MidiPorts.end(); - if (CreatedDeviceInterfaceId != nullptr && CreatedDeviceInterfaceIdCharCount > 0) + if (CreatedDeviceInterfaceId != nullptr && CreatedDeviceInterfaceIdWCharCount > 0) { - CreatedDeviceInterfaceId[CreatedDeviceInterfaceIdCharCount - 1] = (wchar_t)0; + CreatedDeviceInterfaceId[CreatedDeviceInterfaceIdWCharCount - 1] = (wchar_t)0; } @@ -397,6 +395,103 @@ CMidiDeviceManager::ActivateEndpoint } else { + std::vector allInterfaceProperties{}; + + if (IntPropertyCount > 0) + { + // copy the incoming array into a vector so that we can add additional items. + std::vector suppliedInterfaceProperties((DEVPROPERTY*)InterfaceDevProperties, (DEVPROPERTY*)(InterfaceDevProperties) + IntPropertyCount); + + // copy to the main vector that we're going to keep using. There's + // probably a better way to do both init and move in a single step + // without having two vectors. + allInterfaceProperties.insert( + allInterfaceProperties.begin(), + suppliedInterfaceProperties.begin(), + suppliedInterfaceProperties.end() + ); + } + + DEVPROP_BOOLEAN devPropTrue = DEVPROP_TRUE; + DEVPROP_BOOLEAN devPropFalse = DEVPROP_FALSE; + + + // Build common properties so these are consistent from endpoint to endpoint + if (CommonProperties != nullptr) + { + allInterfaceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_AbstractionLayer, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_GUID, (ULONG)(sizeof(GUID)), (PVOID)(&CommonProperties->AbstractionLayerGuid) }); + + allInterfaceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_EndpointDevicePurpose, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_UINT32, (ULONG)(sizeof(UINT32)), (PVOID)(&CommonProperties->EndpointPurpose) }); + + if (CommonProperties->FriendlyName != nullptr && wcslen(CommonProperties->FriendlyName) != 0) + { + allInterfaceProperties.push_back(DEVPROPERTY{ {DEVPKEY_DeviceInterface_FriendlyName, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_STRING, (ULONG)(sizeof(wchar_t) * (wcslen(CommonProperties->FriendlyName) + 1)), (PVOID)CommonProperties->FriendlyName }); + } + + // transport information + + if (CommonProperties->TransportMnemonic != nullptr && wcslen(CommonProperties->TransportMnemonic) != 0) + { + allInterfaceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_TransportMnemonic, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_STRING, (ULONG)(sizeof(wchar_t) * (wcslen(CommonProperties->TransportMnemonic) + 1)), (PVOID)CommonProperties->TransportMnemonic }); + } + + if (CommonProperties->TransportSuppliedEndpointName != nullptr && wcslen(CommonProperties->TransportSuppliedEndpointName) != 0) + { + allInterfaceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_TransportSuppliedEndpointName, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_STRING, (ULONG)(sizeof(wchar_t) * (wcslen(CommonProperties->TransportSuppliedEndpointName) + 1)), (PVOID)CommonProperties->TransportSuppliedEndpointName }); + } + + if (CommonProperties->TransportSuppliedEndpointDescription != nullptr && wcslen(CommonProperties->TransportSuppliedEndpointDescription) != 0) + { + allInterfaceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_TransportSuppliedDescription, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_STRING, (ULONG)(sizeof(wchar_t) * (wcslen(CommonProperties->TransportSuppliedEndpointDescription) + 1)), (PVOID)CommonProperties->TransportSuppliedEndpointDescription }); + } + + if (CommonProperties->UniqueIdentifier != nullptr && wcslen(CommonProperties->UniqueIdentifier) != 0) + { + allInterfaceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_SerialNumber, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_STRING, (ULONG)(sizeof(wchar_t) * (wcslen(CommonProperties->UniqueIdentifier) + 1)), (PVOID)CommonProperties->UniqueIdentifier }); + } + + // user-supplied information, if available + + if (CommonProperties->UserSuppliedEndpointName != nullptr && wcslen(CommonProperties->UserSuppliedEndpointName) != 0) + { + allInterfaceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_UserSuppliedEndpointName, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_STRING, (ULONG)(sizeof(wchar_t) * (wcslen(CommonProperties->UserSuppliedEndpointName) + 1)), (PVOID)CommonProperties->UserSuppliedEndpointName }); + } + + if (CommonProperties->UserSuppliedEndpointDescription != nullptr && wcslen(CommonProperties->UserSuppliedEndpointDescription) != 0) + { + allInterfaceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_UserSuppliedDescription, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_STRING, (ULONG)(sizeof(wchar_t) * (wcslen(CommonProperties->UserSuppliedEndpointDescription) + 1)), (PVOID)CommonProperties->UserSuppliedEndpointDescription }); + } + + // data format. These each have different uses. Native format is the device's format. Supported + // format is how we talk to it from the service (the driver may translate to UMP, for example) + + allInterfaceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_NativeDataFormat, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_BYTE, (ULONG)(sizeof(BYTE)), (PVOID)(&CommonProperties->NativeDataFormat) }); + + allInterfaceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_SupportedDataFormats, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_UINT32, (ULONG)(sizeof(UINT32)), (PVOID)(&CommonProperties->SupportedDataFormats) }); + + // behavior + + allInterfaceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_GenerateIncomingTimestamp, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_BOOLEAN, (ULONG)(sizeof(DEVPROP_BOOLEAN)), (PVOID)(CommonProperties->GenerateIncomingTimestamps ? &devPropTrue : &devPropFalse) }); + + allInterfaceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_EndpointRequiresMetadataHandler, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_BOOLEAN, (ULONG)(sizeof(DEVPROP_BOOLEAN)), (PVOID)(CommonProperties->RequiresMetadataHandler ? &devPropTrue : &devPropFalse) }); + + allInterfaceProperties.push_back(DEVPROPERTY{ {PKEY_MIDI_SupportsMulticlient, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_BOOLEAN, (ULONG)(sizeof(DEVPROP_BOOLEAN)), (PVOID)(CommonProperties->SupportsMultiClient ? &devPropTrue : &devPropFalse) }); + } + std::wstring deviceInterfaceId{ 0 }; auto cleanupOnFailure = wil::scope_exit([&]() @@ -406,7 +501,17 @@ CMidiDeviceManager::ActivateEndpoint }); // Activate the UMP version of this endpoint. - RETURN_IF_FAILED(ActivateEndpointInternal(ParentInstanceId, nullptr, FALSE, MidiFlow, IntPropertyCount, DevPropertyCount, (DEVPROPERTY*)InterfaceDevProperties, (DEVPROPERTY*)DeviceDevProperties, (SW_DEVICE_CREATE_INFO*)CreateInfo, &deviceInterfaceId)); + RETURN_IF_FAILED(ActivateEndpointInternal( + ParentInstanceId, + nullptr, + FALSE, + MidiFlow, + (ULONG)allInterfaceProperties.size(), + DevPropertyCount, + (DEVPROPERTY*)(allInterfaceProperties.data()), + (DEVPROPERTY*)DeviceDevProperties, + (SW_DEVICE_CREATE_INFO*)CreateInfo, + &deviceInterfaceId)); if (!UMPOnly) { @@ -414,23 +519,54 @@ CMidiDeviceManager::ActivateEndpoint if (MidiFlow == MidiFlowBidirectional) { // if this is a bidirectional endpoint, it gets an in and an out midi 1 swd's. - RETURN_IF_FAILED(ActivateEndpointInternal(ParentInstanceId, deviceInterfaceId.c_str(), TRUE, MidiFlowOut, IntPropertyCount, DevPropertyCount, (DEVPROPERTY*)InterfaceDevProperties, (DEVPROPERTY*)DeviceDevProperties, (SW_DEVICE_CREATE_INFO*)CreateInfo, nullptr)); - RETURN_IF_FAILED(ActivateEndpointInternal(ParentInstanceId, deviceInterfaceId.c_str(), TRUE, MidiFlowIn, IntPropertyCount, DevPropertyCount, (DEVPROPERTY*)InterfaceDevProperties, (DEVPROPERTY*)DeviceDevProperties, (SW_DEVICE_CREATE_INFO*)CreateInfo, nullptr)); + RETURN_IF_FAILED(ActivateEndpointInternal( + ParentInstanceId, + deviceInterfaceId.c_str(), + TRUE, + MidiFlowOut, + (ULONG)allInterfaceProperties.size(), + DevPropertyCount, + (DEVPROPERTY*)(allInterfaceProperties.data()), + (DEVPROPERTY*)DeviceDevProperties, + (SW_DEVICE_CREATE_INFO*)CreateInfo, + nullptr)); + + RETURN_IF_FAILED(ActivateEndpointInternal( + ParentInstanceId, + deviceInterfaceId.c_str(), + TRUE, + MidiFlowIn, + (ULONG)allInterfaceProperties.size(), + DevPropertyCount, + (DEVPROPERTY*)(allInterfaceProperties.data()), + (DEVPROPERTY*)DeviceDevProperties, + (SW_DEVICE_CREATE_INFO*)CreateInfo, + nullptr)); } else { - RETURN_IF_FAILED(ActivateEndpointInternal(ParentInstanceId, deviceInterfaceId.c_str(), TRUE, MidiFlow, IntPropertyCount, DevPropertyCount, (DEVPROPERTY*)InterfaceDevProperties, (DEVPROPERTY*)DeviceDevProperties, (SW_DEVICE_CREATE_INFO*)CreateInfo, nullptr)); + RETURN_IF_FAILED(ActivateEndpointInternal( + ParentInstanceId, + deviceInterfaceId.c_str(), + TRUE, + MidiFlow, + (ULONG)allInterfaceProperties.size(), + DevPropertyCount, + (DEVPROPERTY*)(allInterfaceProperties.data()), + (DEVPROPERTY*)DeviceDevProperties, + (SW_DEVICE_CREATE_INFO*)CreateInfo, + nullptr)); } } // return the created device interface Id. This is needed for anything that will // do a match in the Ids from Windows.Devices.Enumeration - if (CreatedDeviceInterfaceId != nullptr && CreatedDeviceInterfaceIdCharCount > 0) + if (CreatedDeviceInterfaceId != nullptr && CreatedDeviceInterfaceIdWCharCount > 0) { //memset((byte*)CreatedDeviceInterfaceId, 0, CreatedDeviceInterfaceIdBufferSize * sizeof(wchar_t)); - deviceInterfaceId.copy(CreatedDeviceInterfaceId, CreatedDeviceInterfaceIdCharCount - 1); + deviceInterfaceId.copy(CreatedDeviceInterfaceId, CreatedDeviceInterfaceIdWCharCount - 1); - CreatedDeviceInterfaceId[CreatedDeviceInterfaceIdCharCount - 1] = (wchar_t)0; + CreatedDeviceInterfaceId[CreatedDeviceInterfaceIdWCharCount - 1] = (wchar_t)0; } cleanupOnFailure.release(); @@ -461,9 +597,11 @@ CMidiDeviceManager::ActivateEndpointInternal __FUNCTION__, TraceLoggingLevel(WINEVENT_LEVEL_INFO), TraceLoggingPointer(this, "this"), - TraceLoggingWideString(ParentInstanceId), - TraceLoggingWideString(AssociatedInstanceId), - TraceLoggingBool(MidiOne) + TraceLoggingWideString(ParentInstanceId, "parent instance id"), + TraceLoggingWideString(AssociatedInstanceId, "associated instance id"), + TraceLoggingBool(MidiOne, "midi 1"), + TraceLoggingULong(IntPropertyCount, "interface prop count"), + TraceLoggingULong(DevPropertyCount, "device prop count") ); @@ -480,6 +618,13 @@ CMidiDeviceManager::ActivateEndpointInternal interfaceProperties.push_back({ {PKEY_MIDI_AssociatedUMP, DEVPROP_STORE_SYSTEM, nullptr}, DEVPROP_TYPE_STRING, static_cast((wcslen(AssociatedInstanceId) + 1) * sizeof(WCHAR)), (PVOID)AssociatedInstanceId }); } + else + { + // necessary for cases where this was previously set and cached + + interfaceProperties.push_back({ {PKEY_MIDI_AssociatedUMP, DEVPROP_STORE_SYSTEM, nullptr}, + DEVPROP_TYPE_EMPTY, 0, nullptr }); + } DEVPROP_BOOLEAN devPropTrue = DEVPROP_TRUE; @@ -493,7 +638,7 @@ CMidiDeviceManager::ActivateEndpointInternal midiPort->InstanceId = internal::NormalizeDeviceInstanceIdWStringCopy(CreateInfo->pszInstanceId); midiPort->MidiFlow = MidiFlow; - midiPort->Enumerator = MidiOne?AUDIO_DEVICE_ENUMERATOR : MIDI_DEVICE_ENUMERATOR; + midiPort->Enumerator = MidiOne ? AUDIO_DEVICE_ENUMERATOR : MIDI_DEVICE_ENUMERATOR; if (MidiOne) { @@ -563,7 +708,6 @@ CMidiDeviceManager::ActivateEndpointInternal TraceLoggingPointer(this, "this"), TraceLoggingWideString(L"Already exists"), TraceLoggingWideString(ParentInstanceId), - TraceLoggingWideString(AssociatedInstanceId), TraceLoggingBool(MidiOne) ); @@ -586,9 +730,48 @@ CMidiDeviceManager::ActivateEndpointInternal SwMidiPortCreateCallback(item->get()->SwDevice.get(), S_OK, &creationContext, nullptr); } } + else + { + TraceLoggingWrite( + MidiSrvTelemetryProvider::Provider(), + __FUNCTION__, + TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + TraceLoggingPointer(this, "this"), + TraceLoggingWideString(L"SwDeviceCreate failed", "message"), + TraceLoggingWideString(ParentInstanceId), + TraceLoggingBool(MidiOne) + ); + } // confirm we were able to register the interface + + if (FAILED(midiPort->hr)) + { + TraceLoggingWrite( + MidiSrvTelemetryProvider::Provider(), + __FUNCTION__, + TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + TraceLoggingPointer(this, "this"), + TraceLoggingHResult(midiPort->hr, "hresult"), + TraceLoggingWideString(L"SwDeviceCreate returned a failed HR", "message"), + TraceLoggingWideString(ParentInstanceId), + TraceLoggingBool(MidiOne) + ); + } RETURN_IF_FAILED(midiPort->hr); + + if (midiPort->SwDeviceState != SWDEVICESTATE::Created) + { + TraceLoggingWrite( + MidiSrvTelemetryProvider::Provider(), + __FUNCTION__, + TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + TraceLoggingPointer(this, "this"), + TraceLoggingWideString(L"SwDeviceState != SWDEVICESTATE::Created", "message"), + TraceLoggingWideString(ParentInstanceId), + TraceLoggingBool(MidiOne) + ); + } RETURN_HR_IF(E_FAIL, midiPort->SwDeviceState != SWDEVICESTATE::Created); if (DeviceInterfaceId) diff --git a/src/api/Service/Exe/stdafx.h b/src/api/Service/Exe/stdafx.h index 6de275e13..9e089d9c4 100644 --- a/src/api/Service/Exe/stdafx.h +++ b/src/api/Service/Exe/stdafx.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -50,7 +51,6 @@ // AbstractionUtilities #include "endpoint_data_helpers.h" #include "swd_property_builders.h" -#include "swd_property_helpers.h" #include "json_helpers.h" // Main definitions diff --git a/src/api/Service/Inc/MidiDeviceManager.h b/src/api/Service/Inc/MidiDeviceManager.h index 918b19caa..94f803e46 100644 --- a/src/api/Service/Inc/MidiDeviceManager.h +++ b/src/api/Service/Inc/MidiDeviceManager.h @@ -98,13 +98,14 @@ class CMidiDeviceManager : _In_ PCWSTR, _In_ BOOL, _In_ MidiFlow, + _In_ PMIDIENDPOINTCOMMONPROPERTIES, _In_ ULONG, _In_ ULONG, _In_ PVOID, _In_ PVOID, _In_ PVOID, _Out_writes_opt_z_(CreatedSwDeviceInterfaceIdCharCount) PWSTR CreatedDeviceInterfaceId, - _In_ ULONG CreatedSwDeviceInterfaceIdCharCount + _In_ ULONG CreatedSwDeviceInterfaceIdWCharCount ); STDMETHOD(DeactivateEndpoint)(_In_ PCWSTR); @@ -143,6 +144,7 @@ class CMidiDeviceManager : private: + HRESULT ActivateEndpointInternal( _In_ PCWSTR, _In_opt_ PCWSTR, diff --git a/src/api/idl/MidiDeviceManagerInterface.idl b/src/api/idl/MidiDeviceManagerInterface.idl index 007d51d93..5804b2b3e 100644 --- a/src/api/idl/MidiDeviceManagerInterface.idl +++ b/src/api/idl/MidiDeviceManagerInterface.idl @@ -12,6 +12,44 @@ import "unknwn.idl"; import "MidiFlow.idl"; import "MidiDataFormat.idl"; +// If you change these, you should also update +// the WinRT MidiEndpointDevicePurpose enum, which is projected through the API +typedef enum +{ + NormalMessageEndpoint = 0, + VirtualDeviceResponder = 100, + InBoxGeneralMidiSynth = 400, + DiagnosticLoopback = 500, + DiagnosticPing = 510, +} MidiEndpointDevicePurposePropertyValue; + + +// This is used when creating a device endpoint from an abstraction +typedef struct +{ + GUID AbstractionLayerGuid; + MidiEndpointDevicePurposePropertyValue EndpointPurpose; + + LPCWSTR FriendlyName; + + LPCWSTR TransportMnemonic; + LPCWSTR TransportSuppliedEndpointName; + LPCWSTR TransportSuppliedEndpointDescription; + + LPCWSTR UserSuppliedEndpointName; + LPCWSTR UserSuppliedEndpointDescription; + + LPCWSTR UniqueIdentifier; + + MidiDataFormat SupportedDataFormats; + BYTE NativeDataFormat; + + BOOL SupportsMultiClient; + BOOL RequiresMetadataHandler; + BOOL GenerateIncomingTimestamps; +} MIDIENDPOINTCOMMONPROPERTIES, *PMIDIENDPOINTCOMMONPROPERTIES; + + [ object, local, @@ -34,13 +72,14 @@ interface IMidiDeviceManagerInterface : IUnknown [in] LPCWSTR ParentInstanceId, [in] BOOL UMPOnly, [in] MidiFlow MidiFlow, + [in] PMIDIENDPOINTCOMMONPROPERTIES CommonProperties, [in] ULONG IntPropertyCount, [in] ULONG DevPropertyCount, [in, annotation("_In_opt_")] PVOID InterfaceDevProperties, [in, annotation("_In_opt_")] PVOID DeviceDevProperties, [in, annotation("_In_opt_")] PVOID CreateInfo, - [out, annotation("_Out_writes_opt_z_(CreatedSwDeviceInterfaceIdCharCount)")] LPWSTR CreatedSwDeviceInterfaceId, - [in] ULONG CreatedSwDeviceInterfaceIdCharCount + [out, annotation("_Out_writes_opt_z_(CreatedSwDeviceInterfaceIdWCharCount)")] LPWSTR CreatedSwDeviceInterfaceId, + [in] ULONG CreatedSwDeviceInterfaceIdWCharCount ); HRESULT UpdateEndpointProperties(