],[TIZEN_BUFFER_ATTR=no])
AM_CONDITIONAL(TIZEN_BUFFER_ATTR, test "x$TIZEN_BUFFER_ATTR" = "xyes")
+#### PCM DUMP ####
+
+AC_ARG_ENABLE(pcm-dump, AC_HELP_STRING([--enable-pcm-dump], [using pcm-dump]),
+ [
+ case "${enableval}" in
+ yes) TIZEN_PCM_DUMP=yes ;;
+ no) TIZEN_PCM_DUMP=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-pcm-dump) ;;
+ esac
+],[TIZEN_PCM_DUMP=no])
+AM_CONDITIONAL(TIZEN_PCM_DUMP, test "x$TIZEN_PCM_DUMP" = "xyes")
+
###################################
# Output #
###################################
Tizen
dlog: ${TIZEN_DLOG}
buffer attributes: ${TIZEN_BUFFER_ATTR}
+ pcm dump: ${TIZEN_PCM_DUMP}
"
if test "${ENABLE_SPEEX}" = "no" && test "${ENABLE_WEBRTC}" = "no" && test "${ENABLE_ADRIAN_EC}" = "no" ; then
Name: pulseaudio
Summary: Improved Linux sound server
Version: 11.1
-Release: 5
+Release: 6
Group: Multimedia/Audio
License: LGPL-2.1
URL: http://pulseaudio.org
--with-access-group=pulse-access \
--enable-dlog \
--enable-buffer-attr \
+ --enable-pcm-dump \
%__make %{?_smp_mflags} V=0
Description: Module building interface for pulseaudio
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lpulsecore-@PA_MAJORMINOR@ -lpulse -L${libdir}/pulse-@PA_MAJORMINOR@/modules -lprotocol-native -L${libdir}/pulseaudio -lpulsecommon-@PA_MAJORMINOR@ @PTHREAD_LIBS@
-Cflags: -D_REENTRANT -DTIZEN_BUFFER_ATTR -D__INCLUDED_FROM_PULSE_AUDIO -DPA_DEFAULT_CONFIG_DIR=\"@PA_DEFAULT_CONFIG_DIR@\" -I${includedir}
+Cflags: -D_REENTRANT -DTIZEN_BUFFER_ATTR -DTIZEN_PCM_DUMP -D__INCLUDED_FROM_PULSE_AUDIO -DPA_DEFAULT_CONFIG_DIR=\"@PA_DEFAULT_CONFIG_DIR@\" -I${includedir}
pactl_LDADD = $(AM_LDADD) libpulse.la libpulsecommon-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS)
pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS)
pactl_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
+if TIZEN_PCM_DUMP
+pactl_CFLAGS += $(VCONF_CFLAGS) -DTIZEN_PCM_DUMP
+pactl_LDADD += $(VCONF_LIBS)
+endif
pasuspender_SOURCES = utils/pasuspender.c
pasuspender_LDADD = $(AM_LDADD) libpulse.la libpulsecommon-@PA_MAJORMINOR@.la
libpulse_la_LIBADD += $(DBUS_LIBS)
endif
+if TIZEN_PCM_DUMP
+libpulse_la_CFLAGS += -DTIZEN_PCM_DUMP
+endif
+
libpulse_simple_la_SOURCES = pulse/simple.c pulse/simple.h
libpulse_simple_la_CFLAGS = $(AM_CFLAGS)
libpulse_simple_la_LIBADD = $(AM_LIBADD) libpulse.la libpulsecommon-@PA_MAJORMINOR@.la
libpulsecore_@PA_MAJORMINOR@_la_LIBADD += $(LIBSAMPLERATE_LIBS)
endif
+if TIZEN_PCM_DUMP
+libpulsecore_@PA_MAJORMINOR@_la_CFLAGS += -DTIZEN_PCM_DUMP
+endif
+
# We split the foreign code off to not be annoyed by warnings we don't care about
noinst_LTLIBRARIES += libpulsecore-foreign.la
if TIZEN_BUFFER_ATTR
libprotocol_native_la_CFLAGS += -DTIZEN_BUFFER_ATTR
endif
+if TIZEN_PCM_DUMP
+libprotocol_native_la_CFLAGS += -DTIZEN_PCM_DUMP
+endif
if HAVE_ESOUND
libprotocol_esound_la_SOURCES = pulsecore/protocol-esound.c pulsecore/protocol-esound.h pulsecore/esound.h
pa_context_set_default_source;
pa_context_set_event_callback;
pa_context_set_name;
+pa_context_set_pcm_dump;
+pa_context_set_pcm_dump_option;
pa_context_set_sink_input_mute;
pa_context_set_sink_input_volume;
pa_context_set_sink_mute_by_index;
return o;
}
+
+#ifdef TIZEN_PCM_DUMP
+pa_operation* pa_context_set_pcm_dump(pa_context *c, uint32_t dump_type, int dump_type_enable, pa_context_success_cb_t cb, void *userdata) {
+ pa_operation *o;
+ pa_tagstruct *t;
+ uint32_t tag;
+
+ pa_assert(c);
+ pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+ PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
+
+ o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
+
+ t = pa_tagstruct_command(c, PA_COMMAND_SET_PCM_DUMP, &tag);
+ pa_tagstruct_putu32(t, dump_type);
+ pa_tagstruct_put_boolean(t, dump_type_enable);
+ pa_pstream_send_tagstruct(c->pstream, t);
+ pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
+
+ return o;
+}
+
+pa_operation* pa_context_set_pcm_dump_option(pa_context *c, uint32_t dump_option, int dump_option_enable, pa_context_success_cb_t cb, void *userdata) {
+ pa_operation *o;
+ pa_tagstruct *t;
+ uint32_t tag;
+
+ pa_assert(c);
+ pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+ PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
+
+ o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
+
+ t = pa_tagstruct_command(c, PA_COMMAND_SET_PCM_DUMP_OPTION, &tag);
+ pa_tagstruct_putu32(t, dump_option);
+ pa_tagstruct_put_boolean(t, dump_option_enable);
+ pa_pstream_send_tagstruct(c->pstream, t);
+ pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
+
+ return o;
+}
+#endif
/** Set the latency offset of a port. \since 3.0 */
pa_operation* pa_context_set_port_latency_offset(pa_context *c, const char *card_name, const char *port_name, int64_t offset, pa_context_success_cb_t cb, void *userdata);
+#ifdef TIZEN_PCM_DUMP
+pa_operation* pa_context_set_pcm_dump(pa_context *c, uint32_t dump_type, int dump_type_enable, pa_context_success_cb_t cb, void *userdata);
+pa_operation* pa_context_set_pcm_dump_option(pa_context *c, uint32_t dump_option, int dump_option_enable, pa_context_success_cb_t cb, void *userdata);
+#endif
+
/** @} */
/** @{ \name Sink Inputs */
pa_core_check_idle(c);
c->state = PA_CORE_RUNNING;
+#ifdef TIZEN_PCM_DUMP
+ c->pcm_dump = 0;
+ c->pcm_dump_option = 0;
+#endif
return c;
}
PA_CORE_HOOK_MAX
} pa_core_hook_t;
+#ifdef TIZEN_PCM_DUMP
+#define PA_PCM_DUMP_PATH_PREFIX "/tmp/pcm"
+#define PA_PCM_DUMP_VCONF_KEY "memory/private/sound/pcm_dump"
+
+enum {
+ PA_PCM_DUMP_GST_DECODER_OUT = 0x00000001U,
+ PA_PCM_DUMP_GST_RESAMPLER_IN = 0x00000008U,
+ PA_PCM_DUMP_GST_RESAMPLER_OUT = 0x00000010U,
+ PA_PCM_DUMP_GST_AUDIO_SINK_IN = 0x00000400U,
+ PA_PCM_DUMP_PA_STREAM_WRITE = 0x00000800U,
+ PA_PCM_DUMP_PA_SINK_INPUT = 0x00002000U,
+ PA_PCM_DUMP_PA_SINK = 0x00004000U,
+ PA_PCM_DUMP_PA_SOURCE = 0x00020000U,
+ PA_PCM_DUMP_PA_SOURCE_OUTPUT = 0x00040000U,
+ PA_PCM_DUMP_PA_STREAM_READ = 0x00100000U,
+ PA_PCM_DUMP_GST_AUDIO_SRC_OUT = 0x00200000U,
+ PA_PCM_DUMP_GST_ENCODER_IN = 0x80000000U,
+};
+
+enum {
+ PA_PCM_DUMP_OPTION_SEPARATED = 0x0001U,
+ PA_PCM_DUMP_OPTION_MONITOR = 0x0002U,
+};
+#endif
+
/* The core structure of PulseAudio. Every PulseAudio daemon contains
* exactly one of these. It is used for storing kind of global
* variables for the daemon. */
/* hooks */
pa_hook hooks[PA_CORE_HOOK_MAX];
+#ifdef TIZEN_PCM_DUMP
+ uint32_t pcm_dump;
+ uint32_t pcm_dump_option;
+#endif
};
PA_DECLARE_PUBLIC_CLASS(pa_core);
* BOTH DIRECTIONS */
PA_COMMAND_REGISTER_MEMFD_SHMID,
+#ifdef TIZEN_PCM_DUMP
+ PA_COMMAND_SET_PCM_DUMP,
+ PA_COMMAND_SET_PCM_DUMP_OPTION,
+#endif
+
PA_COMMAND_MAX
};
pa_pstream_send_simple_ack(c->pstream, tag);
}
+#ifdef TIZEN_PCM_DUMP
+static void command_set_pcm_dump(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
+ pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
+ uint32_t dump_type;
+ bool dump_type_enable;
+
+ pa_native_connection_assert_ref(c);
+ pa_assert(t);
+
+ if (pa_tagstruct_getu32(t, &dump_type) < 0 ||
+ pa_tagstruct_get_boolean(t, &dump_type_enable) < 0 ||
+ !pa_tagstruct_eof(t)) {
+ protocol_error(c);
+ return;
+ }
+
+ CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
+
+ if (dump_type_enable)
+ c->protocol->core->pcm_dump |= dump_type;
+ else
+ c->protocol->core->pcm_dump &= ~dump_type;
+
+ pa_pstream_send_simple_ack(c->pstream, tag);
+}
+
+static void command_set_pcm_dump_option(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
+ pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
+ uint32_t dump_option;
+ bool dump_option_enable;
+
+ pa_native_connection_assert_ref(c);
+ pa_assert(t);
+
+ if (pa_tagstruct_getu32(t, &dump_option) < 0 ||
+ pa_tagstruct_get_boolean(t, &dump_option_enable) < 0 ||
+ !pa_tagstruct_eof(t)) {
+ protocol_error(c);
+ return;
+ }
+
+ CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
+
+ if (dump_option_enable)
+ c->protocol->core->pcm_dump_option |= dump_option;
+ else
+ c->protocol->core->pcm_dump_option &= ~dump_option;
+
+ pa_pstream_send_simple_ack(c->pstream, tag);
+}
+#endif
static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
[PA_COMMAND_ERROR] = NULL,
[PA_COMMAND_TIMEOUT] = NULL,
[PA_COMMAND_REGISTER_MEMFD_SHMID] = command_register_memfd_shmid,
- [PA_COMMAND_EXTENSION] = command_extension
+ [PA_COMMAND_EXTENSION] = command_extension,
+#ifdef TIZEN_PCM_DUMP
+ [PA_COMMAND_SET_PCM_DUMP] = command_set_pcm_dump,
+ [PA_COMMAND_SET_PCM_DUMP_OPTION] = command_set_pcm_dump_option,
+#endif
};
/*** pstream callbacks ***/
#include <stdio.h>
#include <stdlib.h>
+#ifdef TIZEN_PCM_DUMP
+#include <time.h>
+#endif
#include <pulse/utf8.h>
#include <pulse/xmalloc.h>
pa_cvolume volume;
};
+#ifdef TIZEN_PCM_DUMP
+static void pa_sink_input_write_pcm_dump(pa_sink_input *i, 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 (i->core->pcm_dump & PA_PCM_DUMP_PA_SINK_INPUT && !i->pcm_dump_fp && i->state == PA_SINK_INPUT_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(i->sink->proplist, PA_PROP_DEVICE_API))) {
+ if (pa_streq(s_device_api_str, "alsa")) {
+ card_name_str = pa_proplist_gets(i->sink->proplist, "alsa.card_name");
+ device_idx_str = pa_proplist_gets(i->sink->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", i->sink->name);
+ }
+
+ i->dump_path = pa_sprintf_malloc("%s_%s_pa-input%d-sink%d-%s_%dch_%d.raw", PA_PCM_DUMP_PATH_PREFIX, pa_strempty(dump_time),
+ i->index, i->sink->index, pa_strempty(dump_path_surfix), i->sample_spec.channels, i->sample_spec.rate);
+ if (i->dump_path) {
+ i->pcm_dump_fp = fopen(i->dump_path, "w");
+ if (!i->pcm_dump_fp)
+ pa_log_warn("%s open failed", i->dump_path);
+ else
+ pa_log_info("%s opened", i->dump_path);
+ }
+ pa_xfree(dump_time);
+ pa_xfree(dump_path_surfix);
+ /* close file for dump pcm when config is changed */
+ } else if (~i->core->pcm_dump & PA_PCM_DUMP_PA_SINK_INPUT && i->pcm_dump_fp) {
+ fclose(i->pcm_dump_fp);
+ pa_log_info("%s closed", i->dump_path);
+ pa_xfree(i->dump_path);
+ i->pcm_dump_fp = NULL;
+ }
+
+ /* dump pcm */
+ if (i->pcm_dump_fp) {
+ void *ptr = NULL;
+
+ ptr = pa_memblock_acquire(chunk->memblock);
+ if (ptr) {
+ i->dump_length = chunk->length;
+ fwrite((uint8_t *)ptr + chunk->index, 1, chunk->length, i->pcm_dump_fp);
+ } else {
+ i->dump_length = 0;
+ pa_log_warn("pa_memblock_acquire is failed. ptr is NULL");
+ }
+ pa_memblock_release(chunk->memblock);
+ }
+}
+#endif
+
static struct volume_factor_entry *volume_factor_entry_new(const char *key, const pa_cvolume *volume) {
struct volume_factor_entry *entry;
reset_callbacks(i);
i->userdata = NULL;
+#ifdef TIZEN_PCM_DUMP
+ i->pcm_dump_fp = NULL;
+ i->dump_path = NULL;
+ i->dump_length = 0;
+#endif
i->thread_info.state = i->state;
i->thread_info.attached = false;
for (ssync = i->thread_info.sync_next; ssync; ssync = ssync->thread_info.sync_next)
pa_sink_input_set_state_within_thread(ssync, state);
}
+#ifdef TIZEN_PCM_DUMP
+ if (i->state == PA_SINK_INPUT_RUNNING && i->pcm_dump_fp && (i->core->pcm_dump_option & PA_PCM_DUMP_OPTION_SEPARATED)) {
+ /* close file for dump pcm */
+ fclose(i->pcm_dump_fp);
+ pa_log_info("%s closed", i->dump_path);
+ pa_xfree(i->dump_path);
+ i->pcm_dump_fp = NULL;
+ }
+#endif
update_n_corked(i, state);
i->state = state;
if (i->thread_info.resampler)
pa_resampler_free(i->thread_info.resampler);
+#ifdef TIZEN_PCM_DUMP
+ /* close file for dump pcm */
+ if (i->pcm_dump_fp) {
+ fclose(i->pcm_dump_fp);
+ pa_log_info("%s closed", i->dump_path);
+ pa_xfree(i->dump_path);
+ i->pcm_dump_fp = NULL;
+ }
+#endif
if (i->format)
pa_format_info_free(i->format);
pa_cvolume_mute(volume, i->sink->sample_spec.channels);
else
*volume = i->thread_info.soft_volume;
+#ifdef TIZEN_PCM_DUMP
+ pa_sink_input_write_pcm_dump(i, chunk);
+#endif
}
/* Called from thread context */
#ifdef SINK_INPUT_DEBUG
pa_log_debug("dropping %lu", (unsigned long) nbytes);
#endif
+#ifdef TIZEN_PCM_DUMP
+ if (i->pcm_dump_fp && i->dump_length) {
+ int64_t seek_length;
+
+ seek_length = (int64_t) (nbytes - i->dump_length);
+
+ if (seek_length < 0)
+ fseeko(i->pcm_dump_fp, (off_t)seek_length, SEEK_CUR);
+
+ i->dump_length = 0;
+ }
+#endif
pa_memblockq_drop(i->thread_info.render_memblockq, nbytes);
}
if (i->thread_info.rewrite_nbytes == (size_t) -1) {
+#ifdef TIZEN_PCM_DUMP
+ /* rewind pcm */
+ if (i->pcm_dump_fp)
+ fseeko(i->pcm_dump_fp, (off_t)pa_memblockq_get_length(i->thread_info.render_memblockq) * (-1), SEEK_CUR);
+#endif
/* We were asked to drop all buffered data, and rerequest new
* data from implementor the next time peek() is called */
if (amount > 0) {
pa_log_debug("Have to rewind %lu bytes on implementor.", (unsigned long) amount);
+#ifdef TIZEN_PCM_DUMP
+ /* rewind pcm */
+ if (i->pcm_dump_fp)
+ fseeko(i->pcm_dump_fp, (off_t)amount * (-1), SEEK_CUR);
+#endif
/* Tell the implementor */
if (i->process_rewind)
i->process_rewind(i, amount);
pa_hashmap *direct_outputs;
} thread_info;
+#ifdef TIZEN_PCM_DUMP
+ FILE *pcm_dump_fp;
+ char *dump_path;
+ uint32_t dump_length;
+#endif
void *userdata;
};
#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>
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_PA_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_PA_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->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,
}
s->state = state;
+#ifdef TIZEN_PCM_DUMP
+ /* close file for dump pcm */
+ if (s->pcm_dump_fp && (s->core->pcm_dump_option & PA_PCM_DUMP_OPTION_SEPARATED) &&
+ state == PA_SINK_IDLE && original_state == PA_SINK_RUNNING) {
+ fclose(s->pcm_dump_fp);
+ pa_log_info("%s closed", s->dump_path);
+ pa_xfree(s->dump_path);
+ s->pcm_dump_fp = NULL;
+ }
+#endif
if (state != PA_SINK_UNLINKED) { /* if we enter UNLINKED state pa_sink_unlink() will fire the appropriate events */
pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], s);
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);
}
int32_t volume_change_extra_delay;
} thread_info;
+#ifdef TIZEN_PCM_DUMP
+ FILE *pcm_dump_fp;
+ char *dump_path;
+#endif
void *userdata;
};
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#ifdef TIZEN_PCM_DUMP
+#include <time.h>
+#endif
#include <pulse/utf8.h>
#include <pulse/xmalloc.h>
static void source_output_free(pa_object* mo);
static void set_real_ratio(pa_source_output *o, const pa_cvolume *v);
+#ifdef TIZEN_PCM_DUMP
+static void pa_source_output_write_pcm_dump(pa_source_output *o, 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 (o->core->pcm_dump & PA_PCM_DUMP_PA_SOURCE_OUTPUT && !o->pcm_dump_fp && o->state == PA_SOURCE_OUTPUT_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(o->source->proplist, PA_PROP_DEVICE_API))) {
+ if (pa_streq(s_device_api_str, "alsa")) {
+ card_name_str = pa_proplist_gets(o->source->proplist, "alsa.card_name");
+ device_idx_str = pa_proplist_gets(o->source->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", o->source->name);
+ }
+
+ o->dump_path = pa_sprintf_malloc("%s_%s_pa-output%d-source%d-%s_%dch_%d.raw", PA_PCM_DUMP_PATH_PREFIX, pa_strempty(dump_time),
+ o->index, o->source->index, pa_strempty(dump_path_surfix), o->sample_spec.channels, o->sample_spec.rate);
+ if (o->dump_path) {
+ o->pcm_dump_fp = fopen(o->dump_path, "w");
+ if (!o->pcm_dump_fp)
+ pa_log_warn("%s open failed", o->dump_path);
+ else
+ pa_log_info("%s opened", o->dump_path);
+ }
+ pa_xfree(dump_time);
+ pa_xfree(dump_path_surfix);
+ /* close file for dump pcm when config is changed */
+ } else if (~o->core->pcm_dump & PA_PCM_DUMP_PA_SOURCE_OUTPUT && o->pcm_dump_fp) {
+ fclose(o->pcm_dump_fp);
+ pa_log_info("%s closed", o->dump_path);
+ pa_xfree(o->dump_path);
+ o->pcm_dump_fp = NULL;
+ }
+
+ /* dump pcm */
+ if (o->pcm_dump_fp) {
+ void *ptr = NULL;
+
+ ptr = pa_memblock_acquire(chunk->memblock);
+ if (ptr)
+ fwrite((uint8_t *)ptr + chunk->index, 1, chunk->length, o->pcm_dump_fp);
+ else
+ pa_log_warn("pa_memblock_acquire is failed. ptr is NULL");
+
+ pa_memblock_release(chunk->memblock);
+ }
+}
+#endif
pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data) {
pa_assert(data);
/* If the source is not valid, pa_source_output_set_state_within_thread() must be called directly */
pa_source_output_set_state_within_thread(o, state);
+#ifdef TIZEN_PCM_DUMP
+ if (o->state == PA_SOURCE_OUTPUT_RUNNING && o->pcm_dump_fp && (o->core->pcm_dump_option & PA_PCM_DUMP_OPTION_SEPARATED)) {
+ /* close file for dump pcm */
+ fclose(o->pcm_dump_fp);
+ pa_log_info("%s closed", o->dump_path);
+ pa_xfree(o->dump_path);
+ o->pcm_dump_fp = NULL;
+ }
+#endif
update_n_corked(o, state);
o->state = state;
if (o->thread_info.resampler)
pa_resampler_free(o->thread_info.resampler);
+#ifdef TIZEN_PCM_DUMP
+ /* close file for dump pcm */
+ if (o->pcm_dump_fp) {
+ fclose(o->pcm_dump_fp);
+ pa_log_info("%s closed", o->dump_path);
+ pa_xfree(o->dump_path);
+ o->pcm_dump_fp = NULL;
+ }
+#endif
if (o->format)
pa_format_info_free(o->format);
pa_memblock_unref(qchunk.memblock);
pa_memblockq_drop(o->thread_info.delay_memblockq, qchunk.length);
}
+#ifdef TIZEN_PCM_DUMP
+ pa_source_output_write_pcm_dump(o, (pa_memchunk *)chunk);
+#endif
}
/* Called from thread context */
nbytes = pa_resampler_result(o->thread_info.resampler, nbytes);
pa_log_debug("Have to rewind %lu bytes on implementor.", (unsigned long) nbytes);
+#ifdef TIZEN_PCM_DUMP
+ /* rewind pcm */
+ if (o->pcm_dump_fp)
+ fseeko(o->pcm_dump_fp, (off_t)nbytes * (-1), SEEK_CUR);
+#endif
if (nbytes > 0)
o->process_rewind(o, nbytes);
pa_sink_input *direct_on_input; /* may be NULL */
} thread_info;
+#ifdef TIZEN_PCM_DUMP
+ FILE *pcm_dump_fp;
+ char *dump_path;
+#endif
void *userdata;
};
#include <stdio.h>
#include <stdlib.h>
+#ifdef TIZEN_PCM_DUMP
+#include <time.h>
+#endif
#include <pulse/format.h>
#include <pulse/utf8.h>
static void pa_source_volume_change_push(pa_source *s);
static void pa_source_volume_change_flush(pa_source *s);
+#ifdef TIZEN_PCM_DUMP
+static void pa_source_write_pcm_dump(pa_source *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_PA_SOURCE && !s->pcm_dump_fp && s->state == PA_SOURCE_RUNNING &&
+ !(~s->core->pcm_dump_option & PA_PCM_DUMP_OPTION_MONITOR && s->monitor_of)) {
+ 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%s", pa_strnull(card_name_str), pa_strnull(device_idx_str), s->monitor_of ? ".monitor" : "");
+ } else {
+ dump_path_surfix = pa_sprintf_malloc("%s%s", s_device_api_str, s->monitor_of ? ".monitor" : "");
+ }
+ } else {
+ dump_path_surfix = pa_sprintf_malloc("%s", s->name);
+ }
+
+ s->dump_path = pa_sprintf_malloc("%s_%s_pa-src%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_PA_SOURCE && 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_source_new_data* pa_source_new_data_init(pa_source_new_data *data) {
pa_assert(data);
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,
}
s->state = state;
+#ifdef TIZEN_PCM_DUMP
+ /* close file for dump pcm */
+ if (s->pcm_dump_fp && (s->core->pcm_dump_option & PA_PCM_DUMP_OPTION_SEPARATED) &&
+ state == PA_SOURCE_IDLE && original_state == PA_SOURCE_RUNNING) {
+ fclose(s->pcm_dump_fp);
+ pa_log_info("%s closed", s->dump_path);
+ pa_xfree(s->dump_path);
+ s->pcm_dump_fp = NULL;
+ }
+#endif
if (state != PA_SOURCE_UNLINKED) { /* if we enter UNLINKED state pa_source_unlink() will fire the appropriate events */
pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], s);
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);
}
return;
pa_log_debug("Processing rewind...");
+#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(o, s->thread_info.outputs, state) {
pa_source_output_assert_ref(o);
if (s->thread_info.state == PA_SOURCE_SUSPENDED)
return;
+#ifdef TIZEN_PCM_DUMP
+ pa_source_write_pcm_dump(s, (pa_memchunk *)chunk);
+#endif
if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
pa_memchunk vchunk = *chunk;
if (s->thread_info.state == PA_SOURCE_SUSPENDED)
return;
+#ifdef TIZEN_PCM_DUMP
+ pa_source_write_pcm_dump(s, (pa_memchunk *)chunk);
+#endif
if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
pa_memchunk vchunk = *chunk;
int32_t volume_change_extra_delay;
} thread_info;
+#ifdef TIZEN_PCM_DUMP
+ FILE *pcm_dump_fp;
+ char *dump_path;
+#endif
void *userdata;
};