diff options
Diffstat (limited to 'src/pulse')
-rw-r--r-- | src/pulse/channelmap.c | 49 | ||||
-rw-r--r-- | src/pulse/channelmap.h | 70 | ||||
-rw-r--r-- | src/pulse/client-conf.c | 20 | ||||
-rw-r--r-- | src/pulse/def.h | 93 | ||||
-rw-r--r-- | src/pulse/ext-stream-restore.c | 48 | ||||
-rw-r--r-- | src/pulse/ext-stream-restore.h | 8 | ||||
-rw-r--r-- | src/pulse/operation.c | 1 | ||||
-rw-r--r-- | src/pulse/proplist.c | 384 | ||||
-rw-r--r-- | src/pulse/proplist.h | 8 | ||||
-rw-r--r-- | src/pulse/sample.c | 38 | ||||
-rw-r--r-- | src/pulse/sample.h | 4 | ||||
-rw-r--r-- | src/pulse/utf8.c | 26 | ||||
-rw-r--r-- | src/pulse/utf8.h | 6 | ||||
-rw-r--r-- | src/pulse/volume.c | 74 | ||||
-rw-r--r-- | src/pulse/volume.h | 29 |
15 files changed, 715 insertions, 143 deletions
diff --git a/src/pulse/channelmap.c b/src/pulse/channelmap.c index 6ff30c26..983b8977 100644 --- a/src/pulse/channelmap.c +++ b/src/pulse/channelmap.c @@ -434,11 +434,11 @@ const char* pa_channel_position_to_string(pa_channel_position_t pos) { const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos) { - pa_init_i18n(); - if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX) return NULL; + pa_init_i18n(); + return _(pretty_table[pos]); } @@ -448,6 +448,9 @@ int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) { pa_assert(a); pa_assert(b); + pa_return_val_if_fail(pa_channel_map_valid(a), 0); + pa_return_val_if_fail(pa_channel_map_valid(b), 0); + if (a->channels != b->channels) return 0; @@ -502,19 +505,19 @@ pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) { * "mono" here explicitly, because that can be understood as * listing with one channel called "mono". */ - if (strcmp(s, "stereo") == 0) { + if (pa_streq(s, "stereo")) { map.channels = 2; map.map[0] = PA_CHANNEL_POSITION_LEFT; map.map[1] = PA_CHANNEL_POSITION_RIGHT; goto finish; - } else if (strcmp(s, "surround-40") == 0) { + } else if (pa_streq(s, "surround-40")) { map.channels = 4; map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; goto finish; - } else if (strcmp(s, "surround-41") == 0) { + } else if (pa_streq(s, "surround-41")) { map.channels = 5; map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; @@ -522,7 +525,7 @@ pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) { map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; map.map[4] = PA_CHANNEL_POSITION_LFE; goto finish; - } else if (strcmp(s, "surround-50") == 0) { + } else if (pa_streq(s, "surround-50")) { map.channels = 5; map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; @@ -530,7 +533,7 @@ pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) { map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; goto finish; - } else if (strcmp(s, "surround-51") == 0) { + } else if (pa_streq(s, "surround-51")) { map.channels = 6; map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; @@ -539,7 +542,7 @@ pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) { map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; map.map[5] = PA_CHANNEL_POSITION_LFE; goto finish; - } else if (strcmp(s, "surround-71") == 0) { + } else if (pa_streq(s, "surround-71")) { map.channels = 8; map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; @@ -563,13 +566,13 @@ pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) { } /* Some special aliases */ - if (strcmp(p, "left") == 0) + if (pa_streq(p, "left")) map.map[map.channels++] = PA_CHANNEL_POSITION_LEFT; - else if (strcmp(p, "right") == 0) + else if (pa_streq(p, "right")) map.map[map.channels++] = PA_CHANNEL_POSITION_RIGHT; - else if (strcmp(p, "center") == 0) + else if (pa_streq(p, "center")) map.map[map.channels++] = PA_CHANNEL_POSITION_CENTER; - else if (strcmp(p, "subwoofer") == 0) + else if (pa_streq(p, "subwoofer")) map.map[map.channels++] = PA_CHANNEL_POSITION_SUBWOOFER; else { pa_channel_position_t i; @@ -617,11 +620,8 @@ int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *s pa_assert(map); pa_assert(ss); - if (!pa_channel_map_valid(map)) - return 0; - - if (!pa_sample_spec_valid(ss)) - return 0; + pa_return_val_if_fail(pa_channel_map_valid(map), 0); + pa_return_val_if_fail(pa_sample_spec_valid(ss), 0); return map->channels == ss->channels; } @@ -633,6 +633,9 @@ int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) { pa_assert(a); pa_assert(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)); for (i = 0; i < a->channels; i++) @@ -651,6 +654,8 @@ int pa_channel_map_can_balance(const pa_channel_map *map) { pa_assert(map); + pa_return_val_if_fail(pa_channel_map_valid(map), 0); + for (c = 0; c < map->channels; c++) { switch (map->map[c]) { @@ -687,6 +692,10 @@ int pa_channel_map_can_fade(const pa_channel_map *map) { unsigned c; pa_bool_t front = FALSE, rear = FALSE; + pa_assert(map); + + pa_return_val_if_fail(pa_channel_map_valid(map), 0); + for (c = 0; c < map->channels; c++) { switch (map->map[c]) { @@ -727,6 +736,8 @@ const char* pa_channel_map_to_name(const pa_channel_map *map) { pa_assert(map); + pa_return_val_if_fail(pa_channel_map_valid(map), NULL); + memset(in_map, 0, sizeof(in_map)); for (c = 0; c < map->channels; c++) @@ -779,11 +790,15 @@ const char* pa_channel_map_to_pretty_name(const pa_channel_map *map) { pa_assert(map); + pa_return_val_if_fail(pa_channel_map_valid(map), NULL); + memset(in_map, 0, sizeof(in_map)); for (c = 0; c < map->channels; c++) pa_bitset_set(in_map, map->map[c], TRUE); + pa_init_i18n(); + if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, PA_CHANNEL_POSITION_MONO, -1)) return _("Mono"); diff --git a/src/pulse/channelmap.h b/src/pulse/channelmap.h index f9124b2e..a6d37d85 100644 --- a/src/pulse/channelmap.h +++ b/src/pulse/channelmap.h @@ -141,6 +141,66 @@ typedef enum pa_channel_position { PA_CHANNEL_POSITION_MAX } pa_channel_position_t; +/** \cond fulldocs */ +#define PA_CHANNEL_POSITION_INVALID PA_CHANNEL_POSITION_INVALID +#define PA_CHANNEL_POSITION_MONO PA_CHANNEL_POSITION_MONO +#define PA_CHANNEL_POSITION_LEFT PA_CHANNEL_POSITION_LEFT +#define PA_CHANNEL_POSITION_RIGHT PA_CHANNEL_POSITION_RIGHT +#define PA_CHANNEL_POSITION_CENTER PA_CHANNEL_POSITION_CENTER +#define PA_CHANNEL_POSITION_FRONT_LEFT PA_CHANNEL_POSITION_FRONT_LEFT +#define PA_CHANNEL_POSITION_FRONT_RIGHT PA_CHANNEL_POSITION_FRONT_RIGHT +#define PA_CHANNEL_POSITION_FRONT_CENTER PA_CHANNEL_POSITION_FRONT_CENTER +#define PA_CHANNEL_POSITION_REAR_CENTER PA_CHANNEL_POSITION_REAR_CENTER +#define PA_CHANNEL_POSITION_REAR_LEFT PA_CHANNEL_POSITION_REAR_LEFT +#define PA_CHANNEL_POSITION_REAR_RIGHT PA_CHANNEL_POSITION_REAR_RIGHT +#define PA_CHANNEL_POSITION_LFE PA_CHANNEL_POSITION_LFE +#define PA_CHANNEL_POSITION_SUBWOOFER PA_CHANNEL_POSITION_SUBWOOFER +#define PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER +#define PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER +#define PA_CHANNEL_POSITION_SIDE_LEFT PA_CHANNEL_POSITION_SIDE_LEFT +#define PA_CHANNEL_POSITION_SIDE_RIGHT PA_CHANNEL_POSITION_SIDE_RIGHT +#define PA_CHANNEL_POSITION_AUX0 PA_CHANNEL_POSITION_AUX0 +#define PA_CHANNEL_POSITION_AUX1 PA_CHANNEL_POSITION_AUX1 +#define PA_CHANNEL_POSITION_AUX2 PA_CHANNEL_POSITION_AUX2 +#define PA_CHANNEL_POSITION_AUX3 PA_CHANNEL_POSITION_AUX3 +#define PA_CHANNEL_POSITION_AUX4 PA_CHANNEL_POSITION_AUX4 +#define PA_CHANNEL_POSITION_AUX5 PA_CHANNEL_POSITION_AUX5 +#define PA_CHANNEL_POSITION_AUX6 PA_CHANNEL_POSITION_AUX6 +#define PA_CHANNEL_POSITION_AUX7 PA_CHANNEL_POSITION_AUX7 +#define PA_CHANNEL_POSITION_AUX8 PA_CHANNEL_POSITION_AUX8 +#define PA_CHANNEL_POSITION_AUX9 PA_CHANNEL_POSITION_AUX9 +#define PA_CHANNEL_POSITION_AUX10 PA_CHANNEL_POSITION_AUX10 +#define PA_CHANNEL_POSITION_AUX11 PA_CHANNEL_POSITION_AUX11 +#define PA_CHANNEL_POSITION_AUX12 PA_CHANNEL_POSITION_AUX12 +#define PA_CHANNEL_POSITION_AUX13 PA_CHANNEL_POSITION_AUX13 +#define PA_CHANNEL_POSITION_AUX14 PA_CHANNEL_POSITION_AUX14 +#define PA_CHANNEL_POSITION_AUX15 PA_CHANNEL_POSITION_AUX15 +#define PA_CHANNEL_POSITION_AUX16 PA_CHANNEL_POSITION_AUX16 +#define PA_CHANNEL_POSITION_AUX17 PA_CHANNEL_POSITION_AUX17 +#define PA_CHANNEL_POSITION_AUX18 PA_CHANNEL_POSITION_AUX18 +#define PA_CHANNEL_POSITION_AUX19 PA_CHANNEL_POSITION_AUX19 +#define PA_CHANNEL_POSITION_AUX20 PA_CHANNEL_POSITION_AUX20 +#define PA_CHANNEL_POSITION_AUX21 PA_CHANNEL_POSITION_AUX21 +#define PA_CHANNEL_POSITION_AUX22 PA_CHANNEL_POSITION_AUX22 +#define PA_CHANNEL_POSITION_AUX23 PA_CHANNEL_POSITION_AUX23 +#define PA_CHANNEL_POSITION_AUX24 PA_CHANNEL_POSITION_AUX24 +#define PA_CHANNEL_POSITION_AUX25 PA_CHANNEL_POSITION_AUX25 +#define PA_CHANNEL_POSITION_AUX26 PA_CHANNEL_POSITION_AUX26 +#define PA_CHANNEL_POSITION_AUX27 PA_CHANNEL_POSITION_AUX27 +#define PA_CHANNEL_POSITION_AUX28 PA_CHANNEL_POSITION_AUX28 +#define PA_CHANNEL_POSITION_AUX29 PA_CHANNEL_POSITION_AUX29 +#define PA_CHANNEL_POSITION_AUX30 PA_CHANNEL_POSITION_AUX30 +#define PA_CHANNEL_POSITION_AUX31 PA_CHANNEL_POSITION_AUX31 +#define PA_CHANNEL_POSITION_TOP_CENTER PA_CHANNEL_POSITION_TOP_CENTER +#define PA_CHANNEL_POSITION_TOP_FRONT_LEFT PA_CHANNEL_POSITION_TOP_FRONT_LEFT +#define PA_CHANNEL_POSITION_TOP_FRONT_RIGHT PA_CHANNEL_POSITION_TOP_FRONT_RIGHT +#define PA_CHANNEL_POSITION_TOP_FRONT_CENTER PA_CHANNEL_POSITION_TOP_FRONT_CENTER +#define PA_CHANNEL_POSITION_TOP_REAR_LEFT PA_CHANNEL_POSITION_TOP_REAR_LEFT +#define PA_CHANNEL_POSITION_TOP_REAR_RIGHT PA_CHANNEL_POSITION_TOP_REAR_RIGHT +#define PA_CHANNEL_POSITION_TOP_REAR_CENTER PA_CHANNEL_POSITION_TOP_REAR_CENTER +#define PA_CHANNEL_POSITION_MAX PA_CHANNEL_POSITION_MAX +/** \endcond */ + /** A list of channel mapping definitions for pa_channel_map_init_auto() */ typedef enum pa_channel_map_def { PA_CHANNEL_MAP_AIFF, @@ -165,6 +225,16 @@ typedef enum pa_channel_map_def { /**< The default channel map */ } pa_channel_map_def_t; +/** \cond fulldocs */ +#define PA_CHANNEL_MAP_AIFF PA_CHANNEL_MAP_AIFF +#define PA_CHANNEL_MAP_ALSA PA_CHANNEL_MAP_ALSA +#define PA_CHANNEL_MAP_AUX PA_CHANNEL_MAP_AUX +#define PA_CHANNEL_MAP_WAVEEX PA_CHANNEL_MAP_WAVEEX +#define PA_CHANNEL_MAP_OSS PA_CHANNEL_MAP_OSS +#define PA_CHANNEL_MAP_DEF_MAX PA_CHANNEL_MAP_DEF_MAX +#define PA_CHANNEL_MAP_DEFAULT PA_CHANNEL_MAP_DEFAULT +/** \endcond */ + /** A channel map which can be used to attach labels to specific * channels of a stream. These values are relevant for conversion and * mixing of streams */ diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index 58d64642..71f8443d 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -92,16 +92,16 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { /* Prepare the configuration parse table */ pa_config_item table[] = { - { "daemon-binary", pa_config_parse_string, NULL }, - { "extra-arguments", pa_config_parse_string, NULL }, - { "default-sink", pa_config_parse_string, NULL }, - { "default-source", pa_config_parse_string, NULL }, - { "default-server", pa_config_parse_string, NULL }, - { "autospawn", pa_config_parse_bool, NULL }, - { "cookie-file", pa_config_parse_string, NULL }, - { "disable-shm", pa_config_parse_bool, NULL }, - { "shm-size-bytes", pa_config_parse_size, NULL }, - { NULL, NULL, NULL }, + { "daemon-binary", pa_config_parse_string, NULL, NULL }, + { "extra-arguments", pa_config_parse_string, NULL, NULL }, + { "default-sink", pa_config_parse_string, NULL, NULL }, + { "default-source", pa_config_parse_string, NULL, NULL }, + { "default-server", pa_config_parse_string, NULL, NULL }, + { "autospawn", pa_config_parse_bool, NULL, NULL }, + { "cookie-file", pa_config_parse_string, NULL, NULL }, + { "disable-shm", pa_config_parse_bool, NULL, NULL }, + { "shm-size-bytes", pa_config_parse_size, NULL, NULL }, + { NULL, NULL, NULL, NULL }, }; table[0].data = &c->daemon_binary; diff --git a/src/pulse/def.h b/src/pulse/def.h index 1acf19a0..d4fa821a 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -57,6 +57,12 @@ static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x) { } /** \cond fulldocs */ +#define PA_CONTEXT_UNCONNECTED PA_CONTEXT_UNCONNECTED +#define PA_CONTEXT_CONNECTING PA_CONTEXT_CONNECTING +#define PA_CONTEXT_AUTHORIZING PA_CONTEXT_AUTHORIZING +#define PA_CONTEXT_SETTING_NAME PA_CONTEXT_SETTING_NAME +#define PA_CONTEXT_READY PA_CONTEXT_READY +#define PA_CONTEXT_FAILED PA_CONTEXT_FAILED #define PA_CONTEXT_IS_GOOD PA_CONTEXT_IS_GOOD /** \endcond */ @@ -77,6 +83,11 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) { } /** \cond fulldocs */ +#define PA_STREAM_UNCONNECTED PA_STREAM_UNCONNECTED +#define PA_STREAM_CREATING PA_STREAM_CREATING +#define PA_STREAM_READY PA_STREAM_READY +#define PA_STREAM_FAILED PA_STREAM_FAILED +#define PA_STREAM_TERMINATED PA_STREAM_TERMINATED #define PA_STREAM_IS_GOOD PA_STREAM_IS_GOOD /** \endcond */ @@ -87,6 +98,12 @@ typedef enum pa_operation_state { PA_OPERATION_CANCELED /**< The operation has been canceled */ } pa_operation_state_t; +/** \cond fulldocs */ +#define PA_OPERATION_RUNNING PA_OPERATION_RUNNING +#define PA_OPERATION_DONE PA_OPERATION_DONE +#define PA_OPERATION_CANCELED PA_OPERATION_CANCELED +/** \endcond */ + /** An invalid index */ #define PA_INVALID_INDEX ((uint32_t) -1) @@ -109,6 +126,13 @@ typedef enum pa_stream_direction { PA_STREAM_UPLOAD /**< Sample upload stream */ } pa_stream_direction_t; +/** \cond fulldocs */ +#define PA_STREAM_NODIRECTION PA_STREAM_NODIRECTION +#define PA_STREAM_PLAYBACK PA_STREAM_PLAYBACK +#define PA_STREAM_RECORD PA_STREAM_RECORD +#define PA_STREAM_UPLOAD PA_STREAM_UPLOAD +/** \endcond */ + /** Some special flags for stream connections. */ typedef enum pa_stream_flags { @@ -368,6 +392,34 @@ enum { PA_ERR_MAX /**< Not really an error but the first invalid error code */ }; +/** \cond fulldocs */ +#define PA_OK PA_OK +#define PA_ERR_ACCESS PA_ERR_ACCESS +#define PA_ERR_COMMAND PA_ERR_COMMAND +#define PA_ERR_INVALID PA_ERR_INVALID +#define PA_ERR_EXIST PA_ERR_EXIST +#define PA_ERR_NOENTITY PA_ERR_NOENTITY +#define PA_ERR_CONNECTIONREFUSED PA_ERR_CONNECTIONREFUSED +#define PA_ERR_PROTOCOL PA_ERR_PROTOCOL +#define PA_ERR_TIMEOUT PA_ERR_TIMEOUT +#define PA_ERR_AUTHKEY PA_ERR_AUTHKEY +#define PA_ERR_INTERNAL PA_ERR_INTERNAL +#define PA_ERR_CONNECTIONTERMINATED PA_ERR_CONNECTIONTERMINATED +#define PA_ERR_KILLED PA_ERR_KILLED +#define PA_ERR_INVALIDSERVER PA_ERR_INVALIDSERVER +#define PA_ERR_MODINITFAILED PA_ERR_MODINITFAILED +#define PA_ERR_BADSTATE PA_ERR_BADSTATE +#define PA_ERR_NODATA PA_ERR_NODATA +#define PA_ERR_VERSION PA_ERR_VERSION +#define PA_ERR_TOOLARGE PA_ERR_TOOLARGE +#define PA_ERR_NOTSUPPORTED PA_ERR_NOTSUPPORTED +#define PA_ERR_UNKNOWN PA_ERR_UNKNOWN +#define PA_ERR_NOEXTENSION PA_ERR_NOEXTENSION +#define PA_ERR_OBSOLETE PA_ERR_OBSOLETE +#define PA_ERR_NOTIMPLEMENTED PA_ERR_NOTIMPLEMENTED +#define PA_ERR_MAX PA_ERR_MAX +/** \endcond */ + /** Subscription event mask, as used by pa_context_subscribe() */ typedef enum pa_subscription_mask { PA_SUBSCRIPTION_MASK_NULL = 0x0000U, @@ -463,6 +515,36 @@ typedef enum pa_subscription_event_type { /** 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)))) +/** \cond fulldocs */ +#define PA_SUBSCRIPTION_MASK_NULL PA_SUBSCRIPTION_MASK_NULL +#define PA_SUBSCRIPTION_MASK_SINK PA_SUBSCRIPTION_MASK_SINK +#define PA_SUBSCRIPTION_MASK_SOURCE PA_SUBSCRIPTION_MASK_SOURCE +#define PA_SUBSCRIPTION_MASK_SINK_INPUT PA_SUBSCRIPTION_MASK_SINK_INPUT +#define PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT +#define PA_SUBSCRIPTION_MASK_MODULE PA_SUBSCRIPTION_MASK_MODULE +#define PA_SUBSCRIPTION_MASK_CLIENT PA_SUBSCRIPTION_MASK_CLIENT +#define PA_SUBSCRIPTION_MASK_SAMPLE_CACHE PA_SUBSCRIPTION_MASK_SAMPLE_CACHE +#define PA_SUBSCRIPTION_MASK_SERVER PA_SUBSCRIPTION_MASK_SERVER +#define PA_SUBSCRIPTION_MASK_AUTOLOAD PA_SUBSCRIPTION_MASK_AUTOLOAD +#define PA_SUBSCRIPTION_MASK_CARD PA_SUBSCRIPTION_MASK_CARD +#define PA_SUBSCRIPTION_MASK_ALL PA_SUBSCRIPTION_MASK_ALL +#define PA_SUBSCRIPTION_EVENT_SINK PA_SUBSCRIPTION_EVENT_SINK +#define PA_SUBSCRIPTION_EVENT_SOURCE PA_SUBSCRIPTION_EVENT_SOURCE +#define PA_SUBSCRIPTION_EVENT_SINK_INPUT PA_SUBSCRIPTION_EVENT_SINK_INPUT +#define PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT +#define PA_SUBSCRIPTION_EVENT_MODULE PA_SUBSCRIPTION_EVENT_MODULE +#define PA_SUBSCRIPTION_EVENT_CLIENT PA_SUBSCRIPTION_EVENT_CLIENT +#define PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE +#define PA_SUBSCRIPTION_EVENT_SERVER PA_SUBSCRIPTION_EVENT_SERVER +#define PA_SUBSCRIPTION_EVENT_AUTOLOAD PA_SUBSCRIPTION_EVENT_AUTOLOAD +#define PA_SUBSCRIPTION_EVENT_CARD PA_SUBSCRIPTION_EVENT_CARD +#define PA_SUBSCRIPTION_EVENT_FACILITY_MASK PA_SUBSCRIPTION_EVENT_FACILITY_MASK +#define PA_SUBSCRIPTION_EVENT_NEW PA_SUBSCRIPTION_EVENT_NEW +#define PA_SUBSCRIPTION_EVENT_CHANGE PA_SUBSCRIPTION_EVENT_CHANGE +#define PA_SUBSCRIPTION_EVENT_REMOVE PA_SUBSCRIPTION_EVENT_REMOVE +#define PA_SUBSCRIPTION_EVENT_TYPE_MASK PA_SUBSCRIPTION_EVENT_TYPE_MASK +/** \endcond */ + /** A structure for all kinds of timing information of a stream. See * pa_stream_update_timing_info() and pa_stream_get_timing_info(). The * total output latency a sample that is written with @@ -589,6 +671,13 @@ typedef enum pa_seek_mode { /**< Seek relatively to the current end of the buffer queue. */ } pa_seek_mode_t; +/** \cond fulldocs */ +#define PA_SEEK_RELATIVE PA_SEEK_RELATIVE +#define PA_SEEK_ABSOLUTE PA_SEEK_ABSOLUTE +#define PA_SEEK_RELATIVE_ON_READ PA_SEEK_RELATIVE_ON_READ +#define PA_SEEK_RELATIVE_END PA_SEEK_RELATIVE_END +/** \endcond */ + /** Special sink flags. */ typedef enum pa_sink_flags { PA_SINK_HW_VOLUME_CTRL = 0x0001U, @@ -666,6 +755,8 @@ static inline int PA_SINK_IS_OPENED(pa_sink_state_t x) { #define PA_SINK_RUNNING PA_SINK_RUNNING #define PA_SINK_IDLE PA_SINK_IDLE #define PA_SINK_SUSPENDED PA_SINK_SUSPENDED +#define PA_SINK_INIT PA_SINK_INIT +#define PA_SINK_UNLINKED PA_SINK_UNLINKED #define PA_SINK_IS_OPENED PA_SINK_IS_OPENED /** \endcond */ @@ -741,6 +832,8 @@ static inline int PA_SOURCE_IS_OPENED(pa_source_state_t x) { #define PA_SOURCE_RUNNING PA_SOURCE_RUNNING #define PA_SOURCE_IDLE PA_SOURCE_IDLE #define PA_SOURCE_SUSPENDED PA_SOURCE_SUSPENDED +#define PA_SOURCE_INIT PA_SOURCE_INIT +#define PA_SOURCE_UNLINKED PA_SOURCE_UNLINKED #define PA_SOURCE_IS_OPENED PA_SOURCE_IS_OPENED /** \endcond */ diff --git a/src/pulse/ext-stream-restore.c b/src/pulse/ext-stream-restore.c index 703179c5..469c822a 100644 --- a/src/pulse/ext-stream-restore.c +++ b/src/pulse/ext-stream-restore.c @@ -30,6 +30,7 @@ #include <pulsecore/pstream-util.h> #include "internal.h" +#include "operation.h" #include "ext-stream-restore.h" @@ -191,8 +192,8 @@ pa_operation *pa_ext_stream_restore_write( void *userdata) { uint32_t tag; - pa_operation *o; - pa_tagstruct *t; + pa_operation *o = NULL; + pa_tagstruct *t = NULL; pa_assert(c); pa_assert(PA_REFCNT_VALUE(c) >= 1); @@ -213,7 +214,15 @@ pa_operation *pa_ext_stream_restore_write( pa_tagstruct_put_boolean(t, apply_immediately); for (; n > 0; n--, data++) { + if (!data->name || !*data->name) + goto fail; + pa_tagstruct_puts(t, data->name); + + if (data->volume.channels > 0 && + !pa_cvolume_compatible_with_channel_map(&data->volume, &data->channel_map)) + goto fail; + pa_tagstruct_put_channel_map(t, &data->channel_map); pa_tagstruct_put_cvolume(t, &data->volume); pa_tagstruct_puts(t, data->device); @@ -224,6 +233,18 @@ pa_operation *pa_ext_stream_restore_write( 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; + +fail: + if (o) { + pa_operation_cancel(o); + pa_operation_unref(o); + } + + if (t) + pa_tagstruct_free(t); + + pa_context_set_error(c, PA_ERR_INVALID); + return NULL; } pa_operation *pa_ext_stream_restore_delete( @@ -233,8 +254,8 @@ pa_operation *pa_ext_stream_restore_delete( void *userdata) { uint32_t tag; - pa_operation *o; - pa_tagstruct *t; + pa_operation *o = NULL; + pa_tagstruct *t = NULL; const char *const *k; pa_assert(c); @@ -251,13 +272,29 @@ pa_operation *pa_ext_stream_restore_delete( pa_tagstruct_puts(t, "module-stream-restore"); pa_tagstruct_putu32(t, SUBCOMMAND_DELETE); - for (k = s; *k; k++) + for (k = s; *k; k++) { + if (!*k || !**k) + goto fail; + pa_tagstruct_puts(t, *k); + } 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; + +fail: + if (o) { + pa_operation_cancel(o); + pa_operation_unref(o); + } + + if (t) + pa_tagstruct_free(t); + + pa_context_set_error(c, PA_ERR_INVALID); + return NULL; } pa_operation *pa_ext_stream_restore_subscribe( @@ -322,5 +359,4 @@ void pa_ext_stream_restore_command(pa_context *c, uint32_t tag, pa_tagstruct *t) if (c->ext_stream_restore.callback) c->ext_stream_restore.callback(c, c->ext_stream_restore.userdata); - } diff --git a/src/pulse/ext-stream-restore.h b/src/pulse/ext-stream-restore.h index ac01d235..cf9f4ccc 100644 --- a/src/pulse/ext-stream-restore.h +++ b/src/pulse/ext-stream-restore.h @@ -36,10 +36,10 @@ PA_C_DECL_BEGIN * maintained by module-stream-restore. \since 0.9.12 */ typedef struct pa_ext_stream_restore_info { const char *name; /**< Identifier string of the stream. A string like "sink-input-by-role:" or similar followed by some arbitrary property value. */ - pa_channel_map channel_map; /**< The channel map for the volume field */ - pa_cvolume volume; /**< The volume of the stream when it was seen last, if applicable */ - const char *device; /**< The sink/source of the stream when it was last seen */ - int mute; /**< The boolean mute state of the stream when it was last seen, if applicable */ + pa_channel_map channel_map; /**< The channel map for the volume field, if applicable */ + pa_cvolume volume; /**< The volume of the stream when it was seen last, if applicable and saved */ + const char *device; /**< The sink/source of the stream when it was last seen, if applicable and saved */ + int mute; /**< The boolean mute state of the stream when it was last seen, if applicable and saved */ } pa_ext_stream_restore_info; /** Callback prototype for pa_ext_stream_restore_test(). \since 0.9.12 */ diff --git a/src/pulse/operation.c b/src/pulse/operation.c index 13b470a8..aa2bbc05 100644 --- a/src/pulse/operation.c +++ b/src/pulse/operation.c @@ -62,6 +62,7 @@ pa_operation *pa_operation_ref(pa_operation *o) { PA_REFCNT_INC(o); return o; } + void pa_operation_unref(pa_operation *o) { pa_assert(o); pa_assert(PA_REFCNT_VALUE(o) >= 1); diff --git a/src/pulse/proplist.c b/src/pulse/proplist.c index 282fe5cc..db4c9344 100644 --- a/src/pulse/proplist.c +++ b/src/pulse/proplist.c @@ -24,6 +24,7 @@ #endif #include <string.h> +#include <ctype.h> #include <pulse/xmalloc.h> #include <pulse/utf8.h> @@ -46,7 +47,7 @@ struct property { static pa_bool_t property_name_valid(const char *key) { - if (!pa_utf8_valid(key)) + if (!pa_ascii_valid(key)) return FALSE; if (strlen(key) <= 0) @@ -64,8 +65,6 @@ static void property_free(struct property *prop) { } pa_proplist* pa_proplist_new(void) { - pa_init_i18n(); - return MAKE_PROPLIST(pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func)); } @@ -83,6 +82,7 @@ int pa_proplist_sets(pa_proplist *p, const char *key, const char *value) { pa_assert(p); pa_assert(key); + pa_assert(value); if (!property_name_valid(key) || !pa_utf8_valid(value)) return -1; @@ -104,25 +104,130 @@ int pa_proplist_sets(pa_proplist *p, const char *key, const char *value) { } /** Will accept only valid UTF-8 */ +static int proplist_setn(pa_proplist *p, const char *key, size_t key_length, const char *value, size_t value_length) { + struct property *prop; + pa_bool_t add = FALSE; + char *k, *v; + + pa_assert(p); + pa_assert(key); + pa_assert(value); + + k = pa_xstrndup(key, key_length); + v = pa_xstrndup(value, value_length); + + if (!property_name_valid(k) || !pa_utf8_valid(v)) { + pa_xfree(k); + pa_xfree(v); + return -1; + } + + if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), k))) { + prop = pa_xnew(struct property, 1); + prop->key = k; + add = TRUE; + } else { + pa_xfree(prop->value); + pa_xfree(k); + } + + prop->value = v; + prop->nbytes = strlen(v)+1; + + if (add) + pa_hashmap_put(MAKE_HASHMAP(p), prop->key, prop); + + return 0; +} + +static int proplist_sethex(pa_proplist *p, const char *key, size_t key_length, const char *value, size_t value_length) { + struct property *prop; + pa_bool_t add = FALSE; + char *k, *v; + uint8_t *d; + size_t dn; + + pa_assert(p); + pa_assert(key); + pa_assert(value); + + k = pa_xstrndup(key, key_length); + + if (!property_name_valid(k)) { + pa_xfree(k); + return -1; + } + + v = pa_xstrndup(value, value_length); + d = pa_xmalloc(value_length*2+1); + + if ((dn = pa_parsehex(v, d, value_length*2)) == (size_t) -1) { + pa_xfree(k); + pa_xfree(v); + pa_xfree(d); + return -1; + } + + pa_xfree(v); + + if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), k))) { + prop = pa_xnew(struct property, 1); + prop->key = k; + add = TRUE; + } else { + pa_xfree(prop->value); + pa_xfree(k); + } + + d[dn] = 0; + prop->value = d; + prop->nbytes = dn; + + if (add) + pa_hashmap_put(MAKE_HASHMAP(p), prop->key, prop); + + return 0; +} + +/** Will accept only valid UTF-8 */ int pa_proplist_setf(pa_proplist *p, const char *key, const char *format, ...) { + struct property *prop; + pa_bool_t add = FALSE; va_list ap; - int r; - char *t; + char *v; pa_assert(p); pa_assert(key); + pa_assert(format); if (!property_name_valid(key) || !pa_utf8_valid(format)) return -1; va_start(ap, format); - t = pa_vsprintf_malloc(format, ap); + v = pa_vsprintf_malloc(format, ap); va_end(ap); - r = pa_proplist_sets(p, key, t); + if (!pa_utf8_valid(v)) + goto fail; - pa_xfree(t); - return r; + if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key))) { + prop = pa_xnew(struct property, 1); + prop->key = pa_xstrdup(key); + add = TRUE; + } else + pa_xfree(prop->value); + + prop->value = v; + prop->nbytes = strlen(v)+1; + + if (add) + pa_hashmap_put(MAKE_HASHMAP(p), prop->key, prop); + + return 0; + +fail: + pa_xfree(v); + return -1; } int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nbytes) { @@ -131,6 +236,7 @@ int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nb pa_assert(p); pa_assert(key); + pa_assert(data); if (!property_name_valid(key)) return -1; @@ -142,7 +248,9 @@ int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nb } else pa_xfree(prop->value); - prop->value = pa_xmemdup(data, nbytes); + prop->value = pa_xmalloc(nbytes+1); + memcpy(prop->value, data, nbytes); + ((char*) prop->value)[nbytes] = 0; prop->nbytes = nbytes; if (add) @@ -183,6 +291,8 @@ int pa_proplist_get(pa_proplist *p, const char *key, const void **data, size_t * pa_assert(p); pa_assert(key); + pa_assert(data); + pa_assert(nbytes); if (!property_name_valid(key)) return -1; @@ -275,9 +385,32 @@ char *pa_proplist_to_string_sep(pa_proplist *p, const char *sep) { if (!pa_strbuf_isempty(buf)) pa_strbuf_puts(buf, sep); - if ((v = pa_proplist_gets(p, key))) - pa_strbuf_printf(buf, "%s = \"%s\"", key, v); - else { + if ((v = pa_proplist_gets(p, key))) { + const char *t; + + pa_strbuf_printf(buf, "%s = \"", key); + + for (t = v;;) { + size_t h; + + h = strcspn(t, "\""); + + if (h > 0) + pa_strbuf_putsn(buf, t, h); + + t += h; + + if (*t == 0) + break; + + pa_assert(*t == '"'); + pa_strbuf_puts(buf, "\\\""); + + t++; + } + + pa_strbuf_puts(buf, "\""); + } else { const void *value; size_t nbytes; char *c; @@ -304,88 +437,189 @@ char *pa_proplist_to_string(pa_proplist *p) { return t; } -/* Remove all whitepsapce from the beginning and the end of *s. *s may - * be modified. (from conf-parser.c) */ -#define WHITESPACE " \t\n" -#define in_string(c,s) (strchr(s,c) != NULL) - -static char *strip(char *s) { - char *b = s+strspn(s, WHITESPACE); - char *e, *l = NULL; - - for (e = b; *e; e++) - if (!in_string(*e, WHITESPACE)) - l = e; +pa_proplist *pa_proplist_from_string(const char *s) { + enum { + WHITESPACE, + KEY, + AFTER_KEY, + VALUE_START, + VALUE_SIMPLE, + VALUE_DOUBLE_QUOTES, + VALUE_DOUBLE_QUOTES_ESCAPE, + VALUE_TICKS, + VALUE_TICKS_ESCAPED, + VALUE_HEX + } state; + + pa_proplist *pl; + const char *p, *key = NULL, *value = NULL; + size_t key_len = 0, value_len = 0; + + pa_assert(s); + + pl = pa_proplist_new(); + + state = WHITESPACE; + + for (p = s;; p++) { + switch (state) { + + case WHITESPACE: + if (*p == 0) + goto success; + else if (*p == '=') + goto fail; + else if (!isspace(*p)) { + key = p; + state = KEY; + key_len = 1; + } + break; - if (l) - *(l+1) = 0; + case KEY: + if (*p == 0) + goto fail; + else if (*p == '=') + state = VALUE_START; + else if (isspace(*p)) + state = AFTER_KEY; + else + key_len++; + break; - return b; -} + case AFTER_KEY: + if (*p == 0) + goto fail; + else if (*p == '=') + state = VALUE_START; + else if (!isspace(*p)) + goto fail; + break; -pa_proplist *pa_proplist_from_string(const char *str) { - pa_proplist *p; - char *s, *v, *k, *e; + case VALUE_START: + if (*p == 0) + goto fail; + else if (strncmp(p, "hex:", 4) == 0) { + state = VALUE_HEX; + value = p+4; + value_len = 0; + p += 3; + } else if (*p == '\'') { + state = VALUE_TICKS; + value = p+1; + value_len = 0; + } else if (*p == '"') { + state = VALUE_DOUBLE_QUOTES; + value = p+1; + value_len = 0; + } else if (!isspace(*p)) { + state = VALUE_SIMPLE; + value = p; + value_len = 1; + } + break; - pa_assert(str); - pa_assert_se(p = pa_proplist_new()); - pa_assert_se(s = strdup(str)); + case VALUE_SIMPLE: + if (*p == 0 || isspace(*p)) { + if (proplist_setn(pl, key, key_len, value, value_len) < 0) + goto fail; - for (k = s; *k; k = e) { - k = k+strspn(k, WHITESPACE); + if (*p == 0) + goto success; - if (!*k) - break; + state = WHITESPACE; + } else + value_len++; + break; - if (!(v = strchr(k, '='))) { - pa_log("Missing '='."); - break; - } + case VALUE_DOUBLE_QUOTES: + if (*p == 0) + goto fail; + else if (*p == '"') { + char *v; + + v = pa_unescape(pa_xstrndup(value, value_len)); + + if (proplist_setn(pl, key, key_len, v, strlen(v)) < 0) { + pa_xfree(v); + goto fail; + } + + pa_xfree(v); + state = WHITESPACE; + } else if (*p == '\\') { + state = VALUE_DOUBLE_QUOTES_ESCAPE; + value_len++; + } else + value_len++; + break; - *v++ = '\0'; - k = strip(k); + case VALUE_DOUBLE_QUOTES_ESCAPE: + if (*p == 0) + goto fail; + else { + state = VALUE_DOUBLE_QUOTES; + value_len++; + } + break; - v = v+strspn(v, WHITESPACE); - if (*v == '"') { - v++; - if (!(e = strchr(v, '"'))) { /* FIXME: handle escape */ - pa_log("Missing '\"' at end of string value."); + case VALUE_TICKS: + if (*p == 0) + goto fail; + else if (*p == '\'') { + char *v; + + v = pa_unescape(pa_xstrndup(value, value_len)); + + if (proplist_setn(pl, key, key_len, v, strlen(v)) < 0) { + pa_xfree(v); + goto fail; + } + + pa_xfree(v); + state = WHITESPACE; + } else if (*p == '\\') { + state = VALUE_TICKS_ESCAPED; + value_len++; + } else + value_len++; break; - } - *e++ = '\0'; - pa_proplist_sets(p, k, v); - } else { - uint8_t *blob; - if (*v++ != 'h' || *v++ != 'e' || *v++ != 'x' || *v++ != ':') { - pa_log("Value must be a string or \"hex:\""); + case VALUE_TICKS_ESCAPED: + if (*p == 0) + goto fail; + else { + state = VALUE_TICKS; + value_len++; + } break; - } - e = v; - while (in_string(*e, "0123456789abcdefABCDEF")) - ++e; + case VALUE_HEX: + if ((*p >= '0' && *p <= '9') || + (*p >= 'A' && *p <= 'F') || + (*p >= 'a' && *p <= 'f')) { + value_len++; + } else if (*p == 0 || isspace(*p)) { - if ((e - v) % 2) { - pa_log("Invalid \"hex:\" value data"); - break; - } + if (proplist_sethex(pl, key, key_len, value, value_len) < 0) + goto fail; - blob = pa_xmalloc((size_t)(e-v)/2); - if (pa_parsehex(v, blob, (e-v)/2) != (size_t)((e-v)/2)) { - pa_log("Invalid \"hex:\" value data"); - pa_xfree(blob); - break; - } + if (*p == 0) + goto success; - pa_proplist_set(p, k, blob, (e-v)/2); - pa_xfree(blob); + state = WHITESPACE; + } else + goto fail; + break; } } - pa_xfree(s); +success: + return MAKE_PROPLIST(pl); - return p; +fail: + pa_proplist_free(pl); + return NULL; } int pa_proplist_contains(pa_proplist *p, const char *key) { diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h index 990ffd19..9e78aecd 100644 --- a/src/pulse/proplist.h +++ b/src/pulse/proplist.h @@ -136,7 +136,7 @@ PA_C_DECL_BEGIN #define PA_PROP_MODULE_USAGE "module.usage" #define PA_PROP_MODULE_VERSION "module.version" -/** A property list object. Basically a dictionary with UTF-8 strings +/** A property list object. Basically a dictionary with ASCII strings * as keys and arbitrary data as values. \since 0.9.11 */ typedef struct pa_proplist pa_proplist; @@ -194,6 +194,12 @@ typedef enum pa_update_mode { * list. */ } pa_update_mode_t; +/** \cond fulldocs */ +#define PA_UPDATE_SET PA_UPDATE_SET +#define PA_UPDATE_MERGE PA_UPDATE_MERGE +#define PA_UPDATE_REPLACE PA_UPDATE_REPLACE +/** \endcond */ + /** Merge property list "other" into "p", adhering the merge mode as * specified in "mode". \since 0.9.11 */ void pa_proplist_update(pa_proplist *p, pa_update_mode_t mode, pa_proplist *other); diff --git a/src/pulse/sample.c b/src/pulse/sample.c index a6c77345..4b13a337 100644 --- a/src/pulse/sample.c +++ b/src/pulse/sample.c @@ -36,7 +36,7 @@ #include "sample.h" -size_t pa_sample_size(const pa_sample_spec *spec) { +size_t pa_sample_size_of_format(pa_sample_format_t f) { static const size_t table[] = { [PA_SAMPLE_U8] = 1, @@ -54,32 +54,44 @@ size_t pa_sample_size(const pa_sample_spec *spec) { [PA_SAMPLE_S24_32BE] = 4 }; + pa_assert(f >= 0); + pa_assert(f < PA_SAMPLE_MAX); + + return table[f]; +} + +size_t pa_sample_size(const pa_sample_spec *spec) { + pa_assert(spec); - pa_assert(spec->format >= 0); - pa_assert(spec->format < PA_SAMPLE_MAX); + pa_return_val_if_fail(pa_sample_spec_valid(spec), 0); - return table[spec->format]; + return pa_sample_size_of_format(spec->format); } size_t pa_frame_size(const pa_sample_spec *spec) { pa_assert(spec); + pa_return_val_if_fail(pa_sample_spec_valid(spec), 0); return pa_sample_size(spec) * spec->channels; } size_t pa_bytes_per_second(const pa_sample_spec *spec) { pa_assert(spec); + pa_return_val_if_fail(pa_sample_spec_valid(spec), 0); + return spec->rate*pa_frame_size(spec); } pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) { pa_assert(spec); + pa_return_val_if_fail(pa_sample_spec_valid(spec), 0); return (((pa_usec_t) (length / pa_frame_size(spec)) * PA_USEC_PER_SEC) / spec->rate); } size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) { pa_assert(spec); + pa_return_val_if_fail(pa_sample_spec_valid(spec), 0); return (size_t) (((t * spec->rate) / PA_USEC_PER_SEC)) * pa_frame_size(spec); } @@ -112,6 +124,9 @@ int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) { pa_assert(a); pa_assert(b); + pa_return_val_if_fail(pa_sample_spec_valid(a), 0); + pa_return_val_if_fail(pa_sample_spec_valid(b), 0); + return (a->format == b->format) && (a->rate == b->rate) && @@ -143,7 +158,7 @@ const char *pa_sample_format_to_string(pa_sample_format_t f) { char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) { pa_assert(s); - pa_assert(l); + pa_assert(l > 0); pa_assert(spec); pa_init_i18n(); @@ -151,22 +166,25 @@ char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) { if (!pa_sample_spec_valid(spec)) pa_snprintf(s, l, _("(invalid)")); else - pa_snprintf(s, l, "%s %uch %uHz", pa_sample_format_to_string(spec->format), spec->channels, spec->rate); + pa_snprintf(s, l, _("%s %uch %uHz"), pa_sample_format_to_string(spec->format), spec->channels, spec->rate); return s; } char* pa_bytes_snprint(char *s, size_t l, unsigned v) { pa_assert(s); + pa_assert(l > 0); + + pa_init_i18n(); if (v >= ((unsigned) 1024)*1024*1024) - pa_snprintf(s, l, "%0.1f GiB", ((double) v)/1024/1024/1024); + pa_snprintf(s, l, _("%0.1f GiB"), ((double) v)/1024/1024/1024); else if (v >= ((unsigned) 1024)*1024) - pa_snprintf(s, l, "%0.1f MiB", ((double) v)/1024/1024); + pa_snprintf(s, l, _("%0.1f MiB"), ((double) v)/1024/1024); else if (v >= (unsigned) 1024) - pa_snprintf(s, l, "%0.1f KiB", ((double) v)/1024); + pa_snprintf(s, l, _("%0.1f KiB"), ((double) v)/1024); else - pa_snprintf(s, l, "%u B", (unsigned) v); + pa_snprintf(s, l, _("%u B"), (unsigned) v); return s; } diff --git a/src/pulse/sample.h b/src/pulse/sample.h index 45a481fe..3c05b54a 100644 --- a/src/pulse/sample.h +++ b/src/pulse/sample.h @@ -261,6 +261,10 @@ size_t pa_frame_size(const pa_sample_spec *spec) PA_GCC_PURE; /** Return the size of a sample with the specific sample type */ size_t pa_sample_size(const pa_sample_spec *spec) PA_GCC_PURE; +/** Similar to pa_sample_size() but take a sample format instead of a + * full sample spec. \since 0.9.15 */ +size_t pa_sample_size_of_format(pa_sample_format_t f) PA_GCC_PURE; + /** Calculate the time the specified bytes take to play with the * specified sample type. The return value will always be rounded * down for non-integral return values. */ diff --git a/src/pulse/utf8.c b/src/pulse/utf8.c index 7671be46..6b58bde3 100644 --- a/src/pulse/utf8.c +++ b/src/pulse/utf8.c @@ -263,3 +263,29 @@ char* pa_locale_to_utf8 (const char *str) { } #endif + +char *pa_ascii_valid(const char *str) { + const char *p; + pa_assert(str); + + for (p = str; *p; p++) + if ((unsigned char) *p >= 128) + return NULL; + + return (char*) str; +} + +char *pa_ascii_filter(const char *str) { + char *r, *s, *d; + pa_assert(str); + + r = pa_xstrdup(str); + + for (s = r, d = r; *s; s++) + if ((unsigned char) *s < 128) + *(d++) = *s; + + *d = 0; + + return r; +} diff --git a/src/pulse/utf8.h b/src/pulse/utf8.h index 4d751953..b9f74952 100644 --- a/src/pulse/utf8.h +++ b/src/pulse/utf8.h @@ -36,9 +36,15 @@ PA_C_DECL_BEGIN /** Test if the specified strings qualifies as valid UTF8. Return the string if so, otherwise NULL */ char *pa_utf8_valid(const char *str) PA_GCC_PURE; +/** Test if the specified strings qualifies as valid 7-bit ASCII. Return the string if so, otherwise NULL. \since 0.9.15 */ +char *pa_ascii_valid(const char *str) PA_GCC_PURE; + /** Filter all invalid UTF8 characters from the specified string, returning a new fully UTF8 valid string. Don't forget to free the returned string with pa_xfree() */ char *pa_utf8_filter(const char *str); +/** Filter all invalid ASCII characters from the specified string, returning a new fully ASCII valid string. Don't forget to free the returned string with pa_xfree(). \since 0.9.15 */ +char *pa_ascii_filter(const char *str); + /** Convert a UTF-8 string to the current locale. Free the string using pa_xfree(). */ char* pa_utf8_to_locale (const char *str); diff --git a/src/pulse/volume.c b/src/pulse/volume.c index ba2ee8fb..54838e89 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -37,6 +37,9 @@ int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { pa_assert(a); pa_assert(b); + pa_return_val_if_fail(pa_cvolume_valid(a), 0); + pa_return_val_if_fail(pa_cvolume_valid(b), 0); + if (a->channels != b->channels) return 0; @@ -78,7 +81,9 @@ pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) { pa_volume_t pa_cvolume_avg(const pa_cvolume *a) { uint64_t sum = 0; int i; + pa_assert(a); + pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); for (i = 0; i < a->channels; i++) sum += a->values[i]; @@ -91,7 +96,9 @@ pa_volume_t pa_cvolume_avg(const pa_cvolume *a) { pa_volume_t pa_cvolume_max(const pa_cvolume *a) { pa_volume_t m = 0; int i; + pa_assert(a); + pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); for (i = 0; i < a->channels; i++) if (a->values[i] > m) @@ -247,11 +254,12 @@ char *pa_sw_volume_snprint_dB(char *s, size_t l, pa_volume_t v) { return s; } -/** Return non-zero if the volume of all channels is equal to the specified value */ int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { unsigned c; pa_assert(a); + pa_return_val_if_fail(pa_cvolume_valid(a), 0); + for (c = 0; c < a->channels; c++) if (a->values[c] != v) return 0; @@ -266,6 +274,9 @@ pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_assert(a); pa_assert(b); + 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++) dest->values[i] = pa_sw_volume_multiply(a->values[i], b->values[i]); @@ -281,6 +292,9 @@ pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa pa_assert(a); pa_assert(b); + 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++) dest->values[i] = pa_sw_volume_divide(a->values[i], b->values[i]); @@ -373,7 +387,11 @@ pa_cvolume *pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa pa_assert(v); pa_assert(from); pa_assert(to); - pa_assert(v->channels == from->channels); + + pa_return_val_if_fail(pa_cvolume_valid(v), NULL); + pa_return_val_if_fail(pa_channel_map_valid(from), NULL); + pa_return_val_if_fail(pa_channel_map_valid(to), NULL); + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, from), NULL); if (pa_channel_map_equal(from, to)) return v; @@ -419,15 +437,22 @@ int pa_cvolume_compatible(const pa_cvolume *v, const pa_sample_spec *ss) { pa_assert(v); pa_assert(ss); - if (!pa_cvolume_valid(v)) - return 0; - - if (!pa_sample_spec_valid(ss)) - return 0; + pa_return_val_if_fail(pa_cvolume_valid(v), 0); + pa_return_val_if_fail(pa_sample_spec_valid(ss), 0); return v->channels == ss->channels; } +int pa_cvolume_compatible_with_channel_map(const pa_cvolume *v, const pa_channel_map *cm) { + pa_assert(v); + pa_assert(cm); + + pa_return_val_if_fail(pa_cvolume_valid(v), 0); + pa_return_val_if_fail(pa_channel_map_valid(cm), 0); + + return v->channels == cm->channels; +} + static void get_avg_lr(const pa_channel_map *map, const pa_cvolume *v, pa_volume_t *l, pa_volume_t *r) { int c; pa_volume_t left = 0, right = 0; @@ -465,7 +490,13 @@ float pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) { pa_assert(v); pa_assert(map); - pa_assert(map->channels == v->channels); + + pa_return_val_if_fail(pa_cvolume_valid(v), 0.0f); + pa_return_val_if_fail(pa_channel_map_valid(map), 0.0f); + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f); + + if (!pa_channel_map_can_balance(map)) + return 0.0f; get_avg_lr(map, v, &left, &right); @@ -491,12 +522,18 @@ pa_cvolume* pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, flo pa_volume_t left, nleft, right, nright, m; unsigned c; - pa_assert(map->channels == v->channels); pa_assert(map); pa_assert(v); pa_assert(new_balance >= -1.0f); pa_assert(new_balance <= 1.0f); + pa_return_val_if_fail(pa_cvolume_valid(v), NULL); + pa_return_val_if_fail(pa_channel_map_valid(map), NULL); + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); + + if (!pa_channel_map_can_balance(map)) + return v; + get_avg_lr(map, v, &left, &right); m = PA_MAX(left, right); @@ -532,6 +569,9 @@ pa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max) { pa_assert(v); + pa_return_val_if_fail(pa_cvolume_valid(v), NULL); + pa_return_val_if_fail(max != (pa_volume_t) -1, NULL); + for (c = 0; c < v->channels; c++) if (v->values[c] > t) t = v->values[c]; @@ -582,7 +622,13 @@ float pa_cvolume_get_fade(const pa_cvolume *v, const pa_channel_map *map) { pa_assert(v); pa_assert(map); - pa_assert(map->channels == v->channels); + + pa_return_val_if_fail(pa_cvolume_valid(v), 0.0f); + pa_return_val_if_fail(pa_channel_map_valid(map), 0.0f); + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f); + + if (!pa_channel_map_can_fade(map)) + return 0.0f; get_avg_fr(map, v, &front, &rear); @@ -599,12 +645,18 @@ pa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float pa_volume_t front, nfront, rear, nrear, m; unsigned c; - pa_assert(map->channels == v->channels); pa_assert(map); pa_assert(v); pa_assert(new_fade >= -1.0f); pa_assert(new_fade <= 1.0f); + pa_return_val_if_fail(pa_cvolume_valid(v), NULL); + pa_return_val_if_fail(pa_channel_map_valid(map), NULL); + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); + + if (!pa_channel_map_can_fade(map)) + return v; + get_avg_fr(map, v, &front, &rear); m = PA_MAX(front, rear); diff --git a/src/pulse/volume.h b/src/pulse/volume.h index 8eef467f..8bfd0687 100644 --- a/src/pulse/volume.h +++ b/src/pulse/volume.h @@ -230,13 +230,19 @@ double pa_sw_volume_to_linear(pa_volume_t v) PA_GCC_CONST; /** Remap a volume from one channel mapping to a different channel mapping. \since 0.9.12 */ pa_cvolume *pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa_channel_map *to); -/** Return non-zero if the specified volume is compatible with - * the specified sample spec. \since 0.9.13 */ +/** Return non-zero if the specified volume is compatible with the + * specified sample spec. \since 0.9.13 */ int pa_cvolume_compatible(const pa_cvolume *v, const pa_sample_spec *ss) PA_GCC_PURE; +/** Return non-zero if the specified volume is compatible with the + * specified sample spec. \since 0.9.15 */ +int pa_cvolume_compatible_with_channel_map(const pa_cvolume *v, const pa_channel_map *cm) PA_GCC_PURE; + /** Calculate a 'balance' value for the specified volume with the * specified channel map. The return value will range from -1.0f - * (left) to +1.0f (right) \since 0.9.15 */ + * (left) to +1.0f (right). If no balance value is applicable to this + * channel map the return value will always be 0.0f. See + * pa_channel_map_can_balance(). \since 0.9.15 */ float pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) PA_GCC_PURE; /** Adjust the 'balance' value for the specified volume with the @@ -245,22 +251,27 @@ float pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) PA_ * operation might not be reversible! Also, after this call * pa_cvolume_get_balance() is not guaranteed to actually return the * requested balance value (e.g. when the input volume was zero anyway for - * all channels) \since 0.9.15 */ + * all channels). If no balance value is applicable to + * this channel map the volume will not be modified. See + * pa_channel_map_can_balance(). \since 0.9.15 */ pa_cvolume* pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance); /** Calculate a 'fade' value (i.e. 'balance' between front and rear) * for the specified volume with the specified channel map. The return - * value will range from -1.0f (rear) to +1.0f (left) \since - * 0.9.15 */ + * value will range from -1.0f (rear) to +1.0f (left). If no fade + * value is applicable to this channel map the return value will + * always be 0.0f. See pa_channel_map_can_fade(). \since 0.9.15 */ float pa_cvolume_get_fade(const pa_cvolume *v, const pa_channel_map *map) PA_GCC_PURE; /** Adjust the 'fade' value (i.e. 'balance' between front and rear) * for the specified volume with the specified channel map. v will be * modified in place and returned. The balance is a value between * -1.0f and +1.0f. This operation might not be reversible! Also, - * after this call pa_cvolume_get_fade() is not guaranteed to - * actually return the requested fade value (e.g. when the input volume - * was zero anyway for all channels) \since 0.9.15 */ + * after this call pa_cvolume_get_fade() is not guaranteed to actually + * return the requested fade value (e.g. when the input volume was + * zero anyway for all channels). If no fade value is applicable to + * this channel map the volume will not be modified. See + * pa_channel_map_can_fade(). \since 0.9.15 */ pa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float new_fade); /** Scale the passed pa_cvolume structure so that the maximum volume |