/* * Copyright (C) 2014 Michal Ratajsky * * 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; either * version 2 of the licence, 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, see . */ #include #include #include #include #include #include #include #include #include "pulse-connection.h" #include "pulse-client-stream.h" #include "pulse-ext-stream.h" #include "pulse-helpers.h" #include "pulse-stream.h" static void pulse_ext_stream_class_init (PulseExtStreamClass *klass); static void pulse_ext_stream_init (PulseExtStream *ext); G_DEFINE_TYPE (PulseExtStream, pulse_ext_stream, PULSE_TYPE_CLIENT_STREAM); static void pulse_ext_stream_reload (PulseStream *pstream); static gboolean pulse_ext_stream_set_mute (PulseStream *pstream, gboolean mute); static gboolean pulse_ext_stream_set_volume (PulseStream *pstream, pa_cvolume *cvolume); static gboolean pulse_ext_stream_set_parent (PulseClientStream *pclient, PulseStream *parent); static gboolean pulse_ext_stream_remove (PulseClientStream *pclient); static void pulse_ext_stream_class_init (PulseExtStreamClass *klass) { PulseStreamClass *stream_class; PulseClientStreamClass *client_class; stream_class = PULSE_STREAM_CLASS (klass); stream_class->reload = pulse_ext_stream_reload; stream_class->set_mute = pulse_ext_stream_set_mute; stream_class->set_volume = pulse_ext_stream_set_volume; client_class = PULSE_CLIENT_STREAM_CLASS (klass); client_class->set_parent = pulse_ext_stream_set_parent; client_class->remove = pulse_ext_stream_remove; } static void pulse_ext_stream_init (PulseExtStream *ext) { } PulseStream * pulse_ext_stream_new (PulseConnection *connection, const pa_ext_stream_restore_info *info, PulseStream *parent) { PulseStream *ext; g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL); g_return_val_if_fail (info != NULL, NULL); ext = g_object_new (PULSE_TYPE_EXT_STREAM, "connection", connection, NULL); /* Consider the stream name as unchanging parameter */ pulse_stream_update_name (ext, info->name); /* Other data may change at any time, so let's make a use of our update function */ pulse_ext_stream_update (ext, info, parent); return ext; } gboolean pulse_ext_stream_update (PulseStream *pstream, const pa_ext_stream_restore_info *info, PulseStream *parent) { MateMixerClientStreamRole role = MATE_MIXER_CLIENT_STREAM_ROLE_NONE; MateMixerStreamFlags flags = MATE_MIXER_STREAM_CLIENT | MATE_MIXER_STREAM_HAS_VOLUME | MATE_MIXER_STREAM_HAS_MUTE | MATE_MIXER_STREAM_CAN_SET_VOLUME; MateMixerClientStreamFlags client_flags = MATE_MIXER_CLIENT_STREAM_CACHED; PulseClientStream *pclient; gchar *suffix; g_return_val_if_fail (PULSE_IS_EXT_STREAM (pstream), FALSE); g_return_val_if_fail (info != NULL, FALSE); pclient = PULSE_CLIENT_STREAM (pstream); suffix = strchr (info->name, ':'); if (suffix != NULL) suffix++; /* Let all the information update before emitting notify signals */ g_object_freeze_notify (G_OBJECT (pstream)); if (g_str_has_prefix (info->name, "sink-input")) flags |= MATE_MIXER_STREAM_OUTPUT; else if (g_str_has_prefix (info->name, "source-output")) flags |= MATE_MIXER_STREAM_INPUT; else g_debug ("Unknown ext-stream %s", info->name); if (strstr (info->name, "-by-media-role:")) { if (G_LIKELY (suffix != NULL)) role = pulse_convert_media_role_name (suffix); } else if (strstr (info->name, "-by-application-name:")) { client_flags |= MATE_MIXER_CLIENT_STREAM_APPLICATION; if (G_LIKELY (suffix != NULL)) pulse_client_stream_update_app_name (pclient, suffix); } else if (strstr (info->name, "-by-application-id:")) { client_flags |= MATE_MIXER_CLIENT_STREAM_APPLICATION; if (G_LIKELY (suffix != NULL)) pulse_client_stream_update_app_id (pclient, suffix); } /* Flags needed before volume */ pulse_stream_update_flags (pstream, flags); pulse_stream_update_channel_map (pstream, &info->channel_map); pulse_stream_update_volume (pstream, &info->volume, 0); pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE); pulse_client_stream_update_flags (pclient, client_flags); pulse_client_stream_update_role (pclient, role); if (parent != NULL) pulse_client_stream_update_parent (pclient, MATE_MIXER_STREAM (parent)); else pulse_client_stream_update_parent (pclient, NULL); g_object_thaw_notify (G_OBJECT (pstream)); return TRUE; } static void pulse_ext_stream_reload (PulseStream *pstream) { g_return_if_fail (PULSE_IS_EXT_STREAM (pstream)); pulse_connection_load_ext_stream_info (pulse_stream_get_connection (pstream)); } static gboolean pulse_ext_stream_set_mute (PulseStream *pstream, gboolean mute) { MateMixerStream *parent; const pa_channel_map *map; const pa_cvolume *cvolume; pa_ext_stream_restore_info info; g_return_val_if_fail (PULSE_IS_EXT_STREAM (pstream), FALSE); info.name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)); info.mute = mute; map = pulse_stream_get_channel_map (pstream); info.channel_map = *map; cvolume = pulse_stream_get_cvolume (pstream); info.volume = *cvolume; parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (pstream)); if (parent != NULL) info.device = mate_mixer_stream_get_name (parent); else info.device = NULL; return pulse_connection_write_ext_stream (pulse_stream_get_connection (pstream), &info); } static gboolean pulse_ext_stream_set_volume (PulseStream *pstream, pa_cvolume *cvolume) { MateMixerStream *parent; const pa_channel_map *map; pa_ext_stream_restore_info info; g_return_val_if_fail (PULSE_IS_EXT_STREAM (pstream), FALSE); g_return_val_if_fail (cvolume != NULL, FALSE); info.name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)); info.mute = mate_mixer_stream_get_mute (MATE_MIXER_STREAM (pstream)); map = pulse_stream_get_channel_map (pstream); info.channel_map = *map; parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (pstream)); if (parent != NULL) info.device = mate_mixer_stream_get_name (parent); else info.device = NULL; info.volume = *cvolume; return pulse_connection_write_ext_stream (pulse_stream_get_connection (pstream), &info); } static gboolean pulse_ext_stream_set_parent (PulseClientStream *pclient, PulseStream *parent) { PulseStream *pstream; const pa_channel_map *map; const pa_cvolume *cvolume; pa_ext_stream_restore_info info; g_return_val_if_fail (PULSE_IS_EXT_STREAM (pclient), FALSE); g_return_val_if_fail (PULSE_IS_STREAM (parent), FALSE); pstream = PULSE_STREAM (pclient); info.name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)); info.mute = mate_mixer_stream_get_mute (MATE_MIXER_STREAM (pstream)); map = pulse_stream_get_channel_map (pstream); info.channel_map = *map; cvolume = pulse_stream_get_cvolume (pstream); info.volume = *cvolume; info.device = mate_mixer_stream_get_name (MATE_MIXER_STREAM (parent)); return pulse_connection_write_ext_stream (pulse_stream_get_connection (pstream), &info); } static gboolean pulse_ext_stream_remove (PulseClientStream *pclient) { PulseStream *pstream; const gchar *name; g_return_val_if_fail (PULSE_IS_EXT_STREAM (pclient), FALSE); pstream = PULSE_STREAM (pclient); name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)); return pulse_connection_delete_ext_stream (pulse_stream_get_connection (pstream), name); }