]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/sink-input.c
introduce pa_sink_input_get_relative_volume()
[pulseaudio] / src / pulsecore / sink-input.c
index df42cae877fb2a4ad683c4a8a8641846cb710cec..ae2c6f546c58c815974fd946c528c040fae5ed3f 100644 (file)
@@ -6,7 +6,7 @@
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
-  by the Free Software Foundation; either version 2 of the License,
+  by the Free Software Foundation; either version 2.1 of the License,
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
@@ -79,6 +79,18 @@ void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cv
         data->volume = *volume;
 }
 
+void pa_sink_input_new_data_apply_volume_factor(pa_sink_input_new_data *data, const pa_cvolume *volume_factor) {
+    pa_assert(data);
+    pa_assert(volume_factor);
+
+    if (data->volume_factor_is_set)
+        pa_sw_cvolume_multiply(&data->volume_factor, &data->volume_factor, volume_factor);
+    else {
+        data->volume_factor_is_set = TRUE;
+        data->volume_factor = *volume_factor;
+    }
+}
+
 void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, pa_bool_t mute) {
     pa_assert(data);
 
@@ -110,6 +122,7 @@ static void reset_callbacks(pa_sink_input *i) {
     i->get_latency = NULL;
     i->state_change = NULL;
     i->may_move_to = NULL;
+    i->send_event = NULL;
 }
 
 /* Called from main context */
@@ -145,7 +158,6 @@ int pa_sink_input_new(
     pa_return_val_if_fail(data->sink, -PA_ERR_NOENTITY);
     pa_return_val_if_fail(PA_SINK_IS_LINKED(pa_sink_get_state(data->sink)), -PA_ERR_BADSTATE);
     pa_return_val_if_fail(!data->sync_base || (data->sync_base->sink == data->sink && pa_sink_input_get_state(data->sync_base) == PA_SINK_INPUT_CORKED), -PA_ERR_INVALID);
-    pa_return_val_if_fail(!(flags & PA_SINK_INPUT_FAIL_ON_SUSPEND) || pa_sink_get_state(data->sink) != PA_SINK_SUSPENDED, -PA_ERR_BADSTATE);
 
     if (!data->sample_spec_is_set)
         data->sample_spec = data->sink->sample_spec;
@@ -167,16 +179,24 @@ int pa_sink_input_new(
         if (data->sink->flags & PA_SINK_FLAT_VOLUME) {
             data->volume = *pa_sink_get_volume(data->sink, FALSE);
             pa_cvolume_remap(&data->volume, &data->sink->channel_map, &data->channel_map);
-        } else
+            data->volume_is_absolute = TRUE;
+        } else {
             pa_cvolume_reset(&data->volume, data->sample_spec.channels);
+            data->volume_is_absolute = FALSE;
+        }
 
         data->save_volume = FALSE;
-
     }
 
     pa_return_val_if_fail(pa_cvolume_valid(&data->volume), -PA_ERR_INVALID);
     pa_return_val_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec), -PA_ERR_INVALID);
 
+    if (!data->volume_factor_is_set)
+        pa_cvolume_reset(&data->volume_factor, data->sample_spec.channels);
+
+    pa_return_val_if_fail(pa_cvolume_valid(&data->volume_factor), -PA_ERR_INVALID);
+    pa_return_val_if_fail(pa_cvolume_compatible(&data->volume_factor, &data->sample_spec), -PA_ERR_INVALID);
+
     if (!data->muted_is_set)
         data->muted = FALSE;
 
@@ -207,6 +227,12 @@ int pa_sink_input_new(
     if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], data)) < 0)
         return r;
 
