noinst_DATA = README
pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc
+pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc polyplib-glib-mainloop.pc
README:
rm -f README
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
AC_PREREQ(2.57)
-AC_INIT([polypaudio],[0.1],[mzcbylcnhqvb (at) 0pointer (dot) de])
+AC_INIT([polypaudio],[0.2],[mzcbylcnhqvb (at) 0pointer (dot) de])
AC_CONFIG_SRCDIR([polyp/main.c])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([foreign -Wall])
AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false)
-AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf])
+AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc polyplib-glib-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf])
AC_OUTPUT
- future cancellation
- make mcalign merge chunks
- ref counting foo
+- pacat quit() ?
- doxygen
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = ../polyp/polyplib-context.h ../polyp/polyplib-stream.h ../polyp/polyplib.h ../polyp/sample.h ../polyp/polyplib-def.h ../polyp/polyplib-subscribe.h ../polyp/polyplib-introspect.h ../polyp/polyplib-scache.h ../polyp/mainloop-api.h ../polyp/cdecl.h ../polyp/glib-mainloop.h ../polyp/mainloop.h ../polyp/mainloop-signal.h ../polyp/native-common.h ../polyp/polyplib-error.h ../polyp/polyplib-operation.h ../polyp/polyplib-simple.h
+INPUT = ../polyp/polyplib-context.h ../polyp/polyplib-stream.h ../polyp/polyplib.h ../polyp/sample.h ../polyp/polyplib-def.h ../polyp/polyplib-subscribe.h ../polyp/polyplib-introspect.h ../polyp/polyplib-scache.h ../polyp/mainloop-api.h ../polyp/cdecl.h ../polyp/glib-mainloop.h ../polyp/mainloop.h ../polyp/mainloop-signal.h ../polyp/polyplib-error.h ../polyp/polyplib-operation.h ../polyp/polyplib-simple.h
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# directories that contain example code fragments that are included (see
# the \include command).
-EXAMPLE_PATH =
+EXAMPLE_PATH = ../polyp/
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
libpolyp-mainloop-glib.la \
libpolyp-simple.la
-
polypaudio_SOURCES = idxset.c idxset.h \
queue.c queue.h \
strbuf.c strbuf.h \
PA_C_DECL_BEGIN
/** \struct pa_glib_mainloop
- * A GLIB main loop object */
+ * An opaque GLIB main loop object */
struct pa_glib_mainloop;
/** Create a new GLIB main loop object for the specified GLIB main loop context. If c is NULL the default context is used. */
};
/** \struct pa_io_event
- * An IO event source object */
+ * An opaque IO event source object */
struct pa_io_event;
/** \struct pa_defer_event
- * A deferred event source object. Events of this type are triggered once in every main loop iteration */
+ * An opaque deferred event source object. Events of this type are triggered once in every main loop iteration */
struct pa_defer_event;
/** \struct pa_time_event
- * A timer event source object */
+ * An opaque timer event source object */
struct pa_time_event;
/** An abstract mainloop API vtable */
void pa_signal_done(void);
/** \struct pa_signal_event
- * A UNIX signal event source object */
+ * An opaque UNIX signal event source object */
struct pa_signal_event;
/** Create a new UNIX signal event source object */
* as long as you access the main loop object from a single thread only.*/
/** \struct pa_mainloop
- * A main loop object
+ * An opaque main loop object
*/
struct pa_mainloop;
***/
#include "cdecl.h"
+#include "polyplib-def.h"
PA_C_DECL_BEGIN
PA_COMMAND_MAX
};
-enum {
- PA_ERROR_OK,
- PA_ERROR_ACCESS,
- PA_ERROR_COMMAND,
- PA_ERROR_INVALID,
- PA_ERROR_EXIST,
- PA_ERROR_NOENTITY,
- PA_ERROR_CONNECTIONREFUSED,
- PA_ERROR_PROTOCOL,
- PA_ERROR_TIMEOUT,
- PA_ERROR_AUTHKEY,
- PA_ERROR_INTERNAL,
- PA_ERROR_CONNECTIONTERMINATED,
- PA_ERROR_KILLED,
- PA_ERROR_INVALIDSERVER,
- PA_ERROR_MAX
-};
-
#define PA_NATIVE_COOKIE_LENGTH 256
#define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie"
-enum pa_subscription_mask {
- PA_SUBSCRIPTION_MASK_NULL = 0,
- PA_SUBSCRIPTION_MASK_SINK = 1,
- PA_SUBSCRIPTION_MASK_SOURCE = 2,
- PA_SUBSCRIPTION_MASK_SINK_INPUT = 4,
- PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8,
- PA_SUBSCRIPTION_MASK_MODULE = 16,
- PA_SUBSCRIPTION_MASK_CLIENT = 32,
- PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64,
-};
-
-enum pa_subscription_event_type {
- PA_SUBSCRIPTION_EVENT_SINK = 0,
- PA_SUBSCRIPTION_EVENT_SOURCE = 1,
- PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2,
- PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3,
- PA_SUBSCRIPTION_EVENT_MODULE = 4,
- PA_SUBSCRIPTION_EVENT_CLIENT = 5,
- PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6,
- PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 7,
-
- PA_SUBSCRIPTION_EVENT_NEW = 0,
- PA_SUBSCRIPTION_EVENT_CHANGE = 16,
- PA_SUBSCRIPTION_EVENT_REMOVE = 32,
- PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32,
-};
-
-#define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK))))
-
PA_C_DECL_END
#endif
#define BUFSIZE 1024
int main(int argc, char*argv[]) {
+
+ /* The Sample format to use */
static const struct pa_sample_spec ss = {
.format = PA_SAMPLE_S16LE,
.rate = 44100,
.channels = 2
};
+
struct pa_simple *s = NULL;
int ret = 1;
int error;
+ /* Create a new playback stream */
if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, &error))) {
fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
goto finish;
for (;;) {
uint8_t buf[BUFSIZE];
ssize_t r;
-
+
+ /* Read some data ... */
if ((r = read(STDIN_FILENO, buf, sizeof(buf))) <= 0) {
- if (r == 0) /* eof */
+ if (r == 0) /* EOF */
break;
fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno));
goto finish;
}
+ /* ... and play it */
if (pa_simple_write(s, buf, r, &error) < 0) {
fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error));
goto finish;
}
}
- /* Make sure that every single sample way played */
+ /* Make sure that every single sample was played */
if (pa_simple_drain(s, &error) < 0) {
fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error));
goto finish;
static struct pa_io_event* stdio_event = NULL;
+/* A shortcut for terminating the application */
static void quit(int ret) {
assert(mainloop_api);
mainloop_api->quit(mainloop_api, ret);
}
+/* Write some data to the stream */
static void do_stream_write(size_t length) {
size_t l;
assert(length);
}
}
+/* This is called whenever new data may be written to the stream */
static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) {
assert(s && length);
do_stream_write(length);
}
+/* This is called whenever new data may is available */
static void stream_read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) {
assert(s && data && length);
buffer_index = 0;
}
+/* This routine is called whenever the stream state changes */
static void stream_state_callback(struct pa_stream *s, void *userdata) {
assert(s);
}
}
+/* This is called whenever the context status changes */
static void context_state_callback(struct pa_context *c, void *userdata) {
static const struct pa_sample_spec ss = {
.format = PA_SAMPLE_S16LE,
}
}
+/* Connection draining complete */
static void context_drain_complete(struct pa_context*c, void *userdata) {
pa_context_disconnect(c);
}
+/* Stream draining complete */
static void stream_drain_complete(struct pa_stream*s, int success, void *userdata) {
struct pa_operation *o;
}
}
+/* New data on STDIN **/
static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) {
size_t l, w = 0;
ssize_t r;
do_stream_write(w);
}
+/* Some data may be written to STDOUT */
static void stdout_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) {
ssize_t r;
assert(a == mainloop_api && e && stdio_event == e);
}
}
+/* UNIX signal to quit recieved */
static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) {
fprintf(stderr, "Got SIGINT, exiting.\n");
quit(0);
}
+/* Show the current playback latency */
static void stream_get_latency_callback(struct pa_stream *s, uint32_t latency, void *userdata) {
assert(s);
fprintf(stderr, "Current latency is %u usecs.\n", latency);
}
+/* Someone requested that the latency is shown */
static void sigusr1_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) {
if (mode != PLAYBACK)
return;
if (!(bn = strrchr(argv[0], '/')))
bn = argv[0];
+ else
+ bn++;
if (strstr(bn, "rec") || strstr(bn, "mon"))
mode = RECORD;
mode = PLAYBACK;
fprintf(stderr, "Opening a %s stream.\n", mode == RECORD ? "recording" : "playback");
-
+
+ /* Set up a new main loop */
if (!(m = pa_mainloop_new())) {
fprintf(stderr, "pa_mainloop_new() failed.\n");
goto quit;
fprintf(stderr, "source_io() failed.\n");
goto quit;
}
-
- if (!(context = pa_context_new(mainloop_api, argv[0]))) {
+
+ /* Create a new connection context */
+ if (!(context = pa_context_new(mainloop_api, bn))) {
fprintf(stderr, "pa_context_new() failed.\n");
goto quit;
}
pa_context_set_state_callback(context, context_state_callback, NULL);
+ /* Connect the context */
pa_context_connect(context, NULL);
+ /* Run the main loop */
if (pa_mainloop_run(m, &ret) < 0) {
fprintf(stderr, "pa_mainloop_run() failed.\n");
goto quit;
#define BUFSIZE 1024
+/* A simple routine calling UNIX write() in a loop */
static ssize_t loop_write(int fd, const void*data, size_t size) {
ssize_t ret = 0;
}
int main(int argc, char*argv[]) {
+ /* The sample type to use */
static const struct pa_sample_spec ss = {
.format = PA_SAMPLE_S16LE,
.rate = 44100,
int ret = 1;
int error;
+ /* Create the recording stream */
if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, &error))) {
fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
goto finish;
uint8_t buf[BUFSIZE];
ssize_t r;
+ /* Record some data ... */
if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) {
fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error));
goto finish;
}
-
+
+ /* And write it to STDOUT */
if ((r = loop_write(STDOUT_FILENO, buf, sizeof(buf))) <= 0) {
fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno));
goto finish;
#include "polyplib-operation.h"
/** \file
- * Connection contexts */
+ * Connection contexts for asynchrononous communication with a
+ * server. A pa_context object wraps a connection to a polypaudio
+ * server using its native protocol. A context may be used to issue
+ * commands on the server or to create playback or recording
+ * streams. Multiple playback streams may be piped through a single
+ * connection context. Operations on the contect involving
+ * communication with the server are executed asynchronously: i.e. the
+ * client function do not implicitely wait for completion of the
+ * operation on the server. Instead the caller specifies a call back
+ * function that is called when the operation is completed. Currently
+ * running operations may be canceled using pa_operation_cancel(). */
+
+/** \example pacat.c
+ * A playback and recording tool using the asynchronous API */
PA_C_DECL_BEGIN
-/** The state of a connection context */
-enum pa_context_state {
- PA_CONTEXT_UNCONNECTED, /**< The context hasn't been connected yet */
- PA_CONTEXT_CONNECTING, /**< A connection is being established */
- PA_CONTEXT_AUTHORIZING, /**< The client is authorizing itself to the daemon */
- PA_CONTEXT_SETTING_NAME, /**< The client is passing its application name to the daemon */
- PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */
- PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */
- PA_CONTEXT_TERMINATED /**< The connect was terminated cleanly */
-};
-
/** \struct pa_context
- * A connection context to a daemon */
+ * An opaque connection context to a daemon */
struct pa_context;
/** Instantiate a new connection context with an abstract mainloop API
***/
#include <inttypes.h>
-#include "native-common.h"
#include "cdecl.h"
+/** \file
+ * Global definitions */
+
PA_C_DECL_BEGIN
-enum pa_stream_direction {
- PA_STREAM_NODIRECTION,
- PA_STREAM_PLAYBACK,
- PA_STREAM_RECORD,
- PA_STREAM_UPLOAD
+/** The state of a connection context */
+enum pa_context_state {
+ PA_CONTEXT_UNCONNECTED, /**< The context hasn't been connected yet */
+ PA_CONTEXT_CONNECTING, /**< A connection is being established */
+ PA_CONTEXT_AUTHORIZING, /**< The client is authorizing itself to the daemon */
+ PA_CONTEXT_SETTING_NAME, /**< The client is passing its application name to the daemon */
+ PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */
+ PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */
+ PA_CONTEXT_TERMINATED /**< The connection was terminated cleanly */
};
-struct pa_buffer_attr {
- uint32_t maxlength;
- uint32_t tlength;
- uint32_t prebuf;
- uint32_t minreq;
- uint32_t fragsize;
+/** The state of a stream */
+enum pa_stream_state {
+ PA_STREAM_DISCONNECTED, /**< The stream is not yet connected to any sink or source */
+ PA_STREAM_CREATING, /**< The stream is being created */
+ PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */
+ PA_STREAM_FAILED, /**< An error occured that made the stream invalid */
+ PA_STREAM_TERMINATED, /**< The stream has been terminated cleanly */
};
+/** The state of an operation */
+enum pa_operation_state {
+ PA_OPERATION_RUNNING, /**< The operation is still running */
+ PA_OPERATION_DONE, /**< The operation has been completed */
+ PA_OPERATION_CANCELED, /**< The operation has been canceled */
+};
+
+/** An invalid index */
#define PA_INVALID_INDEX ((uint32_t) -1)
+/** The direction of a pa_stream object */
+enum pa_stream_direction {
+ PA_STREAM_NODIRECTION, /**< Invalid direction */
+ PA_STREAM_PLAYBACK, /**< Playback stream */
+ PA_STREAM_RECORD, /**< Record stream */
+ PA_STREAM_UPLOAD /**< Sample upload stream */
+};
+
+/** Playback and record buffer metrics */
+struct pa_buffer_attr{
+ uint32_t maxlength; /**< Maximum length of the buffer */
+ uint32_t tlength; /**< Playback only: target length of the buffer. The server tries to assure that at least tlength bytes are always available in the buffer */
+ uint32_t prebuf; /**< Playback only: pre-buffering. The server does not start with playback before at least prebug bytes are available in the buffer */
+ uint32_t minreq; /**< Playback only: minimum request. The server does not request less than minreq bytes from the client, instead waints until the buffer is free enough to request more bytes at once */
+ uint32_t fragsize; /**< Recording only: fragment size. The server sends data in blocks of fragsize bytes size. Large values deminish interactivity with other operations on the connection context but decrease control overhead. */
+};
+
+/** Error values as used by pa_context_errno(). Use pa_strerror() to convert these values to human readable strings */
+enum {
+ PA_ERROR_OK, /**< No error */
+ PA_ERROR_ACCESS, /**< Access failure */
+ PA_ERROR_COMMAND, /**< Unknown command */
+ PA_ERROR_INVALID, /**< Invalid argument */
+ PA_ERROR_EXIST, /**< Entity exists */
+ PA_ERROR_NOENTITY, /**< No such entity */
+ PA_ERROR_CONNECTIONREFUSED, /**< Connection refused */
+ PA_ERROR_PROTOCOL, /**< Protocol error */
+ PA_ERROR_TIMEOUT, /**< Timeout */
+ PA_ERROR_AUTHKEY, /**< No authorization key */
+ PA_ERROR_INTERNAL, /**< Internal error */
+ PA_ERROR_CONNECTIONTERMINATED, /**< Connection terminated */
+ PA_ERROR_KILLED, /**< Entity killed */
+ PA_ERROR_INVALIDSERVER, /**< Invalid server */
+ PA_ERROR_MAX /**< Not really an error but the first invalid error code */
+};
+
+/** Subscription event mask, as used by pa_context_subscribe() */
+enum pa_subscription_mask {
+ PA_SUBSCRIPTION_MASK_NULL = 0, /**< No events */
+ PA_SUBSCRIPTION_MASK_SINK = 1, /**< Sink events */
+ PA_SUBSCRIPTION_MASK_SOURCE = 2, /**< Source events */
+ PA_SUBSCRIPTION_MASK_SINK_INPUT = 4, /**< Sink input events */
+ PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, /**< Source output events */
+ PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */
+ PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client events */
+ PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */
+};
+
+/** Subscription event types, as used by pa_context_subscribe() */
+enum pa_subscription_event_type {
+ PA_SUBSCRIPTION_EVENT_SINK = 0, /**< Event type: Sink */
+ PA_SUBSCRIPTION_EVENT_SOURCE = 1, /**< Event type: Source */
+ PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, /**< Event type: Sink input */
+ PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, /**< Event type: Source output */
+ PA_SUBSCRIPTION_EVENT_MODULE = 4, /**< Event type: Module */
+ PA_SUBSCRIPTION_EVENT_CLIENT = 5, /**< Event type: Client */
+ PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, /**< Event type: Sample cache item */
+ PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 7, /**< A mask to extract the event type from an event value */
+
+ PA_SUBSCRIPTION_EVENT_NEW = 0, /**< A new object was created */
+ PA_SUBSCRIPTION_EVENT_CHANGE = 16, /**< A property of the object was modified */
+ PA_SUBSCRIPTION_EVENT_REMOVE = 32, /**< An object was removed */
+ PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32, /**< A mask to extract the event operation from an event value */
+};
+
+/** Return one if an event type t matches an event mask bitfield */
+#define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK))))
+
PA_C_DECL_END
#endif
[PA_ERROR_EXIST] = "Entity exists",
[PA_ERROR_NOENTITY] = "No such entity",
[PA_ERROR_CONNECTIONREFUSED] = "Connection refused",
- [PA_ERROR_PROTOCOL] = "Protocol corrupt",
+ [PA_ERROR_PROTOCOL] = "Protocol error",
[PA_ERROR_TIMEOUT] = "Timeout",
- [PA_ERROR_AUTHKEY] = "Not authorization key",
+ [PA_ERROR_AUTHKEY] = "No authorization key",
[PA_ERROR_INTERNAL] = "Internal error",
[PA_ERROR_CONNECTIONTERMINATED] = "Connection terminated",
[PA_ERROR_KILLED] = "Entity killed",
+ [PA_ERROR_INVALIDSERVER] = "Invalid server",
};
const char*pa_strerror(uint32_t error) {
#include <inttypes.h>
#include "cdecl.h"
+/** \file
+ * Error management */
+
PA_C_DECL_BEGIN
/** Return a human readable error message for the specified numeric error code */
#include "polyplib-stream.h"
#include "polyplib-operation.h"
#include "llist.h"
+#include "native-common.h"
#define DEFAULT_MAXLENGTH 204800
#define DEFAULT_TLENGTH 10240
/*** Volume manipulation ***/
-struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
+struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
struct pa_operation *o;
struct pa_tagstruct *t;
uint32_t tag;
return pa_operation_ref(o);
}
-struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
+struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
struct pa_operation *o;
struct pa_tagstruct *t;
uint32_t tag;
return pa_operation_ref(o);
}
-struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
+struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
struct pa_operation *o;
struct pa_tagstruct *t;
uint32_t tag;
#include "polyplib-context.h"
#include "cdecl.h"
+/** \file
+ * Routines for daemon introspection. */
+
PA_C_DECL_BEGIN
struct pa_sink_info {
const char *description;
struct pa_sample_spec sample_spec;
uint32_t owner_module;
- uint32_t volume;
+ pa_volume_t volume;
uint32_t monitor_source;
const char *monitor_source_name;
uint32_t latency;
struct pa_operation* pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
struct pa_operation* pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
+/** Server information */
struct pa_server_info {
- const char *user_name;
- const char *host_name;
- const char *server_version;
- const char *server_name;
- struct pa_sample_spec sample_spec;
+ const char *user_name; /**< User name of the daemon process */
+ const char *host_name; /**< Host name the daemon is running on */
+ const char *server_version; /**< Version string of the daemon */
+ const char *server_name; /**< Server package name (usually "polypaudio") */
+ struct pa_sample_spec sample_spec; /**< Default sample specification */
};
struct pa_operation* pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata);
uint32_t client;
uint32_t sink;
struct pa_sample_spec sample_spec;
- uint32_t volume;
+ pa_volume_t volume;
uint32_t latency;
};
struct pa_operation* pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
struct pa_operation* pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
-struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
+/** Set the volume of a sink device specified by its index */
+struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
+
+/** Set the volume of a sink device specified by its name */
+struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
+
+/** Set the volume of a sink input stream */
+struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
+/** Memory block statistics */
struct pa_stat_info {
- uint32_t memblock_count;
- uint32_t memblock_total;
+ uint32_t memblock_count; /**< Allocated memory blocks */
+ uint32_t memblock_total; /**< Total size of allocated memory blocks */
};
+/** Get daemon memory block statistics */
struct pa_operation* pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_stat_info *i, void *userdata), void *userdata);
PA_C_DECL_END
PA_C_DECL_BEGIN
-enum pa_operation_state {
- PA_OPERATION_RUNNING, /**< The operation is still running */
- PA_OPERATION_DONE, /**< The operation has been completed */
- PA_OPERATION_CANCELED, /**< The operation has been canceled */
-};
-
/** \struct pa_operation
* An asynchronous operation object */
struct pa_operation;
#include "cdecl.h"
/** \file
- * A simple but limited synchronous playback and recording API. */
+ * A simple but limited synchronous playback and recording
+ * API. This is synchronouse, simplified wrapper around the standard
+ * asynchronous API. */
+
+/** \example pacat-simple.c
+ * A simple playback tool using the simple API */
+
+/** \example parec-simple.c
+ * A simple recording tool using the simple API */
PA_C_DECL_BEGIN
/** \struct pa_simple
- * A simple connection object */
+ * An opaque simple connection object */
struct pa_simple;
/** Create a new connection to the server */
PA_C_DECL_BEGIN
-/** The state of a stream */
-enum pa_stream_state {
- PA_STREAM_DISCONNECTED, /**< The stream is not yet connected to any sink or source */
- PA_STREAM_CREATING, /**< The stream is being created */
- PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */
- PA_STREAM_FAILED, /**< An error occured that made the stream invalid */
- PA_STREAM_TERMINATED, /**< The stream has been terminated cleanly */
-};
-
/** \struct pa_stream
- * A stream for playback or recording */
+ * An opaque stream for playback or recording */
struct pa_stream;
/** Create a new, unconnected stream with the specified name and sample type */
#include "polyplib-context.h"
#include "cdecl.h"
+/** \file
+ * Daemon introspection event subscription subsystem. Use this
+ * to be notified whenever the internal layout of daemon changes:
+ * i.e. entities such as sinks or sources are create, removed or
+ * modified. */
+
PA_C_DECL_BEGIN
+/** Enable event notification */
struct pa_operation* pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
+
+/** Set the context specific call back function that is called whenever the state of the daemon changes */
void pa_context_set_subscribe_callback(struct pa_context *c, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata);
PA_C_DECL_END
#include "polyplib-subscribe.h"
#include "polyplib-scache.h"
+/** \file
+ * Include all polyplib header file at once. The following files are included: \ref mainloop-api.h, \ref sample.h,
+ * \ref polyplib-def.h, \ref polyplib-context.h, \ref polyplib-stream.h,
+ * \ref polyplib-introspect.h, \ref polyplib-subscribe.h and \ref polyplib-scache.h
+ * at once */
+
+/** \mainpage
+ *
+ * \section intro_sec Introduction
+ *
+ * This document describes the client API for the polypaudio sound
+ * server. The API comes in two flavours:
+ *
+ * \li The complete but somewhat complicated to use asynchronous API
+ * \li And the simplified, easy to use, but limited synchronous API
+ *
+ * The polypaudio client libraries are thread safe as long as all
+ * objects created by any library function are accessed from the thread
+ * that created them only.
+ *
+ * \section simple_sec Simple API
+ *
+ * Use this if you develop your program in synchronous style and just
+ * need a way to play or record data on the sound server. See
+ * \ref polyplib-simple.h for more details.
+ *
+ * \section async_api Asynchronous API
+ *
+ * Use this if you develop your programs in asynchronous, main loop
+ * based style or want to use advanced features of the polypaudio
+ * API. A good starting point is \ref polyplib-context.h
+ *
+ * The asynchronous API relies on an abstract main loop API that is
+ * described in \ref mainloop-api.h. Two distinct implementations are
+ * available:
+ *
+ * \li \ref mainloop.h: a minimal but fast implementation based on poll()
+ * \li \ref glib-mainloop.h: a wrapper around GLIB's main loop
+ *
+ * UNIX signals may be hooked to a main loop using the functions from
+ * \ref mainloop-signal.h
+ *
+ * \section pkgconfig pkg-config
+ *
+ * The polypaudio libraries provide pkg-config snippets for the different modules. To use the
+ * asynchronous API use "polyplib" as pkg-config file. GLIB main loop
+ * support is available as "polyplib-glib-mainloop". The simple
+ * synchronous API is available as "polyplib-simple".
+ */
+
#endif
struct pa_mix_info {
struct pa_memchunk chunk;
- uint32_t volume;
+ pa_volume_t volume;
void *userdata;
};
-size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, uint32_t volume);
+size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, pa_volume_t volume);
-void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, uint32_t volume);
+void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, pa_volume_t volume);
#endif
return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels);
}
-void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec) {
+void pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec) {
static const char* const table[]= {
[PA_SAMPLE_U8] = "U8",
[PA_SAMPLE_ALAW] = "ALAW",
snprintf(s, l, "%s %uch %uHz", table[spec->format], spec->channels, spec->rate);
}
-uint32_t pa_volume_multiply(uint32_t a, uint32_t b) {
+pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b) {
uint64_t p = a;
p *= b;
p /= PA_VOLUME_NORM;
- return (uint32_t) p;
+ return (pa_volume_t) p;
}
#include "cdecl.h"
+/** \file
+ * Constants and routines for sample type handling */
+
PA_C_DECL_BEGIN
+/** Sample format */
enum pa_sample_format {
- PA_SAMPLE_U8,
- PA_SAMPLE_ALAW,
- PA_SAMPLE_ULAW,
- PA_SAMPLE_S16LE,
- PA_SAMPLE_S16BE,
- PA_SAMPLE_FLOAT32LE,
- PA_SAMPLE_FLOAT32BE,
- PA_SAMPLE_MAX
+ PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */
+ PA_SAMPLE_ALAW, /**< 8 Bit a-Law */
+ PA_SAMPLE_ULAW, /**< 8 Bit mu-Law */
+ PA_SAMPLE_S16LE, /**< Signed 16 Bit PCM, little endian (PC) */
+ PA_SAMPLE_S16BE, /**< Signed 16 Bit PCM, big endian */
+ PA_SAMPLE_FLOAT32LE, /**< 32 Bit IEEE floating point, little endian, range -1..1 */
+ PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1..1 */
+ PA_SAMPLE_MAX /**< Upper limit of valid sample types */
};
#ifdef WORDS_BIGENDIAN
+/** Signed 16 Bit PCM, native endian */
#define PA_SAMPLE_S16NE PA_SAMPLE_S16BE
+/** 32 Bit IEEE floating point, native endian */
#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE
#else
+/** Signed 16 Bit PCM, native endian */
#define PA_SAMPLE_S16NE PA_SAMPLE_S16LE
+/** 32 Bit IEEE floating point, native endian */
#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE
#endif
+
+/** A Shortcut for PA_SAMPLE_FLOAT32NE */
#define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE
/** A sample format and attribute specification */
uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */
};
+/** Return the amount of bytes playback of a second of audio with the speicified sample type takes */
size_t pa_bytes_per_second(const struct pa_sample_spec *spec);
+
+/** Return the size of a frame with the specific sample type */
size_t pa_frame_size(const struct pa_sample_spec *spec);
+
+/** Calculate the time the specified bytes take to play with the specified sample type */
uint32_t pa_bytes_to_usec(size_t length, const struct pa_sample_spec *spec);
+
+/** Return non-zero when the sample type specification is valid */
int pa_sample_spec_valid(const struct pa_sample_spec *spec);
+
+/** Return non-zero when the two sample type specifications match */
int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b);
+/** Maximum required string length for pa_sample_spec_snprint() */
#define PA_SAMPLE_SNPRINT_MAX_LENGTH 32
-void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec);
+
+/** Pretty print a sample type specification to a string */
+void pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec);
+
+/** Volume specification: 0: silence; < 256: diminished volume; 256: normal volume; > 256 amplified volume */
+typedef uint32_t pa_volume_t;
/** Normal volume (100%) */
#define PA_VOLUME_NORM (0x100)
/** Muted volume (0%) */
-#define PA_VOLUME_MUTE (0)
+#define PA_VOLUME_MUTED (0)
/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */
-uint32_t pa_volume_multiply(uint32_t a, uint32_t b);
+pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b);
PA_C_DECL_END
}
}
-void pa_sink_input_set_volume(struct pa_sink_input *i, uint32_t volume) {
+void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume) {
assert(i && i->sink && i->sink->core);
if (i->volume != volume) {
int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk);
void pa_sink_input_drop(struct pa_sink_input *i, size_t length);
-void pa_sink_input_set_volume(struct pa_sink_input *i, uint32_t volume);
+void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume);
#endif
pa_source_set_owner(sink->monitor_source, m);
}
-void pa_sink_set_volume(struct pa_sink *sink, uint32_t volume) {
+void pa_sink_set_volume(struct pa_sink *sink, pa_volume_t volume) {
assert(sink);
if (sink->volume != volume) {
struct pa_source *monitor_source;
- uint32_t volume;
+ pa_volume_t volume;
void (*notify)(struct pa_sink*sink);
uint32_t (*get_latency)(struct pa_sink *s);
void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m);
-void pa_sink_set_volume(struct pa_sink *sink, uint32_t volume);
+void pa_sink_set_volume(struct pa_sink *sink, pa_volume_t volume);
#endif
--- /dev/null
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: polyplib-glib-mainloop
+Description: GLIB main loop wrapper for polypaudio
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lpolyp-mainloop-glib
+Cflags: -D_REENTRANT -I${includedir}
+Requires: polyplib-mainloop
includedir=${prefix}/include
Name: polyplib-mainloop
-Description: Mainloop API of the polypaudio sound daemon
+Description: Main loop support for polypaudio
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lpolyp-mainloop
Cflags: -D_REENTRANT -I${includedir}
includedir=${prefix}/include
Name: polyplib-simple
-Description: Simplistic client interface to polypaudio sound daemon
+Description: Simplified synchronous client interface to polypaudio
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lpolyp-simple
Cflags: -D_REENTRANT -I${includedir}
+Requires: polyplib polyplib-mainloop polyplib-error
includedir=${prefix}/include
Name: polyplib
-Description: Client interface to polypaudio sound daemon
+Description: Client interface to polypaudio
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lpolyp
Cflags: -D_REENTRANT -I${includedir}
+Requires: polyplib-error polyplib-mainloop