#define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
#define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
-static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject);
+PA_DEFINE_PUBLIC_CLASS(pa_source, pa_msgobject);
static void source_free(pa_object *o);
pa_cvolume_reset(&data->volume, data->sample_spec.channels);
pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
- pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels);
+ pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec));
if (!data->muted_is_set)
data->muted = FALSE;
s->core = core;
s->state = PA_SOURCE_INIT;
s->flags = flags;
+ s->priority = 0;
s->suspend_cause = 0;
s->name = pa_xstrdup(name);
s->proplist = pa_proplist_copy(data->proplist);
s->module = data->module;
s->card = data->card;
+ s->priority = pa_device_init_priority(s->proplist);
+
s->sample_spec = data->sample_spec;
s->channel_map = data->channel_map;
s->outputs = pa_idxset_new(NULL, NULL);
s->n_corked = 0;
s->monitor_of = NULL;
+ s->output_from_master = NULL;
- s->virtual_volume = data->volume;
+ s->volume = data->volume;
pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
s->base_volume = PA_VOLUME_NORM;
s->n_volume_steps = PA_VOLUME_NORM+1;
}
/* Called from main thread */
-void pa_source_set_volume(pa_source *s, const pa_cvolume *volume, pa_bool_t save) {
- pa_cvolume old_virtual_volume;
- pa_bool_t virtual_volume_changed;
+void pa_source_set_volume(
+ pa_source *s,
+ const pa_cvolume *volume,
+ pa_bool_t save) {
+
+ pa_bool_t real_changed;
+ pa_cvolume old_volume;
pa_source_assert_ref(s);
pa_assert_ctl_context();
pa_assert(PA_SOURCE_IS_LINKED(s->state));
- pa_assert(volume);
pa_assert(pa_cvolume_valid(volume));
- pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
+ pa_assert(volume->channels == 1 || pa_cvolume_compatible(volume, &s->sample_spec));
+
+ old_volume = s->volume;
+
+ if (pa_cvolume_compatible(volume, &s->sample_spec))
+ s->volume = *volume;
+ else
+ pa_cvolume_scale(&s->volume, pa_cvolume_max(volume));
- old_virtual_volume = s->virtual_volume;
- s->virtual_volume = *volume;
- virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
- s->save_volume = (!virtual_volume_changed && s->save_volume) || save;
+ real_changed = !pa_cvolume_equal(&old_volume, &s->volume);
+ s->save_volume = (!real_changed && s->save_volume) || save;
if (s->set_volume) {
pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
s->set_volume(s);
} else
- s->soft_volume = s->virtual_volume;
+ s->soft_volume = s->volume;
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
- if (virtual_volume_changed)
+ if (real_changed)
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
pa_source_assert_ref(s);
pa_assert_ctl_context();
- pa_assert(volume);
+
+ if (!volume)
+ pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
+ else
+ s->soft_volume = *volume;
if (PA_SOURCE_IS_LINKED(s->state))
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
else
- s->thread_info.soft_volume = *volume;
+ s->thread_info.soft_volume = s->soft_volume;
}
/* Called from main thread */
pa_assert(PA_SOURCE_IS_LINKED(s->state));
if (s->refresh_volume || force_refresh) {
- pa_cvolume old_virtual_volume = s->virtual_volume;
+ pa_cvolume old_volume;
+
+ old_volume = s->volume;
if (s->get_volume)
s->get_volume(s);
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
- if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) {
+ if (!pa_cvolume_equal(&old_volume, &s->volume)) {
s->save_volume = TRUE;
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
}
- return &s->virtual_volume;
+ return &s->volume;
}
/* Called from main thread */
/* The source implementor may call this if the volume changed to make sure everyone is notified */
- if (pa_cvolume_equal(&s->virtual_volume, new_volume))
+ if (pa_cvolume_equal(&s->volume, new_volume))
return;
- s->virtual_volume = *new_volume;
+ s->volume = *new_volume;
s->save_volume = TRUE;
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
pa_source_output_state_t st;
st = pa_source_output_get_state(o);
- pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st));
+
+ /* We do not assert here. It is perfectly valid for a source output to
+ * be in the INIT state (i.e. created, marked done but not yet put)
+ * and we should not care if it's unlinked as it won't contribute
+ * towarards our busy status.
+ */
+ if (!PA_SOURCE_OUTPUT_IS_LINKED(st))
+ continue;
if (st == PA_SOURCE_OUTPUT_CORKED)
continue;
/* Called from main thread */
void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
- pa_source_assert_ref(s);
- pa_assert_ctl_context();
- pa_assert(min_latency);
- pa_assert(max_latency);
-
- if (PA_SOURCE_IS_LINKED(s->state)) {
- pa_usec_t r[2] = { 0, 0 };
-
- pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
-
- *min_latency = r[0];
- *max_latency = r[1];
- } else {
- *min_latency = s->thread_info.min_latency;
- *max_latency = s->thread_info.max_latency;
- }
+ pa_source_assert_ref(s);
+ pa_assert_ctl_context();
+ pa_assert(min_latency);
+ pa_assert(max_latency);
+
+ if (PA_SOURCE_IS_LINKED(s->state)) {
+ pa_usec_t r[2] = { 0, 0 };
+
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
+
+ *min_latency = r[0];
+ *max_latency = r[1];
+ } else {
+ *min_latency = s->thread_info.min_latency;
+ *max_latency = s->thread_info.max_latency;
+ }
}
/* Called from IO thread, and from main thread before pa_source_put() is called */
s->active_port = port;
s->save_port = save;
+ pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED], s);
+
return 0;
}