]> code.delx.au - pulseaudio/blobdiff - src/modules/module-jack-sink.c
introduce default channel map in addition to the default sample spec
[pulseaudio] / src / modules / module-jack-sink.c
index b0cc4b1065cbc3d3cd9825311a2053693c624392..1739f46a815906b1fb7f78a71336704721f771e3 100644 (file)
@@ -1,5 +1,3 @@
-/* $Id$ */
-
 /***
   This file is part of PulseAudio.
 
@@ -28,7 +26,6 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <stdio.h>
-#include <assert.h>
 #include <errno.h>
 #include <string.h>
 #include <fcntl.h>
@@ -54,7 +51,7 @@
 
 /* General overview:
  *
- * Because JACK has a very unflexible event loop management, which
+ * Because JACK has a very unflexible event loop management which
  * doesn't allow us to add our own event sources to the event thread
  * we cannot use the JACK real-time thread for dispatching our PA
  * work. Instead, we run an additional RT thread which does most of
  * source support in JACK.
  */
 
-PA_MODULE_AUTHOR("Lennart Poettering")
-PA_MODULE_DESCRIPTION("JACK Sink")
-PA_MODULE_VERSION(PACKAGE_VERSION)
+PA_MODULE_AUTHOR("Lennart Poettering");
+PA_MODULE_DESCRIPTION("JACK Sink");
+PA_MODULE_LOAD_ONCE(TRUE);
+PA_MODULE_VERSION(PACKAGE_VERSION);
 PA_MODULE_USAGE(
         "sink_name=<name of sink> "
         "server_name=<jack server name> "
         "client_name=<jack client name> "
         "channels=<number of channels> "
         "connect=<connect ports?> "
-        "channel_map=<channel map>")
+        "channel_map=<channel map>");
 
 #define DEFAULT_SINK_NAME "jack_out"
 
@@ -132,12 +130,12 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
                 void *p;
 
                 pa_assert(offset > 0);
-                nbytes = offset * pa_frame_size(&u->sink->sample_spec);
+                nbytes = (size_t) offset * pa_frame_size(&u->sink->sample_spec);
 
                 pa_sink_render_full(u->sink, nbytes, &chunk);
 
                 p = (uint8_t*) pa_memblock_acquire(chunk.memblock) + chunk.index;
-                pa_deinterleave(p, u->buffer, u->channels, sizeof(float), offset);
+                pa_deinterleave(p, u->buffer, u->channels, sizeof(float), (unsigned) offset);
                 pa_memblock_release(chunk.memblock);
 
                 pa_memblock_unref(chunk.memblock);
@@ -151,10 +149,10 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
                 ss.channels = 1;
 
                 for (c = 0; c < u->channels; c++)
-                    pa_silence_memory(u->buffer[c], offset * pa_sample_size(&ss), &ss);
+                    pa_silence_memory(u->buffer[c], (size_t) offset * pa_sample_size(&ss), &ss);
             }
 
-            u->frames_in_buffer = offset;
+            u->frames_in_buffer = (jack_nframes_t) offset;
             u->saved_frame_time = * (jack_nframes_t*) data;
             u->saved_frame_time_valid = TRUE;
 
