]> code.delx.au - pulseaudio/blobdiff - src/modules/module-pipe-source.c
bluetooth: Remove a redundant variable
[pulseaudio] / src / modules / module-pipe-source.c
index 25151d951f7e17f6fb9f42fba5dcf1ef11f7d5b7..36e873227574993aad3e22af4b159ae7a5e84917 100644 (file)
@@ -5,7 +5,7 @@
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
-  by the Free Software Foundation; either version 2 of the License,
+  by the Free Software Foundation; either version 2.1 of the License,
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
 #include <sys/stat.h>
 #include <stdio.h>
 #include <errno.h>
 #include <sys/stat.h>
 #include <stdio.h>
 #include <errno.h>
-#include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <unistd.h>
-#include <limits.h>
-#include <sys/poll.h>
+#include <sys/ioctl.h>
+
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
 
 #include <pulse/xmalloc.h>
 
 
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/thread.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/rtpoll.h>
 #include <pulsecore/thread.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/rtpoll.h>
+#include <pulsecore/poll.h>
 
 #include "module-pipe-source-symdef.h"
 
 PA_MODULE_AUTHOR("Lennart Poettering");
 PA_MODULE_DESCRIPTION("UNIX pipe source");
 PA_MODULE_VERSION(PACKAGE_VERSION);
 
 #include "module-pipe-source-symdef.h"
 
 PA_MODULE_AUTHOR("Lennart Poettering");
 PA_MODULE_DESCRIPTION("UNIX pipe source");
 PA_MODULE_VERSION(PACKAGE_VERSION);
-PA_MODULE_LOAD_ONCE(FALSE);
+PA_MODULE_LOAD_ONCE(false);
 PA_MODULE_USAGE(
         "source_name=<name for the source> "
 PA_MODULE_USAGE(
         "source_name=<name for the source> "
+        "source_properties=<properties for the source> "
         "file=<path of the FIFO> "
         "format=<sample format> "
         "file=<path of the FIFO> "
         "format=<sample format> "
-        "channels=<number of channels> "
         "rate=<sample rate> "
         "rate=<sample rate> "
+        "channels=<number of channels> "
         "channel_map=<channel map>");
 
 #define DEFAULT_FILE_NAME "/tmp/music.input"
         "channel_map=<channel map>");
 
 #define DEFAULT_FILE_NAME "/tmp/music.input"
@@ -80,15 +84,45 @@ struct userdata {
 };
 
 static const char* const valid_modargs[] = {
 };
 
 static const char* const valid_modargs[] = {
+    "source_name",
+    "source_properties",
     "file",
     "file",
+    "format",
     "rate",
     "channels",
     "rate",
     "channels",
-    "format",
-    "source_name",
     "channel_map",
     NULL
 };
 
     "channel_map",
     NULL
 };
 
