From 09dcd54cbf6960ada3c52736a59232d78cbe3339 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 9 Nov 2023 16:07:34 +0900 Subject: [PATCH] AAPXS v2: basic host extension now works. aapxssample now invokes `notify_parameters_changed()` in every `process()` (which usually should not happen but as a dogfooding). --- .../main/cpp/core/aapxs/parameters-aapxs.cpp | 4 +-- .../cpp/core/hosting/PluginInstance.Local.cpp | 35 ++++++++----------- include/aap/core/aapxs/typed-aapxs.h | 8 +++++ include/aap/core/host/plugin-instance.h | 8 +++-- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/androidaudioplugin/src/main/cpp/core/aapxs/parameters-aapxs.cpp b/androidaudioplugin/src/main/cpp/core/aapxs/parameters-aapxs.cpp index 6483f87f..8bf455fd 100644 --- a/androidaudioplugin/src/main/cpp/core/aapxs/parameters-aapxs.cpp +++ b/androidaudioplugin/src/main/cpp/core/aapxs/parameters-aapxs.cpp @@ -103,7 +103,7 @@ AAPXSExtensionServiceProxy aap::xs::AAPXSDefinition_Parameters::aapxs_parameters if (!service->typed_service) service->typed_service = std::make_unique(aapxsInstance, serialization); //*service->typed_service = ParametersServiceAAPXS(aapxsInstance, serialization); - service->service_proxy.aapxs_context = &service->typed_service; + service->service_proxy.aapxs_context = service->typed_service.get(); service->service_proxy.as_host_extension = aapxs_parameters_as_host_extension; return service->service_proxy; } @@ -196,5 +196,5 @@ int32_t aap::xs::ParametersClientAAPXS::getEnumerationAsync(int32_t index, int32 } void aap::xs::ParametersServiceAAPXS::notifyParametersChanged() { - callVoidFunctionSynchronously(OPCODE_NOTIFY_PARAMETERS_CHANGED); + fireVoidFunctionAndForget(OPCODE_NOTIFY_PARAMETERS_CHANGED); } diff --git a/androidaudioplugin/src/main/cpp/core/hosting/PluginInstance.Local.cpp b/androidaudioplugin/src/main/cpp/core/hosting/PluginInstance.Local.cpp index 3470293b..7f9ec7f5 100644 --- a/androidaudioplugin/src/main/cpp/core/hosting/PluginInstance.Local.cpp +++ b/androidaudioplugin/src/main/cpp/core/hosting/PluginInstance.Local.cpp @@ -65,13 +65,14 @@ AndroidAudioPluginHost* aap::LocalPluginInstance::getHostFacadeForCompleteInstan void * aap::LocalPluginInstance::internalGetHostExtension(AndroidAudioPluginHost *host, const char *uri) { auto instance = (LocalPluginInstance *) host->context; + // FIXME: in the future maybe we want to eliminate this kind of special cases. if (strcmp(uri, AAP_PLUGIN_INFO_EXTENSION_URI) == 0) { instance->host_plugin_info.get = get_plugin_info; return &instance->host_plugin_info; } - // FIXME: implement more extensions + // Look up host extension and get proxy via AAPXSDefinition. auto definition = instance->getAAPXSRegistry()->items()->getByUri(uri); - if (definition) { + if (definition && definition->get_host_extension_proxy) { auto aapxsInstance = instance->getAAPXSDispatcher().getHostAAPXSByUri(uri); auto proxy = definition->get_host_extension_proxy(definition, aapxsInstance, aapxsInstance->serialization); return proxy.as_host_extension(&proxy); @@ -176,14 +177,10 @@ void aap::LocalPluginInstance::setupAAPXS() { } static inline void staticSendAAPXSReply(AAPXSRecipientInstance* instance, AAPXSRequestContext* context) { - ((aap::LocalPluginInstance *) instance->host_context)->sendPluginAAPXSReply(context->uri, - context->opcode, - context->serialization->data, - context->serialization->data_size, - context->request_id); + ((aap::LocalPluginInstance *) instance->host_context)->sendPluginAAPXSReply(context); } static inline bool staticSendAAPXSRequest(AAPXSInitiatorInstance* instance, AAPXSRequestContext* context) { - return ((aap::LocalPluginInstance*) instance->host_context)->sendHostAAPXSRequest(context->uri, context->opcode, context->serialization->data, context->serialization->data_size, context->request_id); + return ((aap::LocalPluginInstance*) instance->host_context)->sendHostAAPXSRequest(context); } void aap::LocalPluginInstance::setupAAPXSInstances() { @@ -203,38 +200,34 @@ void aap::LocalPluginInstance::setupAAPXSInstances() { } void -aap::LocalPluginInstance::sendPluginAAPXSReply(const char* uri, int32_t opcode, void *data, int32_t dataSize, uint32_t requestId) { +aap::LocalPluginInstance::sendPluginAAPXSReply(AAPXSRequestContext* request) { if (instantiation_state == PLUGIN_INSTANTIATION_STATE_ACTIVE) { - auto aapxsInstance = getAAPXSDispatcher().getPluginAAPXSByUri(uri); aapxs_midi2_processor.addReply(aapxsProcessorAddEventUmpOutput, this, - uri, + request->uri, // should we support MIDI 2.0 group? 0, - requestId, - aapxsInstance->serialization->data, - dataSize, - opcode); + request->request_id, + request->serialization->data, + request->serialization->data_size, + request->opcode); } else { // it is synchronously handled at Binder IPC, nothing to process here. } } bool -aap::LocalPluginInstance::sendHostAAPXSRequest(const char* uri, int32_t opcode, void *data, int32_t dataSize, uint32_t newRequestId) { - auto aapxsInstance = aapxs_dispatcher.getHostAAPXSByUri(uri); - +aap::LocalPluginInstance::sendHostAAPXSRequest(AAPXSRequestContext* request) { // If it is at ACTIVE state it has to switch to AAPXS SysEx8 MIDI messaging mode, // otherwise it goes to the Binder route. if (instantiation_state == PLUGIN_INSTANTIATION_STATE_ACTIVE) { // aapxsInstance already contains binary data here, so we retrieve data from there. - int32_t group = 0; // will we have to give special semantics on it? // This is an asynchronous function, so we do not wait for the result. - aapxs_host_session.addSession(aapxsSessionAddEventUmpInput, this, group, newRequestId, uri, aapxsInstance->serialization->data, dataSize, opcode); + aapxs_host_session.addSession(aapxsSessionAddEventUmpInput, this, request); return true; } else { // the actual implementation is in AudioPluginInterfaceImpl, kicks `hostExtension()` on the callback proxy object. - ipc_send_extension_message_func(ipc_send_extension_message_context, uri, getInstanceId(), opcode); + ipc_send_extension_message_func(ipc_send_extension_message_context, request->uri, getInstanceId(), request->opcode); return false; } } diff --git a/include/aap/core/aapxs/typed-aapxs.h b/include/aap/core/aapxs/typed-aapxs.h index 81a99121..3d4a8e2a 100644 --- a/include/aap/core/aapxs/typed-aapxs.h +++ b/include/aap/core/aapxs/typed-aapxs.h @@ -79,6 +79,14 @@ namespace aap::xs { if (aapxs_instance->send_aapxs_request(aapxs_instance, &request)) future.wait(); } + + // "Fire and forget" invocation. Host extensions must be always like this. + void fireVoidFunctionAndForget(int32_t opcode) { + uint32_t requestId = aapxs_instance->get_new_request_id(aapxs_instance); + AAPXSRequestContext request{nullptr, nullptr, serialization, urid, uri, requestId, + opcode}; + aapxs_instance->send_aapxs_request(aapxs_instance, &request); + } }; class AAPXSDefinitionWrapper { diff --git a/include/aap/core/host/plugin-instance.h b/include/aap/core/host/plugin-instance.h index 4b12fa96..4d986cef 100644 --- a/include/aap/core/host/plugin-instance.h +++ b/include/aap/core/host/plugin-instance.h @@ -221,8 +221,12 @@ namespace aap { xs::AAPXSDefinitionServiceRegistry* getAAPXSRegistry() { return feature_registry.get(); } xs::AAPXSServiceDispatcher& getAAPXSDispatcher() { return aapxs_dispatcher; } void setupAAPXSInstances(); - void sendPluginAAPXSReply(const char *uri, int32_t opcode, void *data, int32_t dataSize, uint32_t newRequestId); - bool sendHostAAPXSRequest(const char *uri, int32_t opcode, void *data, int32_t dataSize, uint32_t newRequestId); + void sendPluginAAPXSReply(AAPXSRequestContext* request); + // returns true if it is asynchronously invoked without waiting for result, + // or false if it is synchronously completed. + // Note that, however, there should not be synchronous callback in ACTIVE (realtime) mode, because + // there will not be any RT-safe return mode across multiple `process()` calls. + bool sendHostAAPXSRequest(AAPXSRequestContext* request); void setIpcExtensionMessageSender(aapxs_host_ipc_sender sender, void* context) { ipc_send_extension_message_func = sender;