From ad0b21de15eef21bd11949e04d69799ab544aac5 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Wed, 13 Mar 2019 19:05:12 +0900 Subject: [PATCH] tinycompresssink: add h/w volume set Change-Id: I42867b05db74da1d1432d5f2a921934acc34057e --- configure.ac | 11 +- packaging/gst-plugins-tizen.spec | 6 +- tinycompresssink/src/Makefile.am | 4 + tinycompresssink/src/gsttinycompresssink.c | 228 +++++++++++++++++++++++------ tinycompresssink/src/gsttinycompresssink.h | 4 +- tinycompresssink/test/Makefile.am | 12 +- 6 files changed, 199 insertions(+), 66 deletions(-) diff --git a/configure.ac b/configure.ac index 8365cec..a61966f 100644 --- a/configure.ac +++ b/configure.ac @@ -465,6 +465,12 @@ if test "x$GST_TIZEN_USE_TINYCOMPRESS" = "xyes"; then PKG_CHECK_MODULES(TINYCOMPRESS, tinycompress) AC_SUBST(TINYCOMPRESS_CFLAGS) AC_SUBST(TINYCOMPRESS_LIBS) +PKG_CHECK_MODULES(SOUND_MANAGER, capi-media-sound-manager) +AC_SUBST(SOUND_MANAGER_CFLAGS) +AC_SUBST(SOUND_MANAGER_LIBS) +PKG_CHECK_MODULES(ASOUNDLIB, alsa) +AC_SUBST(ASOUNDLIB_CFLAGS) +AC_SUBST(ASOUNDLIB_LIBS) fi dnl use tinycompress test-------------------------------------------------------------------------- @@ -478,11 +484,6 @@ AC_ARG_ENABLE(tinycompress_test, AC_HELP_STRING([--enable-tinycompress_test], [u ], [USE_TINYCOMPRESS_TEST=no]) AM_CONDITIONAL(USE_TINYCOMPRESS_TEST, test "x$USE_TINYCOMPRESS_TEST" = "xyes") -if test "x$USE_TINYCOMPRESS_TEST" = "xyes"; then -PKG_CHECK_MODULES(SOUNDMANAGER, capi-media-sound-manager) -AC_SUBST(SOUNDMANAGER_CFLAGS) -AC_SUBST(SOUNDMANAGER_LIBS) -fi AC_ARG_ENABLE(tests, AC_HELP_STRING([--enable-tests], [unittest build]), [ diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index a32892a..cf9d993 100644 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -48,12 +48,10 @@ BuildRequires: pkgconfig(tizen-extension-client) %if 0%{?gtests:1} BuildRequires: pkgconfig(gmock) %endif -# for tinycompress test -%if 0%{?tinycompresstest:1} -BuildRequires: pkgconfig(capi-media-sound-manager) -%endif # for tizencamerasrc #BuildRequires: pkgconfig(camera-hal-interface) +BuildRequires: pkgconfig(capi-media-sound-manager) +BuildRequires: pkgconfig(alsa) %description GStreamer tizen plugins (common) diff --git a/tinycompresssink/src/Makefile.am b/tinycompresssink/src/Makefile.am index 6cff590..d34fec6 100644 --- a/tinycompresssink/src/Makefile.am +++ b/tinycompresssink/src/Makefile.am @@ -6,10 +6,14 @@ libgsttinycompress_la_CFLAGS = \ $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_BASE_CFLAGS) \ $(GST_CFLAGS) \ + $(SOUND_MANAGER_CFLAGS) \ + $(ASOUNDLIB_CFLAGS) \ $(TINYCOMPRESS_CFLAGS) libgsttinycompress_la_LIBADD = \ $(GST_BASE_LIBS) \ + $(SOUND_MANAGER_LIBS) \ + $(ASOUNDLIB_LIBS) \ $(TINYCOMPRESS_LIBS) libgsttinycompress_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) diff --git a/tinycompresssink/src/gsttinycompresssink.c b/tinycompresssink/src/gsttinycompresssink.c index 8f91102..98242b5 100644 --- a/tinycompresssink/src/gsttinycompresssink.c +++ b/tinycompresssink/src/gsttinycompresssink.c @@ -39,6 +39,14 @@ #include #include +#include +#include + +/* FIXME: This might be configurable (eg. property) */ +#define ALSA_DEFAULT_CARD "Exynos9110Sound" + +#define COMPRESS_VOL_CTRL "ComprTx0 Volume" + static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, @@ -64,7 +72,7 @@ static void gst_tinycompress_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_tinycompress_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static void gst_tinycompress_sink_finalize (GObject * obj); +static void gst_tinycompress_sink_finalize (GObject * object); static GstStateChangeReturn gst_tinycompress_sink_change_state (GstElement * element, GstStateChange transition); @@ -80,7 +88,7 @@ static gboolean gst_tinycompress_sink_event (GstBaseSink * bsink, GstEvent * event); static void -_dump_htpointer (struct compress *compress) +_dump_compress_status (GstTinycompressSink * sink, struct compress *compress) { unsigned int avail; unsigned int sampling_rate = 0; @@ -92,13 +100,91 @@ _dump_htpointer (struct compress *compress) compress_get_tstamp (compress, &samples, &sampling_rate); if (compress_get_hpointer (compress, &avail, &tstamp) != 0) { - GST_ERROR ("Error querying timestamp : %s", compress_get_error (compress)); + GST_ERROR_OBJECT (sink, "Error querying timestamp : %s", + compress_get_error (compress)); } else { - GST_ERROR - ("samples:%10d, rate:%7d, Avail:%7d, DSP played:%4jd.%012jd\n", - samples, sampling_rate, avail, (intmax_t) tstamp.tv_sec, - (intmax_t) tstamp.tv_nsec * 1000); + GST_DEBUG_OBJECT (sink, + "samples:%10d, avail:%7d, DSP played:%4jd.%03jd\n", samples, avail, + (intmax_t) (tstamp.tv_sec / sink->t_codec.ch_in), + (intmax_t) (tstamp.tv_nsec / sink->t_codec.ch_in) / 1000000); + } +} + +static gboolean +_mixer_control_set_value (GstTinycompressSink * sink, const char *ctl_name, + int val) +{ + snd_ctl_t *handle; + snd_ctl_elem_value_t *control; + snd_ctl_elem_id_t *id; + snd_ctl_elem_info_t *info; + snd_ctl_elem_type_t type; + int ret = 0; + int count = 0; + int i = 0; + + ret = snd_ctl_open (&handle, ALSA_DEFAULT_CARD, 0); + if (ret < 0) { + GST_ERROR_OBJECT (sink, "snd_ctl_open error, card: %s: %s", + ALSA_DEFAULT_CARD, snd_strerror (ret)); + return FALSE; + } + + snd_ctl_elem_id_alloca (&id); + snd_ctl_elem_info_alloca (&info); + snd_ctl_elem_value_alloca (&control); + + snd_ctl_elem_id_set_interface (id, SND_CTL_ELEM_IFACE_MIXER); + snd_ctl_elem_id_set_name (id, ctl_name); + + snd_ctl_elem_info_set_id (info, id); + if (snd_ctl_elem_info (handle, info) < 0) { + GST_ERROR_OBJECT (sink, "Cannot find control element: %s", ctl_name); + goto close; + } + snd_ctl_elem_info_get_id (info, id); + + type = snd_ctl_elem_info_get_type (info); + count = snd_ctl_elem_info_get_count (info); + + snd_ctl_elem_value_set_id (control, id); + + snd_ctl_elem_read (handle, control); + + switch (type) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + for (i = 0; i < count; i++) + snd_ctl_elem_value_set_boolean (control, i, val); + break; + + case SND_CTL_ELEM_TYPE_INTEGER: + for (i = 0; i < count; i++) + snd_ctl_elem_value_set_integer (control, i, val); + break; + + case SND_CTL_ELEM_TYPE_ENUMERATED: + for (i = 0; i < count; i++) + snd_ctl_elem_value_set_enumerated (control, i, val); + break; + + default: + GST_WARNING_OBJECT (sink, "unsupported control element type"); + goto close; } + + snd_ctl_elem_write (handle, control); + + snd_ctl_close (handle); + + GST_INFO_OBJECT (sink, "set mixer(%s) = %d success", ctl_name, val); + + return TRUE; + +close: + GST_ERROR_OBJECT (sink, "Error"); + snd_ctl_close (handle); + + return FALSE; } static gboolean @@ -125,7 +211,8 @@ gst_tinycompress_set_codec_param (GstTinycompressSink * sink, GstCaps * caps) sink->t_codec.level = 0; sink->t_codec.ch_mode = 0; sink->t_codec.format = 0; - GST_DEBUG_OBJECT (sink, "t_codec: id(%d), channel(%d), sample_rate(%d)", + + GST_INFO_OBJECT (sink, "t_codec: id(%d), channel(%d), sample_rate(%d)", SND_AUDIOCODEC_MP3, channels, rate); return TRUE; @@ -154,9 +241,7 @@ gst_tinycompress_sink_class_init (GstTinycompressSinkClass * klass) gst_element_class_set_static_metadata (gstelement_class, "Tinycompress Sink", - "Sink", - "Render MP3 data in compress device using tinycompress", - "Tizen"); + "Sink", "Render MP3 data in compress device using tinycompress", "Tizen"); gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate); @@ -174,32 +259,70 @@ gst_tinycompress_sink_class_init (GstTinycompressSinkClass * klass) } static void +_volume_changed_cb (sound_type_e type, unsigned int volume, void *user_data) +{ + GstTinycompressSink *sink = (GstTinycompressSink *) user_data; + + GST_INFO_OBJECT (sink, " type %d, volume %u", type, volume); + + /* FIXME: For now current volume range for media is 0~15, + corresponding mixer control range is 0~8192. + As level matching will be part of tunning issue in the future, + we just set value to level multiplied by 100 which seems to be fine */ + if (type == SOUND_TYPE_MEDIA) + _mixer_control_set_value (sink, COMPRESS_VOL_CTRL, volume * 100); +} + +static void gst_tinycompress_sink_init (GstTinycompressSink * sink) { + int media_volume = -1; + sink->dump = DEFAULT_DUMP; sink->card = DEFAULT_CARD; sink->device = DEFAULT_DEVICE; sink->compress_paused = FALSE; + sink->volume_cb_id = -1; + + if (sound_manager_get_volume (SOUND_TYPE_MEDIA, + &media_volume) != SOUND_MANAGER_ERROR_NONE) + GST_ERROR_OBJECT (sink, "failed to get media volume"); + + if (sound_manager_add_volume_changed_cb (_volume_changed_cb, sink, + &sink->volume_cb_id) != SOUND_MANAGER_ERROR_NONE) + GST_ERROR_OBJECT (sink, "failed to add volume changed cb"); + + GST_INFO_OBJECT (sink, "Initial media volume was %d, added volume cb %d", + media_volume, sink->volume_cb_id); + + _mixer_control_set_value (sink, "ComprTx0 Volume", media_volume * 100); } static void -gst_tinycompress_sink_finalize (GObject * obj) +gst_tinycompress_sink_finalize (GObject * object) { - G_OBJECT_CLASS (parent_class)->finalize (obj); + GstTinycompressSink *sink = GST_TINYCOMPRESS_SINK (object); + + if (sink->volume_cb_id != -1) + if (sound_manager_remove_volume_changed_cb (sink->volume_cb_id) != + SOUND_MANAGER_ERROR_NONE) + GST_ERROR_OBJECT (sink, "failed to remove volume changed cb (id:%d)", + sink->volume_cb_id); + + G_OBJECT_CLASS (parent_class)->finalize (object); } static void gst_tinycompress_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstTinycompressSink *sink; - - sink = GST_TINYCOMPRESS_SINK (object); + GstTinycompressSink *sink = GST_TINYCOMPRESS_SINK (object); switch (prop_id) { case PROP_DUMP: sink->dump = g_value_get_boolean (value); break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -218,6 +341,7 @@ gst_tinycompress_sink_get_property (GObject * object, guint prop_id, case PROP_DUMP: g_value_set_boolean (value, sink->dump); break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -251,17 +375,16 @@ gst_tinycompress_sink_render (GstBaseSink * bsink, GstBuffer * buf) GST_DEBUG_OBJECT (sink, " >> Wrote %u bytes, accum %u", info.size, sink->written); - if (sink->dump) { - _dump_htpointer (sink->compress); - } + /* FIXEME: needs separate property for control */ + _dump_compress_status (sink, sink->compress); if (!is_compress_running (sink->compress) && sink->written >= sink->start_threashold) { - GST_DEBUG_OBJECT (sink, "Start Now!!!"); + GST_INFO_OBJECT (sink, "Start Now!!!"); if (compress_start (sink->compress) != 0) { GST_ERROR_OBJECT (sink, "Could not start!!!"); } else { - GST_ERROR_OBJECT (sink, "Started done!!!"); + GST_INFO_OBJECT (sink, "Started done!!!"); sink->compress_paused = FALSE; } } @@ -282,7 +405,7 @@ gst_tinycompress_sink_get_caps (GstBaseSink * bsink, GstCaps * filter) caps = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink)); GST_OBJECT_UNLOCK (sink); - GST_DEBUG_OBJECT (sink, "Got caps %" GST_PTR_FORMAT, caps); + GST_INFO_OBJECT (sink, "Got caps %" GST_PTR_FORMAT, caps); if (caps && filter) { GstCaps *intersection = @@ -303,7 +426,7 @@ gst_tinycompress_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) GstTinycompressSink *sink; sink = GST_TINYCOMPRESS_SINK (bsink); - GST_DEBUG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps); + GST_INFO_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps); gst_tinycompress_set_codec_param (sink, caps); @@ -330,7 +453,7 @@ gst_tinycompress_resume (GstTinycompressSink * sink) int ret; g_return_val_if_fail (sink != NULL, FALSE); - GST_DEBUG_OBJECT (sink, "gst_tinycompress_resume"); + GST_INFO_OBJECT (sink, "gst_tinycompress_resume"); if (!sink->compress) goto not_opened; @@ -342,7 +465,7 @@ gst_tinycompress_resume (GstTinycompressSink * sink) goto not_started; ret = compress_resume (sink->compress); - GST_LOG_OBJECT (sink, "resuming the device, ret=%d", ret); + GST_INFO_OBJECT (sink, "resuming the device, ret=%d", ret); if (ret != 0) { GST_ERROR_OBJECT (sink, "Error %d resuming device\n", ret); return FALSE; @@ -361,7 +484,7 @@ not_paused: return FALSE; not_started: - GST_LOG_OBJECT (sink, "Note: Tinycompress device is not started!"); + GST_ERROR_OBJECT (sink, "Note: Tinycompress device is not started!"); return FALSE; } @@ -372,7 +495,7 @@ gst_tinycompress_pause (GstTinycompressSink * sink) g_return_val_if_fail (sink != NULL, FALSE); - GST_DEBUG_OBJECT (sink, "gst_tinycompress_pause"); + GST_INFO_OBJECT (sink, "gst_tinycompress_pause"); if (!sink->compress) goto not_opened; @@ -381,7 +504,7 @@ gst_tinycompress_pause (GstTinycompressSink * sink) goto not_started; ret = compress_pause (sink->compress); - GST_LOG_OBJECT (sink, "pausing the device, ret=%d", ret); + GST_INFO_OBJECT (sink, "pausing the device, ret=%d", ret); if (ret != 0) { GST_ERROR_OBJECT (sink, "Error %d pausing device, %s\n", ret, compress_get_error (sink->compress)); @@ -396,7 +519,7 @@ not_opened: return TRUE; not_started: - GST_LOG_OBJECT (sink, "Note: Tinycompress device is not started!"); + GST_ERROR_OBJECT (sink, "Note: Tinycompress device is not started!"); return TRUE; } @@ -413,25 +536,26 @@ gst_tinycompress_unprepare (GstTinycompressSink * sink) compress_close (sink->compress); sink->compress = NULL; - GST_DEBUG_OBJECT (sink, "Compress device %d:%d closed", sink->card, + GST_INFO_OBJECT (sink, "Compress device %d:%d closed", sink->card, sink->device); + sink->compress_paused = FALSE; + sink->written = 0; + GST_OBJECT_UNLOCK (sink); return TRUE; } - static gboolean gst_tinycompress_open (GstTinycompressSink * sink) { g_return_val_if_fail (sink != NULL, FALSE); - GST_DEBUG_OBJECT (sink, "gst_tinycompress_open"); + GST_INFO_OBJECT (sink, "gst_tinycompress_open"); sink->t_config.codec = &sink->t_codec; - GST_OBJECT_LOCK (sink); sink->compress = @@ -442,13 +566,14 @@ gst_tinycompress_open (GstTinycompressSink * sink) goto fail; } - compress_set_max_poll_wait (sink->compress, 3000); // need to property, wait for writting + /* FIXME: need to property, wait for writting */ + compress_set_max_poll_wait (sink->compress, 3000); sink->start_threashold = sink->t_config.fragment_size * sink->t_config.fragments; - GST_DEBUG_OBJECT (sink, "get fragment_size: %d, total number of fragment :%d", + GST_INFO_OBJECT (sink, "Got fragment_size: %d, fragments :%d", sink->t_config.fragment_size, sink->t_config.fragments); - GST_DEBUG_OBJECT (sink, "buffer size for buffering : %d", + GST_INFO_OBJECT (sink, "buffer size for buffering : %d", sink->start_threashold); if (!is_compress_ready (sink->compress)) { @@ -456,7 +581,7 @@ gst_tinycompress_open (GstTinycompressSink * sink) goto fail; } - GST_DEBUG_OBJECT (sink, "Compress device %d:%d opened", sink->card, + GST_INFO_OBJECT (sink, "Compress device %d:%d opened", sink->card, sink->device); sink->written = 0; @@ -474,7 +599,6 @@ fail: } return FALSE; - } static GstStateChangeReturn @@ -486,18 +610,21 @@ gst_tinycompress_sink_change_state (GstElement * element, switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: - GST_DEBUG_OBJECT (sink, "NULL_TO_READY"); + GST_INFO_OBJECT (sink, "NULL_TO_READY"); break; + case GST_STATE_CHANGE_READY_TO_PAUSED: - GST_DEBUG_OBJECT (sink, "READY_TO_PAUSED"); + GST_INFO_OBJECT (sink, "READY_TO_PAUSED"); break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - GST_DEBUG_OBJECT (sink, "PAUSED_TO_PLAYING"); + GST_INFO_OBJECT (sink, "PAUSED_TO_PLAYING"); if (!sink->compress) gst_tinycompress_open (sink); if (sink->compress_paused) gst_tinycompress_resume (sink); break; + default: break; } @@ -506,16 +633,19 @@ gst_tinycompress_sink_change_state (GstElement * element, switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - GST_DEBUG_OBJECT (sink, "PLAYING_TO_PAUSED"); + GST_INFO_OBJECT (sink, "PLAYING_TO_PAUSED"); gst_tinycompress_pause (sink); break; + case GST_STATE_CHANGE_PAUSED_TO_READY: - GST_DEBUG_OBJECT (sink, "PAUSED_TO_READY"); + GST_INFO_OBJECT (sink, "PAUSED_TO_READY"); gst_tinycompress_unprepare (sink); break; + case GST_STATE_CHANGE_READY_TO_NULL: - GST_DEBUG_OBJECT (sink, "READY_TO_NULL"); + GST_INFO_OBJECT (sink, "READY_TO_NULL"); break; + default: break; } @@ -528,13 +658,15 @@ gst_tinycompress_sink_event (GstBaseSink * bsink, GstEvent * event) GstTinycompressSink *sink; sink = GST_TINYCOMPRESS_SINK (bsink); - GST_DEBUG_OBJECT (sink, "got event (%d)", GST_EVENT_TYPE (event)); + GST_INFO_OBJECT (sink, "got event (%s)", + gst_event_type_get_name (GST_EVENT_TYPE (event))); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: - GST_DEBUG_OBJECT (sink, "get GST_EVENT_EOS event..state is %d", + GST_INFO_OBJECT (sink, "get GST_EVENT_EOS event..state is %d", GST_STATE (sink)); break; + default: break; } @@ -553,5 +685,5 @@ plugin_init (GstPlugin * plugin) } GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, tinycompress, - "tinycompress plugin library", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, - GST_PACKAGE_ORIGIN) + "tinycompress plugin library", plugin_init, VERSION, "LGPL", + GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/tinycompresssink/src/gsttinycompresssink.h b/tinycompresssink/src/gsttinycompresssink.h index 15ac7f5..c68f512 100644 --- a/tinycompresssink/src/gsttinycompresssink.h +++ b/tinycompresssink/src/gsttinycompresssink.h @@ -55,13 +55,13 @@ struct _GstTinycompressSink { gint card; gint device; gint written; - gint channels; - gint sample_rate; gint start_threashold; gboolean compress_paused; struct compr_config t_config; struct snd_codec t_codec; struct compress *compress; + + gint volume_cb_id; }; struct _GstTinycompressSinkClass { diff --git a/tinycompresssink/test/Makefile.am b/tinycompresssink/test/Makefile.am index d2b7e36..0a2b9c6 100644 --- a/tinycompresssink/test/Makefile.am +++ b/tinycompresssink/test/Makefile.am @@ -1,7 +1,5 @@ -bin_PROGRAMS = tinycompress_test - -tinycompress_test_SOURCES = tinycompress_test.c - -tinycompress_test_CFLAGS = $(GST_CFLAGS) $(SOUNDMANAGER_CFLAGS) - -tinycompress_test_LDADD = $(GST_LIBS) $(SOUNDMANAGER_LIBS) +bin_PROGRAMS = tinycompress_test + +tinycompress_test_SOURCES = tinycompress_test.c +tinycompress_test_CFLAGS = $(GST_CFLAGS) $(SOUND_MANAGER_CFLAGS) +tinycompress_test_LDADD = $(GST_LIBS) $(SOUND_MANAGER_LIBS) -- 2.7.4