diff --git a/androidaudioplugin/src/main/cpp/CMakeLists.txt b/androidaudioplugin/src/main/cpp/CMakeLists.txt index e6c581c8..f0f1e63f 100644 --- a/androidaudioplugin/src/main/cpp/CMakeLists.txt +++ b/androidaudioplugin/src/main/cpp/CMakeLists.txt @@ -24,6 +24,7 @@ set (androidaudioplugin_SOURCES "core/aapxs/presets-aapxs.cpp" "core/aapxs/state-aapxs.cpp" "core/aapxs/standard-extensions.cpp" + "core/aapxs/urid-aapxs.cpp" ) if (ANDROID) diff --git a/androidaudioplugin/src/main/cpp/core/aapxs/standard-extensions.cpp b/androidaudioplugin/src/main/cpp/core/aapxs/standard-extensions.cpp index 7921a6a0..ca835826 100644 --- a/androidaudioplugin/src/main/cpp/core/aapxs/standard-extensions.cpp +++ b/androidaudioplugin/src/main/cpp/core/aapxs/standard-extensions.cpp @@ -6,6 +6,7 @@ aap::xs::AAPXSDefinition_Parameters parameters; aap::xs::AAPXSDefinition_Presets presets; aap::xs::AAPXSDefinition_State state; aap::xs::AAPXSDefinition_Gui gui; +aap::xs::AAPXSDefinition_Urid urid; aap::xs::AAPXSDefinitionRegistry::AAPXSDefinitionRegistry( std::unique_ptr mapping, @@ -18,6 +19,7 @@ aap::xs::AAPXSDefinitionRegistry::AAPXSDefinitionRegistry( } aap::xs::AAPXSDefinitionRegistry standard_extensions{std::make_unique(), std::vector({ + urid.asPublic(), midi.asPublic(), parameters.asPublic(), presets.asPublic(), diff --git a/androidaudioplugin/src/main/cpp/core/aapxs/urid-aapxs.cpp b/androidaudioplugin/src/main/cpp/core/aapxs/urid-aapxs.cpp new file mode 100644 index 00000000..eecc0670 --- /dev/null +++ b/androidaudioplugin/src/main/cpp/core/aapxs/urid-aapxs.cpp @@ -0,0 +1,62 @@ + +#include "aap/core/aapxs/urid-aapxs.h" +#include "../AAPJniFacade.h" + +void aap::xs::AAPXSDefinition_Urid::aapxs_urid_process_incoming_plugin_aapxs_request( + struct AAPXSDefinition *feature, AAPXSRecipientInstance *aapxsInstance, + AndroidAudioPlugin *plugin, AAPXSRequestContext *request) { + auto ext = (aap_urid_extension_t*) plugin->get_extension(plugin, AAP_URID_EXTENSION_URI); + if (!ext) + return; // FIXME: should there be any global error handling? + switch (request->opcode) { + case OPCODE_MAP: + uint8_t urid = *(uint8_t*) request->serialization->data; + auto len = *(int32_t *) ((uint8_t*) request->serialization->data + 1); + assert(len < AAP_MAX_EXTENSION_URI_SIZE); + char uri[AAP_MAX_EXTENSION_URI_SIZE]; + strncpy(uri, (const char *) (1 + (int32_t *) request->serialization->data), len); + ext->map(ext, plugin, urid, uri); + aapxsInstance->send_aapxs_reply(aapxsInstance, request); + break; + } +} + +void aap::xs::AAPXSDefinition_Urid::aapxs_urid_process_incoming_host_aapxs_request( + struct AAPXSDefinition *feature, AAPXSRecipientInstance *aapxsInstance, + AndroidAudioPluginHost *host, AAPXSRequestContext *request) { + throw std::runtime_error("There is no URID host extension"); +} + +void aap::xs::AAPXSDefinition_Urid::aapxs_urid_process_incoming_plugin_aapxs_reply( + struct AAPXSDefinition *feature, AAPXSInitiatorInstance *aapxsInstance, + AndroidAudioPlugin *plugin, AAPXSRequestContext *request) { + if (request->callback != nullptr) + request->callback(request->callback_user_data, plugin, request->request_id); +} + +void aap::xs::AAPXSDefinition_Urid::aapxs_urid_process_incoming_host_aapxs_reply( + struct AAPXSDefinition *feature, AAPXSInitiatorInstance *aapxsInstance, + AndroidAudioPluginHost *host, AAPXSRequestContext *request) { + if (request->callback != nullptr) + request->callback(request->callback_user_data, host, request->request_id); +} + +AAPXSExtensionClientProxy +aap::xs::AAPXSDefinition_Urid::aapxs_urid_get_plugin_proxy(struct AAPXSDefinition *feature, + AAPXSInitiatorInstance *aapxsInstance, + AAPXSSerializationContext *serialization) { + auto client = (AAPXSDefinition_Urid*) feature->aapxs_context; + if (!client->typed_client) + client->typed_client = std::make_unique(aapxsInstance, serialization); + *client->typed_client = UridClientAAPXS(aapxsInstance, serialization); + client->client_proxy = AAPXSExtensionClientProxy{client->typed_client.get(), aapxs_urid_as_plugin_extension}; + return client->client_proxy; +} + +void aap::xs::UridClientAAPXS::map(uint8_t urid, const char *uri) { + *(uint8_t*) serialization->data = urid; + size_t len = strlen(uri); + *(uint32_t*) ((uint8_t*) serialization->data + 1) = len; + memcpy((uint8_t*) serialization->data + 1 + sizeof(int32_t), uri, len); + callVoidFunctionSynchronously(OPCODE_MAP); +} diff --git a/include/aap/core/aapxs/standard-extensions.h b/include/aap/core/aapxs/standard-extensions.h index 4518b09b..8c2a4418 100644 --- a/include/aap/core/aapxs/standard-extensions.h +++ b/include/aap/core/aapxs/standard-extensions.h @@ -8,6 +8,7 @@ #include "state-aapxs.h" #include "midi-aapxs.h" #include "gui-aapxs.h" +#include "urid-aapxs.h" namespace aap::xs { class StandardExtensions { diff --git a/include/aap/core/aapxs/urid-aapxs.h b/include/aap/core/aapxs/urid-aapxs.h new file mode 100644 index 00000000..be734531 --- /dev/null +++ b/include/aap/core/aapxs/urid-aapxs.h @@ -0,0 +1,96 @@ + + +#ifndef AAP_CORE_URID_AAPXS_H +#define AAP_CORE_URID_AAPXS_H + +#include +#include +#include "aap/aapxs.h" +#include "../../ext/urid.h" +#include "typed-aapxs.h" + +// plugin extension opcodes +const int32_t OPCODE_MAP = 1; + +// host extension opcodes +// ... nothing? + +const int32_t URID_SHARED_MEMORY_SIZE = AAP_MAX_PLUGIN_ID_SIZE + sizeof(int32_t) * 2 + AAP_MAX_EXTENSION_URI_SIZE + 1; + +namespace aap::xs { + class UridClientAAPXS : public TypedAAPXS { + static void staticMap(aap_urid_extension_t* ext, AndroidAudioPlugin*, uint8_t urid, const char* uri) { + return ((UridClientAAPXS*) ext->aapxs_context)->map(urid, uri); + } + aap_urid_extension_t as_public_extension{this, staticMap}; + public: + UridClientAAPXS(AAPXSInitiatorInstance* initiatorInstance, AAPXSSerializationContext* serialization) + : TypedAAPXS(AAP_URID_EXTENSION_URI, initiatorInstance, serialization) { + } + + void map(uint8_t urid, const char* uri); + + aap_urid_extension_t* asPluginExtension() { return &as_public_extension; } + }; + + class UridServiceAAPXS : public TypedAAPXS { + public: + UridServiceAAPXS(AAPXSInitiatorInstance* initiatorInstance, AAPXSSerializationContext* serialization) + : TypedAAPXS(AAP_URID_EXTENSION_URI, initiatorInstance, serialization) { + } + + // nothing? + }; + + class AAPXSDefinition_Urid : public AAPXSDefinitionWrapper { + + static void aapxs_urid_process_incoming_plugin_aapxs_request( + struct AAPXSDefinition* feature, + AAPXSRecipientInstance* aapxsInstance, + AndroidAudioPlugin* plugin, + AAPXSRequestContext* request); + static void aapxs_urid_process_incoming_host_aapxs_request( + struct AAPXSDefinition* feature, + AAPXSRecipientInstance* aapxsInstance, + AndroidAudioPluginHost* host, + AAPXSRequestContext* request); + static void aapxs_urid_process_incoming_plugin_aapxs_reply( + struct AAPXSDefinition* feature, + AAPXSInitiatorInstance* aapxsInstance, + AndroidAudioPlugin* plugin, + AAPXSRequestContext* request); + static void aapxs_urid_process_incoming_host_aapxs_reply( + struct AAPXSDefinition* feature, + AAPXSInitiatorInstance* aapxsInstance, + AndroidAudioPluginHost* host, + AAPXSRequestContext* request); + + // It is used in synchronous context such as `get_extension()` in `binder-client-as-plugin.cpp` etc. + static AAPXSExtensionClientProxy aapxs_urid_get_plugin_proxy( + struct AAPXSDefinition* feature, + AAPXSInitiatorInstance* aapxsInstance, + AAPXSSerializationContext* serialization); + + static void* aapxs_urid_as_plugin_extension(AAPXSExtensionClientProxy* proxy) { + return ((UridClientAAPXS*) proxy->aapxs_context)->asPluginExtension(); + } + + AAPXSDefinition aapxs_urid{this, + AAP_URID_EXTENSION_URI, + URID_SHARED_MEMORY_SIZE, + aapxs_urid_process_incoming_plugin_aapxs_request, + aapxs_urid_process_incoming_host_aapxs_request, + aapxs_urid_process_incoming_plugin_aapxs_reply, + aapxs_urid_process_incoming_host_aapxs_reply, + aapxs_urid_get_plugin_proxy, + nullptr // no host extension + }; + + public: + AAPXSDefinition& asPublic() override { + return aapxs_urid; + } + }; +} + +#endif //AAP_CORE_URID_AAPXS_H diff --git a/include/aap/ext/urid.h b/include/aap/ext/urid.h new file mode 100644 index 00000000..6447e5d2 --- /dev/null +++ b/include/aap/ext/urid.h @@ -0,0 +1,32 @@ +#ifndef AAP_URID_H_INCLUDED +#define AAP_URID_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../android-audio-plugin.h" +#include "stdint.h" + +#define AAP_URID_EXTENSION_URI "urn://androidaudioplugin.org/extensions/urid/v3" + +typedef struct aap_urid_extension_t { + /* + * `aapxs_context` is an opaque pointer assigned and used by AAPXS hosting implementation (libandroidaudioplugin). + * Neither of plugin developer (extension user) or extension developers is supposed to touch it. + * this struct is instantiated per extension in a plugin instance. + */ + void *aapxs_context; + + /* + * Add a mapping from URI to URID. + * It is an error if this function is called once it started "beginPrepare()" call. + */ + void (*map) (aap_urid_extension_t* ext, AndroidAudioPlugin* plugin, uint8_t urid, const char* uri); +} aap_urid_extension_t; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AAP_URID_H_INCLUDED