+++ /dev/null
-/*
- * This file is a part of MAFW
- *
- * Copyright (C) 2007, 2008, 2009 Nokia Corporation, all rights reserved.
- *
- * Contact: Visa Smolander <visa.smolander@nokia.com>
- *
- * This library 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; version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifndef MAFW_GST_RENDERER_DISABLE_PULSE_VOLUME
-
-#include <pulse/pulseaudio.h>
-#include <pulse/glib-mainloop.h>
-#include <pulse/ext-stream-restore.h>
-#include <string.h>
-
-#include "mafw-gst-renderer-worker-volume.h"
-#include "config.h"
-
-#undef G_LOG_DOMAIN
-#define G_LOG_DOMAIN "mafw-gst-renderer-worker-volume"
-
-#define MAFW_GST_RENDERER_WORKER_VOLUME_SERVER NULL
-
-#define MAFW_GST_RENDERER_WORKER_VOLUME_ROLE_PROPERTY "PULSE_PROP_media.role"
-#define MAFW_GST_RENDERER_WORKER_VOLUME_ROLE_PREFIX "sink-input-by-media-role:"
-#define MAFW_GST_RENDERER_WORKER_VOLUME_ROLE "x-maemo"
-
-#define MAFW_GST_RENDERER_WORKER_SET_TIMEOUT 200
-
-
-struct _MafwGstRendererWorkerVolume {
- pa_glib_mainloop *mainloop;
- pa_context *context;
- gdouble pulse_volume;
- gboolean pulse_mute;
- MafwGstRendererWorkerVolumeChangedCb cb;
- gpointer user_data;
- MafwGstRendererWorkerVolumeMuteCb mute_cb;
- gpointer mute_user_data;
- gdouble current_volume;
- gboolean current_mute;
- gboolean pending_operation;
- gdouble pending_operation_volume;
- gboolean pending_operation_mute;
- guint change_request_id;
- pa_operation *pa_operation;
-};
-
-typedef struct {
- MafwGstRendererWorkerVolume *wvolume;
- MafwGstRendererWorkerVolumeInitCb cb;
- gpointer user_data;
-} InitCbClosure;
-
-#define _pa_volume_to_per_one(volume) \
- ((guint) ((((gdouble)(volume) / (gdouble) PA_VOLUME_NORM) + \
- (gdouble) 0.005) * (gdouble) 100.0) / (gdouble) 100.0)
-#define _pa_volume_from_per_one(volume) \
- ((pa_volume_t)((gdouble)(volume) * (gdouble) PA_VOLUME_NORM))
-
-#define _pa_operation_running(wvolume) \
- (wvolume->pa_operation != NULL && \
- pa_operation_get_state(wvolume->pa_operation) == PA_OPERATION_RUNNING)
-
-static void _state_cb_init(pa_context *c, void *data);
-
-
-static gchar *_get_client_name(void) {
- gchar buf[PATH_MAX];
- gchar *name = NULL;
-
- if (pa_get_binary_name(buf, sizeof(buf)))
- name = g_strdup_printf("mafw-gst-renderer[%s]", buf);
- else
- name = g_strdup("mafw-gst-renderer");
-
- return name;
-}
-
-static void _ext_stream_restore_read_cb(pa_context *c,
- const pa_ext_stream_restore2_info *i,
- int eol,
- void *userdata)
-{
- MafwGstRendererWorkerVolume *wvolume = userdata;
- gdouble volume;
- gboolean mute;
-
- if (eol < 0) {
- g_critical("eol parameter should not be < 1. "
- "Discarding volume event");
- return;
- }
-
- if (i == NULL ||
- strcmp(i->name, MAFW_GST_RENDERER_WORKER_VOLUME_ROLE_PREFIX
- MAFW_GST_RENDERER_WORKER_VOLUME_ROLE) != 0) {
- return;
- }
-
- volume = _pa_volume_to_per_one(pa_cvolume_max(&i->volume));
- mute = i->mute != 0 ? TRUE : FALSE;
-
- if (_pa_operation_running(wvolume) ||
- (wvolume->pending_operation &&
- (wvolume->pending_operation_volume != volume
-#ifdef MAFW_GST_RENDERER_ENABLE_MUTE
- || wvolume->pending_operation_mute != mute
-#endif
- ))) {
- g_debug("volume notification, but operation running, ignoring");
- return;
- }
-
- wvolume->pulse_volume = volume;
- wvolume->pulse_mute = mute;
-
- /* EMIT VOLUME */
- g_debug("ext stream volume is %lf (mute: %d) for role %s in device %s",
- wvolume->pulse_volume, wvolume->pulse_mute, i->name, i->device);
- if (!wvolume->pending_operation &&
- wvolume->pulse_volume != wvolume->current_volume) {
- wvolume->current_volume = wvolume->pulse_volume;
- if (wvolume->cb != NULL) {
- g_debug("signalling volume");
- wvolume->cb(wvolume, wvolume->current_volume,
- wvolume->user_data);
- }
- }
-#ifdef MAFW_GST_RENDERER_ENABLE_MUTE
- if (!wvolume->pending_operation &&
- wvolume->pulse_mute != wvolume->current_mute) {
- wvolume->current_mute = wvolume->pulse_mute;
- if (wvolume->mute_cb != NULL) {
- g_debug("signalling mute");
- wvolume->mute_cb(wvolume, wvolume->current_mute,
- wvolume->mute_user_data);
- }
- }
-#endif
-
- wvolume->pending_operation = FALSE;
-}
-
-static void _destroy_context(MafwGstRendererWorkerVolume *wvolume)
-{
- if (wvolume->pa_operation != NULL) {
- if (pa_operation_get_state(wvolume->pa_operation) ==
- PA_OPERATION_RUNNING) {
- pa_operation_cancel(wvolume->pa_operation);
- }
- pa_operation_unref(wvolume->pa_operation);
- wvolume->pa_operation = NULL;
- }
- pa_context_unref(wvolume->context);
-}
-
-static InitCbClosure *_init_cb_closure_new(MafwGstRendererWorkerVolume *wvolume,
- MafwGstRendererWorkerVolumeInitCb cb,
- gpointer user_data)
-{
- InitCbClosure *closure;
-
- closure = g_new(InitCbClosure, 1);
- closure->wvolume = wvolume;
- closure->cb = cb;
- closure->user_data = user_data;
-
- return closure;
-}
-
-static void _connect(gpointer user_data)
-{
- gchar *name = NULL;
- pa_mainloop_api *api = NULL;
- InitCbClosure *closure = user_data;
- MafwGstRendererWorkerVolume *wvolume = closure->wvolume;
-
- name = _get_client_name();
-
- /* get the mainloop api and create a context */
- api = pa_glib_mainloop_get_api(wvolume->mainloop);
- wvolume->context = pa_context_new(api, name);
- g_assert(wvolume->context != NULL);
-
- /* register some essential callbacks */
- pa_context_set_state_callback(wvolume->context, _state_cb_init,
- closure);
-
- g_debug("connecting to pulse");
-
- g_assert(pa_context_connect(wvolume->context,
- MAFW_GST_RENDERER_WORKER_VOLUME_SERVER,
- PA_CONTEXT_NOAUTOSPAWN | PA_CONTEXT_NOFAIL,
- NULL) >= 0);
- g_free(name);
-}
-
-static gboolean _reconnect(gpointer user_data)
-{
- InitCbClosure *closure = user_data;
- MafwGstRendererWorkerVolume *wvolume = closure->wvolume;
-
- g_warning("got disconnected from pulse, reconnecting");
- _destroy_context(wvolume);
- _connect(user_data);
-
- return FALSE;
-}
-
-static void
-_state_cb(pa_context *c, void *data)
-{
- MafwGstRendererWorkerVolume *wvolume = data;
- pa_context_state_t state;
-
- state = pa_context_get_state(c);
-
- switch (state) {
- case PA_CONTEXT_TERMINATED:
- case PA_CONTEXT_FAILED:
- {
- InitCbClosure *closure;
-
- closure = _init_cb_closure_new(wvolume, NULL, NULL);
- g_idle_add(_reconnect, closure);
- break;
- }
- case PA_CONTEXT_READY: {
- pa_operation *o;
-
- o = pa_ext_stream_restore2_read(c, _ext_stream_restore_read_cb,
- wvolume);
- g_assert(o != NULL);
- pa_operation_unref(o);
-
- break;
- }
- default:
- break;
- }
-}
-
-static void _ext_stream_restore_read_cb_init(pa_context *c,
- const pa_ext_stream_restore2_info *i,
- int eol,
- void *userdata)
-{
- InitCbClosure *closure = userdata;
-
- if (eol < 0) {
- g_critical("eol parameter should not be < 1");
- }
-
- if (i == NULL ||
- strcmp(i->name, MAFW_GST_RENDERER_WORKER_VOLUME_ROLE_PREFIX
- MAFW_GST_RENDERER_WORKER_VOLUME_ROLE) != 0)
- return;
-
- closure->wvolume->pulse_volume =
- _pa_volume_to_per_one(pa_cvolume_max(&i->volume));
- closure->wvolume->pulse_mute = i->mute != 0 ? TRUE : FALSE;
- closure->wvolume->current_volume = closure->wvolume->pulse_volume;
- closure->wvolume->current_mute = closure->wvolume->pulse_mute;
-
- /* NOT EMIT VOLUME, BUT DEBUG */
- g_debug("ext stream volume is %lf (mute: %d) for role %s in device %s",
- closure->wvolume->pulse_volume, i->mute, i->name, i->device);
-
- if (closure->cb != NULL) {
- g_debug("initialized: returning volume manager");
- closure->cb(closure->wvolume, closure->user_data);
- } else {
- if (closure->wvolume->cb != NULL) {
- g_debug("signalling volume after reconnection");
- closure->wvolume->cb(closure->wvolume,
- closure->wvolume->current_volume,
- closure->wvolume->user_data);
- }
- if (closure->wvolume->mute_cb != NULL) {
- g_debug("signalling mute after reconnection");
- closure->wvolume->mute_cb(closure->wvolume,
- closure->wvolume->
- current_mute,
- closure->wvolume->
- mute_user_data);
- }
- }
-
- pa_context_set_state_callback(closure->wvolume->context, _state_cb,
- closure->wvolume);
-
- g_free(closure);
-}
-
-static void _ext_stream_restore_subscribe_cb(pa_context *c, void *userdata)
-{
- pa_operation *o;
-
- o = pa_ext_stream_restore2_read(c, _ext_stream_restore_read_cb, userdata);
- g_assert(o != NULL);
- pa_operation_unref(o);
-}
-
-static void
-_state_cb_init(pa_context *c, void *data)
-{
- InitCbClosure *closure = data;
- MafwGstRendererWorkerVolume *wvolume = closure->wvolume;
- pa_context_state_t state;
-
- state = pa_context_get_state(c);
-
- g_debug("state: %d", state);
-
- switch (state) {
- case PA_CONTEXT_TERMINATED:
- case PA_CONTEXT_FAILED:
- g_critical("Connection to pulse failed, reconnection in 1 "
- "second");
- g_timeout_add_seconds(1, _reconnect, closure);
- break;
- case PA_CONTEXT_READY: {
- pa_operation *o;
-
- g_debug("PA_CONTEXT_READY");
-
- o = pa_ext_stream_restore2_read(c,
- _ext_stream_restore_read_cb_init,
- closure);
- g_assert(o != NULL);
- pa_operation_unref(o);
-
- pa_ext_stream_restore_set_subscribe_cb(
- c, _ext_stream_restore_subscribe_cb, wvolume);
-
- o = pa_ext_stream_restore_subscribe(c, 1, NULL, NULL);
- g_assert(o != NULL);
- pa_operation_unref(o);
-
- break;
- }
- default:
- break;
- }
-}
-
-static gboolean _destroy_idle(gpointer data)
-{
- MafwGstRendererWorkerVolume *wvolume = data;
-
- g_debug("destroying");
-
- _destroy_context(wvolume);
- pa_glib_mainloop_free(wvolume->mainloop);
- g_free(wvolume);
-
- return FALSE;
-}
-
-static void
-_state_cb_destroy(pa_context *c, void *data)
-{
- pa_context_state_t state;
-
- state = pa_context_get_state(c);
-
- switch (state) {
- case PA_CONTEXT_TERMINATED:
- g_idle_add(_destroy_idle, data);
- break;
- case PA_CONTEXT_FAILED:
- g_error("Unexpected problem in volume management");
- break;
- default:
- break;
- }
-}
-
-static void _success_cb(pa_context *c, int success, void *userdata)
-{
- if (success == 0) {
- g_critical("Setting volume to pulse operation failed");
- }
-}
-
-static void _remove_set_timeout(MafwGstRendererWorkerVolume *wvolume)
-{
- if (wvolume->change_request_id != 0) {
- g_source_remove(wvolume->change_request_id);
- }
- wvolume->change_request_id = 0;
-}
-
-static gboolean _set_timeout(gpointer data)
-{
- pa_ext_stream_restore2_info info;
- pa_ext_stream_restore2_info *infos[1];
- MafwGstRendererWorkerVolume *wvolume = data;
-
- if (wvolume->pending_operation) {
- g_debug("setting volume ignored as there is still a pending "
- "operation. Waiting till next iteration");
- } else if (wvolume->pulse_volume != wvolume->current_volume
-#ifdef MAFW_GST_RENDERER_ENABLE_MUTE
- || wvolume->pulse_mute != wvolume->current_mute
-#endif
- ) {
-
- info.name = MAFW_GST_RENDERER_WORKER_VOLUME_ROLE_PREFIX
- MAFW_GST_RENDERER_WORKER_VOLUME_ROLE;
- info.channel_map.channels = 1;
- info.channel_map.map[0] = PA_CHANNEL_POSITION_MONO;
- info.device = NULL;
- info.volume_is_absolute = TRUE;
- infos[0] = &info;
-
- info.mute = wvolume->current_mute;
- pa_cvolume_init(&info.volume);
- pa_cvolume_set(&info.volume, info.channel_map.channels,
- _pa_volume_from_per_one(wvolume->
- current_volume));
-
- g_debug("setting volume to %lf and mute to %d",
- wvolume->current_volume, wvolume->current_mute);
-
- if (wvolume->pa_operation != NULL) {
- pa_operation_unref(wvolume->pa_operation);
- }
-
- wvolume->pending_operation = TRUE;
- wvolume->pending_operation_volume = wvolume->current_volume;
- wvolume->pending_operation_mute = wvolume->current_mute;
-
- wvolume->pa_operation = pa_ext_stream_restore2_write(
- wvolume->context,
- PA_UPDATE_REPLACE,
- (const pa_ext_stream_restore2_info*
- const *)infos,
- 1, TRUE, _success_cb, wvolume);
-
- if (wvolume->pa_operation == NULL) {
- g_critical("NULL operation when writing volume to "
- "pulse");
- _remove_set_timeout(wvolume);
- }
- } else {
- g_debug("removing volume timeout");
- _remove_set_timeout(wvolume);
- }
-
- return wvolume->change_request_id != 0;
-}
-
-void mafw_gst_renderer_worker_volume_init(GMainContext *main_context,
- MafwGstRendererWorkerVolumeInitCb cb,
- gpointer user_data,
- MafwGstRendererWorkerVolumeChangedCb
- changed_cb,
- gpointer changed_user_data,
- MafwGstRendererWorkerVolumeMuteCb
- mute_cb, gpointer mute_user_data)
-{
- MafwGstRendererWorkerVolume *wvolume = NULL;
- InitCbClosure *closure;
-
- g_return_if_fail(cb != NULL);
-
- g_assert(g_setenv(MAFW_GST_RENDERER_WORKER_VOLUME_ROLE_PROPERTY,
- MAFW_GST_RENDERER_WORKER_VOLUME_ROLE, FALSE));
-
- g_debug("initializing volume manager");
-
- wvolume = g_new0(MafwGstRendererWorkerVolume, 1);
-
- wvolume->pulse_volume = 1.0;
- wvolume->pulse_mute = FALSE;
- wvolume->cb = changed_cb;
- wvolume->user_data = changed_user_data;
- wvolume->mute_cb = mute_cb;
- wvolume->mute_user_data = mute_user_data;
-
- wvolume->mainloop = pa_glib_mainloop_new(main_context);
- g_assert(wvolume->mainloop != NULL);
-
- closure = _init_cb_closure_new(wvolume, cb, user_data);
- _connect(closure);
-}
-
-void mafw_gst_renderer_worker_volume_set(MafwGstRendererWorkerVolume *wvolume,
- gdouble volume, gboolean mute)
-{
- gboolean signal_volume, signal_mute;
-
- g_return_if_fail(wvolume != NULL);
- g_return_if_fail(pa_context_get_state(wvolume->context) ==
- PA_CONTEXT_READY);
-
-#ifndef MAFW_GST_RENDERER_ENABLE_MUTE
- mute = FALSE;
-#endif
-
- signal_volume = wvolume->current_volume != volume &&
- wvolume->cb != NULL;
- signal_mute = wvolume->current_mute != mute && wvolume->mute_cb != NULL;
-
- wvolume->current_volume = volume;
- wvolume->current_mute = mute;
-
- g_debug("volume set: %lf (mute %d)", volume, mute);
-
- if (signal_volume) {
- g_debug("signalling volume");
- wvolume->cb(wvolume, volume, wvolume->user_data);
- }
-
- if (signal_mute) {
- g_debug("signalling mute");
- wvolume->mute_cb(wvolume, mute, wvolume->mute_user_data);
- }
-
- if ((signal_mute || signal_volume) && wvolume->change_request_id == 0) {
- wvolume->change_request_id =
- g_timeout_add(MAFW_GST_RENDERER_WORKER_SET_TIMEOUT,
- _set_timeout, wvolume);
-
- _set_timeout(wvolume);
- }
-}
-
-gdouble mafw_gst_renderer_worker_volume_get(
- MafwGstRendererWorkerVolume *wvolume)
-{
- g_return_val_if_fail(wvolume != NULL, 0.0);
-
- g_debug("getting volume; %lf", wvolume->current_volume);
-
- return wvolume->current_volume;
-}
-
-gboolean mafw_gst_renderer_worker_volume_is_muted(
- MafwGstRendererWorkerVolume *wvolume)
-{
- g_return_val_if_fail(wvolume != NULL, FALSE);
-
- g_debug("getting mute; %d", wvolume->current_mute);
-
- return wvolume->current_mute;
-}
-
-void mafw_gst_renderer_worker_volume_destroy(
- MafwGstRendererWorkerVolume *wvolume)
-{
- g_return_if_fail(wvolume != NULL);
-
- g_debug("disconnecting");
-
- pa_ext_stream_restore_set_subscribe_cb(wvolume->context, NULL, NULL);
- pa_context_set_state_callback(wvolume->context, _state_cb_destroy,
- wvolume);
- pa_context_disconnect(wvolume->context);
-}
-
-
-
-#else
-
-
-#include "mafw-gst-renderer-worker-volume.h"
-
-#undef G_LOG_DOMAIN
-#define G_LOG_DOMAIN "mafw-gst-renderer-worker-volume-fake"
-
-struct _MafwGstRendererWorkerVolume {
- MafwGstRendererWorkerVolumeChangedCb cb;
- gpointer user_data;
- MafwGstRendererWorkerVolumeMuteCb mute_cb;
- gpointer mute_user_data;
- gdouble current_volume;
- gboolean current_mute;
-};
-
-typedef struct {
- MafwGstRendererWorkerVolume *wvolume;
- MafwGstRendererWorkerVolumeInitCb cb;
- gpointer user_data;
-} InitCbClosure;
-
-static gboolean _init_cb_closure(gpointer user_data)
-{
- InitCbClosure *closure = user_data;
-
- if (closure->cb != NULL) {
- closure->cb(closure->wvolume, closure->user_data);
- }
- g_free(closure);
-
- return FALSE;
-}
-
-void mafw_gst_renderer_worker_volume_init(GMainContext *main_context,
- MafwGstRendererWorkerVolumeInitCb cb,
- gpointer user_data,
- MafwGstRendererWorkerVolumeChangedCb
- changed_cb,
- gpointer changed_user_data,
- MafwGstRendererWorkerVolumeMuteCb
- mute_cb, gpointer mute_user_data)
-{
- MafwGstRendererWorkerVolume *wvolume = NULL;
- InitCbClosure *closure;
-
- g_return_if_fail(cb != NULL);
-
- g_debug("initializing volume manager");
-
- wvolume = g_new0(MafwGstRendererWorkerVolume, 1);
-
- wvolume->cb = changed_cb;
- wvolume->user_data = changed_user_data;
- wvolume->mute_cb = mute_cb;
- wvolume->mute_user_data = mute_user_data;
- wvolume->current_volume = 0.485;
-
- closure = g_new0(InitCbClosure, 1);
- closure->wvolume = wvolume;
- closure->cb = cb;
- closure->user_data = user_data;
- g_idle_add(_init_cb_closure, closure);
-}
-
-void mafw_gst_renderer_worker_volume_set(MafwGstRendererWorkerVolume *wvolume,
- gdouble volume, gboolean mute)
-{
- gboolean signal_volume, signal_mute;
-
- g_return_if_fail(wvolume != NULL);
-
-#ifndef MAFW_GST_RENDERER_ENABLE_MUTE
- mute = FALSE;
-#endif
-
- signal_volume = wvolume->current_volume != volume &&
- wvolume->cb != NULL;
- signal_mute = wvolume->current_mute != mute && wvolume->mute_cb != NULL;
-
- wvolume->current_volume = volume;
- wvolume->current_mute = mute;
-
- g_debug("volume set: %lf (mute %d)", volume, mute);
-
- if (signal_volume) {
- g_debug("signalling volume");
- wvolume->cb(wvolume, volume, wvolume->user_data);
- }
-
- if (signal_mute) {
- g_debug("signalling mute");
- wvolume->mute_cb(wvolume, mute, wvolume->mute_user_data);
- }
-}
-
-gdouble mafw_gst_renderer_worker_volume_get(
- MafwGstRendererWorkerVolume *wvolume)
-{
- g_return_val_if_fail(wvolume != NULL, 0.0);
-
- g_debug("getting volume; %lf", wvolume->current_volume);
-
- return wvolume->current_volume;
-}
-
-gboolean mafw_gst_renderer_worker_volume_is_muted(
- MafwGstRendererWorkerVolume *wvolume)
-{
- g_return_val_if_fail(wvolume != NULL, FALSE);
-
- g_debug("getting mute; %d", wvolume->current_mute);
-
- return wvolume->current_mute;
-}
-
-void mafw_gst_renderer_worker_volume_destroy(
- MafwGstRendererWorkerVolume *wvolume)
-{
- g_return_if_fail(wvolume != NULL);
-
- g_free(wvolume);
-}
-
-#endif