@@ -215,8 +213,8 @@ static void thread_func(void *userdata) {
 
     pa_log_debug("Thread starting up");
 
-    if (u->core->high_priority)
-        pa_make_realtime();
+    if (u->core->realtime_scheduling)
+        pa_make_realtime(u->core->realtime_priority);
 
     pa_thread_mq_install(&u->thread_mq);
     pa_rtpoll_install(u->rtpoll);
@@ -224,6 +222,10 @@ static void thread_func(void *userdata) {
     for (;;) {
         int ret;
 
+        if (PA_SINK_IS_OPENED(u->sink->thread_info.state))
+            if (u->sink->thread_info.rewind_requested)
+                pa_sink_process_rewind(u->sink, 0);
+
         if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
             goto fail;
 
@@ -244,7 +246,7 @@ finish:
 static void jack_error_func(const char*t) {
     char *s;
 
-    s = pa_xstrndup(s, strcspn(s, "\n\r"));
+    s = pa_xstrndup(t, strcspn(t, "\n\r"));
     pa_log_warn("JACK error >%s<", s);
     pa_xfree(s);
 }
@@ -254,8 +256,8 @@ static void jack_init(void *arg) {
 
     pa_log_info("JACK thread starting up.");
 
-    if (u->core->high_priority)
-        pa_make_realtime();
+    if (u->core->realtime_scheduling)
+        pa_make_realtime(u->core->realtime_priority+4);
 }
 
 static void jack_shutdown(void* arg) {
@@ -273,10 +275,10 @@ int pa__init(pa_module*m) {
     jack_status_t status;
     const char *server_name, *client_name;
     uint32_t channels = 0;
-    int do_connect = 1;
+    pa_bool_t do_connect = TRUE;
     unsigned i;
     const char **ports = NULL, **p;
-    char *t;
+    pa_sink_new_data data;
 
     pa_assert(m);
 
@@ -293,16 +295,15 @@ int pa__init(pa_module*m) {
     }
 
     server_name = pa_modargs_get_value(ma, "server_name", NULL);
-    client_name = pa_modargs_get_value(ma, "client_name", "PulseAudio");
+    client_name = pa_modargs_get_value(ma, "client_name", "PulseAudio JACK Sink");
 
     u = pa_xnew0(struct userdata, 1);
     u->core = m->core;
     u->module = m;
     m->userdata = u;
     u->saved_frame_time_valid = FALSE;
-    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
     u->rtpoll = pa_rtpoll_new();
-    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
+    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
 
     /* The queue linking the JACK thread and our RT thread */
     u->jack_msgq = pa_asyncmsgq_new(0);
@@ -312,7 +313,7 @@ int pa__init(pa_module*m) {
      * all other drivers make: supplying the audio device with data is
      * the top priority -- and as long as that is possible we don't do
      * anything else */
-    u->rtpoll_item = pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY-1, u->jack_msgq);
+    u->rtpoll_item = pa_rtpoll_item_new_asyncmsgq_read(u->rtpoll, PA_RTPOLL_EARLY-1, u->jack_msgq);
 
     if (!(u->client = jack_client_open(client_name, server_name ? JackServerName : JackNullOption, &status, server_name))) {
         pa_log("jack_client_open() failed.");
@@ -328,12 +329,18 @@ int pa__init(pa_module*m) {
     if (!channels)
         channels = m->core->default_sample_spec.channels;
 
-    if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) {
+    if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 ||
+        channels <= 0 ||
+        channels > PA_CHANNELS_MAX) {
         pa_log("Failed to parse channels= argument.");
         goto fail;
     }
 
-    pa_channel_map_init_auto(&map, channels, PA_CHANNEL_MAP_ALSA);
+    if (channels == m->core->default_channel_map.channels)
+        map = m->core->default_channel_map;
+    else
+        pa_channel_map_init_extend(&map, channels, PA_CHANNEL_MAP_ALSA);
+
     if (pa_modargs_get_channel_map(ma, NULL, &map) < 0 || map.channels != channels) {
         pa_log("Failed to parse channel_map= argument.");
         goto fail;
@@ -341,7 +348,7 @@ int pa__init(pa_module*m) {
 
     pa_log_info("Successfully connected as '%s'", jack_get_client_name(u->client));
 
-    ss.channels = u->channels = channels;
+    u->channels = ss.channels = (uint8_t) channels;
     ss.rate = jack_get_sample_rate(u->client);
     ss.format = PA_SAMPLE_FLOAT32NE;
 
@@ -354,20 +361,31 @@ int pa__init(pa_module*m) {
         }
     }
 
-    if (!(u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) {
-        pa_log("failed to create sink.");
+    pa_sink_new_data_init(&data);
+    data.driver = __FILE__;
+    data.module = m;
+    pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
+    pa_sink_new_data_set_sample_spec(&data, &ss);
+    pa_sink_new_data_set_channel_map(&data, &map);
+    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "jack");
+    if (server_name)
+        pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, server_name);
+    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Jack sink (%s)", jack_get_client_name(u->client));
+    pa_proplist_sets(data.proplist, "jack.client_name", jack_get_client_name(u->client));
+
+    u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY);
+    pa_sink_new_data_done(&data);
+
+    if (!u->sink) {
+        pa_log("Failed to create sink.");
         goto fail;
     }
 
     u->sink->parent.process_msg = sink_process_msg;
     u->sink->userdata = u;
-    u->sink->flags = PA_SINK_LATENCY;
 
-    pa_sink_set_module(u->sink, m);
     pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
     pa_sink_set_rtpoll(u->sink, u->rtpoll);
-    pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Jack sink (%s)", jack_get_client_name(u->client)));
-    pa_xfree(t);
 
     jack_set_process_callback(u->client, jack_process, u);
     jack_on_shutdown(u->client, jack_shutdown, u);
@@ -418,6 +436,15 @@ fail:
     return -1;
 }
 
+int pa__get_n_used(pa_module *m) {
+    struct userdata *u;
+
+    pa_assert(m);
+    pa_assert_se(u = m->userdata);
+
+    return pa_sink_linked_by(u->sink);
+}
+
 void pa__done(pa_module*m) {
     struct userdata *u;