+static double
+volume_glk_to_gstreamer(glui32 volume_glk)
+{
+ return CLAMP(((double)volume_glk / 0x10000), 0.0, 10.0);
+}
+
+#ifdef GSTREAMER_SOUND
+static gboolean
+volume_change_timeout(schanid_t chan)
+{
+ GTimeVal now;
+ g_get_current_time(&now);
+
+ if(now.tv_sec >= chan->target_time_sec && now.tv_usec >= chan->target_time_usec) {
+ /* We're done - make sure the volume is at the requested level */
+ g_object_set(chan->filter, "volume", chan->target_volume, NULL);
+
+ if(chan->volume_notify)
+ event_throw(chan->glk, evtype_VolumeNotify, NULL, 0, chan->volume_notify);
+
+ chan->volume_timer_id = 0;
+ return FALSE;
+ }
+
+ /* Calculate the appropriate step every time - a busy system may delay or
+ * drop timer ticks */
+ double time_left_msec = (chan->target_time_sec - now.tv_sec) * 1000.0
+ + (chan->target_time_usec - now.tv_usec) / 1000.0;
+ double steps_left = time_left_msec / VOLUME_TIMER_RESOLUTION;
+ double current_volume;
+ g_object_get(chan->filter, "volume", ¤t_volume, NULL);
+ double volume_step = (chan->target_volume - current_volume) / steps_left;
+
+ g_object_set(chan->filter, "volume", current_volume + volume_step, NULL);
+
+ return TRUE;
+}
+#endif /* GSTREAMER_SOUND */
+