alsa-sink/source, sink, source: Consider sample format for avoid-resampling/passthrough 82/182582/5
authorSangchul Lee <sc11.lee@samsung.com>
Tue, 19 Jun 2018 08:04:23 +0000 (17:04 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Mon, 16 Jul 2018 08:07:11 +0000 (17:07 +0900)
Sample format(e.g. 16 bit, 24 bit) was not considered even if the
avoid-resampling option is set or the passthrough mode is used.
This patch checks both sample format and rate of a stream to
determine whether to avoid resampling in case of the option is set.
In other word, it is possble to use the stream's original sample
format and rate without resampling as long as these are supported
by the device.

pa_sink_input_update_rate() and pa_source_output_update_rate() are
renamed to pa_sink_input_update_resampler() and pa_source_output
_update_resampler() respectively.

[Version] 11.1-43
[Issue Type] New feature

Change-Id: Iff4d5490b5072b7a9d711047c684f437c2db8ce0
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
packaging/pulseaudio.spec
src/modules/alsa/alsa-sink.c
src/modules/alsa/alsa-source.c
src/pulsecore/sink-input.c
src/pulsecore/sink-input.h
src/pulsecore/sink.c
src/pulsecore/source-output.c
src/pulsecore/source-output.h
src/pulsecore/source.c

index 25ef74d..1f732e2 100644 (file)
@@ -3,7 +3,7 @@
 Name:             pulseaudio
 Summary:          Improved Linux sound server
 Version:          11.1
-Release:          42
+Release:          43
 Group:            Multimedia/Audio
 License:          LGPL-2.1
 URL:              http://pulseaudio.org
index 561dae6..191c0cc 100644 (file)
@@ -115,12 +115,23 @@ struct userdata {
 #else
     pa_sample_format_t *supported_formats;
     unsigned int *supported_rates;
+    struct {
+        pa_sample_spec sample_spec;
+        size_t fragment_size;
+        size_t nfrags;
+        size_t tsched_size;
+        size_t tsched_watermark;
+        size_t rewind_safeguard;
+    } initial_info;
 #endif
 
     size_t
         frame_size,
         fragment_size,
         hwbuf_size,
+#ifdef __TIZEN__
+        tsched_size,
+#endif
         tsched_watermark,
         tsched_watermark_ref,
         hwbuf_unused,
@@ -1068,12 +1079,47 @@ static void reset_watermark(struct userdata *u, size_t tsched_watermark, pa_samp
                 (double) u->tsched_watermark_usec / PA_USEC_PER_MSEC);
 }
 
+#ifdef __TIZEN__
+static void update_size(struct userdata *u, pa_sample_spec *ss) {
+    pa_assert(u);
+    pa_assert(ss);
+
+    u->frame_size = pa_frame_size(ss);
+    u->frames_per_block = pa_mempool_block_size_max(u->core->mempool) / u->frame_size;
+
+    if (u->initial_info.sample_spec.rate == ss->rate && u->initial_info.sample_spec.format == ss->format) {
+        /* use initial values including module arguments */
+        u->fragment_size = u->initial_info.fragment_size;
+        u->hwbuf_size = u->initial_info.nfrags * u->fragment_size;
+        u->tsched_size = u->initial_info.tsched_size;
+        u->tsched_watermark = u->initial_info.tsched_watermark;
+        u->rewind_safeguard = u->initial_info.rewind_safeguard;
+    } else {
+        u->fragment_size = pa_usec_to_bytes(u->core->default_fragment_size_msec * PA_USEC_PER_MSEC, ss);
+        u->hwbuf_size = u->core->default_n_fragments * u->fragment_size;
+        u->tsched_size = pa_usec_to_bytes(DEFAULT_TSCHED_BUFFER_USEC, ss);
+        u->tsched_watermark = pa_usec_to_bytes(DEFAULT_TSCHED_WATERMARK_USEC, ss);
+        u->rewind_safeguard = PA_MAX(DEFAULT_REWIND_SAFEGUARD_BYTES, pa_usec_to_bytes(DEFAULT_REWIND_SAFEGUARD_USEC, ss));
+    }
+
+    u->tsched_watermark_ref = u->tsched_watermark;
+
+    pa_log_info("Updated frame_size %zu, frames_per_block %lu, fragment_size %zu, hwbuf_size %zu, tsched(size %zu, watermark %zu), rewind_safeguard %zu",
+                u->frame_size, (unsigned long) u->frames_per_block, u->fragment_size, u->hwbuf_size, u->tsched_size, u->tsched_watermark, u->rewind_safeguard);
+}
+#endif
+
 /* Called from IO context */
 static int unsuspend(struct userdata *u) {
     pa_sample_spec ss;
     int err;
     bool b, d;
+#ifndef __TIZEN__
     snd_pcm_uframes_t period_size, buffer_size;
+#else
+    snd_pcm_uframes_t period_frames, buffer_frames;
+    snd_pcm_uframes_t tsched_frames = 0;
+#endif
     char *device_name = NULL;
 
     pa_assert(u);
@@ -1098,13 +1144,27 @@ static int unsuspend(struct userdata *u) {
         goto fail;
     }
 
+#ifdef __TIZEN__
+    if (pa_frame_size(&u->sink->sample_spec) != u->frame_size) {
+        update_size(u, &u->sink->sample_spec);
+        tsched_frames = u->tsched_size / u->frame_size;
+    }
+    period_frames = u->fragment_size / u->frame_size;
+    buffer_frames = u->hwbuf_size / u->frame_size;
+#endif
     ss = u->sink->sample_spec;
+#ifndef __TIZEN__
     period_size = u->fragment_size / u->frame_size;
     buffer_size = u->hwbuf_size / u->frame_size;
+#endif
     b = u->use_mmap;
     d = u->use_tsched;
 
+#ifdef __TIZEN__
+    if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &period_frames, &buffer_frames, tsched_frames, &b, &d, true)) < 0) {
+#else
     if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &period_size, &buffer_size, 0, &b, &d, true)) < 0) {
+#endif
         pa_log("Failed to set hardware parameters: %s", pa_alsa_strerror(err));
         goto fail;
     }
