[pulseaudio-commits] 17 commits - src/Makefile.am src/pulse src/pulsecore

Tanu Kaskinen tanuk at kemper.freedesktop.org
Fri Jan 10 00:18:11 PST 2014


 src/Makefile.am               |    2 
 src/pulse/def.h               |   38 +++++-
 src/pulse/format.c            |  116 +++++++-------------
 src/pulse/format.h            |   74 ++++++++++--
 src/pulse/stream.c            |    1 
 src/pulse/stream.h            |   17 ++
 src/pulsecore/core-format.c   |  243 ++++++++++++++++++++++++++++++++++++++++++
 src/pulsecore/core-format.h   |   81 ++++++++++++++
 src/pulsecore/sink-input.c    |  103 +++++++----------
 src/pulsecore/source-output.c |   98 ++++++----------
 src/pulsecore/stream-util.c   |   86 ++++++++++++++
 src/pulsecore/stream-util.h   |   50 ++++++++
 12 files changed, 695 insertions(+), 214 deletions(-)

New commits:
commit 56e007ebfbfecf7047ef4261e5834862a37e5742
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Wed Dec 18 18:28:55 2013 +0200

    format: Add some error logging

diff --git a/src/pulse/format.c b/src/pulse/format.c
index 6c34594..729c2d2 100644
--- a/src/pulse/format.c
+++ b/src/pulse/format.c
@@ -323,10 +323,13 @@ int pa_format_info_get_prop_int(const pa_format_info *f, const char *key, int *v
         return -PA_ERR_NOENTITY;
 
     o = json_tokener_parse(str);
-    if (is_error(o))
+    if (is_error(o)) {
+        pa_log_debug("Failed to parse format info property '%s'.", key);
         return -PA_ERR_INVALID;
+    }
 
     if (json_object_get_type(o) != json_type_int) {
+        pa_log_debug("Format info property '%s' type is not int.", key);
         json_object_put(o);
         return -PA_ERR_INVALID;
     }
@@ -352,8 +355,10 @@ int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key,
         return -PA_ERR_NOENTITY;
 
     o = json_tokener_parse(str);
-    if (is_error(o))
+    if (is_error(o)) {
+        pa_log_debug("Failed to parse format info property '%s'.", key);
         return -PA_ERR_INVALID;
+    }
 
     if (json_object_get_type(o) != json_type_object)
         goto out;
@@ -373,6 +378,9 @@ int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key,
     ret = 0;
 
 out:
+    if (ret < 0)
+        pa_log_debug("Format info property '%s' is not a valid int range.", key);
+
     json_object_put(o);
     return ret;
 }
@@ -392,8 +400,10 @@ int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key,
         return -PA_ERR_NOENTITY;
 
     o = json_tokener_parse(str);
-    if (is_error(o))
+    if (is_error(o)) {
+        pa_log_debug("Failed to parse format info property '%s'.", key);
         return -PA_ERR_INVALID;
+    }
 
     if (json_object_get_type(o) != json_type_array)
         goto out;
@@ -416,6 +426,9 @@ int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key,
     ret = 0;
 
 out:
+    if (ret < 0)
+        pa_log_debug("Format info property '%s' is not a valid int array.", key);
+
     json_object_put(o);
     return ret;
 }
@@ -433,10 +446,13 @@ int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, cha
         return -PA_ERR_NOENTITY;
 
     o = json_tokener_parse(str);
-    if (is_error(o))
+    if (is_error(o)) {
+        pa_log_debug("Failed to parse format info property '%s'.", key);
         return -PA_ERR_INVALID;
+    }
 
     if (json_object_get_type(o) != json_type_string) {
+        pa_log_debug("Format info property '%s' type is not string.", key);
         json_object_put(o);
         return -PA_ERR_INVALID;
     }
@@ -462,8 +478,10 @@ int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *ke
         return -PA_ERR_NOENTITY;
 
     o = json_tokener_parse(str);
-    if (is_error(o))
+    if (is_error(o)) {
+        pa_log_debug("Failed to parse format info property '%s'.", key);
         return -PA_ERR_INVALID;
+    }
 
     if (json_object_get_type(o) != json_type_array)
         goto out;
@@ -486,6 +504,9 @@ int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *ke
     ret = 0;
 
 out:
+    if (ret < 0)
+        pa_log_debug("Format info property '%s' is not a valid string array.", key);
+
     json_object_put(o);
     return ret;
 }

commit fdf72d3d21b7e8d88aac283293359c04b4877c77
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Wed Dec 4 06:18:42 2013 +0200

    stream: Mention pa_stream_new_extended() in the high-level stream creation documentation

diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index bec668f..49f5789 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -52,9 +52,14 @@
  * \section create_sec Creating
  *
  * To access a stream, a pa_stream object must be created using
- * pa_stream_new(). At this point the audio sample format and mapping of
- * channels must be specified. See \ref sample and \ref channelmap for more
- * information about those structures.
+ * pa_stream_new() or pa_stream_new_extended(). pa_stream_new() is for PCM
+ * streams only, while pa_stream_new_extended() can be used for both PCM and
+ * compressed audio streams. At this point the application must specify what
+ * stream format(s) it supports. See \ref sample and \ref channelmap for more
+ * information on the stream format parameters. FIXME: Those references only
+ * talk about PCM parameters, we should also have an overview page for how the
+ * pa_format_info based stream format configuration works. Bug filed:
+ * https://bugs.freedesktop.org/show_bug.cgi?id=72265
  *
  * This first step will only create a client-side object, representing the
  * stream. To use the stream, a server-side object must be created and

commit a36bf31cae89594b3d56f3264b85fded763fd567
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Tue Dec 17 23:42:09 2013 +0200

    stream: Improve pa_stream_connect_playback() documentation

diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index 40cbe64..bec668f 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -447,7 +447,11 @@ int pa_stream_is_corked(pa_stream *s);
  * making sure the volume passed here has always the same semantics as
  * the volume passed to pa_context_set_sink_input_volume(). It is possible
  * to figure out whether flat volume mode is in effect for a given sink
- * by calling pa_context_get_sink_info_by_name(). */
+ * by calling pa_context_get_sink_info_by_name().
+ *
+ * Since 5.0, it's possible to specify a single-channel volume even if the
+ * stream has multiple channels. In that case the same volume is applied to all
+ * channels. */
 int pa_stream_connect_playback(
         pa_stream *s                  /**< The stream to connect to a sink */,
         const char *dev               /**< Name of the sink to connect to, or NULL for default */ ,

commit 77ebb6567faec67c714c0c91ae1a3bf982197863
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Wed Dec 4 06:17:11 2013 +0200

    def, format: Document how to leave PCM parameters to be decided by the server

diff --git a/src/pulse/def.h b/src/pulse/def.h
index 58190cb..a01c902 100644
--- a/src/pulse/def.h
+++ b/src/pulse/def.h
@@ -232,20 +232,50 @@ typedef enum pa_stream_flags {
      * specified manual buffer metrics it is recommended to update
      * them with pa_stream_set_buffer_attr() to compensate for the
      * changed frame sizes. Only supported when the server is at least
-     * PA 0.9.8. It is ignored on older servers. \since 0.9.8 */
+     * PA 0.9.8. It is ignored on older servers.
+     *
+     * When creating streams with pa_stream_new_extended(), this flag has no
+     * effect. If you specify a format with PCM encoding, and you want the
+     * server to choose the sample format, then you should leave the sample
+     * format unspecified in the pa_format_info object. This also means that
+     * you can't use pa_format_info_from_sample_spec(), because that function
+     * always sets the sample format.
+     *
+     * \since 0.9.8 */
 
     PA_STREAM_FIX_RATE = 0x0080U,
     /**< Use the sample rate of the sink, and possibly ignore the rate
      * the sample spec contains. Usage similar to
-     * PA_STREAM_FIX_FORMAT.Only supported when the server is at least
-     * PA 0.9.8. It is ignored on older servers. \since 0.9.8 */
+     * PA_STREAM_FIX_FORMAT. Only supported when the server is at least
+     * PA 0.9.8. It is ignored on older servers.
+     *
+     * When creating streams with pa_stream_new_extended(), this flag has no
+     * effect. If you specify a format with PCM encoding, and you want the
+     * server to choose the sample rate, then you should leave the rate
+     * unspecified in the pa_format_info object. This also means that you can't
+     * use pa_format_info_from_sample_spec(), because that function always sets
+     * the sample rate.
+     *
+     * \since 0.9.8 */
 
     PA_STREAM_FIX_CHANNELS = 0x0100,
     /**< Use the number of channels and the channel map of the sink,
      * and possibly ignore the number of channels and the map the
      * sample spec and the passed channel map contains. Usage similar
      * to PA_STREAM_FIX_FORMAT. Only supported when the server is at
-     * least PA 0.9.8. It is ignored on older servers. \since 0.9.8 */
+     * least PA 0.9.8. It is ignored on older servers.
+     *
+     * When creating streams with pa_stream_new_extended(), this flag has no
+     * effect. If you specify a format with PCM encoding, and you want the
+     * server to choose the channel count and/or channel map, then you should
+     * leave the channels and/or the channel map unspecified in the
+     * pa_format_info object. This also means that you can't use
+     * pa_format_info_from_sample_spec(), because that function always sets
+     * the channel count (but if you only want to leave the channel map
+     * unspecified, then pa_format_info_from_sample_spec() works, because it
+     * accepts a NULL channel map).
+     *
+     * \since 0.9.8 */
 
     PA_STREAM_DONT_MOVE = 0x0200U,
     /**< Don't allow moving of this stream to another
diff --git a/src/pulse/format.h b/src/pulse/format.h
index e3c8f36..7284642 100644
--- a/src/pulse/format.h
+++ b/src/pulse/format.h
@@ -130,7 +130,18 @@ char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f);
  * \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);
 
-/** Utility function to take a \a pa_sample_spec and generate the corresponding \a pa_format_info. \since 2.0 */
+/** Utility function to take a \a pa_sample_spec and generate the corresponding
+ * \a pa_format_info.
+ *
+ * Note that if you want the server to choose some of the stream parameters,
+ * for example the sample rate, so that they match the device parameters, then
+ * you shouldn't use this function. In order to allow the server to choose
+ * a parameter value, that parameter must be left unspecified in the
+ * pa_format_info object, and this function always specifies all parameters. An
+ * exception is the channel map: if you pass NULL for the channel map, then the
+ * channel map will be left unspecified, allowing the server to choose it.
+ *
+ * \since 2.0 */
 pa_format_info* pa_format_info_from_sample_spec(const pa_sample_spec *ss, const pa_channel_map *map);
 
 /** Utility function to generate a \a pa_sample_spec and \a pa_channel_map corresponding to a given \a pa_format_info. The
@@ -204,13 +215,48 @@ void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const ch
 /** Sets a property with a list of string values on the given format info. \since 1.0 */
 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values);
 
-/** Convenience method to set the sample format as a property on the given format. \since 1.0 */
+/** Convenience method to set the sample format as a property on the given
+ * format.
+ *
+ * Note for PCM: If the sample format is left unspecified in the pa_format_info
+ * object, then the server will select the stream sample format. In that case
+ * the stream sample format will most likely match the device sample format,
+ * meaning that sample format conversion will be avoided.
+ *
+ * \since 1.0 */
 void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf);