+    if ((flags & PA_SINK_INPUT_FAIL_ON_SUSPEND) &&
+        pa_sink_get_state(data->sink) == PA_SINK_SUSPENDED) {
+        pa_log_warn("Failed to create sink input: sink is suspended.");
+        return -PA_ERR_BADSTATE;
+    }
+
     if (pa_idxset_size(data->sink->inputs) >= PA_MAX_INPUTS_PER_SINK) {
         pa_log_warn("Failed to create sink input: too many inputs per sink.");
         return -PA_ERR_TOOLARGE;
@@ -259,6 +285,7 @@ int pa_sink_input_new(
     } else
         i->virtual_volume = data->volume;
 
+    i->volume_factor = data->volume_factor;
     pa_cvolume_init(&i->soft_volume);
     i->save_volume = data->save_volume;
     i->save_sink = data->save_sink;
@@ -441,6 +468,8 @@ void pa_sink_input_unlink(pa_sink_input *i) {
         i->sink = NULL;
     }
 
+    pa_core_maybe_vacuum(i->core);
+
     pa_sink_input_unref(i);
 }
 
@@ -500,7 +529,7 @@ void pa_sink_input_put(pa_sink_input *i) {
         pa_sink_update_flat_volume(i->sink, &new_volume);
         pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE);
     } else
-        i->soft_volume = i->virtual_volume;
+        pa_sw_cvolume_multiply(&i->soft_volume, &i->virtual_volume, &i->volume_factor);
 
     i->thread_info.soft_volume = i->soft_volume;
     i->thread_info.muted = i->muted;
@@ -874,8 +903,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo
 
         /* OK, we are in normal volume mode. The volume only affects
          * ourselves */
-
-        i->soft_volume = *volume;
+        pa_sw_cvolume_multiply(&i->soft_volume, volume, &i->volume_factor);
 
         /* Hooks have the ability to play games with i->soft_volume */
         pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i);
@@ -895,6 +923,28 @@ const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i) {
     return &i->virtual_volume;
 }
 
+/* Called from main context */
+pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v) {
+    pa_sink_input_assert_ref(i);
+    pa_assert(v);
+    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
+
+    *v = i->virtual_volume;
+
+    /* This always returns a relative volume, even in flat volume mode */
+
+    if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
+        pa_cvolume sv;
+
+        sv = *pa_sink_get_volume(i->sink, FALSE);
+
+        pa_sw_cvolume_divide(v, v,
+                             pa_cvolume_remap(&sv, &i->sink->channel_map, &i->channel_map));
+    }
+
+    return v;
+}
+
 /* Called from main context */
 void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save) {
     pa_assert(i);
@@ -920,18 +970,16 @@ pa_bool_t pa_sink_input_get_mute(pa_sink_input *i) {
 }
 
 /* Called from main thread */
-pa_bool_t pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p) {
-
-  pa_sink_input_assert_ref(i);
-
-  pa_proplist_update(i->proplist, mode, p);
+void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p) {
+    pa_sink_input_assert_ref(i);
 
-  if (PA_SINK_IS_LINKED(i->state)) {
-      pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], i);
-      pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
-  }
+    if (p)
+        pa_proplist_update(i->proplist, mode, p);
 
-  return TRUE;
+    if (PA_SINK_IS_LINKED(i->state)) {
+        pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], i);
+        pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+    }
 }
 
 /* Called from main context */
@@ -1066,7 +1114,7 @@ int pa_sink_input_start_move(pa_sink_input *i) {
 
         /* Make the absolute volume relative */
         i->virtual_volume = i->soft_volume;
-        pa_cvolume_reset(&i->soft_volume, i->sample_spec.channels);
+        i->soft_volume = i->volume_factor;
 
         /* We might need to update the sink's volume if we are in flat
          * volume mode. */
@@ -1428,3 +1476,31 @@ pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret) {
 
     return ret;
 }
+
+/* Called from main context */
+void pa_sink_input_send_event(pa_sink_input *i, const char *event, pa_proplist *data) {
+    pa_proplist *pl = NULL;
+    pa_sink_input_send_event_hook_data hook_data;
+
+    pa_sink_input_assert_ref(i);
+    pa_assert(event);
+
+    if (!i->send_event)
+        return;
+
+    if (!data)
+        data = pl = pa_proplist_new();
+
+    hook_data.sink_input = i;
+    hook_data.data = data;
+    hook_data.event = event;
+
+    if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT], &hook_data) < 0)
+        goto finish;
+
+    i->send_event(i, event, data);
+
+finish:
+    if (pl)
+        pa_proplist_free(pl);
+}