diff --git a/.clang-format b/.clang-format index 5cad8912..bd39213c 100644 --- a/.clang-format +++ b/.clang-format @@ -24,6 +24,8 @@ AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Empty AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false +AllowShortLambdasOnASingleLine: Empty +AllowAllArgumentsOnNextLine: true AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false @@ -50,6 +52,7 @@ BraceWrapping: SplitEmptyRecord: true SplitEmptyNamespace: true BeforeLambdaBody: true + AfterCaseLabel: true BreakBeforeBinaryOperators: NonAssignment BreakBeforeTernaryOperators: false diff --git a/.gitignore b/.gitignore index d0d23e8f..6a7b7560 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ /externals/3rdparty/winpcap/Include /externals/3rdparty/winpcap/Lib +.idea/ +cmake-build-debug/ \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8f0f9fd1..3df8eae6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,3 +11,33 @@ Read and follow the coding style and guidelines [from this file](CODING_STYLE_GU - Don't forget to update any impacted CHANGELOG file(s) - Run the *fix_files.sh* script - Start a github pull request + +## To run `fix_files.sh` on MAC + +* Update `bash` from 3.x to latest (5.x) + +The following commands will alter default system shell for the current user to freshly installed bash. + +```bash +brew install bash +echo "/usr/local/bin/bash" | sudo tee -a /etc/shells +chsh -s /usr/local/bin/bash +``` + +You can revert to any shell, listed by + +```bash +cat /etc/shells +``` + +including default system `/bin/bash` or `/bin/zsh` with the following command + +```bash +chsh -s +``` + +* Install latest `clang-format` (11.x) + +```bash +brew install romansavrulin/clang-format/clang-format-lambda --HEAD +``` \ No newline at end of file diff --git a/examples/src/discovery.cpp b/examples/src/discovery.cpp index 4533a62a..e128348a 100644 --- a/examples/src/discovery.cpp +++ b/examples/src/discovery.cpp @@ -147,7 +147,8 @@ void Discovery::onEntityOnline(la::avdecc::controller::Controller const* const / auto const& obj = objIt.second; if (obj.staticModel->memoryObjectType == la::avdecc::entity::model::MemoryObjectType::PngEntity) { - _controller->readDeviceMemory(entity->getEntity().getEntityID(), obj.staticModel->startAddress, obj.staticModel->maximumLength, + _controller->readDeviceMemory( + entity->getEntity().getEntityID(), obj.staticModel->startAddress, obj.staticModel->maximumLength, [](la::avdecc::controller::ControlledEntity const* const /*entity*/, float const percentComplete) { outputText("Memory Object progress: " + std::to_string(percentComplete) + "\n"); diff --git a/examples/src/utils.cpp b/examples/src/utils.cpp index 4d4851c3..dcb94085 100644 --- a/examples/src/utils.cpp +++ b/examples/src/utils.cpp @@ -34,6 +34,18 @@ static SCREEN* s_Screen = nullptr; # include #endif // USE_CURSES +int getUserChoice() +{ +#if defined(USE_CURSES) + if (s_Window == nullptr) + return 0; + int c = wgetch(s_Window); +#else + int c = getch(); +#endif + c -= '0'; + return c; +} void initOutput() { @@ -114,7 +126,7 @@ la::avdecc::protocol::ProtocolInterface::Type chooseProtocolInterfaceType(la::av int index = -1; while (index == -1) { - int c = getch() - '0'; + auto c = getUserChoice(); if (c >= 1 && c <= static_cast(protocolInterfaceTypes.count())) { index = c - 1; @@ -146,6 +158,11 @@ la::avdecc::networkInterface::Interface chooseNetworkInterface() return {}; } + if (interfaces.size() == 1) + { + return interfaces.at(0); + } + // Let the user choose an interface outputText("Choose an interface:\n"); unsigned int intNum = 1; @@ -160,7 +177,7 @@ la::avdecc::networkInterface::Interface chooseNetworkInterface() int index = -1; while (index == -1) { - int c = getch() - '0'; + auto c = getUserChoice(); if (c >= 1 && c <= static_cast(interfaces.size())) { index = c - 1; diff --git a/include/la/avdecc/avdecc.hpp b/include/la/avdecc/avdecc.hpp index 0deafdf4..4ff56bb3 100644 --- a/include/la/avdecc/avdecc.hpp +++ b/include/la/avdecc/avdecc.hpp @@ -50,6 +50,7 @@ /** Controller entity type definition */ #include "internals/controllerEntity.hpp" +#include "internals/talkerEntity.hpp" /** Symbols export definition */ #include "internals/exports.hpp" diff --git a/include/la/avdecc/internals/aggregateEntity.hpp b/include/la/avdecc/internals/aggregateEntity.hpp index a195be5d..e0ec8690 100644 --- a/include/la/avdecc/internals/aggregateEntity.hpp +++ b/include/la/avdecc/internals/aggregateEntity.hpp @@ -31,6 +31,7 @@ #include "entityModel.hpp" #include "entityAddressAccessTypes.hpp" #include "controllerEntity.hpp" +#include "talkerEntity.hpp" #include "exports.hpp" #include @@ -77,7 +78,7 @@ class AggregateEntity : public LocalEntity, public controller::Interface virtual void setControllerDelegate(controller::Delegate* const delegate) noexcept = 0; //virtual void setListenerDelegate(listener::Delegate* const delegate) noexcept = 0; - //virtual void setTalkerDelegate(talker::Delegate* const delegate) noexcept = 0; + virtual void setTalkerDelegate(talker::Delegate* const delegate) noexcept = 0; // Deleted compiler auto-generated methods AggregateEntity(AggregateEntity&&) = delete; diff --git a/include/la/avdecc/internals/endStation.hpp b/include/la/avdecc/internals/endStation.hpp index 983648c6..c3d8a788 100644 --- a/include/la/avdecc/internals/endStation.hpp +++ b/include/la/avdecc/internals/endStation.hpp @@ -27,6 +27,7 @@ #include "entity.hpp" #include "controllerEntity.hpp" +#include "talkerEntity.hpp" #include "aggregateEntity.hpp" #include "protocolInterface.hpp" #include "exports.hpp" diff --git a/include/la/avdecc/internals/talkerEntity.hpp b/include/la/avdecc/internals/talkerEntity.hpp new file mode 100644 index 00000000..edb1f70b --- /dev/null +++ b/include/la/avdecc/internals/talkerEntity.hpp @@ -0,0 +1,474 @@ +/* +* Copyright (C) 2016-2020, L-Acoustics and its contributors + +* This file is part of LA_avdecc. + +* LA_avdecc is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. + +* LA_avdecc is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. + +* You should have received a copy of the GNU Lesser General Public License +* along with LA_avdecc. If not, see . +*/ + +/** +* @file talkerEntity.hpp +* @author Christophe Calmejane +* @brief Avdecc talker entity. +*/ + +#pragma once + +#include "la/avdecc/memoryBuffer.hpp" + +#include "protocolInterface.hpp" +#include "entity.hpp" +#include "entityModel.hpp" +#include "entityAddressAccessTypes.hpp" +#include "exports.hpp" + +#include +#include +#include +#include +#include +#include + +namespace la +{ +namespace avdecc +{ +namespace entity +{ +namespace talker +{ +class Interface +{ +public: + /* Enumeration and Control Protocol (AECP) AEM handlers */ + using AcquireEntityHandler = std::function; + using ReleaseEntityHandler = std::function; + using LockEntityHandler = std::function; + using UnlockEntityHandler = std::function; + using QueryEntityAvailableHandler = std::function; + using QueryTalkerAvailableHandler = std::function; + using RegisterUnsolicitedNotificationsHandler = std::function; + using UnregisterUnsolicitedNotificationsHandler = std::function; + using EntityDescriptorHandler = std::function; + using ConfigurationDescriptorHandler = std::function; + using AudioUnitDescriptorHandler = std::function; + using StreamInputDescriptorHandler = std::function; + using StreamOutputDescriptorHandler = std::function; + using JackInputDescriptorHandler = std::function; + using JackOutputDescriptorHandler = std::function; + using AvbInterfaceDescriptorHandler = std::function; + using ClockSourceDescriptorHandler = std::function; + using MemoryObjectDescriptorHandler = std::function; + using LocaleDescriptorHandler = std::function; + using StringsDescriptorHandler = std::function; + using StreamPortInputDescriptorHandler = std::function; + using StreamPortOutputDescriptorHandler = std::function; + using ExternalPortInputDescriptorHandler = std::function; + using ExternalPortOutputDescriptorHandler = std::function; + using InternalPortInputDescriptorHandler = std::function; + using InternalPortOutputDescriptorHandler = std::function; + using AudioClusterDescriptorHandler = std::function; + using AudioMapDescriptorHandler = std::function; + using ClockDomainDescriptorHandler = std::function; + using SetConfigurationHandler = std::function; + using GetConfigurationHandler = std::function; + using SetStreamInputFormatHandler = std::function; + using GetStreamInputFormatHandler = std::function; + using SetStreamOutputFormatHandler = std::function; + using GetStreamOutputFormatHandler = std::function; + using GetStreamPortInputAudioMapHandler = std::function; + using GetStreamPortOutputAudioMapHandler = std::function; + using AddStreamPortInputAudioMappingsHandler = std::function; + using AddStreamPortOutputAudioMappingsHandler = std::function; + using RemoveStreamPortInputAudioMappingsHandler = std::function; + using RemoveStreamPortOutputAudioMappingsHandler = std::function; + using SetStreamInputInfoHandler = std::function; + using SetStreamOutputInfoHandler = std::function; + using GetStreamInputInfoHandler = std::function; + using GetStreamOutputInfoHandler = std::function; + using SetEntityNameHandler = std::function; + using GetEntityNameHandler = std::function; + using SetEntityGroupNameHandler = std::function; + using GetEntityGroupNameHandler = std::function; + using SetConfigurationNameHandler = std::function; + using GetConfigurationNameHandler = std::function; + using SetAudioUnitNameHandler = std::function; + using GetAudioUnitNameHandler = std::function; + using SetStreamInputNameHandler = std::function; + using GetStreamInputNameHandler = std::function; + using SetStreamOutputNameHandler = std::function; + using GetStreamOutputNameHandler = std::function; + using SetAvbInterfaceNameHandler = std::function; + using GetAvbInterfaceNameHandler = std::function; + using SetClockSourceNameHandler = std::function; + using GetClockSourceNameHandler = std::function; + using SetMemoryObjectNameHandler = std::function; + using GetMemoryObjectNameHandler = std::function; + using SetAudioClusterNameHandler = std::function; + using GetAudioClusterNameHandler = std::function; + using SetClockDomainNameHandler = std::function; + using GetClockDomainNameHandler = std::function; + using SetAudioUnitSamplingRateHandler = std::function; + using GetAudioUnitSamplingRateHandler = std::function; + using SetVideoClusterSamplingRateHandler = std::function; + using GetVideoClusterSamplingRateHandler = std::function; + using SetSensorClusterSamplingRateHandler = std::function; + using GetSensorClusterSamplingRateHandler = std::function; + using SetClockSourceHandler = std::function; + using GetClockSourceHandler = std::function; + using StartStreamInputHandler = std::function; + using StartStreamOutputHandler = std::function; + using StopStreamInputHandler = std::function; + using StopStreamOutputHandler = std::function; + using GetAvbInfoHandler = std::function; + using GetAsPathHandler = std::function; + using GetEntityCountersHandler = std::function; + using GetAvbInterfaceCountersHandler = std::function; + using GetClockDomainCountersHandler = std::function; + using GetStreamInputCountersHandler = std::function; + using GetStreamOutputCountersHandler = std::function; + using StartOperationHandler = std::function; + using AbortOperationHandler = std::function; + using SetMemoryObjectLengthHandler = std::function; + using GetMemoryObjectLengthHandler = std::function; + /* Enumeration and Control Protocol (AECP) AA handlers */ + using AddressAccessHandler = std::function; + /* Enumeration and Control Protocol (AECP) MVU handlers (Milan Vendor Unique) */ + using GetMilanInfoHandler = std::function; + /* Connection Management Protocol (ACMP) handlers */ + using ConnectStreamHandler = std::function; + using DisconnectStreamHandler = std::function; + using DisconnectTalkerStreamHandler = std::function; + using GetTalkerStreamStateHandler = std::function; + using GetListenerStreamStateHandler = std::function; + using GetTalkerStreamConnectionHandler = std::function; + + /* Enumeration and Control Protocol (AECP) AEM */ + virtual void acquireEntity(UniqueIdentifier const targetEntityID, bool const isPersistent, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, AcquireEntityHandler const& handler) const noexcept = 0; + virtual void releaseEntity(UniqueIdentifier const targetEntityID, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, ReleaseEntityHandler const& handler) const noexcept = 0; + virtual void lockEntity(UniqueIdentifier const targetEntityID, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, LockEntityHandler const& handler) const noexcept = 0; + virtual void unlockEntity(UniqueIdentifier const targetEntityID, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, UnlockEntityHandler const& handler) const noexcept = 0; + virtual void queryEntityAvailable(UniqueIdentifier const targetEntityID, QueryEntityAvailableHandler const& handler) const noexcept = 0; + virtual void queryTalkerAvailable(UniqueIdentifier const targetEntityID, QueryTalkerAvailableHandler const& handler) const noexcept = 0; + virtual void registerUnsolicitedNotifications(UniqueIdentifier const targetEntityID, RegisterUnsolicitedNotificationsHandler const& handler) const noexcept = 0; + virtual void unregisterUnsolicitedNotifications(UniqueIdentifier const targetEntityID, UnregisterUnsolicitedNotificationsHandler const& handler) const noexcept = 0; + virtual void readEntityDescriptor(UniqueIdentifier const targetEntityID, EntityDescriptorHandler const& handler) const noexcept = 0; + virtual void readConfigurationDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, ConfigurationDescriptorHandler const& handler) const noexcept = 0; + virtual void readAudioUnitDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::AudioUnitIndex const audioUnitIndex, AudioUnitDescriptorHandler const& handler) const noexcept = 0; + virtual void readStreamInputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, StreamInputDescriptorHandler const& handler) const noexcept = 0; + virtual void readStreamOutputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, StreamOutputDescriptorHandler const& handler) const noexcept = 0; + virtual void readJackInputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::JackIndex const jackIndex, JackInputDescriptorHandler const& handler) const noexcept = 0; + virtual void readJackOutputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::JackIndex const jackIndex, JackOutputDescriptorHandler const& handler) const noexcept = 0; + virtual void readAvbInterfaceDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::AvbInterfaceIndex const avbInterfaceIndex, AvbInterfaceDescriptorHandler const& handler) const noexcept = 0; + virtual void readClockSourceDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClockSourceIndex const clockSourceIndex, ClockSourceDescriptorHandler const& handler) const noexcept = 0; + virtual void readMemoryObjectDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::MemoryObjectIndex const memoryObjectIndex, MemoryObjectDescriptorHandler const& handler) const noexcept = 0; + virtual void readLocaleDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::LocaleIndex const localeIndex, LocaleDescriptorHandler const& handler) const noexcept = 0; + virtual void readStringsDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StringsIndex const stringsIndex, StringsDescriptorHandler const& handler) const noexcept = 0; + virtual void readStreamPortInputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamPortIndex const streamPortIndex, StreamPortInputDescriptorHandler const& handler) const noexcept = 0; + virtual void readStreamPortOutputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamPortIndex const streamPortIndex, StreamPortOutputDescriptorHandler const& handler) const noexcept = 0; + virtual void readExternalPortInputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ExternalPortIndex const externalPortIndex, ExternalPortInputDescriptorHandler const& handler) const noexcept = 0; + virtual void readExternalPortOutputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ExternalPortIndex const externalPortIndex, ExternalPortOutputDescriptorHandler const& handler) const noexcept = 0; + virtual void readInternalPortInputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::InternalPortIndex const internalPortIndex, InternalPortInputDescriptorHandler const& handler) const noexcept = 0; + virtual void readInternalPortOutputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::InternalPortIndex const internalPortIndex, InternalPortOutputDescriptorHandler const& handler) const noexcept = 0; + virtual void readAudioClusterDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClusterIndex const clusterIndex, AudioClusterDescriptorHandler const& handler) const noexcept = 0; + virtual void readAudioMapDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::MapIndex const mapIndex, AudioMapDescriptorHandler const& handler) const noexcept = 0; + virtual void readClockDomainDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClockDomainIndex const clockDomainIndex, ClockDomainDescriptorHandler const& handler) const noexcept = 0; + virtual void setConfiguration(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, SetConfigurationHandler const& handler) const noexcept = 0; + virtual void getConfiguration(UniqueIdentifier const targetEntityID, GetConfigurationHandler const& handler) const noexcept = 0; + virtual void setStreamInputFormat(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, model::StreamFormat const streamFormat, SetStreamInputFormatHandler const& handler) const noexcept = 0; + virtual void getStreamInputFormat(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, GetStreamInputFormatHandler const& handler) const noexcept = 0; + virtual void setStreamOutputFormat(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, model::StreamFormat const streamFormat, SetStreamOutputFormatHandler const& handler) const noexcept = 0; + virtual void getStreamOutputFormat(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, GetStreamOutputFormatHandler const& handler) const noexcept = 0; + virtual void getStreamPortInputAudioMap(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, entity::model::MapIndex const mapIndex, GetStreamPortInputAudioMapHandler const& handler) const noexcept = 0; + virtual void getStreamPortOutputAudioMap(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, entity::model::MapIndex const mapIndex, GetStreamPortOutputAudioMapHandler const& handler) const noexcept = 0; + virtual void addStreamPortInputAudioMappings(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::AudioMappings const& mappings, AddStreamPortInputAudioMappingsHandler const& handler) const noexcept = 0; + virtual void addStreamPortOutputAudioMappings(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::AudioMappings const& mappings, AddStreamPortOutputAudioMappingsHandler const& handler) const noexcept = 0; + virtual void removeStreamPortInputAudioMappings(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::AudioMappings const& mappings, RemoveStreamPortInputAudioMappingsHandler const& handler) const noexcept = 0; + virtual void removeStreamPortOutputAudioMappings(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::AudioMappings const& mappings, RemoveStreamPortOutputAudioMappingsHandler const& handler) const noexcept = 0; + virtual void setStreamInputInfo(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, model::StreamInfo const& info, SetStreamInputInfoHandler const& handler) const noexcept = 0; + virtual void setStreamOutputInfo(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, model::StreamInfo const& info, SetStreamOutputInfoHandler const& handler) const noexcept = 0; + virtual void getStreamInputInfo(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, GetStreamInputInfoHandler const& handler) const noexcept = 0; + virtual void getStreamOutputInfo(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, GetStreamOutputInfoHandler const& handler) const noexcept = 0; + virtual void setEntityName(UniqueIdentifier const targetEntityID, model::AvdeccFixedString const& entityName, SetEntityNameHandler const& handler) const noexcept = 0; + virtual void getEntityName(UniqueIdentifier const targetEntityID, GetEntityNameHandler const& handler) const noexcept = 0; + virtual void setEntityGroupName(UniqueIdentifier const targetEntityID, model::AvdeccFixedString const& entityGroupName, SetEntityGroupNameHandler const& handler) const noexcept = 0; + virtual void getEntityGroupName(UniqueIdentifier const targetEntityID, GetEntityGroupNameHandler const& handler) const noexcept = 0; + virtual void setConfigurationName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::AvdeccFixedString const& configurationName, SetConfigurationNameHandler const& handler) const noexcept = 0; + virtual void getConfigurationName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, GetConfigurationNameHandler const& handler) const noexcept = 0; + virtual void setAudioUnitName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::AudioUnitIndex const audioUnitIndex, model::AvdeccFixedString const& audioUnitName, SetAudioUnitNameHandler const& handler) const noexcept = 0; + virtual void getAudioUnitName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const audioUnitIndex, GetAudioUnitNameHandler const& handler) const noexcept = 0; + virtual void setStreamInputName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, model::AvdeccFixedString const& streamInputName, SetStreamInputNameHandler const& handler) const noexcept = 0; + virtual void getStreamInputName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, GetStreamInputNameHandler const& handler) const noexcept = 0; + virtual void setStreamOutputName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, model::AvdeccFixedString const& streamOutputName, SetStreamOutputNameHandler const& handler) const noexcept = 0; + virtual void getStreamOutputName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, GetStreamOutputNameHandler const& handler) const noexcept = 0; + virtual void setAvbInterfaceName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::AvbInterfaceIndex const avbInterfaceIndex, model::AvdeccFixedString const& avbInterfaceName, SetAvbInterfaceNameHandler const& handler) const noexcept = 0; + virtual void getAvbInterfaceName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const avbInterfaceIndex, GetAvbInterfaceNameHandler const& handler) const noexcept = 0; + virtual void setClockSourceName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClockSourceIndex const clockSourceIndex, model::AvdeccFixedString const& clockSourceName, SetClockSourceNameHandler const& handler) const noexcept = 0; + virtual void getClockSourceName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const clockSourceIndex, GetClockSourceNameHandler const& handler) const noexcept = 0; + virtual void setMemoryObjectName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::MemoryObjectIndex const memoryObjectIndex, model::AvdeccFixedString const& memoryObjectName, SetMemoryObjectNameHandler const& handler) const noexcept = 0; + virtual void getMemoryObjectName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const memoryObjectIndex, GetMemoryObjectNameHandler const& handler) const noexcept = 0; + virtual void setAudioClusterName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClusterIndex const audioClusterIndex, model::AvdeccFixedString const& audioClusterName, SetAudioClusterNameHandler const& handler) const noexcept = 0; + virtual void getAudioClusterName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const audioClusterIndex, GetAudioClusterNameHandler const& handler) const noexcept = 0; + virtual void setClockDomainName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClockDomainIndex const clockDomainIndex, model::AvdeccFixedString const& clockDomainName, SetClockDomainNameHandler const& handler) const noexcept = 0; + virtual void getClockDomainName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const clockDomainIndex, GetClockDomainNameHandler const& handler) const noexcept = 0; + virtual void setAudioUnitSamplingRate(UniqueIdentifier const targetEntityID, model::AudioUnitIndex const audioUnitIndex, model::SamplingRate const samplingRate, SetAudioUnitSamplingRateHandler const& handler) const noexcept = 0; + virtual void getAudioUnitSamplingRate(UniqueIdentifier const targetEntityID, model::AudioUnitIndex const audioUnitIndex, GetAudioUnitSamplingRateHandler const& handler) const noexcept = 0; + virtual void setVideoClusterSamplingRate(UniqueIdentifier const targetEntityID, model::ClusterIndex const videoClusterIndex, model::SamplingRate const samplingRate, SetVideoClusterSamplingRateHandler const& handler) const noexcept = 0; + virtual void getVideoClusterSamplingRate(UniqueIdentifier const targetEntityID, model::ClusterIndex const videoClusterIndex, GetVideoClusterSamplingRateHandler const& handler) const noexcept = 0; + virtual void setSensorClusterSamplingRate(UniqueIdentifier const targetEntityID, model::ClusterIndex const sensorClusterIndex, model::SamplingRate const samplingRate, SetSensorClusterSamplingRateHandler const& handler) const noexcept = 0; + virtual void getSensorClusterSamplingRate(UniqueIdentifier const targetEntityID, model::ClusterIndex const sensorClusterIndex, GetSensorClusterSamplingRateHandler const& handler) const noexcept = 0; + virtual void setClockSource(UniqueIdentifier const targetEntityID, model::ClockDomainIndex const clockDomainIndex, model::ClockSourceIndex const clockSourceIndex, SetClockSourceHandler const& handler) const noexcept = 0; + virtual void getClockSource(UniqueIdentifier const targetEntityID, model::ClockDomainIndex const clockDomainIndex, GetClockSourceHandler const& handler) const noexcept = 0; + virtual void startStreamInput(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, StartStreamInputHandler const& handler) const noexcept = 0; + virtual void startStreamOutput(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, StartStreamOutputHandler const& handler) const noexcept = 0; + virtual void stopStreamInput(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, StopStreamInputHandler const& handler) const noexcept = 0; + virtual void stopStreamOutput(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, StopStreamOutputHandler const& handler) const noexcept = 0; + virtual void getAvbInfo(UniqueIdentifier const targetEntityID, model::AvbInterfaceIndex const avbInterfaceIndex, GetAvbInfoHandler const& handler) const noexcept = 0; + virtual void getAsPath(UniqueIdentifier const targetEntityID, model::AvbInterfaceIndex const avbInterfaceIndex, GetAsPathHandler const& handler) const noexcept = 0; + virtual void getEntityCounters(UniqueIdentifier const targetEntityID, GetEntityCountersHandler const& handler) const noexcept = 0; + virtual void getAvbInterfaceCounters(UniqueIdentifier const targetEntityID, model::AvbInterfaceIndex const avbInterfaceIndex, GetAvbInterfaceCountersHandler const& handler) const noexcept = 0; + virtual void getClockDomainCounters(UniqueIdentifier const targetEntityID, model::ClockDomainIndex const clockDomainIndex, GetClockDomainCountersHandler const& handler) const noexcept = 0; + virtual void getStreamInputCounters(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, GetStreamInputCountersHandler const& handler) const noexcept = 0; + virtual void getStreamOutputCounters(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, GetStreamOutputCountersHandler const& handler) const noexcept = 0; + virtual void startOperation(UniqueIdentifier const targetEntityID, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, model::MemoryObjectOperationType const operationType, MemoryBuffer const& memoryBuffer, StartOperationHandler const& handler) const noexcept = 0; + virtual void abortOperation(UniqueIdentifier const targetEntityID, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, model::OperationID const operationID, AbortOperationHandler const& handler) const noexcept = 0; + virtual void setMemoryObjectLength(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::MemoryObjectIndex const memoryObjectIndex, std::uint64_t const length, SetMemoryObjectLengthHandler const& handler) const noexcept = 0; + virtual void getMemoryObjectLength(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::MemoryObjectIndex const memoryObjectIndex, GetMemoryObjectLengthHandler const& handler) const noexcept = 0; + + /* Enumeration and Control Protocol (AECP) AA */ + virtual void addressAccess(UniqueIdentifier const targetEntityID, addressAccess::Tlvs const& tlvs, AddressAccessHandler const& handler) const noexcept = 0; + + /* Enumeration and Control Protocol (AECP) MVU (Milan Vendor Unique) */ + virtual void getMilanInfo(UniqueIdentifier const targetEntityID, GetMilanInfoHandler const& handler) const noexcept = 0; + + /* Connection Management Protocol (ACMP) */ + virtual void connectStream(model::StreamIdentification const& talkerStream, model::StreamIdentification const& listenerStream, ConnectStreamHandler const& handler) const noexcept = 0; + virtual void disconnectStream(model::StreamIdentification const& talkerStream, model::StreamIdentification const& listenerStream, DisconnectStreamHandler const& handler) const noexcept = 0; + virtual void disconnectTalkerStream(model::StreamIdentification const& talkerStream, model::StreamIdentification const& listenerStream, DisconnectTalkerStreamHandler const& handler) const noexcept = 0; + virtual void getTalkerStreamState(model::StreamIdentification const& talkerStream, GetTalkerStreamStateHandler const& handler) const noexcept = 0; + virtual void getListenerStreamState(model::StreamIdentification const& listenerStream, GetListenerStreamStateHandler const& handler) const noexcept = 0; + virtual void getTalkerStreamConnection(model::StreamIdentification const& talkerStream, std::uint16_t const connectionIndex, GetTalkerStreamConnectionHandler const& handler) const noexcept = 0; + + // Defaulted compiler auto-generated methods + Interface() noexcept = default; + virtual ~Interface() noexcept = default; + Interface(Interface&&) = default; + Interface(Interface const&) = default; + Interface& operator=(Interface const&) = default; + Interface& operator=(Interface&&) = default; +}; + +/** Delegate for all talker related notifications. */ +class Delegate +{ +public: + /* Global notifications */ + /** Called when a fatal error on the transport layer occured. */ + virtual void onTransportError(la::avdecc::entity::talker::Interface const* const /*talker*/) noexcept {} + + /* Discovery Protocol (ADP) */ + /** Called when a new entity was discovered on the network (either local or remote). */ + virtual void onEntityOnline(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::Entity const& /*entity*/) noexcept {} + /** Called when an already discovered entity updated its discovery (ADP) information. */ + virtual void onEntityUpdate(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::Entity const& /*entity*/) noexcept {} // When GpgpGrandMasterID, GpgpDomainNumber or EntityCapabilities changed + /** Called when an already discovered entity went offline or timed out (either local or remote). */ + virtual void onEntityOffline(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/) noexcept {} + + /* Connection Management Protocol sniffed messages (ACMP) (not triggered for our own commands even though ACMP messages are broadcasted, the command's 'result' method will be called in that case) */ + /** Called when a talker connect request has been sniffed on the network. */ + virtual void onTalkerConnectResponseSniffed(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::entity::model::StreamIdentification const& /*talkerStream*/, la::avdecc::entity::model::StreamIdentification const& /*listenerStream*/, std::uint16_t const /*connectionCount*/, la::avdecc::entity::ConnectionFlags const /*flags*/, la::avdecc::entity::LocalEntity::ControlStatus const /*status*/) noexcept {} + /** Called when a talker disconnect request has been sniffed on the network. */ + virtual void onTalkerDisconnectResponseSniffed(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::entity::model::StreamIdentification const& /*talkerStream*/, la::avdecc::entity::model::StreamIdentification const& /*listenerStream*/, std::uint16_t const /*connectionCount*/, la::avdecc::entity::ConnectionFlags const /*flags*/, la::avdecc::entity::LocalEntity::ControlStatus const /*status*/) noexcept {} + /** Called when a listener connect request has been sniffed on the network (either due to a another talker connect, or a fast connect). */ + virtual void onListenerConnectResponseSniffed(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::entity::model::StreamIdentification const& /*talkerStream*/, la::avdecc::entity::model::StreamIdentification const& /*listenerStream*/, std::uint16_t const /*connectionCount*/, la::avdecc::entity::ConnectionFlags const /*flags*/, la::avdecc::entity::LocalEntity::ControlStatus const /*status*/) noexcept {} + /** Called when a listener disconnect request has been sniffed on the network (either due to a another talker disconnect, or a fast disconnect). */ + virtual void onListenerDisconnectResponseSniffed(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::entity::model::StreamIdentification const& /*talkerStream*/, la::avdecc::entity::model::StreamIdentification const& /*listenerStream*/, std::uint16_t const /*connectionCount*/, la::avdecc::entity::ConnectionFlags const /*flags*/, la::avdecc::entity::LocalEntity::ControlStatus const /*status*/) noexcept {} + /** Called when a stream state query has been sniffed on the network. */ + virtual void onGetTalkerStreamStateResponseSniffed(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::entity::model::StreamIdentification const& /*talkerStream*/, la::avdecc::entity::model::StreamIdentification const& /*listenerStream*/, std::uint16_t const /*connectionCount*/, la::avdecc::entity::ConnectionFlags const /*flags*/, la::avdecc::entity::LocalEntity::ControlStatus const /*status*/) noexcept {} + /** Called when a stream state query has been sniffed on the network */ + virtual void onGetListenerStreamStateResponseSniffed(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::entity::model::StreamIdentification const& /*talkerStream*/, la::avdecc::entity::model::StreamIdentification const& /*listenerStream*/, std::uint16_t const /*connectionCount*/, la::avdecc::entity::ConnectionFlags const /*flags*/, la::avdecc::entity::LocalEntity::ControlStatus const /*status*/) noexcept {} + + /* Unsolicited notifications (not triggered for our own commands, the command's 'result' method will be called in that case). Only successfull commands can cause an unsolicited notification. */ + /** Called when an entity has been deregistered from unsolicited notifications. */ + virtual void onDeregisteredFromUnsolicitedNotifications(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/) noexcept {} + /** Called when an entity has been acquired by another talker. */ + virtual void onEntityAcquired(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::UniqueIdentifier const /*owningEntity*/, la::avdecc::entity::model::DescriptorType const /*descriptorType*/, la::avdecc::entity::model::DescriptorIndex const /*descriptorIndex*/) noexcept {} + /** Called when an entity has been released by another talker. */ + virtual void onEntityReleased(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::UniqueIdentifier const /*owningEntity*/, la::avdecc::entity::model::DescriptorType const /*descriptorType*/, la::avdecc::entity::model::DescriptorIndex const /*descriptorIndex*/) noexcept {} + /** Called when an entity has been locked by another talker. */ + virtual void onEntityLocked(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::UniqueIdentifier const /*lockingEntity*/, la::avdecc::entity::model::DescriptorType const /*descriptorType*/, la::avdecc::entity::model::DescriptorIndex const /*descriptorIndex*/) noexcept {} + /** Called when an entity has been unlocked by another talker (or because of the lock timeout). */ + virtual void onEntityUnlocked(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::UniqueIdentifier const /*lockingEntity*/, la::avdecc::entity::model::DescriptorType const /*descriptorType*/, la::avdecc::entity::model::DescriptorIndex const /*descriptorIndex*/) noexcept {} + /** Called when the current configuration was changed by another talker. */ + virtual void onConfigurationChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/) noexcept {} + /** Called when the format of an input stream was changed by another talker. */ + virtual void onStreamInputFormatChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::model::StreamFormat const /*streamFormat*/) noexcept {} + /** Called when the format of an output stream was changed by another talker. */ + virtual void onStreamOutputFormatChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::model::StreamFormat const /*streamFormat*/) noexcept {} + /** Called when the audio mappings of a stream port input was changed by another talker. */ + virtual void onStreamPortInputAudioMappingsChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamPortIndex const /*streamPortIndex*/, la::avdecc::entity::model::MapIndex const /*numberOfMaps*/, la::avdecc::entity::model::MapIndex const /*mapIndex*/, la::avdecc::entity::model::AudioMappings const& /*mappings*/) noexcept {} + /** Called when the audio mappings of a stream port output was changed by another talker. */ + virtual void onStreamPortOutputAudioMappingsChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamPortIndex const /*streamPortIndex*/, la::avdecc::entity::model::MapIndex const /*numberOfMaps*/, la::avdecc::entity::model::MapIndex const /*mapIndex*/, la::avdecc::entity::model::AudioMappings const& /*mappings*/) noexcept {} + /** Called when the information of an input stream was changed by another talker. */ + virtual void onStreamInputInfoChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::model::StreamInfo const& /*info*/, bool const /*fromGetStreamInfoResponse*/) noexcept {} + /** Called when the information of an output stream was changed by another talker. */ + virtual void onStreamOutputInfoChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::model::StreamInfo const& /*info*/, bool const /*fromGetStreamInfoResponse*/) noexcept {} + /** Called when the entity's name was changed by another talker. */ + virtual void onEntityNameChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::AvdeccFixedString const& /*entityName*/) noexcept {} + /** Called when the entity's group name was changed by another talker. */ + virtual void onEntityGroupNameChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::AvdeccFixedString const& /*entityGroupName*/) noexcept {} + /** Called when a configuration name was changed by another talker. */ + virtual void onConfigurationNameChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*configurationName*/) noexcept {} + /** Called when an audio unit name was changed by another talker. */ + virtual void onAudioUnitNameChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::AudioUnitIndex const /*audioUnitIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*audioUnitName*/) noexcept {} + /** Called when an input stream name was changed by another talker. */ + virtual void onStreamInputNameChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*streamName*/) noexcept {} + /** Called when an output stream name was changed by another talker. */ + virtual void onStreamOutputNameChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*streamName*/) noexcept {} + /** Called when an avb interface name was changed by another talker. */ + virtual void onAvbInterfaceNameChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::AvbInterfaceIndex const /*avbInterfaceIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*avbInterfaceName*/) noexcept {} + /** Called when a clock source name was changed by another talker. */ + virtual void onClockSourceNameChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::ClockSourceIndex const /*clockSourceIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*clockSourceName*/) noexcept {} + /** Called when a memory object name was changed by another talker. */ + virtual void onMemoryObjectNameChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::MemoryObjectIndex const /*memoryObjectIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*memoryObjectName*/) noexcept {} + /** Called when an audio cluster name was changed by another talker. */ + virtual void onAudioClusterNameChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::ClusterIndex const /*audioClusterIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*audioClusterName*/) noexcept {} + /** Called when a clock domain name was changed by another talker. */ + virtual void onClockDomainNameChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::ClockDomainIndex const /*clockDomainIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*clockDomainName*/) noexcept {} + /** Called when an AudioUnit sampling rate was changed by another talker. */ + virtual void onAudioUnitSamplingRateChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::AudioUnitIndex const /*audioUnitIndex*/, la::avdecc::entity::model::SamplingRate const /*samplingRate*/) noexcept {} + /** Called when a VideoCluster sampling rate was changed by another talker. */ + virtual void onVideoClusterSamplingRateChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::ClusterIndex const /*videoClusterIndex*/, la::avdecc::entity::model::SamplingRate const /*samplingRate*/) noexcept {} + /** Called when a SensorCluster sampling rate was changed by another talker. */ + virtual void onSensorClusterSamplingRateChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::ClusterIndex const /*sensorClusterIndex*/, la::avdecc::entity::model::SamplingRate const /*samplingRate*/) noexcept {} + /** Called when a clock source was changed by another talker. */ + virtual void onClockSourceChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::ClockDomainIndex const /*clockDomainIndex*/, la::avdecc::entity::model::ClockSourceIndex const /*clockSourceIndex*/) noexcept {} + /** Called when an input stream was started by another talker. */ + virtual void onStreamInputStarted(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/) noexcept {} + /** Called when an output stream was started by another talker. */ + virtual void onStreamOutputStarted(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/) noexcept {} + /** Called when an input stream was stopped by another talker. */ + virtual void onStreamInputStopped(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/) noexcept {} + /** Called when an output stream was stopped by another talker. */ + virtual void onStreamOutputStopped(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/) noexcept {} + /** Called when the Avb Info of an Avb Interface changed. */ + virtual void onAvbInfoChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::AvbInterfaceIndex const /*avbInterfaceIndex*/, la::avdecc::entity::model::AvbInfo const& /*info*/) noexcept {} + /** Called when the AS Path of an Avb Interface changed. */ + virtual void onAsPathChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::AvbInterfaceIndex const /*avbInterfaceIndex*/, la::avdecc::entity::model::AsPath const& /*asPath*/) noexcept {} + /** Called when the counters of Entity changed. */ + virtual void onEntityCountersChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::EntityCounterValidFlags const /*validCounters*/, la::avdecc::entity::model::DescriptorCounters const& /*counters*/) noexcept {} + /** Called when the counters of an Avb Interface changed. */ + virtual void onAvbInterfaceCountersChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::AvbInterfaceIndex const /*avbInterfaceIndex*/, la::avdecc::entity::AvbInterfaceCounterValidFlags const /*validCounters*/, la::avdecc::entity::model::DescriptorCounters const& /*counters*/) noexcept {} + /** Called when the counters of a Clock Domain changed. */ + virtual void onClockDomainCountersChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::ClockDomainIndex const /*clockDomainIndex*/, la::avdecc::entity::ClockDomainCounterValidFlags const /*validCounters*/, la::avdecc::entity::model::DescriptorCounters const& /*counters*/) noexcept {} + /** Called when the counters of a Stream Input changed. */ + virtual void onStreamInputCountersChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::StreamInputCounterValidFlags const /*validCounters*/, la::avdecc::entity::model::DescriptorCounters const& /*counters*/) noexcept {} + /** Called when the counters of a Stream Output changed. */ + virtual void onStreamOutputCountersChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::StreamOutputCounterValidFlags const /*validCounters*/, la::avdecc::entity::model::DescriptorCounters const& /*counters*/) noexcept {} + /** Called when (some or all) audio mappings of a stream port input were added by another talker. */ + virtual void onStreamPortInputAudioMappingsAdded(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamPortIndex const /*streamPortIndex*/, la::avdecc::entity::model::AudioMappings const& /*mappings*/) noexcept {} + /** Called when (some or all) audio mappings of a stream port output were added by another talker. */ + virtual void onStreamPortOutputAudioMappingsAdded(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamPortIndex const /*streamPortIndex*/, la::avdecc::entity::model::AudioMappings const& /*mappings*/) noexcept {} + /** Called when (some or all) audio mappings of a stream port input were removed by another talker. */ + virtual void onStreamPortInputAudioMappingsRemoved(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamPortIndex const /*streamPortIndex*/, la::avdecc::entity::model::AudioMappings const& /*mappings*/) noexcept {} + /** Called when (some or all) audio mappings of a stream port output were removed by another talker. */ + virtual void onStreamPortOutputAudioMappingsRemoved(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::StreamPortIndex const /*streamPortIndex*/, la::avdecc::entity::model::AudioMappings const& /*mappings*/) noexcept {} + /** Called when the length of a MemoryObject changed. */ + virtual void onMemoryObjectLengthChanged(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::MemoryObjectIndex const /*memoryObjectIndex*/, std::uint64_t const /*length*/) noexcept {} + /** Called when there is a status update on an ongoing Operation */ + virtual void onOperationStatus(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/, la::avdecc::entity::model::DescriptorType const /*descriptorType*/, la::avdecc::entity::model::DescriptorIndex const /*descriptorIndex*/, la::avdecc::entity::model::OperationID const /*operationID*/, std::uint16_t const /*percentComplete*/) noexcept {} + + /* Identification notifications */ + /** Called when an entity emits an identify notification. */ + virtual void onEntityIdentifyNotification(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const /*entityID*/) noexcept {} + + /* **** Statistics **** */ + /** Notification for when an AECP Command was resent due to a timeout. If the retry time out again, then onAecpTimeout will be called. */ + virtual void onAecpRetry(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const& /*entityID*/) noexcept {} + /** Notification for when an AECP Command timed out (not called when onAecpRetry is called). */ + virtual void onAecpTimeout(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const& /*entityID*/) noexcept {} + /** Notification for when an AECP Response is received but is not expected (might have already timed out). */ + virtual void onAecpUnexpectedResponse(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const& /*entityID*/) noexcept {} + /** Notification for when an AECP Response is received (not an Unsolicited one) along with the time elapsed between the send and the receive. */ + virtual void onAecpResponseTime(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const& /*entityID*/, std::chrono::milliseconds const& /*responseTime*/) noexcept {} + /** Notification for when an AEM-AECP Unsolicited Response was received. */ + virtual void onAemAecpUnsolicitedReceived(la::avdecc::entity::talker::Interface const* const /*talker*/, la::avdecc::UniqueIdentifier const& /*entityID*/) noexcept {} + + // Defaulted compiler auto-generated methods + Delegate() noexcept = default; + virtual ~Delegate() noexcept = default; + Delegate(Delegate&&) = default; + Delegate(Delegate const&) = default; + Delegate& operator=(Delegate const&) = default; + Delegate& operator=(Delegate&&) = default; +}; +} // namespace talker + +class TalkerEntity : public LocalEntity, public talker::Interface +{ +public: + using UniquePointer = std::unique_ptr; + + /** + * @brief Factory method to create a new TalkerEntity. + * @details Creates a new TalkerEntity as a unique pointer. + * @param[in] protocolInterface The protocol interface to bind the entity to. + * @param[in] commonInformation Common information for this talker entity. + * @param[in] interfacesInformation All interfaces information for this talker entity. + * @param[in] delegate The Delegate to be called whenever a talker related notification occurs. + * @return A new TalkerEntity as a Entity::UniquePointer. + * @note Might throw an Exception. + */ + static UniquePointer create(protocol::ProtocolInterface* const protocolInterface, CommonInformation const& commonInformation, InterfacesInformation const& interfacesInformation, talker::Delegate* const delegate) + { + auto deleter = [](TalkerEntity* self) + { + self->destroy(); + }; + return UniquePointer(createRawTalkerEntity(protocolInterface, commonInformation, interfacesInformation, delegate), deleter); + } + + /* Discovery Protocol (ADP) */ + /** Enables entity advertising with available duration included between 2-62 seconds on the specified interfaceIndex if set, otherwise on all interfaces. Returns false if EntityID is already in use on the local computer, true otherwise. */ + using LocalEntity::enableEntityAdvertising; + /** Disables entity advertising on the specified interfaceIndex if set, otherwise on all interfaces. */ + using LocalEntity::disableEntityAdvertising; + + /* Other methods */ + virtual void setTalkerDelegate(talker::Delegate* const delegate) noexcept = 0; + + // Deleted compiler auto-generated methods + TalkerEntity(TalkerEntity&&) = delete; + TalkerEntity(TalkerEntity const&) = delete; + TalkerEntity& operator=(TalkerEntity const&) = delete; + TalkerEntity& operator=(TalkerEntity&&) = delete; + +protected: + /** Constructor */ + TalkerEntity(CommonInformation const& commonInformation, InterfacesInformation const& interfacesInformation); + + /** Destructor */ + virtual ~TalkerEntity() noexcept = default; + +private: + /** Entry point */ + static LA_AVDECC_API TalkerEntity* LA_AVDECC_CALL_CONVENTION createRawTalkerEntity(protocol::ProtocolInterface* const protocolInterface, CommonInformation const& commonInformation, InterfacesInformation const& interfacesInformation, talker::Delegate* const delegate); + + /** Destroy method for COM-like interface */ + virtual void destroy() noexcept = 0; +}; + +} // namespace entity +} // namespace avdecc +} // namespace la diff --git a/include/la/avdecc/talker/avdeccTalker.hpp b/include/la/avdecc/talker/avdeccTalker.hpp new file mode 100644 index 00000000..72d416da --- /dev/null +++ b/include/la/avdecc/talker/avdeccTalker.hpp @@ -0,0 +1,496 @@ +/* +* Copyright (C) 2016-2020, L-Acoustics and its contributors + +* This file is part of LA_avdecc. + +* LA_avdecc is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. + +* LA_avdecc is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. + +* You should have received a copy of the GNU Lesser General Public License +* along with LA_avdecc. If not, see . +*/ + +/** +* @file avdeccTalker.hpp +* @author Christophe Calmejane +* @brief Avdecc Talker. +*/ + +#pragma once + +#include +#include +#include +#include +#include + +#include "internals/avdeccControlledEntity.hpp" +#include "internals/exports.hpp" + +#include +#include +#include +#include +#include +#include +#include + +namespace la +{ +namespace avdecc +{ +namespace talker +{ +/** +* Interface version of the library, used to check for compatibility between the version used to compile and the runtime version.
+* Everytime the interface changes (what is visible from the user) you increase the InterfaceVersion value.
+* A change in the visible interface is any modification in a public header file except a change in a private non-virtual method +* (either added, removed or signature modification). +* Any other change (including templates, inline methods, defines, typedefs, ...) are considered a modification of the interface. +*/ +constexpr std::uint32_t InterfaceVersion = 211; + +/** +* @brief Checks if the library is compatible with specified interface version. +* @param[in] interfaceVersion The interface version to check for compatibility. +* @return True if the library is compatible. +* @note If the library is not compatible, the application should no longer use the library.
+* When using the avdecc Talker shared library, you must call this version to check the compatibility between the compiled and the loaded version. +*/ +LA_AVDECC_TALKER_API bool LA_AVDECC_TALKER_CALL_CONVENTION isCompatibleWithInterfaceVersion(std::uint32_t const interfaceVersion) noexcept; + +/** +* @brief Gets the avdecc controller library version. +* @details Returns the avdecc controller library version. +* @return A string representing the library version. +*/ +LA_AVDECC_TALKER_API std::string LA_AVDECC_TALKER_CALL_CONVENTION getVersion() noexcept; + +/** +* @brief Gets the avdecc controller shared library interface version. +* @details Returns the avdecc controller shared library interface version. +* @return The interface version. +*/ +LA_AVDECC_TALKER_API std::uint32_t LA_AVDECC_TALKER_CALL_CONVENTION getInterfaceVersion() noexcept; + +enum class CompileOption : std::uint32_t +{ + None = 0, + IgnoreNeitherStaticNorDynamicMappings = 1u << 0, + EnableRedundancy = 1u << 15, + Strict2018Redundancy = 1u << 16, + EnableJsonSupport = 1u << 17, +}; +using CompileOptions = utils::EnumBitfield; + +struct CompileOptionInfo +{ + CompileOption option{ CompileOption::None }; + std::string shortName{}; + std::string longName{}; +}; + +/** +* @brief Gets the avdecc controller library compile options. +* @details Returns the avdecc controller library compile options. +* @return The compile options. +*/ +LA_AVDECC_TALKER_API CompileOptions LA_AVDECC_TALKER_CALL_CONVENTION getCompileOptions() noexcept; + +/** +* @brief Gets the avdecc controller library compile options info. +* @details Returns the avdecc controller library compile options info. +* @return The compile options info. +*/ +LA_AVDECC_TALKER_API std::vector LA_AVDECC_TALKER_CALL_CONVENTION getCompileOptionsInfo() noexcept; + +/* ************************************************************************** */ +/* Talker */ +/* ************************************************************************** */ +/** +* @brief A Talker type entity. +* @details A talker entity that can be controlled by the controller. +*/ +class Talker : public la::avdecc::utils::Subject +{ +public: + using UniquePointer = std::unique_ptr; + using DeviceMemoryBuffer = MemoryBuffer; + + enum class Error + { + NoError = 0, + InvalidProtocolInterfaceType = 1, /**< Selected protocol interface type is invalid */ + InterfaceOpenError = 2, /**< Failed to open interface. */ + InterfaceNotFound = 3, /**< Specified interface not found. */ + InterfaceInvalid = 4, /**< Specified interface is invalid. */ + DuplicateProgID = 5, /**< Specified ProgID is already in use on the local computer. */ + InternalError = 99, /**< Internal error, please report the issue. */ + }; + + class LA_AVDECC_TALKER_API Exception final : public la::avdecc::Exception + { + public: + template + Exception(Error const error, T&& text) noexcept + : la::avdecc::Exception(std::forward(text)) + , _error(error) + { + } + Error getError() const noexcept + { + return _error; + } + + private: + Error const _error{ Error::NoError }; + }; + + enum class QueryCommandError + { + RegisterUnsol, + GetMilanInfo, + EntityDescriptor, + ConfigurationDescriptor, + AudioUnitDescriptor, + StreamInputDescriptor, + StreamOutputDescriptor, + AvbInterfaceDescriptor, + ClockSourceDescriptor, + MemoryObjectDescriptor, + LocaleDescriptor, + StringsDescriptor, + StreamPortInputDescriptor, + StreamPortOutputDescriptor, + AudioClusterDescriptor, + AudioMapDescriptor, + ClockDomainDescriptor, + AcquiredState, + LockedState, + StreamInputAudioMap, + StreamOutputAudioMap, + TalkerStreamState, + ListenerStreamState, + TalkerStreamConnection, + TalkerStreamInfo, + ListenerStreamInfo, + AvbInfo, + AsPath, + EntityCounters, + AvbInterfaceCounters, + ClockDomainCounters, + StreamInputCounters, + StreamOutputCounters, + ConfigurationName, + AudioUnitName, + AudioUnitSamplingRate, + InputStreamName, + InputStreamFormat, + OutputStreamName, + OutputStreamFormat, + AvbInterfaceName, + ClockSourceName, + MemoryObjectName, + MemoryObjectLength, + AudioClusterName, + ClockDomainName, + ClockDomainSourceIndex, + }; + + /** + * @brief Observer for entity state and query results. All handlers are guaranteed to be mutually exclusively called. + * @warning For all handlers, the la::avdecc::controller::ControlledEntity parameter should not be copied, since there + * is no guaranty it will still be valid upon return (although it's guaranteed to be valid for the duration of + * the handler). If you later need to get a new temporary pointer to it call the getControlledEntity method. + */ + class Observer : public la::avdecc::utils::Observer + { + public: + // Global controller notifications + virtual void onTransportError(la::avdecc::controller::Talker const* const /*controller*/) noexcept {} + virtual void onEntityQueryError(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::controller::Talker::QueryCommandError const /*error*/) noexcept {} // Might trigger even if entity is not "online" // Triggered when the controller failed to query all information it needs for an entity to be declared as Online + + // Discovery notifications (ADP) + virtual void onEntityOnline(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/) noexcept {} + virtual void onEntityOffline(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/) noexcept {} + virtual void onEntityCapabilitiesChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/) noexcept {} + virtual void onEntityAssociationChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/) noexcept {} + virtual void onGptpChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::AvbInterfaceIndex const /*avbInterfaceIndex*/, la::avdecc::UniqueIdentifier const /*grandMasterID*/, std::uint8_t const /*grandMasterDomain*/) noexcept {} + + // Global entity notifications + virtual void onUnsolicitedRegistrationChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, bool const /*isSubscribed*/) noexcept {} + virtual void onCompatibilityFlagsChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::controller::ControlledEntity::CompatibilityFlags const /*compatibilityFlags*/) noexcept {} + virtual void onIdentificationStarted(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/) noexcept {} + virtual void onIdentificationStopped(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/) noexcept {} + + // Connection notifications (ACMP) + virtual void onStreamConnectionChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::entity::model::StreamConnectionState const& /*state*/, bool const /*changedByOther*/) noexcept {} + virtual void onStreamConnectionsChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::model::StreamConnections const& /*connections*/) noexcept {} + + // Entity model notifications (unsolicited AECP or changes this controller sent) + virtual void onAcquireStateChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::controller::model::AcquireState const /*acquireState*/, la::avdecc::UniqueIdentifier const /*owningEntity*/) noexcept {} + virtual void onLockStateChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::controller::model::LockState const /*lockState*/, la::avdecc::UniqueIdentifier const /*lockingEntity*/) noexcept {} + virtual void onStreamInputFormatChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::model::StreamFormat const /*streamFormat*/) noexcept {} + virtual void onStreamOutputFormatChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::model::StreamFormat const /*streamFormat*/) noexcept {} + virtual void onStreamInputDynamicInfoChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::model::StreamDynamicInfo const& /*info*/) noexcept {} + virtual void onStreamOutputDynamicInfoChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::model::StreamDynamicInfo const& /*info*/) noexcept {} + virtual void onEntityNameChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::AvdeccFixedString const& /*entityName*/) noexcept {} + virtual void onEntityGroupNameChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::AvdeccFixedString const& /*entityGroupName*/) noexcept {} + virtual void onConfigurationNameChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*configurationName*/) noexcept {} + virtual void onAudioUnitNameChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::AudioUnitIndex const /*audioUnitIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*audioUnitName*/) noexcept {} + virtual void onStreamInputNameChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*streamName*/) noexcept {} + virtual void onStreamOutputNameChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*streamName*/) noexcept {} + virtual void onAvbInterfaceNameChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::AvbInterfaceIndex const /*avbInterfaceIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*avbInterfaceName*/) noexcept {} + virtual void onClockSourceNameChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::ClockSourceIndex const /*clockSourceIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*clockSourceName*/) noexcept {} + virtual void onMemoryObjectNameChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::MemoryObjectIndex const /*memoryObjectIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*memoryObjectName*/) noexcept {} + virtual void onAudioClusterNameChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::ClusterIndex const /*audioClusterIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*audioClusterName*/) noexcept {} + virtual void onClockDomainNameChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::ClockDomainIndex const /*clockDomainIndex*/, la::avdecc::entity::model::AvdeccFixedString const& /*clockDomainName*/) noexcept {} + virtual void onAudioUnitSamplingRateChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::AudioUnitIndex const /*audioUnitIndex*/, la::avdecc::entity::model::SamplingRate const /*samplingRate*/) noexcept {} + virtual void onClockSourceChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::ClockDomainIndex const /*clockDomainIndex*/, la::avdecc::entity::model::ClockSourceIndex const /*clockSourceIndex*/) noexcept {} + virtual void onStreamInputStarted(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/) noexcept {} + virtual void onStreamOutputStarted(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/) noexcept {} + virtual void onStreamInputStopped(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/) noexcept {} + virtual void onStreamOutputStopped(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/) noexcept {} + virtual void onAvbInterfaceInfoChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::AvbInterfaceIndex const /*avbInterfaceIndex*/, la::avdecc::entity::model::AvbInterfaceInfo const& /*info*/) noexcept {} + virtual void onAsPathChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::AvbInterfaceIndex const /*avbInterfaceIndex*/, la::avdecc::entity::model::AsPath const& /*asPath*/) noexcept {} + virtual void onAvbInterfaceLinkStatusChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::AvbInterfaceIndex const /*avbInterfaceIndex*/, la::avdecc::controller::ControlledEntity::InterfaceLinkStatus const /*linkStatus*/) noexcept {} + virtual void onEntityCountersChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::EntityCounters const& /*counters*/) noexcept {} + virtual void onAvbInterfaceCountersChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::AvbInterfaceIndex const /*avbInterfaceIndex*/, la::avdecc::entity::model::AvbInterfaceCounters const& /*counters*/) noexcept {} + virtual void onClockDomainCountersChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::ClockDomainIndex const /*clockDomainIndex*/, la::avdecc::entity::model::ClockDomainCounters const& /*counters*/) noexcept {} + virtual void onStreamInputCountersChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::model::StreamInputCounters const& /*counters*/) noexcept {} + virtual void onStreamOutputCountersChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::StreamIndex const /*streamIndex*/, la::avdecc::entity::model::StreamOutputCounters const& /*counters*/) noexcept {} + virtual void onMemoryObjectLengthChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::ConfigurationIndex const /*configurationIndex*/, la::avdecc::entity::model::MemoryObjectIndex const /*memoryObjectIndex*/, std::uint64_t const /*length*/) noexcept {} + virtual void onStreamPortInputAudioMappingsChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::StreamPortIndex const /*streamPortIndex*/) noexcept {} + virtual void onStreamPortOutputAudioMappingsChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::StreamPortIndex const /*streamPortIndex*/) noexcept {} + virtual void onOperationProgress(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::DescriptorType const /*descriptorType*/, la::avdecc::entity::model::DescriptorIndex const /*descriptorIndex*/, la::avdecc::entity::model::OperationID const /*operationID*/, float const /*percentComplete*/) noexcept {} // A negative percentComplete value means the progress is unknown but still continuing + virtual void onOperationCompleted(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, la::avdecc::entity::model::DescriptorType const /*descriptorType*/, la::avdecc::entity::model::DescriptorIndex const /*descriptorIndex*/, la::avdecc::entity::model::OperationID const /*operationID*/, bool const /*failed*/) noexcept {} + + // Statistics + virtual void onAecpRetryCounterChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, std::uint64_t const /*value*/) noexcept {} + virtual void onAecpTimeoutCounterChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, std::uint64_t const /*value*/) noexcept {} + virtual void onAecpUnexpectedResponseCounterChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, std::uint64_t const /*value*/) noexcept {} + virtual void onAecpResponseAverageTimeChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, std::chrono::milliseconds const& /*value*/) noexcept {} + virtual void onAemAecpUnsolicitedCounterChanged(la::avdecc::controller::Talker const* const /*controller*/, la::avdecc::controller::ControlledEntity const* const /*entity*/, std::uint64_t const /*value*/) noexcept {} + }; + + class ExclusiveAccessToken + { + public: + using UniquePointer = std::unique_ptr; + + enum class AccessType + { + Acquire = 0, + PersistentAcquire = 1, + Lock = 2, + }; + + // Deleted compiler auto-generated methods + ExclusiveAccessToken(ExclusiveAccessToken&&) = delete; + ExclusiveAccessToken(ExclusiveAccessToken const&) = delete; + ExclusiveAccessToken& operator=(ExclusiveAccessToken const&) = delete; + ExclusiveAccessToken& operator=(ExclusiveAccessToken&&) = delete; + + protected: + ExclusiveAccessToken() = default; + virtual ~ExclusiveAccessToken() = default; + }; + + /* Enumeration and Control Protocol (AECP) AEM handlers. WARNING: The 'entity' parameter might be nullptr even if 'status' is AemCommandStatus::Success, in case the unit goes offline right after processing our command. */ + using AcquireEntityHandler = std::function; + using ReleaseEntityHandler = std::function; + using LockEntityHandler = std::function; + using UnlockEntityHandler = std::function; + using SetConfigurationHandler = std::function; + using SetStreamInputFormatHandler = std::function; + using SetStreamOutputFormatHandler = std::function; + using SetStreamInputInfoHandler = std::function; + using SetStreamOutputInfoHandler = std::function; + using SetEntityNameHandler = std::function; + using SetEntityGroupNameHandler = std::function; + using SetConfigurationNameHandler = std::function; + using SetAudioUnitNameHandler = std::function; + using SetStreamInputNameHandler = std::function; + using SetStreamOutputNameHandler = std::function; + using SetAvbInterfaceNameHandler = std::function; + using SetClockSourceNameHandler = std::function; + using SetMemoryObjectNameHandler = std::function; + using SetAudioClusterNameHandler = std::function; + using SetClockDomainNameHandler = std::function; + using SetAudioUnitSamplingRateHandler = std::function; + using SetClockSourceHandler = std::function; + using StartStreamInputHandler = std::function; + using StopStreamInputHandler = std::function; + using StartStreamOutputHandler = std::function; + using StopStreamOutputHandler = std::function; + using AddStreamPortInputAudioMappingsHandler = std::function; + using AddStreamPortOutputAudioMappingsHandler = std::function; + using RemoveStreamPortInputAudioMappingsHandler = std::function; + using RemoveStreamPortOutputAudioMappingsHandler = std::function; + using StartMemoryObjectOperationHandler = std::function; + using AbortOperationHandler = std::function; + using SetMemoryObjectLengthHandler = std::function; + /* Enumeration and Control Protocol (AECP) AA handlers. WARNING: The 'entity' parameter might be nullptr even if 'status' is AemCommandStatus::Success, in case the unit goes offline right after processing our command. */ + using ReadDeviceMemoryProgressHandler = std::function; // A negative percentComplete value means the progress is unknown but still continuing // Returning true will abort the operation + using ReadDeviceMemoryCompletionHandler = std::function; + using WriteDeviceMemoryProgressHandler = std::function; // A negative percentComplete value means the progress is unknown but still continuing // Returning true will abort the operation + using WriteDeviceMemoryCompletionHandler = std::function; + /* Connection Management Protocol (ACMP) handlers */ + using ConnectStreamHandler = std::function; + using DisconnectStreamHandler = std::function; + using DisconnectTalkerStreamHandler = std::function; + using GetListenerStreamStateHandler = std::function; + /* Other handlers */ + using RequestExclusiveAccessResultHandler = std::function; + + /** + * @brief Factory method to create a new Talker. + * @details Creates a new Talker as a unique pointer. + * @param[in] protocolInterfaceType The protocol interface type to use. + * @param[in] interfaceName The name of the interface to bind the controller to. + * Use #la::avdecc::networkInterface::enumerateInterfaces to get a list of valid + * interfaces, and pass the 'name' field of a #la::avdecc::networkInterface::Interface + * to this method. + * @param[in] progID ID that will be used to generate the #UniqueIdentifier for this controller. + * @param[in] entityModelID EntityModelID to publish for this controller. You can use entity::model::makeEntityModelID to create this value. + * @param[in] preferedLocale ISO 639-1 locale code of the prefered locale to use when querying entity information. + * If the specified locale is not found on the entity, then english is used. + * @return A new Talker as a Talker::UniquePointer. + * @note Throws Exception if interfaceName is invalid or inaccessible, or if progID is already used on the local computer. + */ + static UniquePointer create(protocol::ProtocolInterface::Type const protocolInterfaceType, std::string const& interfaceName, std::uint16_t const progID, UniqueIdentifier const entityModelID, std::string const& preferedLocale) + { + auto deleter = [](Talker* controller) + { + controller->destroy(); + }; + return UniquePointer(createRawTalker(protocolInterfaceType, interfaceName, progID, entityModelID, preferedLocale), deleter); + } + + /** Returns the UniqueIdentifier this instance of the controller is using to identify itself on the network */ + virtual UniqueIdentifier getTalkerEID() const noexcept = 0; + + /* Talker configuration methods */ + /** Enables entity advertising with available duration included between 2-62 seconds on the specified interfaceIndex if set, otherwise on all interfaces. Might throw an Exception. */ + virtual void enableEntityAdvertising(std::uint32_t const availableDuration, std::optional const interfaceIndex = std::nullopt) = 0; + /** Disables entity advertising on the specified interfaceIndex if set, otherwise on all interfaces. */ + virtual void disableEntityAdvertising(std::optional const interfaceIndex = std::nullopt) noexcept = 0; + /** Enables the EntityModel cache */ + virtual void enableEntityModelCache() noexcept = 0; + /** Disables the EntityModel cache */ + virtual void disableEntityModelCache() noexcept = 0; + /** Enables complete EntityModel (static part) enumeration. Depending on entities, it might take a much longer time to enumerate. */ + virtual void enableFullStaticEntityModelEnumeration() noexcept = 0; + /** Disables complete EntityModel (static part) enumeration.*/ + virtual void disableFullStaticEntityModelEnumeration() noexcept = 0; + /** Loads an EntityModel file and feed it to the EntityModel cache */ + virtual std::tuple loadEntityModelFile(std::string const& filePath) noexcept = 0; + + /* Enumeration and Control Protocol (AECP) AEM. WARNING: The completion handler will not be called if the controller is destroyed while the query is inflight. Otherwise it will always be called. */ + virtual void acquireEntity(UniqueIdentifier const targetEntityID, bool const isPersistent, AcquireEntityHandler const& handler) const noexcept = 0; + virtual void releaseEntity(UniqueIdentifier const targetEntityID, ReleaseEntityHandler const& handler) const noexcept = 0; + virtual void lockEntity(UniqueIdentifier const targetEntityID, LockEntityHandler const& handler) const noexcept = 0; + virtual void unlockEntity(UniqueIdentifier const targetEntityID, UnlockEntityHandler const& handler) const noexcept = 0; + virtual void setConfiguration(UniqueIdentifier const targetEntityID, entity::model::ConfigurationIndex const configurationIndex, SetConfigurationHandler const& handler) const noexcept = 0; + virtual void setStreamInputFormat(UniqueIdentifier const targetEntityID, entity::model::StreamIndex const streamIndex, entity::model::StreamFormat const streamFormat, SetStreamInputFormatHandler const& handler) const noexcept = 0; + virtual void setStreamOutputFormat(UniqueIdentifier const targetEntityID, entity::model::StreamIndex const streamIndex, entity::model::StreamFormat const streamFormat, SetStreamOutputFormatHandler const& handler) const noexcept = 0; + virtual void setStreamInputInfo(UniqueIdentifier const targetEntityID, entity::model::StreamIndex const streamIndex, entity::model::StreamInfo const& info, SetStreamInputInfoHandler const& handler) const noexcept = 0; + virtual void setStreamOutputInfo(UniqueIdentifier const targetEntityID, entity::model::StreamIndex const streamIndex, entity::model::StreamInfo const& info, SetStreamOutputInfoHandler const& handler) const noexcept = 0; + virtual void setEntityName(UniqueIdentifier const targetEntityID, entity::model::AvdeccFixedString const& name, SetEntityNameHandler const& handler) const noexcept = 0; + virtual void setEntityGroupName(UniqueIdentifier const targetEntityID, entity::model::AvdeccFixedString const& name, SetEntityGroupNameHandler const& handler) const noexcept = 0; + virtual void setConfigurationName(UniqueIdentifier const targetEntityID, entity::model::ConfigurationIndex const configurationIndex, entity::model::AvdeccFixedString const& name, SetConfigurationNameHandler const& handler) const noexcept = 0; + virtual void setAudioUnitName(UniqueIdentifier const targetEntityID, entity::model::ConfigurationIndex const configurationIndex, entity::model::AudioUnitIndex const audioUnitIndex, entity::model::AvdeccFixedString const& name, SetAudioUnitNameHandler const& handler) const noexcept = 0; + virtual void setStreamInputName(UniqueIdentifier const targetEntityID, entity::model::ConfigurationIndex const configurationIndex, entity::model::StreamIndex const streamIndex, entity::model::AvdeccFixedString const& name, SetStreamInputNameHandler const& handler) const noexcept = 0; + virtual void setStreamOutputName(UniqueIdentifier const targetEntityID, entity::model::ConfigurationIndex const configurationIndex, entity::model::StreamIndex const streamIndex, entity::model::AvdeccFixedString const& name, SetStreamOutputNameHandler const& handler) const noexcept = 0; + virtual void setAvbInterfaceName(UniqueIdentifier const targetEntityID, entity::model::ConfigurationIndex const configurationIndex, entity::model::AvbInterfaceIndex const avbInterfaceIndex, entity::model::AvdeccFixedString const& name, SetAvbInterfaceNameHandler const& handler) const noexcept = 0; + virtual void setClockSourceName(UniqueIdentifier const targetEntityID, entity::model::ConfigurationIndex const configurationIndex, entity::model::ClockSourceIndex const clockSourceIndex, entity::model::AvdeccFixedString const& name, SetClockSourceNameHandler const& handler) const noexcept = 0; + virtual void setMemoryObjectName(UniqueIdentifier const targetEntityID, entity::model::ConfigurationIndex const configurationIndex, entity::model::MemoryObjectIndex const memoryObjectIndex, entity::model::AvdeccFixedString const& name, SetMemoryObjectNameHandler const& handler) const noexcept = 0; + virtual void setAudioClusterName(UniqueIdentifier const targetEntityID, entity::model::ConfigurationIndex const configurationIndex, entity::model::ClusterIndex const audioClusterIndex, entity::model::AvdeccFixedString const& name, SetAudioClusterNameHandler const& handler) const noexcept = 0; + virtual void setClockDomainName(UniqueIdentifier const targetEntityID, entity::model::ConfigurationIndex const configurationIndex, entity::model::ClockDomainIndex const clockDomainIndex, entity::model::AvdeccFixedString const& name, SetClockDomainNameHandler const& handler) const noexcept = 0; + virtual void setAudioUnitSamplingRate(UniqueIdentifier const targetEntityID, entity::model::AudioUnitIndex const audioUnitIndex, entity::model::SamplingRate const samplingRate, SetAudioUnitSamplingRateHandler const& handler) const noexcept = 0; + virtual void setClockSource(UniqueIdentifier const targetEntityID, entity::model::ClockDomainIndex const clockDomainIndex, entity::model::ClockSourceIndex const clockSourceIndex, SetClockSourceHandler const& handler) const noexcept = 0; + virtual void startStreamInput(UniqueIdentifier const targetEntityID, entity::model::StreamIndex const streamIndex, StartStreamInputHandler const& handler) const noexcept = 0; + virtual void stopStreamInput(UniqueIdentifier const targetEntityID, entity::model::StreamIndex const streamIndex, StopStreamInputHandler const& handler) const noexcept = 0; + virtual void startStreamOutput(UniqueIdentifier const targetEntityID, entity::model::StreamIndex const streamIndex, StartStreamOutputHandler const& handler) const noexcept = 0; + virtual void stopStreamOutput(UniqueIdentifier const targetEntityID, entity::model::StreamIndex const streamIndex, StopStreamOutputHandler const& handler) const noexcept = 0; + virtual void addStreamPortInputAudioMappings(UniqueIdentifier const targetEntityID, entity::model::StreamPortIndex const streamPortIndex, entity::model::AudioMappings const& mappings, AddStreamPortInputAudioMappingsHandler const& handler) const noexcept = 0; + virtual void addStreamPortOutputAudioMappings(UniqueIdentifier const targetEntityID, entity::model::StreamPortIndex const streamPortIndex, entity::model::AudioMappings const& mappings, AddStreamPortOutputAudioMappingsHandler const& handler) const noexcept = 0; + virtual void removeStreamPortInputAudioMappings(UniqueIdentifier const targetEntityID, entity::model::StreamPortIndex const streamPortIndex, entity::model::AudioMappings const& mappings, RemoveStreamPortInputAudioMappingsHandler const& handler) const noexcept = 0; + virtual void removeStreamPortOutputAudioMappings(UniqueIdentifier const targetEntityID, entity::model::StreamPortIndex const streamPortIndex, entity::model::AudioMappings const& mappings, RemoveStreamPortOutputAudioMappingsHandler const& handler) const noexcept = 0; + virtual void startStoreMemoryObjectOperation(UniqueIdentifier const targetEntityID, entity::model::DescriptorIndex const descriptorIndex, StartMemoryObjectOperationHandler const& handler) const noexcept = 0; + virtual void startStoreAndRebootMemoryObjectOperation(UniqueIdentifier const targetEntityID, entity::model::DescriptorIndex const descriptorIndex, StartMemoryObjectOperationHandler const& handler) const noexcept = 0; + virtual void startReadMemoryObjectOperation(UniqueIdentifier const targetEntityID, entity::model::DescriptorIndex const descriptorIndex, StartMemoryObjectOperationHandler const& handler) const noexcept = 0; + virtual void startEraseMemoryObjectOperation(UniqueIdentifier const targetEntityID, entity::model::DescriptorIndex const descriptorIndex, StartMemoryObjectOperationHandler const& handler) const noexcept = 0; + virtual void startUploadMemoryObjectOperation(UniqueIdentifier const targetEntityID, entity::model::DescriptorIndex const descriptorIndex, std::uint64_t const dataLength, StartMemoryObjectOperationHandler const& handler) const noexcept = 0; + virtual void abortOperation(UniqueIdentifier const targetEntityID, entity::model::DescriptorType const descriptorType, entity::model::DescriptorIndex const descriptorIndex, entity::model::OperationID const operationID, AbortOperationHandler const& handler) const noexcept = 0; + virtual void setMemoryObjectLength(UniqueIdentifier const targetEntityID, entity::model::ConfigurationIndex const configurationIndex, entity::model::MemoryObjectIndex const memoryObjectIndex, std::uint64_t const length, SetMemoryObjectLengthHandler const& handler) const noexcept = 0; + + /* Enumeration and Control Protocol (AECP) AA. WARNING: The completion handler will not be called if the controller is destroyed while the query is inflight. Otherwise it will always be called. */ + virtual void readDeviceMemory(UniqueIdentifier const targetEntityID, std::uint64_t const address, std::uint64_t const length, ReadDeviceMemoryProgressHandler const& progressHandler, ReadDeviceMemoryCompletionHandler const& completionHandler) const noexcept = 0; + virtual void writeDeviceMemory(UniqueIdentifier const targetEntityID, std::uint64_t const address, la::avdecc::controller::Talker::DeviceMemoryBuffer memoryBuffer, WriteDeviceMemoryProgressHandler const& progressHandler, WriteDeviceMemoryCompletionHandler const& completionHandler) const noexcept = 0; + + /* Connection Management Protocol (ACMP). WARNING: The completion handler will not be called if the controller is destroyed while the query is inflight. Otherwise it will always be called. */ + virtual void connectStream(entity::model::StreamIdentification const& talkerStream, entity::model::StreamIdentification const& listenerStream, ConnectStreamHandler const& handler) const noexcept = 0; + virtual void disconnectStream(entity::model::StreamIdentification const& talkerStream, entity::model::StreamIdentification const& listenerStream, DisconnectStreamHandler const& handler) const noexcept = 0; + /** Sends a DisconnectTX message directly to the talker, spoofing the listener. Should only be used to forcefully disconnect a ghost connection on the talker. */ + virtual void disconnectTalkerStream(entity::model::StreamIdentification const& talkerStream, entity::model::StreamIdentification const& listenerStream, DisconnectTalkerStreamHandler const& handler) const noexcept = 0; + virtual void getListenerStreamState(entity::model::StreamIdentification const& listenerStream, GetListenerStreamStateHandler const& handler) const noexcept = 0; + + /** Gets a lock guarded ControlledEntity. While the returned object is in the scope, you are guaranteed to have exclusive access on the ControlledEntity. The returned guard should not be kept or held for more than a few milliseconds. */ + virtual ControlledEntityGuard getControlledEntityGuard(UniqueIdentifier const entityID) const noexcept = 0; + + /** Requests an ExclusiveAccessToken for the specified entityID. If the call succeeded (AemCommandStatus::Success), a valid token will be returned. The handler will always be called, either before the call returns or asynchronously. */ + virtual void requestExclusiveAccess(UniqueIdentifier const entityID, ExclusiveAccessToken::AccessType const type, RequestExclusiveAccessResultHandler&& handler) const noexcept = 0; + + /** BasicLockable concept 'lock' method for the whole Talker */ + virtual void lock() noexcept = 0; + /** BasicLockable concept 'unlock' method for the whole Talker */ + virtual void unlock() noexcept = 0; + + /* Model serialization methods */ + /** Serializes all discovered ControlledEntities as JSON and save to specified file. If 'continueOnError' is specified and some error(s) occured, SerializationError::Incomplete will be returned. */ + virtual std::tuple serializeAllControlledEntitiesAsJson(std::string const& filePath, entity::model::jsonSerializer::Flags const flags, std::string const& dumpSource, bool const continueOnError) const noexcept = 0; + /** Serializes specified ControlledEntity as JSON and save to specified file. */ + virtual std::tuple serializeControlledEntityAsJson(UniqueIdentifier const entityID, std::string const& filePath, entity::model::jsonSerializer::Flags const flags, std::string const& dumpSource) const noexcept = 0; + + /* Model deserialization methods */ + /** Deserializes a JSON file representing an entity, and loads it as a virtual ControlledEntity. */ + virtual std::tuple loadVirtualEntityFromJson(std::string const& filePath, entity::model::jsonSerializer::Flags const flags) noexcept = 0; + + // Deleted compiler auto-generated methods + Talker(Talker const&) = delete; + Talker(Talker&&) = delete; + Talker& operator=(Talker const&) = delete; + Talker& operator=(Talker&&) = delete; + +protected: + /** Constructor */ + Talker() = default; + + /** Destructor */ + virtual ~Talker() = default; + +private: + /** Create method for COM-like interface */ + static LA_AVDECC_TALKER_API Talker* LA_AVDECC_TALKER_CALL_CONVENTION createRawTalker(protocol::ProtocolInterface::Type const protocolInterfaceType, std::string const& interfaceName, std::uint16_t const progID, UniqueIdentifier const entityModelID, std::string const& preferedLocale); + + /** Destroy method for COM-like interface */ + virtual void destroy() noexcept = 0; +}; + +/* Operator overloads */ +constexpr bool operator!(Talker::Error const error) +{ + return error == Talker::Error::NoError; +} + +} // namespace controller +} // namespace avdecc +} // namespace la diff --git a/include/la/avdecc/talker/internals/exports.hpp b/include/la/avdecc/talker/internals/exports.hpp new file mode 100644 index 00000000..93baa5c2 --- /dev/null +++ b/include/la/avdecc/talker/internals/exports.hpp @@ -0,0 +1,52 @@ +/* +* Copyright (C) 2016-2020, L-Acoustics and its contributors + +* This file is part of LA_avdecc. + +* LA_avdecc is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. + +* LA_avdecc is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. + +* You should have received a copy of the GNU Lesser General Public License +* along with LA_avdecc. If not, see . +*/ + +/** +* @file avdecc/talker/internals/exports.hpp +* @author Christophe Calmejane +* @brief OS specific defines for importing and exporting dynamic symbols. +*/ + +#pragma once + +#ifdef _WIN32 + +# define LA_AVDECC_TALKER_CALL_CONVENTION __stdcall + +# if defined(la_avdecc_TALKER_cxx_EXPORTS) +# define LA_AVDECC_TALKER_API __declspec(dllexport) +# elif defined(la_avdecc_TALKER_cxx_STATICS) +# define LA_AVDECC_TALKER_API +# else // !la_avdecc_TALKER_cxx_EXPORTS +# define LA_AVDECC_TALKER_API __declspec(dllimport) +# endif // la_avdecc_TALKER_cxx_EXPORTS + +#else // !_WIN32 + +# define LA_AVDECC_TALKER_CALL_CONVENTION + +# if defined(la_avdecc_TALKER_cxx_EXPORTS) +# define LA_AVDECC_TALKER_API __attribute__((visibility("default"))) +# elif defined(la_avdecc_TALKER_cxx_STATICS) +# define LA_AVDECC_TALKER_API +# else // !la_avdecc_TALKER_cxx_EXPORTS +# define LA_AVDECC_TALKER_API __attribute__((visibility("default"))) +# endif // la_avdecc_TALKER_cxx_EXPORTS + +#endif // _WIN32 diff --git a/scripts/fix_files.sh b/scripts/fix_files.sh index 9d997327..917d1de9 100755 --- a/scripts/fix_files.sh +++ b/scripts/fix_files.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash FIX_FILES_VERSION="1.5" @@ -81,8 +81,9 @@ if [[ $do_clang_format -eq 1 && -f ./.clang-format ]]; then if [ $? -eq 0 ]; then cf_version="$(clang-format --version)" regex="clang-format version 7\.0\.0 \(tags\/RELEASE_700\/final[ 0-9]*\/WithWrappingBeforeLambdaBodyPatch\)" - if [[ ! "$cf_version" =~ $regex ]]; then - echo "Incorrect clang-format: Version 7.0.0 with WrappingBeforeLambdaBody patch required (found: $cf_version)" + regex2="clang-format version 11\.[ 0-9]*" + if [[ ! ( "$cf_version" =~ $regex) && ! ("$cf_version" =~ $regex2) ]]; then + echo "Incorrect clang-format: Version 7.0.0 with WrappingBeforeLambdaBody patch or Version > 10.0 required (found: $cf_version)" exit 1 fi applyFormat "*.[chi]pp" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c698848d..912e64bf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -57,6 +57,7 @@ set (PUBLIC_HEADER_FILES ${LA_ROOT_DIR}/include/la/avdecc/watchDog.hpp ${LA_ROOT_DIR}/include/la/avdecc/internals/aggregateEntity.hpp ${LA_ROOT_DIR}/include/la/avdecc/internals/controllerEntity.hpp + ${LA_ROOT_DIR}/include/la/avdecc/internals/talkerEntity.hpp ${LA_ROOT_DIR}/include/la/avdecc/internals/endian.hpp ${LA_ROOT_DIR}/include/la/avdecc/internals/endStation.hpp ${LA_ROOT_DIR}/include/la/avdecc/internals/entity.hpp @@ -140,6 +141,7 @@ set (HEADER_FILES_ENTITY entity/localEntityImpl.ipp entity/aggregateEntityImpl.hpp entity/controllerCapabilityDelegate.hpp + entity/talkerCapabilityDelegate.hpp entity/controllerEntityImpl.hpp ) @@ -148,6 +150,7 @@ set (SOURCE_FILES_ENTITY entity/localEntityImpl.cpp entity/aggregateEntityImpl.cpp entity/controllerCapabilityDelegate.cpp + entity/talkerCapabilityDelegate.cpp entity/controllerEntityImpl.cpp ) diff --git a/src/entity/aggregateEntityImpl.cpp b/src/entity/aggregateEntityImpl.cpp index 598ca557..2303e5e4 100644 --- a/src/entity/aggregateEntityImpl.cpp +++ b/src/entity/aggregateEntityImpl.cpp @@ -27,6 +27,7 @@ #include "logHelper.hpp" #include "aggregateEntityImpl.hpp" #include "controllerCapabilityDelegate.hpp" +#include "talkerCapabilityDelegate.hpp" #include #include @@ -55,18 +56,19 @@ AggregateEntityImpl::AggregateEntityImpl(protocol::ProtocolInterface* const prot _controllerCapabilityDelegate = std::make_unique(getProtocolInterface(), controllerDelegate, *this, entityID); } - // Entity is listener capable + /*/ Entity is listener capable if (commonInformation.listenerCapabilities.test(ListenerCapability::Implemented)) { AVDECC_ASSERT(false, "TODO: AggregateEntityImpl: Handle listener capability"); - //_listenerCapabilityDelegate = std::make_unique(entityID); - } + _listenerCapabilityDelegate = std::make_unique(entityID); + }*/ // Entity is talker capable if (commonInformation.talkerCapabilities.test(TalkerCapability::Implemented)) { - AVDECC_ASSERT(false, "TODO: AggregateEntityImpl: Handle talker capability"); - //_talkerCapabilityDelegate = std::make_unique(entityID); +#pragma message("set delegate!") + //_talkerCapabilityDelegate = std::make_unique(getProtocolInterface(), controllerDelegate, *this, entityID); + //(entityID); } // Register observer @@ -899,7 +901,7 @@ void AggregateEntityImpl::setControllerDelegate(controller::Delegate* const dele { _listenerCapabilityDelegate->onListenerDelegateChanged(delegate); } -} +}*/ void AggregateEntityImpl::setTalkerDelegate(talker::Delegate* const delegate) noexcept { @@ -907,7 +909,7 @@ void AggregateEntityImpl::setTalkerDelegate(talker::Delegate* const delegate) no { _talkerCapabilityDelegate->onTalkerDelegateChanged(delegate); } -}*/ +} /* ************************************************************************** */ /* protocol::ProtocolInterface::Observer overrides */ diff --git a/src/entity/aggregateEntityImpl.hpp b/src/entity/aggregateEntityImpl.hpp index 429a9479..334b346c 100644 --- a/src/entity/aggregateEntityImpl.hpp +++ b/src/entity/aggregateEntityImpl.hpp @@ -170,7 +170,7 @@ class AggregateEntityImpl : public LocalEntityImpl /* ************************************************************************** */ virtual void setControllerDelegate(controller::Delegate* const delegate) noexcept override; //virtual void setListenerDelegate(listener::Delegate* const delegate) noexcept override; - //virtual void setTalkerDelegate(talker::Delegate* const delegate) noexcept override; + virtual void setTalkerDelegate(talker::Delegate* const delegate) noexcept override; /* ************************************************************************** */ /* protocol::ProtocolInterface::Observer overrides */ diff --git a/src/entity/controllerCapabilityDelegate.cpp b/src/entity/controllerCapabilityDelegate.cpp index 4146857d..a3990431 100644 --- a/src/entity/controllerCapabilityDelegate.cpp +++ b/src/entity/controllerCapabilityDelegate.cpp @@ -1457,7 +1457,7 @@ void CapabilityDelegate::onControllerDelegateChanged(controller::Delegate* const //void CapabilityDelegate::onListenerDelegateChanged(listener::Delegate* const delegate) noexcept {} -//void CapabilityDelegate::onTalkerDelegateChanged(talker::Delegate* const delegate) noexcept {} +void CapabilityDelegate::onTalkerDelegateChanged(talker::Delegate* const delegate) noexcept {} void CapabilityDelegate::onTransportError(protocol::ProtocolInterface* const /*pi*/) noexcept { diff --git a/src/entity/controllerCapabilityDelegate.hpp b/src/entity/controllerCapabilityDelegate.hpp index 627c077c..aaa643f1 100644 --- a/src/entity/controllerCapabilityDelegate.hpp +++ b/src/entity/controllerCapabilityDelegate.hpp @@ -25,6 +25,7 @@ #pragma once #include "la/avdecc/internals/controllerEntity.hpp" +#include "la/avdecc/internals/talkerEntity.hpp" #include "entityImpl.hpp" @@ -176,7 +177,7 @@ class CapabilityDelegate final : public entity::CapabilityDelegate /* **** Global notifications **** */ virtual void onControllerDelegateChanged(controller::Delegate* const delegate) noexcept override; //virtual void onListenerDelegateChanged(listener::Delegate* const delegate) noexcept override; - //virtual void onTalkerDelegateChanged(talker::Delegate* const delegate) noexcept override; + virtual void onTalkerDelegateChanged(talker::Delegate* const delegate) noexcept override; virtual void onTransportError(protocol::ProtocolInterface* const pi) noexcept override; /* **** Discovery notifications **** */ virtual void onLocalEntityOnline(protocol::ProtocolInterface* const pi, Entity const& entity) noexcept override; diff --git a/src/entity/controllerEntityImpl.cpp b/src/entity/controllerEntityImpl.cpp index fcdbdac4..58fe56d6 100644 --- a/src/entity/controllerEntityImpl.cpp +++ b/src/entity/controllerEntityImpl.cpp @@ -27,6 +27,7 @@ #include "logHelper.hpp" #include "controllerEntityImpl.hpp" #include "controllerCapabilityDelegate.hpp" +#include "talkerCapabilityDelegate.hpp" #include #include diff --git a/src/entity/controllerEntityImpl.hpp b/src/entity/controllerEntityImpl.hpp index d2360589..2c930c9d 100644 --- a/src/entity/controllerEntityImpl.hpp +++ b/src/entity/controllerEntityImpl.hpp @@ -25,6 +25,7 @@ #pragma once #include "la/avdecc/internals/controllerEntity.hpp" +#include "la/avdecc/internals/talkerEntity.hpp" #include "la/avdecc/internals/protocolInterface.hpp" #include "la/avdecc/internals/protocolAemAecpdu.hpp" #include "la/avdecc/internals/protocolAaAecpdu.hpp" diff --git a/src/entity/entityImpl.hpp b/src/entity/entityImpl.hpp index e8a937c9..fd1a3459 100644 --- a/src/entity/entityImpl.hpp +++ b/src/entity/entityImpl.hpp @@ -26,6 +26,8 @@ #include "la/avdecc/internals/entity.hpp" #include "la/avdecc/internals/entityModel.hpp" +#include "la/avdecc/internals/talkerEntity.hpp" +#include "la/avdecc/internals/controllerEntity.hpp" #include "la/avdecc/internals/protocolInterface.hpp" #include "la/avdecc/internals/protocolAemAecpdu.hpp" #include "la/avdecc/internals/protocolAaAecpdu.hpp" @@ -193,9 +195,7 @@ class LocalEntityImpl : public SuperClass, public protocol::ProtocolInterface::O if (handler) return std::bind(handler, object, std::forward(params)...); // No handler specified, return an empty handler - return [](LocalEntity::AemCommandStatus const /*error*/) - { - }; + return [](LocalEntity::AemCommandStatus const /*error*/) {}; } template static inline OnAaAECPErrorCallback makeAaAECPErrorHandler(T const& handler, Object const* const object, Ts&&... params) noexcept @@ -203,9 +203,7 @@ class LocalEntityImpl : public SuperClass, public protocol::ProtocolInterface::O if (handler) return std::bind(handler, object, std::forward(params)...); // No handler specified, return an empty handler - return [](LocalEntity::AaCommandStatus const /*error*/) - { - }; + return [](LocalEntity::AaCommandStatus const /*error*/) {}; } template static inline OnMvuAECPErrorCallback makeMvuAECPErrorHandler(T const& handler, Object const* const object, Ts&&... params) noexcept @@ -213,9 +211,7 @@ class LocalEntityImpl : public SuperClass, public protocol::ProtocolInterface::O if (handler) return std::bind(handler, object, std::forward(params)...); // No handler specified, return an empty handler - return [](LocalEntity::MvuCommandStatus const /*error*/) - { - }; + return [](LocalEntity::MvuCommandStatus const /*error*/) {}; } template static inline OnACMPErrorCallback makeACMPErrorHandler(T const& handler, Object const* const object, Ts&&... params) noexcept @@ -223,9 +219,7 @@ class LocalEntityImpl : public SuperClass, public protocol::ProtocolInterface::O if (handler) return std::bind(handler, object, std::forward(params)...); // No handler specified, return an empty handler - return [](LocalEntity::ControlStatus const /*error*/) - { - }; + return [](LocalEntity::ControlStatus const /*error*/) {}; } static LocalEntity::AemCommandStatus convertErrorToAemCommandStatus(protocol::ProtocolInterface::Error const error) noexcept; @@ -533,7 +527,7 @@ class CapabilityDelegate /* **** Global notifications **** */ virtual void onControllerDelegateChanged(controller::Delegate* const delegate) noexcept = 0; //virtual void onListenerDelegateChanged(listener::Delegate* const delegate) noexcept = 0; - //virtual void onTalkerDelegateChanged(talker::Delegate* const delegate) noexcept = 0; + virtual void onTalkerDelegateChanged(talker::Delegate* const delegate) noexcept = 0; virtual void onTransportError(protocol::ProtocolInterface* const /*pi*/) noexcept {} /* **** Discovery notifications **** */ virtual void onLocalEntityOnline(protocol::ProtocolInterface* const /*pi*/, Entity const& /*entity*/) noexcept {} diff --git a/src/entity/talkerCapabilityDelegate.cpp b/src/entity/talkerCapabilityDelegate.cpp new file mode 100644 index 00000000..a026e774 --- /dev/null +++ b/src/entity/talkerCapabilityDelegate.cpp @@ -0,0 +1,3495 @@ +/* +* Copyright (C) 2016-2020, L-Acoustics and its contributors + +* This file is part of LA_avdecc. + +* LA_avdecc is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. + +* LA_avdecc is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. + +* You should have received a copy of the GNU Lesser General Public License +* along with LA_avdecc. If not, see . +*/ + +/** +* @file talkerCapabilityDelegate.cpp +* @author Christophe Calmejane +*/ + +#include "la/avdecc/utils.hpp" + +#include "talkerCapabilityDelegate.hpp" +#include "controllerCapabilityDelegate.hpp" +#include "protocol/protocolAemPayloads.hpp" +#include "protocol/protocolMvuPayloads.hpp" + +#include +#include +#include + +namespace la +{ +namespace avdecc +{ +namespace entity +{ +namespace talker +{ +/* ************************************************************************** */ +/* Static variables used for bindings */ +/* ************************************************************************** */ +static model::AudioMappings const s_emptyMappings{}; // Empty AudioMappings used by timeout callback (needs a ref to an AudioMappings) +static model::StreamInfo const s_emptyStreamInfo{}; // Empty StreamInfo used by timeout callback (needs a ref to a StreamInfo) +static model::AvbInfo const s_emptyAvbInfo{}; // Empty AvbInfo used by timeout callback (needs a ref to an AvbInfo) +static model::AsPath const s_emptyAsPath{}; // Empty AsPath used by timeout callback (needs a ref to an AsPath) +static model::AvdeccFixedString const s_emptyAvdeccFixedString{}; // Empty AvdeccFixedString used by timeout callback (needs a ref to a std::string) +static model::MilanInfo const s_emptyMilanInfo{}; // Empty MilanInfo used by timeout callback (need a ref to a MilanInfo) + +/* ************************************************************************** */ +/* Exceptions */ +/* ************************************************************************** */ +class InvalidDescriptorTypeException final : public Exception +{ +public: + InvalidDescriptorTypeException() + : Exception("Invalid DescriptorType") + { + } +}; + +/* ************************************************************************** */ +/* CapabilityDelegate life cycle */ +/* ************************************************************************** */ +CapabilityDelegate::CapabilityDelegate(protocol::ProtocolInterface* const protocolInterface, talker::Delegate* talkerDelegate, Interface& talkerInterface, UniqueIdentifier const talkerID) noexcept + : _protocolInterface(protocolInterface) + , _talkerDelegate(talkerDelegate) + , _talkerInterface(talkerInterface) + , _talkerID(talkerID) +{ +} + +CapabilityDelegate::~CapabilityDelegate() noexcept {} + +/* ************************************************************************** */ +/* Talker methods */ +/* ************************************************************************** */ +/* Discovery Protocol (ADP) */ +/* Enumeration and Control Protocol (AECP) AEM */ +void CapabilityDelegate::acquireEntity(UniqueIdentifier const targetEntityID, bool const isPersistent, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, Interface::AcquireEntityHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeAcquireEntityCommand(isPersistent ? protocol::AemAcquireEntityFlags::Persistent : protocol::AemAcquireEntityFlags::None, UniqueIdentifier::getNullUniqueIdentifier(), descriptorType, descriptorIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, UniqueIdentifier::getNullUniqueIdentifier(), descriptorType, descriptorIndex); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::AcquireEntity, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize acquireEntity: {}", e.what()); + } +} + +void CapabilityDelegate::releaseEntity(UniqueIdentifier const targetEntityID, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, Interface::ReleaseEntityHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeAcquireEntityCommand(protocol::AemAcquireEntityFlags::Release, UniqueIdentifier::getNullUniqueIdentifier(), descriptorType, descriptorIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, UniqueIdentifier::getNullUniqueIdentifier(), descriptorType, descriptorIndex); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::AcquireEntity, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize releaseEntity: {}", e.what()); + } +} + +void CapabilityDelegate::lockEntity(UniqueIdentifier const targetEntityID, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, Interface::LockEntityHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeLockEntityCommand(protocol::AemLockEntityFlags::None, UniqueIdentifier::getNullUniqueIdentifier(), descriptorType, descriptorIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, UniqueIdentifier::getNullUniqueIdentifier(), descriptorType, descriptorIndex); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::LockEntity, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize lockEntity: {}", e.what()); + } +} + +void CapabilityDelegate::unlockEntity(UniqueIdentifier const targetEntityID, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, Interface::UnlockEntityHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeLockEntityCommand(protocol::AemLockEntityFlags::Unlock, UniqueIdentifier::getNullUniqueIdentifier(), descriptorType, descriptorIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, UniqueIdentifier::getNullUniqueIdentifier(), descriptorType, descriptorIndex); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::LockEntity, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize unlockEntity: {}", e.what()); + } +} + +void CapabilityDelegate::queryEntityAvailable(UniqueIdentifier const targetEntityID, Interface::QueryEntityAvailableHandler const& handler) const noexcept +{ + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1); + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::EntityAvailable, nullptr, 0, errorCallback, handler); +} + +void CapabilityDelegate::queryTalkerAvailable(UniqueIdentifier const targetEntityID, Interface::QueryTalkerAvailableHandler const& handler) const noexcept +{ + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1); + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ControllerAvailable, nullptr, 0, errorCallback, handler); +} + +void CapabilityDelegate::registerUnsolicitedNotifications(UniqueIdentifier const targetEntityID, Interface::RegisterUnsolicitedNotificationsHandler const& handler) const noexcept +{ + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1); + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::RegisterUnsolicitedNotification, nullptr, 0, errorCallback, handler); +} + +void CapabilityDelegate::unregisterUnsolicitedNotifications(UniqueIdentifier const targetEntityID, Interface::UnregisterUnsolicitedNotificationsHandler const& handler) const noexcept +{ + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1); + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::DeregisterUnsolicitedNotification, nullptr, 0, errorCallback, handler); +} + +void CapabilityDelegate::readEntityDescriptor(UniqueIdentifier const targetEntityID, Interface::EntityDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(model::ConfigurationIndex(0u), model::DescriptorType::Entity, model::DescriptorIndex(0u)); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, model::EntityDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readEntityDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readConfigurationDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, Interface::ConfigurationDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(model::ConfigurationIndex(0u), model::DescriptorType::Configuration, static_cast(configurationIndex)); // Passing configurationIndex as a DescriptorIndex is NOT an error. See 7.4.5.1 + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, model::ConfigurationDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readConfigurationDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readAudioUnitDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::AudioUnitIndex const audioUnitIndex, Interface::AudioUnitDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::AudioUnit, audioUnitIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, audioUnitIndex, model::AudioUnitDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readAudioUnitDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readStreamInputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, Interface::StreamInputDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::StreamInput, streamIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, streamIndex, model::StreamDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readStreamInputDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readStreamOutputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, Interface::StreamOutputDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::StreamOutput, streamIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, streamIndex, model::StreamDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readStreamOutputDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readJackInputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::JackIndex const jackIndex, Interface::JackInputDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::JackInput, jackIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, jackIndex, model::JackDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readJackInputDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readJackOutputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::JackIndex const jackIndex, Interface::JackOutputDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::JackOutput, jackIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, jackIndex, model::JackDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readJackOutputDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readAvbInterfaceDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::AvbInterfaceIndex const avbInterfaceIndex, Interface::AvbInterfaceDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::AvbInterface, avbInterfaceIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, avbInterfaceIndex, model::AvbInterfaceDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readAvbInterfaceDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readClockSourceDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClockSourceIndex const clockSourceIndex, Interface::ClockSourceDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::ClockSource, clockSourceIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, clockSourceIndex, model::ClockSourceDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readClockSourceDescriptor: '}", e.what()); + } +} + +void CapabilityDelegate::readMemoryObjectDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::MemoryObjectIndex const memoryObjectIndex, Interface::MemoryObjectDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::MemoryObject, memoryObjectIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, memoryObjectIndex, model::MemoryObjectDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readMemoryObjectDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readLocaleDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::LocaleIndex const localeIndex, Interface::LocaleDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::Locale, localeIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, localeIndex, model::LocaleDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readLocaleDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readStringsDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StringsIndex const stringsIndex, Interface::StringsDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::Strings, stringsIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, stringsIndex, model::StringsDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readStringsDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readStreamPortInputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamPortIndex const streamPortIndex, Interface::StreamPortInputDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::StreamPortInput, streamPortIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, streamPortIndex, model::StreamPortDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readStreamPortInputDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readStreamPortOutputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamPortIndex const streamPortIndex, Interface::StreamPortOutputDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::StreamPortOutput, streamPortIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, streamPortIndex, model::StreamPortDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readStreamPortOutputDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readExternalPortInputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ExternalPortIndex const externalPortIndex, Interface::ExternalPortInputDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::ExternalPortInput, externalPortIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, externalPortIndex, model::ExternalPortDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readExternalPortInputDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readExternalPortOutputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ExternalPortIndex const externalPortIndex, Interface::ExternalPortOutputDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::ExternalPortOutput, externalPortIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, externalPortIndex, model::ExternalPortDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readExternalPortInputDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readInternalPortInputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::InternalPortIndex const internalPortIndex, Interface::InternalPortInputDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::InternalPortInput, internalPortIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, internalPortIndex, model::InternalPortDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readInternalPortInputDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readInternalPortOutputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::InternalPortIndex const internalPortIndex, Interface::InternalPortOutputDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::InternalPortOutput, internalPortIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, internalPortIndex, model::InternalPortDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readInternalPortOutputDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readAudioClusterDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClusterIndex const clusterIndex, Interface::AudioClusterDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::AudioCluster, clusterIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, clusterIndex, model::AudioClusterDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readAudioClusterDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readAudioMapDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::MapIndex const mapIndex, Interface::AudioMapDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::AudioMap, mapIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, mapIndex, model::AudioMapDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readAudioMapDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::readClockDomainDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClockDomainIndex const clockDomainIndex, Interface::ClockDomainDescriptorHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeReadDescriptorCommand(configurationIndex, model::DescriptorType::ClockDomain, clockDomainIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, clockDomainIndex, model::ClockDomainDescriptor{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::ReadDescriptor, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize readClockDomainDescriptor: {}", e.what()); + } +} + +void CapabilityDelegate::setConfiguration(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, Interface::SetConfigurationHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetConfigurationCommand(configurationIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetConfiguration, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setConfiguration: {}", e.what()); + } +} + +void CapabilityDelegate::getConfiguration(UniqueIdentifier const targetEntityID, Interface::GetConfigurationHandler const& handler) const noexcept +{ + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, model::ConfigurationIndex{ 0u }); + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetConfiguration, nullptr, 0, errorCallback, handler); +} + +void CapabilityDelegate::setStreamInputFormat(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, model::StreamFormat const streamFormat, Interface::SetStreamInputFormatHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetStreamFormatCommand(model::DescriptorType::StreamInput, streamIndex, streamFormat); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamIndex, model::StreamFormat()); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetStreamFormat, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setStreamInputFormat: {}", e.what()); + } +} + +void CapabilityDelegate::getStreamInputFormat(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::GetStreamInputFormatHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetStreamFormatCommand(model::DescriptorType::StreamInput, streamIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamIndex, model::StreamFormat()); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetStreamFormat, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getStreamInputFormat: {}", e.what()); + } +} + +void CapabilityDelegate::setStreamOutputFormat(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, model::StreamFormat const streamFormat, Interface::SetStreamOutputFormatHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetStreamFormatCommand(model::DescriptorType::StreamOutput, streamIndex, streamFormat); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamIndex, model::StreamFormat()); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetStreamFormat, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setStreamOutputFormat: {}", e.what()); + } +} + +void CapabilityDelegate::getStreamOutputFormat(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::GetStreamOutputFormatHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetStreamFormatCommand(model::DescriptorType::StreamOutput, streamIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamIndex, model::StreamFormat()); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetStreamFormat, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getStreamOutputFormat: {}", e.what()); + } +} + +void CapabilityDelegate::getStreamPortInputAudioMap(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::MapIndex const mapIndex, Interface::GetStreamPortInputAudioMapHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetAudioMapCommand(model::DescriptorType::StreamPortInput, streamPortIndex, mapIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamPortIndex, model::MapIndex(0), mapIndex, s_emptyMappings); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetAudioMap, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getStreamInputAudioMap: {}", e.what()); + } +} + +void CapabilityDelegate::getStreamPortOutputAudioMap(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::MapIndex const mapIndex, Interface::GetStreamPortOutputAudioMapHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetAudioMapCommand(model::DescriptorType::StreamPortOutput, streamPortIndex, mapIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamPortIndex, model::MapIndex(0), mapIndex, s_emptyMappings); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetAudioMap, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getStreamOutputAudioMap: {}", e.what()); + } +} + +void CapabilityDelegate::addStreamPortInputAudioMappings(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::AudioMappings const& mappings, Interface::AddStreamPortInputAudioMappingsHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeAddAudioMappingsCommand(model::DescriptorType::StreamPortInput, streamPortIndex, mappings); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamPortIndex, s_emptyMappings); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::AddAudioMappings, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize addStreamInputAudioMappings: {}", e.what()); + } +} + +void CapabilityDelegate::addStreamPortOutputAudioMappings(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::AudioMappings const& mappings, Interface::AddStreamPortOutputAudioMappingsHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeAddAudioMappingsCommand(model::DescriptorType::StreamPortOutput, streamPortIndex, mappings); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamPortIndex, s_emptyMappings); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::AddAudioMappings, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize addStreamOutputAudioMappings: {}", e.what()); + } +} + +void CapabilityDelegate::removeStreamPortInputAudioMappings(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::AudioMappings const& mappings, Interface::RemoveStreamPortInputAudioMappingsHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeRemoveAudioMappingsCommand(model::DescriptorType::StreamPortInput, streamPortIndex, mappings); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamPortIndex, s_emptyMappings); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::RemoveAudioMappings, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize removeStreamInputAudioMappings: {}", e.what()); + } +} + +void CapabilityDelegate::removeStreamPortOutputAudioMappings(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::AudioMappings const& mappings, Interface::RemoveStreamPortOutputAudioMappingsHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeRemoveAudioMappingsCommand(model::DescriptorType::StreamPortOutput, streamPortIndex, mappings); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamPortIndex, s_emptyMappings); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::RemoveAudioMappings, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize removeStreamOutputAudioMappings: {}", e.what()); + } +} + +void CapabilityDelegate::setStreamInputInfo(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, model::StreamInfo const& info, Interface::SetStreamInputInfoHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetStreamInfoCommand(model::DescriptorType::StreamInput, streamIndex, info); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamIndex, s_emptyStreamInfo); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetStreamInfo, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setStreamInputInfo: {}", e.what()); + } +} + +void CapabilityDelegate::setStreamOutputInfo(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, model::StreamInfo const& info, Interface::SetStreamOutputInfoHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetStreamInfoCommand(model::DescriptorType::StreamOutput, streamIndex, info); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamIndex, s_emptyStreamInfo); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetStreamInfo, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setStreamOutputInfo: {}", e.what()); + } +} + +void CapabilityDelegate::getStreamInputInfo(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::GetStreamInputInfoHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetStreamInfoCommand(model::DescriptorType::StreamInput, streamIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamIndex, s_emptyStreamInfo); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetStreamInfo, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getStreamInputInfo: {}", e.what()); + } +} + +void CapabilityDelegate::getStreamOutputInfo(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::GetStreamOutputInfoHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetStreamInfoCommand(model::DescriptorType::StreamOutput, streamIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamIndex, s_emptyStreamInfo); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetStreamInfo, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getStreamOutputInfo: {}", e.what()); + } +} + +void CapabilityDelegate::setEntityName(UniqueIdentifier const targetEntityID, model::AvdeccFixedString const& entityName, Interface::SetEntityNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetNameCommand(model::DescriptorType::Entity, 0, 0, 0, entityName); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setName: {}", e.what()); + } +} + +void CapabilityDelegate::getEntityName(UniqueIdentifier const targetEntityID, Interface::GetEntityNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetNameCommand(model::DescriptorType::Entity, 0, 0, 0); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getName: {}", e.what()); + } +} + +void CapabilityDelegate::setEntityGroupName(UniqueIdentifier const targetEntityID, model::AvdeccFixedString const& entityGroupName, Interface::SetEntityGroupNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetNameCommand(model::DescriptorType::Entity, 0, 1, 0, entityGroupName); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setName: {}", e.what()); + } +} + +void CapabilityDelegate::getEntityGroupName(UniqueIdentifier const targetEntityID, Interface::GetEntityGroupNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetNameCommand(model::DescriptorType::Entity, 0, 1, 0); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getName: {}", e.what()); + } +} + +void CapabilityDelegate::setConfigurationName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::AvdeccFixedString const& configurationName, Interface::SetConfigurationNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetNameCommand(model::DescriptorType::Configuration, configurationIndex, 0, 0, configurationName); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setName: {}", e.what()); + } +} + +void CapabilityDelegate::getConfigurationName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, Interface::GetConfigurationNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetNameCommand(model::DescriptorType::Configuration, configurationIndex, 0, 0); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getName: {}", e.what()); + } +} + +void CapabilityDelegate::setAudioUnitName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::AudioUnitIndex const audioUnitIndex, model::AvdeccFixedString const& audioUnitName, Interface::SetAudioUnitNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetNameCommand(model::DescriptorType::AudioUnit, audioUnitIndex, 0, configurationIndex, audioUnitName); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, audioUnitIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setName: {}", e.what()); + } +} + +void CapabilityDelegate::getAudioUnitName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const audioUnitIndex, Interface::GetAudioUnitNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetNameCommand(model::DescriptorType::AudioUnit, audioUnitIndex, 0, configurationIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, audioUnitIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getName: {}", e.what()); + } +} + +void CapabilityDelegate::setStreamInputName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, model::AvdeccFixedString const& streamInputName, Interface::SetStreamInputNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetNameCommand(model::DescriptorType::StreamInput, streamIndex, 0, configurationIndex, streamInputName); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, streamIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setName: {}", e.what()); + } +} + +void CapabilityDelegate::getStreamInputName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, Interface::GetStreamInputNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetNameCommand(model::DescriptorType::StreamInput, streamIndex, 0, configurationIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, streamIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getName: {}", e.what()); + } +} + +void CapabilityDelegate::setStreamOutputName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, model::AvdeccFixedString const& streamOutputName, Interface::SetStreamOutputNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetNameCommand(model::DescriptorType::StreamOutput, streamIndex, 0, configurationIndex, streamOutputName); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, streamIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setName: {}", e.what()); + } +} + +void CapabilityDelegate::getStreamOutputName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, Interface::GetStreamOutputNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetNameCommand(model::DescriptorType::StreamOutput, streamIndex, 0, configurationIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, streamIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getName: {}", e.what()); + } +} + +void CapabilityDelegate::setAvbInterfaceName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::AvbInterfaceIndex const avbInterfaceIndex, model::AvdeccFixedString const& avbInterfaceName, Interface::SetAvbInterfaceNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetNameCommand(model::DescriptorType::AvbInterface, avbInterfaceIndex, 0, configurationIndex, avbInterfaceName); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, avbInterfaceIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setName: {}", e.what()); + } +} + +void CapabilityDelegate::getAvbInterfaceName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const avbInterfaceIndex, Interface::GetAvbInterfaceNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetNameCommand(model::DescriptorType::AvbInterface, avbInterfaceIndex, 0, configurationIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, avbInterfaceIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getName: {}", e.what()); + } +} + +void CapabilityDelegate::setClockSourceName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClockSourceIndex const clockSourceIndex, model::AvdeccFixedString const& clockSourceName, Interface::SetClockSourceNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetNameCommand(model::DescriptorType::ClockSource, clockSourceIndex, 0, configurationIndex, clockSourceName); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, clockSourceIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setName: {}", e.what()); + } +} + +void CapabilityDelegate::getClockSourceName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const clockSourceIndex, Interface::GetClockSourceNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetNameCommand(model::DescriptorType::ClockSource, clockSourceIndex, 0, configurationIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, clockSourceIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getName: {}", e.what()); + } +} + +void CapabilityDelegate::setMemoryObjectName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::MemoryObjectIndex const memoryObjectIndex, model::AvdeccFixedString const& memoryObjectName, Interface::SetMemoryObjectNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetNameCommand(model::DescriptorType::MemoryObject, memoryObjectIndex, 0, configurationIndex, memoryObjectName); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, memoryObjectIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setName: {}", e.what()); + } +} + +void CapabilityDelegate::getMemoryObjectName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const memoryObjectIndex, Interface::GetMemoryObjectNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetNameCommand(model::DescriptorType::MemoryObject, memoryObjectIndex, 0, configurationIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, memoryObjectIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getName: {}", e.what()); + } +} + +void CapabilityDelegate::setAudioClusterName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClusterIndex const audioClusterIndex, model::AvdeccFixedString const& audioClusterName, Interface::SetAudioClusterNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetNameCommand(model::DescriptorType::AudioCluster, audioClusterIndex, 0, configurationIndex, audioClusterName); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, audioClusterIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setName: {}", e.what()); + } +} + +void CapabilityDelegate::getAudioClusterName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const audioClusterIndex, Interface::GetAudioClusterNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetNameCommand(model::DescriptorType::AudioCluster, audioClusterIndex, 0, configurationIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, audioClusterIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getName: {}", e.what()); + } +} + +void CapabilityDelegate::setClockDomainName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClockDomainIndex const clockDomainIndex, model::AvdeccFixedString const& clockDomainName, Interface::SetClockDomainNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetNameCommand(model::DescriptorType::ClockDomain, clockDomainIndex, 0, configurationIndex, clockDomainName); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, clockDomainIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setName: {}", e.what()); + } +} + +void CapabilityDelegate::getClockDomainName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const clockDomainIndex, Interface::GetClockDomainNameHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetNameCommand(model::DescriptorType::ClockDomain, clockDomainIndex, 0, configurationIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, clockDomainIndex, s_emptyAvdeccFixedString); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetName, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getName: {}", e.what()); + } +} + +void CapabilityDelegate::setAudioUnitSamplingRate(UniqueIdentifier const targetEntityID, model::AudioUnitIndex const audioUnitIndex, model::SamplingRate const samplingRate, Interface::SetAudioUnitSamplingRateHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetSamplingRateCommand(model::DescriptorType::AudioUnit, audioUnitIndex, samplingRate); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, audioUnitIndex, model::SamplingRate::getNullSamplingRate()); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetSamplingRate, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setAudioUnitSamplingRate: {}", e.what()); + } +} + +void CapabilityDelegate::getAudioUnitSamplingRate(UniqueIdentifier const targetEntityID, model::AudioUnitIndex const audioUnitIndex, Interface::GetAudioUnitSamplingRateHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetSamplingRateCommand(model::DescriptorType::AudioUnit, audioUnitIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, audioUnitIndex, model::SamplingRate::getNullSamplingRate()); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetSamplingRate, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getAudioUnitSamplingRate: {}", e.what()); + } +} + +void CapabilityDelegate::setVideoClusterSamplingRate(UniqueIdentifier const targetEntityID, model::ClusterIndex const videoClusterIndex, model::SamplingRate const samplingRate, Interface::SetVideoClusterSamplingRateHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetSamplingRateCommand(model::DescriptorType::VideoCluster, videoClusterIndex, samplingRate); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, videoClusterIndex, model::SamplingRate::getNullSamplingRate()); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetSamplingRate, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setVideoClusterSamplingRate: {}", e.what()); + } +} + +void CapabilityDelegate::getVideoClusterSamplingRate(UniqueIdentifier const targetEntityID, model::ClusterIndex const videoClusterIndex, Interface::GetVideoClusterSamplingRateHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetSamplingRateCommand(model::DescriptorType::VideoCluster, videoClusterIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, videoClusterIndex, model::SamplingRate::getNullSamplingRate()); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetSamplingRate, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getVideoClusterSamplingRate: {}", e.what()); + } +} + +void CapabilityDelegate::setSensorClusterSamplingRate(UniqueIdentifier const targetEntityID, model::ClusterIndex const sensorClusterIndex, model::SamplingRate const samplingRate, Interface::SetSensorClusterSamplingRateHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetSamplingRateCommand(model::DescriptorType::SensorCluster, sensorClusterIndex, samplingRate); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, sensorClusterIndex, model::SamplingRate::getNullSamplingRate()); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetSamplingRate, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setSensorClusterSamplingRate: {}", e.what()); + } +} + +void CapabilityDelegate::getSensorClusterSamplingRate(UniqueIdentifier const targetEntityID, model::ClusterIndex const sensorClusterIndex, Interface::GetSensorClusterSamplingRateHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetSamplingRateCommand(model::DescriptorType::SensorCluster, sensorClusterIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, sensorClusterIndex, model::SamplingRate::getNullSamplingRate()); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetSamplingRate, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getSensorClusterSamplingRate: {}", e.what()); + } +} + +void CapabilityDelegate::setClockSource(UniqueIdentifier const targetEntityID, model::ClockDomainIndex const clockDomainIndex, model::ClockSourceIndex const clockSourceIndex, Interface::SetClockSourceHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetClockSourceCommand(model::DescriptorType::ClockDomain, clockDomainIndex, clockSourceIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, clockDomainIndex, model::ClockSourceIndex{ 0u }); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetClockSource, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setClockSource: {}", e.what()); + } +} + +void CapabilityDelegate::getClockSource(UniqueIdentifier const targetEntityID, model::ClockDomainIndex const clockDomainIndex, Interface::GetClockSourceHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetClockSourceCommand(model::DescriptorType::ClockDomain, clockDomainIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, clockDomainIndex, model::ClockSourceIndex{ 0u }); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetClockSource, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getClockSource: {}", e.what()); + } +} + +void CapabilityDelegate::startStreamInput(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::StartStreamInputHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeStartStreamingCommand(model::DescriptorType::StreamInput, streamIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamIndex); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::StartStreaming, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize startStreamInput: {}", e.what()); + } +} + +void CapabilityDelegate::startStreamOutput(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::StartStreamOutputHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeStartStreamingCommand(model::DescriptorType::StreamOutput, streamIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamIndex); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::StartStreaming, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize startStreamOutput: {}", e.what()); + } +} + +void CapabilityDelegate::stopStreamInput(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::StopStreamInputHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeStopStreamingCommand(model::DescriptorType::StreamInput, streamIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamIndex); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::StopStreaming, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize stopStreamInput: {}", e.what()); + } +} + +void CapabilityDelegate::stopStreamOutput(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::StopStreamOutputHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeStopStreamingCommand(model::DescriptorType::StreamOutput, streamIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamIndex); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::StopStreaming, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize stopStreamOutput: {}", e.what()); + } +} + +void CapabilityDelegate::getAvbInfo(UniqueIdentifier const targetEntityID, model::AvbInterfaceIndex const avbInterfaceIndex, Interface::GetAvbInfoHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetAvbInfoCommand(model::DescriptorType::AvbInterface, avbInterfaceIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, avbInterfaceIndex, s_emptyAvbInfo); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetAvbInfo, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getAvbInfo: {}", e.what()); + } +} + +void CapabilityDelegate::getAsPath(UniqueIdentifier const targetEntityID, model::AvbInterfaceIndex const avbInterfaceIndex, Interface::GetAsPathHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetAsPathCommand(avbInterfaceIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, avbInterfaceIndex, s_emptyAsPath); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetAsPath, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getAsPath: {}", e.what()); + } +} + +void CapabilityDelegate::getEntityCounters(UniqueIdentifier const targetEntityID, Interface::GetEntityCountersHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetCountersCommand(model::DescriptorType::Entity, 0); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, EntityCounterValidFlags{}, model::DescriptorCounters{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetCounters, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getEntityCounters: {}", e.what()); + } +} + +void CapabilityDelegate::getAvbInterfaceCounters(UniqueIdentifier const targetEntityID, model::AvbInterfaceIndex const avbInterfaceIndex, Interface::GetAvbInterfaceCountersHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetCountersCommand(model::DescriptorType::AvbInterface, avbInterfaceIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, avbInterfaceIndex, AvbInterfaceCounterValidFlags{}, model::DescriptorCounters{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetCounters, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getAvbInterfaceCounters: {}", e.what()); + } +} + +void CapabilityDelegate::getClockDomainCounters(UniqueIdentifier const targetEntityID, model::ClockDomainIndex const clockDomainIndex, Interface::GetClockDomainCountersHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetCountersCommand(model::DescriptorType::ClockDomain, clockDomainIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, clockDomainIndex, ClockDomainCounterValidFlags{}, model::DescriptorCounters{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetCounters, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getClockDomainCounters: {}", e.what()); + } +} + +void CapabilityDelegate::getStreamInputCounters(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::GetStreamInputCountersHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetCountersCommand(model::DescriptorType::StreamInput, streamIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamIndex, StreamInputCounterValidFlags{}, model::DescriptorCounters{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetCounters, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getStreamInputCounters: {}", e.what()); + } +} + +void CapabilityDelegate::getStreamOutputCounters(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::GetStreamOutputCountersHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetCountersCommand(model::DescriptorType::StreamOutput, streamIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, streamIndex, StreamOutputCounterValidFlags{}, model::DescriptorCounters{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetCounters, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getStreamOutputCounters: {}", e.what()); + } +} + +void CapabilityDelegate::startOperation(UniqueIdentifier const targetEntityID, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, model::MemoryObjectOperationType const operationType, MemoryBuffer const& memoryBuffer, Interface::StartOperationHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeStartOperationCommand(descriptorType, descriptorIndex, model::OperationID{ 0u }, operationType, memoryBuffer); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, descriptorType, descriptorIndex, model::OperationID{ 0u }, operationType, MemoryBuffer{}); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::StartOperation, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize startOperation: {}", e.what()); + } +} + +void CapabilityDelegate::abortOperation(UniqueIdentifier const targetEntityID, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, model::OperationID const operationID, Interface::AbortOperationHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeAbortOperationCommand(descriptorType, descriptorIndex, operationID); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, descriptorType, descriptorIndex, operationID); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::AbortOperation, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize abortOperation: {}", e.what()); + } +} + +void CapabilityDelegate::setMemoryObjectLength(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::MemoryObjectIndex const memoryObjectIndex, std::uint64_t const length, Interface::SetMemoryObjectLengthHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeSetMemoryObjectLengthCommand(configurationIndex, memoryObjectIndex, length); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, memoryObjectIndex, std::uint64_t{ 0u }); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::SetMemoryObjectLength, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize setMemoryObjectLength: {}", e.what()); + } +} + +void CapabilityDelegate::getMemoryObjectLength(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::MemoryObjectIndex const memoryObjectIndex, Interface::GetMemoryObjectLengthHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::aemPayload::serializeGetMemoryObjectLengthCommand(configurationIndex, memoryObjectIndex); + auto const errorCallback = LocalEntityImpl<>::makeAemAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, configurationIndex, memoryObjectIndex, std::uint64_t{ 0u }); + + sendAemAecpCommand(targetEntityID, protocol::AemCommandType::GetMemoryObjectLength, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getMemoryObjectLength: {}", e.what()); + } +} + +/* Enumeration and Control Protocol (AECP) AA */ +void CapabilityDelegate::addressAccess(UniqueIdentifier const targetEntityID, addressAccess::Tlvs const& tlvs, Interface::AddressAccessHandler const& handler) const noexcept +{ + auto const errorCallback = LocalEntityImpl<>::makeAaAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, addressAccess::Tlvs{}); + sendAaAecpCommand(targetEntityID, tlvs, errorCallback, handler); +} + +/* Enumeration and Control Protocol (AECP) MVU (Milan Vendor Unique) */ +void CapabilityDelegate::getMilanInfo(UniqueIdentifier const targetEntityID, Interface::GetMilanInfoHandler const& handler) const noexcept +{ + try + { + auto const ser = protocol::mvuPayload::serializeGetMilanInfoCommand(); + auto const errorCallback = LocalEntityImpl<>::makeMvuAECPErrorHandler(handler, &_talkerInterface, targetEntityID, std::placeholders::_1, s_emptyMilanInfo); + + sendMvuAecpCommand(targetEntityID, protocol::MvuCommandType::GetMilanInfo, ser.data(), ser.size(), errorCallback, handler); + } + catch ([[maybe_unused]] std::exception const& e) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetEntityID, "Failed to serialize getMilanInfo: {}", e.what()); + } +} + +/* Connection Management Protocol (ACMP) */ +void CapabilityDelegate::connectStream(model::StreamIdentification const& talkerStream, model::StreamIdentification const& listenerStream, Interface::ConnectStreamHandler const& handler) const noexcept +{ + auto const errorCallback = LocalEntityImpl<>::makeACMPErrorHandler(handler, &_talkerInterface, talkerStream, listenerStream, std::uint16_t(0), entity::ConnectionFlags{}, std::placeholders::_1); + sendAcmpCommand(protocol::AcmpMessageType::ConnectRxCommand, talkerStream.entityID, talkerStream.streamIndex, listenerStream.entityID, listenerStream.streamIndex, std::uint16_t(0), errorCallback, handler); +} + +void CapabilityDelegate::disconnectStream(model::StreamIdentification const& talkerStream, model::StreamIdentification const& listenerStream, Interface::DisconnectStreamHandler const& handler) const noexcept +{ + auto const errorCallback = LocalEntityImpl<>::makeACMPErrorHandler(handler, &_talkerInterface, talkerStream, listenerStream, std::uint16_t(0), entity::ConnectionFlags{}, std::placeholders::_1); + sendAcmpCommand(protocol::AcmpMessageType::DisconnectRxCommand, talkerStream.entityID, talkerStream.streamIndex, listenerStream.entityID, listenerStream.streamIndex, std::uint16_t(0), errorCallback, handler); +} + +void CapabilityDelegate::disconnectTalkerStream(model::StreamIdentification const& talkerStream, model::StreamIdentification const& listenerStream, Interface::DisconnectTalkerStreamHandler const& handler) const noexcept +{ + auto const errorCallback = LocalEntityImpl<>::makeACMPErrorHandler(handler, &_talkerInterface, talkerStream, listenerStream, std::uint16_t(0), entity::ConnectionFlags{}, std::placeholders::_1); + sendAcmpCommand(protocol::AcmpMessageType::DisconnectTxCommand, talkerStream.entityID, talkerStream.streamIndex, listenerStream.entityID, listenerStream.streamIndex, std::uint16_t(0), errorCallback, handler); +} + +void CapabilityDelegate::getTalkerStreamState(model::StreamIdentification const& talkerStream, Interface::GetTalkerStreamStateHandler const& handler) const noexcept +{ + auto const errorCallback = LocalEntityImpl<>::makeACMPErrorHandler(handler, &_talkerInterface, talkerStream, model::StreamIdentification{}, std::uint16_t(0), entity::ConnectionFlags{}, std::placeholders::_1); + sendAcmpCommand(protocol::AcmpMessageType::GetTxStateCommand, talkerStream.entityID, talkerStream.streamIndex, UniqueIdentifier::getNullUniqueIdentifier(), model::StreamIndex(0), std::uint16_t(0), errorCallback, handler); +} + +void CapabilityDelegate::getListenerStreamState(model::StreamIdentification const& listenerStream, Interface::GetListenerStreamStateHandler const& handler) const noexcept +{ + auto const errorCallback = LocalEntityImpl<>::makeACMPErrorHandler(handler, &_talkerInterface, model::StreamIdentification{}, listenerStream, std::uint16_t(0), entity::ConnectionFlags{}, std::placeholders::_1); + sendAcmpCommand(protocol::AcmpMessageType::GetRxStateCommand, UniqueIdentifier::getNullUniqueIdentifier(), model::StreamIndex(0), listenerStream.entityID, listenerStream.streamIndex, std::uint16_t(0), errorCallback, handler); +} + +void CapabilityDelegate::getTalkerStreamConnection(model::StreamIdentification const& talkerStream, std::uint16_t const connectionIndex, Interface::GetTalkerStreamConnectionHandler const& handler) const noexcept +{ + auto const errorCallback = LocalEntityImpl<>::makeACMPErrorHandler(handler, &_talkerInterface, talkerStream, model::StreamIdentification{}, connectionIndex, entity::ConnectionFlags{}, std::placeholders::_1); + sendAcmpCommand(protocol::AcmpMessageType::GetTxConnectionCommand, talkerStream.entityID, talkerStream.streamIndex, UniqueIdentifier::getNullUniqueIdentifier(), model::StreamIndex(0), connectionIndex, errorCallback, handler); +} + +/* ************************************************************************** */ +/* LocalEntityImpl<>::CapabilityDelegate overrides */ +/* ************************************************************************** */ +/* *** General notifications */ + +void CapabilityDelegate::onControllerDelegateChanged(controller::Delegate* const delegate) noexcept {} + +//void CapabilityDelegate::onListenerDelegateChanged(listener::Delegate* const delegate) noexcept {} + +void CapabilityDelegate::onTalkerDelegateChanged(talker::Delegate* const delegate) noexcept { +#pragma message("TODO: Protect the _controllerDelegate so it cannot be changed while it's being used (use pi's lock ?? Check for deadlocks!)") + _talkerDelegate = delegate; +} + +void CapabilityDelegate::onTransportError(protocol::ProtocolInterface* const /*pi*/) noexcept +{ + utils::invokeProtectedMethod(&talker::Delegate::onTransportError, _talkerDelegate, &_talkerInterface); +} + +/* **** Discovery notifications **** */ +void CapabilityDelegate::onLocalEntityOnline(protocol::ProtocolInterface* const pi, Entity const& entity) noexcept +{ + // Ignore ourself + if (entity.getEntityID() == _talkerID) + return; + + // Forward to RemoteEntityOnline, we handle all discovered entities the same way + onRemoteEntityOnline(pi, entity); +} + +void CapabilityDelegate::onLocalEntityOffline(protocol::ProtocolInterface* const pi, UniqueIdentifier const entityID) noexcept +{ + // Ignore ourself + if (entityID == _talkerID) + return; + + // Forward to RemoteEntityOffline, we handle all discovered entities the same way + onRemoteEntityOffline(pi, entityID); +} + +void CapabilityDelegate::onLocalEntityUpdated(protocol::ProtocolInterface* const pi, Entity const& entity) noexcept +{ + // Ignore ourself + if (entity.getEntityID() == _talkerID) + return; + + // Forward to RemoteEntityUpdated, we handle all discovered entities the same way + onRemoteEntityUpdated(pi, entity); +} + +void CapabilityDelegate::onRemoteEntityOnline(protocol::ProtocolInterface* const pi, Entity const& entity) noexcept +{ + auto const entityID = entity.getEntityID(); + { + // Lock ProtocolInterface + std::lock_guard const lg(*pi); + + // Store or replace entity + { +#ifdef __cpp_lib_unordered_map_try_emplace + AVDECC_ASSERT(_discoveredEntities.find(entityID) == _discoveredEntities.end(), "CapabilityDelegate::onRemoteEntityOnline: Entity already online"); + _discoveredEntities.insert_or_assign(entityID, entity); +#else // !__cpp_lib_unordered_map_try_emplace + auto it = _discoveredEntities.find(entityID); + if (AVDECC_ASSERT_WITH_RET(it == _discoveredEntities.end(), "CapabilityDelegate::onRemoteEntityOnline: Entity already online")) + _discoveredEntities.insert(std::make_pair(entityID, entity)); + else + it->second = entity; +#endif // __cpp_lib_unordered_map_try_emplace + } + } + + utils::invokeProtectedMethod(&talker::Delegate::onEntityOnline, _talkerDelegate, &_talkerInterface, entityID, entity); +} + +void CapabilityDelegate::onRemoteEntityOffline(protocol::ProtocolInterface* const pi, UniqueIdentifier const entityID) noexcept +{ + { + // Lock ProtocolInterface + std::lock_guard const lg(*pi); + + // Remove entity + _discoveredEntities.erase(entityID); + } + + utils::invokeProtectedMethod(&talker::Delegate::onEntityOffline, _talkerDelegate, &_talkerInterface, entityID); +} + +void CapabilityDelegate::onRemoteEntityUpdated(protocol::ProtocolInterface* const pi, Entity const& entity) noexcept +{ + auto const entityID = entity.getEntityID(); + { + // Lock ProtocolInterface + std::lock_guard const lg(*pi); + + // Store or replace entity + { +#ifdef __cpp_lib_unordered_map_try_emplace + AVDECC_ASSERT(_discoveredEntities.find(entityID) != _discoveredEntities.end(), "CapabilityDelegate::onRemoteEntityUpdated: Entity offline"); + _discoveredEntities.insert_or_assign(entityID, entity); +#else // !__cpp_lib_unordered_map_try_emplace + auto it = _discoveredEntities.find(entityID); + if (!AVDECC_ASSERT_WITH_RET(it != _discoveredEntities.end(), "CapabilityDelegate::onRemoteEntityUpdated: Entity offline")) + _discoveredEntities.insert(std::make_pair(entityID, entity)); + else + it->second = entity; +#endif // __cpp_lib_unordered_map_try_emplace + } + } + + utils::invokeProtectedMethod(&talker::Delegate::onEntityUpdate, _talkerDelegate, &_talkerInterface, entityID, entity); +} + +/* **** AECP notifications **** */ +bool CapabilityDelegate::onUnhandledAecpCommand(protocol::ProtocolInterface* const pi, protocol::Aecpdu const& aecpdu) noexcept +{ + if (aecpdu.getMessageType() == protocol::AecpMessageType::AemCommand) + { + auto const& aem = static_cast(aecpdu); + + if (!AVDECC_ASSERT_WITH_RET(_talkerID != aecpdu.getControllerEntityID(), "Message from self should not pass through this function, or maybe if the same entity has Talker/Talker/Listener capabilities? (in that case allow the message to be processed, the ProtocolInterface will optimize the sending)")) + return true; + + if (aem.getCommandType() == protocol::AemCommandType::ControllerAvailable) + { + // We are being asked if we are available, and we are! Reply that + LocalEntityImpl<>::sendAemAecpResponse(pi, aem, protocol::AemAecpStatus::Success, nullptr, 0u); + return true; + } + } + return false; +} + +void CapabilityDelegate::onAecpAemUnsolicitedResponse(protocol::ProtocolInterface* const /*pi*/, protocol::AemAecpdu const& aecpdu) noexcept +{ + // Ignore messages not for me + if (_talkerID != aecpdu.getControllerEntityID()) + return; + + auto const messageType = aecpdu.getMessageType(); + + if (messageType == protocol::AecpMessageType::AemResponse) + { + auto const& aem = static_cast(aecpdu); + if (AVDECC_ASSERT_WITH_RET(aem.getUnsolicited(), "Should only be triggered for unsollicited notifications")) + { + // Process AEM message without any error or answer callbacks, it's not an expected response + processAemAecpResponse(&aecpdu, nullptr, {}); + // Statistics + utils::invokeProtectedMethod(&talker::Delegate::onAemAecpUnsolicitedReceived, _talkerDelegate, &_talkerInterface, aecpdu.getTargetEntityID()); + } + } +} + +void CapabilityDelegate::onAecpAemIdentifyNotification(protocol::ProtocolInterface* const /*pi*/, protocol::AemAecpdu const& aecpdu) noexcept +{ + // Forward the event + utils::invokeProtectedMethod(&talker::Delegate::onEntityIdentifyNotification, _talkerDelegate, &_talkerInterface, aecpdu.getTargetEntityID()); +} + +/* **** ACMP notifications **** */ +void CapabilityDelegate::onAcmpCommand(protocol::ProtocolInterface* const /*pi*/, protocol::Acmpdu const& /*acmpdu*/) noexcept +{ + // Talkers do not care about ACMP Commands (which can only be sniffed ones) +} + +void CapabilityDelegate::onAcmpResponse(protocol::ProtocolInterface* const /*pi*/, protocol::Acmpdu const& acmpdu) noexcept +{ + // Talkers only care about sniffed ACMP Responses here (responses to their commands have already been processed by the ProtocolInterface) + + // Check if it's a response for a Talker (since the communication btw listener and talkers uses our talkerID, we don't want to detect talker's response as ours) + auto const expectedTalkerResponseType = isResponseForTalker(acmpdu.getMessageType()); + + // Only process sniffed responses (ie. Talker response to Listener, or Listener response to another Talker) + if (_talkerID != acmpdu.getControllerEntityID() || !expectedTalkerResponseType) + { + processAcmpResponse(&acmpdu, LocalEntityImpl<>::OnACMPErrorCallback(), LocalEntityImpl<>::AnswerCallback(), true); + } +} + +/* ************************************************************************** */ +/* Talker notifications */ +/* ************************************************************************** */ +/* **** Statistics **** */ +void CapabilityDelegate::onAecpRetry(protocol::ProtocolInterface* const /*pi*/, UniqueIdentifier const& entityID) noexcept +{ + // Statistics + utils::invokeProtectedMethod(&talker::Delegate::onAecpRetry, _talkerDelegate, &_talkerInterface, entityID); +} + +void CapabilityDelegate::onAecpTimeout(protocol::ProtocolInterface* const /*pi*/, UniqueIdentifier const& entityID) noexcept +{ + // Statistics + utils::invokeProtectedMethod(&talker::Delegate::onAecpTimeout, _talkerDelegate, &_talkerInterface, entityID); +} + +void CapabilityDelegate::onAecpUnexpectedResponse(protocol::ProtocolInterface* const /*pi*/, UniqueIdentifier const& entityID) noexcept +{ + // Statistics + utils::invokeProtectedMethod(&talker::Delegate::onAecpUnexpectedResponse, _talkerDelegate, &_talkerInterface, entityID); +} + +void CapabilityDelegate::onAecpResponseTime(protocol::ProtocolInterface* const /*pi*/, UniqueIdentifier const& entityID, std::chrono::milliseconds const& responseTime) noexcept +{ + // Statistics + utils::invokeProtectedMethod(&talker::Delegate::onAecpResponseTime, _talkerDelegate, &_talkerInterface, entityID, responseTime); +} + +/* ************************************************************************** */ +/* Internal methods */ +/* ************************************************************************** */ +bool CapabilityDelegate::isResponseForTalker(protocol::AcmpMessageType const messageType) const noexcept +{ + if (messageType == protocol::AcmpMessageType::ConnectRxResponse || messageType == protocol::AcmpMessageType::DisconnectRxResponse || messageType == protocol::AcmpMessageType::GetRxStateResponse || messageType == protocol::AcmpMessageType::GetTxConnectionResponse) + return true; + return false; +} + +void CapabilityDelegate::sendAemAecpCommand(UniqueIdentifier const targetEntityID, protocol::AemCommandType const commandType, void const* const payload, size_t const payloadLength, LocalEntityImpl<>::OnAemAECPErrorCallback const& onErrorCallback, LocalEntityImpl<>::AnswerCallback const& answerCallback) const noexcept +{ + auto targetMacAddress = networkInterface::MacAddress{}; + + // Search target mac address based on its entityID + { + // Lock ProtocolInterface + std::lock_guard const lg(*_protocolInterface); + + auto const it = _discoveredEntities.find(targetEntityID); + + if (it != _discoveredEntities.end()) + { + // Get entity mac address + targetMacAddress = it->second.getAnyMacAddress(); + } + } + + // Return an error if entity is not found in the list + if (!networkInterface::isMacAddressValid(targetMacAddress)) + { + utils::invokeProtectedHandler(onErrorCallback, LocalEntity::AemCommandStatus::UnknownEntity); + return; + } + + LocalEntityImpl<>::sendAemAecpCommand(_protocolInterface, _talkerID, targetEntityID, targetMacAddress, commandType, payload, payloadLength, + [this, onErrorCallback, answerCallback](protocol::Aecpdu const* const response, LocalEntity::AemCommandStatus const status) + { + if (!!status) + { + processAemAecpResponse(response, onErrorCallback, answerCallback); // We sent an AEM command, we know it's an AEM response (so directly call processAemAecpResponse) + } + else + { + utils::invokeProtectedHandler(onErrorCallback, status); + } + }); +} + +void CapabilityDelegate::sendAaAecpCommand(UniqueIdentifier const targetEntityID, addressAccess::Tlvs const& tlvs, LocalEntityImpl<>::OnAaAECPErrorCallback const& onErrorCallback, LocalEntityImpl<>::AnswerCallback const& answerCallback) const noexcept +{ + auto targetMacAddress = networkInterface::MacAddress{}; + + // Search target mac address based on its entityID + { + // Lock ProtocolInterface + std::lock_guard const lg(*_protocolInterface); + + auto const it = _discoveredEntities.find(targetEntityID); + + if (it != _discoveredEntities.end()) + { + // Get entity mac address + targetMacAddress = it->second.getAnyMacAddress(); + } + } + + // Return an error if entity is not found in the list + if (!networkInterface::isMacAddressValid(targetMacAddress)) + { + utils::invokeProtectedHandler(onErrorCallback, LocalEntity::AaCommandStatus::UnknownEntity); + return; + } + + LocalEntityImpl<>::sendAaAecpCommand(_protocolInterface, _talkerID, targetEntityID, targetMacAddress, tlvs, + [this, onErrorCallback, answerCallback](protocol::Aecpdu const* const response, LocalEntity::AaCommandStatus const status) + { + if (!!status) + { + processAaAecpResponse(response, onErrorCallback, answerCallback); // We sent an Address Access command, we know it's an Address Access response (so directly call processAaAecpResponse) + } + else + { + utils::invokeProtectedHandler(onErrorCallback, status); + } + }); +} + +void CapabilityDelegate::sendMvuAecpCommand(UniqueIdentifier const targetEntityID, protocol::MvuCommandType const commandType, void const* const payload, size_t const payloadLength, LocalEntityImpl<>::OnMvuAECPErrorCallback const& onErrorCallback, LocalEntityImpl<>::AnswerCallback const& answerCallback) const noexcept +{ + auto targetMacAddress = networkInterface::MacAddress{}; + + // Search target mac address based on its entityID + { + // Lock ProtocolInterface + std::lock_guard const lg(*_protocolInterface); + + auto const it = _discoveredEntities.find(targetEntityID); + + if (it != _discoveredEntities.end()) + { + // Get entity mac address + targetMacAddress = it->second.getAnyMacAddress(); + } + } + + // Return an error if entity is not found in the list + if (!networkInterface::isMacAddressValid(targetMacAddress)) + { + utils::invokeProtectedHandler(onErrorCallback, LocalEntity::MvuCommandStatus::UnknownEntity); + return; + } + + LocalEntityImpl<>::sendMvuAecpCommand(_protocolInterface, _talkerID, targetEntityID, targetMacAddress, commandType, payload, payloadLength, + [this, onErrorCallback, answerCallback](protocol::Aecpdu const* const response, LocalEntity::MvuCommandStatus const status) + { + if (!!status) + { + processMvuAecpResponse(response, onErrorCallback, answerCallback); // We sent an MVU command, we know it's an MVU response (so directly call processMvuAecpResponse) + } + else + { + utils::invokeProtectedHandler(onErrorCallback, status); + } + }); +} + +void CapabilityDelegate::sendAcmpCommand(protocol::AcmpMessageType const messageType, UniqueIdentifier const talkerEntityID, model::StreamIndex const talkerStreamIndex, UniqueIdentifier const listenerEntityID, model::StreamIndex const listenerStreamIndex, std::uint16_t const connectionIndex, LocalEntityImpl<>::OnACMPErrorCallback const& onErrorCallback, LocalEntityImpl<>::AnswerCallback const& answerCallback) const noexcept +{ + LocalEntityImpl<>::sendAcmpCommand(_protocolInterface, messageType, _talkerID, talkerEntityID, talkerStreamIndex, listenerEntityID, listenerStreamIndex, connectionIndex, + [this, onErrorCallback, answerCallback](protocol::Acmpdu const* const response, LocalEntity::ControlStatus const status) + { + if (!!status) + { + processAcmpResponse(response, onErrorCallback, answerCallback, false); + } + else + { + utils::invokeProtectedHandler(onErrorCallback, status); + } + }); +} + +void CapabilityDelegate::processAemAecpResponse(protocol::Aecpdu const* const response, LocalEntityImpl<>::OnAemAECPErrorCallback const& onErrorCallback, LocalEntityImpl<>::AnswerCallback const& answerCallback) const noexcept +{ + auto const& aem = static_cast(*response); + auto const status = static_cast(aem.getStatus().getValue()); // We have to convert protocol status to our extended status + + static std::unordered_map::AnswerCallback const& answerCallback)>> s_Dispatch + { + // Acquire Entity + { protocol::AemCommandType::AcquireEntity.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[flags, ownerID, descriptorType, descriptorIndex] = protocol::aemPayload::deserializeAcquireEntityResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeAcquireEntityResponse(aem.getPayload()); + protocol::AemAcquireEntityFlags const flags = std::get<0>(result); + UniqueIdentifier const ownerID = std::get<1>(result); + entity::model::DescriptorType const descriptorType = std::get<2>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<3>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + if ((flags & protocol::AemAcquireEntityFlags::Release) == protocol::AemAcquireEntityFlags::Release) + { + answerCallback.invoke(talkerInterface, targetID, status, ownerID, descriptorType, descriptorIndex); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onEntityReleased, delegate, talkerInterface, targetID, ownerID, descriptorType, descriptorIndex); + } + } + else + { + answerCallback.invoke(talkerInterface, targetID, status, ownerID, descriptorType, descriptorIndex); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onEntityAcquired, delegate, talkerInterface, targetID, ownerID, descriptorType, descriptorIndex); + } + } + } + }, + // Lock Entity + { protocol::AemCommandType::LockEntity.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[flags, lockedID, descriptorType, descriptorIndex] = protocol::aemPayload::deserializeLockEntityResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeLockEntityResponse(aem.getPayload()); + protocol::AemLockEntityFlags const flags = std::get<0>(result); + UniqueIdentifier const lockedID = std::get<1>(result); + entity::model::DescriptorType const descriptorType = std::get<2>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<3>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + if ((flags & protocol::AemLockEntityFlags::Unlock) == protocol::AemLockEntityFlags::Unlock) + { + answerCallback.invoke(talkerInterface, targetID, status, lockedID, descriptorType, descriptorIndex); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onEntityUnlocked, delegate, talkerInterface, targetID, lockedID, descriptorType, descriptorIndex); + } + } + else + { + answerCallback.invoke(talkerInterface, targetID, status, lockedID, descriptorType, descriptorIndex); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onEntityLocked, delegate, talkerInterface, targetID, lockedID, descriptorType, descriptorIndex); + } + } + } + }, + // Entity Available + { protocol::AemCommandType::EntityAvailable.getValue(), [](talker::Delegate* const /*delegate*/, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + auto const targetID = aem.getTargetEntityID(); + answerCallback.invoke(talkerInterface, targetID, status); + } + }, + // Read Descriptor + { protocol::AemCommandType::ReadDescriptor.getValue(), [](talker::Delegate* const /*delegate*/, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + auto const payload = aem.getPayload(); + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[commonSize, configurationIndex, descriptorType, descriptorIndex] = protocol::aemPayload::deserializeReadDescriptorCommonResponse(payload); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeReadDescriptorCommonResponse(payload); + size_t const commonSize = std::get<0>(result); + entity::model::ConfigurationIndex const configurationIndex = std::get<1>(result); + entity::model::DescriptorType const descriptorType = std::get<2>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<3>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + auto const aemStatus = protocol::AemAecpStatus(static_cast(status)); + + switch (descriptorType) + { + case model::DescriptorType::Entity: + { + // Deserialize entity descriptor + auto entityDescriptor = protocol::aemPayload::deserializeReadEntityDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, entityDescriptor); + break; + } + + case model::DescriptorType::Configuration: + { + // Deserialize configuration descriptor + auto configurationDescriptor = protocol::aemPayload::deserializeReadConfigurationDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, static_cast(descriptorIndex), configurationDescriptor); // Passing descriptorIndex as ConfigurationIndex here is NOT an error. See 7.4.5.1 + break; + } + + case model::DescriptorType::AudioUnit: + { + // Deserialize audio unit descriptor + auto audioUnitDescriptor = protocol::aemPayload::deserializeReadAudioUnitDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, audioUnitDescriptor); + break; + } + + case model::DescriptorType::StreamInput: + { + // Deserialize stream input descriptor + auto streamDescriptor = protocol::aemPayload::deserializeReadStreamDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, streamDescriptor); + break; + } + + case model::DescriptorType::StreamOutput: + { + // Deserialize stream output descriptor + auto streamDescriptor = protocol::aemPayload::deserializeReadStreamDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, streamDescriptor); + break; + } + + case model::DescriptorType::JackInput: + { + // Deserialize jack input descriptor + auto jackDescriptor = protocol::aemPayload::deserializeReadJackDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, jackDescriptor); + break; + } + + case model::DescriptorType::JackOutput: + { + // Deserialize jack output descriptor + auto jackDescriptor = protocol::aemPayload::deserializeReadJackDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, jackDescriptor); + break; + } + + case model::DescriptorType::AvbInterface: + { + // Deserialize avb interface descriptor + auto avbInterfaceDescriptor = protocol::aemPayload::deserializeReadAvbInterfaceDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, avbInterfaceDescriptor); + break; + } + + case model::DescriptorType::ClockSource: + { + // Deserialize clock source descriptor + auto clockSourceDescriptor = protocol::aemPayload::deserializeReadClockSourceDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, clockSourceDescriptor); + break; + } + + case model::DescriptorType::MemoryObject: + { + // Deserialize memory object descriptor + auto memoryObjectDescriptor = protocol::aemPayload::deserializeReadMemoryObjectDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, memoryObjectDescriptor); + break; + } + + case model::DescriptorType::Locale: + { + // Deserialize locale descriptor + auto localeDescriptor = protocol::aemPayload::deserializeReadLocaleDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, localeDescriptor); + break; + } + + case model::DescriptorType::Strings: + { + // Deserialize strings descriptor + auto stringsDescriptor = protocol::aemPayload::deserializeReadStringsDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, stringsDescriptor); + break; + } + + case model::DescriptorType::StreamPortInput: + { + // Deserialize stream port descriptor + auto streamPortDescriptor = protocol::aemPayload::deserializeReadStreamPortDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, streamPortDescriptor); + break; + } + + case model::DescriptorType::StreamPortOutput: + { + // Deserialize stream port descriptor + auto streamPortDescriptor = protocol::aemPayload::deserializeReadStreamPortDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, streamPortDescriptor); + break; + } + + case model::DescriptorType::ExternalPortInput: + { + // Deserialize external port descriptor + auto externalPortDescriptor = protocol::aemPayload::deserializeReadExternalPortDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, externalPortDescriptor); + break; + } + + case model::DescriptorType::ExternalPortOutput: + { + // Deserialize external port descriptor + auto externalPortDescriptor = protocol::aemPayload::deserializeReadExternalPortDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, externalPortDescriptor); + break; + } + + case model::DescriptorType::InternalPortInput: + { + // Deserialize internal port descriptor + auto internalPortDescriptor = protocol::aemPayload::deserializeReadInternalPortDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, internalPortDescriptor); + break; + } + + case model::DescriptorType::InternalPortOutput: + { + // Deserialize internal port descriptor + auto internalPortDescriptor = protocol::aemPayload::deserializeReadInternalPortDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, internalPortDescriptor); + break; + } + + case model::DescriptorType::AudioCluster: + { + // Deserialize audio cluster descriptor + auto audioClusterDescriptor = protocol::aemPayload::deserializeReadAudioClusterDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, audioClusterDescriptor); + break; + } + + case model::DescriptorType::AudioMap: + { + // Deserialize audio map descriptor + auto audioMapDescriptor = protocol::aemPayload::deserializeReadAudioMapDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, audioMapDescriptor); + break; + } + + case model::DescriptorType::ClockDomain: + { + // Deserialize clock domain descriptor + auto clockDomainDescriptor = protocol::aemPayload::deserializeReadClockDomainDescriptorResponse(payload, commonSize, aemStatus); + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, clockDomainDescriptor); + break; + } + + default: + AVDECC_ASSERT(false, "Unhandled descriptor type"); + break; + } + } + }, + // Write Descriptor + // Set Configuration + { protocol::AemCommandType::SetConfiguration.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[configurationIndex] = protocol::aemPayload::deserializeSetConfigurationResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeSetConfigurationResponse(aem.getPayload()); + model::ConfigurationIndex const configurationIndex = std::get<0>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onConfigurationChanged, delegate, talkerInterface, targetID, configurationIndex); + } + } + }, + // Get Configuration + { protocol::AemCommandType::GetConfiguration.getValue(), [](talker::Delegate* const /*delegate*/, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[configurationIndex] = protocol::aemPayload::deserializeGetConfigurationResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeGetConfigurationResponse(aem.getPayload()); + model::ConfigurationIndex const configurationIndex = std::get<0>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex); + } + }, + // Set Stream Format + { protocol::AemCommandType::SetStreamFormat.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, streamFormat] = protocol::aemPayload::deserializeSetStreamFormatResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeSetStreamFormatResponse(aem.getPayload()); + model::DescriptorType const descriptorType = std::get<0>(result); + model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::StreamFormat const streamFormat = std::get<2>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + if (descriptorType == model::DescriptorType::StreamInput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, streamFormat); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamInputFormatChanged, delegate, talkerInterface, targetID, descriptorIndex, streamFormat); + } + } + else if (descriptorType == model::DescriptorType::StreamOutput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, streamFormat); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamOutputFormatChanged, delegate, talkerInterface, targetID, descriptorIndex, streamFormat); + } + } + else + throw InvalidDescriptorTypeException(); + } + }, + // Get Stream Format + { protocol::AemCommandType::GetStreamFormat.getValue(), [](talker::Delegate* const /*delegate*/, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, streamFormat] = protocol::aemPayload::deserializeGetStreamFormatResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeGetStreamFormatResponse(aem.getPayload()); + model::DescriptorType const descriptorType = std::get<0>(result); + model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::StreamFormat const streamFormat = std::get<2>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + if (descriptorType == model::DescriptorType::StreamInput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, streamFormat); + } + else if (descriptorType == model::DescriptorType::StreamOutput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, streamFormat); + } + else + throw InvalidDescriptorTypeException(); + } + }, + // Set Stream Info + { protocol::AemCommandType::SetStreamInfo.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, streamInfo] = protocol::aemPayload::deserializeSetStreamInfoResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeSetStreamInfoResponse(aem.getPayload()); + model::DescriptorType const descriptorType = std::get<0>(result); + model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::StreamInfo const streamInfo = std::get<2>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + if (descriptorType == model::DescriptorType::StreamInput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, streamInfo); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamInputInfoChanged, delegate, talkerInterface, targetID, descriptorIndex, streamInfo, false); + } + } + else if (descriptorType == model::DescriptorType::StreamOutput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, streamInfo); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamOutputInfoChanged, delegate, talkerInterface, targetID, descriptorIndex, streamInfo, false); + } + } + else + throw InvalidDescriptorTypeException(); + } + }, + // Get Stream Info + { protocol::AemCommandType::GetStreamInfo.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, streamInfo] = protocol::aemPayload::deserializeGetStreamInfoResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeGetStreamInfoResponse(aem.getPayload()); + model::DescriptorType const descriptorType = std::get<0>(result); + model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::StreamInfo const streamInfo = std::get<2>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + if (descriptorType == model::DescriptorType::StreamInput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, streamInfo); + if (aem.getUnsolicited() && delegate && !!status) // Unsolicited triggered by change in the SRP domain (Clause 7.5.2) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamInputInfoChanged, delegate, talkerInterface, targetID, descriptorIndex, streamInfo, true); + } + } + else if (descriptorType == model::DescriptorType::StreamOutput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, streamInfo); + if (aem.getUnsolicited() && delegate && !!status) // Unsolicited triggered by change in the SRP domain (Clause 7.5.2) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamOutputInfoChanged, delegate, talkerInterface, targetID, descriptorIndex, streamInfo, true); + } + } + else + throw InvalidDescriptorTypeException(); + } + }, + // Set Name + { protocol::AemCommandType::SetName.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, nameIndex, configurationIndex, name] = protocol::aemPayload::deserializeSetNameResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeSetNameResponse(aem.getPayload()); + model::DescriptorType const descriptorType = std::get<0>(result); + model::DescriptorIndex const descriptorIndex = std::get<1>(result); + std::uint16_t const nameIndex = std::get<2>(result); + model::ConfigurationIndex const configurationIndex = std::get<3>(result); + model::AvdeccFixedString const name = std::get<4>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + switch (descriptorType) + { + case model::DescriptorType::Entity: + { + if (descriptorIndex != 0) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Invalid descriptorIndex in SET_NAME response for Entity Descriptor: {}", descriptorIndex); + } + if (configurationIndex != 0) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Invalid configurationIndex in SET_NAME response for Entity Descriptor: {}", configurationIndex); + } + switch (nameIndex) + { + case 0: // entity_name + answerCallback.invoke(talkerInterface, targetID, status, name); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onEntityNameChanged, delegate, talkerInterface, targetID, name); + } + break; + case 1: // group_name + answerCallback.invoke(talkerInterface, targetID, status, name); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onEntityGroupNameChanged, delegate, talkerInterface, targetID, name); + } + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in SET_NAME response for Entity Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::Configuration: + { + if (configurationIndex != 0) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Invalid configurationIndex in SET_NAME response for Configuration Descriptor: ConfigurationIndex={}", configurationIndex); + } + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, name); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onConfigurationNameChanged, delegate, talkerInterface, targetID, descriptorIndex, name); + } + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in SET_NAME response for Configuration Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::AudioUnit: + { + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onAudioUnitNameChanged, delegate, talkerInterface, targetID, configurationIndex, descriptorIndex, name); + } + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in SET_NAME response for AudioUnit Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::StreamInput: + { + switch (nameIndex) + { + case 0: // stream_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamInputNameChanged, delegate, talkerInterface, targetID, configurationIndex, descriptorIndex, name); + } + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in SET_NAME response for StreamInput Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::StreamOutput: + { + switch (nameIndex) + { + case 0: // stream_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamOutputNameChanged, delegate, talkerInterface, targetID, configurationIndex, descriptorIndex, name); + } + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in SET_NAME response for StreamOutput Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::AvbInterface: + { + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onAvbInterfaceNameChanged, delegate, talkerInterface, targetID, configurationIndex, descriptorIndex, name); + } + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in SET_NAME response for AvbInterface Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::ClockSource: + { + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onClockSourceNameChanged, delegate, talkerInterface, targetID, configurationIndex, descriptorIndex, name); + } + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in SET_NAME response for ClockSource Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::MemoryObject: + { + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onMemoryObjectNameChanged, delegate, talkerInterface, targetID, configurationIndex, descriptorIndex, name); + } + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in SET_NAME response for MemoryObject Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::AudioCluster: + { + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onAudioClusterNameChanged, delegate, talkerInterface, targetID, configurationIndex, descriptorIndex, name); + } + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in SET_NAME response for AudioCluster Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::ClockDomain: + { + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onClockDomainNameChanged, delegate, talkerInterface, targetID, configurationIndex, descriptorIndex, name); + } + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in SET_NAME response for ClockDomain Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled descriptorType in SET_NAME response: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + } + }, + // Get Name + { protocol::AemCommandType::GetName.getValue(), [](talker::Delegate* const /*delegate*/, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, nameIndex, configurationIndex, name] = protocol::aemPayload::deserializeGetNameResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeGetNameResponse(aem.getPayload()); + model::DescriptorType const descriptorType = std::get<0>(result); + model::DescriptorIndex const descriptorIndex = std::get<1>(result); + std::uint16_t const nameIndex = std::get<2>(result); + model::ConfigurationIndex const configurationIndex = std::get<3>(result); + model::AvdeccFixedString const name = std::get<4>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + switch (descriptorType) + { + case model::DescriptorType::Entity: + { + if (descriptorIndex != 0) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Invalid descriptorIndex in GET_NAME response for Entity Descriptor: DescriptorIndex={}", descriptorIndex); + } + if (configurationIndex != 0) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Invalid configurationIndex in GET_NAME response for Entity Descriptor: ConfigurationIndex={}", configurationIndex); + } + switch (nameIndex) + { + case 0: // entity_name + answerCallback.invoke(talkerInterface, targetID, status, name); + break; + case 1: // group_name + answerCallback.invoke(talkerInterface, targetID, status, name); + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in GET_NAME response for Entity Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::Configuration: + { + if (configurationIndex != 0) + { + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Invalid configurationIndex in GET_NAME response for Configuration Descriptor: ConfigurationIndex={}", configurationIndex); + } + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, name); + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in GET_NAME response for Configuration Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::AudioUnit: + { + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in GET_NAME response for AudioUnit Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::StreamInput: + { + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in GET_NAME response for StreamInput Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::StreamOutput: + { + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in GET_NAME response for StreamOutput Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::AvbInterface: + { + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in GET_NAME response for AvbInterface Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::ClockSource: + { + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in GET_NAME response for ClockSource Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::MemoryObject: + { + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in GET_NAME response for MemoryObject Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::AudioCluster: + { + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in GET_NAME response for AudioCluster Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + case model::DescriptorType::ClockDomain: + { + switch (nameIndex) + { + case 0: // object_name + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, descriptorIndex, name); + break; + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled nameIndex in GET_NAME response for ClockDomain Descriptor: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + break; + } + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled descriptorType in GET_NAME response: DescriptorType={} DescriptorIndex={} NameIndex={} ConfigurationIndex={} Name={}", utils::to_integral(descriptorType), descriptorIndex, nameIndex, configurationIndex, name.str()); + break; + } + } + }, + // Set Sampling Rate + { protocol::AemCommandType::SetSamplingRate.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, samplingRate] = protocol::aemPayload::deserializeSetSamplingRateResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeSetSamplingRateResponse(aem.getPayload()); + entity::model::DescriptorType const descriptorType = std::get<0>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::SamplingRate const samplingRate = std::get<2>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + if (descriptorType == model::DescriptorType::AudioUnit) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, samplingRate); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onAudioUnitSamplingRateChanged, delegate, talkerInterface, targetID, descriptorIndex, samplingRate); + } + } + else if (descriptorType == model::DescriptorType::VideoCluster) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, samplingRate); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onVideoClusterSamplingRateChanged, delegate, talkerInterface, targetID, descriptorIndex, samplingRate); + } + } + else if (descriptorType == model::DescriptorType::SensorCluster) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, samplingRate); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onSensorClusterSamplingRateChanged, delegate, talkerInterface, targetID, descriptorIndex , samplingRate); + } + } + else + throw InvalidDescriptorTypeException(); + } + }, + // Get Sampling Rate + { protocol::AemCommandType::GetSamplingRate.getValue(), [](talker::Delegate* const /*delegate*/, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, samplingRate] = protocol::aemPayload::deserializeGetSamplingRateResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeGetSamplingRateResponse(aem.getPayload()); + entity::model::DescriptorType const descriptorType = std::get<0>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::SamplingRate const samplingRate = std::get<2>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + if (descriptorType == model::DescriptorType::AudioUnit) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, samplingRate); + } + else if (descriptorType == model::DescriptorType::VideoCluster) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, samplingRate); + } + else if (descriptorType == model::DescriptorType::SensorCluster) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, samplingRate); + } + else + throw InvalidDescriptorTypeException(); + } + }, + // Set Clock Source + { protocol::AemCommandType::SetClockSource.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, clockSourceIndex] = protocol::aemPayload::deserializeSetClockSourceResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeSetClockSourceResponse(aem.getPayload()); + //entity::model::DescriptorType const descriptorType = std::get<0>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::ClockSourceIndex const clockSourceIndex = std::get<2>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, clockSourceIndex); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onClockSourceChanged, delegate, talkerInterface, targetID, descriptorIndex, clockSourceIndex); + } + } + }, + // Get Clock Source + { protocol::AemCommandType::GetClockSource.getValue(),[](talker::Delegate* const /*delegate*/, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, clockSourceIndex] = protocol::aemPayload::deserializeGetClockSourceResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeGetClockSourceResponse(aem.getPayload()); + //entity::model::DescriptorType const descriptorType = std::get<0>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::ClockSourceIndex const clockSourceIndex = std::get<2>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, clockSourceIndex); + } + }, + // Start Streaming + { protocol::AemCommandType::StartStreaming.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex] = protocol::aemPayload::deserializeStartStreamingResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeStartStreamingResponse(aem.getPayload()); + entity::model::DescriptorType const descriptorType = std::get<0>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<1>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + if (descriptorType == model::DescriptorType::StreamInput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamInputStarted, delegate, talkerInterface, targetID, descriptorIndex); + } + } + else if (descriptorType == model::DescriptorType::StreamOutput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamOutputStarted, delegate, talkerInterface, targetID, descriptorIndex); + } + } + else + throw InvalidDescriptorTypeException(); + } + }, + // Stop Streaming + { protocol::AemCommandType::StopStreaming.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex] = protocol::aemPayload::deserializeStopStreamingResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeStopStreamingResponse(aem.getPayload()); + entity::model::DescriptorType const descriptorType = std::get<0>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<1>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + if (descriptorType == model::DescriptorType::StreamInput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamInputStopped, delegate, talkerInterface, targetID, descriptorIndex); + } + } + else if (descriptorType == model::DescriptorType::StreamOutput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamOutputStopped, delegate, talkerInterface, targetID, descriptorIndex); + } + } + else + throw InvalidDescriptorTypeException(); + } + }, + // Register Unsolicited Notifications + { protocol::AemCommandType::RegisterUnsolicitedNotification.getValue(), [](talker::Delegate* const /*delegate*/, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Ignore payload size and content, Apple's implementation is bugged and returns too much data + auto const targetID = aem.getTargetEntityID(); + answerCallback.invoke(talkerInterface, targetID, status); + } + }, + // Unregister Unsolicited Notifications + { protocol::AemCommandType::DeregisterUnsolicitedNotification.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Ignore payload size and content, Apple's implementation is bugged and returns too much data + auto const targetID = aem.getTargetEntityID(); + + answerCallback.invoke(talkerInterface, targetID, status); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onDeregisteredFromUnsolicitedNotifications, delegate, talkerInterface, targetID); + } + } + }, + // GetAvbInfo + { protocol::AemCommandType::GetAvbInfo.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, avbInfo] = protocol::aemPayload::deserializeGetAvbInfoResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeGetAvbInfoResponse(aem.getPayload()); + entity::model::DescriptorType const descriptorType = std::get<0>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::AvbInfo const avbInfo = std::get<2>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + if (descriptorType == model::DescriptorType::AvbInterface) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, avbInfo); + if (aem.getUnsolicited() && delegate && !!status) // Unsolicited triggered by change in the SRP domain (Clause 7.5.2) + { + utils::invokeProtectedMethod(&talker::Delegate::onAvbInfoChanged, delegate, talkerInterface, targetID, descriptorIndex, avbInfo); + } + } + else + throw InvalidDescriptorTypeException(); + } + }, + // GetAsPath + { protocol::AemCommandType::GetAsPath.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorIndex, asPath] = protocol::aemPayload::deserializeGetAsPathResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeGetAsPathResponse(aem.getPayload()); + entity::model::DescriptorIndex const descriptorIndex = std::get<0>(result); + entity::model::AsPath const asPath = std::get<1>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, asPath); + if (aem.getUnsolicited() && delegate && !!status) // Unsolicited triggered by change in the SRP domain (Clause 7.5.2) + { + utils::invokeProtectedMethod(&talker::Delegate::onAsPathChanged, delegate, talkerInterface, targetID, descriptorIndex, asPath); + } + } + }, + // GetCounters + { protocol::AemCommandType::GetCounters.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, validFlags, counters] = protocol::aemPayload::deserializeGetCountersResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeGetCountersResponse(aem.getPayload()); + entity::model::DescriptorType const descriptorType = std::get<0>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::DescriptorCounterValidFlag const validFlags = std::get<2>(result); + entity::model::DescriptorCounters const& counters = std::get<3>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + switch (descriptorType) + { + case model::DescriptorType::Entity: + { + EntityCounterValidFlags flags; + flags.assign(validFlags); + answerCallback.invoke(talkerInterface, targetID, status, flags, counters); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onEntityCountersChanged, delegate, talkerInterface, targetID, flags, counters); + } + if (descriptorIndex != 0) + { + LOG_CONTROLLER_ENTITY_WARN(targetID, "GET_COUNTERS response for ENTITY descriptor uses a non-0 DescriptorIndex: {}", descriptorIndex); + } + break; + } + case model::DescriptorType::AvbInterface: + { + AvbInterfaceCounterValidFlags flags; + flags.assign(validFlags); + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, flags, counters); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onAvbInterfaceCountersChanged, delegate, talkerInterface, targetID, descriptorIndex, flags, counters); + } + break; + } + case model::DescriptorType::ClockDomain: + { + ClockDomainCounterValidFlags flags; + flags.assign(validFlags); + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, flags, counters); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onClockDomainCountersChanged, delegate, talkerInterface, targetID, descriptorIndex, flags, counters); + } + break; + } + case model::DescriptorType::StreamInput: + { + StreamInputCounterValidFlags flags; + flags.assign(validFlags); + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, flags, counters); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamInputCountersChanged, delegate, talkerInterface, targetID, descriptorIndex, flags, counters); + } + break; + } + case model::DescriptorType::StreamOutput: + { + StreamOutputCounterValidFlags flags; + flags.assign(validFlags); + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, flags, counters); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamOutputCountersChanged, delegate, talkerInterface, targetID, descriptorIndex, flags, counters); + } + break; + } + default: + LOG_CONTROLLER_ENTITY_DEBUG(targetID, "Unhandled descriptorType in GET_COUNTERS response: DescriptorType={} DescriptorIndex={}", utils::to_integral(descriptorType), descriptorIndex); + break; + } + } + }, + // Get Audio Map + { protocol::AemCommandType::GetAudioMap.getValue(), []([[maybe_unused]] talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, mapIndex, numberOfMaps, mappings] = protocol::aemPayload::deserializeGetAudioMapResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeGetAudioMapResponse(aem.getPayload()); + entity::model::DescriptorType const descriptorType = std::get<0>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::MapIndex const mapIndex = std::get<2>(result); + entity::model::MapIndex const numberOfMaps = std::get<3>(result); + entity::model::AudioMappings const& mappings = std::get<4>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + if (descriptorType == model::DescriptorType::StreamPortInput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, numberOfMaps, mapIndex, mappings); +#ifdef ALLOW_GET_AUDIO_MAP_UNSOL + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamPortInputAudioMappingsChanged, delegate, talkerInterface, targetID, descriptorIndex, numberOfMaps, mapIndex, mappings); + } +#endif // ALLOW_GET_AUDIO_MAP_UNSOL + } + else if (descriptorType == model::DescriptorType::StreamPortOutput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, numberOfMaps, mapIndex, mappings); +#ifdef ALLOW_GET_AUDIO_MAP_UNSOL + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamPortOutputAudioMappingsChanged, delegate, talkerInterface, targetID, descriptorIndex, numberOfMaps, mapIndex, mappings); + } +#endif + } + else + throw InvalidDescriptorTypeException(); + } + }, + // Add Audio Mappings + { protocol::AemCommandType::AddAudioMappings.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, mappings] = protocol::aemPayload::deserializeAddAudioMappingsResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeAddAudioMappingsResponse(aem.getPayload()); + entity::model::DescriptorType const descriptorType = std::get<0>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::AudioMappings const& mappings = std::get<2>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + if (descriptorType == model::DescriptorType::StreamPortInput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, mappings); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamPortInputAudioMappingsAdded, delegate, talkerInterface, targetID, descriptorIndex, mappings); + } + } + else if (descriptorType == model::DescriptorType::StreamPortOutput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, mappings); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamPortOutputAudioMappingsAdded, delegate, talkerInterface, targetID, descriptorIndex, mappings); + } + } + else + throw InvalidDescriptorTypeException(); + } + }, + // Remove Audio Mappings + { protocol::AemCommandType::RemoveAudioMappings.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, mappings] = protocol::aemPayload::deserializeRemoveAudioMappingsResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeRemoveAudioMappingsResponse(aem.getPayload()); + entity::model::DescriptorType const descriptorType = std::get<0>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::AudioMappings const& mappings = std::get<2>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + if (descriptorType == model::DescriptorType::StreamPortInput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, mappings); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamPortInputAudioMappingsRemoved, delegate, talkerInterface, targetID, descriptorIndex, mappings); + } + } + else if (descriptorType == model::DescriptorType::StreamPortOutput) + { + answerCallback.invoke(talkerInterface, targetID, status, descriptorIndex, mappings); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onStreamPortOutputAudioMappingsRemoved, delegate, talkerInterface, targetID, descriptorIndex, mappings); + } + } + else + throw InvalidDescriptorTypeException(); + } + }, + // Start Operation + { protocol::AemCommandType::StartOperation.getValue(), [](talker::Delegate* const /*delegate*/, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, operationID, operationType, memoryBuffer] = protocol::aemPayload::deserializeStartOperationResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeStartOperationResponse(aem.getPayload()); + entity::model::DescriptorType const descriptorType = std::get<0>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::OperationID const operationID = std::get<2>(result); + entity::model::MemoryObjectOperationType const operationType = std::get<3>(result); + MemoryBuffer const memoryBuffer = std::get<4>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, descriptorType, descriptorIndex, operationID, operationType, memoryBuffer); + } + }, + // Abort Operation + { protocol::AemCommandType::AbortOperation.getValue(), [](talker::Delegate* const /*delegate*/, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, operationID] = protocol::aemPayload::deserializeAbortOperationResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeAbortOperationResponse(aem.getPayload()); + entity::model::DescriptorType const descriptorType = std::get<0>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::OperationID const operationID = std::get<2>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, descriptorType, descriptorIndex, operationID); + } + }, + // Operation Status + { protocol::AemCommandType::OperationStatus.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const /*status*/, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& /*answerCallback*/) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[descriptorType, descriptorIndex, operationID, percentComplete] = protocol::aemPayload::deserializeOperationStatusResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeOperationStatusResponse(aem.getPayload()); + entity::model::DescriptorType const descriptorType = std::get<0>(result); + entity::model::DescriptorIndex const descriptorIndex = std::get<1>(result); + entity::model::OperationID const operationID = std::get<2>(result); + std::uint16_t const percentComplete = std::get<3>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + AVDECC_ASSERT(aem.getUnsolicited(), "OperationStatus can only be an unsolicited response"); + utils::invokeProtectedMethod(&talker::Delegate::onOperationStatus, delegate, talkerInterface, targetID, descriptorType, descriptorIndex, operationID, percentComplete); + } + }, + // Set Memory Object Length + { protocol::AemCommandType::SetMemoryObjectLength.getValue(), [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[configurationIndex, memoryObjectIndex, length] = protocol::aemPayload::deserializeSetMemoryObjectLengthResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeSetMemoryObjectLengthResponse(aem.getPayload()); + entity::model::ConfigurationIndex const configurationIndex = std::get<0>(result); + entity::model::MemoryObjectIndex const memoryObjectIndex = std::get<1>(result); + std::uint64_t const length = std::get<2>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, memoryObjectIndex, length); + if (aem.getUnsolicited() && delegate && !!status) + { + utils::invokeProtectedMethod(&talker::Delegate::onMemoryObjectLengthChanged, delegate, talkerInterface, targetID, configurationIndex, memoryObjectIndex, length); + } + } + }, + // Get Memory Object Length + { protocol::AemCommandType::GetMemoryObjectLength.getValue(),[](talker::Delegate* const /*delegate*/, Interface const* const talkerInterface, LocalEntity::AemCommandStatus const status, protocol::AemAecpdu const& aem, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const[configurationIndex, memoryObjectIndex, length] = protocol::aemPayload::deserializeGetMemoryObjectLengthResponse(aem.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::aemPayload::deserializeGetMemoryObjectLengthResponse(aem.getPayload()); + entity::model::ConfigurationIndex const configurationIndex = std::get<0>(result); + entity::model::MemoryObjectIndex const memoryObjectIndex = std::get<1>(result); + std::uint64_t const length = std::get<2>(result); +#endif // __cpp_structured_bindings + + auto const targetID = aem.getTargetEntityID(); + + // Notify handlers + answerCallback.invoke(talkerInterface, targetID, status, configurationIndex, memoryObjectIndex, length); + } + }, + // Set Stream Backup + // Get Stream Backup + }; + + auto const& it = s_Dispatch.find(aem.getCommandType().getValue()); + if (it == s_Dispatch.end()) + { + // If this is an unsolicited notification, simply log we do not handle the message + if (aem.getUnsolicited()) + { + LOG_CONTROLLER_ENTITY_DEBUG(aem.getTargetEntityID(), "Unsolicited AEM response {} not handled ({})", std::string(aem.getCommandType()), utils::toHexString(aem.getCommandType().getValue())); + } + // But if it's an expected response, this is an internal error since we sent a command and didn't implement the code to handle the response + else + { + LOG_CONTROLLER_ENTITY_ERROR(aem.getTargetEntityID(), "Failed to process AEM response: Unhandled command type {} ({})", std::string(aem.getCommandType()), utils::toHexString(aem.getCommandType().getValue())); + utils::invokeProtectedHandler(onErrorCallback, LocalEntity::AemCommandStatus::InternalError); + } + } + else + { + auto checkProcessInvalidNonSuccessResponse = [status, &aem, &onErrorCallback]([[maybe_unused]] char const* const what) + { + auto st = LocalEntity::AemCommandStatus::ProtocolError; +#if defined(IGNORE_INVALID_NON_SUCCESS_AEM_RESPONSES) + if (status != LocalEntity::AemCommandStatus::Success) + { + // Allow this packet to go through as a non-success response, but some fields might have the default initial value which might not be valid (the spec says even in a response message, some fields have a meaningful value) + st = status; + LOG_CONTROLLER_ENTITY_INFO(aem.getTargetEntityID(), "Received an invalid non-success {} AEM response ({}) from {} but still processing it because of compilation option IGNORE_INVALID_NON_SUCCESS_AEM_RESPONSES", std::string(aem.getCommandType()), what, utils::toHexString(aem.getTargetEntityID(), true)); + } +#endif // IGNORE_INVALID_NON_SUCCESS_AEM_RESPONSES + if (st == LocalEntity::AemCommandStatus::ProtocolError) + { + LOG_CONTROLLER_ENTITY_ERROR(aem.getTargetEntityID(), "Failed to process {} AEM response: {}", std::string(aem.getCommandType()), what); + } + utils::invokeProtectedHandler(onErrorCallback, st); + }; + + try + { + it->second(_talkerDelegate, &_talkerInterface, status, aem, answerCallback); + } + catch (protocol::aemPayload::IncorrectPayloadSizeException const& e) + { + checkProcessInvalidNonSuccessResponse(e.what()); + return; + } + catch (InvalidDescriptorTypeException const& e) + { + checkProcessInvalidNonSuccessResponse(e.what()); + return; + } + catch ([[maybe_unused]] std::exception const& e) // Mainly unpacking errors + { + LOG_CONTROLLER_ENTITY_ERROR(aem.getTargetEntityID(), "Failed to process {} AEM response: {}", std::string(aem.getCommandType()), e.what()); + utils::invokeProtectedHandler(onErrorCallback, LocalEntity::AemCommandStatus::ProtocolError); + return; + } + } +} + +void CapabilityDelegate::processAaAecpResponse(protocol::Aecpdu const* const response, LocalEntityImpl<>::OnAaAECPErrorCallback const& /*onErrorCallback*/, LocalEntityImpl<>::AnswerCallback const& answerCallback) const noexcept +{ + auto const& aa = static_cast(*response); + auto const status = static_cast(aa.getStatus().getValue()); // We have to convert protocol status to our extended status + auto const targetID = aa.getTargetEntityID(); + + answerCallback.invoke(&_talkerInterface, targetID, status, aa.getTlvData()); +} + +void CapabilityDelegate::processMvuAecpResponse(protocol::Aecpdu const* const response, LocalEntityImpl<>::OnMvuAECPErrorCallback const& onErrorCallback, LocalEntityImpl<>::AnswerCallback const& answerCallback) const noexcept +{ + auto const& mvu = static_cast(*response); + auto const status = static_cast(mvu.getStatus().getValue()); // We have to convert protocol status to our extended status + + static std::unordered_map::AnswerCallback const& answerCallback)>> s_Dispatch{ + // Get Milan Info + { protocol::MvuCommandType::GetMilanInfo.getValue(), + [](talker::Delegate* const /*delegate*/, Interface const* const talkerInterface, LocalEntity::MvuCommandStatus const status, protocol::MvuAecpdu const& mvu, LocalEntityImpl<>::AnswerCallback const& answerCallback) + { + // Deserialize payload +#ifdef __cpp_structured_bindings + auto const [milanInfo] = protocol::mvuPayload::deserializeGetMilanInfoResponse(mvu.getPayload()); +#else // !__cpp_structured_bindings + auto const result = protocol::mvuPayload::deserializeGetMilanInfoResponse(mvu.getPayload()); + entity::model::MilanInfo const milanInfo = std::get<0>(result); +#endif // __cpp_structured_bindings + + auto const targetID = mvu.getTargetEntityID(); + + answerCallback.invoke(talkerInterface, targetID, status, milanInfo); + } }, + }; + + auto const& it = s_Dispatch.find(mvu.getCommandType().getValue()); + if (it == s_Dispatch.end()) + { + // It's an expected response, this is an internal error since we sent a command and didn't implement the code to handle the response + LOG_CONTROLLER_ENTITY_ERROR(mvu.getTargetEntityID(), "Failed to process MVU response: Unhandled command type {} ({})", std::string(mvu.getCommandType()), utils::toHexString(mvu.getCommandType().getValue())); + utils::invokeProtectedHandler(onErrorCallback, LocalEntity::MvuCommandStatus::InternalError); + } + else + { + try + { + it->second(_talkerDelegate, &_talkerInterface, status, mvu, answerCallback); + } + catch ([[maybe_unused]] protocol::mvuPayload::IncorrectPayloadSizeException const& e) + { + LOG_CONTROLLER_ENTITY_ERROR(mvu.getTargetEntityID(), "Failed to process {} MVU response: {}", std::string(mvu.getCommandType()), e.what()); + utils::invokeProtectedHandler(onErrorCallback, LocalEntity::MvuCommandStatus::ProtocolError); + return; + } + catch ([[maybe_unused]] InvalidDescriptorTypeException const& e) + { + LOG_CONTROLLER_ENTITY_ERROR(mvu.getTargetEntityID(), "Failed to process {} MVU response: {}", std::string(mvu.getCommandType()), e.what()); + utils::invokeProtectedHandler(onErrorCallback, LocalEntity::MvuCommandStatus::ProtocolError); + return; + } + catch ([[maybe_unused]] std::exception const& e) // Mainly unpacking errors + { + LOG_CONTROLLER_ENTITY_ERROR(mvu.getTargetEntityID(), "Failed to process {} MVU response: {}", std::string(mvu.getCommandType()), e.what()); + utils::invokeProtectedHandler(onErrorCallback, LocalEntity::MvuCommandStatus::ProtocolError); + return; + } + } +} + +void CapabilityDelegate::processAcmpResponse(protocol::Acmpdu const* const response, LocalEntityImpl<>::OnACMPErrorCallback const& onErrorCallback, LocalEntityImpl<>::AnswerCallback const& answerCallback, bool const sniffed) const noexcept +{ + auto const& acmp = static_cast(*response); + auto const status = static_cast(acmp.getStatus().getValue()); // We have to convert protocol status to our extended status + + static std::unordered_map::AnswerCallback const& answerCallback, bool const sniffed)>> s_Dispatch{ + // Connect TX response + { protocol::AcmpMessageType::ConnectTxResponse.getValue(), + [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::ControlStatus const status, protocol::Acmpdu const& acmp, LocalEntityImpl<>::AnswerCallback const& /*answerCallback*/, bool const sniffed) + { + auto const talkerEntityID = acmp.getControllerEntityID(); + auto const talkerStreamIndex = acmp.getTalkerUniqueID(); + auto const listenerEntityID = acmp.getListenerEntityID(); + auto const listenerStreamIndex = acmp.getListenerUniqueID(); + auto const connectionCount = acmp.getConnectionCount(); + auto const flags = acmp.getFlags(); + if (sniffed && delegate) + { + utils::invokeProtectedMethod(&talker::Delegate::onListenerConnectResponseSniffed, delegate, talkerInterface, model::StreamIdentification{ talkerEntityID, talkerStreamIndex }, model::StreamIdentification{ listenerEntityID, listenerStreamIndex }, connectionCount, flags, status); + } + } }, + // Disconnect TX response + { protocol::AcmpMessageType::DisconnectTxResponse.getValue(), + [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::ControlStatus const status, protocol::Acmpdu const& acmp, LocalEntityImpl<>::AnswerCallback const& answerCallback, bool const sniffed) + { + auto const talkerEntityID = acmp.getControllerEntityID(); + auto const talkerStreamIndex = acmp.getTalkerUniqueID(); + auto const listenerEntityID = acmp.getListenerEntityID(); + auto const listenerStreamIndex = acmp.getListenerUniqueID(); + auto const connectionCount = acmp.getConnectionCount(); + auto const flags = acmp.getFlags(); + answerCallback.invoke(talkerInterface, model::StreamIdentification{ talkerEntityID, talkerStreamIndex }, model::StreamIdentification{ listenerEntityID, listenerStreamIndex }, connectionCount, flags, status); + if (sniffed && delegate) + { + utils::invokeProtectedMethod(&talker::Delegate::onListenerDisconnectResponseSniffed, delegate, talkerInterface, model::StreamIdentification{ talkerEntityID, talkerStreamIndex }, model::StreamIdentification{ listenerEntityID, listenerStreamIndex }, connectionCount, flags, status); + } + } }, + // Get TX state response + { protocol::AcmpMessageType::GetTxStateResponse.getValue(), + [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::ControlStatus const status, protocol::Acmpdu const& acmp, LocalEntityImpl<>::AnswerCallback const& answerCallback, bool const sniffed) + { + auto const talkerEntityID = acmp.getControllerEntityID(); + auto const talkerStreamIndex = acmp.getTalkerUniqueID(); + auto const listenerEntityID = acmp.getListenerEntityID(); + auto const listenerStreamIndex = acmp.getListenerUniqueID(); + auto const connectionCount = acmp.getConnectionCount(); + auto const flags = acmp.getFlags(); + answerCallback.invoke(talkerInterface, model::StreamIdentification{ talkerEntityID, talkerStreamIndex }, model::StreamIdentification{ listenerEntityID, listenerStreamIndex }, connectionCount, flags, status); + if (sniffed && delegate) + { + utils::invokeProtectedMethod(&talker::Delegate::onGetTalkerStreamStateResponseSniffed, delegate, talkerInterface, model::StreamIdentification{ talkerEntityID, talkerStreamIndex }, model::StreamIdentification{ listenerEntityID, listenerStreamIndex }, connectionCount, flags, status); + } + } }, + // Connect RX response + { protocol::AcmpMessageType::ConnectRxResponse.getValue(), + [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::ControlStatus const status, protocol::Acmpdu const& acmp, LocalEntityImpl<>::AnswerCallback const& answerCallback, bool const sniffed) + { + auto const talkerEntityID = acmp.getControllerEntityID(); + auto const talkerStreamIndex = acmp.getTalkerUniqueID(); + auto const listenerEntityID = acmp.getListenerEntityID(); + auto const listenerStreamIndex = acmp.getListenerUniqueID(); + auto const connectionCount = acmp.getConnectionCount(); + auto const flags = acmp.getFlags(); + answerCallback.invoke(talkerInterface, model::StreamIdentification{ talkerEntityID, talkerStreamIndex }, model::StreamIdentification{ listenerEntityID, listenerStreamIndex }, connectionCount, flags, status); + if (sniffed && delegate) + { + utils::invokeProtectedMethod(&talker::Delegate::onTalkerConnectResponseSniffed, delegate, talkerInterface, model::StreamIdentification{ talkerEntityID, talkerStreamIndex }, model::StreamIdentification{ listenerEntityID, listenerStreamIndex }, connectionCount, flags, status); + } + } }, + // Disconnect RX response + { protocol::AcmpMessageType::DisconnectRxResponse.getValue(), + [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::ControlStatus const status, protocol::Acmpdu const& acmp, LocalEntityImpl<>::AnswerCallback const& answerCallback, bool const sniffed) + { + auto const talkerEntityID = acmp.getControllerEntityID(); + auto const talkerStreamIndex = acmp.getTalkerUniqueID(); + auto const listenerEntityID = acmp.getListenerEntityID(); + auto const listenerStreamIndex = acmp.getListenerUniqueID(); + auto const connectionCount = acmp.getConnectionCount(); + auto const flags = acmp.getFlags(); + answerCallback.invoke(talkerInterface, model::StreamIdentification{ talkerEntityID, talkerStreamIndex }, model::StreamIdentification{ listenerEntityID, listenerStreamIndex }, connectionCount, flags, status); + if (sniffed && delegate) + { + utils::invokeProtectedMethod(&talker::Delegate::onTalkerDisconnectResponseSniffed, delegate, talkerInterface, model::StreamIdentification{ talkerEntityID, talkerStreamIndex }, model::StreamIdentification{ listenerEntityID, listenerStreamIndex }, connectionCount, flags, status); + } + } }, + // Get RX state response + { protocol::AcmpMessageType::GetRxStateResponse.getValue(), + [](talker::Delegate* const delegate, Interface const* const talkerInterface, LocalEntity::ControlStatus const status, protocol::Acmpdu const& acmp, LocalEntityImpl<>::AnswerCallback const& answerCallback, bool const sniffed) + { + auto const talkerEntityID = acmp.getControllerEntityID(); + auto const talkerStreamIndex = acmp.getTalkerUniqueID(); + auto const listenerEntityID = acmp.getListenerEntityID(); + auto const listenerStreamIndex = acmp.getListenerUniqueID(); + auto const connectionCount = acmp.getConnectionCount(); + auto const flags = acmp.getFlags(); + answerCallback.invoke(talkerInterface, model::StreamIdentification{ talkerEntityID, talkerStreamIndex }, model::StreamIdentification{ listenerEntityID, listenerStreamIndex }, connectionCount, flags, status); + if (sniffed && delegate) + { + utils::invokeProtectedMethod(&talker::Delegate::onGetListenerStreamStateResponseSniffed, delegate, talkerInterface, model::StreamIdentification{ talkerEntityID, talkerStreamIndex }, model::StreamIdentification{ listenerEntityID, listenerStreamIndex }, connectionCount, flags, status); + } + } }, + // Get TX connection response + { protocol::AcmpMessageType::GetTxConnectionResponse.getValue(), + [](talker::Delegate* const /*delegate*/, Interface const* const talkerInterface, LocalEntity::ControlStatus const status, protocol::Acmpdu const& acmp, LocalEntityImpl<>::AnswerCallback const& answerCallback, bool const /*sniffed*/) + { + auto const talkerEntityID = acmp.getControllerEntityID(); + auto const talkerStreamIndex = acmp.getTalkerUniqueID(); + auto const listenerEntityID = acmp.getListenerEntityID(); + auto const listenerStreamIndex = acmp.getListenerUniqueID(); + auto const connectionCount = acmp.getConnectionCount(); + auto const flags = acmp.getFlags(); + answerCallback.invoke(talkerInterface, model::StreamIdentification{ talkerEntityID, talkerStreamIndex }, model::StreamIdentification{ listenerEntityID, listenerStreamIndex }, connectionCount, flags, status); + } }, + }; + + auto const& it = s_Dispatch.find(acmp.getMessageType().getValue()); + if (it == s_Dispatch.end()) + { + // If this is a sniffed message, simply log we do not handle the message + if (sniffed) + { + LOG_CONTROLLER_ENTITY_DEBUG(acmp.getControllerEntityID(), "ACMP response {} not handled ({})", std::string(acmp.getMessageType()), utils::toHexString(acmp.getMessageType().getValue())); + } + // But if it's an expected response, this is an internal error since we sent a command and didn't implement the code to handle the response + else + { + LOG_CONTROLLER_ENTITY_ERROR(acmp.getControllerEntityID(), "Failed to process ACMP response: Unhandled message type {} ({})", std::string(acmp.getMessageType()), utils::toHexString(acmp.getMessageType().getValue())); + utils::invokeProtectedHandler(onErrorCallback, LocalEntity::ControlStatus::InternalError); + } + } + else + { + try + { + it->second(_talkerDelegate, &_talkerInterface, status, acmp, answerCallback, sniffed); + } + catch ([[maybe_unused]] std::exception const& e) // Mainly unpacking errors + { + LOG_CONTROLLER_ENTITY_ERROR(acmp.getControllerEntityID(), "Failed to process ACMP response: {}", e.what()); + utils::invokeProtectedHandler(onErrorCallback, LocalEntity::ControlStatus::ProtocolError); + return; + } + } +} + +} // namespace talker +} // namespace entity +} // namespace avdecc +} // namespace la diff --git a/src/entity/talkerCapabilityDelegate.hpp b/src/entity/talkerCapabilityDelegate.hpp new file mode 100644 index 00000000..e9ca18e0 --- /dev/null +++ b/src/entity/talkerCapabilityDelegate.hpp @@ -0,0 +1,222 @@ +/* +* Copyright (C) 2016-2020, L-Acoustics and its contributors + +* This file is part of LA_avdecc. + +* LA_avdecc is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. + +* LA_avdecc is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. + +* You should have received a copy of the GNU Lesser General Public License +* along with LA_avdecc. If not, see . +*/ + +/** +* @file talkerCapabilityDelegate.hpp +* @author Christophe Calmejane +*/ + +#pragma once + +#include "la/avdecc/internals/talkerEntity.hpp" + +#include "entityImpl.hpp" + +namespace la +{ +namespace avdecc +{ +namespace entity +{ +namespace talker +{ +class CapabilityDelegate final : public entity::CapabilityDelegate +{ +public: + /* ************************************************************************** */ + /* CapabilityDelegate life cycle */ + /* ************************************************************************** */ + CapabilityDelegate(protocol::ProtocolInterface* const protocolInterface, talker::Delegate* talkerDelegate, Interface& talkerInterface, UniqueIdentifier const talkerID) noexcept; + virtual ~CapabilityDelegate() noexcept; + + /* ************************************************************************** */ + /* Talker methods */ + /* ************************************************************************** */ + /* Discovery Protocol (ADP) */ + /* Enumeration and Control Protocol (AECP) AEM */ + void acquireEntity(UniqueIdentifier const targetEntityID, bool const isPersistent, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, Interface::AcquireEntityHandler const& handler) const noexcept; + void releaseEntity(UniqueIdentifier const targetEntityID, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, Interface::ReleaseEntityHandler const& handler) const noexcept; + void lockEntity(UniqueIdentifier const targetEntityID, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, Interface::LockEntityHandler const& handler) const noexcept; + void unlockEntity(UniqueIdentifier const targetEntityID, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, Interface::UnlockEntityHandler const& handler) const noexcept; + void queryEntityAvailable(UniqueIdentifier const targetEntityID, Interface::QueryEntityAvailableHandler const& handler) const noexcept; + void queryTalkerAvailable(UniqueIdentifier const targetEntityID, Interface::QueryTalkerAvailableHandler const& handler) const noexcept; + void registerUnsolicitedNotifications(UniqueIdentifier const targetEntityID, Interface::RegisterUnsolicitedNotificationsHandler const& handler) const noexcept; + void unregisterUnsolicitedNotifications(UniqueIdentifier const targetEntityID, Interface::UnregisterUnsolicitedNotificationsHandler const& handler) const noexcept; + void readEntityDescriptor(UniqueIdentifier const targetEntityID, Interface::EntityDescriptorHandler const& handler) const noexcept; + void readConfigurationDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, Interface::ConfigurationDescriptorHandler const& handler) const noexcept; + void readAudioUnitDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::AudioUnitIndex const audioUnitIndex, Interface::AudioUnitDescriptorHandler const& handler) const noexcept; + void readStreamInputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, Interface::StreamInputDescriptorHandler const& handler) const noexcept; + void readStreamOutputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, Interface::StreamOutputDescriptorHandler const& handler) const noexcept; + void readJackInputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::JackIndex const jackIndex, Interface::JackInputDescriptorHandler const& handler) const noexcept; + void readJackOutputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::JackIndex const jackIndex, Interface::JackOutputDescriptorHandler const& handler) const noexcept; + void readAvbInterfaceDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::AvbInterfaceIndex const avbInterfaceIndex, Interface::AvbInterfaceDescriptorHandler const& handler) const noexcept; + void readClockSourceDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClockSourceIndex const clockSourceIndex, Interface::ClockSourceDescriptorHandler const& handler) const noexcept; + void readMemoryObjectDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::MemoryObjectIndex const memoryObjectIndex, Interface::MemoryObjectDescriptorHandler const& handler) const noexcept; + void readLocaleDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::LocaleIndex const localeIndex, Interface::LocaleDescriptorHandler const& handler) const noexcept; + void readStringsDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StringsIndex const stringsIndex, Interface::StringsDescriptorHandler const& handler) const noexcept; + void readStreamPortInputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamPortIndex const streamPortIndex, Interface::StreamPortInputDescriptorHandler const& handler) const noexcept; + void readStreamPortOutputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamPortIndex const streamPortIndex, Interface::StreamPortOutputDescriptorHandler const& handler) const noexcept; + void readExternalPortInputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ExternalPortIndex const externalPortIndex, Interface::ExternalPortInputDescriptorHandler const& handler) const noexcept; + void readExternalPortOutputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ExternalPortIndex const externalPortIndex, Interface::ExternalPortOutputDescriptorHandler const& handler) const noexcept; + void readInternalPortInputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::InternalPortIndex const internalPortIndex, Interface::InternalPortInputDescriptorHandler const& handler) const noexcept; + void readInternalPortOutputDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::InternalPortIndex const internalPortIndex, Interface::InternalPortOutputDescriptorHandler const& handler) const noexcept; + void readAudioClusterDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClusterIndex const clusterIndex, Interface::AudioClusterDescriptorHandler const& handler) const noexcept; + void readAudioMapDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::MapIndex const mapIndex, Interface::AudioMapDescriptorHandler const& handler) const noexcept; + void readClockDomainDescriptor(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClockDomainIndex const clockDomainIndex, Interface::ClockDomainDescriptorHandler const& handler) const noexcept; + void setConfiguration(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, Interface::SetConfigurationHandler const& handler) const noexcept; + void getConfiguration(UniqueIdentifier const targetEntityID, Interface::GetConfigurationHandler const& handler) const noexcept; + void setStreamInputFormat(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, model::StreamFormat const streamFormat, Interface::SetStreamInputFormatHandler const& handler) const noexcept; + void getStreamInputFormat(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::GetStreamInputFormatHandler const& handler) const noexcept; + void setStreamOutputFormat(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, model::StreamFormat const streamFormat, Interface::SetStreamOutputFormatHandler const& handler) const noexcept; + void getStreamOutputFormat(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::GetStreamOutputFormatHandler const& handler) const noexcept; + void getStreamPortInputAudioMap(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::MapIndex const mapIndex, Interface::GetStreamPortInputAudioMapHandler const& handler) const noexcept; + void getStreamPortOutputAudioMap(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::MapIndex const mapIndex, Interface::GetStreamPortOutputAudioMapHandler const& handler) const noexcept; + void addStreamPortInputAudioMappings(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::AudioMappings const& mappings, Interface::AddStreamPortInputAudioMappingsHandler const& handler) const noexcept; + void addStreamPortOutputAudioMappings(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::AudioMappings const& mappings, Interface::AddStreamPortOutputAudioMappingsHandler const& handler) const noexcept; + void removeStreamPortInputAudioMappings(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::AudioMappings const& mappings, Interface::RemoveStreamPortInputAudioMappingsHandler const& handler) const noexcept; + void removeStreamPortOutputAudioMappings(UniqueIdentifier const targetEntityID, model::StreamPortIndex const streamPortIndex, model::AudioMappings const& mappings, Interface::RemoveStreamPortOutputAudioMappingsHandler const& handler) const noexcept; + void setStreamInputInfo(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, model::StreamInfo const& info, Interface::SetStreamInputInfoHandler const& handler) const noexcept; + void setStreamOutputInfo(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, model::StreamInfo const& info, Interface::SetStreamOutputInfoHandler const& handler) const noexcept; + void getStreamInputInfo(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::GetStreamInputInfoHandler const& handler) const noexcept; + void getStreamOutputInfo(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::GetStreamOutputInfoHandler const& handler) const noexcept; + void setEntityName(UniqueIdentifier const targetEntityID, model::AvdeccFixedString const& entityName, Interface::SetEntityNameHandler const& handler) const noexcept; + void getEntityName(UniqueIdentifier const targetEntityID, Interface::GetEntityNameHandler const& handler) const noexcept; + void setEntityGroupName(UniqueIdentifier const targetEntityID, model::AvdeccFixedString const& entityGroupName, Interface::SetEntityGroupNameHandler const& handler) const noexcept; + void getEntityGroupName(UniqueIdentifier const targetEntityID, Interface::GetEntityGroupNameHandler const& handler) const noexcept; + void setConfigurationName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::AvdeccFixedString const& configurationName, Interface::SetConfigurationNameHandler const& handler) const noexcept; + void getConfigurationName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, Interface::GetConfigurationNameHandler const& handler) const noexcept; + void setAudioUnitName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::AudioUnitIndex const audioUnitIndex, model::AvdeccFixedString const& audioUnitName, Interface::SetAudioUnitNameHandler const& handler) const noexcept; + void getAudioUnitName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const audioUnitIndex, Interface::GetAudioUnitNameHandler const& handler) const noexcept; + void setStreamInputName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, model::AvdeccFixedString const& streamInputName, Interface::SetStreamInputNameHandler const& handler) const noexcept; + void getStreamInputName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, Interface::GetStreamInputNameHandler const& handler) const noexcept; + void setStreamOutputName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, model::AvdeccFixedString const& streamOutputName, Interface::SetStreamOutputNameHandler const& handler) const noexcept; + void getStreamOutputName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const streamIndex, Interface::GetStreamOutputNameHandler const& handler) const noexcept; + void setAvbInterfaceName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::AvbInterfaceIndex const avbInterfaceIndex, model::AvdeccFixedString const& avbInterfaceName, Interface::SetAvbInterfaceNameHandler const& handler) const noexcept; + void getAvbInterfaceName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const avbInterfaceIndex, Interface::GetAvbInterfaceNameHandler const& handler) const noexcept; + void setClockSourceName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClockSourceIndex const clockSourceIndex, model::AvdeccFixedString const& clockSourceName, Interface::SetClockSourceNameHandler const& handler) const noexcept; + void getClockSourceName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const clockSourceIndex, Interface::GetClockSourceNameHandler const& handler) const noexcept; + void setMemoryObjectName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::MemoryObjectIndex const memoryObjectIndex, model::AvdeccFixedString const& memoryObjectName, Interface::SetMemoryObjectNameHandler const& handler) const noexcept; + void getMemoryObjectName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const memoryObjectIndex, Interface::GetMemoryObjectNameHandler const& handler) const noexcept; + void setAudioClusterName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClusterIndex const audioClusterIndex, model::AvdeccFixedString const& audioClusterName, Interface::SetAudioClusterNameHandler const& handler) const noexcept; + void getAudioClusterName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const audioClusterIndex, Interface::GetAudioClusterNameHandler const& handler) const noexcept; + void setClockDomainName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::ClockDomainIndex const clockDomainIndex, model::AvdeccFixedString const& clockDomainName, Interface::SetClockDomainNameHandler const& handler) const noexcept; + void getClockDomainName(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::StreamIndex const clockDomainIndex, Interface::GetClockDomainNameHandler const& handler) const noexcept; + void setAudioUnitSamplingRate(UniqueIdentifier const targetEntityID, model::AudioUnitIndex const audioUnitIndex, model::SamplingRate const samplingRate, Interface::SetAudioUnitSamplingRateHandler const& handler) const noexcept; + void getAudioUnitSamplingRate(UniqueIdentifier const targetEntityID, model::AudioUnitIndex const audioUnitIndex, Interface::GetAudioUnitSamplingRateHandler const& handler) const noexcept; + void setVideoClusterSamplingRate(UniqueIdentifier const targetEntityID, model::ClusterIndex const videoClusterIndex, model::SamplingRate const samplingRate, Interface::SetVideoClusterSamplingRateHandler const& handler) const noexcept; + void getVideoClusterSamplingRate(UniqueIdentifier const targetEntityID, model::ClusterIndex const videoClusterIndex, Interface::GetVideoClusterSamplingRateHandler const& handler) const noexcept; + void setSensorClusterSamplingRate(UniqueIdentifier const targetEntityID, model::ClusterIndex const sensorClusterIndex, model::SamplingRate const samplingRate, Interface::SetSensorClusterSamplingRateHandler const& handler) const noexcept; + void getSensorClusterSamplingRate(UniqueIdentifier const targetEntityID, model::ClusterIndex const sensorClusterIndex, Interface::GetSensorClusterSamplingRateHandler const& handler) const noexcept; + void setClockSource(UniqueIdentifier const targetEntityID, model::ClockDomainIndex const clockDomainIndex, model::ClockSourceIndex const clockSourceIndex, Interface::SetClockSourceHandler const& handler) const noexcept; + void getClockSource(UniqueIdentifier const targetEntityID, model::ClockDomainIndex const clockDomainIndex, Interface::GetClockSourceHandler const& handler) const noexcept; + void startStreamInput(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::StartStreamInputHandler const& handler) const noexcept; + void startStreamOutput(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::StartStreamOutputHandler const& handler) const noexcept; + void stopStreamInput(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::StopStreamInputHandler const& handler) const noexcept; + void stopStreamOutput(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::StopStreamOutputHandler const& handler) const noexcept; + void getAvbInfo(UniqueIdentifier const targetEntityID, model::AvbInterfaceIndex const avbInterfaceIndex, Interface::GetAvbInfoHandler const& handler) const noexcept; + void getAsPath(UniqueIdentifier const targetEntityID, model::AvbInterfaceIndex const avbInterfaceIndex, Interface::GetAsPathHandler const& handler) const noexcept; + void getEntityCounters(UniqueIdentifier const targetEntityID, Interface::GetEntityCountersHandler const& handler) const noexcept; + void getAvbInterfaceCounters(UniqueIdentifier const targetEntityID, model::AvbInterfaceIndex const avbInterfaceIndex, Interface::GetAvbInterfaceCountersHandler const& handler) const noexcept; + void getClockDomainCounters(UniqueIdentifier const targetEntityID, model::ClockDomainIndex const clockDomainIndex, Interface::GetClockDomainCountersHandler const& handler) const noexcept; + void getStreamInputCounters(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::GetStreamInputCountersHandler const& handler) const noexcept; + void getStreamOutputCounters(UniqueIdentifier const targetEntityID, model::StreamIndex const streamIndex, Interface::GetStreamOutputCountersHandler const& handler) const noexcept; + void startOperation(UniqueIdentifier const targetEntityID, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, model::MemoryObjectOperationType const operationType, MemoryBuffer const& memoryBuffer, Interface::StartOperationHandler const& handler) const noexcept; + void abortOperation(UniqueIdentifier const targetEntityID, model::DescriptorType const descriptorType, model::DescriptorIndex const descriptorIndex, model::OperationID const operationID, Interface::AbortOperationHandler const& handler) const noexcept; + void setMemoryObjectLength(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::MemoryObjectIndex const memoryObjectIndex, std::uint64_t const length, Interface::SetMemoryObjectLengthHandler const& handler) const noexcept; + void getMemoryObjectLength(UniqueIdentifier const targetEntityID, model::ConfigurationIndex const configurationIndex, model::MemoryObjectIndex const memoryObjectIndex, Interface::GetMemoryObjectLengthHandler const& handler) const noexcept; + /* Enumeration and Control Protocol (AECP) AA */ + void addressAccess(UniqueIdentifier const targetEntityID, addressAccess::Tlvs const& tlvs, Interface::AddressAccessHandler const& handler) const noexcept; + /* Enumeration and Control Protocol (AECP) MVU (Milan Vendor Unique) */ + void getMilanInfo(UniqueIdentifier const targetEntityID, Interface::GetMilanInfoHandler const& handler) const noexcept; + /* Connection Management Protocol (ACMP) */ + void connectStream(model::StreamIdentification const& talkerStream, model::StreamIdentification const& listenerStream, Interface::ConnectStreamHandler const& handler) const noexcept; + void disconnectStream(model::StreamIdentification const& talkerStream, model::StreamIdentification const& listenerStream, Interface::DisconnectStreamHandler const& handler) const noexcept; + void disconnectTalkerStream(model::StreamIdentification const& talkerStream, model::StreamIdentification const& listenerStream, Interface::DisconnectTalkerStreamHandler const& handler) const noexcept; + void getTalkerStreamState(model::StreamIdentification const& talkerStream, Interface::GetTalkerStreamStateHandler const& handler) const noexcept; + void getListenerStreamState(model::StreamIdentification const& listenerStream, Interface::GetListenerStreamStateHandler const& handler) const noexcept; + void getTalkerStreamConnection(model::StreamIdentification const& talkerStream, std::uint16_t const connectionIndex, Interface::GetTalkerStreamConnectionHandler const& handler) const noexcept; + + /* ************************************************************************** */ + /* Talker notifications */ + /* ************************************************************************** */ + /* **** Statistics **** */ + void onAecpRetry(protocol::ProtocolInterface* const pi, UniqueIdentifier const& entityID) noexcept; + void onAecpTimeout(protocol::ProtocolInterface* const pi, UniqueIdentifier const& entityID) noexcept; + void onAecpUnexpectedResponse(protocol::ProtocolInterface* const pi, UniqueIdentifier const& entityID) noexcept; + void onAecpResponseTime(protocol::ProtocolInterface* const pi, UniqueIdentifier const& entityID, std::chrono::milliseconds const& responseTime) noexcept; + + // Deleted compiler auto-generated methods + CapabilityDelegate(CapabilityDelegate&&) = delete; + CapabilityDelegate(CapabilityDelegate const&) = delete; + CapabilityDelegate& operator=(CapabilityDelegate const&) = delete; + CapabilityDelegate& operator=(CapabilityDelegate&&) = delete; + +private: + using DiscoveredEntities = std::unordered_map; + + /* ************************************************************************** */ + /* CapabilityDelegate overrides */ + /* ************************************************************************** */ + /* **** Global notifications **** */ + virtual void onControllerDelegateChanged(controller::Delegate* const delegate) noexcept override; + //virtual void onListenerDelegateChanged(listener::Delegate* const delegate) noexcept override; + virtual void onTalkerDelegateChanged(talker::Delegate* const delegate) noexcept override; + virtual void onTransportError(protocol::ProtocolInterface* const pi) noexcept override; + /* **** Discovery notifications **** */ + virtual void onLocalEntityOnline(protocol::ProtocolInterface* const pi, Entity const& entity) noexcept override; + virtual void onLocalEntityOffline(protocol::ProtocolInterface* const pi, UniqueIdentifier const entityID) noexcept override; + virtual void onLocalEntityUpdated(protocol::ProtocolInterface* const pi, Entity const& entity) noexcept override; + virtual void onRemoteEntityOnline(protocol::ProtocolInterface* const pi, Entity const& entity) noexcept override; + virtual void onRemoteEntityOffline(protocol::ProtocolInterface* const pi, UniqueIdentifier const entityID) noexcept override; + virtual void onRemoteEntityUpdated(protocol::ProtocolInterface* const pi, Entity const& entity) noexcept override; + /* **** AECP notifications **** */ + virtual bool onUnhandledAecpCommand(protocol::ProtocolInterface* const pi, protocol::Aecpdu const& aecpdu) noexcept override; + virtual void onAecpAemUnsolicitedResponse(protocol::ProtocolInterface* const pi, protocol::AemAecpdu const& aecpdu) noexcept override; + virtual void onAecpAemIdentifyNotification(protocol::ProtocolInterface* const pi, protocol::AemAecpdu const& aecpdu) noexcept override; + /* **** ACMP notifications **** */ + virtual void onAcmpCommand(protocol::ProtocolInterface* const pi, protocol::Acmpdu const& acmpdu) noexcept override; + virtual void onAcmpResponse(protocol::ProtocolInterface* const pi, protocol::Acmpdu const& acmpdu) noexcept override; + + /* ************************************************************************** */ + /* Internal methods */ + /* ************************************************************************** */ + bool isResponseForTalker(protocol::AcmpMessageType const messageType) const noexcept; + void sendAemAecpCommand(UniqueIdentifier const targetEntityID, protocol::AemCommandType const commandType, void const* const payload, size_t const payloadLength, LocalEntityImpl<>::OnAemAECPErrorCallback const& onErrorCallback, LocalEntityImpl<>::AnswerCallback const& answerCallback) const noexcept; + void sendAaAecpCommand(UniqueIdentifier const targetEntityID, addressAccess::Tlvs const& tlvs, LocalEntityImpl<>::OnAaAECPErrorCallback const& onErrorCallback, LocalEntityImpl<>::AnswerCallback const& answerCallback) const noexcept; + void sendMvuAecpCommand(UniqueIdentifier const targetEntityID, protocol::MvuCommandType const commandType, void const* const payload, size_t const payloadLength, LocalEntityImpl<>::OnMvuAECPErrorCallback const& onErrorCallback, LocalEntityImpl<>::AnswerCallback const& answerCallback) const noexcept; + void sendAcmpCommand(protocol::AcmpMessageType const messageType, UniqueIdentifier const talkerEntityID, model::StreamIndex const talkerStreamIndex, UniqueIdentifier const listenerEntityID, model::StreamIndex const listenerStreamIndex, std::uint16_t const connectionIndex, LocalEntityImpl<>::OnACMPErrorCallback const& onErrorCallback, LocalEntityImpl<>::AnswerCallback const& answerCallback) const noexcept; + void processAemAecpResponse(protocol::Aecpdu const* const response, LocalEntityImpl<>::OnAemAECPErrorCallback const& onErrorCallback, LocalEntityImpl<>::AnswerCallback const& answerCallback) const noexcept; + void processAaAecpResponse(protocol::Aecpdu const* const response, LocalEntityImpl<>::OnAaAECPErrorCallback const& onErrorCallback, LocalEntityImpl<>::AnswerCallback const& answerCallback) const noexcept; + void processMvuAecpResponse(protocol::Aecpdu const* const response, LocalEntityImpl<>::OnMvuAECPErrorCallback const& onErrorCallback, LocalEntityImpl<>::AnswerCallback const& answerCallback) const noexcept; + void processAcmpResponse(protocol::Acmpdu const* const response, LocalEntityImpl<>::OnACMPErrorCallback const& onErrorCallback, LocalEntityImpl<>::AnswerCallback const& answerCallback, bool const sniffed) const noexcept; + + /* ************************************************************************** */ + /* Internal variables */ + /* ************************************************************************** */ + protocol::ProtocolInterface* const _protocolInterface{ nullptr }; + talker::Delegate* _talkerDelegate{ nullptr }; + Interface& _talkerInterface; + UniqueIdentifier const _talkerID{ UniqueIdentifier::getNullUniqueIdentifier() }; + DiscoveredEntities _discoveredEntities{}; +}; + +} // namespace talker +} // namespace entity +} // namespace avdecc +} // namespace la diff --git a/src/pch.hpp b/src/pch.hpp index f49d29a7..032f131a 100644 --- a/src/pch.hpp +++ b/src/pch.hpp @@ -31,6 +31,7 @@ #include "la/avdecc/watchDog.hpp" #include "la/avdecc/internals/aggregateEntity.hpp" #include "la/avdecc/internals/controllerEntity.hpp" +#include "la/avdecc/internals/talkerEntity.hpp" #include "la/avdecc/internals/endStation.hpp" #include "la/avdecc/internals/entity.hpp" #include "la/avdecc/internals/entityModel.hpp" @@ -64,6 +65,7 @@ #include "endStationImpl.hpp" #include "entity/aggregateEntityImpl.hpp" #include "entity/controllerCapabilityDelegate.hpp" +#include "entity/talkerCapabilityDelegate.hpp" #include "entity/controllerEntityImpl.hpp" #include "entity/entityImpl.hpp" #include "protocol/protocolAemPayloads.hpp" diff --git a/src/protocolInterface/protocolInterface_macNative.mm b/src/protocolInterface/protocolInterface_macNative.mm index a2ac4561..64ddfb68 100644 --- a/src/protocolInterface/protocolInterface_macNative.mm +++ b/src/protocolInterface/protocolInterface_macNative.mm @@ -67,7 +67,8 @@ @interface FromNative : NSObject #pragma mark - FromNative Implementation @implementation FromNative -+ (la::avdecc::networkInterface::MacAddress)getFirstMacAddress:(NSArray*)array { ++ (la::avdecc::networkInterface::MacAddress)getFirstMacAddress:(NSArray*)array +{ la::avdecc::networkInterface::MacAddress mac; if (array.count > 0) @@ -86,7 +87,8 @@ @implementation FromNative return mac; } -+ (la::avdecc::entity::Entity)makeEntity:(AVB17221Entity*)entity { ++ (la::avdecc::entity::Entity)makeEntity:(AVB17221Entity*)entity +{ auto entityCaps = la::avdecc::entity::EntityCapabilities{}; entityCaps.assign(static_cast(entity.entityCapabilities)); auto talkerCaps = la::avdecc::entity::TalkerCapabilities{}; @@ -125,7 +127,8 @@ @implementation FromNative return la::avdecc::entity::Entity{ commonInfo, { { avbInterfaceIndex, interfaceInfo } } }; } -+ (la::avdecc::protocol::AemAecpdu::UniquePointer)makeAemAecpdu:(AVB17221AECPAEMMessage*)message toDestAddress:(la::avdecc::networkInterface::MacAddress const&)destAddress isResponse:(bool)isResponse { ++ (la::avdecc::protocol::AemAecpdu::UniquePointer)makeAemAecpdu:(AVB17221AECPAEMMessage*)message toDestAddress:(la::avdecc::networkInterface::MacAddress const&)destAddress isResponse:(bool)isResponse +{ auto aemAecpdu = la::avdecc::protocol::AemAecpdu::create(isResponse); auto& aem = static_cast(*aemAecpdu); @@ -148,7 +151,8 @@ @implementation FromNative return aemAecpdu; } -+ (la::avdecc::protocol::AaAecpdu::UniquePointer)makeAaAecpdu:(AVB17221AECPAddressAccessMessage*)message toDestAddress:(la::avdecc::networkInterface::MacAddress const&)destAddress isResponse:(bool)isResponse { ++ (la::avdecc::protocol::AaAecpdu::UniquePointer)makeAaAecpdu:(AVB17221AECPAddressAccessMessage*)message toDestAddress:(la::avdecc::networkInterface::MacAddress const&)destAddress isResponse:(bool)isResponse +{ auto aaAecpdu = la::avdecc::protocol::AaAecpdu::create(isResponse); auto& aa = static_cast(*aaAecpdu); @@ -171,12 +175,14 @@ @implementation FromNative return aaAecpdu; } -+ (la::avdecc::protocol::VuAecpdu::UniquePointer)makeVendorUniqueAecpdu:(AVB17221AECPVendorMessage*)message toDestAddress:(la::avdecc::networkInterface::MacAddress const&)destAddress isResponse:(bool)isResponse { ++ (la::avdecc::protocol::VuAecpdu::UniquePointer)makeVendorUniqueAecpdu:(AVB17221AECPVendorMessage*)message toDestAddress:(la::avdecc::networkInterface::MacAddress const&)destAddress isResponse:(bool)isResponse +{ #pragma message("TODO") return la::avdecc::protocol::VuAecpdu::UniquePointer{ nullptr, nullptr }; } -+ (la::avdecc::protocol::Aecpdu::UniquePointer)makeAecpdu:(AVB17221AECPMessage*)message toDestAddress:(la::avdecc::networkInterface::MacAddress const&)destAddress { ++ (la::avdecc::protocol::Aecpdu::UniquePointer)makeAecpdu:(AVB17221AECPMessage*)message toDestAddress:(la::avdecc::networkInterface::MacAddress const&)destAddress +{ switch ([message messageType]) { case AVB17221AECPMessageTypeAEMCommand: @@ -198,7 +204,8 @@ @implementation FromNative return { nullptr, nullptr }; } -+ (la::avdecc::protocol::Acmpdu::UniquePointer)makeAcmpdu:(AVB17221ACMPMessage*)message { ++ (la::avdecc::protocol::Acmpdu::UniquePointer)makeAcmpdu:(AVB17221ACMPMessage*)message +{ auto acmpdu = la::avdecc::protocol::Acmpdu::create(); auto& acmp = static_cast(*acmpdu); @@ -227,7 +234,8 @@ @implementation FromNative return acmpdu; } -+ (la::avdecc::networkInterface::MacAddress)makeMacAddress:(AVBMACAddress*)macAddress { ++ (la::avdecc::networkInterface::MacAddress)makeMacAddress:(AVBMACAddress*)macAddress +{ la::avdecc::networkInterface::MacAddress mac; auto const* data = [macAddress dataRepresentation]; auto const bufferSize = mac.size() * sizeof(la::avdecc::networkInterface::MacAddress::value_type); @@ -238,7 +246,8 @@ @implementation FromNative return mac; } -+ (la::avdecc::protocol::ProtocolInterface::Error)getProtocolError:(NSError*)error { ++ (la::avdecc::protocol::ProtocolInterface::Error)getProtocolError:(NSError*)error +{ if ([[error domain] isEqualToString:AVBErrorDomain]) { auto const code = IOReturn(error.code); @@ -277,7 +286,8 @@ + (AVBMACAddress*)makeAVBMacAddress:(la::avdecc::networkInterface::MacAddress co #pragma mark - ToNative Implementation @implementation ToNative -+ (AVB17221Entity*)makeAVB17221Entity:(la::avdecc::entity::Entity const&)entity interfaceIndex:(la::avdecc::entity::model::AvbInterfaceIndex)interfaceIndex { ++ (AVB17221Entity*)makeAVB17221Entity:(la::avdecc::entity::Entity const&)entity interfaceIndex:(la::avdecc::entity::model::AvbInterfaceIndex)interfaceIndex +{ auto& interfaceInfo = entity.getInterfaceInformation(interfaceIndex); auto entityCaps{ entity.getEntityCapabilities() }; auto identifyControlIndex{ la::avdecc::entity::model::ControlIndex{ 0u } }; @@ -355,7 +365,8 @@ + (AVB17221Entity*)makeAVB17221Entity:(la::avdecc::entity::Entity const&)entity return e; } -+ (AVB17221AECPAEMMessage*)makeAemMessage:(la::avdecc::protocol::AemAecpdu const&)aecpdu isResponse:(bool)isResponse { ++ (AVB17221AECPAEMMessage*)makeAemMessage:(la::avdecc::protocol::AemAecpdu const&)aecpdu isResponse:(bool)isResponse +{ auto* message = static_cast(nullptr); if (isResponse) @@ -383,7 +394,8 @@ + (AVB17221AECPAEMMessage*)makeAemMessage:(la::avdecc::protocol::AemAecpdu const return message; } -+ (AVB17221AECPAddressAccessMessage*)makeAaMessage:(la::avdecc::protocol::AaAecpdu const&)aecpdu isResponse:(bool)isResponse { ++ (AVB17221AECPAddressAccessMessage*)makeAaMessage:(la::avdecc::protocol::AaAecpdu const&)aecpdu isResponse:(bool)isResponse +{ auto* message = static_cast(nullptr); if (isResponse) @@ -412,7 +424,8 @@ + (AVB17221AECPAddressAccessMessage*)makeAaMessage:(la::avdecc::protocol::AaAecp return message; } -+ (AVB17221AECPVendorMessage*)makeVendorUniqueMessage:(la::avdecc::protocol::VuAecpdu const&)aecpdu isResponse:(bool)isResponse { ++ (AVB17221AECPVendorMessage*)makeVendorUniqueMessage:(la::avdecc::protocol::VuAecpdu const&)aecpdu isResponse:(bool)isResponse +{ auto const message = [[AVB17221AECPVendorMessage alloc] init]; #if !__has_feature(objc_arc) [message autorelease]; @@ -447,7 +460,8 @@ + (AVB17221AECPVendorMessage*)makeVendorUniqueMessage:(la::avdecc::protocol::VuA return message; } -+ (AVB17221AECPMessage*)makeAecpMessage:(la::avdecc::protocol::Aecpdu const&)message { ++ (AVB17221AECPMessage*)makeAecpMessage:(la::avdecc::protocol::Aecpdu const&)message +{ switch (static_cast(message.getMessageType().getValue())) { case AVB17221AECPMessageTypeAEMCommand: @@ -469,7 +483,8 @@ + (AVB17221AECPMessage*)makeAecpMessage:(la::avdecc::protocol::Aecpdu const&)mes return NULL; } -+ (AVBMACAddress*)makeAVBMacAddress:(la::avdecc::networkInterface::MacAddress const&)macAddress { ++ (AVBMACAddress*)makeAVBMacAddress:(la::avdecc::networkInterface::MacAddress const&)macAddress +{ auto* mac = [[AVBMACAddress alloc] initWithBytes:macAddress.data()]; #if !__has_feature(objc_arc) [mac autorelease]; @@ -824,14 +839,16 @@ virtual void onAcmpResponse(la::avdecc::protocol::Acmpdu const& acmpdu) noexcept #pragma mark - BridgeInterface Implementation @implementation BridgeInterface -- (EntityQueues const&)createQueuesForRemoteEntity:(la::avdecc::UniqueIdentifier)entityID { +- (EntityQueues const&)createQueuesForRemoteEntity:(la::avdecc::UniqueIdentifier)entityID +{ EntityQueues eq; eq.aecpQueue = dispatch_queue_create([[NSString stringWithFormat:@"%@.0x%016llx.aecp", [self className], entityID.getValue()] UTF8String], 0); eq.aecpLimiter = dispatch_semaphore_create(la::avdecc::protocol::Aecpdu::DefaultMaxInflightCommands); return _entityQueues[entityID] = std::move(eq); } -+ (BOOL)isSupported { ++ (BOOL)isSupported +{ if ([NSProcessInfo instancesRespondToSelector:@selector(isOperatingSystemAtLeastVersion:)]) { // Minimum required version is macOS 10.11.0 (El Capitan) @@ -842,25 +859,30 @@ + (BOOL)isSupported { } /** std::string to NSString conversion */ -+ (NSString*)getNSString:(std::string const&)cString { ++ (NSString*)getNSString:(std::string const&)cString +{ return [NSString stringWithCString:cString.c_str() encoding:NSUTF8StringEncoding]; } /** NSString to std::string conversion */ -+ (std::string)getStdString:(NSString*)nsString { ++ (std::string)getStdString:(NSString*)nsString +{ return std::string{ [nsString UTF8String] }; } -+ (NSString*)getEntityCapabilities:(AVB17221Entity*)entity { ++ (NSString*)getEntityCapabilities:(AVB17221Entity*)entity +{ return [NSString stringWithFormat:@"%@ %@ %@", (entity.talkerCapabilities & AVB17221ADPTalkerCapabilitiesImplemented) ? @"Talker" : @"", (entity.listenerCapabilities & AVB17221ADPListenerCapabilitiesImplemented) ? @"Listener" : @"", (entity.controllerCapabilities & AVB17221ADPControllerCapabilitiesImplemented) ? @"Controller" : @""]; } -- (void)startAsyncOperation { +- (void)startAsyncOperation +{ std::lock_guard const lg(_lockPending); _pendingCommands++; } -- (void)stopAsyncOperation { +- (void)stopAsyncOperation +{ { std::lock_guard const lg(_lockPending); AVDECC_ASSERT(_pendingCommands > 0, "Trying to stop async operation, but there is no pending operation"); @@ -869,7 +891,8 @@ - (void)stopAsyncOperation { _pendingCondVar.notify_all(); } -- (void)waitAsyncOperations { +- (void)waitAsyncOperations +{ // Wait for all remaining async operations to complete std::unique_lock sync_lg(_lockPending); _pendingCondVar.wait(sync_lg, @@ -880,7 +903,8 @@ - (void)waitAsyncOperations { AVDECC_ASSERT(_pendingCommands == 0, "Waited for pending operations to complete, but there is some remaining one!"); } -- (std::optional)getMatchingInterfaceIndex:(la::avdecc::entity::LocalEntity const&)entity { +- (std::optional)getMatchingInterfaceIndex:(la::avdecc::entity::LocalEntity const&)entity +{ auto avbInterfaceIndex = std::optional{ std::nullopt }; auto const& macAddress = _protocolInterface->getMacAddress(); @@ -897,7 +921,8 @@ - (void)waitAsyncOperations { } /** Initializer */ -- (id)initWithInterfaceName:(NSString*)interfaceName andProtocolInterface:(la::avdecc::protocol::ProtocolInterfaceMacNativeImpl*)protocolInterface { +- (id)initWithInterfaceName:(NSString*)interfaceName andProtocolInterface:(la::avdecc::protocol::ProtocolInterfaceMacNativeImpl*)protocolInterface +{ self = [super init]; if (self) { @@ -911,7 +936,8 @@ - (id)initWithInterfaceName:(NSString*)interfaceName andProtocolInterface:(la::a } /** Deinit method to shutdown every pending operations */ -- (void)deinit { +- (void)deinit +{ // Remove discovery delegate self.interface.entityDiscovery.discoveryDelegate = nil; @@ -949,7 +975,8 @@ - (void)deinit { } /** Destructor */ -- (void)dealloc { +- (void)dealloc +{ [self deinit]; #if !__has_feature(objc_arc) [super dealloc]; @@ -957,16 +984,19 @@ - (void)dealloc { } #pragma mark la::avdecc::protocol::ProtocolInterface bridge methods -- (la::avdecc::UniqueIdentifier)getDynamicEID { +- (la::avdecc::UniqueIdentifier)getDynamicEID +{ return la::avdecc::UniqueIdentifier{ [AVBCentralManager nextAvailableDynamicEntityID] }; } -- (void)releaseDynamicEID:(la::avdecc::UniqueIdentifier)entityID { +- (void)releaseDynamicEID:(la::avdecc::UniqueIdentifier)entityID +{ [AVBCentralManager releaseDynamicEntityID:entityID]; } // Registration of a local process entity (an entity declared inside this process, not all local computer entities) -- (la::avdecc::protocol::ProtocolInterface::Error)registerLocalEntity:(la::avdecc::entity::LocalEntity&)entity { +- (la::avdecc::protocol::ProtocolInterface::Error)registerLocalEntity:(la::avdecc::entity::LocalEntity&)entity +{ // Lock entities now, so we don't get interrupted during registration auto const lg = std::lock_guard{ _lock }; @@ -1002,7 +1032,8 @@ - (void)releaseDynamicEID:(la::avdecc::UniqueIdentifier)entityID { } // Remove handlers for a local process entity -- (void)removeLocalProcessEntityHandlers:(la::avdecc::entity::LocalEntity const&)entity { +- (void)removeLocalProcessEntityHandlers:(la::avdecc::entity::LocalEntity const&)entity +{ auto const entityID = entity.getEntityID(); // Entity is controller capable @@ -1015,7 +1046,8 @@ - (void)removeLocalProcessEntityHandlers:(la::avdecc::entity::LocalEntity const& } // Unregistration of a local process entity -- (la::avdecc::protocol::ProtocolInterface::Error)unregisterLocalEntity:(la::avdecc::entity::LocalEntity const&)entity { +- (la::avdecc::protocol::ProtocolInterface::Error)unregisterLocalEntity:(la::avdecc::entity::LocalEntity const&)entity +{ auto const entityID = entity.getEntityID(); // Remove handlers @@ -1036,7 +1068,8 @@ - (void)removeLocalProcessEntityHandlers:(la::avdecc::entity::LocalEntity const& return la::avdecc::protocol::ProtocolInterface::Error::NoError; } -- (la::avdecc::protocol::ProtocolInterface::Error)setEntityNeedsAdvertise:(const la::avdecc::entity::LocalEntity&)entity flags:(la::avdecc::entity::LocalEntity::AdvertiseFlags)flags { +- (la::avdecc::protocol::ProtocolInterface::Error)setEntityNeedsAdvertise:(const la::avdecc::entity::LocalEntity&)entity flags:(la::avdecc::entity::LocalEntity::AdvertiseFlags)flags +{ NSError* error{ nullptr }; // Change in GrandMaster @@ -1059,7 +1092,8 @@ - (void)removeLocalProcessEntityHandlers:(la::avdecc::entity::LocalEntity const& return la::avdecc::protocol::ProtocolInterface::Error::NoError; } -- (la::avdecc::protocol::ProtocolInterface::Error)enableEntityAdvertising:(la::avdecc::entity::LocalEntity const&)entity { +- (la::avdecc::protocol::ProtocolInterface::Error)enableEntityAdvertising:(la::avdecc::entity::LocalEntity const&)entity +{ NSError* error{ nullptr }; auto const interfaceIndex = [self getMatchingInterfaceIndex:entity]; @@ -1075,7 +1109,8 @@ - (void)removeLocalProcessEntityHandlers:(la::avdecc::entity::LocalEntity const& return la::avdecc::protocol::ProtocolInterface::Error::NoError; } -- (la::avdecc::protocol::ProtocolInterface::Error)disableEntityAdvertising:(la::avdecc::entity::LocalEntity const&)entity { +- (la::avdecc::protocol::ProtocolInterface::Error)disableEntityAdvertising:(la::avdecc::entity::LocalEntity const&)entity +{ NSError* error{ nullptr }; [self.interface.entityDiscovery removeLocalEntity:entity.getEntityID() error:&error]; @@ -1085,7 +1120,8 @@ - (void)removeLocalProcessEntityHandlers:(la::avdecc::entity::LocalEntity const& return la::avdecc::protocol::ProtocolInterface::Error::NoError; } -- (BOOL)discoverRemoteEntities { +- (BOOL)discoverRemoteEntities +{ if (!_primedDiscovery) { [self.interface.entityDiscovery primeIterators]; @@ -1095,7 +1131,8 @@ - (BOOL)discoverRemoteEntities { return [self.interface.entityDiscovery discoverEntities]; } -- (BOOL)discoverRemoteEntity:(la::avdecc::UniqueIdentifier)entityID { +- (BOOL)discoverRemoteEntity:(la::avdecc::UniqueIdentifier)entityID +{ if (!_primedDiscovery) { [self.interface.entityDiscovery primeIterators]; @@ -1105,7 +1142,8 @@ - (BOOL)discoverRemoteEntity:(la::avdecc::UniqueIdentifier)entityID { return [self.interface.entityDiscovery discoverEntity:entityID]; } -- (la::avdecc::protocol::ProtocolInterface::Error)sendAecpCommand:(la::avdecc::protocol::Aecpdu::UniquePointer&&)aecpdu handler:(la::avdecc::protocol::ProtocolInterface::AecpCommandResultHandler const&)onResult { +- (la::avdecc::protocol::ProtocolInterface::Error)sendAecpCommand:(la::avdecc::protocol::Aecpdu::UniquePointer&&)aecpdu handler:(la::avdecc::protocol::ProtocolInterface::AecpCommandResultHandler const&)onResult +{ auto const macAddr = aecpdu->getDestAddress(); // Make a copy of the target macAddress so it can safely be used inside the objC block __block auto resultHandler = onResult; // Make a copy of the handler so it can safely be used inside the objC block. Declare it as __block so we can modify it from the block (to fix a bug that macOS sometimes call the completionHandler twice) @@ -1192,7 +1230,8 @@ - (BOOL)discoverRemoteEntity:(la::avdecc::UniqueIdentifier)entityID { return la::avdecc::protocol::ProtocolInterface::Error::NoError; } -- (la::avdecc::protocol::ProtocolInterface::Error)sendAecpResponse:(la::avdecc::protocol::Aecpdu::UniquePointer&&)aecpdu { +- (la::avdecc::protocol::ProtocolInterface::Error)sendAecpResponse:(la::avdecc::protocol::Aecpdu::UniquePointer&&)aecpdu +{ auto const macAddr = aecpdu->getDestAddress(); // Make a copy of the target macAddress so it can safely be used inside the objC block auto message = [ToNative makeAecpMessage:*aecpdu]; @@ -1246,7 +1285,8 @@ - (BOOL)discoverRemoteEntity:(la::avdecc::UniqueIdentifier)entityID { return la::avdecc::protocol::ProtocolInterface::Error::NoError; } -- (la::avdecc::protocol::ProtocolInterface::Error)sendAcmpCommand:(la::avdecc::protocol::Acmpdu::UniquePointer&&)acmpdu handler:(la::avdecc::protocol::ProtocolInterface::AcmpCommandResultHandler const&)onResult { +- (la::avdecc::protocol::ProtocolInterface::Error)sendAcmpCommand:(la::avdecc::protocol::Acmpdu::UniquePointer&&)acmpdu handler:(la::avdecc::protocol::ProtocolInterface::AcmpCommandResultHandler const&)onResult +{ __block auto resultHandler = onResult; // Make a copy of the handler so it can safely be used inside the objC block. Declare it as __block so we can modify it from the block (to fix a bug that macOS sometimes call the completionHandler twice) auto const& acmp = static_cast(*acmpdu); @@ -1296,20 +1336,24 @@ - (BOOL)discoverRemoteEntity:(la::avdecc::UniqueIdentifier)entityID { return la::avdecc::protocol::ProtocolInterface::Error::NoError; } -- (void)lock { +- (void)lock +{ _lock.lock(); } -- (void)unlock { +- (void)unlock +{ _lock.unlock(); } -- (bool)isSelfLocked { +- (bool)isSelfLocked +{ return _lock.isSelfLocked(); } #pragma mark AVB17221EntityDiscoveryDelegate delegate -- (void)initEntity:(la::avdecc::UniqueIdentifier)entityID { +- (void)initEntity:(la::avdecc::UniqueIdentifier)entityID +{ // Register ACMP sniffing handler for this entity if ([self.interface.acmp setHandler:self forEntityID:entityID]) { @@ -1325,7 +1369,8 @@ - (void)initEntity:(la::avdecc::UniqueIdentifier)entityID { } } -- (void)deinitEntity:(la::avdecc::UniqueIdentifier)entityID { +- (void)deinitEntity:(la::avdecc::UniqueIdentifier)entityID +{ { // Lock auto const lg = std::lock_guard{ _lock }; @@ -1372,7 +1417,8 @@ - (void)deinitEntity:(la::avdecc::UniqueIdentifier)entityID { } // Notification of an arriving local computer entity -- (void)didAddLocalEntity:(AVB17221Entity*)newEntity on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery { +- (void)didAddLocalEntity:(AVB17221Entity*)newEntity on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery +{ [self initEntity:la::avdecc::UniqueIdentifier{ newEntity.entityID }]; // Lock @@ -1384,7 +1430,8 @@ - (void)didAddLocalEntity:(AVB17221Entity*)newEntity on17221EntityDiscovery:(AVB } // Notification of a departing local computer entity -- (void)didRemoveLocalEntity:(AVB17221Entity*)oldEntity on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery { +- (void)didRemoveLocalEntity:(AVB17221Entity*)oldEntity on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery +{ auto const oldEntityID = la::avdecc::UniqueIdentifier{ oldEntity.entityID }; [self deinitEntity:oldEntityID]; @@ -1395,7 +1442,8 @@ - (void)didRemoveLocalEntity:(AVB17221Entity*)oldEntity on17221EntityDiscovery:( _protocolInterface->notifyObserversMethod(&la::avdecc::protocol::ProtocolInterface::Observer::onLocalEntityOffline, _protocolInterface, oldEntityID); } -- (void)didRediscoverLocalEntity:(AVB17221Entity*)entity on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery { +- (void)didRediscoverLocalEntity:(AVB17221Entity*)entity on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery +{ // Check if Entity already in the list { // Lock @@ -1409,7 +1457,8 @@ - (void)didRediscoverLocalEntity:(AVB17221Entity*)entity on17221EntityDiscovery: // Nothing to do, entity has already been detected } -- (void)didUpdateLocalEntity:(AVB17221Entity*)entity changedProperties:(AVB17221EntityPropertyChanged)changedProperties on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery { +- (void)didUpdateLocalEntity:(AVB17221Entity*)entity changedProperties:(AVB17221EntityPropertyChanged)changedProperties on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery +{ constexpr NSUInteger ignoreChangeMask = 0xFFFFFFFF & ~(AVB17221EntityPropertyChangedTimeToLive | AVB17221EntityPropertyChangedAvailableIndex); // If changes are only for flags we want to ignore, return if ((changedProperties & ignoreChangeMask) == 0) @@ -1432,7 +1481,8 @@ - (void)didUpdateLocalEntity:(AVB17221Entity*)entity changedProperties:(AVB17221 } } -- (void)didAddRemoteEntity:(AVB17221Entity*)newEntity on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery { +- (void)didAddRemoteEntity:(AVB17221Entity*)newEntity on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery +{ [self initEntity:la::avdecc::UniqueIdentifier{ newEntity.entityID }]; // Lock @@ -1450,7 +1500,8 @@ - (void)didAddRemoteEntity:(AVB17221Entity*)newEntity on17221EntityDiscovery:(AV _protocolInterface->notifyObserversMethod(&la::avdecc::protocol::ProtocolInterface::Observer::onRemoteEntityOnline, _protocolInterface, e); } -- (void)didRemoveRemoteEntity:(AVB17221Entity*)oldEntity on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery { +- (void)didRemoveRemoteEntity:(AVB17221Entity*)oldEntity on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery +{ auto const oldEntityID = la::avdecc::UniqueIdentifier{ oldEntity.entityID }; [self deinitEntity:oldEntityID]; @@ -1464,7 +1515,8 @@ - (void)didRemoveRemoteEntity:(AVB17221Entity*)oldEntity on17221EntityDiscovery: _protocolInterface->notifyObserversMethod(&la::avdecc::protocol::ProtocolInterface::Observer::onRemoteEntityOffline, _protocolInterface, oldEntityID); } -- (void)didRediscoverRemoteEntity:(AVB17221Entity*)entity on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery { +- (void)didRediscoverRemoteEntity:(AVB17221Entity*)entity on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery +{ // Check if Entity already in the list { // Lock @@ -1478,7 +1530,8 @@ - (void)didRediscoverRemoteEntity:(AVB17221Entity*)entity on17221EntityDiscovery // Nothing to do, entity has already been detected } -- (void)didUpdateRemoteEntity:(AVB17221Entity*)entity changedProperties:(AVB17221EntityPropertyChanged)changedProperties on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery { +- (void)didUpdateRemoteEntity:(AVB17221Entity*)entity changedProperties:(AVB17221EntityPropertyChanged)changedProperties on17221EntityDiscovery:(AVB17221EntityDiscovery*)entityDiscovery +{ // Lock auto const lg = std::lock_guard{ _lock }; @@ -1527,7 +1580,8 @@ - (void)didUpdateRemoteEntity:(AVB17221Entity*)entity changedProperties:(AVB1722 } #pragma mark AVB17221AECPClient delegate -- (BOOL)AECPDidReceiveCommand:(AVB17221AECPMessage*)message onInterface:(AVB17221AECPInterface*)anInterface { +- (BOOL)AECPDidReceiveCommand:(AVB17221AECPMessage*)message onInterface:(AVB17221AECPInterface*)anInterface +{ // This handler is called for all AECP commands targeting one of our registered Entities // Lock @@ -1545,7 +1599,8 @@ - (BOOL)AECPDidReceiveCommand:(AVB17221AECPMessage*)message onInterface:(AVB1722 return YES; } -- (BOOL)AECPDidReceiveResponse:(AVB17221AECPMessage*)message onInterface:(AVB17221AECPInterface*)anInterface { +- (BOOL)AECPDidReceiveResponse:(AVB17221AECPMessage*)message onInterface:(AVB17221AECPInterface*)anInterface +{ // This handler is called for all AECP responses targeting one of our registered Entities, even the messages that are solicited responses and which will be handled by the block of aecp.sendCommand() method // Lock @@ -1589,7 +1644,8 @@ - (BOOL)AECPDidReceiveResponse:(AVB17221AECPMessage*)message onInterface:(AVB172 } #pragma mark AVB17221ACMPClient delegate -- (BOOL)ACMPDidReceiveCommand:(AVB17221ACMPMessage*)message onInterface:(AVB17221ACMPInterface*)anInterface { +- (BOOL)ACMPDidReceiveCommand:(AVB17221ACMPMessage*)message onInterface:(AVB17221ACMPInterface*)anInterface +{ // This handler is called for all ACMP messages, even the messages that are sent by ourself // Lock @@ -1603,7 +1659,8 @@ - (BOOL)ACMPDidReceiveCommand:(AVB17221ACMPMessage*)message onInterface:(AVB1722 return YES; } -- (BOOL)ACMPDidReceiveResponse:(AVB17221ACMPMessage*)message onInterface:(AVB17221ACMPInterface*)anInterface { +- (BOOL)ACMPDidReceiveResponse:(AVB17221ACMPMessage*)message onInterface:(AVB17221ACMPInterface*)anInterface +{ // This handler is called for all ACMP messages, even the messages that are expected responses and which will be handled by the block of acmp.sendACMPCommandMessage() method // Lock