예제 #1
0
static void source_info_cb(pa_context * c, const pa_source_info * i,
			   int is_last, void *userdata)
{
	snd_ctl_pulse_t *ctl = (snd_ctl_pulse_t *) userdata;
	int changed = 0;

	assert(ctl);

	if (is_last) {
		pa_threaded_mainloop_signal(ctl->p->mainloop, 0);
		return;
	}

	assert(i);

	if (!!ctl->source_muted != !!i->mute) {
		ctl->source_muted = i->mute;
		ctl->updated |= UPDATE_SOURCE_MUTE;
		changed = 1;
	}

	if (!pa_cvolume_equal(&ctl->source_volume, &i->volume)) {
		ctl->source_volume = i->volume;
		ctl->updated |= UPDATE_SOURCE_VOL;
		changed = 1;
	}

	if (changed)
		pulse_poll_activate(ctl->p);

}
void AudioSinksManager::InternalAudioSink::sink_info_callback(pa_context* /*c*/,
                                                              const pa_sink_info* info, int eol,
                                                              void* userdata) {
    AudioSinksManager::InternalAudioSink* sink =
            static_cast<AudioSinksManager::InternalAudioSink*>(userdata);
    if (!info) {
        assert(eol);
        return;
    }
    if (sink->sink_idx == static_cast<uint32_t>(-1)) {
        sink->sink_idx = info->index;
        sink->manager->logger->debug("(AudioSink '{}') Sink idx is: {}", sink->name,
                                     sink->sink_idx);
        sink->manager->sink_idx_audio_sink.emplace(sink->sink_idx, sink->shared_from_this());
    } else {
        assert(sink->sink_idx == info->index);
    }

    if (!pa_cvolume_equal(&sink->volume, &info->volume) || sink->muted != info->mute) {
        sink->volume = info->volume;
        sink->muted = !!info->mute;
        assert(sink->volume.channels == 2);
        sink->manager->logger->trace("(AudioSink '{}') Volume changed", sink->name);
        if (sink->volume_callback) {
            sink->volume_callback(static_cast<double>(sink->volume.values[0]) / PA_VOLUME_NORM,
                                  static_cast<double>(sink->volume.values[1]) / PA_VOLUME_NORM,
                                  sink->muted);
        }
    }
}
예제 #3
0
파일: pulsestream.cpp 프로젝트: KDE/phonon
void PulseStream::setVolume(const pa_cvolume *volume)
{
    if (mCachedVolume != -1)
        QMetaObject::invokeMethod(this, "applyCachedVolume", Qt::QueuedConnection);
    if (pa_cvolume_equal(&mVolume, volume) == 0) {
        memcpy(&mVolume, volume, sizeof(mVolume));
        qreal vol = (qreal)pa_cvolume_avg(volume) / PA_VOLUME_NORM;
        // AudioOutput expects the "backend" to supply values that have been
        // adjusted for Stephens' law, so we need to fudge them accordingly
        // so that the %ages match up in KMix/the application's own slider.
        emit volumeChanged(qPow(vol, VOLTAGE_TO_LOUDNESS_EXPONENT));
    }
}
예제 #4
0
static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
    pa_cvolume t;

    if (a->port_valid != b->port_valid ||
        (a->port_valid && strncmp(a->port, b->port, sizeof(a->port))))
        return FALSE;

    if (a->muted_valid != b->muted_valid ||
        (a->muted_valid && (a->muted != b->muted)))
        return FALSE;

    t = b->volume;
    if (a->volume_valid != b->volume_valid ||
        (a->volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->volume)))
        return FALSE;

    return TRUE;
}
void
gvc_channel_map_volume_changed (GvcChannelMap     *map,
                                const pa_cvolume  *cv,
                                gboolean           set)
{
        g_return_if_fail (GVC_IS_CHANNEL_MAP (map));
        g_return_if_fail (cv != NULL);
        g_return_if_fail (pa_cvolume_compatible_with_channel_map(cv, &map->priv->pa_map));

        if (pa_cvolume_equal(cv, &map->priv->pa_volume))
                return;

        map->priv->pa_volume = *cv;

        if (map->priv->pa_volume_is_set == FALSE) {
                map->priv->pa_volume_is_set = TRUE;
                return;
        }
        g_signal_emit (map, signals[VOLUME_CHANGED], 0, set);
}
예제 #6
0
static void source_get_volume_cb(pa_source *s) {
    struct userdata *u;

    pa_source_assert_ref(s);
    pa_assert_se(u = s->userdata);

    if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
        !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
        return;

    /* FIXME, no volume control in source_output, get the info from the master */
    pa_source_get_volume(u->source_output->source, TRUE);

    if (pa_cvolume_equal(&s->volume,&u->source_output->source->volume))
        /* no change */
        return;

    s->volume = u->source_output->source->volume;
    pa_source_set_soft_volume(s, NULL);
}
/* update the volume by firing the appropriate volume hook */
static void voice_update_volumes(struct userdata *u) {
    const pa_cvolume *cvol;

    pa_assert(u);
    pa_assert(u->master_sink);

    cvol = &u->master_sink->real_volume;

    /* check the volume , if its same as previous one then return */
    if (pa_cvolume_equal(cvol, &u->previous_volume))
        return;

    /* assign the current volume, will be used for the next time*/
    u->previous_volume = *cvol;

    if (voice_voip_source_active(u))
        meego_algorithm_hook_fire(u->hooks[HOOK_CALL_VOLUME], (void*)cvol);
    else
        meego_algorithm_hook_fire(u->hooks[HOOK_VOLUME], (void*)cvol);

    pa_log_debug("volume is updated");
}
예제 #8
0
void PulseAudioSystem::stream_restore_read_callback(pa_context *c, const pa_ext_stream_restore_info *i, int eol, void *userdata) {
	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);

	if (eol == 0) {
		QString name = QLatin1String(i->name);

		// were we looking for this restoration?
		if (pas->qhMissingSinks.contains(name)) {
			// make sure it still has the volume we gave it
			if (pa_cvolume_equal(&pas->qhMissingSinks[name].attenuated_volume, &i->volume) != 0) {
				// update the stream restore record
				pa_ext_stream_restore_info restore = *i;
				restore.volume = pas->qhMissingSinks[name].normal_volume;
				pas->iRemainingOperations++;
				pa_operation_unref(pa_ext_stream_restore_write(c, PA_UPDATE_REPLACE, &restore, 1, 1, restore_volume_success_callback, pas));
			}

			pas->qhMissingSinks.remove(name);
		}

	} else if (eol < 0) {
		qWarning("PulseAudio: Couldn't read stream restore database.");
		pas->qhMissingSinks.clear();

	} else {
		// verify missing list is empty
		if (pas->qhMissingSinks.count() > 0) {
			qWarning("PulseAudio: Failed to match %d stream(s).", pas->qhMissingSinks.count());
			pas->qhMissingSinks.clear();
		}

		// trigger the volume completion callback;
		// necessary so that shutdown actions are called
		restore_volume_success_callback(c, 1, pas);
	}
}
예제 #9
0
void PulseAudioSystem::restore_sink_input_list_callback(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata) {
	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);

	if (eol == 0) {
		// if we were tracking this specific sink previously
		if (pas->qhVolumes.contains(i->index)) {
			// and if it has the attenuated volume we applied to it
			if (pa_cvolume_equal(&i->volume, &pas->qhVolumes[i->index].attenuated_volume) != 0) {
				// mark it as matched
				pas->qlMatchedSinks.append(i->index);

				// reset the volume to normal
				pas->iRemainingOperations++;
				pa_operation_unref(pa_context_set_sink_input_volume(c, i->index, &pas->qhVolumes[i->index].normal_volume, restore_volume_success_callback, pas));
			}

		// otherwise, save for matching at the end of iteration
		} else {
			QString restore_id = QLatin1String(pa_proplist_gets(i->proplist, "module-stream-restore.id"));
			PulseAttenuation patt;
			patt.index = i->index;
			patt.normal_volume = i->volume;
			pas->qhUnmatchedSinks[restore_id] = patt;
		}

	} else if (eol < 0) {
		qWarning("PulseAudio: Sink input introspection error.");

	} else {
		// build a list of missing streams by iterating our active list
		QHash<uint32_t, PulseAttenuation>::const_iterator it;
		for (it = pas->qhVolumes.constBegin(); it != pas->qhVolumes.constEnd(); ++it) {
			// skip if previously matched
			if (pas->qlMatchedSinks.contains(it.key())) {
				continue;
			}

			// check if the restore id matches. the only case where this would
			// happen is if the application was reopened during attenuation.
			if (pas->qhUnmatchedSinks.contains(it.value().stream_restore_id)) {
				PulseAttenuation active_sink = pas->qhUnmatchedSinks[it.value().stream_restore_id];
				// if the volume wasn't changed from our attenuation
				if (pa_cvolume_equal(&active_sink.normal_volume, &it.value().attenuated_volume) != 0) {
					// reset the volume to normal
					pas->iRemainingOperations++;
					pa_operation_unref(pa_context_set_sink_input_volume(c, active_sink.index, &it.value().normal_volume, restore_volume_success_callback, pas));
				}
				continue;
			}

			// at this point, we don't know what happened to the sink. add
			// it to a list to check the stream restore database for.
			pas->qhMissingSinks[it.value().stream_restore_id] = it.value();
		}

		// clean up
		pas->qlMatchedSinks.clear();
		pas->qhUnmatchedSinks.clear();
		pas->qhVolumes.clear();

		// if we had missing sinks, check the stream restore database
		// to see if we can find and update them.
		if (pas->qhMissingSinks.count() > 0) {
			pas->iRemainingOperations++;
			pa_operation_unref(pa_ext_stream_restore_read(c, stream_restore_read_callback, pas));
		}

		// trigger the volume completion callback;
		// necessary so that shutdown actions are called
		restore_volume_success_callback(c, 1, pas);
	}
}
예제 #10
0
static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
    struct userdata *u =  userdata;
    pa_sink_input *si = NULL;
    pa_source_output *so = NULL;
    struct rule *r;
    char *name;

    pa_assert(c);
    pa_assert(u);

    if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW) &&
        t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) &&
        t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW) &&
        t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE))
        return;

    if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT) {
        if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx)))
            return;

        if (!si->client || !(name = client_name(si->client)))
            return;
    } else {
        pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT);

        if (!(so = pa_idxset_get_by_index(c->source_outputs, idx)))
            return;

        if (!so->client || !(name = client_name(so->client)))
            return;
    }

    if ((r = pa_hashmap_get(u->hashmap, name))) {
        pa_xfree(name);

        if (si) {

            if (!r->volume_is_set || !pa_cvolume_equal(pa_sink_input_get_volume(si), &r->volume)) {
                pa_log_info("Saving volume for <%s>", r->name);
                r->volume = *pa_sink_input_get_volume(si);
                r->volume_is_set = TRUE;
                u->modified = TRUE;
            }

            if (!r->sink || strcmp(si->sink->name, r->sink) != 0) {
                pa_log_info("Saving sink for <%s>", r->name);
                pa_xfree(r->sink);
                r->sink = pa_xstrdup(si->sink->name);
                u->modified = TRUE;
            }
        } else {
            pa_assert(so);

            if (!r->source || strcmp(so->source->name, r->source) != 0) {
                pa_log_info("Saving source for <%s>", r->name);
                pa_xfree(r->source);
                r->source = pa_xstrdup(so->source->name);
                u->modified = TRUE;
            }
        }

    } else {
        pa_log_info("Creating new entry for <%s>", name);

        r = pa_xnew(struct rule, 1);
        r->name = name;

        if (si) {
            r->volume = *pa_sink_input_get_volume(si);
            r->volume_is_set = TRUE;
            r->sink = pa_xstrdup(si->sink->name);
            r->source = NULL;
        } else {
            pa_assert(so);
            r->volume_is_set = FALSE;
            r->sink = NULL;
            r->source = pa_xstrdup(so->source->name);
        }

        pa_hashmap_put(u->hashmap, r->name, r);
        u->modified = TRUE;
    }

    if (u->modified && !u->save_time_event) {
        struct timeval tv;
        pa_gettimeofday(&tv);
        tv.tv_sec += SAVE_INTERVAL;
        u->save_time_event = u->core->mainloop->time_new(u->core->mainloop, &tv, save_time_callback, u);
    }
}