#define DEFAULT_VOLUME 1.0
#define DEFAULT_MUTE FALSE
#define MAX_VOLUME 10.0
+#ifdef __TIZEN__
+#define DEFAULT_AUDIO_LATENCY "mid"
+#define DEFAULT_AUTO_RENDER_DELAY FALSE
+#endif /* __TIZEN__ */
enum
{
PROP_STREAM_PROPERTIES,
#ifdef __TIZEN__
PROP_AUDIO_LATENCY,
+ PROP_AUTO_RENDER_DELAY,
#endif /* __TIZEN__ */
PROP_LAST
};
-#ifdef __TIZEN__
-#ifdef PCM_DUMP_ENABLE
+#if defined(__TIZEN__) && defined(PCM_DUMP_ENABLE)
#define GST_PULSESINK_DUMP_VCONF_KEY "memory/private/sound/pcm_dump"
#define GST_PULSESINK_DUMP_INPUT_PATH_PREFIX "/tmp/dump_pulsesink_in_"
#define GST_PULSESINK_DUMP_OUTPUT_PATH_PREFIX "/tmp/dump_pulsesink_out_"
#define GST_PULSESINK_DUMP_INPUT_FLAG 0x00000400
#define GST_PULSESINK_DUMP_OUTPUT_FLAG 0x00000800
-#endif
-/* stream latency */
-typedef enum {
- AUDIO_IN_LATENCY_LOW, /* not used in pulsesink */
- AUDIO_IN_LATENCY_MID, /* not used in pulsesink */
- AUDIO_IN_LATENCY_HIGH, /* not used in pulsesink */
- AUDIO_IN_LATENCY_VOIP, /* not used in pulsesink */
- AUDIO_OUT_LATENCY_LOW,
- AUDIO_OUT_LATENCY_MID,
- AUDIO_OUT_LATENCY_HIGH,
- AUDIO_OUT_LATENCY_VOIP,
- AUDIO_LATENCY_MAX
-} StreamLatency;
-/* pulsesink latency */
-typedef enum {
- PULSESINK_LATENCY_LOW = 0,
- PULSESINK_LATENCY_MID,
- PULSESINK_LATENCY_HIGH,
- PULSESINK_LATENCY_VOIP,
-} GstPulseSinkLatency;
-#endif /* __TIZEN__ */
+#endif /* __TIZEN__ && PCM_DUMP_ENABLE */
#define GST_TYPE_PULSERING_BUFFER \
(gst_pulseringbuffer_get_type())
typedef struct _GstPulseContext GstPulseContext;
+/* A note on threading.
+ *
+ * We use a pa_threaded_mainloop to interact with the PulseAudio server. This
+ * starts up a separate thread that runs a mainloop to carry back events,
+ * messages and timing updates from the PulseAudio server.
+ *
+ * In most cases, the PulseAudio API we use communicates with the server and
+ * processes replies asynchronously. Operations on PA objects that result in
+ * such communication are protected with a pa_threaded_mainloop_lock() and
+ * pa_threaded_mainloop_unlock(). These guarantee mutual exclusion with the
+ * mainloop thread -- when an iteration of the mainloop thread begins, it first
+ * tries to acquire this lock, and cannot do so if our code also holds that
+ * lock.
+ *
+ * When we need to complete an operation synchronously, we use
+ * pa_threaded_mainloop_wait() and pa_threaded_mainloop_signal(). These work
+ * much as pthread conditionals do. pa_threaded_mainloop_wait() is called with
+ * the mainloop lock held. It releases the lock (thereby allowing the mainloop
+ * to execute), and waits till one of our callbacks to be executed by the
+ * mainloop thread calls pa_threaded_mainloop_signal(). At the end of the
+ * mainloop iteration, the pa_threaded_mainloop_wait() will reacquire the
+ * mainloop lock and return control to the caller.
+ */
+
/* Store the PA contexts in a hash table to allow easy sharing among
* multiple instances of the sink. Keys are $context_name@$server_name
* (strings) and values should be GstPulseContext pointers.
static guint gst_pulseringbuffer_commit (GstAudioRingBuffer * buf,
guint64 * sample, guchar * data, gint in_samples, gint out_samples,
gint * accum);
+#ifdef __TIZEN__
+static gboolean gst_pulsering_set_corked (GstPulseRingBuffer * pbuf, gboolean corked,
+ gboolean wait);
+#endif
G_DEFINE_TYPE (GstPulseRingBuffer, gst_pulseringbuffer,
GST_TYPE_AUDIO_RING_BUFFER);
pa_context_set_subscribe_callback (pctx->context,
gst_pulsering_context_subscribe_cb, pctx);
+ /* try to connect to the server and wait for completion, we don't want to
+ * autospawn a deamon */
GST_LOG_OBJECT (psink, "connect to server %s",
GST_STR_NULL (psink->server));
- if (pa_context_connect (pctx->context, psink->server, 0, NULL) < 0)
+ if (pa_context_connect (pctx->context, psink->server,
+ PA_CONTEXT_NOAUTOSPAWN, NULL) < 0)
goto connect_failed;
} else {
GST_INFO_OBJECT (psink,
GST_TIMEVAL_TO_TIME (info->timestamp), info->write_index_corrupt,
info->write_index, info->read_index_corrupt, info->read_index,
info->sink_usec, sink_usec);
+#ifdef __TIZEN__
+ if (!psink->auto_render_delay)
+ return;
+
+ if (sink_usec < info->sink_usec)
+ gst_base_sink_set_render_delay (GST_BASE_SINK(psink),
+ (info->sink_usec - sink_usec) * G_GINT64_CONSTANT (1000));
+ else
+ gst_base_sink_set_render_delay (GST_BASE_SINK(psink), 0);
+
+ GST_DEBUG_OBJECT (psink,
+ "Current render delay is %llu", gst_base_sink_get_render_delay (GST_BASE_SINK(psink)));
+#endif
}
static void
GST_ELEMENT_ERROR (psink, STREAM, FORMAT, ("Sink format changed"),
("Sink format changed"));
}
+#ifdef __TIZEN__
+ } else if (!strcmp (name, PA_STREAM_EVENT_POP_TIMEOUT)) {
+ GST_WARNING_OBJECT (psink, "got event [%s], cork stream now!!!!", name);
+ gst_pulsering_set_corked (pbuf, TRUE, FALSE);
+#endif
} else {
GST_DEBUG_OBJECT (psink, "got unknown event %s", name);
}
}
}
-static void
-gst_pulsesink_sink_exist_cb (pa_context * c, const pa_sink_info * i, int eol,
- void *userdata)
-{
- gboolean *is_sink_exist = (gboolean *) userdata;
-
- if (!i)
- *is_sink_exist = FALSE;
- else
- *is_sink_exist = TRUE;
- pa_threaded_mainloop_signal (mainloop, 0);
-}
-
-static gboolean
-gst_pulsesink_device_exist(pa_context *context, gchar *dev)
-{
- pa_operation* o = NULL;
- gboolean device_exist = FALSE;
-
- if (!(o = pa_context_get_sink_info_by_name (context, dev,
- gst_pulsesink_sink_exist_cb, &device_exist)))
- return device_exist;
-
- while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
- pa_threaded_mainloop_wait (mainloop);
- if (!CONTEXT_OK (context))
- break;
- }
-
- pa_operation_unref (o);
- return device_exist;
-}
-
/* This method should create a new stream of the given @spec. No playback should
* start yet so we start in the corked state. */
const pa_buffer_attr *actual;
pa_channel_map channel_map;
pa_operation *o = NULL;
+#ifndef __TIZEN__
pa_cvolume v;
+#endif
pa_cvolume *pv = NULL;
pa_stream_flags_t flags;
const gchar *name;
GDateTime *time = g_date_time_new_now_local();
suffix = g_date_time_format(time, "%m%d_%H%M%S");
- dump_path = g_strdup_printf("%s_%dch_%dhz_%s.pcm", GST_PULSESINK_DUMP_INPUT_PATH_PREFIX, pbuf->channels, spec->rate, suffix);
-
+ dump_path = g_strdup_printf("%s%dch_%dhz_%s.pcm", GST_PULSESINK_DUMP_INPUT_PATH_PREFIX, pbuf->channels, spec->info.rate, suffix);
+ GST_WARNING_OBJECT(psink, "pulse-sink dumping enabled: dump path [%s]", dump_path);
psink->dump_fd_input = fopen(dump_path, "w+");
g_free(suffix);
GST_INFO_OBJECT (psink, "prebuf: %d", wanted.prebuf);
GST_INFO_OBJECT (psink, "minreq: %d", wanted.minreq);
+#ifndef __TIZEN__
/* configure volume when we changed it, else we leave the default */
if (psink->volume_set) {
GST_LOG_OBJECT (psink, "have volume of %f", psink->volume);
} else {
pv = NULL;
}
+#endif
/* construct the flags */
flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE |
PA_STREAM_ADJUST_LATENCY | PA_STREAM_START_CORKED;
+#ifndef __TIZEN__
if (psink->mute_set) {
if (psink->mute)
flags |= PA_STREAM_START_MUTED;
else
flags |= PA_STREAM_START_UNMUTED;
}
+#endif
/* we always start corked (see flags above) */
pbuf->corked = TRUE;
GST_INFO_OBJECT (psink, "negotiated to: %s", print_buf);
#endif
+#ifdef __TIZEN__
+ {
+ uint32_t idx;
+ if ((idx = pa_stream_get_index (pbuf->stream)) == PA_INVALID_INDEX)
+ goto no_index;
+ if (psink->volume_set)
+ gst_pulse_set_volume_ratio (idx, "out", psink->volume);
+ if (psink->mute_set)
+ if (psink->mute)
+ gst_pulse_set_volume_ratio (idx, "out", 0);
+ }
+#endif
/* After we passed the volume off of to PA we never want to set it
again, since it is PA's job to save/restore volumes. */
psink->volume_set = psink->mute_set = FALSE;
pa_strerror (pa_context_errno (pbuf->context))), (NULL));
goto unlock_and_fail;
}
+#ifdef __TIZEN__
+no_index:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("Failed to get stream index: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto unlock_and_fail;
+ }
+#endif
}
/* free the stream that we acquired before */
pa_threaded_mainloop_unlock (mainloop);
}
-/* called from pulse with the mainloop lock */
+#if 0
+/* called from pulse thread with the mainloop lock */
static void
mainloop_enter_defer_cb (pa_mainloop_api * api, void *userdata)
{
pulsesink->defer_pending--;
pa_threaded_mainloop_signal (mainloop, 0);
}
+#endif
/* start/resume playback ASAP, we don't uncork here but in the commit method */
static gboolean
pa_threaded_mainloop_lock (mainloop);
- GST_DEBUG_OBJECT (psink, "scheduling stream status");
- psink->defer_pending++;
- pa_mainloop_api_once (pa_threaded_mainloop_get_api (mainloop),
- mainloop_enter_defer_cb, psink);
-
GST_DEBUG_OBJECT (psink, "starting");
pbuf->paused = FALSE;
g_atomic_int_get (&GST_AUDIO_BASE_SINK (psink)->eos_rendering))
gst_pulsering_set_corked (pbuf, FALSE, FALSE);
+#if 0
+ GST_DEBUG_OBJECT (psink, "scheduling stream status");
+ psink->defer_pending++;
+ pa_mainloop_api_once (pa_threaded_mainloop_get_api (mainloop),
+ mainloop_enter_defer_cb, psink);
+
+ /* Wait for the stream status message to be posted. This needs to be done
+ * synchronously because the callback will take the mainloop lock
+ * (implicitly) and then take the GST_OBJECT_LOCK. Everywhere else, we take
+ * the locks in the reverse order, so not doing this synchronously could
+ * cause a deadlock. */
+ GST_DEBUG_OBJECT (psink, "waiting for stream status (ENTER) to be posted");
+ pa_threaded_mainloop_wait (mainloop);
+#endif
+
pa_threaded_mainloop_unlock (mainloop);
return TRUE;
return res;
}
-/* called from pulse with the mainloop lock */
+#if 0
+/* called from pulse thread with the mainloop lock */
static void
mainloop_leave_defer_cb (pa_mainloop_api * api, void *userdata)
{
pulsesink->defer_pending--;
pa_threaded_mainloop_signal (mainloop, 0);
}
+#endif
/* stop playback, we flush everything. */
static gboolean
pa_operation_cancel (o);
pa_operation_unref (o);
}
-
+#if 0
GST_DEBUG_OBJECT (psink, "scheduling stream status");
psink->defer_pending++;
pa_mainloop_api_once (pa_threaded_mainloop_get_api (mainloop),
mainloop_leave_defer_cb, psink);
+ /* Wait for the stream status message to be posted. This needs to be done
+ * synchronously because the callback will take the mainloop lock
+ * (implicitly) and then take the GST_OBJECT_LOCK. Everywhere else, we take
+ * the locks in the reverse order, so not doing this synchronously could
+ * cause a deadlock. */
+ GST_DEBUG_OBJECT (psink, "waiting for stream status (LEAVE) to be posted");
+ pa_threaded_mainloop_wait (mainloop);
+#endif
+
pa_threaded_mainloop_unlock (mainloop);
return res;
if (pbuf->paused)
goto was_paused;
+#ifdef __TIZEN__
+ /* ensure running clock for whatever out there */
+ if (pbuf->corked) {
+ if (!gst_pulsering_set_corked (pbuf, FALSE, FALSE))
+ goto uncork_failed;
+ }
+#endif
/* offset is in bytes */
offset = *sample * bpf;
static GstStateChangeReturn gst_pulsesink_change_state (GstElement * element,
GstStateChange transition);
-static GstStaticPadTemplate pad_template = GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (PULSE_SINK_TEMPLATE_CAPS));
-
#define gst_pulsesink_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstPulseSink, gst_pulsesink, GST_TYPE_AUDIO_BASE_SINK,
gst_pulsesink_init_contexts ();
}
}
-#ifdef __TIZEN__
-GType
-gst_pulsesink_latency_get_type (void)
-{
- static GType pulseaudio_latency_type = 0;
- static const GEnumValue pulseaudio_latency[] = {
- {PULSESINK_LATENCY_LOW, "Low latency", "low"},
- {PULSESINK_LATENCY_MID, "Mid latency", "mid"},
- {PULSESINK_LATENCY_HIGH, "High latency", "high"},
- {PULSESINK_LATENCY_VOIP, "VOIP latency", "voip"},
- {0, NULL, NULL},
- };
-
- if (!pulseaudio_latency_type) {
- pulseaudio_latency_type =
- g_enum_register_static ("GstPulseSinkLatency", pulseaudio_latency);
- }
- return pulseaudio_latency_type;
-}
-
-#ifdef PCM_DUMP_ENABLE
-static gboolean
-gst_pulsesink_pad_dump_handler (GstPad *pad, GstBuffer *buffer, gpointer data)
+#if defined(__TIZEN__) && defined(PCM_DUMP_ENABLE)
+static GstPadProbeReturn
+gst_pulsesink_pad_dump_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
{
GstPulseSink *psink = GST_PULSESINK_CAST (data);
- int ret = -1;
-
- if (psink->dump_fd_input)
- ret = fwrite(GST_BUFFER_DATA(buffer), 1, GST_BUFFER_SIZE(buffer), psink->dump_fd_input);
-
- return !!ret;
+ size_t written = 0;
+ GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
+ GstMapInfo in_map;
+ if (psink->dump_fd_input) {
+ gst_buffer_map(buffer, &in_map, GST_MAP_READ);
+ written = fwrite(in_map.data, 1, in_map.size, psink->dump_fd_input);
+ if (written != in_map.size)
+ GST_WARNING("failed to write!!! ferror=%d", ferror(psink->dump_fd_input));
+ gst_buffer_unmap(buffer, &in_map);
+ }
+ return GST_PAD_PROBE_OK;
}
-#endif
-#endif /* __TIZEN__ */
+#endif /* __TIZEN__ && PCM_DUMP_ENABLE */
static void
gst_pulsesink_class_init (GstPulseSinkClass * klass)
GstBaseSinkClass *bc;
GstAudioBaseSinkClass *gstaudiosink_class = GST_AUDIO_BASE_SINK_CLASS (klass);
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+ GstCaps *caps;
gchar *clientname;
gobject_class->finalize = gst_pulsesink_finalize;
#ifdef __TIZEN__
g_object_class_install_property (gobject_class,
PROP_AUDIO_LATENCY,
- g_param_spec_enum("latency", "Audio Backend Latency",
- "Audio backend latency", gst_pulsesink_latency_get_type(), PULSESINK_LATENCY_MID,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS ));
+ g_param_spec_string ("latency", "Audio Backend Latency",
+ "Audio Backend Latency (\"low\": Low Latency, \"mid\": Mid Latency, \"high\": High Latency)",
+ DEFAULT_AUDIO_LATENCY,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class,
+ PROP_AUTO_RENDER_DELAY,
+ g_param_spec_boolean ("auto-render-delay", "Auto Render Delay",
+ "Apply render delay automatically", DEFAULT_AUTO_RENDER_DELAY,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
#endif /* __TIZEN__ */
gst_element_class_set_static_metadata (gstelement_class,
"PulseAudio Audio Sink",
"Sink/Audio", "Plays audio to a PulseAudio server", "Lennart Poettering");
+
+ caps =
+ gst_pulse_fix_pcm_caps (gst_caps_from_string (PULSE_SINK_TEMPLATE_CAPS));
gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&pad_template));
+ gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps));
+ gst_caps_unref (caps);
}
static void
pa_stream_set_state_callback (stream, gst_pulsering_stream_state_cb, pbuf);
- if (psink->device && !gst_pulsesink_device_exist (pbuf->context, psink->device))
- {
- GST_WARNING_OBJECT (psink, "Sink:%s is not exist, set sink name to NULL", psink->device);
- g_free (psink->device);
- psink->device = NULL;
- }
if (pa_stream_connect_playback (stream, psink->device, NULL, flags, NULL,
NULL) < 0)
goto error;
goto unlock;
}
+ ret = gst_caps_new_empty ();
+
if (pbuf->stream) {
/* We're in PAUSED or higher */
stream = pbuf->stream;
pbuf->probe_stream = gst_pulsesink_create_probe_stream (psink, pbuf,
format);
+
+ pa_format_info_free (format);
+
if (!pbuf->probe_stream) {
GST_WARNING_OBJECT (psink, "Could not create probe stream");
goto unlock;
}
- pa_format_info_free (format);
-
stream = pbuf->probe_stream;
}
- ret = gst_caps_new_empty ();
-
if (!(o = pa_context_get_sink_info_by_name (pbuf->context,
pa_stream_get_device_name (stream), gst_pulsesink_sink_info_cb,
&device_info)))
}
for (i = g_list_first (device_info.formats); i; i = g_list_next (i)) {
- gst_caps_append (ret,
- gst_pulse_format_info_to_caps ((pa_format_info *) i->data));
+ GstCaps *caps = gst_pulse_format_info_to_caps ((pa_format_info *) i->data);
+ if (caps)
+ gst_caps_append (ret, caps);
}
+unlock:
+ pa_threaded_mainloop_unlock (mainloop);
+ /* FIXME: this could be freed after device_name is got */
+ GST_OBJECT_UNLOCK (pbuf);
+
if (filter) {
GstCaps *tmp = gst_caps_intersect_full (filter, ret,
GST_CAPS_INTERSECT_FIRST);
ret = tmp;
}
-unlock:
- pa_threaded_mainloop_unlock (mainloop);
- /* FIXME: this could be freed after device_name is got */
- GST_OBJECT_UNLOCK (pbuf);
-
out:
free_device_info (&device_info);
pulsesink->mute_set = FALSE;
pulsesink->notify = 0;
+
+ g_atomic_int_set (&pulsesink->format_lost, FALSE);
+ pulsesink->format_lost_time = GST_CLOCK_TIME_NONE;
+
+ pulsesink->properties = NULL;
+ pulsesink->proplist = NULL;
#ifdef __TIZEN__
+ pulsesink->latency = g_strdup (DEFAULT_AUDIO_LATENCY);
+ pulsesink->auto_render_delay = DEFAULT_AUTO_RENDER_DELAY;
+ pulsesink->proplist = pa_proplist_new();
+ pa_proplist_sets(pulsesink->proplist, PA_PROP_MEDIA_TIZEN_AUDIO_LATENCY, pulsesink->latency);
#ifdef PCM_DUMP_ENABLE
if (vconf_get_int(GST_PULSESINK_DUMP_VCONF_KEY, &vconf_dump)) {
GST_WARNING("vconf_get_int %s failed", GST_PULSESINK_DUMP_VCONF_KEY);
pulsesink->dump_fd_input = NULL;
if (pulsesink->need_dump_input) {
sinkpad = gst_element_get_static_pad((GstElement *)pulsesink, "sink");
- gst_pad_add_buffer_probe (sinkpad, G_CALLBACK (gst_pulsesink_pad_dump_handler), pulsesink);
+ if (sinkpad) {
+ gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BUFFER, gst_pulsesink_pad_dump_probe, pulsesink, NULL);
+ gst_object_unref (GST_OBJECT(sinkpad));
+ }
}
#endif
#endif /* __TIZEN__ */
- g_atomic_int_set (&pulsesink->format_lost, FALSE);
- pulsesink->format_lost_time = GST_CLOCK_TIME_NONE;
-
- pulsesink->properties = NULL;
- pulsesink->proplist = NULL;
-
/* override with a custom clock */
if (GST_AUDIO_BASE_SINK (pulsesink)->provided_clock)
gst_object_unref (GST_AUDIO_BASE_SINK (pulsesink)->provided_clock);
if (pulsesink->proplist)
pa_proplist_free (pulsesink->proplist);
+#ifdef __TIZEN__
+ g_free (pulsesink->latency);
+#endif /* __TIZEN__ */
+
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_pulsesink_set_volume (GstPulseSink * psink, gdouble volume)
{
+#ifndef __TIZEN__
pa_cvolume v;
pa_operation *o = NULL;
+#endif
GstPulseRingBuffer *pbuf;
uint32_t idx;
+#ifndef __TIZEN__
if (!mainloop)
goto no_mainloop;
pa_threaded_mainloop_lock (mainloop);
+#endif
GST_DEBUG_OBJECT (psink, "setting volume to %f", volume);
if ((idx = pa_stream_get_index (pbuf->stream)) == PA_INVALID_INDEX)
goto no_index;
+#ifndef __TIZEN__
if (pbuf->is_pcm)
gst_pulse_cvolume_from_linear (&v, pbuf->channels, volume);
else
&v, NULL, NULL)))
goto volume_failed;
+#else
+ if (!psink->mute)
+ gst_pulse_set_volume_ratio (idx, "out", volume);
+ psink->volume = volume;
+#endif
+
/* We don't really care about the result of this call */
unlock:
+#ifndef __TIZEN__
if (o)
pa_operation_unref (o);
pa_threaded_mainloop_unlock (mainloop);
+#endif
return;
/* ERRORS */
+#ifndef __TIZEN__
no_mainloop:
{
psink->volume = volume;
GST_DEBUG_OBJECT (psink, "we have no mainloop");
return;
}
+#endif
no_buffer:
{
psink->volume = volume;
GST_DEBUG_OBJECT (psink, "we don't have a stream index");
goto unlock;
}
+#ifndef __TIZEN__
volume_failed:
{
GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
pa_strerror (pa_context_errno (pbuf->context))), (NULL));
goto unlock;
}
+#endif
}
static void
gst_pulsesink_set_mute (GstPulseSink * psink, gboolean mute)
{
+#ifndef __TIZEN__
pa_operation *o = NULL;
+#endif
GstPulseRingBuffer *pbuf;
uint32_t idx;
+#ifndef __TIZEN__
if (!mainloop)
goto no_mainloop;
pa_threaded_mainloop_lock (mainloop);
+#endif
GST_DEBUG_OBJECT (psink, "setting mute state to %d", mute);
if ((idx = pa_stream_get_index (pbuf->stream)) == PA_INVALID_INDEX)
goto no_index;
+#ifndef __TIZEN__
if (!(o = pa_context_set_sink_input_mute (pbuf->context, idx,
mute, NULL, NULL)))
goto mute_failed;
+#else
+ gst_pulse_set_volume_ratio (idx, "out", mute ? 0 : psink->volume);
+ psink->mute = mute;
+#endif
/* We don't really care about the result of this call */
unlock:
+#ifndef __TIZEN__
if (o)
pa_operation_unref (o);
pa_threaded_mainloop_unlock (mainloop);
+#endif
return;
/* ERRORS */
+#ifndef __TIZEN__
no_mainloop:
{
psink->mute = mute;
GST_DEBUG_OBJECT (psink, "we have no mainloop");
return;
}
+#endif
no_buffer:
{
psink->mute = mute;
GST_DEBUG_OBJECT (psink, "we don't have a stream index");
goto unlock;
}
+#ifndef __TIZEN__
mute_failed:
{
GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
pa_strerror (pa_context_errno (pbuf->context))), (NULL));
goto unlock;
}
+#endif
}
static void
pulsesink->proplist = gst_pulse_make_proplist (pulsesink->properties);
break;
#ifdef __TIZEN__
- case PROP_AUDIO_LATENCY: {
- gint nvalue = 0;
- if (!pulsesink->proplist)
- pulsesink->proplist = pa_proplist_new();
- nvalue = g_value_get_enum(value);
- if(nvalue > PULSESINK_LATENCY_VOIP)
- nvalue = PULSESINK_LATENCY_VOIP;
- if(nvalue < PULSESINK_LATENCY_LOW)
- nvalue = PULSESINK_LATENCY_LOW;
- pa_proplist_setf(pulsesink->proplist, PA_PROP_MEDIA_TIZEN_AUDIO_LATENCY, "%d", nvalue + AUDIO_OUT_LATENCY_LOW);
- pulsesink->latency = nvalue;
- GST_DEBUG_OBJECT(pulsesink, "latency(%d)", nvalue);
- break;
+ case PROP_AUDIO_LATENCY:
+ g_free (pulsesink->latency);
+ pulsesink->latency = g_value_dup_string (value);
+ /* setting NULL restores the default latency */
+ if (pulsesink->latency == NULL) {
+ pulsesink->latency = g_strdup (DEFAULT_AUDIO_LATENCY);
}
+ if (!pulsesink->proplist) {
+ pulsesink->proplist = pa_proplist_new();
+ }
+ pa_proplist_sets(pulsesink->proplist, PA_PROP_MEDIA_TIZEN_AUDIO_LATENCY, pulsesink->latency);
+ GST_DEBUG_OBJECT(pulsesink, "latency(%s)", pulsesink->latency);
+ break;
+ case PROP_AUTO_RENDER_DELAY:
+ pulsesink->auto_render_delay = g_value_get_boolean (value);
+ GST_DEBUG_OBJECT (pulsesink, "setting auto-render-delay to %d", g_value_get_boolean (value));
+ break;
#endif /* __TIZEN__ */
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case PROP_VOLUME:
{
+#ifndef __TIZEN__
gdouble volume;
gst_pulsesink_get_sink_input_info (pulsesink, &volume, NULL);
g_value_set_double (value, volume);
+#else
+ g_value_set_double (value, pulsesink->volume);
+#endif
break;
}
case PROP_MUTE:
{
+#ifndef __TIZEN__
gboolean mute;
gst_pulsesink_get_sink_input_info (pulsesink, NULL, &mute);
g_value_set_boolean (value, mute);
+#else
+ g_value_set_boolean (value, pulsesink->mute);
+#endif
break;
}
case PROP_CLIENT_NAME:
break;
#ifdef __TIZEN__
case PROP_AUDIO_LATENCY:
- g_value_set_enum (value, pulsesink->latency);
+ g_value_set_string (value, pulsesink->latency);
+ break;
+ case PROP_AUTO_RENDER_DELAY:
+ g_value_set_boolean (value, pulsesink->auto_render_delay);
break;
#endif /* __TIZEN__ */
default:
gst_pulsesink_query (GstBaseSink * sink, GstQuery * query)
{
GstPulseSink *pulsesink = GST_PULSESINK_CAST (sink);
- gboolean ret;
+ gboolean ret = FALSE;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CAPS:
if (caps) {
gst_query_set_caps_result (query, caps);
gst_caps_unref (caps);
- return TRUE;
- } else {
- return FALSE;
+ ret = TRUE;
}
+ break;
}
case GST_QUERY_ACCEPT_CAPS:
{