-/** Convenience method to set the sampling rate as a property on the given format. \since 1.0 */
+
+/** Convenience method to set the sampling rate as a property on the given
+ * format.
+ *
+ * Note for PCM: If the sample rate is left unspecified in the pa_format_info
+ * object, then the server will select the stream sample rate. In that case the
+ * stream sample rate will most likely match the device sample rate, meaning
+ * that sample rate conversion will be avoided.
+ *
+ * \since 1.0 */
 void pa_format_info_set_rate(pa_format_info *f, int rate);
-/** Convenience method to set the number of channels as a property on the given format. \since 1.0 */
+
+/** Convenience method to set the number of channels as a property on the given
+ * format.
+ *
+ * Note for PCM: If the channel count is left unspecified in the pa_format_info
+ * object, then the server will select the stream channel count. In that case
+ * the stream channel count will most likely match the device channel count,
+ * meaning that up/downmixing will be avoided.
+ *
+ * \since 1.0 */
 void pa_format_info_set_channels(pa_format_info *f, int channels);
-/** Convenience method to set the channel map as a property on the given format. \since 1.0 */
+
+/** Convenience method to set the channel map as a property on the given
+ * format.
+ *
+ * Note for PCM: If the channel map is left unspecified in the pa_format_info
+ * object, then the server will select the stream channel map. In that case the
+ * stream channel map will most likely match the device channel map, meaning
+ * that remixing will be avoided.
+ *
+ * \since 1.0 */
 void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map);
 
 PA_C_DECL_END

commit f41650a5507cf2b3a32fd39af06043ce0fdd50d9
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Wed Dec 4 06:09:23 2013 +0200

    sink-input, source-output: Interpret missing PCM parameters in format info as a request to decide those parameters at the server end
    
    The "fix flags" (PA_SINK_INPUT_FIX_FORMAT etc.) don't work properly
    with the pa_stream_new_extended() interface. This patch fixes it so
    that the same effect can be achieved by leaving some of the PCM
    parameters unspecified in format info objects. Also, when converting
    a sample spec to a format info when using the old pa_stream_new()
    interface, the "fix flags" are taken into account in that conversion.
    
    BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=68952

diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index c396770..97a55a6 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -32,7 +32,9 @@
 #include <pulse/util.h>
 #include <pulse/internal.h>
 
+#include <pulsecore/core-format.h>
 #include <pulsecore/mix.h>
+#include <pulsecore/stream-util.h>
 #include <pulsecore/core-subscribe.h>
 #include <pulsecore/log.h>
 #include <pulsecore/play-memblockq.h>
@@ -286,12 +288,10 @@ int pa_sink_input_new(
     pa_sink_input *i;
     pa_resampler *resampler = NULL;
     char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], fmt[PA_FORMAT_INFO_SNPRINT_MAX];
-    pa_channel_map original_cm;
+    pa_channel_map volume_map;
     int r;
     char *pt;
     char *memblockq_name;
-    pa_sample_spec ss;
-    pa_channel_map map;
 
     pa_assert(_i);
     pa_assert(core);
@@ -308,11 +308,19 @@ int pa_sink_input_new(
         /* From this point on, we want to work only with formats, and get back
          * to using the sample spec and channel map after all decisions w.r.t.
          * routing are complete. */
-        pa_idxset *tmp = pa_idxset_new(NULL, NULL);
-        pa_format_info *f = pa_format_info_from_sample_spec(&data->sample_spec,
-                data->channel_map_is_set ? &data->channel_map : NULL);
-        pa_idxset_put(tmp, f, NULL);
-        pa_sink_input_new_data_set_formats(data, tmp);
+        pa_format_info *f;
+        pa_idxset *formats;
+
+        f = pa_format_info_from_sample_spec2(&data->sample_spec, data->channel_map_is_set ? &data->channel_map : NULL,
+                                             !(data->flags & PA_SINK_INPUT_FIX_FORMAT),
+                                             !(data->flags & PA_SINK_INPUT_FIX_RATE),
+                                             !(data->flags & PA_SINK_INPUT_FIX_CHANNELS));
+        if (!f)
+            return -PA_ERR_INVALID;
+
+        formats = pa_idxset_new(NULL, NULL);
+        pa_idxset_put(formats, f, NULL);
+        pa_sink_input_new_data_set_formats(data, formats);
     }
 
     if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], data)) < 0)
@@ -351,32 +359,27 @@ int pa_sink_input_new(
         return -PA_ERR_NOTSUPPORTED;
     }
 
-    /* Now populate the sample spec and format according to the final
-     * format that we've negotiated */
-    pa_return_val_if_fail(pa_format_info_to_sample_spec(data->format, &ss, &map) == 0, -PA_ERR_INVALID);
-    pa_sink_input_new_data_set_sample_spec(data, &ss);
-    if (pa_format_info_is_pcm(data->format) && pa_channel_map_valid(&map))
-        pa_sink_input_new_data_set_channel_map(data, &map);
+    if (data->volume_is_set && pa_format_info_is_pcm(data->format)) {
+        /* If volume is set, we need to save the original data->channel_map,
+         * so that we can remap the volume from the original channel map to the
+         * final channel map of the stream in case data->channel_map gets
+         * modified in pa_format_info_to_sample_spec2(). */
+        r = pa_stream_get_volume_channel_map(&data->volume, data->channel_map_is_set ? &data->channel_map : NULL, data->format, &volume_map);
+        if (r < 0)
+            return r;
+    }
 
+    /* Now populate the sample spec and channel map according to the final
+     * format that we've negotiated */
+    r = pa_format_info_to_sample_spec2(data->format, &data->sample_spec, &data->channel_map, &data->sink->sample_spec,
+                                       &data->sink->channel_map);
+    if (r < 0)
+        return r;
 
     r = check_passthrough_connection(pa_sink_input_new_data_is_passthrough(data), data->sink);
     if (r != PA_OK)
         return r;
 
-    if (!data->sample_spec_is_set)
-        data->sample_spec = data->sink->sample_spec;
-
-    pa_return_val_if_fail(pa_sample_spec_valid(&data->sample_spec), -PA_ERR_INVALID);
-
-    if (!data->channel_map_is_set) {
-        if (pa_channel_map_compatible(&data->sink->channel_map, &data->sample_spec))
-            data->channel_map = data->sink->channel_map;
-        else
-            pa_channel_map_init_extend(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
-    }
-
-    pa_return_val_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec), -PA_ERR_INVALID);
-
     /* Don't restore (or save) stream volume for passthrough streams and
      * prevent attenuation/gain */
     if (pa_sink_input_new_data_is_passthrough(data)) {
@@ -395,36 +398,14 @@ int pa_sink_input_new(
     if (!data->volume_writable)
         data->save_volume = false;
 
-    pa_return_val_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec), -PA_ERR_INVALID);
+    if (data->volume_is_set)
+        /* The original volume channel map may be different than the final
+         * stream channel map, so remapping may be needed. */
+        pa_cvolume_remap(&data->volume, &volume_map, &data->channel_map);
 
     if (!data->muted_is_set)
         data->muted = false;
 