@@ -1119,6 +1179,20 @@ static int unsuspend(struct userdata *u) {
         goto fail;
     }
 
+#ifdef __TIZEN__
+    if (tsched_frames) {
+        u->fragment_size = (size_t)(period_frames * u->frame_size);
+        u->hwbuf_size = (size_t)(buffer_frames * u->frame_size);
+        pa_proplist_setf(u->sink->proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%zu", u->hwbuf_size);
+        pa_proplist_setf(u->sink->proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%zu", u->fragment_size);
+    } else if (period_frames * u->frame_size != u->fragment_size ||
+                buffer_frames * u->frame_size != u->hwbuf_size) {
+        pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %zu/%zu, New %lu/%lu)",
+                    u->hwbuf_size, u->fragment_size,
+                    (unsigned long) buffer_frames * u->frame_size, (unsigned long) period_frames * u->frame_size);
+        goto fail;
+    }
+#else
     if (period_size*u->frame_size != u->fragment_size ||
         buffer_size*u->frame_size != u->hwbuf_size) {
         pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu/%lu, New %lu/%lu)",
@@ -1126,6 +1200,7 @@ static int unsuspend(struct userdata *u) {
                     (unsigned long) (buffer_size*u->frame_size), (unsigned long) (period_size*u->frame_size));
         goto fail;
     }
+#endif
 
     if (update_sw_params(u) < 0)
         goto fail;
