#include <stdint.h>
#include <unistd.h>
+#include <sound_manager.h>
+#include <asoundlib.h>
+
+/* 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,
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);
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;
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
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;
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);
}
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;
case PROP_DUMP:
g_value_set_boolean (value, sink->dump);
break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
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;
}
}
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 =
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);
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;
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;
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;
}
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;
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));
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;
}
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 =
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)) {
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;
}
return FALSE;
-
}
static GstStateChangeReturn
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;
}
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;
}
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;
}
}
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)