-    if (data->flags & PA_SINK_INPUT_FIX_FORMAT) {
-        pa_return_val_if_fail(pa_format_info_is_pcm(data->format), -PA_ERR_INVALID);
-        data->sample_spec.format = data->sink->sample_spec.format;
-        pa_format_info_set_sample_format(data->format, data->sample_spec.format);
-    }
-
-    if (data->flags & PA_SINK_INPUT_FIX_RATE) {
-        pa_return_val_if_fail(pa_format_info_is_pcm(data->format), -PA_ERR_INVALID);
-        data->sample_spec.rate = data->sink->sample_spec.rate;
-        pa_format_info_set_rate(data->format, data->sample_spec.rate);
-    }
-
-    original_cm = data->channel_map;
-
-    if (data->flags & PA_SINK_INPUT_FIX_CHANNELS) {
-        pa_return_val_if_fail(pa_format_info_is_pcm(data->format), -PA_ERR_INVALID);
-        data->sample_spec.channels = data->sink->sample_spec.channels;
-        data->channel_map = data->sink->channel_map;
-        pa_format_info_set_channels(data->format, data->sample_spec.channels);
-        pa_format_info_set_channel_map(data->format, &data->channel_map);
-    }
-
-    pa_assert(pa_sample_spec_valid(&data->sample_spec));
-    pa_assert(pa_channel_map_valid(&data->channel_map));
-
     if (!(data->flags & PA_SINK_INPUT_VARIABLE_RATE) &&
         !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec)) {
         /* try to change sink rate. This is done before the FIXATE hook since
@@ -443,9 +424,6 @@ int pa_sink_input_new(
         return -PA_ERR_NOTSUPPORTED;
     }
 
-    /* Due to the fixing of the sample spec the volume might not match anymore */
-    pa_cvolume_remap(&data->volume, &original_cm, &data->channel_map);
-
     if (data->resample_method == PA_RESAMPLER_INVALID)
         data->resample_method = core->resample_method;
 
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 48cd6a0..7b08b7e 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -32,7 +32,9 @@
 #include <pulse/util.h>
 #include <pulse/internal.h>
 
+#include <pulsecore/core-format.h>
 #include <pulsecore/mix.h>
+#include <pulsecore/stream-util.h>
 #include <pulsecore/core-subscribe.h>
 #include <pulsecore/log.h>
 #include <pulsecore/namereg.h>
@@ -221,11 +223,9 @@ int pa_source_output_new(
     pa_source_output *o;
     pa_resampler *resampler = NULL;
     char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], fmt[PA_FORMAT_INFO_SNPRINT_MAX];
-    pa_channel_map original_cm;
+    pa_channel_map volume_map;
     int r;
     char *pt;
-    pa_sample_spec ss;
-    pa_channel_map map;
 
     pa_assert(_o);
     pa_assert(core);
@@ -242,11 +242,19 @@ int pa_source_output_new(
         /* From this point on, we want to work only with formats, and get back
          * to using the sample spec and channel map after all decisions w.r.t.
          * routing are complete. */
-        pa_idxset *tmp = pa_idxset_new(NULL, NULL);
-        pa_format_info *f = pa_format_info_from_sample_spec(&data->sample_spec,
-                data->channel_map_is_set ? &data->channel_map : NULL);
-        pa_idxset_put(tmp, f, NULL);
-        pa_source_output_new_data_set_formats(data, tmp);
+        pa_format_info *f;
+        pa_idxset *formats;
+
+        f = pa_format_info_from_sample_spec2(&data->sample_spec, data->channel_map_is_set ? &data->channel_map : NULL,
+                                             !(data->flags & PA_SOURCE_OUTPUT_FIX_FORMAT),
+                                             !(data->flags & PA_SOURCE_OUTPUT_FIX_RATE),
+                                             !(data->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS));
+        if (!f)
+            return -PA_ERR_INVALID;
+
+        formats = pa_idxset_new(NULL, NULL);
+        pa_idxset_put(formats, f, NULL);
+        pa_source_output_new_data_set_formats(data, formats);
     }
 
     if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], data)) < 0)
@@ -291,26 +299,22 @@ int pa_source_output_new(
         return -PA_ERR_NOTSUPPORTED;
     }
 
-    /* Now populate the sample spec and format according to the final
-     * format that we've negotiated */
-    pa_return_val_if_fail(pa_format_info_to_sample_spec(data->format, &ss, &map) == 0, -PA_ERR_INVALID);
-    pa_source_output_new_data_set_sample_spec(data, &ss);
-    if (pa_format_info_is_pcm(data->format) && pa_channel_map_valid(&map))
-        pa_source_output_new_data_set_channel_map(data, &map);
-
-    if (!data->sample_spec_is_set)
-        data->sample_spec = data->source->sample_spec;
-
-    pa_return_val_if_fail(pa_sample_spec_valid(&data->sample_spec), -PA_ERR_INVALID);
-
-    if (!data->channel_map_is_set) {
-        if (pa_channel_map_compatible(&data->source->channel_map, &data->sample_spec))
-            data->channel_map = data->source->channel_map;
-        else
-            pa_channel_map_init_extend(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
+    if (data->volume_is_set && pa_format_info_is_pcm(data->format)) {
+        /* If volume is set, we need to save the original data->channel_map,
+         * so that we can remap the volume from the original channel map to the
+         * final channel map of the stream in case data->channel_map gets
+         * modified in pa_format_info_to_sample_spec2(). */
+        r = pa_stream_get_volume_channel_map(&data->volume, data->channel_map_is_set ? &data->channel_map : NULL, data->format, &volume_map);
+        if (r < 0)
+            return r;
     }
 
-    pa_return_val_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec), -PA_ERR_INVALID);
+    /* Now populate the sample spec and channel map according to the final
+     * format that we've negotiated */
+    r = pa_format_info_to_sample_spec2(data->format, &data->sample_spec, &data->channel_map, &data->source->sample_spec,
+                                       &data->source->channel_map);
+    if (r < 0)
+        return r;
 
     /* Don't restore (or save) stream volume for passthrough streams and
      * prevent attenuation/gain */
@@ -330,7 +334,10 @@ int pa_source_output_new(
     if (!data->volume_writable)
         data->save_volume = false;
 
-    pa_return_val_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec), -PA_ERR_INVALID);
+    if (data->volume_is_set)
+        /* The original volume channel map may be different than the final
+         * stream channel map, so remapping may be needed. */
+        pa_cvolume_remap(&data->volume, &volume_map, &data->channel_map);
 
     if (!data->volume_factor_is_set)
         pa_cvolume_reset(&data->volume_factor, data->sample_spec.channels);