@@ -1617,19 +1692,15 @@ static bool sink_set_formats(pa_sink *s, pa_idxset *formats) {
 static int sink_reconfigure_cb(pa_sink *s, pa_sample_spec *spec, bool passthrough) {
     struct userdata *u = s->userdata;
     int i;
+#ifndef __TIZEN__
     bool supported = false;
 
     /* FIXME: we only update rate for now */
 
     pa_assert(u);
 
-#ifdef __TIZEN__
-    for (i = 0; u->supported_rates[i]; i++) {
-        if (u->supported_rates[i] == spec->rate) {
-#else
     for (i = 0; u->rates[i]; i++) {
         if (u->rates[i] == spec->rate) {
-#endif
             supported = true;
             break;
         }
@@ -1649,6 +1720,45 @@ static int sink_reconfigure_cb(pa_sink *s, pa_sample_spec *spec, bool passthroug
     /* Passthrough status change is handled during unsuspend */
 
     return -1;
+#else
+    bool format_supported = false;
+    bool rate_supported = false;
+
+    pa_assert(u);
+
+    if (PA_SINK_IS_OPENED(s->state)) {
+        pa_log_warn("Sink is opened, skip it");
+        return -1;
+    }
+
+    for (i = 0; u->supported_formats[i] != PA_SAMPLE_MAX; i++) {
+        if (u->supported_formats[i] == spec->format) {
+            u->sink->sample_spec.format = spec->format;
+                       format_supported = true;
+            pa_log_info("Sink supports sample format of %s", pa_sample_format_to_string(spec->format));
+            break;
+        }
+    }
+
+    for (i = 0; u->supported_rates[i]; i++) {
+        if (u->supported_rates[i] == spec->rate) {
+            u->sink->sample_spec.rate = spec->rate;
+            rate_supported = true;
+            pa_log_info("Sink supports sample rate of %d Hz", spec->rate);
+            break;
+        }
+    }
+
+    if (!format_supported && !rate_supported) {
+        pa_log_warn("Sink does not support both sample format of %s and rate of %d Hz",
+                    pa_sample_format_to_string(spec->format), spec->rate);
+        return -1;
+    }
+
+    /* Passthrough status change is handled during unsuspend */
+
+    return 0;
+#endif
 }
 
 static int process_rewind(struct userdata *u) {
@@ -2166,6 +2276,15 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
     u->module = m;
     u->use_mmap = use_mmap;
     u->use_tsched = use_tsched;
+#ifdef __TIZEN__
+    u->tsched_size = tsched_size;
+    u->initial_info.sample_spec = ss;
+    u->initial_info.nfrags = (size_t) nfrags;
+    u->initial_info.fragment_size = (size_t) frag_size;
+    u->initial_info.tsched_size = (size_t) tsched_size;
+    u->initial_info.tsched_watermark = (size_t) tsched_watermark;
+    u->initial_info.rewind_safeguard = (size_t) rewind_safeguard;
+#endif
     u->deferred_volume = deferred_volume;
     u->fixed_latency_range = fixed_latency_range;
     u->first = true;
index 2970185..a6b8dcf 100644 (file)
@@ -103,12 +103,22 @@ struct userdata {
 #else
     pa_sample_format_t *supported_formats;
     unsigned int *supported_rates;
+    struct {
+        pa_sample_spec sample_spec;
+        size_t fragment_size;
+        size_t nfrags;
+        size_t tsched_size;
+        size_t tsched_watermark;
+    } initial_info;
 #endif
 
     size_t
         frame_size,
         fragment_size,
         hwbuf_size,
+#ifdef __TIZEN__
+        tsched_size,
+#endif
         tsched_watermark,
         tsched_watermark_ref,
         hwbuf_unused,
@@ -948,12 +958,44 @@ static void reset_watermark(struct userdata *u, size_t tsched_watermark, pa_samp
                 (double) u->tsched_watermark_usec / PA_USEC_PER_MSEC);
 }
 
+#ifdef __TIZEN__
+static void update_size(struct userdata *u, pa_sample_spec *ss) {
+    pa_assert(u);
+    pa_assert(ss);
+
+    u->frame_size = pa_frame_size(ss);
+    u->frames_per_block = pa_mempool_block_size_max(u->core->mempool) / u->frame_size;
+
+    if (u->initial_info.sample_spec.rate == ss->rate && u->initial_info.sample_spec.format == ss->format) {
+        /* use initial values including module arguments */
+        u->fragment_size = u->initial_info.fragment_size;
+        u->hwbuf_size = u->initial_info.nfrags * u->fragment_size;
+        u->tsched_size = u->initial_info.tsched_size;
+        u->tsched_watermark = u->initial_info.tsched_watermark;
+    } else {
+        u->fragment_size = pa_usec_to_bytes(u->core->default_fragment_size_msec * PA_USEC_PER_MSEC, ss);
+        u->hwbuf_size = u->core->default_n_fragments * u->fragment_size;
+        u->tsched_size = pa_usec_to_bytes(DEFAULT_TSCHED_BUFFER_USEC, ss);
+        u->tsched_watermark = pa_usec_to_bytes(DEFAULT_TSCHED_WATERMARK_USEC, ss);
+    }
+
+    u->tsched_watermark_ref = u->tsched_watermark;
+    pa_log_info("Updated frame_size %zu, frames_per_block %lu, fragment_size %zu, hwbuf_size %zu, tsched(size %zu, watermark %zu)",
+                u->frame_size, (unsigned long) u->frames_per_block, u->fragment_size, u->hwbuf_size, u->tsched_size, u->tsched_watermark);
+}
+#endif
+
 /* Called from IO context */
 static int unsuspend(struct userdata *u) {
     pa_sample_spec ss;
     int err;
     bool b, d;
+#ifndef __TIZEN__
     snd_pcm_uframes_t period_size, buffer_size;
+#else
+    snd_pcm_uframes_t period_frames, buffer_frames;
+    snd_pcm_uframes_t tsched_frames = 0;
+#endif
 
     pa_assert(u);
     pa_assert(!u->pcm_handle);
@@ -969,13 +1011,27 @@ static int unsuspend(struct userdata *u) {
         goto fail;
     }
 
+#ifdef __TIZEN__
+    if (pa_frame_size(&u->source->sample_spec) != u->frame_size) {
+        update_size(u, &u->source->sample_spec);
+        tsched_frames = u->tsched_size / u->frame_size;
+    }
+    period_frames = u->fragment_size / u->frame_size;
+    buffer_frames = u->hwbuf_size / u->frame_size;
+#endif
     ss = u->source->sample_spec;
+#ifndef __TIZEN__
     period_size = u->fragment_size / u->frame_size;
     buffer_size = u->hwbuf_size / u->frame_size;
+#endif
     b = u->use_mmap;
     d = u->use_tsched;
 
+#ifdef __TIZEN__
+    if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &period_frames, &buffer_frames, tsched_frames, &b, &d, true)) < 0) {
+#else
     if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &period_size, &buffer_size, 0, &b, &d, true)) < 0) {
+#endif
         pa_log("Failed to set hardware parameters: %s", pa_alsa_strerror(err));
         goto fail;
     }
@@ -990,6 +1046,20 @@ static int unsuspend(struct userdata *u) {
         goto fail;
     }
 
+#ifdef __TIZEN__
+    if (tsched_frames) {
+        u->fragment_size = (size_t)(period_frames * u->frame_size);
+        u->hwbuf_size = (size_t)(buffer_frames * u->frame_size);
+        pa_proplist_setf(u->source->proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%zu", u->hwbuf_size);
+        pa_proplist_setf(u->source->proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%zu", u->fragment_size);
+    } else if (period_frames * u->frame_size != u->fragment_size ||
+                buffer_frames * u->frame_size != u->hwbuf_size) {
+        pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %zu/%zu, New %lu/%lu)",
+                    u->hwbuf_size, u->fragment_size,
+                    (unsigned long) buffer_frames * u->frame_size, (unsigned long) period_frames * u->frame_size);
+        goto fail;
+    }
+#else
     if (period_size*u->frame_size != u->fragment_size ||
         buffer_size*u->frame_size != u->hwbuf_size) {
         pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu/%lu, New %lu/%lu)",
@@ -997,6 +1067,7 @@ static int unsuspend(struct userdata *u) {
                     (unsigned long) (buffer_size*u->frame_size), (unsigned long) (period_size*u->frame_size));
         goto fail;
     }
+#endif
 
     if (update_sw_params(u) < 0)
         goto fail;
@@ -1406,19 +1477,15 @@ static void source_update_requested_latency_cb(pa_source *s) {
 static int source_reconfigure_cb(pa_source *s, pa_sample_spec *spec, bool passthrough) {
     struct userdata *u = s->userdata;
     int i;
+#ifndef __TIZEN__
     bool supported = false;
 
     /* FIXME: we only update rate for now */
 
     pa_assert(u);
 
-#ifdef __TIZEN__
-    for (i = 0; u->supported_rates[i]; i++) {
-        if (u->supported_rates[i] == spec->rate) {
-#else
     for (i = 0; u->rates[i]; i++) {
         if (u->rates[i] == spec->rate) {
-#endif
             supported = true;
             break;
         }
@@ -1436,6 +1503,43 @@ static int source_reconfigure_cb(pa_source *s, pa_sample_spec *spec, bool passth
     }
 
     return -1;
+#else
+    bool format_supported = false;
+    bool rate_supported = false;
+
+    pa_assert(u);
+
+    if (PA_SOURCE_IS_OPENED(s->state)) {
+        pa_log_warn("Source is opened, skip it");
+        return -1;
+    }
+
+    for (i = 0; u->supported_formats[i] != PA_SAMPLE_MAX; i++) {
+        if (u->supported_formats[i] == spec->format) {
+            u->source->sample_spec.format = spec->format;
+            format_supported = true;
+            pa_log_info("Source supports sample format of %s", pa_sample_format_to_string(spec->format));
+            break;
+        }
+    }
+
+    for (i = 0; u->supported_rates[i]; i++) {
+        if (u->supported_rates[i] == spec->rate) {
+            u->source->sample_spec.rate = spec->rate;
+            rate_supported = true;
+            pa_log_info("Source supports sample rate of %d Hz", spec->rate);
+            break;
+        }
+    }
+
+    if (!format_supported && !rate_supported) {
+        pa_log_warn("Source does not support both sample format of %s and rate of %d Hz",
+                    pa_sample_format_to_string(spec->format), spec->rate);
+        return -1;
+    }
+
+    return 0;
+#endif
 }
 
 static void thread_func(void *userdata) {
@@ -1846,6 +1950,14 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
     u->module = m;
     u->use_mmap = use_mmap;
     u->use_tsched = use_tsched;
+#ifdef __TIZEN__
+    u->tsched_size = tsched_size;
+    u->initial_info.sample_spec = ss;
+    u->initial_info.nfrags = (size_t) nfrags;
+    u->initial_info.fragment_size = (size_t )frag_size;
+    u->initial_info.tsched_size = (size_t) tsched_size;
+    u->initial_info.tsched_watermark = (size_t) tsched_watermark;
+#endif
     u->deferred_volume = deferred_volume;
     u->fixed_latency_range = fixed_latency_range;
     u->first = true;
index 6351a40..569fdd3 100644 (file)
@@ -524,10 +524,19 @@ int pa_sink_input_new(
 
     if (!(data->flags & PA_SINK_INPUT_VARIABLE_RATE) &&
         !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec)) {
+#ifdef __TIZEN__
+        /* try to change sink format and rate. This is done before the FIXATE hook since
+           module-suspend-on-idle can resume a sink */
+#else
         /* try to change sink rate. This is done before the FIXATE hook since
            module-suspend-on-idle can resume a sink */
+#endif
 
+#ifdef __TIZEN__
+        pa_log_info("Trying to change sample spec");
+#else
         pa_log_info("Trying to change sample rate");
+#endif
         if (pa_sink_reconfigure(data->sink, &data->sample_spec, pa_sink_input_new_data_is_passthrough(data)) >= 0)
             pa_log_info("Rate changed to %u Hz", data->sink->sample_spec.rate);
     }
@@ -751,8 +760,13 @@ static void sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state)
     if (i->sink) {
         if (i->state == PA_SINK_INPUT_CORKED && state == PA_SINK_INPUT_RUNNING && pa_sink_used_by(i->sink) == 0 &&
             !pa_sample_spec_equal(&i->sample_spec, &i->sink->sample_spec)) {
+#ifdef __TIZEN__
+            /* We were uncorked and the sink was not playing anything -- let's try
+             * to update the sample format and rate to avoid resampling */
+#else
             /* We were uncorked and the sink was not playing anything -- let's try
              * to update the sample rate to avoid resampling */
+#endif
             pa_sink_reconfigure(i->sink, &i->sample_spec, pa_sink_input_is_passthrough(i));
         }
 
@@ -2191,6 +2205,16 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, bool save) {
 
     if (!(i->flags & PA_SINK_INPUT_VARIABLE_RATE) &&
         !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec)) {
+#ifdef __TIZEN__
+        /* try to change dest sink format and rate if possible without glitches.
+           module-suspend-on-idle resumes destination sink with
+           SINK_INPUT_MOVE_FINISH hook */
+
+        pa_log_info("Trying to change sample spec");
+        if (pa_sink_reconfigure(dest, &i->sample_spec, pa_sink_input_is_passthrough(i)) >= 0)
+            pa_log_info("format, rate are updated to %s, %u Hz",
+                        pa_sample_format_to_string(dest->sample_spec.format), dest->sample_spec.rate);
+#else
         /* try to change dest sink rate if possible without glitches.
            module-suspend-on-idle resumes destination sink with
            SINK_INPUT_MOVE_FINISH hook */
@@ -2198,6 +2222,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, bool save) {
         pa_log_info("Trying to change sample rate");
         if (pa_sink_reconfigure(dest, &i->sample_spec, pa_sink_input_is_passthrough(i)) >= 0)
             pa_log_info("Rate changed to %u Hz", dest->sample_spec.rate);
+#endif
     }
 
     if (i->moving)
@@ -2215,7 +2240,11 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, bool save) {
     if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED)
         i->sink->n_corked++;
 
+#ifndef __TIZEN__
     pa_sink_input_update_rate(i);
+#else
+    pa_sink_input_update_resampler(i);
+#endif
 
     pa_sink_update_status(dest);
 
@@ -2644,9 +2673,15 @@ finish:
 }
 
 /* Called from main context */
+#ifndef __TIZEN__
 /* Updates the sink input's resampler with whatever the current sink requires
  * -- useful when the underlying sink's rate might have changed */
 int pa_sink_input_update_rate(pa_sink_input *i) {
+#else
+/* Updates the sink input's resampler with whatever the current sink requires
+ * -- useful when the underlying sink's sample spec might have changed */
+int pa_sink_input_update_resampler(pa_sink_input *i) {
+#endif
     pa_resampler *new_resampler;
     char *memblockq_name;
 
index 362e711..d86d630 100644 (file)
@@ -380,7 +380,11 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes, bool rewrite,
 void pa_sink_input_cork(pa_sink_input *i, bool b);
 
 int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate);
+#ifdef __TIZEN__
+int pa_sink_input_update_resampler(pa_sink_input *i);
+#else
 int pa_sink_input_update_rate(pa_sink_input *i);
+#endif
 
 /* This returns the sink's fields converted into out sample type */
 size_t pa_sink_input_get_max_rewind(pa_sink_input *i);
index ae71125..42507cd 100644 (file)
@@ -1576,14 +1576,23 @@ int pa_sink_reconfigure(pa_sink *s, pa_sample_spec *spec, bool passthrough) {
     }
 
     if (PA_SINK_IS_RUNNING(s->state)) {
+#ifdef __TIZEN__
+        pa_log_info("Cannot update sample spec, SINK_IS_RUNNING, will keep using %s and %u Hz",
+                    pa_sample_format_to_string(s->sample_spec.format), s->sample_spec.rate);
+#else
         pa_log_info("Cannot update rate, SINK_IS_RUNNING, will keep using %u Hz",
                     s->sample_spec.rate);
+#endif
         return -1;
     }
 
     if (s->monitor_source) {
         if (PA_SOURCE_IS_RUNNING(s->monitor_source->state) == true) {
+#ifdef __TIZEN__
+            pa_log_info("Cannot update sample spec, monitor source is RUNNING");
+#else
             pa_log_info("Cannot update rate, monitor source is RUNNING");
+#endif
             return -1;
         }
     }
@@ -1596,12 +1605,22 @@ int pa_sink_reconfigure(pa_sink *s, pa_sample_spec *spec, bool passthrough) {
 #ifdef __TIZEN__
     if (!avoid_resampling && s->selected_sample_rate)
         default_rate = alternate_rate = s->selected_sample_rate;
-#endif
+    if (passthrough) {
+        /* We have to try to use the sink input format and rate */
+        desired_spec.format = spec->format;
+        desired_spec.rate = spec->rate;
+#else
     if (passthrough) {
         /* We have to try to use the sink input rate */
         desired_spec.rate = spec->rate;
-
+#endif
+#ifdef __TIZEN__
+    } else if (avoid_resampling && (spec->format != s->sample_spec.format ||
+                spec->rate >= default_rate || spec->rate >= alternate_rate)) {
+        desired_spec.format = spec->format;
+#else
     } else if (avoid_resampling && (spec->rate >= default_rate || spec->rate >= alternate_rate)) {
+#endif
         /* We just try to set the sink input's sample rate if it's not too low */
         desired_spec.rate = spec->rate;
 
@@ -1633,7 +1652,8 @@ int pa_sink_reconfigure(pa_sink *s, pa_sample_spec *spec, bool passthrough) {
         return -1;
 
 #ifdef __TIZEN__
-    pa_log_debug("Suspending sink %s due to changing format, desired rate = %u", s->name, desired_spec.rate);
+    pa_log_debug("Suspending sink %s due to changing format, desired format = %s rate = %u",
+                 s->name, pa_sample_format_to_string(desired_spec.format), desired_spec.rate);
 #else
     pa_log_debug("Suspending sink %s due to changing format", s->name);
 #endif
@@ -1642,12 +1662,21 @@ int pa_sink_reconfigure(pa_sink *s, pa_sample_spec *spec, bool passthrough) {
     if (s->reconfigure(s, &desired_spec, passthrough) >= 0) {
         /* update monitor source as well */
         if (s->monitor_source && !passthrough)
+#ifdef __TIZEN__
+            pa_source_reconfigure(s->monitor_source, &s->sample_spec, false);
+        pa_log_info("Reconfigured successfully");
+#else
             pa_source_reconfigure(s->monitor_source, &desired_spec, false);
         pa_log_info("Changed format successfully");
+#endif
 
         PA_IDXSET_FOREACH(i, s->inputs, idx) {
             if (i->state == PA_SINK_INPUT_CORKED)
+#ifdef __TIZEN__
+                pa_sink_input_update_resampler(i);
+#else
                 pa_sink_input_update_rate(i);
+#endif
         }
 
         ret = 0;
index 7aaaadc..340845f 100644 (file)
@@ -422,12 +422,22 @@ int pa_source_output_new(
 
     if (!(data->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) &&
         !pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec)) {
+#ifdef __TIZEN__
+        /* try to change source format and rate. This is done before the FIXATE hook since
+           module-suspend-on-idle can resume a source */
+
+        pa_log_info("Trying to change sample spec");
+        if (pa_source_reconfigure(data->source, &data->sample_spec, pa_source_output_new_data_is_passthrough(data)) >= 0)
+            pa_log_info("format, rate are updated to %s, %u Hz",
+                        pa_sample_format_to_string(data->source->sample_spec.format), data->source->sample_spec.rate);
+#else
         /* try to change source rate. This is done before the FIXATE hook since
            module-suspend-on-idle can resume a source */
 
         pa_log_info("Trying to change sample rate");
         if (pa_source_reconfigure(data->source, &data->sample_spec, pa_source_output_new_data_is_passthrough(data)) >= 0)
             pa_log_info("Rate changed to %u Hz", data->source->sample_spec.rate);
+#endif
     }
 
     if (pa_source_output_new_data_is_passthrough(data) &&
@@ -597,8 +607,13 @@ static void source_output_set_state(pa_source_output *o, pa_source_output_state_
     if (o->source) {
         if (o->state == PA_SOURCE_OUTPUT_CORKED && state == PA_SOURCE_OUTPUT_RUNNING && pa_source_used_by(o->source) == 0 &&
             !pa_sample_spec_equal(&o->sample_spec, &o->source->sample_spec)) {
+#ifdef __TIZEN__
+            /* We were uncorked and the source was not playing anything -- let's try
+             * to update the sample format and rate to avoid resampling */
+#else
             /* We were uncorked and the source was not playing anything -- let's try
              * to update the sample rate to avoid resampling */
+#endif
             pa_source_reconfigure(o->source, &o->sample_spec, pa_source_output_is_passthrough(o));
         }
 
@@ -1619,6 +1634,16 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, bool save
 
     if (!(o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) &&
         !pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec)) {
+#ifdef __TIZEN__
+        /* try to change dest source format and rate if possible without glitches.
+           module-suspend-on-idle resumes destination source with
+           SOURCE_OUTPUT_MOVE_FINISH hook */
+
+        pa_log_info("Trying to change sample spec");
+        if (pa_source_reconfigure(dest, &o->sample_spec, pa_source_output_is_passthrough(o)) >= 0)
+            pa_log_info("format, rate are updated to %s, %u Hz",
+                        pa_sample_format_to_string(dest->sample_spec.format), dest->sample_spec.rate);
+#else
         /* try to change dest sink rate if possible without glitches.
            module-suspend-on-idle resumes destination source with
            SOURCE_OUTPUT_MOVE_FINISH hook */
@@ -1626,6 +1651,7 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, bool save
         pa_log_info("Trying to change sample rate");
         if (pa_source_reconfigure(dest, &o->sample_spec, pa_source_output_is_passthrough(o)) >= 0)
             pa_log_info("Rate changed to %u Hz", dest->sample_spec.rate);
+#endif
     }
 
     if (o->moving)
@@ -1640,7 +1666,11 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, bool save
     if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED)
         o->source->n_corked++;
 
+#ifndef __TIZEN__
     pa_source_output_update_rate(o);
+#else
+    pa_source_output_update_resampler(o);
+#endif
 
     pa_source_update_status(dest);
 
@@ -1814,9 +1844,15 @@ finish:
 }
 
 /* Called from main context */
+#ifndef __TIZEN__
 /* Updates the source output's resampler with whatever the current source
  * requires -- useful when the underlying source's rate might have changed */
 int pa_source_output_update_rate(pa_source_output *o) {
+#else
+/* Updates the source output's resampler with whatever the current source
+ * requires -- useful when the underlying source's sample spec might have changed */
+int pa_source_output_update_resampler(pa_source_output *o) {
+#endif
     pa_resampler *new_resampler;
     char *memblockq_name;
 
index 001a72d..51f4415 100644 (file)
@@ -300,7 +300,11 @@ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t
 void pa_source_output_cork(pa_source_output *o, bool b);
 
 int pa_source_output_set_rate(pa_source_output *o, uint32_t rate);
+#ifdef __TIZEN__
+int pa_source_output_update_resampler(pa_source_output *o);
+#else
 int pa_source_output_update_rate(pa_source_output *o);
+#endif
 
 size_t pa_source_output_get_max_rewind(pa_source_output *o);
 
index e6f022f..7471338 100644 (file)
@@ -1132,8 +1132,10 @@ int pa_source_reconfigure(pa_source *s, pa_sample_spec *spec, bool passthrough)
     bool avoid_resampling = s->core->avoid_resampling;
 #endif
 
+#ifndef __TIZEN__
     /* We currently only try to reconfigure the sample rate */
 
+#endif
     if (pa_sample_spec_equal(spec, &s->sample_spec))
         return 0;
 
@@ -1146,14 +1148,23 @@ int pa_source_reconfigure(pa_source *s, pa_sample_spec *spec, bool passthrough)
     }
 
     if (PA_SOURCE_IS_RUNNING(s->state)) {
+#ifdef __TIZEN__
+        pa_log_info("Cannot update sample spec, SOURCE_IS_RUNNING, will keep using %s and %u Hz",
+                    pa_sample_format_to_string(s->sample_spec.format), s->sample_spec.rate);
+#else
         pa_log_info("Cannot update rate, SOURCE_IS_RUNNING, will keep using %u Hz",
                     s->sample_spec.rate);
+#endif
         return -1;
     }
 
     if (s->monitor_of) {
         if (PA_SINK_IS_RUNNING(s->monitor_of->state)) {
+#ifdef __TIZEN__
+            pa_log_info("Cannot update sample spec, this is a monitor source and the sink is running.");
+#else
             pa_log_info("Cannot update rate, this is a monitor source and the sink is running.");
+#endif
             return -1;
         }
     }
@@ -1163,11 +1174,23 @@ int pa_source_reconfigure(pa_source *s, pa_sample_spec *spec, bool passthrough)
 
     desired_spec = s->sample_spec;
 
+#ifdef __TIZEN__
+    if (passthrough) {
+        /* We have to try to use the source output format and rate */
+        desired_spec.format = spec->format;
+        desired_spec.rate = spec->rate;
+#else
     if (passthrough) {
         /* We have to try to use the source output rate */
         desired_spec.rate = spec->rate;
-
+#endif
+#ifdef __TIZEN__
+    } else if (avoid_resampling && (spec->format != s->sample_spec.format ||
+                spec->rate >= default_rate || spec->rate >= alternate_rate)) {
+        desired_spec.format = spec->format;
+#else
     } else if (avoid_resampling && (spec->rate >= default_rate || spec->rate >= alternate_rate)) {
+#endif
         /* We just try to set the source output's sample rate if it's not too low */
         desired_spec.rate = spec->rate;
 
@@ -1199,7 +1222,8 @@ int pa_source_reconfigure(pa_source *s, pa_sample_spec *spec, bool passthrough)
         return -1;
 
 #ifdef __TIZEN__
-    pa_log_debug("Suspending source %s due to changing the sample rate to %u", s->name, desired_spec.rate);
+    pa_log_debug("Suspending sink %s due to changing format, desired format = %s rate = %u",
+                 s->name, pa_sample_format_to_string(desired_spec.format), desired_spec.rate);
 #else
     pa_log_debug("Suspending source %s due to changing the sample rate", s->name);
 #endif
@@ -1242,10 +1266,18 @@ int pa_source_reconfigure(pa_source *s, pa_sample_spec *spec, bool passthrough)
 
         PA_IDXSET_FOREACH(o, s->outputs, idx) {
             if (o->state == PA_SOURCE_OUTPUT_CORKED)
+#ifdef __TIZEN__
+                pa_source_output_update_resampler(o);
+#else
                 pa_source_output_update_rate(o);
+#endif
         }
 
+#ifndef __TIZEN__
         pa_log_info("Changed sampling rate successfully");
+#else
+        pa_log_info("Reconfigured successfully");
+#endif
     }
 
     pa_source_suspend(s, false, PA_SUSPEND_INTERNAL);