Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jack Audio Multi Client Support #547

Closed
wants to merge 8 commits into from
Closed

Jack Audio Multi Client Support #547

wants to merge 8 commits into from

Conversation

ghost
Copy link

@ghost ghost commented Feb 5, 2020

Hello,

these fixes add support for Jack "multi client" mode. By multi client I mean allowing to create multiple clients who connect to different servers from one process.

In current Jack version this would result in overwriting synchronization and signalling primitives of shared memory. Each created client would overwrite client before, so that previous client would not be able to accept process and other callbacks and notify server of graph competition.

The patch introduces "global context" reference that holds instance of global and shared memory variables for each created client. This global context reference is then passed to all objects who require it.

Please note this PR disables functionality of metadata - this area is still under development and requires some architectural decisions on how to pass the global pointer to metadata.

Attached c++ test application can be used to verify this use case.

#include <stdint.h>
#include <stdbool.h>
#include <jack/jack.h>
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <string>

#define CLIENTS_NUM 8
#define PORTS_NUM 2

static jack_client_t* clients[CLIENTS_NUM] = {0};
static jack_port_t* ports[CLIENTS_NUM][PORTS_NUM] = {{0}};

char servers[CLIENTS_NUM][32] = {
	"acoustic", "acoustic", "acoustic", "acoustic",
	"media", "media", "media", "media",
};

static int backend_jack_process (const jack_nframes_t nframes, void *arg)
{
	return 0;
}

int main()
{
	jack_status_t status;
	jack_options_t options = (jack_options_t) (JackNoStartServer | JackServerName);
	const unsigned long flags = JackPortIsOutput;

	for (int i = 0; i < CLIENTS_NUM; ++i)
	{
		clients[i] = jack_client_open("client_name", options, &status, servers[i]);
		jack_set_process_callback(clients[i], backend_jack_process, nullptr);

		for (int j = 0; j < PORTS_NUM; ++j)
		{
			std::string portname = "port";
			portname += std::to_string(j);
			ports[i][j] = jack_port_register(clients[i], portname.c_str(),
				JACK_DEFAULT_AUDIO_TYPE, flags, 0);
		}

		jack_activate(clients[i]);
	}

	usleep(6000000);
	
	for (int i = 0; i < CLIENTS_NUM; ++i)
	{
		jack_deactivate(clients[i]);
		jack_client_close(clients[i]);
	}

	return 0;
}

On version before error messages can be seen:

JackAudioDriver::ProcessGraphAsyncMaster: Process error
JackEngine::XRun: client = client_name was not finished, state = Triggered
JackEngine::XRun: client = client_name-01 was not finished, state = Triggered
JackEngine::XRun: client = client_name-02 was not finished, state = Triggered
JackEngine::XRun: client = client_name-03 was not finished, state = Triggered

Patched version does not have these errors and audio is correctly routed between multiple clients and servers.

Verification of changes is done on:

  • qnx platform
  • aarch64 platform

Adam

Adam Miartus and others added 8 commits February 5, 2020 14:18
Change-Id: If3582834e0ca33bf36203a38fe7fd262d96a6827
Signed-off-by: Adam Miartus <[email protected]>
Change-Id: I5f5b4a2d0a52ef12ac4e396f40002e8dec916cfb
Signed-off-by: Timo Wischer <[email protected]>
Change-Id: I66e0960c9ab1a097de3098d4f51e0fff4d064186
Signed-off-by: Timo Wischer <[email protected]>
Change-Id: I88003f8c55184b141ffd4e068eba889776ce9b14
Signed-off-by: Timo Wischer <[email protected]>
fix to reflect programming style of other classes in Jack Audio

Change-Id: I86f5d190d4a9df26a30c5de1b504421efe0202c1
Signed-off-by: Adam Miartus <[email protected]>
no functional change is introduced by this commit, tested with:

jack_lsp
jack_simple_client
jack_connect

Change-Id: Iec690b8f3a37867a98af8f197742dae988d274ea
Signed-off-by: Adam Miartus <[email protected]>
rework to allow creating multiple clients that connecting to different
jack servers in one process

done by creating a client context which holds server id, this context
is then evaluated against global variables that were extended to hold
multiple synchronization instances for each client

Change-Id: I3a6b4a44fe9d820ba6b6bbbeb06b158d9ad43fce
Signed-off-by: Adam Miartus <[email protected]>
metadata:
problem here is that we don't have knowledge of the server, each server is
supposed to have its own metadata instance as can be seen in Metadata
implementation

midi:
does not have reference to global context

Change-Id: I80fde1facde3eca40431464264afdf76a002c752
Signed-off-by: Adam Miartus <[email protected]>
@falkTX
Copy link
Member

falkTX commented Feb 5, 2020

I am sorry, but I am not going to merge this.
You can keep the PR open for anyone interested on it, but I would not want it part of the JACK project.

Let me explain...
It is first time I see ever someone suggesting such a thing - multiple jack servers for a single process. You went even further and actually implemented the whole thing. Very impressive!
But... even for the "jack server under multiple users" scenario, that is already not very well supported (due to lack of interest or users requesting it). Your approach is even less requested.

What is the usecase here?

I see some useful commits there, I can cherry-pick those so your diff ends up smaller.

@ghost
Copy link
Author

ghost commented Feb 6, 2020

Hi Filipe, thank you for having a look. If any commits get merged that's already fine and helping us to maintain with less effort.

As for the use case, we are running multiple instances of jack server (different sample rate requirements + no re-sampling constraint + effort to reduce cpu load). On top of that we are running a virtualization host that spawns an initialization process for guest OS, in this process we are connecting to multiple jack servers. As there is only one process spawned during the initialization of guest OS we have to make sure the static objects are correctly shared.

From architectural/requirements point of view it has to go this way for us therefore this change request came to be.

@twischer-adit
Copy link
Contributor

This PR can be closed. It is replaced by #597

@falkTX falkTX closed this Jun 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants