From cd531f7fbf2f31ce83bc717228fae0bc8e218bdf Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:31:45 +0100 Subject: [PATCH 01/18] Bump version number for future development --- ChangeLog.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index ef5714d..27763e2 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,11 @@ +This is a development build of the ARA Library 2.3. +=== PRELIMINARY - DO NOT USE FOR SHIPPING PRODUCTS! === + + +Changes since previous releases: +- no changes yet + + === ARA SDK 2.2 release (aka 2.2.001) (2022/11/07) === - added surround support for audio sources - added API to determine whether an audio modification actually modifies the underlying audio source From 01b9347692a371b49dc1ee8f8392fe62a4efb917 Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:31:53 +0100 Subject: [PATCH 02/18] Merge IPCDemo into TestHost (initially limited to test cases that don't use plug-in instances, only document controllers) --- Debug/ARADebug.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Debug/ARADebug.h b/Debug/ARADebug.h index 4593eb4..5c0aafb 100644 --- a/Debug/ARADebug.h +++ b/Debug/ARADebug.h @@ -69,7 +69,8 @@ extern "C" // logs to the debugger console and/or to the error output (e.g. stderr) void ARADebugMessage(ARADebugLevel level, const char * file, int line, const char * text, ...); // this logging can be prefixed by a custom static string if desired, which is useful e.g. - // if multiple plug-ins are build using the same compiled library, or in the IPC Demo example + // if multiple plug-ins are build using the same compiled library, or if using the IPC + // capabilities of the ARATestHost example // typically, this setup call is made once when loading the final binary and passes its name void ARASetupDebugMessagePrefix(const char * prefix); #if defined(__cplusplus) From bf91af3f1bebe37f34072a4ecef1a9d52736c170 Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:31:54 +0100 Subject: [PATCH 03/18] Minor cleanup for more consistency --- PlugIn/ARAPlug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PlugIn/ARAPlug.cpp b/PlugIn/ARAPlug.cpp index f1b43fb..08ad19d 100644 --- a/PlugIn/ARAPlug.cpp +++ b/PlugIn/ARAPlug.cpp @@ -931,7 +931,7 @@ void DocumentController::initializeDocument (const ARADocumentProperties* proper ARA_LOG_MODELOBJECT_LIFETIME ("did create document", getDocument ()); willUpdateDocumentProperties (_document, properties); - getDocument ()->updateProperties (properties); + _document->updateProperties (properties); didUpdateDocumentProperties (_document); } From 9a144080bb866a87dc70fc3fa260807d7c3eda62 Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:31:58 +0100 Subject: [PATCH 04/18] Move common initialization of ARA_SUPPORT_VERSION_1 to DispatchBase --- Dispatch/ARADispatchBase.h | 30 ++++++++++++++++++++++++++++++ Dispatch/ARAHostDispatch.h | 19 ------------------- Dispatch/ARAPlugInDispatch.h | 18 ------------------ 3 files changed, 30 insertions(+), 37 deletions(-) diff --git a/Dispatch/ARADispatchBase.h b/Dispatch/ARADispatchBase.h index 2a56824..c5f2644 100644 --- a/Dispatch/ARADispatchBase.h +++ b/Dispatch/ARADispatchBase.h @@ -31,6 +31,36 @@ #include "ARA_API/ARAInterface.h" +/*******************************************************************************/ +/** Optional ARA 1 backwards compatibility. + Hosts and plug-ins can choose support ARA 1 hosts in addition to ARA 2 hosts. + This feature is being phased out as all vendors move to ARA 2, and is not + available on architectures where ARA 1 was not available, such as ARM. + + For hosts, using ARA 1 plug-ins through the implementation provided here + imposes several implicit restrictions: + - each plug-in instance assumes all possible roles (see ARAPlugInInstanceRoleFlags) + - each plug-in instance only is associated with at most one playback region at any time + - the ARA 1 API is mapped to PlaybackRenderer*, the other interfaces will not be provided + - archiving must use ARA 1 style monolithic persistency calls + + Plug-ins will have to implement a several fallbacks in order to work in ARA 1 hosts, + in addition to the support provided by this implementation they need to: + - create dummy region sequences for the playback regions, utilizing the + context information provided via the companion APIs + - implicitly derive ARA selection state from companion API actions +*/ +/*******************************************************************************/ + +#if !defined (ARA_SUPPORT_VERSION_1) + #define ARA_SUPPORT_VERSION_1 0 +#endif + +#if ARA_SUPPORT_VERSION_1 && ARA_CPU_ARM + #error "ARA v1 is not supported on ARM architecture" +#endif + + namespace ARA { /*******************************************************************************/ diff --git a/Dispatch/ARAHostDispatch.h b/Dispatch/ARAHostDispatch.h index 2e1d44c..6cce269 100644 --- a/Dispatch/ARAHostDispatch.h +++ b/Dispatch/ARAHostDispatch.h @@ -30,25 +30,6 @@ namespace Host { //! @addtogroup ARA_Library_Host_Dispatch //! @{ -/*******************************************************************************/ -/** Optional ARA 1 backwards compatibility. - Host can choose support ARA 1 plug-ins in addition to ARA 2 plug-ins. - This results in several restrictions being implicitly imposed when using such plug-ins - through the implementation provided here: - - each plug-in instance assumes all possible roles (see ARAPlugInInstanceRoleFlags) - - each plug-in instance only is associated with at most one playback region at any time - - the ARA 1 API is mapped to PlaybackRenderer*, the other interfaces will not be provided - - archiving must use ARA 1 style monolithic persistency calls -*/ -/*******************************************************************************/ - -#if !defined (ARA_SUPPORT_VERSION_1) - #define ARA_SUPPORT_VERSION_1 0 -#endif - -#if ARA_SUPPORT_VERSION_1 && ARA_CPU_ARM - #error "ARA v1 is not supported on ARM architecture" -#endif /*******************************************************************************/ /** Type safe conversions to/from host ref: toHostRef () and fromHostRef<> (). diff --git a/Dispatch/ARAPlugInDispatch.h b/Dispatch/ARAPlugInDispatch.h index 374ea32..888b9a1 100644 --- a/Dispatch/ARAPlugInDispatch.h +++ b/Dispatch/ARAPlugInDispatch.h @@ -27,24 +27,6 @@ namespace PlugIn { //! @addtogroup ARA_Library_PlugIn_Dispatch //! @{ -/*******************************************************************************/ -/** Optional ARA 1 backwards compatibility. - Plug-ins can choose support ARA 1 hosts in addition to ARA 2 hosts. - Plug-ins will have to implement a lot of fallbacks in addition to the support - provided by this implementation: - - create dummy region sequences for the playback regions, utilizing the - context information provided via the companion APIs - - implicitly derive ARA selection state from companion API actions -*/ -/*******************************************************************************/ -#if !defined (ARA_SUPPORT_VERSION_1) - #define ARA_SUPPORT_VERSION_1 0 -#endif - -#if ARA_SUPPORT_VERSION_1 && ARA_CPU_ARM - #error "ARA v1 is not supported on ARM architecture" -#endif - /*******************************************************************************/ /** Type safe conversions to/from ref: toRef () and fromRef<> (). This macro defines custom overloads of the toRef () and fromRef<> () conversion functions From d3c736bd5ec0f9f51413ee23ed1b3f725e7d05b5 Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:31:58 +0100 Subject: [PATCH 05/18] Move draft of IPC proxies from ARA_Examples to ARA_Library, decoupling it from IPCPort/IPCMessage --- CMakeLists.txt | 36 +- ChangeLog.txt | 3 +- IPC/ARAIPC.h | 162 ++++ IPC/ARAIPCEncoding.h | 1204 ++++++++++++++++++++++++++ IPC/ARAIPCProxyHost.cpp | 1259 +++++++++++++++++++++++++++ IPC/ARAIPCProxyHost.h | 58 ++ IPC/ARAIPCProxyPlugIn.cpp | 1721 +++++++++++++++++++++++++++++++++++++ IPC/ARAIPCProxyPlugIn.h | 70 ++ 8 files changed, 4511 insertions(+), 2 deletions(-) create mode 100644 IPC/ARAIPC.h create mode 100644 IPC/ARAIPCEncoding.h create mode 100644 IPC/ARAIPCProxyHost.cpp create mode 100644 IPC/ARAIPCProxyHost.h create mode 100644 IPC/ARAIPCProxyPlugIn.cpp create mode 100644 IPC/ARAIPCProxyPlugIn.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e2653f..e88ac46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,6 +86,19 @@ function(configure_ARA_Library_target target) PRIVATE -DNOMINMAX=1 ) + elseif(APPLE) + if(XCODE) + set_target_properties(${target} PROPERTIES + XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN YES + XCODE_ATTRIBUTE_GCC_INLINES_ARE_PRIVATE_EXTERN YES + ) + else() + set_target_properties(${target} PROPERTIES + C_VISIBILITY_PRESET hidden + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN ON + ) + endif() elseif(UNIX AND NOT APPLE) set_target_properties(${target} PROPERTIES POSITION_INDEPENDENT_CODE ON @@ -99,7 +112,7 @@ endfunction() # ====================== -# files used in both targets +# files used in both host and plug-in target set(ARA_Library_Common_Files "${CMAKE_CURRENT_SOURCE_DIR}/Debug/ARADebug.h" "${CMAKE_CURRENT_SOURCE_DIR}/Debug/ARADebug.c" @@ -150,4 +163,25 @@ add_library(ARA_PlugIn_Library ${ARA_LIBRARY_TARGET_TYPE} "${CMAKE_CURRENT_SOURCE_DIR}/PlugIn/ARAPlug.h" "${CMAKE_CURRENT_SOURCE_DIR}/PlugIn/ARAPlug.cpp" ) + configure_ARA_Library_target(ARA_PlugIn_Library) + +# ====================== + +add_library(ARA_IPC_Library ${ARA_LIBRARY_TARGET_TYPE} + "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPC.h" + "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCEncoding.h" + "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCProxyHost.h" + "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCProxyHost.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCProxyPlugIn.h" + "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCProxyPlugIn.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCProxyHost.h" + "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCProxyHost.cpp" +) + +target_link_libraries(ARA_IPC_Library PRIVATE + ARA_Host_Library + ARA_PlugIn_Library +) + +configure_ARA_Library_target(ARA_IPC_Library) diff --git a/ChangeLog.txt b/ChangeLog.txt index 27763e2..c0e3ab7 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -3,7 +3,8 @@ This is a development build of the ARA Library 2.3. Changes since previous releases: -- no changes yet +- initial draft of generic ARA IPC library providing a proxy host and a proxy plug-in, + based on heavily refactored IPC Example from earlier SDK releases === ARA SDK 2.2 release (aka 2.2.001) (2022/11/07) === diff --git a/IPC/ARAIPC.h b/IPC/ARAIPC.h new file mode 100644 index 0000000..8e3325c --- /dev/null +++ b/IPC/ARAIPC.h @@ -0,0 +1,162 @@ +//------------------------------------------------------------------------------ +//! \file ARAIPC.h +//! Abstractions shared by both the ARA IPC proxy host and plug-in +//! Typically, this file is not included directly - either ARAIPCProxyHost.h +//! ARAIPCProxyPlugIn.h will be used instead. +//! \project ARA SDK Library +//! \copyright Copyright (c) 2021-2022, Celemony Software GmbH, All Rights Reserved. +//! \license Licensed under the Apache License, Version 2.0 (the "License"); +//! you may not use this file except in compliance with the License. +//! You may obtain a copy of the License at +//! +//! http://www.apache.org/licenses/LICENSE-2.0 +//! +//! Unless required by applicable law or agreed to in writing, software +//! distributed under the License is distributed on an "AS IS" BASIS, +//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//! See the License for the specific language governing permissions and +//! limitations under the License. +//------------------------------------------------------------------------------ + +#ifndef ARAIPC_h +#define ARAIPC_h + + +//! @addtogroup ARA_Library_IPC +//! @{ + + +//! switch to bypass all IPC code +#if !defined (ARA_ENABLE_IPC) + #if defined (__APPLE__) || defined (_WIN32) + #define ARA_ENABLE_IPC 1 + #else + #define ARA_ENABLE_IPC 0 + #endif +#endif + + +#if ARA_ENABLE_IPC + + +#include + + +namespace ARA { +namespace IPC { + + +//! ID type for messages, IDs must be >= kMessageIDRangeStart and < kMessageIDRangeEnd +using MessageID = int32_t; +constexpr MessageID kMessageIDRangeStart { 1 }; +constexpr MessageID kMessageIDRangeEnd { 8*16*16 - 1 }; + +//! key type for message dictionaries - negative keys are reserved for the implementation +using MessageKey = int32_t; + + +class MessageEncoder +{ +public: + virtual ~MessageEncoder () = default; + + //! number types + //! The size variant will also be used for the pointer-sized ARA (host) refs. + //@{ + virtual void appendInt32 (const MessageKey argKey, const int32_t argValue) = 0; + virtual void appendInt64 (const MessageKey argKey, const int64_t argValue) = 0; + virtual void appendSize (const MessageKey argKey, const size_t argValue) = 0; + virtual void appendFloat (const MessageKey argKey, const float argValue) = 0; + virtual void appendDouble (const MessageKey argKey, const double argValue) = 0; + //@} + + //! UTF8-encoded C strings + virtual void appendString (const MessageKey argKey, const char* const argValue) = 0; + + //! raw bytes + //! As optimization, disable copying if the memory containing the bytes stays + //! alive&unchanged until the message has been sent. + virtual void appendBytes (const MessageKey argKey, const uint8_t* argValue, const size_t argSize, const bool copy = true) = 0; + + //! sub-messages to encode compound types + //! The caller is responsible for deleting the encoder after use. + virtual MessageEncoder* appendSubMessage (const MessageKey argKey) = 0; +}; + +class MessageDecoder +{ +public: + virtual ~MessageDecoder () = default; + + //! only for debugging/validation: test if the message contains any key/value pairs + virtual bool isEmpty () const = 0; + + //! number types + //! The size variant will also be used for the pointer-sized ARA (host) refs. + //! Will return false and set argValue to 0 if key not found. + //@{ + virtual bool readInt32 (const MessageKey argKey, int32_t& argValue) const = 0; + virtual bool readInt64 (const MessageKey argKey, int64_t& argValue) const = 0; + virtual bool readSize (const MessageKey argKey, size_t& argValue) const = 0; + virtual bool readFloat (const MessageKey argKey, float& argValue) const = 0; + virtual bool readDouble (const MessageKey argKey, double& argValue) const = 0; + //@} + + //! UTF8-encoded C strings + //! Will return false and set argValue to nullptr if key not found. + virtual bool readString (const MessageKey argKey, const char*& argValue) const = 0; + + //! raw bytes + //! first query size, then provide a buffer large enough to copy the bytes to. + //! readBytesSize () will return false and set argSize to 0 if key not found. + //@{ + virtual bool readBytesSize (const MessageKey argKey, size_t& argSize) const = 0; + virtual void readBytes (const MessageKey argKey, uint8_t* const argValue) const = 0; + //@} + + //! sub-messages to decode compound types + //! returns nullptr if key not found or if the value for the key is not representing a sub-message + //! The caller is responsible for deleting the encoder after use. + virtual MessageDecoder* readSubMessage (const MessageKey argKey) const = 0; +}; + +//! receive function: receives a message readable through the decoder, optionally creating a reply +//! Not using the replyEncoder will return a valid empty message to the sender (useful for void calls). +//! Depending on the underlying implementation, replyEncoder may be nullptr if no reply has been +//! requested by the sender, but providing a dummy encoder in this case is valid too. +//! The sender thread will be blocked until the (possibly empty) reply has been received. +//! A receive function can be called from any thread, but not concurrently. +using ReceiveFunction = void (const MessageID messageID, const MessageDecoder& decoder, MessageEncoder* const replyEncoder); + +//! gateway for sending messages +class Sender +{ +public: + virtual ~Sender () = default; + + using ReplyHandler = std::function; + + //! generate an encoder to encode a new message + //! An encoder can be reused if the same message is sent several times, + //! but it must not be modified after sending. + //! The caller is responsible for deleting the encoder after use. + virtual MessageEncoder* createEncoder () = 0; + + //! send function: send message create using the encoder, blocking until a reply has been received. + //! If an empty reply ("void") is expected, the replyHandler should be nullptr. + //! A send function can be called from any thread, but not concurrently. + virtual void sendMessage (MessageID messageID, const MessageEncoder& encoder, ReplyHandler* const replyHandler) = 0; + + //! Test if the receiver runs on a different architecture with different endianess. + virtual bool receiverEndianessMatches () const { return true; } +}; + + +} // namespace IPC +} // namespace ARA + +#endif // ARA_ENABLE_IPC + +//! @} ARA_Library_IPC + +#endif // ARAIPC_h diff --git a/IPC/ARAIPCEncoding.h b/IPC/ARAIPCEncoding.h new file mode 100644 index 0000000..8b8811e --- /dev/null +++ b/IPC/ARAIPCEncoding.h @@ -0,0 +1,1204 @@ +//------------------------------------------------------------------------------ +//! \file ARAIPCEncoding.h +//! Implementation helpers shared by both the ARA IPC proxy host and plug-in +//! Typically, this file is not included directly - either ARAIPCProxyHost.h +//! ARAIPCProxyPlugIn.h will be used instead. +//! \project ARA SDK Examples +//! \copyright Copyright (c) 2021-2022, Celemony Software GmbH, All Rights Reserved. +//! \license Licensed under the Apache License, Version 2.0 (the "License"); +//! you may not use this file except in compliance with the License. +//! You may obtain a copy of the License at +//! +//! http://www.apache.org/licenses/LICENSE-2.0 +//! +//! Unless required by applicable law or agreed to in writing, software +//! distributed under the License is distributed on an "AS IS" BASIS, +//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//! See the License for the specific language governing permissions and +//! limitations under the License. +//------------------------------------------------------------------------------ + +#ifndef ARAIPCEncoding_h +#define ARAIPCEncoding_h + +#include "ARA_Library/IPC/ARAIPC.h" + + +#if ARA_ENABLE_IPC + +#include "ARA_Library/Debug/ARADebug.h" +#include "ARA_Library/Dispatch/ARAContentReader.h" + +#include +#include +#include +#include +#include +#include +#include + + +namespace ARA { +namespace IPC { + +//------------------------------------------------------------------------------ +// wrapper factories to efficiently handle sending and receiving raw bytes +//------------------------------------------------------------------------------ + +// a read function based on a ptr+size pair or std::vector +// it returns pointer to read bytes from and byte count via reference +// copy should be set to false if the bytes are guaranteed to remain valid +// until the message has been sent - this is the case for all blocking sends, +// but not for non-blocking sends and depends on context for replies +class BytesEncoder : public std::function +{ +public: + BytesEncoder (const uint8_t* const bytes, const size_t size, const bool copy) + : std::function { + [bytes, size, copy] (const uint8_t*& bytesPtr, size_t& bytesSize, bool& bytesCopy) -> void + { + bytesPtr = bytes; + bytesSize = size; + bytesCopy = copy; + } } + {} + BytesEncoder (const std::vector& bytes, const bool copy) + : BytesEncoder { bytes.data (), bytes.size (), copy } + {} +}; + +// a write function based on a ptr+size pair or std::vector +// resizes to the desired byte count and returns pointer to write bytes to +class BytesDecoder : public std::function +{ +public: + BytesDecoder (uint8_t* const bytes, size_t& size) + : std::function { + [bytes, &size] (size_t& bytesSize) -> uint8_t* + { + if (bytesSize > size) + bytesSize = size; // if there is more data then we can take, clip + else + size = bytesSize; // otherwise store size + return bytes; + } } + {} + BytesDecoder (std::vector& bytes) + : std::function { + [&bytes] (size_t& size) -> uint8_t* + { + bytes.resize (size); + return bytes.data (); + } } + {} +}; + + +//------------------------------------------------------------------------------ +// wrapper factories to efficiently handle sending and receiving arrays +//------------------------------------------------------------------------------ + + +template +struct ArrayArgument +{ + static_assert (sizeof(ElementT) > sizeof(ARAByte), "byte-sized arrays should be sent as raw bytes"); + ElementT* elements; + size_t count; +}; + + +//------------------------------------------------------------------------------ +// various private helpers +//------------------------------------------------------------------------------ + +// private helper template to detect ARA ref types +template +struct _IsRefType +{ + static constexpr bool value { false }; +}; +#define ARA_IPC_SPECIALIZE_FOR_REF_TYPE(Type) \ +template<> \ +struct _IsRefType \ +{ \ + static constexpr bool value { true }; \ +}; +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAMusicalContextRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARARegionSequenceRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAAudioSourceRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAAudioModificationRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAPlaybackRegionRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAContentReaderRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARADocumentControllerRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAPlaybackRendererRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAEditorRendererRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAEditorViewRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAPlugInExtensionRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAMusicalContextHostRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARARegionSequenceHostRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAAudioSourceHostRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAAudioModificationHostRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAPlaybackRegionHostRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAContentReaderHostRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAAudioAccessControllerHostRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAAudioReaderHostRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAArchivingControllerHostRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAArchiveReaderHostRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAArchiveWriterHostRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAContentAccessControllerHostRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAModelUpdateControllerHostRef) +ARA_IPC_SPECIALIZE_FOR_REF_TYPE (ARAPlaybackControllerHostRef) +#undef ARA_IPC_SPECIALIZE_FOR_REF_TYPE + + +// helper template to identify pointers to ARA structs in message arguments +template +struct _IsStructPointerArg +{ + struct _False + { + static constexpr bool value { false }; + }; + struct _True + { + static constexpr bool value { true }; + }; + using type = typename std::conditional::value && + std::is_pointer::value && !std::is_same::value, _True, _False>::type; +}; + + +//------------------------------------------------------------------------------ +// private primitive wrappers for IPCMessageEn-/Decoder API that drop the type encoding +// from the name (which is required there for potential C compatibility) +//------------------------------------------------------------------------------ + + +// primitives for appending an argument to a message +inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const int32_t argValue) +{ + encoder.appendInt32 (argKey, argValue); +} +inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const int64_t argValue) +{ + encoder.appendInt64 (argKey, argValue); +} +inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const size_t argValue) +{ + encoder.appendSize (argKey, argValue); +} +inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const float argValue) +{ + encoder.appendFloat (argKey, argValue); +} +inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const double argValue) +{ + encoder.appendDouble (argKey, argValue); +} +inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const char* const argValue) +{ + encoder.appendString (argKey, argValue); +} +inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const BytesEncoder& argValue) +{ + const uint8_t* bytes; + size_t size; + bool copy; + argValue (bytes, size, copy); + encoder.appendBytes (argKey, bytes, size, copy); +} + +// primitives for reading an (optional) argument from a message +inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, int32_t& argValue) +{ + return decoder.readInt32 (argKey, argValue); +} +inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, int64_t& argValue) +{ + return decoder.readInt64 (argKey, argValue); +} +inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, size_t& argValue) +{ + return decoder.readSize (argKey, argValue); +} +inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, float& argValue) +{ + return decoder.readFloat (argKey, argValue); +} +inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, double& argValue) +{ + return decoder.readDouble (argKey, argValue); +} +inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, const char*& argValue) +{ + return decoder.readString (argKey, argValue); +} +inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, BytesDecoder& argValue) +{ + size_t receivedSize; + const auto found { decoder.readBytesSize (argKey, receivedSize) }; + auto availableSize { receivedSize }; + const auto bytes { argValue (availableSize) }; + if (!found) + return false; + if (availableSize < receivedSize) + return false; + decoder.readBytes (argKey, bytes); + return true; +} + + +//------------------------------------------------------------------------------ +// overloads of the IPCMessageEn-/Decoder primitives for types that can be +// directly mapped to a primitive type +//------------------------------------------------------------------------------ + + +// templated overloads of the IPCMessageEn-/Decoder primitives for ARA (host) ref types, +// which are stored as size_t +template::value, bool>::type = true> +inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const T argValue) +{ + encoder.appendSize (argKey, reinterpret_cast (argValue)); +} +template::value, bool>::type = true> +inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, T& argValue) +{ + // \todo is there a safe/proper way across all compilers for this cast to avoid the copy? +// return decoder.readSize (argKey, *reinterpret_cast (&argValue)); + size_t tmp; + const auto success { decoder.readSize (argKey, tmp) }; + argValue = reinterpret_cast (tmp); + return success; +} + +/* instead of using ARA_IPC_ENCODE_EMBEDDED_BYTES below, we could instead allow + sending arrays of ARABytes via this overload (seems simpler but less efficient): +// to read and write arrays of ARAByte (not raw bytes but e.g. ARAKeySignatureIntervalUsage), +// we use int32_t to keep the IPCMessageEn-/Decoder API small +inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const ARAByte argValue) +{ + encoder.appendInt32 (argKey, static_cast (argValue)); +} +inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, ARAByte& argValue) +{ + int32_t tmp; + const auto result { decoder.readInt32 (argKey, tmp) }; + ARA_INTERNAL_ASSERT ((0 <= tmp) && (tmp <= static_cast (std::numeric_limits::max ()))); + argValue = static_cast (tmp); + return result; +} +*/ + + +//------------------------------------------------------------------------------ +// private helper templates to en-/decode ARA API values +// The mapping is 1:1 except for ARA (host)refs which are encoded as size_t, and aggregate types +// (i.e. ARA structs or std::vector<> of types other than ARAByte), which are expressed as sub-messages. +// En- and Decoding use the same implementation technique: +// To support using compound types (arrays, structs) both as indexed sub-message for call arguments +// when sending as well as as root message for replies, there's a templated _ValueEn-/Decoder struct +// for each type which provides an encode&append/read&decode call that extracts a sub-message if +// needed and then performs the en/decode via a separate plain en-/decoding call only available in +// compound types. The latter call will be used directly for compound data type replies. +// In order not to have to spell out _ValueEn-/Decoder<> explicitly, overloaded wrapper function +// templates _encodeAndAppend() and _readAndDecode() are provided. +//------------------------------------------------------------------------------ + + +// declarations of wrapper functions to implicitly deduce _ValueEn-/Decoder<> - +// they are defined further down below, after all specializations are defined +template +inline void _encodeAndAppend (MessageEncoder& encoder, const MessageKey argKey, const ValueT& argValue); +template +inline bool _readAndDecode (ValueT& result, const MessageDecoder& decoder, const MessageKey argKey); + + +// primary templates for basic types (numbers, strings, (host)refs and raw bytes) +template +struct _ValueEncoder +{ + static inline void encodeAndAppend (MessageEncoder& encoder, const MessageKey argKey, const ValueT& argValue) + { + _appendToMessage (encoder, argKey, argValue); + } +}; +template +struct _ValueDecoder +{ + static inline bool readAndDecode (ValueT& result, const MessageDecoder& decoder, const MessageKey argKey) + { + return _readFromMessage (decoder, argKey, result); + } +}; + + +// common base classes for en-/decoding compound types (arrays, structs) via nested messages, +// providing the generic encode&append/read&decode calls +template +struct _CompoundValueEncoderBase +{ + static inline void encodeAndAppend (MessageEncoder& encoder, const MessageKey argKey, const ValueT& argValue) + { + auto subEncoder { encoder.appendSubMessage (argKey) }; + ARA_INTERNAL_ASSERT (subEncoder != nullptr); + _ValueEncoder::encode (*subEncoder, argValue); + delete subEncoder; + } +}; +template +struct _CompoundValueDecoderBase +{ + static inline bool readAndDecode (ValueT& result, const MessageDecoder& decoder, const MessageKey argKey) + { + auto subDecoder { decoder.readSubMessage (argKey) }; + if (subDecoder == nullptr) + return false; + const auto success { _ValueDecoder::decode (result, *subDecoder) }; + delete subDecoder; + return success; + } +}; + + +// specialization for encoding arrays (variable or fixed size) +template +struct _ValueEncoder> : public _CompoundValueEncoderBase> +{ + static inline void encode (MessageEncoder& encoder, const ArrayArgument& value) + { + ARA_INTERNAL_ASSERT (value.count <= static_cast (std::numeric_limits::max ())); + const auto count { static_cast (value.count) }; + _encodeAndAppend (encoder, 0, count); + for (auto i { 0 }; i < count; ++i) + _encodeAndAppend (encoder, i + 1, value.elements[static_cast (i)]); + } +}; + +// specialization for decoding fixed-size arrays +template +struct _ValueDecoder> : public _CompoundValueDecoderBase> +{ + static inline bool decode (ArrayArgument& result, const MessageDecoder& decoder) + { + bool success { true }; + MessageKey count; + success &= _readAndDecode (count, decoder, 0); + success &= (count == static_cast (result.count)); + if (count > static_cast (result.count)) + count = static_cast (result.count); + + for (auto i { 0 }; i < count; ++i) + success &= _readAndDecode (result.elements[static_cast (i)], decoder, i + 1); + return success; + } +}; + +// specialization for decoding variable arrays +template +struct _ValueDecoder> : public _CompoundValueDecoderBase> +{ + static inline bool decode (std::vector& result, const MessageDecoder& decoder) + { + bool success { true }; + MessageKey count; + success &= _readAndDecode (count, decoder, 0); + result.resize (static_cast (count)); + for (auto i { 0 }; i < count; ++i) + success &= _readAndDecode (result[static_cast (i)], decoder, i + 1); + return success; + } +}; + + +// specializations for en/decoding each ARA struct + +#define ARA_IPC_BEGIN_ENCODE(StructT) \ +template<> struct _ValueEncoder : public _CompoundValueEncoderBase \ +{ /* specialization for given struct */ \ + using StructType = StructT; \ + static inline void encode (MessageEncoder& encoder, const StructType& value) \ + { +#define ARA_IPC_ENCODE_MEMBER(member) \ + _encodeAndAppend (encoder, offsetof (StructType, member), value.member); +#define ARA_IPC_ENCODE_EMBEDDED_BYTES(member) \ + const BytesEncoder tmp_##member { reinterpret_cast (value.member), sizeof (value.member), true }; \ + _encodeAndAppend (encoder, offsetof (StructType, member), tmp_##member); +#define ARA_IPC_ENCODE_EMBEDDED_ARRAY(member) \ + const ArrayArgument::type> tmp_##member { value.member, std::extent::value }; \ + _encodeAndAppend (encoder, offsetof (StructType, member), tmp_##member); +#define ARA_IPC_ENCODE_VARIABLE_ARRAY(member, count) \ + if ((value.count > 0) && (value.member != nullptr)) { \ + const ArrayArgument::type> tmp_##member { value.member, value.count }; \ + _encodeAndAppend (encoder, offsetof (StructType, member), tmp_##member); \ + } +#define ARA_IPC_HAS_OPTIONAL_MEMBER(member) \ + /* \todo ARA_IMPLEMENTS_FIELD decorates the type with the ARA:: namespace, */ \ + /* this conflicts with decltype's result - this copied version drops the ARA:: */ \ + (value.structSize > offsetof (std::remove_reference::type, member)) +#define ARA_IPC_ENCODE_OPTIONAL_MEMBER(member) \ + if (ARA_IPC_HAS_OPTIONAL_MEMBER (member)) \ + ARA_IPC_ENCODE_MEMBER (member) +#define ARA_IPC_ENCODE_OPTIONAL_STRUCT_PTR(member) \ + if (ARA_IPC_HAS_OPTIONAL_MEMBER (member) && (value.member != nullptr)) \ + _encodeAndAppend (encoder, offsetof (StructType, member), *value.member); +#define ARA_IPC_END_ENCODE \ + } \ +}; + + +#define ARA_IPC_BEGIN_DECODE(StructT) \ +template<> struct _ValueDecoder : public _CompoundValueDecoderBase \ +{ /* specialization for given struct */ \ + using StructType = StructT; \ + static inline bool decode (StructType& result, const MessageDecoder& decoder) \ + { \ + bool success { true }; +#define ARA_IPC_BEGIN_DECODE_SIZED(StructT) \ + ARA_IPC_BEGIN_DECODE (StructT) \ + result.structSize = k##StructT##MinSize; +#define ARA_IPC_DECODE_MEMBER(member) \ + success &= _readAndDecode (result.member, decoder, offsetof (StructType, member)); \ + ARA_INTERNAL_ASSERT (success); +#define ARA_IPC_DECODE_EMBEDDED_BYTES(member) \ + auto resultSize_##member { sizeof (result.member) }; \ + BytesDecoder tmp_##member { reinterpret_cast (result.member), resultSize_##member }; \ + success &= _readAndDecode (tmp_##member, decoder, offsetof (StructType, member)); \ + success &= (resultSize_##member == sizeof (result.member)); \ + ARA_INTERNAL_ASSERT (success); +#define ARA_IPC_DECODE_EMBEDDED_ARRAY(member) \ + ArrayArgument::type> tmp_##member { result.member, std::extent::value }; \ + success &= _readAndDecode (tmp_##member, decoder, offsetof (StructType, member)); \ + ARA_INTERNAL_ASSERT (success); +#define ARA_IPC_DECODE_VARIABLE_ARRAY(member, count, updateCount) \ + /* \todo the outer struct contains a pointer to the inner array, so we need some */ \ + /* place to store it - this static only works as long as this is single-threaded! */ \ + static std::vector::type>::type> tmp_##member; \ + if (_readAndDecode (tmp_##member, decoder, offsetof (StructType, member))) { \ + result.member = tmp_##member.data (); \ + if (updateCount) { result.count = tmp_##member.size (); } \ + } else { \ + result.member = nullptr; \ + if (updateCount) { result.count = 0; } \ + } +#define ARA_IPC_UPDATE_STRUCT_SIZE_FOR_OPTIONAL(member) \ + /* \todo ARA_IMPLEMENTED_STRUCT_SIZE decorates the type with the ARA:: namespace, */ \ + /* conflicting with the local alias StructType - this copy simply drops the ARA:: */ \ + constexpr auto size { offsetof (StructType, member) + sizeof (static_cast (nullptr)->member) }; \ + result.structSize = std::max (result.structSize, size); +#define ARA_IPC_DECODE_OPTIONAL_MEMBER(member) \ + if (_readAndDecode (result.member, decoder, offsetof (StructType, member))) { \ + ARA_IPC_UPDATE_STRUCT_SIZE_FOR_OPTIONAL (member); \ + } +#define ARA_IPC_DECODE_OPTIONAL_STRUCT_PTR(member) \ + result.member = nullptr; /* set to null because other members may follow */ \ + auto subDecoder_##member { decoder.readSubMessage (offsetof (StructType, member)) }; \ + if (subDecoder_##member != nullptr) { \ + ARA_IPC_UPDATE_STRUCT_SIZE_FOR_OPTIONAL (member); \ + /* \todo the outer struct contains a pointer to the inner struct, so we need some */\ + /* place to store it - this static only works as long as this is single-threaded! */\ + static std::remove_const::type>::type cache; \ + success &= _ValueDecoder::decode (cache, *subDecoder_##member); \ + ARA_INTERNAL_ASSERT (success); \ + result.member = &cache; \ + delete subDecoder_##member; \ + } +#define ARA_IPC_END_DECODE \ + return success; \ + } \ +}; + + +ARA_IPC_BEGIN_ENCODE (ARAColor) + ARA_IPC_ENCODE_MEMBER (r) + ARA_IPC_ENCODE_MEMBER (g) + ARA_IPC_ENCODE_MEMBER (b) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE (ARAColor) + ARA_IPC_DECODE_MEMBER (r) + ARA_IPC_DECODE_MEMBER (g) + ARA_IPC_DECODE_MEMBER (b) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARADocumentProperties) + ARA_IPC_ENCODE_MEMBER (name) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE_SIZED (ARADocumentProperties) + ARA_IPC_DECODE_MEMBER (name) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARAMusicalContextProperties) + ARA_IPC_ENCODE_MEMBER (name) + ARA_IPC_ENCODE_OPTIONAL_MEMBER (orderIndex) + ARA_IPC_ENCODE_OPTIONAL_STRUCT_PTR (color) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE_SIZED (ARAMusicalContextProperties) + ARA_IPC_DECODE_MEMBER (name) + ARA_IPC_DECODE_OPTIONAL_MEMBER (orderIndex) + ARA_IPC_DECODE_OPTIONAL_STRUCT_PTR (color) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARARegionSequenceProperties) + ARA_IPC_ENCODE_MEMBER (name) + ARA_IPC_ENCODE_MEMBER (orderIndex) + ARA_IPC_ENCODE_MEMBER (musicalContextRef) + ARA_IPC_ENCODE_OPTIONAL_STRUCT_PTR (color) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE_SIZED (ARARegionSequenceProperties) + ARA_IPC_DECODE_MEMBER (name) + ARA_IPC_DECODE_MEMBER (orderIndex) + ARA_IPC_DECODE_MEMBER (musicalContextRef) + ARA_IPC_DECODE_OPTIONAL_STRUCT_PTR (color) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARAAudioSourceProperties) + ARA_IPC_ENCODE_MEMBER (name) + ARA_IPC_ENCODE_MEMBER (persistentID) + ARA_IPC_ENCODE_MEMBER (sampleCount) + ARA_IPC_ENCODE_MEMBER (sampleRate) + ARA_IPC_ENCODE_MEMBER (channelCount) + ARA_IPC_ENCODE_MEMBER (merits64BitSamples) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE_SIZED (ARAAudioSourceProperties) + ARA_IPC_DECODE_MEMBER (name) + ARA_IPC_DECODE_MEMBER (persistentID) + ARA_IPC_DECODE_MEMBER (sampleCount) + ARA_IPC_DECODE_MEMBER (sampleRate) + ARA_IPC_DECODE_MEMBER (channelCount) + ARA_IPC_DECODE_MEMBER (merits64BitSamples) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARAAudioModificationProperties) + ARA_IPC_ENCODE_MEMBER (name) + ARA_IPC_ENCODE_MEMBER (persistentID) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE_SIZED (ARAAudioModificationProperties) + ARA_IPC_DECODE_MEMBER (name) + ARA_IPC_DECODE_MEMBER (persistentID) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARAPlaybackRegionProperties) + ARA_IPC_ENCODE_MEMBER (transformationFlags) + ARA_IPC_ENCODE_MEMBER (startInModificationTime) + ARA_IPC_ENCODE_MEMBER (durationInModificationTime) + ARA_IPC_ENCODE_MEMBER (startInPlaybackTime) + ARA_IPC_ENCODE_MEMBER (durationInPlaybackTime) + ARA_IPC_ENCODE_MEMBER (musicalContextRef) + ARA_IPC_ENCODE_OPTIONAL_MEMBER (regionSequenceRef) + ARA_IPC_ENCODE_OPTIONAL_MEMBER (name) + ARA_IPC_ENCODE_OPTIONAL_STRUCT_PTR (color) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE_SIZED (ARAPlaybackRegionProperties) + ARA_IPC_DECODE_MEMBER (transformationFlags) + ARA_IPC_DECODE_MEMBER (startInModificationTime) + ARA_IPC_DECODE_MEMBER (durationInModificationTime) + ARA_IPC_DECODE_MEMBER (startInPlaybackTime) + ARA_IPC_DECODE_MEMBER (durationInPlaybackTime) + ARA_IPC_DECODE_MEMBER (musicalContextRef) + ARA_IPC_DECODE_OPTIONAL_MEMBER (regionSequenceRef) + ARA_IPC_DECODE_OPTIONAL_MEMBER (name) + ARA_IPC_DECODE_OPTIONAL_STRUCT_PTR (color) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARAContentTimeRange) + ARA_IPC_ENCODE_MEMBER (start) + ARA_IPC_ENCODE_MEMBER (duration) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE (ARAContentTimeRange) + ARA_IPC_DECODE_MEMBER (start) + ARA_IPC_DECODE_MEMBER (duration) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARAContentTempoEntry) + ARA_IPC_ENCODE_MEMBER (timePosition) + ARA_IPC_ENCODE_MEMBER (quarterPosition) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE (ARAContentTempoEntry) + ARA_IPC_DECODE_MEMBER (timePosition) + ARA_IPC_DECODE_MEMBER (quarterPosition) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARAContentBarSignature) + ARA_IPC_ENCODE_MEMBER (numerator) + ARA_IPC_ENCODE_MEMBER (denominator) + ARA_IPC_ENCODE_MEMBER (position) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE (ARAContentBarSignature) + ARA_IPC_DECODE_MEMBER (numerator) + ARA_IPC_DECODE_MEMBER (denominator) + ARA_IPC_DECODE_MEMBER (position) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARAContentNote) + ARA_IPC_ENCODE_MEMBER (frequency) + ARA_IPC_ENCODE_MEMBER (pitchNumber) + ARA_IPC_ENCODE_MEMBER (volume) + ARA_IPC_ENCODE_MEMBER (startPosition) + ARA_IPC_ENCODE_MEMBER (attackDuration) + ARA_IPC_ENCODE_MEMBER (noteDuration) + ARA_IPC_ENCODE_MEMBER (signalDuration) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE (ARAContentNote) + ARA_IPC_DECODE_MEMBER (frequency) + ARA_IPC_DECODE_MEMBER (pitchNumber) + ARA_IPC_DECODE_MEMBER (volume) + ARA_IPC_DECODE_MEMBER (startPosition) + ARA_IPC_DECODE_MEMBER (attackDuration) + ARA_IPC_DECODE_MEMBER (noteDuration) + ARA_IPC_DECODE_MEMBER (signalDuration) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARAContentTuning) + ARA_IPC_ENCODE_MEMBER (concertPitchFrequency) + ARA_IPC_ENCODE_MEMBER (root) + ARA_IPC_ENCODE_EMBEDDED_ARRAY (tunings) + ARA_IPC_ENCODE_MEMBER (name) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE (ARAContentTuning) + ARA_IPC_DECODE_MEMBER (concertPitchFrequency) + ARA_IPC_DECODE_MEMBER (root) + ARA_IPC_DECODE_EMBEDDED_ARRAY (tunings) + ARA_IPC_DECODE_MEMBER (name) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARAContentKeySignature) + ARA_IPC_ENCODE_MEMBER (root) + ARA_IPC_ENCODE_EMBEDDED_BYTES (intervals) + ARA_IPC_ENCODE_MEMBER (name) + ARA_IPC_ENCODE_MEMBER (position) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE (ARAContentKeySignature) + ARA_IPC_DECODE_MEMBER (root) + ARA_IPC_DECODE_EMBEDDED_BYTES (intervals) + ARA_IPC_DECODE_MEMBER (name) + ARA_IPC_DECODE_MEMBER (position) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARAContentChord) + ARA_IPC_ENCODE_MEMBER (root) + ARA_IPC_ENCODE_MEMBER (bass) + ARA_IPC_ENCODE_EMBEDDED_BYTES (intervals) + ARA_IPC_ENCODE_MEMBER (name) + ARA_IPC_ENCODE_MEMBER (position) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE (ARAContentChord) + ARA_IPC_DECODE_MEMBER (root) + ARA_IPC_DECODE_MEMBER (bass) + ARA_IPC_DECODE_EMBEDDED_BYTES (intervals) + ARA_IPC_DECODE_MEMBER (name) + ARA_IPC_DECODE_MEMBER (position) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARARestoreObjectsFilter) + ARA_IPC_ENCODE_MEMBER (documentData) + ARA_IPC_ENCODE_VARIABLE_ARRAY (audioSourceArchiveIDs, audioSourceIDsCount) + ARA_IPC_ENCODE_VARIABLE_ARRAY (audioSourceCurrentIDs, audioSourceIDsCount) + ARA_IPC_ENCODE_VARIABLE_ARRAY (audioModificationArchiveIDs, audioModificationIDsCount) + ARA_IPC_ENCODE_VARIABLE_ARRAY (audioModificationCurrentIDs, audioModificationIDsCount) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE_SIZED (ARARestoreObjectsFilter) + ARA_IPC_DECODE_MEMBER (documentData) + ARA_IPC_DECODE_VARIABLE_ARRAY (audioSourceArchiveIDs, audioSourceIDsCount, true) + ARA_IPC_DECODE_VARIABLE_ARRAY (audioSourceCurrentIDs, audioSourceIDsCount, false) + ARA_IPC_DECODE_VARIABLE_ARRAY (audioModificationArchiveIDs, audioModificationIDsCount, true) + ARA_IPC_DECODE_VARIABLE_ARRAY (audioModificationCurrentIDs, audioModificationIDsCount, false) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARAStoreObjectsFilter) + ARA_IPC_ENCODE_MEMBER (documentData) + ARA_IPC_ENCODE_VARIABLE_ARRAY (audioSourceRefs, audioSourceRefsCount) + ARA_IPC_ENCODE_VARIABLE_ARRAY (audioModificationRefs, audioModificationRefsCount) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE_SIZED (ARAStoreObjectsFilter) + ARA_IPC_DECODE_MEMBER (documentData) + ARA_IPC_DECODE_VARIABLE_ARRAY (audioSourceRefs, audioSourceRefsCount, true) + ARA_IPC_DECODE_VARIABLE_ARRAY (audioModificationRefs, audioModificationRefsCount, true) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARAProcessingAlgorithmProperties) + ARA_IPC_ENCODE_MEMBER (persistentID) + ARA_IPC_ENCODE_MEMBER (name) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE_SIZED (ARAProcessingAlgorithmProperties) + ARA_IPC_DECODE_MEMBER (persistentID) + ARA_IPC_DECODE_MEMBER (name) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARAViewSelection) + ARA_IPC_ENCODE_VARIABLE_ARRAY (playbackRegionRefs, playbackRegionRefsCount) + ARA_IPC_ENCODE_VARIABLE_ARRAY (regionSequenceRefs, regionSequenceRefsCount) + ARA_IPC_ENCODE_OPTIONAL_STRUCT_PTR (timeRange) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE_SIZED (ARAViewSelection) + ARA_IPC_DECODE_VARIABLE_ARRAY (playbackRegionRefs, playbackRegionRefsCount, true) + ARA_IPC_DECODE_VARIABLE_ARRAY (regionSequenceRefs, regionSequenceRefsCount, true) + ARA_IPC_DECODE_OPTIONAL_STRUCT_PTR (timeRange) +ARA_IPC_END_DECODE + +ARA_IPC_BEGIN_ENCODE (ARAFactory) + ARA_IPC_ENCODE_MEMBER (lowestSupportedApiGeneration) + ARA_IPC_ENCODE_MEMBER (highestSupportedApiGeneration) + ARA_IPC_ENCODE_MEMBER (factoryID) + ARA_IPC_ENCODE_MEMBER (plugInName) + ARA_IPC_ENCODE_MEMBER (manufacturerName) + ARA_IPC_ENCODE_MEMBER (informationURL) + ARA_IPC_ENCODE_MEMBER (version) + ARA_IPC_ENCODE_MEMBER (documentArchiveID) + ARA_IPC_ENCODE_VARIABLE_ARRAY (compatibleDocumentArchiveIDs, compatibleDocumentArchiveIDsCount) + ARA_IPC_ENCODE_VARIABLE_ARRAY (analyzeableContentTypes, analyzeableContentTypesCount) + ARA_IPC_ENCODE_MEMBER (supportedPlaybackTransformationFlags) + ARA_IPC_ENCODE_OPTIONAL_MEMBER (supportsStoringAudioFileChunks) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE_SIZED (ARAFactory) + ARA_IPC_DECODE_MEMBER (lowestSupportedApiGeneration) + ARA_IPC_DECODE_MEMBER (highestSupportedApiGeneration) + ARA_IPC_DECODE_MEMBER (factoryID) + result.initializeARAWithConfiguration = nullptr; + result.uninitializeARA = nullptr; + ARA_IPC_DECODE_MEMBER (plugInName) + ARA_IPC_DECODE_MEMBER (manufacturerName) + ARA_IPC_DECODE_MEMBER (informationURL) + ARA_IPC_DECODE_MEMBER (version) + result.createDocumentControllerWithDocument = nullptr; + ARA_IPC_DECODE_MEMBER (documentArchiveID) + ARA_IPC_DECODE_VARIABLE_ARRAY (compatibleDocumentArchiveIDs, compatibleDocumentArchiveIDsCount, true) + ARA_IPC_DECODE_VARIABLE_ARRAY (analyzeableContentTypes, analyzeableContentTypesCount, true) + ARA_IPC_DECODE_MEMBER (supportedPlaybackTransformationFlags) + ARA_IPC_DECODE_OPTIONAL_MEMBER (supportsStoringAudioFileChunks) +ARA_IPC_END_DECODE + + +// ARADocumentControllerInterface::storeAudioSourceToAudioFileChunk() must return the documentArchiveID and the +// openAutomatically flag in addition to the return value, we need a special struct to encode this through IPC. +struct StoreAudioSourceToAudioFileChunkReply +{ + ARABool result; + ARAPersistentID documentArchiveID; + ARABool openAutomatically; +}; +ARA_IPC_BEGIN_ENCODE (StoreAudioSourceToAudioFileChunkReply) + ARA_IPC_ENCODE_MEMBER (result) + ARA_IPC_ENCODE_MEMBER (documentArchiveID) + ARA_IPC_ENCODE_MEMBER (openAutomatically) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE (StoreAudioSourceToAudioFileChunkReply) + ARA_IPC_DECODE_MEMBER (result) + ARA_IPC_DECODE_MEMBER (documentArchiveID) + ARA_IPC_DECODE_MEMBER (openAutomatically) +ARA_IPC_END_DECODE + +// ARADocumentControllerInterface::getPlaybackRegionHeadAndTailTime() must return both head- and tailtime. +struct GetPlaybackRegionHeadAndTailTimeReply +{ + ARATimeDuration headTime; + ARATimeDuration tailTime; +}; +ARA_IPC_BEGIN_ENCODE (GetPlaybackRegionHeadAndTailTimeReply) + ARA_IPC_ENCODE_MEMBER (headTime) + ARA_IPC_ENCODE_MEMBER (tailTime) +ARA_IPC_END_ENCODE +ARA_IPC_BEGIN_DECODE (GetPlaybackRegionHeadAndTailTimeReply) + ARA_IPC_DECODE_MEMBER (headTime) + ARA_IPC_DECODE_MEMBER (tailTime) +ARA_IPC_END_DECODE + + +#undef ARA_IPC_BEGIN_ENCODE +#undef ARA_IPC_HAS_OPTIONAL_MEMBER +#undef ARA_IPC_ENCODE_MEMBER +#undef ARA_IPC_ENCODE_EMBEDDED_BYES +#undef ARA_IPC_ENCODE_EMBEDDED_ARRAY +#undef ARA_IPC_ENCODE_VARIABLE_ARRAY +#undef ARA_IPC_ENCODE_OPTIONAL_MEMBER +#undef ARA_IPC_ENCODE_OPTIONAL_STRUCT_PTR +#undef ARA_IPC_END_ENCODE + +#undef ARA_IPC_BEGIN_DECODE +#undef ARA_IPC_BEGIN_DECODE_SIZED +#undef ARA_IPC_DECODE_MEMBER +#undef ARA_IPC_DECODE_EMBEDDED_BYTES +#undef ARA_IPC_DECODE_EMBEDDED_ARRAY +#undef ARA_IPC_DECODE_VARIABLE_ARRAY +#undef ARA_IPC_UPDATE_STRUCT_SIZE_FOR_OPTIONAL +#undef ARA_IPC_DECODE_OPTIONAL_MEMBER +#undef ARA_IPC_DECODE_OPTIONAL_STRUCT_PTR +#undef ARA_IPC_END_DECODE + + +// actual definitions of wrapper functions to implicitly deduce _ValueEn-/Decoder<> - +// they are forward-declared above, before _ValueEn-/Decoder<> are defined +template +inline void _encodeAndAppend (MessageEncoder& encoder, const MessageKey argKey, const ValueT& argValue) +{ + return _ValueEncoder::encodeAndAppend (encoder, argKey, argValue); +} +template +inline bool _readAndDecode (ValueT& result, const MessageDecoder& decoder, const MessageKey argKey) +{ + return _ValueDecoder::readAndDecode (result, decoder, argKey); +} + + +//------------------------------------------------------------------------------ + +// private helper for decodeArguments() to deal with optional arguments +template +struct _IsOptionalArgument +{ + static constexpr bool value { false }; +}; +template +struct _IsOptionalArgument> +{ + static constexpr bool value { true }; +}; + +// private helpers for encodeArguments() and decodeArguments() to deal with the variable arguments one at a time +inline void _encodeArgumentsHelper (MessageEncoder& /*encoder*/, const MessageKey /*argKey*/) +{ +} +template::type::value, bool>::type = true> +inline void _encodeArgumentsHelper (MessageEncoder& encoder, const MessageKey argKey, const ArgT& argValue, const MoreArgs &... moreArgs) +{ + _encodeAndAppend (encoder, argKey, argValue); + _encodeArgumentsHelper (encoder, argKey + 1, moreArgs...); +} +template::type::value, bool>::type = true> +inline void _encodeArgumentsHelper (MessageEncoder& encoder, const MessageKey argKey, const ArgT& argValue, const MoreArgs &... moreArgs) +{ + if (argValue != nullptr) + _encodeAndAppend (encoder, argKey, *argValue); + _encodeArgumentsHelper (encoder, argKey + 1, moreArgs...); +} +template +inline void _encodeArgumentsHelper (MessageEncoder& encoder, const MessageKey argKey, const std::nullptr_t& /*argValue*/, const MoreArgs &... moreArgs) +{ + _encodeArgumentsHelper (encoder, argKey + 1, moreArgs...); +} + +inline void _decodeArgumentsHelper (const MessageDecoder& /*decoder*/, const MessageKey /*argKey*/) +{ +} +template::value, bool>::type = true> +inline void _decodeArgumentsHelper (const MessageDecoder& decoder, const MessageKey argKey, ArgT& argValue, MoreArgs &... moreArgs) +{ + _readAndDecode (argValue, decoder, argKey); + _decodeArgumentsHelper (decoder, argKey + 1, moreArgs...); +} +template::value, bool>::type = true> +inline void _decodeArgumentsHelper (const MessageDecoder& decoder, const MessageKey argKey, ArgT& argValue, MoreArgs &... moreArgs) +{ + argValue.second = _readAndDecode (argValue.first, decoder, argKey); + _decodeArgumentsHelper (decoder, argKey + 1, moreArgs...); +} + +// private helpers for ARA_IPC_HOST_METHOD_ID and ARA_IPC_PLUGIN_METHOD_ID +template +constexpr MessageID _getHostInterfaceID (); +template<> +constexpr MessageID _getHostInterfaceID () { return 0; } +template<> +constexpr MessageID _getHostInterfaceID () { return 1; } +template<> +constexpr MessageID _getHostInterfaceID () { return 2; } +template<> +constexpr MessageID _getHostInterfaceID () { return 3; } +template<> +constexpr MessageID _getHostInterfaceID () { return 4; } + +template +constexpr MessageID _getPlugInInterfaceID (); +template<> +constexpr MessageID _getPlugInInterfaceID () { return 0; } +template<> +constexpr MessageID _getPlugInInterfaceID () { return 1; } +template<> +constexpr MessageID _getPlugInInterfaceID () { return 2; } +template<> +constexpr MessageID _getPlugInInterfaceID () { return 3; } + +template +constexpr MessageID _encodeMessageID () +{ + static_assert (offset > 0, "offset 0 is never a valid function pointer"); + static_assert ((interfaceID < 8), "currently using only 3 bits for interface ID"); +#if defined (__i386__) || defined (_M_IX86) + static_assert ((sizeof (void*) == 4), "compiler settings imply 32 bit pointers"); + static_assert (((offset & 0x3FFFFFF4) == offset), "offset is misaligned or too large"); + return (offset << 1) + interfaceID; // lower 2 bits of offset are 0 due to alignment, must shift 1 bit to store interface ID +#else + static_assert ((sizeof (void*) == 8), "assuming 64 bit pointers per default"); + static_assert (((offset & 0x7FFFFFF8) == offset), "offset is misaligned or too large"); + return offset + interfaceID; // lower 3 bits of offset are 0 due to alignment, can be used to store interface ID +#endif +} + + +//------------------------------------------------------------------------------ +// actual client API +//------------------------------------------------------------------------------ + + +// caller side: create a message ID for a given ARA method +#define ARA_IPC_HOST_METHOD_ID(StructT, member) IPC::_encodeMessageID (), offsetof (StructT, member)> () +#define ARA_IPC_PLUGIN_METHOD_ID(StructT, member) IPC::_encodeMessageID (), offsetof (StructT, member)> () + +// "global" messages that are not passed based on interface structs +constexpr MessageID kGetFactoriesCountMessageID { 1 }; +constexpr MessageID kGetFactoryMessageID { 2 }; +constexpr MessageID kCreateDocumentControllerMessageID { 3 }; + + +// caller side: create a message with the specified arguments +template +inline void encodeArguments (MessageEncoder& encoder, const Args &... args) +{ + _encodeArgumentsHelper (encoder, 0, args...); +} + +// caller side: decode the received reply to a sent message +template::value || !std::is_pod::value, bool>::type = true> +inline bool decodeReply (RetT& result, const MessageDecoder& decoder) +{ + return _readAndDecode (result, decoder, 0); +} +template::value && std::is_pod::value, bool>::type = true> +inline bool decodeReply (RetT& result, const MessageDecoder& decoder) +{ + return _ValueDecoder::decode (result, decoder); +} + + +// callee side: decode the arguments of a received message +template +inline void decodeArguments (const MessageDecoder& decoder, Args &... args) +{ + _decodeArgumentsHelper (decoder, 0, args...); +} + +// callee side: wrapper for optional method arguments: first is the argument value, second if it was present +template +using OptionalArgument = typename std::pair; + +// callee side: encode the reply to a received message +template::value || !std::is_pod::value, bool>::type = true> +inline void encodeReply (MessageEncoder* encoder, const ValueT& value) +{ + ARA_INTERNAL_ASSERT (encoder != nullptr); + _encodeAndAppend (*encoder, 0, value); +} +template::value && std::is_pod::value, bool>::type = true> +inline void encodeReply (MessageEncoder* encoder, const ValueT& value) +{ + ARA_INTERNAL_ASSERT (encoder != nullptr); + _ValueEncoder::encode (*encoder, value); +} + + +// for debugging only: decoding method IDs +inline const char* _decodeMessageID (std::map& cache, const char* interfaceName, const MessageID messageID) +{ + auto it { cache.find (messageID) }; + if (it == cache.end ()) + it = cache.emplace (messageID, std::string { interfaceName } + " method " + std::to_string (messageID >> 3)).first; + return it->second.c_str(); +} +inline const char* decodeHostMessageID (const MessageID messageID) +{ + static std::map cache; + const char* interfaceName; + switch (messageID & 0x7) + { + case 0: interfaceName = "ARAAudioAccessControllerInterface"; break; + case 1: interfaceName = "ARAArchivingControllerInterface"; break; + case 2: interfaceName = "ARAContentAccessControllerInterface"; break; + case 3: interfaceName = "ARAModelUpdateControllerInterface"; break; + case 4: interfaceName = "ARAPlaybackControllerInterface"; break; + default: ARA_INTERNAL_ASSERT (false); interfaceName = "(unknown)"; break; + } + return _decodeMessageID (cache, interfaceName, messageID); +} +inline const char* decodePlugInMessageID (const MessageID messageID) +{ + static std::map cache; + const char* interfaceName; + switch (messageID & 0x7) + { + case 0: interfaceName = "ARADocumentControllerInterface"; break; + case 1: interfaceName = "ARAPlaybackRendererInterface"; break; + case 2: interfaceName = "ARAEditorRendererInterface"; break; + case 3: interfaceName = "ARAEditorViewInterface"; break; + default: ARA_INTERNAL_ASSERT (false); interfaceName = "(unknown)"; break; + } + return _decodeMessageID (cache, interfaceName, messageID); +} + +//------------------------------------------------------------------------------ +// support for content readers +//------------------------------------------------------------------------------ + +inline void encodeContentEvent (MessageEncoder* encoder, const ARAContentType type, const void* eventData) +{ + switch (type) + { + case kARAContentTypeNotes: encodeReply (encoder, *static_cast (eventData)); break; + case kARAContentTypeTempoEntries: encodeReply (encoder, *static_cast (eventData)); break; + case kARAContentTypeBarSignatures: encodeReply (encoder, *static_cast (eventData)); break; + case kARAContentTypeStaticTuning: encodeReply (encoder, *static_cast (eventData)); break; + case kARAContentTypeKeySignatures: encodeReply (encoder, *static_cast (eventData)); break; + case kARAContentTypeSheetChords: encodeReply (encoder, *static_cast (eventData)); break; + default: ARA_INTERNAL_ASSERT (false && "content type not implemented yet"); break; + } +} + +class ContentEventDecoder +{ +public: + ContentEventDecoder (ARAContentType type) + : _decoderFunction { _getDecoderFunctionForContentType (type) }, + _contentString { _findStringMember (type) } + {} + + const void* decode (const MessageDecoder& decoder) + { + (this->*_decoderFunction) (decoder); + return &_eventStorage; + } + +private: + using _DecoderFunction = void (ContentEventDecoder::*) (const MessageDecoder&); + + template + void _decodeContentEvent (const MessageDecoder& decoder) + { + decodeReply (*reinterpret_cast (&this->_eventStorage), decoder); + if (this->_contentString != nullptr) + { + this->_stringStorage.assign (*this->_contentString); + *this->_contentString = this->_stringStorage.c_str (); + } + } + + static inline +#if __cplusplus >= 201402L + constexpr +#endif + _DecoderFunction _getDecoderFunctionForContentType (const ARAContentType type) + { + switch (type) + { + case kARAContentTypeNotes: return &ContentEventDecoder::_decodeContentEvent::DataType>; + case kARAContentTypeTempoEntries: return &ContentEventDecoder::_decodeContentEvent::DataType>; + case kARAContentTypeBarSignatures: return &ContentEventDecoder::_decodeContentEvent::DataType>; + case kARAContentTypeStaticTuning: return &ContentEventDecoder::_decodeContentEvent::DataType>; + case kARAContentTypeKeySignatures: return &ContentEventDecoder::_decodeContentEvent::DataType>; + case kARAContentTypeSheetChords: return &ContentEventDecoder::_decodeContentEvent::DataType>; + default: ARA_INTERNAL_ASSERT (false); return nullptr; + } + } + + static inline +#if __cplusplus >= 201402L + constexpr +#endif + size_t _getStringMemberOffsetForContentType (const ARAContentType type) + { + switch (type) + { + case kARAContentTypeStaticTuning: return offsetof (ARAContentTuning, name); + case kARAContentTypeKeySignatures: return offsetof (ARAContentKeySignature, name); + case kARAContentTypeSheetChords: return offsetof (ARAContentChord, name); + default: return 0; + } + } + + inline ARAUtf8String* _findStringMember (const ARAContentType type) + { + const auto offset { ContentEventDecoder::_getStringMemberOffsetForContentType (type) }; + if (offset == 0) + return nullptr; + return reinterpret_cast (reinterpret_cast (&this->_eventStorage) + offset); + } + +private: + _DecoderFunction const _decoderFunction; // instead of performing the switch (type) for each event, + // we select a templated member function in the c'tor + union + { + ARAContentTempoEntry _tempoEntry; + ARAContentBarSignature _barSignature; + ARAContentNote _note; + ARAContentTuning _tuning; + ARAContentKeySignature _keySignature; + ARAContentChord _chord; + } _eventStorage {}; + + ARAUtf8String* _contentString {}; + std::string _stringStorage {}; + + ARA_DISABLE_COPY_AND_MOVE (ContentEventDecoder) +}; + +//------------------------------------------------------------------------------ +// implementation helpers +//------------------------------------------------------------------------------ + +// helper base class to create and send messages, decoding reply if applicable +// It's possible to specify a CustomDecodeFunction as reply type to access an un-decoded reply +// if needed (e.g. to deal with memory ownership issue). +class RemoteCaller +{ +public: + using CustomDecodeFunction = std::function; + + RemoteCaller (Sender& sender) noexcept : _sender { sender } {} + + template + void remoteCallWithoutReply (const MessageID messageID, const Args &... args) + { + auto encoder { _sender.createEncoder () }; + encodeArguments (*encoder, args...); + _sender.sendMessage (messageID, *encoder, nullptr); + delete encoder; + } + + template + void remoteCallWithReply (RetT& result, const MessageID messageID, const Args &... args) + { + auto encoder { _sender.createEncoder () }; + encodeArguments (*encoder, args...); + Sender::ReplyHandler replyHandler { [&result] (const MessageDecoder& decoder) -> void + { + ARA_INTERNAL_ASSERT (!decoder.isEmpty ()); + decodeReply (result, decoder); + } }; + _sender.sendMessage (messageID, *encoder, &replyHandler); + delete encoder; + } + template + void remoteCallWithReply (CustomDecodeFunction& result, const MessageID messageID, const Args &... args) + { + auto encoder { _sender.createEncoder () }; + encodeArguments (*encoder, args...); + Sender::ReplyHandler replyHandler { [&result] (const MessageDecoder& decoder) -> void + { + ARA_INTERNAL_ASSERT (!decoder.isEmpty ()); + result (decoder); + } }; + _sender.sendMessage (messageID, *encoder, &replyHandler); + delete encoder; + } + + bool receiverEndianessMatches () { return _sender.receiverEndianessMatches (); } + +private: + Sender& _sender; +}; + +} // namespace IPC +} // namespace ARA + +#endif // ARA_ENABLE_IPC + +#endif // ARAIPCEncoding_h diff --git a/IPC/ARAIPCProxyHost.cpp b/IPC/ARAIPCProxyHost.cpp new file mode 100644 index 0000000..66d77ee --- /dev/null +++ b/IPC/ARAIPCProxyHost.cpp @@ -0,0 +1,1259 @@ +//------------------------------------------------------------------------------ +//! \file ARAIPCProxyHost.cpp +//! implementation of host-side ARA IPC proxy host +//! \project ARA SDK Examples +//! \copyright Copyright (c) 2021-2022, Celemony Software GmbH, All Rights Reserved. +//! \license Licensed under the Apache License, Version 2.0 (the "License"); +//! you may not use this file except in compliance with the License. +//! You may obtain a copy of the License at +//! +//! http://www.apache.org/licenses/LICENSE-2.0 +//! +//! Unless required by applicable law or agreed to in writing, software +//! distributed under the License is distributed on an "AS IS" BASIS, +//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//! See the License for the specific language governing permissions and +//! limitations under the License. +//------------------------------------------------------------------------------ + +#include "ARAIPCProxyHost.h" + + +#if ARA_ENABLE_IPC + +#include "ARA_Library/Dispatch/ARAHostDispatch.h" +#include "ARA_Library/Dispatch/ARAPlugInDispatch.h" + +#if ARA_VALIDATE_API_CALLS + #include "ARA_Library/Debug/ARAContentValidator.h" + #include "ARA_Library/Utilities/ARAStdVectorUtilities.h" +#endif + +#include +#include +#include + + +#if ARA_SUPPORT_VERSION_1 + #error "The ARA IPC proxy host implementation does not support ARA 1." +#endif + + +namespace ARA { +namespace IPC { +namespace ProxyHost { + +class AudioAccessController; +class ArchivingController; +class ContentAccessController; +class ModelUpdateController; +class PlaybackController; +class DocumentController; + + +/*******************************************************************************/ + +struct RemoteAudioSource +{ + ARAAudioSourceHostRef mainHostRef; + ARAAudioSourceRef plugInRef; + ARAChannelCount channelCount; +}; +ARA_MAP_REF (RemoteAudioSource, ARAAudioSourceRef) +ARA_MAP_HOST_REF (RemoteAudioSource, ARAAudioSourceHostRef) + +struct RemoteAudioReader +{ + RemoteAudioSource* audioSource; + ARAAudioReaderHostRef mainHostRef; + size_t sampleSize; + void (*swapFunction) (void* buffer, ARASampleCount sampleCount); +}; +ARA_MAP_HOST_REF (RemoteAudioReader, ARAAudioReaderHostRef) + +struct RemoteContentReader +{ + ARAContentReaderRef plugInRef; + ARAContentType contentType; +}; +ARA_MAP_REF (RemoteContentReader, ARAContentReaderRef) + +struct RemoteHostContentReader +{ + RemoteHostContentReader (ARAContentReaderHostRef hostRef, ARAContentType type) + : remoteHostRef { hostRef }, decoder { type } {} + + ARAContentReaderHostRef remoteHostRef; + ContentEventDecoder decoder; +}; +ARA_MAP_HOST_REF (RemoteHostContentReader, ARAContentReaderHostRef) + + +/*******************************************************************************/ +//! Implementation of AudioAccessControllerInterface that channels all calls through IPC +class AudioAccessController : public Host::AudioAccessControllerInterface, public RemoteCaller +{ +public: + AudioAccessController (Sender& sender, ARAAudioAccessControllerHostRef remoteHostRef) noexcept + : RemoteCaller { sender }, _remoteHostRef { remoteHostRef } {} + + ARAAudioReaderHostRef createAudioReaderForSource (ARAAudioSourceHostRef audioSourceHostRef, bool use64BitSamples) noexcept override; + bool readAudioSamples (ARAAudioReaderHostRef audioReaderHostRef, ARASamplePosition samplePosition, ARASampleCount samplesPerChannel, void* const buffers[]) noexcept override; + void destroyAudioReader (ARAAudioReaderHostRef audioReaderHostRef) noexcept override; + +private: + ARAAudioAccessControllerHostRef _remoteHostRef; +}; + +/*******************************************************************************/ + +void _swap (float* ptr) +{ + auto asIntPtr { reinterpret_cast (ptr) }; +#if defined (_MSC_VER) + *asIntPtr = _byteswap_ulong (*asIntPtr); +#elif defined (__GNUC__) + *asIntPtr = __builtin_bswap32 (*asIntPtr); +#else + #error "not implemented for this compiler." +#endif +} +void _swap (double* ptr) +{ + auto asIntPtr { reinterpret_cast (ptr) }; +#if defined (_MSC_VER) + *asIntPtr = _byteswap_uint64 (*asIntPtr); +#elif defined (__GNUC__) + *asIntPtr = __builtin_bswap64 (*asIntPtr); +#else + #error "not implemented for this compiler." +#endif +} + +template +void _swapBuffer (void* buffer, ARASampleCount sampleCount) +{ + for (auto i { 0 }; i < sampleCount; ++i) + _swap (static_cast (buffer) + i); +} + +ARAAudioReaderHostRef AudioAccessController::createAudioReaderForSource (ARAAudioSourceHostRef audioSourceHostRef, bool use64BitSamples) noexcept +{ + auto remoteAudioReader { new RemoteAudioReader }; + remoteAudioReader->audioSource = fromHostRef (audioSourceHostRef); + remoteAudioReader->sampleSize = (use64BitSamples) ? sizeof (double) : sizeof (float); + if (receiverEndianessMatches ()) + remoteAudioReader->swapFunction = nullptr; + else + remoteAudioReader->swapFunction = (use64BitSamples) ? &_swapBuffer : &_swapBuffer; + remoteCallWithReply (remoteAudioReader->mainHostRef, ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, createAudioReaderForSource), _remoteHostRef, remoteAudioReader->audioSource->mainHostRef, use64BitSamples); + return toHostRef (remoteAudioReader); +} + +bool AudioAccessController::readAudioSamples (ARAAudioReaderHostRef audioReaderHostRef, ARASamplePosition samplePosition, + ARASampleCount samplesPerChannel, void* const buffers[]) noexcept +{ + auto remoteAudioReader { fromHostRef (audioReaderHostRef) }; + const auto channelCount { static_cast (remoteAudioReader->audioSource->channelCount) }; + + // recursively limit message size to keep IPC responsive + if (samplesPerChannel > 8192) + { + const auto samplesPerChannel1 { samplesPerChannel / 2 }; + const auto result1 { readAudioSamples (audioReaderHostRef, samplePosition, samplesPerChannel1, buffers) }; + + const auto samplesPerChannel2 { samplesPerChannel - samplesPerChannel1 }; + std::vector buffers2; + buffers2.reserve (channelCount); + for (auto i { 0U }; i < channelCount; ++i) + buffers2.emplace_back (static_cast (buffers[i]) + static_cast (samplesPerChannel1) * remoteAudioReader->sampleSize); + + if (result1) + { + return readAudioSamples (audioReaderHostRef, samplePosition + samplesPerChannel1, samplesPerChannel2, buffers2.data ()); + } + else + { + for (auto i { 0U }; i < channelCount; ++i) + std::memset (buffers2[i], 0, static_cast (samplesPerChannel2) * remoteAudioReader->sampleSize); + return false; + } + } + + // custom decoding to deal with float data memory ownership + bool success { false }; + RemoteCaller::CustomDecodeFunction customDecode { [&success, &remoteAudioReader, &samplesPerChannel, &channelCount, &buffers] (const MessageDecoder& decoder) -> void + { + const auto bufferSize { remoteAudioReader->sampleSize * static_cast (samplesPerChannel) }; + std::vector resultSizes; + std::vector decoders; + resultSizes.reserve (channelCount); + decoders.reserve (channelCount); + for (auto i { 0U }; i < channelCount; ++i) + { + resultSizes.emplace_back (bufferSize); + decoders.emplace_back (static_cast (buffers[i]), resultSizes[i]); + } + + ArrayArgument channelData { decoders.data (), decoders.size () }; + success = decodeReply (channelData, decoder); + if (success) + ARA_INTERNAL_ASSERT (channelData.count == channelCount); + + for (auto i { 0U }; i < channelCount; ++i) + { + if (success) + { + ARA_INTERNAL_ASSERT (resultSizes[i] == bufferSize); + if (remoteAudioReader->swapFunction) + remoteAudioReader->swapFunction (buffers[i], samplesPerChannel); + } + else + { + std::memset (buffers[i], 0, bufferSize); + } + } + + } }; + remoteCallWithReply (customDecode, ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, readAudioSamples), + _remoteHostRef, remoteAudioReader->mainHostRef, samplePosition, samplesPerChannel); + return success; +} + +void AudioAccessController::destroyAudioReader (ARAAudioReaderHostRef audioReaderHostRef) noexcept +{ + auto remoteAudioReader { fromHostRef (audioReaderHostRef) }; + remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, destroyAudioReader), _remoteHostRef, remoteAudioReader->mainHostRef); + delete remoteAudioReader; +} + + +/*******************************************************************************/ +//! Implementation of ArchivingControllerInterface that channels all calls through IPC +class ArchivingController : public Host::ArchivingControllerInterface, public RemoteCaller +{ +public: + ArchivingController (Sender& sender, ARAArchivingControllerHostRef remoteHostRef) noexcept + : RemoteCaller { sender }, _remoteHostRef { remoteHostRef } {} + + ARASize getArchiveSize (ARAArchiveReaderHostRef archiveReaderHostRef) noexcept override; + bool readBytesFromArchive (ARAArchiveReaderHostRef archiveReaderHostRef, ARASize position, ARASize length, ARAByte buffer[]) noexcept override; + bool writeBytesToArchive (ARAArchiveWriterHostRef archiveWriterHostRef, ARASize position, ARASize length, const ARAByte buffer[]) noexcept override; + void notifyDocumentArchivingProgress (float value) noexcept override; + void notifyDocumentUnarchivingProgress (float value) noexcept override; + ARAPersistentID getDocumentArchiveID (ARAArchiveReaderHostRef archiveReaderHostRef) noexcept override; + +private: + ARAArchivingControllerHostRef _remoteHostRef; + std::string _archiveID; +}; + +/*******************************************************************************/ + +ARASize ArchivingController::getArchiveSize (ARAArchiveReaderHostRef archiveReaderHostRef) noexcept +{ + ARASize size; + remoteCallWithReply (size, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, getArchiveSize), _remoteHostRef, archiveReaderHostRef); + return size; +} + +bool ArchivingController::readBytesFromArchive (ARAArchiveReaderHostRef archiveReaderHostRef, ARASize position, ARASize length, ARAByte buffer[]) noexcept +{ + // recursively limit message size to keep IPC responsive + if (length > 131072) + { + const auto length1 { length / 2 }; + const auto result1 { readBytesFromArchive (archiveReaderHostRef, position, length1, buffer) }; + + const auto length2 { length - length1 }; + buffer += length1; + if (result1) + { + return readBytesFromArchive (archiveReaderHostRef, position + length1, length2, buffer); + } + else + { + std::memset (buffer, 0, length2); + return false; + } + } + + auto resultLength { length }; + BytesDecoder writer { buffer, resultLength }; + remoteCallWithReply (writer, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, readBytesFromArchive), + _remoteHostRef, archiveReaderHostRef, position, length); + if (resultLength == length) + { + return true; + } + else + { + std::memset (buffer, 0, length); + return false; + } +} + +bool ArchivingController::writeBytesToArchive (ARAArchiveWriterHostRef archiveWriterHostRef, ARASize position, ARASize length, const ARAByte buffer[]) noexcept +{ + // recursively limit message size to keep IPC responsive + if (length > 131072) + { + const auto length1 { length / 2 }; + const auto result1 { writeBytesToArchive (archiveWriterHostRef, position, length1, buffer) }; + + const auto length2 { length - length1 }; + buffer += length1; + if (result1) + { + return writeBytesToArchive (archiveWriterHostRef, position + length1, length2, buffer); + } + else + { + return false; + } + } + + ARABool success; + remoteCallWithReply (success, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, writeBytesToArchive), + _remoteHostRef, archiveWriterHostRef, position, BytesEncoder { buffer, length, false }); + return (success != kARAFalse); +} + +void ArchivingController::notifyDocumentArchivingProgress (float value) noexcept +{ + remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, notifyDocumentArchivingProgress), _remoteHostRef, value); +} + +void ArchivingController::notifyDocumentUnarchivingProgress (float value) noexcept +{ + remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, notifyDocumentUnarchivingProgress), _remoteHostRef, value); +} + +ARAPersistentID ArchivingController::getDocumentArchiveID (ARAArchiveReaderHostRef archiveReaderHostRef) noexcept +{ + RemoteCaller::CustomDecodeFunction customDecode { [this] (const MessageDecoder& decoder) -> void + { + ARAPersistentID persistentID; + decodeReply (persistentID, decoder); + _archiveID.assign (persistentID); + } }; + remoteCallWithReply (customDecode, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, getDocumentArchiveID), _remoteHostRef, archiveReaderHostRef); + return _archiveID.c_str(); +} + + +/*******************************************************************************/ +//! Implementation of ContentAccessControllerInterface that channels all calls through IPC +class ContentAccessController : public Host::ContentAccessControllerInterface, public RemoteCaller +{ +public: + ContentAccessController (Sender& sender, ARAContentAccessControllerHostRef remoteHostRef) noexcept + : RemoteCaller { sender }, _remoteHostRef { remoteHostRef } {} + + bool isMusicalContextContentAvailable (ARAMusicalContextHostRef musicalContextHostRef, ARAContentType type) noexcept override; + ARAContentGrade getMusicalContextContentGrade (ARAMusicalContextHostRef musicalContextHostRef, ARAContentType type) noexcept override; + ARAContentReaderHostRef createMusicalContextContentReader (ARAMusicalContextHostRef musicalContextHostRef, ARAContentType type, const ARAContentTimeRange* range) noexcept override; + bool isAudioSourceContentAvailable (ARAAudioSourceHostRef audioSourceHostRef, ARAContentType type) noexcept override; + ARAContentGrade getAudioSourceContentGrade (ARAAudioSourceHostRef audioSourceHostRef, ARAContentType type) noexcept override; + ARAContentReaderHostRef createAudioSourceContentReader (ARAAudioSourceHostRef audioSourceHostRef, ARAContentType type, const ARAContentTimeRange* range) noexcept override; + ARAInt32 getContentReaderEventCount (ARAContentReaderHostRef contentReaderHostRef) noexcept override; + const void* getContentReaderDataForEvent (ARAContentReaderHostRef contentReaderHostRef, ARAInt32 eventIndex) noexcept override; + void destroyContentReader (ARAContentReaderHostRef contentReaderHostRef) noexcept override; + +private: + ARAContentAccessControllerHostRef _remoteHostRef; +}; + +/*******************************************************************************/ + +bool ContentAccessController::isMusicalContextContentAvailable (ARAMusicalContextHostRef musicalContextHostRef, ARAContentType type) noexcept +{ + ARABool result; + remoteCallWithReply (result, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, isMusicalContextContentAvailable), + _remoteHostRef, musicalContextHostRef, type); + return (result != kARAFalse); +} + +ARAContentGrade ContentAccessController::getMusicalContextContentGrade (ARAMusicalContextHostRef musicalContextHostRef, ARAContentType type) noexcept +{ + ARAContentGrade grade; + remoteCallWithReply (grade, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getMusicalContextContentGrade), + _remoteHostRef, musicalContextHostRef, type); + return grade; +} + +ARAContentReaderHostRef ContentAccessController::createMusicalContextContentReader (ARAMusicalContextHostRef musicalContextHostRef, ARAContentType type, const ARAContentTimeRange* range) noexcept +{ + ARAContentReaderHostRef contentReaderHostRef; + remoteCallWithReply (contentReaderHostRef, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, createMusicalContextContentReader), + _remoteHostRef, musicalContextHostRef, type, range); + auto contentReader { new RemoteHostContentReader (contentReaderHostRef, type) }; + return toHostRef (contentReader); +} + +bool ContentAccessController::isAudioSourceContentAvailable (ARAAudioSourceHostRef audioSourceHostRef, ARAContentType type) noexcept +{ + ARABool result; + remoteCallWithReply (result, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, isAudioSourceContentAvailable), + _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, type); + return (result != kARAFalse); +} + +ARAContentGrade ContentAccessController::getAudioSourceContentGrade (ARAAudioSourceHostRef audioSourceHostRef, ARAContentType type) noexcept +{ + ARAContentGrade grade; + remoteCallWithReply (grade, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getAudioSourceContentGrade), + _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, type); + return grade; +} + +ARAContentReaderHostRef ContentAccessController::createAudioSourceContentReader (ARAAudioSourceHostRef audioSourceHostRef, ARAContentType type, const ARAContentTimeRange* range) noexcept +{ + ARAContentReaderHostRef contentReaderHostRef; + remoteCallWithReply (contentReaderHostRef, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, createAudioSourceContentReader), + _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, type, range); + auto contentReader { new RemoteHostContentReader (contentReaderHostRef, type) }; + return toHostRef (contentReader); +} + +ARAInt32 ContentAccessController::getContentReaderEventCount (ARAContentReaderHostRef contentReaderHostRef) noexcept +{ + const auto contentReader { fromHostRef (contentReaderHostRef) }; + ARAInt32 count; + remoteCallWithReply (count, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getContentReaderEventCount), + _remoteHostRef, contentReader->remoteHostRef); + return count; +} + +const void* ContentAccessController::getContentReaderDataForEvent (ARAContentReaderHostRef contentReaderHostRef, ARAInt32 eventIndex) noexcept +{ + const auto contentReader { fromHostRef (contentReaderHostRef) }; + const void* result {}; + RemoteCaller::CustomDecodeFunction customDecode { [&result, &contentReader] (const MessageDecoder& decoder) -> void + { + result = contentReader->decoder.decode (decoder); + } }; + remoteCallWithReply (customDecode, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getContentReaderDataForEvent), + _remoteHostRef, contentReader->remoteHostRef, eventIndex); + return result; +} + +void ContentAccessController::destroyContentReader (ARAContentReaderHostRef contentReaderHostRef) noexcept +{ + const auto contentReader { fromHostRef (contentReaderHostRef) }; + remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, destroyContentReader), _remoteHostRef, contentReader->remoteHostRef); + delete contentReader; +} + + +/*******************************************************************************/ +//! Implementation of ModelUpdateControllerInterface that channels all calls through IPC +class ModelUpdateController : public Host::ModelUpdateControllerInterface, public RemoteCaller +{ +public: + ModelUpdateController (Sender& sender, ARAModelUpdateControllerHostRef remoteHostRef) noexcept + : RemoteCaller { sender }, _remoteHostRef { remoteHostRef } {} + + void notifyAudioSourceAnalysisProgress (ARAAudioSourceHostRef audioSourceHostRef, ARAAnalysisProgressState state, float value) noexcept override; + void notifyAudioSourceContentChanged (ARAAudioSourceHostRef audioSourceHostRef, const ARAContentTimeRange* range, ContentUpdateScopes scopeFlags) noexcept override; + void notifyAudioModificationContentChanged (ARAAudioModificationHostRef audioModificationHostRef, const ARAContentTimeRange* range, ContentUpdateScopes scopeFlags) noexcept override; + void notifyPlaybackRegionContentChanged (ARAPlaybackRegionHostRef playbackRegionHostRef, const ARAContentTimeRange* range, ContentUpdateScopes scopeFlags) noexcept override; + +private: + ARAModelUpdateControllerHostRef _remoteHostRef; +}; + +/*******************************************************************************/ + +void ModelUpdateController::notifyAudioSourceAnalysisProgress (ARAAudioSourceHostRef audioSourceHostRef, ARAAnalysisProgressState state, float value) noexcept +{ + remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioSourceAnalysisProgress), _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, state, value); +} + +void ModelUpdateController::notifyAudioSourceContentChanged (ARAAudioSourceHostRef audioSourceHostRef, const ARAContentTimeRange* range, ContentUpdateScopes scopeFlags) noexcept +{ + remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioSourceContentChanged), _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, range, scopeFlags); +} + +void ModelUpdateController::notifyAudioModificationContentChanged (ARAAudioModificationHostRef audioModificationHostRef, const ARAContentTimeRange* range, ContentUpdateScopes scopeFlags) noexcept +{ + remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioModificationContentChanged), _remoteHostRef, audioModificationHostRef, range, scopeFlags); +} + +void ModelUpdateController::notifyPlaybackRegionContentChanged (ARAPlaybackRegionHostRef playbackRegionHostRef, const ARAContentTimeRange* range, ContentUpdateScopes scopeFlags) noexcept +{ + remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyPlaybackRegionContentChanged), _remoteHostRef, playbackRegionHostRef, range, scopeFlags); +} + + +/*******************************************************************************/ +//! Implementation of PlaybackControllerInterface that channels all calls through IPC +class PlaybackController : public Host::PlaybackControllerInterface, public RemoteCaller +{ +public: + PlaybackController (Sender& sender, ARAPlaybackControllerHostRef remoteHostRef) noexcept + : RemoteCaller { sender }, _remoteHostRef { remoteHostRef } {} + + void requestStartPlayback () noexcept override; + void requestStopPlayback () noexcept override; + void requestSetPlaybackPosition (ARATimePosition timePosition) noexcept override; + void requestSetCycleRange (ARATimePosition startTime, ARATimeDuration duration) noexcept override; + void requestEnableCycle (bool enable) noexcept override; + +private: + ARAPlaybackControllerHostRef _remoteHostRef; +}; + +/*******************************************************************************/ + +void PlaybackController::requestStartPlayback () noexcept +{ + remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestStartPlayback), _remoteHostRef); +} + +void PlaybackController::requestStopPlayback () noexcept +{ + remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestStopPlayback), _remoteHostRef); +} + +void PlaybackController::requestSetPlaybackPosition (ARATimePosition timePosition) noexcept +{ + remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestSetPlaybackPosition), _remoteHostRef, timePosition); +} + +void PlaybackController::requestSetCycleRange (ARATimePosition startTime, ARATimeDuration duration) noexcept +{ + remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestSetCycleRange), _remoteHostRef, startTime, duration); +} + +void PlaybackController::requestEnableCycle (bool enable) noexcept +{ + remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestEnableCycle), _remoteHostRef, (enable) ? kARATrue : kARAFalse); +} + + +/*******************************************************************************/ +//! Extension of Host::DocumentController that also stores the host instance visible to the plug-in +class DocumentController : public Host::DocumentController +{ +public: + explicit DocumentController (const Host::DocumentControllerHostInstance* hostInstance, const ARADocumentControllerInstance* instance) noexcept + : Host::DocumentController { instance }, + _hostInstance { hostInstance } + {} + + const Host::DocumentControllerHostInstance* getHostInstance () { return _hostInstance; } + +private: + const Host::DocumentControllerHostInstance* _hostInstance; +}; +ARA_MAP_REF (DocumentController, ARADocumentControllerRef) + + +/*******************************************************************************/ +//! Wrapper class for a plug-in extension instance that can forward remote calls to its sub-interfaces +class PlugInExtension +{ +public: + explicit PlugInExtension (const ARAPlugInExtensionInstance* instance) + : _playbackRenderer { instance }, + _editorRenderer { instance }, + _editorView { instance } + {} + + // Getters for ARA specific plug-in role interfaces + Host::PlaybackRenderer* getPlaybackRenderer () { return &_playbackRenderer; } + Host::EditorRenderer* getEditorRenderer () { return &_editorRenderer; } + Host::EditorView* getEditorView () { return &_editorView; } + +private: + Host::PlaybackRenderer _playbackRenderer; + Host::EditorRenderer _editorRenderer; + Host::EditorView _editorView; +}; +ARA_MAP_REF (PlugInExtension, ARAPlugInExtensionRef, ARAPlaybackRendererRef, ARAEditorRendererRef, ARAEditorViewRef) + + +/*******************************************************************************/ + +std::vector _factories {}; +Sender* _plugInCallbacksSender {}; + +void addFactory (const ARAFactory* factory) +{ + ARA_INTERNAL_ASSERT(factory->highestSupportedApiGeneration >= kARAAPIGeneration_2_0_Final); + ARA_INTERNAL_ASSERT(!ARA::contains (_factories, factory)); + + _factories.emplace_back (factory); +} + +void setPlugInCallbacksSender (Sender* plugInCallbacksSender) +{ + _plugInCallbacksSender = plugInCallbacksSender; +} + +ARADocumentControllerRef getDocumentControllerRefForRemoteRef (ARADocumentControllerRef remoteRef) +{ + return fromRef (remoteRef)->getRef (); +} + +ARAPlugInExtensionRef createPlugInExtension (const ARAPlugInExtensionInstance* instance) +{ + return toRef (new PlugInExtension { instance }); +} + +void destroyPlugInExtension (ARAPlugInExtensionRef plugInExtensionRef) +{ + delete fromRef (plugInExtensionRef); +} + +void hostCommandHandler (const MessageID messageID, const MessageDecoder& decoder, MessageEncoder* const replyEncoder) +{ +// ARA_LOG ("hostCommandHandler received message %s", decodePlugInMessageID (messageID)); + + // ARAFactory + if (messageID == kGetFactoriesCountMessageID) + { + return encodeReply (replyEncoder, _factories.size ()); + } + else if (messageID == kGetFactoryMessageID) + { + ARASize index; + decodeArguments (decoder, index); + ARA_INTERNAL_ASSERT (index < _factories.size ()); + return encodeReply (replyEncoder, *_factories[index]); + } + else if (messageID == kCreateDocumentControllerMessageID) + { + ARAPersistentID factoryID; + ARAAudioAccessControllerHostRef audioAccessControllerHostRef; + ARAArchivingControllerHostRef archivingControllerHostRef; + ARABool provideContentAccessController; + ARAContentAccessControllerHostRef contentAccessControllerHostRef; + ARABool provideModelUpdateController; + ARAModelUpdateControllerHostRef modelUpdateControllerHostRef; + ARABool providePlaybackController; + ARAPlaybackControllerHostRef playbackControllerHostRef; + ARADocumentProperties properties; + decodeArguments (decoder, factoryID, + audioAccessControllerHostRef, archivingControllerHostRef, + provideContentAccessController, contentAccessControllerHostRef, + provideModelUpdateController, modelUpdateControllerHostRef, + providePlaybackController, playbackControllerHostRef, + properties); + + const ARAFactory* factory {}; + for (const auto& f : _factories) + { + if (0 == std::strcmp (f->factoryID, factoryID)) + { + factory = f; + break; + } + } + ARA_INTERNAL_ASSERT (factory != nullptr); + if (factory != nullptr) + { + const auto audioAccessController { new AudioAccessController { *_plugInCallbacksSender, audioAccessControllerHostRef } }; + const auto archivingController { new ArchivingController { *_plugInCallbacksSender, archivingControllerHostRef } }; + const auto contentAccessController { (provideContentAccessController != kARAFalse) ? new ContentAccessController { *_plugInCallbacksSender, contentAccessControllerHostRef } : nullptr }; + const auto modelUpdateController { (provideModelUpdateController != kARAFalse) ? new ModelUpdateController { *_plugInCallbacksSender, modelUpdateControllerHostRef } : nullptr }; + const auto playbackController { (providePlaybackController != kARAFalse) ? new PlaybackController { *_plugInCallbacksSender, playbackControllerHostRef } : nullptr }; + + const auto hostInstance { new Host::DocumentControllerHostInstance { audioAccessController, archivingController, + contentAccessController, modelUpdateController, playbackController } }; + + auto documentControllerInstance { factory->createDocumentControllerWithDocument (hostInstance, &properties) }; + ARA_VALIDATE_API_CONDITION (documentControllerInstance != nullptr); + ARA_VALIDATE_API_INTERFACE (documentControllerInstance->documentControllerInterface, ARADocumentControllerInterface); + auto documentController { new DocumentController (hostInstance, documentControllerInstance) }; + return encodeReply (replyEncoder, ARADocumentControllerRef { toRef (documentController) }); + } + } + + //ARADocumentControllerInterface + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyDocumentController)) + { + ARADocumentControllerRef controllerRef; + decodeArguments (decoder, controllerRef); + auto documentController { fromRef (controllerRef) }; + documentController->destroyDocumentController (); + + delete documentController->getHostInstance ()->getPlaybackController (); + delete documentController->getHostInstance ()->getModelUpdateController (); + delete documentController->getHostInstance ()->getContentAccessController (); + delete documentController->getHostInstance ()->getArchivingController (); + delete documentController->getHostInstance ()->getAudioAccessController (); + delete documentController->getHostInstance (); + delete documentController; + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getFactory)) + { + ARA_INTERNAL_ASSERT (false && "should never be queried here but instead cached from companion API upon setup"); + + ARADocumentControllerRef controllerRef; + decodeArguments (decoder, controllerRef); + + return encodeReply (replyEncoder, *(fromRef (controllerRef)->getFactory ())); + } + + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, beginEditing)) + { + ARADocumentControllerRef controllerRef; + decodeArguments (decoder, controllerRef); + + fromRef (controllerRef)->beginEditing (); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, endEditing)) + { + ARADocumentControllerRef controllerRef; + decodeArguments (decoder, controllerRef); + + fromRef (controllerRef)->endEditing (); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, notifyModelUpdates)) + { + ARADocumentControllerRef controllerRef; + decodeArguments (decoder, controllerRef); + + fromRef (controllerRef)->notifyModelUpdates (); + } + + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, restoreObjectsFromArchive)) + { + ARADocumentControllerRef controllerRef; + ARAArchiveReaderHostRef archiveReaderHostRef; + OptionalArgument filter; + decodeArguments (decoder, controllerRef, archiveReaderHostRef, filter); + + return encodeReply (replyEncoder, fromRef (controllerRef)->restoreObjectsFromArchive (archiveReaderHostRef, (filter.second) ? &filter.first : nullptr) ? kARATrue : kARAFalse); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, storeObjectsToArchive)) + { + ARADocumentControllerRef controllerRef; + ARAArchiveWriterHostRef archiveWriterHostRef; + OptionalArgument filter; + decodeArguments (decoder, controllerRef, archiveWriterHostRef, filter); + + std::vector audioSourceRefs; + if (filter.second && (filter.first.audioSourceRefsCount > 0)) + { + audioSourceRefs.reserve (filter.first.audioSourceRefsCount); + for (auto i { 0U }; i < filter.first.audioSourceRefsCount; ++i) + audioSourceRefs.emplace_back (fromRef (filter.first.audioSourceRefs[i])->plugInRef); + + filter.first.audioSourceRefs = audioSourceRefs.data (); + } + + return encodeReply (replyEncoder, fromRef (controllerRef)->storeObjectsToArchive (archiveWriterHostRef, (filter.second) ? &filter.first : nullptr) ? kARATrue : kARAFalse); + } + + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateDocumentProperties)) + { + ARADocumentControllerRef controllerRef; + ARADocumentProperties properties; + decodeArguments (decoder, controllerRef, properties); + + fromRef (controllerRef)->updateDocumentProperties (&properties); + } + + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createMusicalContext)) + { + ARADocumentControllerRef controllerRef; + ARAMusicalContextHostRef hostRef; + ARAMusicalContextProperties properties; + decodeArguments (decoder, controllerRef, hostRef, properties); + + return encodeReply (replyEncoder, fromRef (controllerRef)->createMusicalContext (hostRef, &properties)); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateMusicalContextProperties)) + { + ARADocumentControllerRef controllerRef; + ARAMusicalContextRef musicalContextRef; + ARAMusicalContextProperties properties; + decodeArguments (decoder, controllerRef, musicalContextRef, properties); + + fromRef (controllerRef)->updateMusicalContextProperties (musicalContextRef, &properties); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateMusicalContextContent)) + { + ARADocumentControllerRef controllerRef; + ARAMusicalContextRef musicalContextRef; + OptionalArgument range; + ARAContentUpdateFlags flags; + decodeArguments (decoder, controllerRef, musicalContextRef, range, flags); + + fromRef (controllerRef)->updateMusicalContextContent (musicalContextRef, (range.second) ? &range.first : nullptr, flags); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyMusicalContext)) + { + ARADocumentControllerRef controllerRef; + ARAMusicalContextRef musicalContextRef; + decodeArguments (decoder, controllerRef, musicalContextRef); + + fromRef (controllerRef)->destroyMusicalContext (musicalContextRef); + } + + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createRegionSequence)) + { + ARADocumentControllerRef controllerRef; + ARARegionSequenceHostRef hostRef; + ARARegionSequenceProperties properties; + decodeArguments (decoder, controllerRef, hostRef, properties); + + return encodeReply (replyEncoder, fromRef (controllerRef)->createRegionSequence (hostRef, &properties)); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateRegionSequenceProperties)) + { + ARADocumentControllerRef controllerRef; + ARARegionSequenceRef regionSequenceRef; + ARARegionSequenceProperties properties; + decodeArguments (decoder, controllerRef, regionSequenceRef, properties); + + fromRef (controllerRef)->updateRegionSequenceProperties (regionSequenceRef, &properties); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyRegionSequence)) + { + ARADocumentControllerRef controllerRef; + ARARegionSequenceRef regionSequenceRef; + decodeArguments (decoder, controllerRef, regionSequenceRef); + + fromRef (controllerRef)->destroyRegionSequence (regionSequenceRef); + } + + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioSource)) + { + auto remoteAudioSource { new RemoteAudioSource }; + + ARADocumentControllerRef controllerRef; + ARAAudioSourceProperties properties; + decodeArguments (decoder, controllerRef, remoteAudioSource->mainHostRef, properties); + + remoteAudioSource->channelCount = properties.channelCount; + remoteAudioSource->plugInRef = fromRef (controllerRef)->createAudioSource (toHostRef (remoteAudioSource), &properties); + + return encodeReply (replyEncoder, ARAAudioSourceRef { toRef (remoteAudioSource) }); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioSourceProperties)) + { + ARADocumentControllerRef controllerRef; + ARAAudioSourceRef audioSourceRef; + ARAAudioSourceProperties properties; + decodeArguments (decoder, controllerRef, audioSourceRef, properties); + + fromRef (controllerRef)->updateAudioSourceProperties (fromRef (audioSourceRef)->plugInRef, &properties); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioSourceContent)) + { + ARADocumentControllerRef controllerRef; + ARAAudioSourceRef audioSourceRef; + OptionalArgument range; + ARAContentUpdateFlags flags; + decodeArguments (decoder, controllerRef, audioSourceRef, range, flags); + + fromRef (controllerRef)->updateAudioSourceContent (fromRef (audioSourceRef)->plugInRef, (range.second) ? &range.first : nullptr, flags); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, enableAudioSourceSamplesAccess)) + { + ARADocumentControllerRef controllerRef; + ARAAudioSourceRef audioSourceRef; + ARABool enable; + decodeArguments (decoder, controllerRef, audioSourceRef, enable); + + fromRef (controllerRef)->enableAudioSourceSamplesAccess (fromRef (audioSourceRef)->plugInRef, (enable) ? kARATrue : kARAFalse); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, deactivateAudioSourceForUndoHistory)) + { + ARADocumentControllerRef controllerRef; + ARAAudioSourceRef audioSourceRef; + ARABool deactivate; + decodeArguments (decoder, controllerRef, audioSourceRef, deactivate); + + fromRef (controllerRef)->deactivateAudioSourceForUndoHistory (fromRef (audioSourceRef)->plugInRef, (deactivate) ? kARATrue : kARAFalse); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, storeAudioSourceToAudioFileChunk)) + { + ARADocumentControllerRef controllerRef; + ARAArchiveWriterHostRef archiveWriterHostRef; + ARAAudioSourceRef audioSourceRef; + decodeArguments (decoder, controllerRef, archiveWriterHostRef, audioSourceRef); + + StoreAudioSourceToAudioFileChunkReply reply; + bool openAutomatically; + reply.result = (fromRef (controllerRef)->storeAudioSourceToAudioFileChunk (archiveWriterHostRef, fromRef (audioSourceRef)->plugInRef, + &reply.documentArchiveID, &openAutomatically)) ? kARATrue : kARAFalse; + reply.openAutomatically = (openAutomatically) ? kARATrue : kARAFalse; + return encodeReply (replyEncoder, reply); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioSourceContentAnalysisIncomplete)) + { + ARADocumentControllerRef controllerRef; + ARAAudioSourceRef audioSourceRef; + ARAContentType contentType; + decodeArguments (decoder, controllerRef, audioSourceRef, contentType); + + return encodeReply (replyEncoder, fromRef (controllerRef)->isAudioSourceContentAnalysisIncomplete (fromRef (audioSourceRef)->plugInRef, contentType)); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, requestAudioSourceContentAnalysis)) + { + ARADocumentControllerRef controllerRef; + ARAAudioSourceRef audioSourceRef; + std::vector contentTypes; + decodeArguments (decoder, controllerRef, audioSourceRef, contentTypes); + + fromRef (controllerRef)->requestAudioSourceContentAnalysis (fromRef (audioSourceRef)->plugInRef, contentTypes.size (), contentTypes.data ()); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioSourceContentAvailable)) + { + ARADocumentControllerRef controllerRef; + ARAAudioSourceRef audioSourceRef; + ARAContentType contentType; + decodeArguments (decoder, controllerRef, audioSourceRef, contentType); + + return encodeReply (replyEncoder, (fromRef (controllerRef)->isAudioSourceContentAvailable (fromRef (audioSourceRef)->plugInRef, contentType)) ? kARATrue : kARAFalse); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getAudioSourceContentGrade)) + { + ARADocumentControllerRef controllerRef; + ARAAudioSourceRef audioSourceRef; + ARAContentType contentType; + decodeArguments (decoder, controllerRef, audioSourceRef, contentType); + + return encodeReply (replyEncoder, fromRef (controllerRef)->getAudioSourceContentGrade (fromRef (audioSourceRef)->plugInRef, contentType)); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioSourceContentReader)) + { + ARADocumentControllerRef controllerRef; + ARAAudioSourceRef audioSourceRef; + ARAContentType contentType; + OptionalArgument range; + decodeArguments (decoder, controllerRef, audioSourceRef, contentType, range); + + auto remoteContentReader { new RemoteContentReader }; + remoteContentReader->plugInRef = fromRef (controllerRef)->createAudioSourceContentReader (fromRef (audioSourceRef)->plugInRef, contentType, (range.second) ? &range.first : nullptr); + remoteContentReader->contentType = contentType; + return encodeReply (replyEncoder, ARAContentReaderRef { toRef (remoteContentReader) }); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyAudioSource)) + { + ARADocumentControllerRef controllerRef; + ARAAudioSourceRef audioSourceRef; + decodeArguments (decoder, controllerRef, audioSourceRef); + + auto remoteAudioSource { fromRef (audioSourceRef) }; + fromRef (controllerRef)->destroyAudioSource (remoteAudioSource->plugInRef); + + delete remoteAudioSource; + } + + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioModification)) + { + ARADocumentControllerRef controllerRef; + ARAAudioSourceRef audioSourceRef; + ARAAudioModificationHostRef hostRef; + ARAAudioModificationProperties properties; + decodeArguments (decoder, controllerRef, audioSourceRef, hostRef, properties); + + return encodeReply (replyEncoder, fromRef (controllerRef)->createAudioModification (fromRef (audioSourceRef)->plugInRef, hostRef, &properties)); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, cloneAudioModification)) + { + ARADocumentControllerRef controllerRef; + ARAAudioModificationRef audioModificationRef; + ARAAudioModificationHostRef hostRef; + ARAAudioModificationProperties properties; + decodeArguments (decoder, controllerRef, audioModificationRef, hostRef, properties); + + return encodeReply (replyEncoder, fromRef (controllerRef)->cloneAudioModification (audioModificationRef, hostRef, &properties)); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioModificationProperties)) + { + ARADocumentControllerRef controllerRef; + ARAAudioModificationRef audioModificationRef; + ARAAudioModificationProperties properties; + decodeArguments (decoder, controllerRef, audioModificationRef, properties); + + fromRef (controllerRef)->updateAudioModificationProperties (audioModificationRef, &properties); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, deactivateAudioModificationForUndoHistory)) + { + ARADocumentControllerRef controllerRef; + ARAAudioModificationRef audioModificationRef; + ARABool deactivate; + decodeArguments (decoder, controllerRef, audioModificationRef, deactivate); + + fromRef (controllerRef)->deactivateAudioModificationForUndoHistory (audioModificationRef, (deactivate) ? kARATrue : kARAFalse); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioModificationContentAvailable)) + { + ARADocumentControllerRef controllerRef; + ARAAudioModificationRef audioModificationRef; + ARAContentType contentType; + decodeArguments (decoder, controllerRef, audioModificationRef, contentType); + + return encodeReply (replyEncoder, (fromRef (controllerRef)->isAudioModificationContentAvailable (audioModificationRef, contentType)) ? kARATrue : kARAFalse); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getAudioModificationContentGrade)) + { + ARADocumentControllerRef controllerRef; + ARAAudioModificationRef audioModificationRef; + ARAContentType contentType; + decodeArguments (decoder, controllerRef, audioModificationRef, contentType); + + return encodeReply (replyEncoder, fromRef (controllerRef)->getAudioModificationContentGrade (audioModificationRef, contentType)); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioModificationContentReader)) + { + ARADocumentControllerRef controllerRef; + ARAAudioModificationRef audioModificationRef; + ARAContentType contentType; + OptionalArgument range; + decodeArguments (decoder, controllerRef, audioModificationRef, contentType, range); + + auto remoteContentReader { new RemoteContentReader }; + remoteContentReader->plugInRef = fromRef (controllerRef)->createAudioModificationContentReader (audioModificationRef, contentType, (range.second) ? &range.first : nullptr); + remoteContentReader->contentType = contentType; + return encodeReply (replyEncoder, ARAContentReaderRef { toRef (remoteContentReader) }); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyAudioModification)) + { + ARADocumentControllerRef controllerRef; + ARAAudioModificationRef audioModificationRef; + decodeArguments (decoder, controllerRef, audioModificationRef); + + fromRef (controllerRef)->destroyAudioModification (audioModificationRef); + } + + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createPlaybackRegion)) + { + ARADocumentControllerRef controllerRef; + ARAAudioModificationRef audioModificationRef; + ARAPlaybackRegionHostRef hostRef; + ARAPlaybackRegionProperties properties; + decodeArguments (decoder, controllerRef, audioModificationRef, hostRef, properties); + + return encodeReply (replyEncoder, fromRef (controllerRef)->createPlaybackRegion (audioModificationRef, hostRef, &properties)); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updatePlaybackRegionProperties)) + { + ARADocumentControllerRef controllerRef; + ARAPlaybackRegionRef playbackRegionRef; + ARAPlaybackRegionProperties properties; + decodeArguments (decoder, controllerRef, playbackRegionRef, properties); + + fromRef (controllerRef)->updatePlaybackRegionProperties (playbackRegionRef, &properties); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getPlaybackRegionHeadAndTailTime)) + { + ARADocumentControllerRef controllerRef; + ARAPlaybackRegionRef playbackRegionRef; + ARABool wantsHeadTime; + ARABool wantsTailTime; + decodeArguments (decoder, controllerRef, playbackRegionRef, wantsHeadTime, wantsTailTime); + + GetPlaybackRegionHeadAndTailTimeReply reply { 0.0, 0.0 }; + fromRef (controllerRef)->getPlaybackRegionHeadAndTailTime (playbackRegionRef, (wantsHeadTime != kARAFalse) ? &reply.headTime : nullptr, + (wantsTailTime != kARAFalse) ? &reply.tailTime : nullptr); + return encodeReply (replyEncoder, reply); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isPlaybackRegionContentAvailable)) + { + ARADocumentControllerRef controllerRef; + ARAPlaybackRegionRef playbackRegionRef; + ARAContentType contentType; + decodeArguments (decoder, controllerRef, playbackRegionRef, contentType); + + return encodeReply (replyEncoder, (fromRef (controllerRef)->isPlaybackRegionContentAvailable (playbackRegionRef, contentType)) ? kARATrue : kARAFalse); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getPlaybackRegionContentGrade)) + { + ARADocumentControllerRef controllerRef; + ARAPlaybackRegionRef playbackRegionRef; + ARAContentType contentType; + decodeArguments (decoder, controllerRef, playbackRegionRef, contentType); + + return encodeReply (replyEncoder, fromRef (controllerRef)->getPlaybackRegionContentGrade (playbackRegionRef, contentType)); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createPlaybackRegionContentReader)) + { + ARADocumentControllerRef controllerRef; + ARAPlaybackRegionRef playbackRegionRef; + ARAContentType contentType; + OptionalArgument range; + decodeArguments (decoder, controllerRef, playbackRegionRef, contentType, range); + + auto remoteContentReader { new RemoteContentReader }; + remoteContentReader->plugInRef = fromRef (controllerRef)->createPlaybackRegionContentReader (playbackRegionRef, contentType, (range.second) ? &range.first : nullptr); + remoteContentReader->contentType = contentType; + return encodeReply (replyEncoder, ARAContentReaderRef { toRef (remoteContentReader) }); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyPlaybackRegion)) + { + ARADocumentControllerRef controllerRef; + ARAPlaybackRegionRef playbackRegionRef; + decodeArguments (decoder, controllerRef, playbackRegionRef); + + fromRef (controllerRef)->destroyPlaybackRegion (playbackRegionRef); + } + + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getContentReaderEventCount)) + { + ARADocumentControllerRef controllerRef; + ARAContentReaderRef contentReaderRef; + decodeArguments (decoder, controllerRef, contentReaderRef); + + return encodeReply (replyEncoder, fromRef (controllerRef)->getContentReaderEventCount (fromRef (contentReaderRef)->plugInRef)); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getContentReaderDataForEvent)) + { + ARADocumentControllerRef controllerRef; + ARAContentReaderRef contentReaderRef; + ARAInt32 eventIndex; + decodeArguments (decoder, controllerRef, contentReaderRef, eventIndex); + + auto remoteContentReader { fromRef (contentReaderRef) }; + const void* eventData { fromRef (controllerRef)->getContentReaderDataForEvent (remoteContentReader->plugInRef, eventIndex) }; + return encodeContentEvent (replyEncoder, remoteContentReader->contentType, eventData); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyContentReader)) + { + ARADocumentControllerRef controllerRef; + ARAContentReaderRef contentReaderRef; + decodeArguments (decoder, controllerRef, contentReaderRef); + + auto remoteContentReader { fromRef (contentReaderRef) }; + fromRef (controllerRef)->destroyContentReader (remoteContentReader->plugInRef); + + delete remoteContentReader; + } + + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmsCount)) + { + ARADocumentControllerRef controllerRef; + decodeArguments (decoder, controllerRef); + + return encodeReply (replyEncoder, fromRef (controllerRef)->getProcessingAlgorithmsCount ()); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmProperties)) + { + ARADocumentControllerRef controllerRef; + ARAInt32 algorithmIndex; + decodeArguments (decoder, controllerRef, algorithmIndex); + + return encodeReply (replyEncoder, *(fromRef (controllerRef)->getProcessingAlgorithmProperties (algorithmIndex))); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmForAudioSource)) + { + ARADocumentControllerRef controllerRef; + ARAAudioSourceRef audioSourceRef; + decodeArguments (decoder, controllerRef, audioSourceRef); + + return encodeReply (replyEncoder, fromRef (controllerRef)->getProcessingAlgorithmForAudioSource (fromRef (audioSourceRef)->plugInRef)); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, requestProcessingAlgorithmForAudioSource)) + { + ARADocumentControllerRef controllerRef; + ARAAudioSourceRef audioSourceRef; + ARAInt32 algorithmIndex; + decodeArguments (decoder, controllerRef, audioSourceRef, algorithmIndex); + + fromRef (controllerRef)->requestProcessingAlgorithmForAudioSource (fromRef (audioSourceRef)->plugInRef, algorithmIndex); + } + + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isLicensedForCapabilities)) + { + ARADocumentControllerRef controllerRef; + ARABool runModalActivationDialogIfNeeded; + std::vector types; + ARAPlaybackTransformationFlags transformationFlags; + decodeArguments (decoder, controllerRef, runModalActivationDialogIfNeeded, types, transformationFlags); + + return encodeReply (replyEncoder, (fromRef (controllerRef)->isLicensedForCapabilities ((runModalActivationDialogIfNeeded != kARAFalse), + types.size(), types.data (), transformationFlags)) ? kARATrue : kARAFalse); + } + + // ARAPlaybackRendererInterface + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARAPlaybackRendererInterface, addPlaybackRegion)) + { + ARAPlaybackRendererRef playbackRendererRef; + ARAPlaybackRegionRef playbackRegionRef; + decodeArguments (decoder, playbackRendererRef, playbackRegionRef); + + fromRef (playbackRendererRef)->getPlaybackRenderer ()->addPlaybackRegion (playbackRegionRef); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARAPlaybackRendererInterface, removePlaybackRegion)) + { + ARAPlaybackRendererRef playbackRendererRef; + ARAPlaybackRegionRef playbackRegionRef; + decodeArguments (decoder, playbackRendererRef, playbackRegionRef); + + fromRef (playbackRendererRef)->getPlaybackRenderer ()->removePlaybackRegion (playbackRegionRef); + } + + // ARAEditorRendererInterface + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, addPlaybackRegion)) + { + ARAEditorRendererRef editorRendererRef; + ARAPlaybackRegionRef playbackRegionRef; + decodeArguments (decoder, editorRendererRef, playbackRegionRef); + + fromRef (editorRendererRef)->getEditorRenderer ()->addPlaybackRegion (playbackRegionRef); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, removePlaybackRegion)) + { + ARAEditorRendererRef editorRendererRef; + ARAPlaybackRegionRef playbackRegionRef; + decodeArguments (decoder, editorRendererRef, playbackRegionRef); + + fromRef (editorRendererRef)->getEditorRenderer ()->removePlaybackRegion (playbackRegionRef); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, addRegionSequence)) + { + ARAEditorRendererRef editorRendererRef; + ARARegionSequenceRef regionSequenceRef; + decodeArguments (decoder, editorRendererRef, regionSequenceRef); + + fromRef (editorRendererRef)->getEditorRenderer ()->addRegionSequence (regionSequenceRef); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, removeRegionSequence)) + { + ARAEditorRendererRef editorRendererRef; + ARARegionSequenceRef regionSequenceRef; + decodeArguments (decoder, editorRendererRef, regionSequenceRef); + + fromRef (editorRendererRef)->getEditorRenderer ()->removeRegionSequence (regionSequenceRef); + } + + // ARAEditorViewInterface + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARAEditorViewInterface, notifySelection)) + { + ARAEditorViewRef editorViewRef; + ARAViewSelection selection; + decodeArguments (decoder, editorViewRef, selection); + + fromRef (editorViewRef)->getEditorView ()->notifySelection (&selection); + } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARAEditorViewInterface, notifyHideRegionSequences)) + { + ARAEditorViewRef editorViewRef; + std::vector regionSequenceRefs; + decodeArguments (decoder, editorViewRef, regionSequenceRefs); + + fromRef (editorViewRef)->getEditorView ()->notifyHideRegionSequences (regionSequenceRefs.size (), regionSequenceRefs.data ()); + } + + else + { + ARA_INTERNAL_ASSERT (false && "unhandled message ID"); + } + + // all calls that create a reply return early from their respective if (). +// it is valid to provide a dummy replyEncoder if no reply has been requested. +// ARA_INTERNAL_ASSERT (replyEncoder == nullptr); +} + +} // namespace ProxyHost +} // namespace IPC +} // namespace ARA + +#endif // ARA_ENABLE_IPC diff --git a/IPC/ARAIPCProxyHost.h b/IPC/ARAIPCProxyHost.h new file mode 100644 index 0000000..ea1d7b2 --- /dev/null +++ b/IPC/ARAIPCProxyHost.h @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +//! \file ARAIPCProxyHost.h +//! implementation of host-side ARA IPC proxy host +//! \project ARA SDK Examples +//! \copyright Copyright (c) 2021-2022, Celemony Software GmbH, All Rights Reserved. +//! \license Licensed under the Apache License, Version 2.0 (the "License"); +//! you may not use this file except in compliance with the License. +//! You may obtain a copy of the License at +//! +//! http://www.apache.org/licenses/LICENSE-2.0 +//! +//! Unless required by applicable law or agreed to in writing, software +//! distributed under the License is distributed on an "AS IS" BASIS, +//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//! See the License for the specific language governing permissions and +//! limitations under the License. +//------------------------------------------------------------------------------ + +#ifndef ARAIPCProxyHost_h +#define ARAIPCProxyHost_h + + +#include "ARAIPCEncoding.h" + + +#if ARA_ENABLE_IPC + + +namespace ARA { +namespace IPC { +namespace ProxyHost { + + +//! static configuration: add the ARA factories that the proxy host will wrap +void addFactory (const ARAFactory* factory); + +//! static configuration: set sender that the proxy host will use to perform callbacks received from the plug-in +void setPlugInCallbacksSender (Sender* plugInCallbacksSender); + +//! static dispatcher: the host command handler that controls the proxy host +void hostCommandHandler (const MessageID messageID, const MessageDecoder& decoder, MessageEncoder* const replyEncoder); + +//! translation needed when establishing the binding to the remote documentController +ARADocumentControllerRef getDocumentControllerRefForRemoteRef (ARADocumentControllerRef remoteRef); + +//! creating and deleting plug-in extension instances associated with the proxy host +ARAPlugInExtensionRef createPlugInExtension (const ARAPlugInExtensionInstance* instance); +void destroyPlugInExtension (ARAPlugInExtensionRef plugInExtensionRef); + + +} // namespace ProxyHost +} // namespace IPC +} // namespace ARA + + +#endif // ARA_ENABLE_IPC + +#endif // ARAIPCProxyHost_h diff --git a/IPC/ARAIPCProxyPlugIn.cpp b/IPC/ARAIPCProxyPlugIn.cpp new file mode 100644 index 0000000..1c16c30 --- /dev/null +++ b/IPC/ARAIPCProxyPlugIn.cpp @@ -0,0 +1,1721 @@ +//------------------------------------------------------------------------------ +//! \file ARAIPCProxyPlugIn.cpp +//! implementation of host-side ARA IPC proxy plug-in +//! \project ARA SDK Examples +//! \copyright Copyright (c) 2021-2022, Celemony Software GmbH, All Rights Reserved. +//! \license Licensed under the Apache License, Version 2.0 (the "License"); +//! you may not use this file except in compliance with the License. +//! You may obtain a copy of the License at +//! +//! http://www.apache.org/licenses/LICENSE-2.0 +//! +//! Unless required by applicable law or agreed to in writing, software +//! distributed under the License is distributed on an "AS IS" BASIS, +//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//! See the License for the specific language governing permissions and +//! limitations under the License. +//------------------------------------------------------------------------------ + +#include "ARAIPCProxyPlugIn.h" + + +#if ARA_ENABLE_IPC + +#include "ARA_Library/Dispatch/ARAPlugInDispatch.h" +#include "ARA_Library/Dispatch/ARAHostDispatch.h" + +#if ARA_VALIDATE_API_CALLS + #include "ARA_Library/Debug/ARAContentValidator.h" +#endif + +#include +#include +#include + + +#if ARA_SUPPORT_VERSION_1 + #error "The ARA IPC proxy plug-in implementation does not support ARA 1." +#endif + + +/*******************************************************************************/ +// configuration switches for debug output +// each can be defined as a nonzero integer to enable the associated logging + +// log each entry from the host into the document controller (except for notifyModelUpdates (), which is called too often) +#ifndef ARA_ENABLE_HOST_ENTRY_LOG + #define ARA_ENABLE_HOST_ENTRY_LOG 0 +#endif + +// log the creation and destruction of plug-in objects +#ifndef ARA_ENABLE_OBJECT_LIFETIME_LOG + #define ARA_ENABLE_OBJECT_LIFETIME_LOG 0 +#endif + +// conditional logging helper functions based on the above switches +#if ARA_ENABLE_HOST_ENTRY_LOG + #define ARA_LOG_HOST_ENTRY(object) ARA_LOG ("Host calls into %s (%p)", __FUNCTION__, object); +#else + #define ARA_LOG_HOST_ENTRY(object) ((void) 0) +#endif + +#if ARA_ENABLE_OBJECT_LIFETIME_LOG + #define ARA_LOG_MODELOBJECT_LIFETIME(message, object) ARA_LOG ("Plug success: document controller %p %s %p", object->getDocumentController (), message, object) +#else + #define ARA_LOG_MODELOBJECT_LIFETIME(message, object) ((void) 0) +#endif + + +/*******************************************************************************/ + +namespace ARA { +namespace IPC { +namespace ProxyPlugIn { + +struct AudioSource; +struct ContentReader; +struct HostContentReader; +struct HostAudioReader; +class DocumentController; +class PlaybackRenderer; +class EditorRenderer; +class EditorView; +class PlugInExtension; + + +/*******************************************************************************/ +// ObjectRef validation helper class - empty class unless ARA_VALIDATE_API_CALLS is enabled + +template +class InstanceValidator +{ +#if ARA_VALIDATE_API_CALLS +protected: + inline InstanceValidator () noexcept + { + auto result { _instances.insert (this) }; + ARA_INTERNAL_ASSERT (result.second); + } + + inline ~InstanceValidator () + { + auto it { _instances.find (this) }; + ARA_INTERNAL_ASSERT (it != _instances.end ()); + _instances.erase (it); + } + +public: + static inline bool isValid (const InstanceValidator* instance) + { + return _instances.find (instance) != _instances.end (); + } + +private: + static std::set _instances; +#endif +}; + +template +std::set*> InstanceValidator::_instances; + +template +inline bool isValidInstance (const SubclassT* instance) +{ + return InstanceValidator::isValid (instance); +} + + +/*******************************************************************************/ + +struct AudioSource +#if ARA_VALIDATE_API_CALLS + : public InstanceValidator +#endif +{ +#if ARA_VALIDATE_API_CALLS + AudioSource (ARAAudioSourceHostRef hostRef_, ARAAudioSourceRef remoteRef_, ARAChannelCount channelCount_, + ARASampleCount sampleCount_, ARASampleRate sampleRate_) + : hostRef { hostRef_ }, remoteRef { remoteRef_ }, channelCount { channelCount_ }, + sampleCount { sampleCount_ }, sampleRate { sampleRate_ } + {} +#endif + + ARAAudioSourceHostRef hostRef; + ARAAudioSourceRef remoteRef; + ARAChannelCount channelCount; +#if ARA_VALIDATE_API_CALLS + ARASampleCount sampleCount; + ARASampleRate sampleRate; +#endif +}; +ARA_MAP_REF (AudioSource, ARAAudioSourceRef) +ARA_MAP_HOST_REF (AudioSource, ARAAudioSourceHostRef) + +struct ContentReader +#if ARA_VALIDATE_API_CALLS + : public InstanceValidator +#endif +{ +#if ARA_VALIDATE_API_CALLS + ContentReader (ARAContentReaderRef remoteRef_, ARAContentType type_) + : remoteRef { remoteRef_ }, decoder { type_ } + {} +#endif + + ARAContentReaderRef remoteRef; + ContentEventDecoder decoder; +}; +ARA_MAP_REF (ContentReader, ARAContentReaderRef) + +struct HostContentReader +{ + ARAContentReaderHostRef hostRef; + ARAContentType contentType; +}; +ARA_MAP_HOST_REF (HostContentReader, ARAContentReaderHostRef) + +struct HostAudioReader +{ + AudioSource* audioSource; + ARAAudioReaderHostRef hostRef; + size_t sampleSize; +}; +ARA_MAP_HOST_REF (HostAudioReader, ARAAudioReaderHostRef) + + +/*******************************************************************************/ +// Implementation of DocumentControllerInterface that channels all calls through IPC + +class DocumentController : public PlugIn::DocumentControllerInterface, protected RemoteCaller, public InstanceValidator +{ +public: + DocumentController (Sender& sender, const ARAFactory* factory, const ARADocumentControllerHostInstance* instance, const ARADocumentProperties* properties) noexcept; + +public: + template + using PropertiesPtr = PlugIn::PropertiesPtr; + + // Destruction + void destroyDocumentController () noexcept override; + + // Factory + const ARAFactory* getFactory () const noexcept override; + + // Update Management + void beginEditing () noexcept override; + void endEditing () noexcept override; + void notifyModelUpdates () noexcept override; + + // Archiving + bool restoreObjectsFromArchive (ARAArchiveReaderHostRef archiveReaderHostRef, const ARARestoreObjectsFilter* filter) noexcept override; + bool storeObjectsToArchive (ARAArchiveWriterHostRef archiveWriterHostRef, const ARAStoreObjectsFilter* filter) noexcept override; + bool storeAudioSourceToAudioFileChunk (ARAArchiveWriterHostRef archiveWriterHostRef, ARAAudioSourceRef audioSourceRef, ARAPersistentID* documentArchiveID, bool* openAutomatically) noexcept override; + + // Document Management + void updateDocumentProperties (PropertiesPtr properties) noexcept override; + + // Musical Context Management + ARAMusicalContextRef createMusicalContext (ARAMusicalContextHostRef hostRef, PropertiesPtr properties) noexcept override; + void updateMusicalContextProperties (ARAMusicalContextRef musicalContextRef, PropertiesPtr properties) noexcept override; + void updateMusicalContextContent (ARAMusicalContextRef musicalContextRef, const ARAContentTimeRange* range, ContentUpdateScopes flags) noexcept override; + void destroyMusicalContext (ARAMusicalContextRef musicalContextRef) noexcept override; + + // Region Sequence Management + ARARegionSequenceRef createRegionSequence (ARARegionSequenceHostRef hostRef, PropertiesPtr properties) noexcept override; + void updateRegionSequenceProperties (ARARegionSequenceRef regionSequence, PropertiesPtr properties) noexcept override; + void destroyRegionSequence (ARARegionSequenceRef regionSequence) noexcept override; + + // Audio Source Management + ARAAudioSourceRef createAudioSource (ARAAudioSourceHostRef hostRef, PropertiesPtr properties) noexcept override; + void updateAudioSourceProperties (ARAAudioSourceRef audioSourceRef, PropertiesPtr properties) noexcept override; + void updateAudioSourceContent (ARAAudioSourceRef audioSourceRef, const ARAContentTimeRange* range, ContentUpdateScopes flags) noexcept override; + void enableAudioSourceSamplesAccess (ARAAudioSourceRef audioSourceRef, bool enable) noexcept override; + void deactivateAudioSourceForUndoHistory (ARAAudioSourceRef audioSourceRef, bool deactivate) noexcept override; + void destroyAudioSource (ARAAudioSourceRef audioSourceRef) noexcept override; + + // Audio Modification Management + ARAAudioModificationRef createAudioModification (ARAAudioSourceRef audioSourceRef, ARAAudioModificationHostRef hostRef, PropertiesPtr properties) noexcept override; + ARAAudioModificationRef cloneAudioModification (ARAAudioModificationRef audioModificationRef, ARAAudioModificationHostRef hostRef, PropertiesPtr properties) noexcept override; + void updateAudioModificationProperties (ARAAudioModificationRef audioModificationRef, PropertiesPtr properties) noexcept override; + void deactivateAudioModificationForUndoHistory (ARAAudioModificationRef audioModificationRef, bool deactivate) noexcept override; + void destroyAudioModification (ARAAudioModificationRef audioModificationRef) noexcept override; + + // Playback Region Management + ARAPlaybackRegionRef createPlaybackRegion (ARAAudioModificationRef audioModificationRef, ARAPlaybackRegionHostRef hostRef, PropertiesPtr properties) noexcept override; + void updatePlaybackRegionProperties (ARAPlaybackRegionRef playbackRegionRef, PropertiesPtr properties) noexcept override; + void getPlaybackRegionHeadAndTailTime (ARAPlaybackRegionRef playbackRegionRef, ARATimeDuration* headTime, ARATimeDuration* tailTime) noexcept override; + void destroyPlaybackRegion (ARAPlaybackRegionRef playbackRegionRef) noexcept override; + + // Content Reader Management + bool isAudioSourceContentAvailable (ARAAudioSourceRef audioSourceRef, ARAContentType type) noexcept override; + ARAContentGrade getAudioSourceContentGrade (ARAAudioSourceRef audioSourceRef, ARAContentType type) noexcept override; + ARAContentReaderRef createAudioSourceContentReader (ARAAudioSourceRef audioSourceRef, ARAContentType type, const ARAContentTimeRange* range) noexcept override; + + bool isAudioModificationContentAvailable (ARAAudioModificationRef audioModificationRef, ARAContentType type) noexcept override; + ARAContentGrade getAudioModificationContentGrade (ARAAudioModificationRef audioModificationRef, ARAContentType type) noexcept override; + ARAContentReaderRef createAudioModificationContentReader (ARAAudioModificationRef audioModificationRef, ARAContentType type, const ARAContentTimeRange* range) noexcept override; + + bool isPlaybackRegionContentAvailable (ARAPlaybackRegionRef playbackRegionRef, ARAContentType type) noexcept override; + ARAContentGrade getPlaybackRegionContentGrade (ARAPlaybackRegionRef playbackRegionRef, ARAContentType type) noexcept override; + ARAContentReaderRef createPlaybackRegionContentReader (ARAPlaybackRegionRef playbackRegionRef, ARAContentType type, const ARAContentTimeRange* range) noexcept override; + + ARAInt32 getContentReaderEventCount (ARAContentReaderRef contentReaderRef) noexcept override; + const void* getContentReaderDataForEvent (ARAContentReaderRef contentReaderRef, ARAInt32 eventIndex) noexcept override; + void destroyContentReader (ARAContentReaderRef contentReaderRef) noexcept override; + + // Controlling Analysis + bool isAudioSourceContentAnalysisIncomplete (ARAAudioSourceRef audioSourceRef, ARAContentType contentType) noexcept override; + void requestAudioSourceContentAnalysis (ARAAudioSourceRef audioSourceRef, ARASize contentTypesCount, const ARAContentType contentTypes[]) noexcept override; + + ARAInt32 getProcessingAlgorithmsCount () noexcept override; + const ARAProcessingAlgorithmProperties* getProcessingAlgorithmProperties (ARAInt32 algorithmIndex) noexcept override; + ARAInt32 getProcessingAlgorithmForAudioSource (ARAAudioSourceRef audioSourceRef) noexcept override; + void requestProcessingAlgorithmForAudioSource (ARAAudioSourceRef audioSourceRef, ARAInt32 algorithmIndex) noexcept override; + + // License Management + bool isLicensedForCapabilities (bool runModalActivationDialogIfNeeded, ARASize contentTypesCount, const ARAContentType contentTypes[], ARAPlaybackTransformationFlags transformationFlags) noexcept override; + + // Accessors for Proxy + const ARADocumentControllerInstance* getInstance () const noexcept { return &_instance; } + ARADocumentControllerRef getRemoteRef () const noexcept { return _remoteRef; } + + // Host Interface Access + PlugIn::HostAudioAccessController* getHostAudioAccessController () noexcept { return &_hostAudioAccessController; } + PlugIn::HostArchivingController* getHostArchivingController () noexcept { return &_hostArchivingController; } + PlugIn::HostContentAccessController* getHostContentAccessController () noexcept { return (_hostContentAccessController.isProvided ()) ? &_hostContentAccessController : nullptr; } + PlugIn::HostModelUpdateController* getHostModelUpdateController () noexcept { return (_hostModelUpdateController.isProvided ()) ? &_hostModelUpdateController : nullptr; } + PlugIn::HostPlaybackController* getHostPlaybackController () noexcept { return (_hostPlaybackController.isProvided ()) ? &_hostPlaybackController : nullptr; } + +private: + void destroyIfUnreferenced () noexcept; + + friend class PlugInExtension; + void addPlugInExtension (PlugInExtension* plugInExtension) noexcept { _plugInExtensions.insert (plugInExtension); } + void removePlugInExtension (PlugInExtension* plugInExtension) noexcept { _plugInExtensions.erase (plugInExtension); if (_plugInExtensions.empty ()) destroyIfUnreferenced (); } + +private: + const ARAFactory* const _factory; + + PlugIn::HostAudioAccessController _hostAudioAccessController; + PlugIn::HostArchivingController _hostArchivingController; + PlugIn::HostContentAccessController _hostContentAccessController; + PlugIn::HostModelUpdateController _hostModelUpdateController; + PlugIn::HostPlaybackController _hostPlaybackController; + + PlugIn::DocumentControllerInstance _instance; + + ARADocumentControllerRef _remoteRef; + + bool _hasBeenDestroyed { false }; + + ARAProcessingAlgorithmProperties _processingAlgorithmData { 0, nullptr, nullptr }; + struct + { + std::string persistentID; + std::string name; + } _processingAlgorithmStrings; + + std::set _plugInExtensions; + + ARA_HOST_MANAGED_OBJECT (DocumentController) +}; +ARA_MAP_HOST_REF (DocumentController, ARAAudioAccessControllerHostRef, ARAArchivingControllerHostRef, + ARAContentAccessControllerHostRef, ARAModelUpdateControllerHostRef, ARAPlaybackControllerHostRef) + + +/*******************************************************************************/ + +DocumentController::DocumentController (Sender& sender, const ARAFactory* factory, const ARADocumentControllerHostInstance* instance, const ARADocumentProperties* properties) noexcept +: RemoteCaller { sender }, + _factory { factory }, + _hostAudioAccessController { instance }, + _hostArchivingController { instance }, + _hostContentAccessController { instance }, + _hostModelUpdateController { instance }, + _hostPlaybackController { instance }, + _instance { this } +{ + ARAAudioAccessControllerHostRef audioAccessControllerHostRef { toHostRef (this) }; + ARAArchivingControllerHostRef archivingControllerHostRef { toHostRef (this) }; + ARAContentAccessControllerHostRef contentAccessControllerHostRef { toHostRef (this) }; + ARAModelUpdateControllerHostRef modelUpdateControllerHostRef { toHostRef (this) }; + ARAPlaybackControllerHostRef playbackControllerHostRef { toHostRef (this) }; + remoteCallWithReply (_remoteRef, kCreateDocumentControllerMessageID, _factory->factoryID, + audioAccessControllerHostRef, archivingControllerHostRef, + (_hostContentAccessController.isProvided ()) ? kARATrue : kARAFalse, contentAccessControllerHostRef, + (_hostModelUpdateController.isProvided ()) ? kARATrue : kARAFalse, modelUpdateControllerHostRef, + (_hostPlaybackController.isProvided ()) ? kARATrue : kARAFalse, playbackControllerHostRef, + properties); + + ARA_LOG_MODELOBJECT_LIFETIME ("did create document controller", _remoteRef); +} + +void DocumentController::destroyDocumentController () noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + ARA_LOG_MODELOBJECT_LIFETIME ("will destroy document controller", _remoteRef); + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyDocumentController), _remoteRef); + + _hasBeenDestroyed = true; + + destroyIfUnreferenced (); +} + +void DocumentController::destroyIfUnreferenced () noexcept +{ + // still in use by host? + if (!_hasBeenDestroyed) + return; + + // still referenced from plug-in instances? + if (!_plugInExtensions.empty ()) + return; + + delete this; +} + +/*******************************************************************************/ + +const ARAFactory* DocumentController::getFactory () const noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + return _factory; +} + +/*******************************************************************************/ + +void DocumentController::beginEditing () noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, beginEditing), _remoteRef); +} + +void DocumentController::endEditing () noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, endEditing), _remoteRef); +} + +void DocumentController::notifyModelUpdates () noexcept +{ +#if ARA_ENABLE_HOST_ENTRY_LOG + static int logCount { 0 }; + constexpr int maxLogCount { 3 }; + if ((++logCount) <= maxLogCount) + { + ARA_LOG_HOST_ENTRY (this); + if (logCount >= maxLogCount) + ARA_LOG ("notifyModelUpdates () called %i times, will now suppress logging future calls to it", maxLogCount); + } +#endif + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + if (!_hostModelUpdateController.isProvided ()) + return; + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, notifyModelUpdates), _remoteRef); +} + +bool DocumentController::restoreObjectsFromArchive (ARAArchiveReaderHostRef archiveReaderHostRef, const ARARestoreObjectsFilter* filter) noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + ARABool success; + remoteCallWithReply (success, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, restoreObjectsFromArchive), _remoteRef, archiveReaderHostRef, filter); + return (success != kARAFalse); +} + +bool DocumentController::storeObjectsToArchive (ARAArchiveWriterHostRef archiveWriterHostRef, const ARAStoreObjectsFilter* filter) noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + ARAStoreObjectsFilter tempFilter; + std::vector remoteAudioSourceRefs; + if ((filter != nullptr) && (filter->audioSourceRefsCount > 0)) + { + remoteAudioSourceRefs.reserve (filter->audioSourceRefsCount); + for (auto i { 0U }; i < filter->audioSourceRefsCount; ++i) + remoteAudioSourceRefs.emplace_back (fromRef (filter->audioSourceRefs[i])->remoteRef); + + tempFilter = *filter; + tempFilter.audioSourceRefs = remoteAudioSourceRefs.data (); + filter = &tempFilter; + } + + ARABool success; + remoteCallWithReply (success, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, storeObjectsToArchive), _remoteRef, archiveWriterHostRef, filter); + return (success!= kARAFalse); +} + +bool DocumentController::storeAudioSourceToAudioFileChunk (ARAArchiveWriterHostRef archiveWriterHostRef, ARAAudioSourceRef audioSourceRef, ARAPersistentID* documentArchiveID, bool* openAutomatically) noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + auto audioSource { fromRef (audioSourceRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); + ARA_VALIDATE_API_ARGUMENT (documentArchiveID, documentArchiveID != nullptr); + ARA_VALIDATE_API_ARGUMENT (openAutomatically, openAutomatically != nullptr); + + bool success { false }; + RemoteCaller::CustomDecodeFunction customDecode { [this, &success, &documentArchiveID, &openAutomatically] (const MessageDecoder& decoder) -> void + { + StoreAudioSourceToAudioFileChunkReply reply; + decodeReply (reply, decoder); + + // find ID string in factory because our return value is a temporary copy + if (0 == std::strcmp (reply.documentArchiveID, _factory->documentArchiveID)) + { + *documentArchiveID = _factory->documentArchiveID; + } + else + { + *documentArchiveID = nullptr; + for (auto i { 0U }; i < _factory->compatibleDocumentArchiveIDsCount; ++i) + { + if (0 == std::strcmp (reply.documentArchiveID, _factory->compatibleDocumentArchiveIDs[i])) + { + *documentArchiveID = _factory->compatibleDocumentArchiveIDs[i]; + break; + } + } + ARA_INTERNAL_ASSERT(*documentArchiveID != nullptr); + } + + *openAutomatically = (reply.openAutomatically != kARAFalse); + success = (reply.result != kARAFalse); + } }; + remoteCallWithReply (customDecode, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, storeAudioSourceToAudioFileChunk), + _remoteRef, archiveWriterHostRef, audioSource->remoteRef); + return success; +} + +void DocumentController::updateDocumentProperties (PropertiesPtr properties) noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + ARA_VALIDATE_API_STRUCT_PTR (properties, ARADocumentProperties); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateDocumentProperties), _remoteRef, *properties); +} + +/*******************************************************************************/ + +ARAMusicalContextRef DocumentController::createMusicalContext (ARAMusicalContextHostRef hostRef, PropertiesPtr properties) noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + ARA_VALIDATE_API_STRUCT_PTR (properties, ARAMusicalContextProperties); + + ARAMusicalContextRef musicalContextRef; + remoteCallWithReply (musicalContextRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createMusicalContext), _remoteRef, hostRef, *properties); + + ARA_LOG_MODELOBJECT_LIFETIME ("did create musical context", musicalContextRef); + return musicalContextRef; +} + +void DocumentController::updateMusicalContextProperties (ARAMusicalContextRef musicalContextRef, PropertiesPtr properties) noexcept +{ + ARA_LOG_HOST_ENTRY (musicalContextRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + ARA_VALIDATE_API_STRUCT_PTR (properties, ARAMusicalContextProperties); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateMusicalContextProperties), _remoteRef, musicalContextRef, *properties); +} + +void DocumentController::updateMusicalContextContent (ARAMusicalContextRef musicalContextRef, const ARAContentTimeRange* range, ContentUpdateScopes flags) noexcept +{ + ARA_LOG_HOST_ENTRY (musicalContextRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateMusicalContextContent), _remoteRef, musicalContextRef, range, flags); +} + +void DocumentController::destroyMusicalContext (ARAMusicalContextRef musicalContextRef) noexcept +{ + ARA_LOG_HOST_ENTRY (musicalContextRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + ARA_LOG_MODELOBJECT_LIFETIME ("will destroy musical context", musicalContextRef); + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyMusicalContext), _remoteRef, musicalContextRef); +} + +/*******************************************************************************/ + +ARARegionSequenceRef DocumentController::createRegionSequence (ARARegionSequenceHostRef hostRef, PropertiesPtr properties) noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + ARA_VALIDATE_API_STRUCT_PTR (properties, ARARegionSequenceProperties); + + ARARegionSequenceRef regionSequenceRef; + remoteCallWithReply (regionSequenceRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createRegionSequence), _remoteRef, hostRef, *properties); + + ARA_LOG_MODELOBJECT_LIFETIME ("did create region sequence", regionSequenceRef); + return regionSequenceRef; +} + +void DocumentController::updateRegionSequenceProperties (ARARegionSequenceRef regionSequenceRef, PropertiesPtr properties) noexcept +{ + ARA_LOG_HOST_ENTRY (regionSequenceRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + ARA_VALIDATE_API_STRUCT_PTR (properties, ARARegionSequenceProperties); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateRegionSequenceProperties), _remoteRef, regionSequenceRef, *properties); +} + +void DocumentController::destroyRegionSequence (ARARegionSequenceRef regionSequenceRef) noexcept +{ + ARA_LOG_HOST_ENTRY (regionSequenceRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + ARA_LOG_MODELOBJECT_LIFETIME ("will destroy region sequence", regionSequenceRef); + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyRegionSequence), _remoteRef, regionSequenceRef); +} + +/*******************************************************************************/ + +ARAAudioSourceRef DocumentController::createAudioSource (ARAAudioSourceHostRef hostRef, PropertiesPtr properties) noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + ARA_VALIDATE_API_STRUCT_PTR (properties, ARAAudioSourceProperties); + + auto audioSource { new AudioSource { hostRef, nullptr, properties->channelCount +#if ARA_VALIDATE_API_CALLS + , properties->sampleCount, properties->sampleRate +#endif + } }; + + remoteCallWithReply (audioSource->remoteRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioSource), + _remoteRef, ARAAudioSourceHostRef { toHostRef (audioSource) }, *properties); + + ARA_LOG_MODELOBJECT_LIFETIME ("did create audio source", audioSourceRef); + return toRef (audioSource); +} + +void DocumentController::updateAudioSourceProperties (ARAAudioSourceRef audioSourceRef, PropertiesPtr properties) noexcept +{ + ARA_LOG_HOST_ENTRY (audioSourceRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + auto audioSource { fromRef (audioSourceRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); + ARA_VALIDATE_API_STRUCT_PTR (properties, ARAAudioSourceProperties); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioSourceProperties), _remoteRef, audioSource->remoteRef, *properties); +} + +void DocumentController::updateAudioSourceContent (ARAAudioSourceRef audioSourceRef, const ARAContentTimeRange* range, ContentUpdateScopes flags) noexcept +{ + ARA_LOG_HOST_ENTRY (audioSourceRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + auto audioSource { fromRef (audioSourceRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioSourceContent), _remoteRef, audioSource->remoteRef, range, flags); +} + +void DocumentController::enableAudioSourceSamplesAccess (ARAAudioSourceRef audioSourceRef, bool enable) noexcept +{ + ARA_LOG_HOST_ENTRY (audioSourceRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + const auto audioSource { fromRef (audioSourceRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, enableAudioSourceSamplesAccess), _remoteRef, audioSource->remoteRef, (enable) ? kARATrue : kARAFalse); +} + +void DocumentController::deactivateAudioSourceForUndoHistory (ARAAudioSourceRef audioSourceRef, bool deactivate) noexcept +{ + ARA_LOG_HOST_ENTRY (audioSourceRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + const auto audioSource { fromRef (audioSourceRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, deactivateAudioSourceForUndoHistory), _remoteRef, audioSource->remoteRef, (deactivate) ? kARATrue : kARAFalse); +} + +void DocumentController::destroyAudioSource (ARAAudioSourceRef audioSourceRef) noexcept +{ + ARA_LOG_HOST_ENTRY (audioSourceRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + const auto audioSource { fromRef (audioSourceRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); + + ARA_LOG_MODELOBJECT_LIFETIME ("will destroy audio source", audioSource->remoteRef); + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyAudioSource), _remoteRef, audioSource->remoteRef); + delete audioSource; +} + +/*******************************************************************************/ + +ARAAudioModificationRef DocumentController::createAudioModification (ARAAudioSourceRef audioSourceRef, ARAAudioModificationHostRef hostRef, PropertiesPtr properties) noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + auto audioSource { fromRef (audioSourceRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); + ARA_VALIDATE_API_STRUCT_PTR (properties, ARAAudioModificationProperties); + + ARAAudioModificationRef audioModificationRef; + remoteCallWithReply (audioModificationRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioModification), + _remoteRef, audioSource->remoteRef, hostRef, *properties); + + ARA_LOG_MODELOBJECT_LIFETIME ("did create audio modification", audioModificationRef); + return audioModificationRef; +} + +ARAAudioModificationRef DocumentController::cloneAudioModification (ARAAudioModificationRef srcAudioModificationRef, ARAAudioModificationHostRef hostRef, PropertiesPtr properties) noexcept +{ + ARA_LOG_HOST_ENTRY (srcAudioModificationRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + ARA_VALIDATE_API_STRUCT_PTR (properties, ARAAudioModificationProperties); + + ARAAudioModificationRef clonedAudioModificationRef; + remoteCallWithReply (clonedAudioModificationRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, cloneAudioModification), + _remoteRef, srcAudioModificationRef, hostRef, *properties); + + ARA_LOG_MODELOBJECT_LIFETIME ("did create cloned audio modification", clonedAudioModificationRef); + return clonedAudioModificationRef; +} + +void DocumentController::updateAudioModificationProperties (ARAAudioModificationRef audioModificationRef, PropertiesPtr properties) noexcept +{ + ARA_LOG_HOST_ENTRY (audioModificationRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + ARA_VALIDATE_API_STRUCT_PTR (properties, ARAAudioModificationProperties); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioModificationProperties), _remoteRef, audioModificationRef, *properties); +} + +void DocumentController::deactivateAudioModificationForUndoHistory (ARAAudioModificationRef audioModificationRef, bool deactivate) noexcept +{ + ARA_LOG_HOST_ENTRY (audioModificationRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, deactivateAudioModificationForUndoHistory), _remoteRef, audioModificationRef, (deactivate) ? kARATrue : kARAFalse); +} + +void DocumentController::destroyAudioModification (ARAAudioModificationRef audioModificationRef) noexcept +{ + ARA_LOG_HOST_ENTRY (audioModificationRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + ARA_LOG_MODELOBJECT_LIFETIME ("will destroy audio modification", audioModification); + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyAudioModification), _remoteRef, audioModificationRef); +} + +/*******************************************************************************/ + +ARAPlaybackRegionRef DocumentController::createPlaybackRegion (ARAAudioModificationRef audioModificationRef, ARAPlaybackRegionHostRef hostRef, PropertiesPtr properties) noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + ARA_VALIDATE_API_STRUCT_PTR (properties, ARAPlaybackRegionProperties); + + ARAPlaybackRegionRef playbackRegionRef; + remoteCallWithReply (playbackRegionRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createPlaybackRegion), + _remoteRef, audioModificationRef, hostRef, *properties); + + ARA_LOG_MODELOBJECT_LIFETIME ("did create playback region", playbackRegionRef); + return playbackRegionRef; +} + +void DocumentController::updatePlaybackRegionProperties (ARAPlaybackRegionRef playbackRegionRef, PropertiesPtr properties) noexcept +{ + ARA_LOG_HOST_ENTRY (playbackRegionRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + ARA_VALIDATE_API_STRUCT_PTR (properties, ARAPlaybackRegionProperties); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updatePlaybackRegionProperties), _remoteRef, playbackRegionRef, *properties); +} + +void DocumentController::getPlaybackRegionHeadAndTailTime (ARAPlaybackRegionRef playbackRegionRef, ARATimeDuration* headTime, ARATimeDuration* tailTime) noexcept +{ + ARA_LOG_HOST_ENTRY (playbackRegionRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + ARA_VALIDATE_API_ARGUMENT (headTime, headTime != nullptr); + ARA_VALIDATE_API_ARGUMENT (tailTime, tailTime != nullptr); + + GetPlaybackRegionHeadAndTailTimeReply reply; + remoteCallWithReply (reply, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getPlaybackRegionHeadAndTailTime), + _remoteRef, playbackRegionRef, (headTime != nullptr) ? kARATrue : kARAFalse, (tailTime != nullptr) ? kARATrue : kARAFalse); + if (headTime != nullptr) + *headTime = reply.headTime; + if (tailTime != nullptr) + *tailTime = reply.tailTime; +} + +void DocumentController::destroyPlaybackRegion (ARAPlaybackRegionRef playbackRegionRef) noexcept +{ + ARA_LOG_HOST_ENTRY (playbackRegionRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + ARA_LOG_MODELOBJECT_LIFETIME ("will destroy playback region", playbackRegionRef); + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyPlaybackRegion), _remoteRef, playbackRegionRef); +} + +/*******************************************************************************/ + +bool DocumentController::isAudioSourceContentAvailable (ARAAudioSourceRef audioSourceRef, ARAContentType type) noexcept +{ + ARA_LOG_HOST_ENTRY (audioSourceRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); const auto audioSource { fromRef (audioSourceRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); + + ARABool result; + remoteCallWithReply (result, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioSourceContentAvailable), _remoteRef, audioSource->remoteRef, type); + return (result != kARAFalse); +} + +ARAContentGrade DocumentController::getAudioSourceContentGrade (ARAAudioSourceRef audioSourceRef, ARAContentType type) noexcept +{ + ARA_LOG_HOST_ENTRY (audioSourceRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + const auto audioSource { fromRef (audioSourceRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); + + ARAContentGrade grade; + remoteCallWithReply (grade, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getAudioSourceContentGrade), _remoteRef, audioSource->remoteRef, type); + return grade; +} + +ARAContentReaderRef DocumentController::createAudioSourceContentReader (ARAAudioSourceRef audioSourceRef, ARAContentType type, const ARAContentTimeRange* range) noexcept +{ + ARA_LOG_HOST_ENTRY (audioSourceRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + const auto audioSource { fromRef (audioSourceRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); + + ARAContentReaderRef contentReaderRef; + remoteCallWithReply (contentReaderRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioSourceContentReader), + _remoteRef, audioSource->remoteRef, type, range); + + auto contentReader { new ContentReader { contentReaderRef, type } }; +#if ARA_ENABLE_OBJECT_LIFETIME_LOG + ARA_LOG ("Plug success: did create content reader %p for audio source %p", contentReaderRef, audioSourceRef); +#endif + return toRef (contentReader); +} + +/*******************************************************************************/ + +bool DocumentController::isAudioModificationContentAvailable (ARAAudioModificationRef audioModificationRef, ARAContentType type) noexcept +{ + ARA_LOG_HOST_ENTRY (audioModificationRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + ARABool result; + remoteCallWithReply (result, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioModificationContentAvailable), _remoteRef, audioModificationRef, type); + return (result != kARAFalse); +} + +ARAContentGrade DocumentController::getAudioModificationContentGrade (ARAAudioModificationRef audioModificationRef, ARAContentType type) noexcept +{ + ARA_LOG_HOST_ENTRY (audioModificationRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + ARAContentGrade grade; + remoteCallWithReply (grade, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getAudioModificationContentGrade), _remoteRef, audioModificationRef, type); + return grade; +} + +ARAContentReaderRef DocumentController::createAudioModificationContentReader (ARAAudioModificationRef audioModificationRef, ARAContentType type, const ARAContentTimeRange* range) noexcept +{ + ARA_LOG_HOST_ENTRY (audioModificationRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + ARAContentReaderRef contentReaderRef; + remoteCallWithReply (contentReaderRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioModificationContentReader), + _remoteRef, audioModificationRef, type, range); + + auto contentReader { new ContentReader { contentReaderRef, type } }; +#if ARA_ENABLE_OBJECT_LIFETIME_LOG + ARA_LOG ("Plug success: did create content reader %p for audio modification %p", contentReaderRef, audioModificationRef); +#endif + return toRef (contentReader); +} + +/*******************************************************************************/ + +bool DocumentController::isPlaybackRegionContentAvailable (ARAPlaybackRegionRef playbackRegionRef, ARAContentType type) noexcept +{ + ARA_LOG_HOST_ENTRY (playbackRegionRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + ARABool result; + remoteCallWithReply (result, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isPlaybackRegionContentAvailable), _remoteRef, playbackRegionRef, type); + return (result != kARAFalse); +} + +ARAContentGrade DocumentController::getPlaybackRegionContentGrade (ARAPlaybackRegionRef playbackRegionRef, ARAContentType type) noexcept +{ + ARA_LOG_HOST_ENTRY (playbackRegionRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + ARAContentGrade grade; + remoteCallWithReply (grade, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getPlaybackRegionContentGrade), _remoteRef, playbackRegionRef, type); + return grade; +} + +ARAContentReaderRef DocumentController::createPlaybackRegionContentReader (ARAPlaybackRegionRef playbackRegionRef, ARAContentType type, const ARAContentTimeRange* range) noexcept +{ + ARA_LOG_HOST_ENTRY (playbackRegionRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + ARAContentReaderRef contentReaderRef; + remoteCallWithReply (contentReaderRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createPlaybackRegionContentReader), + _remoteRef, playbackRegionRef, type, range); + + auto contentReader { new ContentReader { contentReaderRef, type } }; +#if ARA_ENABLE_OBJECT_LIFETIME_LOG + ARA_LOG ("Plug success: did create content reader %p for playback region %p", contentReaderRef, playbackRegionRef); +#endif + return toRef (contentReader); +} + +/*******************************************************************************/ + +ARAInt32 DocumentController::getContentReaderEventCount (ARAContentReaderRef contentReaderRef) noexcept +{ + ARA_LOG_HOST_ENTRY (contentReaderRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + const auto contentReader { fromRef (contentReaderRef) }; + ARA_VALIDATE_API_ARGUMENT (contentReader, isValidInstance (contentReader)); + + ARAInt32 count; + remoteCallWithReply (count, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getContentReaderEventCount), _remoteRef, contentReader->remoteRef); + return count; +} + +const void* DocumentController::getContentReaderDataForEvent (ARAContentReaderRef contentReaderRef, ARAInt32 eventIndex) noexcept +{ + ARA_LOG_HOST_ENTRY (contentReaderRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + const auto contentReader { fromRef (contentReaderRef) }; + ARA_VALIDATE_API_ARGUMENT (contentReader, isValidInstance (contentReader)); + + const void* result {}; + RemoteCaller::CustomDecodeFunction customDecode { [&result, &contentReader] (const MessageDecoder& decoder) -> void + { + result = contentReader->decoder.decode (decoder); + } }; + remoteCallWithReply (customDecode, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getContentReaderDataForEvent), + _remoteRef, contentReader->remoteRef, eventIndex); + return result; +} + +void DocumentController::destroyContentReader (ARAContentReaderRef contentReaderRef) noexcept +{ + ARA_LOG_HOST_ENTRY (contentReaderRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + const auto contentReader { fromRef (contentReaderRef) }; + ARA_VALIDATE_API_ARGUMENT (contentReader, isValidInstance (contentReader)); + + ARA_LOG_MODELOBJECT_LIFETIME ("will destroy content reader", contentReader->remoteRef); + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyContentReader), _remoteRef, contentReader->remoteRef); + + delete contentReader; +} + +/*******************************************************************************/ + +bool DocumentController::isAudioSourceContentAnalysisIncomplete (ARAAudioSourceRef audioSourceRef, ARAContentType type) noexcept +{ + ARA_LOG_HOST_ENTRY (audioSourceRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + const auto audioSource { fromRef (audioSourceRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); + + ARABool result; + remoteCallWithReply (result, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioSourceContentAnalysisIncomplete), + _remoteRef, audioSource->remoteRef, type); + return (result != kARAFalse); +} + +void DocumentController::requestAudioSourceContentAnalysis (ARAAudioSourceRef audioSourceRef, ARASize contentTypesCount, const ARAContentType contentTypes[]) noexcept +{ + ARA_LOG_HOST_ENTRY (audioSourceRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + const auto audioSource { fromRef (audioSourceRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); + + const ArrayArgument types { contentTypes, contentTypesCount }; + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, requestAudioSourceContentAnalysis), _remoteRef, audioSource->remoteRef, types); +} + +ARAInt32 DocumentController::getProcessingAlgorithmsCount () noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + ARAInt32 count; + remoteCallWithReply (count, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmsCount), _remoteRef); + return count; +} + +const ARAProcessingAlgorithmProperties* DocumentController::getProcessingAlgorithmProperties (ARAInt32 algorithmIndex) noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + RemoteCaller::CustomDecodeFunction customDecode { [this] (const MessageDecoder& decoder) -> void + { + ARAProcessingAlgorithmProperties reply; + decodeReply (reply, decoder); + _processingAlgorithmStrings.persistentID = reply.persistentID; + _processingAlgorithmStrings.name = reply.name; + _processingAlgorithmData = reply; + _processingAlgorithmData.persistentID = _processingAlgorithmStrings.persistentID.c_str (); + _processingAlgorithmData.name = _processingAlgorithmStrings.name.c_str (); + } }; + remoteCallWithReply (customDecode, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmProperties), _remoteRef, algorithmIndex); + return &_processingAlgorithmData; +} + +ARAInt32 DocumentController::getProcessingAlgorithmForAudioSource (ARAAudioSourceRef audioSourceRef) noexcept +{ + ARA_LOG_HOST_ENTRY (audioSourceRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + const auto audioSource { fromRef (audioSourceRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); + + ARAInt32 result; + remoteCallWithReply (result, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmForAudioSource), _remoteRef, audioSource->remoteRef); + return result; +} + +void DocumentController::requestProcessingAlgorithmForAudioSource (ARAAudioSourceRef audioSourceRef, ARAInt32 algorithmIndex) noexcept +{ + ARA_LOG_HOST_ENTRY (audioSourceRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + const auto audioSource { fromRef (audioSourceRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, requestProcessingAlgorithmForAudioSource), _remoteRef, audioSource->remoteRef, algorithmIndex); +} + +/*******************************************************************************/ + +bool DocumentController::isLicensedForCapabilities (bool runModalActivationDialogIfNeeded, ARASize contentTypesCount, const ARAContentType contentTypes[], ARAPlaybackTransformationFlags transformationFlags) noexcept +{ + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + const ArrayArgument types { contentTypes, contentTypesCount }; + ARABool result; + remoteCallWithReply (result, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isLicensedForCapabilities), + _remoteRef, (runModalActivationDialogIfNeeded) ? kARATrue : kARAFalse, types, transformationFlags); + return (result != kARAFalse); +} + + +/*******************************************************************************/ +// Implementation of PlaybackRendererInterface that channels all calls through IPC + +class PlaybackRenderer : public PlugIn::PlaybackRendererInterface, protected RemoteCaller, public InstanceValidator +{ +public: + explicit PlaybackRenderer (Sender& sender, ARAPlaybackRendererRef remoteRef) noexcept + : RemoteCaller { sender }, + _remoteRef { remoteRef } + {} + + // Inherited public interface used by the C++ dispatcher, to be called by the ARAPlugInDispatch code exclusively. + void addPlaybackRegion (ARAPlaybackRegionRef playbackRegionRef) noexcept override + { + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAPlaybackRendererInterface, addPlaybackRegion), _remoteRef, playbackRegionRef); + } + void removePlaybackRegion (ARAPlaybackRegionRef playbackRegionRef) noexcept override + { + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAPlaybackRendererInterface, removePlaybackRegion), _remoteRef, playbackRegionRef); + } + +private: + ARAPlaybackRendererRef const _remoteRef; + + ARA_HOST_MANAGED_OBJECT (PlaybackRenderer) +}; + + +/*******************************************************************************/ +// Implementation of EditorRendererInterface that channels all calls through IPC + +class EditorRenderer : public PlugIn::EditorRendererInterface, protected RemoteCaller, public InstanceValidator +{ +public: + explicit EditorRenderer (Sender& sender, ARAEditorRendererRef remoteRef) noexcept + : RemoteCaller { sender }, + _remoteRef { remoteRef } + {} + + // Inherited public interface used by the C++ dispatcher, to be called by the ARAPlugInDispatch code exclusively. + void addPlaybackRegion (ARAPlaybackRegionRef playbackRegionRef) noexcept override + { + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, addPlaybackRegion), _remoteRef, playbackRegionRef); + } + void removePlaybackRegion (ARAPlaybackRegionRef playbackRegionRef) noexcept override + { + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, removePlaybackRegion), _remoteRef, playbackRegionRef); + } + + void addRegionSequence (ARARegionSequenceRef regionSequenceRef) noexcept override + { + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, addRegionSequence), _remoteRef, regionSequenceRef); + } + void removeRegionSequence (ARARegionSequenceRef regionSequenceRef) noexcept override + { + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, removeRegionSequence), _remoteRef, regionSequenceRef); + } + +private: + ARAEditorRendererRef const _remoteRef; + + ARA_HOST_MANAGED_OBJECT (EditorRenderer) +}; + + +/*******************************************************************************/ +// Implementation of EditorRendererInterface that channels all calls through IPC + +class EditorView : public PlugIn::EditorViewInterface, protected RemoteCaller, public InstanceValidator +{ +public: + explicit EditorView (Sender& sender, ARAEditorViewRef remoteRef) noexcept + : RemoteCaller { sender }, + _remoteRef { remoteRef } + {} + + // Inherited public interface used by the C++ dispatcher, to be called by the ARAPlugInDispatch code exclusively. + void notifySelection (SizedStructPtr selection) noexcept override + { + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + ARA_VALIDATE_API_STRUCT_PTR (selection, ARAViewSelection); + + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAEditorViewInterface, notifySelection), _remoteRef, *selection); + } + void notifyHideRegionSequences (ARASize regionSequenceRefsCount, const ARARegionSequenceRef regionSequenceRefs[]) noexcept override + { + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + const ArrayArgument sequences { regionSequenceRefs, regionSequenceRefsCount }; + remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAEditorViewInterface, notifyHideRegionSequences), _remoteRef, sequences); + } + +private: + ARAEditorViewRef const _remoteRef; + + ARA_HOST_MANAGED_OBJECT (EditorView) +}; + + +/*******************************************************************************/ +// implementation of ARAPlugInExtensionInstance that uses the above instance role classes + +class PlugInExtension : public PlugIn::PlugInExtensionInstance +{ +public: + PlugInExtension (Sender& sender, ARADocumentControllerRef documentControllerRef, + ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles, + size_t remotePlugInExtensionRef) noexcept + : PlugIn::PlugInExtensionInstance { (((knownRoles & kARAPlaybackRendererRole) == 0) || ((assignedRoles & kARAPlaybackRendererRole) != 0)) ? + new PlaybackRenderer (sender, reinterpret_cast (remotePlugInExtensionRef)) : nullptr, + (((knownRoles & kARAEditorRendererRole) == 0) || ((assignedRoles & kARAEditorRendererRole) != 0)) ? + new EditorRenderer (sender, reinterpret_cast (remotePlugInExtensionRef)) : nullptr, + (((knownRoles & kARAEditorViewRole) == 0) || ((assignedRoles & kARAEditorViewRole) != 0)) ? + new EditorView (sender, reinterpret_cast (remotePlugInExtensionRef)) : nullptr }, + _documentController { PlugIn::fromRef (documentControllerRef) } + { + plugInExtensionRef = reinterpret_cast (remotePlugInExtensionRef); + + ARA_LOG_HOST_ENTRY (this); + ARA_VALIDATE_API_ARGUMENT (documentControllerRef, isValidInstance (_documentController)); + + _documentController->addPlugInExtension (this); + +#if ARA_ENABLE_OBJECT_LIFETIME_LOG + ARA_LOG ("Plug success: did create plug-in extension %p (playbackRenderer %p, editorRenderer %p, editorView %p)", this, getPlaybackRenderer (), getEditorRenderer (), getEditorView ()); +#endif + } + + ~PlugInExtension () noexcept + { + ARA_LOG_HOST_ENTRY (this); +#if ARA_ENABLE_OBJECT_LIFETIME_LOG + ARA_LOG ("Plug success: will destroy plug-in extension %p (playbackRenderer %p, editorRenderer %p, editorView %p)", this, getPlaybackRenderer (), getEditorRenderer (), getEditorView ()); +#endif + + _documentController->removePlugInExtension (this); + + delete getEditorView (); + delete getEditorRenderer (); + delete getPlaybackRenderer (); + } + +private: + DocumentController* const _documentController; + + ARA_HOST_MANAGED_OBJECT (PlugInExtension) +}; + + +/*******************************************************************************/ +// Utility class that wraps an ARAFactory. + +class Factory +{ +public: + Factory (Sender& hostCommandsSender, size_t index); + + const ARADocumentControllerInstance* createDocumentControllerWithDocument (const ARADocumentControllerHostInstance* hostInstance, + const ARADocumentProperties* properties); + + const ARAFactory* getFactory () const { return &_factory; } + Sender& getHostCommandsSender () const { return _hostCommandsSender; } + +private: + Sender& _hostCommandsSender; + + ARAFactory _factory; + struct + { + std::string factoryID; + std::string plugInName; + std::string manufacturerName; + std::string informationURL; + std::string version; + std::string documentArchiveID; + } _factoryStrings; + std::vector _factoryCompatibleIDStrings; + std::vector _factoryCompatibleIDs; + std::vector _factoryAnalyzableTypes; +}; + +Factory::Factory (Sender& hostCommandsSender, size_t index) +: _hostCommandsSender { hostCommandsSender } +{ + RemoteCaller::CustomDecodeFunction customDecode { [this] (const MessageDecoder& decoder) -> void + { + decodeReply (_factory, decoder); + + ARA_VALIDATE_API_ARGUMENT(&_factory, _factory.highestSupportedApiGeneration >= kARAAPIGeneration_2_0_Final); + + _factoryStrings.factoryID = _factory.factoryID; + _factory.factoryID = _factoryStrings.factoryID.c_str (); + + _factoryStrings.plugInName = _factory.plugInName; + _factory.plugInName = _factoryStrings.plugInName.c_str (); + _factoryStrings.manufacturerName = _factory.manufacturerName; + _factory.manufacturerName = _factoryStrings.manufacturerName.c_str (); + _factoryStrings.informationURL = _factory.informationURL; + _factory.informationURL = _factoryStrings.informationURL.c_str (); + _factoryStrings.version = _factory.version; + _factory.version = _factoryStrings.version.c_str (); + + _factoryStrings.documentArchiveID = _factory.documentArchiveID; + _factory.documentArchiveID = _factoryStrings.documentArchiveID.c_str (); + + _factoryCompatibleIDStrings.reserve (_factory.compatibleDocumentArchiveIDsCount); + _factoryCompatibleIDs.reserve (_factory.compatibleDocumentArchiveIDsCount); + for (auto i { 0U }; i < _factory.compatibleDocumentArchiveIDsCount; ++i) + { + _factoryCompatibleIDStrings.emplace_back (_factory.compatibleDocumentArchiveIDs[i]); + _factoryCompatibleIDs.emplace_back (_factoryCompatibleIDStrings[i].c_str ()); + } + _factory.compatibleDocumentArchiveIDs = _factoryCompatibleIDs.data (); + + _factoryAnalyzableTypes.reserve (_factory.analyzeableContentTypesCount); + for (auto i { 0U }; i < _factory.analyzeableContentTypesCount; ++i) + _factoryAnalyzableTypes.emplace_back (_factory.analyzeableContentTypes[i]); + _factory.analyzeableContentTypes = _factoryAnalyzableTypes.data (); + } }; + + RemoteCaller { _hostCommandsSender }.remoteCallWithReply (customDecode, kGetFactoryMessageID, index); +} + +std::vector _factories {}; + +size_t initializeFactories (Sender& hostCommandsSender) +{ + size_t count; + RemoteCaller { hostCommandsSender }.remoteCallWithReply (count, kGetFactoriesCountMessageID); + ARA_INTERNAL_ASSERT (count > 0); + + _factories.reserve (count); + for (auto i { 0U }; i < count; ++i) + _factories.emplace_back (hostCommandsSender, i); + return _factories.size (); +} + +Factory* getFactoryAtIndex (size_t index) +{ + ARA_INTERNAL_ASSERT (index < _factories.size ()); + return &_factories[index]; +} + +const ARAFactory* getFactoryData (Factory* proxyFactory) +{ + return proxyFactory->getFactory (); +} + +const ARADocumentControllerInstance* createDocumentControllerWithDocument (Factory* proxyFactory, const ARADocumentControllerHostInstance* hostInstance, const ARADocumentProperties* properties) +{ + auto result { new DocumentController { proxyFactory->getHostCommandsSender (), proxyFactory->getFactory (), hostInstance, properties} }; + return result->getInstance (); +} + +ARADocumentControllerRef getDocumentControllerRemoteRef (ARADocumentControllerRef documentControllerRef) +{ + return static_cast (PlugIn::fromRef (documentControllerRef))->getRemoteRef (); +} + +const ARAPlugInExtensionInstance* createPlugInExtensionInstance (size_t remoteExtensionRef, Sender& sender, ARADocumentControllerRef documentControllerRef, + ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles) +{ + return new PlugInExtension { sender, documentControllerRef, knownRoles, assignedRoles, remoteExtensionRef }; +} + +void destroyPlugInExtensionInstance (const ARAPlugInExtensionInstance* plugInExtensionInstance) +{ + delete static_cast (plugInExtensionInstance); +} + +void plugInCallbacksDispatcher (const MessageID messageID, const MessageDecoder& decoder, MessageEncoder* const replyEncoder) +{ +// ARA_LOG ("plugInCallbackDispatcher received message %s", decodeHostMessageID (messageID)); + + // ARAAudioAccessControllerInterface + if (messageID == ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, createAudioReaderForSource)) + { + ARAAudioAccessControllerHostRef controllerHostRef; + ARAAudioSourceHostRef audioSourceHostRef; + ARABool use64BitSamples; + decodeArguments (decoder, controllerHostRef, audioSourceHostRef, use64BitSamples); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + auto audioSource { fromHostRef (audioSourceHostRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSourceHostRef, isValidInstance (audioSource)); + + auto reader { new HostAudioReader { audioSource, nullptr, (use64BitSamples != kARAFalse) ? sizeof (double) : sizeof (float) } }; + reader->hostRef = documentController->getHostAudioAccessController ()->createAudioReaderForSource (audioSource->hostRef, (use64BitSamples) ? kARATrue : kARAFalse); + ARAAudioReaderHostRef audioReaderHostRef { toHostRef (reader) }; + return encodeReply (replyEncoder, audioReaderHostRef); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, readAudioSamples)) + { + ARAAudioAccessControllerHostRef controllerHostRef; + ARAAudioReaderHostRef audioReaderHostRef; + ARASamplePosition samplePosition; + ARASampleCount samplesPerChannel; + decodeArguments (decoder, controllerHostRef, audioReaderHostRef, samplePosition, samplesPerChannel); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + auto reader { fromHostRef (audioReaderHostRef) }; + + // \todo using static (plus not copy bytes) here assumes single-threaded callbacks, but currently this is a valid requirement + static std::vector bufferData; + const auto channelCount { static_cast (reader->audioSource->channelCount) }; + const auto bufferSize { reader->sampleSize * static_cast (samplesPerChannel) }; + const auto allBuffersSize { channelCount * bufferSize }; + if (bufferData.size () < allBuffersSize) + bufferData.resize (allBuffersSize); + + static std::vector sampleBuffers; + static std::vector encoders; + if (sampleBuffers.size () < channelCount) + sampleBuffers.resize (channelCount, nullptr); + if (encoders.size () < channelCount) + encoders.resize (channelCount, { nullptr, 0, false }); + for (auto i { 0U }; i < channelCount; ++i) + { + const auto buffer { bufferData.data () + i * bufferSize }; + sampleBuffers[i] = buffer; + encoders[i] = { buffer, bufferSize, false }; + } + + if (documentController->getHostAudioAccessController ()->readAudioSamples (reader->hostRef, samplePosition, samplesPerChannel, sampleBuffers.data ())) + return encodeReply (replyEncoder, ArrayArgument { encoders.data (), encoders.size () }); + else + return; // send empty reply as indication of failure + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, destroyAudioReader)) + { + ARAAudioAccessControllerHostRef controllerHostRef; + ARAAudioReaderHostRef audioReaderHostRef; + decodeArguments (decoder, controllerHostRef, audioReaderHostRef); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + auto reader { fromHostRef (audioReaderHostRef) }; + + documentController->getHostAudioAccessController ()->destroyAudioReader (reader->hostRef); + delete reader; + } + + // ARAArchivingControllerInterface + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, getArchiveSize)) + { + ARAArchivingControllerHostRef controllerHostRef; + ARAArchiveReaderHostRef archiveReaderHostRef; + decodeArguments (decoder, controllerHostRef, archiveReaderHostRef); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + return encodeReply (replyEncoder, documentController->getHostArchivingController ()->getArchiveSize (archiveReaderHostRef)); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, readBytesFromArchive)) + { + ARAArchivingControllerHostRef controllerHostRef; + ARAArchiveReaderHostRef archiveReaderHostRef; + ARASize position; + ARASize length; + decodeArguments (decoder, controllerHostRef, archiveReaderHostRef, position, length); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + // \todo using static here assumes single-threaded callbacks, but currently this is a valid requirement + static std::vector bytes; + bytes.resize (length); + if (!documentController->getHostArchivingController ()->readBytesFromArchive (archiveReaderHostRef, position, length, bytes.data ())) + bytes.clear (); + return encodeReply (replyEncoder, BytesEncoder { bytes, false }); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, writeBytesToArchive)) + { + ARAArchivingControllerHostRef controllerHostRef; + ARAArchiveWriterHostRef archiveWriterHostRef; + ARASize position; + std::vector bytes; + BytesDecoder writer { bytes }; + decodeArguments (decoder, controllerHostRef, archiveWriterHostRef, position, writer); + ARA_INTERNAL_ASSERT (bytes.size () > 0); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + return encodeReply (replyEncoder, documentController->getHostArchivingController ()->writeBytesToArchive (archiveWriterHostRef, position, bytes.size (), bytes.data ())); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, notifyDocumentArchivingProgress)) + { + ARAArchivingControllerHostRef controllerHostRef; + float value; + decodeArguments (decoder, controllerHostRef, value); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + documentController->getHostArchivingController ()->notifyDocumentArchivingProgress (value); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, notifyDocumentUnarchivingProgress)) + { + ARAArchivingControllerHostRef controllerHostRef; + float value; + decodeArguments (decoder, controllerHostRef, value); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + documentController->getHostArchivingController ()->notifyDocumentUnarchivingProgress (value); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, getDocumentArchiveID)) + { + ARAArchivingControllerHostRef controllerHostRef; + ARAArchiveReaderHostRef archiveReaderHostRef; + decodeArguments (decoder, controllerHostRef, archiveReaderHostRef); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + return encodeReply (replyEncoder, documentController->getHostArchivingController ()->getDocumentArchiveID (archiveReaderHostRef)); + } + + // ARAContentAccessControllerInterface + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, isMusicalContextContentAvailable)) + { + ARAModelUpdateControllerHostRef controllerHostRef; + ARAMusicalContextHostRef musicalContextHostRef; + ARAContentType contentType; + decodeArguments (decoder, controllerHostRef, musicalContextHostRef, contentType); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + return encodeReply (replyEncoder, (documentController->getHostContentAccessController ()->isMusicalContextContentAvailable (musicalContextHostRef, contentType)) ? kARATrue : kARAFalse); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getMusicalContextContentGrade)) + { + ARAModelUpdateControllerHostRef controllerHostRef; + ARAMusicalContextHostRef musicalContextHostRef; + ARAContentType contentType; + decodeArguments (decoder, controllerHostRef, musicalContextHostRef, contentType); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + return encodeReply (replyEncoder, documentController->getHostContentAccessController ()->getMusicalContextContentGrade (musicalContextHostRef, contentType)); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, createMusicalContextContentReader)) + { + ARAModelUpdateControllerHostRef controllerHostRef; + ARAMusicalContextHostRef musicalContextHostRef; + ARAContentType contentType; + OptionalArgument range; + decodeArguments (decoder, controllerHostRef, musicalContextHostRef, contentType, range); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + auto hostContentReader { new HostContentReader }; + hostContentReader->hostRef = documentController->getHostContentAccessController ()->createMusicalContextContentReader (musicalContextHostRef, contentType, (range.second) ? &range.first : nullptr); + hostContentReader->contentType = contentType; + + return encodeReply (replyEncoder, ARAContentReaderHostRef { toHostRef (hostContentReader) }); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, isAudioSourceContentAvailable)) + { + ARAModelUpdateControllerHostRef controllerHostRef; + ARAAudioSourceHostRef audioSourceHostRef; + ARAContentType contentType; + decodeArguments (decoder, controllerHostRef, audioSourceHostRef, contentType); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + auto audioSource { fromHostRef (audioSourceHostRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSourceHostRef, isValidInstance (audioSource)); + + return encodeReply (replyEncoder, (documentController->getHostContentAccessController ()->isAudioSourceContentAvailable (audioSource->hostRef, contentType)) ? kARATrue : kARAFalse); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getAudioSourceContentGrade)) + { + ARAModelUpdateControllerHostRef controllerHostRef; + ARAAudioSourceHostRef audioSourceHostRef; + ARAContentType contentType; + decodeArguments (decoder, controllerHostRef, audioSourceHostRef, contentType); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + auto audioSource { fromHostRef (audioSourceHostRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSourceHostRef, isValidInstance (audioSource)); + + return encodeReply (replyEncoder, documentController->getHostContentAccessController ()->getAudioSourceContentGrade (audioSource->hostRef, contentType)); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, createAudioSourceContentReader)) + { + ARAModelUpdateControllerHostRef controllerHostRef; + ARAAudioSourceHostRef audioSourceHostRef; + ARAContentType contentType; + OptionalArgument range; + decodeArguments (decoder, controllerHostRef, audioSourceHostRef, contentType, range); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + auto audioSource { fromHostRef (audioSourceHostRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSourceHostRef, isValidInstance (audioSource)); + + auto hostContentReader { new HostContentReader }; + hostContentReader->hostRef = documentController->getHostContentAccessController ()->createAudioSourceContentReader (audioSource->hostRef, contentType, (range.second) ? &range.first : nullptr); + hostContentReader->contentType = contentType; + return encodeReply (replyEncoder, ARAContentReaderHostRef { toHostRef (hostContentReader) }); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getContentReaderEventCount)) + { + ARAModelUpdateControllerHostRef controllerHostRef; + ARAContentReaderHostRef contentReaderHostRef; + decodeArguments (decoder, controllerHostRef, contentReaderHostRef); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + auto hostContentReader { fromHostRef (contentReaderHostRef) }; + + return encodeReply (replyEncoder, documentController->getHostContentAccessController ()->getContentReaderEventCount (hostContentReader->hostRef)); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getContentReaderDataForEvent)) + { + ARAModelUpdateControllerHostRef controllerHostRef; + ARAContentReaderHostRef contentReaderHostRef; + ARAInt32 eventIndex; + decodeArguments (decoder, controllerHostRef, contentReaderHostRef, eventIndex); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + auto hostContentReader { fromHostRef (contentReaderHostRef) }; + + const void* eventData { documentController->getHostContentAccessController ()->getContentReaderDataForEvent (hostContentReader->hostRef, eventIndex) }; + return encodeContentEvent (replyEncoder, hostContentReader->contentType, eventData); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, destroyContentReader)) + { + ARAModelUpdateControllerHostRef controllerHostRef; + ARAContentReaderHostRef contentReaderHostRef; + decodeArguments (decoder, controllerHostRef, contentReaderHostRef); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + auto hostContentReader { fromHostRef (contentReaderHostRef) }; + + documentController->getHostContentAccessController ()->destroyContentReader (hostContentReader->hostRef); + delete hostContentReader; + } + + // ARAModelUpdateControllerInterface + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioSourceAnalysisProgress)) + { + ARAModelUpdateControllerHostRef controllerHostRef; + ARAAudioSourceHostRef audioSourceHostRef; + ARAAnalysisProgressState state; + float value; + decodeArguments (decoder, controllerHostRef, audioSourceHostRef, state, value); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + auto audioSource { fromHostRef (audioSourceHostRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSourceHostRef, isValidInstance (audioSource)); + + documentController->getHostModelUpdateController ()->notifyAudioSourceAnalysisProgress (audioSource->hostRef, state, value); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioSourceContentChanged)) + { + ARAModelUpdateControllerHostRef controllerHostRef; + ARAAudioSourceHostRef audioSourceHostRef; + OptionalArgument range; + ARAContentUpdateFlags scopeFlags; + decodeArguments (decoder, controllerHostRef, audioSourceHostRef, range, scopeFlags); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + auto audioSource { fromHostRef (audioSourceHostRef) }; + ARA_VALIDATE_API_ARGUMENT (audioSourceHostRef, isValidInstance (audioSource)); + + documentController->getHostModelUpdateController ()->notifyAudioSourceContentChanged (audioSource->hostRef, (range.second) ? &range.first : nullptr, scopeFlags); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioModificationContentChanged)) + { + ARAModelUpdateControllerHostRef controllerHostRef; + ARAAudioModificationHostRef audioModificationHostRef; + OptionalArgument range; + ARAContentUpdateFlags scopeFlags; + decodeArguments (decoder, controllerHostRef, audioModificationHostRef, range, scopeFlags); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + documentController->getHostModelUpdateController ()->notifyAudioModificationContentChanged (audioModificationHostRef, (range.second) ? &range.first : nullptr, scopeFlags); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyPlaybackRegionContentChanged)) + { + ARAModelUpdateControllerHostRef controllerHostRef; + ARAPlaybackRegionHostRef playbackRegionHostRef; + OptionalArgument range; + ARAContentUpdateFlags scopeFlags; + decodeArguments (decoder, controllerHostRef, playbackRegionHostRef, range, scopeFlags); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + documentController->getHostModelUpdateController ()->notifyPlaybackRegionContentChanged (playbackRegionHostRef, (range.second) ? &range.first : nullptr, scopeFlags); + } + + // ARAPlaybackControllerInterface + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestStartPlayback)) + { + ARAPlaybackControllerHostRef controllerHostRef; + decodeArguments (decoder, controllerHostRef); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + documentController->getHostPlaybackController ()->requestStartPlayback (); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestStopPlayback)) + { + ARAPlaybackControllerHostRef controllerHostRef; + decodeArguments (decoder, controllerHostRef); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + documentController->getHostPlaybackController ()->requestStopPlayback (); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestSetPlaybackPosition)) + { + ARAPlaybackControllerHostRef controllerHostRef; + ARATimePosition timePosition; + decodeArguments (decoder, controllerHostRef, timePosition); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + documentController->getHostPlaybackController ()->requestSetPlaybackPosition (timePosition); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestSetCycleRange)) + { + ARAPlaybackControllerHostRef controllerHostRef; + ARATimePosition startTime; + ARATimeDuration duration; + decodeArguments (decoder, controllerHostRef, startTime, duration); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + documentController->getHostPlaybackController ()->requestSetCycleRange (startTime, duration); + } + else if (messageID == ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestEnableCycle)) + { + ARAPlaybackControllerHostRef controllerHostRef; + ARABool enable; + decodeArguments (decoder, controllerHostRef, enable); + + auto documentController { fromHostRef (controllerHostRef) }; + ARA_VALIDATE_API_ARGUMENT (controllerHostRef, isValidInstance (documentController)); + + documentController->getHostPlaybackController ()->requestEnableCycle (enable != kARAFalse); + } + else + { + ARA_INTERNAL_ASSERT (false && "unhandled message ID"); + } + + // all calls that create a reply return early from their respective if (). +// it is valid to provide a dummy replyEncoder if no reply has been requested. +// ARA_INTERNAL_ASSERT (replyEncoder == nullptr); +} + +} // namespace ProxyPlugIn +} // namespace IPC +} // namespace ARA + +#endif // ARA_ENABLE_IPC diff --git a/IPC/ARAIPCProxyPlugIn.h b/IPC/ARAIPCProxyPlugIn.h new file mode 100644 index 0000000..839411f --- /dev/null +++ b/IPC/ARAIPCProxyPlugIn.h @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +//! \file ARAIPCProxyPlugIn.h +//! implementation of host-side ARA IPC proxy plug-in +//! \project ARA SDK Examples +//! \copyright Copyright (c) 2021-2022, Celemony Software GmbH, All Rights Reserved. +//! \license Licensed under the Apache License, Version 2.0 (the "License"); +//! you may not use this file except in compliance with the License. +//! You may obtain a copy of the License at +//! +//! http://www.apache.org/licenses/LICENSE-2.0 +//! +//! Unless required by applicable law or agreed to in writing, software +//! distributed under the License is distributed on an "AS IS" BASIS, +//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//! See the License for the specific language governing permissions and +//! limitations under the License. +//------------------------------------------------------------------------------ + +#ifndef ARAIPCProxyPlugIn_h +#define ARAIPCProxyPlugIn_h + +#include "ARAIPCEncoding.h" + + +#if ARA_ENABLE_IPC + + +namespace ARA { +namespace IPC { +namespace ProxyPlugIn { + + +class Factory; + + +//! static initialization +size_t initializeFactories (Sender& hostCommandsSender); + +//! access proxies to the factories provided by the remote plug-in +Factory* getFactoryAtIndex (size_t index); + +//! get copy of the remote factory data, with all function calls removed +const ARAFactory* getFactoryData (Factory* proxyFactory); + +//! proxy document controller creation call, to be used instead of ARAFactory.createDocumentControllerWithDocument () +const ARADocumentControllerInstance* createDocumentControllerWithDocument (Factory* proxyFactory, + const ARADocumentControllerHostInstance* hostInstance, + const ARADocumentProperties* properties); + +//! static handler of received messages +void plugInCallbacksDispatcher (const MessageID messageID, const MessageDecoder& decoder, MessageEncoder* const replyEncoder); + +//! \todo to perform the binding to the remote plug-in instance, the host needs access to this translation... +ARADocumentControllerRef getDocumentControllerRemoteRef (ARADocumentControllerRef documentControllerRef); + +//! create the plug-in extension when performing the binding to the remote plug-in instance +const ARAPlugInExtensionInstance* createPlugInExtensionInstance (size_t remoteExtensionRef, Sender& sender, ARADocumentControllerRef documentControllerRef, + ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles); +//! destroy the plug-in extension when destroying the remote plug-in instance +void destroyPlugInExtensionInstance (const ARAPlugInExtensionInstance* plugInExtension); + + +} // namespace ProxyPlugIn +} // namespace IPC +} // namespace ARA + + +#endif // ARA_ENABLE_IPC + +#endif // ARAIPCProxyPlugIn_h From 5abdb1c45895db5d355513478b912d15a018d15a Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:31:58 +0100 Subject: [PATCH 06/18] Make IPC proxies C compatible (for Audio Unit code in ObjC/Swift) --- IPC/ARAIPC.h | 141 +++++++++++++------- IPC/ARAIPCEncoding.h | 273 +++++++++++++++++++------------------- IPC/ARAIPCProxyHost.cpp | 50 ++++--- IPC/ARAIPCProxyHost.h | 27 ++-- IPC/ARAIPCProxyPlugIn.cpp | 72 +++++----- IPC/ARAIPCProxyPlugIn.h | 36 ++--- 6 files changed, 333 insertions(+), 266 deletions(-) diff --git a/IPC/ARAIPC.h b/IPC/ARAIPC.h index 8e3325c..7cc69da 100644 --- a/IPC/ARAIPC.h +++ b/IPC/ARAIPC.h @@ -22,10 +22,12 @@ #define ARAIPC_h +#include "ARA_API/ARAInterface.h" + + //! @addtogroup ARA_Library_IPC //! @{ - //! switch to bypass all IPC code #if !defined (ARA_ENABLE_IPC) #if defined (__APPLE__) || defined (_WIN32) @@ -39,121 +41,164 @@ #if ARA_ENABLE_IPC -#include - - +#if defined(__cplusplus) namespace ARA { namespace IPC { +extern "C" { +#endif -//! ID type for messages, IDs must be >= kMessageIDRangeStart and < kMessageIDRangeEnd -using MessageID = int32_t; -constexpr MessageID kMessageIDRangeStart { 1 }; -constexpr MessageID kMessageIDRangeEnd { 8*16*16 - 1 }; +//! ID type for messages, IDs must be >= kARAIPCMessageIDRangeStart and < kARAIPCMessageIDRangeEnd +typedef ARAInt32 ARAIPCMessageID; +#if defined(__cplusplus) + constexpr ARAIPCMessageID kARAIPCMessageIDRangeStart { 1 }; + constexpr ARAIPCMessageID kARAIPCMessageIDRangeEnd { 8*16*16 - 1 }; +#else + #define kARAIPCMessageIDRangeStart ((ARAIPCMessageID) 1) + #define kARAIPCMessageIDRangeEnd ((ARAIPCMessageID) 8*16*16 - 1) +#endif + //! key type for message dictionaries - negative keys are reserved for the implementation -using MessageKey = int32_t; +typedef ARAInt32 ARAIPCMessageKey; + +//! Message Encoder +//! @{ +typedef struct ARAIPCMessageEncoderImplementation * ARAIPCMessageEncoderRef; -class MessageEncoder +typedef struct ARAIPCMessageEncoderInterface { -public: - virtual ~MessageEncoder () = default; + //! destructor + void (ARA_CALL *destroyEncoder) (ARAIPCMessageEncoderRef encoderRef); //! number types //! The size variant will also be used for the pointer-sized ARA (host) refs. //@{ - virtual void appendInt32 (const MessageKey argKey, const int32_t argValue) = 0; - virtual void appendInt64 (const MessageKey argKey, const int64_t argValue) = 0; - virtual void appendSize (const MessageKey argKey, const size_t argValue) = 0; - virtual void appendFloat (const MessageKey argKey, const float argValue) = 0; - virtual void appendDouble (const MessageKey argKey, const double argValue) = 0; + void (ARA_CALL *appendInt32) (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey, int32_t argValue); + void (ARA_CALL *appendInt64) (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey, int64_t argValue); + void (ARA_CALL *appendSize) (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey, size_t argValue); + void (ARA_CALL *appendFloat) (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey, float argValue); + void (ARA_CALL *appendDouble) (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey, double argValue); //@} //! UTF8-encoded C strings - virtual void appendString (const MessageKey argKey, const char* const argValue) = 0; + void (ARA_CALL *appendString) (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey, const char * argValue); //! raw bytes //! As optimization, disable copying if the memory containing the bytes stays //! alive&unchanged until the message has been sent. - virtual void appendBytes (const MessageKey argKey, const uint8_t* argValue, const size_t argSize, const bool copy = true) = 0; + void (ARA_CALL *appendBytes) (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey, const uint8_t * argValue, size_t argSize, bool copy); //! sub-messages to encode compound types //! The caller is responsible for deleting the encoder after use. - virtual MessageEncoder* appendSubMessage (const MessageKey argKey) = 0; -}; + ARAIPCMessageEncoderRef (ARA_CALL *appendSubMessage) (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey); +} ARAIPCMessageEncoderInterface; -class MessageDecoder +typedef struct ARAIPCMessageEncoder { -public: - virtual ~MessageDecoder () = default; + ARAIPCMessageEncoderRef ref; + const ARAIPCMessageEncoderInterface * methods; // this preferably would be called "interface", but there's a system-defined macro in Windows with that name... +} ARAIPCMessageEncoder; +//! @} + + +//! Message Decoder +//! @{ +typedef struct ARAIPCMessageDecoderImplementation * ARAIPCMessageDecoderRef; + +typedef struct ARAIPCMessageDecoderInterface +{ + //! destructor + void (ARA_CALL *destroyDecoder) (ARAIPCMessageDecoderRef messageDecoderRef); //! only for debugging/validation: test if the message contains any key/value pairs - virtual bool isEmpty () const = 0; + bool (ARA_CALL *isEmpty) (ARAIPCMessageDecoderRef messageDecoderRef); //! number types //! The size variant will also be used for the pointer-sized ARA (host) refs. //! Will return false and set argValue to 0 if key not found. //@{ - virtual bool readInt32 (const MessageKey argKey, int32_t& argValue) const = 0; - virtual bool readInt64 (const MessageKey argKey, int64_t& argValue) const = 0; - virtual bool readSize (const MessageKey argKey, size_t& argValue) const = 0; - virtual bool readFloat (const MessageKey argKey, float& argValue) const = 0; - virtual bool readDouble (const MessageKey argKey, double& argValue) const = 0; + bool (ARA_CALL *readInt32) (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, int32_t * argValue); + bool (ARA_CALL *readInt64) (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, int64_t * argValue); + bool (ARA_CALL *readSize) (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, size_t * argValue); + bool (ARA_CALL *readFloat) (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, float * argValue); + bool (ARA_CALL *readDouble) (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, double * argValue); //@} //! UTF8-encoded C strings - //! Will return false and set argValue to nullptr if key not found. - virtual bool readString (const MessageKey argKey, const char*& argValue) const = 0; + //! Will return false and set argValue to NULL if key not found. + bool (ARA_CALL *readString) (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, const char ** argValue); //! raw bytes //! first query size, then provide a buffer large enough to copy the bytes to. //! readBytesSize () will return false and set argSize to 0 if key not found. //@{ - virtual bool readBytesSize (const MessageKey argKey, size_t& argSize) const = 0; - virtual void readBytes (const MessageKey argKey, uint8_t* const argValue) const = 0; + bool (ARA_CALL *readBytesSize) (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, size_t * argSize); + void (ARA_CALL *readBytes) (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, uint8_t * argValue); //@} //! sub-messages to decode compound types //! returns nullptr if key not found or if the value for the key is not representing a sub-message //! The caller is responsible for deleting the encoder after use. - virtual MessageDecoder* readSubMessage (const MessageKey argKey) const = 0; -}; + ARAIPCMessageDecoderRef (ARA_CALL *readSubMessage) (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey); +} ARAIPCMessageDecoderInterface; + +typedef struct ARAIPCMessageDecoder +{ + ARAIPCMessageDecoderRef ref; + const ARAIPCMessageDecoderInterface * methods; // this preferably would be called "interface", but there's a system-defined macro in Windows with that name... +} ARAIPCMessageDecoder; +//! @} + -//! receive function: receives a message readable through the decoder, optionally creating a reply +//! Message Receiver: a function that receives a message readable through the decoder, optionally creating a reply //! Not using the replyEncoder will return a valid empty message to the sender (useful for void calls). //! Depending on the underlying implementation, replyEncoder may be nullptr if no reply has been //! requested by the sender, but providing a dummy encoder in this case is valid too. //! The sender thread will be blocked until the (possibly empty) reply has been received. //! A receive function can be called from any thread, but not concurrently. -using ReceiveFunction = void (const MessageID messageID, const MessageDecoder& decoder, MessageEncoder* const replyEncoder); +typedef void (ARA_CALL *ARAIPCMessageReceiver) (const ARAIPCMessageID messageID, const ARAIPCMessageDecoder decoder, ARAIPCMessageEncoder * replyEncoder); -//! gateway for sending messages -class Sender -{ -public: - virtual ~Sender () = default; +//! Reply Handler: a function that is called to process the reply to a message +typedef void (ARA_CALL *ARAIPCReplyHandler) (const ARAIPCMessageDecoder decoder, void * userData); - using ReplyHandler = std::function; +//! Message Sender: gateway for sending messages +//! @{ +typedef struct ARAIPCMessageSenderImplementation * ARAIPCMessageSenderRef; +typedef struct ARAIPCMessageSenderInterface +{ //! generate an encoder to encode a new message //! An encoder can be reused if the same message is sent several times, //! but it must not be modified after sending. //! The caller is responsible for deleting the encoder after use. - virtual MessageEncoder* createEncoder () = 0; + ARAIPCMessageEncoder (ARA_CALL *createEncoder) (ARAIPCMessageSenderRef messageSenderRef); //! send function: send message create using the encoder, blocking until a reply has been received. //! If an empty reply ("void") is expected, the replyHandler should be nullptr. //! A send function can be called from any thread, but not concurrently. - virtual void sendMessage (MessageID messageID, const MessageEncoder& encoder, ReplyHandler* const replyHandler) = 0; + void (ARA_CALL *sendMessage) (ARAIPCMessageSenderRef messageSenderRef, ARAIPCMessageID messageID, const ARAIPCMessageEncoder * encoder, + ARAIPCReplyHandler * const replyHandler, void * replyHandlerUserData); //! Test if the receiver runs on a different architecture with different endianess. - virtual bool receiverEndianessMatches () const { return true; } -}; + bool (ARA_CALL *receiverEndianessMatches) (ARAIPCMessageSenderRef messageSenderRef); +} ARAIPCMessageSenderInterface; + +typedef struct ARAIPCMessageSender +{ + ARAIPCMessageSenderRef ref; + const ARAIPCMessageSenderInterface * methods; // this preferably would be called "interface", but there's a system-defined macro in Windows with that name... +} ARAIPCMessageSender; +//! @} +#if defined(__cplusplus) +} // extern "C" } // namespace IPC } // namespace ARA +#endif + #endif // ARA_ENABLE_IPC diff --git a/IPC/ARAIPCEncoding.h b/IPC/ARAIPCEncoding.h index 8b8811e..526bf79 100644 --- a/IPC/ARAIPCEncoding.h +++ b/IPC/ARAIPCEncoding.h @@ -24,7 +24,7 @@ #include "ARA_Library/IPC/ARAIPC.h" -#if ARA_ENABLE_IPC +#if ARA_ENABLE_IPC && defined(__cplusplus) #include "ARA_Library/Debug/ARADebug.h" #include "ARA_Library/Dispatch/ARAContentReader.h" @@ -170,81 +170,80 @@ struct _IsStructPointerArg //------------------------------------------------------------------------------ -// private primitive wrappers for IPCMessageEn-/Decoder API that drop the type encoding -// from the name (which is required there for potential C compatibility) +// private primitive wrappers for MessageEn-/Decoder C API //------------------------------------------------------------------------------ // primitives for appending an argument to a message -inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const int32_t argValue) +inline void _appendToMessage (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const int32_t argValue) { - encoder.appendInt32 (argKey, argValue); + encoder.methods->appendInt32 (encoder.ref, argKey, argValue); } -inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const int64_t argValue) +inline void _appendToMessage (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const int64_t argValue) { - encoder.appendInt64 (argKey, argValue); + encoder.methods->appendInt64 (encoder.ref, argKey, argValue); } -inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const size_t argValue) +inline void _appendToMessage (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const size_t argValue) { - encoder.appendSize (argKey, argValue); + encoder.methods->appendSize (encoder.ref, argKey, argValue); } -inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const float argValue) +inline void _appendToMessage (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const float argValue) { - encoder.appendFloat (argKey, argValue); + encoder.methods->appendFloat (encoder.ref, argKey, argValue); } -inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const double argValue) +inline void _appendToMessage (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const double argValue) { - encoder.appendDouble (argKey, argValue); + encoder.methods->appendDouble (encoder.ref, argKey, argValue); } -inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const char* const argValue) +inline void _appendToMessage (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const char* const argValue) { - encoder.appendString (argKey, argValue); + encoder.methods->appendString (encoder.ref, argKey, argValue); } -inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const BytesEncoder& argValue) +inline void _appendToMessage (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const BytesEncoder& argValue) { const uint8_t* bytes; size_t size; bool copy; argValue (bytes, size, copy); - encoder.appendBytes (argKey, bytes, size, copy); + encoder.methods->appendBytes (encoder.ref, argKey, bytes, size, copy); } // primitives for reading an (optional) argument from a message -inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, int32_t& argValue) +inline bool _readFromMessage (const ARAIPCMessageDecoder& decoder, const ARAIPCMessageKey argKey, int32_t& argValue) { - return decoder.readInt32 (argKey, argValue); + return decoder.methods->readInt32 (decoder.ref, argKey, &argValue); } -inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, int64_t& argValue) +inline bool _readFromMessage (const ARAIPCMessageDecoder& decoder, const ARAIPCMessageKey argKey, int64_t& argValue) { - return decoder.readInt64 (argKey, argValue); + return decoder.methods->readInt64 (decoder.ref, argKey, &argValue); } -inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, size_t& argValue) +inline bool _readFromMessage (const ARAIPCMessageDecoder& decoder, const ARAIPCMessageKey argKey, size_t& argValue) { - return decoder.readSize (argKey, argValue); + return decoder.methods->readSize (decoder.ref, argKey, &argValue); } -inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, float& argValue) +inline bool _readFromMessage (const ARAIPCMessageDecoder& decoder, const ARAIPCMessageKey argKey, float& argValue) { - return decoder.readFloat (argKey, argValue); + return decoder.methods->readFloat (decoder.ref, argKey, &argValue); } -inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, double& argValue) +inline bool _readFromMessage (const ARAIPCMessageDecoder& decoder, const ARAIPCMessageKey argKey, double& argValue) { - return decoder.readDouble (argKey, argValue); + return decoder.methods->readDouble (decoder.ref, argKey, &argValue); } -inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, const char*& argValue) +inline bool _readFromMessage (const ARAIPCMessageDecoder& decoder, const ARAIPCMessageKey argKey, const char*& argValue) { - return decoder.readString (argKey, argValue); + return decoder.methods->readString (decoder.ref, argKey, &argValue); } -inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, BytesDecoder& argValue) +inline bool _readFromMessage (const ARAIPCMessageDecoder& decoder, const ARAIPCMessageKey argKey, BytesDecoder& argValue) { size_t receivedSize; - const auto found { decoder.readBytesSize (argKey, receivedSize) }; + const auto found { decoder.methods->readBytesSize (decoder.ref, argKey, &receivedSize) }; auto availableSize { receivedSize }; const auto bytes { argValue (availableSize) }; if (!found) return false; if (availableSize < receivedSize) return false; - decoder.readBytes (argKey, bytes); + decoder.methods->readBytes (decoder.ref, argKey, bytes); return true; } @@ -258,17 +257,17 @@ inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey ar // templated overloads of the IPCMessageEn-/Decoder primitives for ARA (host) ref types, // which are stored as size_t template::value, bool>::type = true> -inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const T argValue) +inline void _appendToMessage (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const T argValue) { - encoder.appendSize (argKey, reinterpret_cast (argValue)); + encoder.methods->appendSize (encoder.ref, argKey, reinterpret_cast (argValue)); } template::value, bool>::type = true> -inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, T& argValue) +inline bool _readFromMessage (const ARAIPCMessageDecoder& decoder, const ARAIPCMessageKey argKey, T& argValue) { // \todo is there a safe/proper way across all compilers for this cast to avoid the copy? // return decoder.readSize (argKey, *reinterpret_cast (&argValue)); size_t tmp; - const auto success { decoder.readSize (argKey, tmp) }; + const auto success { decoder.methods->readSize (decoder.ref, argKey, &tmp) }; argValue = reinterpret_cast (tmp); return success; } @@ -277,11 +276,11 @@ inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey ar sending arrays of ARABytes via this overload (seems simpler but less efficient): // to read and write arrays of ARAByte (not raw bytes but e.g. ARAKeySignatureIntervalUsage), // we use int32_t to keep the IPCMessageEn-/Decoder API small -inline void _appendToMessage (MessageEncoder& encoder, const MessageKey argKey, const ARAByte argValue) +inline void _appendToMessage (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const ARAByte argValue) { encoder.appendInt32 (argKey, static_cast (argValue)); } -inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey argKey, ARAByte& argValue) +inline bool _readFromMessage (const ARAIPCMessageDecoder& decoder, const ARAIPCMessageKey argKey, ARAByte& argValue) { int32_t tmp; const auto result { decoder.readInt32 (argKey, tmp) }; @@ -310,16 +309,16 @@ inline bool _readFromMessage (const MessageDecoder& decoder, const MessageKey ar // declarations of wrapper functions to implicitly deduce _ValueEn-/Decoder<> - // they are defined further down below, after all specializations are defined template -inline void _encodeAndAppend (MessageEncoder& encoder, const MessageKey argKey, const ValueT& argValue); +inline void _encodeAndAppend (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const ValueT& argValue); template -inline bool _readAndDecode (ValueT& result, const MessageDecoder& decoder, const MessageKey argKey); +inline bool _readAndDecode (ValueT& result, const ARAIPCMessageDecoder& decoder, const ARAIPCMessageKey argKey); // primary templates for basic types (numbers, strings, (host)refs and raw bytes) template struct _ValueEncoder { - static inline void encodeAndAppend (MessageEncoder& encoder, const MessageKey argKey, const ValueT& argValue) + static inline void encodeAndAppend (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const ValueT& argValue) { _appendToMessage (encoder, argKey, argValue); } @@ -327,7 +326,7 @@ struct _ValueEncoder template struct _ValueDecoder { - static inline bool readAndDecode (ValueT& result, const MessageDecoder& decoder, const MessageKey argKey) + static inline bool readAndDecode (ValueT& result, const ARAIPCMessageDecoder& decoder, const ARAIPCMessageKey argKey) { return _readFromMessage (decoder, argKey, result); } @@ -339,24 +338,26 @@ struct _ValueDecoder template struct _CompoundValueEncoderBase { - static inline void encodeAndAppend (MessageEncoder& encoder, const MessageKey argKey, const ValueT& argValue) + static inline void encodeAndAppend (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const ValueT& argValue) { - auto subEncoder { encoder.appendSubMessage (argKey) }; - ARA_INTERNAL_ASSERT (subEncoder != nullptr); - _ValueEncoder::encode (*subEncoder, argValue); - delete subEncoder; + auto subEncoderRef { encoder.methods->appendSubMessage (encoder.ref, argKey) }; + ARA_INTERNAL_ASSERT (subEncoderRef != nullptr); + ARAIPCMessageEncoder subEncoder { subEncoderRef, encoder.methods }; + _ValueEncoder::encode (subEncoder, argValue); + encoder.methods->destroyEncoder (subEncoderRef); } }; template struct _CompoundValueDecoderBase { - static inline bool readAndDecode (ValueT& result, const MessageDecoder& decoder, const MessageKey argKey) + static inline bool readAndDecode (ValueT& result, const ARAIPCMessageDecoder& decoder, const ARAIPCMessageKey argKey) { - auto subDecoder { decoder.readSubMessage (argKey) }; - if (subDecoder == nullptr) + auto subDecoderRef { decoder.methods->readSubMessage (decoder.ref, argKey) }; + if (subDecoderRef == nullptr) return false; - const auto success { _ValueDecoder::decode (result, *subDecoder) }; - delete subDecoder; + ARAIPCMessageDecoder subDecoder { subDecoderRef, decoder.methods }; + const auto success { _ValueDecoder::decode (result, subDecoder) }; + decoder.methods->destroyDecoder (subDecoderRef); return success; } }; @@ -366,10 +367,10 @@ struct _CompoundValueDecoderBase template struct _ValueEncoder> : public _CompoundValueEncoderBase> { - static inline void encode (MessageEncoder& encoder, const ArrayArgument& value) + static inline void encode (ARAIPCMessageEncoder& encoder, const ArrayArgument& value) { - ARA_INTERNAL_ASSERT (value.count <= static_cast (std::numeric_limits::max ())); - const auto count { static_cast (value.count) }; + ARA_INTERNAL_ASSERT (value.count <= static_cast (std::numeric_limits::max ())); + const auto count { static_cast (value.count) }; _encodeAndAppend (encoder, 0, count); for (auto i { 0 }; i < count; ++i) _encodeAndAppend (encoder, i + 1, value.elements[static_cast (i)]); @@ -380,14 +381,14 @@ struct _ValueEncoder> : public _CompoundValueEncoderBase template struct _ValueDecoder> : public _CompoundValueDecoderBase> { - static inline bool decode (ArrayArgument& result, const MessageDecoder& decoder) + static inline bool decode (ArrayArgument& result, const ARAIPCMessageDecoder& decoder) { bool success { true }; - MessageKey count; + ARAIPCMessageKey count; success &= _readAndDecode (count, decoder, 0); - success &= (count == static_cast (result.count)); - if (count > static_cast (result.count)) - count = static_cast (result.count); + success &= (count == static_cast (result.count)); + if (count > static_cast (result.count)) + count = static_cast (result.count); for (auto i { 0 }; i < count; ++i) success &= _readAndDecode (result.elements[static_cast (i)], decoder, i + 1); @@ -399,10 +400,10 @@ struct _ValueDecoder> : public _CompoundValueDecoderBase template struct _ValueDecoder> : public _CompoundValueDecoderBase> { - static inline bool decode (std::vector& result, const MessageDecoder& decoder) + static inline bool decode (std::vector& result, const ARAIPCMessageDecoder& decoder) { bool success { true }; - MessageKey count; + ARAIPCMessageKey count; success &= _readAndDecode (count, decoder, 0); result.resize (static_cast (count)); for (auto i { 0 }; i < count; ++i) @@ -418,7 +419,7 @@ struct _ValueDecoder> : public _CompoundValueDecoderBase struct _ValueEncoder : public _CompoundValueEncoderBase \ { /* specialization for given struct */ \ using StructType = StructT; \ - static inline void encode (MessageEncoder& encoder, const StructType& value) \ + static inline void encode (ARAIPCMessageEncoder& encoder, const StructType& value) \ { #define ARA_IPC_ENCODE_MEMBER(member) \ _encodeAndAppend (encoder, offsetof (StructType, member), value.member); @@ -452,7 +453,7 @@ template<> struct _ValueEncoder : public _CompoundValueEncoderBase struct _ValueDecoder : public _CompoundValueDecoderBase \ { /* specialization for given struct */ \ using StructType = StructT; \ - static inline bool decode (StructType& result, const MessageDecoder& decoder) \ + static inline bool decode (StructType& result, const ARAIPCMessageDecoder& decoder) \ { \ bool success { true }; #define ARA_IPC_BEGIN_DECODE_SIZED(StructT) \ @@ -493,16 +494,17 @@ template<> struct _ValueDecoder : public _CompoundValueDecoderBasereadSubMessage (decoder.ref, offsetof (StructType, member)) }; \ + if (subDecoderRef_##member != nullptr) { \ ARA_IPC_UPDATE_STRUCT_SIZE_FOR_OPTIONAL (member); \ + ARAIPCMessageDecoder subDecoder { subDecoderRef_##member, decoder.methods }; \ /* \todo the outer struct contains a pointer to the inner struct, so we need some */\ /* place to store it - this static only works as long as this is single-threaded! */\ static std::remove_const::type>::type cache; \ - success &= _ValueDecoder::decode (cache, *subDecoder_##member); \ + success &= _ValueDecoder::decode (cache, subDecoder); \ ARA_INTERNAL_ASSERT (success); \ result.member = &cache; \ - delete subDecoder_##member; \ + decoder.methods->destroyDecoder (subDecoderRef_##member); \ } #define ARA_IPC_END_DECODE \ return success; \ @@ -829,12 +831,12 @@ ARA_IPC_END_DECODE // actual definitions of wrapper functions to implicitly deduce _ValueEn-/Decoder<> - // they are forward-declared above, before _ValueEn-/Decoder<> are defined template -inline void _encodeAndAppend (MessageEncoder& encoder, const MessageKey argKey, const ValueT& argValue) +inline void _encodeAndAppend (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const ValueT& argValue) { return _ValueEncoder::encodeAndAppend (encoder, argKey, argValue); } template -inline bool _readAndDecode (ValueT& result, const MessageDecoder& decoder, const MessageKey argKey) +inline bool _readAndDecode (ValueT& result, const ARAIPCMessageDecoder& decoder, const ARAIPCMessageKey argKey) { return _ValueDecoder::readAndDecode (result, decoder, argKey); } @@ -855,39 +857,39 @@ struct _IsOptionalArgument> }; // private helpers for encodeArguments() and decodeArguments() to deal with the variable arguments one at a time -inline void _encodeArgumentsHelper (MessageEncoder& /*encoder*/, const MessageKey /*argKey*/) +inline void _encodeArgumentsHelper (ARAIPCMessageEncoder& /*encoder*/, const ARAIPCMessageKey /*argKey*/) { } template::type::value, bool>::type = true> -inline void _encodeArgumentsHelper (MessageEncoder& encoder, const MessageKey argKey, const ArgT& argValue, const MoreArgs &... moreArgs) +inline void _encodeArgumentsHelper (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const ArgT& argValue, const MoreArgs &... moreArgs) { _encodeAndAppend (encoder, argKey, argValue); _encodeArgumentsHelper (encoder, argKey + 1, moreArgs...); } template::type::value, bool>::type = true> -inline void _encodeArgumentsHelper (MessageEncoder& encoder, const MessageKey argKey, const ArgT& argValue, const MoreArgs &... moreArgs) +inline void _encodeArgumentsHelper (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const ArgT& argValue, const MoreArgs &... moreArgs) { if (argValue != nullptr) _encodeAndAppend (encoder, argKey, *argValue); _encodeArgumentsHelper (encoder, argKey + 1, moreArgs...); } template -inline void _encodeArgumentsHelper (MessageEncoder& encoder, const MessageKey argKey, const std::nullptr_t& /*argValue*/, const MoreArgs &... moreArgs) +inline void _encodeArgumentsHelper (ARAIPCMessageEncoder& encoder, const ARAIPCMessageKey argKey, const std::nullptr_t& /*argValue*/, const MoreArgs &... moreArgs) { _encodeArgumentsHelper (encoder, argKey + 1, moreArgs...); } -inline void _decodeArgumentsHelper (const MessageDecoder& /*decoder*/, const MessageKey /*argKey*/) +inline void _decodeArgumentsHelper (const ARAIPCMessageDecoder& /*decoder*/, const ARAIPCMessageKey /*argKey*/) { } template::value, bool>::type = true> -inline void _decodeArgumentsHelper (const MessageDecoder& decoder, const MessageKey argKey, ArgT& argValue, MoreArgs &... moreArgs) +inline void _decodeArgumentsHelper (const ARAIPCMessageDecoder& decoder, const ARAIPCMessageKey argKey, ArgT& argValue, MoreArgs &... moreArgs) { _readAndDecode (argValue, decoder, argKey); _decodeArgumentsHelper (decoder, argKey + 1, moreArgs...); } template::value, bool>::type = true> -inline void _decodeArgumentsHelper (const MessageDecoder& decoder, const MessageKey argKey, ArgT& argValue, MoreArgs &... moreArgs) +inline void _decodeArgumentsHelper (const ARAIPCMessageDecoder& decoder, const ARAIPCMessageKey argKey, ArgT& argValue, MoreArgs &... moreArgs) { argValue.second = _readAndDecode (argValue.first, decoder, argKey); _decodeArgumentsHelper (decoder, argKey + 1, moreArgs...); @@ -895,31 +897,31 @@ inline void _decodeArgumentsHelper (const MessageDecoder& decoder, const Message // private helpers for ARA_IPC_HOST_METHOD_ID and ARA_IPC_PLUGIN_METHOD_ID template -constexpr MessageID _getHostInterfaceID (); +constexpr ARAIPCMessageID _getHostInterfaceID (); template<> -constexpr MessageID _getHostInterfaceID () { return 0; } +constexpr ARAIPCMessageID _getHostInterfaceID () { return 0; } template<> -constexpr MessageID _getHostInterfaceID () { return 1; } +constexpr ARAIPCMessageID _getHostInterfaceID () { return 1; } template<> -constexpr MessageID _getHostInterfaceID () { return 2; } +constexpr ARAIPCMessageID _getHostInterfaceID () { return 2; } template<> -constexpr MessageID _getHostInterfaceID () { return 3; } +constexpr ARAIPCMessageID _getHostInterfaceID () { return 3; } template<> -constexpr MessageID _getHostInterfaceID () { return 4; } +constexpr ARAIPCMessageID _getHostInterfaceID () { return 4; } template -constexpr MessageID _getPlugInInterfaceID (); +constexpr ARAIPCMessageID _getPlugInInterfaceID (); template<> -constexpr MessageID _getPlugInInterfaceID () { return 0; } +constexpr ARAIPCMessageID _getPlugInInterfaceID () { return 0; } template<> -constexpr MessageID _getPlugInInterfaceID () { return 1; } +constexpr ARAIPCMessageID _getPlugInInterfaceID () { return 1; } template<> -constexpr MessageID _getPlugInInterfaceID () { return 2; } +constexpr ARAIPCMessageID _getPlugInInterfaceID () { return 2; } template<> -constexpr MessageID _getPlugInInterfaceID () { return 3; } +constexpr ARAIPCMessageID _getPlugInInterfaceID () { return 3; } -template -constexpr MessageID _encodeMessageID () +template +constexpr ARAIPCMessageID _encodeMessageID () { static_assert (offset > 0, "offset 0 is never a valid function pointer"); static_assert ((interfaceID < 8), "currently using only 3 bits for interface ID"); @@ -945,26 +947,26 @@ constexpr MessageID _encodeMessageID () #define ARA_IPC_PLUGIN_METHOD_ID(StructT, member) IPC::_encodeMessageID (), offsetof (StructT, member)> () // "global" messages that are not passed based on interface structs -constexpr MessageID kGetFactoriesCountMessageID { 1 }; -constexpr MessageID kGetFactoryMessageID { 2 }; -constexpr MessageID kCreateDocumentControllerMessageID { 3 }; +constexpr ARAIPCMessageID kGetFactoriesCountMessageID { 1 }; +constexpr ARAIPCMessageID kGetFactoryMessageID { 2 }; +constexpr ARAIPCMessageID kCreateDocumentControllerMessageID { 3 }; // caller side: create a message with the specified arguments template -inline void encodeArguments (MessageEncoder& encoder, const Args &... args) +inline void encodeArguments (ARAIPCMessageEncoder& encoder, const Args &... args) { _encodeArgumentsHelper (encoder, 0, args...); } // caller side: decode the received reply to a sent message template::value || !std::is_pod::value, bool>::type = true> -inline bool decodeReply (RetT& result, const MessageDecoder& decoder) +inline bool decodeReply (RetT& result, const ARAIPCMessageDecoder& decoder) { return _readAndDecode (result, decoder, 0); } template::value && std::is_pod::value, bool>::type = true> -inline bool decodeReply (RetT& result, const MessageDecoder& decoder) +inline bool decodeReply (RetT& result, const ARAIPCMessageDecoder& decoder) { return _ValueDecoder::decode (result, decoder); } @@ -972,9 +974,10 @@ inline bool decodeReply (RetT& result, const MessageDecoder& decoder) // callee side: decode the arguments of a received message template -inline void decodeArguments (const MessageDecoder& decoder, Args &... args) +inline void decodeArguments (const ARAIPCMessageDecoder* decoder, Args &... args) { - _decodeArgumentsHelper (decoder, 0, args...); + ARA_INTERNAL_ASSERT (decoder != nullptr); + _decodeArgumentsHelper (*decoder, 0, args...); } // callee side: wrapper for optional method arguments: first is the argument value, second if it was present @@ -983,13 +986,13 @@ using OptionalArgument = typename std::pair; // callee side: encode the reply to a received message template::value || !std::is_pod::value, bool>::type = true> -inline void encodeReply (MessageEncoder* encoder, const ValueT& value) +inline void encodeReply (ARAIPCMessageEncoder* encoder, const ValueT& value) { ARA_INTERNAL_ASSERT (encoder != nullptr); _encodeAndAppend (*encoder, 0, value); } template::value && std::is_pod::value, bool>::type = true> -inline void encodeReply (MessageEncoder* encoder, const ValueT& value) +inline void encodeReply (ARAIPCMessageEncoder* encoder, const ValueT& value) { ARA_INTERNAL_ASSERT (encoder != nullptr); _ValueEncoder::encode (*encoder, value); @@ -997,16 +1000,16 @@ inline void encodeReply (MessageEncoder* encoder, const ValueT& value) // for debugging only: decoding method IDs -inline const char* _decodeMessageID (std::map& cache, const char* interfaceName, const MessageID messageID) +inline const char* _decodeMessageID (std::map& cache, const char* interfaceName, const ARAIPCMessageID messageID) { auto it { cache.find (messageID) }; if (it == cache.end ()) it = cache.emplace (messageID, std::string { interfaceName } + " method " + std::to_string (messageID >> 3)).first; return it->second.c_str(); } -inline const char* decodeHostMessageID (const MessageID messageID) +inline const char* decodeHostMessageID (const ARAIPCMessageID messageID) { - static std::map cache; + static std::map cache; const char* interfaceName; switch (messageID & 0x7) { @@ -1019,9 +1022,9 @@ inline const char* decodeHostMessageID (const MessageID messageID) } return _decodeMessageID (cache, interfaceName, messageID); } -inline const char* decodePlugInMessageID (const MessageID messageID) +inline const char* decodePlugInMessageID (const ARAIPCMessageID messageID) { - static std::map cache; + static std::map cache; const char* interfaceName; switch (messageID & 0x7) { @@ -1038,7 +1041,7 @@ inline const char* decodePlugInMessageID (const MessageID messageID) // support for content readers //------------------------------------------------------------------------------ -inline void encodeContentEvent (MessageEncoder* encoder, const ARAContentType type, const void* eventData) +inline void encodeContentEvent (ARAIPCMessageEncoder* encoder, const ARAContentType type, const void* eventData) { switch (type) { @@ -1060,17 +1063,17 @@ class ContentEventDecoder _contentString { _findStringMember (type) } {} - const void* decode (const MessageDecoder& decoder) + const void* decode (const ARAIPCMessageDecoder& decoder) { (this->*_decoderFunction) (decoder); return &_eventStorage; } private: - using _DecoderFunction = void (ContentEventDecoder::*) (const MessageDecoder&); + using _DecoderFunction = void (ContentEventDecoder::*) (const ARAIPCMessageDecoder&); template - void _decodeContentEvent (const MessageDecoder& decoder) + void _decodeContentEvent (const ARAIPCMessageDecoder& decoder) { decodeReply (*reinterpret_cast (&this->_eventStorage), decoder); if (this->_contentString != nullptr) @@ -1150,55 +1153,55 @@ class ContentEventDecoder class RemoteCaller { public: - using CustomDecodeFunction = std::function; + using CustomDecodeFunction = std::function; - RemoteCaller (Sender& sender) noexcept : _sender { sender } {} + RemoteCaller (ARAIPCMessageSender sender) noexcept : _sender { sender } {} template - void remoteCallWithoutReply (const MessageID messageID, const Args &... args) + void remoteCallWithoutReply (const ARAIPCMessageID messageID, const Args &... args) { - auto encoder { _sender.createEncoder () }; - encodeArguments (*encoder, args...); - _sender.sendMessage (messageID, *encoder, nullptr); - delete encoder; + auto encoder { _sender.methods->createEncoder (_sender.ref) }; + encodeArguments (encoder, args...); + _sender.methods->sendMessage (_sender.ref, messageID, &encoder, nullptr, nullptr); + encoder.methods->destroyEncoder (encoder.ref); } template - void remoteCallWithReply (RetT& result, const MessageID messageID, const Args &... args) + void remoteCallWithReply (RetT& result, const ARAIPCMessageID messageID, const Args &... args) { - auto encoder { _sender.createEncoder () }; - encodeArguments (*encoder, args...); - Sender::ReplyHandler replyHandler { [&result] (const MessageDecoder& decoder) -> void + auto encoder { _sender.methods->createEncoder (_sender.ref) }; + encodeArguments (encoder, args...); + ARAIPCReplyHandler replyHandler { [] (const ARAIPCMessageDecoder decoder, void* userData) -> void { - ARA_INTERNAL_ASSERT (!decoder.isEmpty ()); - decodeReply (result, decoder); + ARA_INTERNAL_ASSERT (!decoder.methods->isEmpty (decoder.ref)); + decodeReply (*reinterpret_cast (userData), decoder); } }; - _sender.sendMessage (messageID, *encoder, &replyHandler); - delete encoder; + _sender.methods->sendMessage (_sender.ref, messageID, &encoder, &replyHandler, &result); + encoder.methods->destroyEncoder (encoder.ref); } template - void remoteCallWithReply (CustomDecodeFunction& result, const MessageID messageID, const Args &... args) + void remoteCallWithReply (CustomDecodeFunction& decodeFunction, const ARAIPCMessageID messageID, const Args &... args) { - auto encoder { _sender.createEncoder () }; - encodeArguments (*encoder, args...); - Sender::ReplyHandler replyHandler { [&result] (const MessageDecoder& decoder) -> void + auto encoder { _sender.methods->createEncoder (_sender.ref) }; + encodeArguments (encoder, args...); + ARAIPCReplyHandler replyHandler { [] (const ARAIPCMessageDecoder decoder, void* userData) -> void { - ARA_INTERNAL_ASSERT (!decoder.isEmpty ()); - result (decoder); + ARA_INTERNAL_ASSERT (!decoder.methods->isEmpty (decoder.ref)); + (*reinterpret_cast (userData)) (decoder); } }; - _sender.sendMessage (messageID, *encoder, &replyHandler); - delete encoder; + _sender.methods->sendMessage (_sender.ref, messageID, &encoder, &replyHandler, &decodeFunction); + encoder.methods->destroyEncoder (encoder.ref); } - bool receiverEndianessMatches () { return _sender.receiverEndianessMatches (); } + bool receiverEndianessMatches () { return _sender.methods->receiverEndianessMatches (_sender.ref); } private: - Sender& _sender; + ARAIPCMessageSender _sender; }; } // namespace IPC } // namespace ARA -#endif // ARA_ENABLE_IPC +#endif // ARA_ENABLE_IPC && defined(__cplusplus) #endif // ARAIPCEncoding_h diff --git a/IPC/ARAIPCProxyHost.cpp b/IPC/ARAIPCProxyHost.cpp index 66d77ee..ae1a61c 100644 --- a/IPC/ARAIPCProxyHost.cpp +++ b/IPC/ARAIPCProxyHost.cpp @@ -21,6 +21,7 @@ #if ARA_ENABLE_IPC +#include "ARA_Library/IPC/ARAIPCEncoding.h" #include "ARA_Library/Dispatch/ARAHostDispatch.h" #include "ARA_Library/Dispatch/ARAPlugInDispatch.h" @@ -94,7 +95,7 @@ ARA_MAP_HOST_REF (RemoteHostContentReader, ARAContentReaderHostRef) class AudioAccessController : public Host::AudioAccessControllerInterface, public RemoteCaller { public: - AudioAccessController (Sender& sender, ARAAudioAccessControllerHostRef remoteHostRef) noexcept + AudioAccessController (ARAIPCMessageSender sender, ARAAudioAccessControllerHostRef remoteHostRef) noexcept : RemoteCaller { sender }, _remoteHostRef { remoteHostRef } {} ARAAudioReaderHostRef createAudioReaderForSource (ARAAudioSourceHostRef audioSourceHostRef, bool use64BitSamples) noexcept override; @@ -182,7 +183,7 @@ bool AudioAccessController::readAudioSamples (ARAAudioReaderHostRef audioReaderH // custom decoding to deal with float data memory ownership bool success { false }; - RemoteCaller::CustomDecodeFunction customDecode { [&success, &remoteAudioReader, &samplesPerChannel, &channelCount, &buffers] (const MessageDecoder& decoder) -> void + RemoteCaller::CustomDecodeFunction customDecode { [&success, &remoteAudioReader, &samplesPerChannel, &channelCount, &buffers] (const ARAIPCMessageDecoder& decoder) -> void { const auto bufferSize { remoteAudioReader->sampleSize * static_cast (samplesPerChannel) }; std::vector resultSizes; @@ -233,7 +234,7 @@ void AudioAccessController::destroyAudioReader (ARAAudioReaderHostRef audioReade class ArchivingController : public Host::ArchivingControllerInterface, public RemoteCaller { public: - ArchivingController (Sender& sender, ARAArchivingControllerHostRef remoteHostRef) noexcept + ArchivingController (ARAIPCMessageSender sender, ARAArchivingControllerHostRef remoteHostRef) noexcept : RemoteCaller { sender }, _remoteHostRef { remoteHostRef } {} ARASize getArchiveSize (ARAArchiveReaderHostRef archiveReaderHostRef) noexcept override; @@ -331,7 +332,7 @@ void ArchivingController::notifyDocumentUnarchivingProgress (float value) noexce ARAPersistentID ArchivingController::getDocumentArchiveID (ARAArchiveReaderHostRef archiveReaderHostRef) noexcept { - RemoteCaller::CustomDecodeFunction customDecode { [this] (const MessageDecoder& decoder) -> void + RemoteCaller::CustomDecodeFunction customDecode { [this] (const ARAIPCMessageDecoder& decoder) -> void { ARAPersistentID persistentID; decodeReply (persistentID, decoder); @@ -347,7 +348,7 @@ ARAPersistentID ArchivingController::getDocumentArchiveID (ARAArchiveReaderHostR class ContentAccessController : public Host::ContentAccessControllerInterface, public RemoteCaller { public: - ContentAccessController (Sender& sender, ARAContentAccessControllerHostRef remoteHostRef) noexcept + ContentAccessController (ARAIPCMessageSender sender, ARAContentAccessControllerHostRef remoteHostRef) noexcept : RemoteCaller { sender }, _remoteHostRef { remoteHostRef } {} bool isMusicalContextContentAvailable (ARAMusicalContextHostRef musicalContextHostRef, ARAContentType type) noexcept override; @@ -429,7 +430,7 @@ const void* ContentAccessController::getContentReaderDataForEvent (ARAContentRea { const auto contentReader { fromHostRef (contentReaderHostRef) }; const void* result {}; - RemoteCaller::CustomDecodeFunction customDecode { [&result, &contentReader] (const MessageDecoder& decoder) -> void + RemoteCaller::CustomDecodeFunction customDecode { [&result, &contentReader] (const ARAIPCMessageDecoder& decoder) -> void { result = contentReader->decoder.decode (decoder); } }; @@ -451,7 +452,7 @@ void ContentAccessController::destroyContentReader (ARAContentReaderHostRef cont class ModelUpdateController : public Host::ModelUpdateControllerInterface, public RemoteCaller { public: - ModelUpdateController (Sender& sender, ARAModelUpdateControllerHostRef remoteHostRef) noexcept + ModelUpdateController (ARAIPCMessageSender sender, ARAModelUpdateControllerHostRef remoteHostRef) noexcept : RemoteCaller { sender }, _remoteHostRef { remoteHostRef } {} void notifyAudioSourceAnalysisProgress (ARAAudioSourceHostRef audioSourceHostRef, ARAAnalysisProgressState state, float value) noexcept override; @@ -491,7 +492,7 @@ void ModelUpdateController::notifyPlaybackRegionContentChanged (ARAPlaybackRegio class PlaybackController : public Host::PlaybackControllerInterface, public RemoteCaller { public: - PlaybackController (Sender& sender, ARAPlaybackControllerHostRef remoteHostRef) noexcept + PlaybackController (ARAIPCMessageSender sender, ARAPlaybackControllerHostRef remoteHostRef) noexcept : RemoteCaller { sender }, _remoteHostRef { remoteHostRef } {} void requestStartPlayback () noexcept override; @@ -576,10 +577,16 @@ ARA_MAP_REF (PlugInExtension, ARAPlugInExtensionRef, ARAPlaybackRendererRef, ARA /*******************************************************************************/ +} // namespace ProxyHost +using namespace ProxyHost; + +/*******************************************************************************/ + + std::vector _factories {}; -Sender* _plugInCallbacksSender {}; +ARAIPCMessageSender _plugInCallbacksSender {}; -void addFactory (const ARAFactory* factory) +void ARAIPCProxyHostAddFactory (const ARAFactory* factory) { ARA_INTERNAL_ASSERT(factory->highestSupportedApiGeneration >= kARAAPIGeneration_2_0_Final); ARA_INTERNAL_ASSERT(!ARA::contains (_factories, factory)); @@ -587,29 +594,29 @@ void addFactory (const ARAFactory* factory) _factories.emplace_back (factory); } -void setPlugInCallbacksSender (Sender* plugInCallbacksSender) +void ARAIPCProxyHostSetPlugInCallbacksSender (ARAIPCMessageSender plugInCallbacksSender) { _plugInCallbacksSender = plugInCallbacksSender; } -ARADocumentControllerRef getDocumentControllerRefForRemoteRef (ARADocumentControllerRef remoteRef) +ARADocumentControllerRef ARAIPCProxyHostTranslateDocumentControllerRef (ARADocumentControllerRef remoteRef) { return fromRef (remoteRef)->getRef (); } -ARAPlugInExtensionRef createPlugInExtension (const ARAPlugInExtensionInstance* instance) +ARAPlugInExtensionRef ARAIPCProxyHostCreatePlugInExtension (const ARAPlugInExtensionInstance* instance) { return toRef (new PlugInExtension { instance }); } -void destroyPlugInExtension (ARAPlugInExtensionRef plugInExtensionRef) +void ARAIPCProxyHostDestroyPlugInExtension (ARAPlugInExtensionRef plugInExtensionRef) { delete fromRef (plugInExtensionRef); } -void hostCommandHandler (const MessageID messageID, const MessageDecoder& decoder, MessageEncoder* const replyEncoder) +void ARAIPCProxyHostCommandHandler (const ARAIPCMessageID messageID, const ARAIPCMessageDecoder* const decoder, ARAIPCMessageEncoder* const replyEncoder) { -// ARA_LOG ("hostCommandHandler received message %s", decodePlugInMessageID (messageID)); +// ARA_LOG ("ARAIPCProxyHostCommandHandler received message %s", decodePlugInMessageID (messageID)); // ARAFactory if (messageID == kGetFactoriesCountMessageID) @@ -654,11 +661,11 @@ void hostCommandHandler (const MessageID messageID, const MessageDecoder& decode ARA_INTERNAL_ASSERT (factory != nullptr); if (factory != nullptr) { - const auto audioAccessController { new AudioAccessController { *_plugInCallbacksSender, audioAccessControllerHostRef } }; - const auto archivingController { new ArchivingController { *_plugInCallbacksSender, archivingControllerHostRef } }; - const auto contentAccessController { (provideContentAccessController != kARAFalse) ? new ContentAccessController { *_plugInCallbacksSender, contentAccessControllerHostRef } : nullptr }; - const auto modelUpdateController { (provideModelUpdateController != kARAFalse) ? new ModelUpdateController { *_plugInCallbacksSender, modelUpdateControllerHostRef } : nullptr }; - const auto playbackController { (providePlaybackController != kARAFalse) ? new PlaybackController { *_plugInCallbacksSender, playbackControllerHostRef } : nullptr }; + const auto audioAccessController { new AudioAccessController { _plugInCallbacksSender, audioAccessControllerHostRef } }; + const auto archivingController { new ArchivingController { _plugInCallbacksSender, archivingControllerHostRef } }; + const auto contentAccessController { (provideContentAccessController != kARAFalse) ? new ContentAccessController { _plugInCallbacksSender, contentAccessControllerHostRef } : nullptr }; + const auto modelUpdateController { (provideModelUpdateController != kARAFalse) ? new ModelUpdateController { _plugInCallbacksSender, modelUpdateControllerHostRef } : nullptr }; + const auto playbackController { (providePlaybackController != kARAFalse) ? new PlaybackController { _plugInCallbacksSender, playbackControllerHostRef } : nullptr }; const auto hostInstance { new Host::DocumentControllerHostInstance { audioAccessController, archivingController, contentAccessController, modelUpdateController, playbackController } }; @@ -1252,7 +1259,6 @@ void hostCommandHandler (const MessageID messageID, const MessageDecoder& decode // ARA_INTERNAL_ASSERT (replyEncoder == nullptr); } -} // namespace ProxyHost } // namespace IPC } // namespace ARA diff --git a/IPC/ARAIPCProxyHost.h b/IPC/ARAIPCProxyHost.h index ea1d7b2..c650b45 100644 --- a/IPC/ARAIPCProxyHost.h +++ b/IPC/ARAIPCProxyHost.h @@ -20,37 +20,40 @@ #define ARAIPCProxyHost_h -#include "ARAIPCEncoding.h" - +#include "ARA_Library/IPC/ARAIPC.h" #if ARA_ENABLE_IPC +#if defined(__cplusplus) namespace ARA { namespace IPC { -namespace ProxyHost { +extern "C" { +#endif + - //! static configuration: add the ARA factories that the proxy host will wrap -void addFactory (const ARAFactory* factory); +void ARAIPCProxyHostAddFactory(const ARAFactory * factory); //! static configuration: set sender that the proxy host will use to perform callbacks received from the plug-in -void setPlugInCallbacksSender (Sender* plugInCallbacksSender); +void ARAIPCProxyHostSetPlugInCallbacksSender(ARAIPCMessageSender plugInCallbacksSender); //! static dispatcher: the host command handler that controls the proxy host -void hostCommandHandler (const MessageID messageID, const MessageDecoder& decoder, MessageEncoder* const replyEncoder); +void ARAIPCProxyHostCommandHandler(const ARAIPCMessageID messageID, const ARAIPCMessageDecoder * decoder, ARAIPCMessageEncoder * replyEncoder); //! translation needed when establishing the binding to the remote documentController -ARADocumentControllerRef getDocumentControllerRefForRemoteRef (ARADocumentControllerRef remoteRef); +ARADocumentControllerRef ARAIPCProxyHostTranslateDocumentControllerRef(ARADocumentControllerRef remoteRef); //! creating and deleting plug-in extension instances associated with the proxy host -ARAPlugInExtensionRef createPlugInExtension (const ARAPlugInExtensionInstance* instance); -void destroyPlugInExtension (ARAPlugInExtensionRef plugInExtensionRef); +ARAPlugInExtensionRef ARAIPCProxyHostCreatePlugInExtension(const ARAPlugInExtensionInstance * instance); +void ARAIPCProxyHostDestroyPlugInExtension(ARAPlugInExtensionRef plugInExtensionRef); + - -} // namespace ProxyHost +#if defined(__cplusplus) +} // extern "C" } // namespace IPC } // namespace ARA +#endif #endif // ARA_ENABLE_IPC diff --git a/IPC/ARAIPCProxyPlugIn.cpp b/IPC/ARAIPCProxyPlugIn.cpp index 1c16c30..47037c8 100644 --- a/IPC/ARAIPCProxyPlugIn.cpp +++ b/IPC/ARAIPCProxyPlugIn.cpp @@ -21,6 +21,7 @@ #if ARA_ENABLE_IPC +#include "ARA_Library/IPC/ARAIPCEncoding.h" #include "ARA_Library/Dispatch/ARAPlugInDispatch.h" #include "ARA_Library/Dispatch/ARAHostDispatch.h" @@ -189,7 +190,7 @@ ARA_MAP_HOST_REF (HostAudioReader, ARAAudioReaderHostRef) class DocumentController : public PlugIn::DocumentControllerInterface, protected RemoteCaller, public InstanceValidator { public: - DocumentController (Sender& sender, const ARAFactory* factory, const ARADocumentControllerHostInstance* instance, const ARADocumentProperties* properties) noexcept; + DocumentController (ARAIPCMessageSender sender, const ARAFactory* factory, const ARADocumentControllerHostInstance* instance, const ARADocumentProperties* properties) noexcept; public: template @@ -325,7 +326,7 @@ ARA_MAP_HOST_REF (DocumentController, ARAAudioAccessControllerHostRef, ARAArchiv /*******************************************************************************/ -DocumentController::DocumentController (Sender& sender, const ARAFactory* factory, const ARADocumentControllerHostInstance* instance, const ARADocumentProperties* properties) noexcept +DocumentController::DocumentController (ARAIPCMessageSender sender, const ARAFactory* factory, const ARADocumentControllerHostInstance* instance, const ARADocumentProperties* properties) noexcept : RemoteCaller { sender }, _factory { factory }, _hostAudioAccessController { instance }, @@ -467,7 +468,7 @@ bool DocumentController::storeAudioSourceToAudioFileChunk (ARAArchiveWriterHostR ARA_VALIDATE_API_ARGUMENT (openAutomatically, openAutomatically != nullptr); bool success { false }; - RemoteCaller::CustomDecodeFunction customDecode { [this, &success, &documentArchiveID, &openAutomatically] (const MessageDecoder& decoder) -> void + RemoteCaller::CustomDecodeFunction customDecode { [this, &success, &documentArchiveID, &openAutomatically] (const ARAIPCMessageDecoder& decoder) -> void { StoreAudioSourceToAudioFileChunkReply reply; decodeReply (reply, decoder); @@ -905,7 +906,7 @@ const void* DocumentController::getContentReaderDataForEvent (ARAContentReaderRe ARA_VALIDATE_API_ARGUMENT (contentReader, isValidInstance (contentReader)); const void* result {}; - RemoteCaller::CustomDecodeFunction customDecode { [&result, &contentReader] (const MessageDecoder& decoder) -> void + RemoteCaller::CustomDecodeFunction customDecode { [&result, &contentReader] (const ARAIPCMessageDecoder& decoder) -> void { result = contentReader->decoder.decode (decoder); } }; @@ -968,7 +969,7 @@ const ARAProcessingAlgorithmProperties* DocumentController::getProcessingAlgorit ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - RemoteCaller::CustomDecodeFunction customDecode { [this] (const MessageDecoder& decoder) -> void + RemoteCaller::CustomDecodeFunction customDecode { [this] (const ARAIPCMessageDecoder& decoder) -> void { ARAProcessingAlgorithmProperties reply; decodeReply (reply, decoder); @@ -1025,7 +1026,7 @@ bool DocumentController::isLicensedForCapabilities (bool runModalActivationDialo class PlaybackRenderer : public PlugIn::PlaybackRendererInterface, protected RemoteCaller, public InstanceValidator { public: - explicit PlaybackRenderer (Sender& sender, ARAPlaybackRendererRef remoteRef) noexcept + explicit PlaybackRenderer (ARAIPCMessageSender sender, ARAPlaybackRendererRef remoteRef) noexcept : RemoteCaller { sender }, _remoteRef { remoteRef } {} @@ -1059,7 +1060,7 @@ class PlaybackRenderer : public PlugIn::PlaybackRendererInterface, protected Rem class EditorRenderer : public PlugIn::EditorRendererInterface, protected RemoteCaller, public InstanceValidator { public: - explicit EditorRenderer (Sender& sender, ARAEditorRendererRef remoteRef) noexcept + explicit EditorRenderer (ARAIPCMessageSender sender, ARAEditorRendererRef remoteRef) noexcept : RemoteCaller { sender }, _remoteRef { remoteRef } {} @@ -1108,7 +1109,7 @@ class EditorRenderer : public PlugIn::EditorRendererInterface, protected RemoteC class EditorView : public PlugIn::EditorViewInterface, protected RemoteCaller, public InstanceValidator { public: - explicit EditorView (Sender& sender, ARAEditorViewRef remoteRef) noexcept + explicit EditorView (ARAIPCMessageSender sender, ARAEditorViewRef remoteRef) noexcept : RemoteCaller { sender }, _remoteRef { remoteRef } {} @@ -1144,9 +1145,9 @@ class EditorView : public PlugIn::EditorViewInterface, protected RemoteCaller, p class PlugInExtension : public PlugIn::PlugInExtensionInstance { public: - PlugInExtension (Sender& sender, ARADocumentControllerRef documentControllerRef, - ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles, - size_t remotePlugInExtensionRef) noexcept + PlugInExtension (ARAIPCMessageSender sender, ARADocumentControllerRef documentControllerRef, + ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles, + size_t remotePlugInExtensionRef) noexcept : PlugIn::PlugInExtensionInstance { (((knownRoles & kARAPlaybackRendererRole) == 0) || ((assignedRoles & kARAPlaybackRendererRole) != 0)) ? new PlaybackRenderer (sender, reinterpret_cast (remotePlugInExtensionRef)) : nullptr, (((knownRoles & kARAEditorRendererRole) == 0) || ((assignedRoles & kARAEditorRendererRole) != 0)) ? @@ -1188,22 +1189,27 @@ class PlugInExtension : public PlugIn::PlugInExtensionInstance }; +/*******************************************************************************/ + +} // namespace ProxyPlugIn +using namespace ProxyPlugIn; + /*******************************************************************************/ // Utility class that wraps an ARAFactory. -class Factory +struct ARAIPCProxyPlugInFactory { public: - Factory (Sender& hostCommandsSender, size_t index); + ARAIPCProxyPlugInFactory (ARAIPCMessageSender hostCommandsSender, size_t index); const ARADocumentControllerInstance* createDocumentControllerWithDocument (const ARADocumentControllerHostInstance* hostInstance, const ARADocumentProperties* properties); const ARAFactory* getFactory () const { return &_factory; } - Sender& getHostCommandsSender () const { return _hostCommandsSender; } + ARAIPCMessageSender getHostCommandsSender () const { return _hostCommandsSender; } private: - Sender& _hostCommandsSender; + ARAIPCMessageSender _hostCommandsSender; ARAFactory _factory; struct @@ -1220,10 +1226,10 @@ class Factory std::vector _factoryAnalyzableTypes; }; -Factory::Factory (Sender& hostCommandsSender, size_t index) +ARAIPCProxyPlugInFactory::ARAIPCProxyPlugInFactory (ARAIPCMessageSender hostCommandsSender, size_t index) : _hostCommandsSender { hostCommandsSender } { - RemoteCaller::CustomDecodeFunction customDecode { [this] (const MessageDecoder& decoder) -> void + RemoteCaller::CustomDecodeFunction customDecode { [this] (const ARAIPCMessageDecoder& decoder) -> void { decodeReply (_factory, decoder); @@ -1262,54 +1268,55 @@ Factory::Factory (Sender& hostCommandsSender, size_t index) RemoteCaller { _hostCommandsSender }.remoteCallWithReply (customDecode, kGetFactoryMessageID, index); } -std::vector _factories {}; +std::vector _proxyFactories {}; -size_t initializeFactories (Sender& hostCommandsSender) +size_t ARAIPCProxyPlugInInitializeFactories (ARAIPCMessageSender hostCommandsSender) { size_t count; RemoteCaller { hostCommandsSender }.remoteCallWithReply (count, kGetFactoriesCountMessageID); ARA_INTERNAL_ASSERT (count > 0); - _factories.reserve (count); + _proxyFactories.reserve (count); for (auto i { 0U }; i < count; ++i) - _factories.emplace_back (hostCommandsSender, i); - return _factories.size (); + _proxyFactories.emplace_back (hostCommandsSender, i); + return _proxyFactories.size (); } -Factory* getFactoryAtIndex (size_t index) +ARAIPCProxyPlugInFactory* ARAIPCProxyPlugInGetFactoryAtIndex (size_t index) { - ARA_INTERNAL_ASSERT (index < _factories.size ()); - return &_factories[index]; + ARA_INTERNAL_ASSERT (index < _proxyFactories.size ()); + return &_proxyFactories[index]; } -const ARAFactory* getFactoryData (Factory* proxyFactory) +const ARAFactory* ARAIPCProxyPlugInGetFactoryData (ARAIPCProxyPlugInFactory* proxyFactory) { return proxyFactory->getFactory (); } -const ARADocumentControllerInstance* createDocumentControllerWithDocument (Factory* proxyFactory, const ARADocumentControllerHostInstance* hostInstance, const ARADocumentProperties* properties) +const ARADocumentControllerInstance* ARAIPCProxyPlugInCreateDocumentControllerWithDocument (ARAIPCProxyPlugInFactory* proxyFactory, + const ARADocumentControllerHostInstance* hostInstance, const ARADocumentProperties* properties) { auto result { new DocumentController { proxyFactory->getHostCommandsSender (), proxyFactory->getFactory (), hostInstance, properties} }; return result->getInstance (); } -ARADocumentControllerRef getDocumentControllerRemoteRef (ARADocumentControllerRef documentControllerRef) +ARADocumentControllerRef ARAIPCProxyPlugInTranslateDocumentControllerRef (ARADocumentControllerRef documentControllerRef) { return static_cast (PlugIn::fromRef (documentControllerRef))->getRemoteRef (); } -const ARAPlugInExtensionInstance* createPlugInExtensionInstance (size_t remoteExtensionRef, Sender& sender, ARADocumentControllerRef documentControllerRef, - ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles) +const ARAPlugInExtensionInstance* ARAIPCProxyPlugInCreatePlugInExtension (size_t remoteExtensionRef, ARAIPCMessageSender sender, ARADocumentControllerRef documentControllerRef, + ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles) { return new PlugInExtension { sender, documentControllerRef, knownRoles, assignedRoles, remoteExtensionRef }; } -void destroyPlugInExtensionInstance (const ARAPlugInExtensionInstance* plugInExtensionInstance) +void ARAIPCProxyPlugInDestroyPlugInExtension (const ARAPlugInExtensionInstance* plugInExtensionInstance) { delete static_cast (plugInExtensionInstance); } -void plugInCallbacksDispatcher (const MessageID messageID, const MessageDecoder& decoder, MessageEncoder* const replyEncoder) +void ARAIPCProxyPlugInCallbacksDispatcher (const ARAIPCMessageID messageID, const ARAIPCMessageDecoder* const decoder, ARAIPCMessageEncoder* const replyEncoder) { // ARA_LOG ("plugInCallbackDispatcher received message %s", decodeHostMessageID (messageID)); @@ -1714,7 +1721,6 @@ void plugInCallbacksDispatcher (const MessageID messageID, const MessageDecoder& // ARA_INTERNAL_ASSERT (replyEncoder == nullptr); } -} // namespace ProxyPlugIn } // namespace IPC } // namespace ARA diff --git a/IPC/ARAIPCProxyPlugIn.h b/IPC/ARAIPCProxyPlugIn.h index 839411f..a2c0de2 100644 --- a/IPC/ARAIPCProxyPlugIn.h +++ b/IPC/ARAIPCProxyPlugIn.h @@ -19,50 +19,54 @@ #ifndef ARAIPCProxyPlugIn_h #define ARAIPCProxyPlugIn_h -#include "ARAIPCEncoding.h" +#include "ARA_Library/IPC/ARAIPC.h" #if ARA_ENABLE_IPC +#if defined(__cplusplus) namespace ARA { namespace IPC { -namespace ProxyPlugIn { +extern "C" { +#endif -class Factory; +typedef struct ARAIPCProxyPlugInFactory ARAIPCProxyPlugInFactory; //! static initialization -size_t initializeFactories (Sender& hostCommandsSender); +size_t ARAIPCProxyPlugInInitializeFactories(ARAIPCMessageSender hostCommandsSender); //! access proxies to the factories provided by the remote plug-in -Factory* getFactoryAtIndex (size_t index); +ARAIPCProxyPlugInFactory * ARAIPCProxyPlugInGetFactoryAtIndex(size_t index); //! get copy of the remote factory data, with all function calls removed -const ARAFactory* getFactoryData (Factory* proxyFactory); +const ARAFactory * ARAIPCProxyPlugInGetFactoryData(ARAIPCProxyPlugInFactory * proxyFactory); -//! proxy document controller creation call, to be used instead of ARAFactory.createDocumentControllerWithDocument () -const ARADocumentControllerInstance* createDocumentControllerWithDocument (Factory* proxyFactory, - const ARADocumentControllerHostInstance* hostInstance, - const ARADocumentProperties* properties); +//! proxy document controller creation call, to be used instead of ARAFactory.createDocumentControllerWithDocument() +const ARADocumentControllerInstance * ARAIPCProxyPlugInCreateDocumentControllerWithDocument(ARAIPCProxyPlugInFactory * proxyFactory, + const ARADocumentControllerHostInstance * hostInstance, + const ARADocumentProperties * properties); //! static handler of received messages -void plugInCallbacksDispatcher (const MessageID messageID, const MessageDecoder& decoder, MessageEncoder* const replyEncoder); +void ARAIPCProxyPlugInCallbacksDispatcher(const ARAIPCMessageID messageID, const ARAIPCMessageDecoder * decoder, ARAIPCMessageEncoder * replyEncoder); //! \todo to perform the binding to the remote plug-in instance, the host needs access to this translation... -ARADocumentControllerRef getDocumentControllerRemoteRef (ARADocumentControllerRef documentControllerRef); +ARADocumentControllerRef ARAIPCProxyPlugInTranslateDocumentControllerRef(ARADocumentControllerRef documentControllerRef); //! create the plug-in extension when performing the binding to the remote plug-in instance -const ARAPlugInExtensionInstance* createPlugInExtensionInstance (size_t remoteExtensionRef, Sender& sender, ARADocumentControllerRef documentControllerRef, - ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles); +const ARAPlugInExtensionInstance * ARAIPCProxyPlugInCreatePlugInExtension(size_t remoteExtensionRef, ARAIPCMessageSender sender, ARADocumentControllerRef documentControllerRef, + ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles); //! destroy the plug-in extension when destroying the remote plug-in instance -void destroyPlugInExtensionInstance (const ARAPlugInExtensionInstance* plugInExtension); +void ARAIPCProxyPlugInDestroyPlugInExtension(const ARAPlugInExtensionInstance * plugInExtension); -} // namespace ProxyPlugIn +#if defined(__cplusplus) +} // extern "C" } // namespace IPC } // namespace ARA +#endif #endif // ARA_ENABLE_IPC From a619cc131b3cef807fc08e3e52157de9c9ae7e5e Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:31:58 +0100 Subject: [PATCH 07/18] Enable hosts to use of multiple different plug-ins through IPC proxies at the same time --- IPC/ARAIPCProxyPlugIn.cpp | 150 +++++++++++++++++++------------------- IPC/ARAIPCProxyPlugIn.h | 18 ++--- 2 files changed, 84 insertions(+), 84 deletions(-) diff --git a/IPC/ARAIPCProxyPlugIn.cpp b/IPC/ARAIPCProxyPlugIn.cpp index 47037c8..2e43742 100644 --- a/IPC/ARAIPCProxyPlugIn.cpp +++ b/IPC/ARAIPCProxyPlugIn.cpp @@ -30,6 +30,7 @@ #endif #include +#include #include #include @@ -1191,26 +1192,8 @@ class PlugInExtension : public PlugIn::PlugInExtensionInstance /*******************************************************************************/ -} // namespace ProxyPlugIn -using namespace ProxyPlugIn; - -/*******************************************************************************/ -// Utility class that wraps an ARAFactory. - -struct ARAIPCProxyPlugInFactory +struct RemoteFactory { -public: - ARAIPCProxyPlugInFactory (ARAIPCMessageSender hostCommandsSender, size_t index); - - const ARADocumentControllerInstance* createDocumentControllerWithDocument (const ARADocumentControllerHostInstance* hostInstance, - const ARADocumentProperties* properties); - - const ARAFactory* getFactory () const { return &_factory; } - ARAIPCMessageSender getHostCommandsSender () const { return _hostCommandsSender; } - -private: - ARAIPCMessageSender _hostCommandsSender; - ARAFactory _factory; struct { @@ -1220,83 +1203,104 @@ struct ARAIPCProxyPlugInFactory std::string informationURL; std::string version; std::string documentArchiveID; - } _factoryStrings; - std::vector _factoryCompatibleIDStrings; - std::vector _factoryCompatibleIDs; - std::vector _factoryAnalyzableTypes; + } _strings; + std::vector _compatibleIDStrings; + std::vector _compatibleIDs; + std::vector _analyzableTypes; }; -ARAIPCProxyPlugInFactory::ARAIPCProxyPlugInFactory (ARAIPCMessageSender hostCommandsSender, size_t index) -: _hostCommandsSender { hostCommandsSender } +std::map _factories {}; + + +/*******************************************************************************/ + +} // namespace ProxyPlugIn +using namespace ProxyPlugIn; + +/*******************************************************************************/ + + +size_t ARAIPCProxyPlugInGetFactoriesCount (ARAIPCMessageSender hostCommandsSender) { - RemoteCaller::CustomDecodeFunction customDecode { [this] (const ARAIPCMessageDecoder& decoder) -> void + size_t count; + RemoteCaller { hostCommandsSender }.remoteCallWithReply (count, kGetFactoriesCountMessageID); + ARA_INTERNAL_ASSERT (count > 0); + return count; +} + +const ARAFactory* ARAIPCProxyPlugInGetFactoryAtIndex (ARAIPCMessageSender hostCommandsSender, size_t index) +{ + RemoteFactory remoteFactory; + RemoteCaller::CustomDecodeFunction customDecode { [&remoteFactory] (const ARAIPCMessageDecoder& decoder) -> void { - decodeReply (_factory, decoder); + decodeReply (remoteFactory._factory, decoder); - ARA_VALIDATE_API_ARGUMENT(&_factory, _factory.highestSupportedApiGeneration >= kARAAPIGeneration_2_0_Final); + ARA_VALIDATE_API_ARGUMENT(&remoteFactory._factory, remoteFactory._factory.highestSupportedApiGeneration >= kARAAPIGeneration_2_0_Final); - _factoryStrings.factoryID = _factory.factoryID; - _factory.factoryID = _factoryStrings.factoryID.c_str (); + remoteFactory._strings.factoryID = remoteFactory._factory.factoryID; + remoteFactory._factory.factoryID = remoteFactory._strings.factoryID.c_str (); - _factoryStrings.plugInName = _factory.plugInName; - _factory.plugInName = _factoryStrings.plugInName.c_str (); - _factoryStrings.manufacturerName = _factory.manufacturerName; - _factory.manufacturerName = _factoryStrings.manufacturerName.c_str (); - _factoryStrings.informationURL = _factory.informationURL; - _factory.informationURL = _factoryStrings.informationURL.c_str (); - _factoryStrings.version = _factory.version; - _factory.version = _factoryStrings.version.c_str (); + remoteFactory._strings.plugInName = remoteFactory._factory.plugInName; + remoteFactory._factory.plugInName = remoteFactory._strings.plugInName.c_str (); + remoteFactory._strings.manufacturerName = remoteFactory._factory.manufacturerName; + remoteFactory._factory.manufacturerName = remoteFactory._strings.manufacturerName.c_str (); + remoteFactory._strings.informationURL = remoteFactory._factory.informationURL; + remoteFactory._factory.informationURL = remoteFactory._strings.informationURL.c_str (); + remoteFactory._strings.version = remoteFactory._factory.version; + remoteFactory._factory.version = remoteFactory._strings.version.c_str (); - _factoryStrings.documentArchiveID = _factory.documentArchiveID; - _factory.documentArchiveID = _factoryStrings.documentArchiveID.c_str (); + remoteFactory._strings.documentArchiveID = remoteFactory._factory.documentArchiveID; + remoteFactory._factory.documentArchiveID = remoteFactory._strings.documentArchiveID.c_str (); - _factoryCompatibleIDStrings.reserve (_factory.compatibleDocumentArchiveIDsCount); - _factoryCompatibleIDs.reserve (_factory.compatibleDocumentArchiveIDsCount); - for (auto i { 0U }; i < _factory.compatibleDocumentArchiveIDsCount; ++i) + remoteFactory._compatibleIDStrings.reserve (remoteFactory._factory.compatibleDocumentArchiveIDsCount); + remoteFactory._compatibleIDs.reserve (remoteFactory._factory.compatibleDocumentArchiveIDsCount); + for (auto i { 0U }; i < remoteFactory._factory.compatibleDocumentArchiveIDsCount; ++i) { - _factoryCompatibleIDStrings.emplace_back (_factory.compatibleDocumentArchiveIDs[i]); - _factoryCompatibleIDs.emplace_back (_factoryCompatibleIDStrings[i].c_str ()); + remoteFactory._compatibleIDStrings.emplace_back (remoteFactory._factory.compatibleDocumentArchiveIDs[i]); + remoteFactory._compatibleIDs.emplace_back (remoteFactory._compatibleIDStrings[i].c_str ()); } - _factory.compatibleDocumentArchiveIDs = _factoryCompatibleIDs.data (); + remoteFactory._factory.compatibleDocumentArchiveIDs = remoteFactory._compatibleIDs.data (); - _factoryAnalyzableTypes.reserve (_factory.analyzeableContentTypesCount); - for (auto i { 0U }; i < _factory.analyzeableContentTypesCount; ++i) - _factoryAnalyzableTypes.emplace_back (_factory.analyzeableContentTypes[i]); - _factory.analyzeableContentTypes = _factoryAnalyzableTypes.data (); + remoteFactory._analyzableTypes.reserve (remoteFactory._factory.analyzeableContentTypesCount); + for (auto i { 0U }; i < remoteFactory._factory.analyzeableContentTypesCount; ++i) + remoteFactory._analyzableTypes.emplace_back (remoteFactory._factory.analyzeableContentTypes[i]); + remoteFactory._factory.analyzeableContentTypes = remoteFactory._analyzableTypes.data (); } }; - RemoteCaller { _hostCommandsSender }.remoteCallWithReply (customDecode, kGetFactoryMessageID, index); -} + RemoteCaller { hostCommandsSender }.remoteCallWithReply (customDecode, kGetFactoryMessageID, index); -std::vector _proxyFactories {}; + const auto result { _factories.insert (std::make_pair (remoteFactory._strings.factoryID, remoteFactory)) }; + if (result.second) + { + result.first->second._factory.factoryID = result.first->second._strings.factoryID.c_str (); -size_t ARAIPCProxyPlugInInitializeFactories (ARAIPCMessageSender hostCommandsSender) -{ - size_t count; - RemoteCaller { hostCommandsSender }.remoteCallWithReply (count, kGetFactoriesCountMessageID); - ARA_INTERNAL_ASSERT (count > 0); + result.first->second._factory.factoryID = result.first->second._strings.factoryID.c_str (); + result.first->second._factory.plugInName = result.first->second._strings.plugInName.c_str (); + result.first->second._factory.manufacturerName = result.first->second._strings.manufacturerName.c_str (); + result.first->second._factory.informationURL = result.first->second._strings.informationURL.c_str (); + result.first->second._factory.version = result.first->second._strings.version.c_str (); - _proxyFactories.reserve (count); - for (auto i { 0U }; i < count; ++i) - _proxyFactories.emplace_back (hostCommandsSender, i); - return _proxyFactories.size (); -} + result.first->second._factory.documentArchiveID = result.first->second._strings.documentArchiveID.c_str (); -ARAIPCProxyPlugInFactory* ARAIPCProxyPlugInGetFactoryAtIndex (size_t index) -{ - ARA_INTERNAL_ASSERT (index < _proxyFactories.size ()); - return &_proxyFactories[index]; -} + for (auto i { 0U }; i < result.first->second._compatibleIDStrings.size (); ++i) + result.first->second._compatibleIDs[i] = result.first->second._compatibleIDStrings[i].c_str (); + result.first->second._factory.compatibleDocumentArchiveIDs = result.first->second._compatibleIDs.data (); -const ARAFactory* ARAIPCProxyPlugInGetFactoryData (ARAIPCProxyPlugInFactory* proxyFactory) -{ - return proxyFactory->getFactory (); + result.first->second._factory.analyzeableContentTypes = result.first->second._analyzableTypes.data (); + } + return &result.first->second._factory; } -const ARADocumentControllerInstance* ARAIPCProxyPlugInCreateDocumentControllerWithDocument (ARAIPCProxyPlugInFactory* proxyFactory, +const ARADocumentControllerInstance* ARAIPCProxyPlugInCreateDocumentControllerWithDocument ( + ARAIPCMessageSender hostCommandsSender, const ARAPersistentID factoryID, const ARADocumentControllerHostInstance* hostInstance, const ARADocumentProperties* properties) { - auto result { new DocumentController { proxyFactory->getHostCommandsSender (), proxyFactory->getFactory (), hostInstance, properties} }; + const auto cached { _factories.find (std::string { factoryID }) }; + ARA_INTERNAL_ASSERT (cached != _factories.end ()); + if (cached == _factories.end ()) + return nullptr; + + auto result { new DocumentController { hostCommandsSender, &cached->second._factory, hostInstance, properties} }; return result->getInstance (); } diff --git a/IPC/ARAIPCProxyPlugIn.h b/IPC/ARAIPCProxyPlugIn.h index a2c0de2..80ab224 100644 --- a/IPC/ARAIPCProxyPlugIn.h +++ b/IPC/ARAIPCProxyPlugIn.h @@ -32,20 +32,16 @@ extern "C" { #endif -typedef struct ARAIPCProxyPlugInFactory ARAIPCProxyPlugInFactory; +//! counts the factories available through the message channel the sender is accessing +size_t ARAIPCProxyPlugInGetFactoriesCount(ARAIPCMessageSender hostCommandsSender); - -//! static initialization -size_t ARAIPCProxyPlugInInitializeFactories(ARAIPCMessageSender hostCommandsSender); - -//! access proxies to the factories provided by the remote plug-in -ARAIPCProxyPlugInFactory * ARAIPCProxyPlugInGetFactoryAtIndex(size_t index); - -//! get copy of the remote factory data, with all function calls removed -const ARAFactory * ARAIPCProxyPlugInGetFactoryData(ARAIPCProxyPlugInFactory * proxyFactory); +//! get a static copy of the remote factory data, with all function calls removed +//! index must be smaller than the result of ARAIPCProxyPlugInGetFactoriesCount() +const ARAFactory * ARAIPCProxyPlugInGetFactoryAtIndex(ARAIPCMessageSender hostCommandsSender, size_t index); //! proxy document controller creation call, to be used instead of ARAFactory.createDocumentControllerWithDocument() -const ARADocumentControllerInstance * ARAIPCProxyPlugInCreateDocumentControllerWithDocument(ARAIPCProxyPlugInFactory * proxyFactory, +const ARADocumentControllerInstance * ARAIPCProxyPlugInCreateDocumentControllerWithDocument(ARAIPCMessageSender hostCommandsSender, + const ARAPersistentID factoryID, const ARADocumentControllerHostInstance * hostInstance, const ARADocumentProperties * properties); From e2bd4830e3438e5db657fc7efac39e7918d8984e Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:31:59 +0100 Subject: [PATCH 08/18] Move CF-based IPC en/decoding from ARA_Examples to ARA_Library --- CMakeLists.txt | 7 + IPC/ARAIPCCFEncoding.cpp | 376 +++++++++++++++++++++++++++++++++++++++ IPC/ARAIPCCFEncoding.h | 52 ++++++ 3 files changed, 435 insertions(+) create mode 100644 IPC/ARAIPCCFEncoding.cpp create mode 100644 IPC/ARAIPCCFEncoding.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e88ac46..d076bd6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,6 +179,13 @@ add_library(ARA_IPC_Library ${ARA_LIBRARY_TARGET_TYPE} "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCProxyHost.cpp" ) +if(APPLE) + target_sources(ARA_IPC_Library PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCCFEncoding.h" + "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCCFEncoding.cpp" + ) +endif() + target_link_libraries(ARA_IPC_Library PRIVATE ARA_Host_Library ARA_PlugIn_Library diff --git a/IPC/ARAIPCCFEncoding.cpp b/IPC/ARAIPCCFEncoding.cpp new file mode 100644 index 0000000..b73600d --- /dev/null +++ b/IPC/ARAIPCCFEncoding.cpp @@ -0,0 +1,376 @@ +//------------------------------------------------------------------------------ +//! \file ARAIPCCFEncoding.cpp +//! Implementation of ARAIPCMessageEn-/Decoder backed by CF(Mutable)Dictionary +//! \project ARA SDK Examples +//! \copyright Copyright (c) 2021-2022, Celemony Software GmbH, All Rights Reserved. +//! \license Licensed under the Apache License, Version 2.0 (the "License"); +//! you may not use this file except in compliance with the License. +//! You may obtain a copy of the License at +//! +//! http://www.apache.org/licenses/LICENSE-2.0 +//! +//! Unless required by applicable law or agreed to in writing, software +//! distributed under the License is distributed on an "AS IS" BASIS, +//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//! See the License for the specific language governing permissions and +//! limitations under the License. +//------------------------------------------------------------------------------ + +#include "ARAIPCCFEncoding.h" + + +#if ARA_ENABLE_IPC && defined (__APPLE__) + + +#include "ARA_Library/Debug/ARADebug.h" + +#include +#include +#include + + +namespace ARA { +namespace IPC { +extern "C" { + + +#if defined (__GNUC__) + _Pragma ("GCC diagnostic push") + _Pragma ("GCC diagnostic ignored \"-Wold-style-cast\"") +#endif + + + +class _CFReleaser +{ +public: + explicit _CFReleaser (CFStringRef ref) : _ref { ref } {} + _CFReleaser (const _CFReleaser& other) { _ref = (CFStringRef) CFRetain (other._ref); } + _CFReleaser (_CFReleaser&& other) { _ref = other._ref; other._ref = CFStringRef {}; } + ~_CFReleaser () { CFRelease (_ref); } + operator CFStringRef () { return _ref; } +private: + CFStringRef _ref; +}; + + + +// wrap key value into CFString (no reference count transferred to caller) +CFStringRef ARA_CALL ARAIPCCFMessageGetEncodedKey (ARAIPCMessageKey argKey) +{ + ARA_INTERNAL_ASSERT (argKey >= 0); + // \todo All plist formats available for CFPropertyListCreateData () in createEncodedMessage () need CFString keys. + // Once we switch to the more modern (NS)XPC API we shall be able to use CFNumber keys directly... + static std::map cache; + auto existingEntry { cache.find (argKey) }; + if (existingEntry != cache.end ()) + return existingEntry->second; + return cache.emplace (argKey, CFStringCreateWithCString (kCFAllocatorDefault, std::to_string (argKey).c_str (), kCFStringEncodingUTF8)).first->second; +} + + + +inline ARAIPCMessageEncoderRef ARAIPCCFMessageToEncoderRef (CFMutableDictionaryRef dictionary) +{ + return (ARAIPCMessageEncoderRef) dictionary; +} + +inline CFMutableDictionaryRef ARAIPCCFMessageFromEncoderRef (ARAIPCMessageEncoderRef messageEncoderRef) +{ + return (CFMutableDictionaryRef) messageEncoderRef; +} + +void ARA_CALL ARAIPCCFMessageDestroyEncoder (ARAIPCMessageEncoderRef messageEncoderRef) +{ + if (messageEncoderRef) + CFRelease (ARAIPCCFMessageFromEncoderRef (messageEncoderRef)); +} + +void ARA_CALL ARAIPCCFMessageAppendInt32 (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey, int32_t argValue) +{ + auto argObject { CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &argValue) }; + CFDictionarySetValue (ARAIPCCFMessageFromEncoderRef (messageEncoderRef), ARAIPCCFMessageGetEncodedKey (argKey), argObject); + CFRelease (argObject); +} + +void ARA_CALL ARAIPCCFMessageAppendInt64 (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey, int64_t argValue) +{ + auto argObject { CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &argValue) }; + CFDictionarySetValue (ARAIPCCFMessageFromEncoderRef (messageEncoderRef), ARAIPCCFMessageGetEncodedKey (argKey), argObject); + CFRelease (argObject); +} + +void ARA_CALL ARAIPCCFMessageAppendSize (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey, size_t argValue) +{ + static_assert (sizeof (SInt64) == sizeof (size_t), "integer type needs adjustment for this compiler setup"); + + auto argObject { CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &argValue) }; + CFDictionarySetValue (ARAIPCCFMessageFromEncoderRef (messageEncoderRef), ARAIPCCFMessageGetEncodedKey (argKey), argObject); + CFRelease (argObject); +} + +void ARA_CALL ARAIPCCFMessageAppendFloat (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey, float argValue) +{ + auto argObject { CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &argValue) }; + CFDictionarySetValue (ARAIPCCFMessageFromEncoderRef (messageEncoderRef), ARAIPCCFMessageGetEncodedKey (argKey), argObject); + CFRelease (argObject); +} + +void ARA_CALL ARAIPCCFMessageAppendDouble (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey, double argValue) +{ + auto argObject { CFNumberCreate (kCFAllocatorDefault, kCFNumberDoubleType, &argValue) }; + CFDictionarySetValue (ARAIPCCFMessageFromEncoderRef (messageEncoderRef), ARAIPCCFMessageGetEncodedKey (argKey), argObject); + CFRelease (argObject); +} + +void ARA_CALL ARAIPCCFMessageAppendString (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey, const char* argValue) +{ + auto argObject { CFStringCreateWithCString (kCFAllocatorDefault, argValue, kCFStringEncodingUTF8) }; + CFDictionarySetValue (ARAIPCCFMessageFromEncoderRef (messageEncoderRef), ARAIPCCFMessageGetEncodedKey (argKey), argObject); + CFRelease (argObject); +} + +void ARA_CALL ARAIPCCFMessageAppendBytes (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey, const uint8_t* argValue, size_t argSize, bool copy) +{ + CFDataRef argObject; + if (copy) + argObject = CFDataCreate (kCFAllocatorDefault, argValue, (CFIndex) argSize); + else + argObject = CFDataCreateWithBytesNoCopy (kCFAllocatorDefault, argValue, (CFIndex) argSize, kCFAllocatorNull); + CFDictionarySetValue (ARAIPCCFMessageFromEncoderRef (messageEncoderRef), ARAIPCCFMessageGetEncodedKey (argKey), argObject); + CFRelease (argObject); +} + +ARAIPCMessageEncoderRef ARA_CALL ARAIPCCFMessageAppendSubMessage (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageKey argKey) +{ + auto argObject { CFDictionaryCreateMutable (kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) }; + CFDictionarySetValue (ARAIPCCFMessageFromEncoderRef (messageEncoderRef), ARAIPCCFMessageGetEncodedKey (argKey), argObject); + return (ARAIPCMessageEncoderRef) argObject; +} + +ARAIPCMessageEncoder ARAIPCCFCreateMessageEncoder (void) +{ + static const ARA::IPC::ARAIPCMessageEncoderInterface encoderMethods + { + ARAIPCCFMessageDestroyEncoder, + ARAIPCCFMessageAppendInt32, + ARAIPCCFMessageAppendInt64, + ARAIPCCFMessageAppendSize, + ARAIPCCFMessageAppendFloat, + ARAIPCCFMessageAppendDouble, + ARAIPCCFMessageAppendString, + ARAIPCCFMessageAppendBytes, + ARAIPCCFMessageAppendSubMessage + }; + + return { ARAIPCCFMessageToEncoderRef (CFDictionaryCreateMutable (kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)), &encoderMethods }; +} + +__attribute__((cf_returns_retained)) CFDataRef ARAIPCCFCreateMessageEncoderData (ARAIPCMessageEncoderRef messageEncoderRef) +{ + const auto dictionary { ARAIPCCFMessageFromEncoderRef (messageEncoderRef) }; + if ((!dictionary) || (CFDictionaryGetCount (dictionary) == 0)) + return nullptr; + return CFPropertyListCreateData (kCFAllocatorDefault, dictionary, kCFPropertyListBinaryFormat_v1_0, 0, nullptr); +} + + + +inline ARAIPCMessageDecoderRef ARAIPCCFMessageToDecoderRef (CFDictionaryRef dictionary) +{ + return (ARAIPCMessageDecoderRef) dictionary; +} + +inline CFDictionaryRef ARAIPCCFMessageFromDecoderRef (ARAIPCMessageDecoderRef messageDecoderRef) +{ + return (CFDictionaryRef) messageDecoderRef; +} + +void ARA_CALL ARAIPCCFMessageDestroyDecoder (ARAIPCMessageDecoderRef messageDecoderRef) +{ + if (messageDecoderRef) + CFRelease (ARAIPCCFMessageFromDecoderRef (messageDecoderRef)); +} + +bool ARA_CALL ARAIPCCFMessageIsEmpty (ARAIPCMessageDecoderRef messageDecoderRef) +{ + return (!messageDecoderRef) || (CFDictionaryGetCount (ARAIPCCFMessageFromDecoderRef (messageDecoderRef)) == 0); +} + +bool ARA_CALL ARAIPCCFMessageReadInt32 (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, int32_t* argValue) +{ + CFNumberRef number {}; + if (messageDecoderRef) + number = (CFNumberRef) CFDictionaryGetValue (ARAIPCCFMessageFromDecoderRef (messageDecoderRef), ARAIPCCFMessageGetEncodedKey (argKey)); + if (!number) + { + *argValue = 0; + return false; + } + ARA_INTERNAL_ASSERT (CFGetTypeID (number) == CFNumberGetTypeID ()); + CFNumberGetValue (number, kCFNumberSInt32Type, argValue); + return true; +} + +bool ARA_CALL ARAIPCCFMessageReadInt64 (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, int64_t* argValue) +{ + CFNumberRef number {}; + if (messageDecoderRef) + number = (CFNumberRef) CFDictionaryGetValue (ARAIPCCFMessageFromDecoderRef (messageDecoderRef), ARAIPCCFMessageGetEncodedKey (argKey)); + if (!number) + { + *argValue = 0; + return false; + } + ARA_INTERNAL_ASSERT (CFGetTypeID (number) == CFNumberGetTypeID ()); + CFNumberGetValue (number, kCFNumberSInt64Type, argValue); + return true; +} + +bool ARA_CALL ARAIPCCFMessageReadSize (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, size_t* argValue) +{ + static_assert (sizeof (SInt64) == sizeof (size_t), "integer type needs adjustment for this compiler setup"); + + CFNumberRef number {}; + if (messageDecoderRef) + number = (CFNumberRef) CFDictionaryGetValue (ARAIPCCFMessageFromDecoderRef (messageDecoderRef), ARAIPCCFMessageGetEncodedKey (argKey)); + if (!number) + { + *argValue = 0; + return false; + } + ARA_INTERNAL_ASSERT (CFGetTypeID (number) == CFNumberGetTypeID ()); + CFNumberGetValue (number, kCFNumberSInt64Type, argValue); + return true; +} + +bool ARA_CALL ARAIPCCFMessageReadFloat (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, float* argValue) +{ + CFNumberRef number {}; + if (messageDecoderRef) + number = (CFNumberRef) CFDictionaryGetValue (ARAIPCCFMessageFromDecoderRef (messageDecoderRef), ARAIPCCFMessageGetEncodedKey (argKey)); + if (!number) + { + *argValue = 0.0f; + return false; + } + ARA_INTERNAL_ASSERT (CFGetTypeID (number) == CFNumberGetTypeID ()); + CFNumberGetValue (number, kCFNumberFloatType, argValue); + return true; +} + +bool ARA_CALL ARAIPCCFMessageReadDouble (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, double* argValue) +{ + CFNumberRef number {}; + if (messageDecoderRef) + number = (CFNumberRef) CFDictionaryGetValue (ARAIPCCFMessageFromDecoderRef (messageDecoderRef), ARAIPCCFMessageGetEncodedKey (argKey)); + if (!number) + { + *argValue = 0.0; + return false; + } + ARA_INTERNAL_ASSERT (CFGetTypeID (number) == CFNumberGetTypeID ()); + CFNumberGetValue (number, kCFNumberDoubleType, argValue); + return true; +} + +bool ARA_CALL ARAIPCCFMessageReadString (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, const char** argValue) +{ + CFStringRef string {}; + if (messageDecoderRef) + string = (CFStringRef) CFDictionaryGetValue (ARAIPCCFMessageFromDecoderRef (messageDecoderRef), ARAIPCCFMessageGetEncodedKey (argKey)); + if (!string) + { + *argValue = nullptr; + return false; + } + ARA_INTERNAL_ASSERT (string && (CFGetTypeID (string) == CFStringGetTypeID ())); + *argValue = CFStringGetCStringPtr (string, kCFStringEncodingUTF8); + if (!*argValue) // CFStringGetCStringPtr() may fail e.g. with chord names like "G/D" + { + const auto length { CFStringGetLength (string) }; + std::string temp; // \todo does not work: { static_cast (length), char { 0 } }; + temp.assign ( static_cast (length) , char { 0 } ); + CFIndex ARA_MAYBE_UNUSED_VAR (count) { CFStringGetBytes (string, CFRangeMake (0, length), kCFStringEncodingUTF8, 0, false, (UInt8*)(&temp[0]), length, nullptr) }; + ARA_INTERNAL_ASSERT (count == length); + static std::set strings; // \todo static cache of "undecodeable" strings requires single-threaded use - maybe make iVar instead? + strings.insert (temp); + *argValue = strings.find (temp)->c_str (); + } + return true; +} + +bool ARA_CALL ARAIPCCFMessageReadBytesSize (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, size_t* argSize) +{ + CFDataRef bytes {}; + if (messageDecoderRef) + bytes = (CFDataRef) CFDictionaryGetValue (ARAIPCCFMessageFromDecoderRef (messageDecoderRef), ARAIPCCFMessageGetEncodedKey (argKey)); + if (!bytes) + { + *argSize = 0; + return false; + } + ARA_INTERNAL_ASSERT (bytes && (CFGetTypeID (bytes) == CFDataGetTypeID ())); + *argSize = (size_t) CFDataGetLength (bytes); + return true; + +} + +void ARA_CALL ARAIPCCFMessageReadBytes (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey, uint8_t* argValue) +{ + ARA_INTERNAL_ASSERT (messageDecoderRef); + auto bytes { (CFDataRef) CFDictionaryGetValue (ARAIPCCFMessageFromDecoderRef (messageDecoderRef), ARAIPCCFMessageGetEncodedKey (argKey)) }; + ARA_INTERNAL_ASSERT (bytes && (CFGetTypeID (bytes) == CFDataGetTypeID ())); + const auto length { CFDataGetLength (bytes) }; + CFDataGetBytes (bytes, CFRangeMake (0, length), argValue); +} + +ARAIPCMessageDecoderRef ARA_CALL ARAIPCCFMessageReadSubMessage (ARAIPCMessageDecoderRef messageDecoderRef, ARAIPCMessageKey argKey) +{ + auto dictionary { (CFDictionaryRef) CFDictionaryGetValue (ARAIPCCFMessageFromDecoderRef (messageDecoderRef), ARAIPCCFMessageGetEncodedKey (argKey)) }; + ARA_INTERNAL_ASSERT (!dictionary || (CFGetTypeID (dictionary) == CFDictionaryGetTypeID ())); + if (dictionary) + CFRetain (dictionary); + return ARAIPCCFMessageToDecoderRef (dictionary); +} + +ARAIPCMessageDecoder ARAIPCCFCreateMessageDecoder (CFDataRef messageData) +{ + static const ARA::IPC::ARAIPCMessageDecoderInterface decoderMethods + { + ARAIPCCFMessageDestroyDecoder, + ARAIPCCFMessageIsEmpty, + ARAIPCCFMessageReadInt32, + ARAIPCCFMessageReadInt64, + ARAIPCCFMessageReadSize, + ARAIPCCFMessageReadFloat, + ARAIPCCFMessageReadDouble, + ARAIPCCFMessageReadString, + ARAIPCCFMessageReadBytesSize, + ARAIPCCFMessageReadBytes, + ARAIPCCFMessageReadSubMessage + }; + + if (CFDataGetLength (messageData) == 0) + return { nullptr, &decoderMethods }; + auto dictionary { (CFDictionaryRef) CFPropertyListCreateWithData (kCFAllocatorDefault, messageData, kCFPropertyListImmutable, nullptr, nullptr) }; + ARA_INTERNAL_ASSERT (dictionary && (CFGetTypeID (dictionary) == CFDictionaryGetTypeID ())); +#if defined (__clang_analyzer__) + // \todo hotfix to silence the analyzer: it does not know that ARAIPCMessageDecoder + // is supposed to store the retained value and release upon destruction - + // what would be the proper annotation here? + CFRelease (dictionary); +#endif + return { ARAIPCCFMessageToDecoderRef (dictionary), &decoderMethods }; +} + + +#if defined (__APPLE__) + _Pragma ("GCC diagnostic pop") +#endif + +} // extern "C" +} // namespace IPC +} // namespace ARA + +#endif // ARA_ENABLE_IPC && defined (__APPLE__) diff --git a/IPC/ARAIPCCFEncoding.h b/IPC/ARAIPCCFEncoding.h new file mode 100644 index 0000000..3d7188e --- /dev/null +++ b/IPC/ARAIPCCFEncoding.h @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +//! \file ARAIPCCFEncoding.h +//! Implementation of ARAIPCMessageEn-/Decoder backed by CF(Mutable)Dictionary +//! \project ARA SDK Examples +//! \copyright Copyright (c) 2021-2022, Celemony Software GmbH, All Rights Reserved. +//! \license Licensed under the Apache License, Version 2.0 (the "License"); +//! you may not use this file except in compliance with the License. +//! You may obtain a copy of the License at +//! +//! http://www.apache.org/licenses/LICENSE-2.0 +//! +//! Unless required by applicable law or agreed to in writing, software +//! distributed under the License is distributed on an "AS IS" BASIS, +//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//! See the License for the specific language governing permissions and +//! limitations under the License. +//------------------------------------------------------------------------------ + +#ifndef ARAIPCCFEncoding_h +#define ARAIPCCFEncoding_h + +#include "ARA_Library/IPC/ARAIPC.h" + + +#if ARA_ENABLE_IPC && defined(__APPLE__) + +#include + + +#if defined(__cplusplus) +namespace ARA { +namespace IPC { +extern "C" { +#endif + + +ARAIPCMessageEncoder ARAIPCCFCreateMessageEncoder(void); +__attribute__((cf_returns_retained)) CFDataRef ARAIPCCFCreateMessageEncoderData(ARAIPCMessageEncoderRef messageEncoderRef); + +ARAIPCMessageDecoder ARAIPCCFCreateMessageDecoder(CFDataRef messageData); + + +#if defined(__cplusplus) +} // extern "C" +} // namespace IPC +} // namespace ARA +#endif + + +#endif // ARA_ENABLE_IPC && defined(__APPLE__) + +#endif // ARAIPCCFEncoding_h From cf4546081fbf72bf28ffa988c63bf4307a0bc1b0 Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:31:59 +0100 Subject: [PATCH 09/18] Make locks in IPC context-dependent to allow for stacked messages (e.g. direct content reading from update notifications) --- CMakeLists.txt | 2 + IPC/ARAIPC.h | 4 +- IPC/ARAIPCEncoding.h | 12 ++-- IPC/ARAIPCLockingContext.cpp | 99 +++++++++++++++++++++++++++++ IPC/ARAIPCLockingContext.h | 95 +++++++++++++++++++++++++++ IPC/ARAIPCProxyHost.cpp | 54 ++++++++-------- IPC/ARAIPCProxyPlugIn.cpp | 120 +++++++++++++++++------------------ 7 files changed, 291 insertions(+), 95 deletions(-) create mode 100644 IPC/ARAIPCLockingContext.cpp create mode 100644 IPC/ARAIPCLockingContext.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d076bd6..dff3d04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,6 +171,8 @@ configure_ARA_Library_target(ARA_PlugIn_Library) add_library(ARA_IPC_Library ${ARA_LIBRARY_TARGET_TYPE} "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPC.h" "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCEncoding.h" + "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCLockingContext.h" + "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCLockingContext.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCProxyHost.h" "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCProxyHost.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCProxyPlugIn.h" diff --git a/IPC/ARAIPC.h b/IPC/ARAIPC.h index 7cc69da..0c1cbd9 100644 --- a/IPC/ARAIPC.h +++ b/IPC/ARAIPC.h @@ -178,8 +178,8 @@ typedef struct ARAIPCMessageSenderInterface //! send function: send message create using the encoder, blocking until a reply has been received. //! If an empty reply ("void") is expected, the replyHandler should be nullptr. //! A send function can be called from any thread, but not concurrently. - void (ARA_CALL *sendMessage) (ARAIPCMessageSenderRef messageSenderRef, ARAIPCMessageID messageID, const ARAIPCMessageEncoder * encoder, - ARAIPCReplyHandler * const replyHandler, void * replyHandlerUserData); + void (ARA_CALL *sendMessage) (const bool stackable, ARAIPCMessageSenderRef messageSenderRef, ARAIPCMessageID messageID, + const ARAIPCMessageEncoder * encoder, ARAIPCReplyHandler * const replyHandler, void * replyHandlerUserData); //! Test if the receiver runs on a different architecture with different endianess. bool (ARA_CALL *receiverEndianessMatches) (ARAIPCMessageSenderRef messageSenderRef); diff --git a/IPC/ARAIPCEncoding.h b/IPC/ARAIPCEncoding.h index 526bf79..218bf79 100644 --- a/IPC/ARAIPCEncoding.h +++ b/IPC/ARAIPCEncoding.h @@ -1158,16 +1158,16 @@ class RemoteCaller RemoteCaller (ARAIPCMessageSender sender) noexcept : _sender { sender } {} template - void remoteCallWithoutReply (const ARAIPCMessageID messageID, const Args &... args) + void remoteCallWithoutReply (const bool stackable, const ARAIPCMessageID messageID, const Args &... args) { auto encoder { _sender.methods->createEncoder (_sender.ref) }; encodeArguments (encoder, args...); - _sender.methods->sendMessage (_sender.ref, messageID, &encoder, nullptr, nullptr); + _sender.methods->sendMessage (stackable, _sender.ref, messageID, &encoder, nullptr, nullptr); encoder.methods->destroyEncoder (encoder.ref); } template - void remoteCallWithReply (RetT& result, const ARAIPCMessageID messageID, const Args &... args) + void remoteCallWithReply (RetT& result, const bool stackable, const ARAIPCMessageID messageID, const Args &... args) { auto encoder { _sender.methods->createEncoder (_sender.ref) }; encodeArguments (encoder, args...); @@ -1176,11 +1176,11 @@ class RemoteCaller ARA_INTERNAL_ASSERT (!decoder.methods->isEmpty (decoder.ref)); decodeReply (*reinterpret_cast (userData), decoder); } }; - _sender.methods->sendMessage (_sender.ref, messageID, &encoder, &replyHandler, &result); + _sender.methods->sendMessage (stackable, _sender.ref, messageID, &encoder, &replyHandler, &result); encoder.methods->destroyEncoder (encoder.ref); } template - void remoteCallWithReply (CustomDecodeFunction& decodeFunction, const ARAIPCMessageID messageID, const Args &... args) + void remoteCallWithReply (CustomDecodeFunction& decodeFunction, const bool stackable, const ARAIPCMessageID messageID, const Args &... args) { auto encoder { _sender.methods->createEncoder (_sender.ref) }; encodeArguments (encoder, args...); @@ -1189,7 +1189,7 @@ class RemoteCaller ARA_INTERNAL_ASSERT (!decoder.methods->isEmpty (decoder.ref)); (*reinterpret_cast (userData)) (decoder); } }; - _sender.methods->sendMessage (_sender.ref, messageID, &encoder, &replyHandler, &decodeFunction); + _sender.methods->sendMessage (stackable, _sender.ref, messageID, &encoder, &replyHandler, &decodeFunction); encoder.methods->destroyEncoder (encoder.ref); } diff --git a/IPC/ARAIPCLockingContext.cpp b/IPC/ARAIPCLockingContext.cpp new file mode 100644 index 0000000..e874496 --- /dev/null +++ b/IPC/ARAIPCLockingContext.cpp @@ -0,0 +1,99 @@ +//------------------------------------------------------------------------------ +//! \file ARAIPCLockingContext.cpp +//! Implementation of locking IPC access to make it appear single-threaded +//! \project ARA SDK Examples +//! \copyright Copyright (c) 2021-2022, Celemony Software GmbH, All Rights Reserved. +//! \license Licensed under the Apache License, Version 2.0 (the "License"); +//! you may not use this file except in compliance with the License. +//! You may obtain a copy of the License at +//! +//! http://www.apache.org/licenses/LICENSE-2.0 +//! +//! Unless required by applicable law or agreed to in writing, software +//! distributed under the License is distributed on an "AS IS" BASIS, +//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//! See the License for the specific language governing permissions and +//! limitations under the License. +//------------------------------------------------------------------------------ + +#include "ARAIPCLockingContext.h" + + +#if ARA_ENABLE_IPC + + +#include "ARA_Library/Debug/ARADebug.h" + +#include +#include + + +namespace ARA { +namespace IPC { +extern "C" { + + +struct ARAIPCLockingContextImplementation +{ + std::mutex sendMutex {}; + std::mutex handleMutex {}; + bool sendIsStackable {}; +}; + + +thread_local ARAIPCLockingContextRef _currentHandlingLockingContextRef {}; + + +ARAIPCLockingContextRef ARA_CALL ARAIPCCreateLockingContext (void) +{ + return new ARAIPCLockingContextImplementation; +} + +void ARA_CALL ARAIPCDestroyLockingContext (ARAIPCLockingContextRef lockingContextRef) +{ + delete lockingContextRef; +} + +ARAIPCLockingContextMessageSendingToken ARA_CALL ARAIPCLockContextBeforeSendingMessage (ARAIPCLockingContextRef lockingContextRef, bool stackable) +{ + const auto useLock { !lockingContextRef->sendIsStackable || (_currentHandlingLockingContextRef != lockingContextRef) }; + if (useLock) + { + lockingContextRef->sendMutex.lock (); + lockingContextRef->sendIsStackable = stackable; + } + return useLock; +} + +void ARA_CALL ARAIPCUnlockContextAfterSendingMessage (ARAIPCLockingContextRef lockingContextRef, ARAIPCLockingContextMessageSendingToken lockToken) +{ + if (lockToken) + { + lockingContextRef->sendIsStackable = false; + lockingContextRef->sendMutex.unlock (); + } +} + +ARAIPCLockingContextMessageHandlingToken ARA_CALL ARAIPCLockContextBeforeHandlingMessage (ARAIPCLockingContextRef lockingContextRef) +{ + if (_currentHandlingLockingContextRef != lockingContextRef) + lockingContextRef->handleMutex.lock (); + const auto result { _currentHandlingLockingContextRef }; + _currentHandlingLockingContextRef = lockingContextRef; + return result; +} + +void ARA_CALL ARAIPCUnlockContextAfterHandlingMessage (ARAIPCLockingContextRef lockingContextRef, ARAIPCLockingContextMessageHandlingToken lockToken) +{ + ARA_INTERNAL_ASSERT (_currentHandlingLockingContextRef == lockingContextRef); + if (lockingContextRef != lockToken) + lockingContextRef->handleMutex.unlock (); + _currentHandlingLockingContextRef = lockToken; +} + + +} // extern "C" +} // namespace IPC +} // namespace ARA + +#endif // ARA_ENABLE_IPC diff --git a/IPC/ARAIPCLockingContext.h b/IPC/ARAIPCLockingContext.h new file mode 100644 index 0000000..79efa4b --- /dev/null +++ b/IPC/ARAIPCLockingContext.h @@ -0,0 +1,95 @@ +//------------------------------------------------------------------------------ +//! \file ARAIPCLockingContext.h +//! Implementation of locking IPC access to make it appear single-threaded +//! \project ARA SDK Examples +//! \copyright Copyright (c) 2021-2022, Celemony Software GmbH, All Rights Reserved. +//! \license Licensed under the Apache License, Version 2.0 (the "License"); +//! you may not use this file except in compliance with the License. +//! You may obtain a copy of the License at +//! +//! http://www.apache.org/licenses/LICENSE-2.0 +//! +//! Unless required by applicable law or agreed to in writing, software +//! distributed under the License is distributed on an "AS IS" BASIS, +//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//! See the License for the specific language governing permissions and +//! limitations under the License. +//------------------------------------------------------------------------------ + +#ifndef ARAIPCLockingContext_h +#define ARAIPCLockingContext_h + + +#include "ARA_Library/IPC/ARAIPC.h" + + +//! @addtogroup ARA_Library_IPC +//! @{ + +#if ARA_ENABLE_IPC + + +#if defined(__cplusplus) +namespace ARA { +namespace IPC { +extern "C" { +#endif + +//! Locking Context +//! The underlying IPC implementation must channel several threads through one or more single-threaded +//! IPC channel, requiring proper locking. At the same time, sending and receiving messages may be +//! distributed across different threads, and may be stacked, so proper locking depends on the specific +//! calls - for example, the host might call ARADocumentControllerInterface::notifyModelUpdates(), +//! causing the plug-in to respond with ARAModelUpdateControllerInterface.notifyAudioSourceContentChanged(), +//! which in turn triggers a host call to ARADocumentControllerInterface::isAudioSourceContentAvailable() etc. +//! At the same time, the host may make render calls through the Companion API and another thread in +//! the plug-in might be call ARAAudioAccessControllerInterface::readAudioSamples(). +//! To handle this properly, the locking strategy is separated into this LockingContext class. +//! All communication that interacts in the non-IPC ARA world must use the same locking context, +//! i.e. all calls to/from a given document controller and all plug-in extensions bound to it. +//! \todo Are all Companion API calls independent of ARA, or might there be the need in certain +//! situations to also lock around some Companion API calls? +//! \todo It is possible for a LockingContext instance to be used across several communication +//! channels if the IPC is distributed accordingly. +//! @{ + +//! opaque token representing an instance of a LockingContext +typedef struct ARAIPCLockingContextImplementation * ARAIPCLockingContextRef; + +//! creation and destruction of LockingContext instances +//@{ +ARAIPCLockingContextRef ARA_CALL ARAIPCCreateLockingContext (void); +void ARA_CALL ARAIPCDestroyLockingContext (ARAIPCLockingContextRef lockingContextRef); +//@} + +//! locking around sending a message through the associated IPC channel(s) +//! The opaque token returned by the locking call must be passed on to the unlocking call. +//@{ +typedef bool ARAIPCLockingContextMessageSendingToken; +ARAIPCLockingContextMessageSendingToken ARA_CALL ARAIPCLockContextBeforeSendingMessage (ARAIPCLockingContextRef lockingContextRef, bool stackable); +void ARA_CALL ARAIPCUnlockContextAfterSendingMessage (ARAIPCLockingContextRef lockingContextRef, ARAIPCLockingContextMessageSendingToken lockToken); +//@} + +//! locking around handling a message received through the associated IPC channel(s) +//! The opaque token returned by the locking call must be passed on to the unlocking call. +//@{ +typedef ARAIPCLockingContextRef ARAIPCLockingContextMessageHandlingToken; +ARAIPCLockingContextMessageHandlingToken ARA_CALL ARAIPCLockContextBeforeHandlingMessage (ARAIPCLockingContextRef lockingContextRef); +void ARA_CALL ARAIPCUnlockContextAfterHandlingMessage (ARAIPCLockingContextRef lockingContextRef, ARAIPCLockingContextMessageHandlingToken lockToken); +//@} + +//! @} + + +#if defined(__cplusplus) +} // extern "C" +} // namespace IPC +} // namespace ARA +#endif + + +#endif // ARA_ENABLE_IPC + +//! @} ARA_Library_IPC + +#endif // ARAIPCLockingContext_h diff --git a/IPC/ARAIPCProxyHost.cpp b/IPC/ARAIPCProxyHost.cpp index ae1a61c..45d8117 100644 --- a/IPC/ARAIPCProxyHost.cpp +++ b/IPC/ARAIPCProxyHost.cpp @@ -147,7 +147,7 @@ ARAAudioReaderHostRef AudioAccessController::createAudioReaderForSource (ARAAudi remoteAudioReader->swapFunction = nullptr; else remoteAudioReader->swapFunction = (use64BitSamples) ? &_swapBuffer : &_swapBuffer; - remoteCallWithReply (remoteAudioReader->mainHostRef, ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, createAudioReaderForSource), _remoteHostRef, remoteAudioReader->audioSource->mainHostRef, use64BitSamples); + remoteCallWithReply (remoteAudioReader->mainHostRef, false, ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, createAudioReaderForSource), _remoteHostRef, remoteAudioReader->audioSource->mainHostRef, use64BitSamples); return toHostRef (remoteAudioReader); } @@ -216,7 +216,7 @@ bool AudioAccessController::readAudioSamples (ARAAudioReaderHostRef audioReaderH } } }; - remoteCallWithReply (customDecode, ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, readAudioSamples), + remoteCallWithReply (customDecode, false, ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, readAudioSamples), _remoteHostRef, remoteAudioReader->mainHostRef, samplePosition, samplesPerChannel); return success; } @@ -224,7 +224,7 @@ bool AudioAccessController::readAudioSamples (ARAAudioReaderHostRef audioReaderH void AudioAccessController::destroyAudioReader (ARAAudioReaderHostRef audioReaderHostRef) noexcept { auto remoteAudioReader { fromHostRef (audioReaderHostRef) }; - remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, destroyAudioReader), _remoteHostRef, remoteAudioReader->mainHostRef); + remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, destroyAudioReader), _remoteHostRef, remoteAudioReader->mainHostRef); delete remoteAudioReader; } @@ -254,7 +254,7 @@ class ArchivingController : public Host::ArchivingControllerInterface, public Re ARASize ArchivingController::getArchiveSize (ARAArchiveReaderHostRef archiveReaderHostRef) noexcept { ARASize size; - remoteCallWithReply (size, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, getArchiveSize), _remoteHostRef, archiveReaderHostRef); + remoteCallWithReply (size, false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, getArchiveSize), _remoteHostRef, archiveReaderHostRef); return size; } @@ -281,7 +281,7 @@ bool ArchivingController::readBytesFromArchive (ARAArchiveReaderHostRef archiveR auto resultLength { length }; BytesDecoder writer { buffer, resultLength }; - remoteCallWithReply (writer, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, readBytesFromArchive), + remoteCallWithReply (writer, false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, readBytesFromArchive), _remoteHostRef, archiveReaderHostRef, position, length); if (resultLength == length) { @@ -315,19 +315,19 @@ bool ArchivingController::writeBytesToArchive (ARAArchiveWriterHostRef archiveWr } ARABool success; - remoteCallWithReply (success, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, writeBytesToArchive), + remoteCallWithReply (success, false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, writeBytesToArchive), _remoteHostRef, archiveWriterHostRef, position, BytesEncoder { buffer, length, false }); return (success != kARAFalse); } void ArchivingController::notifyDocumentArchivingProgress (float value) noexcept { - remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, notifyDocumentArchivingProgress), _remoteHostRef, value); + remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, notifyDocumentArchivingProgress), _remoteHostRef, value); } void ArchivingController::notifyDocumentUnarchivingProgress (float value) noexcept { - remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, notifyDocumentUnarchivingProgress), _remoteHostRef, value); + remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, notifyDocumentUnarchivingProgress), _remoteHostRef, value); } ARAPersistentID ArchivingController::getDocumentArchiveID (ARAArchiveReaderHostRef archiveReaderHostRef) noexcept @@ -338,7 +338,7 @@ ARAPersistentID ArchivingController::getDocumentArchiveID (ARAArchiveReaderHostR decodeReply (persistentID, decoder); _archiveID.assign (persistentID); } }; - remoteCallWithReply (customDecode, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, getDocumentArchiveID), _remoteHostRef, archiveReaderHostRef); + remoteCallWithReply (customDecode, false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, getDocumentArchiveID), _remoteHostRef, archiveReaderHostRef); return _archiveID.c_str(); } @@ -370,7 +370,7 @@ class ContentAccessController : public Host::ContentAccessControllerInterface, p bool ContentAccessController::isMusicalContextContentAvailable (ARAMusicalContextHostRef musicalContextHostRef, ARAContentType type) noexcept { ARABool result; - remoteCallWithReply (result, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, isMusicalContextContentAvailable), + remoteCallWithReply (result, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, isMusicalContextContentAvailable), _remoteHostRef, musicalContextHostRef, type); return (result != kARAFalse); } @@ -378,7 +378,7 @@ bool ContentAccessController::isMusicalContextContentAvailable (ARAMusicalContex ARAContentGrade ContentAccessController::getMusicalContextContentGrade (ARAMusicalContextHostRef musicalContextHostRef, ARAContentType type) noexcept { ARAContentGrade grade; - remoteCallWithReply (grade, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getMusicalContextContentGrade), + remoteCallWithReply (grade, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getMusicalContextContentGrade), _remoteHostRef, musicalContextHostRef, type); return grade; } @@ -386,7 +386,7 @@ ARAContentGrade ContentAccessController::getMusicalContextContentGrade (ARAMusic ARAContentReaderHostRef ContentAccessController::createMusicalContextContentReader (ARAMusicalContextHostRef musicalContextHostRef, ARAContentType type, const ARAContentTimeRange* range) noexcept { ARAContentReaderHostRef contentReaderHostRef; - remoteCallWithReply (contentReaderHostRef, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, createMusicalContextContentReader), + remoteCallWithReply (contentReaderHostRef, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, createMusicalContextContentReader), _remoteHostRef, musicalContextHostRef, type, range); auto contentReader { new RemoteHostContentReader (contentReaderHostRef, type) }; return toHostRef (contentReader); @@ -395,7 +395,7 @@ ARAContentReaderHostRef ContentAccessController::createMusicalContextContentRead bool ContentAccessController::isAudioSourceContentAvailable (ARAAudioSourceHostRef audioSourceHostRef, ARAContentType type) noexcept { ARABool result; - remoteCallWithReply (result, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, isAudioSourceContentAvailable), + remoteCallWithReply (result, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, isAudioSourceContentAvailable), _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, type); return (result != kARAFalse); } @@ -403,7 +403,7 @@ bool ContentAccessController::isAudioSourceContentAvailable (ARAAudioSourceHostR ARAContentGrade ContentAccessController::getAudioSourceContentGrade (ARAAudioSourceHostRef audioSourceHostRef, ARAContentType type) noexcept { ARAContentGrade grade; - remoteCallWithReply (grade, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getAudioSourceContentGrade), + remoteCallWithReply (grade, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getAudioSourceContentGrade), _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, type); return grade; } @@ -411,7 +411,7 @@ ARAContentGrade ContentAccessController::getAudioSourceContentGrade (ARAAudioSou ARAContentReaderHostRef ContentAccessController::createAudioSourceContentReader (ARAAudioSourceHostRef audioSourceHostRef, ARAContentType type, const ARAContentTimeRange* range) noexcept { ARAContentReaderHostRef contentReaderHostRef; - remoteCallWithReply (contentReaderHostRef, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, createAudioSourceContentReader), + remoteCallWithReply (contentReaderHostRef, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, createAudioSourceContentReader), _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, type, range); auto contentReader { new RemoteHostContentReader (contentReaderHostRef, type) }; return toHostRef (contentReader); @@ -421,7 +421,7 @@ ARAInt32 ContentAccessController::getContentReaderEventCount (ARAContentReaderHo { const auto contentReader { fromHostRef (contentReaderHostRef) }; ARAInt32 count; - remoteCallWithReply (count, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getContentReaderEventCount), + remoteCallWithReply (count, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getContentReaderEventCount), _remoteHostRef, contentReader->remoteHostRef); return count; } @@ -434,7 +434,7 @@ const void* ContentAccessController::getContentReaderDataForEvent (ARAContentRea { result = contentReader->decoder.decode (decoder); } }; - remoteCallWithReply (customDecode, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getContentReaderDataForEvent), + remoteCallWithReply (customDecode, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getContentReaderDataForEvent), _remoteHostRef, contentReader->remoteHostRef, eventIndex); return result; } @@ -442,7 +442,7 @@ const void* ContentAccessController::getContentReaderDataForEvent (ARAContentRea void ContentAccessController::destroyContentReader (ARAContentReaderHostRef contentReaderHostRef) noexcept { const auto contentReader { fromHostRef (contentReaderHostRef) }; - remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, destroyContentReader), _remoteHostRef, contentReader->remoteHostRef); + remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, destroyContentReader), _remoteHostRef, contentReader->remoteHostRef); delete contentReader; } @@ -468,22 +468,22 @@ class ModelUpdateController : public Host::ModelUpdateControllerInterface, publi void ModelUpdateController::notifyAudioSourceAnalysisProgress (ARAAudioSourceHostRef audioSourceHostRef, ARAAnalysisProgressState state, float value) noexcept { - remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioSourceAnalysisProgress), _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, state, value); + remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioSourceAnalysisProgress), _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, state, value); } void ModelUpdateController::notifyAudioSourceContentChanged (ARAAudioSourceHostRef audioSourceHostRef, const ARAContentTimeRange* range, ContentUpdateScopes scopeFlags) noexcept { - remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioSourceContentChanged), _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, range, scopeFlags); + remoteCallWithoutReply (true, ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioSourceContentChanged), _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, range, scopeFlags); } void ModelUpdateController::notifyAudioModificationContentChanged (ARAAudioModificationHostRef audioModificationHostRef, const ARAContentTimeRange* range, ContentUpdateScopes scopeFlags) noexcept { - remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioModificationContentChanged), _remoteHostRef, audioModificationHostRef, range, scopeFlags); + remoteCallWithoutReply (true, ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioModificationContentChanged), _remoteHostRef, audioModificationHostRef, range, scopeFlags); } void ModelUpdateController::notifyPlaybackRegionContentChanged (ARAPlaybackRegionHostRef playbackRegionHostRef, const ARAContentTimeRange* range, ContentUpdateScopes scopeFlags) noexcept { - remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyPlaybackRegionContentChanged), _remoteHostRef, playbackRegionHostRef, range, scopeFlags); + remoteCallWithoutReply (true, ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyPlaybackRegionContentChanged), _remoteHostRef, playbackRegionHostRef, range, scopeFlags); } @@ -509,27 +509,27 @@ class PlaybackController : public Host::PlaybackControllerInterface, public Remo void PlaybackController::requestStartPlayback () noexcept { - remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestStartPlayback), _remoteHostRef); + remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestStartPlayback), _remoteHostRef); } void PlaybackController::requestStopPlayback () noexcept { - remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestStopPlayback), _remoteHostRef); + remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestStopPlayback), _remoteHostRef); } void PlaybackController::requestSetPlaybackPosition (ARATimePosition timePosition) noexcept { - remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestSetPlaybackPosition), _remoteHostRef, timePosition); + remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestSetPlaybackPosition), _remoteHostRef, timePosition); } void PlaybackController::requestSetCycleRange (ARATimePosition startTime, ARATimeDuration duration) noexcept { - remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestSetCycleRange), _remoteHostRef, startTime, duration); + remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestSetCycleRange), _remoteHostRef, startTime, duration); } void PlaybackController::requestEnableCycle (bool enable) noexcept { - remoteCallWithoutReply (ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestEnableCycle), _remoteHostRef, (enable) ? kARATrue : kARAFalse); + remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestEnableCycle), _remoteHostRef, (enable) ? kARATrue : kARAFalse); } diff --git a/IPC/ARAIPCProxyPlugIn.cpp b/IPC/ARAIPCProxyPlugIn.cpp index 2e43742..bb1cd4a 100644 --- a/IPC/ARAIPCProxyPlugIn.cpp +++ b/IPC/ARAIPCProxyPlugIn.cpp @@ -342,7 +342,7 @@ DocumentController::DocumentController (ARAIPCMessageSender sender, const ARAFac ARAContentAccessControllerHostRef contentAccessControllerHostRef { toHostRef (this) }; ARAModelUpdateControllerHostRef modelUpdateControllerHostRef { toHostRef (this) }; ARAPlaybackControllerHostRef playbackControllerHostRef { toHostRef (this) }; - remoteCallWithReply (_remoteRef, kCreateDocumentControllerMessageID, _factory->factoryID, + remoteCallWithReply (_remoteRef, false, kCreateDocumentControllerMessageID, _factory->factoryID, audioAccessControllerHostRef, archivingControllerHostRef, (_hostContentAccessController.isProvided ()) ? kARATrue : kARAFalse, contentAccessControllerHostRef, (_hostModelUpdateController.isProvided ()) ? kARATrue : kARAFalse, modelUpdateControllerHostRef, @@ -358,7 +358,7 @@ void DocumentController::destroyDocumentController () noexcept ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARA_LOG_MODELOBJECT_LIFETIME ("will destroy document controller", _remoteRef); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyDocumentController), _remoteRef); + remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyDocumentController), _remoteRef); _hasBeenDestroyed = true; @@ -395,7 +395,7 @@ void DocumentController::beginEditing () noexcept ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, beginEditing), _remoteRef); + remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, beginEditing), _remoteRef); } void DocumentController::endEditing () noexcept @@ -403,7 +403,7 @@ void DocumentController::endEditing () noexcept ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, endEditing), _remoteRef); + remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, endEditing), _remoteRef); } void DocumentController::notifyModelUpdates () noexcept @@ -423,7 +423,7 @@ void DocumentController::notifyModelUpdates () noexcept if (!_hostModelUpdateController.isProvided ()) return; - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, notifyModelUpdates), _remoteRef); + remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, notifyModelUpdates), _remoteRef); } bool DocumentController::restoreObjectsFromArchive (ARAArchiveReaderHostRef archiveReaderHostRef, const ARARestoreObjectsFilter* filter) noexcept @@ -432,7 +432,7 @@ bool DocumentController::restoreObjectsFromArchive (ARAArchiveReaderHostRef arch ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARABool success; - remoteCallWithReply (success, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, restoreObjectsFromArchive), _remoteRef, archiveReaderHostRef, filter); + remoteCallWithReply (success, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, restoreObjectsFromArchive), _remoteRef, archiveReaderHostRef, filter); return (success != kARAFalse); } @@ -455,7 +455,7 @@ bool DocumentController::storeObjectsToArchive (ARAArchiveWriterHostRef archiveW } ARABool success; - remoteCallWithReply (success, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, storeObjectsToArchive), _remoteRef, archiveWriterHostRef, filter); + remoteCallWithReply (success, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, storeObjectsToArchive), _remoteRef, archiveWriterHostRef, filter); return (success!= kARAFalse); } @@ -496,7 +496,7 @@ bool DocumentController::storeAudioSourceToAudioFileChunk (ARAArchiveWriterHostR *openAutomatically = (reply.openAutomatically != kARAFalse); success = (reply.result != kARAFalse); } }; - remoteCallWithReply (customDecode, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, storeAudioSourceToAudioFileChunk), + remoteCallWithReply (customDecode, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, storeAudioSourceToAudioFileChunk), _remoteRef, archiveWriterHostRef, audioSource->remoteRef); return success; } @@ -507,7 +507,7 @@ void DocumentController::updateDocumentProperties (PropertiesPtrremoteRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioSource), + remoteCallWithReply (audioSource->remoteRef, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioSource), _remoteRef, ARAAudioSourceHostRef { toHostRef (audioSource) }, *properties); ARA_LOG_MODELOBJECT_LIFETIME ("did create audio source", audioSourceRef); @@ -613,7 +613,7 @@ void DocumentController::updateAudioSourceProperties (ARAAudioSourceRef audioSou ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); ARA_VALIDATE_API_STRUCT_PTR (properties, ARAAudioSourceProperties); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioSourceProperties), _remoteRef, audioSource->remoteRef, *properties); + remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioSourceProperties), _remoteRef, audioSource->remoteRef, *properties); } void DocumentController::updateAudioSourceContent (ARAAudioSourceRef audioSourceRef, const ARAContentTimeRange* range, ContentUpdateScopes flags) noexcept @@ -623,7 +623,7 @@ void DocumentController::updateAudioSourceContent (ARAAudioSourceRef audioSource auto audioSource { fromRef (audioSourceRef) }; ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioSourceContent), _remoteRef, audioSource->remoteRef, range, flags); + remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioSourceContent), _remoteRef, audioSource->remoteRef, range, flags); } void DocumentController::enableAudioSourceSamplesAccess (ARAAudioSourceRef audioSourceRef, bool enable) noexcept @@ -633,7 +633,7 @@ void DocumentController::enableAudioSourceSamplesAccess (ARAAudioSourceRef audio const auto audioSource { fromRef (audioSourceRef) }; ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, enableAudioSourceSamplesAccess), _remoteRef, audioSource->remoteRef, (enable) ? kARATrue : kARAFalse); + remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, enableAudioSourceSamplesAccess), _remoteRef, audioSource->remoteRef, (enable) ? kARATrue : kARAFalse); } void DocumentController::deactivateAudioSourceForUndoHistory (ARAAudioSourceRef audioSourceRef, bool deactivate) noexcept @@ -643,7 +643,7 @@ void DocumentController::deactivateAudioSourceForUndoHistory (ARAAudioSourceRef const auto audioSource { fromRef (audioSourceRef) }; ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, deactivateAudioSourceForUndoHistory), _remoteRef, audioSource->remoteRef, (deactivate) ? kARATrue : kARAFalse); + remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, deactivateAudioSourceForUndoHistory), _remoteRef, audioSource->remoteRef, (deactivate) ? kARATrue : kARAFalse); } void DocumentController::destroyAudioSource (ARAAudioSourceRef audioSourceRef) noexcept @@ -654,7 +654,7 @@ void DocumentController::destroyAudioSource (ARAAudioSourceRef audioSourceRef) n ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); ARA_LOG_MODELOBJECT_LIFETIME ("will destroy audio source", audioSource->remoteRef); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyAudioSource), _remoteRef, audioSource->remoteRef); + remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyAudioSource), _remoteRef, audioSource->remoteRef); delete audioSource; } @@ -669,7 +669,7 @@ ARAAudioModificationRef DocumentController::createAudioModification (ARAAudioSou ARA_VALIDATE_API_STRUCT_PTR (properties, ARAAudioModificationProperties); ARAAudioModificationRef audioModificationRef; - remoteCallWithReply (audioModificationRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioModification), + remoteCallWithReply (audioModificationRef, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioModification), _remoteRef, audioSource->remoteRef, hostRef, *properties); ARA_LOG_MODELOBJECT_LIFETIME ("did create audio modification", audioModificationRef); @@ -683,7 +683,7 @@ ARAAudioModificationRef DocumentController::cloneAudioModification (ARAAudioModi ARA_VALIDATE_API_STRUCT_PTR (properties, ARAAudioModificationProperties); ARAAudioModificationRef clonedAudioModificationRef; - remoteCallWithReply (clonedAudioModificationRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, cloneAudioModification), + remoteCallWithReply (clonedAudioModificationRef, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, cloneAudioModification), _remoteRef, srcAudioModificationRef, hostRef, *properties); ARA_LOG_MODELOBJECT_LIFETIME ("did create cloned audio modification", clonedAudioModificationRef); @@ -696,7 +696,7 @@ void DocumentController::updateAudioModificationProperties (ARAAudioModification ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARA_VALIDATE_API_STRUCT_PTR (properties, ARAAudioModificationProperties); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioModificationProperties), _remoteRef, audioModificationRef, *properties); + remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioModificationProperties), _remoteRef, audioModificationRef, *properties); } void DocumentController::deactivateAudioModificationForUndoHistory (ARAAudioModificationRef audioModificationRef, bool deactivate) noexcept @@ -704,7 +704,7 @@ void DocumentController::deactivateAudioModificationForUndoHistory (ARAAudioModi ARA_LOG_HOST_ENTRY (audioModificationRef); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, deactivateAudioModificationForUndoHistory), _remoteRef, audioModificationRef, (deactivate) ? kARATrue : kARAFalse); + remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, deactivateAudioModificationForUndoHistory), _remoteRef, audioModificationRef, (deactivate) ? kARATrue : kARAFalse); } void DocumentController::destroyAudioModification (ARAAudioModificationRef audioModificationRef) noexcept @@ -713,7 +713,7 @@ void DocumentController::destroyAudioModification (ARAAudioModificationRef audio ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARA_LOG_MODELOBJECT_LIFETIME ("will destroy audio modification", audioModification); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyAudioModification), _remoteRef, audioModificationRef); + remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyAudioModification), _remoteRef, audioModificationRef); } /*******************************************************************************/ @@ -725,7 +725,7 @@ ARAPlaybackRegionRef DocumentController::createPlaybackRegion (ARAAudioModificat ARA_VALIDATE_API_STRUCT_PTR (properties, ARAPlaybackRegionProperties); ARAPlaybackRegionRef playbackRegionRef; - remoteCallWithReply (playbackRegionRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createPlaybackRegion), + remoteCallWithReply (playbackRegionRef, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createPlaybackRegion), _remoteRef, audioModificationRef, hostRef, *properties); ARA_LOG_MODELOBJECT_LIFETIME ("did create playback region", playbackRegionRef); @@ -738,7 +738,7 @@ void DocumentController::updatePlaybackRegionProperties (ARAPlaybackRegionRef pl ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARA_VALIDATE_API_STRUCT_PTR (properties, ARAPlaybackRegionProperties); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updatePlaybackRegionProperties), _remoteRef, playbackRegionRef, *properties); + remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updatePlaybackRegionProperties), _remoteRef, playbackRegionRef, *properties); } void DocumentController::getPlaybackRegionHeadAndTailTime (ARAPlaybackRegionRef playbackRegionRef, ARATimeDuration* headTime, ARATimeDuration* tailTime) noexcept @@ -749,7 +749,7 @@ void DocumentController::getPlaybackRegionHeadAndTailTime (ARAPlaybackRegionRef ARA_VALIDATE_API_ARGUMENT (tailTime, tailTime != nullptr); GetPlaybackRegionHeadAndTailTimeReply reply; - remoteCallWithReply (reply, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getPlaybackRegionHeadAndTailTime), + remoteCallWithReply (reply, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getPlaybackRegionHeadAndTailTime), _remoteRef, playbackRegionRef, (headTime != nullptr) ? kARATrue : kARAFalse, (tailTime != nullptr) ? kARATrue : kARAFalse); if (headTime != nullptr) *headTime = reply.headTime; @@ -763,7 +763,7 @@ void DocumentController::destroyPlaybackRegion (ARAPlaybackRegionRef playbackReg ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARA_LOG_MODELOBJECT_LIFETIME ("will destroy playback region", playbackRegionRef); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyPlaybackRegion), _remoteRef, playbackRegionRef); + remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyPlaybackRegion), _remoteRef, playbackRegionRef); } /*******************************************************************************/ @@ -775,7 +775,7 @@ bool DocumentController::isAudioSourceContentAvailable (ARAAudioSourceRef audioS ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); ARABool result; - remoteCallWithReply (result, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioSourceContentAvailable), _remoteRef, audioSource->remoteRef, type); + remoteCallWithReply (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioSourceContentAvailable), _remoteRef, audioSource->remoteRef, type); return (result != kARAFalse); } @@ -787,7 +787,7 @@ ARAContentGrade DocumentController::getAudioSourceContentGrade (ARAAudioSourceRe ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); ARAContentGrade grade; - remoteCallWithReply (grade, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getAudioSourceContentGrade), _remoteRef, audioSource->remoteRef, type); + remoteCallWithReply (grade, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getAudioSourceContentGrade), _remoteRef, audioSource->remoteRef, type); return grade; } @@ -799,7 +799,7 @@ ARAContentReaderRef DocumentController::createAudioSourceContentReader (ARAAudio ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); ARAContentReaderRef contentReaderRef; - remoteCallWithReply (contentReaderRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioSourceContentReader), + remoteCallWithReply (contentReaderRef, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioSourceContentReader), _remoteRef, audioSource->remoteRef, type, range); auto contentReader { new ContentReader { contentReaderRef, type } }; @@ -817,7 +817,7 @@ bool DocumentController::isAudioModificationContentAvailable (ARAAudioModificati ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARABool result; - remoteCallWithReply (result, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioModificationContentAvailable), _remoteRef, audioModificationRef, type); + remoteCallWithReply (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioModificationContentAvailable), _remoteRef, audioModificationRef, type); return (result != kARAFalse); } @@ -827,7 +827,7 @@ ARAContentGrade DocumentController::getAudioModificationContentGrade (ARAAudioMo ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARAContentGrade grade; - remoteCallWithReply (grade, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getAudioModificationContentGrade), _remoteRef, audioModificationRef, type); + remoteCallWithReply (grade, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getAudioModificationContentGrade), _remoteRef, audioModificationRef, type); return grade; } @@ -837,7 +837,7 @@ ARAContentReaderRef DocumentController::createAudioModificationContentReader (AR ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARAContentReaderRef contentReaderRef; - remoteCallWithReply (contentReaderRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioModificationContentReader), + remoteCallWithReply (contentReaderRef, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioModificationContentReader), _remoteRef, audioModificationRef, type, range); auto contentReader { new ContentReader { contentReaderRef, type } }; @@ -855,7 +855,7 @@ bool DocumentController::isPlaybackRegionContentAvailable (ARAPlaybackRegionRef ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARABool result; - remoteCallWithReply (result, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isPlaybackRegionContentAvailable), _remoteRef, playbackRegionRef, type); + remoteCallWithReply (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isPlaybackRegionContentAvailable), _remoteRef, playbackRegionRef, type); return (result != kARAFalse); } @@ -865,7 +865,7 @@ ARAContentGrade DocumentController::getPlaybackRegionContentGrade (ARAPlaybackRe ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARAContentGrade grade; - remoteCallWithReply (grade, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getPlaybackRegionContentGrade), _remoteRef, playbackRegionRef, type); + remoteCallWithReply (grade, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getPlaybackRegionContentGrade), _remoteRef, playbackRegionRef, type); return grade; } @@ -875,7 +875,7 @@ ARAContentReaderRef DocumentController::createPlaybackRegionContentReader (ARAPl ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARAContentReaderRef contentReaderRef; - remoteCallWithReply (contentReaderRef, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createPlaybackRegionContentReader), + remoteCallWithReply (contentReaderRef, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createPlaybackRegionContentReader), _remoteRef, playbackRegionRef, type, range); auto contentReader { new ContentReader { contentReaderRef, type } }; @@ -895,7 +895,7 @@ ARAInt32 DocumentController::getContentReaderEventCount (ARAContentReaderRef con ARA_VALIDATE_API_ARGUMENT (contentReader, isValidInstance (contentReader)); ARAInt32 count; - remoteCallWithReply (count, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getContentReaderEventCount), _remoteRef, contentReader->remoteRef); + remoteCallWithReply (count, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getContentReaderEventCount), _remoteRef, contentReader->remoteRef); return count; } @@ -911,7 +911,7 @@ const void* DocumentController::getContentReaderDataForEvent (ARAContentReaderRe { result = contentReader->decoder.decode (decoder); } }; - remoteCallWithReply (customDecode, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getContentReaderDataForEvent), + remoteCallWithReply (customDecode, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getContentReaderDataForEvent), _remoteRef, contentReader->remoteRef, eventIndex); return result; } @@ -924,7 +924,7 @@ void DocumentController::destroyContentReader (ARAContentReaderRef contentReader ARA_VALIDATE_API_ARGUMENT (contentReader, isValidInstance (contentReader)); ARA_LOG_MODELOBJECT_LIFETIME ("will destroy content reader", contentReader->remoteRef); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyContentReader), _remoteRef, contentReader->remoteRef); + remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyContentReader), _remoteRef, contentReader->remoteRef); delete contentReader; } @@ -939,7 +939,7 @@ bool DocumentController::isAudioSourceContentAnalysisIncomplete (ARAAudioSourceR ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); ARABool result; - remoteCallWithReply (result, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioSourceContentAnalysisIncomplete), + remoteCallWithReply (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioSourceContentAnalysisIncomplete), _remoteRef, audioSource->remoteRef, type); return (result != kARAFalse); } @@ -952,7 +952,7 @@ void DocumentController::requestAudioSourceContentAnalysis (ARAAudioSourceRef au ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); const ArrayArgument types { contentTypes, contentTypesCount }; - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, requestAudioSourceContentAnalysis), _remoteRef, audioSource->remoteRef, types); + remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, requestAudioSourceContentAnalysis), _remoteRef, audioSource->remoteRef, types); } ARAInt32 DocumentController::getProcessingAlgorithmsCount () noexcept @@ -961,7 +961,7 @@ ARAInt32 DocumentController::getProcessingAlgorithmsCount () noexcept ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARAInt32 count; - remoteCallWithReply (count, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmsCount), _remoteRef); + remoteCallWithReply (count, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmsCount), _remoteRef); return count; } @@ -980,7 +980,7 @@ const ARAProcessingAlgorithmProperties* DocumentController::getProcessingAlgorit _processingAlgorithmData.persistentID = _processingAlgorithmStrings.persistentID.c_str (); _processingAlgorithmData.name = _processingAlgorithmStrings.name.c_str (); } }; - remoteCallWithReply (customDecode, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmProperties), _remoteRef, algorithmIndex); + remoteCallWithReply (customDecode, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmProperties), _remoteRef, algorithmIndex); return &_processingAlgorithmData; } @@ -992,7 +992,7 @@ ARAInt32 DocumentController::getProcessingAlgorithmForAudioSource (ARAAudioSourc ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); ARAInt32 result; - remoteCallWithReply (result, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmForAudioSource), _remoteRef, audioSource->remoteRef); + remoteCallWithReply (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmForAudioSource), _remoteRef, audioSource->remoteRef); return result; } @@ -1003,7 +1003,7 @@ void DocumentController::requestProcessingAlgorithmForAudioSource (ARAAudioSourc const auto audioSource { fromRef (audioSourceRef) }; ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, requestProcessingAlgorithmForAudioSource), _remoteRef, audioSource->remoteRef, algorithmIndex); + remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, requestProcessingAlgorithmForAudioSource), _remoteRef, audioSource->remoteRef, algorithmIndex); } /*******************************************************************************/ @@ -1015,7 +1015,7 @@ bool DocumentController::isLicensedForCapabilities (bool runModalActivationDialo const ArrayArgument types { contentTypes, contentTypesCount }; ARABool result; - remoteCallWithReply (result, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isLicensedForCapabilities), + remoteCallWithReply (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isLicensedForCapabilities), _remoteRef, (runModalActivationDialogIfNeeded) ? kARATrue : kARAFalse, types, transformationFlags); return (result != kARAFalse); } @@ -1038,14 +1038,14 @@ class PlaybackRenderer : public PlugIn::PlaybackRendererInterface, protected Rem ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAPlaybackRendererInterface, addPlaybackRegion), _remoteRef, playbackRegionRef); + remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAPlaybackRendererInterface, addPlaybackRegion), _remoteRef, playbackRegionRef); } void removePlaybackRegion (ARAPlaybackRegionRef playbackRegionRef) noexcept override { ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAPlaybackRendererInterface, removePlaybackRegion), _remoteRef, playbackRegionRef); + remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAPlaybackRendererInterface, removePlaybackRegion), _remoteRef, playbackRegionRef); } private: @@ -1072,14 +1072,14 @@ class EditorRenderer : public PlugIn::EditorRendererInterface, protected RemoteC ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, addPlaybackRegion), _remoteRef, playbackRegionRef); + remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, addPlaybackRegion), _remoteRef, playbackRegionRef); } void removePlaybackRegion (ARAPlaybackRegionRef playbackRegionRef) noexcept override { ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, removePlaybackRegion), _remoteRef, playbackRegionRef); + remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, removePlaybackRegion), _remoteRef, playbackRegionRef); } void addRegionSequence (ARARegionSequenceRef regionSequenceRef) noexcept override @@ -1087,14 +1087,14 @@ class EditorRenderer : public PlugIn::EditorRendererInterface, protected RemoteC ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, addRegionSequence), _remoteRef, regionSequenceRef); + remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, addRegionSequence), _remoteRef, regionSequenceRef); } void removeRegionSequence (ARARegionSequenceRef regionSequenceRef) noexcept override { ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, removeRegionSequence), _remoteRef, regionSequenceRef); + remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, removeRegionSequence), _remoteRef, regionSequenceRef); } private: @@ -1122,7 +1122,7 @@ class EditorView : public PlugIn::EditorViewInterface, protected RemoteCaller, p ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARA_VALIDATE_API_STRUCT_PTR (selection, ARAViewSelection); - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAEditorViewInterface, notifySelection), _remoteRef, *selection); + remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorViewInterface, notifySelection), _remoteRef, *selection); } void notifyHideRegionSequences (ARASize regionSequenceRefsCount, const ARARegionSequenceRef regionSequenceRefs[]) noexcept override { @@ -1130,7 +1130,7 @@ class EditorView : public PlugIn::EditorViewInterface, protected RemoteCaller, p ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); const ArrayArgument sequences { regionSequenceRefs, regionSequenceRefsCount }; - remoteCallWithoutReply (ARA_IPC_PLUGIN_METHOD_ID (ARAEditorViewInterface, notifyHideRegionSequences), _remoteRef, sequences); + remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorViewInterface, notifyHideRegionSequences), _remoteRef, sequences); } private: @@ -1223,7 +1223,7 @@ using namespace ProxyPlugIn; size_t ARAIPCProxyPlugInGetFactoriesCount (ARAIPCMessageSender hostCommandsSender) { size_t count; - RemoteCaller { hostCommandsSender }.remoteCallWithReply (count, kGetFactoriesCountMessageID); + RemoteCaller { hostCommandsSender }.remoteCallWithReply (count, false, kGetFactoriesCountMessageID); ARA_INTERNAL_ASSERT (count > 0); return count; } @@ -1267,7 +1267,7 @@ const ARAFactory* ARAIPCProxyPlugInGetFactoryAtIndex (ARAIPCMessageSender hostCo remoteFactory._factory.analyzeableContentTypes = remoteFactory._analyzableTypes.data (); } }; - RemoteCaller { hostCommandsSender }.remoteCallWithReply (customDecode, kGetFactoryMessageID, index); + RemoteCaller { hostCommandsSender }.remoteCallWithReply (customDecode, false, kGetFactoryMessageID, index); const auto result { _factories.insert (std::make_pair (remoteFactory._strings.factoryID, remoteFactory)) }; if (result.second) From 5e5273b661d28e6c14d30c7c56393b3409486057 Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:31:59 +0100 Subject: [PATCH 10/18] IPC encoding fixes for optional name members such as the various name fields --- IPC/ARAIPCEncoding.h | 114 +++++++++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 43 deletions(-) diff --git a/IPC/ARAIPCEncoding.h b/IPC/ARAIPCEncoding.h index 218bf79..7cd023c 100644 --- a/IPC/ARAIPCEncoding.h +++ b/IPC/ARAIPCEncoding.h @@ -434,16 +434,25 @@ template<> struct _ValueEncoder : public _CompoundValueEncoderBase::type> tmp_##member { value.member, value.count }; \ _encodeAndAppend (encoder, offsetof (StructType, member), tmp_##member); \ } -#define ARA_IPC_HAS_OPTIONAL_MEMBER(member) \ +#define ARA_IPC_ENCODE_OPTIONAL_MEMBER(member) \ + if (value.member != nullptr) \ + ARA_IPC_ENCODE_MEMBER (member) +#define ARA_IPC_HAS_ADDENDUM_MEMBER(member) \ /* \todo ARA_IMPLEMENTS_FIELD decorates the type with the ARA:: namespace, */ \ /* this conflicts with decltype's result - this copied version drops the ARA:: */ \ (value.structSize > offsetof (std::remove_reference::type, member)) -#define ARA_IPC_ENCODE_OPTIONAL_MEMBER(member) \ - if (ARA_IPC_HAS_OPTIONAL_MEMBER (member)) \ +#define ARA_IPC_ENCODE_ADDENDUM_MEMBER(member) \ + if (ARA_IPC_HAS_ADDENDUM_MEMBER (member)) \ ARA_IPC_ENCODE_MEMBER (member) +#define ARA_IPC_ENCODE_OPTIONAL_ADDENDUM_MEMBER(member) \ + if (ARA_IPC_HAS_ADDENDUM_MEMBER (member)) \ + ARA_IPC_ENCODE_OPTIONAL_MEMBER (member) #define ARA_IPC_ENCODE_OPTIONAL_STRUCT_PTR(member) \ - if (ARA_IPC_HAS_OPTIONAL_MEMBER (member) && (value.member != nullptr)) \ + if (value.member != nullptr) \ _encodeAndAppend (encoder, offsetof (StructType, member), *value.member); +#define ARA_IPC_ENCODE_OPTIONAL_ADDENDUM_STRUCT_PTR(member) \ + if (ARA_IPC_HAS_ADDENDUM_MEMBER (member)) \ + ARA_IPC_ENCODE_OPTIONAL_STRUCT_PTR(member) #define ARA_IPC_END_ENCODE \ } \ }; @@ -483,20 +492,26 @@ template<> struct _ValueDecoder : public _CompoundValueDecoderBase (nullptr)->member) }; \ result.structSize = std::max (result.structSize, size); -#define ARA_IPC_DECODE_OPTIONAL_MEMBER(member) \ +#define ARA_IPC_DECODE_ADDENDUM_MEMBER(member) \ if (_readAndDecode (result.member, decoder, offsetof (StructType, member))) { \ ARA_IPC_UPDATE_STRUCT_SIZE_FOR_OPTIONAL (member); \ } -#define ARA_IPC_DECODE_OPTIONAL_STRUCT_PTR(member) \ - result.member = nullptr; /* set to null because other members may follow */ \ +#define ARA_IPC_DECODE_OPTIONAL_ADDENDUM_MEMBER(member) \ + ARA_IPC_DECODE_ADDENDUM_MEMBER(member) \ + else { \ + result.member = nullptr; \ + } +#define ARA_IPC_DECODE_OPTIONAL_STRUCT_PTR(member, OPTIONAL_UPDATE_MACRO) \ auto subDecoderRef_##member { decoder.methods->readSubMessage (decoder.ref, offsetof (StructType, member)) }; \ if (subDecoderRef_##member != nullptr) { \ - ARA_IPC_UPDATE_STRUCT_SIZE_FOR_OPTIONAL (member); \ ARAIPCMessageDecoder subDecoder { subDecoderRef_##member, decoder.methods }; \ /* \todo the outer struct contains a pointer to the inner struct, so we need some */\ /* place to store it - this static only works as long as this is single-threaded! */\ @@ -504,8 +519,14 @@ template<> struct _ValueDecoder : public _CompoundValueDecoderBase::decode (cache, subDecoder); \ ARA_INTERNAL_ASSERT (success); \ result.member = &cache; \ + { OPTIONAL_UPDATE_MACRO } \ decoder.methods->destroyDecoder (subDecoderRef_##member); \ + } \ + else { \ + result.member = nullptr; \ } +#define ARA_IPC_DECODE_OPTIONAL_ADDENDUM_STRUCT_PTR(member) \ + ARA_IPC_DECODE_OPTIONAL_STRUCT_PTR (member, ARA_IPC_UPDATE_STRUCT_SIZE_FOR_OPTIONAL (member)) #define ARA_IPC_END_DECODE \ return success; \ } \ @@ -524,38 +545,38 @@ ARA_IPC_BEGIN_DECODE (ARAColor) ARA_IPC_END_DECODE ARA_IPC_BEGIN_ENCODE (ARADocumentProperties) - ARA_IPC_ENCODE_MEMBER (name) + ARA_IPC_ENCODE_OPTIONAL_MEMBER (name) ARA_IPC_END_ENCODE ARA_IPC_BEGIN_DECODE_SIZED (ARADocumentProperties) - ARA_IPC_DECODE_MEMBER (name) + ARA_IPC_DECODE_OPTIONAL_MEMBER (name) ARA_IPC_END_DECODE ARA_IPC_BEGIN_ENCODE (ARAMusicalContextProperties) - ARA_IPC_ENCODE_MEMBER (name) - ARA_IPC_ENCODE_OPTIONAL_MEMBER (orderIndex) - ARA_IPC_ENCODE_OPTIONAL_STRUCT_PTR (color) + ARA_IPC_ENCODE_OPTIONAL_ADDENDUM_MEMBER (name) + ARA_IPC_ENCODE_ADDENDUM_MEMBER (orderIndex) + ARA_IPC_ENCODE_OPTIONAL_ADDENDUM_STRUCT_PTR (color) ARA_IPC_END_ENCODE ARA_IPC_BEGIN_DECODE_SIZED (ARAMusicalContextProperties) - ARA_IPC_DECODE_MEMBER (name) - ARA_IPC_DECODE_OPTIONAL_MEMBER (orderIndex) - ARA_IPC_DECODE_OPTIONAL_STRUCT_PTR (color) + ARA_IPC_DECODE_OPTIONAL_ADDENDUM_MEMBER (name) + ARA_IPC_DECODE_ADDENDUM_MEMBER (orderIndex) + ARA_IPC_DECODE_OPTIONAL_ADDENDUM_STRUCT_PTR (color) ARA_IPC_END_DECODE ARA_IPC_BEGIN_ENCODE (ARARegionSequenceProperties) - ARA_IPC_ENCODE_MEMBER (name) + ARA_IPC_ENCODE_OPTIONAL_MEMBER (name) ARA_IPC_ENCODE_MEMBER (orderIndex) ARA_IPC_ENCODE_MEMBER (musicalContextRef) - ARA_IPC_ENCODE_OPTIONAL_STRUCT_PTR (color) + ARA_IPC_ENCODE_OPTIONAL_ADDENDUM_STRUCT_PTR (color) ARA_IPC_END_ENCODE ARA_IPC_BEGIN_DECODE_SIZED (ARARegionSequenceProperties) - ARA_IPC_DECODE_MEMBER (name) + ARA_IPC_DECODE_OPTIONAL_MEMBER (name) ARA_IPC_DECODE_MEMBER (orderIndex) ARA_IPC_DECODE_MEMBER (musicalContextRef) - ARA_IPC_DECODE_OPTIONAL_STRUCT_PTR (color) + ARA_IPC_DECODE_OPTIONAL_ADDENDUM_STRUCT_PTR (color) ARA_IPC_END_DECODE ARA_IPC_BEGIN_ENCODE (ARAAudioSourceProperties) - ARA_IPC_ENCODE_MEMBER (name) + ARA_IPC_ENCODE_OPTIONAL_MEMBER (name) ARA_IPC_ENCODE_MEMBER (persistentID) ARA_IPC_ENCODE_MEMBER (sampleCount) ARA_IPC_ENCODE_MEMBER (sampleRate) @@ -563,7 +584,7 @@ ARA_IPC_BEGIN_ENCODE (ARAAudioSourceProperties) ARA_IPC_ENCODE_MEMBER (merits64BitSamples) ARA_IPC_END_ENCODE ARA_IPC_BEGIN_DECODE_SIZED (ARAAudioSourceProperties) - ARA_IPC_DECODE_MEMBER (name) + ARA_IPC_DECODE_OPTIONAL_MEMBER (name) ARA_IPC_DECODE_MEMBER (persistentID) ARA_IPC_DECODE_MEMBER (sampleCount) ARA_IPC_DECODE_MEMBER (sampleRate) @@ -572,11 +593,11 @@ ARA_IPC_BEGIN_DECODE_SIZED (ARAAudioSourceProperties) ARA_IPC_END_DECODE ARA_IPC_BEGIN_ENCODE (ARAAudioModificationProperties) - ARA_IPC_ENCODE_MEMBER (name) + ARA_IPC_ENCODE_OPTIONAL_MEMBER (name) ARA_IPC_ENCODE_MEMBER (persistentID) ARA_IPC_END_ENCODE ARA_IPC_BEGIN_DECODE_SIZED (ARAAudioModificationProperties) - ARA_IPC_DECODE_MEMBER (name) + ARA_IPC_DECODE_OPTIONAL_MEMBER (name) ARA_IPC_DECODE_MEMBER (persistentID) ARA_IPC_END_DECODE @@ -586,10 +607,11 @@ ARA_IPC_BEGIN_ENCODE (ARAPlaybackRegionProperties) ARA_IPC_ENCODE_MEMBER (durationInModificationTime) ARA_IPC_ENCODE_MEMBER (startInPlaybackTime) ARA_IPC_ENCODE_MEMBER (durationInPlaybackTime) - ARA_IPC_ENCODE_MEMBER (musicalContextRef) - ARA_IPC_ENCODE_OPTIONAL_MEMBER (regionSequenceRef) - ARA_IPC_ENCODE_OPTIONAL_MEMBER (name) - ARA_IPC_ENCODE_OPTIONAL_STRUCT_PTR (color) + if (!ARA_IPC_HAS_ADDENDUM_MEMBER(regionSequenceRef)) + ARA_IPC_ENCODE_MEMBER (musicalContextRef) + ARA_IPC_ENCODE_ADDENDUM_MEMBER (regionSequenceRef) + ARA_IPC_ENCODE_OPTIONAL_ADDENDUM_MEMBER (name) + ARA_IPC_ENCODE_OPTIONAL_ADDENDUM_STRUCT_PTR (color) ARA_IPC_END_ENCODE ARA_IPC_BEGIN_DECODE_SIZED (ARAPlaybackRegionProperties) ARA_IPC_DECODE_MEMBER (transformationFlags) @@ -597,10 +619,10 @@ ARA_IPC_BEGIN_DECODE_SIZED (ARAPlaybackRegionProperties) ARA_IPC_DECODE_MEMBER (durationInModificationTime) ARA_IPC_DECODE_MEMBER (startInPlaybackTime) ARA_IPC_DECODE_MEMBER (durationInPlaybackTime) - ARA_IPC_DECODE_MEMBER (musicalContextRef) - ARA_IPC_DECODE_OPTIONAL_MEMBER (regionSequenceRef) - ARA_IPC_DECODE_OPTIONAL_MEMBER (name) - ARA_IPC_DECODE_OPTIONAL_STRUCT_PTR (color) + ARA_IPC_DECODE_OPTIONAL_MEMBER (musicalContextRef) + ARA_IPC_DECODE_ADDENDUM_MEMBER (regionSequenceRef) + ARA_IPC_DECODE_OPTIONAL_ADDENDUM_MEMBER (name) + ARA_IPC_DECODE_OPTIONAL_ADDENDUM_STRUCT_PTR (color) ARA_IPC_END_DECODE ARA_IPC_BEGIN_ENCODE (ARAContentTimeRange) @@ -655,25 +677,25 @@ ARA_IPC_BEGIN_ENCODE (ARAContentTuning) ARA_IPC_ENCODE_MEMBER (concertPitchFrequency) ARA_IPC_ENCODE_MEMBER (root) ARA_IPC_ENCODE_EMBEDDED_ARRAY (tunings) - ARA_IPC_ENCODE_MEMBER (name) + ARA_IPC_ENCODE_OPTIONAL_MEMBER (name) ARA_IPC_END_ENCODE ARA_IPC_BEGIN_DECODE (ARAContentTuning) ARA_IPC_DECODE_MEMBER (concertPitchFrequency) ARA_IPC_DECODE_MEMBER (root) ARA_IPC_DECODE_EMBEDDED_ARRAY (tunings) - ARA_IPC_DECODE_MEMBER (name) + ARA_IPC_DECODE_OPTIONAL_MEMBER (name) ARA_IPC_END_DECODE ARA_IPC_BEGIN_ENCODE (ARAContentKeySignature) ARA_IPC_ENCODE_MEMBER (root) ARA_IPC_ENCODE_EMBEDDED_BYTES (intervals) - ARA_IPC_ENCODE_MEMBER (name) + ARA_IPC_ENCODE_OPTIONAL_MEMBER (name) ARA_IPC_ENCODE_MEMBER (position) ARA_IPC_END_ENCODE ARA_IPC_BEGIN_DECODE (ARAContentKeySignature) ARA_IPC_DECODE_MEMBER (root) ARA_IPC_DECODE_EMBEDDED_BYTES (intervals) - ARA_IPC_DECODE_MEMBER (name) + ARA_IPC_DECODE_OPTIONAL_MEMBER (name) ARA_IPC_DECODE_MEMBER (position) ARA_IPC_END_DECODE @@ -681,14 +703,14 @@ ARA_IPC_BEGIN_ENCODE (ARAContentChord) ARA_IPC_ENCODE_MEMBER (root) ARA_IPC_ENCODE_MEMBER (bass) ARA_IPC_ENCODE_EMBEDDED_BYTES (intervals) - ARA_IPC_ENCODE_MEMBER (name) + ARA_IPC_ENCODE_OPTIONAL_MEMBER (name) ARA_IPC_ENCODE_MEMBER (position) ARA_IPC_END_ENCODE ARA_IPC_BEGIN_DECODE (ARAContentChord) ARA_IPC_DECODE_MEMBER (root) ARA_IPC_DECODE_MEMBER (bass) ARA_IPC_DECODE_EMBEDDED_BYTES (intervals) - ARA_IPC_DECODE_MEMBER (name) + ARA_IPC_DECODE_OPTIONAL_MEMBER (name) ARA_IPC_DECODE_MEMBER (position) ARA_IPC_END_DECODE @@ -735,7 +757,7 @@ ARA_IPC_END_ENCODE ARA_IPC_BEGIN_DECODE_SIZED (ARAViewSelection) ARA_IPC_DECODE_VARIABLE_ARRAY (playbackRegionRefs, playbackRegionRefsCount, true) ARA_IPC_DECODE_VARIABLE_ARRAY (regionSequenceRefs, regionSequenceRefsCount, true) - ARA_IPC_DECODE_OPTIONAL_STRUCT_PTR (timeRange) + ARA_IPC_DECODE_OPTIONAL_STRUCT_PTR (timeRange, ) ARA_IPC_END_DECODE ARA_IPC_BEGIN_ENCODE (ARAFactory) @@ -750,7 +772,7 @@ ARA_IPC_BEGIN_ENCODE (ARAFactory) ARA_IPC_ENCODE_VARIABLE_ARRAY (compatibleDocumentArchiveIDs, compatibleDocumentArchiveIDsCount) ARA_IPC_ENCODE_VARIABLE_ARRAY (analyzeableContentTypes, analyzeableContentTypesCount) ARA_IPC_ENCODE_MEMBER (supportedPlaybackTransformationFlags) - ARA_IPC_ENCODE_OPTIONAL_MEMBER (supportsStoringAudioFileChunks) + ARA_IPC_ENCODE_ADDENDUM_MEMBER (supportsStoringAudioFileChunks) ARA_IPC_END_ENCODE ARA_IPC_BEGIN_DECODE_SIZED (ARAFactory) ARA_IPC_DECODE_MEMBER (lowestSupportedApiGeneration) @@ -767,7 +789,7 @@ ARA_IPC_BEGIN_DECODE_SIZED (ARAFactory) ARA_IPC_DECODE_VARIABLE_ARRAY (compatibleDocumentArchiveIDs, compatibleDocumentArchiveIDsCount, true) ARA_IPC_DECODE_VARIABLE_ARRAY (analyzeableContentTypes, analyzeableContentTypesCount, true) ARA_IPC_DECODE_MEMBER (supportedPlaybackTransformationFlags) - ARA_IPC_DECODE_OPTIONAL_MEMBER (supportsStoringAudioFileChunks) + ARA_IPC_DECODE_ADDENDUM_MEMBER (supportsStoringAudioFileChunks) ARA_IPC_END_DECODE @@ -807,13 +829,16 @@ ARA_IPC_END_DECODE #undef ARA_IPC_BEGIN_ENCODE -#undef ARA_IPC_HAS_OPTIONAL_MEMBER #undef ARA_IPC_ENCODE_MEMBER #undef ARA_IPC_ENCODE_EMBEDDED_BYES #undef ARA_IPC_ENCODE_EMBEDDED_ARRAY #undef ARA_IPC_ENCODE_VARIABLE_ARRAY #undef ARA_IPC_ENCODE_OPTIONAL_MEMBER +#undef ARA_IPC_HAS_ADDENDUM_MEMBER +#undef ARA_IPC_ENCODE_ADDENDUM_MEMBER +#undef ARA_IPC_ENCODE_OPTIONAL_ADDENDUM_MEMBER #undef ARA_IPC_ENCODE_OPTIONAL_STRUCT_PTR +#undef ARA_IPC_ENCODE_OPTIONAL_ADDENDUM_STRUCT_PTR #undef ARA_IPC_END_ENCODE #undef ARA_IPC_BEGIN_DECODE @@ -822,9 +847,12 @@ ARA_IPC_END_DECODE #undef ARA_IPC_DECODE_EMBEDDED_BYTES #undef ARA_IPC_DECODE_EMBEDDED_ARRAY #undef ARA_IPC_DECODE_VARIABLE_ARRAY -#undef ARA_IPC_UPDATE_STRUCT_SIZE_FOR_OPTIONAL #undef ARA_IPC_DECODE_OPTIONAL_MEMBER +#undef ARA_IPC_UPDATE_STRUCT_SIZE_FOR_OPTIONAL +#undef ARA_IPC_DECODE_ADDENDUM_MEMBER +#undef ARA_IPC_DECODE_OPTIONAL_ADDENDUM_MEMBER #undef ARA_IPC_DECODE_OPTIONAL_STRUCT_PTR +#undef ARA_IPC_DECODE_OPTIONAL_ADDENDUM_STRUCT_PTR #undef ARA_IPC_END_DECODE From 64aa0bb904548a3878bc8a425e22d8bb2de896ce Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:32:00 +0100 Subject: [PATCH 11/18] Hide IPC proxy internal mappings by generalzing the binding call in the IPC and delegating its actual execution to the outer hosting code --- IPC/ARAIPC.h | 11 +++++++++++ IPC/ARAIPCEncoding.h | 1 + IPC/ARAIPCProxyHost.cpp | 24 +++++++++++++++--------- IPC/ARAIPCProxyHost.h | 15 ++++++--------- IPC/ARAIPCProxyPlugIn.cpp | 18 +++++++++++------- IPC/ARAIPCProxyPlugIn.h | 15 +++++++-------- 6 files changed, 51 insertions(+), 33 deletions(-) diff --git a/IPC/ARAIPC.h b/IPC/ARAIPC.h index 0c1cbd9..bcbb685 100644 --- a/IPC/ARAIPC.h +++ b/IPC/ARAIPC.h @@ -193,6 +193,17 @@ typedef struct ARAIPCMessageSender //! @} +//! Companion API: opaque encapsulation +//! @{ +//! to keep the IPC decoupled from the Companion API in use, the IPC code uses an opaque token to represent a plug-in instance +typedef size_t ARAIPCPlugInInstanceRef; + +//! callback that the proxy uses to execute the binding of an opaque Companion API plug-in instance to the given document controller +typedef const ARAPlugInExtensionInstance* (*ARAIPCBindingHandler) (ARAIPCPlugInInstanceRef plugInInstanceRef, + ARADocumentControllerRef controllerRef, ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles); +//! @} + + #if defined(__cplusplus) } // extern "C" } // namespace IPC diff --git a/IPC/ARAIPCEncoding.h b/IPC/ARAIPCEncoding.h index 7cd023c..36b63f0 100644 --- a/IPC/ARAIPCEncoding.h +++ b/IPC/ARAIPCEncoding.h @@ -978,6 +978,7 @@ constexpr ARAIPCMessageID _encodeMessageID () constexpr ARAIPCMessageID kGetFactoriesCountMessageID { 1 }; constexpr ARAIPCMessageID kGetFactoryMessageID { 2 }; constexpr ARAIPCMessageID kCreateDocumentControllerMessageID { 3 }; +constexpr ARAIPCMessageID kBindToDocumentControllerMessageID { 4 }; // caller side: create a message with the specified arguments diff --git a/IPC/ARAIPCProxyHost.cpp b/IPC/ARAIPCProxyHost.cpp index 45d8117..ffdd1ad 100644 --- a/IPC/ARAIPCProxyHost.cpp +++ b/IPC/ARAIPCProxyHost.cpp @@ -585,6 +585,7 @@ using namespace ProxyHost; std::vector _factories {}; ARAIPCMessageSender _plugInCallbacksSender {}; +ARAIPCBindingHandler _bindingHandler {}; void ARAIPCProxyHostAddFactory (const ARAFactory* factory) { @@ -599,19 +600,14 @@ void ARAIPCProxyHostSetPlugInCallbacksSender (ARAIPCMessageSender plugInCallback _plugInCallbacksSender = plugInCallbacksSender; } -ARADocumentControllerRef ARAIPCProxyHostTranslateDocumentControllerRef (ARADocumentControllerRef remoteRef) +void ARAIPCProxyHostSetBindingHandler(ARAIPCBindingHandler handler) { - return fromRef (remoteRef)->getRef (); + _bindingHandler = handler; } -ARAPlugInExtensionRef ARAIPCProxyHostCreatePlugInExtension (const ARAPlugInExtensionInstance* instance) +void ARAIPCProxyHostCleanupBinding (const ARA::ARAPlugInExtensionInstance* plugInExtensionInstance) { - return toRef (new PlugInExtension { instance }); -} - -void ARAIPCProxyHostDestroyPlugInExtension (ARAPlugInExtensionRef plugInExtensionRef) -{ - delete fromRef (plugInExtensionRef); + delete fromRef (plugInExtensionInstance->plugInExtensionRef); } void ARAIPCProxyHostCommandHandler (const ARAIPCMessageID messageID, const ARAIPCMessageDecoder* const decoder, ARAIPCMessageEncoder* const replyEncoder) @@ -677,6 +673,16 @@ void ARAIPCProxyHostCommandHandler (const ARAIPCMessageID messageID, const ARAIP return encodeReply (replyEncoder, ARADocumentControllerRef { toRef (documentController) }); } } + else if (messageID == kBindToDocumentControllerMessageID) + { + ARAIPCPlugInInstanceRef plugInInstanceRef; + ARADocumentControllerRef controllerRef; + ARAPlugInInstanceRoleFlags knownRoles; + ARAPlugInInstanceRoleFlags assignedRoles; + decodeArguments (decoder, plugInInstanceRef, controllerRef, knownRoles, assignedRoles); + const auto plugInExtensionInstance { _bindingHandler (plugInInstanceRef, fromRef (controllerRef)->getRef (), knownRoles, assignedRoles) }; + return encodeReply (replyEncoder, ARAPlugInExtensionRef { toRef (new PlugInExtension { plugInExtensionInstance })}); + } //ARADocumentControllerInterface else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyDocumentController)) diff --git a/IPC/ARAIPCProxyHost.h b/IPC/ARAIPCProxyHost.h index c650b45..aaa657a 100644 --- a/IPC/ARAIPCProxyHost.h +++ b/IPC/ARAIPCProxyHost.h @@ -19,11 +19,10 @@ #ifndef ARAIPCProxyHost_h #define ARAIPCProxyHost_h - #include "ARA_Library/IPC/ARAIPC.h" -#if ARA_ENABLE_IPC +#if ARA_ENABLE_IPC #if defined(__cplusplus) namespace ARA { @@ -38,15 +37,14 @@ void ARAIPCProxyHostAddFactory(const ARAFactory * factory); //! static configuration: set sender that the proxy host will use to perform callbacks received from the plug-in void ARAIPCProxyHostSetPlugInCallbacksSender(ARAIPCMessageSender plugInCallbacksSender); +//! static configuration: set the callback to execute the binding of Companion API plug-in instances to ARA document controllers +void ARAIPCProxyHostSetBindingHandler(ARAIPCBindingHandler handler); + //! static dispatcher: the host command handler that controls the proxy host void ARAIPCProxyHostCommandHandler(const ARAIPCMessageID messageID, const ARAIPCMessageDecoder * decoder, ARAIPCMessageEncoder * replyEncoder); -//! translation needed when establishing the binding to the remote documentController -ARADocumentControllerRef ARAIPCProxyHostTranslateDocumentControllerRef(ARADocumentControllerRef remoteRef); - -//! creating and deleting plug-in extension instances associated with the proxy host -ARAPlugInExtensionRef ARAIPCProxyHostCreatePlugInExtension(const ARAPlugInExtensionInstance * instance); -void ARAIPCProxyHostDestroyPlugInExtension(ARAPlugInExtensionRef plugInExtensionRef); +//! trigger proper teardown of proxy plug-in extension when destroying Companion API plug-in instances that have been bound to ARA +void ARAIPCProxyHostCleanupBinding(const ARAPlugInExtensionInstance * plugInExtensionInstance); #if defined(__cplusplus) @@ -55,7 +53,6 @@ void ARAIPCProxyHostDestroyPlugInExtension(ARAPlugInExtensionRef plugInExtension } // namespace ARA #endif - #endif // ARA_ENABLE_IPC #endif // ARAIPCProxyHost_h diff --git a/IPC/ARAIPCProxyPlugIn.cpp b/IPC/ARAIPCProxyPlugIn.cpp index bb1cd4a..6e74e24 100644 --- a/IPC/ARAIPCProxyPlugIn.cpp +++ b/IPC/ARAIPCProxyPlugIn.cpp @@ -1304,18 +1304,22 @@ const ARADocumentControllerInstance* ARAIPCProxyPlugInCreateDocumentControllerWi return result->getInstance (); } -ARADocumentControllerRef ARAIPCProxyPlugInTranslateDocumentControllerRef (ARADocumentControllerRef documentControllerRef) -{ - return static_cast (PlugIn::fromRef (documentControllerRef))->getRemoteRef (); -} - -const ARAPlugInExtensionInstance* ARAIPCProxyPlugInCreatePlugInExtension (size_t remoteExtensionRef, ARAIPCMessageSender sender, ARADocumentControllerRef documentControllerRef, +const ARAPlugInExtensionInstance* ARAIPCProxyPlugInBindToDocumentController (ARAIPCPlugInInstanceRef remoteRef, ARAIPCMessageSender sender, ARADocumentControllerRef documentControllerRef, ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles) { + const auto remoteDocumentControllerRef { static_cast (PlugIn::fromRef (documentControllerRef))->getRemoteRef () }; + + size_t remoteExtensionRef {}; + RemoteCaller::CustomDecodeFunction customDecode { [&remoteExtensionRef] (const ARAIPCMessageDecoder& decoder) -> void + { + decoder.methods->readSize (decoder.ref, 0, &remoteExtensionRef); + } }; + RemoteCaller { sender }.remoteCallWithReply (customDecode, false, kBindToDocumentControllerMessageID, remoteRef, remoteDocumentControllerRef, knownRoles, assignedRoles); + return new PlugInExtension { sender, documentControllerRef, knownRoles, assignedRoles, remoteExtensionRef }; } -void ARAIPCProxyPlugInDestroyPlugInExtension (const ARAPlugInExtensionInstance* plugInExtensionInstance) +void ARAIPCProxyPlugInCleanupBinding (const ARAPlugInExtensionInstance* plugInExtensionInstance) { delete static_cast (plugInExtensionInstance); } diff --git a/IPC/ARAIPCProxyPlugIn.h b/IPC/ARAIPCProxyPlugIn.h index 80ab224..2997f47 100644 --- a/IPC/ARAIPCProxyPlugIn.h +++ b/IPC/ARAIPCProxyPlugIn.h @@ -48,14 +48,13 @@ const ARADocumentControllerInstance * ARAIPCProxyPlugInCreateDocumentControllerW //! static handler of received messages void ARAIPCProxyPlugInCallbacksDispatcher(const ARAIPCMessageID messageID, const ARAIPCMessageDecoder * decoder, ARAIPCMessageEncoder * replyEncoder); -//! \todo to perform the binding to the remote plug-in instance, the host needs access to this translation... -ARADocumentControllerRef ARAIPCProxyPlugInTranslateDocumentControllerRef(ARADocumentControllerRef documentControllerRef); - -//! create the plug-in extension when performing the binding to the remote plug-in instance -const ARAPlugInExtensionInstance * ARAIPCProxyPlugInCreatePlugInExtension(size_t remoteExtensionRef, ARAIPCMessageSender sender, ARADocumentControllerRef documentControllerRef, - ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles); -//! destroy the plug-in extension when destroying the remote plug-in instance -void ARAIPCProxyPlugInDestroyPlugInExtension(const ARAPlugInExtensionInstance * plugInExtension); +//! create the proxy plug-in extension when performing the binding to the remote plug-in instance +const ARAPlugInExtensionInstance * ARAIPCProxyPlugInBindToDocumentController(ARAIPCPlugInInstanceRef remoteRef, + ARAIPCMessageSender sender, ARADocumentControllerRef documentControllerRef, + ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles); + +//! trigger proper teardown of proxy plug-in extension upon destroying a remote plug-in instance that has been bound to ARA +void ARAIPCProxyPlugInCleanupBinding(const ARAPlugInExtensionInstance * plugInExtension); #if defined(__cplusplus) From e5bf6a50452fda5dd5ebb9191a7b2e6a91237cc0 Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:32:00 +0100 Subject: [PATCH 12/18] Add proper support of ARA (un)initialization to IPC proxy --- IPC/ARAIPCEncoding.h | 14 ++++++++---- IPC/ARAIPCProxyHost.cpp | 45 ++++++++++++++++++++++++++++----------- IPC/ARAIPCProxyPlugIn.cpp | 11 ++++++++++ IPC/ARAIPCProxyPlugIn.h | 8 +++++++ PlugIn/ARAPlug.cpp | 3 +++ 5 files changed, 64 insertions(+), 17 deletions(-) diff --git a/IPC/ARAIPCEncoding.h b/IPC/ARAIPCEncoding.h index 36b63f0..b820fab 100644 --- a/IPC/ARAIPCEncoding.h +++ b/IPC/ARAIPCEncoding.h @@ -974,11 +974,17 @@ constexpr ARAIPCMessageID _encodeMessageID () #define ARA_IPC_HOST_METHOD_ID(StructT, member) IPC::_encodeMessageID (), offsetof (StructT, member)> () #define ARA_IPC_PLUGIN_METHOD_ID(StructT, member) IPC::_encodeMessageID (), offsetof (StructT, member)> () + // "global" messages that are not passed based on interface structs -constexpr ARAIPCMessageID kGetFactoriesCountMessageID { 1 }; -constexpr ARAIPCMessageID kGetFactoryMessageID { 2 }; -constexpr ARAIPCMessageID kCreateDocumentControllerMessageID { 3 }; -constexpr ARAIPCMessageID kBindToDocumentControllerMessageID { 4 }; +enum : ARA::IPC::ARAIPCMessageID +{ + kGetFactoriesCountMessageID = 1, + kGetFactoryMessageID = 2, + kInitializeARAMessageID = 3, + kCreateDocumentControllerMessageID = 4, + kBindToDocumentControllerMessageID = 5, + kUninitializeARAMessageID = 6 +}; // caller side: create a message with the specified arguments diff --git a/IPC/ARAIPCProxyHost.cpp b/IPC/ARAIPCProxyHost.cpp index ffdd1ad..cc741a7 100644 --- a/IPC/ARAIPCProxyHost.cpp +++ b/IPC/ARAIPCProxyHost.cpp @@ -610,6 +610,18 @@ void ARAIPCProxyHostCleanupBinding (const ARA::ARAPlugInExtensionInstance* plugI delete fromRef (plugInExtensionInstance->plugInExtensionRef); } +const ARAFactory* getFactoryWithID (ARAPersistentID factoryID) +{ + for (const auto& factory : _factories) + { + if (0 == std::strcmp (factory->factoryID, factoryID)) + return factory; + } + + ARA_INTERNAL_ASSERT(false && "provided factory ID not previously registered via ARAIPCProxyHostAddFactory()"); + return nullptr; +} + void ARAIPCProxyHostCommandHandler (const ARAIPCMessageID messageID, const ARAIPCMessageDecoder* const decoder, ARAIPCMessageEncoder* const replyEncoder) { // ARA_LOG ("ARAIPCProxyHostCommandHandler received message %s", decodePlugInMessageID (messageID)); @@ -626,6 +638,16 @@ void ARAIPCProxyHostCommandHandler (const ARAIPCMessageID messageID, const ARAIP ARA_INTERNAL_ASSERT (index < _factories.size ()); return encodeReply (replyEncoder, *_factories[index]); } + else if (messageID == kInitializeARAMessageID) + { + ARAPersistentID factoryID; + ARA::SizedStruct interfaceConfig = { kARAAPIGeneration_2_0_Final, nullptr }; + decodeArguments (decoder, factoryID, interfaceConfig.desiredApiGeneration); + ARA_INTERNAL_ASSERT (interfaceConfig.desiredApiGeneration >= kARAAPIGeneration_2_0_Final); + + if (const ARAFactory* const factory { getFactoryWithID (factoryID) }) + factory->initializeARAWithConfiguration(&interfaceConfig); + } else if (messageID == kCreateDocumentControllerMessageID) { ARAPersistentID factoryID; @@ -645,17 +667,7 @@ void ARAIPCProxyHostCommandHandler (const ARAIPCMessageID messageID, const ARAIP providePlaybackController, playbackControllerHostRef, properties); - const ARAFactory* factory {}; - for (const auto& f : _factories) - { - if (0 == std::strcmp (f->factoryID, factoryID)) - { - factory = f; - break; - } - } - ARA_INTERNAL_ASSERT (factory != nullptr); - if (factory != nullptr) + if (const ARAFactory* const factory { getFactoryWithID (factoryID) }) { const auto audioAccessController { new AudioAccessController { _plugInCallbacksSender, audioAccessControllerHostRef } }; const auto archivingController { new ArchivingController { _plugInCallbacksSender, archivingControllerHostRef } }; @@ -683,6 +695,14 @@ void ARAIPCProxyHostCommandHandler (const ARAIPCMessageID messageID, const ARAIP const auto plugInExtensionInstance { _bindingHandler (plugInInstanceRef, fromRef (controllerRef)->getRef (), knownRoles, assignedRoles) }; return encodeReply (replyEncoder, ARAPlugInExtensionRef { toRef (new PlugInExtension { plugInExtensionInstance })}); } + else if (messageID == kUninitializeARAMessageID) + { + ARAPersistentID factoryID; + decodeArguments (decoder, factoryID); + + if (const ARAFactory* const factory { getFactoryWithID (factoryID) }) + factory->uninitializeARA(); + } //ARADocumentControllerInterface else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyDocumentController)) @@ -1261,8 +1281,7 @@ void ARAIPCProxyHostCommandHandler (const ARAIPCMessageID messageID, const ARAIP } // all calls that create a reply return early from their respective if (). -// it is valid to provide a dummy replyEncoder if no reply has been requested. -// ARA_INTERNAL_ASSERT (replyEncoder == nullptr); +// ARA_INTERNAL_ASSERT ((replyEncoder == nullptr) || replyEncoder->methods->isEmpty (replyEncoder->ref)); } } // namespace IPC diff --git a/IPC/ARAIPCProxyPlugIn.cpp b/IPC/ARAIPCProxyPlugIn.cpp index 6e74e24..79f1ce7 100644 --- a/IPC/ARAIPCProxyPlugIn.cpp +++ b/IPC/ARAIPCProxyPlugIn.cpp @@ -1291,6 +1291,12 @@ const ARAFactory* ARAIPCProxyPlugInGetFactoryAtIndex (ARAIPCMessageSender hostCo return &result.first->second._factory; } +void ARAIPCProxyPlugInInitializeARA (ARAIPCMessageSender hostCommandsSender, const ARAPersistentID factoryID, ARAAPIGeneration desiredApiGeneration) +{ + ARA_INTERNAL_ASSERT (desiredApiGeneration >= kARAAPIGeneration_2_0_Final); + RemoteCaller { hostCommandsSender }.remoteCallWithoutReply(false, kInitializeARAMessageID, factoryID, desiredApiGeneration); +} + const ARADocumentControllerInstance* ARAIPCProxyPlugInCreateDocumentControllerWithDocument ( ARAIPCMessageSender hostCommandsSender, const ARAPersistentID factoryID, const ARADocumentControllerHostInstance* hostInstance, const ARADocumentProperties* properties) @@ -1324,6 +1330,11 @@ void ARAIPCProxyPlugInCleanupBinding (const ARAPlugInExtensionInstance* plugInEx delete static_cast (plugInExtensionInstance); } +void ARAIPCProxyPlugInUninitializeARA (ARAIPCMessageSender hostCommandsSender, const ARAPersistentID factoryID) +{ + RemoteCaller { hostCommandsSender }.remoteCallWithoutReply (false, kUninitializeARAMessageID, factoryID); +} + void ARAIPCProxyPlugInCallbacksDispatcher (const ARAIPCMessageID messageID, const ARAIPCMessageDecoder* const decoder, ARAIPCMessageEncoder* const replyEncoder) { // ARA_LOG ("plugInCallbackDispatcher received message %s", decodeHostMessageID (messageID)); diff --git a/IPC/ARAIPCProxyPlugIn.h b/IPC/ARAIPCProxyPlugIn.h index 2997f47..c5e85d6 100644 --- a/IPC/ARAIPCProxyPlugIn.h +++ b/IPC/ARAIPCProxyPlugIn.h @@ -39,6 +39,11 @@ size_t ARAIPCProxyPlugInGetFactoriesCount(ARAIPCMessageSender hostCommandsSender //! index must be smaller than the result of ARAIPCProxyPlugInGetFactoriesCount() const ARAFactory * ARAIPCProxyPlugInGetFactoryAtIndex(ARAIPCMessageSender hostCommandsSender, size_t index); +//! proxy initialization call, to be used instead of ARAFactory.initializeARAWithConfiguration() +// \todo we're currently not supporting propagating ARA assertions through IPC, +// because it would require to make all calls stackable... +void ARAIPCProxyPlugInInitializeARA(ARAIPCMessageSender hostCommandsSender, const ARAPersistentID factoryID, ARAAPIGeneration desiredApiGeneration); + //! proxy document controller creation call, to be used instead of ARAFactory.createDocumentControllerWithDocument() const ARADocumentControllerInstance * ARAIPCProxyPlugInCreateDocumentControllerWithDocument(ARAIPCMessageSender hostCommandsSender, const ARAPersistentID factoryID, @@ -56,6 +61,9 @@ const ARAPlugInExtensionInstance * ARAIPCProxyPlugInBindToDocumentController(ARA //! trigger proper teardown of proxy plug-in extension upon destroying a remote plug-in instance that has been bound to ARA void ARAIPCProxyPlugInCleanupBinding(const ARAPlugInExtensionInstance * plugInExtension); +//! proxy uninitialization call, to be used instead of ARAFactory.uninitializeARA() +void ARAIPCProxyPlugInUninitializeARA(ARAIPCMessageSender hostCommandsSender, const ARAPersistentID factoryID); + #if defined(__cplusplus) } // extern "C" diff --git a/PlugIn/ARAPlug.cpp b/PlugIn/ARAPlug.cpp index 08ad19d..533c560 100644 --- a/PlugIn/ARAPlug.cpp +++ b/PlugIn/ARAPlug.cpp @@ -2815,6 +2815,9 @@ void PlugInEntry::uninitializeARA () noexcept const ARADocumentControllerInstance* PlugInEntry::createDocumentControllerWithDocument (const ARADocumentControllerHostInstance* hostInstance, const ARADocumentProperties* properties) noexcept { ARA_LOG_HOST_ENTRY (nullptr); + + ARA_VALIDATE_API_STATE ((_usedApiGeneration != 0) && "ARAFactory::initializeARAWithConfiguration () not called!"); + ARA_VALIDATE_API_STRUCT_PTR (hostInstance, ARADocumentControllerHostInstance); ARA_VALIDATE_API_INTERFACE (hostInstance->audioAccessControllerInterface, ARAAudioAccessControllerInterface); ARA_VALIDATE_API_INTERFACE (hostInstance->archivingControllerInterface, ARAArchivingControllerInterface); From 3feecf1aef45e7f182c741601f7bd4a3efe47529 Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:32:00 +0100 Subject: [PATCH 13/18] Add draft of channel arrangement to IPC --- IPC/ARAIPCEncoding.h | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/IPC/ARAIPCEncoding.h b/IPC/ARAIPCEncoding.h index b820fab..b8654d6 100644 --- a/IPC/ARAIPCEncoding.h +++ b/IPC/ARAIPCEncoding.h @@ -28,6 +28,7 @@ #include "ARA_Library/Debug/ARADebug.h" #include "ARA_Library/Dispatch/ARAContentReader.h" +#include "ARA_Library/Utilities/ARAChannelArrangement.h" #include #include @@ -582,6 +583,22 @@ ARA_IPC_BEGIN_ENCODE (ARAAudioSourceProperties) ARA_IPC_ENCODE_MEMBER (sampleRate) ARA_IPC_ENCODE_MEMBER (channelCount) ARA_IPC_ENCODE_MEMBER (merits64BitSamples) + ARA_IPC_ENCODE_ADDENDUM_MEMBER (channelArrangementDataType) + if (ARA_IPC_HAS_ADDENDUM_MEMBER (channelArrangement)) + { + // \todo potential endianess conversion is missing here if needed - but this is not known here, + // it must be performed in the calling code. + // this means the caller would need to copy the incoming data for mutation - + // maybe it would be better to move receiverEndianessMatches () from the sending side to + // the receiving side? We need to review how such a change would affect audio readers etc. + const ChannelArrangement channelArrangement { value.channelArrangementDataType, value.channelArrangement }; + const auto size { channelArrangement.getDataSize () }; + if (size > 0) + { + const BytesEncoder tmp_channelArrangement { reinterpret_cast (value.channelArrangement), size, true }; + _encodeAndAppend (encoder, offsetof (ARAAudioSourceProperties, channelArrangement), tmp_channelArrangement); + } + } ARA_IPC_END_ENCODE ARA_IPC_BEGIN_DECODE_SIZED (ARAAudioSourceProperties) ARA_IPC_DECODE_OPTIONAL_MEMBER (name) @@ -590,6 +607,40 @@ ARA_IPC_BEGIN_DECODE_SIZED (ARAAudioSourceProperties) ARA_IPC_DECODE_MEMBER (sampleRate) ARA_IPC_DECODE_MEMBER (channelCount) ARA_IPC_DECODE_MEMBER (merits64BitSamples) + ARA_IPC_DECODE_ADDENDUM_MEMBER (channelArrangementDataType) + if (result.structSize > offsetof (ARAAudioSourceProperties, channelArrangementDataType)) + { + ARA_IPC_UPDATE_STRUCT_SIZE_FOR_OPTIONAL (channelArrangement); + + if (result.channelArrangementDataType == kARAChannelArrangementUndefined) + { + result.channelArrangement = nullptr; + } + else + { + /* \todo the outer struct contains a pointer to the inner struct, so we need some */ + /* place to store it - this static only works as long as this is single-threaded! */ + static union + { + ARAInt64 speakerArrangement; + ARAInt32 stemFormat; + ARAByte audioChannelLayoutBytes[2016UL]; // some arbitrary limit that can be conveniently allocated + } cache; + auto resultSize_channelArrangement { sizeof (cache.audioChannelLayoutBytes) }; + BytesDecoder tmp_channelArrangement { cache.audioChannelLayoutBytes, resultSize_channelArrangement }; + if (_readAndDecode (tmp_channelArrangement, decoder, offsetof (ARAAudioSourceProperties, channelArrangement)) && + (resultSize_channelArrangement < sizeof (cache.audioChannelLayoutBytes))) + { + result.channelArrangement = &cache.audioChannelLayoutBytes; + } + else + { + result.channelArrangementDataType = kARAChannelArrangementUndefined; + result.channelArrangement = nullptr; + success = false; + } + } + } ARA_IPC_END_DECODE ARA_IPC_BEGIN_ENCODE (ARAAudioModificationProperties) From c53aa69225f5f62bf45aa110026b4ff4265570db Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:32:00 +0100 Subject: [PATCH 14/18] Add draft of isAudioModificationPreservingAudioSourceSignal() to IPC --- IPC/ARAIPCProxyHost.cpp | 8 ++++++++ IPC/ARAIPCProxyPlugIn.cpp | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/IPC/ARAIPCProxyHost.cpp b/IPC/ARAIPCProxyHost.cpp index cc741a7..8d1bfd7 100644 --- a/IPC/ARAIPCProxyHost.cpp +++ b/IPC/ARAIPCProxyHost.cpp @@ -1008,6 +1008,14 @@ void ARAIPCProxyHostCommandHandler (const ARAIPCMessageID messageID, const ARAIP fromRef (controllerRef)->updateAudioModificationProperties (audioModificationRef, &properties); } + else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioModificationPreservingAudioSourceSignal)) + { + ARADocumentControllerRef controllerRef; + ARAAudioModificationRef audioModificationRef; + decodeArguments (decoder, controllerRef, audioModificationRef); + + return encodeReply (replyEncoder, (fromRef (controllerRef)->isAudioModificationPreservingAudioSourceSignal (audioModificationRef)) ? kARATrue : kARAFalse); + } else if (messageID == ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, deactivateAudioModificationForUndoHistory)) { ARADocumentControllerRef controllerRef; diff --git a/IPC/ARAIPCProxyPlugIn.cpp b/IPC/ARAIPCProxyPlugIn.cpp index 79f1ce7..c3de12e 100644 --- a/IPC/ARAIPCProxyPlugIn.cpp +++ b/IPC/ARAIPCProxyPlugIn.cpp @@ -239,6 +239,7 @@ class DocumentController : public PlugIn::DocumentControllerInterface, protected ARAAudioModificationRef createAudioModification (ARAAudioSourceRef audioSourceRef, ARAAudioModificationHostRef hostRef, PropertiesPtr properties) noexcept override; ARAAudioModificationRef cloneAudioModification (ARAAudioModificationRef audioModificationRef, ARAAudioModificationHostRef hostRef, PropertiesPtr properties) noexcept override; void updateAudioModificationProperties (ARAAudioModificationRef audioModificationRef, PropertiesPtr properties) noexcept override; + bool isAudioModificationPreservingAudioSourceSignal (ARAAudioModificationRef audioModificationRef) noexcept override; void deactivateAudioModificationForUndoHistory (ARAAudioModificationRef audioModificationRef, bool deactivate) noexcept override; void destroyAudioModification (ARAAudioModificationRef audioModificationRef) noexcept override; @@ -699,6 +700,16 @@ void DocumentController::updateAudioModificationProperties (ARAAudioModification remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioModificationProperties), _remoteRef, audioModificationRef, *properties); } +bool DocumentController::isAudioModificationPreservingAudioSourceSignal (ARAAudioModificationRef audioModificationRef) noexcept +{ + ARA_LOG_HOST_ENTRY (audioModificationRef); + ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); + + ARABool result; + remoteCallWithReply (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioModificationPreservingAudioSourceSignal), _remoteRef, audioModificationRef); + return (result != kARAFalse); +} + void DocumentController::deactivateAudioModificationForUndoHistory (ARAAudioModificationRef audioModificationRef, bool deactivate) noexcept { ARA_LOG_HOST_ENTRY (audioModificationRef); From 419267bca026437a24aacd5fecb556f5b68fdfcb Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:32:00 +0100 Subject: [PATCH 15/18] Unify remoteCallWith/WithoutReply() by adding an intermediate wrapper for IPC message IDs to resolve overload ambiguities --- IPC/ARAIPCEncoding.h | 103 ++++++++++++++++-------- IPC/ARAIPCProxyHost.cpp | 89 ++++++++++----------- IPC/ARAIPCProxyPlugIn.cpp | 160 +++++++++++++++++++------------------- 3 files changed, 192 insertions(+), 160 deletions(-) diff --git a/IPC/ARAIPCEncoding.h b/IPC/ARAIPCEncoding.h index b8654d6..05cc953 100644 --- a/IPC/ARAIPCEncoding.h +++ b/IPC/ARAIPCEncoding.h @@ -999,44 +999,79 @@ constexpr ARAIPCMessageID _getPlugInInterfaceID () { template<> constexpr ARAIPCMessageID _getPlugInInterfaceID () { return 3; } -template -constexpr ARAIPCMessageID _encodeMessageID () -{ - static_assert (offset > 0, "offset 0 is never a valid function pointer"); - static_assert ((interfaceID < 8), "currently using only 3 bits for interface ID"); -#if defined (__i386__) || defined (_M_IX86) - static_assert ((sizeof (void*) == 4), "compiler settings imply 32 bit pointers"); - static_assert (((offset & 0x3FFFFFF4) == offset), "offset is misaligned or too large"); - return (offset << 1) + interfaceID; // lower 2 bits of offset are 0 due to alignment, must shift 1 bit to store interface ID -#else - static_assert ((sizeof (void*) == 8), "assuming 64 bit pointers per default"); - static_assert (((offset & 0x7FFFFFF8) == offset), "offset is misaligned or too large"); - return offset + interfaceID; // lower 3 bits of offset are 0 due to alignment, can be used to store interface ID -#endif -} - //------------------------------------------------------------------------------ // actual client API //------------------------------------------------------------------------------ -// caller side: create a message ID for a given ARA method -#define ARA_IPC_HOST_METHOD_ID(StructT, member) IPC::_encodeMessageID (), offsetof (StructT, member)> () -#define ARA_IPC_PLUGIN_METHOD_ID(StructT, member) IPC::_encodeMessageID (), offsetof (StructT, member)> () +// helper class wrapping ARAIPCMessageID to prevent implicit conversions to/from +// ARAIPCMessageID, so that they can be identified reliably in call signatures +// this is important e.g. for the various forms of RemoteCaller::remoteCall (). +class MethodID +{ +private: + constexpr MethodID (ARAIPCMessageID messageID) : _id { messageID } {} +public: + template + static inline constexpr MethodID createWithARAInterfaceIDAndOffset () + { + static_assert (offset > 0, "offset 0 is never a valid function pointer"); + static_assert ((interfaceID < 8), "currently using only 3 bits for interface ID"); + #if defined (__i386__) || defined (_M_IX86) + static_assert ((sizeof (void*) == 4), "compiler settings imply 32 bit pointers"); + static_assert (((offset & 0x3FFFFFF4) == offset), "offset is misaligned or too large"); + return (offset << 1) + interfaceID; // lower 2 bits of offset are 0 due to alignment, must shift 1 bit to store interface ID + #else + static_assert ((sizeof (void*) == 8), "assuming 64 bit pointers per default"); + static_assert (((offset & 0x7FFFFFF8) == offset), "offset is misaligned or too large"); + return offset + interfaceID; // lower 3 bits of offset are 0 due to alignment, can be used to store interface ID + #endif + } -// "global" messages that are not passed based on interface structs -enum : ARA::IPC::ARAIPCMessageID -{ - kGetFactoriesCountMessageID = 1, - kGetFactoryMessageID = 2, - kInitializeARAMessageID = 3, - kCreateDocumentControllerMessageID = 4, - kBindToDocumentControllerMessageID = 5, - kUninitializeARAMessageID = 6 + template + static inline constexpr MethodID createWithARASetupMethodID () + { + static_assert ((methodID >= kARAIPCMessageIDRangeStart) && (methodID < kARAIPCMessageIDRangeEnd), "must be in valid ARA message ID range"); + return methodID; + } + + template + static inline constexpr MethodID createWithNonARAMethodID () + { + static_assert ((methodID < kARAIPCMessageIDRangeStart) || (methodID >= kARAIPCMessageIDRangeStart), "must not be in valid ARA message range"); + return methodID; + } + + constexpr ARAIPCMessageID getMessageID () const { return _id; } +private: + const ARAIPCMessageID _id; }; +inline bool operator== (const ARAIPCMessageID messageID, const MethodID methodID) +{ + return (messageID == methodID.getMessageID ()); +} +inline bool operator== (const MethodID methodID, const ARAIPCMessageID messageID) +{ + return (messageID == methodID.getMessageID ()); +} + + +// create a MethodID for a given host-side or plug-in-side ARA method +#define ARA_IPC_HOST_METHOD_ID(StructT, member) MethodID::createWithARAInterfaceIDAndOffset <_getHostInterfaceID (), offsetof (StructT, member)> () +#define ARA_IPC_PLUGIN_METHOD_ID(StructT, member) MethodID::createWithARAInterfaceIDAndOffset <_getPlugInInterfaceID (), offsetof (StructT, member)> () + + +// "global" messages for startup and teardown that are not calculated based on interface structs +constexpr auto kGetFactoriesCountMethodID { MethodID::createWithARASetupMethodID<1> () }; +constexpr auto kGetFactoryMethodID { MethodID::createWithARASetupMethodID<2> () }; +constexpr auto kInitializeARAMethodID { MethodID::createWithARASetupMethodID<3> () }; +constexpr auto kCreateDocumentControllerMethodID { MethodID::createWithARASetupMethodID<4> () }; +constexpr auto kBindToDocumentControllerMethodID { MethodID::createWithARASetupMethodID<5> () }; +constexpr auto kUninitializeARAMethodID { MethodID::createWithARASetupMethodID<6> () }; + // caller side: create a message with the specified arguments template @@ -1244,16 +1279,16 @@ class RemoteCaller RemoteCaller (ARAIPCMessageSender sender) noexcept : _sender { sender } {} template - void remoteCallWithoutReply (const bool stackable, const ARAIPCMessageID messageID, const Args &... args) + void remoteCall (const bool stackable, const MethodID methodID, const Args &... args) { auto encoder { _sender.methods->createEncoder (_sender.ref) }; encodeArguments (encoder, args...); - _sender.methods->sendMessage (stackable, _sender.ref, messageID, &encoder, nullptr, nullptr); + _sender.methods->sendMessage (stackable, _sender.ref, methodID.getMessageID (), &encoder, nullptr, nullptr); encoder.methods->destroyEncoder (encoder.ref); } template - void remoteCallWithReply (RetT& result, const bool stackable, const ARAIPCMessageID messageID, const Args &... args) + void remoteCall (RetT& result, const bool stackable, const MethodID methodID, const Args &... args) { auto encoder { _sender.methods->createEncoder (_sender.ref) }; encodeArguments (encoder, args...); @@ -1262,11 +1297,11 @@ class RemoteCaller ARA_INTERNAL_ASSERT (!decoder.methods->isEmpty (decoder.ref)); decodeReply (*reinterpret_cast (userData), decoder); } }; - _sender.methods->sendMessage (stackable, _sender.ref, messageID, &encoder, &replyHandler, &result); + _sender.methods->sendMessage (stackable, _sender.ref, methodID.getMessageID (), &encoder, &replyHandler, &result); encoder.methods->destroyEncoder (encoder.ref); } template - void remoteCallWithReply (CustomDecodeFunction& decodeFunction, const bool stackable, const ARAIPCMessageID messageID, const Args &... args) + void remoteCall (CustomDecodeFunction& decodeFunction, const bool stackable, const MethodID methodID, const Args &... args) { auto encoder { _sender.methods->createEncoder (_sender.ref) }; encodeArguments (encoder, args...); @@ -1275,7 +1310,7 @@ class RemoteCaller ARA_INTERNAL_ASSERT (!decoder.methods->isEmpty (decoder.ref)); (*reinterpret_cast (userData)) (decoder); } }; - _sender.methods->sendMessage (stackable, _sender.ref, messageID, &encoder, &replyHandler, &decodeFunction); + _sender.methods->sendMessage (stackable, _sender.ref, methodID.getMessageID (), &encoder, &replyHandler, &decodeFunction); encoder.methods->destroyEncoder (encoder.ref); } diff --git a/IPC/ARAIPCProxyHost.cpp b/IPC/ARAIPCProxyHost.cpp index 8d1bfd7..5c1c293 100644 --- a/IPC/ARAIPCProxyHost.cpp +++ b/IPC/ARAIPCProxyHost.cpp @@ -147,7 +147,8 @@ ARAAudioReaderHostRef AudioAccessController::createAudioReaderForSource (ARAAudi remoteAudioReader->swapFunction = nullptr; else remoteAudioReader->swapFunction = (use64BitSamples) ? &_swapBuffer : &_swapBuffer; - remoteCallWithReply (remoteAudioReader->mainHostRef, false, ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, createAudioReaderForSource), _remoteHostRef, remoteAudioReader->audioSource->mainHostRef, use64BitSamples); + remoteCall (remoteAudioReader->mainHostRef, false, ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, createAudioReaderForSource), + _remoteHostRef, remoteAudioReader->audioSource->mainHostRef, use64BitSamples); return toHostRef (remoteAudioReader); } @@ -216,15 +217,15 @@ bool AudioAccessController::readAudioSamples (ARAAudioReaderHostRef audioReaderH } } }; - remoteCallWithReply (customDecode, false, ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, readAudioSamples), - _remoteHostRef, remoteAudioReader->mainHostRef, samplePosition, samplesPerChannel); + remoteCall (customDecode, false, ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, readAudioSamples), + _remoteHostRef, remoteAudioReader->mainHostRef, samplePosition, samplesPerChannel); return success; } void AudioAccessController::destroyAudioReader (ARAAudioReaderHostRef audioReaderHostRef) noexcept { auto remoteAudioReader { fromHostRef (audioReaderHostRef) }; - remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, destroyAudioReader), _remoteHostRef, remoteAudioReader->mainHostRef); + remoteCall (false, ARA_IPC_HOST_METHOD_ID (ARAAudioAccessControllerInterface, destroyAudioReader), _remoteHostRef, remoteAudioReader->mainHostRef); delete remoteAudioReader; } @@ -254,7 +255,7 @@ class ArchivingController : public Host::ArchivingControllerInterface, public Re ARASize ArchivingController::getArchiveSize (ARAArchiveReaderHostRef archiveReaderHostRef) noexcept { ARASize size; - remoteCallWithReply (size, false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, getArchiveSize), _remoteHostRef, archiveReaderHostRef); + remoteCall (size, false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, getArchiveSize), _remoteHostRef, archiveReaderHostRef); return size; } @@ -281,7 +282,7 @@ bool ArchivingController::readBytesFromArchive (ARAArchiveReaderHostRef archiveR auto resultLength { length }; BytesDecoder writer { buffer, resultLength }; - remoteCallWithReply (writer, false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, readBytesFromArchive), + remoteCall (writer, false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, readBytesFromArchive), _remoteHostRef, archiveReaderHostRef, position, length); if (resultLength == length) { @@ -305,29 +306,25 @@ bool ArchivingController::writeBytesToArchive (ARAArchiveWriterHostRef archiveWr const auto length2 { length - length1 }; buffer += length1; if (result1) - { return writeBytesToArchive (archiveWriterHostRef, position + length1, length2, buffer); - } else - { return false; - } } ARABool success; - remoteCallWithReply (success, false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, writeBytesToArchive), + remoteCall (success, false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, writeBytesToArchive), _remoteHostRef, archiveWriterHostRef, position, BytesEncoder { buffer, length, false }); return (success != kARAFalse); } void ArchivingController::notifyDocumentArchivingProgress (float value) noexcept { - remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, notifyDocumentArchivingProgress), _remoteHostRef, value); + remoteCall (false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, notifyDocumentArchivingProgress), _remoteHostRef, value); } void ArchivingController::notifyDocumentUnarchivingProgress (float value) noexcept { - remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, notifyDocumentUnarchivingProgress), _remoteHostRef, value); + remoteCall (false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, notifyDocumentUnarchivingProgress), _remoteHostRef, value); } ARAPersistentID ArchivingController::getDocumentArchiveID (ARAArchiveReaderHostRef archiveReaderHostRef) noexcept @@ -338,7 +335,7 @@ ARAPersistentID ArchivingController::getDocumentArchiveID (ARAArchiveReaderHostR decodeReply (persistentID, decoder); _archiveID.assign (persistentID); } }; - remoteCallWithReply (customDecode, false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, getDocumentArchiveID), _remoteHostRef, archiveReaderHostRef); + remoteCall (customDecode, false, ARA_IPC_HOST_METHOD_ID (ARAArchivingControllerInterface, getDocumentArchiveID), _remoteHostRef, archiveReaderHostRef); return _archiveID.c_str(); } @@ -370,24 +367,24 @@ class ContentAccessController : public Host::ContentAccessControllerInterface, p bool ContentAccessController::isMusicalContextContentAvailable (ARAMusicalContextHostRef musicalContextHostRef, ARAContentType type) noexcept { ARABool result; - remoteCallWithReply (result, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, isMusicalContextContentAvailable), - _remoteHostRef, musicalContextHostRef, type); + remoteCall (result, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, isMusicalContextContentAvailable), + _remoteHostRef, musicalContextHostRef, type); return (result != kARAFalse); } ARAContentGrade ContentAccessController::getMusicalContextContentGrade (ARAMusicalContextHostRef musicalContextHostRef, ARAContentType type) noexcept { ARAContentGrade grade; - remoteCallWithReply (grade, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getMusicalContextContentGrade), - _remoteHostRef, musicalContextHostRef, type); + remoteCall (grade, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getMusicalContextContentGrade), + _remoteHostRef, musicalContextHostRef, type); return grade; } ARAContentReaderHostRef ContentAccessController::createMusicalContextContentReader (ARAMusicalContextHostRef musicalContextHostRef, ARAContentType type, const ARAContentTimeRange* range) noexcept { ARAContentReaderHostRef contentReaderHostRef; - remoteCallWithReply (contentReaderHostRef, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, createMusicalContextContentReader), - _remoteHostRef, musicalContextHostRef, type, range); + remoteCall (contentReaderHostRef, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, createMusicalContextContentReader), + _remoteHostRef, musicalContextHostRef, type, range); auto contentReader { new RemoteHostContentReader (contentReaderHostRef, type) }; return toHostRef (contentReader); } @@ -395,24 +392,24 @@ ARAContentReaderHostRef ContentAccessController::createMusicalContextContentRead bool ContentAccessController::isAudioSourceContentAvailable (ARAAudioSourceHostRef audioSourceHostRef, ARAContentType type) noexcept { ARABool result; - remoteCallWithReply (result, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, isAudioSourceContentAvailable), - _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, type); + remoteCall (result, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, isAudioSourceContentAvailable), + _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, type); return (result != kARAFalse); } ARAContentGrade ContentAccessController::getAudioSourceContentGrade (ARAAudioSourceHostRef audioSourceHostRef, ARAContentType type) noexcept { ARAContentGrade grade; - remoteCallWithReply (grade, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getAudioSourceContentGrade), - _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, type); + remoteCall (grade, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getAudioSourceContentGrade), + _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, type); return grade; } ARAContentReaderHostRef ContentAccessController::createAudioSourceContentReader (ARAAudioSourceHostRef audioSourceHostRef, ARAContentType type, const ARAContentTimeRange* range) noexcept { ARAContentReaderHostRef contentReaderHostRef; - remoteCallWithReply (contentReaderHostRef, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, createAudioSourceContentReader), - _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, type, range); + remoteCall (contentReaderHostRef, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, createAudioSourceContentReader), + _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, type, range); auto contentReader { new RemoteHostContentReader (contentReaderHostRef, type) }; return toHostRef (contentReader); } @@ -421,8 +418,8 @@ ARAInt32 ContentAccessController::getContentReaderEventCount (ARAContentReaderHo { const auto contentReader { fromHostRef (contentReaderHostRef) }; ARAInt32 count; - remoteCallWithReply (count, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getContentReaderEventCount), - _remoteHostRef, contentReader->remoteHostRef); + remoteCall (count, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getContentReaderEventCount), + _remoteHostRef, contentReader->remoteHostRef); return count; } @@ -434,15 +431,15 @@ const void* ContentAccessController::getContentReaderDataForEvent (ARAContentRea { result = contentReader->decoder.decode (decoder); } }; - remoteCallWithReply (customDecode, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getContentReaderDataForEvent), - _remoteHostRef, contentReader->remoteHostRef, eventIndex); + remoteCall (customDecode, false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, getContentReaderDataForEvent), + _remoteHostRef, contentReader->remoteHostRef, eventIndex); return result; } void ContentAccessController::destroyContentReader (ARAContentReaderHostRef contentReaderHostRef) noexcept { const auto contentReader { fromHostRef (contentReaderHostRef) }; - remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, destroyContentReader), _remoteHostRef, contentReader->remoteHostRef); + remoteCall (false, ARA_IPC_HOST_METHOD_ID (ARAContentAccessControllerInterface, destroyContentReader), _remoteHostRef, contentReader->remoteHostRef); delete contentReader; } @@ -468,22 +465,22 @@ class ModelUpdateController : public Host::ModelUpdateControllerInterface, publi void ModelUpdateController::notifyAudioSourceAnalysisProgress (ARAAudioSourceHostRef audioSourceHostRef, ARAAnalysisProgressState state, float value) noexcept { - remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioSourceAnalysisProgress), _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, state, value); + remoteCall (false, ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioSourceAnalysisProgress), _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, state, value); } void ModelUpdateController::notifyAudioSourceContentChanged (ARAAudioSourceHostRef audioSourceHostRef, const ARAContentTimeRange* range, ContentUpdateScopes scopeFlags) noexcept { - remoteCallWithoutReply (true, ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioSourceContentChanged), _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, range, scopeFlags); + remoteCall (true, ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioSourceContentChanged), _remoteHostRef, fromHostRef (audioSourceHostRef)->mainHostRef, range, scopeFlags); } void ModelUpdateController::notifyAudioModificationContentChanged (ARAAudioModificationHostRef audioModificationHostRef, const ARAContentTimeRange* range, ContentUpdateScopes scopeFlags) noexcept { - remoteCallWithoutReply (true, ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioModificationContentChanged), _remoteHostRef, audioModificationHostRef, range, scopeFlags); + remoteCall (true, ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyAudioModificationContentChanged), _remoteHostRef, audioModificationHostRef, range, scopeFlags); } void ModelUpdateController::notifyPlaybackRegionContentChanged (ARAPlaybackRegionHostRef playbackRegionHostRef, const ARAContentTimeRange* range, ContentUpdateScopes scopeFlags) noexcept { - remoteCallWithoutReply (true, ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyPlaybackRegionContentChanged), _remoteHostRef, playbackRegionHostRef, range, scopeFlags); + remoteCall (true, ARA_IPC_HOST_METHOD_ID (ARAModelUpdateControllerInterface, notifyPlaybackRegionContentChanged), _remoteHostRef, playbackRegionHostRef, range, scopeFlags); } @@ -509,27 +506,27 @@ class PlaybackController : public Host::PlaybackControllerInterface, public Remo void PlaybackController::requestStartPlayback () noexcept { - remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestStartPlayback), _remoteHostRef); + remoteCall (false, ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestStartPlayback), _remoteHostRef); } void PlaybackController::requestStopPlayback () noexcept { - remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestStopPlayback), _remoteHostRef); + remoteCall (false, ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestStopPlayback), _remoteHostRef); } void PlaybackController::requestSetPlaybackPosition (ARATimePosition timePosition) noexcept { - remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestSetPlaybackPosition), _remoteHostRef, timePosition); + remoteCall (false, ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestSetPlaybackPosition), _remoteHostRef, timePosition); } void PlaybackController::requestSetCycleRange (ARATimePosition startTime, ARATimeDuration duration) noexcept { - remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestSetCycleRange), _remoteHostRef, startTime, duration); + remoteCall (false, ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestSetCycleRange), _remoteHostRef, startTime, duration); } void PlaybackController::requestEnableCycle (bool enable) noexcept { - remoteCallWithoutReply (false, ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestEnableCycle), _remoteHostRef, (enable) ? kARATrue : kARAFalse); + remoteCall (false, ARA_IPC_HOST_METHOD_ID (ARAPlaybackControllerInterface, requestEnableCycle), _remoteHostRef, (enable) ? kARATrue : kARAFalse); } @@ -627,18 +624,18 @@ void ARAIPCProxyHostCommandHandler (const ARAIPCMessageID messageID, const ARAIP // ARA_LOG ("ARAIPCProxyHostCommandHandler received message %s", decodePlugInMessageID (messageID)); // ARAFactory - if (messageID == kGetFactoriesCountMessageID) + if (messageID == kGetFactoriesCountMethodID) { return encodeReply (replyEncoder, _factories.size ()); } - else if (messageID == kGetFactoryMessageID) + else if (messageID == kGetFactoryMethodID) { ARASize index; decodeArguments (decoder, index); ARA_INTERNAL_ASSERT (index < _factories.size ()); return encodeReply (replyEncoder, *_factories[index]); } - else if (messageID == kInitializeARAMessageID) + else if (messageID == kInitializeARAMethodID) { ARAPersistentID factoryID; ARA::SizedStruct interfaceConfig = { kARAAPIGeneration_2_0_Final, nullptr }; @@ -648,7 +645,7 @@ void ARAIPCProxyHostCommandHandler (const ARAIPCMessageID messageID, const ARAIP if (const ARAFactory* const factory { getFactoryWithID (factoryID) }) factory->initializeARAWithConfiguration(&interfaceConfig); } - else if (messageID == kCreateDocumentControllerMessageID) + else if (messageID == kCreateDocumentControllerMethodID) { ARAPersistentID factoryID; ARAAudioAccessControllerHostRef audioAccessControllerHostRef; @@ -685,7 +682,7 @@ void ARAIPCProxyHostCommandHandler (const ARAIPCMessageID messageID, const ARAIP return encodeReply (replyEncoder, ARADocumentControllerRef { toRef (documentController) }); } } - else if (messageID == kBindToDocumentControllerMessageID) + else if (messageID == kBindToDocumentControllerMethodID) { ARAIPCPlugInInstanceRef plugInInstanceRef; ARADocumentControllerRef controllerRef; @@ -695,7 +692,7 @@ void ARAIPCProxyHostCommandHandler (const ARAIPCMessageID messageID, const ARAIP const auto plugInExtensionInstance { _bindingHandler (plugInInstanceRef, fromRef (controllerRef)->getRef (), knownRoles, assignedRoles) }; return encodeReply (replyEncoder, ARAPlugInExtensionRef { toRef (new PlugInExtension { plugInExtensionInstance })}); } - else if (messageID == kUninitializeARAMessageID) + else if (messageID == kUninitializeARAMethodID) { ARAPersistentID factoryID; decodeArguments (decoder, factoryID); diff --git a/IPC/ARAIPCProxyPlugIn.cpp b/IPC/ARAIPCProxyPlugIn.cpp index c3de12e..07e3054 100644 --- a/IPC/ARAIPCProxyPlugIn.cpp +++ b/IPC/ARAIPCProxyPlugIn.cpp @@ -343,12 +343,12 @@ DocumentController::DocumentController (ARAIPCMessageSender sender, const ARAFac ARAContentAccessControllerHostRef contentAccessControllerHostRef { toHostRef (this) }; ARAModelUpdateControllerHostRef modelUpdateControllerHostRef { toHostRef (this) }; ARAPlaybackControllerHostRef playbackControllerHostRef { toHostRef (this) }; - remoteCallWithReply (_remoteRef, false, kCreateDocumentControllerMessageID, _factory->factoryID, - audioAccessControllerHostRef, archivingControllerHostRef, - (_hostContentAccessController.isProvided ()) ? kARATrue : kARAFalse, contentAccessControllerHostRef, - (_hostModelUpdateController.isProvided ()) ? kARATrue : kARAFalse, modelUpdateControllerHostRef, - (_hostPlaybackController.isProvided ()) ? kARATrue : kARAFalse, playbackControllerHostRef, - properties); + remoteCall (_remoteRef, false, kCreateDocumentControllerMethodID, _factory->factoryID, + audioAccessControllerHostRef, archivingControllerHostRef, + (_hostContentAccessController.isProvided ()) ? kARATrue : kARAFalse, contentAccessControllerHostRef, + (_hostModelUpdateController.isProvided ()) ? kARATrue : kARAFalse, modelUpdateControllerHostRef, + (_hostPlaybackController.isProvided ()) ? kARATrue : kARAFalse, playbackControllerHostRef, + properties); ARA_LOG_MODELOBJECT_LIFETIME ("did create document controller", _remoteRef); } @@ -359,7 +359,7 @@ void DocumentController::destroyDocumentController () noexcept ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARA_LOG_MODELOBJECT_LIFETIME ("will destroy document controller", _remoteRef); - remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyDocumentController), _remoteRef); + remoteCall (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyDocumentController), _remoteRef); _hasBeenDestroyed = true; @@ -396,7 +396,7 @@ void DocumentController::beginEditing () noexcept ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, beginEditing), _remoteRef); + remoteCall (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, beginEditing), _remoteRef); } void DocumentController::endEditing () noexcept @@ -404,7 +404,7 @@ void DocumentController::endEditing () noexcept ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, endEditing), _remoteRef); + remoteCall (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, endEditing), _remoteRef); } void DocumentController::notifyModelUpdates () noexcept @@ -424,7 +424,7 @@ void DocumentController::notifyModelUpdates () noexcept if (!_hostModelUpdateController.isProvided ()) return; - remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, notifyModelUpdates), _remoteRef); + remoteCall (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, notifyModelUpdates), _remoteRef); } bool DocumentController::restoreObjectsFromArchive (ARAArchiveReaderHostRef archiveReaderHostRef, const ARARestoreObjectsFilter* filter) noexcept @@ -433,7 +433,7 @@ bool DocumentController::restoreObjectsFromArchive (ARAArchiveReaderHostRef arch ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARABool success; - remoteCallWithReply (success, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, restoreObjectsFromArchive), _remoteRef, archiveReaderHostRef, filter); + remoteCall (success, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, restoreObjectsFromArchive), _remoteRef, archiveReaderHostRef, filter); return (success != kARAFalse); } @@ -456,7 +456,7 @@ bool DocumentController::storeObjectsToArchive (ARAArchiveWriterHostRef archiveW } ARABool success; - remoteCallWithReply (success, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, storeObjectsToArchive), _remoteRef, archiveWriterHostRef, filter); + remoteCall (success, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, storeObjectsToArchive), _remoteRef, archiveWriterHostRef, filter); return (success!= kARAFalse); } @@ -497,8 +497,8 @@ bool DocumentController::storeAudioSourceToAudioFileChunk (ARAArchiveWriterHostR *openAutomatically = (reply.openAutomatically != kARAFalse); success = (reply.result != kARAFalse); } }; - remoteCallWithReply (customDecode, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, storeAudioSourceToAudioFileChunk), - _remoteRef, archiveWriterHostRef, audioSource->remoteRef); + remoteCall (customDecode, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, storeAudioSourceToAudioFileChunk), + _remoteRef, archiveWriterHostRef, audioSource->remoteRef); return success; } @@ -508,7 +508,7 @@ void DocumentController::updateDocumentProperties (PropertiesPtrremoteRef, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioSource), - _remoteRef, ARAAudioSourceHostRef { toHostRef (audioSource) }, *properties); + remoteCall (audioSource->remoteRef, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioSource), + _remoteRef, ARAAudioSourceHostRef { toHostRef (audioSource) }, *properties); ARA_LOG_MODELOBJECT_LIFETIME ("did create audio source", audioSourceRef); return toRef (audioSource); @@ -614,7 +614,7 @@ void DocumentController::updateAudioSourceProperties (ARAAudioSourceRef audioSou ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); ARA_VALIDATE_API_STRUCT_PTR (properties, ARAAudioSourceProperties); - remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioSourceProperties), _remoteRef, audioSource->remoteRef, *properties); + remoteCall (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioSourceProperties), _remoteRef, audioSource->remoteRef, *properties); } void DocumentController::updateAudioSourceContent (ARAAudioSourceRef audioSourceRef, const ARAContentTimeRange* range, ContentUpdateScopes flags) noexcept @@ -624,7 +624,7 @@ void DocumentController::updateAudioSourceContent (ARAAudioSourceRef audioSource auto audioSource { fromRef (audioSourceRef) }; ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); - remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioSourceContent), _remoteRef, audioSource->remoteRef, range, flags); + remoteCall (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioSourceContent), _remoteRef, audioSource->remoteRef, range, flags); } void DocumentController::enableAudioSourceSamplesAccess (ARAAudioSourceRef audioSourceRef, bool enable) noexcept @@ -634,7 +634,7 @@ void DocumentController::enableAudioSourceSamplesAccess (ARAAudioSourceRef audio const auto audioSource { fromRef (audioSourceRef) }; ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); - remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, enableAudioSourceSamplesAccess), _remoteRef, audioSource->remoteRef, (enable) ? kARATrue : kARAFalse); + remoteCall (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, enableAudioSourceSamplesAccess), _remoteRef, audioSource->remoteRef, (enable) ? kARATrue : kARAFalse); } void DocumentController::deactivateAudioSourceForUndoHistory (ARAAudioSourceRef audioSourceRef, bool deactivate) noexcept @@ -644,7 +644,7 @@ void DocumentController::deactivateAudioSourceForUndoHistory (ARAAudioSourceRef const auto audioSource { fromRef (audioSourceRef) }; ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); - remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, deactivateAudioSourceForUndoHistory), _remoteRef, audioSource->remoteRef, (deactivate) ? kARATrue : kARAFalse); + remoteCall (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, deactivateAudioSourceForUndoHistory), _remoteRef, audioSource->remoteRef, (deactivate) ? kARATrue : kARAFalse); } void DocumentController::destroyAudioSource (ARAAudioSourceRef audioSourceRef) noexcept @@ -655,7 +655,7 @@ void DocumentController::destroyAudioSource (ARAAudioSourceRef audioSourceRef) n ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); ARA_LOG_MODELOBJECT_LIFETIME ("will destroy audio source", audioSource->remoteRef); - remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyAudioSource), _remoteRef, audioSource->remoteRef); + remoteCall (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyAudioSource), _remoteRef, audioSource->remoteRef); delete audioSource; } @@ -670,8 +670,8 @@ ARAAudioModificationRef DocumentController::createAudioModification (ARAAudioSou ARA_VALIDATE_API_STRUCT_PTR (properties, ARAAudioModificationProperties); ARAAudioModificationRef audioModificationRef; - remoteCallWithReply (audioModificationRef, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioModification), - _remoteRef, audioSource->remoteRef, hostRef, *properties); + remoteCall (audioModificationRef, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioModification), + _remoteRef, audioSource->remoteRef, hostRef, *properties); ARA_LOG_MODELOBJECT_LIFETIME ("did create audio modification", audioModificationRef); return audioModificationRef; @@ -684,8 +684,8 @@ ARAAudioModificationRef DocumentController::cloneAudioModification (ARAAudioModi ARA_VALIDATE_API_STRUCT_PTR (properties, ARAAudioModificationProperties); ARAAudioModificationRef clonedAudioModificationRef; - remoteCallWithReply (clonedAudioModificationRef, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, cloneAudioModification), - _remoteRef, srcAudioModificationRef, hostRef, *properties); + remoteCall (clonedAudioModificationRef, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, cloneAudioModification), + _remoteRef, srcAudioModificationRef, hostRef, *properties); ARA_LOG_MODELOBJECT_LIFETIME ("did create cloned audio modification", clonedAudioModificationRef); return clonedAudioModificationRef; @@ -697,7 +697,7 @@ void DocumentController::updateAudioModificationProperties (ARAAudioModification ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARA_VALIDATE_API_STRUCT_PTR (properties, ARAAudioModificationProperties); - remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioModificationProperties), _remoteRef, audioModificationRef, *properties); + remoteCall (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updateAudioModificationProperties), _remoteRef, audioModificationRef, *properties); } bool DocumentController::isAudioModificationPreservingAudioSourceSignal (ARAAudioModificationRef audioModificationRef) noexcept @@ -706,7 +706,7 @@ bool DocumentController::isAudioModificationPreservingAudioSourceSignal (ARAAudi ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARABool result; - remoteCallWithReply (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioModificationPreservingAudioSourceSignal), _remoteRef, audioModificationRef); + remoteCall (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioModificationPreservingAudioSourceSignal), _remoteRef, audioModificationRef); return (result != kARAFalse); } @@ -715,7 +715,7 @@ void DocumentController::deactivateAudioModificationForUndoHistory (ARAAudioModi ARA_LOG_HOST_ENTRY (audioModificationRef); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, deactivateAudioModificationForUndoHistory), _remoteRef, audioModificationRef, (deactivate) ? kARATrue : kARAFalse); + remoteCall (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, deactivateAudioModificationForUndoHistory), _remoteRef, audioModificationRef, (deactivate) ? kARATrue : kARAFalse); } void DocumentController::destroyAudioModification (ARAAudioModificationRef audioModificationRef) noexcept @@ -724,7 +724,7 @@ void DocumentController::destroyAudioModification (ARAAudioModificationRef audio ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARA_LOG_MODELOBJECT_LIFETIME ("will destroy audio modification", audioModification); - remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyAudioModification), _remoteRef, audioModificationRef); + remoteCall (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyAudioModification), _remoteRef, audioModificationRef); } /*******************************************************************************/ @@ -736,8 +736,8 @@ ARAPlaybackRegionRef DocumentController::createPlaybackRegion (ARAAudioModificat ARA_VALIDATE_API_STRUCT_PTR (properties, ARAPlaybackRegionProperties); ARAPlaybackRegionRef playbackRegionRef; - remoteCallWithReply (playbackRegionRef, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createPlaybackRegion), - _remoteRef, audioModificationRef, hostRef, *properties); + remoteCall (playbackRegionRef, true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createPlaybackRegion), + _remoteRef, audioModificationRef, hostRef, *properties); ARA_LOG_MODELOBJECT_LIFETIME ("did create playback region", playbackRegionRef); return playbackRegionRef; @@ -749,7 +749,7 @@ void DocumentController::updatePlaybackRegionProperties (ARAPlaybackRegionRef pl ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARA_VALIDATE_API_STRUCT_PTR (properties, ARAPlaybackRegionProperties); - remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updatePlaybackRegionProperties), _remoteRef, playbackRegionRef, *properties); + remoteCall (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, updatePlaybackRegionProperties), _remoteRef, playbackRegionRef, *properties); } void DocumentController::getPlaybackRegionHeadAndTailTime (ARAPlaybackRegionRef playbackRegionRef, ARATimeDuration* headTime, ARATimeDuration* tailTime) noexcept @@ -760,8 +760,8 @@ void DocumentController::getPlaybackRegionHeadAndTailTime (ARAPlaybackRegionRef ARA_VALIDATE_API_ARGUMENT (tailTime, tailTime != nullptr); GetPlaybackRegionHeadAndTailTimeReply reply; - remoteCallWithReply (reply, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getPlaybackRegionHeadAndTailTime), - _remoteRef, playbackRegionRef, (headTime != nullptr) ? kARATrue : kARAFalse, (tailTime != nullptr) ? kARATrue : kARAFalse); + remoteCall (reply, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getPlaybackRegionHeadAndTailTime), + _remoteRef, playbackRegionRef, (headTime != nullptr) ? kARATrue : kARAFalse, (tailTime != nullptr) ? kARATrue : kARAFalse); if (headTime != nullptr) *headTime = reply.headTime; if (tailTime != nullptr) @@ -774,7 +774,7 @@ void DocumentController::destroyPlaybackRegion (ARAPlaybackRegionRef playbackReg ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARA_LOG_MODELOBJECT_LIFETIME ("will destroy playback region", playbackRegionRef); - remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyPlaybackRegion), _remoteRef, playbackRegionRef); + remoteCall (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyPlaybackRegion), _remoteRef, playbackRegionRef); } /*******************************************************************************/ @@ -786,7 +786,7 @@ bool DocumentController::isAudioSourceContentAvailable (ARAAudioSourceRef audioS ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); ARABool result; - remoteCallWithReply (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioSourceContentAvailable), _remoteRef, audioSource->remoteRef, type); + remoteCall (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioSourceContentAvailable), _remoteRef, audioSource->remoteRef, type); return (result != kARAFalse); } @@ -798,7 +798,7 @@ ARAContentGrade DocumentController::getAudioSourceContentGrade (ARAAudioSourceRe ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); ARAContentGrade grade; - remoteCallWithReply (grade, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getAudioSourceContentGrade), _remoteRef, audioSource->remoteRef, type); + remoteCall (grade, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getAudioSourceContentGrade), _remoteRef, audioSource->remoteRef, type); return grade; } @@ -810,8 +810,8 @@ ARAContentReaderRef DocumentController::createAudioSourceContentReader (ARAAudio ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); ARAContentReaderRef contentReaderRef; - remoteCallWithReply (contentReaderRef, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioSourceContentReader), - _remoteRef, audioSource->remoteRef, type, range); + remoteCall (contentReaderRef, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioSourceContentReader), + _remoteRef, audioSource->remoteRef, type, range); auto contentReader { new ContentReader { contentReaderRef, type } }; #if ARA_ENABLE_OBJECT_LIFETIME_LOG @@ -828,7 +828,7 @@ bool DocumentController::isAudioModificationContentAvailable (ARAAudioModificati ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARABool result; - remoteCallWithReply (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioModificationContentAvailable), _remoteRef, audioModificationRef, type); + remoteCall (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioModificationContentAvailable), _remoteRef, audioModificationRef, type); return (result != kARAFalse); } @@ -838,7 +838,7 @@ ARAContentGrade DocumentController::getAudioModificationContentGrade (ARAAudioMo ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARAContentGrade grade; - remoteCallWithReply (grade, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getAudioModificationContentGrade), _remoteRef, audioModificationRef, type); + remoteCall (grade, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getAudioModificationContentGrade), _remoteRef, audioModificationRef, type); return grade; } @@ -848,8 +848,8 @@ ARAContentReaderRef DocumentController::createAudioModificationContentReader (AR ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARAContentReaderRef contentReaderRef; - remoteCallWithReply (contentReaderRef, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioModificationContentReader), - _remoteRef, audioModificationRef, type, range); + remoteCall (contentReaderRef, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createAudioModificationContentReader), + _remoteRef, audioModificationRef, type, range); auto contentReader { new ContentReader { contentReaderRef, type } }; #if ARA_ENABLE_OBJECT_LIFETIME_LOG @@ -866,7 +866,7 @@ bool DocumentController::isPlaybackRegionContentAvailable (ARAPlaybackRegionRef ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARABool result; - remoteCallWithReply (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isPlaybackRegionContentAvailable), _remoteRef, playbackRegionRef, type); + remoteCall (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isPlaybackRegionContentAvailable), _remoteRef, playbackRegionRef, type); return (result != kARAFalse); } @@ -876,7 +876,7 @@ ARAContentGrade DocumentController::getPlaybackRegionContentGrade (ARAPlaybackRe ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARAContentGrade grade; - remoteCallWithReply (grade, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getPlaybackRegionContentGrade), _remoteRef, playbackRegionRef, type); + remoteCall (grade, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getPlaybackRegionContentGrade), _remoteRef, playbackRegionRef, type); return grade; } @@ -886,7 +886,7 @@ ARAContentReaderRef DocumentController::createPlaybackRegionContentReader (ARAPl ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARAContentReaderRef contentReaderRef; - remoteCallWithReply (contentReaderRef, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createPlaybackRegionContentReader), + remoteCall (contentReaderRef, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, createPlaybackRegionContentReader), _remoteRef, playbackRegionRef, type, range); auto contentReader { new ContentReader { contentReaderRef, type } }; @@ -906,7 +906,7 @@ ARAInt32 DocumentController::getContentReaderEventCount (ARAContentReaderRef con ARA_VALIDATE_API_ARGUMENT (contentReader, isValidInstance (contentReader)); ARAInt32 count; - remoteCallWithReply (count, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getContentReaderEventCount), _remoteRef, contentReader->remoteRef); + remoteCall (count, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getContentReaderEventCount), _remoteRef, contentReader->remoteRef); return count; } @@ -922,8 +922,8 @@ const void* DocumentController::getContentReaderDataForEvent (ARAContentReaderRe { result = contentReader->decoder.decode (decoder); } }; - remoteCallWithReply (customDecode, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getContentReaderDataForEvent), - _remoteRef, contentReader->remoteRef, eventIndex); + remoteCall (customDecode, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getContentReaderDataForEvent), + _remoteRef, contentReader->remoteRef, eventIndex); return result; } @@ -935,7 +935,7 @@ void DocumentController::destroyContentReader (ARAContentReaderRef contentReader ARA_VALIDATE_API_ARGUMENT (contentReader, isValidInstance (contentReader)); ARA_LOG_MODELOBJECT_LIFETIME ("will destroy content reader", contentReader->remoteRef); - remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyContentReader), _remoteRef, contentReader->remoteRef); + remoteCall (false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, destroyContentReader), _remoteRef, contentReader->remoteRef); delete contentReader; } @@ -950,8 +950,8 @@ bool DocumentController::isAudioSourceContentAnalysisIncomplete (ARAAudioSourceR ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); ARABool result; - remoteCallWithReply (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioSourceContentAnalysisIncomplete), - _remoteRef, audioSource->remoteRef, type); + remoteCall (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isAudioSourceContentAnalysisIncomplete), + _remoteRef, audioSource->remoteRef, type); return (result != kARAFalse); } @@ -963,7 +963,7 @@ void DocumentController::requestAudioSourceContentAnalysis (ARAAudioSourceRef au ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); const ArrayArgument types { contentTypes, contentTypesCount }; - remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, requestAudioSourceContentAnalysis), _remoteRef, audioSource->remoteRef, types); + remoteCall (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, requestAudioSourceContentAnalysis), _remoteRef, audioSource->remoteRef, types); } ARAInt32 DocumentController::getProcessingAlgorithmsCount () noexcept @@ -972,7 +972,7 @@ ARAInt32 DocumentController::getProcessingAlgorithmsCount () noexcept ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARAInt32 count; - remoteCallWithReply (count, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmsCount), _remoteRef); + remoteCall (count, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmsCount), _remoteRef); return count; } @@ -991,7 +991,7 @@ const ARAProcessingAlgorithmProperties* DocumentController::getProcessingAlgorit _processingAlgorithmData.persistentID = _processingAlgorithmStrings.persistentID.c_str (); _processingAlgorithmData.name = _processingAlgorithmStrings.name.c_str (); } }; - remoteCallWithReply (customDecode, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmProperties), _remoteRef, algorithmIndex); + remoteCall (customDecode, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmProperties), _remoteRef, algorithmIndex); return &_processingAlgorithmData; } @@ -1003,7 +1003,7 @@ ARAInt32 DocumentController::getProcessingAlgorithmForAudioSource (ARAAudioSourc ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); ARAInt32 result; - remoteCallWithReply (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmForAudioSource), _remoteRef, audioSource->remoteRef); + remoteCall (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, getProcessingAlgorithmForAudioSource), _remoteRef, audioSource->remoteRef); return result; } @@ -1014,7 +1014,7 @@ void DocumentController::requestProcessingAlgorithmForAudioSource (ARAAudioSourc const auto audioSource { fromRef (audioSourceRef) }; ARA_VALIDATE_API_ARGUMENT (audioSource, isValidInstance (audioSource)); - remoteCallWithoutReply (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, requestProcessingAlgorithmForAudioSource), _remoteRef, audioSource->remoteRef, algorithmIndex); + remoteCall (true, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, requestProcessingAlgorithmForAudioSource), _remoteRef, audioSource->remoteRef, algorithmIndex); } /*******************************************************************************/ @@ -1026,8 +1026,8 @@ bool DocumentController::isLicensedForCapabilities (bool runModalActivationDialo const ArrayArgument types { contentTypes, contentTypesCount }; ARABool result; - remoteCallWithReply (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isLicensedForCapabilities), - _remoteRef, (runModalActivationDialogIfNeeded) ? kARATrue : kARAFalse, types, transformationFlags); + remoteCall (result, false, ARA_IPC_PLUGIN_METHOD_ID (ARADocumentControllerInterface, isLicensedForCapabilities), + _remoteRef, (runModalActivationDialogIfNeeded) ? kARATrue : kARAFalse, types, transformationFlags); return (result != kARAFalse); } @@ -1049,14 +1049,14 @@ class PlaybackRenderer : public PlugIn::PlaybackRendererInterface, protected Rem ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAPlaybackRendererInterface, addPlaybackRegion), _remoteRef, playbackRegionRef); + remoteCall (false, ARA_IPC_PLUGIN_METHOD_ID (ARAPlaybackRendererInterface, addPlaybackRegion), _remoteRef, playbackRegionRef); } void removePlaybackRegion (ARAPlaybackRegionRef playbackRegionRef) noexcept override { ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAPlaybackRendererInterface, removePlaybackRegion), _remoteRef, playbackRegionRef); + remoteCall (false, ARA_IPC_PLUGIN_METHOD_ID (ARAPlaybackRendererInterface, removePlaybackRegion), _remoteRef, playbackRegionRef); } private: @@ -1083,14 +1083,14 @@ class EditorRenderer : public PlugIn::EditorRendererInterface, protected RemoteC ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, addPlaybackRegion), _remoteRef, playbackRegionRef); + remoteCall (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, addPlaybackRegion), _remoteRef, playbackRegionRef); } void removePlaybackRegion (ARAPlaybackRegionRef playbackRegionRef) noexcept override { ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, removePlaybackRegion), _remoteRef, playbackRegionRef); + remoteCall (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, removePlaybackRegion), _remoteRef, playbackRegionRef); } void addRegionSequence (ARARegionSequenceRef regionSequenceRef) noexcept override @@ -1098,14 +1098,14 @@ class EditorRenderer : public PlugIn::EditorRendererInterface, protected RemoteC ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, addRegionSequence), _remoteRef, regionSequenceRef); + remoteCall (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, addRegionSequence), _remoteRef, regionSequenceRef); } void removeRegionSequence (ARARegionSequenceRef regionSequenceRef) noexcept override { ARA_LOG_HOST_ENTRY (this); ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); - remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, removeRegionSequence), _remoteRef, regionSequenceRef); + remoteCall (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorRendererInterface, removeRegionSequence), _remoteRef, regionSequenceRef); } private: @@ -1133,7 +1133,7 @@ class EditorView : public PlugIn::EditorViewInterface, protected RemoteCaller, p ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); ARA_VALIDATE_API_STRUCT_PTR (selection, ARAViewSelection); - remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorViewInterface, notifySelection), _remoteRef, *selection); + remoteCall (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorViewInterface, notifySelection), _remoteRef, *selection); } void notifyHideRegionSequences (ARASize regionSequenceRefsCount, const ARARegionSequenceRef regionSequenceRefs[]) noexcept override { @@ -1141,7 +1141,7 @@ class EditorView : public PlugIn::EditorViewInterface, protected RemoteCaller, p ARA_VALIDATE_API_ARGUMENT (this, isValidInstance (this)); const ArrayArgument sequences { regionSequenceRefs, regionSequenceRefsCount }; - remoteCallWithoutReply (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorViewInterface, notifyHideRegionSequences), _remoteRef, sequences); + remoteCall (false, ARA_IPC_PLUGIN_METHOD_ID (ARAEditorViewInterface, notifyHideRegionSequences), _remoteRef, sequences); } private: @@ -1234,7 +1234,7 @@ using namespace ProxyPlugIn; size_t ARAIPCProxyPlugInGetFactoriesCount (ARAIPCMessageSender hostCommandsSender) { size_t count; - RemoteCaller { hostCommandsSender }.remoteCallWithReply (count, false, kGetFactoriesCountMessageID); + RemoteCaller { hostCommandsSender }.remoteCall (count, false, kGetFactoriesCountMethodID); ARA_INTERNAL_ASSERT (count > 0); return count; } @@ -1278,7 +1278,7 @@ const ARAFactory* ARAIPCProxyPlugInGetFactoryAtIndex (ARAIPCMessageSender hostCo remoteFactory._factory.analyzeableContentTypes = remoteFactory._analyzableTypes.data (); } }; - RemoteCaller { hostCommandsSender }.remoteCallWithReply (customDecode, false, kGetFactoryMessageID, index); + RemoteCaller { hostCommandsSender }.remoteCall (customDecode, false, kGetFactoryMethodID, index); const auto result { _factories.insert (std::make_pair (remoteFactory._strings.factoryID, remoteFactory)) }; if (result.second) @@ -1305,7 +1305,7 @@ const ARAFactory* ARAIPCProxyPlugInGetFactoryAtIndex (ARAIPCMessageSender hostCo void ARAIPCProxyPlugInInitializeARA (ARAIPCMessageSender hostCommandsSender, const ARAPersistentID factoryID, ARAAPIGeneration desiredApiGeneration) { ARA_INTERNAL_ASSERT (desiredApiGeneration >= kARAAPIGeneration_2_0_Final); - RemoteCaller { hostCommandsSender }.remoteCallWithoutReply(false, kInitializeARAMessageID, factoryID, desiredApiGeneration); + RemoteCaller { hostCommandsSender }.remoteCall (false, kInitializeARAMethodID, factoryID, desiredApiGeneration); } const ARADocumentControllerInstance* ARAIPCProxyPlugInCreateDocumentControllerWithDocument ( @@ -1331,7 +1331,7 @@ const ARAPlugInExtensionInstance* ARAIPCProxyPlugInBindToDocumentController (ARA { decoder.methods->readSize (decoder.ref, 0, &remoteExtensionRef); } }; - RemoteCaller { sender }.remoteCallWithReply (customDecode, false, kBindToDocumentControllerMessageID, remoteRef, remoteDocumentControllerRef, knownRoles, assignedRoles); + RemoteCaller { sender }.remoteCall (customDecode, false, kBindToDocumentControllerMethodID, remoteRef, remoteDocumentControllerRef, knownRoles, assignedRoles); return new PlugInExtension { sender, documentControllerRef, knownRoles, assignedRoles, remoteExtensionRef }; } @@ -1343,7 +1343,7 @@ void ARAIPCProxyPlugInCleanupBinding (const ARAPlugInExtensionInstance* plugInEx void ARAIPCProxyPlugInUninitializeARA (ARAIPCMessageSender hostCommandsSender, const ARAPersistentID factoryID) { - RemoteCaller { hostCommandsSender }.remoteCallWithoutReply (false, kUninitializeARAMessageID, factoryID); + RemoteCaller { hostCommandsSender }.remoteCall (false, kUninitializeARAMethodID, factoryID); } void ARAIPCProxyPlugInCallbacksDispatcher (const ARAIPCMessageID messageID, const ARAIPCMessageDecoder* const decoder, ARAIPCMessageEncoder* const replyEncoder) From 5cf7a1409c7c0ced1110af4f446409bb1d407bcc Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:32:01 +0100 Subject: [PATCH 16/18] Initial draft of channeling ARA IPC through upcoming macOS 13 AudioUnit API addition --- CMakeLists.txt | 2 + IPC/ARAIPCAudioUnit_v3.h | 107 ++++++++++++ IPC/ARAIPCAudioUnit_v3.m | 358 +++++++++++++++++++++++++++++++++++++++ IPC/ARAIPCCFEncoding.cpp | 69 ++++++-- IPC/ARAIPCCFEncoding.h | 4 + 5 files changed, 529 insertions(+), 11 deletions(-) create mode 100644 IPC/ARAIPCAudioUnit_v3.h create mode 100644 IPC/ARAIPCAudioUnit_v3.m diff --git a/CMakeLists.txt b/CMakeLists.txt index dff3d04..b1fdcc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,6 +183,8 @@ add_library(ARA_IPC_Library ${ARA_LIBRARY_TARGET_TYPE} if(APPLE) target_sources(ARA_IPC_Library PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCAudioUnit_v3.h" + "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCAudioUnit_v3.m" "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCCFEncoding.h" "${CMAKE_CURRENT_SOURCE_DIR}/IPC/ARAIPCCFEncoding.cpp" ) diff --git a/IPC/ARAIPCAudioUnit_v3.h b/IPC/ARAIPCAudioUnit_v3.h new file mode 100644 index 0000000..73b2343 --- /dev/null +++ b/IPC/ARAIPCAudioUnit_v3.h @@ -0,0 +1,107 @@ +//------------------------------------------------------------------------------ +//! \file ARAIPCAudioUnit_v3.h +//! Implementation of ARA IPC message sending through AUMessageChannel +//! \project ARA SDK Examples +//! \copyright Copyright (c) 2021-2022, Celemony Software GmbH, All Rights Reserved. +//! \license Licensed under the Apache License, Version 2.0 (the "License"); +//! you may not use this file except in compliance with the License. +//! You may obtain a copy of the License at +//! +//! http://www.apache.org/licenses/LICENSE-2.0 +//! +//! Unless required by applicable law or agreed to in writing, software +//! distributed under the License is distributed on an "AS IS" BASIS, +//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//! See the License for the specific language governing permissions and +//! limitations under the License. +//------------------------------------------------------------------------------ + +#import "ARA_API/ARAAudioUnit_v3.h" + + +// using ARA IPC for Audio Units requires to compile for macOS 13 or higher +#if defined(__MAC_13_0) + #define ARA_AUDIOUNITV3_IPC_IS_AVAILABLE 1 +#else + #define ARA_AUDIOUNITV3_IPC_IS_AVAILABLE 0 +#endif + +#if ARA_AUDIOUNITV3_IPC_IS_AVAILABLE + + +#import "ARA_Library/IPC/ARAIPC.h" +#import "ARA_Library/IPC/ARAIPCLockingContext.h" + + +#if defined(__cplusplus) +namespace ARA { +namespace IPC { +extern "C" { +#endif + + +API_AVAILABLE_BEGIN(macos(13.0)) + + +//! host side: initialize the message sender used for all factory-related messaging for all +//! Audio Units that have the same component as the provided audioUnit +//! will return false if the Audio Unit does not implement ARAAudioUnit or [AUAudioUnit messageChannelFor:], +//! leaving the channel uninitalized +//! this sender can be used for the calls to ARAIPCAUProxyPlugInGetFactory(), ARAIPCProxyPlugInInitializeARA(), +//! ARAIPCProxyPlugInCreateDocumentControllerWithDocument() and ARAIPCProxyPlugInUninitializeARA() +bool ARA_CALL ARAIPCAUProxyPlugInInitializeFactoryMessageSender(ARAIPCMessageSender * _Nonnull messageSender, AUAudioUnit * _Nonnull audioUnit, ARAIPCLockingContextRef _Nonnull lockingContextRef); + +//! host side: get the ARA factory for the audio unit +//! will return NULL if the Audio Unit does not implement ARAAudioUnit or [AUAudioUnit messageChannelFor:] +const ARAFactory * _Nonnull ARA_CALL ARAIPCAUProxyPlugInGetFactory(ARAIPCMessageSender messageSender); + +//! host side: create the plug-in extension when performing the binding to the remote plug-in instance +//! also initialzies the messageSender which remains valid until ARAIPCAUProxyPlugInCleanupBinding() is called +//! the document controller must be created through a factory obtained through ARAIPCAUProxyPlugInGetFactory() +//! will return NULL if the Audio Unit does not implement ARAAudioUnit or [AUAudioUnit messageChannelFor:], +//! leaving messageSender uninitalized in that case +const ARAPlugInExtensionInstance * _Nullable ARA_CALL ARAIPCAUProxyPlugInBindToDocumentController(AUAudioUnit * _Nonnull audioUnit, + ARAIPCLockingContextRef _Nonnull lockingContextRef, + ARADocumentControllerRef _Nonnull documentControllerRef, + ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles, + ARAIPCMessageSender * _Nonnull messageSender); + +//! host side: trigger proper teardown of proxy plug-in extension when Companion API instance is destroyed +//! the messageSender must have been initialized by ARAIPCAUProxyPlugInBindToDocumentController() and will be uninitialized +void ARA_CALL ARAIPCAUProxyPlugInCleanupBinding(ARAIPCMessageSender messageSender); + +//! host side: uninitialize the sender set up in ARAIPCAUProxyPlugInInitializeFactoryMessageSender() +void ARA_CALL ARAIPCAUProxyPlugInUninitializeFactoryMessageSender(ARAIPCMessageSender messageSender); + + +//! plug-in side: static configuration: add the ARA factories that the IPC shall handle +void ARA_CALL ARAIPCAUProxyHostAddFactory(const ARAFactory * _Nonnull factory); + +//! callback that the proxy uses to execute the binding of an AUAudioUnit to the given document controller +typedef const ARAPlugInExtensionInstance * _Nonnull (^ARAIPCAUBindingHandler)(AUAudioUnit * _Nonnull audioUnit, ARADocumentControllerRef _Nonnull controllerRef, + ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles); + +//! plug-in side: static configuration: after adding all factories, initialize the IPC (before allocating any instances) +void ARA_CALL ARAIPCAUProxyHostInitialize(NSObject * _Nonnull factoryMessageChannel, ARAIPCAUBindingHandler _Nonnull bindingHandler); + +//! plug-in side: implementation for AUMessageChannel -callAudioUnit: +NSDictionary * _Nonnull ARA_CALL ARAIPCAUProxyHostCommandHandler (AUAudioUnit * _Nullable audioUnit, NSDictionary * _Nonnull wrappedMessage); + +//! plug-in side: trigger proper teardown of proxy plug-in extension when Companion API instance is destroyed +void ARA_CALL ARAIPCAUProxyHostCleanupBinding(const ARAPlugInExtensionInstance * _Nonnull plugInExtensionInstance); + +//! plug-in side: static cleanup upon shutdown +void ARA_CALL ARAIPCAUProxyHostUninitalize(void); + + +API_AVAILABLE_END + + +#if defined(__cplusplus) +} // extern "C" +} // namespace IPC +} // namespace ARA +#endif + + +#endif // ARA_AUDIOUNITV3_IPC_IS_AVAILABLE diff --git a/IPC/ARAIPCAudioUnit_v3.m b/IPC/ARAIPCAudioUnit_v3.m new file mode 100644 index 0000000..d788640 --- /dev/null +++ b/IPC/ARAIPCAudioUnit_v3.m @@ -0,0 +1,358 @@ +//------------------------------------------------------------------------------ +//! \file ARAIPCAudioUnit_v3.m +//! Implementation of ARA IPC message sending through AUMessageChannel +//! \project ARA SDK Examples +//! \copyright Copyright (c) 2021-2022, Celemony Software GmbH, All Rights Reserved. +//! \license Licensed under the Apache License, Version 2.0 (the "License"); +//! you may not use this file except in compliance with the License. +//! You may obtain a copy of the License at +//! +//! http://www.apache.org/licenses/LICENSE-2.0 +//! +//! Unless required by applicable law or agreed to in writing, software +//! distributed under the License is distributed on an "AS IS" BASIS, +//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//! See the License for the specific language governing permissions and +//! limitations under the License. +//------------------------------------------------------------------------------ + +#import "ARAIPCAudioUnit_v3.h" + + +#if ARA_AUDIOUNITV3_IPC_IS_AVAILABLE + + +#import "ARA_Library/Debug/ARADebug.h" +#import "ARA_Library/IPC/ARAIPCCFEncoding.h" +#import "ARA_Library/IPC/ARAIPCProxyHost.h" +#import "ARA_Library/IPC/ARAIPCProxyPlugIn.h" +#if !ARA_ENABLE_IPC + #error "configuration mismatch: enabling ARA_AUDIOUNITV3_IPC_IS_AVAILABLE requires enabling ARA_ENABLE_IPC too" +#endif + + +#if defined(__cplusplus) +namespace ARA { +namespace IPC { +extern "C" { +#endif + + +API_AVAILABLE_BEGIN(macos(13.0)) + + +// custom IPC message to read the remote instance ref +const ARAIPCMessageID kARAIPCGetRemoteInstanceRef = -1; + + +// "base class" layout used in plug-in and host +typedef struct ARAIPCMessageSenderImplementation +{ + NSObject * __strong messageChannel; + ARAIPCLockingContextRef lockingContextRef; +} ARAIPCMessageSenderImplementation; + +// "subclass" used for plug-in extension proxies with added fields +typedef struct ARAIPCAUProxyPlugInExtensionMessageSenderImplementation +{ + ARAIPCMessageSenderImplementation base; + ARAIPCPlugInInstanceRef remoteInstanceRef; // stores "ref" for the remote ARAIPCAUAudioUnit instance + const ARAPlugInExtensionInstance * plugInExtensionInstance; // stored only for proper cleanup +} ARAIPCAUProxyPlugInExtensionMessageSenderImplementation; + + +// message sender implementations for host and plug-in +ARAIPCMessageEncoder ARA_CALL ARAIPCAUCreateEncoder(ARAIPCMessageSenderRef ARA_MAYBE_UNUSED_ARG(messageSenderRef)) +{ + return ARAIPCCFCreateMessageEncoder(); +} + +void ARA_CALL ARAIPCAUProxyPlugInSendMessage(const bool stackable, ARAIPCMessageSenderRef messageSenderRef, ARAIPCMessageID messageID, const ARAIPCMessageEncoder * encoder, + ARAIPCReplyHandler * const replyHandler, void * replyHandlerUserData) +{ + @autoreleasepool + { + NSDictionary * message = CFBridgingRelease(ARAIPCCFCopyMessageEncoderDictionaryAddingMessageID(encoder->ref, messageID)); + const ARAIPCLockingContextMessageSendingToken lockToken = ARAIPCLockContextBeforeSendingMessage(messageSenderRef->lockingContextRef, stackable); + if (replyHandler) + { + CFDictionaryRef _Nonnull reply = (__bridge CFDictionaryRef)[messageSenderRef->messageChannel callAudioUnit:message]; + ARAIPCMessageDecoder replyDecoder = ARAIPCCFCreateMessageDecoderWithDictionary(reply); + (*replyHandler)(replyDecoder, replyHandlerUserData); + replyDecoder.methods->destroyDecoder(replyDecoder.ref); + } + else + { + NSDictionary * _Nonnull reply = [messageSenderRef->messageChannel callAudioUnit:message]; + ARA_INTERNAL_ASSERT([reply count] == 0); + } + ARAIPCUnlockContextAfterSendingMessage(messageSenderRef->lockingContextRef, lockToken); + } +} + +void ARA_CALL ARAIPCAUProxyHostSendMessage(const bool stackable, ARAIPCMessageSenderRef messageSenderRef, ARAIPCMessageID messageID, const ARAIPCMessageEncoder * encoder, + ARAIPCReplyHandler * const replyHandler, void * replyHandlerUserData) +{ + @autoreleasepool + { + CallHostBlock callHostBlock = messageSenderRef->messageChannel.callHostBlock; + if (callHostBlock) + { + NSDictionary * message = CFBridgingRelease(ARAIPCCFCopyMessageEncoderDictionaryAddingMessageID(encoder->ref, messageID)); + const ARAIPCLockingContextMessageSendingToken lockToken = ARAIPCLockContextBeforeSendingMessage(messageSenderRef->lockingContextRef, stackable); + if (replyHandler) + { + CFDictionaryRef _Nullable reply = (__bridge CFDictionaryRef)callHostBlock(message); + ARAIPCMessageDecoder replyDecoder = ARAIPCCFCreateMessageDecoderWithDictionary(reply); + (*replyHandler)(replyDecoder, replyHandlerUserData); + replyDecoder.methods->destroyDecoder(replyDecoder.ref); + } + else + { + NSDictionary * _Nullable reply = callHostBlock(message); + ARA_INTERNAL_ASSERT([reply count] == 0); + } + ARAIPCUnlockContextAfterSendingMessage(messageSenderRef->lockingContextRef, lockToken); + } + else + { + ARA_INTERNAL_ASSERT(false && "trying to send IPC message while host has not set callHostBlock"); + if (replyHandler) + { + ARAIPCMessageDecoder replyDecoder = ARAIPCCFCreateMessageDecoderWithDictionary(NULL); + (*replyHandler)(replyDecoder, replyHandlerUserData); + replyDecoder.methods->destroyDecoder(replyDecoder.ref); + } + } + } +} + +bool ARA_CALL ARAIPCAUReceiverEndianessMatches(ARAIPCMessageSenderRef ARA_MAYBE_UNUSED_ARG(messageSenderRef)) +{ + // \todo shouldn't the AUMessageChannel provide this information? + return true; +} + +ARAIPCMessageSender ARA_CALL ARAIPCAUInitializeSender(ARAIPCMessageSenderImplementation * ref, const ARAIPCMessageSenderInterface * methods, + NSObject * _Nonnull messageChannel, ARAIPCLockingContextRef _Nonnull lockingContextRef) +{ + ARAIPCMessageSender sender; + sender.methods = methods; + + sender.ref = ref; + ARA_INTERNAL_ASSERT(sender.ref != NULL); +#if __has_feature(objc_arc) + memset((void*)ref, 0, sizeof(((ARAIPCMessageSenderImplementation *)NULL)->messageChannel)); // partially clear malloced memory or else ARC will try to release some "old object" upon assign + sender.ref->messageChannel = messageChannel; +#else + sender.ref->messageChannel = [messageChannel retain]; +#endif + sender.ref->lockingContextRef = lockingContextRef; + + return sender; +} + +void ARA_CALL ARAIPCAUDestroyMessageSender(ARAIPCMessageSender messageSender) +{ +#if __has_feature(objc_arc) + messageSender.ref->messageChannel = nil; +#else + [messageSender.ref->messageChannel release]; +#endif + free(messageSender.ref); +} + + + +void ARA_CALL ARAIPCAUGetRemoteInstanceReplyHandler(const ARAIPCMessageDecoder decoder, void * _Nullable userData) +{ + ARA_INTERNAL_ASSERT(!decoder.methods->isEmpty(decoder.ref)); + bool ARA_MAYBE_UNUSED_VAR(success) = decoder.methods->readSize(decoder.ref, 0, (ARAIPCPlugInInstanceRef*)userData); + ARA_INTERNAL_ASSERT(success); +} + +ARAIPCMessageSender ARA_CALL ARAIPCAUProxyPlugInCreateMessageSender(NSObject * _Nonnull messageChannel, + ARAIPCMessageSenderRef messageSenderRef, + ARAIPCLockingContextRef _Nonnull lockingContextRef) +{ + static const ARAIPCMessageSenderInterface senderInterface = { ARAIPCAUCreateEncoder, ARAIPCAUProxyPlugInSendMessage, ARAIPCAUReceiverEndianessMatches }; + ARAIPCMessageSender sender = ARAIPCAUInitializeSender(messageSenderRef, &senderInterface, messageChannel, lockingContextRef); + + // \todo we happen to use the same message block with the same locking context for both the + // ARA_AUDIOUNIT_FACTORY_CUSTOM_MESSAGES_UTI and all ARA_AUDIOUNIT_PLUGINEXTENSION_CUSTOM_MESSAGES_UTI uses, + // but it is generally unclear here how to set the correct message block if the channel is shared. + messageChannel.callHostBlock = ^NSDictionary * _Nullable (NSDictionary * _Nonnull message) + { + ARAIPCMessageDecoder messageDecoder = ARAIPCCFCreateMessageDecoderWithDictionary((__bridge CFDictionaryRef)message); + ARAIPCMessageID messageID = ARAIPCCFGetMessageIDFromDictionary(messageDecoder.ref); + + ARAIPCMessageEncoder replyEncoder = ARAIPCCFCreateMessageEncoder(); + + const ARAIPCLockingContextMessageHandlingToken lockToken = ARAIPCLockContextBeforeHandlingMessage(lockingContextRef); + ARAIPCProxyPlugInCallbacksDispatcher(messageID, &messageDecoder, &replyEncoder); + ARAIPCUnlockContextAfterHandlingMessage(lockingContextRef, lockToken); + + messageDecoder.methods->destroyDecoder(messageDecoder.ref); + + NSDictionary * replyDictionary = CFBridgingRelease(ARAIPCCFCopyMessageEncoderDictionary(replyEncoder.ref)); + replyEncoder.methods->destroyEncoder(replyEncoder.ref); + return replyDictionary; + }; + + return sender; +} + +id _Nullable ARA_CALL ARAIPCAUGetMessageChannel(AUAudioUnit * _Nonnull audioUnit, NSString * _Nonnull identifier) +{ + // AUAudioUnits created before macOS 13 will not know about this API yet + if (![audioUnit respondsToSelector:@selector(messageChannelFor:)]) + return nil; + + return [(AUAudioUnit *) audioUnit messageChannelFor:identifier]; +} + +bool ARA_CALL ARAIPCAUProxyPlugInInitializeFactoryMessageSender(ARAIPCMessageSender * _Nonnull messageSender, + AUAudioUnit * _Nonnull audioUnit, ARAIPCLockingContextRef _Nonnull lockingContextRef) +{ + id _Nullable messageChannel = ARAIPCAUGetMessageChannel(audioUnit, ARA_AUDIOUNIT_FACTORY_CUSTOM_MESSAGES_UTI); + if (!messageChannel) + return false; + + ARAIPCMessageSenderImplementation * messageSenderRef = malloc(sizeof(ARAIPCMessageSenderImplementation)); + *messageSender = ARAIPCAUProxyPlugInCreateMessageSender((NSObject * _Nonnull)messageChannel, messageSenderRef, lockingContextRef); + return true; +} + +const ARAFactory * _Nonnull ARA_CALL ARAIPCAUProxyPlugInGetFactory(ARAIPCMessageSender messageSender) +{ + ARA_VALIDATE_API_CONDITION(ARAIPCProxyPlugInGetFactoriesCount(messageSender) == 1); + const ARAFactory * result = ARAIPCProxyPlugInGetFactoryAtIndex(messageSender, 0); + ARA_VALIDATE_API_CONDITION(result != NULL); + return result; +} + +const ARAPlugInExtensionInstance * _Nullable ARA_CALL ARAIPCAUProxyPlugInBindToDocumentController(AUAudioUnit * _Nonnull audioUnit, + ARAIPCLockingContextRef _Nonnull lockingContextRef, + ARADocumentControllerRef _Nonnull documentControllerRef, + ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles, + ARAIPCMessageSender * _Nonnull messageSender) +{ + id _Nullable messageChannel = ARAIPCAUGetMessageChannel(audioUnit, ARA_AUDIOUNIT_PLUGINEXTENSION_CUSTOM_MESSAGES_UTI); + if (!messageChannel) + return NULL; + + ARAIPCAUProxyPlugInExtensionMessageSenderImplementation * messageSenderRef = malloc(sizeof(ARAIPCAUProxyPlugInExtensionMessageSenderImplementation)); + messageSenderRef->plugInExtensionInstance = NULL; + *messageSender = ARAIPCAUProxyPlugInCreateMessageSender((NSObject * _Nonnull)messageChannel, (ARAIPCMessageSenderImplementation *)messageSenderRef, lockingContextRef); + + ARAIPCMessageEncoder encoder = messageSender->methods->createEncoder(messageSender->ref); + ARAIPCReplyHandler replyHandler = ARAIPCAUGetRemoteInstanceReplyHandler; + messageSender->methods->sendMessage(false, messageSender->ref, kARAIPCGetRemoteInstanceRef, &encoder, &replyHandler, &messageSenderRef->remoteInstanceRef); + encoder.methods->destroyEncoder(encoder.ref); + + messageSenderRef->plugInExtensionInstance = ARAIPCProxyPlugInBindToDocumentController(messageSenderRef->remoteInstanceRef, *messageSender, documentControllerRef, knownRoles, assignedRoles); + return messageSenderRef->plugInExtensionInstance; +} + +void ARA_CALL ARAIPCAUProxyPlugInCleanupBinding(ARAIPCMessageSender messageSender) +{ + ARAIPCAUProxyPlugInExtensionMessageSenderImplementation * messageSenderRef = (ARAIPCAUProxyPlugInExtensionMessageSenderImplementation *)messageSender.ref; + if (messageSenderRef->plugInExtensionInstance) + ARAIPCProxyPlugInCleanupBinding(messageSenderRef->plugInExtensionInstance); + + ARAIPCAUDestroyMessageSender(messageSender); +} + +void ARA_CALL ARAIPCAUProxyPlugInUninitializeFactoryMessageSender(ARAIPCMessageSender messageSender) +{ + ARAIPCAUDestroyMessageSender(messageSender); +} + + + +ARAIPCLockingContextRef _sharedPlugInLockingContextRef; +ARAIPCMessageSender _sharedPlugInCallbacksSender; + +void ARA_CALL ARAIPCAUProxyHostAddFactory(const ARAFactory * _Nonnull factory) +{ + ARAIPCProxyHostAddFactory(factory); +} + +ARAIPCAUBindingHandler _bindingHandler = nil; + +const ARAPlugInExtensionInstance * ARA_CALL ARAIPCAUBindingHandlerWrapper(ARAIPCPlugInInstanceRef plugInInstanceRef, ARADocumentControllerRef controllerRef, + ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles) +{ + AUAudioUnit * audioUnit = (__bridge AUAudioUnit *)(void *)plugInInstanceRef; + return _bindingHandler (audioUnit, controllerRef, knownRoles, assignedRoles); +} + +void ARA_CALL ARAIPCAUProxyHostInitialize(NSObject * _Nonnull factoryMessageChannel, ARAIPCAUBindingHandler _Nonnull bindingHandler) +{ + _sharedPlugInLockingContextRef = ARAIPCCreateLockingContext(); + + static const ARAIPCMessageSenderInterface senderInterface = { ARAIPCAUCreateEncoder, ARAIPCAUProxyHostSendMessage, ARAIPCAUReceiverEndianessMatches }; + _sharedPlugInCallbacksSender = ARAIPCAUInitializeSender(malloc(sizeof(ARAIPCMessageSenderImplementation)), &senderInterface, factoryMessageChannel, _sharedPlugInLockingContextRef); + ARAIPCProxyHostSetPlugInCallbacksSender(_sharedPlugInCallbacksSender); + +#if __has_feature(objc_arc) + _bindingHandler = bindingHandler; +#else + _bindingHandler = [bindingHandler retain]; +#endif + ARAIPCProxyHostSetBindingHandler(ARAIPCAUBindingHandlerWrapper); +} + +NSDictionary * _Nonnull ARA_CALL ARAIPCAUProxyHostCommandHandler (AUAudioUnit * _Nullable audioUnit, NSDictionary * _Nonnull message) +{ + ARAIPCMessageDecoder messageDecoder = ARAIPCCFCreateMessageDecoderWithDictionary((__bridge CFDictionaryRef)message); + ARAIPCMessageID messageID = ARAIPCCFGetMessageIDFromDictionary(messageDecoder.ref); + + ARAIPCMessageEncoder replyEncoder = ARAIPCCFCreateMessageEncoder(); + + if (messageID == kARAIPCGetRemoteInstanceRef) + { + replyEncoder.methods->appendSize(replyEncoder.ref, 0, (ARAIPCPlugInInstanceRef)audioUnit); + } + else + { + const ARAIPCLockingContextMessageHandlingToken lockToken = ARAIPCLockContextBeforeHandlingMessage(_sharedPlugInLockingContextRef); + ARAIPCProxyHostCommandHandler(messageID, &messageDecoder, &replyEncoder); + ARAIPCUnlockContextAfterHandlingMessage(_sharedPlugInLockingContextRef, lockToken); + } + + messageDecoder.methods->destroyDecoder(messageDecoder.ref); + + NSDictionary * replyDictionary = CFBridgingRelease(ARAIPCCFCopyMessageEncoderDictionary(replyEncoder.ref)); + replyEncoder.methods->destroyEncoder(replyEncoder.ref); + return replyDictionary; +} + +void ARA_CALL ARAIPCAUProxyHostCleanupBinding(const ARAPlugInExtensionInstance * _Nonnull plugInExtensionInstance) +{ + ARAIPCProxyHostCleanupBinding(plugInExtensionInstance); +} + +void ARA_CALL ARAIPCAUProxyHostUninitalize(void) +{ +#if __has_feature(objc_arc) + _bindingHandler = nil; +#else + [_bindingHandler release]; +#endif + ARAIPCAUDestroyMessageSender(_sharedPlugInCallbacksSender); + ARAIPCDestroyLockingContext(_sharedPlugInLockingContextRef); +} + + +API_AVAILABLE_END + + +#if defined(__cplusplus) +} // extern "C" +} // namespace IPC +} // namespace ARA +#endif + + +#endif // ARA_AUDIOUNITV3_IPC_IS_AVAILABLE diff --git a/IPC/ARAIPCCFEncoding.cpp b/IPC/ARAIPCCFEncoding.cpp index b73600d..93aae33 100644 --- a/IPC/ARAIPCCFEncoding.cpp +++ b/IPC/ARAIPCCFEncoding.cpp @@ -40,6 +40,9 @@ extern "C" { #endif +// the message ID will be added to the underlying dictionary with a key that does not conflict with other message keys +constexpr ARAIPCMessageKey messageIDKey { -1 }; + class _CFReleaser { @@ -56,9 +59,11 @@ class _CFReleaser // wrap key value into CFString (no reference count transferred to caller) -CFStringRef ARA_CALL ARAIPCCFMessageGetEncodedKey (ARAIPCMessageKey argKey) +CFStringRef ARA_CALL ARAIPCCFMessageGetEncodedKey (ARAIPCMessageKey argKey, bool isInternalCall = false) { - ARA_INTERNAL_ASSERT (argKey >= 0); + if (!isInternalCall) + ARA_INTERNAL_ASSERT (argKey >= 0); + // \todo All plist formats available for CFPropertyListCreateData () in createEncodedMessage () need CFString keys. // Once we switch to the more modern (NS)XPC API we shall be able to use CFNumber keys directly... static std::map cache; @@ -166,6 +171,26 @@ ARAIPCMessageEncoder ARAIPCCFCreateMessageEncoder (void) return { ARAIPCCFMessageToEncoderRef (CFDictionaryCreateMutable (kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)), &encoderMethods }; } +__attribute__((cf_returns_retained)) CFDictionaryRef ARAIPCCFCopyMessageEncoderDictionary (ARAIPCMessageEncoderRef messageEncoderRef) +{ + const auto dictionary { ARAIPCCFMessageFromEncoderRef (messageEncoderRef) }; + ARA_INTERNAL_ASSERT (dictionary); + CFRetain (dictionary); + return dictionary; +} + +__attribute__((cf_returns_retained)) CFDictionaryRef ARAIPCCFCopyMessageEncoderDictionaryAddingMessageID (ARAIPCMessageEncoderRef messageEncoderRef, ARAIPCMessageID messageIDValue) +{ + static_assert (std::is_same::value, "encoding needs to be adopted here if key type is changed"); + auto messageIDObject { CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &messageIDValue) }; + auto dictionary { ARAIPCCFMessageFromEncoderRef (messageEncoderRef) }; + ARA_INTERNAL_ASSERT (dictionary); + CFDictionarySetValue (dictionary, ARAIPCCFMessageGetEncodedKey (messageIDKey, true), messageIDObject); + CFRelease (messageIDObject); + CFRetain (dictionary); + return dictionary; +} + __attribute__((cf_returns_retained)) CFDataRef ARAIPCCFCreateMessageEncoderData (ARAIPCMessageEncoderRef messageEncoderRef) { const auto dictionary { ARAIPCCFMessageFromEncoderRef (messageEncoderRef) }; @@ -334,7 +359,7 @@ ARAIPCMessageDecoderRef ARA_CALL ARAIPCCFMessageReadSubMessage (ARAIPCMessageDec return ARAIPCCFMessageToDecoderRef (dictionary); } -ARAIPCMessageDecoder ARAIPCCFCreateMessageDecoder (CFDataRef messageData) +ARAIPCMessageDecoder ARAIPCCFCreateMessageDecoderWithRetainedDictionary (CFDictionaryRef __attribute__((cf_consumed)) messageDictionary) { static const ARA::IPC::ARAIPCMessageDecoderInterface decoderMethods { @@ -351,17 +376,39 @@ ARAIPCMessageDecoder ARAIPCCFCreateMessageDecoder (CFDataRef messageData) ARAIPCCFMessageReadSubMessage }; + return { ARAIPCCFMessageToDecoderRef (messageDictionary), &decoderMethods }; +} + +ARAIPCMessageDecoder ARAIPCCFCreateMessageDecoderWithDictionary (CFDictionaryRef messageDictionary) +{ + if (messageDictionary) + CFRetain (messageDictionary); + + return ARAIPCCFCreateMessageDecoderWithRetainedDictionary (messageDictionary); +} + +ARAIPCMessageID ARAIPCCFGetMessageIDFromDictionary (ARAIPCMessageDecoderRef messageDecoderRef) +{ + const auto dictionary { ARAIPCCFMessageFromDecoderRef (messageDecoderRef) }; + ARA_INTERNAL_ASSERT (dictionary != nullptr); + const auto number { (CFNumberRef) CFDictionaryGetValue (dictionary, ARAIPCCFMessageGetEncodedKey (messageIDKey, true)) }; + ARA_INTERNAL_ASSERT (number != nullptr); + ARA_INTERNAL_ASSERT (CFGetTypeID (number) == CFNumberGetTypeID ()); + static_assert (std::is_same::value, "decoding needs to be adopted here if key type is changed"); + ARAIPCMessageID result; + CFNumberGetValue (number, kCFNumberSInt32Type, &result); + return result; +} + +ARAIPCMessageDecoder ARAIPCCFCreateMessageDecoder (CFDataRef messageData) +{ if (CFDataGetLength (messageData) == 0) - return { nullptr, &decoderMethods }; + return ARAIPCCFCreateMessageDecoderWithRetainedDictionary (nullptr); + auto dictionary { (CFDictionaryRef) CFPropertyListCreateWithData (kCFAllocatorDefault, messageData, kCFPropertyListImmutable, nullptr, nullptr) }; ARA_INTERNAL_ASSERT (dictionary && (CFGetTypeID (dictionary) == CFDictionaryGetTypeID ())); -#if defined (__clang_analyzer__) - // \todo hotfix to silence the analyzer: it does not know that ARAIPCMessageDecoder - // is supposed to store the retained value and release upon destruction - - // what would be the proper annotation here? - CFRelease (dictionary); -#endif - return { ARAIPCCFMessageToDecoderRef (dictionary), &decoderMethods }; + auto result { ARAIPCCFCreateMessageDecoderWithRetainedDictionary (dictionary) }; + return result; } diff --git a/IPC/ARAIPCCFEncoding.h b/IPC/ARAIPCCFEncoding.h index 3d7188e..4b64e22 100644 --- a/IPC/ARAIPCCFEncoding.h +++ b/IPC/ARAIPCCFEncoding.h @@ -35,8 +35,12 @@ extern "C" { ARAIPCMessageEncoder ARAIPCCFCreateMessageEncoder(void); +__attribute__((cf_returns_retained)) CFDictionaryRef ARAIPCCFCopyMessageEncoderDictionary(ARAIPCMessageEncoderRef messageEncoder); +__attribute__((cf_returns_retained)) CFDictionaryRef ARAIPCCFCopyMessageEncoderDictionaryAddingMessageID(ARAIPCMessageEncoderRef messageEncoder, ARAIPCMessageID messageIDValue); __attribute__((cf_returns_retained)) CFDataRef ARAIPCCFCreateMessageEncoderData(ARAIPCMessageEncoderRef messageEncoderRef); +ARAIPCMessageDecoder ARAIPCCFCreateMessageDecoderWithDictionary(CFDictionaryRef messageDictionary); +ARAIPCMessageID ARAIPCCFGetMessageIDFromDictionary(ARAIPCMessageDecoderRef messageDecoderRef); ARAIPCMessageDecoder ARAIPCCFCreateMessageDecoder(CFDataRef messageData); From d98dd12877acbd38ef6c257333c08ca8600db7f3 Mon Sep 17 00:00:00 2001 From: sgretscher <41306803+sgretscher@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:32:01 +0100 Subject: [PATCH 17/18] Add workaround for macOS 13 destroying remote Audio Units asynchronously In order to maintain actual host call order with synchronous ARA calls, destruction must be synchronous. --- IPC/ARAIPCAudioUnit_v3.h | 8 +++++++- IPC/ARAIPCAudioUnit_v3.m | 27 ++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/IPC/ARAIPCAudioUnit_v3.h b/IPC/ARAIPCAudioUnit_v3.h index 73b2343..266e271 100644 --- a/IPC/ARAIPCAudioUnit_v3.h +++ b/IPC/ARAIPCAudioUnit_v3.h @@ -81,8 +81,14 @@ void ARA_CALL ARAIPCAUProxyHostAddFactory(const ARAFactory * _Nonnull factory); typedef const ARAPlugInExtensionInstance * _Nonnull (^ARAIPCAUBindingHandler)(AUAudioUnit * _Nonnull audioUnit, ARADocumentControllerRef _Nonnull controllerRef, ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles); +//! callback that the proxy uses to ensure synchronous destruction of a an AUAudioUnit bound to ARA +//! this extra hook is necessary because the regular teardown via dealloc is delayed in macOS 13 on +//! the remote end, causing race conditions with ARA teardown methods send after plug-in destruction +typedef void (^ARAIPCAUDestructionHandler)(AUAudioUnit * _Nonnull audioUnit); + //! plug-in side: static configuration: after adding all factories, initialize the IPC (before allocating any instances) -void ARA_CALL ARAIPCAUProxyHostInitialize(NSObject * _Nonnull factoryMessageChannel, ARAIPCAUBindingHandler _Nonnull bindingHandler); +void ARA_CALL ARAIPCAUProxyHostInitialize(NSObject * _Nonnull factoryMessageChannel, + ARAIPCAUBindingHandler _Nonnull bindingHandler, ARAIPCAUDestructionHandler _Nonnull destructionHandler); //! plug-in side: implementation for AUMessageChannel -callAudioUnit: NSDictionary * _Nonnull ARA_CALL ARAIPCAUProxyHostCommandHandler (AUAudioUnit * _Nullable audioUnit, NSDictionary * _Nonnull wrappedMessage); diff --git a/IPC/ARAIPCAudioUnit_v3.m b/IPC/ARAIPCAudioUnit_v3.m index d788640..87dd4ad 100644 --- a/IPC/ARAIPCAudioUnit_v3.m +++ b/IPC/ARAIPCAudioUnit_v3.m @@ -44,6 +44,9 @@ // custom IPC message to read the remote instance ref const ARAIPCMessageID kARAIPCGetRemoteInstanceRef = -1; +// custom IPC message to force synchronous IPC shutdown despite the OS shutting down asynchronously +const ARAIPCMessageID kARAIPCDestroyRemoteInstance = -2; + // "base class" layout used in plug-in and host typedef struct ARAIPCMessageSenderImplementation @@ -258,7 +261,14 @@ void ARA_CALL ARAIPCAUProxyPlugInCleanupBinding(ARAIPCMessageSender messageSende { ARAIPCAUProxyPlugInExtensionMessageSenderImplementation * messageSenderRef = (ARAIPCAUProxyPlugInExtensionMessageSenderImplementation *)messageSender.ref; if (messageSenderRef->plugInExtensionInstance) + { + ARAIPCMessageEncoder encoder = messageSender.methods->createEncoder(messageSender.ref); + encoder.methods->appendSize(encoder.ref, 0, messageSenderRef->remoteInstanceRef); + messageSender.methods->sendMessage(false, messageSender.ref, kARAIPCDestroyRemoteInstance, &encoder, NULL, NULL); + encoder.methods->destroyEncoder(encoder.ref); + ARAIPCProxyPlugInCleanupBinding(messageSenderRef->plugInExtensionInstance); + } ARAIPCAUDestroyMessageSender(messageSender); } @@ -279,6 +289,7 @@ void ARA_CALL ARAIPCAUProxyHostAddFactory(const ARAFactory * _Nonnull factory) } ARAIPCAUBindingHandler _bindingHandler = nil; +ARAIPCAUDestructionHandler _destructionHandler = nil; const ARAPlugInExtensionInstance * ARA_CALL ARAIPCAUBindingHandlerWrapper(ARAIPCPlugInInstanceRef plugInInstanceRef, ARADocumentControllerRef controllerRef, ARAPlugInInstanceRoleFlags knownRoles, ARAPlugInInstanceRoleFlags assignedRoles) @@ -287,7 +298,7 @@ void ARA_CALL ARAIPCAUProxyHostAddFactory(const ARAFactory * _Nonnull factory) return _bindingHandler (audioUnit, controllerRef, knownRoles, assignedRoles); } -void ARA_CALL ARAIPCAUProxyHostInitialize(NSObject * _Nonnull factoryMessageChannel, ARAIPCAUBindingHandler _Nonnull bindingHandler) +void ARA_CALL ARAIPCAUProxyHostInitialize(NSObject * _Nonnull factoryMessageChannel, ARAIPCAUBindingHandler _Nonnull bindingHandler, ARAIPCAUDestructionHandler _Nonnull destructionHandler) { _sharedPlugInLockingContextRef = ARAIPCCreateLockingContext(); @@ -297,8 +308,10 @@ void ARA_CALL ARAIPCAUProxyHostInitialize(NSObject * _Nonnull #if __has_feature(objc_arc) _bindingHandler = bindingHandler; + _destructionHandler = destructionHandler; #else _bindingHandler = [bindingHandler retain]; + _destructionHandler = [destructionHandler retain]; #endif ARAIPCProxyHostSetBindingHandler(ARAIPCAUBindingHandlerWrapper); } @@ -314,6 +327,16 @@ void ARA_CALL ARAIPCAUProxyHostInitialize(NSObject * _Nonnull { replyEncoder.methods->appendSize(replyEncoder.ref, 0, (ARAIPCPlugInInstanceRef)audioUnit); } + else if (messageID == kARAIPCDestroyRemoteInstance) + { + ARA_INTERNAL_ASSERT(!messageDecoder.methods->isEmpty(messageDecoder.ref)); + ARAIPCPlugInInstanceRef plugInInstanceRef; + bool ARA_MAYBE_UNUSED_VAR(success) = messageDecoder.methods->readSize(messageDecoder.ref, 0, &plugInInstanceRef); + ARA_INTERNAL_ASSERT(success); + + AUAudioUnit * audioUnit = (__bridge AUAudioUnit *)(void *)plugInInstanceRef; + _destructionHandler (audioUnit); + } else { const ARAIPCLockingContextMessageHandlingToken lockToken = ARAIPCLockContextBeforeHandlingMessage(_sharedPlugInLockingContextRef); @@ -337,8 +360,10 @@ void ARA_CALL ARAIPCAUProxyHostUninitalize(void) { #if __has_feature(objc_arc) _bindingHandler = nil; + _destructionHandler = nil; #else [_bindingHandler release]; + [_destructionHandler release]; #endif ARAIPCAUDestroyMessageSender(_sharedPlugInCallbacksSender); ARAIPCDestroyLockingContext(_sharedPlugInLockingContextRef); From 8bc292fdf62b0aa027d2fb9571ec4a53d69abdc2 Mon Sep 17 00:00:00 2001 From: Dan Raviv Date: Fri, 11 Nov 2022 13:21:35 -0800 Subject: [PATCH 18/18] Initialize atomic_flag Avoids Clang UB sanitizer warning on test_and_set in DocumentController ctor --- PlugIn/ARAPlug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PlugIn/ARAPlug.h b/PlugIn/ARAPlug.h index eec4b33..13e7706 100644 --- a/PlugIn/ARAPlug.h +++ b/PlugIn/ARAPlug.h @@ -1355,7 +1355,7 @@ class DocumentController : public DocumentControllerInterface, std::map _audioSourceContentUpdates; std::map _audioModificationContentUpdates; std::map _playbackRegionContentUpdates; - std::atomic_flag _analysisProgressIsSynced/* { true } C++ standard only allows for default-init to false */; + std::atomic_flag _analysisProgressIsSynced = ATOMIC_FLAG_INIT; bool _isHostEditingDocument { false };