@@ -345,31 +352,6 @@ int pa_source_output_new(
     if (!data->muted_is_set)
         data->muted = false;
 
-    if (data->flags & PA_SOURCE_OUTPUT_FIX_FORMAT) {
-        pa_return_val_if_fail(pa_format_info_is_pcm(data->format), -PA_ERR_INVALID);
-        data->sample_spec.format = data->source->sample_spec.format;
-        pa_format_info_set_sample_format(data->format, data->sample_spec.format);
-    }
-
-    if (data->flags & PA_SOURCE_OUTPUT_FIX_RATE) {
-        pa_return_val_if_fail(pa_format_info_is_pcm(data->format), -PA_ERR_INVALID);
-        pa_format_info_set_rate(data->format, data->sample_spec.rate);
-        data->sample_spec.rate = data->source->sample_spec.rate;
-    }
-
-    original_cm = data->channel_map;
-
-    if (data->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS) {
-        pa_return_val_if_fail(pa_format_info_is_pcm(data->format), -PA_ERR_INVALID);
-        data->sample_spec.channels = data->source->sample_spec.channels;
-        data->channel_map = data->source->channel_map;
-        pa_format_info_set_channels(data->format, data->sample_spec.channels);
-        pa_format_info_set_channel_map(data->format, &data->channel_map);
-    }
-
-    pa_assert(pa_sample_spec_valid(&data->sample_spec));
-    pa_assert(pa_channel_map_valid(&data->channel_map));
-
     if (!(data->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) &&
         !pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec)) {
         /* try to change source rate. This is done before the FIXATE hook since
@@ -388,9 +370,6 @@ int pa_source_output_new(
         return -PA_ERR_NOTSUPPORTED;
     }
 
-    /* Due to the fixing of the sample spec the volume might not match anymore */
-    pa_cvolume_remap(&data->volume, &original_cm, &data->channel_map);
-
     if (data->resample_method == PA_RESAMPLER_INVALID)
         data->resample_method = core->resample_method;
 

commit d27a650cd5b30fecaa794e6e485dc557881de83e
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Tue Dec 17 21:22:50 2013 +0200

    stream: Remove a volume channel validity check
    
    The check is done for clients that use pa_stream_new() but not for
    clients that use pa_stream_new_extended(). This is inconsistent. We
    could check that the volume channels match the channels set in the
    format info struct that is passed to pa_stream_new_extended(), but
    that doesn't work if the format info doesn't contain the channel
    information (that can happen if the client wants the server to choose
    the channel count for the stream). And it should also be possible to
    pass a mono volume for a multi-channel stream. The check could be
    extended to handle all these cases, but I don't see much point in
    wasting time on that. The server will anyway validate the stream
    parameters, it's not particularly important to fail already when the
    stream is being created at the client side.

diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index d376326..8e35c29 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -1224,7 +1224,6 @@ static int create_stream(
      * client development easier */
 
     PA_CHECK_VALIDITY(s->context, direction == PA_STREAM_RECORD || !(flags & (PA_STREAM_PEAK_DETECT)), PA_ERR_INVALID);
-    PA_CHECK_VALIDITY(s->context, !volume || s->n_formats || (pa_sample_spec_valid(&s->sample_spec) && volume->channels == s->sample_spec.channels), PA_ERR_INVALID);
     PA_CHECK_VALIDITY(s->context, !sync_stream || (direction == PA_STREAM_PLAYBACK && sync_stream->direction == PA_STREAM_PLAYBACK), PA_ERR_INVALID);
     PA_CHECK_VALIDITY(s->context, (flags & (PA_STREAM_ADJUST_LATENCY|PA_STREAM_EARLY_REQUESTS)) != (PA_STREAM_ADJUST_LATENCY|PA_STREAM_EARLY_REQUESTS), PA_ERR_INVALID);
 

commit 6cdb569b8332c4453603ab09eec4ad0cf1c28e33
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Tue Dec 17 21:17:55 2013 +0200

    stream-util: Add pa_stream_get_volume_channel_map()
    
    The new function isn't used yet, but it soon will.

diff --git a/src/Makefile.am b/src/Makefile.am
index b2f6405..28049ea 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -895,6 +895,7 @@ libpulsecore_ at PA_MAJORMINOR@_la_SOURCES = \
 		pulsecore/remap_mmx.c pulsecore/remap_sse.c \
 		pulsecore/resampler.c pulsecore/resampler.h \
 		pulsecore/rtpoll.c pulsecore/rtpoll.h \
+		pulsecore/stream-util.c pulsecore/stream-util.h \
 		pulsecore/mix.c pulsecore/mix.h \
 		pulsecore/cpu.h \
 		pulsecore/cpu-arm.c pulsecore/cpu-arm.h \
diff --git a/src/pulsecore/stream-util.c b/src/pulsecore/stream-util.c
new file mode 100644
index 0000000..bed8da0
--- /dev/null
+++ b/src/pulsecore/stream-util.c
@@ -0,0 +1,86 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2013 Intel Corporation
+
+  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
+  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 "stream-util.h"
+
+#include <pulse/def.h>
+
+#include <pulsecore/core-format.h>
+#include <pulsecore/macro.h>
+
+int pa_stream_get_volume_channel_map(const pa_cvolume *volume, const pa_channel_map *original_map, const pa_format_info *format,
+                                     pa_channel_map *volume_map) {
+    int r;
+    pa_channel_map volume_map_local;
+
+    pa_assert(volume);
+    pa_assert(format);
+    pa_assert(volume_map);
+
+    if (original_map) {
+        if (volume->channels == original_map->channels) {
+            *volume_map = *original_map;
+            return 0;
+        }
+
+        if (volume->channels == 1) {
+            pa_channel_map_init_mono(volume_map);
+            return 0;
+        }
+
+        pa_log_info("Invalid stream parameters: the volume is incompatible with the channel map.");
+        return -PA_ERR_INVALID;
+    }
+
+    r = pa_format_info_get_channel_map(format, &volume_map_local);
+    if (r == -PA_ERR_NOENTITY) {
+        if (volume->channels == 1) {
+            pa_channel_map_init_mono(volume_map);
+            return 0;
+        }
+
+        pa_log_info("Invalid stream parameters: multi-channel volume is set, but channel map is not.");
+        return -PA_ERR_INVALID;
+    }
+
+    if (r < 0) {
+        pa_log_info("Invalid channel map.");
+        return -PA_ERR_INVALID;
+    }
+
+    if (volume->channels == volume_map_local.channels) {
+        *volume_map = volume_map_local;
+        return 0;
+    }
+
+    if (volume->channels == 1) {
+        pa_channel_map_init_mono(volume_map);
+        return 0;
+    }
+
+    pa_log_info("Invalid stream parameters: the volume is incompatible with the channel map.");
+
+    return -PA_ERR_INVALID;
+}
diff --git a/src/pulsecore/stream-util.h b/src/pulsecore/stream-util.h
new file mode 100644
index 0000000..fd22ab3
--- /dev/null
+++ b/src/pulsecore/stream-util.h
@@ -0,0 +1,50 @@
+#ifndef foostreamutilhfoo
+#define foostreamutilhfoo
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2013 Intel Corporation
+
+  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
+  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/format.h>
+#include <pulse/volume.h>
+
+/* This is a helper function that is called from pa_sink_input_new() and
+ * pa_source_output_new(). The job of this function is to figure out what
+ * channel map should be used for interpreting the volume that was set for the
+ * stream. The channel map that the client intended for the volume may be
+ * different than the final stream channel map, because the client may want the
+ * server to decide the stream channel map.
+ *
+ * volume is the volume for which the channel map should be figured out.
+ *
+ * original_map is the channel map that is set in the new data struct's
+ * channel_map field. If the channel map hasn't been set in the new data, then
+ * original_map should be NULL.
+ *
+ * format is the negotiated format for the stream. It's used as a fallback if
+ * original_map is not available.
+ *
+ * On success, the result is saved in volume_map. It's possible that this
+ * function fails to figure out the right channel map for the volume, in which
+ * case a negative error code is returned. */
+int pa_stream_get_volume_channel_map(const pa_cvolume *volume, const pa_channel_map *original_map, const pa_format_info *format,
+                                     pa_channel_map *volume_map);
+
+#endif

commit a3a795ef3d740b9b41d188f0a00296e0561831f0
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Tue Dec 17 21:14:18 2013 +0200

    format, core-format: Constify some function parameters

diff --git a/src/pulse/format.c b/src/pulse/format.c
index 9b42cdb..6c34594 100644
--- a/src/pulse/format.c
+++ b/src/pulse/format.c
@@ -171,7 +171,7 @@ error:
     goto out;
 }
 
-int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second) {
+int pa_format_info_is_compatible(const pa_format_info *first, const pa_format_info *second) {
     const char *key;
     void *state = NULL;
 
@@ -194,7 +194,7 @@ int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second)
     return true;
 }
 
-pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_map *map) {
+pa_format_info* pa_format_info_from_sample_spec(const pa_sample_spec *ss, const pa_channel_map *map) {
     char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
     pa_format_info *f;
 
@@ -217,7 +217,7 @@ pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_m
 }
 
 /* For PCM streams */
-int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
+int pa_format_info_to_sample_spec(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
     pa_assert(f);
     pa_assert(ss);
 
@@ -236,7 +236,7 @@ int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_chan
     return 0;
 }
 
-pa_prop_type_t pa_format_info_get_prop_type(pa_format_info *f, const char *key) {
+pa_prop_type_t pa_format_info_get_prop_type(const pa_format_info *f, const char *key) {
     const char *str;
     json_object *o, *o1;
     pa_prop_type_t type;
@@ -310,7 +310,7 @@ pa_prop_type_t pa_format_info_get_prop_type(pa_format_info *f, const char *key)
     return type;
 }
 
-int pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v) {
+int pa_format_info_get_prop_int(const pa_format_info *f, const char *key, int *v) {
     const char *str;
     json_object *o;
 
@@ -337,7 +337,7 @@ int pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v) {
     return 0;
 }
 
-int pa_format_info_get_prop_int_range(pa_format_info *f, const char *key, int *min, int *max) {
+int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key, int *min, int *max) {
     const char *str;
     json_object *o, *o1;
     int ret = -PA_ERR_INVALID;
@@ -377,7 +377,7 @@ out:
     return ret;
 }
 
-int pa_format_info_get_prop_int_array(pa_format_info *f, const char *key, int **values, int *n_values) {
+int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key, int **values, int *n_values) {
     const char *str;
     json_object *o, *o1;
     int i, ret = -PA_ERR_INVALID;
@@ -420,7 +420,7 @@ out:
     return ret;
 }
 
-int pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v) {
+int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v) {
     const char *str = NULL;
     json_object *o;
 
@@ -447,7 +447,7 @@ int pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v)
     return 0;
 }
 
-int pa_format_info_get_prop_string_array(pa_format_info *f, const char *key, char ***values, int *n_values) {
+int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *key, char ***values, int *n_values) {
     const char *str;
     json_object *o, *o1;
     int i, ret = -PA_ERR_INVALID;
diff --git a/src/pulse/format.h b/src/pulse/format.h
index 4184bee..e3c8f36 100644
--- a/src/pulse/format.h
+++ b/src/pulse/format.h
@@ -114,7 +114,7 @@ int pa_format_info_is_pcm(const pa_format_info *f);
  * stream's format is compatible with a given sink. In such a case,
  * \a first would be the sink's format and \a second would be the
  * stream's. \since 1.0 */
-int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second);
+int pa_format_info_is_compatible(const pa_format_info *first, const pa_format_info *second);
 
 /** Maximum required string length for
  * pa_format_info_snprint(). Please note that this value can change
@@ -131,14 +131,14 @@ char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f);
 pa_format_info* pa_format_info_from_string(const char *str);
 
 /** Utility function to take a \a pa_sample_spec and generate the corresponding \a pa_format_info. \since 2.0 */
-pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_map *map);
+pa_format_info* pa_format_info_from_sample_spec(const pa_sample_spec *ss, const pa_channel_map *map);
 
 /** Utility function to generate a \a pa_sample_spec and \a pa_channel_map corresponding to a given \a pa_format_info. The
  * conversion for PCM formats is straight-forward. For non-PCM formats, if there is a fixed size-time conversion (i.e. all
  * IEC61937-encapsulated formats), a "fake" sample spec whose size-time conversion corresponds to this format is provided and
  * the channel map argument is ignored. For formats with variable size-time conversion, this function will fail. Returns a
  * negative integer if conversion failed and 0 on success. \since 2.0 */
