sink-input: adjust log level of empty-pop operations
[platform/upstream/pulseaudio.git] / src / pulsecore / sink.c
index 56a3ce4..ae3be39 100644 (file)
@@ -25,6 +25,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#ifdef TIZEN_PCM_DUMP
+#include <time.h>
+#endif
 
 #include <pulse/introspect.h>
 #include <pulse/format.h>
@@ -46,6 +49,9 @@
 #include <pulsecore/macro.h>
 #include <pulsecore/play-memblockq.h>
 #include <pulsecore/flist.h>
+#ifdef __TIZEN__
+#include <pulsecore/proplist-util.h>
+#endif
 
 #include "sink.h"
 
@@ -75,6 +81,69 @@ static void pa_sink_volume_change_push(pa_sink *s);
 static void pa_sink_volume_change_flush(pa_sink *s);
 static void pa_sink_volume_change_rewind(pa_sink *s, size_t nbytes);
 
+#ifdef TIZEN_PCM_DUMP
+static void pa_sink_write_pcm_dump(pa_sink *s, pa_memchunk *chunk)
+{
+    char *dump_time = NULL, *dump_path_surfix = NULL;
+    const char *s_device_api_str, *card_name_str, *device_idx_str;
+    struct timeval now;
+    struct tm tm;
+    char datetime[7];
+
+    /* open file for dump pcm */
+    if (s->core->pcm_dump & PA_PCM_DUMP_SINK && !s->pcm_dump_fp && s->state == PA_SINK_RUNNING) {
+        pa_gettimeofday(&now);
+        localtime_r(&now.tv_sec, &tm);
+        memset(&datetime[0], 0x00, sizeof(datetime));
+        strftime(&datetime[0], sizeof(datetime), "%H%M%S", &tm);
+        dump_time = pa_sprintf_malloc("%s.%03ld", &datetime[0], now.tv_usec / 1000);
+
+        if ((s_device_api_str = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_API))) {
+            if (pa_streq(s_device_api_str, "alsa")) {
+                card_name_str = pa_proplist_gets(s->proplist, "alsa.card_name");
+                device_idx_str = pa_proplist_gets(s->proplist, "alsa.device");
+                dump_path_surfix = pa_sprintf_malloc("%s.%s", pa_strnull(card_name_str), pa_strnull(device_idx_str));
+            } else {
+                dump_path_surfix = pa_sprintf_malloc("%s", s_device_api_str);
+            }
+        } else {
+            dump_path_surfix = pa_sprintf_malloc("%s", s->name);
+        }
+
+        s->dump_path = pa_sprintf_malloc("%s_%s_pa-sink%d-%s_%dch_%d.raw", PA_PCM_DUMP_PATH_PREFIX, pa_strempty(dump_time),
+            s->index, pa_strempty(dump_path_surfix), s->sample_spec.channels, s->sample_spec.rate);
+        if (s->dump_path) {
+            s->pcm_dump_fp = fopen(s->dump_path, "w");
+            if (!s->pcm_dump_fp)
+                pa_log_warn("%s open failed", s->dump_path);
+            else
+                pa_log_info("%s opened", s->dump_path);
+        }
+        pa_xfree(dump_time);
+        pa_xfree(dump_path_surfix);
+    /* close file for dump pcm when config is changed */
+    } else if (~s->core->pcm_dump & PA_PCM_DUMP_SINK && s->pcm_dump_fp) {
+        fclose(s->pcm_dump_fp);
+        pa_log_info("%s closed", s->dump_path);
+        pa_xfree(s->dump_path);
+        s->pcm_dump_fp = NULL;
+    }
+
+    /* dump pcm */
+    if (s->pcm_dump_fp) {
+        void *ptr = NULL;
+
+        ptr = pa_memblock_acquire(chunk->memblock);
+        if (ptr)
+            fwrite((uint8_t *)ptr + chunk->index, 1, chunk->length, s->pcm_dump_fp);
+        else
+            pa_log_warn("pa_memblock_acquire is failed. ptr is NULL");
+
+        pa_memblock_release(chunk->memblock);
+    }
+}
+#endif
+
 pa_sink_new_data* pa_sink_new_data_init(pa_sink_new_data *data) {
     pa_assert(data);
 
@@ -282,6 +351,10 @@ pa_sink* pa_sink_new(
         s->avoid_resampling = data->avoid_resampling;
     else
         s->avoid_resampling = s->core->avoid_resampling;
+#ifdef __TIZEN__
+    s->selected_sample_format = s->sample_spec.format;
+    s->selected_sample_rate = s->sample_spec.rate;
+#endif
 
     s->inputs = pa_idxset_new(NULL, NULL);
     s->n_corked = 0;
@@ -323,6 +396,10 @@ pa_sink* pa_sink_new(
 
     s->save_volume = data->save_volume;
     s->save_muted = data->save_muted;
+#ifdef TIZEN_PCM_DUMP
+    s->pcm_dump_fp = NULL;
+    s->dump_path = NULL;
+#endif
 
     pa_silence_memchunk_get(
             &core->silence_cache,
@@ -482,6 +559,15 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t
         }
     }
 
+#ifdef TIZEN_PCM_DUMP
+    /* close file for dump pcm */
+    if (s->pcm_dump_fp && (s->core->pcm_dump & PA_PCM_DUMP_SEPARATED) && suspending) {
+        fclose(s->pcm_dump_fp);
+        pa_log_info("%s closed", s->dump_path);
+        pa_xfree(s->dump_path);
+        s->pcm_dump_fp = NULL;
+    }
+#endif
     old_suspend_cause = s->suspend_cause;
     if (suspend_cause_changed) {
         char old_cause_buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE];
@@ -784,6 +870,10 @@ void pa_sink_unlink(pa_sink* s) {
         j = i;
     }
 
+    /* Unlink monitor source before unlinking the sink */
+    if (s->monitor_source)
+        pa_source_unlink(s->monitor_source);
+
     if (linked)
         /* It's important to keep the suspend cause unchanged when unlinking,
          * because if we remove the SESSION suspend cause here, the alsa sink
@@ -795,9 +885,6 @@ void pa_sink_unlink(pa_sink* s) {
 
     reset_callbacks(s);
 
-    if (s->monitor_source)
-        pa_source_unlink(s->monitor_source);
-
     if (linked) {
         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
         pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], s);
@@ -837,6 +924,15 @@ static void sink_free(pa_object *o) {
     if (s->ports)
         pa_hashmap_free(s->ports);
 
+#ifdef TIZEN_PCM_DUMP
+    /* close file for dump pcm */
+    if (s->pcm_dump_fp) {
+        fclose(s->pcm_dump_fp);
+        pa_log_info("%s closed", s->dump_path);
+        pa_xfree(s->dump_path);
+        s->pcm_dump_fp = NULL;
+    }
+#endif
     pa_xfree(s);
 }
 
@@ -1070,6 +1166,11 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
         pa_log_debug("Processing rewind...");
         if (s->flags & PA_SINK_DEFERRED_VOLUME)
             pa_sink_volume_change_rewind(s, nbytes);
+#ifdef TIZEN_PCM_DUMP
+        /* rewind pcm */
+        if (s->pcm_dump_fp)
+            fseeko(s->pcm_dump_fp, (off_t)nbytes * (-1), SEEK_CUR);
+#endif
     }
 
     PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
