summaryrefslogtreecommitdiffstats
path: root/src/pulsecore
diff options
context:
space:
mode:
Diffstat (limited to 'src/pulsecore')
-rw-r--r--src/pulsecore/core-util.c125
-rw-r--r--src/pulsecore/core-util.h4
-rw-r--r--src/pulsecore/core.c2
-rw-r--r--src/pulsecore/core.h2
-rw-r--r--src/pulsecore/msgobject.c14
-rw-r--r--src/pulsecore/msgobject.h8
-rw-r--r--src/pulsecore/object.c18
-rw-r--r--src/pulsecore/object.h51
-rw-r--r--src/pulsecore/play-memblockq.c3
-rw-r--r--src/pulsecore/protocol-esound.c3
-rw-r--r--src/pulsecore/protocol-native.c15
-rw-r--r--src/pulsecore/protocol-simple.c3
-rw-r--r--src/pulsecore/sink-input.c23
-rw-r--r--src/pulsecore/sink-input.h14
-rw-r--r--src/pulsecore/sink.c18
-rw-r--r--src/pulsecore/sink.h2
-rw-r--r--src/pulsecore/sound-file-stream.c3
-rw-r--r--src/pulsecore/source-output.c4
-rw-r--r--src/pulsecore/source-output.h2
-rw-r--r--src/pulsecore/source.c2
-rw-r--r--src/pulsecore/source.h2
-rw-r--r--src/pulsecore/usergroup.c372
-rw-r--r--src/pulsecore/usergroup.h51
23 files changed, 581 insertions, 160 deletions
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index ef8c8472..0eb32cc4 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -115,6 +115,7 @@
#include <pulsecore/macro.h>
#include <pulsecore/thread.h>
#include <pulsecore/strbuf.h>
+#include <pulsecore/usergroup.h>
#include "core-util.h"
@@ -969,42 +970,24 @@ fail:
/* Check whether the specified GID and the group name match */
static int is_group(gid_t gid, const char *name) {
- struct group group, *result = NULL;
- long n;
- void *data;
+ struct group *group = NULL;
int r = -1;
-#ifdef HAVE_GETGRGID_R
-
-#ifdef _SC_GETGR_R_SIZE_MAX
- n = sysconf(_SC_GETGR_R_SIZE_MAX);
-#else
- n = -1;
-#endif
- if (n <= 0)
- n = 512;
-
- data = pa_xmalloc((size_t) n);
-
- if ((errno = getgrgid_r(gid, &group, data, (size_t) n, &result)) || !result)
-#else
errno = 0;
- if (!(result = getgrgid(gid)))
-#endif
+ if (!(group = pa_getgrgid_malloc(gid)))
{
if (!errno)
errno = ENOENT;
- pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno));
+ pa_log("pa_getgrgid_malloc(%u): %s", gid, pa_cstrerror(errno));
goto finish;
}
- r = strcmp(name, result->gr_name) == 0;
+ r = strcmp(name, group->gr_name) == 0;
finish:
-
- pa_xfree(data);
+ pa_getgrgid_free(group);
return r;
}
@@ -1053,69 +1036,37 @@ finish:
/* Check whether the specifc user id is a member of the specified group */
int pa_uid_in_group(uid_t uid, const char *name) {
- char *g_buf = NULL, *p_buf = NULL;
- long g_n, p_n;
- struct group grbuf, *gr = NULL;
+ struct group *group = NULL;
char **i;
int r = -1;
-#ifdef HAVE_GETGRNAM_R
-
-#ifdef _SC_GETGR_R_SIZE_MAX
- g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
-#else
- g_n = -1;
-#endif
- if (g_n <= 0)
- g_n = 512;
-
- g_buf = pa_xmalloc((size_t) g_n);
-
- if ((errno = getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr)) != 0 || !gr)
-#else
errno = 0;
- if (!(gr = getgrnam(name)))
-#endif
+ if (!(group = pa_getgrnam_malloc(name)))
{
if (!errno)
errno = ENOENT;
goto finish;
}
-#ifdef HAVE_GETPWNAM_R
-
-#ifdef _SC_GETPW_R_SIZE_MAX
- p_n = sysconf(_SC_GETPW_R_SIZE_MAX);
-#else
- p_n = -1;
-#endif
- if (p_n <= 0)
- p_n = 512;
-
- p_buf = pa_xmalloc((size_t) p_n);
-#endif
-
r = 0;
- for (i = gr->gr_mem; *i; i++) {
- struct passwd pwbuf, *pw = NULL;
+ for (i = group->gr_mem; *i; i++) {
+ struct passwd *pw = NULL;
-#ifdef HAVE_GETPWNAM_R
- if ((errno = getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw)) != 0 || !pw)
-#else
errno = 0;
- if (!(pw = getpwnam(*i)))
-#endif
+ if (!(pw = pa_getpwnam_malloc(*i)))
continue;
- if (pw->pw_uid == uid) {
+ if (pw->pw_uid == uid)
r = 1;
+
+ pa_getpwnam_free(pw);
+
+ if (r == 1)
break;
- }
}
finish:
- pa_xfree(g_buf);
- pa_xfree(p_buf);
+ pa_getgrnam_free(group);
return r;
}
@@ -1123,27 +1074,10 @@ finish:
/* Get the GID of a gfiven group, return (gid_t) -1 on failure. */
gid_t pa_get_gid_of_group(const char *name) {
gid_t ret = (gid_t) -1;
- char *g_buf = NULL;
- long g_n;
- struct group grbuf, *gr = NULL;
-
-#ifdef HAVE_GETGRNAM_R
+ struct group *gr = NULL;
-#ifdef _SC_GETGR_R_SIZE_MAX
- g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
-#else
- g_n = -1;
-#endif
- if (g_n <= 0)
- g_n = 512;
-
- g_buf = pa_xmalloc((size_t) g_n);
-
- if ((errno = getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr)) != 0 || !gr)
-#else
errno = 0;
- if (!(gr = getgrnam(name)))
-#endif
+ if (!(gr = pa_getgrnam_malloc(name)))
{
if (!errno)
errno = ENOENT;
@@ -1153,7 +1087,7 @@ gid_t pa_get_gid_of_group(const char *name) {
ret = gr->gr_gid;
finish:
- pa_xfree(g_buf);
+ pa_getgrnam_free(gr);
return ret;
}
@@ -2862,3 +2796,22 @@ void pa_reset_personality(void) {
#endif
}
+
+#if defined(__linux__) && !defined(__OPTIMIZE__)
+
+pa_bool_t pa_run_from_build_tree(void) {
+ char *rp;
+ pa_bool_t b = FALSE;
+
+ /* We abuse __OPTIMIZE__ as a check whether we are a debug build
+ * or not. */
+
+ if ((rp = pa_readlink("/proc/self/exe"))) {
+ b = pa_startswith(rp, PA_BUILDDIR);
+ pa_xfree(rp);
+ }
+
+ return b;
+}
+
+#endif
diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h
index 3d3aec71..2551f794 100644
--- a/src/pulsecore/core-util.h
+++ b/src/pulsecore/core-util.h
@@ -243,4 +243,8 @@ size_t pa_pipe_buf(int fd);
void pa_reset_personality(void);
+#if defined(__linux__) && !defined(__OPTIMIZE__)
+pa_bool_t pa_run_from_build_tree(void);
+#endif
+
#endif
diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
index f5eb8352..f0726453 100644
--- a/src/pulsecore/core.c
+++ b/src/pulsecore/core.c
@@ -47,7 +47,7 @@
#include "core.h"
-static PA_DEFINE_CHECK_TYPE(pa_core, pa_msgobject);
+PA_DEFINE_PUBLIC_CLASS(pa_core, pa_msgobject);
static int core_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
pa_core *c = PA_CORE(o);
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index f6ec7122..c1002f93 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -165,7 +165,7 @@ struct pa_core {
pa_hook hooks[PA_CORE_HOOK_MAX];
};
-PA_DECLARE_CLASS(pa_core);
+PA_DECLARE_PUBLIC_CLASS(pa_core);
#define PA_CORE(o) pa_core_cast(o)
enum {
diff --git a/src/pulsecore/msgobject.c b/src/pulsecore/msgobject.c
index 6a2a612d..075a28c5 100644
--- a/src/pulsecore/msgobject.c
+++ b/src/pulsecore/msgobject.c
@@ -26,22 +26,22 @@
#include "msgobject.h"
-PA_DEFINE_CHECK_TYPE(pa_msgobject, pa_object);
+PA_DEFINE_PUBLIC_CLASS(pa_msgobject, pa_object);
-pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name)) {
+pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_id, pa_bool_t (*check_type)(const char *type_name)) {
pa_msgobject *o;
pa_assert(size > sizeof(pa_msgobject));
- pa_assert(type_name);
+ pa_assert(type_id);
if (!check_type)
check_type = pa_msgobject_check_type;
- pa_assert(check_type(type_name));
- pa_assert(check_type("pa_object"));
- pa_assert(check_type("pa_msgobject"));
+ pa_assert(check_type(type_id));
+ pa_assert(check_type(pa_object_type_id));
+ pa_assert(check_type(pa_msgobject_type_id));
- o = PA_MSGOBJECT(pa_object_new_internal(size, type_name, check_type));
+ o = PA_MSGOBJECT(pa_object_new_internal(size, type_id, check_type));
o->process_msg = NULL;
return o;
}
diff --git a/src/pulsecore/msgobject.h b/src/pulsecore/msgobject.h
index a35a23b5..ee0ec1ed 100644
--- a/src/pulsecore/msgobject.h
+++ b/src/pulsecore/msgobject.h
@@ -38,15 +38,13 @@ struct pa_msgobject {
int (*process_msg)(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
};
-pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name));
+pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_id, pa_bool_t (*check_type)(const char *type_name));
-int pa_msgobject_check_type(const char *type);
-
-#define pa_msgobject_new(type) ((type*) pa_msgobject_new_internal(sizeof(type), #type, type##_check_type))
+#define pa_msgobject_new(type) ((type*) pa_msgobject_new_internal(sizeof(type), type##_type_id, type##_check_type))
#define pa_msgobject_free ((void (*) (pa_msgobject* o)) pa_object_free)
#define PA_MSGOBJECT(o) pa_msgobject_cast(o)
-PA_DECLARE_CLASS(pa_msgobject);
+PA_DECLARE_PUBLIC_CLASS(pa_msgobject);
#endif
diff --git a/src/pulsecore/object.c b/src/pulsecore/object.c
index f3ead9c5..099d50d9 100644
--- a/src/pulsecore/object.c
+++ b/src/pulsecore/object.c
@@ -28,21 +28,23 @@
#include "object.h"
-pa_object *pa_object_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name)) {
+const char pa_object_type_id[] = "pa_object";
+
+pa_object *pa_object_new_internal(size_t size, const char *type_id, pa_bool_t (*check_type)(const char *type_id)) {
pa_object *o;
pa_assert(size > sizeof(pa_object));
- pa_assert(type_name);
+ pa_assert(type_id);
if (!check_type)
check_type = pa_object_check_type;
- pa_assert(check_type(type_name));
- pa_assert(check_type("pa_object"));
+ pa_assert(check_type(type_id));
+ pa_assert(check_type(pa_object_type_id));
o = pa_xmalloc(size);
PA_REFCNT_INIT(o);
- o->type_name = type_name;
+ o->type_id = type_id;
o->free = pa_object_free;
o->check_type = check_type;
@@ -65,8 +67,8 @@ void pa_object_unref(pa_object *o) {
}
}
-int pa_object_check_type(const char *type_name) {
- pa_assert(type_name);
+pa_bool_t pa_object_check_type(const char *type_id) {
+ pa_assert(type_id);
- return pa_streq(type_name, "pa_object");
+ return type_id == pa_object_type_id;
}
diff --git a/src/pulsecore/object.h b/src/pulsecore/object.h
index 43e79327..4c120cd5 100644
--- a/src/pulsecore/object.h
+++ b/src/pulsecore/object.h
@@ -34,21 +34,23 @@ typedef struct pa_object pa_object;
struct pa_object {
PA_REFCNT_DECLARE;
- const char *type_name;
+ const char *type_id;
void (*free)(pa_object *o);
- int (*check_type)(const char *type_name);
+ pa_bool_t (*check_type)(const char *type_name);
};
-pa_object *pa_object_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name));
-#define pa_object_new(type) ((type*) pa_object_new_internal(sizeof(type), #type, type##_check_type)
+pa_object *pa_object_new_internal(size_t size, const char *type_id, pa_bool_t (*check_type)(const char *type_id));
+#define pa_object_new(type) ((type*) pa_object_new_internal(sizeof(type), type##_type_id, type##_check_type)
#define pa_object_free ((void (*) (pa_object* _obj)) pa_xfree)
-int pa_object_check_type(const char *type);
+pa_bool_t pa_object_check_type(const char *type_id);
-static inline int pa_object_isinstance(void *o) {
+extern const char pa_object_type_id[];
+
+static inline pa_bool_t pa_object_isinstance(void *o) {
pa_object *obj = (pa_object*) o;
- return obj ? obj->check_type("pa_object") : 0;
+ return obj ? obj->check_type(pa_object_type_id) : TRUE;
}
pa_object *pa_object_ref(pa_object *o);
@@ -60,7 +62,7 @@ static inline int pa_object_refcnt(pa_object *o) {
static inline pa_object* pa_object_cast(void *o) {
pa_object *obj = (pa_object*) o;
- pa_assert(!obj || obj->check_type("pa_object"));
+ pa_assert(!obj || obj->check_type(pa_object_type_id));
return obj;
}
@@ -68,10 +70,10 @@ static inline pa_object* pa_object_cast(void *o) {
#define PA_OBJECT(o) pa_object_cast(o)
-#define PA_DECLARE_CLASS(c) \
- static inline int c##_isinstance(void *o) { \
+#define PA_DECLARE_CLASS_COMMON(c) \
+ static inline pa_bool_t c##_isinstance(void *o) { \
pa_object *obj = (pa_object*) o; \
- return obj ? obj->check_type(#c) : 1; \
+ return obj ? obj->check_type(c##_type_id) : TRUE; \
} \
static inline c* c##_cast(void *o) { \
pa_assert(c##_isinstance(o)); \
@@ -91,12 +93,27 @@ static inline pa_object* pa_object_cast(void *o) {
} \
struct __stupid_useless_struct_to_allow_trailing_semicolon
-#define PA_DEFINE_CHECK_TYPE(c, parent) \
- int c##_check_type(const char *type) { \
- pa_assert(type); \
- if (strcmp(type, #c) == 0) \
- return 1; \
- return parent##_check_type(type); \
+#define PA_DECLARE_PUBLIC_CLASS(c) \
+ extern const char c##_type_id[]; \
+ PA_DECLARE_CLASS_COMMON(c); \
+ pa_bool_t c##_check_type(const char *type_id)
+
+#define PA_DEFINE_PUBLIC_CLASS(c, parent) \
+ const char c##_type_id[] = #c; \
+ pa_bool_t c##_check_type(const char *type_id) { \
+ if (type_id == c##_type_id) \
+ return TRUE; \
+ return parent##_check_type(type_id); \
+ } \
+ struct __stupid_useless_struct_to_allow_trailing_semicolon
+
+#define PA_DEFINE_PRIVATE_CLASS(c, parent) \
+ static const char c##_type_id[] = #c; \
+ PA_DECLARE_CLASS_COMMON(c); \
+ static pa_bool_t c##_check_type(const char *type_id) { \
+ if (type_id == c##_type_id) \
+ return TRUE; \
+ return parent##_check_type(type_id); \
} \
struct __stupid_useless_struct_to_allow_trailing_semicolon
diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c
index fceb2ca1..b0d76993 100644
--- a/src/pulsecore/play-memblockq.c
+++ b/src/pulsecore/play-memblockq.c
@@ -47,9 +47,8 @@ enum {
MEMBLOCKQ_STREAM_MESSAGE_UNLINK,
};
-PA_DECLARE_CLASS(memblockq_stream);
+PA_DEFINE_PRIVATE_CLASS(memblockq_stream, pa_msgobject);
#define MEMBLOCKQ_STREAM(o) (memblockq_stream_cast(o))
-static PA_DEFINE_CHECK_TYPE(memblockq_stream, pa_msgobject);
static void memblockq_stream_unlink(memblockq_stream *u) {
pa_assert(u);
diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c
index f64552aa..cfbaee6f 100644
--- a/src/pulsecore/protocol-esound.c
+++ b/src/pulsecore/protocol-esound.c
@@ -120,9 +120,8 @@ typedef struct connection {
pa_time_event *auth_timeout_event;
} connection;
-PA_DECLARE_CLASS(connection);
+PA_DEFINE_PRIVATE_CLASS(connection, pa_msgobject);
#define CONNECTION(o) (connection_cast(o))
-static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject);
struct pa_esound_protocol {
PA_REFCNT_DECLARE;
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index b1285e15..6678d847 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -98,17 +98,15 @@ typedef struct record_stream {
pa_usec_t current_source_latency;
} record_stream;
-PA_DECLARE_CLASS(record_stream);
#define RECORD_STREAM(o) (record_stream_cast(o))
-static PA_DEFINE_CHECK_TYPE(record_stream, pa_msgobject);
+PA_DEFINE_PRIVATE_CLASS(record_stream, pa_msgobject);
typedef struct output_stream {
pa_msgobject parent;
} output_stream;
-PA_DECLARE_CLASS(output_stream);
#define OUTPUT_STREAM(o) (output_stream_cast(o))
-static PA_DEFINE_CHECK_TYPE(output_stream, pa_msgobject);
+PA_DEFINE_PRIVATE_CLASS(output_stream, pa_msgobject);
typedef struct playback_stream {
output_stream parent;
@@ -138,9 +136,8 @@ typedef struct playback_stream {
uint64_t playing_for, underrun_for;
} playback_stream;
-PA_DECLARE_CLASS(playback_stream);
#define PLAYBACK_STREAM(o) (playback_stream_cast(o))
-static PA_DEFINE_CHECK_TYPE(playback_stream, output_stream);
+PA_DEFINE_PRIVATE_CLASS(playback_stream, output_stream);
typedef struct upload_stream {
output_stream parent;
@@ -156,9 +153,8 @@ typedef struct upload_stream {
pa_proplist *proplist;
} upload_stream;
-PA_DECLARE_CLASS(upload_stream);
#define UPLOAD_STREAM(o) (upload_stream_cast(o))
-static PA_DEFINE_CHECK_TYPE(upload_stream, output_stream);
+PA_DEFINE_PRIVATE_CLASS(upload_stream, output_stream);
struct pa_native_connection {
pa_msgobject parent;
@@ -176,9 +172,8 @@ struct pa_native_connection {
pa_time_event *auth_timeout_event;
};
-PA_DECLARE_CLASS(pa_native_connection);
#define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
-static PA_DEFINE_CHECK_TYPE(pa_native_connection, pa_msgobject);
+PA_DEFINE_PRIVATE_CLASS(pa_native_connection, pa_msgobject);
struct pa_native_protocol {
PA_REFCNT_DECLARE;
diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c
index 776d74b6..95ec6ac8 100644
--- a/src/pulsecore/protocol-simple.c
+++ b/src/pulsecore/protocol-simple.c
@@ -69,9 +69,8 @@ typedef struct connection {
} playback;
} connection;
-PA_DECLARE_CLASS(connection);
+PA_DEFINE_PRIVATE_CLASS(connection, pa_msgobject);
#define CONNECTION(o) (connection_cast(o))
-static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject);
struct pa_simple_protocol {
PA_REFCNT_DECLARE;
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index a29334f9..0ad95e6f 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -44,7 +44,7 @@
#define MEMBLOCKQ_MAXLENGTH (32*1024*1024)
#define CONVERT_BUFFER_LENGTH (PA_PAGE_SIZE)
-static PA_DEFINE_CHECK_TYPE(pa_sink_input, pa_msgobject);
+PA_DEFINE_PUBLIC_CLASS(pa_sink_input, pa_msgobject);
static void sink_input_free(pa_object *o);
static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v);
@@ -126,6 +126,8 @@ static void reset_callbacks(pa_sink_input *i) {
i->state_change = NULL;
i->may_move_to = NULL;
i->send_event = NULL;
+ i->volume_changed = NULL;
+ i->mute_changed = NULL;
}
/* Called from main context */
@@ -485,7 +487,10 @@ static void sink_input_free(pa_object *o) {
pa_log_info("Freeing input %u \"%s\"", i->index, pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME)));
- pa_assert(!i->thread_info.attached);
+ /* Side note: this function must be able to destruct properly any
+ * kind of sink input in any state, even those which are
+ * "half-moved" or are connected to sinks that have no asyncmsgq
+ * and are hence half-destructed themselves! */
if (i->thread_info.render_memblockq)
pa_memblockq_free(i->thread_info.render_memblockq);
@@ -968,7 +973,10 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo
pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0);
}
- /* The virtual volume changed, let's tell people so */
+ /* The volume changed, let's tell people so */
+ if (i->volume_changed)
+ i->volume_changed(i);
+
pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
}
@@ -999,6 +1007,11 @@ void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save) {
i->save_muted = save;
pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE, NULL, 0, NULL) == 0);
+
+ /* The mute status changed, let's tell people so */
+ if (i->mute_changed)
+ i->mute_changed(i);
+
pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
}
@@ -1263,6 +1276,10 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
/* Notify everyone */
pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], i);
+
+ if (i->volume_changed)
+ i->volume_changed(i);
+
pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
return 0;
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index ea0f8c0e..fe6cf75c 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -192,8 +192,16 @@ struct pa_sink_input {
pa_bool_t (*may_move_to) (pa_sink_input *i, pa_sink *s); /* may be NULL */
/* If non-NULL this function is used to dispatch asynchronous
- * control events. */
- void (*send_event)(pa_sink_input *i, const char *event, pa_proplist* data);
+ * control events. Called from main context. */
+ void (*send_event)(pa_sink_input *i, const char *event, pa_proplist* data); /* may be NULL */
+
+ /* If non-NULL this function is called whenever the sink input
+ * volume changes. Called from main context */
+ void (*volume_changed)(pa_sink_input *i); /* may be NULL */
+
+ /* If non-NULL this function is called whenever the sink input
+ * mute status changes. Called from main context */
+ void (*mute_changed)(pa_sink_input *i); /* may be NULL */
struct {
pa_sink_input_state_t state;
@@ -227,7 +235,7 @@ struct pa_sink_input {
void *userdata;
};
-PA_DECLARE_CLASS(pa_sink_input);
+PA_DECLARE_PUBLIC_CLASS(pa_sink_input);
#define PA_SINK_INPUT(o) pa_sink_input_cast(o)
enum {
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 1cce8e6b..5cec7747 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -52,7 +52,7 @@
#define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
#define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
-static PA_DEFINE_CHECK_TYPE(pa_sink, pa_msgobject);
+PA_DEFINE_PUBLIC_CLASS(pa_sink, pa_msgobject);
static void sink_free(pa_object *s);
@@ -1380,9 +1380,14 @@ static void propagate_reference_volume(pa_sink *s) {
pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map);
pa_sw_cvolume_multiply(&i->volume, &remapped, &i->reference_ratio);
- /* The reference volume changed, let's tell people so */
- if (!pa_cvolume_equal(&old_volume, &i->volume))
+ /* The volume changed, let's tell people so */
+ if (!pa_cvolume_equal(&old_volume, &i->volume)) {
+
+ if (i->volume_changed)
+ i->volume_changed(i);
+
pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+ }
}
}
@@ -1522,8 +1527,13 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume)
pa_sw_cvolume_multiply(&i->volume, &remapped, &i->reference_ratio);
/* Notify if something changed */
- if (!pa_cvolume_equal(&old_volume, &i->volume))
+ if (!pa_cvolume_equal(&old_volume, &i->volume)) {
+
+ if (i->volume_changed)
+ i->volume_changed(i);
+
pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+ }
}
}
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index 936d1c2a..b5284b71 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -191,7 +191,7 @@ struct pa_sink {
void *userdata;
};
-PA_DECLARE_CLASS(pa_sink);
+PA_DECLARE_PUBLIC_CLASS(pa_sink);
#define PA_SINK(s) (pa_sink_cast(s))
typedef enum pa_sink_message {
diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c
index 502e5c69..f41c53f3 100644
--- a/src/pulsecore/sound-file-stream.c
+++ b/src/pulsecore/sound-file-stream.c
@@ -64,9 +64,8 @@ enum {
FILE_STREAM_MESSAGE_UNLINK
};
-PA_DECLARE_CLASS(file_stream);
+PA_DEFINE_PRIVATE_CLASS(file_stream, pa_msgobject);
#define FILE_STREAM(o) (file_stream_cast(o))
-static PA_DEFINE_CHECK_TYPE(file_stream, pa_msgobject);
/* Called from main context */
static void file_stream_unlink(file_stream *u) {
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 3803a6cc..43733400 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -41,7 +41,7 @@
#define MEMBLOCKQ_MAXLENGTH (32*1024*1024)
-static PA_DEFINE_CHECK_TYPE(pa_source_output, pa_msgobject);
+PA_DEFINE_PUBLIC_CLASS(pa_source_output, pa_msgobject);
static void source_output_free(pa_object* mo);
@@ -359,8 +359,6 @@ static void source_output_free(pa_object* mo) {
pa_log_info("Freeing output %u \"%s\"", o->index, pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME)));
- pa_assert(!o->thread_info.attached);
-
if (o->thread_info.delay_memblockq)
pa_memblockq_free(o->thread_info.delay_memblockq);
diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
index a70a3fdb..aca9ddf2 100644
--- a/src/pulsecore/source-output.h
+++ b/src/pulsecore/source-output.h
@@ -182,7 +182,7 @@ struct pa_source_output {
void *userdata;
};
-PA_DECLARE_CLASS(pa_source_output);
+PA_DECLARE_PUBLIC_CLASS(pa_source_output);
#define PA_SOURCE_OUTPUT(o) pa_source_output_cast(o)
enum {
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 8aa07f5e..3026654e 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -46,7 +46,7 @@
#define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
#define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
-static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject);
+PA_DEFINE_PUBLIC_CLASS(pa_source, pa_msgobject);
static void source_free(pa_object *o);
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index 7b3e4953..df3f99df 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -158,7 +158,7 @@ struct pa_source {
void *userdata;
};
-PA_DECLARE_CLASS(pa_source);
+PA_DECLARE_PUBLIC_CLASS(pa_source);
#define PA_SOURCE(s) pa_source_cast(s)
typedef enum pa_source_message {
diff --git a/src/pulsecore/usergroup.c b/src/pulsecore/usergroup.c
new file mode 100644
index 00000000..71b13bca
--- /dev/null
+++ b/src/pulsecore/usergroup.c
@@ -0,0 +1,372 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2009 Ted Percival
+
+ 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.1 of the
+ License, or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <errno.h>
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+
+#include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
+
+#include "usergroup.h"
+
+#ifdef HAVE_GRP_H
+
+/* Returns a suitable starting size for a getgrnam_r() or getgrgid_r() buffer,
+ plus the size of a struct group.
+ */
+static size_t starting_getgr_buflen(void) {
+ size_t full_size;
+ long n;
+#ifdef _SC_GETGR_R_SIZE_MAX
+ n = sysconf(_SC_GETGR_R_SIZE_MAX);
+#else
+ n = -1;
+#endif
+ if (n <= 0)
+ n = 512;
+
+ full_size = (size_t) n + sizeof(struct group);
+
+ if (full_size < (size_t) n) /* check for integer overflow */
+ return (size_t) n;
+
+ return full_size;
+}
+
+/* Returns a suitable starting size for a getpwnam_r() or getpwuid_r() buffer,
+ plus the size of a struct passwd.
+ */
+static size_t starting_getpw_buflen(void) {
+ long n;
+ size_t full_size;
+
+#ifdef _SC_GETPW_R_SIZE_MAX
+ n = sysconf(_SC_GETPW_R_SIZE_MAX);
+#else
+ n = -1;
+#endif
+ if (n <= 0)
+ n = 512;
+
+ full_size = (size_t) n + sizeof(struct passwd);
+
+ if (full_size < (size_t) n) /* check for integer overflow */
+ return (size_t) n;
+
+ return full_size;
+}
+
+/* Given a memory allocation (*bufptr) and its length (*buflenptr),
+ double the size of the allocation, updating the given buffer and length
+ arguments. This function should be used in conjunction with the pa_*alloc
+ and pa_xfree functions.
+
+ Unlike realloc(), this function does *not* retain the original buffer's
+ contents.
+
+ Returns 0 on success, nonzero on error. The error cause is indicated by
+ errno.
+ */
+static int expand_buffer_trashcontents(void **bufptr, size_t *buflenptr) {
+ size_t newlen;
+
+ if (!bufptr || !*bufptr || !buflenptr) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ newlen = *buflenptr * 2;
+
+ if (newlen < *buflenptr) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+
+ /* Don't bother retaining memory contents; free & alloc anew */
+ pa_xfree(*bufptr);
+
+ *bufptr = pa_xmalloc(newlen);
+ *buflenptr = newlen;
+
+ return 0;
+}
+
+#ifdef HAVE_GETGRGID_R
+/* Thread-safe getgrgid() replacement.
+ Returned value should be freed using pa_getgrgid_free() when the caller is
+ finished with the returned group data.
+
+ API is the same as getgrgid(), errors are indicated by a NULL return;
+ consult errno for the error cause (zero it before calling).
+ */
+struct group *pa_getgrgid_malloc(gid_t gid) {
+ size_t buflen, getgr_buflen;
+ int err;
+ void *buf;
+ void *getgr_buf;
+ struct group *result = NULL;
+
+ buflen = starting_getgr_buflen();
+ buf = pa_xmalloc(buflen);
+
+ getgr_buflen = buflen - sizeof(struct group);
+ getgr_buf = (char *)buf + sizeof(struct group);
+
+ while ((err = getgrgid_r(gid, (struct group *)buf, getgr_buf,
+ getgr_buflen, &result)) == ERANGE)
+ {
+ if (expand_buffer_trashcontents(&buf, &buflen))
+ break;
+
+ getgr_buflen = buflen - sizeof(struct group);
+ getgr_buf = (char *)buf + sizeof(struct group);
+ }
+
+ if (err || !result) {
+ result = NULL;
+ if (buf) {
+ pa_xfree(buf);
+ buf = NULL;
+ }
+ }
+
+ pa_assert(result == buf || result == NULL);
+
+ return result;
+}
+
+void pa_getgrgid_free(struct group *grp) {
+ pa_xfree(grp);
+}
+
+#else /* !HAVE_GETGRGID_R */
+
+struct group *pa_getgrgid_malloc(gid_t gid) {
+ return getgrgid(gid);
+}
+
+void pa_getgrgid_free(struct group *grp) {
+ /* nothing */
+ return;
+}
+
+#endif /* !HAVE_GETGRGID_R */
+
+#ifdef HAVE_GETGRNAM_R
+/* Thread-safe getgrnam() function.
+ Returned value should be freed using pa_getgrnam_free() when the caller is
+ finished with the returned group data.
+
+ API is the same as getgrnam(), errors are indicated by a NULL return;
+ consult errno for the error cause (zero it before calling).
+ */
+struct group *pa_getgrnam_malloc(const char *name) {
+ size_t buflen, getgr_buflen;
+ int err;
+ void *buf;
+ void *getgr_buf;
+ struct group *result = NULL;
+
+ buflen = starting_getgr_buflen();
+ buf = pa_xmalloc(buflen);
+
+ getgr_buflen = buflen - sizeof(struct group);
+ getgr_buf = (char *)buf + sizeof(struct group);
+
+ while ((err = getgrnam_r(name, (struct group *)buf, getgr_buf,
+ getgr_buflen, &result)) == ERANGE)
+ {
+ if (expand_buffer_trashcontents(&buf, &buflen))
+ break;
+
+ getgr_buflen = buflen - sizeof(struct group);
+ getgr_buf = (char *)buf + sizeof(struct group);
+ }
+
+ if (err || !result) {
+ result = NULL;
+ if (buf) {
+ pa_xfree(buf);
+ buf = NULL;
+ }
+ }
+
+ pa_assert(result == buf || result == NULL);
+
+ return result;
+}
+
+void pa_getgrnam_free(struct group *group) {
+ pa_xfree(group);
+}
+
+#else /* !HAVE_GETGRNAM_R */
+
+struct group *pa_getgrnam_malloc(const char *name) {
+ return getgrnam(name);
+}
+
+void pa_getgrnam_free(struct group *group) {
+ /* nothing */
+ return;
+}
+
+#endif /* HAVE_GETGRNAM_R */
+
+#endif /* HAVE_GRP_H */
+
+#ifdef HAVE_PWD_H
+
+#ifdef HAVE_GETPWNAM_R
+/* Thread-safe getpwnam() function.
+ Returned value should be freed using pa_getpwnam_free() when the caller is
+ finished with the returned passwd data.
+
+ API is the same as getpwnam(), errors are indicated by a NULL return;
+ consult errno for the error cause (zero it before calling).
+ */
+struct passwd *pa_getpwnam_malloc(const char *name) {
+ size_t buflen, getpw_buflen;
+ int err;
+ void *buf;
+ void *getpw_buf;
+ struct passwd *result = NULL;
+
+ buflen = starting_getpw_buflen();
+ buf = pa_xmalloc(buflen);
+
+ getpw_buflen = buflen - sizeof(struct passwd);
+ getpw_buf = (char *)buf + sizeof(struct passwd);
+
+ while ((err = getpwnam_r(name, (struct passwd *)buf, getpw_buf,
+ getpw_buflen, &result)) == ERANGE)
+ {
+ if (expand_buffer_trashcontents(&buf, &buflen))
+ break;
+
+ getpw_buflen = buflen - sizeof(struct passwd);
+ getpw_buf = (char *)buf + sizeof(struct passwd);
+ }
+
+ if (err || !result) {
+ result = NULL;
+ if (buf) {
+ pa_xfree(buf);
+ buf = NULL;
+ }
+ }
+
+ pa_assert(result == buf || result == NULL);
+
+ return result;
+}
+
+void pa_getpwnam_free(struct passwd *passwd) {
+ pa_xfree(passwd);
+}
+
+#else /* !HAVE_GETPWNAM_R */
+
+struct passwd *pa_getpwnam_malloc(const char *name) {
+ return getpwnam(name);
+}
+
+void pa_getpwnam_free(struct passwd *passwd) {
+ /* nothing */
+ return;
+}
+
+#endif /* !HAVE_GETPWNAM_R */
+
+#ifdef HAVE_GETPWUID_R
+/* Thread-safe getpwuid() function.
+ Returned value should be freed using pa_getpwuid_free() when the caller is
+ finished with the returned group data.
+
+ API is the same as getpwuid(), errors are indicated by a NULL return;
+ consult errno for the error cause (zero it before calling).
+ */
+struct passwd *pa_getpwuid_malloc(uid_t uid) {
+ size_t buflen, getpw_buflen;
+ int err;
+ void *buf;
+ void *getpw_buf;
+ struct passwd *result = NULL;
+
+ buflen = starting_getpw_buflen();
+ buf = pa_xmalloc(buflen);
+
+ getpw_buflen = buflen - sizeof(struct passwd);
+ getpw_buf = (char *)buf + sizeof(struct passwd);
+
+ while ((err = getpwuid_r(uid, (struct passwd *)buf, getpw_buf,
+ getpw_buflen, &result)) == ERANGE)
+ {
+ if (expand_buffer_trashcontents(&buf, &buflen))
+ break;
+
+ getpw_buflen = buflen - sizeof(struct passwd);
+ getpw_buf = (char *)buf + sizeof(struct passwd);
+ }
+
+ if (err || !result) {
+ result = NULL;
+ if (buf) {
+ pa_xfree(buf);
+ buf = NULL;
+ }
+ }
+
+ pa_assert(result == buf || result == NULL);
+
+ return result;
+}
+
+void pa_getpwuid_free(struct passwd *passwd) {
+ pa_xfree(passwd);
+}
+
+#else /* !HAVE_GETPWUID_R */
+
+struct passwd *pa_getpwuid_malloc(uid_t uid) {
+ return getpwuid(uid);
+}
+
+void pa_getpwuid_free(struct passwd *passwd) {
+ /* nothing */
+ return;
+}
+
+#endif /* !HAVE_GETPWUID_R */
+
+#endif /* HAVE_PWD_H */
diff --git a/src/pulsecore/usergroup.h b/src/pulsecore/usergroup.h
new file mode 100644
index 00000000..1c091638
--- /dev/null
+++ b/src/pulsecore/usergroup.h
@@ -0,0 +1,51 @@
+#ifndef foousergrouphfoo
+#define foousergrouphfoo
+
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2009 Ted Percival
+
+ 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.1 of the
+ License, or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#include <sys/types.h>
+
+#ifndef PACKAGE
+#error "Please include config.h before including this file!"
+#endif
+
+#ifdef HAVE_GRP_H
+
+struct group *pa_getgrgid_malloc(gid_t gid);
+void pa_getgrgid_free(struct group *grp);
+
+struct group *pa_getgrnam_malloc(const char *name);
+void pa_getgrnam_free(struct group *group);
+
+#endif /* HAVE_GRP_H */
+
+#ifdef HAVE_PWD_H
+
+struct passwd *pa_getpwuid_malloc(uid_t uid);
+void pa_getpwuid_free(struct passwd *passwd);
+
+struct passwd *pa_getpwnam_malloc(const char *name);
+void pa_getpwnam_free(struct passwd *passwd);
+
+#endif /* HAVE_PWD_H */
+
+#endif /* foousergrouphfoo */