* allow the user to set the jack client name

* take the number of channels for the sink from the number of physical ports in the jack server
* name the polypaudio ports in the jack server after their channel position in polypaudio


git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@737 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2006-04-18 13:20:50 +00:00
parent 8b99a067a8
commit cf85794e23

View file

@ -52,10 +52,10 @@ PA_MODULE_DESCRIPTION("Jack Sink")
PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_VERSION(PACKAGE_VERSION)
PA_MODULE_USAGE( PA_MODULE_USAGE(
"sink_name=<name of sink> " "sink_name=<name of sink> "
"server_name=<server name> " "server_name=<jack server name> "
"client_name=<jack client name> "
"channels=<number of channels> " "channels=<number of channels> "
"connect=<connect ports?>" "connect=<connect ports?>"
"port_prefix=<port prefix>"
) )
#define DEFAULT_SINK_NAME "jack_out" #define DEFAULT_SINK_NAME "jack_out"
@ -82,15 +82,15 @@ struct userdata {
pa_io_event *io_event; pa_io_event *io_event;
jack_nframes_t frames_in_buffer; jack_nframes_t frames_in_buffer;
struct timeval timestamp; jack_nframes_t timestamp;
}; };
static const char* const valid_modargs[] = { static const char* const valid_modargs[] = {
"sink_name", "sink_name",
"server_name", "server_name",
"client_name",
"channels", "channels",
"connect", "connect",
"port_prefix",
NULL NULL
}; };
@ -193,7 +193,7 @@ static int jack_process(jack_nframes_t nframes, void *arg) {
pthread_cond_wait(&u->cond, &u->mutex); pthread_cond_wait(&u->cond, &u->mutex);
u->frames_in_buffer = nframes; u->frames_in_buffer = nframes;
pa_gettimeofday(&u->timestamp); u->timestamp = jack_get_current_transport_frame(u->client);
pthread_mutex_unlock(&u->mutex); pthread_mutex_unlock(&u->mutex);
} }
@ -203,20 +203,26 @@ static int jack_process(jack_nframes_t nframes, void *arg) {
static pa_usec_t sink_get_latency_cb(pa_sink *s) { static pa_usec_t sink_get_latency_cb(pa_sink *s) {
struct userdata *u; struct userdata *u;
pa_usec_t t, delta; jack_nframes_t n, l, d;
assert(s); assert(s);
u = s->userdata; u = s->userdata;
if (jack_transport_query(u->client, NULL) != JackTransportRolling) if (jack_transport_query(u->client, NULL) != JackTransportRolling)
return 0; return 0;
delta = pa_timeval_age(&u->timestamp); n = jack_get_current_transport_frame(u->client);
t = pa_bytes_to_usec(jack_port_get_total_latency(u->client, u->port[0]) * pa_frame_size(&s->sample_spec), &s->sample_spec);
if (t > delta) if (n < u->timestamp)
return t - delta;
else
return 0; return 0;
d = n - u->timestamp;
l = jack_port_get_total_latency(u->client, u->port[0]) + u->frames_in_buffer;
if (d >= l)
return 0;
return pa_bytes_to_usec((l - d) * pa_frame_size(&s->sample_spec), &s->sample_spec);
} }
static void jack_error_func(const char*t) { static void jack_error_func(const char*t) {
@ -226,13 +232,14 @@ static void jack_error_func(const char*t) {
int pa__init(pa_core *c, pa_module*m) { int pa__init(pa_core *c, pa_module*m) {
struct userdata *u = NULL; struct userdata *u = NULL;
pa_sample_spec ss; pa_sample_spec ss;
pa_channel_map cm;
pa_modargs *ma = NULL; pa_modargs *ma = NULL;
jack_status_t status; jack_status_t status;
const char *server_name; const char *server_name, *client_name;
uint32_t channels; uint32_t channels = 0;
int connect = 1; int connect = 1;
const char *pfx;
unsigned i; unsigned i;
const char **ports = NULL, **p;
assert(c); assert(c);
assert(m); assert(m);
@ -244,18 +251,13 @@ int pa__init(pa_core *c, pa_module*m) {
goto fail; goto fail;
} }
channels = c->default_sample_spec.channels;
if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) {
pa_log(__FILE__": failed to parse channels= argument.");
goto fail;
}
if (pa_modargs_get_value_boolean(ma, "connect", &connect) < 0) { if (pa_modargs_get_value_boolean(ma, "connect", &connect) < 0) {
pa_log(__FILE__": failed to parse connect= argument."); pa_log(__FILE__": failed to parse connect= argument.");
goto fail; goto fail;
} }
server_name = pa_modargs_get_value(ma, "server_name", NULL); server_name = pa_modargs_get_value(ma, "server_name", NULL);
client_name = pa_modargs_get_value(ma, "client_name", "polypaudio");
u = pa_xnew0(struct userdata, 1); u = pa_xnew0(struct userdata, 1);
m->userdata = u; m->userdata = u;
@ -273,11 +275,25 @@ int pa__init(pa_core *c, pa_module*m) {
pa_make_nonblock_fd(u->pipe_fds[1]); pa_make_nonblock_fd(u->pipe_fds[1]);
if (!(u->client = jack_client_open("polypaudio", server_name ? JackServerName : JackNullOption, &status, server_name))) { if (!(u->client = jack_client_open(client_name, server_name ? JackServerName : JackNullOption, &status, server_name))) {
pa_log(__FILE__": jack_client_open() failed."); pa_log(__FILE__": jack_client_open() failed.");
goto fail; goto fail;
} }
ports = jack_get_ports(u->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput);
channels = 0;
for (p = ports; *p; p++)
channels++;
if (!channels)
channels = c->default_sample_spec.channels;
if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) {
pa_log(__FILE__": failed to parse channels= argument.");
goto fail;
}
pa_log_info(__FILE__": Successfully connected as '%s'", jack_get_client_name(u->client)); pa_log_info(__FILE__": Successfully connected as '%s'", jack_get_client_name(u->client));
ss.channels = u->channels = channels; ss.channels = u->channels = channels;
@ -286,20 +302,16 @@ int pa__init(pa_core *c, pa_module*m) {
assert(pa_sample_spec_valid(&ss)); assert(pa_sample_spec_valid(&ss));
pfx = pa_modargs_get_value(ma, "port_prefix", "channel"); pa_channel_map_init_auto(&cm, channels);
for (i = 0; i < ss.channels; i++) { for (i = 0; i < ss.channels; i++) {
char tmp[64]; if (!(u->port[i] = jack_port_register(u->client, pa_channel_position_to_string(cm.map[i]), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput|JackPortIsTerminal, 0))) {
snprintf(tmp, sizeof(tmp), "%s_%i", pfx, i+1);
if (!(u->port[i] = jack_port_register(u->client, tmp, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput/*|JackPortIsTerminal*/, 0))) {
pa_log(__FILE__": jack_port_register() failed."); pa_log(__FILE__": jack_port_register() failed.");
goto fail; goto fail;
} }
} }
if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &cm))) {
pa_log(__FILE__": failed to create sink."); pa_log(__FILE__": failed to create sink.");
goto fail; goto fail;
} }
@ -318,11 +330,9 @@ int pa__init(pa_core *c, pa_module*m) {
} }
if (connect) { if (connect) {
const char **p, **ports = jack_get_ports(u->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput);
for (i = 0, p = ports; i < ss.channels; i++, p++) { for (i = 0, p = ports; i < ss.channels; i++, p++) {
if (!p) { if (!*p) {
pa_log(__FILE__": not enough physical output ports, leaving unconnected."); pa_log(__FILE__": not enough physical output ports, leaving unconnected.");
break; break;
} }
@ -335,11 +345,11 @@ int pa__init(pa_core *c, pa_module*m) {
} }
} }
free(ports);
} }
u->io_event = c->mainloop->io_new(c->mainloop, u->pipe_fds[0], PA_IO_EVENT_INPUT, io_event_cb, u); u->io_event = c->mainloop->io_new(c->mainloop, u->pipe_fds[0], PA_IO_EVENT_INPUT, io_event_cb, u);
free(ports);
pa_modargs_free(ma); pa_modargs_free(ma);
return 0; return 0;
@ -347,6 +357,8 @@ int pa__init(pa_core *c, pa_module*m) {
fail: fail:
if (ma) if (ma)
pa_modargs_free(ma); pa_modargs_free(ma);
free(ports);
pa__done(c, m); pa__done(c, m);