@@ -1303,6 +1404,9 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
 
     inputs_drop(s, info, n, result);
 
+#ifdef TIZEN_PCM_DUMP
+    pa_sink_write_pcm_dump(s, result);
+#endif
     pa_sink_unref(s);
 }
 
@@ -1388,6 +1492,9 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
 
     inputs_drop(s, info, n, target);
 
+#ifdef TIZEN_PCM_DUMP
+    pa_sink_write_pcm_dump(s, target);
+#endif
     pa_sink_unref(s);
 }
 
@@ -1480,10 +1587,12 @@ void pa_sink_reconfigure(pa_sink *s, pa_sample_spec *spec, bool passthrough) {
     if (!s->reconfigure)
         return;
 
+#ifndef __TIZEN__
     if (PA_UNLIKELY(default_rate == alternate_rate && !passthrough && !avoid_resampling)) {
         pa_log_debug("Default and alternate sample rates are the same, so there is no point in switching.");
         return;
     }
+#endif
 
     if (PA_SINK_IS_RUNNING(s->state)) {
         pa_log_info("Cannot update sample spec, SINK_IS_RUNNING, will keep using %s and %u Hz",
@@ -1503,6 +1612,12 @@ void pa_sink_reconfigure(pa_sink *s, pa_sample_spec *spec, bool passthrough) {
 
     desired_spec = s->sample_spec;
 
+#ifdef __TIZEN__
+    if (!avoid_resampling) {
+        default_rate = alternate_rate = s->selected_sample_rate;
+        desired_spec.format = s->selected_sample_format;
+    }
+#endif
     if (passthrough) {
         /* We have to try to use the sink input format and rate */
         desired_spec.format = spec->format;
@@ -1538,7 +1653,14 @@ void pa_sink_reconfigure(pa_sink *s, pa_sample_spec *spec, bool passthrough) {
     }
 
     if (pa_sample_spec_equal(&desired_spec, &s->sample_spec) && passthrough == pa_sink_is_passthrough(s))
+#ifdef __TIZEN__
+    {
+        pa_log_info("desired spec is same as sink->sample_spec");
+        return;
+    }
+#else
         return;
+#endif
 
     if (!passthrough && pa_sink_used_by(s) > 0)
         return;
@@ -2382,7 +2504,11 @@ void pa_sink_mute_changed(pa_sink *s, bool new_muted) {
 }
 
 /* Called from main thread */
+#ifdef __TIZEN__
+void pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
+#else
 bool pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
+#endif
     pa_sink_assert_ref(s);
     pa_assert_ctl_context();
 
@@ -2394,8 +2520,29 @@ bool pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p)
         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
     }
 
+#ifndef __TIZEN__
     return true;
+#endif
+}
+
+#ifdef __TIZEN__
+/* Called from main thread */
+void pa_sink_update_proplist_remote_access_permission(pa_sink *s, bool allowed) {
+    pa_proplist* p = NULL;
+
+    pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
+
+    p = pa_proplist_new();
+
+    if (pa_proplist_set_remote_access_permission(p, allowed) == 0)
+         pa_sink_update_proplist(s, PA_UPDATE_REPLACE, p);
+    else
+        pa_log_error("set remote access permission %d on proplist %p failed", allowed, p);
+
+    pa_proplist_free(p);
 }
+#endif /* __TIZEN__ */
 
 /* Called from main thread */
 /* FIXME -- this should be dropped and be merged into pa_sink_update_proplist() */
@@ -3430,6 +3577,8 @@ int pa_sink_set_port(pa_sink *s, const char *name, bool save) {
         return 0;
     }
 
+    s->port_changing = true;
+
     if (s->set_port(s, port) < 0)
         return -PA_ERR_NOENTITY;
 
@@ -3447,6 +3596,8 @@ int pa_sink_set_port(pa_sink *s, const char *name, bool save) {
 
     pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], s);
 
+    s->port_changing = false;
+
     return 0;
 }
 
