man/pactl.1.xml.in | 8 +++ src/modules/alsa/alsa-sink.c | 69 +++++++++++++++++++++++++++++++++ src/modules/module-device-restore.c | 57 ++++++++++++++++++++++----- src/pulse/format.c | 75 ++++++++++++++++++++++++++++++------ src/pulse/format.h | 7 +++ src/pulsecore/sink.c | 16 +++++++ src/pulsecore/sink.h | 11 ++++- src/utils/pactl.c | 66 ++++++++++++++++++++++++++++++- 8 files changed, 282 insertions(+), 27 deletions(-)
New commits: commit 50b420aebd876557a64f9015e1197e7d12201f5f Author: Arun Raghavan <arun.ragha...@collabora.co.uk> Date: Mon Aug 15 12:07:02 2011 +0530 device-restore: Log invalid sink index while setting formats This makes it easier to catch errors when using 'pactl set-sink-formats' diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c index 671ffd4..6c5c27e 100644 --- a/src/modules/module-device-restore.c +++ b/src/modules/module-device-restore.c @@ -826,8 +826,10 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio } /* Now find our sink */ - if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index))) + if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index))) { + pa_log("Could not find sink #%d", sink_index); goto fail; + } /* Read or create an entry */ name = pa_sprintf_malloc("sink:%s", sink->name); commit b9d517cd515a6d53de592b7c33e47caaff738b6c Author: Arun Raghavan <arun.ragha...@collabora.co.uk> Date: Mon Aug 15 11:23:59 2011 +0530 sink: Fix lazy commenting diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 0bd5e81..3f89784 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -217,17 +217,17 @@ struct pa_sink { /* Called whenever the port shall be changed. Called from main * thread. */ - int (*set_port)(pa_sink *s, pa_device_port *port); /* ditto */ + int (*set_port)(pa_sink *s, pa_device_port *port); /* may be NULL */ /* Called to get the list of formats supported by the sink, sorted * in descending order of preference. */ - pa_idxset* (*get_formats)(pa_sink *s); /* ditto */ + pa_idxset* (*get_formats)(pa_sink *s); /* may be NULL */ /* Called to set the list of formats supported by the sink. Can be * NULL if the sink does not support this. Returns TRUE on success, * FALSE otherwise (for example when an unsupportable format is * set). Makes a copy of the formats passed in. */ - pa_bool_t (*set_formats)(pa_sink *s, pa_idxset *formats); /* ditto */ + pa_bool_t (*set_formats)(pa_sink *s, pa_idxset *formats); /* may be NULL */ /* Contains copies of the above data so that the real-time worker * thread can work without access locking */ commit 0f3be7b72b2a1ba72a209628e19789dcf8132f11 Author: Arun Raghavan <arun.ragha...@collabora.co.uk> Date: Mon Aug 15 09:47:09 2011 +0530 pactl: Add a set-sink-formats command This uses the module-device-restore protocol extension to save formats on sinks that support it. diff --git a/man/pactl.1.xml.in b/man/pactl.1.xml.in index 3a70fb6..f0060fb 100644 --- a/man/pactl.1.xml.in +++ b/man/pactl.1.xml.in @@ -218,6 +218,14 @@ USA. </option> <option> + <p><opt>set-sink-formats</opt> <arg>SINK</arg> <arg>FORMATS</arg></p> + <optdesc><p>Set the supported formats of the specified sink (identified by its numerical index) if supported by the sink. + <arg>FORMATS</arg> is specified as a semi-colon (;) separated list of formats in the form + 'encoding[, key1=value1, key2=value2, ...]' (for example, AC3 at 32000, 44100 and 48000 Hz would be specified as + 'ac3-iec61937, format.rate = "[ 32000, 44100, 48000 ]"'). + </p></optdesc> </option> + + <option> <p><opt>subscribe</opt></p> <optdesc><p>Subscribe to events, pactl does not exit by itself, but keeps waiting for new events.</p></optdesc> </option> diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 2c5be93..947c6e9 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -36,6 +36,7 @@ #include <sndfile.h> #include <pulse/pulseaudio.h> +#include <pulse/ext-device-restore.h> #include <pulsecore/i18n.h> #include <pulsecore/macro.h> @@ -55,11 +56,13 @@ static char *module_args = NULL, *card_name = NULL, *profile_name = NULL, - *port_name = NULL; + *port_name = NULL, + *formats = NULL; static uint32_t sink_input_idx = PA_INVALID_INDEX, - source_output_idx = PA_INVALID_INDEX; + source_output_idx = PA_INVALID_INDEX, + sink_idx = PA_INVALID_INDEX; static pa_bool_t short_list_format = FALSE; static uint32_t module_index; @@ -111,6 +114,7 @@ static enum { SET_SINK_MUTE, SET_SOURCE_MUTE, SET_SINK_INPUT_MUTE, + SET_SINK_FORMATS, SUBSCRIBE } action = NONE; @@ -882,6 +886,44 @@ static void get_source_output_volume_callback(pa_context *c, const pa_source_out pa_operation_unref(pa_context_set_source_output_volume(c, source_output_idx, &cv, simple_callback, NULL)); } +/* PA_MAX_FORMATS is defined in internal.h so we just define a sane value here */ +#define MAX_FORMATS 256 + +static void set_sink_formats(pa_context *c, uint32_t sink, const char *str) { + pa_format_info *f_arr[MAX_FORMATS]; + char *format = NULL; + const char *state = NULL; + int i = 0; + + while ((format = pa_split(str, ";", &state))) { + pa_format_info *f = pa_format_info_from_string(pa_strip(format)); + + if (!f) { + pa_log(_("Failed to set format: invalid format string %s"), format); + goto error; + } + + f_arr[i++] = f; + pa_xfree(format); + } + + pa_operation_unref(pa_ext_device_restore_save_sink_formats(c, sink, i, f_arr, simple_callback, NULL)); + +done: + if (format) + pa_xfree(format); + while(i--) + pa_format_info_free(f_arr[i]); + + return; + +error: + while(i--) + pa_format_info_free(f_arr[i]); + quit(1); + goto done; +} + static void stream_state_callback(pa_stream *s, void *userdata) { pa_assert(s); @@ -1157,6 +1199,10 @@ static void context_state_callback(pa_context *c, void *userdata) { } break; + case SET_SINK_FORMATS: + set_sink_formats(c, sink_idx, formats); + break; + case SUBSCRIBE: pa_context_set_subscribe_callback(c, context_subscribe_callback, NULL); @@ -1270,6 +1316,7 @@ static void help(const char *argv0) { printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink-input|source-output)-volume", _("#N VOLUME")); printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink|source)-mute", _("NAME|#N 1|0")); printf("%s %s %s %s\n", argv0, _("[options]"), "set-sink-input-mute", _("#N 1|0")); + printf("%s %s %s %s\n", argv0, _("[options]"), "set-sink-formats", _("#N FORMATS")); printf("%s %s %s\n", argv0, _("[options]"), "subscribe"); printf(_("\n" @@ -1662,7 +1709,19 @@ int main(int argc, char *argv[]) { action = SUBSCRIBE; - else if (pa_streq(argv[optind], "help")) { + else if (pa_streq(argv[optind], "set-sink-formats")) { + int32_t tmp; + + if (argc != optind+3 || pa_atoi(argv[optind+1], &tmp) < 0) { + pa_log(_("You have to specify a sink index and a semicolon-separated list of supported formats")); + goto quit; + } + + sink_idx = tmp; + action = SET_SINK_FORMATS; + formats = pa_xstrdup(argv[optind+2]); + + } else if (pa_streq(argv[optind], "help")) { help(bn); ret = 0; goto quit; @@ -1723,6 +1782,7 @@ quit: pa_xfree(card_name); pa_xfree(profile_name); pa_xfree(port_name); + pa_xfree(formats); if (sndfile) sf_close(sndfile); commit 8bffbcde1b9ac41703be9c242f4f9f172d5649bb Author: Arun Raghavan <arun.ragha...@collabora.co.uk> Date: Fri Aug 12 21:55:48 2011 +0530 format: Add string to pa_format_info conversion function This will help accept string formats from the command like (so we can set formats using pactl). diff --git a/src/pulse/format.c b/src/pulse/format.c index 112b103..f4eed83 100644 --- a/src/pulse/format.c +++ b/src/pulse/format.c @@ -41,20 +41,30 @@ static int pa_format_info_prop_compatible(const char *one, const char *two); -const char *pa_encoding_to_string(pa_encoding_t e) { - static const char* const table[]= { - [PA_ENCODING_PCM] = "pcm", - [PA_ENCODING_AC3_IEC61937] = "ac3-iec61937", - [PA_ENCODING_EAC3_IEC61937] = "eac3-iec61937", - [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937", - [PA_ENCODING_DTS_IEC61937] = "dts-iec61937", - [PA_ENCODING_ANY] = "any", - }; +static const char* const _encoding_str_table[]= { + [PA_ENCODING_PCM] = "pcm", + [PA_ENCODING_AC3_IEC61937] = "ac3-iec61937", + [PA_ENCODING_EAC3_IEC61937] = "eac3-iec61937", + [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937", + [PA_ENCODING_DTS_IEC61937] = "dts-iec61937", + [PA_ENCODING_ANY] = "any", +}; +const char *pa_encoding_to_string(pa_encoding_t e) { if (e < 0 || e >= PA_ENCODING_MAX) return NULL; - return table[e]; + return _encoding_str_table[e]; +} + +pa_encoding_t pa_encoding_from_string(const char *encoding) { + pa_encoding_t e; + + for (e = PA_ENCODING_ANY; e < PA_ENCODING_MAX; e++) + if (pa_streq(_encoding_str_table[e], encoding)) + return e; + + return PA_ENCODING_INVALID; } pa_format_info* pa_format_info_new(void) { @@ -125,6 +135,44 @@ char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) { return s; } +pa_format_info* pa_format_info_from_string(const char *str) { + pa_format_info *f = pa_format_info_new(); + char *encoding = NULL, *properties = NULL; + size_t pos; + + pos = strcspn(str, ","); + + encoding = pa_xstrndup(str, pos); + f->encoding = pa_encoding_from_string(pa_strip(encoding)); + if (f->encoding == PA_ENCODING_INVALID) + goto error; + + if (pos != strlen(str)) { + pa_proplist *plist; + + properties = pa_xstrdup(&str[pos+1]); + plist = pa_proplist_from_string(properties); + + if (!plist) + goto error; + + pa_proplist_free(f->plist); + f->plist = plist; + } + +out: + if (encoding) + pa_xfree(encoding); + if (properties) + pa_xfree(properties); + return f; + +error: + pa_format_info_free(f); + f = NULL; + goto out; +} + int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second) { const char *key; void *state = NULL; diff --git a/src/pulse/format.h b/src/pulse/format.h index 821149c..b8b829e 100644 --- a/src/pulse/format.h +++ b/src/pulse/format.h @@ -62,6 +62,9 @@ typedef enum pa_encoding { /** Returns a printable string representing the given encoding type. \since 1.0 */ const char *pa_encoding_to_string(pa_encoding_t e) PA_GCC_CONST; +/** Converts a string of the form returned by \a pa_encoding_to_string() back to a \a pa_encoding_t. \since 1.0 */ +pa_encoding_t pa_encoding_from_string(const char *encoding); + /**< Represents the format of data provided in a stream or processed by a sink. \since 1.0 */ typedef struct pa_format_info { pa_encoding_t encoding; @@ -105,6 +108,10 @@ int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second); /** Return a human-readable string representing the given format. \since 1.0 */ char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f); +/** Parse a human-readable string of the form generated by + * \a pa_format_info_snprint() into a pa_format_info structure. \since 1.0 */ +pa_format_info* pa_format_info_from_string(const char *str); + /** Sets an integer property on the given format info */ void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value); /** Sets a property with a list of integer values on the given format info */ commit 348c51bfcdfa58bc99e44329b3aa1067adc0e920 Author: Arun Raghavan <arun.ragha...@collabora.co.uk> Date: Fri Aug 12 21:04:38 2011 +0530 format: Make pa_format_info_snprint() more parseable Removes the comma as the proplist separator since that makes pa_proplist_from_string() break and prints only the encoding if there are no properties (instead of "<encoding>, (no properties)"). diff --git a/src/pulse/format.c b/src/pulse/format.c index 81c329f..112b103 100644 --- a/src/pulse/format.c +++ b/src/pulse/format.c @@ -114,8 +114,11 @@ char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) { if (!pa_format_info_valid(f)) pa_snprintf(s, l, _("(invalid)")); else { - tmp = pa_proplist_to_string_sep(f->plist, ", "); - pa_snprintf(s, l, _("%s, %s"), pa_encoding_to_string(f->encoding), tmp[0] ? tmp : _("(no properties)")); + tmp = pa_proplist_to_string_sep(f->plist, " "); + if (tmp[0]) + pa_snprintf(s, l, "%s, %s", pa_encoding_to_string(f->encoding), tmp); + else + pa_snprintf(s, l, "%s", pa_encoding_to_string(f->encoding)); pa_xfree(tmp); } commit 248394c8bfdaea5b57e2e68df89bebb498b22601 Author: Arun Raghavan <arun.ragha...@collabora.co.uk> Date: Fri Aug 12 20:27:34 2011 +0530 device-restore: Set sink format when possible This implements the actual setting of sink formats when a new sink is added or when the set of available formats changes. diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c index 9441813..671ffd4 100644 --- a/src/modules/module-device-restore.c +++ b/src/modules/module-device-restore.c @@ -63,7 +63,8 @@ PA_MODULE_LOAD_ONCE(TRUE); PA_MODULE_USAGE( "restore_port=<Save/restore port?> " "restore_volume=<Save/restore volumes?> " - "restore_muted=<Save/restore muted states?>"); + "restore_muted=<Save/restore muted states?> " + "restore_formats=<Save/restore saved formats?>"); #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC) @@ -71,6 +72,7 @@ static const char* const valid_modargs[] = { "restore_volume", "restore_muted", "restore_port", + "restore_formats", NULL }; @@ -81,6 +83,7 @@ struct userdata { pa_hook_slot *sink_new_hook_slot, *sink_fixate_hook_slot, + *sink_put_hook_slot, *source_new_hook_slot, *source_fixate_hook_slot, *connection_unlink_hook_slot; @@ -93,6 +96,7 @@ struct userdata { pa_bool_t restore_volume; pa_bool_t restore_muted; pa_bool_t restore_port; + pa_bool_t restore_formats; }; /* Protocol extention commands */ @@ -590,6 +594,30 @@ static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data * return PA_HOOK_OK; } +static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) { + char *name; + struct entry *e; + + pa_assert(c); + pa_assert(sink); + pa_assert(u); + pa_assert(u->restore_formats); + + name = pa_sprintf_malloc("sink:%s", sink->name); + + if ((e = entry_read(u, name))) { + + if (!pa_sink_set_formats(sink, e->formats)) + pa_log_debug("Could not set format on sink %s", sink->name); + + entry_free(e); + } + + pa_xfree(name); + + return PA_HOOK_OK; +} + static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) { char *name; struct entry *e; @@ -828,7 +856,7 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio goto fail; } - if (entry_write(u, name, e)) + if (pa_sink_set_formats(sink, e->formats) && entry_write(u, name, e)) trigger_save(u, sink_index); else pa_log_warn("Could not save format info for sink %s", sink->name); @@ -870,7 +898,7 @@ int pa__init(pa_module*m) { pa_sink *sink; pa_source *source; uint32_t idx; - pa_bool_t restore_volume = TRUE, restore_muted = TRUE, restore_port = TRUE; + pa_bool_t restore_volume = TRUE, restore_muted = TRUE, restore_port = TRUE, restore_formats = TRUE; pa_assert(m); @@ -881,12 +909,13 @@ int pa__init(pa_module*m) { if (pa_modargs_get_value_boolean(ma, "restore_volume", &restore_volume) < 0 || pa_modargs_get_value_boolean(ma, "restore_muted", &restore_muted) < 0 || - pa_modargs_get_value_boolean(ma, "restore_port", &restore_port) < 0) { - pa_log("restore_port=, restore_volume= and restore_muted= expect boolean arguments"); + pa_modargs_get_value_boolean(ma, "restore_port", &restore_port) < 0 || + pa_modargs_get_value_boolean(ma, "restore_formats", &restore_formats) < 0) { + pa_log("restore_port, restore_volume, restore_muted and restore_formats expect boolean arguments"); goto fail; } - if (!restore_muted && !restore_volume && !restore_port) + if (!restore_muted && !restore_volume && !restore_port && !restore_formats) pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring port enabled!"); m->userdata = u = pa_xnew0(struct userdata, 1); @@ -895,6 +924,7 @@ int pa__init(pa_module*m) { u->restore_volume = restore_volume; u->restore_muted = restore_muted; u->restore_port = restore_port; + u->restore_formats = restore_formats; u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); @@ -915,6 +945,9 @@ int pa__init(pa_module*m) { u->source_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) source_fixate_hook_callback, u); } + if (restore_formats) + u->sink_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) sink_put_hook_callback, u); + if (!(fname = pa_state_path("device-volumes", TRUE))) goto fail; @@ -964,6 +997,8 @@ void pa__done(pa_module*m) { pa_hook_slot_free(u->sink_new_hook_slot); if (u->source_new_hook_slot) pa_hook_slot_free(u->source_new_hook_slot); + if (u->sink_put_hook_slot) + pa_hook_slot_free(u->sink_put_hook_slot); if (u->connection_unlink_hook_slot) pa_hook_slot_free(u->connection_unlink_hook_slot); commit ba163b8b23bcd72c35b028eb0b43c31a6ae1724d Author: Arun Raghavan <arun.ragha...@collabora.co.uk> Date: Fri Aug 12 19:33:41 2011 +0530 device-restore: Make bools not be bit fields This makes the pa_bool_t members of userdata not be a single bit field since pa_bool_t can be an int, potentially causing signedness issues in comparisons. diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c index 75b1e40..9441813 100644 --- a/src/modules/module-device-restore.c +++ b/src/modules/module-device-restore.c @@ -90,9 +90,9 @@ struct userdata { pa_native_protocol *protocol; pa_idxset *subscribed; - pa_bool_t restore_volume:1; - pa_bool_t restore_muted:1; - pa_bool_t restore_port:1; + pa_bool_t restore_volume; + pa_bool_t restore_muted; + pa_bool_t restore_port; }; /* Protocol extention commands */ commit 51fcee89029063998913d1ccab7df54134d72b8d Author: Arun Raghavan <arun.ragha...@collabora.co.uk> Date: Fri Aug 12 16:36:00 2011 +0530 alsa: Implement get/set_formats() This implements the sink get_formats() and set_formats() API in alsa-sink. Modules can use this to allow users to specify what formats their receivers support. diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index c4aa75b..44331a3 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -36,6 +36,7 @@ #include <pulse/timeval.h> #include <pulse/volume.h> #include <pulse/xmalloc.h> +#include <pulse/internal.h> #include <pulsecore/core.h> #include <pulsecore/i18n.h> @@ -144,6 +145,8 @@ struct userdata { pa_usec_t smoother_interval; pa_usec_t last_smoother_update; + pa_idxset *formats; + pa_reserve_wrapper *reserve; pa_hook_slot *reserve_slot; pa_reserve_monitor_wrapper *monitor; @@ -152,6 +155,15 @@ struct userdata { static void userdata_free(struct userdata *u); +/* FIXME: Is there a better way to do this than device names? */ +static pa_bool_t is_iec958(struct userdata *u) { + return (strncmp("iec958", u->device_name, 6) == 0); +} + +static pa_bool_t is_hdmi(struct userdata *u) { + return (strncmp("hdmi", u->device_name, 4) == 0); +} + static pa_hook_result_t reserve_cb(pa_reserve_wrapper *r, void *forced, struct userdata *u) { pa_assert(r); pa_assert(u); @@ -1475,6 +1487,45 @@ static void sink_update_requested_latency_cb(pa_sink *s) { } } +static pa_idxset* sink_get_formats(pa_sink *s) { + struct userdata *u = s->userdata; + pa_idxset *ret = pa_idxset_new(NULL, NULL); + pa_format_info *f; + uint32_t idx; + + pa_assert(u); + + PA_IDXSET_FOREACH(f, u->formats, idx) { + pa_idxset_put(ret, pa_format_info_copy(f), NULL); + } + + return ret; +} + +static pa_bool_t sink_set_formats(pa_sink *s, pa_idxset *formats) { + struct userdata *u = s->userdata; + pa_format_info *f; + uint32_t idx; + + pa_assert(u); + + /* FIXME: also validate sample rates against what the device supports */ + PA_IDXSET_FOREACH(f, formats, idx) { + if (is_iec958(u) && f->encoding == PA_ENCODING_EAC3_IEC61937) + /* EAC3 cannot be sent over over S/PDIF */ + return FALSE; + } + + pa_idxset_free(u->formats, (pa_free2_cb_t) pa_format_info_free2, NULL); + u->formats = pa_idxset_new(NULL, NULL); + + PA_IDXSET_FOREACH(f, formats, idx) { + pa_idxset_put(u->formats, pa_format_info_copy(f), NULL); + } + + return TRUE; +} + static int process_rewind(struct userdata *u) { snd_pcm_sframes_t unused; size_t rewind_nbytes, unused_nbytes, limit_nbytes; @@ -2182,6 +2233,21 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca if ((data.volume_is_set || data.muted_is_set) && u->sink->write_volume) u->sink->write_volume(u->sink); + if (is_iec958(u) || is_hdmi(u)) { + /* For S/PDIF and HDMI, allow getting/setting custom formats */ + pa_format_info *format; + + /* To start with, we only support PCM formats. Other formats may be added + * with pa_sink_set_formats().*/ + format = pa_format_info_new(); + format->encoding = PA_ENCODING_PCM; + u->formats = pa_idxset_new(NULL, NULL); + pa_idxset_put(u->formats, format, NULL); + + u->sink->get_formats = sink_get_formats; + u->sink->set_formats = sink_set_formats; + } + pa_sink_put(u->sink); if (profile_set) @@ -2247,6 +2313,9 @@ static void userdata_free(struct userdata *u) { if (u->smoother) pa_smoother_free(u->smoother); + if (u->formats) + pa_idxset_free(u->formats, (pa_free2_cb_t) pa_format_info_free2, NULL); + reserve_done(u); monitor_done(u); commit 485d4dd54260b680b0e5d0af35ad380280a4c826 Author: Arun Raghavan <arun.ragha...@collabora.co.uk> Date: Fri Aug 12 16:34:28 2011 +0530 sink: Add a set_formats() API This adds API to let external sources specify what formats a sink supports. Sinks must opt-in to allow this, and can perform some validation if required. diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 42a8eb3..6277698 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -180,6 +180,7 @@ static void reset_callbacks(pa_sink *s) { s->update_requested_latency = NULL; s->set_port = NULL; s->get_formats = NULL; + s->set_formats = NULL; } /* Called from main context */ @@ -3429,6 +3430,21 @@ pa_idxset* pa_sink_get_formats(pa_sink *s) { } /* Called from the main thread */ +/* Allows an external source to set what formats a sink supports if the sink + * permits this. The function makes a copy of the formats on success. */ +pa_bool_t pa_sink_set_formats(pa_sink *s, pa_idxset *formats) { + pa_assert(s); + pa_assert(formats); + + if (s->set_formats) + /* Sink supports setting formats -- let's give it a shot */ + return s->set_formats(s, formats); + else + /* Sink doesn't support setting this -- bail out */ + return FALSE; +} + +/* Called from the main thread */ /* Checks if the sink can accept this format */ pa_bool_t pa_sink_check_format(pa_sink *s, pa_format_info *f) { diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 8aa04b8..0bd5e81 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -223,6 +223,12 @@ struct pa_sink { * in descending order of preference. */ pa_idxset* (*get_formats)(pa_sink *s); /* ditto */ + /* Called to set the list of formats supported by the sink. Can be + * NULL if the sink does not support this. Returns TRUE on success, + * FALSE otherwise (for example when an unsupportable format is + * set). Makes a copy of the formats passed in. */ + pa_bool_t (*set_formats)(pa_sink *s, pa_idxset *formats); /* ditto */ + /* Contains copies of the above data so that the real-time worker * thread can work without access locking */ struct { @@ -434,6 +440,7 @@ void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save); void pa_sink_move_all_fail(pa_queue *q); pa_idxset* pa_sink_get_formats(pa_sink *s); +pa_bool_t pa_sink_set_formats(pa_sink *s, pa_idxset *formats); pa_bool_t pa_sink_check_format(pa_sink *s, pa_format_info *f); pa_idxset* pa_sink_check_formats(pa_sink *s, pa_idxset *in_formats); _______________________________________________ pulseaudio-commits mailing list pulseaudio-commits@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-commits