Skip to content

Commit

Permalink
[WIP] async realtime AAPXS work.
Browse files Browse the repository at this point in the history
It implements basic workflow for asynchronous realtime AAPXS support. context:

#169
#176
  • Loading branch information
atsushieno committed Sep 28, 2023
1 parent 3f624bb commit fd1e00f
Show file tree
Hide file tree
Showing 12 changed files with 311 additions and 91 deletions.
1 change: 1 addition & 0 deletions androidaudioplugin/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ project(androidaudioplugin LANGUAGES CXX)

# List of sources. Android build has some additional sources.
set (androidaudioplugin_SOURCES
"core/hosting/AAPXSMidi2ClientSession.cpp"
"core/hosting/AAPXSMidi2Processor.cpp"
"core/hosting/PluginInformation.cpp"
"core/hosting/PluginInstance.cpp"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@


#include "aap/core/AAPXSMidi2ClientSession.h"
#include <stdlib.h>
#include "aap/core/aap_midi2_helper.h"
#include "aap/ext/midi.h"

aap::AAPXSMidi2ClientSession::AAPXSMidi2ClientSession(int32_t midiBufferSize)
: midi_buffer_size(midiBufferSize) {
aapxs_rt_midi_buffer = (uint8_t*) calloc(1, midi_buffer_size);
aapxs_rt_conversion_helper_buffer = (uint8_t*) calloc(1, midi_buffer_size);
aap_midi2_aapxs_parse_context_prepare(&aapxs_parse_context,
aapxs_rt_midi_buffer,
aapxs_rt_conversion_helper_buffer,
AAP_MIDI2_AAPXS_DATA_MAX_SIZE);
}

aap::AAPXSMidi2ClientSession::~AAPXSMidi2ClientSession() {
if (aapxs_rt_midi_buffer)
free(aapxs_rt_midi_buffer);
if (aapxs_rt_conversion_helper_buffer)
free(aapxs_rt_conversion_helper_buffer);
}

void aap::AAPXSMidi2ClientSession::addSession(
void (*addMidi2Event)(AAPXSMidi2ClientSession * session, void *userData, int32_t messageSize),
void* addMidi2EventUserData,
int32_t group,
int32_t requestId,
AAPXSClientInstance *aapxsInstance,
int32_t messageSize,
int32_t opcode) {
size_t size = aap_midi2_generate_aapxs_sysex8((uint32_t*) aapxs_rt_midi_buffer,
midi_buffer_size / sizeof(int32_t),
(uint8_t*) aapxs_rt_conversion_helper_buffer,
midi_buffer_size,
group,
requestId,
aapxsInstance->uri,
opcode,
(uint8_t*) aapxsInstance->data,
messageSize);
addMidi2Event(this, addMidi2EventUserData, size);
}

void aap::AAPXSMidi2ClientSession::processReply(void* buffer) {
auto mbh = (AAPMidiBufferHeader *) buffer;
void* data = mbh + 1;
CMIDI2_UMP_SEQUENCE_FOREACH(data, mbh->length, iter) {
auto umpSize = mbh->length - ((uint8_t*) iter - (uint8_t*) data);
if (aap_midi2_parse_aapxs_sysex8(&aapxs_parse_context, iter, umpSize))
handle_reply(&aapxs_parse_context);

// FIXME: should we remove those AAPXS SysEx8 from the UMP buffer?
// It is going to be extraneous to the host.
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,40 @@ void aap::AAPXSMidi2Processor::process(void* buffer) {
void* data = mbh + 1;
CMIDI2_UMP_SEQUENCE_FOREACH(data, mbh->length, iter) {
auto umpSize = mbh->length - ((uint8_t*) iter - (uint8_t*) data);
if (aap_midi2_parse_aapxs_sysex8(&aapxs_parse_context, iter, umpSize))
if (aap_midi2_parse_aapxs_sysex8(&aapxs_parse_context, iter, umpSize)) {
call_extension(&aapxs_parse_context);

// FIXME: should we remove those extension bytes from the UMP buffer?
// It is going to be extraneous to the plugin.
auto ump = (cmidi2_ump*) iter;
ump += 4;
while (cmidi2_ump_get_message_type(ump) == CMIDI2_MESSAGE_TYPE_SYSEX8_MDS &&
cmidi2_ump_get_status_code(ump) < CMIDI2_SYSEX_END)
ump += 4;
iter = (uint8_t*) ump;
}

// FIXME: should we remove those AAPXS SysEx8 bytes from the UMP buffer?
// It is going to be extraneous to the rest of the plugin processing.
}
}


void aap::AAPXSMidi2Processor::addReply(
void (*addMidi2Event)(AAPXSMidi2Processor * processor, void *userData, int32_t messageSize),
void* addMidi2EventUserData,
int32_t group,
int32_t requestId,
AAPXSServiceInstance *aapxsInstance,
int32_t messageSize,
int32_t opcode) {
size_t size = aap_midi2_generate_aapxs_sysex8((uint32_t*) midi2_aapxs_data_buffer,
AAP_MIDI2_AAPXS_DATA_MAX_SIZE / sizeof(int32_t),
(uint8_t*) midi2_aapxs_conversion_helper_buffer,
AAP_MIDI2_AAPXS_DATA_MAX_SIZE,
group,
requestId,
aapxsInstance->uri,
opcode,
(uint8_t*) aapxsInstance->data,
messageSize);
addMidi2Event(this, addMidi2EventUserData, size);
}
8 changes: 5 additions & 3 deletions androidaudioplugin/src/main/cpp/core/hosting/PluginHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ void initializeStandardAAPXSRegistry() {
}


aap::PluginHost::PluginHost(PluginListSnapshot* contextPluginList, AAPXSRegistry* aapxsRegistry)
: plugin_list(contextPluginList)
{
aap::PluginHost::PluginHost(PluginListSnapshot* contextPluginList,
AAPXSRegistry* aapxsRegistry,
int32_t eventMidi2InputBufferSize)
: plugin_list(contextPluginList),
event_midi2_input_buffer_size(eventMidi2InputBufferSize) {
assert(contextPluginList);

if (standard_aapxs_registry == nullptr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@

#define LOG_TAG "AAP.Local.Instance"


void aapxsProcessorAddEventUmpOutput(aap::AAPXSMidi2Processor* processor, void* context, int32_t messageSize) {
auto instance = (aap::LocalPluginInstance *) context;
instance->addEventUmpOutput(processor->midi2_aapxs_data_buffer, messageSize);
}


aap::LocalPluginInstance::LocalPluginInstance(PluginHost *host,
AAPXSRegistry *aapxsRegistry,
int32_t instanceId,
Expand All @@ -23,6 +30,17 @@ aap::LocalPluginInstance::LocalPluginInstance(PluginHost *host,
// We need to copy extension data buffer before calling it.
memcpy(aapxsInstance->data, (int32_t*) context->data, context->dataSize);
controlExtension(context->uri, context->opcode);

// FIXME: this should be called only at the *end* of controlExtension()
// which should be asynchronously handled.
aapxs_midi2_processor.addReply(aapxsProcessorAddEventUmpOutput,
this,
context->group,
context->request_id,
aapxsInstance,
context->dataSize,
context->opcode
);
});
}

Expand Down Expand Up @@ -149,7 +167,20 @@ void aap::LocalPluginInstance::requestProcessToHost() {
((PluginService*) host)->requestProcessToHost(instance_id);
}

void aap::LocalPluginInstance::processAAPXSSysEx8Input() {
const char* local_trace_name = "AAP::LocalPluginInstance_process";
void aap::LocalPluginInstance::process(int32_t frameCount, int32_t timeoutInNanoseconds) {
process_requested_to_host = false;

struct timespec timeSpecBegin{}, timeSpecEnd{};
#if ANDROID
if (ATrace_isEnabled()) {
ATrace_beginSection(local_trace_name);
clock_gettime(CLOCK_REALTIME, &timeSpecBegin);
}
#endif

// retrieve AAPXS SysEx8 requests and start extension calls, if any.
// (might be synchronously done)
for (auto i = 0, n = getNumPorts(); i < n; i++) {
auto port = getPort(i);
if (port->getContentType() != AAP_CONTENT_TYPE_MIDI2 ||
Expand All @@ -159,4 +190,24 @@ void aap::LocalPluginInstance::processAAPXSSysEx8Input() {
void* data = aapBuffer->get_buffer(*aapBuffer, i);
aapxs_midi2_processor.process(data);
}

plugin->process(plugin, getAudioPluginBuffer(), frameCount, timeoutInNanoseconds);

// before sending back to host, merge AAPXS SysEx8 UMPs from async extension calls
// into the plugin's MIDI output buffer.
if (std::unique_lock<NanoSleepLock> tryLock(ump_sequence_merger_mutex, std::try_to_lock); tryLock.owns_lock()) {
merge_ump_sequences(AAP_PORT_DIRECTION_OUTPUT, event_midi2_merge_buffer, event_midi2_buffer_size,
event_midi2_buffer, event_midi2_buffer_offset,
getAudioPluginBuffer(), this);
event_midi2_buffer_offset = 0;
}

#if ANDROID
if (ATrace_isEnabled()) {
clock_gettime(CLOCK_REALTIME, &timeSpecEnd);
ATrace_setCounter(local_trace_name,
(timeSpecEnd.tv_sec - timeSpecBegin.tv_sec) * 1000000000 + timeSpecEnd.tv_nsec - timeSpecBegin.tv_nsec);
ATrace_endSection();
}
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@ aap::RemotePluginInstance::RemotePluginInstance(PluginClient* client,
client(client),
aapxs_registry(aapxsRegistry),
standards(this),
aapxs_manager(std::make_unique<RemoteAAPXSManager>(this)) {
aapxs_manager(std::make_unique<RemoteAAPXSManager>(this)),
aapxs_session(eventMidi2InputBufferSize) {
shared_memory_store = new ClientPluginSharedMemoryStore();

aapxs_session.setReplyHandler([&](aap_midi2_aapxs_parse_context* context) {
auto aapxsInstance = aapxs_manager->getInstanceFor(context->uri);
aapxsInstance->endAsyncCall(context);
});
}

void aap::RemotePluginInstance::configurePorts() {
Expand Down Expand Up @@ -48,15 +54,29 @@ AndroidAudioPluginHost* aap::RemotePluginInstance::getHostFacadeForCompleteInsta
return &plugin_host_facade;
}

void aapxsSessionAddEventUmpInput(aap::AAPXSMidi2ClientSession* client, void* context, int32_t messageSize) {
auto instance = (aap::RemotePluginInstance *) context;
instance->addEventUmpInput(client->aapxs_rt_midi_buffer, messageSize);
}

void aap::RemotePluginInstance::sendExtensionMessage(const char *uri, int32_t messageSize, int32_t opcode) {
auto aapxsInstance = aapxs_manager->getInstanceFor(uri);

// Here we have to get a native plugin instance and send extension message.
// It is kind af annoying because we used to implement Binder-specific part only within the
// plugin API (binder-client-as-plugin.cpp)...
// So far, instead of rewriting a lot of code to do so, we let AAPClientContext
// assign its implementation details that handle Binder messaging as a std::function.
send_extension_message_impl(aapxsInstance->uri, getInstanceId(), messageSize, opcode);
// 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?
int32_t requestId = aapxsSysEx8RequestSerial();
aapxs_session.addSession(aapxsSessionAddEventUmpInput, this, group, requestId, aapxsInstance, messageSize, opcode);
} else {
// Here we have to get a native plugin instance and send extension message.
// It is kind af annoying because we used to implement Binder-specific part only within the
// plugin API (binder-client-as-plugin.cpp)...
// So far, instead of rewriting a lot of code to do so, we let AAPClientContext
// assign its implementation details that handle Binder messaging as a std::function.
send_extension_message_impl(aapxsInstance->uri, getInstanceId(), messageSize, opcode);
}
}

void aap::RemotePluginInstance::prepare(int frameCount) {
Expand Down Expand Up @@ -120,6 +140,48 @@ uint32_t aap::RemotePluginInstance::aapxsSysEx8RequestSerial() {
return aapxs_request_id_serial++;
}

void aap::RemotePluginInstance::process(int32_t frameCount, int32_t timeoutInNanoseconds) {
const char* remote_trace_name = "AAP::RemotePluginInstance_process";
struct timespec timeSpecBegin{}, timeSpecEnd{};
#if ANDROID
if (ATrace_isEnabled()) {
ATrace_beginSection(remote_trace_name);
clock_gettime(CLOCK_REALTIME, &timeSpecBegin);
}
#endif

// merge input from UI with the host's MIDI inputs
if (std::unique_lock<NanoSleepLock> tryLock(ump_sequence_merger_mutex, std::try_to_lock); tryLock.owns_lock()) {
merge_ump_sequences(AAP_PORT_DIRECTION_INPUT, event_midi2_merge_buffer, event_midi2_buffer_size,
event_midi2_buffer, event_midi2_buffer_offset,
getAudioPluginBuffer(), this);
event_midi2_buffer_offset = 0;
}

// now we can pass the input to the plugin.
plugin->process(plugin, getAudioPluginBuffer(), frameCount, timeoutInNanoseconds);

// retrieve AAPXS SysEx8 replies if any.
for (auto i = 0, n = getNumPorts(); i < n; i++) {
auto port = getPort(i);
if (port->getContentType() != AAP_CONTENT_TYPE_MIDI2 ||
port->getPortDirection() != AAP_PORT_DIRECTION_OUTPUT)
continue;
auto aapBuffer = getAudioPluginBuffer();
void* data = aapBuffer->get_buffer(*aapBuffer, i);
aapxs_session.processReply(data);
}

#if ANDROID
if (ATrace_isEnabled()) {
clock_gettime(CLOCK_REALTIME, &timeSpecEnd);
ATrace_setCounter(remote_trace_name,
(timeSpecEnd.tv_sec - timeSpecBegin.tv_sec) * 1000000000 + timeSpecEnd.tv_nsec - timeSpecBegin.tv_nsec);
ATrace_endSection();
}
#endif
}

//----

aap::RemotePluginInstance::RemotePluginNativeUIController::RemotePluginNativeUIController(RemotePluginInstance* owner) {
Expand Down Expand Up @@ -156,4 +218,3 @@ void aap::RemoteAAPXSManager::staticSendExtensionMessage(AAPXSClientInstance* cl
auto thisObj = (RemotePluginInstance*) clientInstance->host_context;
thisObj->sendExtensionMessage(clientInstance->uri, messageSize, opcode);
}

Loading

0 comments on commit fd1e00f

Please sign in to comment.