@@ -3577,6 +3728,14 @@ unsigned pa_device_init_priority(pa_proplist *p) {
 
     pa_assert(p);
 
+    /* JACK sinks and sources get very high priority so that we'll switch the
+     * default devices automatically when jackd starts and
+     * module-jackdbus-detect creates the jack sink and source. */
+    if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_API))) {
+        if (pa_streq(s, "jack"))
+            priority += 10000;
+    }
+
     if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS))) {
 
         if (pa_streq(s, "sound"))
@@ -3609,10 +3768,18 @@ unsigned pa_device_init_priority(pa_proplist *p) {
 
     if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_NAME))) {
 
-        if (pa_startswith(s, "analog-"))
+        if (pa_startswith(s, "analog-")) {
             priority += 9;
+
+            /* If an analog device has an intended role of "phone", it probably
+             * co-exists with another device that is meant for everything else,
+             * and that other device should have higher priority than the phone
+             * device. */
+            if (pa_str_in_list_spaces(pa_proplist_gets(p, PA_PROP_DEVICE_INTENDED_ROLES), "phone"))
+                priority -= 1;
+        }
         else if (pa_startswith(s, "iec958-"))
-            priority += 8;
+            priority += 7;
     }
 
     return priority;
@@ -3973,6 +4140,10 @@ void pa_sink_move_streams_to_default_sink(pa_core *core, pa_sink *old_sink, bool
         if (!i->sink)
             continue;
 
+        /* Don't move sink-inputs which connect filter sinks to their target sinks */
+        if (i->origin_sink)
+            continue;
+
         /* If default_sink_changed is false, the old sink became unavailable, so all streams must be moved. */
         if (pa_safe_streq(old_sink->name, i->preferred_sink) && default_sink_changed)
             continue;