mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-08 13:29:59 -05:00
Merge branch 'master' into dbus-work
Conflicts: src/daemon/daemon-conf.c src/daemon/daemon-conf.h src/daemon/main.c src/pulsecore/dbus-util.h
This commit is contained in:
commit
0bc538b08c
207 changed files with 33341 additions and 18718 deletions
|
|
@ -30,9 +30,11 @@
|
|||
|
||||
#include <pulse/xmalloc.h>
|
||||
#include <pulse/i18n.h>
|
||||
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/macro.h>
|
||||
#include <pulsecore/bitset.h>
|
||||
#include <pulsecore/sample-util.h>
|
||||
|
||||
#include "channelmap.h"
|
||||
|
||||
|
|
@ -491,6 +493,27 @@ char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) {
|
|||
return s;
|
||||
}
|
||||
|
||||
pa_channel_position_t pa_channel_position_from_string(const char *p) {
|
||||
pa_channel_position_t i;
|
||||
pa_assert(p);
|
||||
|
||||
/* Some special aliases */
|
||||
if (pa_streq(p, "left"))
|
||||
return PA_CHANNEL_POSITION_LEFT;
|
||||
else if (pa_streq(p, "right"))
|
||||
return PA_CHANNEL_POSITION_RIGHT;
|
||||
else if (pa_streq(p, "center"))
|
||||
return PA_CHANNEL_POSITION_CENTER;
|
||||
else if (pa_streq(p, "subwoofer"))
|
||||
return PA_CHANNEL_POSITION_SUBWOOFER;
|
||||
|
||||
for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++)
|
||||
if (pa_streq(p, table[i]))
|
||||
return i;
|
||||
|
||||
return PA_CHANNEL_POSITION_INVALID;
|
||||
}
|
||||
|
||||
pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
|
||||
const char *state;
|
||||
pa_channel_map map;
|
||||
|
|
@ -559,36 +582,19 @@ pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
|
|||
map.channels = 0;
|
||||
|
||||
while ((p = pa_split(s, ",", &state))) {
|
||||
pa_channel_position_t f;
|
||||
|
||||
if (map.channels >= PA_CHANNELS_MAX) {
|
||||
pa_xfree(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Some special aliases */
|
||||
if (pa_streq(p, "left"))
|
||||
map.map[map.channels++] = PA_CHANNEL_POSITION_LEFT;
|
||||
else if (pa_streq(p, "right"))
|
||||
map.map[map.channels++] = PA_CHANNEL_POSITION_RIGHT;
|
||||
else if (pa_streq(p, "center"))
|
||||
map.map[map.channels++] = PA_CHANNEL_POSITION_CENTER;
|
||||
else if (pa_streq(p, "subwoofer"))
|
||||
map.map[map.channels++] = PA_CHANNEL_POSITION_SUBWOOFER;
|
||||
else {
|
||||
pa_channel_position_t i;
|
||||
|
||||
for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++)
|
||||
if (strcmp(p, table[i]) == 0) {
|
||||
map.map[map.channels++] = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= PA_CHANNEL_POSITION_MAX) {
|
||||
pa_xfree(p);
|
||||
return NULL;
|
||||
}
|
||||
if ((f = pa_channel_position_from_string(p)) == PA_CHANNEL_POSITION_INVALID) {
|
||||
pa_xfree(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
map.map[map.channels++] = f;
|
||||
pa_xfree(p);
|
||||
}
|
||||
|
||||
|
|
@ -627,8 +633,7 @@ int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *s
|
|||
}
|
||||
|
||||
int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) {
|
||||
pa_bitset_t in_a[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
|
||||
unsigned i;
|
||||
pa_channel_position_mask_t am, bm;
|
||||
|
||||
pa_assert(a);
|
||||
pa_assert(b);
|
||||
|
|
@ -636,98 +641,36 @@ int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) {
|
|||
pa_return_val_if_fail(pa_channel_map_valid(a), 0);
|
||||
pa_return_val_if_fail(pa_channel_map_valid(b), 0);
|
||||
|
||||
memset(in_a, 0, sizeof(in_a));
|
||||
am = pa_channel_map_mask(a);
|
||||
bm = pa_channel_map_mask(b);
|
||||
|
||||
for (i = 0; i < a->channels; i++)
|
||||
pa_bitset_set(in_a, a->map[i], TRUE);
|
||||
|
||||
for (i = 0; i < b->channels; i++)
|
||||
if (!pa_bitset_get(in_a, b->map[i]))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
return (bm & am) == bm;
|
||||
}
|
||||
|
||||
int pa_channel_map_can_balance(const pa_channel_map *map) {
|
||||
unsigned c;
|
||||
pa_bool_t left = FALSE, right = FALSE;
|
||||
pa_channel_position_mask_t m;
|
||||
|
||||
pa_assert(map);
|
||||
|
||||
pa_return_val_if_fail(pa_channel_map_valid(map), 0);
|
||||
|
||||
for (c = 0; c < map->channels; c++) {
|
||||
m = pa_channel_map_mask(map);
|
||||
|
||||
switch (map->map[c]) {
|
||||
case PA_CHANNEL_POSITION_LEFT:
|
||||
case PA_CHANNEL_POSITION_REAR_LEFT:
|
||||
case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
|
||||
case PA_CHANNEL_POSITION_SIDE_LEFT:
|
||||
case PA_CHANNEL_POSITION_TOP_FRONT_LEFT:
|
||||
case PA_CHANNEL_POSITION_TOP_REAR_LEFT:
|
||||
left = TRUE;
|
||||
break;
|
||||
|
||||
case PA_CHANNEL_POSITION_RIGHT:
|
||||
case PA_CHANNEL_POSITION_REAR_RIGHT:
|
||||
case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
|
||||
case PA_CHANNEL_POSITION_SIDE_RIGHT:
|
||||
case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:
|
||||
case PA_CHANNEL_POSITION_TOP_REAR_RIGHT:
|
||||
right = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
if (left && right)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return
|
||||
(PA_CHANNEL_POSITION_MASK_LEFT & m) &&
|
||||
(PA_CHANNEL_POSITION_MASK_RIGHT & m);
|
||||
}
|
||||
|
||||
int pa_channel_map_can_fade(const pa_channel_map *map) {
|
||||
unsigned c;
|
||||
pa_bool_t front = FALSE, rear = FALSE;
|
||||
pa_channel_position_mask_t m;
|
||||
|
||||
pa_assert(map);
|
||||
|
||||
pa_return_val_if_fail(pa_channel_map_valid(map), 0);
|
||||
|
||||
for (c = 0; c < map->channels; c++) {
|
||||
m = pa_channel_map_mask(map);
|
||||
|
||||
switch (map->map[c]) {
|
||||
case PA_CHANNEL_POSITION_FRONT_LEFT:
|
||||
case PA_CHANNEL_POSITION_FRONT_RIGHT:
|
||||
case PA_CHANNEL_POSITION_FRONT_CENTER:
|
||||
case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
|
||||
case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
|
||||
case PA_CHANNEL_POSITION_TOP_FRONT_LEFT:
|
||||
case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:
|
||||
case PA_CHANNEL_POSITION_TOP_FRONT_CENTER:
|
||||
front = TRUE;
|
||||
break;
|
||||
|
||||
case PA_CHANNEL_POSITION_REAR_LEFT:
|
||||
case PA_CHANNEL_POSITION_REAR_RIGHT:
|
||||
case PA_CHANNEL_POSITION_REAR_CENTER:
|
||||
case PA_CHANNEL_POSITION_TOP_REAR_LEFT:
|
||||
case PA_CHANNEL_POSITION_TOP_REAR_RIGHT:
|
||||
case PA_CHANNEL_POSITION_TOP_REAR_CENTER:
|
||||
rear = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
if (front && rear)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return
|
||||
(PA_CHANNEL_POSITION_MASK_FRONT & m) &&
|
||||
(PA_CHANNEL_POSITION_MASK_REAR & m);
|
||||
}
|
||||
|
||||
const char* pa_channel_map_to_name(const pa_channel_map *map) {
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ typedef enum pa_channel_position {
|
|||
typedef uint64_t pa_channel_position_mask_t;
|
||||
|
||||
/** Makes a bit mask from a channel position. \since 0.9.16 */
|
||||
#define PA_CHANNEL_POSITION_MASK(f) ((pa_channel_position_mask_t) (1 << (f)))
|
||||
#define PA_CHANNEL_POSITION_MASK(f) ((pa_channel_position_mask_t) (1ULL << (f)))
|
||||
|
||||
/** A list of channel mapping definitions for pa_channel_map_init_auto() */
|
||||
typedef enum pa_channel_map_def {
|
||||
|
|
@ -282,6 +282,9 @@ pa_channel_map* pa_channel_map_init_extend(pa_channel_map *m, unsigned channels,
|
|||
/** Return a text label for the specified channel position */
|
||||
const char* pa_channel_position_to_string(pa_channel_position_t pos) PA_GCC_PURE;
|
||||
|
||||
/* The inverse of pa_channel_position_to_string(). \since 0.9.16 */
|
||||
pa_channel_position_t pa_channel_position_from_string(const char *s) PA_GCC_PURE;
|
||||
|
||||
/** Return a human readable text label for the specified channel position. \since 0.9.7 */
|
||||
const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos);
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@
|
|||
#include <pulse/utf8.h>
|
||||
#include <pulse/util.h>
|
||||
#include <pulse/i18n.h>
|
||||
#include <pulse/mainloop.h>
|
||||
#include <pulse/timeval.h>
|
||||
|
||||
#include <pulsecore/winsock.h>
|
||||
#include <pulsecore/core-error.h>
|
||||
|
|
@ -64,6 +66,7 @@
|
|||
#include <pulsecore/dynarray.h>
|
||||
#include <pulsecore/socket-client.h>
|
||||
#include <pulsecore/pstream-util.h>
|
||||
#include <pulsecore/core-rtclock.h>
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/log.h>
|
||||
#include <pulsecore/socket-util.h>
|
||||
|
|
@ -157,6 +160,7 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
|
|||
c->playback_streams = pa_dynarray_new();
|
||||
c->record_streams = pa_dynarray_new();
|
||||
c->client_index = PA_INVALID_INDEX;
|
||||
c->use_rtclock = pa_mainloop_is_our_api(mainloop);
|
||||
|
||||
PA_LLIST_HEAD_INIT(pa_stream, c->streams);
|
||||
PA_LLIST_HEAD_INIT(pa_operation, c->operations);
|
||||
|
|
@ -540,7 +544,7 @@ static void setup_context(pa_context *c, pa_iochannel *io) {
|
|||
pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
|
||||
|
||||
pa_assert(!c->pdispatch);
|
||||
c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
|
||||
c->pdispatch = pa_pdispatch_new(c->mainloop, c->use_rtclock, command_table, PA_COMMAND_MAX);
|
||||
|
||||
if (!c->conf->cookie_valid)
|
||||
pa_log_info(_("No cookie loaded. Attempting to connect without."));
|
||||
|
|
@ -757,7 +761,7 @@ static void track_pulseaudio_on_dbus(pa_context *c, DBusBusType type, pa_dbus_wr
|
|||
pa_assert(conn);
|
||||
|
||||
dbus_error_init(&error);
|
||||
if (!(*conn = pa_dbus_wrap_connection_new(c->mainloop, type, &error)) || dbus_error_is_set(&error)) {
|
||||
if (!(*conn = pa_dbus_wrap_connection_new(c->mainloop, c->use_rtclock, type, &error)) || dbus_error_is_set(&error)) {
|
||||
pa_log_warn("Unable to contact DBUS: %s: %s", error.name, error.message);
|
||||
goto finish;
|
||||
}
|
||||
|
|
@ -827,7 +831,7 @@ static int try_next_connection(pa_context *c) {
|
|||
pa_xfree(c->server);
|
||||
c->server = pa_xstrdup(u);
|
||||
|
||||
if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT)))
|
||||
if (!(c->client = pa_socket_client_new_string(c->mainloop, c->use_rtclock, u, PA_NATIVE_DEFAULT_PORT)))
|
||||
continue;
|
||||
|
||||
c->is_local = !!pa_socket_client_is_local(c->client);
|
||||
|
|
@ -1443,3 +1447,31 @@ finish:
|
|||
if (pl)
|
||||
pa_proplist_free(pl);
|
||||
}
|
||||
|
||||
pa_time_event* pa_context_rttime_new(pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata) {
|
||||
struct timeval tv;
|
||||
|
||||
pa_assert(c);
|
||||
pa_assert(c->mainloop);
|
||||
|
||||
if (usec == PA_USEC_INVALID)
|
||||
return c->mainloop->time_new(c->mainloop, NULL, cb, userdata);
|
||||
|
||||
pa_timeval_rtstore(&tv, usec, c->use_rtclock);
|
||||
|
||||
return c->mainloop->time_new(c->mainloop, &tv, cb, userdata);
|
||||
}
|
||||
|
||||
void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec) {
|
||||
struct timeval tv;
|
||||
|
||||
pa_assert(c);
|
||||
pa_assert(c->mainloop);
|
||||
|
||||
if (usec == PA_USEC_INVALID)
|
||||
c->mainloop->time_restart(e, NULL);
|
||||
else {
|
||||
pa_timeval_rtstore(&tv, usec, c->use_rtclock);
|
||||
c->mainloop->time_restart(e, &tv);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -260,6 +260,14 @@ pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[]
|
|||
* introspection functions, such as pa_context_get_client_info(). \since 0.9.11 */
|
||||
uint32_t pa_context_get_index(pa_context *s);
|
||||
|
||||
/** Create a new timer event source for the specified time (wrapper
|
||||
for mainloop->time_new). \since 0.9.16 */
|
||||
pa_time_event* pa_context_rttime_new(pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata);
|
||||
/** Restart a running or expired timer event source (wrapper
|
||||
for mainloop->time_restart). \since 0.9.16 */
|
||||
void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec);
|
||||
|
||||
|
||||
PA_C_DECL_END
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -393,6 +393,7 @@ enum {
|
|||
PA_ERR_OBSOLETE, /**< Obsolete functionality. \since 0.9.15 */
|
||||
PA_ERR_NOTIMPLEMENTED, /**< Missing implementation. \since 0.9.15 */
|
||||
PA_ERR_FORKED, /**< The caller forked without calling execve() and tried to reuse the context. \since 0.9.15 */
|
||||
PA_ERR_IO, /**< An IO error happened. \since 0.9.16 */
|
||||
PA_ERR_MAX /**< Not really an error but the first invalid error code */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ struct pa_context {
|
|||
pa_bool_t server_specified:1;
|
||||
pa_bool_t no_fail:1;
|
||||
pa_bool_t do_autospawn:1;
|
||||
pa_bool_t use_rtclock:1;
|
||||
pa_spawn_api spawn_api;
|
||||
|
||||
pa_strlist *server_list;
|
||||
|
|
@ -279,4 +280,6 @@ pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *ta
|
|||
|
||||
void pa_ext_stream_restore_command(pa_context *c, uint32_t tag, pa_tagstruct *t);
|
||||
|
||||
pa_bool_t pa_mainloop_is_our_api(pa_mainloop_api*m);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ static void context_stat_callback(pa_pdispatch *pd, uint32_t command, uint32_t t
|
|||
pa_assert(o);
|
||||
pa_assert(PA_REFCNT_VALUE(o) >= 1);
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
pa_zero(i);
|
||||
|
||||
if (!o->context)
|
||||
goto finish;
|
||||
|
|
@ -93,7 +93,7 @@ static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command,
|
|||
pa_assert(o);
|
||||
pa_assert(PA_REFCNT_VALUE(o) >= 1);
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
pa_zero(i);
|
||||
|
||||
if (!o->context)
|
||||
goto finish;
|
||||
|
|
@ -161,8 +161,10 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, u
|
|||
pa_bool_t mute;
|
||||
uint32_t flags;
|
||||
uint32_t state;
|
||||
uint32_t j;
|
||||
const char *ap = NULL;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
pa_zero(i);
|
||||
i.proplist = pa_proplist_new();
|
||||
i.base_volume = PA_VOLUME_NORM;
|
||||
i.n_volume_steps = PA_VOLUME_NORM+1;
|
||||
|
|
@ -190,13 +192,53 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, u
|
|||
(pa_tagstruct_get_volume(t, &i.base_volume) < 0 ||
|
||||
pa_tagstruct_getu32(t, &state) < 0 ||
|
||||
pa_tagstruct_getu32(t, &i.n_volume_steps) < 0 ||
|
||||
pa_tagstruct_getu32(t, &i.card) < 0))) {
|
||||
pa_tagstruct_getu32(t, &i.card) < 0)) ||
|
||||
(o->context->version >= 16 &&
|
||||
(pa_tagstruct_getu32(t, &i.n_ports)))) {
|
||||
|
||||
pa_context_fail(o->context, PA_ERR_PROTOCOL);
|
||||
pa_proplist_free(i.proplist);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (i.n_ports > 0) {
|
||||
i.ports = pa_xnew(pa_sink_port_info*, i.n_ports+1);
|
||||
i.ports[0] = pa_xnew(pa_sink_port_info, i.n_ports);
|
||||
|
||||
for (j = 0; j < i.n_ports; j++) {
|
||||
if (pa_tagstruct_gets(t, &i.ports[0][j].name) < 0 ||
|
||||
pa_tagstruct_gets(t, &i.ports[0][j].description) < 0 ||
|
||||
pa_tagstruct_getu32(t, &i.ports[0][j].priority) < 0) {
|
||||
|
||||
pa_context_fail(o->context, PA_ERR_PROTOCOL);
|
||||
pa_xfree(i.ports);
|
||||
pa_xfree(i.ports[0]);
|
||||
pa_proplist_free(i.proplist);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
i.ports[j] = &i.ports[0][j];
|
||||
}
|
||||
|
||||
i.ports[j] = NULL;
|
||||
}
|
||||
|
||||
if (pa_tagstruct_gets(t, &ap) < 0) {
|
||||
pa_context_fail(o->context, PA_ERR_PROTOCOL);
|
||||
pa_xfree(i.ports[0]);
|
||||
pa_xfree(i.ports);
|
||||
pa_proplist_free(i.proplist);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (ap) {
|
||||
for (j = 0; j < i.n_ports; j++)
|
||||
if (pa_streq(i.ports[j]->name, ap)) {
|
||||
i.active_port = i.ports[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i.mute = (int) mute;
|
||||
i.flags = (pa_sink_flags_t) flags;
|
||||
i.state = (pa_sink_state_t) state;
|
||||
|
|
@ -271,6 +313,56 @@ pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name,
|
|||
return o;
|
||||
}
|
||||
|
||||
pa_operation* pa_context_set_sink_port_by_index(pa_context *c, uint32_t idx, const char*port, pa_context_success_cb_t cb, void *userdata) {
|
||||
pa_operation *o;
|
||||
pa_tagstruct *t;
|
||||
uint32_t tag;
|
||||
|
||||
pa_assert(c);
|
||||
pa_assert(PA_REFCNT_VALUE(c) >= 1);
|
||||
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 16, PA_ERR_NOTSUPPORTED);
|
||||
|
||||
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
|
||||
|
||||
t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_PORT, &tag);
|
||||
pa_tagstruct_putu32(t, idx);
|
||||
pa_tagstruct_puts(t, NULL);
|
||||
pa_tagstruct_puts(t, port);
|
||||
pa_pstream_send_tagstruct(c->pstream, t);
|
||||
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
pa_operation* pa_context_set_sink_port_by_name(pa_context *c, const char *name, const char*port, pa_context_success_cb_t cb, void *userdata) {
|
||||
pa_operation *o;
|
||||
pa_tagstruct *t;
|
||||
uint32_t tag;
|
||||
|
||||
pa_assert(c);
|
||||
pa_assert(PA_REFCNT_VALUE(c) >= 1);
|
||||
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID);
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 16, PA_ERR_NOTSUPPORTED);
|
||||
|
||||
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
|
||||
|
||||
t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_PORT, &tag);
|
||||
pa_tagstruct_putu32(t, PA_INVALID_INDEX);
|
||||
pa_tagstruct_puts(t, name);
|
||||
pa_tagstruct_puts(t, port);
|
||||
pa_pstream_send_tagstruct(c->pstream, t);
|
||||
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
/*** Source info ***/
|
||||
|
||||
static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
|
||||
|
|
@ -296,8 +388,10 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command,
|
|||
pa_bool_t mute;
|
||||
uint32_t flags;
|
||||
uint32_t state;
|
||||
unsigned j;
|
||||
const char *ap;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
pa_zero(i);
|
||||
i.proplist = pa_proplist_new();
|
||||
i.base_volume = PA_VOLUME_NORM;
|
||||
i.n_volume_steps = PA_VOLUME_NORM+1;
|
||||
|
|
@ -325,13 +419,53 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command,
|
|||
(pa_tagstruct_get_volume(t, &i.base_volume) < 0 ||
|
||||
pa_tagstruct_getu32(t, &state) < 0 ||
|
||||
pa_tagstruct_getu32(t, &i.n_volume_steps) < 0 ||
|
||||
pa_tagstruct_getu32(t, &i.card) < 0))) {
|
||||
pa_tagstruct_getu32(t, &i.card) < 0)) ||
|
||||
(o->context->version >= 16 &&
|
||||
(pa_tagstruct_getu32(t, &i.n_ports)))) {
|
||||
|
||||
pa_context_fail(o->context, PA_ERR_PROTOCOL);
|
||||
pa_proplist_free(i.proplist);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (i.n_ports > 0) {
|
||||
i.ports = pa_xnew(pa_source_port_info*, i.n_ports+1);
|
||||
i.ports[0] = pa_xnew(pa_source_port_info, i.n_ports);
|
||||
|
||||
for (j = 0; j < i.n_ports; j++) {
|
||||
if (pa_tagstruct_gets(t, &i.ports[0][j].name) < 0 ||
|
||||
pa_tagstruct_gets(t, &i.ports[0][j].description) < 0 ||
|
||||
pa_tagstruct_getu32(t, &i.ports[0][j].priority) < 0) {
|
||||
|
||||
pa_context_fail(o->context, PA_ERR_PROTOCOL);
|
||||
pa_xfree(i.ports[0]);
|
||||
pa_xfree(i.ports);
|
||||
pa_proplist_free(i.proplist);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
i.ports[j] = &i.ports[0][j];
|
||||
}
|
||||
|
||||
i.ports[j] = NULL;
|
||||
}
|
||||
|
||||
if (pa_tagstruct_gets(t, &ap) < 0) {
|
||||
pa_context_fail(o->context, PA_ERR_PROTOCOL);
|
||||
pa_xfree(i.ports[0]);
|
||||
pa_xfree(i.ports);
|
||||
pa_proplist_free(i.proplist);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (ap) {
|
||||
for (j = 0; j < i.n_ports; j++)
|
||||
if (pa_streq(i.ports[j]->name, ap)) {
|
||||
i.active_port = i.ports[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i.mute = (int) mute;
|
||||
i.flags = (pa_source_flags_t) flags;
|
||||
i.state = (pa_source_state_t) state;
|
||||
|
|
@ -406,6 +540,56 @@ pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name
|
|||
return o;
|
||||
}
|
||||
|
||||
pa_operation* pa_context_set_source_port_by_index(pa_context *c, uint32_t idx, const char*port, pa_context_success_cb_t cb, void *userdata) {
|
||||
pa_operation *o;
|
||||
pa_tagstruct *t;
|
||||
uint32_t tag;
|
||||
|
||||
pa_assert(c);
|
||||
pa_assert(PA_REFCNT_VALUE(c) >= 1);
|
||||
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 16, PA_ERR_NOTSUPPORTED);
|
||||
|
||||
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
|
||||
|
||||
t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_PORT, &tag);
|
||||
pa_tagstruct_putu32(t, idx);
|
||||
pa_tagstruct_puts(t, NULL);
|
||||
pa_tagstruct_puts(t, port);
|
||||
pa_pstream_send_tagstruct(c->pstream, t);
|
||||
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
pa_operation* pa_context_set_source_port_by_name(pa_context *c, const char *name, const char*port, pa_context_success_cb_t cb, void *userdata) {
|
||||
pa_operation *o;
|
||||
pa_tagstruct *t;
|
||||
uint32_t tag;
|
||||
|
||||
pa_assert(c);
|
||||
pa_assert(PA_REFCNT_VALUE(c) >= 1);
|
||||
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID);
|
||||
PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 16, PA_ERR_NOTSUPPORTED);
|
||||
|
||||
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
|
||||
|
||||
t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_PORT, &tag);
|
||||
pa_tagstruct_putu32(t, PA_INVALID_INDEX);
|
||||
pa_tagstruct_puts(t, name);
|
||||
pa_tagstruct_puts(t, port);
|
||||
pa_pstream_send_tagstruct(c->pstream, t);
|
||||
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
/*** Client info ***/
|
||||
|
||||
static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
|
||||
|
|
@ -429,7 +613,7 @@ static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command,
|
|||
while (!pa_tagstruct_eof(t)) {
|
||||
pa_client_info i;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
pa_zero(i);
|
||||
i.proplist = pa_proplist_new();
|
||||
|
||||
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
|
||||
|
|
@ -514,7 +698,7 @@ static void context_get_card_info_callback(pa_pdispatch *pd, uint32_t command, u
|
|||
uint32_t j;
|
||||
const char*ap;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
pa_zero(i);
|
||||
|
||||
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
|
||||
pa_tagstruct_gets(t, &i.name) < 0 ||
|
||||
|
|
@ -527,7 +711,7 @@ static void context_get_card_info_callback(pa_pdispatch *pd, uint32_t command, u
|
|||
}
|
||||
|
||||
if (i.n_profiles > 0) {
|
||||
i.profiles = pa_xnew(pa_card_profile_info, i.n_profiles+1);
|
||||
i.profiles = pa_xnew0(pa_card_profile_info, i.n_profiles+1);
|
||||
|
||||
for (j = 0; j < i.n_profiles; j++) {
|
||||
|
||||
|
|
@ -715,7 +899,7 @@ static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command,
|
|||
pa_module_info i;
|
||||
pa_bool_t auto_unload = FALSE;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
pa_zero(i);
|
||||
i.proplist = pa_proplist_new();
|
||||
|
||||
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
|
||||
|
|
@ -800,7 +984,7 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm
|
|||
pa_sink_input_info i;
|
||||
pa_bool_t mute = FALSE;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
pa_zero(i);
|
||||
i.proplist = pa_proplist_new();
|
||||
|
||||
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
|
||||
|
|
@ -894,7 +1078,7 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c
|
|||
while (!pa_tagstruct_eof(t)) {
|
||||
pa_source_output_info i;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
pa_zero(i);
|
||||
i.proplist = pa_proplist_new();
|
||||
|
||||
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
|
||||
|
|
@ -1236,7 +1420,7 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command,
|
|||
pa_sample_info i;
|
||||
pa_bool_t lazy = FALSE;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
pa_zero(i);
|
||||
i.proplist = pa_proplist_new();
|
||||
|
||||
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
|
||||
|
|
|
|||
|
|
@ -193,6 +193,15 @@ PA_C_DECL_BEGIN
|
|||
|
||||
/** @{ \name Sinks */
|
||||
|
||||
/** Stores information about a specific port of a sink. Please
|
||||
* note that this structure can be extended as part of evolutionary
|
||||
* API updates at any time in any new release. \since 0.9.16 */
|
||||
typedef struct pa_sink_port_info {
|
||||
const char *name; /**< Name of this port */
|
||||
const char *description; /**< Description of this port */
|
||||
uint32_t priority; /**< The higher this value is the more useful this port is as a default */
|
||||
} pa_sink_port_info;
|
||||
|
||||
/** Stores information about sinks. Please note that this structure
|
||||
* can be extended as part of evolutionary API updates at any time in
|
||||
* any new release. */
|
||||
|
|
@ -216,6 +225,9 @@ typedef struct pa_sink_info {
|
|||
pa_sink_state_t state; /**< State \since 0.9.15 */
|
||||
uint32_t n_volume_steps; /**< Number of volume steps for sinks which do not support arbitrary volumes. \since 0.9.15 */
|
||||
uint32_t card; /**< Card index, or PA_INVALID_INDEX. \since 0.9.15 */
|
||||
uint32_t n_ports; /**< Number of entries in port array \since 0.9.16 */
|
||||
pa_sink_port_info** ports; /**< Array of available ports, or NULL. Array is terminated by an entry set to NULL. The number of entries is stored in n_ports \since 0.9.16 */
|
||||
pa_sink_port_info* active_port; /**< Pointer to active port in the array, or NULL \since 0.9.16 */
|
||||
} pa_sink_info;
|
||||
|
||||
/** Callback prototype for pa_context_get_sink_info_by_name() and friends */
|
||||
|
|
@ -248,10 +260,25 @@ pa_operation* pa_context_suspend_sink_by_name(pa_context *c, const char *sink_na
|
|||
/** Suspend/Resume a sink. If idx is PA_INVALID_INDEX all sinks will be suspended. \since 0.9.7 */
|
||||
pa_operation* pa_context_suspend_sink_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata);
|
||||
|
||||
/** Change the profile of a sink. \since 0.9.16 */
|
||||
pa_operation* pa_context_set_sink_port_by_index(pa_context *c, uint32_t idx, const char*port, pa_context_success_cb_t cb, void *userdata);
|
||||
|
||||
/** Change the profile of a sink. \since 0.9.15 */
|
||||
pa_operation* pa_context_set_sink_port_by_name(pa_context *c, const char*name, const char*port, pa_context_success_cb_t cb, void *userdata);
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @{ \name Sources */
|
||||
|
||||
/** Stores information about a specific port of a source. Please
|
||||
* note that this structure can be extended as part of evolutionary
|
||||
* API updates at any time in any new release. \since 0.9.16 */
|
||||
typedef struct pa_source_port_info {
|
||||
const char *name; /**< Name of this port */
|
||||
const char *description; /**< Description of this port */
|
||||
uint32_t priority; /**< The higher this value is the more useful this port is as a default */
|
||||
} pa_source_port_info;
|
||||
|
||||
/** Stores information about sources. Please note that this structure
|
||||
* can be extended as part of evolutionary API updates at any time in
|
||||
* any new release. */
|
||||
|
|
@ -275,6 +302,9 @@ typedef struct pa_source_info {
|
|||
pa_source_state_t state; /**< State \since 0.9.15 */
|
||||
uint32_t n_volume_steps; /**< Number of volume steps for sources which do not support arbitrary volumes. \since 0.9.15 */
|
||||
uint32_t card; /**< Card index, or PA_INVALID_INDEX. \since 0.9.15 */
|
||||
uint32_t n_ports; /**< Number of entries in port array \since 0.9.16 */
|
||||
pa_source_port_info** ports; /**< Array of available ports, or NULL. Array is terminated by an entry set to NULL. The number of entries is stored in n_ports \since 0.9.16 */
|
||||
pa_source_port_info* active_port; /**< Pointer to active port in the array, or NULL \since 0.9.16 */
|
||||
} pa_source_info;
|
||||
|
||||
/** Callback prototype for pa_context_get_source_info_by_name() and friends */
|
||||
|
|
@ -301,6 +331,12 @@ pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, i
|
|||
/** Set the mute switch of a source device specified by its name */
|
||||
pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata);
|
||||
|
||||
/** Change the profile of a source. \since 0.9.16 */
|
||||
pa_operation* pa_context_set_source_port_by_index(pa_context *c, uint32_t idx, const char*port, pa_context_success_cb_t cb, void *userdata);
|
||||
|
||||
/** Change the profile of a source. \since 0.9.15 */
|
||||
pa_operation* pa_context_set_source_port_by_name(pa_context *c, const char*name, const char*port, pa_context_success_cb_t cb, void *userdata);
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @{ \name Server */
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <time.h>
|
||||
|
||||
#include <pulse/cdecl.h>
|
||||
#include <pulse/sample.h>
|
||||
#include <pulse/version.h>
|
||||
|
||||
/** \file
|
||||
|
|
|
|||
|
|
@ -42,10 +42,12 @@
|
|||
#include <pulsecore/pipe.h>
|
||||
#endif
|
||||
|
||||
#include <pulse/i18n.h>
|
||||
#include <pulse/rtclock.h>
|
||||
#include <pulse/timeval.h>
|
||||
#include <pulse/xmalloc.h>
|
||||
#include <pulse/i18n.h>
|
||||
|
||||
#include <pulsecore/core-rtclock.h>
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/llist.h>
|
||||
#include <pulsecore/log.h>
|
||||
|
|
@ -54,6 +56,7 @@
|
|||
#include <pulsecore/macro.h>
|
||||
|
||||
#include "mainloop.h"
|
||||
#include "internal.h"
|
||||
|
||||
struct pa_io_event {
|
||||
pa_mainloop *mainloop;
|
||||
|
|
@ -75,7 +78,7 @@ struct pa_time_event {
|
|||
pa_bool_t dead:1;
|
||||
|
||||
pa_bool_t enabled:1;
|
||||
struct timeval timeval;
|
||||
pa_usec_t time;
|
||||
|
||||
pa_time_event_cb_t callback;
|
||||
void *userdata;
|
||||
|
|
@ -317,6 +320,23 @@ static void mainloop_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy
|
|||
}
|
||||
|
||||
/* Time events */
|
||||
static pa_usec_t timeval_load(const struct timeval *tv) {
|
||||
pa_bool_t is_rtclock;
|
||||
struct timeval ttv;
|
||||
|
||||
if (!tv)
|
||||
return PA_USEC_INVALID;
|
||||
|
||||
ttv = *tv;
|
||||
is_rtclock = !!(ttv.tv_usec & PA_TIMEVAL_RTCLOCK);
|
||||
ttv.tv_usec &= ~PA_TIMEVAL_RTCLOCK;
|
||||
|
||||
if (!is_rtclock)
|
||||
pa_rtclock_from_wallclock(&ttv);
|
||||
|
||||
return pa_timeval_load(&ttv);
|
||||
}
|
||||
|
||||
static pa_time_event* mainloop_time_new(
|
||||
pa_mainloop_api*a,
|
||||
const struct timeval *tv,
|
||||
|
|
@ -325,11 +345,14 @@ static pa_time_event* mainloop_time_new(
|
|||
|
||||
pa_mainloop *m;
|
||||
pa_time_event *e;
|
||||
pa_usec_t t;
|
||||
|
||||
pa_assert(a);
|
||||
pa_assert(a->userdata);
|
||||
pa_assert(callback);
|
||||
|
||||
t = timeval_load(tv);
|
||||
|
||||
m = a->userdata;
|
||||
pa_assert(a == &m->api);
|
||||
|
||||
|
|
@ -337,15 +360,15 @@ static pa_time_event* mainloop_time_new(
|
|||
e->mainloop = m;
|
||||
e->dead = FALSE;
|
||||
|
||||
if ((e->enabled = !!tv)) {
|
||||
e->timeval = *tv;
|
||||
if ((e->enabled = (t != PA_USEC_INVALID))) {
|
||||
e->time = t;
|
||||
|
||||
m->n_enabled_time_events++;
|
||||
|
||||
if (m->cached_next_time_event) {
|
||||
pa_assert(m->cached_next_time_event->enabled);
|
||||
|
||||
if (pa_timeval_cmp(tv, &m->cached_next_time_event->timeval) < 0)
|
||||
if (t < m->cached_next_time_event->time)
|
||||
m->cached_next_time_event = e;
|
||||
}
|
||||
}
|
||||
|
|
@ -363,24 +386,30 @@ static pa_time_event* mainloop_time_new(
|
|||
}
|
||||
|
||||
static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) {
|
||||
pa_bool_t valid;
|
||||
pa_usec_t t;
|
||||
|
||||
pa_assert(e);
|
||||
pa_assert(!e->dead);
|
||||
|
||||
if (e->enabled && !tv) {
|
||||
t = timeval_load(tv);
|
||||
|
||||
valid = (t != PA_USEC_INVALID);
|
||||
if (e->enabled && !valid) {
|
||||
pa_assert(e->mainloop->n_enabled_time_events > 0);
|
||||
e->mainloop->n_enabled_time_events--;
|
||||
} else if (!e->enabled && tv)
|
||||
} else if (!e->enabled && valid)
|
||||
e->mainloop->n_enabled_time_events++;
|
||||
|
||||
if ((e->enabled = !!tv)) {
|
||||
e->timeval = *tv;
|
||||
if ((e->enabled = valid)) {
|
||||
e->time = t;
|
||||
pa_mainloop_wakeup(e->mainloop);
|
||||
}
|
||||
|
||||
if (e->mainloop->cached_next_time_event && e->enabled) {
|
||||
pa_assert(e->mainloop->cached_next_time_event->enabled);
|
||||
|
||||
if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0)
|
||||
if (t < e->mainloop->cached_next_time_event->time)
|
||||
e->mainloop->cached_next_time_event = e;
|
||||
} else if (e->mainloop->cached_next_time_event == e)
|
||||
e->mainloop->cached_next_time_event = NULL;
|
||||
|
|
@ -428,10 +457,10 @@ static void mainloop_quit(pa_mainloop_api*a, int retval) {
|
|||
static const pa_mainloop_api vtable = {
|
||||
.userdata = NULL,
|
||||
|
||||
.io_new= mainloop_io_new,
|
||||
.io_enable= mainloop_io_enable,
|
||||
.io_free= mainloop_io_free,
|
||||
.io_set_destroy= mainloop_io_set_destroy,
|
||||
.io_new = mainloop_io_new,
|
||||
.io_enable = mainloop_io_enable,
|
||||
.io_free = mainloop_io_free,
|
||||
.io_set_destroy = mainloop_io_set_destroy,
|
||||
|
||||
.time_new = mainloop_time_new,
|
||||
.time_restart = mainloop_time_restart,
|
||||
|
|
@ -721,11 +750,11 @@ static pa_time_event* find_next_time_event(pa_mainloop *m) {
|
|||
if (t->dead || !t->enabled)
|
||||
continue;
|
||||
|
||||
if (!n || pa_timeval_cmp(&t->timeval, &n->timeval) < 0) {
|
||||
if (!n || t->time < n->time) {
|
||||
n = t;
|
||||
|
||||
/* Shortcut for tv = { 0, 0 } */
|
||||
if (n->timeval.tv_sec <= 0)
|
||||
/* Shortcut for time == 0 */
|
||||
if (n->time == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -736,7 +765,6 @@ static pa_time_event* find_next_time_event(pa_mainloop *m) {
|
|||
|
||||
static int calc_next_timeout(pa_mainloop *m) {
|
||||
pa_time_event *t;
|
||||
struct timeval now;
|
||||
pa_usec_t usec;
|
||||
|
||||
if (!m->n_enabled_time_events)
|
||||
|
|
@ -745,41 +773,41 @@ static int calc_next_timeout(pa_mainloop *m) {
|
|||
t = find_next_time_event(m);
|
||||
pa_assert(t);
|
||||
|
||||
if (t->timeval.tv_sec <= 0)
|
||||
if (t->time == 0)
|
||||
return 0;
|
||||
|
||||
pa_gettimeofday(&now);
|
||||
usec = t->time - pa_rtclock_now();
|
||||
|
||||
if (pa_timeval_cmp(&t->timeval, &now) <= 0)
|
||||
if (usec <= 0)
|
||||
return 0;
|
||||
|
||||
usec = pa_timeval_diff(&t->timeval, &now);
|
||||
return (int) (usec / 1000);
|
||||
return (int) (usec / 1000); /* in milliseconds */
|
||||
}
|
||||
|
||||
static int dispatch_timeout(pa_mainloop *m) {
|
||||
pa_time_event *e;
|
||||
struct timeval now;
|
||||
pa_usec_t now;
|
||||
int r = 0;
|
||||
pa_assert(m);
|
||||
|
||||
if (m->n_enabled_time_events <= 0)
|
||||
return 0;
|
||||
|
||||
pa_gettimeofday(&now);
|
||||
now = pa_rtclock_now();
|
||||
|
||||
for (e = m->time_events; e && !m->quit; e = e->next) {
|
||||
|
||||
if (e->dead || !e->enabled)
|
||||
continue;
|
||||
|
||||
if (pa_timeval_cmp(&e->timeval, &now) <= 0) {
|
||||
if (e->time <= now) {
|
||||
struct timeval tv;
|
||||
pa_assert(e->callback);
|
||||
|
||||
/* Disable time event */
|
||||
mainloop_time_restart(e, NULL);
|
||||
|
||||
e->callback(&m->api, e, &e->timeval, e->userdata);
|
||||
e->callback(&m->api, e, pa_timeval_rtstore(&tv, e->time, TRUE), e->userdata);
|
||||
|
||||
r++;
|
||||
}
|
||||
|
|
@ -967,3 +995,9 @@ void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *use
|
|||
m->poll_func = poll_func;
|
||||
m->poll_func_userdata = userdata;
|
||||
}
|
||||
|
||||
pa_bool_t pa_mainloop_is_our_api(pa_mainloop_api*m) {
|
||||
pa_assert(m);
|
||||
|
||||
return m->io_new == mainloop_io_new;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,6 +206,9 @@ PA_C_DECL_BEGIN
|
|||
/** For devices: profile identifier for the profile this devices is in. e.g. "analog-stereo", "analog-surround-40", "iec958-stereo", ...*/
|
||||
#define PA_PROP_DEVICE_PROFILE_NAME "device.profile.name"
|
||||
|
||||
/** For devices: intended use. A comma seperated list of roles (see PA_PROP_MEDIA_ROLE) this device is particularly well suited for, due to latency, quality or form factor. \since 0.9.16 */
|
||||
#define PA_PROP_DEVICE_INTENDED_ROLES "device.intended_roles"
|
||||
|
||||
/** For devices: human readable one-line description of the profile this device is in. e.g. "Analog Stereo", ... */
|
||||
#define PA_PROP_DEVICE_PROFILE_DESCRIPTION "device.profile.description"
|
||||
|
||||
|
|
|
|||
35
src/pulse/rtclock.c
Normal file
35
src/pulse/rtclock.c
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/***
|
||||
This file is part of PulseAudio.
|
||||
|
||||
Copyright 2004-2006 Lennart Poettering
|
||||
|
||||
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 <pulsecore/core-rtclock.h>
|
||||
|
||||
#include "rtclock.h"
|
||||
#include "timeval.h"
|
||||
|
||||
pa_usec_t pa_rtclock_now(void) {
|
||||
struct timeval tv;
|
||||
|
||||
return pa_timeval_load(pa_rtclock_get(&tv));
|
||||
}
|
||||
41
src/pulse/rtclock.h
Normal file
41
src/pulse/rtclock.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef foortclockfoo
|
||||
#define foortclockfoo
|
||||
|
||||
/***
|
||||
This file is part of PulseAudio.
|
||||
|
||||
Copyright 2004-2009 Lennart Poettering
|
||||
|
||||
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 <pulse/cdecl.h>
|
||||
#include <pulse/def.h>
|
||||
#include <pulse/gccmacro.h>
|
||||
|
||||
/** \file
|
||||
* Monotonic clock utilities. */
|
||||
|
||||
PA_C_DECL_BEGIN
|
||||
|
||||
/** Return the current monotonic system time in usec, if such a clock
|
||||
* is available. If it is not available this will return the
|
||||
* wallclock time instead. \since 0.9.16 */
|
||||
pa_usec_t pa_rtclock_now(void);
|
||||
|
||||
PA_C_DECL_END
|
||||
|
||||
#endif
|
||||
|
|
@ -30,13 +30,14 @@
|
|||
|
||||
#include <pulse/def.h>
|
||||
#include <pulse/timeval.h>
|
||||
#include <pulse/rtclock.h>
|
||||
#include <pulse/xmalloc.h>
|
||||
|
||||
#include <pulsecore/pstream-util.h>
|
||||
#include <pulsecore/log.h>
|
||||
#include <pulsecore/hashmap.h>
|
||||
#include <pulsecore/macro.h>
|
||||
#include <pulsecore/rtclock.h>
|
||||
#include <pulsecore/core-rtclock.h>
|
||||
|
||||
#include "fork-detect.h"
|
||||
#include "internal.h"
|
||||
|
|
@ -319,14 +320,10 @@ static void request_auto_timing_update(pa_stream *s, pa_bool_t force) {
|
|||
}
|
||||
|
||||
if (s->auto_timing_update_event) {
|
||||
struct timeval next;
|
||||
|
||||
if (force)
|
||||
s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC;
|
||||
|
||||
pa_gettimeofday(&next);
|
||||
pa_timeval_add(&next, s->auto_timing_interval_usec);
|
||||
s->mainloop->time_restart(s->auto_timing_update_event, &next);
|
||||
pa_context_rttime_restart(s->context, s->auto_timing_update_event, pa_rtclock_now() + s->auto_timing_interval_usec);
|
||||
|
||||
s->auto_timing_interval_usec = PA_MIN(AUTO_TIMING_INTERVAL_END_USEC, s->auto_timing_interval_usec*2);
|
||||
}
|
||||
|
|
@ -373,7 +370,7 @@ static void check_smoother_status(pa_stream *s, pa_bool_t aposteriori, pa_bool_t
|
|||
if (!s->smoother)
|
||||
return;
|
||||
|
||||
x = pa_rtclock_usec();
|
||||
x = pa_rtclock_now();
|
||||
|
||||
if (s->timing_info_valid) {
|
||||
if (aposteriori)
|
||||
|
|
@ -800,7 +797,7 @@ static void invalidate_indexes(pa_stream *s, pa_bool_t r, pa_bool_t w) {
|
|||
request_auto_timing_update(s, TRUE);
|
||||
}
|
||||
|
||||
static void auto_timing_update_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *tv, void *userdata) {
|
||||
static void auto_timing_update_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
|
||||
pa_stream *s = userdata;
|
||||
|
||||
pa_assert(s);
|
||||
|
|
@ -822,12 +819,9 @@ static void create_stream_complete(pa_stream *s) {
|
|||
s->write_callback(s, (size_t) s->requested_bytes, s->write_userdata);
|
||||
|
||||
if (s->flags & PA_STREAM_AUTO_TIMING_UPDATE) {
|
||||
struct timeval tv;
|
||||
pa_gettimeofday(&tv);
|
||||
s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC;
|
||||
pa_timeval_add(&tv, s->auto_timing_interval_usec);
|
||||
pa_assert(!s->auto_timing_update_event);
|
||||
s->auto_timing_update_event = s->mainloop->time_new(s->mainloop, &tv, &auto_timing_update_callback, s);
|
||||
s->auto_timing_update_event = pa_context_rttime_new(s->context, pa_rtclock_now() + s->auto_timing_interval_usec, &auto_timing_update_callback, s);
|
||||
|
||||
request_auto_timing_update(s, TRUE);
|
||||
}
|
||||
|
|
@ -1057,7 +1051,7 @@ static int create_stream(
|
|||
if (flags & PA_STREAM_INTERPOLATE_TIMING) {
|
||||
pa_usec_t x;
|
||||
|
||||
x = pa_rtclock_usec();
|
||||
x = pa_rtclock_now();
|
||||
|
||||
pa_assert(!s->smoother);
|
||||
s->smoother = pa_smoother_new(
|
||||
|
|
@ -1594,7 +1588,7 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command,
|
|||
if (o->stream->smoother) {
|
||||
pa_usec_t u, x;
|
||||
|
||||
u = x = pa_rtclock_usec() - i->transport_usec;
|
||||
u = x = pa_rtclock_now() - i->transport_usec;
|
||||
|
||||
if (o->stream->direction == PA_STREAM_PLAYBACK && o->context->version >= 13) {
|
||||
pa_usec_t su;
|
||||
|
|
@ -2103,7 +2097,7 @@ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) {
|
|||
PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.write_index_corrupt, PA_ERR_NODATA);
|
||||
|
||||
if (s->smoother)
|
||||
usec = pa_smoother_get(s->smoother, pa_rtclock_usec());
|
||||
usec = pa_smoother_get(s->smoother, pa_rtclock_now());
|
||||
else
|
||||
usec = calc_time(s, FALSE);
|
||||
|
||||
|
|
|
|||
|
|
@ -40,16 +40,19 @@ PA_C_DECL_BEGIN
|
|||
#define PA_USEC_PER_SEC ((pa_usec_t) 1000000ULL)
|
||||
|
||||
/** The number of nanoseconds in a second */
|
||||
#define PA_NSEC_PER_SEC ((pa_usec_t) 1000000000ULL)
|
||||
#define PA_NSEC_PER_SEC ((unsigned long long) 1000000000ULL)
|
||||
|
||||
/** The number of microseconds in a millisecond */
|
||||
#define PA_USEC_PER_MSEC ((pa_usec_t) 1000ULL)
|
||||
|
||||
/** The number of nanoseconds in a millisecond */
|
||||
#define PA_NSEC_PER_MSEC ((pa_usec_t) 1000000ULL)
|
||||
#define PA_NSEC_PER_MSEC ((unsigned long long) 1000000ULL)
|
||||
|
||||
/** The number of nanoseconds in a microsecond */
|
||||
#define PA_NSEC_PER_USEC ((pa_usec_t) 1000ULL)
|
||||
#define PA_NSEC_PER_USEC ((unsigned long long) 1000ULL)
|
||||
|
||||
/** Invalid time in usec */
|
||||
#define PA_USEC_INVALID ((pa_usec_t) -1)
|
||||
|
||||
struct timeval;
|
||||
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ const char* pa_get_library_version(void);
|
|||
* newer than the specified. \since 0.9.16 */
|
||||
#define PA_CHECK_VERSION(major,minor,micro) \
|
||||
((PA_MAJOR > (major)) || \
|
||||
(PA_MAJOR == (major) && CA_MINOR > (minor)) || \
|
||||
(PA_MAJOR == (major) && CA_MINOR == (minor) && CA_MICRO >= (micro)))
|
||||
(PA_MAJOR == (major) && PA_MINOR > (minor)) || \
|
||||
(PA_MAJOR == (major) && PA_MINOR == (minor) && PA_MICRO >= (micro)))
|
||||
|
||||
PA_C_DECL_END
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,10 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <pulse/i18n.h>
|
||||
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/macro.h>
|
||||
#include <pulsecore/sample-util.h>
|
||||
|
||||
#include "volume.h"
|
||||
|
||||
|
|
@ -344,7 +346,7 @@ pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const
|
|||
pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
|
||||
pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
|
||||
|
||||
for (i = 0; i < a->channels && i < b->channels && i < PA_CHANNELS_MAX; i++)
|
||||
for (i = 0; i < a->channels && i < b->channels; i++)
|
||||
dest->values[i] = pa_sw_volume_multiply(a->values[i], b->values[i]);
|
||||
|
||||
dest->channels = (uint8_t) i;
|
||||
|
|
@ -352,6 +354,22 @@ pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const
|
|||
return dest;
|
||||
}
|
||||
|
||||
pa_cvolume *pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) {
|
||||
unsigned i;
|
||||
|
||||
pa_assert(dest);
|
||||
pa_assert(a);
|
||||
|
||||
pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
|
||||
|
||||
for (i = 0; i < a->channels; i++)
|
||||
dest->values[i] = pa_sw_volume_multiply(a->values[i], b);
|
||||
|
||||
dest->channels = (uint8_t) i;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) {
|
||||
unsigned i;
|
||||
|
||||
|
|
@ -362,7 +380,7 @@ pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa
|
|||
pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
|
||||
pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
|
||||
|
||||
for (i = 0; i < a->channels && i < b->channels && i < PA_CHANNELS_MAX; i++)
|
||||
for (i = 0; i < a->channels && i < b->channels; i++)
|
||||
dest->values[i] = pa_sw_volume_divide(a->values[i], b->values[i]);
|
||||
|
||||
dest->channels = (uint8_t) i;
|
||||
|
|
@ -370,6 +388,22 @@ pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa
|
|||
return dest;
|
||||
}
|
||||
|
||||
pa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) {
|
||||
unsigned i;
|
||||
|
||||
pa_assert(dest);
|
||||
pa_assert(a);
|
||||
|
||||
pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
|
||||
|
||||
for (i = 0; i < a->channels; i++)
|
||||
dest->values[i] = pa_sw_volume_divide(a->values[i], b);
|
||||
|
||||
dest->channels = (uint8_t) i;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
int pa_cvolume_valid(const pa_cvolume *v) {
|
||||
unsigned c;
|
||||
|
||||
|
|
@ -386,65 +420,27 @@ int pa_cvolume_valid(const pa_cvolume *v) {
|
|||
}
|
||||
|
||||
static pa_bool_t on_left(pa_channel_position_t p) {
|
||||
|
||||
return
|
||||
p == PA_CHANNEL_POSITION_FRONT_LEFT ||
|
||||
p == PA_CHANNEL_POSITION_REAR_LEFT ||
|
||||
p == PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER ||
|
||||
p == PA_CHANNEL_POSITION_SIDE_LEFT ||
|
||||
p == PA_CHANNEL_POSITION_TOP_FRONT_LEFT ||
|
||||
p == PA_CHANNEL_POSITION_TOP_REAR_LEFT;
|
||||
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LEFT);
|
||||
}
|
||||
|
||||
static pa_bool_t on_right(pa_channel_position_t p) {
|
||||
|
||||
return
|
||||
p == PA_CHANNEL_POSITION_FRONT_RIGHT ||
|
||||
p == PA_CHANNEL_POSITION_REAR_RIGHT ||
|
||||
p == PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER ||
|
||||
p == PA_CHANNEL_POSITION_SIDE_RIGHT ||
|
||||
p == PA_CHANNEL_POSITION_TOP_FRONT_RIGHT ||
|
||||
p == PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
|
||||
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_RIGHT);
|
||||
}
|
||||
|
||||
static pa_bool_t on_center(pa_channel_position_t p) {
|
||||
|
||||
return
|
||||
p == PA_CHANNEL_POSITION_FRONT_CENTER ||
|
||||
p == PA_CHANNEL_POSITION_REAR_CENTER ||
|
||||
p == PA_CHANNEL_POSITION_TOP_CENTER ||
|
||||
p == PA_CHANNEL_POSITION_TOP_FRONT_CENTER ||
|
||||
p == PA_CHANNEL_POSITION_TOP_REAR_CENTER;
|
||||
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_CENTER);
|
||||
}
|
||||
|
||||
static pa_bool_t on_lfe(pa_channel_position_t p) {
|
||||
|
||||
return
|
||||
p == PA_CHANNEL_POSITION_LFE;
|
||||
return p == PA_CHANNEL_POSITION_LFE;
|
||||
}
|
||||
|
||||
static pa_bool_t on_front(pa_channel_position_t p) {
|
||||
|
||||
return
|
||||
p == PA_CHANNEL_POSITION_FRONT_LEFT ||
|
||||
p == PA_CHANNEL_POSITION_FRONT_RIGHT ||
|
||||
p == PA_CHANNEL_POSITION_FRONT_CENTER ||
|
||||
p == PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER ||
|
||||
p == PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER ||
|
||||
p == PA_CHANNEL_POSITION_TOP_FRONT_LEFT ||
|
||||
p == PA_CHANNEL_POSITION_TOP_FRONT_RIGHT ||
|
||||
p == PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
|
||||
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_FRONT);
|
||||
}
|
||||
|
||||
static pa_bool_t on_rear(pa_channel_position_t p) {
|
||||
|
||||
return
|
||||
p == PA_CHANNEL_POSITION_REAR_LEFT ||
|
||||
p == PA_CHANNEL_POSITION_REAR_RIGHT ||
|
||||
p == PA_CHANNEL_POSITION_REAR_CENTER ||
|
||||
p == PA_CHANNEL_POSITION_TOP_REAR_LEFT ||
|
||||
p == PA_CHANNEL_POSITION_TOP_REAR_RIGHT ||
|
||||
p == PA_CHANNEL_POSITION_TOP_REAR_CENTER;
|
||||
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_REAR);
|
||||
}
|
||||
|
||||
pa_cvolume *pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa_channel_map *to) {
|
||||
|
|
|
|||
|
|
@ -216,16 +216,26 @@ pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) PA_GCC_CONST;
|
|||
* *dest. This is only valid for software volumes! */
|
||||
pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b);
|
||||
|
||||
/** Multiply a per-channel volume with a scalar volume and return the
|
||||
* result in *dest. This is only valid for software volumes! \since
|
||||
* 0.9.16 */
|
||||
pa_cvolume *pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b);
|
||||
|
||||
/** Divide two volume specifications, return the result. This uses
|
||||
* PA_VOLUME_NORM as neutral element of division. This is only valid
|
||||
* for software volumes! If a division by zero is tried the result
|
||||
* will be 0. \since 0.9.13 */
|
||||
pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) PA_GCC_CONST;
|
||||
|
||||
/** Multiply to per-channel volumes and return the result in
|
||||
/** Divide two per-channel volumes and return the result in
|
||||
* *dest. This is only valid for software volumes! \since 0.9.13 */
|
||||
pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b);
|
||||
|
||||
/** Divide a per-channel volume by a scalar volume and return the
|
||||
* result in *dest. This is only valid for software volumes! \since
|
||||
* 0.9.16 */
|
||||
pa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b);
|
||||
|
||||
/** Convert a decibel value to a volume (amplitude, not power). This is only valid for software volumes! */
|
||||
pa_volume_t pa_sw_volume_from_dB(double f) PA_GCC_CONST;
|
||||
|
||||
|
|
|
|||
|
|
@ -88,9 +88,20 @@ static inline void* _pa_xnewdup_internal(const void *p, size_t n, size_t k) {
|
|||
return pa_xmemdup(p, n*k);
|
||||
}
|
||||
|
||||
/** Same as pa_xnew() but set the memory to zero */
|
||||
/** Same as pa_xnew() but duplicate the specified data */
|
||||
#define pa_xnewdup(type, p, n) ((type*) _pa_xnewdup_internal((p), (n), sizeof(type)))
|
||||
|
||||
/** Internal helper for pa_xrenew() */
|
||||
static void* _pa_xrenew_internal(void *p, size_t n, size_t k) PA_GCC_MALLOC PA_GCC_ALLOC_SIZE2(2,3);
|
||||
|
||||
static inline void* _pa_xrenew_internal(void *p, size_t n, size_t k) {
|
||||
assert(n < INT_MAX/k);
|
||||
return pa_xrealloc(p, n*k);
|
||||
}
|
||||
|
||||
/** Reallocate n new structures of the specified type. */
|
||||
#define pa_xrenew(type, p, n) ((type*) _pa_xrenew_internal(p, (n), sizeof(type)))
|
||||
|
||||
PA_C_DECL_END
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue