#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>
#include <pulsecore/macro.h>
#include <pulsecore/play-memblockq.h>
#include <pulsecore/flist.h>
+#ifdef __TIZEN__
+#include <pulsecore/proplist-util.h>
+#endif
#include "sink.h"
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);
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;
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,
}
}
+#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];
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);
}
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) {
inputs_drop(s, info, n, result);
+#ifdef TIZEN_PCM_DUMP
+ pa_sink_write_pcm_dump(s, result);
+#endif
pa_sink_unref(s);
}
inputs_drop(s, info, n, target);
+#ifdef TIZEN_PCM_DUMP
+ pa_sink_write_pcm_dump(s, target);
+#endif
pa_sink_unref(s);
}
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",
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;
}
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;
}
/* 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();
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() */
return 0;
}
+ s->port_changing = true;
+
if (s->set_port(s, port) < 0)
return -PA_ERR_NOENTITY;
pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], s);
+ s->port_changing = false;
+
return 0;
}