playsink: Require the streamvolume interface on the sink when using the sink's volume/mute properties

If the sink has properties named volume and mute, we have no idea about their
meaning. The streamvolume interface standardizes the meaning.

In the case of osxaudiosink for example, the current volume property has a
range of 0.0 to 1.0, but we need 0.0 to 10.0 or similar. Also osxaudiosink
has no mute property. As such, the volume element should be used here instead.

https://bugzilla.gnome.org/show_bug.cgi?id=752156
This commit is contained in:
Sebastian Dröge 2015-07-10 11:53:24 +03:00
parent 8be88f0364
commit f99a24f8b3

View file

@ -105,7 +105,6 @@ typedef struct
GstElement *volume; /* element with the volume property */
gboolean sink_volume; /* if the volume was provided by the sink */
gulong notify_volume_id;
GstElement *mute; /* element with the mute property */
gulong notify_mute_id;
GstElement *sink;
GstElement *ts_offset;
@ -730,7 +729,7 @@ disconnect_audio_chain (GstPlayAudioChain * chain, GstPlaySink * playsink)
if (chain->notify_volume_id)
g_signal_handler_disconnect (chain->volume, chain->notify_volume_id);
if (chain->notify_mute_id)
g_signal_handler_disconnect (chain->mute, chain->notify_mute_id);
g_signal_handler_disconnect (chain->volume, chain->notify_mute_id);
chain->notify_volume_id = chain->notify_mute_id = 0;
}
}
@ -1148,12 +1147,10 @@ gst_play_sink_set_volume (GstPlaySink * playsink, gdouble volume)
playsink->volume = volume;
chain = (GstPlayAudioChain *) playsink->audiochain;
if (chain && chain->volume) {
GST_LOG_OBJECT (playsink, "elements: volume=%" GST_PTR_FORMAT ", mute=%"
GST_PTR_FORMAT "; new volume=%.03f, mute=%d", chain->volume,
chain->mute, volume, playsink->mute);
/* if there is a mute element or we are not muted, set the volume */
if (chain->mute || !playsink->mute)
g_object_set (chain->volume, "volume", volume, NULL);
GST_LOG_OBJECT (playsink,
"elements: volume=%" GST_PTR_FORMAT "; new volume=%.03f, mute=%d",
chain->volume, volume, playsink->mute);
g_object_set (chain->volume, "volume", volume, NULL);
} else {
GST_LOG_OBJECT (playsink, "no volume element");
playsink->volume_changed = TRUE;
@ -1171,10 +1168,8 @@ gst_play_sink_get_volume (GstPlaySink * playsink)
chain = (GstPlayAudioChain *) playsink->audiochain;
result = playsink->volume;
if (chain && chain->volume) {
if (chain->mute || !playsink->mute) {
g_object_get (chain->volume, "volume", &result, NULL);
playsink->volume = result;
}
g_object_get (chain->volume, "volume", &result, NULL);
playsink->volume = result;
}
GST_PLAY_SINK_UNLOCK (playsink);
@ -1189,16 +1184,8 @@ gst_play_sink_set_mute (GstPlaySink * playsink, gboolean mute)
GST_PLAY_SINK_LOCK (playsink);
playsink->mute = mute;
chain = (GstPlayAudioChain *) playsink->audiochain;
if (chain) {
if (chain->mute) {
g_object_set (chain->mute, "mute", mute, NULL);
} else if (chain->volume) {
if (mute)
g_object_set (chain->volume, "volume", (gdouble) 0.0, NULL);
else
g_object_set (chain->volume, "volume", (gdouble) playsink->volume,
NULL);
}
if (chain && chain->volume) {
g_object_set (chain->volume, "mute", mute, NULL);
} else {
playsink->mute_changed = TRUE;
}
@ -1213,8 +1200,8 @@ gst_play_sink_get_mute (GstPlaySink * playsink)
GST_PLAY_SINK_LOCK (playsink);
chain = (GstPlayAudioChain *) playsink->audiochain;
if (chain && chain->mute) {
g_object_get (chain->mute, "mute", &result, NULL);
if (chain && chain->volume) {
g_object_get (chain->volume, "mute", &result, NULL);
playsink->mute = result;
} else {
result = playsink->mute;
@ -2767,11 +2754,16 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw)
gst_play_sink_find_property_sinks (playsink, chain->sink, "ts-offset",
G_TYPE_INT64));
/* check if the sink, or something within the sink, has the volume property.
* If it does we don't need to add a volume element. */
elem =
gst_play_sink_find_property_sinks (playsink, chain->sink, "volume",
G_TYPE_DOUBLE);
/* check if the sink, or something within the sink, implements the
* streamvolume interface. If it does we don't need to add a volume element. */
if (GST_IS_BIN (chain->sink))
elem =
gst_bin_get_by_interface (GST_BIN_CAST (chain->sink),
GST_TYPE_STREAM_VOLUME);
else if (GST_IS_STREAM_VOLUME (chain->sink))
elem = gst_object_ref (chain->sink);
else
elem = NULL;
chain->notify_volume_id = chain->notify_mute_id = 0;
if (elem) {
chain->volume = elem;
@ -2782,29 +2774,15 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw)
GST_DEBUG_OBJECT (playsink, "the sink has a volume property");
have_volume = TRUE;
chain->sink_volume = TRUE;
/* if the sink also has a mute property we can use this as well. We'll only
* use the mute property if there is a volume property. We can simulate the
* mute with the volume otherwise. */
chain->mute =
gst_play_sink_find_property_sinks (playsink, chain->sink, "mute",
G_TYPE_BOOLEAN);
if (chain->mute) {
GST_DEBUG_OBJECT (playsink, "the sink has a mute property");
chain->notify_mute_id = g_signal_connect (chain->mute, "notify::mute",
G_CALLBACK (notify_mute_cb), playsink);
}
chain->notify_mute_id = g_signal_connect (chain->volume, "notify::mute",
G_CALLBACK (notify_mute_cb), playsink);
/* use the sink to control the volume and mute */
if (playsink->volume_changed) {
g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL);
playsink->volume_changed = FALSE;
}
if (playsink->mute_changed) {
if (chain->mute) {
g_object_set (chain->mute, "mute", playsink->mute, NULL);
} else {
if (playsink->mute)
g_object_set (chain->volume, "volume", (gdouble) 0.0, NULL);
}
g_object_set (chain->volume, "mute", playsink->mute, NULL);
playsink->mute_changed = FALSE;
}
} else {
@ -2848,14 +2826,13 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw)
G_CALLBACK (notify_volume_cb), playsink);
/* volume also has the mute property */
chain->mute = chain->volume;
chain->notify_mute_id = g_signal_connect (chain->mute, "notify::mute",
chain->notify_mute_id = g_signal_connect (chain->volume, "notify::mute",
G_CALLBACK (notify_mute_cb), playsink);
/* configure with the latest volume and mute */
g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume,
NULL);
g_object_set (G_OBJECT (chain->mute), "mute", playsink->mute, NULL);
g_object_set (G_OBJECT (chain->volume), "mute", playsink->mute, NULL);
}
}
}
@ -2980,11 +2957,16 @@ setup_audio_chain (GstPlaySink * playsink, gboolean raw)
/* Disconnect signals */
disconnect_audio_chain (chain, playsink);
/* check if the sink, or something within the sink, has the volume property.
* If it does we don't need to add a volume element. */
elem =
gst_play_sink_find_property_sinks (playsink, chain->sink, "volume",
G_TYPE_DOUBLE);
/* check if the sink, or something within the sink, implements the
* streamvolume interface. If it does we don't need to add a volume element. */
if (GST_IS_BIN (chain->sink))
elem =
gst_bin_get_by_interface (GST_BIN_CAST (chain->sink),
GST_TYPE_STREAM_VOLUME);
else if (GST_IS_STREAM_VOLUME (chain->sink))
elem = gst_object_ref (chain->sink);
else
elem = NULL;
if (elem) {
chain->volume = elem;
@ -2998,19 +2980,10 @@ setup_audio_chain (GstPlaySink * playsink, gboolean raw)
chain->notify_volume_id = g_signal_connect (chain->volume, "notify::volume",
G_CALLBACK (notify_volume_cb), playsink);
/* if the sink also has a mute property we can use this as well. We'll only
* use the mute property if there is a volume property. We can simulate the
* mute with the volume otherwise. */
chain->mute =
gst_play_sink_find_property_sinks (playsink, chain->sink, "mute",
G_TYPE_BOOLEAN);
if (chain->mute) {
GST_DEBUG_OBJECT (playsink, "the sink has a mute property");
chain->notify_mute_id = g_signal_connect (chain->mute, "notify::mute",
G_CALLBACK (notify_mute_cb), playsink);
g_object_set (chain->mute, "mute", playsink->mute, NULL);
playsink->mute_changed = FALSE;
}
chain->notify_mute_id = g_signal_connect (chain->volume, "notify::mute",
G_CALLBACK (notify_mute_cb), playsink);
g_object_set (chain->volume, "mute", playsink->mute, NULL);
playsink->mute_changed = FALSE;
g_object_set (chain->conv, "use-volume", FALSE, NULL);
} else if (conv) {
@ -3021,18 +2994,17 @@ setup_audio_chain (GstPlaySink * playsink, gboolean raw)
if (conv->volume && (playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME)) {
chain->volume = conv->volume;
chain->mute = chain->volume;
chain->notify_volume_id =
g_signal_connect (chain->volume, "notify::volume",
G_CALLBACK (notify_volume_cb), playsink);
chain->notify_mute_id = g_signal_connect (chain->mute, "notify::mute",
chain->notify_mute_id = g_signal_connect (chain->volume, "notify::mute",
G_CALLBACK (notify_mute_cb), playsink);
/* configure with the latest volume and mute */
g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL);
g_object_set (G_OBJECT (chain->mute), "mute", playsink->mute, NULL);
g_object_set (G_OBJECT (chain->volume), "mute", playsink->mute, NULL);
}
GST_DEBUG_OBJECT (playsink, "reusing existing volume element");
@ -3501,7 +3473,6 @@ gst_play_sink_do_reconfigure (GstPlaySink * playsink)
activate_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE);
disconnect_audio_chain (playsink->audiochain, playsink);
playsink->audiochain->volume = NULL;
playsink->audiochain->mute = NULL;
if (playsink->audiochain->ts_offset)
gst_object_unref (playsink->audiochain->ts_offset);
playsink->audiochain->ts_offset = NULL;
@ -3610,7 +3581,6 @@ gst_play_sink_do_reconfigure (GstPlaySink * playsink)
if (playsink->audiochain->sink_volume) {
disconnect_audio_chain (playsink->audiochain, playsink);
playsink->audiochain->volume = NULL;
playsink->audiochain->mute = NULL;
if (playsink->audiochain->ts_offset)
gst_object_unref (playsink->audiochain->ts_offset);
playsink->audiochain->ts_offset = NULL;
@ -4813,11 +4783,10 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
/* fall through */
case GST_STATE_CHANGE_READY_TO_NULL:
if (playsink->audiochain && playsink->audiochain->sink_volume) {
/* remove our links to the mute and volume elements when they were
/* remove our links to the volume elements when they were
* provided by a sink */
disconnect_audio_chain (playsink->audiochain, playsink);
playsink->audiochain->volume = NULL;
playsink->audiochain->mute = NULL;
}
if (playsink->audiochain && playsink->audiochain->ts_offset) {