-int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map);
+int pa_format_info_to_sample_spec(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map);
 
 /** Represents the type of value type of a property on a \ref pa_format_info. \since 2.0 */
 typedef enum pa_prop_type_t {
@@ -171,24 +171,24 @@ typedef enum pa_prop_type_t {
 /** \endcond */
 
 /** Gets the type of property \a key in a given \ref pa_format_info. \since 2.0 */
-pa_prop_type_t pa_format_info_get_prop_type(pa_format_info *f, const char *key);
+pa_prop_type_t pa_format_info_get_prop_type(const pa_format_info *f, const char *key);
 
 /** Gets an integer property from the given format info. Returns 0 on success and a negative integer on failure. \since 2.0 */
-int pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v);
+int pa_format_info_get_prop_int(const pa_format_info *f, const char *key, int *v);
 /** Gets an integer range property from the given format info. Returns 0 on success and a negative integer on failure.
  * \since 2.0 */
-int pa_format_info_get_prop_int_range(pa_format_info *f, const char *key, int *min, int *max);
+int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key, int *min, int *max);
 /** Gets an integer array property from the given format info. \a values contains the values and \a n_values contains the
  * number of elements. The caller must free \a values using \ref pa_xfree. Returns 0 on success and a negative integer on
  * failure. \since 2.0 */
-int pa_format_info_get_prop_int_array(pa_format_info *f, const char *key, int **values, int *n_values);
+int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key, int **values, int *n_values);
 /** Gets a string property from the given format info.  The caller must free the returned string using \ref pa_xfree. Returns
  * 0 on success and a negative integer on failure. \since 2.0 */
-int pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v);
+int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v);
 /** Gets a string array property from the given format info. \a values contains the values and \a n_values contains
  * the number of elements. The caller must free \a values using \ref pa_format_info_free_string_array. Returns 0 on success and
  * a negative integer on failure. \since 2.0 */
-int pa_format_info_get_prop_string_array(pa_format_info *f, const char *key, char ***values, int *n_values);
+int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *key, char ***values, int *n_values);
 
 /** Frees a string array returned by \ref pa_format_info_get_prop_string_array. \since 2.0 */
 void pa_format_info_free_string_array(char **values, int n_values);
diff --git a/src/pulsecore/core-format.c b/src/pulsecore/core-format.c
index 79aff93..2c03c47 100644
--- a/src/pulsecore/core-format.c
+++ b/src/pulsecore/core-format.c
@@ -28,7 +28,7 @@
 
 #include <pulsecore/macro.h>
 