+static int source_process_msg(
+        pa_msgobject *o,
+        int code,
+        void *data,
+        int64_t offset,
+        pa_memchunk *chunk) {
+
+    struct userdata *u = PA_SOURCE(o)->userdata;
+
+    switch (code) {
+
+        case PA_SOURCE_MESSAGE_GET_LATENCY: {
+            size_t n = 0;
+
+#ifdef FIONREAD
+            int l;
+
+            if (ioctl(u->fd, FIONREAD, &l) >= 0 && l > 0)
+                n = (size_t) l;
+#endif
+
+            *((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->source->sample_spec);
+            return 0;
+        }
+    }
+
+    return pa_source_process_msg(o, code, data, offset, chunk);
+}
+
 static void thread_func(void *userdata) {
     struct userdata *u = userdata;
     int read_type = 0;
 static void thread_func(void *userdata) {
     struct userdata *u = userdata;
     int read_type = 0;
@@ -98,7 +132,6 @@ static void thread_func(void *userdata) {
     pa_log_debug("Thread starting up");
 
     pa_thread_mq_install(&u->thread_mq);
     pa_log_debug("Thread starting up");
 
     pa_thread_mq_install(&u->thread_mq);
-    pa_rtpoll_install(u->rtpoll);
 
     for (;;) {
         int ret;
 
     for (;;) {
         int ret;
@@ -112,7 +145,7 @@ static void thread_func(void *userdata) {
             void *p;
 
             if (!u->memchunk.memblock) {
             void *p;
 
             if (!u->memchunk.memblock) {
-                u->memchunk.memblock = pa_memblock_new(u->core->mempool, PIPE_BUF);
+                u->memchunk.memblock = pa_memblock_new(u->core->mempool, pa_pipe_buf(u->fd));
                 u->memchunk.index = u->memchunk.length = 0;
             }
 
                 u->memchunk.index = u->memchunk.length = 0;
             }
 
@@ -129,7 +162,7 @@ static void thread_func(void *userdata) {
                 if (errno == EINTR)
                     continue;
                 else if (errno != EAGAIN) {
                 if (errno == EINTR)
                     continue;
                 else if (errno != EAGAIN) {
-                    pa_log("Faile to read data from FIFO: %s", pa_cstrerror(errno));
+                    pa_log("Failed to read data from FIFO: %s", pa_cstrerror(errno));
                     goto fail;
                 }
 
                     goto fail;
                 }
 
@@ -151,7 +184,7 @@ static void thread_func(void *userdata) {
         /* Hmm, nothing to do. Let's sleep */
         pollfd->events = (short) (u->source->thread_info.state == PA_SOURCE_RUNNING ? POLLIN : 0);
 
         /* Hmm, nothing to do. Let's sleep */
         pollfd->events = (short) (u->source->thread_info.state == PA_SOURCE_RUNNING ? POLLIN : 0);
 
-        if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
+        if ((ret = pa_rtpoll_run(u->rtpoll, true)) < 0)
             goto fail;
 
         if (ret == 0)
             goto fail;
 
         if (ret == 0)
@@ -175,7 +208,7 @@ finish:
     pa_log_debug("Thread shutting down");
 }
 
     pa_log_debug("Thread shutting down");
 }
 
-int pa__init(pa_module*m) {
+int pa__init(pa_module *m) {
     struct userdata *u;
     struct stat st;
     pa_sample_spec ss;
     struct userdata *u;
     struct stat st;
     pa_sample_spec ss;
@@ -187,37 +220,39 @@ int pa__init(pa_module*m) {
     pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
     pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log("failed to parse module arguments.");
+        pa_log("Failed to parse module arguments.");
         goto fail;
     }
 
     ss = m->core->default_sample_spec;
         goto fail;
     }
 
     ss = m->core->default_sample_spec;
+    map = m->core->default_channel_map;
     if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
     if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
-        pa_log("invalid sample format specification or channel map");
+        pa_log("Invalid sample format specification or channel map");
         goto fail;
     }
 
         goto fail;
     }
 
-    u = pa_xnew0(struct userdata, 1);
+    m->userdata = u = pa_xnew0(struct userdata, 1);
     u->core = m->core;
     u->module = m;
     u->core = m->core;
     u->module = m;
-    m->userdata = u;
     pa_memchunk_reset(&u->memchunk);
     u->rtpoll = pa_rtpoll_new();
     pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
 
     u->filename = pa_runtime_path(pa_modargs_get_value(ma, "file", DEFAULT_FILE_NAME));
 
     pa_memchunk_reset(&u->memchunk);
     u->rtpoll = pa_rtpoll_new();
     pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
 
     u->filename = pa_runtime_path(pa_modargs_get_value(ma, "file", DEFAULT_FILE_NAME));
 
-    mkfifo(u->filename, 0666);
-    if ((u->fd = open(u->filename, O_RDWR|O_NOCTTY)) < 0) {
+    if (mkfifo(u->filename, 0666) < 0) {
+        pa_log("mkfifo('%s'): %s", u->filename, pa_cstrerror(errno));
+        goto fail;
+    }
+    if ((u->fd = pa_open_cloexec(u->filename, O_RDWR, 0)) < 0) {
         pa_log("open('%s'): %s", u->filename, pa_cstrerror(errno));
         goto fail;
     }
 
         pa_log("open('%s'): %s", u->filename, pa_cstrerror(errno));
         goto fail;
     }
 
-    pa_make_fd_cloexec(u->fd);
     pa_make_fd_nonblock(u->fd);
 
     if (fstat(u->fd, &st) < 0) {
     pa_make_fd_nonblock(u->fd);
 
     if (fstat(u->fd, &st) < 0) {
-        pa_log("fstat('%s'): %s",u->filename, pa_cstrerror(errno));
+        pa_log("fstat('%s'): %s", u->filename, pa_cstrerror(errno));
         goto fail;
     }
 
         goto fail;
     }
 
@@ -235,7 +270,13 @@ int pa__init(pa_module*m) {
     pa_source_new_data_set_sample_spec(&data, &ss);
     pa_source_new_data_set_channel_map(&data, &map);
 
     pa_source_new_data_set_sample_spec(&data, &ss);
     pa_source_new_data_set_channel_map(&data, &map);
 
-    u->source = pa_source_new(m->core, &data, 0);
+    if (pa_modargs_get_proplist(ma, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
+        pa_log("Invalid properties");
+        pa_source_new_data_done(&data);
+        goto fail;
+    }
+
+    u->source = pa_source_new(m->core, &data, PA_SOURCE_LATENCY);
     pa_source_new_data_done(&data);
 
     if (!u->source) {
     pa_source_new_data_done(&data);
 
     if (!u->source) {
@@ -243,17 +284,19 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
         goto fail;
     }
 
+    u->source->parent.process_msg = source_process_msg;
     u->source->userdata = u;
 
     pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
     pa_source_set_rtpoll(u->source, u->rtpoll);
     u->source->userdata = u;
 
     pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
     pa_source_set_rtpoll(u->source, u->rtpoll);
+    pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(pa_pipe_buf(u->fd), &u->source->sample_spec));
 
     u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
     pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
     pollfd->fd = u->fd;
     pollfd->events = pollfd->revents = 0;
 
 
     u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
     pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
     pollfd->fd = u->fd;
     pollfd->events = pollfd->revents = 0;
 
-    if (!(u->thread = pa_thread_new(thread_func, u))) {
+    if (!(u->thread = pa_thread_new("pipe-source", thread_func, u))) {
         pa_log("Failed to create thread.");
         goto fail;
     }
         pa_log("Failed to create thread.");
         goto fail;
     }
@@ -273,7 +316,16 @@ fail:
     return -1;
 }
 
     return -1;
 }
 
-void pa__done(pa_module*m) {
+int pa__get_n_used(pa_module *m) {
+    struct userdata *u;
+
+    pa_assert(m);
+    pa_assert_se(u = m->userdata);
+
+    return pa_source_linked_by(u->source);
+}
+
+void pa__done(pa_module *m) {
     struct userdata *u;
 
     pa_assert(m);
     struct userdata *u;
 
     pa_assert(m);