-int pa_format_info_get_sample_format(pa_format_info *f, pa_sample_format_t *sf) {
+int pa_format_info_get_sample_format(const pa_format_info *f, pa_sample_format_t *sf) {
     int r;
     char *sf_str;
     pa_sample_format_t sf_local;
@@ -53,7 +53,7 @@ int pa_format_info_get_sample_format(pa_format_info *f, pa_sample_format_t *sf)
     return 0;
 }
 
-int pa_format_info_get_rate(pa_format_info *f, uint32_t *rate) {
+int pa_format_info_get_rate(const pa_format_info *f, uint32_t *rate) {
     int r;
     int rate_local;
 
@@ -74,7 +74,7 @@ int pa_format_info_get_rate(pa_format_info *f, uint32_t *rate) {
     return 0;
 }
 
-int pa_format_info_get_channels(pa_format_info *f, uint8_t *channels) {
+int pa_format_info_get_channels(const pa_format_info *f, uint8_t *channels) {
     int r;
     int channels_local;
 
@@ -95,7 +95,7 @@ int pa_format_info_get_channels(pa_format_info *f, uint8_t *channels) {
     return 0;
 }
 
-int pa_format_info_get_channel_map(pa_format_info *f, pa_channel_map *map) {
+int pa_format_info_get_channel_map(const pa_format_info *f, pa_channel_map *map) {
     int r;
     char *map_str;
 
@@ -154,8 +154,8 @@ fail:
     return NULL;
 }
 
-int pa_format_info_to_sample_spec2(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map, pa_sample_spec *fallback_ss,
-                                   pa_channel_map *fallback_map) {
+int pa_format_info_to_sample_spec2(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map,
+                                   const pa_sample_spec *fallback_ss, const pa_channel_map *fallback_map) {
     int r, r2;
     pa_sample_spec ss_local;
     pa_channel_map map_local;
@@ -218,7 +218,7 @@ int pa_format_info_to_sample_spec2(pa_format_info *f, pa_sample_spec *ss, pa_cha
     return 0;
 }
 
-int pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
+int pa_format_info_to_sample_spec_fake(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
     int rate;
 
     pa_assert(f);
diff --git a/src/pulsecore/core-format.h b/src/pulsecore/core-format.h
index ce3923e..f2fa12e 100644
--- a/src/pulsecore/core-format.h
+++ b/src/pulsecore/core-format.h
@@ -27,22 +27,22 @@
 /* Gets the sample format stored in the format info. Returns a negative error
  * code on failure. If the sample format property is not set at all, returns
  * -PA_ERR_NOENTITY. */
-int pa_format_info_get_sample_format(pa_format_info *f, pa_sample_format_t *sf);
+int pa_format_info_get_sample_format(const pa_format_info *f, pa_sample_format_t *sf);
 
 /* Gets the sample rate stored in the format info. Returns a negative error
  * code on failure. If the sample rate property is not set at all, returns
  * -PA_ERR_NOENTITY. */
-int pa_format_info_get_rate(pa_format_info *f, uint32_t *rate);
+int pa_format_info_get_rate(const pa_format_info *f, uint32_t *rate);
 
 /* Gets the channel count stored in the format info. Returns a negative error
  * code on failure. If the channels property is not set at all, returns
  * -PA_ERR_NOENTITY. */
-int pa_format_info_get_channels(pa_format_info *f, uint8_t *channels);
+int pa_format_info_get_channels(const pa_format_info *f, uint8_t *channels);
 
 /* Gets the channel map stored in the format info. Returns a negative error
  * code on failure. If the channel map property is not set at all, returns
  * -PA_ERR_NOENTITY. */
-int pa_format_info_get_channel_map(pa_format_info *f, pa_channel_map *map);
+int pa_format_info_get_channel_map(const pa_format_info *f, pa_channel_map *map);
 
 /* Convert a sample spec and an optional channel map to a new PCM format info
  * object (remember to free it). If map is NULL, then the channel map will be
@@ -69,13 +69,13 @@ pa_format_info *pa_format_info_from_sample_spec2(const pa_sample_spec *ss, const
  * a fallback sample spec and channel map. That functionality can't be added to
  * the original function, because the function is part of the public API and
  * adding parameters to it would break the API. */
-int pa_format_info_to_sample_spec2(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map, pa_sample_spec *fallback_ss,
-                                   pa_channel_map *fallback_map);
+int pa_format_info_to_sample_spec2(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map,
+                                   const pa_sample_spec *fallback_ss, const pa_channel_map *fallback_map);
 
 /* For compressed formats. Converts the format info into a sample spec and a
  * channel map that an ALSA device can use as its configuration parameters when
  * playing back the compressed data. That is, the returned sample spec doesn't
  * describe the audio content, but the device parameters. */
-int pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map);
+int pa_format_info_to_sample_spec_fake(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map);
 
 #endif

commit 71816ecb7f81fe7a124cefa2258cfa64046908a1
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Tue Dec 3 16:54:48 2013 +0200

    sink-input, source-output: Do routing related validity checks immediately after routing
    
    It's more logical that way.

diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index e45ecf1..c396770 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -325,8 +325,13 @@ int pa_sink_input_new(
         pa_return_val_if_fail(sink, -PA_ERR_NOENTITY);
         pa_sink_input_new_data_set_sink(data, sink, false);
     }
-    /* Routing's done, we have a sink. Now let's fix the format and set up the
-     * sample spec */
+
+    pa_return_val_if_fail(PA_SINK_IS_LINKED(pa_sink_get_state(data->sink)), -PA_ERR_BADSTATE);
+    pa_return_val_if_fail(!data->sync_base || (data->sync_base->sink == data->sink
+                                               && pa_sink_input_get_state(data->sync_base) == PA_SINK_INPUT_CORKED),
+                          -PA_ERR_INVALID);
+
+    /* Routing's done, we have a sink. Now let's fix the format. */
 
     /* If something didn't pick a format for us, pick the top-most format since
      * we assume this is sorted in priority order */
@@ -353,8 +358,6 @@ int pa_sink_input_new(
     if (pa_format_info_is_pcm(data->format) && pa_channel_map_valid(&map))
         pa_sink_input_new_data_set_channel_map(data, &map);
 
-    pa_return_val_if_fail(PA_SINK_IS_LINKED(pa_sink_get_state(data->sink)), -PA_ERR_BADSTATE);
-    pa_return_val_if_fail(!data->sync_base || (data->sync_base->sink == data->sink && pa_sink_input_get_state(data->sync_base) == PA_SINK_INPUT_CORKED), -PA_ERR_INVALID);
 
     r = check_passthrough_connection(pa_sink_input_new_data_is_passthrough(data), data->sink);
     if (r != PA_OK)
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 834a418..48cd6a0 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -268,8 +268,10 @@ int pa_source_output_new(
         pa_source_output_new_data_set_source(data, source, false);
     }
 
-    /* Routing's done, we have a source. Now let's fix the format and set up the
-     * sample spec */
+    pa_return_val_if_fail(PA_SOURCE_IS_LINKED(pa_source_get_state(data->source)), -PA_ERR_BADSTATE);
+    pa_return_val_if_fail(!data->direct_on_input || data->direct_on_input->sink == data->source->monitor_of, -PA_ERR_INVALID);
+
+    /* Routing's done, we have a source. Now let's fix the format. */
 
     /* If something didn't pick a format for us, pick the top-most format since
      * we assume this is sorted in priority order */
@@ -296,9 +298,6 @@ int pa_source_output_new(
     if (pa_format_info_is_pcm(data->format) && pa_channel_map_valid(&map))
         pa_source_output_new_data_set_channel_map(data, &map);
 
-    pa_return_val_if_fail(PA_SOURCE_IS_LINKED(pa_source_get_state(data->source)), -PA_ERR_BADSTATE);
-    pa_return_val_if_fail(!data->direct_on_input || data->direct_on_input->sink == data->source->monitor_of, -PA_ERR_INVALID);
-
     if (!data->sample_spec_is_set)
         data->sample_spec = data->source->sample_spec;
 

commit d78d8246b41c688303f59d6ba7f34b52132c67b8
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Tue Dec 3 17:49:51 2013 +0200

    core-format: Add pa_format_info_from_sample_spec2()
    
    The function will be used in pa_sink_input_new() and
    pa_source_output_new() to convert the sample spec given by the client
    to a format info object. The set_format, set_rate and set_channels
    will be set according to the stream flags (PA_SINK_INPUT_FIX_FORMAT
    etc.).

diff --git a/src/pulsecore/core-format.c b/src/pulsecore/core-format.c
index ce1cab3..79aff93 100644
--- a/src/pulsecore/core-format.c
+++ b/src/pulsecore/core-format.c
@@ -117,6 +117,43 @@ int pa_format_info_get_channel_map(pa_format_info *f, pa_channel_map *map) {
     return 0;
 }
 
+pa_format_info *pa_format_info_from_sample_spec2(const pa_sample_spec *ss, const pa_channel_map *map, bool set_format,
+                                                 bool set_rate, bool set_channels) {
+    pa_format_info *format = NULL;
+
+    pa_assert(ss);
+
+    format = pa_format_info_new();
+    format->encoding = PA_ENCODING_PCM;
+
+    if (set_format)
+        pa_format_info_set_sample_format(format, ss->format);
+
+    if (set_rate)
+        pa_format_info_set_rate(format, ss->rate);
+
+    if (set_channels) {
+        pa_format_info_set_channels(format, ss->channels);
+
+        if (map) {
+            if (map->channels != ss->channels) {
+                pa_log_debug("Channel map is incompatible with the sample spec.");
+                goto fail;
+            }
+
+            pa_format_info_set_channel_map(format, map);
+        }
+    }
+
+    return format;
+
+fail:
+    if (format)
+        pa_format_info_free(format);
+
+    return NULL;
+}
+
 int pa_format_info_to_sample_spec2(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map, pa_sample_spec *fallback_ss,
                                    pa_channel_map *fallback_map) {
     int r, r2;
diff --git a/src/pulsecore/core-format.h b/src/pulsecore/core-format.h
index 9342acc..ce3923e 100644
--- a/src/pulsecore/core-format.h
+++ b/src/pulsecore/core-format.h
@@ -22,6 +22,8 @@
 
 #include <pulse/format.h>
 
+#include <stdbool.h>
+
 /* Gets the sample format stored in the format info. Returns a negative error
  * code on failure. If the sample format property is not set at all, returns
  * -PA_ERR_NOENTITY. */
@@ -42,6 +44,22 @@ int pa_format_info_get_channels(pa_format_info *f, uint8_t *channels);
  * -PA_ERR_NOENTITY. */
 int pa_format_info_get_channel_map(pa_format_info *f, pa_channel_map *map);
 
+/* Convert a sample spec and an optional channel map to a new PCM format info
+ * object (remember to free it). If map is NULL, then the channel map will be
+ * left unspecified. If some fields of the sample spec should be ignored, pass
+ * false for set_format, set_rate and set_channels as appropriate, then those
+ * fields will be left unspecified. This function returns NULL if the input is
+ * invalid (for example, setting the sample rate was requested, but the rate
+ * in ss is invalid).
+ *
+ * pa_format_info_from_sample_spec() exists too. This "version 2" was created,
+ * because the original function doesn't provide the possibility of ignoring
+ * some of the sample spec fields. That functionality can't be added to the
+ * original function, because the function is a part of the public API and
+ * adding parameters to it would break the API. */
+pa_format_info *pa_format_info_from_sample_spec2(const pa_sample_spec *ss, const pa_channel_map *map, bool set_format,
+                                                 bool set_rate, bool set_channels);
+
 /* Convert the format info into a sample spec and a channel map. If the format
  * info doesn't contain some information, the fallback sample spec and channel
  * map are used to populate the output.

commit 30a32d35c8b91cafc004961828a7d0acbce74f1f
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Mon Nov 18 19:58:37 2013 +0200

    core-format: Add pa_format_info_to_sample_spec2()
    
    The function will be used in pa_sink_input_new() and
    pa_source_output_new(). The fallback parameters are used to merge the
    data in the format info with the sink/source sample spec and channel
    map, when the format info is lacking some information.

diff --git a/src/pulsecore/core-format.c b/src/pulsecore/core-format.c
index 799b2da..ce1cab3 100644
--- a/src/pulsecore/core-format.c
+++ b/src/pulsecore/core-format.c
@@ -117,6 +117,70 @@ int pa_format_info_get_channel_map(pa_format_info *f, pa_channel_map *map) {
     return 0;
 }
 
+int pa_format_info_to_sample_spec2(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map, pa_sample_spec *fallback_ss,
+                                   pa_channel_map *fallback_map) {
+    int r, r2;
+    pa_sample_spec ss_local;
+    pa_channel_map map_local;
+
+    pa_assert(f);
+    pa_assert(ss);
+    pa_assert(map);
+    pa_assert(fallback_ss);
+    pa_assert(fallback_map);
+
+    if (!pa_format_info_is_pcm(f))
+        return pa_format_info_to_sample_spec_fake(f, ss, map);
+
+    r = pa_format_info_get_sample_format(f, &ss_local.format);
+    if (r == -PA_ERR_NOENTITY)
+        ss_local.format = fallback_ss->format;
+    else if (r < 0)
+        return r;
+
+    pa_assert(pa_sample_format_valid(ss_local.format));
+
+    r = pa_format_info_get_rate(f, &ss_local.rate);
+    if (r == -PA_ERR_NOENTITY)
+        ss_local.rate = fallback_ss->rate;
+    else if (r < 0)
+        return r;
+
+    pa_assert(pa_sample_rate_valid(ss_local.rate));
+
+    r = pa_format_info_get_channels(f, &ss_local.channels);
+    r2 = pa_format_info_get_channel_map(f, &map_local);
+    if (r == -PA_ERR_NOENTITY && r2 >= 0)
+        ss_local.channels = map_local.channels;
+    else if (r == -PA_ERR_NOENTITY)
+        ss_local.channels = fallback_ss->channels;
+    else if (r < 0)
+        return r;
+
+    pa_assert(pa_channels_valid(ss_local.channels));
+
+    if (r2 >= 0 && map_local.channels != ss_local.channels) {
+        pa_log_debug("Channel map is not compatible with the sample spec.");
+        return -PA_ERR_INVALID;
+    }
+
+    if (r2 == -PA_ERR_NOENTITY) {
+        if (fallback_map->channels == ss_local.channels)
+            map_local = *fallback_map;
+        else
+            pa_channel_map_init_extend(&map_local, ss_local.channels, PA_CHANNEL_MAP_DEFAULT);
+    } else if (r2 < 0)
+        return r2;
+
+    pa_assert(pa_channel_map_valid(&map_local));
+    pa_assert(ss_local.channels == map_local.channels);
+
+    *ss = ss_local;
+    *map = map_local;
+
+    return 0;
+}
+
 int pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
     int rate;
 
diff --git a/src/pulsecore/core-format.h b/src/pulsecore/core-format.h
index 086cbed..9342acc 100644
--- a/src/pulsecore/core-format.h
+++ b/src/pulsecore/core-format.h
@@ -42,6 +42,18 @@ int pa_format_info_get_channels(pa_format_info *f, uint8_t *channels);
  * -PA_ERR_NOENTITY. */
 int pa_format_info_get_channel_map(pa_format_info *f, pa_channel_map *map);
 
+/* Convert the format info into a sample spec and a channel map. If the format
+ * info doesn't contain some information, the fallback sample spec and channel
+ * map are used to populate the output.
+ *
+ * pa_format_info_to_sample_spec() exists too. This "version 2" was created,
+ * because the original function doesn't provide the possibility of specifying
+ * a fallback sample spec and channel map. That functionality can't be added to
+ * the original function, because the function is part of the public API and
+ * adding parameters to it would break the API. */
+int pa_format_info_to_sample_spec2(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map, pa_sample_spec *fallback_ss,
+                                   pa_channel_map *fallback_map);
+
 /* For compressed formats. Converts the format info into a sample spec and a
  * channel map that an ALSA device can use as its configuration parameters when
  * playing back the compressed data. That is, the returned sample spec doesn't

commit dfa3c507001d583574a04cf87ed1f0123553ddac
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Tue Dec 3 16:45:45 2013 +0200

    format: Simplify pa_format_info_to_sample_spec()

diff --git a/src/pulse/format.c b/src/pulse/format.c
index 4f4b342..9b42cdb 100644
--- a/src/pulse/format.c
+++ b/src/pulse/format.c
@@ -218,8 +218,6 @@ pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_m
 
 /* For PCM streams */
 int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
-    int ret = -PA_ERR_INVALID;
-
     pa_assert(f);
     pa_assert(ss);
 
@@ -227,18 +225,15 @@ int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_chan
         return pa_format_info_to_sample_spec_fake(f, ss, map);
 
     if (pa_format_info_get_sample_format(f, &ss->format) < 0)
-        goto out;
+        return -PA_ERR_INVALID;
     if (pa_format_info_get_rate(f, &ss->rate) < 0)
-        goto out;
+        return -PA_ERR_INVALID;
     if (pa_format_info_get_channels(f, &ss->channels) < 0)
-        goto out;
+        return -PA_ERR_INVALID;
     if (map && pa_format_info_get_channel_map(f, map) < 0)
-        goto out;
-
-    ret = 0;
+        return -PA_ERR_INVALID;
 
-out:
-    return ret;
+    return 0;
 }
 
 pa_prop_type_t pa_format_info_get_prop_type(pa_format_info *f, const char *key) {

commit 3a5a0f6652c749f42ba3757fd563a3ff7b6b35af
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Mon Nov 25 14:59:44 2013 +0200

    core-format: Add pa_format_info_get_channel_map()

diff --git a/src/pulse/format.c b/src/pulse/format.c
index 424df0e..4f4b342 100644
--- a/src/pulse/format.c
+++ b/src/pulse/format.c
@@ -218,7 +218,6 @@ pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_m
 
 /* For PCM streams */
 int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
-    char *m = NULL;
     int ret = -PA_ERR_INVALID;
 
     pa_assert(f);
@@ -233,21 +232,12 @@ int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_chan
         goto out;
     if (pa_format_info_get_channels(f, &ss->channels) < 0)
         goto out;
-
-    if (map) {
-        pa_channel_map_init(map);
-
-        if (pa_format_info_get_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, &m) == 0)
-            if (pa_channel_map_parse(map, m) == NULL)
-                goto out;
-    }
+    if (map && pa_format_info_get_channel_map(f, map) < 0)
+        goto out;
 
     ret = 0;
 
 out:
-    if (m)
-        pa_xfree(m);
-
     return ret;
 }
 
diff --git a/src/pulsecore/core-format.c b/src/pulsecore/core-format.c
index c245719..799b2da 100644
--- a/src/pulsecore/core-format.c
+++ b/src/pulsecore/core-format.c
@@ -95,6 +95,28 @@ int pa_format_info_get_channels(pa_format_info *f, uint8_t *channels) {
     return 0;
 }
 
+int pa_format_info_get_channel_map(pa_format_info *f, pa_channel_map *map) {
+    int r;
+    char *map_str;
+
+    pa_assert(f);
+    pa_assert(map);
+
+    r = pa_format_info_get_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, &map_str);
+    if (r < 0)
+        return r;
+
+    map = pa_channel_map_parse(map, map_str);
+    pa_xfree(map_str);
+
+    if (!map) {
+        pa_log_debug("Failed to parse channel map.");
+        return -PA_ERR_INVALID;
+    }
+
+    return 0;
+}
+
 int pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
     int rate;
 
diff --git a/src/pulsecore/core-format.h b/src/pulsecore/core-format.h
index 06fb51f..086cbed 100644
--- a/src/pulsecore/core-format.h
+++ b/src/pulsecore/core-format.h
@@ -37,6 +37,11 @@ int pa_format_info_get_rate(pa_format_info *f, uint32_t *rate);
  * -PA_ERR_NOENTITY. */
 int pa_format_info_get_channels(pa_format_info *f, uint8_t *channels);
 
+/* Gets the channel map stored in the format info. Returns a negative error
+ * code on failure. If the channel map property is not set at all, returns
+ * -PA_ERR_NOENTITY. */
+int pa_format_info_get_channel_map(pa_format_info *f, pa_channel_map *map);
+
 /* For compressed formats. Converts the format info into a sample spec and a
  * channel map that an ALSA device can use as its configuration parameters when
  * playing back the compressed data. That is, the returned sample spec doesn't

commit 066dd942aa1855f1a05d1352b13dd540fa0c033f
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Mon Nov 25 14:51:37 2013 +0200

    core-format: Add pa_format_info_get_channels()
    
    This also fixes an issue in pa_format_info_to_sample_spec(): it did
    no validation for the channels value. Now the validation is taken care
    of in pa_format_info_get_channels().

diff --git a/src/pulse/format.c b/src/pulse/format.c
index 1b4a154..424df0e 100644
--- a/src/pulse/format.c
+++ b/src/pulse/format.c
@@ -219,7 +219,6 @@ pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_m
 /* For PCM streams */
 int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
     char *m = NULL;
-    int channels;
     int ret = -PA_ERR_INVALID;
 
     pa_assert(f);
@@ -232,11 +231,9 @@ int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_chan
         goto out;
     if (pa_format_info_get_rate(f, &ss->rate) < 0)
         goto out;
-    if (pa_format_info_get_prop_int(f, PA_PROP_FORMAT_CHANNELS, &channels))
+    if (pa_format_info_get_channels(f, &ss->channels) < 0)
         goto out;
 
-    ss->channels = (uint8_t) channels;
-
     if (map) {
         pa_channel_map_init(map);
 
diff --git a/src/pulsecore/core-format.c b/src/pulsecore/core-format.c
index 43ad468..c245719 100644
--- a/src/pulsecore/core-format.c
+++ b/src/pulsecore/core-format.c
@@ -74,6 +74,27 @@ int pa_format_info_get_rate(pa_format_info *f, uint32_t *rate) {
     return 0;
 }
 
+int pa_format_info_get_channels(pa_format_info *f, uint8_t *channels) {
+    int r;
+    int channels_local;
+
+    pa_assert(f);
+    pa_assert(channels);
+
+    r = pa_format_info_get_prop_int(f, PA_PROP_FORMAT_CHANNELS, &channels_local);
+    if (r < 0)
+        return r;
+
+    if (!pa_channels_valid(channels_local)) {
+        pa_log_debug("Invalid channel count: %i", channels_local);
+        return -PA_ERR_INVALID;
+    }
+
+    *channels = channels_local;
+
+    return 0;
+}
+
 int pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
     int rate;
 
diff --git a/src/pulsecore/core-format.h b/src/pulsecore/core-format.h
index 7e5d982..06fb51f 100644
--- a/src/pulsecore/core-format.h
+++ b/src/pulsecore/core-format.h
@@ -32,6 +32,11 @@ int pa_format_info_get_sample_format(pa_format_info *f, pa_sample_format_t *sf);
  * -PA_ERR_NOENTITY. */
 int pa_format_info_get_rate(pa_format_info *f, uint32_t *rate);
 
+/* Gets the channel count stored in the format info. Returns a negative error
+ * code on failure. If the channels property is not set at all, returns
+ * -PA_ERR_NOENTITY. */
+int pa_format_info_get_channels(pa_format_info *f, uint8_t *channels);
+
 /* For compressed formats. Converts the format info into a sample spec and a
  * channel map that an ALSA device can use as its configuration parameters when
  * playing back the compressed data. That is, the returned sample spec doesn't

commit 85a3f560d1089ad595cde6181a88cb1e72423e49
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Mon Nov 25 14:34:58 2013 +0200

    core-format: Add pa_format_info_get_rate()
    
    This also fixes an issue in pa_format_info_to_sample_spec(): it did
    no validation for the rate value. Now the validation is taken care of
    in pa_format_info_get_rate().

diff --git a/src/pulse/format.c b/src/pulse/format.c
index 0b87560..1b4a154 100644
--- a/src/pulse/format.c
+++ b/src/pulse/format.c
@@ -219,7 +219,7 @@ pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_m
 /* For PCM streams */
 int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
     char *m = NULL;
-    int rate, channels;
+    int channels;
     int ret = -PA_ERR_INVALID;
 
     pa_assert(f);
@@ -230,12 +230,11 @@ int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_chan
 
     if (pa_format_info_get_sample_format(f, &ss->format) < 0)
         goto out;
-    if (pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate))
+    if (pa_format_info_get_rate(f, &ss->rate) < 0)
         goto out;
     if (pa_format_info_get_prop_int(f, PA_PROP_FORMAT_CHANNELS, &channels))
         goto out;
 
-    ss->rate = (uint32_t) rate;
     ss->channels = (uint8_t) channels;
 
     if (map) {
diff --git a/src/pulsecore/core-format.c b/src/pulsecore/core-format.c
index cb65e9e..43ad468 100644
--- a/src/pulsecore/core-format.c
+++ b/src/pulsecore/core-format.c
@@ -53,6 +53,27 @@ int pa_format_info_get_sample_format(pa_format_info *f, pa_sample_format_t *sf)
     return 0;
 }
 
+int pa_format_info_get_rate(pa_format_info *f, uint32_t *rate) {
+    int r;
+    int rate_local;
+
+    pa_assert(f);
+    pa_assert(rate);
+
+    r = pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate_local);
+    if (r < 0)
+        return r;
+
+    if (!pa_sample_rate_valid(rate_local)) {
+        pa_log_debug("Invalid sample rate: %i", rate_local);
+        return -PA_ERR_INVALID;
+    }
+
+    *rate = rate_local;
+
+    return 0;
+}
+
 int pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
     int rate;
 
diff --git a/src/pulsecore/core-format.h b/src/pulsecore/core-format.h
index 8299730..7e5d982 100644
--- a/src/pulsecore/core-format.h
+++ b/src/pulsecore/core-format.h
@@ -27,6 +27,11 @@
  * -PA_ERR_NOENTITY. */
 int pa_format_info_get_sample_format(pa_format_info *f, pa_sample_format_t *sf);
 
+/* Gets the sample rate stored in the format info. Returns a negative error
+ * code on failure. If the sample rate property is not set at all, returns
+ * -PA_ERR_NOENTITY. */
+int pa_format_info_get_rate(pa_format_info *f, uint32_t *rate);
+
 /* For compressed formats. Converts the format info into a sample spec and a
  * channel map that an ALSA device can use as its configuration parameters when
  * playing back the compressed data. That is, the returned sample spec doesn't

commit eae16f41a4d75ab4d35ddf5045b2fd7c83430754
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Mon Nov 25 16:15:54 2013 +0200

    core-format: Add pa_format_info_get_sample_format()

diff --git a/src/pulse/format.c b/src/pulse/format.c
index 9c7e13e..0b87560 100644
--- a/src/pulse/format.c
+++ b/src/pulse/format.c
@@ -218,7 +218,7 @@ pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_m
 
 /* For PCM streams */
 int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
-    char *sf = NULL, *m = NULL;
+    char *m = NULL;
     int rate, channels;
     int ret = -PA_ERR_INVALID;
 
@@ -228,16 +228,13 @@ int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_chan
     if (!pa_format_info_is_pcm(f))
         return pa_format_info_to_sample_spec_fake(f, ss, map);
 
-    if (pa_format_info_get_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, &sf))
+    if (pa_format_info_get_sample_format(f, &ss->format) < 0)
         goto out;
     if (pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate))
         goto out;
     if (pa_format_info_get_prop_int(f, PA_PROP_FORMAT_CHANNELS, &channels))
         goto out;
 
-    if ((ss->format = pa_parse_sample_format(sf)) == PA_SAMPLE_INVALID)
-        goto out;
-
     ss->rate = (uint32_t) rate;
     ss->channels = (uint8_t) channels;
 
@@ -252,8 +249,6 @@ int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_chan
     ret = 0;
 
 out:
-    if (sf)
-        pa_xfree(sf);
     if (m)
         pa_xfree(m);
 
diff --git a/src/pulsecore/core-format.c b/src/pulsecore/core-format.c
index 6e7c1fb..cb65e9e 100644
--- a/src/pulsecore/core-format.c
+++ b/src/pulsecore/core-format.c
@@ -24,9 +24,35 @@
 #include "core-format.h"
 
 #include <pulse/def.h>
+#include <pulse/xmalloc.h>
 
 #include <pulsecore/macro.h>
 
+int pa_format_info_get_sample_format(pa_format_info *f, pa_sample_format_t *sf) {
+    int r;
+    char *sf_str;
+    pa_sample_format_t sf_local;
+
+    pa_assert(f);
+    pa_assert(sf);
+
+    r = pa_format_info_get_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, &sf_str);
+    if (r < 0)
+        return r;
+
+    sf_local = pa_parse_sample_format(sf_str);
+    pa_xfree(sf_str);
+
+    if (!pa_sample_format_valid(sf_local)) {
+        pa_log_debug("Invalid sample format.");
+        return -PA_ERR_INVALID;
+    }
+
+    *sf = sf_local;
+
+    return 0;
+}
+
 int pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
     int rate;
 
diff --git a/src/pulsecore/core-format.h b/src/pulsecore/core-format.h
index ef2c8dc..8299730 100644
--- a/src/pulsecore/core-format.h
+++ b/src/pulsecore/core-format.h
@@ -22,6 +22,11 @@
 
 #include <pulse/format.h>
 
+/* Gets the sample format stored in the format info. Returns a negative error
+ * code on failure. If the sample format property is not set at all, returns
+ * -PA_ERR_NOENTITY. */
+int pa_format_info_get_sample_format(pa_format_info *f, pa_sample_format_t *sf);
+
 /* For compressed formats. Converts the format info into a sample spec and a
  * channel map that an ALSA device can use as its configuration parameters when
  * playing back the compressed data. That is, the returned sample spec doesn't

commit d2c9b46acaa11cdaf15726cd8e453a0cefc277cf
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Mon Nov 18 19:43:48 2013 +0200

    Move pa_format_info_to_sample_spec_fake() to core-format
    
    I will need to use the function from outside libpulse.
    
    I added the channel map argument, because the function will be called
    from another function that is expected to initialize the channel map.
    I don't know if it's in practice necessary, but it shouldn't do any
    harm either.

diff --git a/src/Makefile.am b/src/Makefile.am
index c89cd6d..b2f6405 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -614,6 +614,7 @@ libpulsecommon_ at PA_MAJORMINOR@_la_SOURCES = \
 		pulsecore/authkey.c pulsecore/authkey.h \
 		pulsecore/conf-parser.c pulsecore/conf-parser.h \
 		pulsecore/core-error.c pulsecore/core-error.h \
+		pulsecore/core-format.c pulsecore/core-format.h \
 		pulsecore/core-rtclock.c pulsecore/core-rtclock.h \
 		pulsecore/core-util.c pulsecore/core-util.h \
 		pulsecore/creds.h \
diff --git a/src/pulse/format.c b/src/pulse/format.c
index c0c53bf..9c7e13e 100644
--- a/src/pulse/format.c
+++ b/src/pulse/format.c
@@ -30,6 +30,7 @@
 #include <pulse/internal.h>
 #include <pulse/xmalloc.h>
 
+#include <pulsecore/core-format.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/i18n.h>
 #include <pulsecore/macro.h>
@@ -215,28 +216,6 @@ pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_m
     return f;
 }
 
-/* For compressed streams */
-static int pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss) {
-    int rate;
-
-    pa_assert(f);
-    pa_assert(ss);
-
-    /* Note: When we add support for non-IEC61937 encapsulated compressed
-     * formats, this function should return a non-zero values for these. */
-
-    ss->format = PA_SAMPLE_S16LE;
-    ss->channels = 2;
-
-    pa_return_val_if_fail(pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate) == 0, -PA_ERR_INVALID);
-    ss->rate = (uint32_t) rate;
-
-    if (f->encoding == PA_ENCODING_EAC3_IEC61937)
-        ss->rate *= 4;
-
-    return 0;
-}
-
 /* For PCM streams */
 int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
     char *sf = NULL, *m = NULL;
@@ -247,7 +226,7 @@ int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_chan
     pa_assert(ss);
 
     if (!pa_format_info_is_pcm(f))
-        return pa_format_info_to_sample_spec_fake(f, ss);
+        return pa_format_info_to_sample_spec_fake(f, ss, map);
 
     if (pa_format_info_get_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, &sf))
         goto out;
diff --git a/src/pulsecore/core-format.c b/src/pulsecore/core-format.c
new file mode 100644
index 0000000..6e7c1fb
--- /dev/null
+++ b/src/pulsecore/core-format.c
@@ -0,0 +1,52 @@
+/***
+  This file is part of PulseAudio.
+
+  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
+  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 "core-format.h"
+
+#include <pulse/def.h>
+
+#include <pulsecore/macro.h>
+
+int pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
+    int rate;
+
+    pa_assert(f);
+    pa_assert(ss);
+
+    /* Note: When we add support for non-IEC61937 encapsulated compressed
+     * formats, this function should return a non-zero values for these. */
+
+    ss->format = PA_SAMPLE_S16LE;
+    ss->channels = 2;
+
+    if (map)
+        pa_channel_map_init_stereo(map);
+
+    pa_return_val_if_fail(pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate) == 0, -PA_ERR_INVALID);
+    ss->rate = (uint32_t) rate;
+
+    if (f->encoding == PA_ENCODING_EAC3_IEC61937)
+        ss->rate *= 4;
+
+    return 0;
+}
diff --git a/src/pulsecore/core-format.h b/src/pulsecore/core-format.h
new file mode 100644
index 0000000..ef2c8dc
--- /dev/null
+++ b/src/pulsecore/core-format.h
@@ -0,0 +1,31 @@
+#ifndef foocoreformathfoo
+#define foocoreformathfoo
+
+/***
+  This file is part of PulseAudio.
+
+  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
+  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/format.h>
+
+/* For compressed formats. Converts the format info into a sample spec and a
+ * channel map that an ALSA device can use as its configuration parameters when
+ * playing back the compressed data. That is, the returned sample spec doesn't
+ * describe the audio content, but the device parameters. */
+int pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map);
+
+#endif



More information about the pulseaudio-commits mailing list