summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ABOUT-NLS1327
-rw-r--r--AUTHORS1
-rw-r--r--Makefile.am5
-rw-r--r--NEWS5
-rwxr-xr-xautogen.sh1
-rw-r--r--backends/alsa/Makefile.am1
-rw-r--r--backends/alsa/alsa-backend.c333
-rw-r--r--backends/alsa/alsa-constants.c189
-rw-r--r--backends/alsa/alsa-constants.h21
-rw-r--r--backends/alsa/alsa-device.c690
-rw-r--r--backends/alsa/alsa-device.h4
-rw-r--r--backends/alsa/alsa-element.c16
-rw-r--r--backends/alsa/alsa-element.h3
-rw-r--r--backends/alsa/alsa-stream-control.c110
-rw-r--r--backends/alsa/alsa-stream-control.h6
-rw-r--r--backends/alsa/alsa-stream-input-control.c12
-rw-r--r--backends/alsa/alsa-stream-input-control.h4
-rw-r--r--backends/alsa/alsa-stream-output-control.c12
-rw-r--r--backends/alsa/alsa-stream-output-control.h4
-rw-r--r--backends/alsa/alsa-stream.c335
-rw-r--r--backends/alsa/alsa-stream.h41
-rw-r--r--backends/alsa/alsa-switch-option.c3
-rw-r--r--backends/alsa/alsa-switch-option.h12
-rw-r--r--backends/alsa/alsa-switch.c47
-rw-r--r--backends/alsa/alsa-switch.h7
-rw-r--r--backends/alsa/alsa-toggle.c37
-rw-r--r--backends/alsa/alsa-toggle.h11
-rw-r--r--backends/null/Makefile.am1
-rw-r--r--backends/null/null-backend.c3
-rw-r--r--backends/oss/Makefile.am8
-rw-r--r--backends/oss/oss-backend.c367
-rw-r--r--backends/oss/oss-backend.h8
-rw-r--r--backends/oss/oss-device.c665
-rw-r--r--backends/oss/oss-device.h12
-rw-r--r--backends/oss/oss-stream-control.c200
-rw-r--r--backends/oss/oss-stream-control.h23
-rw-r--r--backends/oss/oss-stream.c251
-rw-r--r--backends/oss/oss-stream.h32
-rw-r--r--backends/oss/oss-switch-option.c72
-rw-r--r--backends/oss/oss-switch-option.h69
-rw-r--r--backends/oss/oss-switch.c203
-rw-r--r--backends/oss/oss-switch.h70
-rw-r--r--backends/oss/oss-types.h32
-rw-r--r--backends/pulse/Makefile.am24
-rw-r--r--backends/pulse/pulse-backend.c1078
-rw-r--r--backends/pulse/pulse-backend.h9
-rw-r--r--backends/pulse/pulse-client-stream.c433
-rw-r--r--backends/pulse/pulse-client-stream.h94
-rw-r--r--backends/pulse/pulse-connection.c39
-rw-r--r--backends/pulse/pulse-connection.h5
-rw-r--r--backends/pulse/pulse-device-profile.c88
-rw-r--r--backends/pulse/pulse-device-profile.h69
-rw-r--r--backends/pulse/pulse-device-switch.c261
-rw-r--r--backends/pulse/pulse-device-switch.h77
-rw-r--r--backends/pulse/pulse-device.c575
-rw-r--r--backends/pulse/pulse-device.h33
-rw-r--r--backends/pulse/pulse-ext-stream.c374
-rw-r--r--backends/pulse/pulse-ext-stream.h30
-rw-r--r--backends/pulse/pulse-helpers.c27
-rw-r--r--backends/pulse/pulse-helpers.h9
-rw-r--r--backends/pulse/pulse-monitor.c52
-rw-r--r--backends/pulse/pulse-monitor.h10
-rw-r--r--backends/pulse/pulse-port-switch.c241
-rw-r--r--backends/pulse/pulse-port-switch.h77
-rw-r--r--backends/pulse/pulse-port.c89
-rw-r--r--backends/pulse/pulse-port.h70
-rw-r--r--backends/pulse/pulse-sink-control.c161
-rw-r--r--backends/pulse/pulse-sink-control.h67
-rw-r--r--backends/pulse/pulse-sink-input.c321
-rw-r--r--backends/pulse/pulse-sink-input.h22
-rw-r--r--backends/pulse/pulse-sink-switch.c76
-rw-r--r--backends/pulse/pulse-sink-switch.h62
-rw-r--r--backends/pulse/pulse-sink.c382
-rw-r--r--backends/pulse/pulse-sink.h24
-rw-r--r--backends/pulse/pulse-source-control.c154
-rw-r--r--backends/pulse/pulse-source-control.h67
-rw-r--r--backends/pulse/pulse-source-output.c306
-rw-r--r--backends/pulse/pulse-source-output.h37
-rw-r--r--backends/pulse/pulse-source-switch.c76
-rw-r--r--backends/pulse/pulse-source-switch.h62
-rw-r--r--backends/pulse/pulse-source.c339
-rw-r--r--backends/pulse/pulse-source.h27
-rw-r--r--backends/pulse/pulse-stream-control.c744
-rw-r--r--backends/pulse/pulse-stream-control.h94
-rw-r--r--backends/pulse/pulse-stream.c1225
-rw-r--r--backends/pulse/pulse-stream.h64
-rw-r--r--backends/pulse/pulse-types.h45
-rw-r--r--configure.ac15
-rw-r--r--examples/monitor.c173
-rw-r--r--libmatemixer/Makefile.am14
-rw-r--r--libmatemixer/matemixer-app-info-private.h51
-rw-r--r--libmatemixer/matemixer-app-info.c142
-rw-r--r--libmatemixer/matemixer-app-info.h (renamed from libmatemixer/matemixer-backend-private.h)24
-rw-r--r--libmatemixer/matemixer-backend-module.c1
-rw-r--r--libmatemixer/matemixer-backend-module.h2
-rw-r--r--libmatemixer/matemixer-backend.c359
-rw-r--r--libmatemixer/matemixer-backend.h113
-rw-r--r--libmatemixer/matemixer-client-stream.c373
-rw-r--r--libmatemixer/matemixer-client-stream.h91
-rw-r--r--libmatemixer/matemixer-context.c216
-rw-r--r--libmatemixer/matemixer-context.h112
-rw-r--r--libmatemixer/matemixer-device-profile-private.h44
-rw-r--r--libmatemixer/matemixer-device-profile.c370
-rw-r--r--libmatemixer/matemixer-device-profile.h67
-rw-r--r--libmatemixer/matemixer-device.c182
-rw-r--r--libmatemixer/matemixer-device.h76
-rw-r--r--libmatemixer/matemixer-enum-types.c127
-rw-r--r--libmatemixer/matemixer-enum-types.h24
-rw-r--r--libmatemixer/matemixer-enums.h145
-rw-r--r--libmatemixer/matemixer-private.h13
-rw-r--r--libmatemixer/matemixer-stored-control.c52
-rw-r--r--libmatemixer/matemixer-stored-control.h59
-rw-r--r--libmatemixer/matemixer-stream-control-private.h4
-rw-r--r--libmatemixer/matemixer-stream-control.c436
-rw-r--r--libmatemixer/matemixer-stream-control.h193
-rw-r--r--libmatemixer/matemixer-stream-private.h32
-rw-r--r--libmatemixer/matemixer-stream.c311
-rw-r--r--libmatemixer/matemixer-stream.h55
-rw-r--r--libmatemixer/matemixer-switch-option-private.h2
-rw-r--r--libmatemixer/matemixer-switch-option.c2
-rw-r--r--libmatemixer/matemixer-switch-option.h12
-rw-r--r--libmatemixer/matemixer-switch-private.h1
-rw-r--r--libmatemixer/matemixer-switch.c144
-rw-r--r--libmatemixer/matemixer-switch.h22
-rw-r--r--libmatemixer/matemixer-toggle.c40
-rw-r--r--libmatemixer/matemixer-toggle.h23
-rw-r--r--libmatemixer/matemixer-types.h3
-rw-r--r--libmatemixer/matemixer.c5
-rw-r--r--libmatemixer/matemixer.h7
-rw-r--r--po/ChangeLog12
-rw-r--r--po/Makevars41
-rw-r--r--po/POTFILES.in1
132 files changed, 10441 insertions, 7122 deletions
diff --git a/ABOUT-NLS b/ABOUT-NLS
new file mode 100644
index 0000000..4f50fb5
--- /dev/null
+++ b/ABOUT-NLS
@@ -0,0 +1,1327 @@
+1 Notes on the Free Translation Project
+***************************************
+
+Free software is going international! The Free Translation Project is
+a way to get maintainers of free software, translators, and users all
+together, so that free software will gradually become able to speak many
+languages. A few packages already provide translations for their
+messages.
+
+ If you found this `ABOUT-NLS' file inside a distribution, you may
+assume that the distributed package does use GNU `gettext' internally,
+itself available at your nearest GNU archive site. But you do _not_
+need to install GNU `gettext' prior to configuring, installing or using
+this package with messages translated.
+
+ Installers will find here some useful hints. These notes also
+explain how users should proceed for getting the programs to use the
+available translations. They tell how people wanting to contribute and
+work on translations can contact the appropriate team.
+
+ When reporting bugs in the `intl/' directory or bugs which may be
+related to internationalization, you should tell about the version of
+`gettext' which is used. The information can be found in the
+`intl/VERSION' file, in internationalized packages.
+
+1.1 Quick configuration advice
+==============================
+
+If you want to exploit the full power of internationalization, you
+should configure it using
+
+ ./configure --with-included-gettext
+
+to force usage of internationalizing routines provided within this
+package, despite the existence of internationalizing capabilities in the
+operating system where this package is being installed. So far, only
+the `gettext' implementation in the GNU C library version 2 provides as
+many features (such as locale alias, message inheritance, automatic
+charset conversion or plural form handling) as the implementation here.
+It is also not possible to offer this additional functionality on top
+of a `catgets' implementation. Future versions of GNU `gettext' will
+very likely convey even more functionality. So it might be a good idea
+to change to GNU `gettext' as soon as possible.
+
+ So you need _not_ provide this option if you are using GNU libc 2 or
+you have installed a recent copy of the GNU gettext package with the
+included `libintl'.
+
+1.2 INSTALL Matters
+===================
+
+Some packages are "localizable" when properly installed; the programs
+they contain can be made to speak your own native language. Most such
+packages use GNU `gettext'. Other packages have their own ways to
+internationalization, predating GNU `gettext'.
+
+ By default, this package will be installed to allow translation of
+messages. It will automatically detect whether the system already
+provides the GNU `gettext' functions. If not, the included GNU
+`gettext' library will be used. This library is wholly contained
+within this package, usually in the `intl/' subdirectory, so prior
+installation of the GNU `gettext' package is _not_ required.
+Installers may use special options at configuration time for changing
+the default behaviour. The commands:
+
+ ./configure --with-included-gettext
+ ./configure --disable-nls
+
+will, respectively, bypass any pre-existing `gettext' to use the
+internationalizing routines provided within this package, or else,
+_totally_ disable translation of messages.
+
+ When you already have GNU `gettext' installed on your system and run
+configure without an option for your new package, `configure' will
+probably detect the previously built and installed `libintl.a' file and
+will decide to use this. This might not be desirable. You should use
+the more recent version of the GNU `gettext' library. I.e. if the file
+`intl/VERSION' shows that the library which comes with this package is
+more recent, you should use
+
+ ./configure --with-included-gettext
+
+to prevent auto-detection.
+
+ The configuration process will not test for the `catgets' function
+and therefore it will not be used. The reason is that even an
+emulation of `gettext' on top of `catgets' could not provide all the
+extensions of the GNU `gettext' library.
+
+ Internationalized packages usually have many `po/LL.po' files, where
+LL gives an ISO 639 two-letter code identifying the language. Unless
+translations have been forbidden at `configure' time by using the
+`--disable-nls' switch, all available translations are installed
+together with the package. However, the environment variable `LINGUAS'
+may be set, prior to configuration, to limit the installed set.
+`LINGUAS' should then contain a space separated list of two-letter
+codes, stating which languages are allowed.
+
+1.3 Using This Package
+======================
+
+As a user, if your language has been installed for this package, you
+only have to set the `LANG' environment variable to the appropriate
+`LL_CC' combination. If you happen to have the `LC_ALL' or some other
+`LC_xxx' environment variables set, you should unset them before
+setting `LANG', otherwise the setting of `LANG' will not have the
+desired effect. Here `LL' is an ISO 639 two-letter language code, and
+`CC' is an ISO 3166 two-letter country code. For example, let's
+suppose that you speak German and live in Germany. At the shell
+prompt, merely execute `setenv LANG de_DE' (in `csh'),
+`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash').
+This can be done from your `.login' or `.profile' file, once and for
+all.
+
+ You might think that the country code specification is redundant.
+But in fact, some languages have dialects in different countries. For
+example, `de_AT' is used for Austria, and `pt_BR' for Brazil. The
+country code serves to distinguish the dialects.
+
+ The locale naming convention of `LL_CC', with `LL' denoting the
+language and `CC' denoting the country, is the one use on systems based
+on GNU libc. On other systems, some variations of this scheme are
+used, such as `LL' or `LL_CC.ENCODING'. You can get the list of
+locales supported by your system for your language by running the
+command `locale -a | grep '^LL''.
+
+ Not all programs have translations for all languages. By default, an
+English message is shown in place of a nonexistent translation. If you
+understand other languages, you can set up a priority list of languages.
+This is done through a different environment variable, called
+`LANGUAGE'. GNU `gettext' gives preference to `LANGUAGE' over `LANG'
+for the purpose of message handling, but you still need to have `LANG'
+set to the primary language; this is required by other parts of the
+system libraries. For example, some Swedish users who would rather
+read translations in German than English for when Swedish is not
+available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'.
+
+ Special advice for Norwegian users: The language code for Norwegian
+bokma*l changed from `no' to `nb' recently (in 2003). During the
+transition period, while some message catalogs for this language are
+installed under `nb' and some older ones under `no', it's recommended
+for Norwegian users to set `LANGUAGE' to `nb:no' so that both newer and
+older translations are used.
+
+ In the `LANGUAGE' environment variable, but not in the `LANG'
+environment variable, `LL_CC' combinations can be abbreviated as `LL'
+to denote the language's main dialect. For example, `de' is equivalent
+to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT'
+(Portuguese as spoken in Portugal) in this context.
+
+1.4 Translating Teams
+=====================
+
+For the Free Translation Project to be a success, we need interested
+people who like their own language and write it well, and who are also
+able to synergize with other translators speaking the same language.
+Each translation team has its own mailing list. The up-to-date list of
+teams can be found at the Free Translation Project's homepage,
+`http://translationproject.org/', in the "Teams" area.
+
+ If you'd like to volunteer to _work_ at translating messages, you
+should become a member of the translating team for your own language.
+The subscribing address is _not_ the same as the list itself, it has
+`-request' appended. For example, speakers of Swedish can send a
+message to `[email protected]', having this message body:
+
+ subscribe
+
+ Keep in mind that team members are expected to participate
+_actively_ in translations, or at solving translational difficulties,
+rather than merely lurking around. If your team does not exist yet and
+you want to start one, or if you are unsure about what to do or how to
+get started, please write to `[email protected]' to
+reach the coordinator for all translator teams.
+
+ The English team is special. It works at improving and uniformizing
+the terminology in use. Proven linguistic skills are praised more than
+programming skills, here.
+
+1.5 Available Packages
+======================
+
+Languages are not equally supported in all packages. The following
+matrix shows the current state of internationalization, as of May 2010.
+The matrix shows, in regard of each package, for which languages PO
+files have been submitted to translation coordination, with a
+translation percentage of at least 50%.
+
+ Ready PO files af am ar as ast az be be@latin bg bn_IN bs ca crh
+ +---------------------------------------------------+
+ a2ps | [] [] |
+ aegis | |
+ ant-phone | |
+ anubis | |
+ aspell | [] [] |
+ bash | |
+ bfd | |
+ bibshelf | [] |
+ binutils | |
+ bison | |
+ bison-runtime | [] |
+ bluez-pin | [] [] |
+ bombono-dvd | |
+ buzztard | |
+ cflow | |
+ clisp | |
+ coreutils | [] [] |
+ cpio | |
+ cppi | |
+ cpplib | [] |
+ cryptsetup | |
+ dfarc | |
+ dialog | [] [] |
+ dico | |
+ diffutils | [] |
+ dink | |
+ doodle | |
+ e2fsprogs | [] |
+ enscript | [] |
+ exif | |
+ fetchmail | [] |
+ findutils | [] |
+ flex | [] |
+ freedink | |
+ gas | |
+ gawk | [] [] |
+ gcal | [] |
+ gcc | |
+ gettext-examples | [] [] [] [] |
+ gettext-runtime | [] [] [] |
+ gettext-tools | [] [] |
+ gip | [] |
+ gjay | |
+ gliv | [] |
+ glunarclock | [] [] |
+ gnubiff | |
+ gnucash | [] |
+ gnuedu | |
+ gnulib | |
+ gnunet | |
+ gnunet-gtk | |
+ gnutls | |
+ gold | |
+ gpe-aerial | |
+ gpe-beam | |
+ gpe-bluetooth | |
+ gpe-calendar | |
+ gpe-clock | [] |
+ gpe-conf | |
+ gpe-contacts | |
+ gpe-edit | |
+ gpe-filemanager | |
+ gpe-go | |
+ gpe-login | |
+ gpe-ownerinfo | [] |
+ gpe-package | |
+ gpe-sketchbook | |
+ gpe-su | [] |
+ gpe-taskmanager | [] |
+ gpe-timesheet | [] |
+ gpe-today | [] |
+ gpe-todo | |
+ gphoto2 | |
+ gprof | [] |
+ gpsdrive | |
+ gramadoir | |
+ grep | |
+ grub | [] [] |
+ gsasl | |
+ gss | |
+ gst-plugins-bad | [] |
+ gst-plugins-base | [] |
+ gst-plugins-good | [] |
+ gst-plugins-ugly | [] |
+ gstreamer | [] [] [] |
+ gtick | |
+ gtkam | [] |
+ gtkorphan | [] |
+ gtkspell | [] [] [] |
+ gutenprint | |
+ hello | [] |
+ help2man | |
+ hylafax | |
+ idutils | |
+ indent | [] [] |
+ iso_15924 | |
+ iso_3166 | [] [] [] [] [] [] [] [] |
+ iso_3166_2 | |
+ iso_4217 | |
+ iso_639 | [] [] [] [] [] |
+ iso_639_3 | [] |
+ jwhois | |
+ kbd | |
+ keytouch | [] |
+ keytouch-editor | |
+ keytouch-keyboa... | [] |
+ klavaro | [] |
+ latrine | |
+ ld | [] |
+ leafpad | [] [] |
+ libc | [] [] |
+ libexif | () |
+ libextractor | |
+ libgnutls | |
+ libgpewidget | |
+ libgpg-error | |
+ libgphoto2 | |
+ libgphoto2_port | |
+ libgsasl | |
+ libiconv | [] |
+ libidn | |
+ lifelines | |
+ liferea | [] [] |
+ lilypond | |
+ linkdr | [] |
+ lordsawar | |
+ lprng | |
+ lynx | [] |
+ m4 | |
+ mailfromd | |
+ mailutils | |
+ make | |
+ man-db | |
+ man-db-manpages | |
+ minicom | |
+ mkisofs | |
+ myserver | |
+ nano | [] [] |
+ opcodes | |
+ parted | |
+ pies | |
+ popt | |
+ psmisc | |
+ pspp | [] |
+ pwdutils | |
+ radius | [] |
+ recode | [] [] |
+ rosegarden | |
+ rpm | |
+ rush | |
+ sarg | |
+ screem | |
+ scrollkeeper | [] [] [] |
+ sed | [] [] |
+ sharutils | [] [] |
+ shishi | |
+ skencil | |
+ solfege | |
+ solfege-manual | |
+ soundtracker | |
+ sp | |
+ sysstat | |
+ tar | [] |
+ texinfo | |
+ tin | |
+ unicode-han-tra... | |
+ unicode-transla... | |
+ util-linux-ng | [] |
+ vice | |
+ vmm | |
+ vorbis-tools | |
+ wastesedge | |
+ wdiff | |
+ wget | [] [] |
+ wyslij-po | |
+ xchat | [] [] [] [] |
+ xdg-user-dirs | [] [] [] [] [] [] [] [] [] |
+ xkeyboard-config | [] [] [] |
+ +---------------------------------------------------+
+ af am ar as ast az be be@latin bg bn_IN bs ca crh
+ 6 0 2 3 19 1 11 3 28 3 1 38 5
+
+ cs da de el en en_GB en_ZA eo es et eu fa fi
+ +-------------------------------------------------+
+ a2ps | [] [] [] [] [] [] [] [] |
+ aegis | [] [] [] |
+ ant-phone | [] () |
+ anubis | [] [] [] |
+ aspell | [] [] [] [] [] |
+ bash | [] [] [] [] |
+ bfd | [] [] |
+ bibshelf | [] [] [] [] |
+ binutils | [] [] |
+ bison | [] [] [] |
+ bison-runtime | [] [] [] [] [] |
+ bluez-pin | [] [] [] [] [] [] [] |
+ bombono-dvd | [] [] |
+ buzztard | [] [] [] |
+ cflow | [] [] [] |
+ clisp | [] [] [] [] |
+ coreutils | [] [] [] [] |
+ cpio | [] |
+ cppi | [] |
+ cpplib | [] [] [] |
+ cryptsetup | [] |
+ dfarc | [] [] [] [] |
+ dialog | [] [] [] [] [] |
+ dico | |
+ diffutils | [] [] [] [] [] [] [] |
+ dink | [] [] [] |
+ doodle | [] |
+ e2fsprogs | [] [] [] |
+ enscript | [] [] [] |
+ exif | () [] [] [] |
+ fetchmail | [] [] () [] [] [] |
+ findutils | [] [] [] [] |
+ flex | [] [] [] |
+ freedink | [] [] [] [] |
+ gas | [] |
+ gawk | [] [] [] |
+ gcal | [] |
+ gcc | [] [] |
+ gettext-examples | [] [] [] [] [] |
+ gettext-runtime | [] [] [] [] [] |
+ gettext-tools | [] [] [] |
+ gip | [] [] [] [] [] |
+ gjay | [] [] |
+ gliv | [] [] [] [] |
+ glunarclock | [] [] [] |
+ gnubiff | () |
+ gnucash | [] () () () () () |
+ gnuedu | [] [] |
+ gnulib | [] [] [] |
+ gnunet | |
+ gnunet-gtk | [] |
+ gnutls | [] [] |
+ gold | [] [] |
+ gpe-aerial | [] [] [] [] [] |
+ gpe-beam | [] [] [] [] [] |
+ gpe-bluetooth | [] [] [] |
+ gpe-calendar | [] [] |
+ gpe-clock | [] [] [] [] [] |
+ gpe-conf | [] [] [] [] |
+ gpe-contacts | [] [] [] [] |
+ gpe-edit | [] [] [] |
+ gpe-filemanager | [] [] [] [] |
+ gpe-go | [] [] [] [] [] |
+ gpe-login | [] [] [] |
+ gpe-ownerinfo | [] [] [] [] [] |
+ gpe-package | [] [] [] [] |
+ gpe-sketchbook | [] [] [] [] [] |
+ gpe-su | [] [] [] [] [] |
+ gpe-taskmanager | [] [] [] [] [] |
+ gpe-timesheet | [] [] [] [] [] |
+ gpe-today | [] [] [] [] [] |
+ gpe-todo | [] [] [] [] |
+ gphoto2 | [] [] () [] [] [] [] |
+ gprof | [] [] [] [] |
+ gpsdrive | [] [] [] |
+ gramadoir | [] [] [] |
+ grep | [] [] |
+ grub | [] [] [] |
+ gsasl | [] [] |
+ gss | [] |
+ gst-plugins-bad | [] [] [] [] [] [] |
+ gst-plugins-base | [] [] [] [] [] [] |
+ gst-plugins-good | [] [] [] [] [] [] [] |
+ gst-plugins-ugly | [] [] [] [] [] [] [] |
+ gstreamer | [] [] [] [] [] [] |
+ gtick | [] () [] [] |
+ gtkam | [] [] () [] [] |
+ gtkorphan | [] [] [] [] |
+ gtkspell | [] [] [] [] [] [] [] [] |
+ gutenprint | [] [] [] [] |
+ hello | [] [] [] [] [] |
+ help2man | [] [] |
+ hylafax | [] [] |
+ idutils | [] [] [] |
+ indent | [] [] [] [] [] [] [] [] |
+ iso_15924 | [] () [] [] [] |
+ iso_3166 | [] [] [] () [] [] [] () [] |
+ iso_3166_2 | () |
+ iso_4217 | [] [] [] () [] [] [] |
+ iso_639 | [] [] [] () [] [] [] |
+ iso_639_3 | |
+ jwhois | [] [] |
+ kbd | [] [] [] [] [] |
+ keytouch | [] [] [] |
+ keytouch-editor | [] [] [] |
+ keytouch-keyboa... | [] [] |
+ klavaro | [] [] [] [] |
+ latrine | [] () [] |
+ ld | [] [] [] |
+ leafpad | [] [] [] [] [] [] [] |
+ libc | [] [] [] [] [] |
+ libexif | [] [] () |
+ libextractor | |
+ libgnutls | [] |
+ libgpewidget | [] [] [] |
+ libgpg-error | [] [] |
+ libgphoto2 | [] () |
+ libgphoto2_port | [] () [] |
+ libgsasl | [] |
+ libiconv | [] [] [] [] [] [] |
+ libidn | [] [] [] [] |
+ lifelines | [] () |
+ liferea | [] [] [] [] [] |
+ lilypond | [] [] [] [] |
+ linkdr | [] [] [] [] |
+ lordsawar | [] |
+ lprng | |
+ lynx | [] [] [] [] |
+ m4 | [] [] [] [] [] |
+ mailfromd | |
+ mailutils | [] |
+ make | [] [] [] [] |
+ man-db | |
+ man-db-manpages | |
+ minicom | [] [] [] [] [] |
+ mkisofs | [] |
+ myserver | |
+ nano | [] [] [] [] |
+ opcodes | [] [] [] |
+ parted | [] [] |
+ pies | |
+ popt | [] [] [] [] [] [] |
+ psmisc | [] [] [] [] |
+ pspp | [] |
+ pwdutils | [] |
+ radius | [] |
+ recode | [] [] [] [] [] [] [] |
+ rosegarden | () () () () |
+ rpm | [] [] [] |
+ rush | |
+ sarg | |
+ screem | |
+ scrollkeeper | [] [] [] [] [] [] |
+ sed | [] [] [] [] [] [] [] |
+ sharutils | [] [] [] [] [] |
+ shishi | |
+ skencil | [] () [] |
+ solfege | [] [] [] [] |
+ solfege-manual | [] [] |
+ soundtracker | [] [] [] |
+ sp | [] |
+ sysstat | [] [] [] [] |
+ tar | [] [] [] [] [] |
+ texinfo | [] [] [] |
+ tin | [] [] |
+ unicode-han-tra... | |
+ unicode-transla... | |
+ util-linux-ng | [] [] [] [] [] |
+ vice | () () |
+ vmm | [] |
+ vorbis-tools | [] [] |
+ wastesedge | [] |
+ wdiff | [] [] [] |
+ wget | [] [] [] [] |
+ wyslij-po | [] |
+ xchat | [] [] [] [] [] [] |
+ xdg-user-dirs | [] [] [] [] [] [] [] [] [] |
+ xkeyboard-config | [] [] [] [] [] [] |
+ +-------------------------------------------------+
+ cs da de el en en_GB en_ZA eo es et eu fa fi
+ 64 105 117 18 1 8 0 28 89 18 19 0 104
+
+ fr ga gl gu he hi hr hu hy id is it ja ka kn
+ +------------------------------------------------+
+ a2ps | [] [] [] |
+ aegis | [] [] |
+ ant-phone | [] [] |
+ anubis | [] [] [] |
+ aspell | [] [] [] [] |
+ bash | [] [] [] |
+ bfd | [] [] |
+ bibshelf | [] [] [] [] |
+ binutils | [] [] |
+ bison | [] [] [] |
+ bison-runtime | [] [] [] [] [] |
+ bluez-pin | [] [] [] [] [] [] [] |
+ bombono-dvd | |
+ buzztard | [] |
+ cflow | [] [] |
+ clisp | [] |
+ coreutils | [] [] [] [] [] |
+ cpio | [] [] [] |
+ cppi | [] |
+ cpplib | [] [] |
+ cryptsetup | [] [] [] |
+ dfarc | [] [] |
+ dialog | [] [] [] [] [] [] [] |
+ dico | |
+ diffutils | [] [] [] [] [] [] [] [] |
+ dink | [] |
+ doodle | [] [] |
+ e2fsprogs | [] [] |
+ enscript | [] [] [] [] |
+ exif | [] [] [] [] [] |
+ fetchmail | [] [] [] [] |
+ findutils | [] [] [] [] [] |
+ flex | [] [] |
+ freedink | [] [] |
+ gas | [] [] |
+ gawk | [] [] [] [] () [] |
+ gcal | [] |
+ gcc | [] |
+ gettext-examples | [] [] [] [] [] [] |
+ gettext-runtime | [] [] [] [] [] |
+ gettext-tools | [] [] [] [] |
+ gip | [] [] [] [] [] |
+ gjay | |
+ gliv | () |
+ glunarclock | [] [] [] |
+ gnubiff | () [] () |
+ gnucash | () () () () [] |
+ gnuedu | [] [] |
+ gnulib | [] [] [] [] [] |
+ gnunet | |
+ gnunet-gtk | [] |
+ gnutls | [] [] |
+ gold | [] |
+ gpe-aerial | [] [] |
+ gpe-beam | [] [] [] |
+ gpe-bluetooth | [] [] [] |
+ gpe-calendar | [] |
+ gpe-clock | [] [] [] [] |
+ gpe-conf | [] [] [] |
+ gpe-contacts | [] [] [] |
+ gpe-edit | [] [] |
+ gpe-filemanager | [] [] [] |
+ gpe-go | [] [] [] [] |
+ gpe-login | [] [] |
+ gpe-ownerinfo | [] [] [] [] |
+ gpe-package | [] [] |
+ gpe-sketchbook | [] [] [] |
+ gpe-su | [] [] [] [] [] |
+ gpe-taskmanager | [] [] [] [] |
+ gpe-timesheet | [] [] [] [] |
+ gpe-today | [] [] [] [] [] [] |
+ gpe-todo | [] [] |
+ gphoto2 | [] [] [] [] [] |
+ gprof | [] [] [] |
+ gpsdrive | [] [] [] |
+ gramadoir | [] [] [] |
+ grep | [] |
+ grub | [] [] [] |
+ gsasl | [] [] [] [] |
+ gss | [] [] [] [] |
+ gst-plugins-bad | [] [] [] [] |
+ gst-plugins-base | [] [] [] [] [] |
+ gst-plugins-good | [] [] [] [] [] |
+ gst-plugins-ugly | [] [] [] [] [] |
+ gstreamer | [] [] [] [] |
+ gtick | [] [] [] [] |
+ gtkam | [] [] [] [] [] |
+ gtkorphan | [] [] [] |
+ gtkspell | [] [] [] [] [] [] [] [] |
+ gutenprint | [] [] [] |
+ hello | [] [] |
+ help2man | [] |
+ hylafax | [] |
+ idutils | [] [] [] [] [] |
+ indent | [] [] [] [] [] [] [] |
+ iso_15924 | () [] [] |
+ iso_3166 | () [] [] [] [] [] [] [] [] [] [] |
+ iso_3166_2 | () [] [] [] |
+ iso_4217 | () [] [] [] [] |
+ iso_639 | () [] [] [] [] [] [] [] |
+ iso_639_3 | () [] [] |
+ jwhois | [] [] [] [] |
+ kbd | [] [] |
+ keytouch | [] [] [] [] [] |
+ keytouch-editor | [] [] [] [] |
+ keytouch-keyboa... | [] [] [] [] |
+ klavaro | [] [] |
+ latrine | [] [] |
+ ld | [] [] [] |
+ leafpad | [] [] [] [] [] [] () |
+ libc | [] [] [] [] |
+ libexif | |
+ libextractor | |
+ libgnutls | [] [] |
+ libgpewidget | [] [] [] |
+ libgpg-error | [] [] |
+ libgphoto2 | [] [] [] |
+ libgphoto2_port | [] [] [] |
+ libgsasl | [] [] [] [] |
+ libiconv | [] [] [] [] [] |
+ libidn | [] [] [] |
+ lifelines | () |
+ liferea | [] [] [] [] |
+ lilypond | [] |
+ linkdr | [] [] [] [] |
+ lordsawar | |
+ lprng | [] |
+ lynx | [] [] [] [] [] |
+ m4 | [] [] [] [] [] |
+ mailfromd | |
+ mailutils | [] [] |
+ make | [] [] [] [] [] [] [] [] |
+ man-db | [] [] |
+ man-db-manpages | [] |
+ minicom | [] [] [] [] |
+ mkisofs | [] [] [] |
+ myserver | |
+ nano | [] [] [] [] [] |
+ opcodes | [] [] [] |
+ parted | [] [] [] [] |
+ pies | |
+ popt | [] [] [] [] [] [] [] [] |
+ psmisc | [] [] |
+ pspp | |
+ pwdutils | [] [] |
+ radius | [] [] |
+ recode | [] [] [] [] [] [] [] |
+ rosegarden | () () () () |
+ rpm | [] [] |
+ rush | |
+ sarg | [] |
+ screem | [] [] |
+ scrollkeeper | [] [] [] |
+ sed | [] [] [] [] [] [] [] |
+ sharutils | [] [] [] [] [] [] |
+ shishi | [] |
+ skencil | [] |
+ solfege | [] [] [] |
+ solfege-manual | [] [] |
+ soundtracker | [] [] |
+ sp | [] () |
+ sysstat | [] [] [] [] |
+ tar | [] [] [] [] [] [] |
+ texinfo | [] [] [] [] |
+ tin | [] |
+ unicode-han-tra... | |
+ unicode-transla... | [] [] |
+ util-linux-ng | [] [] [] [] [] |
+ vice | () () () |
+ vmm | [] |
+ vorbis-tools | [] |
+ wastesedge | () () |
+ wdiff | |
+ wget | [] [] [] [] [] [] [] |
+ wyslij-po | [] [] |
+ xchat | [] [] [] [] [] [] [] [] |
+ xdg-user-dirs | [] [] [] [] [] [] [] [] [] [] [] |
+ xkeyboard-config | [] [] [] [] |
+ +------------------------------------------------+
+ fr ga gl gu he hi hr hu hy id is it ja ka kn
+ 121 53 20 4 8 2 5 53 2 120 5 83 66 0 4
+
+ ko ku ky lg lt lv mk ml mn mr ms mt nb nds ne
+ +-----------------------------------------------+
+ a2ps | [] |
+ aegis | |
+ ant-phone | |
+ anubis | [] [] |
+ aspell | [] |
+ bash | |
+ bfd | |
+ bibshelf | [] [] |
+ binutils | |
+ bison | [] |
+ bison-runtime | [] [] [] [] [] |
+ bluez-pin | [] [] [] [] [] |
+ bombono-dvd | |
+ buzztard | |
+ cflow | |
+ clisp | |
+ coreutils | [] |
+ cpio | |
+ cppi | |
+ cpplib | |
+ cryptsetup | |
+ dfarc | [] |
+ dialog | [] [] [] [] [] |
+ dico | |
+ diffutils | [] [] |
+ dink | |
+ doodle | |
+ e2fsprogs | |
+ enscript | |
+ exif | [] |
+ fetchmail | |
+ findutils | |
+ flex | |
+ freedink | [] |
+ gas | |
+ gawk | |
+ gcal | |
+ gcc | |
+ gettext-examples | [] [] [] [] |
+ gettext-runtime | [] |
+ gettext-tools | [] |
+ gip | [] [] |
+ gjay | |
+ gliv | |
+ glunarclock | [] |
+ gnubiff | |
+ gnucash | () () () () |
+ gnuedu | |
+ gnulib | |
+ gnunet | |
+ gnunet-gtk | |
+ gnutls | [] |
+ gold | |
+ gpe-aerial | [] |
+ gpe-beam | [] |
+ gpe-bluetooth | [] [] |
+ gpe-calendar | [] |
+ gpe-clock | [] [] [] [] [] |
+ gpe-conf | [] [] |
+ gpe-contacts | [] [] |
+ gpe-edit | [] |
+ gpe-filemanager | [] [] |
+ gpe-go | [] [] [] |
+ gpe-login | [] |
+ gpe-ownerinfo | [] [] |
+ gpe-package | [] [] |
+ gpe-sketchbook | [] [] |
+ gpe-su | [] [] [] [] [] [] |
+ gpe-taskmanager | [] [] [] [] [] [] |
+ gpe-timesheet | [] [] |
+ gpe-today | [] [] [] [] |
+ gpe-todo | [] [] |
+ gphoto2 | |
+ gprof | [] |
+ gpsdrive | |
+ gramadoir | |
+ grep | |
+ grub | |
+ gsasl | |
+ gss | |
+ gst-plugins-bad | [] [] |
+ gst-plugins-base | [] [] |
+ gst-plugins-good | [] [] |
+ gst-plugins-ugly | [] [] [] [] [] |
+ gstreamer | |
+ gtick | |
+ gtkam | [] |
+ gtkorphan | [] [] |
+ gtkspell | [] [] [] [] [] [] [] |
+ gutenprint | |
+ hello | [] [] [] |
+ help2man | |
+ hylafax | |
+ idutils | |
+ indent | |
+ iso_15924 | [] [] |
+ iso_3166 | [] [] () [] [] [] [] [] |
+ iso_3166_2 | |
+ iso_4217 | [] [] |
+ iso_639 | [] [] |
+ iso_639_3 | [] |
+ jwhois | [] |
+ kbd | |
+ keytouch | [] |
+ keytouch-editor | [] |
+ keytouch-keyboa... | [] |
+ klavaro | [] |
+ latrine | [] |
+ ld | |
+ leafpad | [] [] [] |
+ libc | [] |
+ libexif | |
+ libextractor | |
+ libgnutls | [] |
+ libgpewidget | [] [] |
+ libgpg-error | |
+ libgphoto2 | |
+ libgphoto2_port | |
+ libgsasl | |
+ libiconv | |
+ libidn | |
+ lifelines | |
+ liferea | |
+ lilypond | |
+ linkdr | |
+ lordsawar | |
+ lprng | |
+ lynx | |
+ m4 | |
+ mailfromd | |
+ mailutils | |
+ make | [] |
+ man-db | |
+ man-db-manpages | |
+ minicom | [] |
+ mkisofs | |
+ myserver | |
+ nano | [] [] |
+ opcodes | |
+ parted | |
+ pies | |
+ popt | [] [] [] |
+ psmisc | |
+ pspp | |
+ pwdutils | |
+ radius | |
+ recode | |
+ rosegarden | |
+ rpm | |
+ rush | |
+ sarg | |
+ screem | |
+ scrollkeeper | [] [] |
+ sed | |
+ sharutils | |
+ shishi | |
+ skencil | |
+ solfege | [] |
+ solfege-manual | |
+ soundtracker | |
+ sp | |
+ sysstat | [] |
+ tar | [] |
+ texinfo | [] |
+ tin | |
+ unicode-han-tra... | |
+ unicode-transla... | |
+ util-linux-ng | |
+ vice | |
+ vmm | |
+ vorbis-tools | |
+ wastesedge | |
+ wdiff | |
+ wget | [] |
+ wyslij-po | |
+ xchat | [] [] [] |
+ xdg-user-dirs | [] [] [] [] [] [] [] [] |
+ xkeyboard-config | [] [] [] |
+ +-----------------------------------------------+
+ ko ku ky lg lt lv mk ml mn mr ms mt nb nds ne
+ 20 5 10 1 12 48 4 2 2 4 24 10 19 3 1
+
+ nl nn or pa pl ps pt pt_BR ro ru rw sk sl sq sr
+ +---------------------------------------------------+
+ a2ps | [] [] [] [] [] [] [] [] |
+ aegis | [] [] [] |
+ ant-phone | [] [] |
+ anubis | [] [] [] |
+ aspell | [] [] [] [] [] |
+ bash | [] [] |
+ bfd | [] |
+ bibshelf | [] [] |
+ binutils | [] [] |
+ bison | [] [] [] |
+ bison-runtime | [] [] [] [] [] [] [] |
+ bluez-pin | [] [] [] [] [] [] [] [] |
+ bombono-dvd | [] () |
+ buzztard | [] [] |
+ cflow | [] |
+ clisp | [] [] |
+ coreutils | [] [] [] [] [] [] |
+ cpio | [] [] [] |
+ cppi | [] |
+ cpplib | [] |
+ cryptsetup | [] |
+ dfarc | [] |
+ dialog | [] [] [] [] |
+ dico | [] |
+ diffutils | [] [] [] [] [] [] |
+ dink | () |
+ doodle | [] [] |
+ e2fsprogs | [] [] |
+ enscript | [] [] [] [] [] |
+ exif | [] [] [] () [] |
+ fetchmail | [] [] [] [] |
+ findutils | [] [] [] [] [] |
+ flex | [] [] [] [] [] |
+ freedink | [] [] |
+ gas | |
+ gawk | [] [] [] [] |
+ gcal | |
+ gcc | [] |
+ gettext-examples | [] [] [] [] [] [] [] [] |
+ gettext-runtime | [] [] [] [] [] [] [] [] [] |
+ gettext-tools | [] [] [] [] [] [] |
+ gip | [] [] [] [] [] |
+ gjay | |
+ gliv | [] [] [] [] [] [] |
+ glunarclock | [] [] [] [] [] |
+ gnubiff | [] () |
+ gnucash | [] () () () |
+ gnuedu | [] |
+ gnulib | [] [] [] [] |
+ gnunet | |
+ gnunet-gtk | |
+ gnutls | [] [] |
+ gold | |
+ gpe-aerial | [] [] [] [] [] [] [] |
+ gpe-beam | [] [] [] [] [] [] [] |
+ gpe-bluetooth | [] [] |
+ gpe-calendar | [] [] [] [] |
+ gpe-clock | [] [] [] [] [] [] [] [] |
+ gpe-conf | [] [] [] [] [] [] [] |
+ gpe-contacts | [] [] [] [] [] |
+ gpe-edit | [] [] [] |
+ gpe-filemanager | [] [] [] |
+ gpe-go | [] [] [] [] [] [] [] [] |
+ gpe-login | [] [] |
+ gpe-ownerinfo | [] [] [] [] [] [] [] [] |
+ gpe-package | [] [] |
+ gpe-sketchbook | [] [] [] [] [] [] [] |
+ gpe-su | [] [] [] [] [] [] [] [] |
+ gpe-taskmanager | [] [] [] [] [] [] [] [] |
+ gpe-timesheet | [] [] [] [] [] [] [] [] |
+ gpe-today | [] [] [] [] [] [] [] [] |
+ gpe-todo | [] [] [] [] [] |
+ gphoto2 | [] [] [] [] [] [] [] [] |
+ gprof | [] [] [] |
+ gpsdrive | [] [] |
+ gramadoir | [] [] |
+ grep | [] [] [] [] |
+ grub | [] [] [] |
+ gsasl | [] [] [] [] |
+ gss | [] [] [] |
+ gst-plugins-bad | [] [] [] [] [] |
+ gst-plugins-base | [] [] [] [] [] |
+ gst-plugins-good | [] [] [] [] [] |
+ gst-plugins-ugly | [] [] [] [] [] [] |
+ gstreamer | [] [] [] [] [] |
+ gtick | [] [] [] |
+ gtkam | [] [] [] [] [] [] |
+ gtkorphan | [] |
+ gtkspell | [] [] [] [] [] [] [] [] [] [] |
+ gutenprint | [] [] |
+ hello | [] [] [] [] |
+ help2man | [] [] |
+ hylafax | [] |
+ idutils | [] [] [] [] [] |
+ indent | [] [] [] [] [] [] [] |
+ iso_15924 | [] [] [] [] |
+ iso_3166 | [] [] [] [] [] () [] [] [] [] [] [] [] [] |
+ iso_3166_2 | [] [] [] |
+ iso_4217 | [] [] [] [] [] [] [] [] |
+ iso_639 | [] [] [] [] [] [] [] [] [] |
+ iso_639_3 | [] [] |
+ jwhois | [] [] [] [] |
+ kbd | [] [] [] |
+ keytouch | [] [] [] |
+ keytouch-editor | [] [] [] |
+ keytouch-keyboa... | [] [] [] |
+ klavaro | [] [] |
+ latrine | [] [] |
+ ld | |
+ leafpad | [] [] [] [] [] [] [] [] [] |
+ libc | [] [] [] [] |
+ libexif | [] [] () [] |
+ libextractor | |
+ libgnutls | [] [] |
+ libgpewidget | [] [] [] |
+ libgpg-error | [] [] |
+ libgphoto2 | [] [] |
+ libgphoto2_port | [] [] [] [] |
+ libgsasl | [] [] [] [] [] |
+ libiconv | [] [] [] [] [] |
+ libidn | [] [] |
+ lifelines | [] [] |
+ liferea | [] [] [] [] [] () () [] |
+ lilypond | [] |
+ linkdr | [] [] [] |
+ lordsawar | |
+ lprng | [] |
+ lynx | [] [] [] |
+ m4 | [] [] [] [] [] |
+ mailfromd | [] |
+ mailutils | [] |
+ make | [] [] [] [] |
+ man-db | [] [] [] |
+ man-db-manpages | [] [] [] |
+ minicom | [] [] [] [] |
+ mkisofs | [] [] [] |
+ myserver | |
+ nano | [] [] [] [] |
+ opcodes | [] [] |
+ parted | [] [] [] [] |
+ pies | [] |
+ popt | [] [] [] [] |
+ psmisc | [] [] [] |
+ pspp | [] [] |
+ pwdutils | [] |
+ radius | [] [] [] |
+ recode | [] [] [] [] [] [] [] [] |
+ rosegarden | () () |
+ rpm | [] [] [] |
+ rush | [] [] |
+ sarg | |
+ screem | |
+ scrollkeeper | [] [] [] [] [] [] [] [] |
+ sed | [] [] [] [] [] [] [] [] [] |
+ sharutils | [] [] [] [] |
+ shishi | [] |
+ skencil | [] [] |
+ solfege | [] [] [] [] |
+ solfege-manual | [] [] [] |
+ soundtracker | [] |
+ sp | |
+ sysstat | [] [] [] [] |
+ tar | [] [] [] [] |
+ texinfo | [] [] [] [] |
+ tin | [] |
+ unicode-han-tra... | |
+ unicode-transla... | |
+ util-linux-ng | [] [] [] [] [] |
+ vice | [] |
+ vmm | [] |
+ vorbis-tools | [] [] |
+ wastesedge | [] |
+ wdiff | [] [] |
+ wget | [] [] [] [] [] [] [] |
+ wyslij-po | [] [] [] |
+ xchat | [] [] [] [] [] [] [] [] [] |
+ xdg-user-dirs | [] [] [] [] [] [] [] [] [] [] [] [] [] [] |
+ xkeyboard-config | [] [] [] [] [] |
+ +---------------------------------------------------+
+ nl nn or pa pl ps pt pt_BR ro ru rw sk sl sq sr
+ 135 10 4 7 105 1 29 61 47 91 3 55 47 8 37
+
+ sv sw ta te tg th tr uk vi wa zh_CN zh_HK zh_TW
+ +---------------------------------------------------+
+ a2ps | [] [] [] [] [] | 27
+ aegis | [] | 9
+ ant-phone | [] [] [] [] | 9
+ anubis | [] [] [] [] | 15
+ aspell | [] [] [] | 20
+ bash | [] [] | 11
+ bfd | [] | 6
+ bibshelf | [] [] [] | 16
+ binutils | [] [] | 8
+ bison | [] [] | 12
+ bison-runtime | [] [] [] [] [] [] | 29
+ bluez-pin | [] [] [] [] [] [] [] [] | 37
+ bombono-dvd | [] | 4
+ buzztard | [] | 7
+ cflow | [] [] [] | 9
+ clisp | | 10
+ coreutils | [] [] [] [] | 22
+ cpio | [] [] [] [] [] [] | 13
+ cppi | [] [] | 5
+ cpplib | [] [] [] [] [] [] | 13
+ cryptsetup | [] [] | 7
+ dfarc | [] | 9
+ dialog | [] [] [] [] [] [] [] | 30
+ dico | [] | 2
+ diffutils | [] [] [] [] [] [] | 30
+ dink | | 4
+ doodle | [] [] | 7
+ e2fsprogs | [] [] [] | 11
+ enscript | [] [] [] [] | 17
+ exif | [] [] [] | 16
+ fetchmail | [] [] [] | 17
+ findutils | [] [] [] [] [] | 20
+ flex | [] [] [] [] | 15
+ freedink | [] | 10
+ gas | [] | 4
+ gawk | [] [] [] [] | 18
+ gcal | [] [] | 5
+ gcc | [] [] [] | 7
+ gettext-examples | [] [] [] [] [] [] [] | 34
+ gettext-runtime | [] [] [] [] [] [] [] | 30
+ gettext-tools | [] [] [] [] [] [] | 22
+ gip | [] [] [] [] | 22
+ gjay | [] | 3
+ gliv | [] [] [] | 14
+ glunarclock | [] [] [] [] [] | 19
+ gnubiff | [] [] | 4
+ gnucash | () [] () () | 9
+ gnuedu | [] [] | 7
+ gnulib | [] [] [] [] | 16
+ gnunet | [] | 1
+ gnunet-gtk | [] [] [] | 5
+ gnutls | [] [] [] | 10
+ gold | [] | 4
+ gpe-aerial | [] [] [] | 18
+ gpe-beam | [] [] [] | 19
+ gpe-bluetooth | [] [] [] | 13
+ gpe-calendar | [] [] [] [] | 12
+ gpe-clock | [] [] [] [] [] | 28
+ gpe-conf | [] [] [] [] | 20
+ gpe-contacts | [] [] [] | 17
+ gpe-edit | [] [] [] | 12
+ gpe-filemanager | [] [] [] [] | 16
+ gpe-go | [] [] [] [] [] | 25
+ gpe-login | [] [] [] | 11
+ gpe-ownerinfo | [] [] [] [] [] | 25
+ gpe-package | [] [] [] | 13
+ gpe-sketchbook | [] [] [] | 20
+ gpe-su | [] [] [] [] [] | 30
+ gpe-taskmanager | [] [] [] [] [] | 29
+ gpe-timesheet | [] [] [] [] [] | 25
+ gpe-today | [] [] [] [] [] [] | 30
+ gpe-todo | [] [] [] [] | 17
+ gphoto2 | [] [] [] [] [] | 24
+ gprof | [] [] [] | 15
+ gpsdrive | [] [] [] | 11
+ gramadoir | [] [] [] | 11
+ grep | [] [] [] | 10
+ grub | [] [] [] | 14
+ gsasl | [] [] [] [] | 14
+ gss | [] [] [] | 11
+ gst-plugins-bad | [] [] [] [] | 22
+ gst-plugins-base | [] [] [] [] [] | 24
+ gst-plugins-good | [] [] [] [] [] | 25
+ gst-plugins-ugly | [] [] [] [] [] | 29
+ gstreamer | [] [] [] [] | 22
+ gtick | [] [] [] | 13
+ gtkam | [] [] [] | 20
+ gtkorphan | [] [] [] | 14
+ gtkspell | [] [] [] [] [] [] [] [] [] | 45
+ gutenprint | [] | 10
+ hello | [] [] [] [] [] [] | 21
+ help2man | [] [] | 7
+ hylafax | [] | 5
+ idutils | [] [] [] [] | 17
+ indent | [] [] [] [] [] [] | 30
+ iso_15924 | () [] () [] [] | 16
+ iso_3166 | [] [] () [] [] () [] [] [] () | 53
+ iso_3166_2 | () [] () [] | 9
+ iso_4217 | [] () [] [] () [] [] | 26
+ iso_639 | [] [] [] () [] () [] [] [] [] | 38
+ iso_639_3 | [] () | 8
+ jwhois | [] [] [] [] [] | 16
+ kbd | [] [] [] [] [] | 15
+ keytouch | [] [] [] | 16
+ keytouch-editor | [] [] [] | 14
+ keytouch-keyboa... | [] [] [] | 14
+ klavaro | [] | 11
+ latrine | [] [] [] | 10
+ ld | [] [] [] [] | 11
+ leafpad | [] [] [] [] [] [] | 33
+ libc | [] [] [] [] [] | 21
+ libexif | [] () | 6
+ libextractor | [] | 1
+ libgnutls | [] [] [] | 9
+ libgpewidget | [] [] [] | 14
+ libgpg-error | [] [] [] | 9
+ libgphoto2 | [] [] | 8
+ libgphoto2_port | [] [] [] [] | 13
+ libgsasl | [] [] [] | 13
+ libiconv | [] [] [] [] | 21
+ libidn | () [] [] | 11
+ lifelines | [] | 4
+ liferea | [] [] [] | 21
+ lilypond | [] | 7
+ linkdr | [] [] [] [] [] | 17
+ lordsawar | | 1
+ lprng | [] | 3
+ lynx | [] [] [] [] | 17
+ m4 | [] [] [] [] | 19
+ mailfromd | [] [] | 3
+ mailutils | [] | 5
+ make | [] [] [] [] | 21
+ man-db | [] [] [] | 8
+ man-db-manpages | | 4
+ minicom | [] [] | 16
+ mkisofs | [] [] | 9
+ myserver | | 0
+ nano | [] [] [] [] | 21
+ opcodes | [] [] [] | 11
+ parted | [] [] [] [] [] | 15
+ pies | [] [] | 3
+ popt | [] [] [] [] [] [] | 27
+ psmisc | [] [] | 11
+ pspp | | 4
+ pwdutils | [] [] | 6
+ radius | [] [] | 9
+ recode | [] [] [] [] | 28
+ rosegarden | () | 0
+ rpm | [] [] [] | 11
+ rush | [] [] | 4
+ sarg | | 1
+ screem | [] | 3
+ scrollkeeper | [] [] [] [] [] | 27
+ sed | [] [] [] [] [] | 30
+ sharutils | [] [] [] [] [] | 22
+ shishi | [] | 3
+ skencil | [] [] | 7
+ solfege | [] [] [] [] | 16
+ solfege-manual | [] | 8
+ soundtracker | [] [] [] | 9
+ sp | [] | 3
+ sysstat | [] [] | 15
+ tar | [] [] [] [] [] [] | 23
+ texinfo | [] [] [] [] | 16
+ tin | | 4
+ unicode-han-tra... | | 0
+ unicode-transla... | | 2
+ util-linux-ng | [] [] [] [] | 20
+ vice | () () | 1
+ vmm | [] | 4
+ vorbis-tools | [] | 6
+ wastesedge | | 2
+ wdiff | [] [] | 7
+ wget | [] [] [] [] [] | 26
+ wyslij-po | [] [] | 8
+ xchat | [] [] [] [] [] [] | 36
+ xdg-user-dirs | [] [] [] [] [] [] [] [] [] | 60
+ xkeyboard-config | [] [] [] [] | 25
+ +---------------------------------------------------+
+ 84 teams sv sw ta te tg th tr uk vi wa zh_CN zh_HK zh_TW
+ 178 domains 119 1 3 2 0 10 66 50 155 17 97 7 41 2610
+
+ Some counters in the preceding matrix are higher than the number of
+visible blocks let us expect. This is because a few extra PO files are
+used for implementing regional variants of languages, or language
+dialects.
+
+ For a PO file in the matrix above to be effective, the package to
+which it applies should also have been internationalized and
+distributed as such by its maintainer. There might be an observable
+lag between the mere existence a PO file and its wide availability in a
+distribution.
+
+ If May 2010 seems to be old, you may fetch a more recent copy of
+this `ABOUT-NLS' file on most GNU archive sites. The most up-to-date
+matrix with full percentage details can be found at
+`http://translationproject.org/extra/matrix.html'.
+
+1.6 Using `gettext' in new packages
+===================================
+
+If you are writing a freely available program and want to
+internationalize it you are welcome to use GNU `gettext' in your
+package. Of course you have to respect the GNU Library General Public
+License which covers the use of the GNU `gettext' library. This means
+in particular that even non-free programs can use `libintl' as a shared
+library, whereas only free software can use `libintl' as a static
+library or use modified versions of `libintl'.
+
+ Once the sources are changed appropriately and the setup can handle
+the use of `gettext' the only thing missing are the translations. The
+Free Translation Project is also available for packages which are not
+developed inside the GNU project. Therefore the information given above
+applies also for every other Free Software Project. Contact
+`[email protected]' to make the `.pot' files available
+to the translation teams.
+
diff --git a/AUTHORS b/AUTHORS
index 99318be..f6aa159 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,2 +1 @@
Michal Ratajsky <[email protected]>
-
diff --git a/Makefile.am b/Makefile.am
index 38ca12f..168460b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,9 +5,10 @@ SUBDIRS = \
backends \
data \
docs \
- examples
+ examples \
+ po
-EXTRA_DIST = autogen.sh
+EXTRA_DIST = build-aux/config.rpath autogen.sh
MAINTAINERCLEANFILES = \
$(srcdir)/aclocal.m4 \
diff --git a/NEWS b/NEWS
index e69de29..7e3105b 100644
--- a/NEWS
+++ b/NEWS
@@ -0,0 +1,5 @@
+=============
+Version 1.9.0
+=============
+
+- Initial release
diff --git a/autogen.sh b/autogen.sh
index 62cf8eb..74de42b 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -18,6 +18,7 @@ which mate-autogen || {
}
REQUIRED_AUTOMAKE_VERSION=1.9
+REQUIRED_INTLTOOL_VERSION=0.35
REQUIRED_GTK_DOC_VERSION=1.9
USE_COMMON_DOC_BUILD=yes
diff --git a/backends/alsa/Makefile.am b/backends/alsa/Makefile.am
index 220bb3b..48dcaba 100644
--- a/backends/alsa/Makefile.am
+++ b/backends/alsa/Makefile.am
@@ -3,6 +3,7 @@ backenddir = $(libdir)/libmatemixer
backend_LTLIBRARIES = libmatemixer-alsa.la
AM_CPPFLAGS = \
+ -Wno-unknown-pragmas \
-I$(top_srcdir) \
-DG_LOG_DOMAIN=\"libmatemixer-alsa\"
diff --git a/backends/alsa/alsa-backend.c b/backends/alsa/alsa-backend.c
index 7a17b85..6bac691 100644
--- a/backends/alsa/alsa-backend.c
+++ b/backends/alsa/alsa-backend.c
@@ -27,12 +27,22 @@
#include "alsa-stream.h"
#define BACKEND_NAME "ALSA"
-#define BACKEND_PRIORITY 9
+#define BACKEND_PRIORITY 20
+
+#define ALSA_DEVICE_GET_ID(d) \
+ (g_object_get_data (G_OBJECT (d), "__matemixer_alsa_device_id"))
+
+#define ALSA_DEVICE_SET_ID(d,id) \
+ (g_object_set_data_full (G_OBJECT (d), \
+ "__matemixer_alsa_device_id", \
+ g_strdup (id), \
+ g_free))
struct _AlsaBackendPrivate
{
GSource *timeout_source;
- GHashTable *devices;
+ GList *streams;
+ GList *devices;
GHashTable *devices_ids;
};
@@ -47,26 +57,38 @@ static void alsa_backend_finalize (GObject *object);
G_DEFINE_DYNAMIC_TYPE (AlsaBackend, alsa_backend, MATE_MIXER_TYPE_BACKEND)
#pragma clang diagnostic pop
-static gboolean alsa_backend_open (MateMixerBackend *backend);
-static void alsa_backend_close (MateMixerBackend *backend);
-static GList * alsa_backend_list_devices (MateMixerBackend *backend);
-static GList * alsa_backend_list_streams (MateMixerBackend *backend);
+static gboolean alsa_backend_open (MateMixerBackend *backend);
+static void alsa_backend_close (MateMixerBackend *backend);
+static const GList *alsa_backend_list_devices (MateMixerBackend *backend);
+static const GList *alsa_backend_list_streams (MateMixerBackend *backend);
+
+static gboolean read_devices (AlsaBackend *alsa);
+
+static gboolean read_device (AlsaBackend *alsa,
+ const gchar *card);
+
+static void add_device (AlsaBackend *alsa,
+ AlsaDevice *device);
-static gboolean read_devices (AlsaBackend *alsa);
+static void remove_device (AlsaBackend *alsa,
+ AlsaDevice *device);
+static void remove_device_by_name (AlsaBackend *alsa,
+ const gchar *name);
+static void remove_device_by_list_item (AlsaBackend *alsa,
+ GList *item);
-static gboolean read_device (AlsaBackend *alsa,
- const gchar *card);
+static void remove_stream (AlsaBackend *alsa,
+ const gchar *name);
-static void add_device (AlsaBackend *alsa,
- AlsaDevice *device);
+static void select_default_input_stream (AlsaBackend *alsa);
+static void select_default_output_stream (AlsaBackend *alsa);
-static void remove_device (AlsaBackend *alsa,
- AlsaDevice *device);
-static void remove_stream (AlsaBackend *alsa,
- const gchar *name);
+static void free_stream_list (AlsaBackend *alsa);
-static void select_default_input_stream (AlsaBackend *alsa);
-static void select_default_output_stream (AlsaBackend *alsa);
+static gint compare_devices (gconstpointer a,
+ gconstpointer b);
+static gint compare_device_name (gconstpointer a,
+ gconstpointer b);
static MateMixerBackendInfo info;
@@ -118,11 +140,6 @@ alsa_backend_init (AlsaBackend *alsa)
ALSA_TYPE_BACKEND,
AlsaBackendPrivate);
- alsa->priv->devices = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- g_object_unref);
-
alsa->priv->devices_ids = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
@@ -151,7 +168,6 @@ alsa_backend_finalize (GObject *object)
alsa = ALSA_BACKEND (object);
- g_hash_table_unref (alsa->priv->devices);
g_hash_table_unref (alsa->priv->devices_ids);
G_OBJECT_CLASS (alsa_backend_parent_class)->finalize (object);
@@ -166,9 +182,8 @@ alsa_backend_open (MateMixerBackend *backend)
alsa = ALSA_BACKEND (backend);
- /* Poll ALSA for changes every 500 milliseconds, this actually only
- * discovers added or changed sound cards, sound card related events
- * are handled by AlsaDevices */
+ /* Poll ALSA for changes every second, this only discovers added or removed
+ * sound cards, sound card related events are handled by AlsaDevices */
alsa->priv->timeout_source = g_timeout_source_new_seconds (1);
g_source_set_callback (alsa->priv->timeout_source,
(GSourceFunc) read_devices,
@@ -197,61 +212,60 @@ alsa_backend_close (MateMixerBackend *backend)
g_source_destroy (alsa->priv->timeout_source);
- g_hash_table_remove_all (alsa->priv->devices);
+ if (alsa->priv->devices != NULL) {
+ g_list_free_full (alsa->priv->devices, g_object_unref);
+ alsa->priv->devices = NULL;
+ }
+
+ free_stream_list (alsa);
+
g_hash_table_remove_all (alsa->priv->devices_ids);
_mate_mixer_backend_set_state (backend, MATE_MIXER_STATE_IDLE);
}
-static GList *
+static const GList *
alsa_backend_list_devices (MateMixerBackend *backend)
{
- GList *list;
-
g_return_val_if_fail (ALSA_IS_BACKEND (backend), NULL);
- /* Convert the hash table to a linked list, this list is expected to be
- * cached in the main library */
- list = g_hash_table_get_values (ALSA_BACKEND (backend)->priv->devices);
- if (list != NULL)
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
-
- return list;
+ return ALSA_BACKEND (backend)->priv->devices;
}
-static GList *
+static const GList *
alsa_backend_list_streams (MateMixerBackend *backend)
{
- AlsaBackend *alsa;
- GHashTableIter iter;
- gpointer value;
- GList *list = NULL;
+ AlsaBackend *alsa;
g_return_val_if_fail (ALSA_IS_BACKEND (backend), NULL);
alsa = ALSA_BACKEND (backend);
- /* We don't keep a list or hash table of all streams here, instead walk
- * through the list of devices and create the list manually, each device
- * has at most one input and one output stream */
- g_hash_table_iter_init (&iter, alsa->priv->devices);
-
- while (g_hash_table_iter_next (&iter, NULL, &value)) {
- AlsaDevice *device = ALSA_DEVICE (value);
- AlsaStream *stream;
-
- stream = alsa_device_get_output_stream (device);
- if (stream != NULL)
- list = g_list_prepend (list, stream);
- stream = alsa_device_get_input_stream (device);
- if (stream != NULL)
- list = g_list_prepend (list, stream);
+ if (alsa->priv->streams == NULL) {
+ GList *list;
+
+ /* Walk through the list of devices and create the stream list, each
+ * device has at most one input and one output stream */
+ list = alsa->priv->devices;
+
+ while (list != NULL) {
+ AlsaDevice *device = ALSA_DEVICE (list->data);
+ AlsaStream *stream;
+
+ stream = alsa_device_get_input_stream (device);
+ if (stream != NULL) {
+ alsa->priv->streams =
+ g_list_append (alsa->priv->streams, g_object_ref (stream));
+ }
+ stream = alsa_device_get_output_stream (device);
+ if (stream != NULL) {
+ alsa->priv->streams =
+ g_list_append (alsa->priv->streams, g_object_ref (stream));
+ }
+ list = list->next;
+ }
}
-
- if (list != NULL)
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
-
- return list;
+ return alsa->priv->streams;
}
static gboolean
@@ -260,12 +274,12 @@ read_devices (AlsaBackend *alsa)
gint num;
gint ret;
gchar card[16];
- gboolean changed = FALSE;
+ gboolean added = FALSE;
/* Read the default device first, it will be either one of the hardware cards
* that will be queried later, or a software mixer */
if (read_device (alsa, "default") == TRUE)
- changed = TRUE;
+ added = TRUE;
for (num = -1;;) {
/* Read number of the next sound card */
@@ -277,12 +291,12 @@ read_devices (AlsaBackend *alsa)
g_snprintf (card, sizeof (card), "hw:%d", num);
if (read_device (alsa, card) == TRUE)
- changed = TRUE;
+ added = TRUE;
}
/* If any card has been added, make sure we have the most suitable default
* input and output streams */
- if (changed == TRUE) {
+ if (added == TRUE) {
select_default_input_stream (alsa);
select_default_output_stream (alsa);
}
@@ -300,15 +314,13 @@ read_device (AlsaBackend *alsa, const gchar *card)
/* The device may be already known, remove it if it's known and fails
* to be read, this happens for example when PulseAudio is killed */
- device = g_hash_table_lookup (alsa->priv->devices, card);
-
ret = snd_ctl_open (&ctl, card, 0);
if (ret < 0) {
g_warning ("Failed to open ALSA control for %s: %s",
card,
snd_strerror (ret));
- if (device != NULL)
- remove_device (alsa, device);
+
+ remove_device_by_name (alsa, card);
return FALSE;
}
@@ -317,9 +329,8 @@ read_device (AlsaBackend *alsa, const gchar *card)
ret = snd_ctl_card_info (ctl, info);
if (ret < 0) {
g_warning ("Failed to read card info: %s", snd_strerror (ret));
- if (device != NULL)
- remove_device (alsa, device);
+ remove_device_by_name (alsa, card);
snd_ctl_close (ctl);
return FALSE;
}
@@ -342,11 +353,7 @@ read_device (AlsaBackend *alsa, const gchar *card)
return FALSE;
}
- g_object_set_data_full (G_OBJECT (device),
- "__matemixer_alsa_device_id",
- g_strdup (id),
- g_free);
-
+ ALSA_DEVICE_SET_ID (device, id);
add_device (alsa, device);
snd_ctl_close (ctl);
@@ -356,19 +363,13 @@ read_device (AlsaBackend *alsa, const gchar *card)
static void
add_device (AlsaBackend *alsa, AlsaDevice *device)
{
- const gchar *name;
-
- name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device));
+ alsa->priv->devices = g_list_insert_sorted_with_data (alsa->priv->devices,
+ device,
+ (GCompareDataFunc) compare_devices,
+ NULL);
- g_hash_table_insert (alsa->priv->devices,
- g_strdup (name),
- g_object_ref (device));
-
- /* Remember the device identifier, use a single string copy as we only free
- * the hash table key */
- g_hash_table_add (alsa->priv->devices_ids,
- g_strdup (g_object_get_data (G_OBJECT (device),
- "__matemixer_alsa_device_id")));
+ /* Keep track of device identifiers */
+ g_hash_table_add (alsa->priv->devices_ids, g_strdup (ALSA_DEVICE_GET_ID (device)));
g_signal_connect_swapped (G_OBJECT (device),
"closed",
@@ -379,7 +380,22 @@ add_device (AlsaBackend *alsa, AlsaDevice *device)
G_CALLBACK (remove_stream),
alsa);
- g_signal_emit_by_name (G_OBJECT (alsa), "device-added", name);
+ g_signal_connect_swapped (G_OBJECT (device),
+ "closed",
+ G_CALLBACK (free_stream_list),
+ alsa);
+ g_signal_connect_swapped (G_OBJECT (device),
+ "stream-added",
+ G_CALLBACK (free_stream_list),
+ alsa);
+ g_signal_connect_swapped (G_OBJECT (device),
+ "stream-removed",
+ G_CALLBACK (free_stream_list),
+ alsa);
+
+ g_signal_emit_by_name (G_OBJECT (alsa),
+ "device-added",
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
/* Load the device elements after emitting device-added, because the load
* function will most likely emit stream-added on the device and backend */
@@ -389,27 +405,48 @@ add_device (AlsaBackend *alsa, AlsaDevice *device)
static void
remove_device (AlsaBackend *alsa, AlsaDevice *device)
{
- const gchar *name;
+ GList *item;
+
+ item = g_list_find (alsa->priv->devices, device);
+ if (item != NULL)
+ remove_device_by_list_item (alsa, item);
+}
+
+static void
+remove_device_by_name (AlsaBackend *alsa, const gchar *name)
+{
+ GList *item;
+
+ item = g_list_find_custom (alsa->priv->devices, name, compare_device_name);
+ if (item != NULL)
+ remove_device_by_list_item (alsa, item);
+}
+
+static void
+remove_device_by_list_item (AlsaBackend *alsa, GList *item)
+{
+ AlsaDevice *device;
+
+ device = ALSA_DEVICE (item->data);
- name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device));
+ g_signal_handlers_disconnect_by_data (G_OBJECT (device), alsa);
- g_signal_handlers_disconnect_by_func (G_OBJECT (device),
- G_CALLBACK (remove_device),
- alsa);
- g_signal_handlers_disconnect_by_func (G_OBJECT (device),
- G_CALLBACK (remove_stream),
- alsa);
+ if (alsa_device_is_open (device) == TRUE)
+ alsa_device_close (device);
+
+ alsa->priv->devices = g_list_delete_link (alsa->priv->devices, item);
- /* Remove the device */
g_hash_table_remove (alsa->priv->devices_ids,
- g_object_get_data (G_OBJECT (device),
- "__matemixer_alsa_device_id"));
+ ALSA_DEVICE_GET_ID (device));
+
+ /* The list may and may not have been invalidate by device signals */
+ free_stream_list (alsa);
- // XXX close the device and make it remove streams
- g_hash_table_remove (alsa->priv->devices, name);
g_signal_emit_by_name (G_OBJECT (alsa),
"device-removed",
- name);
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
+
+ g_object_unref (device);
}
static void
@@ -419,7 +456,6 @@ remove_stream (AlsaBackend *alsa, const gchar *name)
stream = mate_mixer_backend_get_default_input_stream (MATE_MIXER_BACKEND (alsa));
- // XXX see if the change happens after stream is removed or before
if (stream != NULL && strcmp (mate_mixer_stream_get_name (stream), name) == 0)
select_default_input_stream (alsa);
@@ -432,36 +468,19 @@ remove_stream (AlsaBackend *alsa, const gchar *name)
static void
select_default_input_stream (AlsaBackend *alsa)
{
- AlsaDevice *device;
- AlsaStream *stream;
- gchar card[16];
- gint num;
-
- /* Always prefer stream in the "default" device */
- device = g_hash_table_lookup (alsa->priv->devices, "default");
- if (device != NULL) {
- stream = alsa_device_get_input_stream (device);
- if (stream != NULL) {
- _mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (alsa),
- MATE_MIXER_STREAM (stream));
- return;
- }
- }
+ GList *list;
- /* If there is no input stream in the default device, search the cards in
- * the correct order */
- for (num = 0;; num++) {
- g_snprintf (card, sizeof (card), "hw:%d", num);
+ list = alsa->priv->devices;
+ while (list != NULL) {
+ AlsaDevice *device = ALSA_DEVICE (list->data);
+ AlsaStream *stream = alsa_device_get_input_stream (device);
- device = g_hash_table_lookup (alsa->priv->devices, card);
- if (device == NULL)
- break;
- stream = alsa_device_get_input_stream (device);
if (stream != NULL) {
_mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (alsa),
MATE_MIXER_STREAM (stream));
return;
}
+ list = list->next;
}
/* In the worst case unset the default stream */
@@ -471,38 +490,50 @@ select_default_input_stream (AlsaBackend *alsa)
static void
select_default_output_stream (AlsaBackend *alsa)
{
- AlsaDevice *device;
- AlsaStream *stream;
- gchar card[16];
- gint num;
-
- /* Always prefer stream in the "default" device */
- device = g_hash_table_lookup (alsa->priv->devices, "default");
- if (device != NULL) {
- stream = alsa_device_get_output_stream (device);
- if (stream != NULL) {
- _mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (alsa),
- MATE_MIXER_STREAM (stream));
- return;
- }
- }
+ GList *list;
- /* If there is no input stream in the default device, search the cards in
- * the correct order */
- for (num = 0;; num++) {
- g_snprintf (card, sizeof (card), "hw:%d", num);
+ list = alsa->priv->devices;
+ while (list != NULL) {
+ AlsaDevice *device = ALSA_DEVICE (list->data);
+ AlsaStream *stream = alsa_device_get_output_stream (device);
- device = g_hash_table_lookup (alsa->priv->devices, card);
- if (device == NULL)
- break;
- stream = alsa_device_get_output_stream (device);
if (stream != NULL) {
_mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (alsa),
MATE_MIXER_STREAM (stream));
return;
}
+ list = list->next;
}
/* In the worst case unset the default stream */
_mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (alsa), NULL);
}
+
+static void
+free_stream_list (AlsaBackend *alsa)
+{
+ if (alsa->priv->streams == NULL)
+ return;
+
+ g_list_free_full (alsa->priv->streams, g_object_unref);
+
+ alsa->priv->streams = NULL;
+}
+
+static gint
+compare_devices (gconstpointer a, gconstpointer b)
+{
+ MateMixerDevice *d1 = MATE_MIXER_DEVICE (a);
+ MateMixerDevice *d2 = MATE_MIXER_DEVICE (b);
+
+ return strcmp (mate_mixer_device_get_name (d1), mate_mixer_device_get_name (d2));
+}
+
+static gint
+compare_device_name (gconstpointer a, gconstpointer b)
+{
+ MateMixerDevice *device = MATE_MIXER_DEVICE (a);
+ const gchar *name = (const gchar *) b;
+
+ return strcmp (mate_mixer_device_get_name (device), name);
+}
diff --git a/backends/alsa/alsa-constants.c b/backends/alsa/alsa-constants.c
index 2124a2e..7b7021f 100644
--- a/backends/alsa/alsa-constants.c
+++ b/backends/alsa/alsa-constants.c
@@ -22,15 +22,190 @@
#include "alsa-constants.h"
-// XXX add more and probably move them somewhere else
+/*
+ * These lists of ALSA mixer elements are based on PulseAudio's mixer paths and own
+ * observations. The intention is to provide translatable and in some cases better
+ * readable labels and role assignments. The controls list is also used for selecting
+ * the default controls and the selection machanism relies on the order of elements,
+ * so more useful elements should be placed on the top. The last two boolean values
+ * indicate whether we prefer the element to be used as a default input or output
+ * control.
+ *
+ * Of course the lists are very incomplete and it would be great if users validated and
+ * refreshed them from time to time.
+ */
const AlsaControlInfo alsa_controls[] =
{
- { "Master", N_("Master"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER },
- { "Speaker", N_("Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER },
- { "Capture", N_("Capture"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER },
- { "PCM", N_("PCM"), MATE_MIXER_STREAM_CONTROL_ROLE_PCM },
- { "Line", N_("Line"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT },
- { "Mic", N_("Mic"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT },
+ /* Output controls */
+ { "Master", N_("Master"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, FALSE, TRUE },
+ { "Hardware Master", N_("Hardware Master"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, FALSE, TRUE },
+ { "PCM", N_("PCM"), MATE_MIXER_STREAM_CONTROL_ROLE_PCM, FALSE, TRUE },
+ { "Desktop Speaker", N_("Desktop Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Speaker", N_("Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Front", N_("Front Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Front Speaker", N_("Front Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Speaker Front", N_("Front Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Headphone", N_("Headphone"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Headphone2", N_("Headphone 2"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Headset", N_("Headset"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Master Surround", N_("Surround Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Surround", N_("Surround Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Surround Speaker", N_("Surround Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Speaker Surround", N_("Surround Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Center", N_("Center Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Center Speaker", N_("Center Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "CLFE", N_("CLFE Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Speaker CLFE", N_("CLFE Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Master Mono", N_("Master Mono"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, FALSE, TRUE },
+ { "Master Digital", N_("Master Digital"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, FALSE, TRUE },
+ { "Digital/SPDIF", N_("Digital"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, FALSE, TRUE },
+ { "Speaker Side", N_("Side Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Side", N_("Side Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Rear", N_("Rear Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, TRUE },
+ { "Wave", N_("Wave"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, FALSE, TRUE },
+ { "Phone", N_("Phone"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, FALSE, TRUE },
+ { "CD", N_("CD"), MATE_MIXER_STREAM_CONTROL_ROLE_CD, FALSE, TRUE },
+ { "Music", N_("Music"), MATE_MIXER_STREAM_CONTROL_ROLE_MUSIC, FALSE, TRUE },
+ { "AC97", N_("AC97"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, FALSE, TRUE },
+ { "LFE", N_("LFE Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, FALSE },
+ { "LFE Speaker", N_("LFE Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, FALSE },
+ { "Bass Speaker", N_("Bass Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, FALSE },
+ { "PC Speaker", N_("PC Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, FALSE, FALSE },
+ { "Synth", N_("Synth"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, FALSE, FALSE },
+ { "MIDI", N_("MIDI"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, FALSE, FALSE },
+ { "Synth/MIDI", N_("Synth/MIDI"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, FALSE, FALSE },
+ { "Bass", N_("Bass"), MATE_MIXER_STREAM_CONTROL_ROLE_BASS, FALSE, FALSE },
+ { "Treble", N_("Treble"), MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE, FALSE, FALSE },
+
+ /* Input controls */
+ { "Capture", N_("Capture"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, TRUE, FALSE },
+ { "Mic", N_("Microphone"), MATE_MIXER_STREAM_CONTROL_ROLE_MICROPHONE, TRUE, FALSE },
+ { "Mic/Line", N_("Microphone/Line In"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, TRUE, FALSE },
+ { "Internal Mic", N_("Internal Microphone"), MATE_MIXER_STREAM_CONTROL_ROLE_MICROPHONE, TRUE, FALSE },
+ { "Int Mic", N_("Internal Microphone"), MATE_MIXER_STREAM_CONTROL_ROLE_MICROPHONE, TRUE, FALSE },
+ { "Front Mic", N_("Front Microphone"), MATE_MIXER_STREAM_CONTROL_ROLE_MICROPHONE, TRUE, FALSE },
+ { "Rear Mic", N_("Rear Microphone"), MATE_MIXER_STREAM_CONTROL_ROLE_MICROPHONE, TRUE, FALSE },
+ { "Dock Mic", N_("Dock Microphone"), MATE_MIXER_STREAM_CONTROL_ROLE_MICROPHONE, TRUE, FALSE },
+ { "Headphone Mic", N_("Headphone Microphone"), MATE_MIXER_STREAM_CONTROL_ROLE_MICROPHONE, TRUE, FALSE },
+ { "Headset Mic", N_("Headset Microphone"), MATE_MIXER_STREAM_CONTROL_ROLE_MICROPHONE, TRUE, FALSE },
+ { "Inverted Internal Mic", N_("Inverted Internal Microphone"), MATE_MIXER_STREAM_CONTROL_ROLE_MICROPHONE, TRUE, FALSE },
+ { "Line", N_("Line In"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, TRUE, FALSE },
+ { "Aux", N_("Auxiliary"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, TRUE, FALSE },
+ { "Video", N_("Video"), MATE_MIXER_STREAM_CONTROL_ROLE_VIDEO, TRUE, FALSE },
+ { "TV Tuner", N_("TV Tuner"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, TRUE, FALSE },
+ { "FM", N_("FM"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, TRUE, FALSE },
+ { "Mic Boost", N_("Microphone Boost"), MATE_MIXER_STREAM_CONTROL_ROLE_BOOST, FALSE, FALSE },
+ { "Mic Boost (+20dB)", N_("Microphone Boost (+20dB)"), MATE_MIXER_STREAM_CONTROL_ROLE_BOOST, FALSE, FALSE },
+ { "Int Mic Boost", N_("Internal Microphone Boost"), MATE_MIXER_STREAM_CONTROL_ROLE_BOOST, FALSE, FALSE },
+ { "Internal Mic Boost", N_("Internal Microphone Boost"), MATE_MIXER_STREAM_CONTROL_ROLE_BOOST, FALSE, FALSE },
+ { "Front Mic Boost", N_("Front Microphone Boost"), MATE_MIXER_STREAM_CONTROL_ROLE_BOOST, FALSE, FALSE },
+ { "Rear Mic Boost", N_("Rear Microphone Boost"), MATE_MIXER_STREAM_CONTROL_ROLE_BOOST, FALSE, FALSE },
+ { "Dock Mic Boost", N_("Dock Microphone Boost"), MATE_MIXER_STREAM_CONTROL_ROLE_BOOST, FALSE, FALSE },
+ { "Headphone Mic Boost", N_("Headphone Microphone Boost"), MATE_MIXER_STREAM_CONTROL_ROLE_BOOST, FALSE, FALSE },
+ { "Headset Mic Boost", N_("Headset Microphone Boost"), MATE_MIXER_STREAM_CONTROL_ROLE_BOOST, FALSE, FALSE },
+ { "Line Boost", N_("Line In Boost"), MATE_MIXER_STREAM_CONTROL_ROLE_BOOST, FALSE, FALSE },
+ { NULL }
+};
+
+/* Switches and toggles */
+const AlsaSwitchInfo alsa_switches[] =
+{
+ { "Analog Output", N_("Analog Output"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "Analog Source", N_("Analog Source"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "Capture Source", N_("Capture Source"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "Input Source", N_("Input Source"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "Input Source Select", N_("Input Source Select"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "Digital Input Source", N_("Digital Input Source"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "PCM Capture Source", N_("PCM Capture Source"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "IEC958 Playback Source", N_("Digital Playback Source"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "Mono Output Select", N_("Mono Output Select"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "Shared Mic/Line in", N_("Shared Mic/Line In"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "Mic Select", N_("Microphone Select"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "Mic Jack Mode", N_("Microphone Jack Mode"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "Surround Jack Mode", N_("Surround Jack Mode"), MATE_MIXER_SWITCH_ROLE_UNKNOWN },
+ { "Auto-Mute Mode", N_("Auto-Mute Mode"), MATE_MIXER_SWITCH_ROLE_UNKNOWN },
+
+ /* (Probably) toggles */
+ { "External Amplifier", N_("External Amplifier"), MATE_MIXER_SWITCH_ROLE_UNKNOWN },
+ { "Bass Boost", N_("Bass Boost"), MATE_MIXER_SWITCH_ROLE_BOOST },
+ { "Capture Boost", N_("Capture Boost"), MATE_MIXER_SWITCH_ROLE_BOOST },
+ { "IEC958", N_("Digital"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "IEC958 In", N_("Digital In"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "IEC958 Optical Raw", N_("Optical"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "Auto Gain Control", N_("Auto Gain Control"), MATE_MIXER_SWITCH_ROLE_UNKNOWN },
+ { "Mix", N_("Mix"), MATE_MIXER_SWITCH_ROLE_UNKNOWN },
+ { "Mix Mono", N_("Mix Mono"), MATE_MIXER_SWITCH_ROLE_UNKNOWN },
+ { "Mic Capture", N_("Mic Capture"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "Input 1", N_("Input 1"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { "Input 2", N_("Input 2"), MATE_MIXER_SWITCH_ROLE_PORT },
+ { NULL }
+};
+
+const AlsaSwitchOptionInfo alsa_switch_options[] =
+{
+ /* Output options */
+ { "Speakers", N_("Speakers"), NULL },
+ { "Headphones", N_("Headphones"), NULL },
+ { "FP Headphones", N_("Front Panel Headphones"), NULL },
+
+ /* Microphone options */
+ { "Mic", N_("Microphone"), "audio-input-microphone" },
+ { "Microphone", N_("Microphone"), "audio-input-microphone" },
+ { "Mic1", N_("Microphone 1"), "audio-input-microphone" },
+ { "Mic2", N_("Microphone 2"), "audio-input-microphone" },
+ { "Mic in", N_("Microphone In"), "audio-input-microphone" },
+ { "Mic In", N_("Microphone In"), "audio-input-microphone" },
+ { "Front Mic", N_("Front Microphone"), "audio-input-microphone" },
+ { "Front Microphone", N_("Front Microphone"), "audio-input-microphone" },
+ { "Headphone Mic", N_("Headphone Microphone"), "audio-input-microphone" },
+ { "Headset Mic", N_("Headset Microphone"), "audio-input-microphone" },
+ { "Dock Mic", N_("Dock Microphone"), "audio-input-microphone" },
+ { "Internal Mic", N_("Internal Microphone"), "audio-input-microphone" },
+ { "Int Mic", N_("Internal Microphone"), "audio-input-microphone" },
+ { "Internal Mic 1", N_("Internal Microphone 1"), "audio-input-microphone" },
+ { "iMic", N_("Internal Microphone"), "audio-input-microphone" },
+ { "i-Mic", N_("Internal Microphone"), "audio-input-microphone" },
+ { "IntMic", N_("Internal Microphone"), "audio-input-microphone" },
+ { "Int DMic", N_("Internal Digital Microphone"), "audio-input-microphone" },
+ { "Digital Mic", N_("Digital Microphone"), "audio-input-microphone" },
+ { "Digital Mic 1", N_("Digital Microphone 1"), "audio-input-microphone" },
+ { "Digital Mic 2", N_("Digital Microphone 2"), "audio-input-microphone" },
+ { "D-Mic", N_("Digital Microphone"), "audio-input-microphone" },
+ { "ExtMic", N_("External Microphone"), "audio-input-microphone" },
+ { "Ext Mic", N_("External Microphone"), "audio-input-microphone" },
+ { "E-Mic", N_("External Microphone"), "audio-input-microphone" },
+ { "e-Mic", N_("External Microphone"), "audio-input-microphone" },
+ { "Rear Mic", N_("Rear Microphone"), "audio-input-microphone" },
+ { "Cam Mic", N_("Camera Microphone"), "audio-input-microphone" },
+
+ /* Other options */
+ { "Analog", N_("Analog"), NULL },
+ { "Analog In", N_("Analog In"), NULL },
+ { "Analog Inputs", N_("Analog Inputs"), NULL },
+ { "Line in", N_("Line In"), NULL },
+ { "Line In", N_("Line In"), NULL },
+ { "Line-In", N_("Line In"), NULL },
+ { "Mic/Line", N_("Microphone/Line In"), NULL },
+ { "Line/Mic", N_("Line In/Microphone"), NULL },
+ { "LineIn", N_("Line In"), NULL },
+ { "Line", N_("Line In"), NULL },
+ { "Input1", N_("Input 1"), NULL },
+ { "Input2", N_("Input 2"), NULL },
+ { "IEC958 In", N_("Digital In"), NULL },
+ { "TV Tuner", N_("TV Tuner"), NULL },
+ { "FM", N_("FM"), NULL },
+ { "AUX", N_("Auxiliary"), NULL },
+ { "AUX IN", N_("Auxiliary In"), NULL },
+ { "Aux In", N_("Auxiliary In"), NULL },
+ { "Aux", N_("Auxiliary"), NULL },
+ { "Aux0", N_("Auxiliary 0"), NULL },
+ { "Aux1", N_("Auxiliary 1"), NULL },
+ { "Aux2", N_("Auxiliary 2"), NULL },
+ { "Aux3", N_("Auxiliary 3"), NULL },
+ { "Docking-Station", N_("Docking Station"), NULL },
+ { "Mixer", N_("Mixer"), NULL },
+ { "Unknown1", N_("Unknown 1"), NULL },
+ { "Unknown2", N_("Unknown 2"), NULL },
{ NULL }
};
diff --git a/backends/alsa/alsa-constants.h b/backends/alsa/alsa-constants.h
index 81257c7..8137289 100644
--- a/backends/alsa/alsa-constants.h
+++ b/backends/alsa/alsa-constants.h
@@ -22,14 +22,35 @@
#include <alsa/asoundlib.h>
#include <libmatemixer/matemixer.h>
+G_BEGIN_DECLS
+
typedef struct {
gchar *name;
gchar *label;
MateMixerStreamControlRole role;
+ gboolean use_default_input;
+ gboolean use_default_output;
} AlsaControlInfo;
+typedef struct {
+ gchar *name;
+ gchar *label;
+ MateMixerSwitchRole role;
+} AlsaSwitchInfo;
+
+typedef struct {
+ gchar *name;
+ gchar *label;
+ gchar *icon;
+} AlsaSwitchOptionInfo;
+
extern const AlsaControlInfo alsa_controls[];
+extern const AlsaSwitchInfo alsa_switches[];
+extern const AlsaSwitchOptionInfo alsa_switch_options[];
+
extern const MateMixerChannelPosition alsa_channel_map_from[];
extern const snd_mixer_selem_channel_id_t alsa_channel_map_to[];
+G_END_DECLS
+
#endif /* ALSA_CONSTANTS_H */
diff --git a/backends/alsa/alsa-device.c b/backends/alsa/alsa-device.c
index 5acc6f5..f7f705e 100644
--- a/backends/alsa/alsa-device.c
+++ b/backends/alsa/alsa-device.c
@@ -15,7 +15,9 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#include <strings.h>
+#include <string.h>
+#include <libintl.h>
+
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
@@ -35,6 +37,18 @@
#define ALSA_DEVICE_ICON "audio-card"
+#define ALSA_STREAM_CONTROL_GET_SCORE(c) \
+ (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (c), \
+ "__matemixer_alsa_control_score")))
+
+#define ALSA_STREAM_CONTROL_SET_SCORE(c,score) \
+ (g_object_set_data (G_OBJECT (c), \
+ "__matemixer_alsa_control_score", \
+ GINT_TO_POINTER (score)))
+
+#define ALSA_STREAM_DEFAULT_CONTROL_GET_SCORE(s) \
+ (ALSA_STREAM_CONTROL_GET_SCORE (alsa_stream_get_default_control (ALSA_STREAM (s))))
+
struct _AlsaDevicePrivate
{
snd_mixer_t *handle;
@@ -43,7 +57,8 @@ struct _AlsaDevicePrivate
GCond cond;
AlsaStream *input;
AlsaStream *output;
- GHashTable *switches;
+ GList *streams;
+ GList *switches;
gboolean events_pending;
};
@@ -61,64 +76,83 @@ static void alsa_device_finalize (GObject *object);
G_DEFINE_TYPE (AlsaDevice, alsa_device, MATE_MIXER_TYPE_DEVICE)
-static MateMixerSwitch *alsa_device_get_switch (MateMixerDevice *mmd,
- const gchar *name);
+static const GList * alsa_device_list_streams (MateMixerDevice *mmd);
+static const GList * alsa_device_list_switches (MateMixerDevice *mmd);
+
+static gboolean add_stream_input_control (AlsaDevice *device,
+ snd_mixer_elem_t *el);
+static gboolean add_stream_output_control (AlsaDevice *device,
+ snd_mixer_elem_t *el);
+
+static gboolean add_switch (AlsaDevice *device,
+ AlsaStream *stream,
+ snd_mixer_elem_t *el);
-static GList * alsa_device_list_streams (MateMixerDevice *mmd);
-static GList * alsa_device_list_switches (MateMixerDevice *mmd);
+static gboolean add_device_switch (AlsaDevice *device,
+ snd_mixer_elem_t *el);
-static gboolean add_stream_input_control (AlsaDevice *device,
- snd_mixer_elem_t *el);
-static gboolean add_stream_output_control (AlsaDevice *device,
- snd_mixer_elem_t *el);
+static gboolean add_stream_input_switch (AlsaDevice *device,
+ snd_mixer_elem_t *el);
+static gboolean add_stream_output_switch (AlsaDevice *device,
+ snd_mixer_elem_t *el);
-static gboolean add_switch (AlsaDevice *device,
- AlsaStream *stream,
- snd_mixer_elem_t *el);
+static gboolean add_stream_input_toggle (AlsaDevice *device,
+ snd_mixer_elem_t *el);
+static gboolean add_stream_output_toggle (AlsaDevice *device,
+ snd_mixer_elem_t *el);
-static gboolean add_device_switch (AlsaDevice *device,
- snd_mixer_elem_t *el);
+static void load_element (AlsaDevice *device,
+ snd_mixer_elem_t *el);
-static gboolean add_stream_input_switch (AlsaDevice *device,
- snd_mixer_elem_t *el);
-static gboolean add_stream_output_switch (AlsaDevice *device,
- snd_mixer_elem_t *el);
+static void load_elements_by_name (AlsaDevice *device,
+ const gchar *name);
-static gboolean add_stream_input_toggle (AlsaDevice *device,
- snd_mixer_elem_t *el);
-static gboolean add_stream_output_toggle (AlsaDevice *device,
- snd_mixer_elem_t *el);
+static void remove_elements_by_name (AlsaDevice *device,
+ const gchar *name);
-static void load_element (AlsaDevice *device,
- snd_mixer_elem_t *el);
+static void handle_poll (AlsaDevice *device);
-static void load_elements_by_name (AlsaDevice *device,
- const gchar *name);
+static gboolean handle_process_events (AlsaDevice *device);
-static void remove_elements_by_name (AlsaDevice *device,
- const gchar *name);
+static int handle_callback (snd_mixer_t *handle,
+ guint mask,
+ snd_mixer_elem_t *el);
+static int handle_element_callback (snd_mixer_elem_t *el,
+ guint mask);
-static void handle_poll (AlsaDevice *device);
+static void validate_default_controls (AlsaDevice *device);
-static gboolean handle_process_events (AlsaDevice *device);
+static AlsaStreamControl *get_best_stream_control (AlsaStream *stream);
-static int handle_callback (snd_mixer_t *handle,
- guint mask,
- snd_mixer_elem_t *el);
-static int handle_element_callback (snd_mixer_elem_t *el,
- guint mask);
+static gchar * get_element_name (snd_mixer_elem_t *el);
-static void close_device (AlsaDevice *device);
+static void get_control_info (snd_mixer_elem_t *el,
+ gchar **name,
+ gchar **label,
+ MateMixerStreamControlRole *role,
+ gint *score);
+static void get_input_control_info (snd_mixer_elem_t *el,
+ gchar **name,
+ gchar **label,
+ MateMixerStreamControlRole *role,
+ gint *score);
+static void get_output_control_info (snd_mixer_elem_t *el,
+ gchar **name,
+ gchar **label,
+ MateMixerStreamControlRole *role,
+ gint *score);
-static gchar * get_element_name (snd_mixer_elem_t *el);
-static void get_control_info (snd_mixer_elem_t *el,
- gchar **name,
- gchar **label,
- MateMixerStreamControlRole *role);
+static void get_switch_info (snd_mixer_elem_t *el,
+ gchar **name,
+ gchar **label,
+ MateMixerSwitchRole *role);
-static void get_switch_info (snd_mixer_elem_t *el,
- gchar **name,
- gchar **label);
+static void close_mixer (AlsaDevice *device);
+
+static void free_stream_list (AlsaDevice *device);
+
+static gint compare_switch_name (gconstpointer a,
+ gconstpointer b);
static void
alsa_device_class_init (AlsaDeviceClass *klass)
@@ -131,14 +165,13 @@ alsa_device_class_init (AlsaDeviceClass *klass)
object_class->finalize = alsa_device_finalize;
device_class = MATE_MIXER_DEVICE_CLASS (klass);
- device_class->get_switch = alsa_device_get_switch;
device_class->list_streams = alsa_device_list_streams;
device_class->list_switches = alsa_device_list_switches;
signals[CLOSED] =
g_signal_new ("closed",
G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
+ G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (AlsaDeviceClass, closed),
NULL,
NULL,
@@ -157,11 +190,6 @@ alsa_device_init (AlsaDevice *device)
ALSA_TYPE_DEVICE,
AlsaDevicePrivate);
- device->priv->switches = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- g_object_unref);
-
device->priv->context = g_main_context_ref_thread_default ();
g_mutex_init (&device->priv->mutex);
@@ -178,7 +206,12 @@ alsa_device_dispose (GObject *object)
g_clear_object (&device->priv->input);
g_clear_object (&device->priv->output);
- g_hash_table_remove_all (device->priv->switches);
+ if (device->priv->switches != NULL) {
+ g_list_free_full (device->priv->switches, g_object_unref);
+ device->priv->switches = NULL;
+ }
+
+ free_stream_list (device);
G_OBJECT_CLASS (alsa_device_parent_class)->dispose (object);
}
@@ -193,11 +226,9 @@ alsa_device_finalize (GObject *object)
g_mutex_clear (&device->priv->mutex);
g_cond_clear (&device->priv->cond);
- g_hash_table_unref (device->priv->switches);
g_main_context_unref (device->priv->context);
- if (device->priv->handle != NULL)
- snd_mixer_close (device->priv->handle);
+ close_mixer (device);
G_OBJECT_CLASS (alsa_device_parent_class)->dispose (object);
}
@@ -208,7 +239,7 @@ alsa_device_new (const gchar *name, const gchar *label)
AlsaDevice *device;
gchar *stream_name;
- g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
g_return_val_if_fail (label != NULL, NULL);
device = g_object_new (ALSA_TYPE_DEVICE,
@@ -223,13 +254,13 @@ alsa_device_new (const gchar *name, const gchar *label)
stream_name = g_strdup_printf ("alsa-input-%s", name);
device->priv->input = alsa_stream_new (stream_name,
MATE_MIXER_DEVICE (device),
- MATE_MIXER_STREAM_INPUT);
+ MATE_MIXER_DIRECTION_INPUT);
g_free (stream_name);
stream_name = g_strdup_printf ("alsa-output-%s", name);
device->priv->output = alsa_stream_new (stream_name,
MATE_MIXER_DEVICE (device),
- MATE_MIXER_STREAM_OUTPUT);
+ MATE_MIXER_DIRECTION_OUTPUT);
g_free (stream_name);
return device;
@@ -289,6 +320,72 @@ alsa_device_open (AlsaDevice *device)
return TRUE;
}
+gboolean
+alsa_device_is_open (AlsaDevice *device)
+{
+ g_return_val_if_fail (ALSA_IS_DEVICE (device), FALSE);
+
+ if (device->priv->handle != NULL)
+ return TRUE;
+
+ return FALSE;
+}
+
+void
+alsa_device_close (AlsaDevice *device)
+{
+ GList *list;
+
+ g_return_if_fail (ALSA_IS_DEVICE (device));
+
+ if (device->priv->handle == NULL)
+ return;
+
+ /* Make each stream remove its controls and switches */
+ if (alsa_stream_has_controls_or_switches (device->priv->input) == TRUE) {
+ const gchar *name =
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (device->priv->input));
+
+ alsa_stream_remove_all (device->priv->input);
+ free_stream_list (device);
+
+ g_signal_emit_by_name (G_OBJECT (device),
+ "stream-removed",
+ name);
+ }
+
+ if (alsa_stream_has_controls_or_switches (device->priv->output) == TRUE) {
+ const gchar *name =
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (device->priv->output));
+
+ alsa_stream_remove_all (device->priv->output);
+ free_stream_list (device);
+
+ g_signal_emit_by_name (G_OBJECT (device),
+ "stream-removed",
+ name);
+ }
+
+ /* Remove device switches */
+ list = device->priv->switches;
+ while (list != NULL) {
+ MateMixerSwitch *swtch = MATE_MIXER_SWITCH (list->data);
+ GList *next = list->next;
+
+ device->priv->switches = g_list_delete_link (device->priv->switches, list);
+ g_signal_emit_by_name (G_OBJECT (device),
+ "switch-removed",
+ mate_mixer_switch_get_name (swtch));
+ g_object_unref (swtch);
+
+ list = next;
+ }
+
+ close_mixer (device);
+
+ g_signal_emit (G_OBJECT (device), signals[CLOSED], 0);
+}
+
void
alsa_device_load (AlsaDevice *device)
{
@@ -307,6 +404,9 @@ alsa_device_load (AlsaDevice *device)
el = snd_mixer_elem_next (el);
}
+ /* Assign proper default controls */
+ validate_default_controls (device);
+
/* Set callback for ALSA events */
snd_mixer_set_callback (device->priv->handle, handle_callback);
snd_mixer_set_callback_private (device->priv->handle, device);
@@ -332,7 +432,7 @@ alsa_device_get_input_stream (AlsaDevice *device)
/* Normally controlless streams should not exist, here we simulate the
* behaviour for the owning instance */
- if (alsa_stream_is_empty (device->priv->input) == FALSE)
+ if (alsa_stream_has_controls_or_switches (device->priv->input) == TRUE)
return device->priv->input;
return NULL;
@@ -345,7 +445,7 @@ alsa_device_get_output_stream (AlsaDevice *device)
/* Normally controlless streams should not exist, here we simulate the
* behaviour for the owning instance */
- if (alsa_stream_is_empty (device->priv->output) == FALSE)
+ if (alsa_stream_has_controls_or_switches (device->priv->output) == TRUE)
return device->priv->output;
return NULL;
@@ -360,44 +460,39 @@ add_element (AlsaDevice *device, AlsaStream *stream, AlsaElement *element)
return FALSE;
if (stream != NULL) {
- gboolean empty = FALSE;
-
- if (alsa_stream_is_empty (stream) == TRUE) {
+ if (alsa_stream_has_controls_or_switches (stream) == FALSE) {
const gchar *name =
mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream));
+ free_stream_list (device);
+
/* Pretend the stream has just been created now that we are adding
* the first control */
g_signal_emit_by_name (G_OBJECT (device),
"stream-added",
name);
- empty = TRUE;
}
if (ALSA_IS_STREAM_CONTROL (element)) {
+ /* Stream control */
alsa_stream_add_control (stream, ALSA_STREAM_CONTROL (element));
-
- /* If this is the first control, set it as the default one.
- * The controls often seem to come in the order of importance, but this is
- * driver specific, so we may later see if there is another control which
- * better matches the default. */
- if (empty == TRUE)
- alsa_stream_set_default_control (stream, ALSA_STREAM_CONTROL (element));
-
added = TRUE;
} else if (ALSA_IS_SWITCH (element)) {
/* Switch belonging to a stream */
alsa_stream_add_switch (stream, ALSA_SWITCH (element));
added = TRUE;
+ } else if (ALSA_IS_TOGGLE (element)) {
+ /* Toggle belonging to a stream */
+ alsa_stream_add_toggle (stream, ALSA_TOGGLE (element));
+ added = TRUE;
}
- } else if (ALSA_IS_SWITCH (element)) {
+ } else if (ALSA_IS_SWITCH (element) || ALSA_IS_TOGGLE (element)) {
/* Switch belonging to the device */
const gchar *name =
mate_mixer_switch_get_name (MATE_MIXER_SWITCH (element));
- g_hash_table_insert (device->priv->switches,
- g_strdup (name),
- g_object_ref (element));
+ device->priv->switches =
+ g_list_append (device->priv->switches, g_object_ref (element));
g_signal_emit_by_name (G_OBJECT (device),
"switch-added",
@@ -414,47 +509,32 @@ add_element (AlsaDevice *device, AlsaStream *stream, AlsaElement *element)
return added;
}
-static MateMixerSwitch *
-alsa_device_get_switch (MateMixerDevice *mmd, const gchar *name)
-{
- g_return_val_if_fail (ALSA_IS_DEVICE (mmd), NULL);
- g_return_val_if_fail (name != NULL, NULL);
-
- return g_hash_table_lookup (ALSA_DEVICE (mmd)->priv->switches, name);
-}
-
-static GList *
+static const GList *
alsa_device_list_streams (MateMixerDevice *mmd)
{
AlsaDevice *device;
- GList *list = NULL;
g_return_val_if_fail (ALSA_IS_DEVICE (mmd), NULL);
device = ALSA_DEVICE (mmd);
- if (device->priv->output != NULL)
- list = g_list_prepend (list, g_object_ref (device->priv->output));
- if (device->priv->input != NULL)
- list = g_list_prepend (list, g_object_ref (device->priv->input));
-
- return list;
+ if (device->priv->streams == NULL) {
+ if (device->priv->output != NULL)
+ device->priv->streams = g_list_prepend (device->priv->streams,
+ g_object_ref (device->priv->output));
+ if (device->priv->input != NULL)
+ device->priv->streams = g_list_prepend (device->priv->streams,
+ g_object_ref (device->priv->input));
+ }
+ return device->priv->streams;
}
-static GList *
+static const GList *
alsa_device_list_switches (MateMixerDevice *mmd)
{
- GList *list;
-
g_return_val_if_fail (ALSA_IS_DEVICE (mmd), NULL);
- /* Convert the hash table to a linked list, this list is expected to be
- * cached in the main library */
- list = g_hash_table_get_values (ALSA_DEVICE (mmd)->priv->switches);
- if (list != NULL)
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
-
- return list;
+ return ALSA_DEVICE (mmd)->priv->switches;
}
static gboolean
@@ -463,25 +543,28 @@ add_stream_input_control (AlsaDevice *device, snd_mixer_elem_t *el)
AlsaStreamControl *control;
gchar *name;
gchar *label;
+ gboolean ret;
+ gint score;
MateMixerStreamControlRole role;
- get_control_info (el, &name, &label, &role);
+ get_input_control_info (el, &name, &label, &role, &score);
- g_debug ("Found device %s input control %s",
+ g_debug ("Reading device %s input control %s",
mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)),
- label);
+ name);
- control = alsa_stream_input_control_new (name, label, role);
+ control = alsa_stream_input_control_new (name, label, role, device->priv->input);
g_free (name);
g_free (label);
+ ALSA_STREAM_CONTROL_SET_SCORE (control, score);
+
alsa_element_set_snd_element (ALSA_ELEMENT (control), el);
- if (add_element (device, device->priv->input, ALSA_ELEMENT (control)) == FALSE) {
- g_object_unref (control);
- return FALSE;
- }
- return TRUE;
+ ret = add_element (device, device->priv->input, ALSA_ELEMENT (control));
+
+ g_object_unref (control);
+ return ret;
}
static gboolean
@@ -490,49 +573,51 @@ add_stream_output_control (AlsaDevice *device, snd_mixer_elem_t *el)
AlsaStreamControl *control;
gchar *label;
gchar *name;
+ gboolean ret;
+ gint score;
MateMixerStreamControlRole role;
- get_control_info (el, &name, &label, &role);
+ get_output_control_info (el, &name, &label, &role, &score);
- g_debug ("Found device %s output control %s",
+ g_debug ("Reading device %s output control %s",
mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)),
- label);
+ name);
- control = alsa_stream_output_control_new (name, label, role);
+ control = alsa_stream_output_control_new (name, label, role, device->priv->output);
g_free (name);
g_free (label);
+ ALSA_STREAM_CONTROL_SET_SCORE (control, score);
+
alsa_element_set_snd_element (ALSA_ELEMENT (control), el);
- if (add_element (device, device->priv->output, ALSA_ELEMENT (control)) == FALSE) {
- g_object_unref (control);
- return FALSE;
- }
- return TRUE;
+ ret = add_element (device, device->priv->output, ALSA_ELEMENT (control));
+
+ g_object_unref (control);
+ return ret;
}
static AlsaToggle *
create_toggle (AlsaDevice *device, snd_mixer_elem_t *el, AlsaToggleType type)
{
- AlsaToggle *toggle;
- AlsaSwitchOption *on;
- AlsaSwitchOption *off;
- gchar *name;
- gchar *label;
+ AlsaToggle *toggle;
+ AlsaSwitchOption *on;
+ AlsaSwitchOption *off;
+ gchar *name;
+ gchar *label;
+ MateMixerSwitchRole role;
on = alsa_switch_option_new ("On", _("On"), NULL, 1);
off = alsa_switch_option_new ("Off", _("Off"), NULL, 0);
- get_switch_info (el, &name, &label);
- toggle = alsa_toggle_new (name,
- label,
- type,
- on, off);
- g_free (name);
- g_free (label);
+ get_switch_info (el, &name, &label, &role);
+
+ toggle = alsa_toggle_new (name, label, role, type, on, off);
alsa_element_set_snd_element (ALSA_ELEMENT (toggle), el);
+ g_free (name);
+ g_free (label);
g_object_unref (on);
g_object_unref (off);
@@ -542,14 +627,15 @@ create_toggle (AlsaDevice *device, snd_mixer_elem_t *el, AlsaToggleType type)
static gboolean
add_switch (AlsaDevice *device, AlsaStream *stream, snd_mixer_elem_t *el)
{
- AlsaElement *element = NULL;
- GList *options = NULL;
- gchar *name;
- gchar *label;
- gchar item[128];
- guint i;
- gint count;
- gint ret;
+ AlsaElement *element = NULL;
+ GList *options = NULL;
+ gchar *name;
+ gchar *label;
+ gchar item[128];
+ guint i;
+ gint count;
+ gboolean ret;
+ MateMixerSwitchRole role;
count = snd_mixer_selem_get_enum_items (el);
if G_UNLIKELY (count <= 0) {
@@ -560,30 +646,44 @@ add_switch (AlsaDevice *device, AlsaStream *stream, snd_mixer_elem_t *el)
}
for (i = 0; i < count; i++) {
- ret = snd_mixer_selem_get_enum_item_name (el, i,
- sizeof (item),
- item);
- if G_LIKELY (ret == 0)
- options = g_list_prepend (options,
- alsa_switch_option_new (item, item, NULL, i));
- else
+ gint ret = snd_mixer_selem_get_enum_item_name (el, i, sizeof (item), item);
+
+ if G_LIKELY (ret == 0) {
+ gint j;
+ AlsaSwitchOption *option = NULL;
+
+ for (j = 0; alsa_switch_options[j].name != NULL; j++)
+ if (strcmp (item, alsa_switch_options[j].name) == 0) {
+ option = alsa_switch_option_new (item,
+ gettext (alsa_switch_options[j].label),
+ alsa_switch_options[j].icon,
+ i);
+ break;
+ }
+
+ if (option == NULL)
+ option = alsa_switch_option_new (item, item, NULL, i);
+
+ options = g_list_prepend (options, option);
+ } else
g_warning ("Failed to read switch item name: %s", snd_strerror (ret));
}
- get_switch_info (el, &name, &label);
+ get_switch_info (el, &name, &label, &role);
/* Takes ownership of options */
- element = ALSA_ELEMENT (alsa_switch_new (name, label, g_list_reverse (options)));
+ element = ALSA_ELEMENT (alsa_switch_new (name, label,
+ role,
+ g_list_reverse (options)));
g_free (name);
g_free (label);
alsa_element_set_snd_element (element, el);
- if (add_element (device, stream, element) == FALSE) {
- g_object_unref (element);
- return FALSE;
- }
- return TRUE;
+ ret = add_element (device, stream, element);
+
+ g_object_unref (element);
+ return ret;
}
static gboolean
@@ -623,6 +723,7 @@ static gboolean
add_stream_input_toggle (AlsaDevice *device, snd_mixer_elem_t *el)
{
AlsaToggle *toggle;
+ gboolean ret;
g_debug ("Reading device %s input toggle %s",
mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)),
@@ -630,17 +731,17 @@ add_stream_input_toggle (AlsaDevice *device, snd_mixer_elem_t *el)
toggle = create_toggle (device, el, ALSA_TOGGLE_CAPTURE);
- if (add_element (device, device->priv->input, ALSA_ELEMENT (toggle)) == FALSE) {
- g_object_unref (toggle);
- return FALSE;
- }
- return TRUE;
+ ret = add_element (device, device->priv->input, ALSA_ELEMENT (toggle));
+
+ g_object_unref (toggle);
+ return ret;
}
static gboolean
add_stream_output_toggle (AlsaDevice *device, snd_mixer_elem_t *el)
{
AlsaToggle *toggle;
+ gboolean ret;
g_debug ("Reading device %s output toggle %s",
mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)),
@@ -648,11 +749,10 @@ add_stream_output_toggle (AlsaDevice *device, snd_mixer_elem_t *el)
toggle = create_toggle (device, el, ALSA_TOGGLE_PLAYBACK);
- if (add_element (device, device->priv->output, ALSA_ELEMENT (toggle)) == FALSE) {
- g_object_unref (toggle);
- return FALSE;
- }
- return TRUE;
+ ret = add_element (device, device->priv->output, ALSA_ELEMENT (toggle));
+
+ g_object_unref (toggle);
+ return ret;
}
static void
@@ -671,8 +771,7 @@ load_element (AlsaDevice *device, snd_mixer_elem_t *el)
penum = TRUE;
/* Enumerated controls which are not marked as capture or playback
- * are considered to be a part of the whole device, although sometimes
- * this is incorrectly reported by the driver */
+ * are considered to be a part of the whole device */
if (cenum == FALSE && penum == FALSE) {
add_device_switch (device, el);
}
@@ -707,25 +806,28 @@ load_element (AlsaDevice *device, snd_mixer_elem_t *el)
static void
load_elements_by_name (AlsaDevice *device, const gchar *name)
{
- AlsaElement *element;
+ GList *item;
alsa_stream_load_elements (device->priv->input, name);
alsa_stream_load_elements (device->priv->output, name);
- element = g_hash_table_lookup (device->priv->switches, name);
- if (element != NULL)
- alsa_element_load (element);
+ item = g_list_find_custom (device->priv->switches, name, compare_switch_name);
+ if (item != NULL)
+ alsa_element_load (ALSA_ELEMENT (item->data));
}
static void
remove_elements_by_name (AlsaDevice *device, const gchar *name)
{
+ GList *item;
+
if (alsa_stream_remove_elements (device->priv->input, name) == TRUE) {
/* Removing last stream element "removes" the stream */
- if (alsa_stream_is_empty (device->priv->input) == TRUE) {
+ if (alsa_stream_has_controls_or_switches (device->priv->input) == FALSE) {
const gchar *stream_name =
mate_mixer_stream_get_name (MATE_MIXER_STREAM (device->priv->input));
+ free_stream_list (device);
g_signal_emit_by_name (G_OBJECT (device),
"stream-removed",
stream_name);
@@ -734,20 +836,28 @@ remove_elements_by_name (AlsaDevice *device, const gchar *name)
if (alsa_stream_remove_elements (device->priv->output, name) == TRUE) {
/* Removing last stream element "removes" the stream */
- if (alsa_stream_is_empty (device->priv->output) == TRUE) {
+ if (alsa_stream_has_controls_or_switches (device->priv->output) == FALSE) {
const gchar *stream_name =
mate_mixer_stream_get_name (MATE_MIXER_STREAM (device->priv->output));
+ free_stream_list (device);
g_signal_emit_by_name (G_OBJECT (device),
"stream-removed",
stream_name);
}
}
- if (g_hash_table_remove (device->priv->switches, name) == TRUE)
+ item = g_list_find_custom (device->priv->switches, name, compare_switch_name);
+ if (item != NULL) {
+ MateMixerSwitch *swtch = MATE_MIXER_SWITCH (item->data);
+
+ device->priv->switches = g_list_delete_link (device->priv->switches, item);
g_signal_emit_by_name (G_OBJECT (device),
"switch-removed",
- name);
+ mate_mixer_switch_get_name (swtch));
+
+ g_object_unref (swtch);
+ }
}
static void
@@ -806,7 +916,7 @@ handle_process_events (AlsaDevice *device)
if (device->priv->handle != NULL) {
gint ret = snd_mixer_handle_events (device->priv->handle);
if (ret < 0)
- close_device (device);
+ alsa_device_close (device);
}
device->priv->events_pending = FALSE;
@@ -826,7 +936,15 @@ handle_callback (snd_mixer_t *handle, guint mask, snd_mixer_elem_t *el)
if (mask & SND_CTL_EVENT_MASK_ADD) {
AlsaDevice *device = snd_mixer_get_callback_private (handle);
+ if (device->priv->handle == NULL) {
+ /* The mixer is already closed */
+ return 0;
+ }
+
load_element (device, el);
+
+ /* Revalidate default controls assignment */
+ validate_default_controls (device);
}
return 0;
}
@@ -838,6 +956,11 @@ handle_element_callback (snd_mixer_elem_t *el, guint mask)
gchar *name;
device = snd_mixer_elem_get_callback_private (el);
+ if (device->priv->handle == NULL) {
+ /* The mixer is already closed */
+ return 0;
+ }
+
name = get_element_name (el);
if (mask == SND_CTL_EVENT_MASK_REMOVE) {
@@ -846,10 +969,16 @@ handle_element_callback (snd_mixer_elem_t *el, guint mask)
snd_mixer_elem_set_callback (el, NULL);
remove_elements_by_name (device, name);
+
+ /* Revalidate default controls assignment */
+ validate_default_controls (device);
} else {
if (mask & SND_CTL_EVENT_MASK_INFO) {
remove_elements_by_name (device, name);
load_element (device, el);
+
+ /* Revalidate default controls assignment */
+ validate_default_controls (device);
}
if (mask & SND_CTL_EVENT_MASK_VALUE)
load_elements_by_name (device, name);
@@ -860,16 +989,86 @@ handle_element_callback (snd_mixer_elem_t *el, guint mask)
}
static void
-close_device (AlsaDevice *device)
+validate_default_controls (AlsaDevice *device)
{
- if (device->priv->handle != NULL) {
- snd_mixer_close (device->priv->handle);
- device->priv->handle = NULL;
+ AlsaStreamControl *best;
+ gint best_score;
+ gint current_score;
+
+ /*
+ * Select the most suitable default control. Don't try too hard here because
+ * our list of known elements is incomplete and most drivers seem to provide
+ * the list in a reasonable order with the best element at the start. Each
+ * element in our list has a value (or score) which is simply its position
+ * in the list. Better elements are on the top, so smaller value represents
+ * a better element.
+ *
+ * Two cases are handled here:
+ * 1) The current default control is in our list, but the list also includes
+ * a better element.
+ * 2) The current default control is not in our list, but the list includes
+ * an element which is reasonably good.
+ *
+ * In other cases just keep the first control as the default.
+ */
+ if (alsa_stream_has_controls (device->priv->input) == TRUE) {
+ best = get_best_stream_control (device->priv->input);
+
+ best_score = ALSA_STREAM_CONTROL_GET_SCORE (best);
+ current_score = ALSA_STREAM_DEFAULT_CONTROL_GET_SCORE (device->priv->input);
+
+ /* See if the best element would make a good default one */
+ if (best_score > -1) {
+ g_debug ("Found usable default input element %s (score %d)",
+ mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (best)),
+ best_score);
+
+ if (current_score == -1 || best_score < current_score)
+ alsa_stream_set_default_control (device->priv->input, best);
+ }
}
- /* This signal tells the owner that the device has been closed voluntarily
- * from within the instance */
- g_signal_emit (G_OBJECT (device), signals[CLOSED], 0);
+ if (alsa_stream_has_controls (device->priv->output) == TRUE) {
+ best = get_best_stream_control (device->priv->output);
+
+ best_score = ALSA_STREAM_CONTROL_GET_SCORE (best);
+ current_score = ALSA_STREAM_DEFAULT_CONTROL_GET_SCORE (device->priv->output);
+
+ /* See if the best element would make a good default one */
+ if (best_score > -1) {
+ g_debug ("Found usable default output element %s (score %d)",
+ mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (best)),
+ best_score);
+
+ if (current_score == -1 || best_score < current_score)
+ alsa_stream_set_default_control (device->priv->output, best);
+ }
+ }
+}
+
+static AlsaStreamControl *
+get_best_stream_control (AlsaStream *stream)
+{
+ const GList *list;
+ AlsaStreamControl *best = NULL;
+ guint best_score = -1;
+
+ list = mate_mixer_stream_list_controls (MATE_MIXER_STREAM (stream));
+ while (list != NULL) {
+ AlsaStreamControl *current;
+ guint current_score;
+
+ current = ALSA_STREAM_CONTROL (list->data);
+ current_score = ALSA_STREAM_CONTROL_GET_SCORE (current);
+
+ if (best == NULL || (current_score != -1 &&
+ (best_score == -1 || current_score < best_score))) {
+ best = current;
+ best_score = current_score;
+ }
+ list = list->next;
+ }
+ return best;
}
static gchar *
@@ -884,7 +1083,8 @@ static void
get_control_info (snd_mixer_elem_t *el,
gchar **name,
gchar **label,
- MateMixerStreamControlRole *role)
+ MateMixerStreamControlRole *role,
+ gint *score)
{
MateMixerStreamControlRole r = MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN;
const gchar *n;
@@ -893,49 +1093,119 @@ get_control_info (snd_mixer_elem_t *el,
n = snd_mixer_selem_get_name (el);
- for (i = 0; alsa_controls[i].name != NULL; i++)
- if (strcmp (n, alsa_controls[i].name) == 0) {
- l = alsa_controls[i].label;
- r = alsa_controls[i].role;
- break;
- }
+ for (i = 0; alsa_controls[i].name != NULL; i++) {
+ if (strcmp (n, alsa_controls[i].name) != 0)
+ continue;
+
+ l = gettext (alsa_controls[i].label);
+ r = alsa_controls[i].role;
+ break;
+ }
*name = get_element_name (el);
- if (l != NULL)
+ if (l != NULL) {
*label = g_strdup (l);
- else
+ *score = i;
+ } else {
*label = g_strdup (n);
+ *score = -1;
+ }
*role = r;
}
static void
-get_switch_info (snd_mixer_elem_t *el,
- gchar **name,
- gchar **label)
+get_input_control_info (snd_mixer_elem_t *el,
+ gchar **name,
+ gchar **label,
+ MateMixerStreamControlRole *role,
+ gint *score)
{
- // MateMixerStreamControlRole r = MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN;
- const gchar *n;
- const gchar *l = NULL;
- // gint i;
+ get_control_info (el, name, label, role, score);
+
+ if (*score > -1 && alsa_controls[*score].use_default_input == FALSE)
+ *score = -1;
+}
+
+static void
+get_output_control_info (snd_mixer_elem_t *el,
+ gchar **name,
+ gchar **label,
+ MateMixerStreamControlRole *role,
+ gint *score)
+{
+ get_control_info (el, name, label, role, score);
+
+ if (*score > -1 && alsa_controls[*score].use_default_output == FALSE)
+ *score = -1;
+}
+
+static void
+get_switch_info (snd_mixer_elem_t *el,
+ gchar **name,
+ gchar **label,
+ MateMixerSwitchRole *role)
+{
+ MateMixerSwitchRole r = MATE_MIXER_SWITCH_ROLE_UNKNOWN;
+ const gchar *n;
+ const gchar *l = NULL;
+ gint i;
n = snd_mixer_selem_get_name (el);
- // TODO provide translated label and flags
+ for (i = 0; alsa_switches[i].name != NULL; i++) {
+ if (strcmp (n, alsa_switches[i].name) != 0)
+ continue;
+
+ l = gettext (alsa_switches[i].label);
+ r = alsa_switches[i].role;
+ break;
+ }
-/*
- for (i = 0; alsa_controls[i].name != NULL; i++)
- if (strcmp (n, alsa_controls[i].name) == 0) {
- l = alsa_controls[i].label;
- r = alsa_controls[i].role;
- break;
- }
-*/
*name = get_element_name (el);
if (l != NULL)
*label = g_strdup (l);
else
*label = g_strdup (n);
- // *role = r;
+ *role = r;
+}
+
+static void
+close_mixer (AlsaDevice *device)
+{
+ snd_mixer_t *handle;
+
+ if (device->priv->handle == NULL)
+ return;
+
+ /* Closing the mixer may fire up remove callbacks, prevent this by unsetting
+ * the handle before closing it and checking it in the callback.
+ * Ideally, we should unset callbacks from all the elements, but this seems
+ * to do the job. */
+ handle = device->priv->handle;
+
+ device->priv->handle = NULL;
+ snd_mixer_close (handle);
+}
+
+static void
+free_stream_list (AlsaDevice *device)
+{
+ /* This function is called each time the stream list changes */
+ if (device->priv->streams == NULL)
+ return;
+
+ g_list_free_full (device->priv->streams, g_object_unref);
+
+ device->priv->streams = NULL;
+}
+
+static gint
+compare_switch_name (gconstpointer a, gconstpointer b)
+{
+ MateMixerSwitch *swtch = MATE_MIXER_SWITCH (a);
+ const gchar *name = (const gchar *) b;
+
+ return strcmp (mate_mixer_switch_get_name (swtch), name);
}
diff --git a/backends/alsa/alsa-device.h b/backends/alsa/alsa-device.h
index 3b3c970..9e908cf 100644
--- a/backends/alsa/alsa-device.h
+++ b/backends/alsa/alsa-device.h
@@ -20,6 +20,7 @@
#include <glib.h>
#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
#include "alsa-stream.h"
@@ -64,6 +65,9 @@ AlsaDevice *alsa_device_new (const gchar *name,
const gchar *label);
gboolean alsa_device_open (AlsaDevice *device);
+gboolean alsa_device_is_open (AlsaDevice *device);
+void alsa_device_close (AlsaDevice *device);
+
void alsa_device_load (AlsaDevice *device);
AlsaStream *alsa_device_get_input_stream (AlsaDevice *device);
diff --git a/backends/alsa/alsa-element.c b/backends/alsa/alsa-element.c
index f925064..d837965 100644
--- a/backends/alsa/alsa-element.c
+++ b/backends/alsa/alsa-element.c
@@ -51,3 +51,19 @@ alsa_element_load (AlsaElement *element)
return ALSA_ELEMENT_GET_INTERFACE (element)->load (element);
}
+
+void
+alsa_element_close (AlsaElement *element)
+{
+ AlsaElementInterface *iface;
+
+ g_return_if_fail (ALSA_IS_ELEMENT (element));
+
+ /* Close the element by unsetting the ALSA element and optionally calling
+ * a closing function */
+ alsa_element_set_snd_element (element, NULL);
+
+ iface = ALSA_ELEMENT_GET_INTERFACE (element);
+ if (iface->close != NULL)
+ iface->close (element);
+}
diff --git a/backends/alsa/alsa-element.h b/backends/alsa/alsa-element.h
index 01d30f1..1c30f68 100644
--- a/backends/alsa/alsa-element.h
+++ b/backends/alsa/alsa-element.h
@@ -46,6 +46,7 @@ struct _AlsaElementInterface
snd_mixer_elem_t *el);
gboolean (*load) (AlsaElement *element);
+ void (*close) (AlsaElement *element);
};
GType alsa_element_get_type (void) G_GNUC_CONST;
@@ -56,6 +57,8 @@ void alsa_element_set_snd_element (AlsaElement *element,
gboolean alsa_element_load (AlsaElement *element);
+void alsa_element_close (AlsaElement *element);
+
G_END_DECLS
#endif /* ALSA_ELEMENT_H */
diff --git a/backends/alsa/alsa-stream-control.c b/backends/alsa/alsa-stream-control.c
index bc7a937..97a0f8b 100644
--- a/backends/alsa/alsa-stream-control.c
+++ b/backends/alsa/alsa-stream-control.c
@@ -18,6 +18,7 @@
#include <glib.h>
#include <glib-object.h>
#include <alsa/asoundlib.h>
+
#include <libmatemixer/matemixer.h>
#include <libmatemixer/matemixer-private.h>
@@ -159,64 +160,67 @@ alsa_stream_control_set_data (AlsaStreamControl *control, AlsaControlData *data)
{
MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_NO_FLAGS;
MateMixerStreamControl *mmsc;
+ gboolean mute = FALSE;
g_return_if_fail (ALSA_IS_STREAM_CONTROL (control));
g_return_if_fail (data != NULL);
mmsc = MATE_MIXER_STREAM_CONTROL (control);
+ control->priv->data = *data;
+
g_object_freeze_notify (G_OBJECT (control));
if (data->channels > 0) {
if (data->switch_usable == TRUE) {
- flags |= MATE_MIXER_STREAM_CONTROL_HAS_MUTE;
+ /* If the mute switch is joined, all the channels get the same value,
+ * otherwise the element has per-channel mute, which we don't support.
+ * In that case, treat the control as unmuted if any channel is
+ * unmuted. */
+ if (data->channels == 1 || data->switch_joined == TRUE) {
+ mute = data->m[0];
+ } else {
+ gint i;
+ mute = TRUE;
+ for (i = 0; i < data->channels; i++)
+ if (data->m[i] == FALSE) {
+ mute = FALSE;
+ break;
+ }
+ }
+
+ flags |= MATE_MIXER_STREAM_CONTROL_MUTE_READABLE;
if (data->active == TRUE)
- flags |= MATE_MIXER_STREAM_CONTROL_CAN_SET_MUTE;
+ flags |= MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE;
}
- flags |= MATE_MIXER_STREAM_CONTROL_HAS_VOLUME;
+
+ flags |= MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE;
if (data->active == TRUE)
- flags |= MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME;
- }
- if (data->max_decibel > -MATE_MIXER_INFINITY)
- flags |= MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL;
+ flags |= MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE;
- control->priv->data = *data;
- control->priv->channel_mask = _mate_mixer_create_channel_mask (data->c, data->channels);
+ if (data->max_decibel > -MATE_MIXER_INFINITY)
+ flags |= MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL;
- if (data->volume_joined == FALSE) {
- if (MATE_MIXER_CHANNEL_MASK_HAS_LEFT (control->priv->channel_mask) &&
- MATE_MIXER_CHANNEL_MASK_HAS_RIGHT (control->priv->channel_mask))
- flags |= MATE_MIXER_STREAM_CONTROL_CAN_BALANCE;
+ control->priv->channel_mask = _mate_mixer_create_channel_mask (data->c, data->channels);
+
+ if (data->volume_joined == FALSE) {
+ if (MATE_MIXER_CHANNEL_MASK_HAS_LEFT (control->priv->channel_mask) &&
+ MATE_MIXER_CHANNEL_MASK_HAS_RIGHT (control->priv->channel_mask))
+ flags |= MATE_MIXER_STREAM_CONTROL_CAN_BALANCE;
+
+ if (MATE_MIXER_CHANNEL_MASK_HAS_FRONT (control->priv->channel_mask) &&
+ MATE_MIXER_CHANNEL_MASK_HAS_BACK (control->priv->channel_mask))
+ flags |= MATE_MIXER_STREAM_CONTROL_CAN_FADE;
+ }
- if (MATE_MIXER_CHANNEL_MASK_HAS_FRONT (control->priv->channel_mask) &&
- MATE_MIXER_CHANNEL_MASK_HAS_BACK (control->priv->channel_mask))
- flags |= MATE_MIXER_STREAM_CONTROL_CAN_FADE;
+ g_object_notify (G_OBJECT (control), "volume");
+ } else {
+ control->priv->channel_mask = 0;
}
+ _mate_mixer_stream_control_set_mute (mmsc, mute);
_mate_mixer_stream_control_set_flags (mmsc, flags);
- if (data->switch_usable == TRUE) {
- gboolean mute;
-
- /* If the mute switch is joined, all the channels get the same value,
- * otherwise the element has per-channel mute, which we don't support.
- * In that case, treat the control as unmuted if any channel is
- * unmuted. */
- if (data->channels == 1 || data->switch_joined == TRUE) {
- mute = data->m[0];
- } else {
- gint i;
- mute = TRUE;
- for (i = 0; i < data->channels; i++)
- if (data->m[i] == FALSE) {
- mute = FALSE;
- break;
- }
- }
- _mate_mixer_stream_control_set_mute (mmsc, mute);
- } else
- _mate_mixer_stream_control_set_mute (mmsc, FALSE);
-
if (flags & MATE_MIXER_STREAM_CONTROL_CAN_BALANCE)
_mate_mixer_stream_control_set_balance (mmsc, control_data_get_balance (data));
if (flags & MATE_MIXER_STREAM_CONTROL_CAN_FADE)
@@ -237,7 +241,6 @@ static void
alsa_stream_control_set_snd_element (AlsaElement *element, snd_mixer_elem_t *el)
{
g_return_if_fail (ALSA_IS_STREAM_CONTROL (element));
- g_return_if_fail (el != NULL);
ALSA_STREAM_CONTROL (element)->priv->element = el;
}
@@ -288,6 +291,8 @@ alsa_stream_control_set_mute (MateMixerStreamControl *mmsc, gboolean mute)
for (i = 0; i < control->priv->data.channels; i++)
control->priv->data.m[i] = mute;
+
+ _mate_mixer_stream_control_set_mute (mmsc, mute);
}
return TRUE;
}
@@ -344,6 +349,8 @@ alsa_stream_control_set_volume (MateMixerStreamControl *mmsc, guint volume)
for (i = 0; i < control->priv->data.channels; i++)
control->priv->data.v[i] = volume;
+ control->priv->data.volume = volume;
+
g_object_notify (G_OBJECT (control), "volume");
}
return TRUE;
@@ -364,7 +371,7 @@ alsa_stream_control_get_decibel (MateMixerStreamControl *mmsc)
volume = alsa_stream_control_get_volume (mmsc);
if (klass->get_decibel_from_volume (control, volume, &decibel) == FALSE)
- return FALSE;
+ return -MATE_MIXER_INFINITY;
return decibel;
}
@@ -428,7 +435,7 @@ alsa_stream_control_get_channel_volume (MateMixerStreamControl *mmsc, guint chan
control = ALSA_STREAM_CONTROL (mmsc);
if (channel >= control->priv->data.channels)
- return FALSE;
+ return 0;
return control->priv->data.v[channel];
}
@@ -463,6 +470,7 @@ alsa_stream_control_set_channel_volume (MateMixerStreamControl *mmsc, guint chan
if (klass->set_channel_volume (control, c, volume) == FALSE)
return FALSE;
+ // XXX recalc total volume
control->priv->data.v[channel] = volume;
g_object_notify (G_OBJECT (control), "volume");
@@ -483,13 +491,13 @@ alsa_stream_control_get_channel_decibel (MateMixerStreamControl *mmsc, guint cha
control = ALSA_STREAM_CONTROL (mmsc);
if (channel >= control->priv->data.channels)
- return FALSE;
+ return -MATE_MIXER_INFINITY;
klass = ALSA_STREAM_CONTROL_GET_CLASS (control);
volume = control->priv->data.v[channel];
if (klass->get_decibel_from_volume (control, volume, &decibel) == FALSE)
- return FALSE;
+ return -MATE_MIXER_INFINITY;
return decibel;
}
@@ -637,27 +645,27 @@ alsa_stream_control_set_fade (MateMixerStreamControl *mmsc, gfloat fade)
}
static guint
-alsa_stream_control_get_min_volume (MateMixerStreamControl *msc)
+alsa_stream_control_get_min_volume (MateMixerStreamControl *mmsc)
{
- return ALSA_STREAM_CONTROL (msc)->priv->data.min;
+ return ALSA_STREAM_CONTROL (mmsc)->priv->data.min;
}
static guint
-alsa_stream_control_get_max_volume (MateMixerStreamControl *msc)
+alsa_stream_control_get_max_volume (MateMixerStreamControl *mmsc)
{
- return ALSA_STREAM_CONTROL (msc)->priv->data.max;
+ return ALSA_STREAM_CONTROL (mmsc)->priv->data.max;
}
static guint
-alsa_stream_control_get_normal_volume (MateMixerStreamControl *msc)
+alsa_stream_control_get_normal_volume (MateMixerStreamControl *mmsc)
{
- return ALSA_STREAM_CONTROL (msc)->priv->data.max;
+ return ALSA_STREAM_CONTROL (mmsc)->priv->data.max;
}
static guint
-alsa_stream_control_get_base_volume (MateMixerStreamControl *msc)
+alsa_stream_control_get_base_volume (MateMixerStreamControl *mmsc)
{
- return ALSA_STREAM_CONTROL (msc)->priv->data.max;
+ return ALSA_STREAM_CONTROL (mmsc)->priv->data.max;
}
static void
diff --git a/backends/alsa/alsa-stream-control.h b/backends/alsa/alsa-stream-control.h
index f9ac6b6..acd02bd 100644
--- a/backends/alsa/alsa-stream-control.h
+++ b/backends/alsa/alsa-stream-control.h
@@ -41,9 +41,6 @@ typedef struct {
guint channels;
} AlsaControlData;
-extern const MateMixerChannelPosition alsa_channel_map_from[SND_MIXER_SCHN_LAST];
-extern const snd_mixer_selem_channel_id_t alsa_channel_map_to[MATE_MIXER_CHANNEL_MAX];
-
#define ALSA_TYPE_STREAM_CONTROL \
(alsa_stream_control_get_type ())
#define ALSA_STREAM_CONTROL(o) \
@@ -103,9 +100,6 @@ AlsaControlData * alsa_stream_control_get_data (AlsaStreamControl
void alsa_stream_control_set_data (AlsaStreamControl *control,
AlsaControlData *data);
-gboolean alsa_stream_control_set_role (AlsaStreamControl *control,
- MateMixerStreamControlRole role);
-
G_END_DECLS
#endif /* ALSA_STREAM_CONTROL_H */
diff --git a/backends/alsa/alsa-stream-input-control.c b/backends/alsa/alsa-stream-input-control.c
index 2ef0c42..2e3f46d 100644
--- a/backends/alsa/alsa-stream-input-control.c
+++ b/backends/alsa/alsa-stream-input-control.c
@@ -22,6 +22,7 @@
#include <libmatemixer/matemixer.h>
#include <libmatemixer/matemixer-private.h>
+#include "alsa-constants.h"
#include "alsa-element.h"
#include "alsa-stream-control.h"
#include "alsa-stream-input-control.h"
@@ -51,8 +52,7 @@ static gboolean alsa_stream_input_control_get_decibel_from_volume (AlsaStreamCon
guint volume,
gdouble *decibel);
-static void read_volume_data (snd_mixer_elem_t *el,
- AlsaControlData *data);
+static void read_volume_data (snd_mixer_elem_t *el, AlsaControlData *data);
static void
alsa_stream_input_control_class_init (AlsaStreamInputControlClass *klass)
@@ -77,12 +77,14 @@ alsa_stream_input_control_init (AlsaStreamInputControl *control)
AlsaStreamControl *
alsa_stream_input_control_new (const gchar *name,
const gchar *label,
- MateMixerStreamControlRole role)
+ MateMixerStreamControlRole role,
+ AlsaStream *stream)
{
return g_object_new (ALSA_TYPE_STREAM_INPUT_CONTROL,
"name", name,
"label", label,
"role", role,
+ "stream", stream,
NULL);
}
@@ -98,7 +100,6 @@ alsa_stream_input_control_load (AlsaStreamControl *control)
if G_UNLIKELY (el == NULL)
return FALSE;
- /* Expect that the element has a volume control */
if G_UNLIKELY (snd_mixer_selem_has_capture_volume (el) == 0 &&
snd_mixer_selem_has_common_volume (el) == 0) {
g_warn_if_reached ();
@@ -180,8 +181,7 @@ alsa_stream_input_control_set_channel_volume (AlsaStreamControl *contr
if G_UNLIKELY (el == NULL)
return FALSE;
- /* Set the volume for a single channels, the volume may still be "joined" and
- * set all the channels by itself */
+ /* Set the volume for a single channel */
ret = snd_mixer_selem_set_capture_volume (el, channel, volume);
if (ret < 0) {
g_warning ("Failed to set channel volume: %s", snd_strerror (ret));
diff --git a/backends/alsa/alsa-stream-input-control.h b/backends/alsa/alsa-stream-input-control.h
index c427e3c..0ce885a 100644
--- a/backends/alsa/alsa-stream-input-control.h
+++ b/backends/alsa/alsa-stream-input-control.h
@@ -22,6 +22,7 @@
#include <glib-object.h>
#include <libmatemixer/matemixer.h>
+#include "alsa-stream.h"
#include "alsa-stream-control.h"
G_BEGIN_DECLS
@@ -57,7 +58,8 @@ GType alsa_stream_input_control_get_type (void) G_GNUC_CONST;
AlsaStreamControl *alsa_stream_input_control_new (const gchar *name,
const gchar *label,
- MateMixerStreamControlRole role);
+ MateMixerStreamControlRole role,
+ AlsaStream *stream);
G_END_DECLS
diff --git a/backends/alsa/alsa-stream-output-control.c b/backends/alsa/alsa-stream-output-control.c
index 5a3e6b3..1f4faf8 100644
--- a/backends/alsa/alsa-stream-output-control.c
+++ b/backends/alsa/alsa-stream-output-control.c
@@ -22,6 +22,7 @@
#include <libmatemixer/matemixer.h>
#include <libmatemixer/matemixer-private.h>
+#include "alsa-constants.h"
#include "alsa-element.h"
#include "alsa-stream-control.h"
#include "alsa-stream-output-control.h"
@@ -51,8 +52,7 @@ static gboolean alsa_stream_output_control_get_decibel_from_volume (AlsaStreamCo
guint volume,
gdouble *decibel);
-static void read_volume_data (snd_mixer_elem_t *el,
- AlsaControlData *data);
+static void read_volume_data (snd_mixer_elem_t *el, AlsaControlData *data);
static void
alsa_stream_output_control_class_init (AlsaStreamOutputControlClass *klass)
@@ -77,12 +77,14 @@ alsa_stream_output_control_init (AlsaStreamOutputControl *control)
AlsaStreamControl *
alsa_stream_output_control_new (const gchar *name,
const gchar *label,
- MateMixerStreamControlRole role)
+ MateMixerStreamControlRole role,
+ AlsaStream *stream)
{
return g_object_new (ALSA_TYPE_STREAM_OUTPUT_CONTROL,
"name", name,
"label", label,
"role", role,
+ "stream", stream,
NULL);
}
@@ -98,7 +100,6 @@ alsa_stream_output_control_load (AlsaStreamControl *control)
if G_UNLIKELY (el == NULL)
return FALSE;
- /* Expect that the element has a volume control */
if G_UNLIKELY (snd_mixer_selem_has_playback_volume (el) == 0 &&
snd_mixer_selem_has_common_volume (el) == 0) {
g_warn_if_reached ();
@@ -180,8 +181,7 @@ alsa_stream_output_control_set_channel_volume (AlsaStreamControl *cont
if G_UNLIKELY (el == NULL)
return FALSE;
- /* Set the volume for a single channels, the volume may still be "joined" and
- * set all the channels by itself */
+ /* Set the volume for a single channel */
ret = snd_mixer_selem_set_playback_volume (el, channel, volume);
if (ret < 0) {
g_warning ("Failed to set channel volume: %s", snd_strerror (ret));
diff --git a/backends/alsa/alsa-stream-output-control.h b/backends/alsa/alsa-stream-output-control.h
index 845eaae..9a5b708 100644
--- a/backends/alsa/alsa-stream-output-control.h
+++ b/backends/alsa/alsa-stream-output-control.h
@@ -22,6 +22,7 @@
#include <glib-object.h>
#include <libmatemixer/matemixer.h>
+#include "alsa-stream.h"
#include "alsa-stream-control.h"
G_BEGIN_DECLS
@@ -57,7 +58,8 @@ GType alsa_stream_output_control_get_type (void) G_GNUC_CONST;
AlsaStreamControl *alsa_stream_output_control_new (const gchar *name,
const gchar *label,
- MateMixerStreamControlRole role);
+ MateMixerStreamControlRole role,
+ AlsaStream *stream);
G_END_DECLS
diff --git a/backends/alsa/alsa-stream.c b/backends/alsa/alsa-stream.c
index d2f68d4..bc9c1b5 100644
--- a/backends/alsa/alsa-stream.c
+++ b/backends/alsa/alsa-stream.c
@@ -18,6 +18,7 @@
#include <glib.h>
#include <glib-object.h>
#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include "alsa-element.h"
#include "alsa-stream.h"
@@ -26,27 +27,23 @@
struct _AlsaStreamPrivate
{
- GHashTable *switches;
- GHashTable *controls;
- MateMixerStreamControl *control;
+ GList *switches;
+ GList *controls;
};
static void alsa_stream_class_init (AlsaStreamClass *klass);
static void alsa_stream_init (AlsaStream *stream);
static void alsa_stream_dispose (GObject *object);
-static void alsa_stream_finalize (GObject *object);
G_DEFINE_TYPE (AlsaStream, alsa_stream, MATE_MIXER_TYPE_STREAM)
-static MateMixerStreamControl *alsa_stream_get_control (MateMixerStream *mms,
- const gchar *name);
-static MateMixerStreamControl *alsa_stream_get_default_control (MateMixerStream *mms);
-
-static MateMixerSwitch * alsa_stream_get_switch (MateMixerStream *mms,
- const gchar *name);
+static const GList *alsa_stream_list_controls (MateMixerStream *mms);
+static const GList *alsa_stream_list_switches (MateMixerStream *mms);
-static GList * alsa_stream_list_controls (MateMixerStream *mms);
-static GList * alsa_stream_list_switches (MateMixerStream *mms);
+static gint compare_control_name (gconstpointer a,
+ gconstpointer b);
+static gint compare_switch_name (gconstpointer a,
+ gconstpointer b);
static void
alsa_stream_class_init (AlsaStreamClass *klass)
@@ -55,15 +52,11 @@ alsa_stream_class_init (AlsaStreamClass *klass)
MateMixerStreamClass *stream_class;
object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = alsa_stream_dispose;
- object_class->finalize = alsa_stream_finalize;
+ object_class->dispose = alsa_stream_dispose;
stream_class = MATE_MIXER_STREAM_CLASS (klass);
- stream_class->get_control = alsa_stream_get_control;
- stream_class->get_default_control = alsa_stream_get_default_control;
- stream_class->get_switch = alsa_stream_get_switch;
- stream_class->list_controls = alsa_stream_list_controls;
- stream_class->list_switches = alsa_stream_list_switches;
+ stream_class->list_controls = alsa_stream_list_controls;
+ stream_class->list_switches = alsa_stream_list_switches;
g_type_class_add_private (object_class, sizeof (AlsaStreamPrivate));
}
@@ -74,16 +67,6 @@ alsa_stream_init (AlsaStream *stream)
stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
ALSA_TYPE_STREAM,
AlsaStreamPrivate);
-
- stream->priv->controls = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- g_object_unref);
-
- stream->priv->switches = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- g_object_unref);
}
static void
@@ -93,36 +76,30 @@ alsa_stream_dispose (GObject *object)
stream = ALSA_STREAM (object);
- g_hash_table_remove_all (stream->priv->controls);
- g_hash_table_remove_all (stream->priv->switches);
-
- g_clear_object (&stream->priv->control);
+ if (stream->priv->controls != NULL) {
+ g_list_free_full (stream->priv->controls, g_object_unref);
+ stream->priv->controls = NULL;
+ }
+ if (stream->priv->switches != NULL) {
+ g_list_free_full (stream->priv->switches, g_object_unref);
+ stream->priv->switches = NULL;
+ }
G_OBJECT_CLASS (alsa_stream_parent_class)->dispose (object);
}
-static void
-alsa_stream_finalize (GObject *object)
-{
- AlsaStream *stream;
-
- stream = ALSA_STREAM (object);
-
- g_hash_table_destroy (stream->priv->controls);
- g_hash_table_destroy (stream->priv->switches);
-
- G_OBJECT_CLASS (alsa_stream_parent_class)->finalize (object);
-}
-
AlsaStream *
-alsa_stream_new (const gchar *name,
- MateMixerDevice *device,
- MateMixerStreamFlags flags)
+alsa_stream_new (const gchar *name,
+ MateMixerDevice *device,
+ MateMixerDirection direction)
{
+ const gchar *label = mate_mixer_device_get_label (device);
+
return g_object_new (ALSA_TYPE_STREAM,
"name", name,
+ "label", label,
"device", device,
- "flags", flags,
+ "direction", direction,
NULL);
}
@@ -135,9 +112,16 @@ alsa_stream_add_control (AlsaStream *stream, AlsaStreamControl *control)
g_return_if_fail (ALSA_IS_STREAM_CONTROL (control));
name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (control));
- g_hash_table_insert (stream->priv->controls,
- g_strdup (name),
- g_object_ref (control));
+
+ stream->priv->controls =
+ g_list_append (stream->priv->controls, g_object_ref (control));
+
+ g_signal_emit_by_name (G_OBJECT (stream),
+ "control-added",
+ name);
+
+ if (alsa_stream_has_default_control (stream) == FALSE)
+ alsa_stream_set_default_control (stream, control);
}
void
@@ -149,125 +133,250 @@ alsa_stream_add_switch (AlsaStream *stream, AlsaSwitch *swtch)
g_return_if_fail (ALSA_IS_SWITCH (swtch));
name = mate_mixer_switch_get_name (MATE_MIXER_SWITCH (swtch));
- g_hash_table_insert (stream->priv->switches,
- g_strdup (name),
- g_object_ref (swtch));
+
+ stream->priv->switches =
+ g_list_append (stream->priv->switches, g_object_ref (swtch));
+
+ g_signal_emit_by_name (G_OBJECT (stream),
+ "switch-added",
+ name);
+}
+
+void
+alsa_stream_add_toggle (AlsaStream *stream, AlsaToggle *toggle)
+{
+ const gchar *name;
+
+ g_return_if_fail (ALSA_IS_STREAM (stream));
+ g_return_if_fail (ALSA_IS_TOGGLE (toggle));
+
+ name = mate_mixer_switch_get_name (MATE_MIXER_SWITCH (toggle));
+
+ /* Toggle is MateMixerSwitch, but not AlsaSwitch */
+ stream->priv->switches =
+ g_list_append (stream->priv->switches, g_object_ref (toggle));
+
+ g_signal_emit_by_name (G_OBJECT (stream),
+ "switch-added",
+ name);
+}
+
+gboolean
+alsa_stream_has_controls (AlsaStream *stream)
+{
+ g_return_val_if_fail (ALSA_IS_STREAM (stream), FALSE);
+
+ if (stream->priv->controls != NULL)
+ return TRUE;
+
+ return FALSE;
}
gboolean
-alsa_stream_is_empty (AlsaStream *stream)
+alsa_stream_has_switches (AlsaStream *stream)
{
g_return_val_if_fail (ALSA_IS_STREAM (stream), FALSE);
- if (g_hash_table_size (stream->priv->controls) > 0 ||
- g_hash_table_size (stream->priv->switches) > 0)
- return FALSE;
+ if (stream->priv->switches != NULL)
+ return TRUE;
- return TRUE;
+ return FALSE;
+}
+
+gboolean
+alsa_stream_has_controls_or_switches (AlsaStream *stream)
+{
+ g_return_val_if_fail (ALSA_IS_STREAM (stream), FALSE);
+
+ if (stream->priv->controls != NULL ||
+ stream->priv->switches != NULL)
+ return TRUE;
+
+ return FALSE;
+}
+
+gboolean
+alsa_stream_has_default_control (AlsaStream *stream)
+{
+ g_return_val_if_fail (ALSA_IS_STREAM (stream), FALSE);
+
+ if (mate_mixer_stream_get_default_control (MATE_MIXER_STREAM (stream)) != NULL)
+ return TRUE;
+
+ return FALSE;
+}
+
+AlsaStreamControl *
+alsa_stream_get_default_control (AlsaStream *stream)
+{
+ MateMixerStreamControl *control;
+
+ g_return_val_if_fail (ALSA_IS_STREAM (stream), NULL);
+
+ control = mate_mixer_stream_get_default_control (MATE_MIXER_STREAM (stream));
+ if (control != NULL)
+ return ALSA_STREAM_CONTROL (control);
+
+ return NULL;
}
void
alsa_stream_set_default_control (AlsaStream *stream, AlsaStreamControl *control)
{
g_return_if_fail (ALSA_IS_STREAM (stream));
- g_return_if_fail (ALSA_IS_STREAM_CONTROL (control));
-
- /* This function is only used internally so avoid validating that the control
- * belongs to this stream */
- if (stream->priv->control != NULL)
- g_object_unref (stream->priv->control);
+ g_return_if_fail (control == NULL || ALSA_IS_STREAM_CONTROL (control));
- if (control != NULL)
- stream->priv->control = MATE_MIXER_STREAM_CONTROL (g_object_ref (control));
+ if (control == NULL)
+ _mate_mixer_stream_set_default_control (MATE_MIXER_STREAM (stream), NULL);
else
- stream->priv->control = NULL;
+ _mate_mixer_stream_set_default_control (MATE_MIXER_STREAM (stream),
+ MATE_MIXER_STREAM_CONTROL (control));
}
void
alsa_stream_load_elements (AlsaStream *stream, const gchar *name)
{
- AlsaElement *element;
+ GList *item;
g_return_if_fail (ALSA_IS_STREAM (stream));
g_return_if_fail (name != NULL);
- element = g_hash_table_lookup (stream->priv->controls, name);
- if (element != NULL)
- alsa_element_load (element);
+ item = g_list_find_custom (stream->priv->controls, name, compare_control_name);
+ if (item != NULL)
+ alsa_element_load (ALSA_ELEMENT (item->data));
- element = g_hash_table_lookup (stream->priv->switches, name);
- if (element != NULL)
- alsa_element_load (element);
+ item = g_list_find_custom (stream->priv->switches, name, compare_switch_name);
+ if (item != NULL)
+ alsa_element_load (ALSA_ELEMENT (item->data));
}
gboolean
alsa_stream_remove_elements (AlsaStream *stream, const gchar *name)
{
+ GList *item;
gboolean removed = FALSE;
g_return_val_if_fail (ALSA_IS_STREAM (stream), FALSE);
g_return_val_if_fail (name != NULL, FALSE);
- if (g_hash_table_remove (stream->priv->controls, name) == TRUE)
+ item = g_list_find_custom (stream->priv->controls, name, compare_control_name);
+ if (item != NULL) {
+ MateMixerStreamControl *control = MATE_MIXER_STREAM_CONTROL (item->data);
+
+ alsa_element_close (ALSA_ELEMENT (control));
+ stream->priv->controls = g_list_delete_link (stream->priv->controls, item);
+
+ /* Change the default control if we have just removed it */
+ if (control == mate_mixer_stream_get_default_control (MATE_MIXER_STREAM (stream))) {
+ AlsaStreamControl *first = NULL;
+
+ if (stream->priv->controls != NULL)
+ first = ALSA_STREAM_CONTROL (stream->priv->controls->data);
+
+ alsa_stream_set_default_control (stream, first);
+ }
+
+ g_signal_emit_by_name (G_OBJECT (stream),
+ "control-removed",
+ mate_mixer_stream_control_get_name (control));
+
+ g_object_unref (control);
removed = TRUE;
- if (g_hash_table_remove (stream->priv->switches, name) == TRUE)
+ }
+
+ item = g_list_find_custom (stream->priv->switches, name, compare_switch_name);
+ if (item != NULL) {
+ MateMixerSwitch *swtch = MATE_MIXER_SWITCH (item->data);
+
+ alsa_element_close (ALSA_ELEMENT (swtch));
+
+ stream->priv->switches = g_list_delete_link (stream->priv->switches, item);
+ g_signal_emit_by_name (G_OBJECT (stream),
+ "switch-removed",
+ mate_mixer_switch_get_name (swtch));
+
+ g_object_unref (swtch);
removed = TRUE;
+ }
return removed;
}
-static MateMixerStreamControl *
-alsa_stream_get_control (MateMixerStream *mms, const gchar *name)
+void
+alsa_stream_remove_all (AlsaStream *stream)
{
- g_return_val_if_fail (ALSA_IS_STREAM (mms), NULL);
+ GList *list;
- return g_hash_table_lookup (ALSA_STREAM (mms)->priv->controls, name);
-}
+ g_return_if_fail (ALSA_IS_STREAM (stream));
-static MateMixerStreamControl *
-alsa_stream_get_default_control (MateMixerStream *mms)
-{
- g_return_val_if_fail (ALSA_IS_STREAM (mms), NULL);
+ /* Remove all stream controls */
+ list = stream->priv->controls;
+ while (list != NULL) {
+ MateMixerStreamControl *control = MATE_MIXER_STREAM_CONTROL (list->data);
+ GList *next = list->next;
+
+ alsa_element_close (ALSA_ELEMENT (control));
+
+ stream->priv->controls = g_list_delete_link (stream->priv->controls, list);
+ g_signal_emit_by_name (G_OBJECT (stream),
+ "control-removed",
+ mate_mixer_stream_control_get_name (control));
+
+ g_object_unref (control);
+ list = next;
+ }
+
+ /* Unset the default stream control */
+ alsa_stream_set_default_control (stream, NULL);
+
+ /* Remove all stream switches */
+ list = stream->priv->switches;
+ while (list != NULL) {
+ MateMixerSwitch *swtch = MATE_MIXER_SWITCH (list->data);
+ GList *next = list->next;
+
+ alsa_element_close (ALSA_ELEMENT (swtch));
- return ALSA_STREAM (mms)->priv->control;
+ stream->priv->switches = g_list_delete_link (stream->priv->switches, list);
+ g_signal_emit_by_name (G_OBJECT (stream),
+ "switch-removed",
+ mate_mixer_switch_get_name (swtch));
+
+ g_object_unref (swtch);
+ list = next;
+ }
}
-static MateMixerSwitch *
-alsa_stream_get_switch (MateMixerStream *mms, const gchar *name)
+static const GList *
+alsa_stream_list_controls (MateMixerStream *mms)
{
g_return_val_if_fail (ALSA_IS_STREAM (mms), NULL);
- return g_hash_table_lookup (ALSA_STREAM (mms)->priv->switches, name);
+ return ALSA_STREAM (mms)->priv->controls;
}
-static GList *
-alsa_stream_list_controls (MateMixerStream *mms)
+static const GList *
+alsa_stream_list_switches (MateMixerStream *mms)
{
- GList *list;
-
g_return_val_if_fail (ALSA_IS_STREAM (mms), NULL);
- /* Convert the hash table to a linked list, this list is expected to be
- * cached in the main library */
- list = g_hash_table_get_values (ALSA_STREAM (mms)->priv->controls);
- if (list != NULL)
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
-
- return list;
+ return ALSA_STREAM (mms)->priv->switches;
}
-static GList *
-alsa_stream_list_switches (MateMixerStream *mms)
+static gint
+compare_control_name (gconstpointer a, gconstpointer b)
{
- GList *list;
+ MateMixerStreamControl *control = MATE_MIXER_STREAM_CONTROL (a);
+ const gchar *name = (const gchar *) b;
- g_return_val_if_fail (ALSA_IS_STREAM (mms), NULL);
+ return strcmp (mate_mixer_stream_control_get_name (control), name);
+}
- /* Convert the hash table to a linked list, this list is expected to be
- * cached in the main library */
- list = g_hash_table_get_values (ALSA_STREAM (mms)->priv->switches);
- if (list != NULL)
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
+static gint
+compare_switch_name (gconstpointer a, gconstpointer b)
+{
+ MateMixerSwitch *swtch = MATE_MIXER_SWITCH (a);
+ const gchar *name = (const gchar *) b;
- return list;
+ return strcmp (mate_mixer_switch_get_name (swtch), name);
}
diff --git a/backends/alsa/alsa-stream.h b/backends/alsa/alsa-stream.h
index f26a643..5aa3095 100644
--- a/backends/alsa/alsa-stream.h
+++ b/backends/alsa/alsa-stream.h
@@ -22,9 +22,9 @@
#include <glib-object.h>
#include <libmatemixer/matemixer.h>
-#include "alsa-element.h"
#include "alsa-stream-control.h"
#include "alsa-switch.h"
+#include "alsa-toggle.h"
G_BEGIN_DECLS
@@ -58,30 +58,35 @@ struct _AlsaStreamClass
MateMixerStreamClass parent_class;
};
-GType alsa_stream_get_type (void) G_GNUC_CONST;
+GType alsa_stream_get_type (void) G_GNUC_CONST;
-AlsaStream *alsa_stream_new (const gchar *name,
- MateMixerDevice *device,
- MateMixerStreamFlags flags);
+AlsaStream * alsa_stream_new (const gchar *name,
+ MateMixerDevice *device,
+ MateMixerDirection direction);
-void alsa_stream_add_control (AlsaStream *stream,
- AlsaStreamControl *control);
+void alsa_stream_add_control (AlsaStream *stream,
+ AlsaStreamControl *control);
+void alsa_stream_add_switch (AlsaStream *stream,
+ AlsaSwitch *swtch);
+void alsa_stream_add_toggle (AlsaStream *stream,
+ AlsaToggle *toggle);
-void alsa_stream_add_switch (AlsaStream *stream,
- AlsaSwitch *swtch);
+gboolean alsa_stream_has_controls (AlsaStream *stream);
+gboolean alsa_stream_has_switches (AlsaStream *stream);
+gboolean alsa_stream_has_controls_or_switches (AlsaStream *stream);
+gboolean alsa_stream_has_default_control (AlsaStream *stream);
-gboolean alsa_stream_is_empty (AlsaStream *stream);
+AlsaStreamControl *alsa_stream_get_default_control (AlsaStream *stream);
+void alsa_stream_set_default_control (AlsaStream *stream,
+ AlsaStreamControl *control);
-void alsa_stream_set_default_control (AlsaStream *stream,
- AlsaStreamControl *control);
+void alsa_stream_load_elements (AlsaStream *stream,
+ const gchar *name);
-void alsa_stream_load_elements (AlsaStream *stream,
- const gchar *name);
+gboolean alsa_stream_remove_elements (AlsaStream *stream,
+ const gchar *name);
-gboolean alsa_stream_remove_elements (AlsaStream *stream,
- const gchar *name);
-
-void alsa_stream_remove_all (AlsaStream *stream);
+void alsa_stream_remove_all (AlsaStream *stream);
G_END_DECLS
diff --git a/backends/alsa/alsa-switch-option.c b/backends/alsa/alsa-switch-option.c
index 2173113..1800df2 100644
--- a/backends/alsa/alsa-switch-option.c
+++ b/backends/alsa/alsa-switch-option.c
@@ -18,9 +18,7 @@
#include <glib.h>
#include <glib-object.h>
#include <alsa/asoundlib.h>
-
#include <libmatemixer/matemixer.h>
-#include <libmatemixer/matemixer-private.h>
#include "alsa-switch-option.h"
@@ -59,6 +57,7 @@ alsa_switch_option_new (const gchar *name,
option = g_object_new (ALSA_TYPE_SWITCH_OPTION,
"name", name,
"label", label,
+ "icon", icon,
NULL);
option->priv->id = id;
diff --git a/backends/alsa/alsa-switch-option.h b/backends/alsa/alsa-switch-option.h
index c2dda87..98d4f57 100644
--- a/backends/alsa/alsa-switch-option.h
+++ b/backends/alsa/alsa-switch-option.h
@@ -24,17 +24,17 @@
G_BEGIN_DECLS
-#define ALSA_TYPE_SWITCH_OPTION \
+#define ALSA_TYPE_SWITCH_OPTION \
(alsa_switch_option_get_type ())
-#define ALSA_SWITCH_OPTION(o) \
+#define ALSA_SWITCH_OPTION(o) \
(G_TYPE_CHECK_INSTANCE_CAST ((o), ALSA_TYPE_SWITCH_OPTION, AlsaSwitchOption))
-#define ALSA_IS_SWITCH_OPTION(o) \
+#define ALSA_IS_SWITCH_OPTION(o) \
(G_TYPE_CHECK_INSTANCE_TYPE ((o), ALSA_TYPE_SWITCH_OPTION))
-#define ALSA_SWITCH_OPTION_CLASS(k) \
+#define ALSA_SWITCH_OPTION_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), ALSA_TYPE_SWITCH_OPTION, AlsaSwitchOptionClass))
-#define ALSA_IS_SWITCH_OPTION_CLASS(k) \
+#define ALSA_IS_SWITCH_OPTION_CLASS(k) \
(G_TYPE_CHECK_CLASS_TYPE ((k), ALSA_TYPE_SWITCH_OPTION))
-#define ALSA_SWITCH_OPTION_GET_CLASS(o) \
+#define ALSA_SWITCH_OPTION_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), ALSA_TYPE_SWITCH_OPTION, AlsaSwitchOptionClass))
typedef struct _AlsaSwitchOption AlsaSwitchOption;
diff --git a/backends/alsa/alsa-switch.c b/backends/alsa/alsa-switch.c
index 15151ae..6a0f1f4 100644
--- a/backends/alsa/alsa-switch.c
+++ b/backends/alsa/alsa-switch.c
@@ -37,6 +37,7 @@ static void alsa_element_interface_init (AlsaElementInterface *iface);
static void alsa_switch_class_init (AlsaSwitchClass *klass);
static void alsa_switch_init (AlsaSwitch *swtch);
+static void alsa_switch_dispose (GObject *object);
G_DEFINE_TYPE_WITH_CODE (AlsaSwitch, alsa_switch,
MATE_MIXER_TYPE_SWITCH,
@@ -46,7 +47,7 @@ G_DEFINE_TYPE_WITH_CODE (AlsaSwitch, alsa_switch,
static gboolean alsa_switch_set_active_option (MateMixerSwitch *mms,
MateMixerSwitchOption *mmso);
-static GList * alsa_switch_list_options (MateMixerSwitch *mms);
+static const GList * alsa_switch_list_options (MateMixerSwitch *mms);
static snd_mixer_elem_t * alsa_switch_get_snd_element (AlsaElement *element);
static void alsa_switch_set_snd_element (AlsaElement *element,
@@ -64,8 +65,12 @@ alsa_element_interface_init (AlsaElementInterface *iface)
static void
alsa_switch_class_init (AlsaSwitchClass *klass)
{
+ GObjectClass *object_class;
MateMixerSwitchClass *switch_class;
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = alsa_switch_dispose;
+
switch_class = MATE_MIXER_SWITCH_CLASS (klass);
switch_class->set_active_option = alsa_switch_set_active_option;
switch_class->list_options = alsa_switch_list_options;
@@ -74,6 +79,21 @@ alsa_switch_class_init (AlsaSwitchClass *klass)
}
static void
+alsa_switch_dispose (GObject *object)
+{
+ AlsaSwitch *swtch;
+
+ swtch = ALSA_SWITCH (object);
+
+ if (swtch->priv->options != NULL) {
+ g_list_free_full (swtch->priv->options, g_object_unref);
+ swtch->priv->options = NULL;
+ }
+
+ G_OBJECT_CLASS (alsa_switch_parent_class)->dispose (object);
+}
+
+static void
alsa_switch_init (AlsaSwitch *swtch)
{
swtch->priv = G_TYPE_INSTANCE_GET_PRIVATE (swtch,
@@ -82,13 +102,17 @@ alsa_switch_init (AlsaSwitch *swtch)
}
AlsaSwitch *
-alsa_switch_new (const gchar *name, const gchar *label, GList *options)
+alsa_switch_new (const gchar *name,
+ const gchar *label,
+ MateMixerSwitchRole role,
+ GList *options)
{
AlsaSwitch *swtch;
swtch = g_object_new (ALSA_TYPE_SWITCH,
"name", name,
"label", label,
+ "role", role,
NULL);
/* Takes ownership of options */
@@ -109,6 +133,9 @@ alsa_switch_set_active_option (MateMixerSwitch *mms, MateMixerSwitchOption *mmso
swtch = ALSA_SWITCH (mms);
+ if G_UNLIKELY (swtch->priv->element == NULL)
+ return FALSE;
+
/* The channel mask is created when reading the active option the first
* time, so a successful load must be done before changing the option */
if G_UNLIKELY (swtch->priv->channel_mask == 0) {
@@ -136,12 +163,12 @@ alsa_switch_set_active_option (MateMixerSwitch *mms, MateMixerSwitchOption *mmso
return set_item;
}
-static GList *
-alsa_switch_list_options (MateMixerSwitch *swtch)
+static const GList *
+alsa_switch_list_options (MateMixerSwitch *mms)
{
- g_return_val_if_fail (ALSA_IS_SWITCH (swtch), NULL);
+ g_return_val_if_fail (ALSA_IS_SWITCH (mms), NULL);
- return ALSA_SWITCH (swtch)->priv->options;
+ return ALSA_SWITCH (mms)->priv->options;
}
static snd_mixer_elem_t *
@@ -156,7 +183,6 @@ static void
alsa_switch_set_snd_element (AlsaElement *element, snd_mixer_elem_t *el)
{
g_return_if_fail (ALSA_IS_SWITCH (element));
- g_return_if_fail (el != NULL);
ALSA_SWITCH (element)->priv->element = el;
}
@@ -170,8 +196,13 @@ alsa_switch_load (AlsaElement *element)
gint ret;
snd_mixer_selem_channel_id_t c;
+ g_return_val_if_fail (ALSA_IS_SWITCH (element), FALSE);
+
swtch = ALSA_SWITCH (element);
+ if G_UNLIKELY (swtch->priv->element == NULL)
+ return FALSE;
+
/* When reading the first time we try all the channels, otherwise only the
* ones which returned success before */
if (swtch->priv->channel_mask == 0) {
@@ -220,7 +251,7 @@ alsa_switch_load (AlsaElement *element)
}
g_warning ("Unknown active option of switch %s: %d",
- snd_mixer_selem_get_name (swtch->priv->element),
+ mate_mixer_switch_get_name (MATE_MIXER_SWITCH (swtch)),
item);
return FALSE;
diff --git a/backends/alsa/alsa-switch.h b/backends/alsa/alsa-switch.h
index fdcfb87..b7f5931 100644
--- a/backends/alsa/alsa-switch.h
+++ b/backends/alsa/alsa-switch.h
@@ -56,9 +56,10 @@ struct _AlsaSwitchClass
GType alsa_switch_get_type (void) G_GNUC_CONST;
-AlsaSwitch *alsa_switch_new (const gchar *name,
- const gchar *label,
- GList *options);
+AlsaSwitch *alsa_switch_new (const gchar *name,
+ const gchar *label,
+ MateMixerSwitchRole role,
+ GList *options);
G_END_DECLS
diff --git a/backends/alsa/alsa-toggle.c b/backends/alsa/alsa-toggle.c
index efa3460..a7958c9 100644
--- a/backends/alsa/alsa-toggle.c
+++ b/backends/alsa/alsa-toggle.c
@@ -42,13 +42,13 @@ G_DEFINE_TYPE_WITH_CODE (AlsaToggle, alsa_toggle, MATE_MIXER_TYPE_TOGGLE,
G_IMPLEMENT_INTERFACE (ALSA_TYPE_ELEMENT,
alsa_element_interface_init))
-static gboolean alsa_toggle_set_active_option (MateMixerSwitch *mms,
- MateMixerSwitchOption *mmso);
+static gboolean alsa_toggle_set_active_option (MateMixerSwitch *mms,
+ MateMixerSwitchOption *mmso);
-static snd_mixer_elem_t * alsa_toggle_get_snd_element (AlsaElement *element);
-static void alsa_toggle_set_snd_element (AlsaElement *element,
- snd_mixer_elem_t *el);
-static gboolean alsa_toggle_load (AlsaElement *element);
+static snd_mixer_elem_t *alsa_toggle_get_snd_element (AlsaElement *element);
+static void alsa_toggle_set_snd_element (AlsaElement *element,
+ snd_mixer_elem_t *el);
+static gboolean alsa_toggle_load (AlsaElement *element);
static void
alsa_element_interface_init (AlsaElementInterface *iface)
@@ -78,17 +78,20 @@ alsa_toggle_init (AlsaToggle *toggle)
}
AlsaToggle *
-alsa_toggle_new (const gchar *name,
- const gchar *label,
- AlsaToggleType type,
- AlsaSwitchOption *on,
- AlsaSwitchOption *off)
+alsa_toggle_new (const gchar *name,
+ const gchar *label,
+ MateMixerSwitchRole role,
+ AlsaToggleType type,
+ AlsaSwitchOption *on,
+ AlsaSwitchOption *off)
{
AlsaToggle *toggle;
toggle = g_object_new (ALSA_TYPE_TOGGLE,
"name", name,
"label", label,
+ "flags", MATE_MIXER_SWITCH_TOGGLE,
+ "role", role,
"state-option-on", on,
"state-option-off", off,
NULL);
@@ -109,7 +112,12 @@ alsa_toggle_set_active_option (MateMixerSwitch *mms, MateMixerSwitchOption *mmso
toggle = ALSA_TOGGLE (mms);
- /* For toggles the 0/1 value is stored as the switch option id */
+ if G_UNLIKELY (toggle->priv->element == NULL)
+ return FALSE;
+
+ /* For toggles the 0/1 value is stored as the switch option id, there is not really
+ * a need to validate that the option belong to the switch, just make sure it
+ * contains the value 0 or 1 */
value = alsa_switch_option_get_id (ALSA_SWITCH_OPTION (mmso));
if G_UNLIKELY (value != 0 && value != 1) {
g_warn_if_reached ();
@@ -143,7 +151,6 @@ static void
alsa_toggle_set_snd_element (AlsaElement *element, snd_mixer_elem_t *el)
{
g_return_if_fail (ALSA_IS_TOGGLE (element));
- g_return_if_fail (el != NULL);
ALSA_TOGGLE (element)->priv->element = el;
}
@@ -158,6 +165,9 @@ alsa_toggle_load (AlsaElement *element)
toggle = ALSA_TOGGLE (element);
+ if G_UNLIKELY (toggle->priv->element == NULL)
+ return FALSE;
+
/* When reading the first time we try all the channels, otherwise only the
* ones which returned success before */
if (toggle->priv->channel_mask == 0) {
@@ -207,7 +217,6 @@ alsa_toggle_load (AlsaElement *element)
active = mate_mixer_toggle_get_state_option (MATE_MIXER_TOGGLE (toggle), FALSE);
_mate_mixer_switch_set_active_option (MATE_MIXER_SWITCH (toggle), active);
-
return TRUE;
}
diff --git a/backends/alsa/alsa-toggle.h b/backends/alsa/alsa-toggle.h
index d9c083b..1e1993c 100644
--- a/backends/alsa/alsa-toggle.h
+++ b/backends/alsa/alsa-toggle.h
@@ -63,11 +63,12 @@ struct _AlsaToggleClass
GType alsa_toggle_get_type (void) G_GNUC_CONST;
-AlsaToggle *alsa_toggle_new (const gchar *name,
- const gchar *label,
- AlsaToggleType type,
- AlsaSwitchOption *on,
- AlsaSwitchOption *off);
+AlsaToggle *alsa_toggle_new (const gchar *name,
+ const gchar *label,
+ MateMixerSwitchRole role,
+ AlsaToggleType type,
+ AlsaSwitchOption *on,
+ AlsaSwitchOption *off);
G_END_DECLS
diff --git a/backends/null/Makefile.am b/backends/null/Makefile.am
index 8ce28d1..08005e4 100644
--- a/backends/null/Makefile.am
+++ b/backends/null/Makefile.am
@@ -3,6 +3,7 @@ backenddir = $(libdir)/libmatemixer
backend_LTLIBRARIES = libmatemixer-null.la
AM_CPPFLAGS = \
+ -Wno-unknown-pragmas \
-I$(top_srcdir) \
-DG_LOG_DOMAIN=\"libmatemixer-null\"
diff --git a/backends/null/null-backend.c b/backends/null/null-backend.c
index 49038b1..ee0ad2e 100644
--- a/backends/null/null-backend.c
+++ b/backends/null/null-backend.c
@@ -29,7 +29,10 @@ static void null_backend_class_init (NullBackendClass *klass);
static void null_backend_class_finalize (NullBackendClass *klass);
static void null_backend_init (NullBackend *null);
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
G_DEFINE_DYNAMIC_TYPE (NullBackend, null_backend, MATE_MIXER_TYPE_BACKEND)
+#pragma clang diagnostic pop
static gboolean null_backend_open (MateMixerBackend *backend);
diff --git a/backends/oss/Makefile.am b/backends/oss/Makefile.am
index 44caeb8..f535a37 100644
--- a/backends/oss/Makefile.am
+++ b/backends/oss/Makefile.am
@@ -3,6 +3,7 @@ backenddir = $(libdir)/libmatemixer
backend_LTLIBRARIES = libmatemixer-oss.la
AM_CPPFLAGS = \
+ -Wno-unknown-pragmas \
-I$(top_srcdir) \
-DG_LOG_DOMAIN=\"libmatemixer-oss\"
@@ -19,7 +20,12 @@ libmatemixer_oss_la_SOURCES = \
oss-stream.c \
oss-stream.h \
oss-stream-control.c \
- oss-stream-control.h
+ oss-stream-control.h \
+ oss-switch.c \
+ oss-switch.h \
+ oss-switch-option.c \
+ oss-switch-option.h \
+ oss-types.h
libmatemixer_oss_la_LIBADD = \
$(GLIB_LIBS) \
diff --git a/backends/oss/oss-backend.c b/backends/oss/oss-backend.c
index 2b5eca7..23d265b 100644
--- a/backends/oss/oss-backend.c
+++ b/backends/oss/oss-backend.c
@@ -32,7 +32,7 @@
#include "oss-stream.h"
#define BACKEND_NAME "OSS"
-#define BACKEND_PRIORITY 9
+#define BACKEND_PRIORITY 10
#if !defined(__linux__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
/* At least on systems based on FreeBSD we will need to read device names
@@ -47,7 +47,9 @@ struct _OssBackendPrivate
{
gchar *default_device;
GSource *timeout_source;
- GHashTable *devices;
+ GList *streams;
+ GList *devices;
+ GHashTable *devices_paths;
};
static void oss_backend_class_init (OssBackendClass *klass);
@@ -61,36 +63,49 @@ static void oss_backend_finalize (GObject *object);
G_DEFINE_DYNAMIC_TYPE (OssBackend, oss_backend, MATE_MIXER_TYPE_BACKEND)
#pragma clang diagnostic pop
-static gboolean oss_backend_open (MateMixerBackend *backend);
-static void oss_backend_close (MateMixerBackend *backend);
-static GList * oss_backend_list_devices (MateMixerBackend *backend);
-static GList * oss_backend_list_streams (MateMixerBackend *backend);
+static gboolean oss_backend_open (MateMixerBackend *backend);
+static void oss_backend_close (MateMixerBackend *backend);
+static const GList *oss_backend_list_devices (MateMixerBackend *backend);
+static const GList *oss_backend_list_streams (MateMixerBackend *backend);
-static gboolean read_devices (OssBackend *oss);
+static gboolean read_devices (OssBackend *oss);
-static gboolean read_device (OssBackend *oss,
- const gchar *path,
- gboolean *added);
+static gboolean read_device (OssBackend *oss,
+ const gchar *path,
+ gboolean *added);
-static gchar * read_device_label (OssBackend *oss,
- const gchar *path,
- gint fd);
+static gchar * read_device_label (OssBackend *oss,
+ const gchar *path,
+ gint fd);
-static gchar * read_device_label_sndstat (OssBackend *oss,
- const gchar *sndstat,
- const gchar *path,
- guint index) G_GNUC_UNUSED;
+static gchar * read_device_label_sndstat (OssBackend *oss,
+ const gchar *sndstat,
+ const gchar *path,
+ guint index) G_GNUC_UNUSED;
-static void add_device (OssBackend *oss,
- OssDevice *device);
-static void remove_device (OssBackend *oss,
- OssDevice *device);
+static void add_device (OssBackend *oss,
+ OssDevice *device);
+static void remove_device (OssBackend *oss,
+ OssDevice *device);
-static void remove_stream (OssBackend *oss,
- const gchar *name);
+static void remove_device_by_path (OssBackend *oss,
+ const gchar *path);
-static void select_default_input_stream (OssBackend *oss);
-static void select_default_output_stream (OssBackend *oss);
+static void remove_device_by_list_item (OssBackend *oss,
+ GList *item);
+
+static void remove_stream (OssBackend *oss,
+ const gchar *name);
+
+static void select_default_input_stream (OssBackend *oss);
+static void select_default_output_stream (OssBackend *oss);
+
+static void free_stream_list (OssBackend *oss);
+
+static gint compare_devices (gconstpointer a,
+ gconstpointer b);
+static gint compare_device_path (gconstpointer a,
+ gconstpointer b);
static MateMixerBackendInfo info;
@@ -142,10 +157,10 @@ oss_backend_init (OssBackend *oss)
OSS_TYPE_BACKEND,
OssBackendPrivate);
- oss->priv->devices = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- g_object_unref);
+ oss->priv->devices_paths = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ NULL);
}
static void
@@ -170,7 +185,7 @@ oss_backend_finalize (GObject *object)
oss = OSS_BACKEND (object);
- g_hash_table_destroy (oss->priv->devices);
+ g_hash_table_unref (oss->priv->devices_paths);
G_OBJECT_CLASS (oss_backend_parent_class)->finalize (object);
}
@@ -212,63 +227,65 @@ oss_backend_close (MateMixerBackend *backend)
oss = OSS_BACKEND (backend);
g_source_destroy (oss->priv->timeout_source);
- g_hash_table_remove_all (oss->priv->devices);
- g_free (oss->priv->default_device);
- oss->priv->default_device = NULL;
+ if (oss->priv->devices != NULL) {
+ g_list_free_full (oss->priv->devices, g_object_unref);
+ oss->priv->devices = NULL;
+ }
+ if (oss->priv->default_device != NULL) {
+ g_free (oss->priv->default_device);
+ oss->priv->default_device = NULL;
+ }
+
+ free_stream_list (oss);
+
+ g_hash_table_remove_all (oss->priv->devices_paths);
_mate_mixer_backend_set_state (backend, MATE_MIXER_STATE_IDLE);
}
-static GList *
+static const GList *
oss_backend_list_devices (MateMixerBackend *backend)
{
- GList *list;
-
g_return_val_if_fail (OSS_IS_BACKEND (backend), NULL);
- /* Convert the hash table to a linked list, this list is expected to be
- * cached in the main library */
- list = g_hash_table_get_values (OSS_BACKEND (backend)->priv->devices);
- if (list != NULL)
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
-
- return list;
+ return OSS_BACKEND (backend)->priv->devices;
}
-static GList *
+static const GList *
oss_backend_list_streams (MateMixerBackend *backend)
{
- OssBackend *oss;
- GHashTableIter iter;
- gpointer value;
- GList *list = NULL;
+ OssBackend *oss;
g_return_val_if_fail (OSS_IS_BACKEND (backend), NULL);
oss = OSS_BACKEND (backend);
- /* We don't keep a list or hash table of all streams here, instead walk
- * through the list of devices and create the list manually, each device
- * has at most one input and one output stream */
- g_hash_table_iter_init (&iter, oss->priv->devices);
+ if (oss->priv->streams == NULL) {
+ GList *list;
- while (g_hash_table_iter_next (&iter, NULL, &value)) {
- OssDevice *device = OSS_DEVICE (value);
- OssStream *stream;
+ /* Walk through the list of devices and create the stream list, each
+ * device has at most one input and one output stream */
+ list = oss->priv->devices;
- stream = oss_device_get_output_stream (device);
- if (stream != NULL)
- list = g_list_prepend (list, stream);
- stream = oss_device_get_input_stream (device);
- if (stream != NULL)
- list = g_list_prepend (list, stream);
- }
+ while (list != NULL) {
+ OssDevice *device = OSS_DEVICE (list->data);
+ OssStream *stream;
- if (list != NULL)
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
-
- return list;
+ stream = oss_device_get_input_stream (device);
+ if (stream != NULL) {
+ oss->priv->streams =
+ g_list_append (oss->priv->streams, g_object_ref (stream));
+ }
+ stream = oss_device_get_output_stream (device);
+ if (stream != NULL) {
+ oss->priv->streams =
+ g_list_append (oss->priv->streams, g_object_ref (stream));
+ }
+ list = list->next;
+ }
+ }
+ return oss->priv->streams;
}
static gboolean
@@ -278,8 +295,10 @@ read_devices (OssBackend *oss)
gboolean added = FALSE;
for (i = 0; i < OSS_MAX_DEVICES; i++) {
- gboolean added_current;
- gchar *path = g_strdup_printf ("/dev/mixer%i", i);
+ gchar *path;
+ gboolean added_current = FALSE;
+
+ path = g_strdup_printf ("/dev/mixer%i", i);
/* On recent FreeBSD both /dev/mixer and /dev/mixer0 point to the same
* mixer device, on NetBSD and OpenBSD /dev/mixer is a symlink to one
@@ -289,7 +308,7 @@ read_devices (OssBackend *oss)
if (read_device (oss, path, &added_current) == FALSE && i == 0)
read_device (oss, "/dev/mixer", &added_current);
- if (added_current)
+ if (added_current == TRUE)
added = TRUE;
g_free (path);
@@ -312,16 +331,12 @@ read_device (OssBackend *oss, const gchar *path, gboolean *added)
gchar *bname;
gchar *label;
- device = g_hash_table_lookup (oss->priv->devices, path);
- *added = FALSE;
-
fd = g_open (path, O_RDWR, 0);
if (fd == -1) {
if (errno != ENOENT && errno != ENXIO)
g_debug ("%s: %s", path, g_strerror (errno));
- if (device != NULL)
- remove_device (oss, device);
+ remove_device_by_path (oss, path);
return FALSE;
}
@@ -329,7 +344,7 @@ read_device (OssBackend *oss, const gchar *path, gboolean *added)
* still tested to be absolutely sure that the device is removed it case
* it has disappeared, but normally the device's polling facility should
* handle this by itself */
- if (device != NULL) {
+ if (g_hash_table_contains (oss->priv->devices_paths, path) == TRUE) {
close (fd);
return TRUE;
}
@@ -345,8 +360,9 @@ read_device (OssBackend *oss, const gchar *path, gboolean *added)
if ((*added = oss_device_open (device)) == TRUE)
add_device (oss, device);
+ else
+ g_object_unref (device);
- g_object_unref (device);
return *added;
}
@@ -445,44 +461,104 @@ read_device_label_sndstat (OssBackend *oss,
static void
add_device (OssBackend *oss, OssDevice *device)
{
- const gchar *name;
+ oss->priv->devices =
+ g_list_insert_sorted_with_data (oss->priv->devices,
+ device,
+ (GCompareDataFunc) compare_devices,
+ NULL);
- name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device));
+ /* Keep track of added device paths */
+ g_hash_table_add (oss->priv->devices_paths,
+ g_strdup (oss_device_get_path (device)));
- g_hash_table_insert (oss->priv->devices,
- g_strdup (oss_device_get_path (device)),
- g_object_ref (device));
-
- // XXX make device emit it when closed
+ g_signal_connect_swapped (G_OBJECT (device),
+ "closed",
+ G_CALLBACK (remove_device),
+ oss);
g_signal_connect_swapped (G_OBJECT (device),
"stream-removed",
G_CALLBACK (remove_stream),
oss);
- g_signal_emit_by_name (G_OBJECT (oss), "device-added", name);
+ g_signal_connect_swapped (G_OBJECT (device),
+ "closed",
+ G_CALLBACK (free_stream_list),
+ oss);
+ g_signal_connect_swapped (G_OBJECT (device),
+ "stream-added",
+ G_CALLBACK (free_stream_list),
+ oss);
+ g_signal_connect_swapped (G_OBJECT (device),
+ "stream-removed",
+ G_CALLBACK (free_stream_list),
+ oss);
+ g_signal_emit_by_name (G_OBJECT (oss),
+ "device-added",
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
+
+ /* Load the device elements after emitting device-added, because the load
+ * function will most likely emit stream-added on the device and backend */
oss_device_load (device);
}
static void
remove_device (OssBackend *oss, OssDevice *device)
{
- const gchar *name;
+ GList *item;
+
+ item = g_list_find (oss->priv->devices, device);
+ if (item != NULL)
+ remove_device_by_list_item (oss, item);
+}
+
+static void
+remove_device_by_path (OssBackend *oss, const gchar *path)
+{
+ GList *item;
+
+ item = g_list_find_custom (oss->priv->devices, path, compare_device_path);
+ if (item != NULL)
+ remove_device_by_list_item (oss, item);
+}
+
+static void
+remove_device_by_list_item (OssBackend *oss, GList *item)
+{
+ OssDevice *device;
const gchar *path;
- path = oss_device_get_path (device);
- name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device));
+ device = OSS_DEVICE (item->data);
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (device),
+ G_CALLBACK (remove_device),
+ oss);
+
+ if (oss_device_is_open (device) == TRUE)
+ oss_device_close (device);
g_signal_handlers_disconnect_by_func (G_OBJECT (device),
G_CALLBACK (remove_stream),
oss);
- // XXX close the device and make it remove streams
- g_hash_table_remove (oss->priv->devices, path);
+ oss->priv->devices = g_list_delete_link (oss->priv->devices, item);
+
+ path = oss_device_get_path (device);
+ g_hash_table_remove (oss->priv->devices_paths, path);
+
+ if (g_strcmp0 (oss->priv->default_device, path) == 0) {
+ g_free (oss->priv->default_device);
+ oss->priv->default_device = NULL;
+ }
+
+ /* The list may and may not have been invalidate by device signals */
+ free_stream_list (oss);
g_signal_emit_by_name (G_OBJECT (oss),
"device-removed",
- name);
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
+
+ g_object_unref (device);
}
static void
@@ -492,7 +568,6 @@ remove_stream (OssBackend *oss, const gchar *name)
stream = mate_mixer_backend_get_default_input_stream (MATE_MIXER_BACKEND (oss));
- // XXX see if the change happens after stream is removed or before
if (stream != NULL && strcmp (mate_mixer_stream_get_name (stream), name) == 0)
select_default_input_stream (oss);
@@ -502,16 +577,31 @@ remove_stream (OssBackend *oss, const gchar *name)
select_default_output_stream (oss);
}
+static OssDevice *
+get_default_device (OssBackend *oss)
+{
+ GList *item;
+
+ if (oss->priv->default_device == NULL)
+ return NULL;
+
+ item = g_list_find_custom (oss->priv->devices,
+ oss->priv->default_device,
+ compare_device_path);
+ if G_LIKELY (item != NULL)
+ return OSS_DEVICE (item->data);
+
+ return NULL;
+}
+
static void
select_default_input_stream (OssBackend *oss)
{
- OssDevice *device = NULL;
+ OssDevice *device;
OssStream *stream;
- gint i;
+ GList *list;
- /* Always prefer stream in the "default" device */
- if (oss->priv->default_device != NULL)
- device = g_hash_table_lookup (oss->priv->devices, oss->priv->default_device);
+ device = get_default_device (oss);
if (device != NULL) {
stream = oss_device_get_input_stream (device);
if (stream != NULL) {
@@ -521,23 +611,17 @@ select_default_input_stream (OssBackend *oss)
}
}
- for (i = 0; i < OSS_MAX_DEVICES; i++) {
- gchar *path = g_strdup_printf ("/dev/mixer%i", i);
-
- device = g_hash_table_lookup (oss->priv->devices, path);
- if (device == NULL && i == 0)
- device = g_hash_table_lookup (oss->priv->devices, "/dev/mixer");
+ list = oss->priv->devices;
+ while (list != NULL) {
+ device = OSS_DEVICE (list->data);
+ stream = oss_device_get_input_stream (device);
- if (device != NULL) {
- stream = oss_device_get_input_stream (device);
- if (stream != NULL) {
- _mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (oss),
- MATE_MIXER_STREAM (stream));
- g_free (path);
- return;
- }
+ if (stream != NULL) {
+ _mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (oss),
+ MATE_MIXER_STREAM (stream));
+ return;
}
- g_free (path);
+ list = list->next;
}
/* In the worst case unset the default stream */
@@ -547,13 +631,11 @@ select_default_input_stream (OssBackend *oss)
static void
select_default_output_stream (OssBackend *oss)
{
- OssDevice *device = NULL;
+ OssDevice *device;
OssStream *stream;
- gint i;
+ GList *list;
- /* Always prefer stream in the "default" device */
- if (oss->priv->default_device != NULL)
- device = g_hash_table_lookup (oss->priv->devices, oss->priv->default_device);
+ device = get_default_device (oss);
if (device != NULL) {
stream = oss_device_get_output_stream (device);
if (stream != NULL) {
@@ -563,25 +645,48 @@ select_default_output_stream (OssBackend *oss)
}
}
- for (i = 0; i < OSS_MAX_DEVICES; i++) {
- gchar *path = g_strdup_printf ("/dev/mixer%i", i);
-
- device = g_hash_table_lookup (oss->priv->devices, path);
- if (device == NULL && i == 0)
- device = g_hash_table_lookup (oss->priv->devices, "/dev/mixer");
+ list = oss->priv->devices;
+ while (list != NULL) {
+ device = OSS_DEVICE (list->data);
+ stream = oss_device_get_output_stream (device);
- if (device != NULL) {
- stream = oss_device_get_output_stream (device);
- if (stream != NULL) {
- _mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (oss),
- MATE_MIXER_STREAM (stream));
- g_free (path);
- return;
- }
+ if (stream != NULL) {
+ _mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (oss),
+ MATE_MIXER_STREAM (stream));
+ return;
}
- g_free (path);
+ list = list->next;
}
/* In the worst case unset the default stream */
_mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (oss), NULL);
}
+
+static void
+free_stream_list (OssBackend *oss)
+{
+ if (oss->priv->streams == NULL)
+ return;
+
+ g_list_free_full (oss->priv->streams, g_object_unref);
+
+ oss->priv->streams = NULL;
+}
+
+static gint
+compare_devices (gconstpointer a, gconstpointer b)
+{
+ MateMixerDevice *d1 = MATE_MIXER_DEVICE (a);
+ MateMixerDevice *d2 = MATE_MIXER_DEVICE (b);
+
+ return strcmp (mate_mixer_device_get_name (d1), mate_mixer_device_get_name (d2));
+}
+
+static gint
+compare_device_path (gconstpointer a, gconstpointer b)
+{
+ OssDevice *device = OSS_DEVICE (a);
+ const gchar *path = (const gchar *) b;
+
+ return strcmp (oss_device_get_path (device), path);
+}
diff --git a/backends/oss/oss-backend.h b/backends/oss/oss-backend.h
index 325b61c..9617e79 100644
--- a/backends/oss/oss-backend.h
+++ b/backends/oss/oss-backend.h
@@ -20,9 +20,10 @@
#include <glib.h>
#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
-#include <libmatemixer/matemixer-backend.h>
-#include <libmatemixer/matemixer-backend-module.h>
+#include "oss-types.h"
#define OSS_TYPE_BACKEND \
(oss_backend_get_type ())
@@ -37,7 +38,6 @@
#define OSS_BACKEND_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), OSS_TYPE_BACKEND, OssBackendClass))
-typedef struct _OssBackend OssBackend;
typedef struct _OssBackendClass OssBackendClass;
typedef struct _OssBackendPrivate OssBackendPrivate;
@@ -54,7 +54,7 @@ struct _OssBackendClass
MateMixerBackendClass parent_class;
};
-GType oss_backend_get_type (void) G_GNUC_CONST;
+GType oss_backend_get_type (void) G_GNUC_CONST;
/* Support function for dynamic loading of the backend module */
void backend_module_init (GTypeModule *module);
diff --git a/backends/oss/oss-device.c b/backends/oss/oss-device.c
index cf51705..44ed18f 100644
--- a/backends/oss/oss-device.c
+++ b/backends/oss/oss-device.c
@@ -16,7 +16,6 @@
*/
#include <errno.h>
-#include <unistd.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
@@ -29,87 +28,184 @@
#include "oss-device.h"
#include "oss-stream.h"
#include "oss-stream-control.h"
+#include "oss-switch-option.h"
+
+/*
+ * NOTES:
+ *
+ * OSS has a predefined list of channels (or "devices"), which historically used
+ * to be mapped to individual sound card pins. At this time, the channels are
+ * chosen somehow arbitrarily by drivers.
+ *
+ * Each of the channels may have a record switch, which toggles between playback
+ * and capture direction. OSS doesn't have mute switches and we can't really use
+ * the record switch as one. For this reason all channels are modelled as
+ * muteless stream controls and the record switch is modelled as a port switch.
+ *
+ * Also, we avoid modelling capturable channels as both input and output channels,
+ * because the ones which allow capture are normally capture-only channels
+ * (OSS just doesn't have the ability to make the distinction), so each channel in
+ * the list contains a flag of whether it can be used as a capture source, given
+ * that it's reported as capturable. Capturable channels are therefore modelled
+ * as input controls and this approach avoids for example putting PCM in an input
+ * stream (which makes no sense).
+ *
+ * OSS also has an indicator of whether the record switch is exclusive (only
+ * allows one capture source at a time), to simplify the lives of applications
+ * we always create a port switch and therefore assume the exclusivity is always
+ * true. Ideally, we should probably model a bunch of toggles, one for each channel
+ * with capture capability if they are known not to be exclusive.
+ */
#define OSS_DEVICE_ICON "audio-card"
-typedef enum
-{
+#define OSS_POLL_TIMEOUT_NORMAL 500
+#define OSS_POLL_TIMEOUT_RAPID 50
+#define OSS_POLL_TIMEOUT_RESTORE 3000
+
+typedef enum {
+ OSS_POLL_NORMAL,
+ OSS_POLL_RAPID
+} OssPollMode;
+
+typedef enum {
OSS_DEV_ANY,
OSS_DEV_INPUT,
OSS_DEV_OUTPUT
-} OssDevType;
+} OssDevChannelType;
-typedef struct
-{
+typedef struct {
gchar *name;
gchar *label;
MateMixerStreamControlRole role;
- OssDevType type;
-} OssDev;
-
-static const OssDev oss_devices[] = {
- { "vol", N_("Volume"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, OSS_DEV_OUTPUT },
- { "bass", N_("Bass"), MATE_MIXER_STREAM_CONTROL_ROLE_BASS, OSS_DEV_OUTPUT },
- { "treble", N_("Treble"), MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE, OSS_DEV_OUTPUT },
- { "synth", N_("Synth"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_INPUT },
- { "pcm", N_("PCM"), MATE_MIXER_STREAM_CONTROL_ROLE_PCM, OSS_DEV_OUTPUT },
+ OssDevChannelType type;
+ gchar *icon;
+} OssDevChannel;
+
+/* Index of a channel in the array corresponds to the channel number passed to ioctl()s,
+ * device names are takes from soundcard.h */
+static const OssDevChannel oss_devices[] = {
+ { "vol", N_("Volume"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, OSS_DEV_OUTPUT, NULL },
+ { "bass", N_("Bass"), MATE_MIXER_STREAM_CONTROL_ROLE_BASS, OSS_DEV_OUTPUT, NULL },
+ { "treble", N_("Treble"), MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE, OSS_DEV_OUTPUT, NULL },
+ { "synth", N_("Synth"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_INPUT, NULL },
+ { "pcm", N_("PCM"), MATE_MIXER_STREAM_CONTROL_ROLE_PCM, OSS_DEV_OUTPUT, NULL },
/* OSS manual says this should be the beeper, but Linux OSS seems to assign it to
* regular volume control */
- { "speaker", N_("Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, OSS_DEV_OUTPUT },
- { "line", N_("Line-in"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
- { "mic", N_("Microphone"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
- { "cd", N_("CD"), MATE_MIXER_STREAM_CONTROL_ROLE_CD, OSS_DEV_INPUT },
+ { "speaker", N_("Speaker"), MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, OSS_DEV_OUTPUT, NULL },
+ { "line", N_("Line In"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT, NULL },
+ { "mic", N_("Microphone"), MATE_MIXER_STREAM_CONTROL_ROLE_MICROPHONE, OSS_DEV_INPUT, "audio-input-microphone" },
+ { "cd", N_("CD"), MATE_MIXER_STREAM_CONTROL_ROLE_CD, OSS_DEV_INPUT, NULL },
/* Recording monitor */
- { "mix", N_("Mixer"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT },
- { "pcm2", N_("PCM-2"), MATE_MIXER_STREAM_CONTROL_ROLE_PCM, OSS_DEV_OUTPUT },
+ { "mix", N_("Mixer"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT, NULL },
+ { "pcm2", N_("PCM 2"), MATE_MIXER_STREAM_CONTROL_ROLE_PCM, OSS_DEV_OUTPUT, NULL },
/* Recording level (master input) */
- { "rec", N_("Record"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, OSS_DEV_INPUT },
- { "igain", N_("In-gain"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_INPUT },
- { "ogain", N_("Out-gain"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT },
- { "line1", N_("Line-1"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
- { "line2", N_("Line-2"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
- { "line3", N_("Line-3"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
- { "dig1", N_("Digital-1"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_ANY },
- { "dig2", N_("Digital-2"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_ANY },
- { "dig3", N_("Digital-3"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_ANY },
- { "phin", N_("Phone-in"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
- { "phout", N_("Phone-out"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_OUTPUT },
- { "video", N_("Video"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
- { "radio", N_("Radio"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT },
- { "monitor", N_("Monitor"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT },
- { "depth", N_("3D-depth"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT },
- { "center", N_("3D-center"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT },
- { "midi", N_("MIDI"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_INPUT }
+ { "rec", N_("Record"), MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, OSS_DEV_INPUT, NULL },
+ { "igain", N_("Input Gain"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_INPUT, NULL },
+ { "ogain", N_("Output Gain"), MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, OSS_DEV_OUTPUT, NULL },
+ { "line1", N_("Line In 1"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT, NULL },
+ { "line2", N_("Line In 2"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT, NULL },
+ { "line3", N_("Line In 3"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT, NULL },
+ /* These 3 can be attached to either digital input or output */
+ { "dig1", N_("Digital 1"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_ANY, NULL },
+ { "dig2", N_("Digital 2"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_ANY, NULL },
+ { "dig3", N_("Digital 3"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_ANY, NULL },
+ { "phin", N_("Phone In"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT, NULL },
+ { "phout", N_("Phone Out"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_OUTPUT, NULL },
+ { "video", N_("Video"), MATE_MIXER_STREAM_CONTROL_ROLE_VIDEO, OSS_DEV_INPUT, NULL },
+ { "radio", N_("Radio"), MATE_MIXER_STREAM_CONTROL_ROLE_PORT, OSS_DEV_INPUT, NULL },
+
+ /* soundcard.h on some systems include more channels, but different files provide
+ * different meanings for the remaining ones and the value is doubtful */
};
#define OSS_N_DEVICES MIN (G_N_ELEMENTS (oss_devices), SOUND_MIXER_NRDEVICES)
+/* Priorities for selecting default controls */
+static const gint oss_input_priority[] = {
+ 11, /* rec */
+ 12, /* igain */
+ 7, /* mic */
+ 6, /* line */
+ 14, /* line1 */
+ 15, /* line2 */
+ 16, /* line3 */
+ 17, /* dig1 */
+ 18, /* dig2 */
+ 19, /* dig3 */
+ 20, /* phin */
+ 8, /* cd */
+ 22, /* video */
+ 23, /* radio */
+ 3, /* synth */
+ 27 /* midi */
+};
+
+static const gint oss_output_priority[] = {
+ 0, /* vol */
+ 4, /* pcm */
+ 10, /* pcm2 */
+ 5, /* speaker */
+ 17, /* dig1 */
+ 18, /* dig2 */
+ 19, /* dig3 */
+ 25, /* depth */
+ 26, /* center */
+ 21, /* phone out */
+ 13, /* ogain */
+ 9, /* mix */
+ 24, /* monitor */
+ 1, /* bass */
+ 2 /* treble */
+};
+
struct _OssDevicePrivate
{
- gint fd;
- gchar *path;
- gint devmask;
- gint stereodevs;
- gint recmask;
- gint recsrc;
- OssStream *input;
- OssStream *output;
+ gint fd;
+ gchar *path;
+ gint devmask;
+ gint stereodevs;
+ gint recmask;
+ guint poll_tag;
+ guint poll_tag_restore;
+ guint poll_counter;
+ gboolean poll_use_counter;
+ OssPollMode poll_mode;
+ GList *streams;
+ OssStream *input;
+ OssStream *output;
+};
+
+enum {
+ CLOSED,
+ N_SIGNALS
};
-static void oss_device_class_init (OssDeviceClass *klass);
-static void oss_device_init (OssDevice *device);
-static void oss_device_dispose (GObject *object);
-static void oss_device_finalize (GObject *object);
+static guint signals[N_SIGNALS] = { 0, };
+
+static void oss_device_class_init (OssDeviceClass *klass);
+static void oss_device_init (OssDevice *device);
+static void oss_device_dispose (GObject *object);
+static void oss_device_finalize (GObject *object);
G_DEFINE_TYPE (OssDevice, oss_device, MATE_MIXER_TYPE_DEVICE)
-static GList * oss_device_list_streams (MateMixerDevice *device);
+static const GList *oss_device_list_streams (MateMixerDevice *mmd);
+
+static gboolean poll_mixer (OssDevice *device);
+static gboolean poll_mixer_restore (OssDevice *device);
+
+static void read_mixer_devices (OssDevice *device);
+static void read_mixer_switch (OssDevice *device);
-static gboolean read_mixer_devices (OssDevice *device);
+static guint create_poll_source (OssDevice *device,
+ OssPollMode mode);
+static guint create_poll_restore_source (OssDevice *device);
-static gboolean set_stream_default_control (OssStream *stream,
- OssStreamControl *control,
- gboolean force);
+static void free_stream_list (OssDevice *device);
+
+static gint compare_stream_control_devnum (gconstpointer a,
+ gconstpointer b);
static void
oss_device_class_init (OssDeviceClass *klass)
@@ -124,6 +220,18 @@ oss_device_class_init (OssDeviceClass *klass)
device_class = MATE_MIXER_DEVICE_CLASS (klass);
device_class->list_streams = oss_device_list_streams;
+ signals[CLOSED] =
+ g_signal_new ("closed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (OssDeviceClass, closed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0,
+ G_TYPE_NONE);
+
g_type_class_add_private (object_class, sizeof (OssDevicePrivate));
}
@@ -145,6 +253,8 @@ oss_device_dispose (GObject *object)
g_clear_object (&device->priv->input);
g_clear_object (&device->priv->output);
+ free_stream_list (device);
+
G_OBJECT_CLASS (oss_device_parent_class)->dispose (object);
}
@@ -153,13 +263,19 @@ oss_device_finalize (GObject *object)
{
OssDevice *device = OSS_DEVICE (object);
- close (device->priv->fd);
+ if (device->priv->fd != -1)
+ close (device->priv->fd);
+
+ g_free (device->priv->path);
G_OBJECT_CLASS (oss_device_parent_class)->finalize (object);
}
OssDevice *
-oss_device_new (const gchar *name, const gchar *label, const gchar *path, gint fd)
+oss_device_new (const gchar *name,
+ const gchar *label,
+ const gchar *path,
+ gint fd)
{
OssDevice *device;
gchar *stream_name;
@@ -180,13 +296,13 @@ oss_device_new (const gchar *name, const gchar *label, const gchar *path, gint f
stream_name = g_strdup_printf ("oss-input-%s", name);
device->priv->input = oss_stream_new (stream_name,
MATE_MIXER_DEVICE (device),
- MATE_MIXER_STREAM_INPUT);
+ MATE_MIXER_DIRECTION_INPUT);
g_free (stream_name);
stream_name = g_strdup_printf ("oss-output-%s", name);
device->priv->output = oss_stream_new (stream_name,
MATE_MIXER_DEVICE (device),
- MATE_MIXER_STREAM_OUTPUT);
+ MATE_MIXER_DIRECTION_OUTPUT);
g_free (stream_name);
return device;
@@ -205,30 +321,19 @@ oss_device_open (OssDevice *device)
/* Read the essential information about the device, these values are not
* expected to change and will not be queried */
- ret = ioctl (device->priv->fd,
- MIXER_READ (SOUND_MIXER_DEVMASK),
+ ret = ioctl (device->priv->fd, MIXER_READ (SOUND_MIXER_DEVMASK),
&device->priv->devmask);
- if (ret != 0)
+ if (ret == -1)
goto fail;
- ret = ioctl (device->priv->fd,
- MIXER_READ (SOUND_MIXER_STEREODEVS),
+ ret = ioctl (device->priv->fd, MIXER_READ (SOUND_MIXER_STEREODEVS),
&device->priv->stereodevs);
- if (ret < 0)
+ if (ret == -1)
goto fail;
- ret = ioctl (device->priv->fd,
- MIXER_READ (SOUND_MIXER_RECMASK),
+ ret = ioctl (device->priv->fd, MIXER_READ (SOUND_MIXER_RECMASK),
&device->priv->recmask);
- if (ret < 0)
- goto fail;
-
- /* The recording source mask may change at any time, here we just read
- * the initial value */
- ret = ioctl (device->priv->fd,
- MIXER_READ (SOUND_MIXER_RECSRC),
- &device->priv->recsrc);
- if (ret < 0)
+ if (ret == -1)
goto fail;
/* NOTE: Linux also supports SOUND_MIXER_OUTSRC and SOUND_MIXER_OUTMASK which
@@ -246,41 +351,135 @@ fail:
}
gboolean
-oss_device_load (OssDevice *device)
+oss_device_is_open (OssDevice *device)
{
- MateMixerStreamControl *control;
-
g_return_val_if_fail (OSS_IS_DEVICE (device), FALSE);
- read_mixer_devices (device);
+ if (device->priv->fd != -1)
+ return TRUE;
+
+ return FALSE;
+}
+
+void
+oss_device_close (OssDevice *device)
+{
+ g_return_if_fail (OSS_IS_DEVICE (device));
- control = mate_mixer_stream_get_default_control (MATE_MIXER_STREAM (device->priv->input));
- if (control == NULL) {
- // XXX pick something
+ if (device->priv->fd == -1)
+ return;
+
+ /* Make each stream remove its controls and switch */
+ if (oss_stream_has_controls (device->priv->input) == TRUE) {
+ const gchar *name =
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (device->priv->input));
+
+ oss_stream_remove_all (device->priv->input);
+ free_stream_list (device);
+
+ g_signal_emit_by_name (G_OBJECT (device),
+ "stream-removed",
+ name);
}
- if (control != NULL)
- g_debug ("Default input stream control is %s",
- mate_mixer_stream_control_get_label (control));
+ if (oss_stream_has_controls (device->priv->output) == TRUE) {
+ const gchar *name =
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (device->priv->output));
+
+ oss_stream_remove_all (device->priv->output);
+ free_stream_list (device);
- control = mate_mixer_stream_get_default_control (MATE_MIXER_STREAM (device->priv->output));
- if (control == NULL) {
- // XXX pick something
+ g_signal_emit_by_name (G_OBJECT (device),
+ "stream-removed",
+ name);
}
- if (control != NULL)
- g_debug ("Default output stream control is %s",
- mate_mixer_stream_control_get_label (control));
+ if (device->priv->poll_tag != 0)
+ g_source_remove (device->priv->poll_tag);
- return TRUE;
+ if (device->priv->poll_tag_restore != 0)
+ g_source_remove (device->priv->poll_tag_restore);
+
+ close (device->priv->fd);
+ device->priv->fd = -1;
+
+ g_signal_emit (G_OBJECT (device), signals[CLOSED], 0);
}
-gint
-oss_device_get_fd (OssDevice *device)
+void
+oss_device_load (OssDevice *device)
{
- g_return_val_if_fail (OSS_IS_DEVICE (device), -1);
+ const GList *controls;
+ guint i;
+
+ g_return_if_fail (OSS_IS_DEVICE (device));
+
+ read_mixer_devices (device);
- return device->priv->fd;
+ /* Set default input control */
+ if (oss_stream_has_controls (device->priv->input) == TRUE) {
+ controls = mate_mixer_stream_list_controls (MATE_MIXER_STREAM (device->priv->input));
+
+ for (i = 0; i < G_N_ELEMENTS (oss_input_priority); i++) {
+ GList *item = g_list_find_custom ((GList *) controls,
+ GINT_TO_POINTER (oss_input_priority[i]),
+ compare_stream_control_devnum);
+ if (item == NULL)
+ continue;
+
+ oss_stream_set_default_control (device->priv->input,
+ OSS_STREAM_CONTROL (item->data));
+ break;
+ }
+ }
+
+ /* Set default output control */
+ if (oss_stream_has_controls (device->priv->output) == TRUE) {
+ controls = mate_mixer_stream_list_controls (MATE_MIXER_STREAM (device->priv->output));
+
+ for (i = 0; i < G_N_ELEMENTS (oss_output_priority); i++) {
+ GList *item = g_list_find_custom ((GList *) controls,
+ GINT_TO_POINTER (oss_output_priority[i]),
+ compare_stream_control_devnum);
+ if (item == NULL)
+ continue;
+
+ oss_stream_set_default_control (device->priv->output,
+ OSS_STREAM_CONTROL (item->data));
+ break;
+ }
+ }
+
+ if (device->priv->recmask != 0)
+ read_mixer_switch (device);
+
+ /* See if we can use the modify_counter field to optimize polling */
+#ifdef SOUND_MIXER_INFO
+ do {
+ struct mixer_info info;
+ gint ret;
+
+ ret = ioctl (device->priv->fd, SOUND_MIXER_INFO, &info);
+ if (ret == 0) {
+ device->priv->poll_counter = info.modify_counter;
+ device->priv->poll_use_counter = TRUE;
+ }
+ } while (0);
+#endif
+
+ /*
+ * Use a polling strategy inspired by KMix:
+ *
+ * Poll for changes with the OSS_POLL_TIMEOUT_NORMAL interval, when we
+ * encounter a change in modify_counter, decrease the interval to
+ * OSS_POLL_TIMEOUT_RAPID for a few seconds to allow for smoother
+ * adjustments, for example when user drags a slider.
+ *
+ * This way is not used on systems which don't support the modify_counter
+ * field, because there is no way to find out whether anything has
+ * changed and therefore when to start the rapid polling.
+ */
+ device->priv->poll_tag = create_poll_source (device, OSS_POLL_NORMAL);
}
const gchar *
@@ -307,98 +506,254 @@ oss_device_get_output_stream (OssDevice *device)
return device->priv->output;
}
-static GList *
+static const GList *
oss_device_list_streams (MateMixerDevice *mmd)
{
OssDevice *device;
- GList *list = NULL;
g_return_val_if_fail (OSS_IS_DEVICE (mmd), NULL);
device = OSS_DEVICE (mmd);
- if (device->priv->output != NULL)
- list = g_list_prepend (list, g_object_ref (device->priv->output));
- if (device->priv->input != NULL)
- list = g_list_prepend (list, g_object_ref (device->priv->input));
-
- return list;
+ if (device->priv->streams == NULL) {
+ if (device->priv->output != NULL)
+ device->priv->streams = g_list_prepend (device->priv->streams,
+ g_object_ref (device->priv->output));
+ if (device->priv->input != NULL)
+ device->priv->streams = g_list_prepend (device->priv->streams,
+ g_object_ref (device->priv->input));
+ }
+ return device->priv->streams;
}
#define OSS_MASK_HAS_DEVICE(mask,i) ((gboolean) (((mask) & (1 << (i))) > 0))
-static gboolean
+static void
read_mixer_devices (OssDevice *device)
{
- gint i;
+ OssStreamControl *control;
+ const gchar *name;
+ guint i;
+
+ name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device));
for (i = 0; i < OSS_N_DEVICES; i++) {
- OssStreamControl *control;
- gboolean input = FALSE;
+ OssStream *stream;
+ gboolean stereo;
/* Skip unavailable controls */
if (OSS_MASK_HAS_DEVICE (device->priv->devmask, i) == FALSE)
continue;
- if (oss_devices[i].type == OSS_DEV_ANY) {
- input = OSS_MASK_HAS_DEVICE (device->priv->recmask, i);
- }
- else if (oss_devices[i].type == OSS_DEV_INPUT) {
- input = TRUE;
- }
+ if (OSS_MASK_HAS_DEVICE (device->priv->recmask, i) == TRUE)
+ stream = device->priv->input;
+ else
+ stream = device->priv->output;
- control = oss_stream_control_new (oss_devices[i].name,
- oss_devices[i].label,
+ stereo = OSS_MASK_HAS_DEVICE (device->priv->stereodevs, i);
+ control = oss_stream_control_new (oss_devices[i].name, gettext (oss_devices[i].label),
oss_devices[i].role,
+ stream,
device->priv->fd,
i,
- OSS_MASK_HAS_DEVICE (device->priv->stereodevs, i));
-
- if (input == TRUE) {
- oss_stream_add_control (OSS_STREAM (device->priv->input), control);
-
- if (i == SOUND_MIXER_RECLEV || i == SOUND_MIXER_IGAIN) {
- if (i == SOUND_MIXER_RECLEV)
- set_stream_default_control (OSS_STREAM (device->priv->input),
- control,
- TRUE);
- else
- set_stream_default_control (OSS_STREAM (device->priv->input),
- control,
- FALSE);
- }
+ stereo);
+
+ if (oss_stream_has_controls (stream) == FALSE) {
+ const gchar *name =
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream));
+
+ free_stream_list (device);
+
+ /* Pretend the stream has just been created now that we are adding
+ * the first control */
+ g_signal_emit_by_name (G_OBJECT (device),
+ "stream-added",
+ name);
+ }
+
+ g_debug ("Adding device %s control %s",
+ name,
+ mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (control)));
+
+ oss_stream_add_control (stream, control);
+ oss_stream_control_load (control);
+
+ g_object_unref (control);
+ }
+}
+
+static void
+read_mixer_switch (OssDevice *device)
+{
+ GList *options = NULL;
+ guint i;
+
+ for (i = 0; i < OSS_N_DEVICES; i++) {
+ OssSwitchOption *option;
+
+ if (OSS_MASK_HAS_DEVICE (device->priv->recmask, i) == FALSE)
+ continue;
+
+ option = oss_switch_option_new (oss_devices[i].name,
+ gettext (oss_devices[i].label),
+ oss_devices[i].icon,
+ i);
+ options = g_list_prepend (options, option);
+ }
+
+ if G_LIKELY (options != NULL)
+ oss_stream_set_switch_data (device->priv->input,
+ device->priv->fd,
+ options);
+}
+
+static gboolean
+poll_mixer (OssDevice *device)
+{
+ gboolean load = TRUE;
+
+ if G_UNLIKELY (device->priv->fd == -1)
+ return G_SOURCE_REMOVE;
+
+#ifdef SOUND_MIXER_INFO
+ if (device->priv->poll_use_counter == TRUE) {
+ gint ret;
+ struct mixer_info info;
+
+ /*
+ * The modify_counter field increases each time a change happens on
+ * the device.
+ *
+ * If this ioctl() works, we use the field to only poll the controls
+ * if a change actually occured and we can also adjust the poll interval.
+ *
+ * This works well at least on Linux, NetBSD and OpenBSD. This call is
+ * not supported on FreeBSD as of version 10.
+ *
+ * The call is also used to detect unplugged devices early, when not
+ * supported, the unplug is still caught in the backend.
+ */
+ ret = ioctl (device->priv->fd, SOUND_MIXER_INFO, &info);
+ if (ret == -1) {
+ if (errno == EINTR)
+ return G_SOURCE_CONTINUE;
+
+ oss_device_close (device);
+ return G_SOURCE_REMOVE;
+ }
+
+ if (device->priv->poll_counter < info.modify_counter) {
+ device->priv->poll_counter = info.modify_counter;
} else {
- oss_stream_add_control (OSS_STREAM (device->priv->output), control);
-
- if (i == SOUND_MIXER_VOLUME || i == SOUND_MIXER_PCM) {
- if (i == SOUND_MIXER_VOLUME)
- set_stream_default_control (OSS_STREAM (device->priv->output),
- control,
- TRUE);
- else
- set_stream_default_control (OSS_STREAM (device->priv->output),
- control,
- FALSE);
- }
+ load = FALSE;
}
+ }
+#endif
+
+ if (load == TRUE) {
+ oss_stream_load (device->priv->input);
+ oss_stream_load (device->priv->output);
+
+ if (device->priv->poll_use_counter == TRUE &&
+ device->priv->poll_mode == OSS_POLL_NORMAL) {
+ /* Create a new rapid source */
+ device->priv->poll_tag = create_poll_source (device, OSS_POLL_RAPID);
- g_debug ("Added control %s",
- mate_mixer_stream_control_get_label (MATE_MIXER_STREAM_CONTROL (control)));
+ /* Also create another source to restore the poll interval to the
+ * original state */
+ device->priv->poll_tag_restore = create_poll_restore_source (device);
- oss_stream_control_update (control);
+ device->priv->poll_mode = OSS_POLL_RAPID;
+ return G_SOURCE_REMOVE;
+ }
}
- return TRUE;
+ return G_SOURCE_CONTINUE;
}
static gboolean
-set_stream_default_control (OssStream *stream, OssStreamControl *control, gboolean force)
+poll_mixer_restore (OssDevice *device)
{
- MateMixerStreamControl *current;
+ if G_LIKELY (device->priv->poll_mode == OSS_POLL_RAPID) {
+ /* Remove the current rapid source */
+ g_source_remove (device->priv->poll_tag);
- current = mate_mixer_stream_get_default_control (MATE_MIXER_STREAM (stream));
- if (current == NULL || force == TRUE) {
- oss_stream_set_default_control (stream, OSS_STREAM_CONTROL (control));
- return TRUE;
+ device->priv->poll_tag = create_poll_source (device, OSS_POLL_NORMAL);
+ device->priv->poll_mode = OSS_POLL_NORMAL;
}
- return FALSE;
+
+ /* Remove the tag for this function as it is only called once, the tag
+ * is only kept so we can remove it in the case the device is closed */
+ device->priv->poll_tag_restore = 0;
+
+ return G_SOURCE_REMOVE;
+}
+
+static guint
+create_poll_source (OssDevice *device, OssPollMode mode)
+{
+ GSource *source;
+ guint timeout;
+ guint tag;
+
+ switch (mode) {
+ case OSS_POLL_NORMAL:
+ timeout = OSS_POLL_TIMEOUT_NORMAL;
+ break;
+ case OSS_POLL_RAPID:
+ timeout = OSS_POLL_TIMEOUT_RAPID;
+ break;
+ default:
+ g_warn_if_reached ();
+ return 0;
+ }
+
+ source = g_timeout_source_new (timeout);
+ g_source_set_callback (source,
+ (GSourceFunc) poll_mixer,
+ device,
+ NULL);
+
+ tag = g_source_attach (source, g_main_context_get_thread_default ());
+ g_source_unref (source);
+
+ return tag;
+}
+
+static guint
+create_poll_restore_source (OssDevice *device)
+{
+ GSource *source;
+ guint tag;
+
+ source = g_timeout_source_new (OSS_POLL_TIMEOUT_RESTORE);
+ g_source_set_callback (source,
+ (GSourceFunc) poll_mixer_restore,
+ device,
+ NULL);
+
+ tag = g_source_attach (source, g_main_context_get_thread_default ());
+ g_source_unref (source);
+
+ return tag;
+}
+
+static void
+free_stream_list (OssDevice *device)
+{
+ /* This function is called each time the stream list changes */
+ if (device->priv->streams == NULL)
+ return;
+
+ g_list_free_full (device->priv->streams, g_object_unref);
+
+ device->priv->streams = NULL;
+}
+
+static gint
+compare_stream_control_devnum (gconstpointer a, gconstpointer b)
+{
+ OssStreamControl *control = OSS_STREAM_CONTROL (a);
+ guint devnum = GPOINTER_TO_INT (b);
+
+ return !(oss_stream_control_get_devnum (control) == devnum);
}
diff --git a/backends/oss/oss-device.h b/backends/oss/oss-device.h
index 261a884..a723f41 100644
--- a/backends/oss/oss-device.h
+++ b/backends/oss/oss-device.h
@@ -22,7 +22,7 @@
#include <glib-object.h>
#include <libmatemixer/matemixer.h>
-#include "oss-stream.h"
+#include "oss-types.h"
G_BEGIN_DECLS
@@ -39,7 +39,6 @@ G_BEGIN_DECLS
#define OSS_DEVICE_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), OSS_TYPE_DEVICE, OssDeviceClass))
-typedef struct _OssDevice OssDevice;
typedef struct _OssDeviceClass OssDeviceClass;
typedef struct _OssDevicePrivate OssDevicePrivate;
@@ -54,6 +53,9 @@ struct _OssDevice
struct _OssDeviceClass
{
MateMixerDeviceClass parent;
+
+ /*< private >*/
+ void (*closed) (OssDevice *device);
};
GType oss_device_get_type (void) G_GNUC_CONST;
@@ -64,9 +66,11 @@ OssDevice * oss_device_new (const gchar *name,
gint fd);
gboolean oss_device_open (OssDevice *device);
-gboolean oss_device_load (OssDevice *device);
+gboolean oss_device_is_open (OssDevice *device);
+void oss_device_close (OssDevice *device);
+
+void oss_device_load (OssDevice *device);
-gint oss_device_get_fd (OssDevice *device);
const gchar *oss_device_get_path (OssDevice *device);
OssStream * oss_device_get_input_stream (OssDevice *device);
diff --git a/backends/oss/oss-stream-control.c b/backends/oss/oss-stream-control.c
index 5161528..0307fc7 100644
--- a/backends/oss/oss-stream-control.c
+++ b/backends/oss/oss-stream-control.c
@@ -26,27 +26,28 @@
#include "oss-common.h"
#include "oss-stream-control.h"
+#define OSS_VOLUME_JOIN(left,right) (((left) & 0xFF) | (((right) & 0xFF) << 8))
+
+#define OSS_VOLUME_JOIN_SAME(volume) (OSS_VOLUME_JOIN ((volume), (volume)))
+#define OSS_VOLUME_JOIN_ARRAY(volume) (OSS_VOLUME_JOIN ((volume[0]), (volume[1])))
+
+#define OSS_VOLUME_TAKE_LEFT(volume) ((volume) & 0xFF)
+#define OSS_VOLUME_TAKE_RIGHT(volume) (((volume) >> 8) & 0xFF)
+
struct _OssStreamControlPrivate
{
- gint fd;
- gint devnum;
- guint volume[2];
- gfloat balance;
- gboolean stereo;
- MateMixerStreamControlRole role;
- MateMixerStreamControlFlags flags;
+ gint fd;
+ gint devnum;
+ guint8 volume[2];
+ gboolean stereo;
};
static void oss_stream_control_class_init (OssStreamControlClass *klass);
-
static void oss_stream_control_init (OssStreamControl *control);
static void oss_stream_control_finalize (GObject *object);
G_DEFINE_TYPE (OssStreamControl, oss_stream_control, MATE_MIXER_TYPE_STREAM_CONTROL)
-static gboolean oss_stream_control_set_mute (MateMixerStreamControl *mmsc,
- gboolean mute);
-
static guint oss_stream_control_get_num_channels (MateMixerStreamControl *mmsc);
static guint oss_stream_control_get_volume (MateMixerStreamControl *mmsc);
@@ -73,7 +74,9 @@ static guint oss_stream_control_get_max_volume (MateMix
static guint oss_stream_control_get_normal_volume (MateMixerStreamControl *mmsc);
static guint oss_stream_control_get_base_volume (MateMixerStreamControl *mmsc);
-static gboolean write_volume (OssStreamControl *control,
+static void read_balance (OssStreamControl *control);
+
+static gboolean write_and_set_volume (OssStreamControl *control,
gint volume);
static void
@@ -86,14 +89,13 @@ oss_stream_control_class_init (OssStreamControlClass *klass)
object_class->finalize = oss_stream_control_finalize;
control_class = MATE_MIXER_STREAM_CONTROL_CLASS (klass);
- control_class->set_mute = oss_stream_control_set_mute;
control_class->get_num_channels = oss_stream_control_get_num_channels;
control_class->get_volume = oss_stream_control_get_volume;
control_class->set_volume = oss_stream_control_set_volume;
control_class->get_channel_volume = oss_stream_control_get_channel_volume;
control_class->set_channel_volume = oss_stream_control_set_channel_volume;
- control_class->get_channel_position = oss_stream_control_get_channel_position;
control_class->has_channel_position = oss_stream_control_has_channel_position;
+ control_class->get_channel_position = oss_stream_control_get_channel_position;
control_class->set_balance = oss_stream_control_set_balance;
control_class->get_min_volume = oss_stream_control_get_min_volume;
control_class->get_max_volume = oss_stream_control_get_max_volume;
@@ -118,7 +120,8 @@ oss_stream_control_finalize (GObject *object)
control = OSS_STREAM_CONTROL (object);
- close (control->priv->fd);
+ if (control->priv->fd != -1)
+ close (control->priv->fd);
G_OBJECT_CLASS (oss_stream_control_parent_class)->finalize (object);
}
@@ -127,6 +130,7 @@ OssStreamControl *
oss_stream_control_new (const gchar *name,
const gchar *label,
MateMixerStreamControlRole role,
+ OssStream *stream,
gint fd,
gint devnum,
gboolean stereo)
@@ -134,8 +138,11 @@ oss_stream_control_new (const gchar *name,
OssStreamControl *control;
MateMixerStreamControlFlags flags;
- flags = MATE_MIXER_STREAM_CONTROL_HAS_VOLUME |
- MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME;
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (label != NULL, NULL);
+
+ flags = MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE;
if (stereo == TRUE)
flags |= MATE_MIXER_STREAM_CONTROL_CAN_BALANCE;
@@ -143,6 +150,8 @@ oss_stream_control_new (const gchar *name,
"name", name,
"label", label,
"flags", flags,
+ "role", role,
+ "stream", stream,
NULL);
control->priv->fd = fd;
@@ -151,52 +160,50 @@ oss_stream_control_new (const gchar *name,
return control;
}
-gboolean
-oss_stream_control_update (OssStreamControl *control)
+gint
+oss_stream_control_get_devnum (OssStreamControl *control)
{
- gint v;
- gint ret;
+ g_return_val_if_fail (OSS_IS_STREAM_CONTROL (control), 0);
- g_return_val_if_fail (OSS_IS_STREAM_CONTROL (control), FALSE);
+ return control->priv->devnum;
+}
- ret = ioctl (control->priv->fd, MIXER_READ (control->priv->devnum), &v);
- if (ret < 0) {
- g_warning ("Failed to read volume: %s", g_strerror (errno));
- return FALSE;
- }
+void
+oss_stream_control_load (OssStreamControl *control)
+{
+ gint v, ret;
- control->priv->volume[0] = v & 0xFF;
+ g_return_if_fail (OSS_IS_STREAM_CONTROL (control));
- if (control->priv->stereo == TRUE) {
- gfloat balance;
- guint left;
- guint right;
-
- control->priv->volume[1] = (v >> 8) & 0xFF;
-
- /* Calculate balance */
- left = control->priv->volume[0];
- right = control->priv->volume[1];
- if (left == right)
- balance = 0.0f;
- else if (left > right)
- balance = -1.0f + ((gfloat) right / (gfloat) left);
- else
- balance = +1.0f - ((gfloat) left / (gfloat) right);
+ if G_UNLIKELY (control->priv->fd == -1)
+ return;
+
+ ret = ioctl (control->priv->fd, MIXER_READ (control->priv->devnum), &v);
+ if (ret == -1)
+ return;
+
+ if (v != OSS_VOLUME_JOIN_ARRAY (control->priv->volume)) {
+ control->priv->volume[0] = OSS_VOLUME_TAKE_LEFT (v);
+ if (control->priv->stereo == TRUE)
+ control->priv->volume[1] = OSS_VOLUME_TAKE_RIGHT (v);
- _mate_mixer_stream_control_set_balance (MATE_MIXER_STREAM_CONTROL (control),
- balance);
+ g_object_notify (G_OBJECT (control), "volume");
}
- return TRUE;
+
+ if (control->priv->stereo == TRUE)
+ read_balance (control);
}
-static gboolean
-oss_stream_control_set_mute (MateMixerStreamControl *mmsc, gboolean mute)
+void
+oss_stream_control_close (OssStreamControl *control)
{
- g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE);
+ g_return_if_fail (OSS_IS_STREAM_CONTROL (control));
- // TODO
- return TRUE;
+ if (control->priv->fd == -1)
+ return;
+
+ close (control->priv->fd);
+ control->priv->fd = -1;
}
static guint
@@ -226,17 +233,15 @@ static gboolean
oss_stream_control_set_volume (MateMixerStreamControl *mmsc, guint volume)
{
OssStreamControl *control;
- gint v;
g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE);
control = OSS_STREAM_CONTROL (mmsc);
- v = CLAMP (volume, 0, 100);
- if (control->priv->stereo == TRUE)
- v |= (volume & 0xFF) << 8;
+ if G_UNLIKELY (control->priv->fd == -1)
+ return FALSE;
- return write_volume (control, v);
+ return write_and_set_volume (control, OSS_VOLUME_JOIN_SAME (CLAMP (volume, 0, 100)));
}
static guint
@@ -269,27 +274,26 @@ oss_stream_control_set_channel_volume (MateMixerStreamControl *mmsc,
g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE);
control = OSS_STREAM_CONTROL (mmsc);
- volume = CLAMP (volume, 0, 100);
- if (control->priv->stereo == TRUE) {
- if (channel > 1)
- return FALSE;
+ if G_UNLIKELY (control->priv->fd == -1)
+ return FALSE;
+ if (channel > 1 || (control->priv->stereo == FALSE && channel > 0))
+ return FALSE;
- /* Stereo channel volume - left channel is in the lowest 8 bits and
+ volume = CLAMP (volume, 0, 100);
+
+ if (control->priv->stereo == TRUE) {
+ /* Stereo channel volume - left channel is in the lower 8 bits and
* right channel is in the higher 8 bits */
if (channel == 0)
- v = volume | (control->priv->volume[1] << 8);
+ v = OSS_VOLUME_JOIN (volume, control->priv->volume[1]);
else
- v = control->priv->volume[0] | (volume << 8);
+ v = OSS_VOLUME_JOIN (control->priv->volume[0], volume);
} else {
- if (channel > 0)
- return FALSE;
-
- /* Single channel volume - only lowest 8 bits are used */
+ /* Single channel volume - only lower 8 bits are used */
v = volume;
}
-
- return write_volume (control, v);
+ return write_and_set_volume (control, v);
}
static MateMixerChannelPosition
@@ -334,24 +338,24 @@ oss_stream_control_set_balance (MateMixerStreamControl *mmsc, gfloat balance)
{
OssStreamControl *control;
guint max;
- gint v;
+ gint volume[2];
g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE);
control = OSS_STREAM_CONTROL (mmsc);
+ if G_UNLIKELY (control->priv->fd == -1)
+ return FALSE;
+
max = MAX (control->priv->volume[0], control->priv->volume[1]);
if (balance <= 0) {
- control->priv->volume[1] = (balance + 1.0f) * max;
- control->priv->volume[0] = max;
+ volume[1] = (balance + 1.0f) * max;
+ volume[0] = max;
} else {
- control->priv->volume[0] = (1.0f - balance) * max;
- control->priv->volume[1] = max;
+ volume[0] = (1.0f - balance) * max;
+ volume[1] = max;
}
-
- v = control->priv->volume[0] | (control->priv->volume[1] << 8);
-
- return write_volume (control, v);
+ return write_and_set_volume (control, OSS_VOLUME_JOIN_ARRAY (volume));
}
static guint
@@ -378,15 +382,45 @@ oss_stream_control_get_base_volume (MateMixerStreamControl *mmsc)
return 100;
}
+static void
+read_balance (OssStreamControl *control)
+{
+ gfloat balance;
+ guint left = control->priv->volume[0];
+ guint right = control->priv->volume[1];
+
+ if (left == right)
+ balance = 0.0f;
+ else if (left > right)
+ balance = -1.0f + ((gfloat) right / (gfloat) left);
+ else
+ balance = +1.0f - ((gfloat) left / (gfloat) right);
+
+ _mate_mixer_stream_control_set_balance (MATE_MIXER_STREAM_CONTROL (control),
+ balance);
+}
+
static gboolean
-write_volume (OssStreamControl *control, gint volume)
+write_and_set_volume (OssStreamControl *control, gint volume)
{
gint ret;
+ /* Nothing to do? */
+ if (volume == OSS_VOLUME_JOIN_ARRAY (control->priv->volume))
+ return TRUE;
+
ret = ioctl (control->priv->fd, MIXER_WRITE (control->priv->devnum), &volume);
- if (ret < 0) {
- g_warning ("Failed to set volume: %s", g_strerror (errno));
+ if (ret == -1)
return FALSE;
- }
+
+ oss_stream_control_load (control);
+ return TRUE;
+
+ /* The ioctl may make adjustments to the passed volume, so make sure we have
+ * the correct value saved */
+ control->priv->volume[0] = OSS_VOLUME_TAKE_LEFT (volume);
+ control->priv->volume[1] = OSS_VOLUME_TAKE_RIGHT (volume);
+
+ g_object_notify (G_OBJECT (control), "volume");
return TRUE;
}
diff --git a/backends/oss/oss-stream-control.h b/backends/oss/oss-stream-control.h
index c839faf..1957088 100644
--- a/backends/oss/oss-stream-control.h
+++ b/backends/oss/oss-stream-control.h
@@ -22,6 +22,8 @@
#include <glib-object.h>
#include <libmatemixer/matemixer.h>
+#include "oss-types.h"
+
G_BEGIN_DECLS
#define OSS_TYPE_STREAM_CONTROL \
@@ -37,7 +39,6 @@ G_BEGIN_DECLS
#define OSS_STREAM_CONTROL_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), OSS_TYPE_STREAM_CONTROL, OssStreamControlClass))
-typedef struct _OssStreamControl OssStreamControl;
typedef struct _OssStreamControlClass OssStreamControlClass;
typedef struct _OssStreamControlPrivate OssStreamControlPrivate;
@@ -54,16 +55,20 @@ struct _OssStreamControlClass
MateMixerStreamControlClass parent;
};
-GType oss_stream_control_get_type (void) G_GNUC_CONST;
+GType oss_stream_control_get_type (void) G_GNUC_CONST;
+
+OssStreamControl *oss_stream_control_new (const gchar *name,
+ const gchar *label,
+ MateMixerStreamControlRole role,
+ OssStream *stream,
+ gint fd,
+ gint devnum,
+ gboolean stereo);
-OssStreamControl *oss_stream_control_new (const gchar *name,
- const gchar *label,
- MateMixerStreamControlRole role,
- gint fd,
- gint devnum,
- gboolean stereo);
+gint oss_stream_control_get_devnum (OssStreamControl *control);
-gboolean oss_stream_control_update (OssStreamControl *control);
+void oss_stream_control_load (OssStreamControl *control);
+void oss_stream_control_close (OssStreamControl *control);
G_END_DECLS
diff --git a/backends/oss/oss-stream.c b/backends/oss/oss-stream.c
index 5f0c629..227c88b 100644
--- a/backends/oss/oss-stream.c
+++ b/backends/oss/oss-stream.c
@@ -16,32 +16,32 @@
*/
#include <glib.h>
+#include <glib/gi18n.h>
#include <glib-object.h>
#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
-#include "oss-device.h"
#include "oss-stream.h"
#include "oss-stream-control.h"
+#include "oss-switch.h"
+
+#define OSS_STREAM_SWITCH_NAME "port"
struct _OssStreamPrivate
{
- GHashTable *controls;
- OssStreamControl *control;
+ OssSwitch *swtch;
+ GList *switches;
+ GList *controls;
};
-static void oss_stream_class_init (OssStreamClass *klass);
-
-static void oss_stream_init (OssStream *ostream);
-static void oss_stream_dispose (GObject *object);
-static void oss_stream_finalize (GObject *object);
+static void oss_stream_class_init (OssStreamClass *klass);
+static void oss_stream_init (OssStream *stream);
+static void oss_stream_dispose (GObject *object);
G_DEFINE_TYPE (OssStream, oss_stream, MATE_MIXER_TYPE_STREAM)
-static MateMixerStreamControl *oss_stream_get_control (MateMixerStream *stream,
- const gchar *name);
-static MateMixerStreamControl *oss_stream_get_default_control (MateMixerStream *stream);
-
-static GList * oss_stream_list_controls (MateMixerStream *stream);
+static const GList *oss_stream_list_controls (MateMixerStream *mms);
+static const GList *oss_stream_list_switches (MateMixerStream *mms);
static void
oss_stream_class_init (OssStreamClass *klass)
@@ -50,13 +50,11 @@ oss_stream_class_init (OssStreamClass *klass)
MateMixerStreamClass *stream_class;
object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = oss_stream_dispose;
- object_class->finalize = oss_stream_finalize;
+ object_class->dispose = oss_stream_dispose;
stream_class = MATE_MIXER_STREAM_CLASS (klass);
- stream_class->get_control = oss_stream_get_control;
- stream_class->get_default_control = oss_stream_get_default_control;
- stream_class->list_controls = oss_stream_list_controls;
+ stream_class->list_controls = oss_stream_list_controls;
+ stream_class->list_switches = oss_stream_list_switches;
g_type_class_add_private (object_class, sizeof (OssStreamPrivate));
}
@@ -67,11 +65,6 @@ oss_stream_init (OssStream *stream)
stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
OSS_TYPE_STREAM,
OssStreamPrivate);
-
- stream->priv->controls = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- g_object_unref);
}
static void
@@ -81,103 +74,201 @@ oss_stream_dispose (GObject *object)
stream = OSS_STREAM (object);
- g_clear_object (&stream->priv->control);
- g_hash_table_remove_all (stream->priv->controls);
+ if (stream->priv->controls != NULL) {
+ g_list_free_full (stream->priv->controls, g_object_unref);
+ stream->priv->controls = NULL;
+ }
+ if (stream->priv->switches != NULL) {
+ g_list_free_full (stream->priv->switches, g_object_unref);
+ stream->priv->switches = NULL;
+ }
+
+ g_clear_object (&stream->priv->swtch);
G_OBJECT_CLASS (oss_stream_parent_class)->dispose (object);
}
-static void
-oss_stream_finalize (GObject *object)
+OssStream *
+oss_stream_new (const gchar *name,
+ MateMixerDevice *device,
+ MateMixerDirection direction)
{
- OssStream *stream;
+ const gchar *label = mate_mixer_device_get_label (device);
+
+ return g_object_new (OSS_TYPE_STREAM,
+ "name", name,
+ "label", label,
+ "device", device,
+ "direction", direction,
+ NULL);
+}
- stream = OSS_STREAM (object);
+void
+oss_stream_add_control (OssStream *stream, OssStreamControl *control)
+{
+ const gchar *name;
+
+ g_return_if_fail (OSS_IS_STREAM (stream));
+ g_return_if_fail (OSS_IS_STREAM_CONTROL (control));
- g_hash_table_destroy (stream->priv->controls);
+ name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (control));
+
+ stream->priv->controls =
+ g_list_append (stream->priv->controls, g_object_ref (control));
- G_OBJECT_CLASS (oss_stream_parent_class)->finalize (object);
+ g_signal_emit_by_name (G_OBJECT (stream),
+ "control-added",
+ name);
}
-OssStream *
-oss_stream_new (const gchar *name,
- MateMixerDevice *device,
- MateMixerStreamFlags flags)
+void
+oss_stream_load (OssStream *stream)
{
- OssStream *stream;
+ GList *list;
+
+ g_return_if_fail (OSS_IS_STREAM (stream));
+
+ list = stream->priv->controls;
+ while (list != NULL) {
+ OssStreamControl *control = OSS_STREAM_CONTROL (list->data);
- stream = g_object_new (OSS_TYPE_STREAM,
- "name", name,
- "device", device,
- "flags", flags,
- NULL);
- return stream;
+ oss_stream_control_load (control);
+ list = list->next;
+ }
+
+ if (stream->priv->swtch != NULL)
+ oss_switch_load (stream->priv->swtch);
}
gboolean
-oss_stream_add_control (OssStream *stream, OssStreamControl *control)
+oss_stream_has_controls (OssStream *stream)
{
- const gchar *name;
-
g_return_val_if_fail (OSS_IS_STREAM (stream), FALSE);
- g_return_val_if_fail (OSS_IS_STREAM_CONTROL (control), FALSE);
- name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (control));
+ if (stream->priv->controls != NULL)
+ return TRUE;
- g_hash_table_insert (stream->priv->controls,
- g_strdup (name),
- control);
- return TRUE;
+ return FALSE;
}
gboolean
-oss_stream_set_default_control (OssStream *stream, OssStreamControl *control)
+oss_stream_has_default_control (OssStream *stream)
{
g_return_val_if_fail (OSS_IS_STREAM (stream), FALSE);
- g_return_val_if_fail (OSS_IS_STREAM_CONTROL (control), FALSE);
-
- /* This function is only used internally so avoid validating that the control
- * belongs to this stream */
- if (stream->priv->control != NULL)
- g_object_unref (stream->priv->control);
- if G_LIKELY (control != NULL)
- stream->priv->control = g_object_ref (control);
- else
- stream->priv->control = NULL;
+ if (mate_mixer_stream_get_default_control (MATE_MIXER_STREAM (stream)) != NULL)
+ return TRUE;
- return TRUE;
+ return FALSE;
}
-static MateMixerStreamControl *
-oss_stream_get_control (MateMixerStream *mms, const gchar *name)
+OssStreamControl *
+oss_stream_get_default_control (OssStream *stream)
{
- g_return_val_if_fail (OSS_IS_STREAM (mms), NULL);
- g_return_val_if_fail (name != NULL, NULL);
+ MateMixerStreamControl *control;
+
+ g_return_val_if_fail (OSS_IS_STREAM (stream), NULL);
+
+ control = mate_mixer_stream_get_default_control (MATE_MIXER_STREAM (stream));
+ if (control != NULL)
+ return OSS_STREAM_CONTROL (control);
- return g_hash_table_lookup (OSS_STREAM (mms)->priv->controls, name);
+ return NULL;
}
-static MateMixerStreamControl *
-oss_stream_get_default_control (MateMixerStream *mms)
+void
+oss_stream_set_default_control (OssStream *stream, OssStreamControl *control)
{
- g_return_val_if_fail (OSS_IS_STREAM (mms), NULL);
+ g_return_if_fail (OSS_IS_STREAM (stream));
+ g_return_if_fail (control == NULL || OSS_IS_STREAM_CONTROL (control));
+
+ if (control == NULL)
+ _mate_mixer_stream_set_default_control (MATE_MIXER_STREAM (stream), NULL);
+ else
+ _mate_mixer_stream_set_default_control (MATE_MIXER_STREAM (stream),
+ MATE_MIXER_STREAM_CONTROL (control));
+}
- return MATE_MIXER_STREAM_CONTROL (OSS_STREAM (mms)->priv->control);
+void
+oss_stream_set_switch_data (OssStream *stream, gint fd, GList *options)
+{
+ g_return_if_fail (OSS_IS_STREAM (stream));
+ g_return_if_fail (fd != -1);
+ g_return_if_fail (options != NULL);
+
+ /* Function may only be called once */
+ if G_UNLIKELY (stream->priv->swtch != NULL) {
+ g_warn_if_reached ();
+ return;
+ }
+
+ /* Takes ownership of options */
+ stream->priv->swtch = oss_switch_new (OSS_STREAM_SWITCH_NAME,
+ _("Capture Source"),
+ fd,
+ options);
+
+ /* Read the active selection */
+ oss_switch_load (stream->priv->swtch);
+
+ stream->priv->switches = g_list_prepend (NULL, g_object_ref (stream->priv->swtch));
+ g_signal_emit_by_name (G_OBJECT (stream),
+ "switch-added",
+ OSS_STREAM_SWITCH_NAME);
}
-static GList *
-oss_stream_list_controls (MateMixerStream *mms)
+void
+oss_stream_remove_all (OssStream *stream)
{
GList *list;
+ g_return_if_fail (OSS_IS_STREAM (stream));
+
+ list = stream->priv->controls;
+ while (list != NULL) {
+ MateMixerStreamControl *control = MATE_MIXER_STREAM_CONTROL (list->data);
+ GList *next = list->next;
+
+ oss_stream_control_close (OSS_STREAM_CONTROL (control));
+
+ stream->priv->controls = g_list_delete_link (stream->priv->controls, list);
+ g_signal_emit_by_name (G_OBJECT (stream),
+ "control-removed",
+ mate_mixer_stream_control_get_name (control));
+
+ g_object_unref (control);
+ list = next;
+ }
+
+ /* Unset the default stream control */
+ oss_stream_set_default_control (stream, NULL);
+
+ if (stream->priv->swtch != NULL) {
+ oss_switch_close (stream->priv->swtch);
+
+ g_list_free_full (stream->priv->switches, g_object_unref);
+ stream->priv->switches = NULL;
+
+ g_signal_emit_by_name (G_OBJECT (stream),
+ "switch-removed",
+ OSS_STREAM_SWITCH_NAME);
+
+ g_clear_object (&stream->priv->swtch);
+ }
+}
+
+static const GList *
+oss_stream_list_controls (MateMixerStream *mms)
+{
g_return_val_if_fail (OSS_IS_STREAM (mms), NULL);
- /* Convert the hash table to a linked list, this list is expected to be
- * cached in the main library */
- list = g_hash_table_get_values (OSS_STREAM (mms)->priv->controls);
- if (list != NULL)
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
+ return OSS_STREAM (mms)->priv->controls;
+}
+
+static const GList *
+oss_stream_list_switches (MateMixerStream *mms)
+{
+ g_return_val_if_fail (OSS_IS_STREAM (mms), NULL);
- return list;
+ return OSS_STREAM (mms)->priv->switches;
}
diff --git a/backends/oss/oss-stream.h b/backends/oss/oss-stream.h
index 0470eb7..2ade0d8 100644
--- a/backends/oss/oss-stream.h
+++ b/backends/oss/oss-stream.h
@@ -22,8 +22,7 @@
#include <glib-object.h>
#include <libmatemixer/matemixer.h>
-#include "oss-device.h"
-#include "oss-stream-control.h"
+#include "oss-types.h"
G_BEGIN_DECLS
@@ -40,7 +39,6 @@ G_BEGIN_DECLS
#define OSS_STREAM_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), OSS_TYPE_STREAM, OssStreamClass))
-typedef struct _OssStream OssStream;
typedef struct _OssStreamClass OssStreamClass;
typedef struct _OssStreamPrivate OssStreamPrivate;
@@ -57,17 +55,29 @@ struct _OssStreamClass
MateMixerStreamClass parent;
};
-GType oss_stream_get_type (void) G_GNUC_CONST;
+GType oss_stream_get_type (void) G_GNUC_CONST;
-OssStream *oss_stream_new (const gchar *name,
- MateMixerDevice *device,
- MateMixerStreamFlags flags);
+OssStream * oss_stream_new (const gchar *name,
+ MateMixerDevice *device,
+ MateMixerDirection direction);
-gboolean oss_stream_add_control (OssStream *stream,
- OssStreamControl *control);
+void oss_stream_add_control (OssStream *stream,
+ OssStreamControl *control);
-gboolean oss_stream_set_default_control (OssStream *stream,
- OssStreamControl *control);
+void oss_stream_load (OssStream *stream);
+
+gboolean oss_stream_has_controls (OssStream *stream);
+gboolean oss_stream_has_default_control (OssStream *stream);
+
+OssStreamControl *oss_stream_get_default_control (OssStream *stream);
+void oss_stream_set_default_control (OssStream *stream,
+ OssStreamControl *control);
+
+void oss_stream_set_switch_data (OssStream *stream,
+ gint fd,
+ GList *options);
+
+void oss_stream_remove_all (OssStream *stream);
G_END_DECLS
diff --git a/backends/oss/oss-switch-option.c b/backends/oss/oss-switch-option.c
new file mode 100644
index 0000000..862133d
--- /dev/null
+++ b/backends/oss/oss-switch-option.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "oss-switch-option.h"
+
+struct _OssSwitchOptionPrivate
+{
+ guint devnum;
+};
+
+static void oss_switch_option_class_init (OssSwitchOptionClass *klass);
+static void oss_switch_option_init (OssSwitchOption *option);
+
+G_DEFINE_TYPE (OssSwitchOption, oss_switch_option, MATE_MIXER_TYPE_SWITCH_OPTION)
+
+static void
+oss_switch_option_class_init (OssSwitchOptionClass *klass)
+{
+ g_type_class_add_private (G_OBJECT_CLASS (klass), sizeof (OssSwitchOptionPrivate));
+}
+
+static void
+oss_switch_option_init (OssSwitchOption *option)
+{
+ option->priv = G_TYPE_INSTANCE_GET_PRIVATE (option,
+ OSS_TYPE_SWITCH_OPTION,
+ OssSwitchOptionPrivate);
+}
+
+OssSwitchOption *
+oss_switch_option_new (const gchar *name,
+ const gchar *label,
+ const gchar *icon,
+ guint devnum)
+{
+ OssSwitchOption *option;
+
+ option = g_object_new (OSS_TYPE_SWITCH_OPTION,
+ "name", name,
+ "label", label,
+ "icon", icon,
+ NULL);
+
+ option->priv->devnum = devnum;
+ return option;
+}
+
+guint
+oss_switch_option_get_devnum (OssSwitchOption *option)
+{
+ g_return_val_if_fail (OSS_IS_SWITCH_OPTION (option), 0);
+
+ return option->priv->devnum;
+}
diff --git a/backends/oss/oss-switch-option.h b/backends/oss/oss-switch-option.h
new file mode 100644
index 0000000..91c21e3
--- /dev/null
+++ b/backends/oss/oss-switch-option.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OSS_SWITCH_OPTION_H
+#define OSS_SWITCH_OPTION_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "oss-types.h"
+
+G_BEGIN_DECLS
+
+#define OSS_TYPE_SWITCH_OPTION \
+ (oss_switch_option_get_type ())
+#define OSS_SWITCH_OPTION(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), OSS_TYPE_SWITCH_OPTION, OssSwitchOption))
+#define OSS_IS_SWITCH_OPTION(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSS_TYPE_SWITCH_OPTION))
+#define OSS_SWITCH_OPTION_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), OSS_TYPE_SWITCH_OPTION, OssSwitchOptionClass))
+#define OSS_IS_SWITCH_OPTION_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), OSS_TYPE_SWITCH_OPTION))
+#define OSS_SWITCH_OPTION_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), OSS_TYPE_SWITCH_OPTION, OssSwitchOptionClass))
+
+typedef struct _OssSwitchOptionClass OssSwitchOptionClass;
+typedef struct _OssSwitchOptionPrivate OssSwitchOptionPrivate;
+
+struct _OssSwitchOption
+{
+ MateMixerSwitchOption parent;
+
+ /*< private >*/
+ OssSwitchOptionPrivate *priv;
+};
+
+struct _OssSwitchOptionClass
+{
+ MateMixerSwitchOptionClass parent_class;
+};
+
+GType oss_switch_option_get_type (void) G_GNUC_CONST;
+
+OssSwitchOption *oss_switch_option_new (const gchar *name,
+ const gchar *label,
+ const gchar *icon,
+ guint devnum);
+
+guint oss_switch_option_get_devnum (OssSwitchOption *option);
+
+G_END_DECLS
+
+#endif /* OSS_SWITCH_OPTION_H */
diff --git a/backends/oss/oss-switch.c b/backends/oss/oss-switch.c
new file mode 100644
index 0000000..b138051
--- /dev/null
+++ b/backends/oss/oss-switch.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "oss-common.h"
+#include "oss-switch.h"
+#include "oss-switch-option.h"
+
+struct _OssSwitchPrivate
+{
+ gint fd;
+ GList *options;
+};
+
+static void oss_switch_class_init (OssSwitchClass *klass);
+static void oss_switch_init (OssSwitch *swtch);
+static void oss_switch_dispose (GObject *object);
+static void oss_switch_finalize (GObject *object);
+
+G_DEFINE_TYPE (OssSwitch, oss_switch, MATE_MIXER_TYPE_SWITCH)
+
+static gboolean oss_switch_set_active_option (MateMixerSwitch *mms,
+ MateMixerSwitchOption *mmso);
+
+static const GList *oss_switch_list_options (MateMixerSwitch *mms);
+
+static void
+oss_switch_class_init (OssSwitchClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerSwitchClass *switch_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = oss_switch_dispose;
+ object_class->finalize = oss_switch_finalize;
+
+ switch_class = MATE_MIXER_SWITCH_CLASS (klass);
+ switch_class->set_active_option = oss_switch_set_active_option;
+ switch_class->list_options = oss_switch_list_options;
+
+ g_type_class_add_private (G_OBJECT_CLASS (klass), sizeof (OssSwitchPrivate));
+}
+
+static void
+oss_switch_init (OssSwitch *swtch)
+{
+ swtch->priv = G_TYPE_INSTANCE_GET_PRIVATE (swtch,
+ OSS_TYPE_SWITCH,
+ OssSwitchPrivate);
+}
+
+static void
+oss_switch_dispose (GObject *object)
+{
+ OssSwitch *swtch;
+
+ swtch = OSS_SWITCH (object);
+
+ if (swtch->priv->options != NULL) {
+ g_list_free_full (swtch->priv->options, g_object_unref);
+ swtch->priv->options = NULL;
+ }
+
+ G_OBJECT_CLASS (oss_switch_parent_class)->dispose (object);
+}
+
+static void
+oss_switch_finalize (GObject *object)
+{
+ OssSwitch *swtch;
+
+ swtch = OSS_SWITCH (object);
+
+ if (swtch->priv->fd != -1)
+ close (swtch->priv->fd);
+
+ G_OBJECT_CLASS (oss_switch_parent_class)->finalize (object);
+}
+
+OssSwitch *
+oss_switch_new (const gchar *name,
+ const gchar *label,
+ gint fd,
+ GList *options)
+{
+ OssSwitch *swtch;
+
+ swtch = g_object_new (OSS_TYPE_SWITCH,
+ "name", name,
+ "label", label,
+ "flags", MATE_MIXER_SWITCH_ALLOWS_NO_ACTIVE_OPTION,
+ "role", MATE_MIXER_SWITCH_ROLE_PORT,
+ NULL);
+
+ /* Takes ownership of options */
+ swtch->priv->fd = dup (fd);
+ swtch->priv->options = options;
+
+ return swtch;
+}
+
+void
+oss_switch_load (OssSwitch *swtch)
+{
+ GList *list;
+ gint recsrc;
+ gint ret;
+
+ g_return_if_fail (OSS_IS_SWITCH (swtch));
+
+ if G_UNLIKELY (swtch->priv->fd == -1)
+ return;
+
+ ret = ioctl (swtch->priv->fd, MIXER_READ (SOUND_MIXER_RECSRC), &recsrc);
+ if (ret == -1)
+ return;
+ if (recsrc == 0) {
+ _mate_mixer_switch_set_active_option (MATE_MIXER_SWITCH (swtch), NULL);
+ return;
+ }
+
+ list = swtch->priv->options;
+ while (list != NULL) {
+ OssSwitchOption *option = OSS_SWITCH_OPTION (list->data);
+ gint devnum = oss_switch_option_get_devnum (option);
+
+ /* Mark the selected option when we find it */
+ if (recsrc & (1 << devnum)) {
+ _mate_mixer_switch_set_active_option (MATE_MIXER_SWITCH (swtch),
+ MATE_MIXER_SWITCH_OPTION (option));
+ return;
+ }
+ list = list->next;
+ }
+
+ g_warning ("Unknown active option of switch %s",
+ mate_mixer_switch_get_name (MATE_MIXER_SWITCH (swtch)));
+}
+
+void
+oss_switch_close (OssSwitch *swtch)
+{
+ g_return_if_fail (OSS_IS_SWITCH (swtch));
+
+ if (swtch->priv->fd == -1)
+ return;
+
+ close (swtch->priv->fd);
+ swtch->priv->fd = -1;
+}
+
+static gboolean
+oss_switch_set_active_option (MateMixerSwitch *mms, MateMixerSwitchOption *mmso)
+{
+ OssSwitch *swtch;
+ gint ret;
+ gint recsrc;
+ gint devnum;
+
+ g_return_val_if_fail (OSS_IS_SWITCH (mms), FALSE);
+ g_return_val_if_fail (OSS_IS_SWITCH_OPTION (mmso), FALSE);
+
+ swtch = OSS_SWITCH (mms);
+
+ if G_UNLIKELY (swtch->priv->fd == -1)
+ return FALSE;
+
+ devnum = oss_switch_option_get_devnum (OSS_SWITCH_OPTION (mmso));
+ recsrc = 1 << devnum;
+
+ ret = ioctl (swtch->priv->fd, MIXER_WRITE (SOUND_MIXER_RECSRC), &recsrc);
+ if (ret == -1)
+ return FALSE;
+
+ return TRUE;
+}
+
+static const GList *
+oss_switch_list_options (MateMixerSwitch *mms)
+{
+ g_return_val_if_fail (OSS_IS_SWITCH (mms), NULL);
+
+ return OSS_SWITCH (mms)->priv->options;
+}
diff --git a/backends/oss/oss-switch.h b/backends/oss/oss-switch.h
new file mode 100644
index 0000000..dc91758
--- /dev/null
+++ b/backends/oss/oss-switch.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OSS_SWITCH_H
+#define OSS_SWITCH_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "oss-types.h"
+
+G_BEGIN_DECLS
+
+#define OSS_TYPE_SWITCH \
+ (oss_switch_get_type ())
+#define OSS_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), OSS_TYPE_SWITCH, OssSwitch))
+#define OSS_IS_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSS_TYPE_SWITCH))
+#define OSS_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), OSS_TYPE_SWITCH, OssSwitchClass))
+#define OSS_IS_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), OSS_TYPE_SWITCH))
+#define OSS_SWITCH_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), OSS_TYPE_SWITCH, OssSwitchClass))
+
+typedef struct _OssSwitchClass OssSwitchClass;
+typedef struct _OssSwitchPrivate OssSwitchPrivate;
+
+struct _OssSwitch
+{
+ MateMixerSwitch parent;
+
+ /*< private >*/
+ OssSwitchPrivate *priv;
+};
+
+struct _OssSwitchClass
+{
+ MateMixerSwitchClass parent_class;
+};
+
+GType oss_switch_get_type (void) G_GNUC_CONST;
+
+OssSwitch *oss_switch_new (const gchar *name,
+ const gchar *label,
+ gint fd,
+ GList *options);
+
+void oss_switch_load (OssSwitch *swtch);
+void oss_switch_close (OssSwitch *swtch);
+
+G_END_DECLS
+
+#endif /* OSS_SWITCH_H */
diff --git a/backends/oss/oss-types.h b/backends/oss/oss-types.h
new file mode 100644
index 0000000..afd4f58
--- /dev/null
+++ b/backends/oss/oss-types.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OSS_TYPES_H
+#define OSS_TYPES_H
+
+G_BEGIN_DECLS
+
+typedef struct _OssBackend OssBackend;
+typedef struct _OssDevice OssDevice;
+typedef struct _OssStream OssStream;
+typedef struct _OssStreamControl OssStreamControl;
+typedef struct _OssSwitch OssSwitch;
+typedef struct _OssSwitchOption OssSwitchOption;
+
+G_END_DECLS
+
+#endif /* OSS_TYPES_H */
diff --git a/backends/pulse/Makefile.am b/backends/pulse/Makefile.am
index 0e5a4d6..4c851bf 100644
--- a/backends/pulse/Makefile.am
+++ b/backends/pulse/Makefile.am
@@ -3,6 +3,7 @@ backenddir = $(libdir)/libmatemixer
backend_LTLIBRARIES = libmatemixer-pulse.la
AM_CPPFLAGS = \
+ -Wno-unknown-pragmas \
-I$(top_srcdir) \
-DG_LOG_DOMAIN=\"libmatemixer-pulse\"
@@ -13,12 +14,14 @@ libmatemixer_pulse_la_CFLAGS = \
libmatemixer_pulse_la_SOURCES = \
pulse-backend.c \
pulse-backend.h \
- pulse-client-stream.c \
- pulse-client-stream.h \
pulse-connection.c \
pulse-connection.h \
pulse-device.c \
pulse-device.h \
+ pulse-device-profile.c \
+ pulse-device-profile.h \
+ pulse-device-switch.c \
+ pulse-device-switch.h \
pulse-enums.h \
pulse-enum-types.c \
pulse-enum-types.h \
@@ -28,16 +31,31 @@ libmatemixer_pulse_la_SOURCES = \
pulse-helpers.h \
pulse-monitor.c \
pulse-monitor.h \
+ pulse-port.c \
+ pulse-port.h \
+ pulse-port-switch.c \
+ pulse-port-switch.h \
pulse-stream.c \
pulse-stream.h \
+ pulse-stream-control.c \
+ pulse-stream-control.h \
pulse-sink.c \
pulse-sink.h \
+ pulse-sink-control.c \
+ pulse-sink-control.h \
pulse-sink-input.c \
pulse-sink-input.h \
+ pulse-sink-switch.c \
+ pulse-sink-switch.h \
pulse-source.c \
pulse-source.h \
+ pulse-source-control.c \
+ pulse-source-control.h \
pulse-source-output.c \
- pulse-source-output.h
+ pulse-source-output.h \
+ pulse-source-switch.c \
+ pulse-source-switch.h \
+ pulse-types.h
libmatemixer_pulse_la_LIBADD = \
$(GLIB_LIBS) \
diff --git a/backends/pulse/pulse-backend.c b/backends/pulse/pulse-backend.c
index 0494545..e1b7ed5 100644
--- a/backends/pulse/pulse-backend.c
+++ b/backends/pulse/pulse-backend.c
@@ -19,9 +19,8 @@
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-backend.h>
-#include <libmatemixer/matemixer-backend-module.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include <pulse/ext-stream-restore.h>
@@ -38,72 +37,110 @@
#include "pulse-source-output.h"
#define BACKEND_NAME "PulseAudio"
-#define BACKEND_PRIORITY 10
+#define BACKEND_PRIORITY 100
struct _PulseBackendPrivate
{
- gchar *app_name;
- gchar *app_id;
- gchar *app_version;
- gchar *app_icon;
- gchar *server_address;
- gboolean connected_once;
- GSource *connect_source;
- MateMixerStream *default_sink;
- MateMixerStream *default_source;
- GHashTable *devices;
- GHashTable *streams;
- GHashTable *ext_streams;
- MateMixerState state;
- PulseConnection *connection;
-};
-
-enum {
- PROP_0,
- PROP_STATE,
- PROP_DEFAULT_INPUT,
- PROP_DEFAULT_OUTPUT,
- N_PROPERTIES
+ guint connect_tag;
+ gboolean connected_once;
+ GHashTable *devices;
+ GHashTable *sinks;
+ GHashTable *sources;
+ GHashTable *sink_inputs;
+ GHashTable *source_outputs;
+ GHashTable *ext_streams;
+ GList *devices_list;
+ GList *streams_list;
+ GList *ext_streams_list;
+ MateMixerAppInfo *app_info;
+ gchar *server_address;
+ PulseConnection *connection;
};
-static void mate_mixer_backend_interface_init (MateMixerBackendInterface *iface);
+#define PULSE_CHANGE_STATE(p, s) \
+ (_mate_mixer_backend_set_state (MATE_MIXER_BACKEND (p), (s)))
+#define PULSE_GET_DEFAULT_SINK(p) \
+ (mate_mixer_backend_get_default_output_stream (MATE_MIXER_BACKEND (p)))
+#define PULSE_GET_DEFAULT_SOURCE(p) \
+ (mate_mixer_backend_get_default_input_stream (MATE_MIXER_BACKEND (p)))
+#define PULSE_SET_DEFAULT_SINK(p, s) \
+ (_mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (p), MATE_MIXER_STREAM (s)))
+#define PULSE_SET_DEFAULT_SOURCE(p, s) \
+ (_mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (p), MATE_MIXER_STREAM (s)))
+
+#define PULSE_GET_PENDING_SINK(p) \
+ (g_object_get_data (G_OBJECT (p), \
+ "__matemixer_pulse_pending_sink")) \
+
+#define PULSE_SET_PENDING_SINK(p,name) \
+ (g_object_set_data_full (G_OBJECT (p), \
+ "__matemixer_pulse_pending_sink", \
+ g_strdup (name), \
+ g_free))
+
+#define PULSE_SET_PENDING_SINK_NULL(p) \
+ (g_object_set_data (G_OBJECT (p), \
+ "__matemixer_pulse_pending_sink", \
+ NULL))
+
+#define PULSE_GET_PENDING_SOURCE(p) \
+ (g_object_get_data (G_OBJECT (p), \
+ "__matemixer_pulse_pending_source")) \
+
+#define PULSE_SET_PENDING_SOURCE(p,name) \
+ (g_object_set_data_full (G_OBJECT (p), \
+ "__matemixer_pulse_pending_source", \
+ g_strdup (name), \
+ g_free))
+
+#define PULSE_SET_PENDING_SOURCE_NULL(p) \
+ (g_object_set_data (G_OBJECT (p), \
+ "__matemixer_pulse_pending_source", \
+ NULL))
+
+#define PULSE_GET_HANGING(o) \
+ ((gboolean) g_object_get_data (G_OBJECT (o), \
+ "__matemixer_pulse_hanging"))
+
+#define PULSE_SET_HANGING(o) \
+ (g_object_set_data (G_OBJECT (o), \
+ "__matemixer_pulse_hanging", \
+ GUINT_TO_POINTER (1)))
+
+#define PULSE_UNSET_HANGING(o) \
+ (g_object_steal_data (G_OBJECT (o), \
+ "__matemixer_pulse_hanging"))
static void pulse_backend_class_init (PulseBackendClass *klass);
static void pulse_backend_class_finalize (PulseBackendClass *klass);
-static void pulse_backend_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec);
-
static void pulse_backend_init (PulseBackend *pulse);
static void pulse_backend_dispose (GObject *object);
static void pulse_backend_finalize (GObject *object);
-G_DEFINE_DYNAMIC_TYPE_EXTENDED (PulseBackend, pulse_backend,
- G_TYPE_OBJECT, 0,
- G_IMPLEMENT_INTERFACE_DYNAMIC (MATE_MIXER_TYPE_BACKEND,
- mate_mixer_backend_interface_init))
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+G_DEFINE_DYNAMIC_TYPE (PulseBackend, pulse_backend, MATE_MIXER_TYPE_BACKEND)
+#pragma clang diagnostic pop
-static gboolean pulse_backend_open (MateMixerBackend *backend);
-static void pulse_backend_close (MateMixerBackend *backend);
+static gboolean pulse_backend_open (MateMixerBackend *backend);
+static void pulse_backend_close (MateMixerBackend *backend);
-static MateMixerState pulse_backend_get_state (MateMixerBackend *backend);
+static void pulse_backend_set_app_info (MateMixerBackend *backend,
+ MateMixerAppInfo *info);
-static void pulse_backend_set_data (MateMixerBackend *backend,
- const MateMixerBackendData *data);
+static void pulse_backend_set_server_address (MateMixerBackend *backend,
+ const gchar *address);
-static GList * pulse_backend_list_devices (MateMixerBackend *backend);
-static GList * pulse_backend_list_streams (MateMixerBackend *backend);
-static GList * pulse_backend_list_cached_streams (MateMixerBackend *backend);
+static const GList * pulse_backend_list_devices (MateMixerBackend *backend);
+static const GList * pulse_backend_list_streams (MateMixerBackend *backend);
+static const GList * pulse_backend_list_stored_controls (MateMixerBackend *backend);
-static MateMixerStream *pulse_backend_get_default_input_stream (MateMixerBackend *backend);
-static gboolean pulse_backend_set_default_input_stream (MateMixerBackend *backend,
- MateMixerStream *stream);
+static gboolean pulse_backend_set_default_input_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
-static MateMixerStream *pulse_backend_get_default_output_stream (MateMixerBackend *backend);
-static gboolean pulse_backend_set_default_output_stream (MateMixerBackend *backend,
- MateMixerStream *stream);
+static gboolean pulse_backend_set_default_output_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
static void on_connection_state_notify (PulseConnection *connection,
GParamSpec *pspec,
@@ -152,32 +189,16 @@ static void on_connection_ext_stream_info (PulseConnection
PulseBackend *pulse);
static gboolean connect_source_reconnect (PulseBackend *pulse);
-static void connect_source_remove (PulseBackend *pulse);
static void check_pending_sink (PulseBackend *pulse,
PulseStream *stream);
static void check_pending_source (PulseBackend *pulse,
PulseStream *stream);
-static void mark_hanging (PulseBackend *pulse);
-static void mark_hanging_hash (GHashTable *hash);
-
-static void unmark_hanging (PulseBackend *pulse,
- GObject *object);
-
-static void remove_hanging (PulseBackend *pulse);
-static void remove_device (PulseBackend *pulse,
- PulseDevice *device);
-static void remove_stream (PulseBackend *pulse,
- PulseStream *stream);
-
-static void change_state (PulseBackend *backend,
- MateMixerState state);
+static void free_list_devices (PulseBackend *pulse);
+static void free_list_streams (PulseBackend *pulse);
+static void free_list_ext_streams (PulseBackend *pulse);
-static gint compare_devices (gconstpointer a,
- gconstpointer b);
-static gint compare_streams (gconstpointer a,
- gconstpointer b);
static gboolean compare_stream_names (gpointer key,
gpointer value,
gpointer user_data);
@@ -195,78 +216,42 @@ backend_module_init (GTypeModule *module)
info.backend_type = MATE_MIXER_BACKEND_PULSEAUDIO;
}
-const MateMixerBackendInfo *
-backend_module_get_info (void)
+const MateMixerBackendInfo *backend_module_get_info (void)
{
return &info;
}
static void
-mate_mixer_backend_interface_init (MateMixerBackendInterface *iface)
-{
- iface->open = pulse_backend_open;
- iface->close = pulse_backend_close;
- iface->get_state = pulse_backend_get_state;
- iface->set_data = pulse_backend_set_data;
- iface->list_devices = pulse_backend_list_devices;
- iface->list_streams = pulse_backend_list_streams;
- iface->list_cached_streams = pulse_backend_list_cached_streams;
- iface->get_default_input_stream = pulse_backend_get_default_input_stream;
- iface->set_default_input_stream = pulse_backend_set_default_input_stream;
- iface->get_default_output_stream = pulse_backend_get_default_output_stream;
- iface->set_default_output_stream = pulse_backend_set_default_output_stream;
-}
-
-static void
pulse_backend_class_init (PulseBackendClass *klass)
{
- GObjectClass *object_class;
+ GObjectClass *object_class;
+ MateMixerBackendClass *backend_class;
object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = pulse_backend_dispose;
- object_class->finalize = pulse_backend_finalize;
- object_class->get_property = pulse_backend_get_property;
-
- g_object_class_override_property (object_class, PROP_STATE, "state");
- g_object_class_override_property (object_class, PROP_DEFAULT_INPUT, "default-input");
- g_object_class_override_property (object_class, PROP_DEFAULT_OUTPUT, "default-output");
+ object_class->dispose = pulse_backend_dispose;
+ object_class->finalize = pulse_backend_finalize;
+
+ backend_class = MATE_MIXER_BACKEND_CLASS (klass);
+ backend_class->set_app_info = pulse_backend_set_app_info;
+ backend_class->set_server_address = pulse_backend_set_server_address;
+ backend_class->open = pulse_backend_open;
+ backend_class->close = pulse_backend_close;
+ backend_class->list_devices = pulse_backend_list_devices;
+ backend_class->list_streams = pulse_backend_list_streams;
+ backend_class->list_stored_controls = pulse_backend_list_stored_controls;
+ backend_class->set_default_input_stream = pulse_backend_set_default_input_stream;
+ backend_class->set_default_output_stream = pulse_backend_set_default_output_stream;
g_type_class_add_private (object_class, sizeof (PulseBackendPrivate));
}
-/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE_EXTENDED() */
+/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE() */
static void
pulse_backend_class_finalize (PulseBackendClass *klass)
{
}
static void
-pulse_backend_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec)
-{
- PulseBackend *pulse;
-
- pulse = PULSE_BACKEND (object);
-
- switch (param_id) {
- case PROP_STATE:
- g_value_set_enum (value, pulse->priv->state);
- break;
- case PROP_DEFAULT_INPUT:
- g_value_set_object (value, pulse->priv->default_source);
- break;
- case PROP_DEFAULT_OUTPUT:
- g_value_set_object (value, pulse->priv->default_sink);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
- break;
- }
-}
-
-static void
pulse_backend_init (PulseBackend *pulse)
{
pulse->priv = G_TYPE_INSTANCE_GET_PRIVATE (pulse,
@@ -279,22 +264,46 @@ pulse_backend_init (PulseBackend *pulse)
g_direct_equal,
NULL,
g_object_unref);
- pulse->priv->streams =
- g_hash_table_new_full (g_int64_hash,
- g_int64_equal,
- g_free,
+ pulse->priv->sinks =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
g_object_unref);
+ pulse->priv->sources =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+
pulse->priv->ext_streams =
g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
g_object_unref);
+
+ pulse->priv->sink_inputs =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+ pulse->priv->source_outputs =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
}
static void
pulse_backend_dispose (GObject *object)
{
- pulse_backend_close (MATE_MIXER_BACKEND (object));
+ MateMixerBackend *backend;
+ MateMixerState state;
+
+ backend = MATE_MIXER_BACKEND (object);
+
+ state = mate_mixer_backend_get_state (backend);
+ if (state != MATE_MIXER_STATE_IDLE)
+ pulse_backend_close (backend);
G_OBJECT_CLASS (pulse_backend_parent_class)->dispose (object);
}
@@ -306,19 +315,24 @@ pulse_backend_finalize (GObject *object)
pulse = PULSE_BACKEND (object);
- g_free (pulse->priv->app_name);
- g_free (pulse->priv->app_id);
- g_free (pulse->priv->app_version);
- g_free (pulse->priv->app_icon);
- g_free (pulse->priv->server_address);
+ if (pulse->priv->app_info != NULL)
+ _mate_mixer_app_info_free (pulse->priv->app_info);
- g_hash_table_destroy (pulse->priv->devices);
- g_hash_table_destroy (pulse->priv->streams);
- g_hash_table_destroy (pulse->priv->ext_streams);
+ g_hash_table_unref (pulse->priv->devices);
+ g_hash_table_unref (pulse->priv->sinks);
+ g_hash_table_unref (pulse->priv->sources);
+ g_hash_table_unref (pulse->priv->ext_streams);
+ g_hash_table_unref (pulse->priv->sink_inputs);
+ g_hash_table_unref (pulse->priv->source_outputs);
G_OBJECT_CLASS (pulse_backend_parent_class)->finalize (object);
}
+#define PULSE_APP_NAME(p) (mate_mixer_app_info_get_name (p->priv->app_info))
+#define PULSE_APP_ID(p) (mate_mixer_app_info_get_id (p->priv->app_info))
+#define PULSE_APP_VERSION(p) (mate_mixer_app_info_get_version (p->priv->app_info))
+#define PULSE_APP_ICON(p) (mate_mixer_app_info_get_icon (p->priv->app_info))
+
static gboolean
pulse_backend_open (MateMixerBackend *backend)
{
@@ -329,22 +343,22 @@ pulse_backend_open (MateMixerBackend *backend)
pulse = PULSE_BACKEND (backend);
- if (G_UNLIKELY (pulse->priv->connection != NULL)) {
+ if G_UNLIKELY (pulse->priv->connection != NULL) {
g_warn_if_reached ();
return TRUE;
}
- connection = pulse_connection_new (pulse->priv->app_name,
- pulse->priv->app_id,
- pulse->priv->app_version,
- pulse->priv->app_icon,
+ connection = pulse_connection_new (PULSE_APP_NAME (pulse),
+ PULSE_APP_ID (pulse),
+ PULSE_APP_VERSION (pulse),
+ PULSE_APP_ICON (pulse),
pulse->priv->server_address);
/* No connection attempt is made during the construction of the connection,
* but it sets up the PulseAudio structures, which might fail in an
* unlikely case */
- if (G_UNLIKELY (connection == NULL)) {
- change_state (pulse, MATE_MIXER_STATE_FAILED);
+ if G_UNLIKELY (connection == NULL) {
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_FAILED);
return FALSE;
}
@@ -409,16 +423,21 @@ pulse_backend_open (MateMixerBackend *backend)
G_CALLBACK (on_connection_ext_stream_info),
pulse);
- change_state (pulse, MATE_MIXER_STATE_CONNECTING);
+ PULSE_CHANGE_STATE (backend, MATE_MIXER_STATE_CONNECTING);
/* Connect to the PulseAudio server, this might fail either instantly or
* asynchronously, for example when remote connection timeouts */
if (pulse_connection_connect (connection, FALSE) == FALSE) {
g_object_unref (connection);
- change_state (pulse, MATE_MIXER_STATE_FAILED);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_FAILED);
return FALSE;
}
+ _mate_mixer_backend_set_flags (backend,
+ MATE_MIXER_BACKEND_HAS_APPLICATION_CONTROLS |
+ MATE_MIXER_BACKEND_CAN_SET_DEFAULT_INPUT_STREAM |
+ MATE_MIXER_BACKEND_CAN_SET_DEFAULT_OUTPUT_STREAM);
+
pulse->priv->connection = connection;
return TRUE;
}
@@ -432,7 +451,10 @@ pulse_backend_close (MateMixerBackend *backend)
pulse = PULSE_BACKEND (backend);
- connect_source_remove (pulse);
+ if (pulse->priv->connect_tag != 0) {
+ g_source_remove (pulse->priv->connect_tag);
+ pulse->priv->connect_tag = 0;
+ }
if (pulse->priv->connection != NULL) {
g_signal_handlers_disconnect_by_data (G_OBJECT (pulse->priv->connection),
@@ -441,109 +463,100 @@ pulse_backend_close (MateMixerBackend *backend)
g_clear_object (&pulse->priv->connection);
}
- g_clear_object (&pulse->priv->default_sink);
- g_clear_object (&pulse->priv->default_source);
-
g_hash_table_remove_all (pulse->priv->devices);
- g_hash_table_remove_all (pulse->priv->streams);
+ g_hash_table_remove_all (pulse->priv->sinks);
+ g_hash_table_remove_all (pulse->priv->sources);
g_hash_table_remove_all (pulse->priv->ext_streams);
pulse->priv->connected_once = FALSE;
- change_state (pulse, MATE_MIXER_STATE_IDLE);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_IDLE);
}
-static MateMixerState
-pulse_backend_get_state (MateMixerBackend *backend)
+static void
+pulse_backend_set_app_info (MateMixerBackend *backend, MateMixerAppInfo *info)
{
- g_return_val_if_fail (PULSE_IS_BACKEND (backend), MATE_MIXER_STATE_UNKNOWN);
+ PulseBackend *pulse;
+
+ g_return_if_fail (PULSE_IS_BACKEND (backend));
+ g_return_if_fail (info != NULL);
+
+ pulse = PULSE_BACKEND (backend);
- return PULSE_BACKEND (backend)->priv->state;
+ if (pulse->priv->app_info != NULL)
+ _mate_mixer_app_info_free (pulse->priv->app_info);
+
+ pulse->priv->app_info = _mate_mixer_app_info_copy (info);
}
static void
-pulse_backend_set_data (MateMixerBackend *backend, const MateMixerBackendData *data)
+pulse_backend_set_server_address (MateMixerBackend *backend, const gchar *address)
{
- PulseBackend *pulse;
-
g_return_if_fail (PULSE_IS_BACKEND (backend));
- g_return_if_fail (data != NULL);
- pulse = PULSE_BACKEND (backend);
+ g_free (PULSE_BACKEND (backend)->priv->server_address);
- g_free (pulse->priv->app_name);
- g_free (pulse->priv->app_id);
- g_free (pulse->priv->app_version);
- g_free (pulse->priv->app_icon);
- g_free (pulse->priv->server_address);
-
- pulse->priv->app_name = g_strdup (data->app_name);
- pulse->priv->app_id = g_strdup (data->app_id);
- pulse->priv->app_version = g_strdup (data->app_version);
- pulse->priv->app_icon = g_strdup (data->app_icon);
- pulse->priv->server_address = g_strdup (data->server_address);
+ PULSE_BACKEND (backend)->priv->server_address = g_strdup (address);
}
-static GList *
+static const GList *
pulse_backend_list_devices (MateMixerBackend *backend)
{
- GList *list;
+ PulseBackend *pulse;
g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
- /* Convert the hash table to a sorted linked list, this list is expected
- * to be cached in the main library */
- list = g_hash_table_get_values (PULSE_BACKEND (backend)->priv->devices);
- if (list != NULL) {
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
+ pulse = PULSE_BACKEND (backend);
- return g_list_sort (list, compare_devices);
+ if (pulse->priv->devices_list == NULL) {
+ pulse->priv->devices_list = g_hash_table_get_values (pulse->priv->devices);
+ if (pulse->priv->devices_list != NULL)
+ g_list_foreach (pulse->priv->devices_list, (GFunc) g_object_ref, NULL);
}
- return NULL;
+ return pulse->priv->devices_list;
}
-static GList *
+static const GList *
pulse_backend_list_streams (MateMixerBackend *backend)
{
- GList *list;
+ PulseBackend *pulse;
g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
- /* Convert the hash table to a sorted linked list, this list is expected
- * to be cached in the main library */
- list = g_hash_table_get_values (PULSE_BACKEND (backend)->priv->streams);
- if (list != NULL) {
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
-
- return g_list_sort (list, compare_streams);
- }
- return NULL;
-}
+ pulse = PULSE_BACKEND (backend);
-static GList *
-pulse_backend_list_cached_streams (MateMixerBackend *backend)
-{
- GList *list;
+ if (pulse->priv->streams_list == NULL) {
+ GList *sinks;
+ GList *sources;
- g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
+ sinks = g_hash_table_get_values (pulse->priv->sinks);
+ if (sinks != NULL)
+ g_list_foreach (sinks, (GFunc) g_object_ref, NULL);
- /* Convert the hash table to a sorted linked list, this list is expected
- * to be cached in the main library */
- list = g_hash_table_get_values (PULSE_BACKEND (backend)->priv->ext_streams);
- if (list != NULL) {
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
+ sources = g_hash_table_get_values (pulse->priv->sources);
+ if (sources != NULL)
+ g_list_foreach (sources, (GFunc) g_object_ref, NULL);
- return g_list_sort (list, compare_streams);
+ pulse->priv->streams_list = g_list_concat (sinks, sources);
}
- return NULL;
+ return pulse->priv->streams_list;
}
-static MateMixerStream *
-pulse_backend_get_default_input_stream (MateMixerBackend *backend)
+static const GList *
+pulse_backend_list_stored_controls (MateMixerBackend *backend)
{
+ PulseBackend *pulse;
+
g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
- return PULSE_BACKEND (backend)->priv->default_source;
+ pulse = PULSE_BACKEND (backend);
+
+ if (pulse->priv->ext_streams_list == NULL) {
+ pulse->priv->ext_streams_list = g_hash_table_get_values (pulse->priv->ext_streams);
+ if (pulse->priv->ext_streams_list != NULL)
+ g_list_foreach (pulse->priv->ext_streams_list, (GFunc) g_object_ref, NULL);
+ }
+ return pulse->priv->ext_streams_list;
}
static gboolean
@@ -562,29 +575,13 @@ pulse_backend_set_default_input_stream (MateMixerBackend *backend,
if (pulse_connection_set_default_source (pulse->priv->connection, name) == FALSE)
return FALSE;
- if (pulse->priv->default_source != NULL)
- g_object_unref (pulse->priv->default_source);
-
- pulse->priv->default_source = g_object_ref (stream);
-
/* We might be in the process of setting a default source for which the details
* are not yet known, make sure the change does not happen */
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-source",
- NULL);
-
- g_object_notify (G_OBJECT (pulse), "default-input");
+ PULSE_SET_PENDING_SOURCE_NULL (pulse);
+ PULSE_SET_DEFAULT_SOURCE (pulse, stream);
return TRUE;
}
-static MateMixerStream *
-pulse_backend_get_default_output_stream (MateMixerBackend *backend)
-{
- g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
-
- return PULSE_BACKEND (backend)->priv->default_sink;
-}
-
static gboolean
pulse_backend_set_default_output_stream (MateMixerBackend *backend,
MateMixerStream *stream)
@@ -601,18 +598,10 @@ pulse_backend_set_default_output_stream (MateMixerBackend *backend,
if (pulse_connection_set_default_sink (pulse->priv->connection, name) == FALSE)
return FALSE;
- if (pulse->priv->default_sink != NULL)
- g_object_unref (pulse->priv->default_sink);
-
- pulse->priv->default_sink = g_object_ref (stream);
-
/* We might be in the process of setting a default sink for which the details
* are not yet known, make sure the change does not happen */
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-sink",
- NULL);
-
- g_object_notify (G_OBJECT (pulse), "default-output");
+ PULSE_SET_PENDING_SINK_NULL (pulse);
+ PULSE_SET_DEFAULT_SINK (pulse, stream);
return TRUE;
}
@@ -633,41 +622,41 @@ on_connection_state_notify (PulseConnection *connection,
* Stream callbacks will unmark available streams and remaining
* unavailable streams will be removed when the CONNECTED state
* is reached. */
- mark_hanging (pulse);
- change_state (pulse, MATE_MIXER_STATE_CONNECTING);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_CONNECTING);
- if (pulse->priv->connect_source == NULL &&
- pulse_connection_connect (connection, TRUE) == FALSE) {
- pulse->priv->connect_source = g_timeout_source_new (200);
+ if G_UNLIKELY (pulse->priv->connect_tag != 0)
+ break;
- g_source_set_callback (pulse->priv->connect_source,
+ if (pulse_connection_connect (connection, TRUE) == FALSE) {
+ GSource *source;
+
+ source = g_timeout_source_new (200);
+ g_source_set_callback (source,
(GSourceFunc) connect_source_reconnect,
pulse,
- (GDestroyNotify) connect_source_remove);
+ NULL);
+ pulse->priv->connect_tag =
+ g_source_attach (source, g_main_context_get_thread_default ());
- g_source_attach (pulse->priv->connect_source,
- g_main_context_get_thread_default ());
+ g_source_unref (source);
}
break;
}
/* First connection attempt has failed */
- change_state (pulse, MATE_MIXER_STATE_FAILED);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_FAILED);
break;
case PULSE_CONNECTION_CONNECTING:
case PULSE_CONNECTION_AUTHORIZING:
case PULSE_CONNECTION_LOADING:
- change_state (pulse, MATE_MIXER_STATE_CONNECTING);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_CONNECTING);
break;
case PULSE_CONNECTION_CONNECTED:
- if (pulse->priv->connected_once == TRUE)
- remove_hanging (pulse);
- else
- pulse->priv->connected_once = TRUE;
+ pulse->priv->connected_once = TRUE;
- change_state (pulse, MATE_MIXER_STATE_READY);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_READY);
break;
}
}
@@ -677,18 +666,17 @@ on_connection_server_info (PulseConnection *connection,
const pa_server_info *info,
PulseBackend *pulse)
{
- const gchar *name_source = NULL;
- const gchar *name_sink = NULL;
+ MateMixerStream *stream;
+ const gchar *name_source = NULL;
+ const gchar *name_sink = NULL;
- if (pulse->priv->default_source != NULL)
- name_source = mate_mixer_stream_get_name (pulse->priv->default_source);
+ stream = PULSE_GET_DEFAULT_SOURCE (pulse);
+ if (stream != NULL)
+ name_source = mate_mixer_stream_get_name (stream);
if (g_strcmp0 (name_source, info->default_source_name) != 0) {
- if (pulse->priv->default_source != NULL)
- g_clear_object (&pulse->priv->default_source);
-
if (info->default_source_name != NULL) {
- MateMixerStream *stream = g_hash_table_find (pulse->priv->streams,
+ MateMixerStream *stream = g_hash_table_find (pulse->priv->sources,
compare_stream_names,
(gpointer) info->default_source_name);
@@ -698,20 +686,14 @@ on_connection_server_info (PulseConnection *connection,
* When this happens, remember the name of the stream and wait for the
* stream info callback. */
if (stream != NULL) {
- pulse->priv->default_source = g_object_ref (stream);
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-source",
- NULL);
-
- g_debug ("Default input stream changed to %s", info->default_source_name);
+ PULSE_SET_DEFAULT_SOURCE (pulse, stream);
+ PULSE_SET_PENDING_SOURCE_NULL (pulse);
} else {
g_debug ("Default input stream changed to unknown stream %s",
info->default_source_name);
- g_object_set_data_full (G_OBJECT (pulse),
- "backend-pending-source",
- g_strdup (info->default_source_name),
- g_free);
+ PULSE_SET_PENDING_SOURCE (pulse, info->default_source_name);
+ PULSE_SET_DEFAULT_SOURCE (pulse, NULL);
/* In most cases (for example changing profile) the stream info
* arrives by itself, but do not rely on it and request it explicitely.
@@ -721,20 +703,16 @@ on_connection_server_info (PulseConnection *connection,
info->default_source_name);
}
} else
- g_debug ("Default input stream unset");
-
- g_object_notify (G_OBJECT (pulse), "default-input");
+ PULSE_SET_DEFAULT_SOURCE (pulse, NULL);
}
- if (pulse->priv->default_sink != NULL)
- name_sink = mate_mixer_stream_get_name (pulse->priv->default_sink);
+ stream = PULSE_GET_DEFAULT_SINK (pulse);
+ if (stream != NULL)
+ name_sink = mate_mixer_stream_get_name (stream);
if (g_strcmp0 (name_sink, info->default_sink_name) != 0) {
- if (pulse->priv->default_sink != NULL)
- g_clear_object (&pulse->priv->default_sink);
-
if (info->default_sink_name != NULL) {
- MateMixerStream *stream = g_hash_table_find (pulse->priv->streams,
+ MateMixerStream *stream = g_hash_table_find (pulse->priv->sinks,
compare_stream_names,
(gpointer) info->default_sink_name);
@@ -744,21 +722,14 @@ on_connection_server_info (PulseConnection *connection,
* When this happens, remember the name of the stream and wait for the
* stream info callback. */
if (stream != NULL) {
- pulse->priv->default_sink = g_object_ref (stream);
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-sink",
- NULL);
-
- g_debug ("Default output stream changed to %s", info->default_sink_name);
-
+ PULSE_SET_DEFAULT_SINK (pulse, stream);
+ PULSE_SET_PENDING_SINK_NULL (pulse);
} else {
g_debug ("Default output stream changed to unknown stream %s",
info->default_sink_name);
- g_object_set_data_full (G_OBJECT (pulse),
- "backend-pending-sink",
- g_strdup (info->default_sink_name),
- g_free);
+ PULSE_SET_PENDING_SINK (pulse, info->default_sink_name);
+ PULSE_SET_DEFAULT_SINK (pulse, NULL);
/* In most cases (for example changing profile) the stream info
* arrives by itself, but do not rely on it and request it explicitely.
@@ -768,12 +739,10 @@ on_connection_server_info (PulseConnection *connection,
info->default_sink_name);
}
} else
- g_debug ("Default output stream unset");
-
- g_object_notify (G_OBJECT (pulse), "default-output");
+ PULSE_SET_DEFAULT_SINK (pulse, NULL);
}
- if (pulse->priv->state != MATE_MIXER_STATE_READY)
+ if (mate_mixer_backend_get_state (MATE_MIXER_BACKEND (pulse)) != MATE_MIXER_STATE_READY)
g_debug ("Sound server is %s version %s, running on %s",
info->server_name,
info->server_version,
@@ -790,21 +759,17 @@ on_connection_card_info (PulseConnection *connection,
device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (info->index));
if (device == NULL) {
device = pulse_device_new (connection, info);
- if (G_UNLIKELY (device == NULL))
- return;
- g_hash_table_insert (pulse->priv->devices, GUINT_TO_POINTER (info->index), device);
+ g_hash_table_insert (pulse->priv->devices,
+ GUINT_TO_POINTER (info->index),
+ device);
+ free_list_devices (pulse);
g_signal_emit_by_name (G_OBJECT (pulse),
"device-added",
mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
- } else {
+ } else
pulse_device_update (device, info);
-
- /* The object might be hanging if reconnecting is in progress, remove the
- * hanging flag to prevent it from being removed when connected */
- unmark_hanging (pulse, G_OBJECT (device));
- }
}
static void
@@ -813,29 +778,22 @@ on_connection_card_removed (PulseConnection *connection,
PulseBackend *pulse)
{
PulseDevice *device;
+ gchar *name;
device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (index));
- if (G_UNLIKELY (device == NULL))
+ if G_UNLIKELY (device == NULL)
return;
- remove_device (pulse, device);
-}
+ name = g_strdup (mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
-/* PulseAudio uses 32-bit integers as indices for sinks, sink inputs, sources and
- * source inputs, these indices are not unique among the different kinds of streams,
- * but we want to keep all of them in a single hash table. Allow this by using 64-bit
- * hash table keys, use the lower 32 bits for the PulseAudio index and some of the
- * higher bits to indicate what kind of stream it is. */
-enum {
- HASH_BIT_SINK = (1ULL << 63),
- HASH_BIT_SINK_INPUT = (1ULL << 62),
- HASH_BIT_SOURCE = (1ULL << 61),
- HASH_BIT_SOURCE_OUTPUT = (1ULL << 60)
-};
-#define HASH_ID_SINK(idx) (((idx) & 0xffffffff) | HASH_BIT_SINK)
-#define HASH_ID_SINK_INPUT(idx) (((idx) & 0xffffffff) | HASH_BIT_SINK_INPUT)
-#define HASH_ID_SOURCE(idx) (((idx) & 0xffffffff) | HASH_BIT_SOURCE)
-#define HASH_ID_SOURCE_OUTPUT(idx) (((idx) & 0xffffffff) | HASH_BIT_SOURCE_OUTPUT)
+ g_hash_table_remove (pulse->priv->devices, GUINT_TO_POINTER (index));
+
+ free_list_devices (pulse);
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "device-removed",
+ name);
+ g_free (name);
+}
static void
on_connection_sink_info (PulseConnection *connection,
@@ -844,32 +802,36 @@ on_connection_sink_info (PulseConnection *connection,
{
PulseDevice *device = NULL;
PulseStream *stream;
- gint64 index = HASH_ID_SINK (info->index);
if (info->card != PA_INVALID_INDEX)
- device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (info->card));
+ device = g_hash_table_lookup (pulse->priv->devices,
+ GUINT_TO_POINTER (info->card));
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
+ stream = g_hash_table_lookup (pulse->priv->sinks, GUINT_TO_POINTER (info->index));
if (stream == NULL) {
- stream = pulse_sink_new (connection, info, device);
- if (G_UNLIKELY (stream == NULL))
- return;
+ stream = PULSE_STREAM (pulse_sink_new (connection, info, device));
- g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+ free_list_streams (pulse);
+ g_hash_table_insert (pulse->priv->sinks,
+ GUINT_TO_POINTER (info->index),
+ stream);
- g_signal_emit_by_name (G_OBJECT (pulse),
- "stream-added",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ if (device != NULL) {
+ pulse_device_add_stream (device, stream);
+ } else {
+ const gchar *name =
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream));
+ /* Only emit when not a part of the device, otherwise emitted by
+ * the main library */
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-added",
+ name);
+ }
/* We might be waiting for this sink to set it as the default */
check_pending_sink (pulse, stream);
- } else {
- pulse_sink_update (stream, info, device);
-
- /* The object might be hanging if reconnecting is in progress, remove the
- * hanging flag to prevent it from being removed when connected */
- unmark_hanging (pulse, G_OBJECT (stream));
- }
+ } else
+ pulse_sink_update (PULSE_SINK (stream), info);
}
static void
@@ -878,13 +840,38 @@ on_connection_sink_removed (PulseConnection *connection,
PulseBackend *pulse)
{
PulseStream *stream;
- gint64 index = HASH_ID_SINK (idx);
+ PulseDevice *device;
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (G_UNLIKELY (stream == NULL))
+ stream = g_hash_table_lookup (pulse->priv->sinks, GUINT_TO_POINTER (idx));
+ if G_UNLIKELY (stream == NULL)
return;
- remove_stream (pulse, stream);
+ g_object_ref (stream);
+
+ free_list_streams (pulse);
+ g_hash_table_remove (pulse->priv->sinks, GUINT_TO_POINTER (idx));
+
+ device = pulse_stream_get_device (stream);
+ if (device != NULL) {
+ pulse_device_remove_stream (device, stream);
+ } else {
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-removed",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ }
+
+ /* The removed stream might be one of the default streams, this happens
+ * especially when switching profiles, after which PulseAudio removes the
+ * old streams and creates new ones with different names */
+ if (MATE_MIXER_STREAM (stream) == PULSE_GET_DEFAULT_SINK (pulse)) {
+ PULSE_SET_DEFAULT_SINK (pulse, NULL);
+
+ /* PulseAudio usually sends a server info update by itself when default
+ * stream changes, but there is at least one case when it does not - setting
+ * a card profile to off, so to be sure request an update explicitely */
+ pulse_connection_load_server_info (pulse->priv->connection);
+ }
+ g_object_unref (stream);
}
static void
@@ -892,40 +879,20 @@ on_connection_sink_input_info (PulseConnection *connection,
const pa_sink_input_info *info,
PulseBackend *pulse)
{
- PulseStream *stream;
- PulseStream *parent = NULL;
- gint64 index;
+ PulseSink *sink;
- if (G_LIKELY (info->sink != PA_INVALID_INDEX)) {
- index = HASH_ID_SINK (info->sink);
-
- parent = g_hash_table_lookup (pulse->priv->streams, &index);
- if (G_UNLIKELY (parent == NULL))
- g_debug ("Unknown parent %d of PulseAudio sink input %s",
- info->sink,
- info->name);
- }
-
- index = HASH_ID_SINK_INPUT (info->index);
-
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (stream == NULL) {
- stream = pulse_sink_input_new (connection, info, parent);
- if (G_UNLIKELY (stream == NULL))
- return;
+ if G_UNLIKELY (info->sink == PA_INVALID_INDEX)
+ return;
- g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+ sink = g_hash_table_lookup (pulse->priv->sinks, GUINT_TO_POINTER (info->sink));
+ if G_UNLIKELY (sink == NULL)
+ return;
- g_signal_emit_by_name (G_OBJECT (pulse),
- "stream-added",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
- } else {
- pulse_sink_input_update (stream, info, parent);
+ pulse_sink_add_input (sink, info);
- /* The object might be hanging if reconnecting is in progress, remove the
- * hanging flag to prevent it from being removed when connected */
- unmark_hanging (pulse, G_OBJECT (stream));
- }
+ g_hash_table_insert (pulse->priv->sink_inputs,
+ GUINT_TO_POINTER (info->index),
+ g_object_ref (sink));
}
static void
@@ -933,14 +900,13 @@ on_connection_sink_input_removed (PulseConnection *connection,
guint idx,
PulseBackend *pulse)
{
- PulseStream *stream;
- gint64 index = HASH_ID_SINK_INPUT (idx);
+ PulseSink *sink;
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (G_UNLIKELY (stream == NULL))
+ sink = g_hash_table_lookup (pulse->priv->sink_inputs, GUINT_TO_POINTER (idx));
+ if G_UNLIKELY (sink == NULL)
return;
- remove_stream (pulse, stream);
+ pulse_sink_remove_input (sink, idx);
}
static void
@@ -950,36 +916,40 @@ on_connection_source_info (PulseConnection *connection,
{
PulseDevice *device = NULL;
PulseStream *stream;
- gint64 index = HASH_ID_SOURCE (info->index);
/* Skip monitor streams */
if (info->monitor_of_sink != PA_INVALID_INDEX)
return;
if (info->card != PA_INVALID_INDEX)
- device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (info->card));
+ device = g_hash_table_lookup (pulse->priv->devices,
+ GUINT_TO_POINTER (info->card));
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
+ stream = g_hash_table_lookup (pulse->priv->sources, GUINT_TO_POINTER (info->index));
if (stream == NULL) {
- stream = pulse_source_new (connection, info, device);
- if (G_UNLIKELY (stream == NULL))
- return;
+ stream = PULSE_STREAM (pulse_source_new (connection, info, device));
- g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+ free_list_streams (pulse);
+ g_hash_table_insert (pulse->priv->sources,
+ GUINT_TO_POINTER (info->index),
+ stream);
- g_signal_emit_by_name (G_OBJECT (pulse),
- "stream-added",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ if (device != NULL) {
+ pulse_device_add_stream (device, stream);
+ } else {
+ const gchar *name =
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream));
+ /* Only emit when not a part of the device, otherwise emitted by
+ * the main library */
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-added",
+ name);
+ }
/* We might be waiting for this source to set it as the default */
check_pending_source (pulse, stream);
- } else {
- pulse_source_update (stream, info, device);
-
- /* The object might be hanging if reconnecting is in progress, remove the
- * hanging flag to prevent it from being removed when connected */
- unmark_hanging (pulse, G_OBJECT (stream));
- }
+ } else
+ pulse_source_update (PULSE_SOURCE (stream), info);
}
static void
@@ -987,14 +957,39 @@ on_connection_source_removed (PulseConnection *connection,
guint idx,
PulseBackend *pulse)
{
+ PulseDevice *device;
PulseStream *stream;
- gint64 index = HASH_ID_SOURCE (idx);
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (G_UNLIKELY (stream == NULL))
+ stream = g_hash_table_lookup (pulse->priv->sources, GUINT_TO_POINTER (idx));
+ if G_UNLIKELY (stream == NULL)
return;
- remove_stream (pulse, stream);
+ g_object_ref (stream);
+
+ free_list_streams (pulse);
+ g_hash_table_remove (pulse->priv->sources, GUINT_TO_POINTER (idx));
+
+ device = pulse_stream_get_device (stream);
+ if (device != NULL) {
+ pulse_device_remove_stream (device, stream);
+ } else {
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-removed",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ }
+
+ /* The removed stream might be one of the default streams, this happens
+ * especially when switching profiles, after which PulseAudio removes the
+ * old streams and creates new ones with different names */
+ if (MATE_MIXER_STREAM (stream) == PULSE_GET_DEFAULT_SOURCE (pulse)) {
+ PULSE_SET_DEFAULT_SOURCE (pulse, NULL);
+
+ /* PulseAudio usually sends a server info update by itself when default
+ * stream changes, but there is at least one case when it does not - setting
+ * a card profile to off, so to be sure request an update explicitely */
+ pulse_connection_load_server_info (pulse->priv->connection);
+ }
+ g_object_unref (stream);
}
static void
@@ -1002,39 +997,20 @@ on_connection_source_output_info (PulseConnection *connection,
const pa_source_output_info *info,
PulseBackend *pulse)
{
- PulseStream *stream;
- PulseStream *parent = NULL;
- gint64 index;
-
- if (G_LIKELY (info->source != PA_INVALID_INDEX)) {
- index = HASH_ID_SOURCE (info->source);
-
- /* Most likely a monitor source that we have skipped */
- parent = g_hash_table_lookup (pulse->priv->streams, &index);
- if (parent == NULL)
- return;
- }
+ PulseSource *source;
- index = HASH_ID_SOURCE_OUTPUT (info->index);
-
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (stream == NULL) {
- stream = pulse_source_output_new (connection, info, parent);
- if (G_UNLIKELY (stream == NULL))
- return;
+ if G_UNLIKELY (info->source == PA_INVALID_INDEX)
+ return;
- g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+ source = g_hash_table_lookup (pulse->priv->sources, GUINT_TO_POINTER (info->source));
+ if G_UNLIKELY (source == NULL)
+ return;
- g_signal_emit_by_name (G_OBJECT (pulse),
- "stream-added",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
- } else {
- pulse_source_output_update (stream, info, parent);
+ pulse_source_add_output (source, info);
- /* The object might be hanging if reconnecting is in progress, remove the
- * hanging flag to prevent it from being removed when connected */
- unmark_hanging (pulse, G_OBJECT (stream));
- }
+ g_hash_table_insert (pulse->priv->source_outputs,
+ GUINT_TO_POINTER (info->index),
+ g_object_ref (source));
}
static void
@@ -1042,14 +1018,13 @@ on_connection_source_output_removed (PulseConnection *connection,
guint idx,
PulseBackend *pulse)
{
- PulseStream *stream;
- gint64 index = HASH_ID_SOURCE_OUTPUT (idx);
+ PulseSource *source;
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (G_UNLIKELY (stream == NULL))
+ source = g_hash_table_lookup (pulse->priv->source_outputs, GUINT_TO_POINTER (idx));
+ if G_UNLIKELY (source == NULL)
return;
- remove_stream (pulse, stream);
+ pulse_source_remove_output (source, idx);
}
static void
@@ -1057,63 +1032,75 @@ on_connection_ext_stream_info (PulseConnection *connection,
const pa_ext_stream_restore_info *info,
PulseBackend *pulse)
{
- PulseStream *stream;
- PulseStream *parent = NULL;
+ PulseExtStream *ext;
+ PulseStream *parent = NULL;
- if (G_LIKELY (info->device != NULL))
- parent = g_hash_table_find (pulse->priv->streams, compare_stream_names,
+ if (info->device != NULL) {
+ parent = g_hash_table_find (pulse->priv->sinks, compare_stream_names,
(gpointer) info->device);
- stream = g_hash_table_lookup (pulse->priv->ext_streams, info->name);
- if (stream == NULL) {
- stream = pulse_ext_stream_new (connection, info, parent);
- if (G_UNLIKELY (stream == NULL))
- return;
+ if (parent == NULL)
+ parent = g_hash_table_find (pulse->priv->sources, compare_stream_names,
+ (gpointer) info->device);
+ }
+
+ ext = g_hash_table_lookup (pulse->priv->ext_streams, info->name);
+ if (ext == NULL) {
+ ext = pulse_ext_stream_new (connection, info, parent);
- g_hash_table_insert (pulse->priv->ext_streams, g_strdup (info->name), stream);
+ free_list_ext_streams (pulse);
+ g_hash_table_insert (pulse->priv->ext_streams,
+ g_strdup (info->name),
+ ext);
g_signal_emit_by_name (G_OBJECT (pulse),
- "cached-stream-added",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ "stored-control-added",
+ mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (ext)));
} else {
- pulse_ext_stream_update (stream, info, parent);
+ pulse_ext_stream_update (ext, info, parent);
/* The object might be hanging if ext-streams are being loaded, remove
* the hanging flag to prevent it from being removed */
- unmark_hanging (pulse, G_OBJECT (stream));
+ PULSE_UNSET_HANGING (ext);
}
}
static void
on_connection_ext_stream_loading (PulseConnection *connection, PulseBackend *pulse)
{
- mark_hanging_hash (pulse->priv->ext_streams);
+ GHashTableIter iter;
+ gpointer ext;
+
+ g_hash_table_iter_init (&iter, pulse->priv->ext_streams);
+
+ while (g_hash_table_iter_next (&iter, NULL, &ext) == TRUE)
+ PULSE_SET_HANGING (ext);
}
static void
on_connection_ext_stream_loaded (PulseConnection *connection, PulseBackend *pulse)
{
GHashTableIter iter;
- gpointer value;
+ gpointer name;
+ gpointer ext;
g_hash_table_iter_init (&iter, pulse->priv->ext_streams);
- while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE) {
- guint hanging =
- GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (value), "backend-hanging"));
+ while (g_hash_table_iter_next (&iter, &name, &ext) == TRUE) {
+ if (PULSE_GET_HANGING (ext) == FALSE)
+ continue;
- if (hanging == 1) {
- gchar *name = g_strdup ((const gchar *) value);
+ free_list_ext_streams (pulse);
+ g_hash_table_remove (pulse->priv->ext_streams, (gconstpointer) name);
- g_hash_table_remove (pulse->priv->ext_streams, (gconstpointer) name);
- g_signal_emit_by_name (G_OBJECT (pulse),
- "cached-stream-removed",
- name);
- g_free (name);
- }
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stored-control-removed",
+ name);
}
+ g_debug ("Ext-streams refreshed");
}
+// XXX rename
static gboolean
connect_source_reconnect (PulseBackend *pulse)
{
@@ -1121,16 +1108,10 @@ connect_source_reconnect (PulseBackend *pulse)
* and wait for the connection state notifications, otherwise this function
* will be called again */
if (pulse_connection_connect (pulse->priv->connection, TRUE) == TRUE) {
- connect_source_remove (pulse);
- return FALSE;
+ pulse->priv->connect_tag = 0;
+ return G_SOURCE_REMOVE;
}
- return TRUE;
-}
-
-static void
-connect_source_remove (PulseBackend *pulse)
-{
- g_clear_pointer (&pulse->priv->connect_source, g_source_unref);
+ return G_SOURCE_CONTINUE;
}
static void
@@ -1141,7 +1122,7 @@ check_pending_sink (PulseBackend *pulse, PulseStream *stream)
/* See if the currently added sream matches the default input stream
* we are waiting for */
- pending = g_object_get_data (G_OBJECT (pulse), "backend-pending-sink");
+ pending = PULSE_GET_PENDING_SINK (pulse);
if (pending == NULL)
return;
@@ -1149,14 +1130,10 @@ check_pending_sink (PulseBackend *pulse, PulseStream *stream)
if (g_strcmp0 (pending, name) != 0)
return;
- pulse->priv->default_sink = g_object_ref (stream);
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-sink",
- NULL);
+ g_debug ("Setting default output stream to pending stream %s", name);
- g_debug ("Default output stream changed to pending stream %s", name);
-
- g_object_notify (G_OBJECT (pulse), "default-output");
+ PULSE_SET_PENDING_SINK_NULL (pulse);
+ PULSE_SET_DEFAULT_SINK (pulse, stream);
}
static void
@@ -1167,7 +1144,7 @@ check_pending_source (PulseBackend *pulse, PulseStream *stream)
/* See if the currently added sream matches the default input stream
* we are waiting for */
- pending = g_object_get_data (G_OBJECT (pulse), "backend-pending-source");
+ pending = PULSE_GET_PENDING_SOURCE (pulse);
if (pending == NULL)
return;
@@ -1175,160 +1152,43 @@ check_pending_source (PulseBackend *pulse, PulseStream *stream)
if (g_strcmp0 (pending, name) != 0)
return;
- pulse->priv->default_source = g_object_ref (stream);
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-source",
- NULL);
-
- g_debug ("Default input stream changed to pending stream %s", name);
+ g_debug ("Setting default input stream to pending stream %s", name);
- g_object_notify (G_OBJECT (pulse), "default-input");
+ PULSE_SET_PENDING_SOURCE_NULL (pulse);
+ PULSE_SET_DEFAULT_SOURCE (pulse, stream);
}
static void
-mark_hanging (PulseBackend *pulse)
+free_list_devices (PulseBackend *pulse)
{
- /* Mark devices and streams as hanging, ext-streams are handled separately */
- mark_hanging_hash (pulse->priv->devices);
- mark_hanging_hash (pulse->priv->streams);
-}
-
-static void
-mark_hanging_hash (GHashTable *hash)
-{
- GHashTableIter iter;
- gpointer value;
-
- g_hash_table_iter_init (&iter, hash);
-
- while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE)
- g_object_set_data (G_OBJECT (value), "backend-hanging", GUINT_TO_POINTER (1));
-}
-
-static void
-unmark_hanging (PulseBackend *pulse, GObject *object)
-{
- if (pulse->priv->connected_once == FALSE)
- return;
- if (pulse->priv->state == MATE_MIXER_STATE_READY)
+ if (pulse->priv->devices_list == NULL)
return;
- g_object_steal_data (object, "backend-hanging");
-}
-
-static void
-remove_hanging (PulseBackend *pulse)
-{
- GHashTableIter iter;
- gpointer value;
-
- g_hash_table_iter_init (&iter, pulse->priv->devices);
-
- while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE) {
- guint hanging =
- GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (value), "backend-hanging"));
-
- if (hanging == 1)
- remove_device (pulse, PULSE_DEVICE (value));
- }
-
- g_hash_table_iter_init (&iter, pulse->priv->streams);
-
- while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE) {
- guint hanging =
- GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (value), "backend-hanging"));
+ g_list_free_full (pulse->priv->devices_list, g_object_unref);
- if (hanging == 1)
- remove_stream (pulse, PULSE_STREAM (value));
- }
-}
-
-static void
-remove_device (PulseBackend *pulse, PulseDevice *device)
-{
- gchar *name;
-
- name = g_strdup (mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
-
- g_hash_table_remove (pulse->priv->devices,
- GUINT_TO_POINTER (pulse_device_get_index (device)));
-
- g_signal_emit_by_name (G_OBJECT (pulse), "device-removed", name);
- g_free (name);
+ pulse->priv->devices_list = NULL;
}
static void
-remove_stream (PulseBackend *pulse, PulseStream *stream)
+free_list_streams (PulseBackend *pulse)
{
- gchar *name;
- guint32 idx;
- gint64 index;
- gboolean reload = FALSE;
-
- /* The removed stream might be one of the default streams, this happens
- * especially when switching profiles, after which PulseAudio removes the
- * old streams and creates new ones with different names */
- if (MATE_MIXER_STREAM (stream) == pulse->priv->default_sink) {
- g_clear_object (&pulse->priv->default_sink);
-
- g_object_notify (G_OBJECT (pulse), "default-output");
- reload = TRUE;
- }
- else if (MATE_MIXER_STREAM (stream) == pulse->priv->default_source) {
- g_clear_object (&pulse->priv->default_source);
-
- g_object_notify (G_OBJECT (pulse), "default-input");
- reload = TRUE;
- }
-
- idx = pulse_stream_get_index (stream);
-
- if (PULSE_IS_SINK (stream))
- index = HASH_ID_SINK (idx);
- else if (PULSE_IS_SINK_INPUT (stream))
- index = HASH_ID_SINK_INPUT (idx);
- else if (PULSE_IS_SOURCE (stream))
- index = HASH_ID_SOURCE (idx);
- else
- index = HASH_ID_SOURCE_OUTPUT (idx);
-
- name = g_strdup (mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
-
- g_hash_table_remove (pulse->priv->streams, &index);
+ if (pulse->priv->streams_list == NULL)
+ return;
- /* PulseAudio usually sends a server info update by itself when default
- * stream changes, but there is at least one case when it does not - setting
- * a card profile to off, so to be sure request an update explicitely */
- if (reload == TRUE)
- pulse_connection_load_server_info (pulse->priv->connection);
+ g_list_free_full (pulse->priv->streams_list, g_object_unref);
- g_signal_emit_by_name (G_OBJECT (pulse), "stream-removed", name);
- g_free (name);
+ pulse->priv->streams_list = NULL;
}
static void
-change_state (PulseBackend *backend, MateMixerState state)
+free_list_ext_streams (PulseBackend *pulse)
{
- if (backend->priv->state == state)
+ if (pulse->priv->ext_streams_list == NULL)
return;
- backend->priv->state = state;
-
- g_object_notify (G_OBJECT (backend), "state");
-}
+ g_list_free_full (pulse->priv->ext_streams_list, g_object_unref);
-static gint
-compare_devices (gconstpointer a, gconstpointer b)
-{
- return strcmp (mate_mixer_device_get_name (MATE_MIXER_DEVICE (a)),
- mate_mixer_device_get_name (MATE_MIXER_DEVICE (b)));
-}
-
-static gint
-compare_streams (gconstpointer a, gconstpointer b)
-{
- return strcmp (mate_mixer_stream_get_name (MATE_MIXER_STREAM (a)),
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (b)));
+ pulse->priv->ext_streams_list = NULL;
}
static gboolean
@@ -1336,5 +1196,5 @@ compare_stream_names (gpointer key, gpointer value, gpointer user_data)
{
MateMixerStream *stream = MATE_MIXER_STREAM (value);
- return !strcmp (mate_mixer_stream_get_name (stream), (const gchar *) user_data);
+ return strcmp (mate_mixer_stream_get_name (stream), (const gchar *) user_data) == 0;
}
diff --git a/backends/pulse/pulse-backend.h b/backends/pulse/pulse-backend.h
index bd1face..2c4b8a8 100644
--- a/backends/pulse/pulse-backend.h
+++ b/backends/pulse/pulse-backend.h
@@ -20,8 +20,10 @@
#include <glib.h>
#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
-#include <libmatemixer/matemixer-backend-module.h>
+#include "pulse-types.h"
#define PULSE_TYPE_BACKEND \
(pulse_backend_get_type ())
@@ -36,13 +38,12 @@
#define PULSE_BACKEND_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_BACKEND, PulseBackendClass))
-typedef struct _PulseBackend PulseBackend;
typedef struct _PulseBackendClass PulseBackendClass;
typedef struct _PulseBackendPrivate PulseBackendPrivate;
struct _PulseBackend
{
- GObject parent;
+ MateMixerBackend parent;
/*< private >*/
PulseBackendPrivate *priv;
@@ -50,7 +51,7 @@ struct _PulseBackend
struct _PulseBackendClass
{
- GObjectClass parent_class;
+ MateMixerBackendClass parent_class;
};
GType pulse_backend_get_type (void) G_GNUC_CONST;
diff --git a/backends/pulse/pulse-client-stream.c b/backends/pulse/pulse-client-stream.c
deleted file mode 100644
index b99c498..0000000
--- a/backends/pulse/pulse-client-stream.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * Copyright (C) 2014 Michal Ratajsky <[email protected]>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <string.h>
-#include <glib.h>
-#include <glib-object.h>
-
-#include <libmatemixer/matemixer-client-stream.h>
-#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-stream.h>
-
-#include <pulse/pulseaudio.h>
-
-#include "pulse-client-stream.h"
-#include "pulse-sink.h"
-#include "pulse-source.h"
-#include "pulse-stream.h"
-
-struct _PulseClientStreamPrivate
-{
- gchar *app_name;
- gchar *app_id;
- gchar *app_version;
- gchar *app_icon;
- MateMixerStream *parent;
- MateMixerClientStreamFlags flags;
- MateMixerClientStreamRole role;
-};
-
-enum {
- PROP_0,
- PROP_CLIENT_FLAGS,
- PROP_ROLE,
- PROP_PARENT,
- PROP_APP_NAME,
- PROP_APP_ID,
- PROP_APP_VERSION,
- PROP_APP_ICON
-};
-
-enum {
- REMOVED,
- N_SIGNALS
-};
-
-static guint signals[N_SIGNALS] = { 0, };
-
-static void mate_mixer_client_stream_interface_init (MateMixerClientStreamInterface *iface);
-
-static void pulse_client_stream_class_init (PulseClientStreamClass *klass);
-
-static void pulse_client_stream_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec);
-
-static void pulse_client_stream_init (PulseClientStream *client);
-static void pulse_client_stream_dispose (GObject *object);
-static void pulse_client_stream_finalize (GObject *object);
-
-G_DEFINE_ABSTRACT_TYPE_WITH_CODE (PulseClientStream, pulse_client_stream, PULSE_TYPE_STREAM,
- G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_CLIENT_STREAM,
- mate_mixer_client_stream_interface_init))
-
-static MateMixerClientStreamFlags pulse_client_stream_get_flags (MateMixerClientStream *client);
-static MateMixerClientStreamRole pulse_client_stream_get_role (MateMixerClientStream *client);
-
-static MateMixerStream * pulse_client_stream_get_parent (MateMixerClientStream *client);
-static gboolean pulse_client_stream_set_parent (MateMixerClientStream *client,
- MateMixerStream *parent);
-
-static gboolean pulse_client_stream_remove (MateMixerClientStream *client);
-
-static const gchar * pulse_client_stream_get_app_name (MateMixerClientStream *client);
-static const gchar * pulse_client_stream_get_app_id (MateMixerClientStream *client);
-static const gchar * pulse_client_stream_get_app_version (MateMixerClientStream *client);
-static const gchar * pulse_client_stream_get_app_icon (MateMixerClientStream *client);
-
-static void
-mate_mixer_client_stream_interface_init (MateMixerClientStreamInterface *iface)
-{
- iface->get_flags = pulse_client_stream_get_flags;
- iface->get_role = pulse_client_stream_get_role;
- iface->get_parent = pulse_client_stream_get_parent;
- iface->set_parent = pulse_client_stream_set_parent;
- iface->remove = pulse_client_stream_remove;
- iface->get_app_name = pulse_client_stream_get_app_name;
- iface->get_app_id = pulse_client_stream_get_app_id;
- iface->get_app_version = pulse_client_stream_get_app_version;
- iface->get_app_icon = pulse_client_stream_get_app_icon;
-}
-
-static void
-pulse_client_stream_class_init (PulseClientStreamClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = pulse_client_stream_dispose;
- object_class->finalize = pulse_client_stream_finalize;
- object_class->get_property = pulse_client_stream_get_property;
-
- signals[REMOVED] =
- g_signal_new ("removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseClientStreamClass, removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0,
- G_TYPE_NONE);
-
- g_object_class_override_property (object_class, PROP_CLIENT_FLAGS, "client-flags");
- g_object_class_override_property (object_class, PROP_ROLE, "role");
- g_object_class_override_property (object_class, PROP_PARENT, "parent");
- g_object_class_override_property (object_class, PROP_APP_NAME, "app-name");
- g_object_class_override_property (object_class, PROP_APP_ID, "app-id");
- g_object_class_override_property (object_class, PROP_APP_VERSION, "app-version");
- g_object_class_override_property (object_class, PROP_APP_ICON, "app-icon");
-
- g_type_class_add_private (object_class, sizeof (PulseClientStreamPrivate));
-}
-
-static void
-pulse_client_stream_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec)
-{
- PulseClientStream *client;
-
- client = PULSE_CLIENT_STREAM (object);
-
- switch (param_id) {
- case PROP_CLIENT_FLAGS:
- g_value_set_flags (value, client->priv->flags);
- break;
- case PROP_ROLE:
- g_value_set_enum (value, client->priv->role);
- break;
- case PROP_PARENT:
- g_value_set_object (value, client->priv->parent);
- break;
- case PROP_APP_NAME:
- g_value_set_string (value, client->priv->app_name);
- break;
- case PROP_APP_ID:
- g_value_set_string (value, client->priv->app_id);
- break;
- case PROP_APP_VERSION:
- g_value_set_string (value, client->priv->app_version);
- break;
- case PROP_APP_ICON:
- g_value_set_string (value, client->priv->app_icon);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
- break;
- }
-}
-
-static void
-pulse_client_stream_init (PulseClientStream *client)
-{
- client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client,
- PULSE_TYPE_CLIENT_STREAM,
- PulseClientStreamPrivate);
-}
-
-static void
-pulse_client_stream_dispose (GObject *object)
-{
- PulseClientStream *client;
-
- client = PULSE_CLIENT_STREAM (object);
-
- g_clear_object (&client->priv->parent);
-
- G_OBJECT_CLASS (pulse_client_stream_parent_class)->dispose (object);
-}
-
-static void
-pulse_client_stream_finalize (GObject *object)
-{
- PulseClientStream *client;
-
- client = PULSE_CLIENT_STREAM (object);
-
- g_free (client->priv->app_name);
- g_free (client->priv->app_id);
- g_free (client->priv->app_version);
- g_free (client->priv->app_icon);
-
- G_OBJECT_CLASS (pulse_client_stream_parent_class)->finalize (object);
-}
-
-gboolean
-pulse_client_stream_update_flags (PulseClientStream *pclient,
- MateMixerClientStreamFlags flags)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
-
- if (pclient->priv->flags != flags) {
- pclient->priv->flags = flags;
-
- g_object_notify (G_OBJECT (pclient), "client-flags");
- }
- return TRUE;
-}
-
-gboolean
-pulse_client_stream_update_parent (PulseClientStream *pclient, MateMixerStream *parent)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
-
- if (pclient->priv->parent != parent) {
- g_clear_object (&pclient->priv->parent);
-
- if (G_LIKELY (parent != NULL))
- pclient->priv->parent = g_object_ref (parent);
-
- g_object_notify (G_OBJECT (pclient), "parent");
- }
- return TRUE;
-}
-
-gboolean
-pulse_client_stream_update_role (PulseClientStream *pclient,
- MateMixerClientStreamRole role)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
-
- if (pclient->priv->role != role) {
- pclient->priv->role = role;
-
- g_object_notify (G_OBJECT (pclient), "role");
- }
- return TRUE;
-}
-
-gboolean
-pulse_client_stream_update_app_name (PulseClientStream *pclient, const gchar *app_name)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
-
- if (g_strcmp0 (pclient->priv->app_name, app_name) != 0) {
- g_free (pclient->priv->app_name);
- pclient->priv->app_name = g_strdup (app_name);
-
- g_object_notify (G_OBJECT (pclient), "app-name");
- }
- return TRUE;
-}
-
-gboolean
-pulse_client_stream_update_app_id (PulseClientStream *pclient, const gchar *app_id)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
-
- if (g_strcmp0 (pclient->priv->app_id, app_id) != 0) {
- g_free (pclient->priv->app_id);
- pclient->priv->app_id = g_strdup (app_id);
-
- g_object_notify (G_OBJECT (pclient), "app-id");
- }
- return TRUE;
-}
-
-gboolean
-pulse_client_stream_update_app_version (PulseClientStream *pclient, const gchar *app_version)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
-
- if (g_strcmp0 (pclient->priv->app_version, app_version) != 0) {
- g_free (pclient->priv->app_version);
- pclient->priv->app_version = g_strdup (app_version);
-
- g_object_notify (G_OBJECT (pclient), "app-version");
- }
- return TRUE;
-}
-
-gboolean
-pulse_client_stream_update_app_icon (PulseClientStream *pclient, const gchar *app_icon)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
-
- if (g_strcmp0 (pclient->priv->app_icon, app_icon) != 0) {
- g_free (pclient->priv->app_icon);
- pclient->priv->app_icon = g_strdup (app_icon);
-
- g_object_notify (G_OBJECT (pclient), "app-icon");
- }
- return TRUE;
-}
-
-static MateMixerClientStreamFlags
-pulse_client_stream_get_flags (MateMixerClientStream *client)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), MATE_MIXER_CLIENT_STREAM_NO_FLAGS);
-
- return PULSE_CLIENT_STREAM (client)->priv->flags;
-}
-
-static MateMixerClientStreamRole
-pulse_client_stream_get_role (MateMixerClientStream *client)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), MATE_MIXER_CLIENT_STREAM_ROLE_NONE);
-
- return PULSE_CLIENT_STREAM (client)->priv->role;
-}
-
-static MateMixerStream *
-pulse_client_stream_get_parent (MateMixerClientStream *client)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
-
- return PULSE_CLIENT_STREAM (client)->priv->parent;
-}
-
-static gboolean
-pulse_client_stream_set_parent (MateMixerClientStream *client, MateMixerStream *parent)
-{
- MateMixerStreamFlags flags;
- PulseClientStream *pclient;
- PulseClientStreamClass *klass;
-
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
- g_return_val_if_fail (PULSE_IS_STREAM (parent), FALSE);
-
- pclient = PULSE_CLIENT_STREAM (client);
- klass = PULSE_CLIENT_STREAM_GET_CLASS (pclient);
-
- if (pclient->priv->parent == parent)
- return TRUE;
-
- flags = mate_mixer_stream_get_flags (MATE_MIXER_STREAM (pclient));
-
- /* Validate the parent stream */
- if (flags & MATE_MIXER_STREAM_INPUT && !PULSE_IS_SOURCE (parent)) {
- g_warning ("Could not change stream parent to %s: not a parent input stream",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (parent)));
- return FALSE;
- } else if (flags & MATE_MIXER_STREAM_OUTPUT && !PULSE_IS_SINK (parent)) {
- g_warning ("Could not change stream parent to %s: not a parent output stream",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (parent)));
- return FALSE;
- }
-
- /* Set the parent */
- if (klass->set_parent (pclient, PULSE_STREAM (parent)) == FALSE)
- return FALSE;
-
- if (pclient->priv->parent != NULL)
- g_object_unref (pclient->priv->parent);
-
- /* It is allowed for the parent to be NULL when the instance is created, but
- * changing the parent requires a valid parent stream */
- pclient->priv->parent = g_object_ref (parent);
-
- g_object_notify (G_OBJECT (client), "parent");
- return TRUE;
-}
-
-static gboolean
-pulse_client_stream_remove (MateMixerClientStream *client)
-{
- PulseClientStream *pclient;
- PulseClientStreamClass *klass;
-
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
-
- pclient = PULSE_CLIENT_STREAM (client);
- klass = PULSE_CLIENT_STREAM_GET_CLASS (pclient);
-
- if (klass->remove (pclient) == FALSE)
- return FALSE;
-
- // XXX handle this in the backend
- g_signal_emit (G_OBJECT (client),
- signals[REMOVED],
- 0);
-
- return TRUE;
-}
-
-static const gchar *
-pulse_client_stream_get_app_name (MateMixerClientStream *client)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
-
- return PULSE_CLIENT_STREAM (client)->priv->app_name;
-}
-
-static const gchar *
-pulse_client_stream_get_app_id (MateMixerClientStream *client)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
-
- return PULSE_CLIENT_STREAM (client)->priv->app_id;
-}
-
-static const gchar *
-pulse_client_stream_get_app_version (MateMixerClientStream *client)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
-
- return PULSE_CLIENT_STREAM (client)->priv->app_version;
-}
-
-static const gchar *
-pulse_client_stream_get_app_icon (MateMixerClientStream *client)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
-
- return PULSE_CLIENT_STREAM (client)->priv->app_icon;
-}
diff --git a/backends/pulse/pulse-client-stream.h b/backends/pulse/pulse-client-stream.h
deleted file mode 100644
index fe24dc3..0000000
--- a/backends/pulse/pulse-client-stream.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2014 Michal Ratajsky <[email protected]>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PULSE_CLIENT_STREAM_H
-#define PULSE_CLIENT_STREAM_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include <libmatemixer/matemixer-client-stream.h>
-#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-stream.h>
-
-#include "pulse-stream.h"
-
-G_BEGIN_DECLS
-
-#define PULSE_TYPE_CLIENT_STREAM \
- (pulse_client_stream_get_type ())
-#define PULSE_CLIENT_STREAM(o) \
- (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_CLIENT_STREAM, PulseClientStream))
-#define PULSE_IS_CLIENT_STREAM(o) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_CLIENT_STREAM))
-#define PULSE_CLIENT_STREAM_CLASS(k) \
- (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_CLIENT_STREAM, PulseClientStreamClass))
-#define PULSE_IS_CLIENT_STREAM_CLASS(k) \
- (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_CLIENT_STREAM))
-#define PULSE_CLIENT_STREAM_GET_CLASS(o) \
- (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_CLIENT_STREAM, PulseClientStreamClass))
-
-typedef struct _PulseClientStream PulseClientStream;
-typedef struct _PulseClientStreamClass PulseClientStreamClass;
-typedef struct _PulseClientStreamPrivate PulseClientStreamPrivate;
-
-struct _PulseClientStream
-{
- PulseStream parent;
-
- /*< private >*/
- PulseClientStreamPrivate *priv;
-};
-
-struct _PulseClientStreamClass
-{
- PulseStreamClass parent_class;
-
- /*< private >*/
- /* Virtual table */
- gboolean (*set_parent) (PulseClientStream *pclient,
- PulseStream *pstream);
-
- gboolean (*remove) (PulseClientStream *pclient);
-
- /* Signals */
- void (*removed) (PulseClientStream *pclient);
-};
-
-GType pulse_client_stream_get_type (void) G_GNUC_CONST;
-
-gboolean pulse_client_stream_update_flags (PulseClientStream *pclient,
- MateMixerClientStreamFlags flags);
-
-gboolean pulse_client_stream_update_role (PulseClientStream *pclient,
- MateMixerClientStreamRole role);
-
-gboolean pulse_client_stream_update_parent (PulseClientStream *pclient,
- MateMixerStream *parent);
-
-gboolean pulse_client_stream_update_app_name (PulseClientStream *pclient,
- const gchar *app_name);
-gboolean pulse_client_stream_update_app_id (PulseClientStream *pclient,
- const gchar *app_id);
-gboolean pulse_client_stream_update_app_version (PulseClientStream *pclient,
- const gchar *app_version);
-gboolean pulse_client_stream_update_app_icon (PulseClientStream *pclient,
- const gchar *app_icon);
-
-G_END_DECLS
-
-#endif /* PULSE_CLIENT_STREAM_H */
diff --git a/backends/pulse/pulse-connection.c b/backends/pulse/pulse-connection.c
index cc39caf..7344d2e 100644
--- a/backends/pulse/pulse-connection.c
+++ b/backends/pulse/pulse-connection.c
@@ -31,14 +31,14 @@
struct _PulseConnectionPrivate
{
- gchar *server;
- guint outstanding;
- pa_context *context;
- pa_proplist *proplist;
- pa_glib_mainloop *mainloop;
- gboolean ext_streams_loading;
- gboolean ext_streams_dirty;
- PulseConnectionState state;
+ gchar *server;
+ guint outstanding;
+ pa_context *context;
+ pa_proplist *proplist;
+ pa_glib_mainloop *mainloop;
+ gboolean ext_streams_loading;
+ gboolean ext_streams_dirty;
+ PulseConnectionState state;
};
enum {
@@ -417,7 +417,7 @@ pulse_connection_new (const gchar *app_name,
PulseConnection *connection;
mainloop = pa_glib_mainloop_new (g_main_context_get_thread_default ());
- if (G_UNLIKELY (mainloop == NULL)) {
+ if G_UNLIKELY (mainloop == NULL) {
g_warning ("Failed to create PulseAudio main loop");
return NULL;
}
@@ -468,7 +468,7 @@ pulse_connection_connect (PulseConnection *connection, gboolean wait_for_daemon)
context = pa_context_new_with_proplist (mainloop,
NULL,
connection->priv->proplist);
- if (G_UNLIKELY (context == NULL)) {
+ if G_UNLIKELY (context == NULL) {
g_warning ("Failed to create PulseAudio context");
return FALSE;
}
@@ -774,7 +774,6 @@ pulse_connection_create_monitor (PulseConnection *connection,
return pulse_monitor_new (connection->priv->context,
connection->priv->proplist,
- NULL,
index_source,
index_sink_input);
}
@@ -1227,7 +1226,7 @@ load_lists (PulseConnection *connection)
GSList *ops = NULL;
pa_operation *op;
- if (G_UNLIKELY (connection->priv->outstanding > 0)) {
+ if G_UNLIKELY (connection->priv->outstanding > 0) {
g_warn_if_reached ();
return FALSE;
}
@@ -1235,7 +1234,7 @@ load_lists (PulseConnection *connection)
op = pa_context_get_card_info_list (connection->priv->context,
pulse_card_info_cb,
connection);
- if (G_UNLIKELY (op == NULL))
+ if G_UNLIKELY (op == NULL)
goto error;
ops = g_slist_prepend (ops, op);
@@ -1243,7 +1242,7 @@ load_lists (PulseConnection *connection)
op = pa_context_get_sink_info_list (connection->priv->context,
pulse_sink_info_cb,
connection);
- if (G_UNLIKELY (op == NULL))
+ if G_UNLIKELY (op == NULL)
goto error;
ops = g_slist_prepend (ops, op);
@@ -1251,7 +1250,7 @@ load_lists (PulseConnection *connection)
op = pa_context_get_sink_input_info_list (connection->priv->context,
pulse_sink_input_info_cb,
connection);
- if (G_UNLIKELY (op == NULL))
+ if G_UNLIKELY (op == NULL)
goto error;
ops = g_slist_prepend (ops, op);
@@ -1259,7 +1258,7 @@ load_lists (PulseConnection *connection)
op = pa_context_get_source_info_list (connection->priv->context,
pulse_source_info_cb,
connection);
- if (G_UNLIKELY (op == NULL))
+ if G_UNLIKELY (op == NULL)
goto error;
ops = g_slist_prepend (ops, op);
@@ -1267,7 +1266,7 @@ load_lists (PulseConnection *connection)
op = pa_context_get_source_output_info_list (connection->priv->context,
pulse_source_output_info_cb,
connection);
- if (G_UNLIKELY (op == NULL))
+ if G_UNLIKELY (op == NULL)
goto error;
ops = g_slist_prepend (ops, op);
@@ -1303,7 +1302,7 @@ load_list_finished (PulseConnection *connection)
* as the final step in the connection process */
connection->priv->outstanding--;
- if (G_UNLIKELY (connection->priv->outstanding < 0)) {
+ if G_UNLIKELY (connection->priv->outstanding < 0) {
g_warn_if_reached ();
connection->priv->outstanding = 0;
}
@@ -1311,7 +1310,7 @@ load_list_finished (PulseConnection *connection)
if (connection->priv->outstanding == 0) {
gboolean ret = pulse_connection_load_server_info (connection);
- if (G_UNLIKELY (ret == FALSE)) {
+ if G_UNLIKELY (ret == FALSE) {
pulse_connection_disconnect (connection);
return FALSE;
}
@@ -1640,7 +1639,7 @@ change_state (PulseConnection *connection, PulseConnectionState state)
static gboolean
process_pulse_operation (PulseConnection *connection, pa_operation *op)
{
- if (G_UNLIKELY (op == NULL)) {
+ if G_UNLIKELY (op == NULL) {
g_warning ("PulseAudio operation failed: %s",
pa_strerror (pa_context_errno (connection->priv->context)));
return FALSE;
diff --git a/backends/pulse/pulse-connection.h b/backends/pulse/pulse-connection.h
index b9119fd..7dc0bfb 100644
--- a/backends/pulse/pulse-connection.h
+++ b/backends/pulse/pulse-connection.h
@@ -25,7 +25,7 @@
#include <pulse/ext-stream-restore.h>
#include "pulse-enums.h"
-#include "pulse-monitor.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
@@ -42,7 +42,6 @@ G_BEGIN_DECLS
#define PULSE_CONNECTION_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_CONNECTION, PulseConnectionClass))
-typedef struct _PulseConnection PulseConnection;
typedef struct _PulseConnectionClass PulseConnectionClass;
typedef struct _PulseConnectionPrivate PulseConnectionPrivate;
@@ -59,7 +58,6 @@ struct _PulseConnectionClass
GObjectClass parent_class;
/*< private >*/
- /* Signals */
void (*server_info) (PulseConnection *connection,
const pa_server_info *info);
@@ -201,7 +199,6 @@ gboolean pulse_connection_kill_source_output (PulseConnection
gboolean pulse_connection_write_ext_stream (PulseConnection *connection,
const pa_ext_stream_restore_info *info);
-
gboolean pulse_connection_delete_ext_stream (PulseConnection *connection,
const gchar *name);
diff --git a/backends/pulse/pulse-device-profile.c b/backends/pulse/pulse-device-profile.c
new file mode 100644
index 0000000..5487841
--- /dev/null
+++ b/backends/pulse/pulse-device-profile.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-connection.h"
+#include "pulse-device.h"
+#include "pulse-device-profile.h"
+
+struct _PulseDeviceProfilePrivate
+{
+ guint priority;
+};
+
+static void pulse_device_profile_class_init (PulseDeviceProfileClass *klass);
+static void pulse_device_profile_init (PulseDeviceProfile *profile);
+
+G_DEFINE_TYPE (PulseDeviceProfile, pulse_device_profile, MATE_MIXER_TYPE_SWITCH_OPTION)
+
+static void
+pulse_device_profile_class_init (PulseDeviceProfileClass *klass)
+{
+ g_type_class_add_private (klass, sizeof (PulseDeviceProfilePrivate));
+}
+
+static void
+pulse_device_profile_init (PulseDeviceProfile *profile)
+{
+ profile->priv = G_TYPE_INSTANCE_GET_PRIVATE (profile,
+ PULSE_TYPE_DEVICE_PROFILE,
+ PulseDeviceProfilePrivate);
+}
+
+PulseDeviceProfile *
+pulse_device_profile_new (const gchar *name,
+ const gchar *label,
+ guint priority)
+{
+ PulseDeviceProfile *profile;
+
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (label != NULL, NULL);
+
+ profile = g_object_new (PULSE_TYPE_DEVICE_PROFILE,
+ "name", name,
+ "label", label,
+ NULL);
+
+ profile->priv->priority = priority;
+ return profile;
+}
+
+const gchar *
+pulse_device_profile_get_name (PulseDeviceProfile *profile)
+{
+ g_return_val_if_fail (PULSE_IS_DEVICE_PROFILE (profile), NULL);
+
+ return mate_mixer_switch_option_get_name (MATE_MIXER_SWITCH_OPTION (profile));
+}
+
+guint
+pulse_device_profile_get_priority (PulseDeviceProfile *profile)
+{
+ g_return_val_if_fail (PULSE_IS_DEVICE_PROFILE (profile), 0);
+
+ return profile->priv->priority;
+}
diff --git a/backends/pulse/pulse-device-profile.h b/backends/pulse/pulse-device-profile.h
new file mode 100644
index 0000000..0a9c3f4
--- /dev/null
+++ b/backends/pulse/pulse-device-profile.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_DEVICE_PROFILE_H
+#define PULSE_DEVICE_PROFILE_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_DEVICE_PROFILE \
+ (pulse_device_profile_get_type ())
+#define PULSE_DEVICE_PROFILE(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_DEVICE_PROFILE, PulseDeviceProfile))
+#define PULSE_IS_DEVICE_PROFILE(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_DEVICE_PROFILE))
+#define PULSE_DEVICE_PROFILE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_DEVICE_PROFILE, PulseDeviceProfileClass))
+#define PULSE_IS_DEVICE_PROFILE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_DEVICE_PROFILE))
+#define PULSE_DEVICE_PROFILE_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_IS_DEVICE_PROFILE, PulseDeviceProfileClass))
+
+typedef struct _PulseDeviceProfileClass PulseDeviceProfileClass;
+typedef struct _PulseDeviceProfilePrivate PulseDeviceProfilePrivate;
+
+struct _PulseDeviceProfile
+{
+ MateMixerSwitchOption parent;
+
+ /*< private >*/
+ PulseDeviceProfilePrivate *priv;
+};
+
+struct _PulseDeviceProfileClass
+{
+ MateMixerSwitchOptionClass parent;
+};
+
+GType pulse_device_profile_get_type (void) G_GNUC_CONST;
+
+PulseDeviceProfile *pulse_device_profile_new (const gchar *name,
+ const gchar *label,
+ guint priority);
+
+const gchar * pulse_device_profile_get_name (PulseDeviceProfile *profile);
+guint pulse_device_profile_get_priority (PulseDeviceProfile *profile);
+
+G_END_DECLS
+
+#endif /* PULSE_DEVICE_PROFILE_H */
diff --git a/backends/pulse/pulse-device-switch.c b/backends/pulse/pulse-device-switch.c
new file mode 100644
index 0000000..7a43d0a
--- /dev/null
+++ b/backends/pulse/pulse-device-switch.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "pulse-connection.h"
+#include "pulse-device.h"
+#include "pulse-device-profile.h"
+#include "pulse-device-switch.h"
+
+struct _PulseDeviceSwitchPrivate
+{
+ GList *profiles;
+ PulseDevice *device;
+};
+
+enum {
+ PROP_0,
+ PROP_DEVICE,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+static void pulse_device_switch_class_init (PulseDeviceSwitchClass *klass);
+
+static void pulse_device_switch_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void pulse_device_switch_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void pulse_device_switch_init (PulseDeviceSwitch *swtch);
+static void pulse_device_switch_dispose (GObject *object);
+
+G_DEFINE_TYPE (PulseDeviceSwitch, pulse_device_switch, MATE_MIXER_TYPE_SWITCH)
+
+static gboolean pulse_device_switch_set_active_option (MateMixerSwitch *mms,
+ MateMixerSwitchOption *mmso);
+
+static const GList *pulse_device_switch_list_options (MateMixerSwitch *mms);
+
+static gint compare_profiles (gconstpointer a,
+ gconstpointer b);
+static gint compare_profile_name (gconstpointer a,
+ gconstpointer b);
+
+static void
+pulse_device_switch_class_init (PulseDeviceSwitchClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerSwitchClass *switch_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_device_switch_dispose;
+ object_class->get_property = pulse_device_switch_get_property;
+ object_class->set_property = pulse_device_switch_set_property;
+
+ switch_class = MATE_MIXER_SWITCH_CLASS (klass);
+ switch_class->set_active_option = pulse_device_switch_set_active_option;
+ switch_class->list_options = pulse_device_switch_list_options;
+
+ properties[PROP_DEVICE] =
+ g_param_spec_object ("device",
+ "Device",
+ "PulseAudio device",
+ PULSE_TYPE_DEVICE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ g_type_class_add_private (G_OBJECT_CLASS (klass), sizeof (PulseDeviceSwitchPrivate));
+}
+
+static void
+pulse_device_switch_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PulseDeviceSwitch *swtch;
+
+ swtch = PULSE_DEVICE_SWITCH (object);
+
+ switch (param_id) {
+ case PROP_DEVICE:
+ g_value_set_object (value, swtch->priv->device);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_device_switch_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PulseDeviceSwitch *swtch;
+
+ swtch = PULSE_DEVICE_SWITCH (object);
+
+ switch (param_id) {
+ case PROP_DEVICE:
+ /* Construct-only object */
+ swtch->priv->device = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_device_switch_init (PulseDeviceSwitch *swtch)
+{
+ swtch->priv = G_TYPE_INSTANCE_GET_PRIVATE (swtch,
+ PULSE_TYPE_DEVICE_SWITCH,
+ PulseDeviceSwitchPrivate);
+}
+
+static void
+pulse_device_switch_dispose (GObject *object)
+{
+ PulseDeviceSwitch *swtch;
+
+ swtch = PULSE_DEVICE_SWITCH (object);
+
+ g_clear_object (&swtch->priv->device);
+
+ G_OBJECT_CLASS (pulse_device_switch_parent_class)->dispose (object);
+}
+
+PulseDeviceSwitch *
+pulse_device_switch_new (const gchar *name, const gchar *label, PulseDevice *device)
+{
+ return g_object_new (PULSE_TYPE_DEVICE_SWITCH,
+ "name", name,
+ "label", label,
+ "role", MATE_MIXER_SWITCH_ROLE_DEVICE_PROFILE,
+ "device", device,
+ NULL);
+}
+
+PulseDevice *
+pulse_device_switch_get_device (PulseDeviceSwitch *swtch)
+{
+ g_return_val_if_fail (PULSE_IS_DEVICE_SWITCH (swtch), NULL);
+
+ return swtch->priv->device;
+}
+
+void
+pulse_device_switch_add_profile (PulseDeviceSwitch *swtch, PulseDeviceProfile *profile)
+{
+ g_return_if_fail (PULSE_IS_DEVICE_SWITCH (swtch));
+ g_return_if_fail (PULSE_IS_DEVICE_PROFILE (profile));
+
+ swtch->priv->profiles = g_list_insert_sorted (swtch->priv->profiles,
+ profile,
+ compare_profiles);
+}
+
+void
+pulse_device_switch_set_active_profile (PulseDeviceSwitch *swtch,
+ PulseDeviceProfile *profile)
+{
+ g_return_if_fail (PULSE_IS_DEVICE_SWITCH (swtch));
+ g_return_if_fail (PULSE_IS_DEVICE_PROFILE (profile));
+
+ _mate_mixer_switch_set_active_option (MATE_MIXER_SWITCH (swtch),
+ MATE_MIXER_SWITCH_OPTION (profile));
+}
+
+void
+pulse_device_switch_set_active_profile_by_name (PulseDeviceSwitch *swtch, const gchar *name)
+{
+ GList *item;
+
+ g_return_if_fail (PULSE_IS_DEVICE_SWITCH (swtch));
+ g_return_if_fail (name != NULL);
+
+ item = g_list_find_custom (swtch->priv->profiles, name, compare_profile_name);
+ if G_UNLIKELY (item == NULL) {
+ g_debug ("Invalid device switch profile name %s", name);
+ return;
+ }
+ pulse_device_switch_set_active_profile (swtch, PULSE_DEVICE_PROFILE (item->data));
+}
+
+static gboolean
+pulse_device_switch_set_active_option (MateMixerSwitch *mms, MateMixerSwitchOption *mmso)
+{
+ PulseDevice *device;
+ const gchar *device_name;
+ const gchar *profile_name;
+
+ g_return_val_if_fail (PULSE_IS_DEVICE_SWITCH (mms), FALSE);
+ g_return_val_if_fail (PULSE_IS_DEVICE_PROFILE (mmso), FALSE);
+
+ device = pulse_device_switch_get_device (PULSE_DEVICE_SWITCH (mms));
+ if G_UNLIKELY (device == NULL)
+ return FALSE;
+
+ device_name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device));
+ profile_name = mate_mixer_switch_option_get_name (mmso);
+
+ return pulse_connection_set_card_profile (pulse_device_get_connection (device),
+ device_name,
+ profile_name);
+}
+
+static const GList *
+pulse_device_switch_list_options (MateMixerSwitch *swtch)
+{
+ g_return_val_if_fail (PULSE_IS_DEVICE_SWITCH (swtch), NULL);
+
+ return PULSE_DEVICE_SWITCH (swtch)->priv->profiles;
+}
+
+static gint
+compare_profiles (gconstpointer a, gconstpointer b)
+{
+ return pulse_device_profile_get_priority (PULSE_DEVICE_PROFILE (b)) -
+ pulse_device_profile_get_priority (PULSE_DEVICE_PROFILE (a));
+}
+
+static gint
+compare_profile_name (gconstpointer a, gconstpointer b)
+{
+ PulseDeviceProfile *profile = PULSE_DEVICE_PROFILE (a);
+ const gchar *name = (const gchar *) b;
+
+ return strcmp (pulse_device_profile_get_name (profile), name);
+}
diff --git a/backends/pulse/pulse-device-switch.h b/backends/pulse/pulse-device-switch.h
new file mode 100644
index 0000000..50f4a68
--- /dev/null
+++ b/backends/pulse/pulse-device-switch.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_DEVICE_SWITCH_H
+#define PULSE_DEVICE_SWITCH_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_DEVICE_SWITCH \
+ (pulse_device_switch_get_type ())
+#define PULSE_DEVICE_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_DEVICE_SWITCH, PulseDeviceSwitch))
+#define PULSE_IS_DEVICE_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_DEVICE_SWITCH))
+#define PULSE_DEVICE_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_DEVICE_SWITCH, PulseDeviceSwitchClass))
+#define PULSE_IS_DEVICE_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_DEVICE_SWITCH))
+#define PULSE_DEVICE_SWITCH_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_DEVICE_SWITCH, PulseDeviceSwitchClass))
+
+typedef struct _PulseDeviceSwitchClass PulseDeviceSwitchClass;
+typedef struct _PulseDeviceSwitchPrivate PulseDeviceSwitchPrivate;
+
+struct _PulseDeviceSwitch
+{
+ MateMixerSwitch parent;
+
+ /*< private >*/
+ PulseDeviceSwitchPrivate *priv;
+};
+
+struct _PulseDeviceSwitchClass
+{
+ MateMixerSwitchClass parent_class;
+};
+
+GType pulse_device_switch_get_type (void) G_GNUC_CONST;
+
+PulseDeviceSwitch *pulse_device_switch_new (const gchar *name,
+ const gchar *label,
+ PulseDevice *device);
+
+PulseDevice * pulse_device_switch_get_device (PulseDeviceSwitch *swtch);
+
+void pulse_device_switch_add_profile (PulseDeviceSwitch *swtch,
+ PulseDeviceProfile *profile);
+
+void pulse_device_switch_set_active_profile (PulseDeviceSwitch *swtch,
+ PulseDeviceProfile *profile);
+
+void pulse_device_switch_set_active_profile_by_name (PulseDeviceSwitch *swtch,
+ const gchar *name);
+
+G_END_DECLS
+
+#endif /* PULSE_DEVICE_SWITCH_H */
diff --git a/backends/pulse/pulse-device.c b/backends/pulse/pulse-device.c
index 96e06c8..5403712 100644
--- a/backends/pulse/pulse-device.c
+++ b/backends/pulse/pulse-device.c
@@ -17,45 +17,40 @@
#include <string.h>
#include <glib.h>
+#include <glib/gi18n.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-device.h>
-#include <libmatemixer/matemixer-device-profile.h>
-#include <libmatemixer/matemixer-device-profile-private.h>
-#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-port.h>
-#include <libmatemixer/matemixer-port-private.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
#include "pulse-device.h"
+#include "pulse-device-profile.h"
+#include "pulse-device-switch.h"
+#include "pulse-port.h"
+#include "pulse-stream.h"
struct _PulseDevicePrivate
{
- guint32 index;
- gchar *name;
- gchar *description;
- gchar *icon;
- GHashTable *ports;
- GList *ports_list;
- GHashTable *profiles;
- GList *profiles_list;
- PulseConnection *connection;
- MateMixerDeviceProfile *profile;
+ guint32 index;
+ GHashTable *ports;
+ GHashTable *streams;
+ GList *streams_list;
+ GList *switches_list;
+ PulseConnection *connection;
+ PulseDeviceSwitch *pswitch;
};
enum {
PROP_0,
- PROP_NAME,
- PROP_DESCRIPTION,
- PROP_ICON,
- PROP_ACTIVE_PROFILE,
PROP_INDEX,
- PROP_CONNECTION
+ PROP_CONNECTION,
+ N_PROPERTIES
};
-static void mate_mixer_device_interface_init (MateMixerDeviceInterface *iface);
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
static void pulse_device_class_init (PulseDeviceClass *klass);
@@ -72,60 +67,25 @@ static void pulse_device_init (PulseDevice *device);
static void pulse_device_dispose (GObject *object);
static void pulse_device_finalize (GObject *object);
-G_DEFINE_TYPE_WITH_CODE (PulseDevice, pulse_device, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_DEVICE,
- mate_mixer_device_interface_init))
+G_DEFINE_TYPE (PulseDevice, pulse_device, MATE_MIXER_TYPE_DEVICE)
-#if PA_CHECK_VERSION (5, 0, 0)
-typedef pa_card_profile_info2 _pa_card_profile_info;
-#else
-typedef pa_card_profile_info _pa_card_profile_info;
-#endif
-
-static const gchar * pulse_device_get_name (MateMixerDevice *device);
-static const gchar * pulse_device_get_description (MateMixerDevice *device);
-static const gchar * pulse_device_get_icon (MateMixerDevice *device);
+static MateMixerStream *pulse_device_get_stream (MateMixerDevice *mmd,
+ const gchar *name);
-static MateMixerPort * pulse_device_get_port (MateMixerDevice *device,
- const gchar *name);
-static MateMixerDeviceProfile *pulse_device_get_profile (MateMixerDevice *device,
- const gchar *name);
+static const GList * pulse_device_list_streams (MateMixerDevice *mmd);
+static const GList * pulse_device_list_switches (MateMixerDevice *mmd);
-static const GList * pulse_device_list_ports (MateMixerDevice *device);
-static const GList * pulse_device_list_profiles (MateMixerDevice *device);
+static void pulse_device_load (PulseDevice *device,
+ const pa_card_info *info);
-static MateMixerDeviceProfile *pulse_device_get_active_profile (MateMixerDevice *device);
-static gboolean pulse_device_set_active_profile (MateMixerDevice *device,
- MateMixerDeviceProfile *profile);
-
-static void update_port (PulseDevice *device,
- pa_card_port_info *p_info);
-static void update_profile (PulseDevice *device,
- _pa_card_profile_info *p_info);
-
-static gint compare_ports (gconstpointer a,
- gconstpointer b);
-static gint compare_profiles (gconstpointer a,
- gconstpointer b);
-
-static void
-mate_mixer_device_interface_init (MateMixerDeviceInterface *iface)
-{
- iface->get_name = pulse_device_get_name;
- iface->get_description = pulse_device_get_description;
- iface->get_icon = pulse_device_get_icon;
- iface->get_port = pulse_device_get_port;
- iface->get_profile = pulse_device_get_profile;
- iface->list_ports = pulse_device_list_ports;
- iface->list_profiles = pulse_device_list_profiles;
- iface->get_active_profile = pulse_device_get_active_profile;
- iface->set_active_profile = pulse_device_set_active_profile;
-}
+static void free_list_streams (PulseDevice *device);
+static void free_list_switches (PulseDevice *device);
static void
pulse_device_class_init (PulseDeviceClass *klass)
{
- GObjectClass *object_class;
+ GObjectClass *object_class;
+ MateMixerDeviceClass *device_class;
object_class = G_OBJECT_CLASS (klass);
object_class->dispose = pulse_device_dispose;
@@ -133,31 +93,32 @@ pulse_device_class_init (PulseDeviceClass *klass)
object_class->get_property = pulse_device_get_property;
object_class->set_property = pulse_device_set_property;
- g_object_class_install_property (object_class,
- PROP_INDEX,
- g_param_spec_uint ("index",
- "Index",
- "Device index",
- 0,
- G_MAXUINT,
- 0,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (object_class,
- PROP_CONNECTION,
- g_param_spec_object ("connection",
- "Connection",
- "PulseAudio connection",
- PULSE_TYPE_CONNECTION,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_override_property (object_class, PROP_NAME, "name");
- g_object_class_override_property (object_class, PROP_DESCRIPTION, "description");
- g_object_class_override_property (object_class, PROP_ICON, "icon");
- g_object_class_override_property (object_class, PROP_ACTIVE_PROFILE, "active-profile");
+ device_class = MATE_MIXER_DEVICE_CLASS (klass);
+ device_class->get_stream = pulse_device_get_stream;
+ device_class->list_streams = pulse_device_list_streams;
+ device_class->list_switches = pulse_device_list_switches;
+
+ properties[PROP_INDEX] =
+ g_param_spec_uint ("index",
+ "Index",
+ "Index of the device",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_CONNECTION] =
+ g_param_spec_object ("connection",
+ "Connection",
+ "PulseAudio connection",
+ PULSE_TYPE_CONNECTION,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
g_type_class_add_private (object_class, sizeof (PulseDevicePrivate));
}
@@ -173,18 +134,6 @@ pulse_device_get_property (GObject *object,
device = PULSE_DEVICE (object);
switch (param_id) {
- case PROP_NAME:
- g_value_set_string (value, device->priv->name);
- break;
- case PROP_DESCRIPTION:
- g_value_set_string (value, device->priv->description);
- break;
- case PROP_ICON:
- g_value_set_string (value, device->priv->icon);
- break;
- case PROP_ACTIVE_PROFILE:
- g_value_set_object (value, device->priv->profile);
- break;
case PROP_INDEX:
g_value_set_uint (value, device->priv->index);
break;
@@ -212,7 +161,6 @@ pulse_device_set_property (GObject *object,
device->priv->index = g_value_get_uint (value);
break;
case PROP_CONNECTION:
- /* Construct-only object */
device->priv->connection = g_value_dup_object (value);
break;
default:
@@ -233,10 +181,10 @@ pulse_device_init (PulseDevice *device)
g_free,
g_object_unref);
- device->priv->profiles = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- g_object_unref);
+ device->priv->streams = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
}
static void
@@ -246,20 +194,14 @@ pulse_device_dispose (GObject *object)
device = PULSE_DEVICE (object);
- if (device->priv->ports_list != NULL) {
- g_list_free_full (device->priv->ports_list, g_object_unref);
- device->priv->ports_list = NULL;
- }
g_hash_table_remove_all (device->priv->ports);
+ g_hash_table_remove_all (device->priv->streams);
- if (device->priv->profiles_list != NULL) {
- g_list_free_full (device->priv->profiles_list, g_object_unref);
- device->priv->profiles_list = NULL;
- }
- g_hash_table_remove_all (device->priv->profiles);
-
- g_clear_object (&device->priv->profile);
g_clear_object (&device->priv->connection);
+ g_clear_object (&device->priv->pswitch);
+
+ free_list_streams (device);
+ free_list_switches (device);
G_OBJECT_CLASS (pulse_device_parent_class)->dispose (object);
}
@@ -271,12 +213,8 @@ pulse_device_finalize (GObject *object)
device = PULSE_DEVICE (object);
- g_free (device->priv->name);
- g_free (device->priv->description);
- g_free (device->priv->icon);
-
- g_hash_table_destroy (device->priv->ports);
- g_hash_table_destroy (device->priv->profiles);
+ g_hash_table_unref (device->priv->ports);
+ g_hash_table_unref (device->priv->streams);
G_OBJECT_CLASS (pulse_device_parent_class)->finalize (object);
}
@@ -285,123 +223,86 @@ PulseDevice *
pulse_device_new (PulseConnection *connection, const pa_card_info *info)
{
PulseDevice *device;
+ const gchar *label;
+ const gchar *icon;
g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (info != NULL, NULL);
+ label = pa_proplist_gets (info->proplist, PA_PROP_DEVICE_DESCRIPTION);
+ if G_UNLIKELY (label == NULL)
+ label = info->name;
+
+ icon = pa_proplist_gets (info->proplist, PA_PROP_DEVICE_ICON_NAME);
+ if G_UNLIKELY (icon == NULL)
+ icon = "audio-card";
+
/* Consider the device index as unchanging parameter */
device = g_object_new (PULSE_TYPE_DEVICE,
- "connection", connection,
"index", info->index,
+ "connection", connection,
+ "name", info->name,
+ "label", label,
+ "icon", icon,
NULL);
- /* Other data may change at any time, so let's make a use of our update function */
+ pulse_device_load (device, info);
pulse_device_update (device, info);
return device;
}
-gboolean
+void
pulse_device_update (PulseDevice *device, const pa_card_info *info)
{
- MateMixerDeviceProfile *profile = NULL;
- const gchar *prop;
- guint32 i;
-
- g_return_val_if_fail (PULSE_IS_DEVICE (device), FALSE);
- g_return_val_if_fail (info != NULL, FALSE);
-
- /* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (device));
-
- /* Name */
- if (g_strcmp0 (device->priv->name, info->name) != 0) {
- g_free (device->priv->name);
- device->priv->name = g_strdup (info->name);
-
- g_object_notify (G_OBJECT (device), "name");
- }
-
- /* Description */
- prop = pa_proplist_gets (info->proplist, PA_PROP_DEVICE_DESCRIPTION);
-
- if (G_UNLIKELY (prop == NULL))
- prop = info->name;
-
- if (g_strcmp0 (device->priv->description, prop) != 0) {
- g_free (device->priv->description);
- device->priv->description = g_strdup (prop);
-
- g_object_notify (G_OBJECT (device), "description");
- }
-
- /* Icon */
- prop = pa_proplist_gets (info->proplist, PA_PROP_DEVICE_ICON_NAME);
-
- if (G_UNLIKELY (prop == NULL))
- prop = "audio-card";
-
- if (g_strcmp0 (device->priv->icon, prop) != 0) {
- g_free (device->priv->icon);
- device->priv->icon = g_strdup (prop);
-
- g_object_notify (G_OBJECT (device), "icon");
- }
-
-#if PA_CHECK_VERSION (2, 0, 0)
- /* List of ports */
- for (i = 0; i < info->n_ports; i++) {
- update_port (device, info->ports[i]);
- }
-#endif
+ g_return_if_fail (PULSE_IS_DEVICE (device));
+ g_return_if_fail (info != NULL);
- /* List of profiles */
- for (i = 0; i < info->n_profiles; i++) {
#if PA_CHECK_VERSION (5, 0, 0)
- pa_card_profile_info2 *p_info = info->profiles2[i];
-
- /* PulseAudio 5.0 includes a new pa_card_profile_info2 which only
- * differs in the new available flag, we use it not to include profiles
- * which are unavailable */
- if (p_info->available == 0)
- continue;
+ if G_LIKELY (info->active_profile2 != NULL)
+ pulse_device_switch_set_active_profile_by_name (device->priv->pswitch,
+ info->active_profile2->name);
#else
- /* The old profile list is an array of structs, not pointers */
- pa_card_profile_info *p_info = &info->profiles[i];
+ if G_LIKELY (info->active_profile != NULL)
+ pulse_device_switch_set_active_profile_by_name (device->priv->pswitch,
+ info->active_profile->name);
#endif
- update_profile (device, p_info);
- }
-
- /* Figure out whether the currently active profile has changed */
- profile = NULL;
+}
-#if PA_CHECK_VERSION (5, 0, 0)
- if (G_LIKELY (info->active_profile2 != NULL))
- profile = g_hash_table_lookup (device->priv->profiles, info->active_profile2->name);
-#else
- if (G_LIKELY (info->active_profile != NULL))
- profile = g_hash_table_lookup (device->priv->profiles, info->active_profile->name);
-#endif
+void
+pulse_device_add_stream (PulseDevice *device, PulseStream *stream)
+{
+ const gchar *name;
- if (profile != device->priv->profile) {
- g_clear_object (&device->priv->profile);
+ g_return_if_fail (PULSE_IS_DEVICE (device));
+ g_return_if_fail (PULSE_IS_STREAM (stream));
- if (G_LIKELY (profile != NULL))
- device->priv->profile = g_object_ref (profile);
+ name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream));
- g_object_notify (G_OBJECT (device), "active-profile");
- }
+ free_list_streams (device);
- g_object_thaw_notify (G_OBJECT (device));
- return TRUE;
+ g_hash_table_insert (device->priv->streams, g_strdup (name), stream);
+ g_signal_emit_by_name (G_OBJECT (device),
+ "stream-added",
+ name);
}
-PulseConnection *
-pulse_device_get_connection (PulseDevice *device)
+void
+pulse_device_remove_stream (PulseDevice *device, PulseStream *stream)
{
- g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
+ const gchar *name;
- return device->priv->connection;
+ g_return_if_fail (PULSE_IS_DEVICE (device));
+ g_return_if_fail (PULSE_IS_STREAM (stream));
+
+ name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream));
+
+ free_list_streams (device);
+
+ g_hash_table_remove (device->priv->streams, name);
+ g_signal_emit_by_name (G_OBJECT (device),
+ "stream-removed",
+ name);
}
guint32
@@ -412,222 +313,130 @@ pulse_device_get_index (PulseDevice *device)
return device->priv->index;
}
-static const gchar *
-pulse_device_get_name (MateMixerDevice *device)
-{
- g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
-
- return PULSE_DEVICE (device)->priv->name;
-}
-
-static const gchar *
-pulse_device_get_description (MateMixerDevice *device)
-{
- g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
-
- return PULSE_DEVICE (device)->priv->description;
-}
-
-static const gchar *
-pulse_device_get_icon (MateMixerDevice *device)
+PulseConnection *
+pulse_device_get_connection (PulseDevice *device)
{
g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
- return PULSE_DEVICE (device)->priv->icon;
+ return device->priv->connection;
}
-static MateMixerPort *
-pulse_device_get_port (MateMixerDevice *device, const gchar *name)
+PulsePort *
+pulse_device_get_port (PulseDevice *device, const gchar *name)
{
g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
- g_return_val_if_fail (name != NULL, NULL);
- return g_hash_table_lookup (PULSE_DEVICE (device)->priv->ports, name);
+ return g_hash_table_lookup (device->priv->ports, name);
}
-static MateMixerDeviceProfile *
-pulse_device_get_profile (MateMixerDevice *device, const gchar *name)
+static MateMixerStream *
+pulse_device_get_stream (MateMixerDevice *mmd, const gchar *name)
{
- g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (PULSE_IS_DEVICE (mmd), NULL);
g_return_val_if_fail (name != NULL, NULL);
- return g_hash_table_lookup (PULSE_DEVICE (device)->priv->profiles, name);
+ return g_hash_table_lookup (PULSE_DEVICE (mmd)->priv->streams, name);
}
static const GList *
-pulse_device_list_ports (MateMixerDevice *device)
+pulse_device_list_streams (MateMixerDevice *mmd)
{
- PulseDevice *pulse;
-
- g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
-
- pulse = PULSE_DEVICE (device);
+ PulseDevice *device;
- if (pulse->priv->ports_list == NULL) {
- GList *list = g_hash_table_get_values (pulse->priv->ports);
+ g_return_val_if_fail (PULSE_IS_DEVICE (mmd), NULL);
- if (list != NULL) {
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
+ device = PULSE_DEVICE (mmd);
- pulse->priv->ports_list = g_list_sort (list, compare_ports);
- }
+ if (device->priv->streams_list == NULL) {
+ device->priv->streams_list = g_hash_table_get_values (device->priv->streams);
+ if (device->priv->streams_list != NULL)
+ g_list_foreach (device->priv->streams_list, (GFunc) g_object_ref, NULL);
}
-
- return (const GList *) pulse->priv->ports_list;
+ return device->priv->streams_list;
}
static const GList *
-pulse_device_list_profiles (MateMixerDevice *device)
+pulse_device_list_switches (MateMixerDevice *mmd)
{
- PulseDevice *pulse;
-
- g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
-
- pulse = PULSE_DEVICE (device);
-
- if (pulse->priv->profiles_list == NULL) {
- GList *list = g_hash_table_get_values (pulse->priv->profiles);
-
- if (list != NULL) {
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
-
- pulse->priv->profiles_list = g_list_sort (list, compare_profiles);
- }
- }
+ g_return_val_if_fail (PULSE_IS_DEVICE (mmd), NULL);
- return (const GList *) pulse->priv->profiles_list;
+ return PULSE_DEVICE (mmd)->priv->switches_list;
}
-static MateMixerDeviceProfile *
-pulse_device_get_active_profile (MateMixerDevice *device)
+static void
+pulse_device_load (PulseDevice *device, const pa_card_info *info)
{
- g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
+ guint i;
- return PULSE_DEVICE (device)->priv->profile;
-}
+#if PA_CHECK_VERSION (2, 0, 0)
+ for (i = 0; i < info->n_ports; i++) {
+ PulsePort *port;
+ const gchar *name;
+ const gchar *icon;
-static gboolean
-pulse_device_set_active_profile (MateMixerDevice *device, MateMixerDeviceProfile *profile)
-{
- PulseDevice *pulse;
- const gchar *name;
- gboolean ret;
+ name = info->ports[i]->name;
+ icon = pa_proplist_gets (info->ports[i]->proplist, "device.icon_name");
- g_return_val_if_fail (PULSE_IS_DEVICE (device), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
+ port = pulse_port_new (name,
+ info->ports[i]->description,
+ icon,
+ info->ports[i]->priority);
- pulse = PULSE_DEVICE (device);
+ g_hash_table_insert (device->priv->ports, g_strdup (name), port);
+ }
+#endif
- name = mate_mixer_device_profile_get_name (profile);
+ /* Create the device profile switch */
+ if (info->n_profiles > 0) {
+ device->priv->pswitch = pulse_device_switch_new ("profile",
+ _("Profile"),
+ device);
- /* Make sure the profile belongs to the device */
- if (g_hash_table_lookup (pulse->priv->profiles, name) == NULL) {
- g_warning ("Profile %s does not belong to device %s", name, pulse->priv->name);
- return FALSE;
+ device->priv->switches_list = g_list_prepend (NULL, g_object_ref (device->priv->pswitch));
}
- ret = pulse_connection_set_card_profile (pulse->priv->connection,
- pulse->priv->name,
- name);
- if (ret == TRUE) {
- if (pulse->priv->profile != NULL)
- g_object_unref (pulse->priv->profile);
+ for (i = 0; i < info->n_profiles; i++) {
+ PulseDeviceProfile *profile;
+
+#if PA_CHECK_VERSION (5, 0, 0)
+ pa_card_profile_info2 *p_info = info->profiles2[i];
+
+ /* PulseAudio 5.0 includes a new pa_card_profile_info2 which only
+ * differs in the new available flag, we use it not to include profiles
+ * which are unavailable */
+ if (p_info->available == 0)
+ continue;
+#else
+ /* The old profile list is an array of structs, not pointers */
+ pa_card_profile_info *p_info = &info->profiles[i];
+#endif
- pulse->priv->profile = g_object_ref (profile);
+ profile = pulse_device_profile_new (p_info->name,
+ p_info->description,
+ p_info->priority);
- g_object_notify (G_OBJECT (device), "active-profile");
+ pulse_device_switch_add_profile (device->priv->pswitch, profile);
}
- return ret;
}
static void
-update_port (PulseDevice *device, pa_card_port_info *p_info)
+free_list_streams (PulseDevice *device)
{
- MateMixerPort *port;
- MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS;
- const gchar *icon;
-
- icon = pa_proplist_gets (p_info->proplist, "device.icon_name");
-
- if (p_info->available == PA_PORT_AVAILABLE_YES)
- flags |= MATE_MIXER_PORT_AVAILABLE;
-
- if (p_info->direction & PA_DIRECTION_INPUT)
- flags |= MATE_MIXER_PORT_INPUT;
- if (p_info->direction & PA_DIRECTION_OUTPUT)
- flags |= MATE_MIXER_PORT_OUTPUT;
-
- port = g_hash_table_lookup (device->priv->ports, p_info->name);
-
- if (port != NULL) {
- /* Update existing port */
- _mate_mixer_port_update_description (port, p_info->description);
- _mate_mixer_port_update_icon (port, icon);
- _mate_mixer_port_update_priority (port, p_info->priority);
- _mate_mixer_port_update_flags (port, flags);
- } else {
- /* Add previously unknown port to the hash table */
- port = _mate_mixer_port_new (p_info->name,
- p_info->description,
- icon,
- p_info->priority,
- flags);
-
- g_hash_table_insert (device->priv->ports, g_strdup (p_info->name), port);
- }
+ if (device->priv->streams_list == NULL)
+ return;
+
+ g_list_free_full (device->priv->streams_list, g_object_unref);
+
+ device->priv->streams_list = NULL;
}
static void
-update_profile (PulseDevice *device, _pa_card_profile_info *p_info)
+free_list_switches (PulseDevice *device)
{
- MateMixerDeviceProfile *profile;
-
- profile = g_hash_table_lookup (device->priv->profiles, p_info->name);
-
- if (profile != NULL) {
- /* Update existing profile */
- _mate_mixer_device_profile_update_description (profile, p_info->description);
- _mate_mixer_device_profile_update_priority (profile, p_info->priority);
- _mate_mixer_device_profile_update_num_input_streams (profile, p_info->n_sources);
- _mate_mixer_device_profile_update_num_output_streams (profile, p_info->n_sinks);
- } else {
- /* Add previously unknown profile to the hash table */
- profile = _mate_mixer_device_profile_new (p_info->name,
- p_info->description,
- p_info->priority,
- p_info->n_sources,
- p_info->n_sinks);
-
- g_hash_table_insert (device->priv->profiles, g_strdup (p_info->name), profile);
- }
-}
+ if (device->priv->switches_list == NULL)
+ return;
-static gint
-compare_ports (gconstpointer a, gconstpointer b)
-{
- MateMixerPort *p1 = MATE_MIXER_PORT (a);
- MateMixerPort *p2 = MATE_MIXER_PORT (b);
-
- gint ret = (gint) (mate_mixer_port_get_priority (p2) -
- mate_mixer_port_get_priority (p1));
- if (ret != 0)
- return ret;
- else
- return strcmp (mate_mixer_port_get_name (p1),
- mate_mixer_port_get_name (p2));
-}
+ g_list_free_full (device->priv->switches_list, g_object_unref);
-static gint
-compare_profiles (gconstpointer a, gconstpointer b)
-{
- MateMixerDeviceProfile *p1 = MATE_MIXER_DEVICE_PROFILE (a);
- MateMixerDeviceProfile *p2 = MATE_MIXER_DEVICE_PROFILE (b);
-
- gint ret = (gint) (mate_mixer_device_profile_get_priority (p2) -
- mate_mixer_device_profile_get_priority (p1));
- if (ret != 0)
- return ret;
- else
- return strcmp (mate_mixer_device_profile_get_name (p1),
- mate_mixer_device_profile_get_name (p2));
+ device->priv->switches_list = NULL;
}
diff --git a/backends/pulse/pulse-device.h b/backends/pulse/pulse-device.h
index 94c331f..863330f 100644
--- a/backends/pulse/pulse-device.h
+++ b/backends/pulse/pulse-device.h
@@ -20,33 +20,33 @@
#include <glib.h>
#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
#include <pulse/pulseaudio.h>
-#include "pulse-connection.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
-#define PULSE_TYPE_DEVICE \
+#define PULSE_TYPE_DEVICE \
(pulse_device_get_type ())
-#define PULSE_DEVICE(o) \
+#define PULSE_DEVICE(o) \
(G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_DEVICE, PulseDevice))
-#define PULSE_IS_DEVICE(o) \
+#define PULSE_IS_DEVICE(o) \
(G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_DEVICE))
-#define PULSE_DEVICE_CLASS(k) \
+#define PULSE_DEVICE_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_DEVICE, PulseDeviceClass))
-#define PULSE_IS_DEVICE_CLASS(k) \
+#define PULSE_IS_DEVICE_CLASS(k) \
(G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_DEVICE))
-#define PULSE_DEVICE_GET_CLASS(o) \
+#define PULSE_DEVICE_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_IS_DEVICE, PulseDeviceClass))
-typedef struct _PulseDevice PulseDevice;
typedef struct _PulseDeviceClass PulseDeviceClass;
typedef struct _PulseDevicePrivate PulseDevicePrivate;
struct _PulseDevice
{
- GObject parent;
+ MateMixerDevice parent;
/*< private >*/
PulseDevicePrivate *priv;
@@ -54,20 +54,29 @@ struct _PulseDevice
struct _PulseDeviceClass
{
- GObjectClass parent;
+ MateMixerDeviceClass parent;
};
GType pulse_device_get_type (void) G_GNUC_CONST;
-PulseDevice *pulse_device_new (PulseConnection *connection,
+PulseDevice * pulse_device_new (PulseConnection *connection,
const pa_card_info *info);
-gboolean pulse_device_update (PulseDevice *device,
+void pulse_device_update (PulseDevice *device,
const pa_card_info *info);
+void pulse_device_add_stream (PulseDevice *device,
+ PulseStream *stream);
+
+void pulse_device_remove_stream (PulseDevice *device,
+ PulseStream *stream);
+
guint32 pulse_device_get_index (PulseDevice *device);
PulseConnection *pulse_device_get_connection (PulseDevice *device);
+PulsePort * pulse_device_get_port (PulseDevice *device,
+ const gchar *name);
+
G_END_DECLS
#endif /* PULSE_DEVICE_H */
diff --git a/backends/pulse/pulse-ext-stream.c b/backends/pulse/pulse-ext-stream.c
index b00e967..3e7490a 100644
--- a/backends/pulse/pulse-ext-stream.c
+++ b/backends/pulse/pulse-ext-stream.c
@@ -19,252 +19,326 @@
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-client-stream.h>
-#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include <pulse/ext-stream-restore.h>
#include "pulse-connection.h"
-#include "pulse-client-stream.h"
#include "pulse-ext-stream.h"
#include "pulse-helpers.h"
#include "pulse-stream.h"
+#include "pulse-stream-control.h"
-static void pulse_ext_stream_class_init (PulseExtStreamClass *klass);
-static void pulse_ext_stream_init (PulseExtStream *ext);
+struct _PulseExtStreamPrivate
+{
+ MateMixerAppInfo *app_info;
+ MateMixerDirection direction;
+};
-G_DEFINE_TYPE (PulseExtStream, pulse_ext_stream, PULSE_TYPE_CLIENT_STREAM);
+enum {
+ PROP_0,
+ PROP_DIRECTION
+};
-static void pulse_ext_stream_reload (PulseStream *pstream);
+static void mate_mixer_stored_control_interface_init (MateMixerStoredControlInterface *iface);
-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);
-static void
-pulse_ext_stream_class_init (PulseExtStreamClass *klass)
-{
- PulseStreamClass *stream_class;
- PulseClientStreamClass *client_class;
+static void pulse_ext_stream_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void pulse_ext_stream_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
- stream_class = PULSE_STREAM_CLASS (klass);
+static void pulse_ext_stream_init (PulseExtStream *ext);
- 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;
+G_DEFINE_TYPE_WITH_CODE (PulseExtStream, pulse_ext_stream, PULSE_TYPE_STREAM_CONTROL,
+ G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_STORED_CONTROL,
+ mate_mixer_stored_control_interface_init))
- client_class = PULSE_CLIENT_STREAM_CLASS (klass);
+static MateMixerDirection pulse_ext_stream_get_direction (MateMixerStoredControl *mmsc);
- client_class->set_parent = pulse_ext_stream_set_parent;
- client_class->remove = pulse_ext_stream_remove;
-}
+static MateMixerAppInfo * pulse_ext_stream_get_app_info (MateMixerStreamControl *mmsc);
+
+static gboolean pulse_ext_stream_set_stream (MateMixerStreamControl *mmsc,
+ MateMixerStream *mms);
+
+static gboolean pulse_ext_stream_set_mute (PulseStreamControl *control,
+ gboolean mute);
+static gboolean pulse_ext_stream_set_volume (PulseStreamControl *control,
+ pa_cvolume *cvolume);
+
+static void fill_ext_stream_restore_info (PulseStreamControl *control,
+ pa_ext_stream_restore_info *info);
static void
-pulse_ext_stream_init (PulseExtStream *ext)
+mate_mixer_stored_control_interface_init (MateMixerStoredControlInterface *iface)
{
+ iface->get_direction = pulse_ext_stream_get_direction;
}
-PulseStream *
-pulse_ext_stream_new (PulseConnection *connection,
- const pa_ext_stream_restore_info *info,
- PulseStream *parent)
+static void
+pulse_ext_stream_class_init (PulseExtStreamClass *klass)
{
- PulseStream *ext;
+ GObjectClass *object_class;
+ MateMixerStreamControlClass *control_class;
+ PulseStreamControlClass *pulse_class;
- g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
- g_return_val_if_fail (info != NULL, NULL);
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->get_property = pulse_ext_stream_get_property;
+ object_class->set_property = pulse_ext_stream_set_property;
- ext = g_object_new (PULSE_TYPE_EXT_STREAM,
- "connection", connection,
- NULL);
+ control_class = MATE_MIXER_STREAM_CONTROL_CLASS (klass);
+ control_class->get_app_info = pulse_ext_stream_get_app_info;
+ control_class->set_stream = pulse_ext_stream_set_stream;
- /* Consider the stream name as unchanging parameter */
- pulse_stream_update_name (ext, info->name);
+ pulse_class = PULSE_STREAM_CONTROL_CLASS (klass);
+ pulse_class->set_mute = pulse_ext_stream_set_mute;
+ pulse_class->set_volume = pulse_ext_stream_set_volume;
- /* Other data may change at any time, so let's make a use of our update function */
- pulse_ext_stream_update (ext, info, parent);
+ g_object_class_override_property (object_class, PROP_DIRECTION, "direction");
- return ext;
+ g_type_class_add_private (object_class, sizeof (PulseExtStreamPrivate));
}
-gboolean
-pulse_ext_stream_update (PulseStream *pstream,
- const pa_ext_stream_restore_info *info,
- PulseStream *parent)
+static void
+pulse_ext_stream_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- 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;
+ PulseExtStream *ext;
- PulseClientStream *pclient;
- gchar *suffix;
+ ext = PULSE_EXT_STREAM (object);
- g_return_val_if_fail (PULSE_IS_EXT_STREAM (pstream), FALSE);
- g_return_val_if_fail (info != NULL, FALSE);
+ switch (param_id) {
+ case PROP_DIRECTION:
+ g_value_set_enum (value, ext->priv->direction);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
- pclient = PULSE_CLIENT_STREAM (pstream);
+static void
+pulse_ext_stream_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PulseExtStream *ext;
- suffix = strchr (info->name, ':');
- if (suffix != NULL)
- suffix++;
+ ext = PULSE_EXT_STREAM (object);
- /* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (pstream));
+ switch (param_id) {
+ case PROP_DIRECTION:
+ ext->priv->direction = g_value_get_enum (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_ext_stream_init (PulseExtStream *ext)
+{
+ ext->priv = G_TYPE_INSTANCE_GET_PRIVATE (ext,
+ PULSE_TYPE_EXT_STREAM,
+ PulseExtStreamPrivate);
+}
+
+PulseExtStream *
+pulse_ext_stream_new (PulseConnection *connection,
+ const pa_ext_stream_restore_info *info,
+ PulseStream *parent)
+{
+ PulseExtStream *ext;
+ gchar *suffix;
+ MateMixerDirection direction;
+ MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_MUTE_READABLE |
+ MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE;
+ MateMixerStreamControlRole role = MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN;
+ MateMixerAppInfo *app_info;
+
+ MateMixerStreamControlMediaRole media_role = MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (info != NULL, NULL);
if (g_str_has_prefix (info->name, "sink-input"))
- flags |= MATE_MIXER_STREAM_OUTPUT;
+ direction = MATE_MIXER_DIRECTION_OUTPUT;
else if (g_str_has_prefix (info->name, "source-output"))
- flags |= MATE_MIXER_STREAM_INPUT;
+ direction = MATE_MIXER_DIRECTION_INPUT;
else
- g_debug ("Unknown ext-stream %s", info->name);
+ direction = MATE_MIXER_DIRECTION_UNKNOWN;
+
+ app_info = _mate_mixer_app_info_new ();
+
+ suffix = strchr (info->name, ':');
+ if (suffix != NULL)
+ suffix++;
if (strstr (info->name, "-by-media-role:")) {
if (G_LIKELY (suffix != NULL))
- role = pulse_convert_media_role_name (suffix);
+ media_role = pulse_convert_media_role_name (suffix);
}
else if (strstr (info->name, "-by-application-name:")) {
- client_flags |= MATE_MIXER_CLIENT_STREAM_APPLICATION;
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION;
if (G_LIKELY (suffix != NULL))
- pulse_client_stream_update_app_name (pclient, suffix);
+ _mate_mixer_app_info_set_name (app_info, suffix);
}
else if (strstr (info->name, "-by-application-id:")) {
- client_flags |= MATE_MIXER_CLIENT_STREAM_APPLICATION;
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION;
if (G_LIKELY (suffix != NULL))
- pulse_client_stream_update_app_id (pclient, suffix);
+ _mate_mixer_app_info_set_id (app_info, suffix);
}
- /* Flags needed before volume */
- pulse_stream_update_flags (pstream, flags);
+ ext = g_object_new (PULSE_TYPE_EXT_STREAM,
+ "flags", flags,
+ "role", role,
+ "media-role", media_role,
+ "name", info->name,
+ "connection", connection,
+ "direction", direction,
+ "stream", parent,
+ NULL);
- pulse_stream_update_channel_map (pstream, &info->channel_map);
- pulse_stream_update_volume (pstream, &info->volume, 0);
+ if (role == MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION)
+ ext->priv->app_info = app_info;
+ else
+ _mate_mixer_app_info_free (app_info);
- pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
+ pulse_ext_stream_update (ext, info, parent);
+ return ext;
+}
- pulse_client_stream_update_flags (pclient, client_flags);
- pulse_client_stream_update_role (pclient, role);
+void
+pulse_ext_stream_update (PulseExtStream *ext,
+ const pa_ext_stream_restore_info *info,
+ PulseStream *parent)
+{
+ g_return_if_fail (PULSE_IS_EXT_STREAM (ext));
+ g_return_if_fail (info != NULL);
- if (parent != NULL)
- pulse_client_stream_update_parent (pclient, MATE_MIXER_STREAM (parent));
- else
- pulse_client_stream_update_parent (pclient, NULL);
+ /* Let all the information update before emitting notify signals */
+ g_object_freeze_notify (G_OBJECT (ext));
+
+ _mate_mixer_stream_control_set_mute (MATE_MIXER_STREAM_CONTROL (ext),
+ info->mute ? TRUE : FALSE);
- g_object_thaw_notify (G_OBJECT (pstream));
- return TRUE;
+ pulse_stream_control_set_channel_map (PULSE_STREAM_CONTROL (ext),
+ &info->channel_map);
+
+ pulse_stream_control_set_cvolume (PULSE_STREAM_CONTROL (ext),
+ &info->volume,
+ 0);
+
+ _mate_mixer_stream_control_set_stream (MATE_MIXER_STREAM_CONTROL (ext),
+ MATE_MIXER_STREAM (parent));
+
+ g_object_thaw_notify (G_OBJECT (ext));
}
-static void
-pulse_ext_stream_reload (PulseStream *pstream)
+static MateMixerDirection
+pulse_ext_stream_get_direction (MateMixerStoredControl *mmsc)
{
- g_return_if_fail (PULSE_IS_EXT_STREAM (pstream));
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), MATE_MIXER_DIRECTION_UNKNOWN);
- pulse_connection_load_ext_stream_info (pulse_stream_get_connection (pstream));
+ return PULSE_EXT_STREAM (mmsc)->priv->direction;
}
-static gboolean
-pulse_ext_stream_set_mute (PulseStream *pstream, gboolean mute)
+static MateMixerAppInfo *
+pulse_ext_stream_get_app_info (MateMixerStreamControl *mmsc)
{
- 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 (mmsc), NULL);
- g_return_val_if_fail (PULSE_IS_EXT_STREAM (pstream), FALSE);
+ return PULSE_EXT_STREAM (mmsc)->priv->app_info;
+}
- info.name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream));
- info.mute = mute;
+static gboolean
+pulse_ext_stream_set_stream (MateMixerStreamControl *mmsc, MateMixerStream *mms)
+{
+ pa_ext_stream_restore_info info;
- map = pulse_stream_get_channel_map (pstream);
- info.channel_map = *map;
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), FALSE);
+ g_return_val_if_fail (mms == NULL || PULSE_IS_STREAM (mms), FALSE);
- cvolume = pulse_stream_get_cvolume (pstream);
- info.volume = *cvolume;
+ fill_ext_stream_restore_info (PULSE_STREAM_CONTROL (mms), &info);
- parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (pstream));
- if (parent != NULL)
- info.device = mate_mixer_stream_get_name (parent);
+ if (mms != NULL)
+ info.device = mate_mixer_stream_get_name (mms);
else
info.device = NULL;
- return pulse_connection_write_ext_stream (pulse_stream_get_connection (pstream), &info);
+ return pulse_connection_write_ext_stream (pulse_stream_control_get_connection (PULSE_STREAM_CONTROL (mmsc)),
+ &info);
}
static gboolean
-pulse_ext_stream_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
+pulse_ext_stream_set_mute (PulseStreamControl *control, gboolean mute)
{
- 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));
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (control), FALSE);
- 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;
+ fill_ext_stream_restore_info (control, &info);
- info.volume = *cvolume;
+ info.mute = mute;
- return pulse_connection_write_ext_stream (pulse_stream_get_connection (pstream), &info);
+ return pulse_connection_write_ext_stream (pulse_stream_control_get_connection (control),
+ &info);
}
static gboolean
-pulse_ext_stream_set_parent (PulseClientStream *pclient, PulseStream *parent)
+pulse_ext_stream_set_volume (PulseStreamControl *control, pa_cvolume *cvolume)
{
- 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));
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (control), FALSE);
+ g_return_val_if_fail (cvolume != NULL, FALSE);
- map = pulse_stream_get_channel_map (pstream);
- info.channel_map = *map;
+ fill_ext_stream_restore_info (control, &info);
- 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);
+ return pulse_connection_write_ext_stream (pulse_stream_control_get_connection (control),
+ &info);
}
-static gboolean
-pulse_ext_stream_remove (PulseClientStream *pclient)
+static void
+fill_ext_stream_restore_info (PulseStreamControl *control,
+ pa_ext_stream_restore_info *info)
{
- PulseStream *pstream;
- const gchar *name;
+ MateMixerStream *stream;
+ MateMixerStreamControl *mmsc;
+ const pa_channel_map *map;
+ const pa_cvolume *cvolume;
+
+ mmsc = MATE_MIXER_STREAM_CONTROL (control);
- g_return_val_if_fail (PULSE_IS_EXT_STREAM (pclient), FALSE);
+ info->name = mate_mixer_stream_control_get_name (mmsc);
+ info->mute = mate_mixer_stream_control_get_mute (mmsc);
- pstream = PULSE_STREAM (pclient);
- name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream));
+ map = pulse_stream_control_get_channel_map (control);
+ info->channel_map = *map;
- return pulse_connection_delete_ext_stream (pulse_stream_get_connection (pstream), name);
+ cvolume = pulse_stream_control_get_cvolume (control);
+ info->volume = *cvolume;
+
+ stream = mate_mixer_stream_control_get_stream (mmsc);
+ if (stream != NULL)
+ info->device = mate_mixer_stream_get_name (stream);
+ else
+ info->device = NULL;
}
diff --git a/backends/pulse/pulse-ext-stream.h b/backends/pulse/pulse-ext-stream.h
index e8dabb6..b667dc7 100644
--- a/backends/pulse/pulse-ext-stream.h
+++ b/backends/pulse/pulse-ext-stream.h
@@ -24,9 +24,8 @@
#include <pulse/pulseaudio.h>
#include <pulse/ext-stream-restore.h>
-#include "pulse-client-stream.h"
-#include "pulse-connection.h"
-#include "pulse-stream.h"
+#include "pulse-stream-control.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
@@ -43,28 +42,31 @@ G_BEGIN_DECLS
#define PULSE_EXT_STREAM_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_EXT_STREAM, PulseExtStreamClass))
-typedef struct _PulseExtStream PulseExtStream;
-typedef struct _PulseExtStreamClass PulseExtStreamClass;
+typedef struct _PulseExtStreamClass PulseExtStreamClass;
+typedef struct _PulseExtStreamPrivate PulseExtStreamPrivate;
struct _PulseExtStream
{
- PulseClientStream parent;
+ PulseStreamControl parent;
+
+ /*< private >*/
+ PulseExtStreamPrivate *priv;
};
struct _PulseExtStreamClass
{
- PulseClientStreamClass parent_class;
+ PulseStreamControlClass parent_class;
};
-GType pulse_ext_stream_get_type (void) G_GNUC_CONST;
+GType pulse_ext_stream_get_type (void) G_GNUC_CONST;
-PulseStream *pulse_ext_stream_new (PulseConnection *connection,
- const pa_ext_stream_restore_info *info,
- PulseStream *parent);
+PulseExtStream *pulse_ext_stream_new (PulseConnection *connection,
+ const pa_ext_stream_restore_info *info,
+ PulseStream *parent);
-gboolean pulse_ext_stream_update (PulseStream *pstream,
- const pa_ext_stream_restore_info *info,
- PulseStream *parent);
+void pulse_ext_stream_update (PulseExtStream *ext,
+ const pa_ext_stream_restore_info *info,
+ PulseStream *parent);
G_END_DECLS
diff --git a/backends/pulse/pulse-helpers.c b/backends/pulse/pulse-helpers.c
index 577f2c6..73f8cdb 100644
--- a/backends/pulse/pulse-helpers.c
+++ b/backends/pulse/pulse-helpers.c
@@ -29,6 +29,7 @@ typedef struct {
pa_channel_position_t pa_position;
} PositionMap;
+// XXX optimize
static PositionMap const position_map[] = {
{ MATE_MIXER_CHANNEL_UNKNOWN, PA_CHANNEL_POSITION_INVALID },
{ MATE_MIXER_CHANNEL_MONO, PA_CHANNEL_POSITION_MONO },
@@ -76,42 +77,42 @@ pulse_convert_position_to_pulse (MateMixerChannelPosition position)
return PA_CHANNEL_POSITION_INVALID;
}
-MateMixerClientStreamRole
+MateMixerStreamControlMediaRole
pulse_convert_media_role_name (const gchar *name)
{
if (!strcmp (name, "video")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_VIDEO;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_VIDEO;
}
else if (!strcmp (name, "music")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_MUSIC;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_MUSIC;
}
else if (!strcmp (name, "game")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_GAME;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_GAME;
}
else if (!strcmp (name, "event")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_EVENT;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_EVENT;
}
else if (!strcmp (name, "phone")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_PHONE;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_PHONE;
}
else if (!strcmp (name, "animation")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_ANIMATION;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_ANIMATION;
}
else if (!strcmp (name, "production")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_PRODUCTION;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_PRODUCTION;
}
else if (!strcmp (name, "a11y")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_A11Y;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_A11Y;
}
else if (!strcmp (name, "test")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_TEST;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_TEST;
}
else if (!strcmp (name, "abstract")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_ABSTRACT;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_ABSTRACT;
}
else if (!strcmp (name, "filter")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_FILTER;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_FILTER;
}
- return MATE_MIXER_CLIENT_STREAM_ROLE_NONE;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN;
}
diff --git a/backends/pulse/pulse-helpers.h b/backends/pulse/pulse-helpers.h
index 7ccd753..667fc3c 100644
--- a/backends/pulse/pulse-helpers.h
+++ b/backends/pulse/pulse-helpers.h
@@ -19,17 +19,16 @@
#define PULSE_HELPERS_H
#include <glib.h>
-
-#include <libmatemixer/matemixer-enums.h>
+#include <libmatemixer/matemixer.h>
#include <pulse/pulseaudio.h>
G_BEGIN_DECLS
-MateMixerChannelPosition pulse_convert_position_from_pulse (pa_channel_position_t position);
-pa_channel_position_t pulse_convert_position_to_pulse (MateMixerChannelPosition position);
+MateMixerChannelPosition pulse_convert_position_from_pulse (pa_channel_position_t position);
+pa_channel_position_t pulse_convert_position_to_pulse (MateMixerChannelPosition position);
-MateMixerClientStreamRole pulse_convert_media_role_name (const gchar *name);
+MateMixerStreamControlMediaRole pulse_convert_media_role_name (const gchar *name);
G_END_DECLS
diff --git a/backends/pulse/pulse-monitor.c b/backends/pulse/pulse-monitor.c
index 3d5b4a8..915b71b 100644
--- a/backends/pulse/pulse-monitor.c
+++ b/backends/pulse/pulse-monitor.c
@@ -16,6 +16,7 @@
*/
#include <glib.h>
+#include <glib/gi18n.h>
#include <glib-object.h>
#include <pulse/pulseaudio.h>
@@ -27,7 +28,6 @@ struct _PulseMonitorPrivate
pa_context *context;
pa_proplist *proplist;
pa_stream *stream;
- gchar *name;
guint32 index_source;
guint32 index_sink_input;
gboolean enabled;
@@ -36,7 +36,6 @@ struct _PulseMonitorPrivate
enum {
PROP_0,
PROP_ENABLED,
- PROP_NAME,
PROP_INDEX_SOURCE,
PROP_INDEX_SINK_INPUT,
N_PROPERTIES
@@ -91,15 +90,6 @@ pulse_monitor_class_init (PulseMonitorClass *klass)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
- properties[PROP_NAME] =
- g_param_spec_string ("name",
- "Name",
- "Name of the monitor",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT |
- G_PARAM_STATIC_STRINGS);
-
properties[PROP_INDEX_SOURCE] =
g_param_spec_uint ("index-source",
"Index of source",
@@ -153,9 +143,6 @@ pulse_monitor_get_property (GObject *object,
case PROP_ENABLED:
g_value_set_boolean (value, monitor->priv->enabled);
break;
- case PROP_NAME:
- g_value_set_string (value, monitor->priv->name);
- break;
case PROP_INDEX_SOURCE:
g_value_set_uint (value, monitor->priv->index_source);
break;
@@ -179,9 +166,6 @@ pulse_monitor_set_property (GObject *object,
monitor = PULSE_MONITOR (object);
switch (param_id) {
- case PROP_NAME:
- pulse_monitor_set_name (monitor, g_value_get_string (value));
- break;
case PROP_INDEX_SOURCE:
monitor->priv->index_source = g_value_get_uint (value);
break;
@@ -218,15 +202,12 @@ pulse_monitor_finalize (GObject *object)
pa_context_unref (monitor->priv->context);
pa_proplist_free (monitor->priv->proplist);
- g_free (monitor->priv->name);
-
G_OBJECT_CLASS (pulse_monitor_parent_class)->finalize (object);
}
PulseMonitor *
pulse_monitor_new (pa_context *context,
pa_proplist *proplist,
- const gchar *name,
guint32 index_source,
guint32 index_sink_input)
{
@@ -236,7 +217,6 @@ pulse_monitor_new (pa_context *context,
g_return_val_if_fail (proplist != NULL, NULL);
monitor = g_object_new (PULSE_TYPE_MONITOR,
- "name", name,
"index-source", index_source,
"index-sink-input", index_sink_input,
NULL);
@@ -280,34 +260,11 @@ pulse_monitor_set_enabled (PulseMonitor *monitor, gboolean enabled)
return TRUE;
}
-const gchar *
-pulse_monitor_get_name (PulseMonitor *monitor)
-{
- g_return_val_if_fail (PULSE_IS_MONITOR (monitor), NULL);
-
- return monitor->priv->name;
-}
-
-gboolean
-pulse_monitor_set_name (PulseMonitor *monitor, const gchar *name)
-{
- g_return_val_if_fail (PULSE_IS_MONITOR (monitor), FALSE);
-
- if (g_strcmp0 (name, monitor->priv->name) != 0) {
- g_free (monitor->priv->name);
- monitor->priv->name = g_strdup (name);
-
- g_object_notify_by_pspec (G_OBJECT (monitor), properties[PROP_NAME]);
- }
- return TRUE;
-}
-
static gboolean
stream_connect (PulseMonitor *monitor)
{
pa_sample_spec spec;
pa_buffer_attr attr;
- const gchar *name;
gchar *idx;
int ret;
@@ -320,14 +277,9 @@ stream_connect (PulseMonitor *monitor)
spec.format = PA_SAMPLE_FLOAT32;
spec.rate = 25;
- if (monitor->priv->name != NULL)
- name = monitor->priv->name;
- else
- name = "Peak detect";
-
monitor->priv->stream =
pa_stream_new_with_proplist (monitor->priv->context,
- name,
+ _("Peak detect"),
&spec,
NULL,
monitor->priv->proplist);
diff --git a/backends/pulse/pulse-monitor.h b/backends/pulse/pulse-monitor.h
index 41147f5..e371ec3 100644
--- a/backends/pulse/pulse-monitor.h
+++ b/backends/pulse/pulse-monitor.h
@@ -23,6 +23,8 @@
#include <pulse/pulseaudio.h>
+#include "pulse-types.h"
+
G_BEGIN_DECLS
#define PULSE_TYPE_MONITOR \
@@ -38,7 +40,6 @@ G_BEGIN_DECLS
#define PULSE_MONITOR_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_MONITOR, PulseMonitorClass))
-typedef struct _PulseMonitor PulseMonitor;
typedef struct _PulseMonitorClass PulseMonitorClass;
typedef struct _PulseMonitorPrivate PulseMonitorPrivate;
@@ -54,7 +55,7 @@ struct _PulseMonitorClass
{
GObjectClass parent_class;
- /* Signals */
+ /*< private >*/
void (*value) (PulseMonitor *monitor,
gdouble value);
};
@@ -63,7 +64,6 @@ GType pulse_monitor_get_type (void) G_GNUC_CONST;
PulseMonitor *pulse_monitor_new (pa_context *context,
pa_proplist *proplist,
- const gchar *name,
guint32 index_source,
guint32 index_sink_input);
@@ -71,10 +71,6 @@ gboolean pulse_monitor_get_enabled (PulseMonitor *monitor);
gboolean pulse_monitor_set_enabled (PulseMonitor *monitor,
gboolean enabled);
-const gchar * pulse_monitor_get_name (PulseMonitor *monitor);
-gboolean pulse_monitor_set_name (PulseMonitor *monitor,
- const gchar *name);
-
G_END_DECLS
#endif /* PULSE_MONITOR_H */
diff --git a/backends/pulse/pulse-port-switch.c b/backends/pulse/pulse-port-switch.c
new file mode 100644
index 0000000..08f1543
--- /dev/null
+++ b/backends/pulse/pulse-port-switch.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "pulse-connection.h"
+#include "pulse-port.h"
+#include "pulse-port-switch.h"
+#include "pulse-stream.h"
+
+struct _PulsePortSwitchPrivate
+{
+ GList *ports;
+ PulseStream *stream;
+};
+
+enum {
+ PROP_0,
+ PROP_STREAM,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+static void pulse_port_switch_class_init (PulsePortSwitchClass *klass);
+
+static void pulse_port_switch_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void pulse_port_switch_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void pulse_port_switch_init (PulsePortSwitch *swtch);
+static void pulse_port_switch_dispose (GObject *object);
+
+G_DEFINE_ABSTRACT_TYPE (PulsePortSwitch, pulse_port_switch, MATE_MIXER_TYPE_SWITCH)
+
+static gboolean pulse_port_switch_set_active_option (MateMixerSwitch *mms,
+ MateMixerSwitchOption *mmso);
+
+static const GList *pulse_port_switch_list_options (MateMixerSwitch *mms);
+
+static gint compare_ports (gconstpointer a,
+ gconstpointer b);
+static gint compare_port_name (gconstpointer a,
+ gconstpointer b);
+
+static void
+pulse_port_switch_class_init (PulsePortSwitchClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerSwitchClass *switch_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_port_switch_dispose;
+ object_class->get_property = pulse_port_switch_get_property;
+ object_class->set_property = pulse_port_switch_set_property;
+
+ switch_class = MATE_MIXER_SWITCH_CLASS (klass);
+ switch_class->set_active_option = pulse_port_switch_set_active_option;
+ switch_class->list_options = pulse_port_switch_list_options;
+
+ properties[PROP_STREAM] =
+ g_param_spec_object ("stream",
+ "Stream",
+ "PulseAudio stream",
+ PULSE_TYPE_STREAM,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ g_type_class_add_private (G_OBJECT_CLASS (klass), sizeof (PulsePortSwitchPrivate));
+}
+
+static void
+pulse_port_switch_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PulsePortSwitch *swtch;
+
+ swtch = PULSE_PORT_SWITCH (object);
+
+ switch (param_id) {
+ case PROP_STREAM:
+ g_value_set_object (value, swtch->priv->stream);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_port_switch_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PulsePortSwitch *swtch;
+
+ swtch = PULSE_PORT_SWITCH (object);
+
+ switch (param_id) {
+ case PROP_STREAM:
+ /* Construct-only object */
+ swtch->priv->stream = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_port_switch_init (PulsePortSwitch *swtch)
+{
+ swtch->priv = G_TYPE_INSTANCE_GET_PRIVATE (swtch,
+ PULSE_TYPE_PORT_SWITCH,
+ PulsePortSwitchPrivate);
+}
+
+static void
+pulse_port_switch_dispose (GObject *object)
+{
+ PulsePortSwitch *swtch;
+
+ swtch = PULSE_PORT_SWITCH (object);
+
+ g_clear_object (&swtch->priv->stream);
+
+ G_OBJECT_CLASS (pulse_port_switch_parent_class)->dispose (object);
+}
+
+PulseStream *
+pulse_port_switch_get_stream (PulsePortSwitch *swtch)
+{
+ g_return_val_if_fail (PULSE_IS_PORT_SWITCH (swtch), NULL);
+
+ return swtch->priv->stream;
+}
+
+void
+pulse_port_switch_add_port (PulsePortSwitch *swtch, PulsePort *port)
+{
+ g_return_if_fail (PULSE_IS_PORT_SWITCH (swtch));
+ g_return_if_fail (PULSE_IS_PORT (port));
+
+ swtch->priv->ports = g_list_insert_sorted (swtch->priv->ports,
+ port,
+ compare_ports);
+}
+
+void
+pulse_port_switch_set_active_port (PulsePortSwitch *swtch, PulsePort *port)
+{
+ g_return_if_fail (PULSE_IS_PORT_SWITCH (swtch));
+ g_return_if_fail (PULSE_IS_PORT (port));
+
+ _mate_mixer_switch_set_active_option (MATE_MIXER_SWITCH (swtch),
+ MATE_MIXER_SWITCH_OPTION (port));
+}
+
+void
+pulse_port_switch_set_active_port_by_name (PulsePortSwitch *swtch, const gchar *name)
+{
+ GList *item;
+
+ g_return_if_fail (PULSE_IS_PORT_SWITCH (swtch));
+ g_return_if_fail (name != NULL);
+
+ item = g_list_find_custom (swtch->priv->ports, name, compare_port_name);
+ if G_UNLIKELY (item == NULL) {
+ g_debug ("Invalid switch port name %s", name);
+ return;
+ }
+ pulse_port_switch_set_active_port (swtch, PULSE_PORT (item->data));
+}
+
+static gboolean
+pulse_port_switch_set_active_option (MateMixerSwitch *mms, MateMixerSwitchOption *mmso)
+{
+ PulsePortSwitchClass *klass;
+
+ g_return_val_if_fail (PULSE_IS_PORT_SWITCH (mms), FALSE);
+ g_return_val_if_fail (PULSE_IS_PORT (mmso), FALSE);
+
+ klass = PULSE_PORT_SWITCH_GET_CLASS (PULSE_PORT_SWITCH (mms));
+
+ return klass->set_active_port (PULSE_PORT_SWITCH (mms),
+ PULSE_PORT (mmso));
+}
+
+static const GList *
+pulse_port_switch_list_options (MateMixerSwitch *swtch)
+{
+ g_return_val_if_fail (PULSE_IS_PORT_SWITCH (swtch), NULL);
+
+ return PULSE_PORT_SWITCH (swtch)->priv->ports;
+}
+
+static gint
+compare_ports (gconstpointer a, gconstpointer b)
+{
+ return pulse_port_get_priority (PULSE_PORT (b)) -
+ pulse_port_get_priority (PULSE_PORT (a));
+}
+
+static gint
+compare_port_name (gconstpointer a, gconstpointer b)
+{
+ PulsePort *port = PULSE_PORT (a);
+ const gchar *name = (const gchar *) b;
+
+ return strcmp (pulse_port_get_name (port), name);
+}
diff --git a/backends/pulse/pulse-port-switch.h b/backends/pulse/pulse-port-switch.h
new file mode 100644
index 0000000..6ccef38
--- /dev/null
+++ b/backends/pulse/pulse-port-switch.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_PORT_SWITCH_H
+#define PULSE_PORT_SWITCH_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_PORT_SWITCH \
+ (pulse_port_switch_get_type ())
+#define PULSE_PORT_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_PORT_SWITCH, PulsePortSwitch))
+#define PULSE_IS_PORT_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_PORT_SWITCH))
+#define PULSE_PORT_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_PORT_SWITCH, PulsePortSwitchClass))
+#define PULSE_IS_PORT_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_PORT_SWITCH))
+#define PULSE_PORT_SWITCH_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_PORT_SWITCH, PulsePortSwitchClass))
+
+typedef struct _PulsePortSwitchClass PulsePortSwitchClass;
+typedef struct _PulsePortSwitchPrivate PulsePortSwitchPrivate;
+
+struct _PulsePortSwitch
+{
+ MateMixerSwitch parent;
+
+ /*< private >*/
+ PulsePortSwitchPrivate *priv;
+};
+
+struct _PulsePortSwitchClass
+{
+ MateMixerSwitchClass parent_class;
+
+ /*< private >*/
+ gboolean (*set_active_port) (PulsePortSwitch *swtch,
+ PulsePort *port);
+};
+
+GType pulse_port_switch_get_type (void) G_GNUC_CONST;
+
+PulseStream *pulse_port_switch_get_stream (PulsePortSwitch *swtch);
+
+void pulse_port_switch_add_port (PulsePortSwitch *swtch,
+ PulsePort *port);
+
+void pulse_port_switch_set_active_port (PulsePortSwitch *swtch,
+ PulsePort *port);
+
+void pulse_port_switch_set_active_port_by_name (PulsePortSwitch *swtch,
+ const gchar *name);
+
+G_END_DECLS
+
+#endif /* PULSE_PORT_SWITCH_H */
diff --git a/backends/pulse/pulse-port.c b/backends/pulse/pulse-port.c
new file mode 100644
index 0000000..f427448
--- /dev/null
+++ b/backends/pulse/pulse-port.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-connection.h"
+#include "pulse-port.h"
+
+struct _PulsePortPrivate
+{
+ guint priority;
+};
+
+static void pulse_port_class_init (PulsePortClass *klass);
+static void pulse_port_init (PulsePort *port);
+
+G_DEFINE_TYPE (PulsePort, pulse_port, MATE_MIXER_TYPE_SWITCH_OPTION)
+
+static void
+pulse_port_class_init (PulsePortClass *klass)
+{
+ g_type_class_add_private (klass, sizeof (PulsePortPrivate));
+}
+
+static void
+pulse_port_init (PulsePort *port)
+{
+ port->priv = G_TYPE_INSTANCE_GET_PRIVATE (port,
+ PULSE_TYPE_PORT,
+ PulsePortPrivate);
+}
+
+PulsePort *
+pulse_port_new (const gchar *name,
+ const gchar *label,
+ const gchar *icon,
+ guint priority)
+{
+ PulsePort *port;
+
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (label != NULL, NULL);
+
+ port = g_object_new (PULSE_TYPE_PORT,
+ "name", name,
+ "label", label,
+ "icon", icon,
+ NULL);
+
+ port->priv->priority = priority;
+ return port;
+}
+
+const gchar *
+pulse_port_get_name (PulsePort *port)
+{
+ g_return_val_if_fail (PULSE_IS_PORT (port), NULL);
+
+ return mate_mixer_switch_option_get_name (MATE_MIXER_SWITCH_OPTION (port));
+}
+
+guint
+pulse_port_get_priority (PulsePort *port)
+{
+ g_return_val_if_fail (PULSE_IS_PORT (port), 0);
+
+ return port->priv->priority;
+}
diff --git a/backends/pulse/pulse-port.h b/backends/pulse/pulse-port.h
new file mode 100644
index 0000000..241fa2d
--- /dev/null
+++ b/backends/pulse/pulse-port.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_PORT_H
+#define PULSE_PORT_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_PORT \
+ (pulse_port_get_type ())
+#define PULSE_PORT(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_PORT, PulsePort))
+#define PULSE_IS_PORT(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_PORT))
+#define PULSE_PORT_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_PORT, PulsePortClass))
+#define PULSE_IS_PORT_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_PORT))
+#define PULSE_PORT_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_IS_PORT, PulsePortClass))
+
+typedef struct _PulsePortClass PulsePortClass;
+typedef struct _PulsePortPrivate PulsePortPrivate;
+
+struct _PulsePort
+{
+ MateMixerSwitchOption parent;
+
+ /*< private >*/
+ PulsePortPrivate *priv;
+};
+
+struct _PulsePortClass
+{
+ MateMixerSwitchOptionClass parent;
+};
+
+GType pulse_port_get_type (void) G_GNUC_CONST;
+
+PulsePort * pulse_port_new (const gchar *name,
+ const gchar *label,
+ const gchar *icon,
+ guint priority);
+
+const gchar *pulse_port_get_name (PulsePort *port);
+guint pulse_port_get_priority (PulsePort *port);
+
+G_END_DECLS
+
+#endif /* PULSE_PORT_H */
diff --git a/backends/pulse/pulse-sink-control.c b/backends/pulse/pulse-sink-control.c
new file mode 100644
index 0000000..500cef0
--- /dev/null
+++ b/backends/pulse/pulse-sink-control.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-connection.h"
+#include "pulse-monitor.h"
+#include "pulse-stream-control.h"
+#include "pulse-sink.h"
+#include "pulse-sink-control.h"
+
+static void pulse_sink_control_class_init (PulseSinkControlClass *klass);
+static void pulse_sink_control_init (PulseSinkControl *control);
+
+G_DEFINE_TYPE (PulseSinkControl, pulse_sink_control, PULSE_TYPE_STREAM_CONTROL);
+
+static gboolean pulse_sink_control_set_mute (PulseStreamControl *psc,
+ gboolean mute);
+static gboolean pulse_sink_control_set_volume (PulseStreamControl *psc,
+ pa_cvolume *cvolume);
+static PulseMonitor *pulse_sink_control_create_monitor (PulseStreamControl *psc);
+
+static void
+pulse_sink_control_class_init (PulseSinkControlClass *klass)
+{
+ PulseStreamControlClass *control_class;
+
+ control_class = PULSE_STREAM_CONTROL_CLASS (klass);
+ control_class->set_mute = pulse_sink_control_set_mute;
+ control_class->set_volume = pulse_sink_control_set_volume;
+ control_class->create_monitor = pulse_sink_control_create_monitor;
+}
+
+static void
+pulse_sink_control_init (PulseSinkControl *control)
+{
+}
+
+PulseSinkControl *
+pulse_sink_control_new (PulseSink *sink,
+ const pa_sink_info *info)
+{
+ PulseSinkControl *control;
+ MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_MUTE_READABLE |
+ MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE;
+ MateMixerStreamControlRole role;
+ guint32 index;
+
+ g_return_val_if_fail (PULSE_IS_SINK (sink), NULL);
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (info->active_port != NULL)
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_PORT;
+ else
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_MASTER;
+
+ /* Build the flag list */
+ if (info->flags & PA_SINK_DECIBEL_VOLUME)
+ flags |= MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL;
+
+ index = pulse_sink_get_index_monitor (sink);
+ if (index != PA_INVALID_INDEX)
+ flags |= MATE_MIXER_STREAM_CONTROL_HAS_MONITOR;
+
+ control = g_object_new (PULSE_TYPE_SINK_CONTROL,
+ "name", info->name,
+ "label", info->description,
+ "flags", flags,
+ "role", role,
+ "stream", sink,
+ NULL);
+
+ pulse_sink_control_update (control, info);
+ return control;
+}
+
+void
+pulse_sink_control_update (PulseSinkControl *control, const pa_sink_info *info)
+{
+ g_return_if_fail (PULSE_IS_SINK_CONTROL (control));
+ g_return_if_fail (info != NULL);
+
+ /* Let all the information update before emitting notify signals */
+ g_object_freeze_notify (G_OBJECT (control));
+
+ _mate_mixer_stream_control_set_mute (MATE_MIXER_STREAM_CONTROL (control),
+ info->mute ? TRUE : FALSE);
+
+ pulse_stream_control_set_channel_map (PULSE_STREAM_CONTROL (control),
+ &info->channel_map);
+
+ pulse_stream_control_set_cvolume (PULSE_STREAM_CONTROL (control),
+ &info->volume,
+ info->base_volume);
+
+ g_object_thaw_notify (G_OBJECT (control));
+}
+
+static gboolean
+pulse_sink_control_set_mute (PulseStreamControl *psc, gboolean mute)
+{
+ g_return_val_if_fail (PULSE_IS_SINK_CONTROL (psc), FALSE);
+
+ return pulse_connection_set_sink_mute (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ PULSE_STREAM_CONTROL_GET_STREAM_INDEX (psc),
+ mute);
+}
+
+static gboolean
+pulse_sink_control_set_volume (PulseStreamControl *psc, pa_cvolume *cvolume)
+{
+ g_return_val_if_fail (PULSE_IS_SINK_CONTROL (psc), FALSE);
+ g_return_val_if_fail (cvolume != NULL, FALSE);
+
+ return pulse_connection_set_sink_volume (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ PULSE_STREAM_CONTROL_GET_STREAM_INDEX (psc),
+ cvolume);
+}
+
+static PulseMonitor *
+pulse_sink_control_create_monitor (PulseStreamControl *psc)
+{
+ PulseSink *sink;
+ guint32 index;
+
+ g_return_val_if_fail (PULSE_IS_SINK_CONTROL (psc), NULL);
+
+ sink = PULSE_SINK (mate_mixer_stream_control_get_stream (MATE_MIXER_STREAM_CONTROL (psc)));
+
+ index = pulse_sink_get_index_monitor (sink);
+ if G_UNLIKELY (index == PA_INVALID_INDEX) {
+ g_debug ("Monitor of stream control %s is not available",
+ mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (psc)));
+ return NULL;
+ }
+
+ return pulse_connection_create_monitor (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ index,
+ PA_INVALID_INDEX);
+}
diff --git a/backends/pulse/pulse-sink-control.h b/backends/pulse/pulse-sink-control.h
new file mode 100644
index 0000000..e9570f4
--- /dev/null
+++ b/backends/pulse/pulse-sink-control.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_SINK_CONTROL_H
+#define PULSE_SINK_CONTROL_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-stream-control.h"
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_SINK_CONTROL \
+ (pulse_sink_control_get_type ())
+#define PULSE_SINK_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_SINK_CONTROL, PulseSinkControl))
+#define PULSE_IS_SINK_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_SINK_CONTROL))
+#define PULSE_SINK_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SINK_CONTROL, PulseSinkControlClass))
+#define PULSE_IS_SINK_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SINK_CONTROL))
+#define PULSE_SINK_CONTROL_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SINK_CONTROL, PulseSinkControlClass))
+
+typedef struct _PulseSinkControlClass PulseSinkControlClass;
+typedef struct _PulseSinkControlPrivate PulseSinkControlPrivate;
+
+struct _PulseSinkControl
+{
+ PulseStreamControl parent;
+};
+
+struct _PulseSinkControlClass
+{
+ PulseStreamControlClass parent_class;
+};
+
+GType pulse_sink_control_get_type (void) G_GNUC_CONST;
+
+PulseSinkControl *pulse_sink_control_new (PulseSink *sink,
+ const pa_sink_info *info);
+
+void pulse_sink_control_update (PulseSinkControl *control,
+ const pa_sink_info *info);
+
+G_END_DECLS
+
+#endif /* PULSE_SINK_CONTROL_H */
diff --git a/backends/pulse/pulse-sink-input.c b/backends/pulse/pulse-sink-input.c
index 1d5f9c2..eab85b8 100644
--- a/backends/pulse/pulse-sink-input.c
+++ b/backends/pulse/pulse-sink-input.c
@@ -15,57 +15,41 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#include <string.h>
#include <glib.h>
#include <glib-object.h>
-
-#include <libmatemixer/matemixer-client-stream.h>
-#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
-#include "pulse-client-stream.h"
#include "pulse-helpers.h"
#include "pulse-monitor.h"
#include "pulse-sink.h"
#include "pulse-sink-input.h"
#include "pulse-stream.h"
+#include "pulse-stream-control.h"
static void pulse_sink_input_class_init (PulseSinkInputClass *klass);
static void pulse_sink_input_init (PulseSinkInput *input);
-G_DEFINE_TYPE (PulseSinkInput, pulse_sink_input, PULSE_TYPE_CLIENT_STREAM);
-
-static void pulse_sink_input_reload (PulseStream *pstream);
+G_DEFINE_TYPE (PulseSinkInput, pulse_sink_input, PULSE_TYPE_STREAM_CONTROL);
-static gboolean pulse_sink_input_set_mute (PulseStream *pstream,
- gboolean mute);
-static gboolean pulse_sink_input_set_volume (PulseStream *pstream,
- pa_cvolume *cvolume);
-static gboolean pulse_sink_input_set_parent (PulseClientStream *pclient,
- PulseStream *parent);
-static gboolean pulse_sink_input_remove (PulseClientStream *pclient);
-static PulseMonitor *pulse_sink_input_create_monitor (PulseStream *pstream);
+static gboolean pulse_sink_input_set_mute (PulseStreamControl *psc,
+ gboolean mute);
+static gboolean pulse_sink_input_set_volume (PulseStreamControl *psc,
+ pa_cvolume *cvolume);
+static PulseMonitor *pulse_sink_input_create_monitor (PulseStreamControl *psc);
static void
pulse_sink_input_class_init (PulseSinkInputClass *klass)
{
- PulseStreamClass *stream_class;
- PulseClientStreamClass *client_class;
-
- stream_class = PULSE_STREAM_CLASS (klass);
+ PulseStreamControlClass *control_class;
- stream_class->reload = pulse_sink_input_reload;
- stream_class->set_mute = pulse_sink_input_set_mute;
- stream_class->set_volume = pulse_sink_input_set_volume;
- stream_class->create_monitor = pulse_sink_input_create_monitor;
-
- client_class = PULSE_CLIENT_STREAM_CLASS (klass);
-
- client_class->set_parent = pulse_sink_input_set_parent;
- client_class->remove = pulse_sink_input_remove;
+ control_class = PULSE_STREAM_CONTROL_CLASS (klass);
+ control_class->set_mute = pulse_sink_input_set_mute;
+ control_class->set_volume = pulse_sink_input_set_volume;
+ control_class->create_monitor = pulse_sink_input_create_monitor;
}
static void
@@ -73,230 +57,171 @@ pulse_sink_input_init (PulseSinkInput *input)
{
}
-PulseStream *
-pulse_sink_input_new (PulseConnection *connection,
- const pa_sink_input_info *info,
- PulseStream *parent)
+PulseSinkInput *
+pulse_sink_input_new (PulseSink *sink, const pa_sink_input_info *info)
{
- PulseSinkInput *input;
+ PulseSinkInput *input;
+ gchar *name;
+ const gchar *prop;
+ const gchar *label = NULL;
+ MateMixerAppInfo *app_info = NULL;
- g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
- g_return_val_if_fail (info != NULL, NULL);
+ MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_MUTE_READABLE |
+ MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_MONITOR;
+ MateMixerStreamControlRole role = MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN;
- /* Consider the sink input index as unchanging parameter */
- input = g_object_new (PULSE_TYPE_SINK_INPUT,
- "connection", connection,
- "index", info->index,
- NULL);
+ MateMixerStreamControlMediaRole media_role = MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN;
- /* Other data may change at any time, so let's make a use of our update function */
- pulse_sink_input_update (PULSE_STREAM (input), info, parent);
-
- return PULSE_STREAM (input);
-}
-
-gboolean
-pulse_sink_input_update (PulseStream *pstream,
- const pa_sink_input_info *info,
- PulseStream *parent)
-{
- MateMixerStreamFlags flags = MATE_MIXER_STREAM_OUTPUT |
- MATE_MIXER_STREAM_CLIENT |
- MATE_MIXER_STREAM_HAS_MUTE |
- MATE_MIXER_STREAM_HAS_MONITOR;
- PulseClientStream *pclient;
- const gchar *prop;
- const gchar *description = NULL;
- gchar *name;
-
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (pstream), FALSE);
- g_return_val_if_fail (info != NULL, FALSE);
-
- pclient = PULSE_CLIENT_STREAM (pstream);
-
- /* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (pstream));
+ g_return_val_if_fail (PULSE_IS_SINK (sink), NULL);
+ g_return_val_if_fail (info != NULL, NULL);
/* Many mixer applications query the Pulse client list and use the client
* name here, but we use the name only as an identifier, so let's avoid
* this unnecessary overhead and use a custom name.
* Also make sure to make the name unique by including the PulseAudio index. */
- name = g_strdup_printf ("pulse-stream-client-output-%lu", (gulong) info->index);
-
- pulse_stream_update_name (pstream, name);
- g_free (name);
-
- prop = pa_proplist_gets (info->proplist, PA_PROP_MEDIA_ROLE);
- if (prop != NULL) {
- MateMixerClientStreamRole role = pulse_convert_media_role_name (prop);
-
- if (role == MATE_MIXER_CLIENT_STREAM_ROLE_EVENT) {
- /* The event description seems to provide much better readable
- * description for event streams */
- prop = pa_proplist_gets (info->proplist, PA_PROP_EVENT_DESCRIPTION);
-
- if (G_LIKELY (prop != NULL))
- description = prop;
- }
- pulse_client_stream_update_role (pclient, role);
- } else
- pulse_client_stream_update_role (pclient, MATE_MIXER_CLIENT_STREAM_ROLE_NONE);
-
- if (description == NULL)
- description = info->name;
-
- pulse_stream_update_description (pstream, description);
- pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
-
- if (info->client != PA_INVALID_INDEX)
- pulse_client_stream_update_flags (pclient, MATE_MIXER_CLIENT_STREAM_APPLICATION);
- else
- pulse_client_stream_update_flags (pclient, MATE_MIXER_CLIENT_STREAM_NO_FLAGS);
-
- if (G_LIKELY (parent != NULL)) {
- if (pulse_sink_get_monitor_index (parent) != PA_INVALID_INDEX)
- flags |= MATE_MIXER_STREAM_HAS_MONITOR;
-
- pulse_client_stream_update_parent (pclient, MATE_MIXER_STREAM (parent));
- } else
- pulse_client_stream_update_parent (pclient, NULL);
+ name = g_strdup_printf ("pulse-output-control-%lu", (gulong) info->index);
#if PA_CHECK_VERSION(1, 0, 0)
if (info->has_volume) {
flags |=
- MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME;
+ MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL;
if (info->volume_writable)
- flags |= MATE_MIXER_STREAM_CAN_SET_VOLUME;
+ flags |= MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE;
}
-
- /* Flags needed before volume */
- pulse_stream_update_flags (pstream, flags);
- pulse_stream_update_channel_map (pstream, &info->channel_map);
-
- if (info->has_volume)
- pulse_stream_update_volume (pstream, &info->volume, 0);
- else
- pulse_stream_update_volume (pstream, NULL, 0);
#else
/* Pre-1.0 PulseAudio does not include the has_volume and volume_writable
* fields, but does include the volume info, so let's give it a try */
flags |=
- MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME |
- MATE_MIXER_STREAM_CAN_SET_VOLUME;
+ MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL;
+#endif
- /* Flags needed before volume */
- pulse_stream_update_flags (pstream, flags);
- pulse_stream_update_channel_map (pstream, &info->channel_map);
+ if (info->client != PA_INVALID_INDEX) {
+ app_info = _mate_mixer_app_info_new ();
- pulse_stream_update_volume (pstream, &info->volume, 0);
-#endif
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION;
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_NAME);
- if (prop != NULL)
- pulse_client_stream_update_app_name (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_NAME);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_name (app_info, prop);
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ID);
- if (prop != NULL)
- pulse_client_stream_update_app_id (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ID);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_id (app_info, prop);
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_VERSION);
- if (prop != NULL)
- pulse_client_stream_update_app_version (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_VERSION);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_version (app_info, prop);
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ICON_NAME);
- if (prop != NULL)
- pulse_client_stream_update_app_icon (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ICON_NAME);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_icon (app_info, prop);
+ }
- // XXX needs to fix monitor if parent changes
+ prop = pa_proplist_gets (info->proplist, PA_PROP_MEDIA_ROLE);
+ if (prop != NULL) {
+ media_role = pulse_convert_media_role_name (prop);
- g_object_thaw_notify (G_OBJECT (pstream));
- return TRUE;
-}
+ if (media_role == MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_EVENT) {
+ /* The event description seems to provide much better readable
+ * description for event streams */
+ prop = pa_proplist_gets (info->proplist, PA_PROP_EVENT_DESCRIPTION);
+ if (prop != NULL)
+ label = prop;
+ }
+ }
-static void
-pulse_sink_input_reload (PulseStream *pstream)
-{
- g_return_if_fail (PULSE_IS_SINK_INPUT (pstream));
+ if (label == NULL)
+ label = info->name;
- pulse_connection_load_sink_input_info (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream));
-}
+ input = g_object_new (PULSE_TYPE_SINK_INPUT,
+ "name", name,
+ "label", label,
+ "flags", flags,
+ "role", role,
+ "media-role", media_role,
+ "index", info->index,
+ "stream", sink,
+ NULL);
+ g_free (name);
-static gboolean
-pulse_sink_input_set_mute (PulseStream *pstream, gboolean mute)
-{
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (pstream), FALSE);
+ if (app_info != NULL)
+ pulse_stream_control_set_app_info (PULSE_STREAM_CONTROL (input), app_info);
- return pulse_connection_set_sink_input_mute (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- mute);
+ pulse_sink_input_update (input, info);
+ return input;
}
-static gboolean
-pulse_sink_input_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
+void
+pulse_sink_input_update (PulseSinkInput *input, const pa_sink_input_info *info)
{
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (pstream), FALSE);
- g_return_val_if_fail (cvolume != NULL, FALSE);
+ g_return_if_fail (PULSE_IS_SINK_INPUT (input));
+ g_return_if_fail (info != NULL);
- return pulse_connection_set_sink_input_volume (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- cvolume);
-}
+ /* Let all the information update before emitting notify signals */
+ g_object_freeze_notify (G_OBJECT (input));
-static gboolean
-pulse_sink_input_set_parent (PulseClientStream *pclient, PulseStream *parent)
-{
- PulseStream *pstream;
+ _mate_mixer_stream_control_set_mute (MATE_MIXER_STREAM_CONTROL (input),
+ info->mute ? TRUE : FALSE);
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (pclient), FALSE);
+#if PA_CHECK_VERSION(1, 0, 0)
+ pulse_stream_control_set_channel_map (PULSE_STREAM_CONTROL (input), &info->channel_map);
- pstream = PULSE_STREAM (pclient);
+ if (info->has_volume)
+ pulse_stream_control_set_cvolume (PULSE_STREAM_CONTROL (input), &info->volume, 0);
+ else
+ pulse_stream_control_set_cvolume (PULSE_STREAM_CONTROL (input), NULL, 0);
+#else
+ pulse_stream_control_set_channel_map (PULSE_STREAM_CONTROL (input), &info->channel_map);
+ pulse_stream_control_set_volume (PULSE_STREAM_CONTROL (input), &info->volume, 0);
+#endif
- return pulse_connection_move_sink_input (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- pulse_stream_get_index (parent));
+ g_object_thaw_notify (G_OBJECT (input));
}
static gboolean
-pulse_sink_input_remove (PulseClientStream *pclient)
+pulse_sink_input_set_mute (PulseStreamControl *psc, gboolean mute)
{
- PulseStream *pstream;
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (psc), FALSE);
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (pclient), FALSE);
+ return pulse_connection_set_sink_input_mute (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ pulse_stream_control_get_index (psc),
+ mute);
+}
- pstream = PULSE_STREAM (pclient);
+static gboolean
+pulse_sink_input_set_volume (PulseStreamControl *psc, pa_cvolume *cvolume)
+{
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (psc), FALSE);
+ g_return_val_if_fail (cvolume != NULL, FALSE);
- return pulse_connection_kill_sink_input (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream));
+ return pulse_connection_set_sink_input_volume (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ pulse_stream_control_get_index (psc),
+ cvolume);
}
static PulseMonitor *
-pulse_sink_input_create_monitor (PulseStream *pstream)
+pulse_sink_input_create_monitor (PulseStreamControl *psc)
{
- MateMixerStream *parent;
- guint32 index;
-
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (pstream), NULL);
+ PulseSink *sink;
+ guint32 index;
- parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (pstream));
- if (G_UNLIKELY (parent == NULL)) {
- g_debug ("Not creating monitor for client stream %s as it is not available",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)));
- return NULL;
- }
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (psc), NULL);
- index = pulse_sink_get_monitor_index (PULSE_STREAM (parent));
+ sink = PULSE_SINK (mate_mixer_stream_control_get_stream (MATE_MIXER_STREAM_CONTROL (psc)));
- if (G_UNLIKELY (index == PA_INVALID_INDEX)) {
- g_debug ("Not creating monitor for client stream %s as it is not available",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)));
+ index = pulse_sink_get_index_monitor (sink);
+ if G_UNLIKELY (index == PA_INVALID_INDEX) {
+ g_debug ("Monitor of stream control %s is not available",
+ mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (psc)));
return NULL;
}
- return pulse_connection_create_monitor (pulse_stream_get_connection (pstream),
+ return pulse_connection_create_monitor (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
index,
- pulse_stream_get_index (pstream));
+ pulse_stream_control_get_index (psc));
}
diff --git a/backends/pulse/pulse-sink-input.h b/backends/pulse/pulse-sink-input.h
index 1e5004b..127eab6 100644
--- a/backends/pulse/pulse-sink-input.h
+++ b/backends/pulse/pulse-sink-input.h
@@ -23,9 +23,8 @@
#include <pulse/pulseaudio.h>
-#include "pulse-client-stream.h"
-#include "pulse-connection.h"
-#include "pulse-stream.h"
+#include "pulse-stream-control.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
@@ -42,28 +41,25 @@ G_BEGIN_DECLS
#define PULSE_SINK_INPUT_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SINK_INPUT, PulseSinkInputClass))
-typedef struct _PulseSinkInput PulseSinkInput;
typedef struct _PulseSinkInputClass PulseSinkInputClass;
struct _PulseSinkInput
{
- PulseClientStream parent;
+ PulseStreamControl parent;
};
struct _PulseSinkInputClass
{
- PulseClientStreamClass parent_class;
+ PulseStreamControlClass parent_class;
};
-GType pulse_sink_input_get_type (void) G_GNUC_CONST;
+GType pulse_sink_input_get_type (void) G_GNUC_CONST;
-PulseStream *pulse_sink_input_new (PulseConnection *connection,
- const pa_sink_input_info *info,
- PulseStream *parent);
+PulseSinkInput *pulse_sink_input_new (PulseSink *sink,
+ const pa_sink_input_info *info);
-gboolean pulse_sink_input_update (PulseStream *pstream,
- const pa_sink_input_info *info,
- PulseStream *parent);
+void pulse_sink_input_update (PulseSinkInput *input,
+ const pa_sink_input_info *info);
G_END_DECLS
diff --git a/backends/pulse/pulse-sink-switch.c b/backends/pulse/pulse-sink-switch.c
new file mode 100644
index 0000000..0e08dac
--- /dev/null
+++ b/backends/pulse/pulse-sink-switch.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "pulse-connection.h"
+#include "pulse-port.h"
+#include "pulse-port-switch.h"
+#include "pulse-sink-switch.h"
+#include "pulse-stream.h"
+
+static void pulse_sink_switch_class_init (PulseSinkSwitchClass *klass);
+static void pulse_sink_switch_init (PulseSinkSwitch *swtch);
+
+G_DEFINE_TYPE (PulseSinkSwitch, pulse_sink_switch, PULSE_TYPE_PORT_SWITCH)
+
+static gboolean pulse_sink_switch_set_active_port (PulsePortSwitch *swtch,
+ PulsePort *port);
+
+static void
+pulse_sink_switch_class_init (PulseSinkSwitchClass *klass)
+{
+ PulsePortSwitchClass *switch_class;
+
+ switch_class = PULSE_PORT_SWITCH_CLASS (klass);
+ switch_class->set_active_port = pulse_sink_switch_set_active_port;
+}
+
+static void
+pulse_sink_switch_init (PulseSinkSwitch *swtch)
+{
+}
+
+PulsePortSwitch *
+pulse_sink_switch_new (const gchar *name, const gchar *label, PulseSink *sink)
+{
+ return g_object_new (PULSE_TYPE_SINK_SWITCH,
+ "name", name,
+ "label", label,
+ "role", MATE_MIXER_SWITCH_ROLE_PORT,
+ "stream", sink,
+ NULL);
+}
+
+static gboolean
+pulse_sink_switch_set_active_port (PulsePortSwitch *swtch, PulsePort *port)
+{
+ PulseStream *stream;
+
+ g_return_val_if_fail (PULSE_IS_SINK_SWITCH (swtch), FALSE);
+ g_return_val_if_fail (PULSE_IS_PORT (port), FALSE);
+
+ stream = pulse_port_switch_get_stream (swtch);
+
+ return pulse_connection_set_sink_port (pulse_stream_get_connection (stream),
+ pulse_stream_get_index (stream),
+ pulse_port_get_name (port));
+}
diff --git a/backends/pulse/pulse-sink-switch.h b/backends/pulse/pulse-sink-switch.h
new file mode 100644
index 0000000..71ed4c9
--- /dev/null
+++ b/backends/pulse/pulse-sink-switch.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_SINK_SWITCH_H
+#define PULSE_SINK_SWITCH_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_SINK_SWITCH \
+ (pulse_sink_switch_get_type ())
+#define PULSE_SINK_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_SINK_SWITCH, PulseSinkSwitch))
+#define PULSE_IS_SINK_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_SINK_SWITCH))
+#define PULSE_SINK_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SINK_SWITCH, PulseSinkSwitchClass))
+#define PULSE_IS_SINK_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SINK_SWITCH))
+#define PULSE_SINK_SWITCH_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SINK_SWITCH, PulseSinkSwitchClass))
+
+typedef struct _PulseSinkSwitchClass PulseSinkSwitchClass;
+typedef struct _PulseSinkSwitchPrivate PulseSinkSwitchPrivate;
+
+struct _PulseSinkSwitch
+{
+ PulsePortSwitch parent;
+};
+
+struct _PulseSinkSwitchClass
+{
+ PulsePortSwitchClass parent_class;
+};
+
+GType pulse_sink_switch_get_type (void) G_GNUC_CONST;
+
+PulsePortSwitch *pulse_sink_switch_new (const gchar *name,
+ const gchar *label,
+ PulseSink *sink);
+
+G_END_DECLS
+
+#endif /* PULSE_SINK_SWITCH_H */
diff --git a/backends/pulse/pulse-sink.c b/backends/pulse/pulse-sink.c
index 0f828b1..d2f0280 100644
--- a/backends/pulse/pulse-sink.c
+++ b/backends/pulse/pulse-sink.c
@@ -16,62 +16,57 @@
*/
#include <glib.h>
+#include <glib/gi18n.h>
#include <glib-object.h>
-
-#include <libmatemixer/matemixer-port.h>
-#include <libmatemixer/matemixer-port-private.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
#include "pulse-device.h"
#include "pulse-monitor.h"
+#include "pulse-port.h"
+#include "pulse-port-switch.h"
#include "pulse-stream.h"
#include "pulse-sink.h"
+#include "pulse-sink-control.h"
+#include "pulse-sink-input.h"
+#include "pulse-sink-switch.h"
struct _PulseSinkPrivate
{
- guint32 index_monitor;
+ guint32 monitor;
+ GHashTable *inputs;
+ PulsePortSwitch *pswitch;
+ GList *streams_list;
+ GList *switches_list;
+ PulseSinkControl *control;
};
static void pulse_sink_class_init (PulseSinkClass *klass);
static void pulse_sink_init (PulseSink *sink);
+static void pulse_sink_dispose (GObject *object);
+static void pulse_sink_finalize (GObject *object);
G_DEFINE_TYPE (PulseSink, pulse_sink, PULSE_TYPE_STREAM);
-static void pulse_sink_reload (PulseStream *pstream);
-
-static gboolean pulse_sink_set_mute (PulseStream *pstream,
- gboolean mute);
-static gboolean pulse_sink_set_volume (PulseStream *pstream,
- pa_cvolume *cvolume);
-static gboolean pulse_sink_set_active_port (PulseStream *pstream,
- MateMixerPort *port);
-
-static gboolean pulse_sink_suspend (PulseStream *pstream);
-static gboolean pulse_sink_resume (PulseStream *pstream);
-
-static PulseMonitor *pulse_sink_create_monitor (PulseStream *pstream);
-
-static void update_ports (PulseStream *pstream,
- pa_sink_port_info **ports,
- pa_sink_port_info *active);
+static const GList *pulse_sink_list_controls (MateMixerStream *mms);
+static const GList *pulse_sink_list_switches (MateMixerStream *mms);
static void
pulse_sink_class_init (PulseSinkClass *klass)
{
- PulseStreamClass *stream_class;
+ GObjectClass *object_class;
+ MateMixerStreamClass *stream_class;
- stream_class = PULSE_STREAM_CLASS (klass);
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_sink_dispose;
+ object_class->finalize = pulse_sink_finalize;
- stream_class->reload = pulse_sink_reload;
- stream_class->set_mute = pulse_sink_set_mute;
- stream_class->set_volume = pulse_sink_set_volume;
- stream_class->set_active_port = pulse_sink_set_active_port;
- stream_class->suspend = pulse_sink_suspend;
- stream_class->resume = pulse_sink_resume;
- stream_class->create_monitor = pulse_sink_create_monitor;
+ stream_class = MATE_MIXER_STREAM_CLASS (klass);
+ stream_class->list_controls = pulse_sink_list_controls;
+ stream_class->list_switches = pulse_sink_list_switches;
g_type_class_add_private (klass, sizeof (PulseSinkPrivate));
}
@@ -83,247 +78,190 @@ pulse_sink_init (PulseSink *sink)
PULSE_TYPE_SINK,
PulseSinkPrivate);
- sink->priv->index_monitor = PA_INVALID_INDEX;
+ sink->priv->inputs = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+
+ sink->priv->monitor = PA_INVALID_INDEX;
}
-PulseStream *
-pulse_sink_new (PulseConnection *connection,
- const pa_sink_info *info,
- PulseDevice *device)
+static void
+pulse_sink_dispose (GObject *object)
{
- PulseStream *stream;
+ PulseSink *sink;
- g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
- g_return_val_if_fail (info != NULL, NULL);
+ sink = PULSE_SINK (object);
- /* Consider the sink index as unchanging parameter */
- stream = g_object_new (PULSE_TYPE_SINK,
- "connection", connection,
- "index", info->index,
- NULL);
+ g_clear_object (&sink->priv->control);
+ g_clear_object (&sink->priv->pswitch);
- /* Other data may change at any time, so let's make a use of our update function */
- pulse_sink_update (stream, info, device);
+ g_hash_table_remove_all (sink->priv->inputs);
- return stream;
+ G_OBJECT_CLASS (pulse_sink_parent_class)->dispose (object);
}
-guint32
-pulse_sink_get_monitor_index (PulseStream *pstream)
+static void
+pulse_sink_finalize (GObject *object)
{
- g_return_val_if_fail (PULSE_IS_SINK (pstream), PA_INVALID_INDEX);
+ PulseSink *sink;
+
+ sink = PULSE_SINK (object);
- return PULSE_SINK (pstream)->priv->index_monitor;
+ g_hash_table_unref (sink->priv->inputs);
+
+ G_OBJECT_CLASS (pulse_sink_parent_class)->finalize (object);
}
-gboolean
-pulse_sink_update (PulseStream *pstream, const pa_sink_info *info, PulseDevice *device)
+PulseSink *
+pulse_sink_new (PulseConnection *connection,
+ const pa_sink_info *info,
+ PulseDevice *device)
{
- MateMixerStreamFlags flags = MATE_MIXER_STREAM_OUTPUT |
- MATE_MIXER_STREAM_HAS_MUTE |
- MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_CAN_SET_VOLUME |
- MATE_MIXER_STREAM_CAN_SUSPEND;
PulseSink *sink;
- g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
- g_return_val_if_fail (info != NULL, FALSE);
-
- /* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (pstream));
-
- pulse_stream_update_name (pstream, info->name);
- pulse_stream_update_description (pstream, info->description);
- pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
-
- /* Stream state */
- switch (info->state) {
- case PA_SINK_RUNNING:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_RUNNING);
- break;
- case PA_SINK_IDLE:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_IDLE);
- break;
- case PA_SINK_SUSPENDED:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_SUSPENDED);
- break;
- default:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_UNKNOWN);
- break;
- }
-
- /* Build the flag list */
- if (info->flags & PA_SINK_DECIBEL_VOLUME)
- flags |= MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME;
- if (info->flags & PA_SINK_FLAT_VOLUME)
- flags |= MATE_MIXER_STREAM_HAS_FLAT_VOLUME;
-
- sink = PULSE_SINK (pstream);
-
- if (sink->priv->index_monitor == PA_INVALID_INDEX)
- sink->priv->index_monitor = info->monitor_source;
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (info != NULL, NULL);
- if (sink->priv->index_monitor != PA_INVALID_INDEX)
- flags |= MATE_MIXER_STREAM_HAS_MONITOR;
+ sink = g_object_new (PULSE_TYPE_SINK,
+ "name", info->name,
+ "label", info->description,
+ "device", device,
+ "direction", MATE_MIXER_DIRECTION_OUTPUT,
+ "connection", connection,
+ "index", info->index,
+ NULL);
+
+ sink->priv->control = pulse_sink_control_new (sink, info);
+
+ if (info->n_ports > 0) {
+ pa_sink_port_info **ports = info->ports;
+
+ /* Create the port switch */
+ sink->priv->pswitch = pulse_sink_switch_new ("port", _("Port"), sink);
+
+ while (*ports != NULL) {
+ pa_sink_port_info *p = *ports++;
+ PulsePort *port;
+ const gchar *icon = NULL;
+
+ /* A port may include an icon but in PulseAudio sink and source ports
+ * the property is not included, for this reason ports are also read from
+ * devices where the icons may be present */
+ if (device != NULL) {
+ port = pulse_device_get_port (PULSE_DEVICE (device), p->name);
+ if (port != NULL)
+ icon = mate_mixer_switch_option_get_icon (MATE_MIXER_SWITCH_OPTION (port));
+ }
- /* Flags must be updated before volume */
- pulse_stream_update_flags (pstream, flags);
+ port = pulse_port_new (p->name,
+ p->description,
+ icon,
+ p->priority);
- pulse_stream_update_channel_map (pstream, &info->channel_map);
- pulse_stream_update_volume (pstream, &info->volume, info->base_volume);
+ pulse_port_switch_add_port (sink->priv->pswitch, port);
- pulse_stream_update_device (pstream, MATE_MIXER_DEVICE (device));
+ if (p == info->active_port)
+ pulse_port_switch_set_active_port (sink->priv->pswitch, port);
+ }
- /* Ports must be updated after device */
- if (info->ports != NULL) {
- update_ports (pstream, info->ports, info->active_port);
+ g_debug ("Created port list for sink %s", info->name);
}
- g_object_thaw_notify (G_OBJECT (pstream));
- return TRUE;
-}
-
-static void
-pulse_sink_reload (PulseStream *pstream)
-{
- g_return_if_fail (PULSE_IS_SINK (pstream));
+ pulse_sink_update (sink, info);
- pulse_connection_load_sink_info (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream));
+ _mate_mixer_stream_set_default_control (MATE_MIXER_STREAM (sink),
+ MATE_MIXER_STREAM_CONTROL (sink->priv->control));
+ return sink;
}
-static gboolean
-pulse_sink_set_mute (PulseStream *pstream, gboolean mute)
+void
+pulse_sink_add_input (PulseSink *sink, const pa_sink_input_info *info)
{
- g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
-
- return pulse_connection_set_sink_mute (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- mute);
+ PulseSinkInput *input;
+
+ /* This function is used for both creating and refreshing sink inputs */
+ input = g_hash_table_lookup (sink->priv->inputs, GINT_TO_POINTER (info->index));
+ if (input == NULL) {
+ const gchar *name;
+
+ input = pulse_sink_input_new (sink, info);
+ g_hash_table_insert (sink->priv->inputs,
+ GINT_TO_POINTER (info->index),
+ input);
+
+ name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (input));
+ g_signal_emit_by_name (G_OBJECT (sink),
+ "control-added",
+ name);
+ } else
+ pulse_sink_input_update (input, info);
}
-static gboolean
-pulse_sink_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
+void
+pulse_sink_remove_input (PulseSink *sink, guint32 index)
{
- g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
- g_return_val_if_fail (cvolume != NULL, FALSE);
+ PulseSinkInput *input;
+ const gchar *name;
- return pulse_connection_set_sink_volume (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- cvolume);
-}
+ input = g_hash_table_lookup (sink->priv->inputs, GINT_TO_POINTER (index));
+ if G_UNLIKELY (input == NULL)
+ return;
-static gboolean
-pulse_sink_set_active_port (PulseStream *pstream, MateMixerPort *port)
-{
- g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
+ name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (input));
- return pulse_connection_set_sink_port (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- mate_mixer_port_get_name (port));
+ g_hash_table_remove (sink->priv->inputs, GINT_TO_POINTER (index));
+ g_signal_emit_by_name (G_OBJECT (sink),
+ "control-removed",
+ name);
}
-static gboolean
-pulse_sink_suspend (PulseStream *pstream)
+void
+pulse_sink_update (PulseSink *sink, const pa_sink_info *info)
{
- g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
+ g_return_if_fail (PULSE_IS_SINK (sink));
+ g_return_if_fail (info != NULL);
- return pulse_connection_suspend_sink (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- TRUE);
+ /* The switch doesn't allow being unset, PulseAudio should always include
+ * the active port name if the are any ports available */
+ if (info->active_port != NULL)
+ pulse_port_switch_set_active_port_by_name (sink->priv->pswitch,
+ info->active_port->name);
+
+ sink->priv->monitor = info->monitor_source;
}
-static gboolean
-pulse_sink_resume (PulseStream *pstream)
+guint32
+pulse_sink_get_index_monitor (PulseSink *sink)
{
- g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
+ g_return_val_if_fail (PULSE_IS_SINK (sink), 0);
- return pulse_connection_suspend_sink (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- FALSE);
+ return sink->priv->monitor;
}
-static PulseMonitor *
-pulse_sink_create_monitor (PulseStream *pstream)
+static const GList *
+pulse_sink_list_controls (MateMixerStream *mms)
{
- guint32 index;
+ GList *list;
- g_return_val_if_fail (PULSE_IS_SINK (pstream), NULL);
+ g_return_val_if_fail (PULSE_IS_SINK (mms), NULL);
- index = pulse_sink_get_monitor_index (pstream);
+ // XXX
+ list = g_hash_table_get_values (PULSE_SINK (mms)->priv->inputs);
+ if (list != NULL)
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
- if (G_UNLIKELY (index == PA_INVALID_INDEX)) {
- g_debug ("Not creating monitor for stream %s: not available",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)));
- return NULL;
- }
-
- return pulse_connection_create_monitor (pulse_stream_get_connection (pstream),
- index,
- PA_INVALID_INDEX);
+ return g_list_prepend (list, g_object_ref (PULSE_SINK (mms)->priv->control));
}
-static void
-update_ports (PulseStream *pstream,
- pa_sink_port_info **ports,
- pa_sink_port_info *active)
+static const GList *
+pulse_sink_list_switches (MateMixerStream *mms)
{
- MateMixerPort *port;
- MateMixerDevice *device;
- GHashTable *hash;
-
- hash = pulse_stream_get_ports (pstream);
-
- while (*ports != NULL) {
- MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS;
- pa_sink_port_info *info = *ports;
- const gchar *icon = NULL;
-
- device = mate_mixer_stream_get_device (MATE_MIXER_STREAM (pstream));
- if (device != NULL) {
- port = mate_mixer_device_get_port (device, info->name);
-
- if (port != NULL) {
- flags = mate_mixer_port_get_flags (port);
- icon = mate_mixer_port_get_icon (port);
- }
- }
-
-#if PA_CHECK_VERSION(2, 0, 0)
- if (info->available == PA_PORT_AVAILABLE_YES)
- flags |= MATE_MIXER_PORT_AVAILABLE;
- else
- flags &= ~MATE_MIXER_PORT_AVAILABLE;
-#endif
-
- port = g_hash_table_lookup (hash, info->name);
-
- if (port != NULL) {
- /* Update existing port */
- _mate_mixer_port_update_description (port, info->description);
- _mate_mixer_port_update_icon (port, icon);
- _mate_mixer_port_update_priority (port, info->priority);
- _mate_mixer_port_update_flags (port, flags);
- } else {
- /* Add previously unknown port to the hash table */
- port = _mate_mixer_port_new (info->name,
- info->description,
- icon,
- info->priority,
- flags);
-
- g_hash_table_insert (hash, g_strdup (info->name), port);
- }
-
- ports++;
- }
+ g_return_val_if_fail (PULSE_IS_SINK (mms), NULL);
- /* Active port */
- if (G_LIKELY (active != NULL))
- port = g_hash_table_lookup (hash, active->name);
- else
- port = NULL;
+ // XXX
+ if (PULSE_SINK (mms)->priv->pswitch != NULL)
+ return g_list_prepend (NULL, PULSE_SINK (mms)->priv->pswitch);
- pulse_stream_update_active_port (pstream, port);
+ return NULL;
}
diff --git a/backends/pulse/pulse-sink.h b/backends/pulse/pulse-sink.h
index c0631ca..5eaeaa0 100644
--- a/backends/pulse/pulse-sink.h
+++ b/backends/pulse/pulse-sink.h
@@ -23,9 +23,8 @@
#include <pulse/pulseaudio.h>
-#include "pulse-connection.h"
-#include "pulse-device.h"
#include "pulse-stream.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
@@ -42,7 +41,6 @@ G_BEGIN_DECLS
#define PULSE_SINK_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SINK, PulseSinkClass))
-typedef struct _PulseSink PulseSink;
typedef struct _PulseSinkClass PulseSinkClass;
typedef struct _PulseSinkPrivate PulseSinkPrivate;
@@ -59,17 +57,21 @@ struct _PulseSinkClass
PulseStreamClass parent_class;
};
-GType pulse_sink_get_type (void) G_GNUC_CONST;
+GType pulse_sink_get_type (void) G_GNUC_CONST;
-PulseStream *pulse_sink_new (PulseConnection *connection,
- const pa_sink_info *info,
- PulseDevice *device);
+PulseSink *pulse_sink_new (PulseConnection *connection,
+ const pa_sink_info *info,
+ PulseDevice *device);
-guint32 pulse_sink_get_monitor_index (PulseStream *pstream);
+void pulse_sink_add_input (PulseSink *sink,
+ const pa_sink_input_info *info);
-gboolean pulse_sink_update (PulseStream *pstream,
- const pa_sink_info *info,
- PulseDevice *device);
+void pulse_sink_remove_input (PulseSink *sink, guint32 index);
+
+void pulse_sink_update (PulseSink *sink,
+ const pa_sink_info *info);
+
+guint32 pulse_sink_get_index_monitor (PulseSink *sink);
G_END_DECLS
diff --git a/backends/pulse/pulse-source-control.c b/backends/pulse/pulse-source-control.c
new file mode 100644
index 0000000..3ed1573
--- /dev/null
+++ b/backends/pulse/pulse-source-control.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-connection.h"
+#include "pulse-monitor.h"
+#include "pulse-stream-control.h"
+#include "pulse-source.h"
+#include "pulse-source-control.h"
+
+static void pulse_source_control_class_init (PulseSourceControlClass *klass);
+static void pulse_source_control_init (PulseSourceControl *control);
+
+G_DEFINE_TYPE (PulseSourceControl, pulse_source_control, PULSE_TYPE_STREAM_CONTROL);
+
+static gboolean pulse_source_control_set_mute (PulseStreamControl *psc,
+ gboolean mute);
+static gboolean pulse_source_control_set_volume (PulseStreamControl *psc,
+ pa_cvolume *cvolume);
+static PulseMonitor *pulse_source_control_create_monitor (PulseStreamControl *psc);
+
+static void
+pulse_source_control_class_init (PulseSourceControlClass *klass)
+{
+ PulseStreamControlClass *control_class;
+
+ control_class = PULSE_STREAM_CONTROL_CLASS (klass);
+ control_class->set_mute = pulse_source_control_set_mute;
+ control_class->set_volume = pulse_source_control_set_volume;
+ control_class->create_monitor = pulse_source_control_create_monitor;
+}
+
+static void
+pulse_source_control_init (PulseSourceControl *control)
+{
+}
+
+PulseSourceControl *
+pulse_source_control_new (PulseSource *source,
+ const pa_source_info *info)
+{
+ PulseSourceControl *control;
+ MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_MUTE_READABLE |
+ MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_MONITOR;
+ MateMixerStreamControlRole role;
+
+ g_return_val_if_fail (PULSE_IS_SOURCE (source), NULL);
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (info->active_port != NULL)
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_PORT;
+ else
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_MASTER;
+
+ /* Build the flag list */
+ if (info->flags & PA_SOURCE_DECIBEL_VOLUME)
+ flags |= MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL;
+
+ control = g_object_new (PULSE_TYPE_SOURCE_CONTROL,
+ "name", info->name,
+ "label", info->description,
+ "flags", flags,
+ "role", role,
+ "stream", source,
+ NULL);
+
+ pulse_source_control_update (control, info);
+ return control;
+}
+
+void
+pulse_source_control_update (PulseSourceControl *control, const pa_source_info *info)
+{
+ g_return_if_fail (PULSE_IS_SOURCE_CONTROL (control));
+ g_return_if_fail (info != NULL);
+
+ /* Let all the information update before emitting notify signals */
+ g_object_freeze_notify (G_OBJECT (control));
+
+ _mate_mixer_stream_control_set_mute (MATE_MIXER_STREAM_CONTROL (control),
+ info->mute ? TRUE : FALSE);
+
+ pulse_stream_control_set_channel_map (PULSE_STREAM_CONTROL (control),
+ &info->channel_map);
+
+ pulse_stream_control_set_cvolume (PULSE_STREAM_CONTROL (control),
+ &info->volume,
+ info->base_volume);
+
+ g_object_thaw_notify (G_OBJECT (control));
+}
+
+static gboolean
+pulse_source_control_set_mute (PulseStreamControl *psc, gboolean mute)
+{
+ g_return_val_if_fail (PULSE_IS_SOURCE_CONTROL (psc), FALSE);
+
+ return pulse_connection_set_source_mute (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ PULSE_STREAM_CONTROL_GET_STREAM_INDEX (psc),
+ mute);
+}
+
+static gboolean
+pulse_source_control_set_volume (PulseStreamControl *psc, pa_cvolume *cvolume)
+{
+ g_return_val_if_fail (PULSE_IS_SOURCE_CONTROL (psc), FALSE);
+ g_return_val_if_fail (cvolume != NULL, FALSE);
+
+ return pulse_connection_set_source_volume (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ PULSE_STREAM_CONTROL_GET_STREAM_INDEX (psc),
+ cvolume);
+}
+
+static PulseMonitor *
+pulse_source_control_create_monitor (PulseStreamControl *psc)
+{
+ guint32 index;
+
+ g_return_val_if_fail (PULSE_IS_SOURCE_CONTROL (psc), NULL);
+
+ index = PULSE_STREAM_CONTROL_GET_STREAM_INDEX (psc);
+ if G_UNLIKELY (index == PA_INVALID_INDEX) {
+ g_debug ("Monitor of stream control %s is not available",
+ mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (psc)));
+ return NULL;
+ }
+
+ return pulse_connection_create_monitor (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ index,
+ PA_INVALID_INDEX);
+}
diff --git a/backends/pulse/pulse-source-control.h b/backends/pulse/pulse-source-control.h
new file mode 100644
index 0000000..a8d659f
--- /dev/null
+++ b/backends/pulse/pulse-source-control.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_SOURCE_CONTROL_H
+#define PULSE_SOURCE_CONTROL_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-stream-control.h"
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_SOURCE_CONTROL \
+ (pulse_source_control_get_type ())
+#define PULSE_SOURCE_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_SOURCE_CONTROL, PulseSourceControl))
+#define PULSE_IS_SOURCE_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_SOURCE_CONTROL))
+#define PULSE_SOURCE_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SOURCE_CONTROL, PulseSourceControlClass))
+#define PULSE_IS_SOURCE_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SOURCE_CONTROL))
+#define PULSE_SOURCE_CONTROL_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SOURCE_CONTROL, PulseSourceControlClass))
+
+typedef struct _PulseSourceControlClass PulseSourceControlClass;
+typedef struct _PulseSourceControlPrivate PulseSourceControlPrivate;
+
+struct _PulseSourceControl
+{
+ PulseStreamControl parent;
+};
+
+struct _PulseSourceControlClass
+{
+ PulseStreamControlClass parent_class;
+};
+
+GType pulse_source_control_get_type (void) G_GNUC_CONST;
+
+PulseSourceControl *pulse_source_control_new (PulseSource *source,
+ const pa_source_info *info);
+
+void pulse_source_control_update (PulseSourceControl *control,
+ const pa_source_info *info);
+
+G_END_DECLS
+
+#endif /* PULSE_SOURCE_CONTROL_H */
diff --git a/backends/pulse/pulse-source-output.c b/backends/pulse/pulse-source-output.c
index 6cbd888..69fc3e4 100644
--- a/backends/pulse/pulse-source-output.c
+++ b/backends/pulse/pulse-source-output.c
@@ -17,56 +17,39 @@
#include <glib.h>
#include <glib-object.h>
-#include <string.h>
-
-#include <libmatemixer/matemixer-client-stream.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
-#include "pulse-client-stream.h"
#include "pulse-helpers.h"
#include "pulse-monitor.h"
-#include "pulse-stream.h"
#include "pulse-source.h"
#include "pulse-source-output.h"
+#include "pulse-stream.h"
+#include "pulse-stream-control.h"
static void pulse_source_output_class_init (PulseSourceOutputClass *klass);
static void pulse_source_output_init (PulseSourceOutput *output);
-G_DEFINE_TYPE (PulseSourceOutput, pulse_source_output, PULSE_TYPE_CLIENT_STREAM);
-
-static void pulse_source_output_reload (PulseStream *pstream);
-
-static gboolean pulse_source_output_set_mute (PulseStream *pstream,
- gboolean mute);
-static gboolean pulse_source_output_set_volume (PulseStream *pstream,
- pa_cvolume *cvolume);
+G_DEFINE_TYPE (PulseSourceOutput, pulse_source_output, PULSE_TYPE_STREAM_CONTROL);
-static gboolean pulse_source_output_set_parent (PulseClientStream *pclient,
- PulseStream *parent);
-static gboolean pulse_source_output_remove (PulseClientStream *pclient);
-
-static PulseMonitor *pulse_source_output_create_monitor (PulseStream *pstream);
+static gboolean pulse_source_output_set_mute (PulseStreamControl *psc,
+ gboolean mute);
+static gboolean pulse_source_output_set_volume (PulseStreamControl *psc,
+ pa_cvolume *cvolume);
+static PulseMonitor *pulse_source_output_create_monitor (PulseStreamControl *psc);
static void
pulse_source_output_class_init (PulseSourceOutputClass *klass)
{
- PulseStreamClass *stream_class;
- PulseClientStreamClass *client_class;
-
- stream_class = PULSE_STREAM_CLASS (klass);
-
- stream_class->reload = pulse_source_output_reload;
- stream_class->set_mute = pulse_source_output_set_mute;
- stream_class->set_volume = pulse_source_output_set_volume;
- stream_class->create_monitor = pulse_source_output_create_monitor;
-
- client_class = PULSE_CLIENT_STREAM_CLASS (klass);
+ PulseStreamControlClass *control_class;
- client_class->set_parent = pulse_source_output_set_parent;
- client_class->remove = pulse_source_output_remove;
+ control_class = PULSE_STREAM_CONTROL_CLASS (klass);
+ control_class->set_mute = pulse_source_output_set_mute;
+ control_class->set_volume = pulse_source_output_set_volume;
+ control_class->create_monitor = pulse_source_output_create_monitor;
}
static void
@@ -74,210 +57,157 @@ pulse_source_output_init (PulseSourceOutput *output)
{
}
-PulseStream *
-pulse_source_output_new (PulseConnection *connection,
- const pa_source_output_info *info,
- PulseStream *parent)
+PulseSourceOutput *
+pulse_source_output_new (PulseSource *source,
+ const pa_source_output_info *info)
{
PulseSourceOutput *output;
+ gchar *name;
+ const gchar *prop;
+ MateMixerAppInfo *app_info = NULL;
- g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
- g_return_val_if_fail (info != NULL, NULL);
-
- /* Consider the sink input index as unchanging parameter */
- output = g_object_new (PULSE_TYPE_SOURCE_OUTPUT,
- "connection", connection,
- "index", info->index,
- NULL);
-
- /* Other data may change at any time, so let's make a use of our update function */
- pulse_source_output_update (PULSE_STREAM (output), info, parent);
+ MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_MUTE_READABLE |
+ MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_MONITOR;
+ MateMixerStreamControlRole role = MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN;
- return PULSE_STREAM (output);
-}
+ MateMixerStreamControlMediaRole media_role = MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN;
-gboolean
-pulse_source_output_update (PulseStream *pstream,
- const pa_source_output_info *info,
- PulseStream *parent)
-{
- MateMixerStreamFlags flags = MATE_MIXER_STREAM_INPUT |
- MATE_MIXER_STREAM_CLIENT;
- PulseClientStream *pclient;
- const gchar *prop;
- const gchar *description = NULL;
- gchar *name;
+ g_return_val_if_fail (PULSE_IS_SOURCE (source), NULL);
+ g_return_val_if_fail (info != NULL, NULL);
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pstream), FALSE);
- g_return_val_if_fail (info != NULL, FALSE);
+ /* Many mixer applications query the Pulse client list and use the client
+ * name here, but we use the name only as an identifier, so let's avoid
+ * this unnecessary overhead and use a custom name.
+ * Also make sure to make the name unique by including the PulseAudio index. */
+ name = g_strdup_printf ("pulse-input-control-%lu", (gulong) info->index);
- pclient = PULSE_CLIENT_STREAM (pstream);
+#if PA_CHECK_VERSION(1, 0, 0)
+ if (info->has_volume) {
+ flags |=
+ MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL;
- /* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (pstream));
+ if (info->volume_writable)
+ flags |= MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE;
+ }
+#else
+ /* Pre-1.0 PulseAudio does not include the has_volume and volume_writable
+ * fields, but does include the volume info, so let's give it a try */
+ flags |=
+ MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL;
+#endif
- /* Many other mixer applications query the Pulse client list and use the
- * client name here, but we use the name only as an identifier, so let's avoid
- * this unnecessary overhead and use a custom name.
- * Also make sure to make the name unique by including the Pulse index. */
- name = g_strdup_printf ("pulse-stream-client-input-%lu", (gulong) info->index);
+ if (info->client != PA_INVALID_INDEX) {
+ app_info = _mate_mixer_app_info_new ();
- pulse_stream_update_name (pstream, name);
- g_free (name);
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION;
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_NAME);
- if (prop != NULL)
- pulse_client_stream_update_app_name (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_NAME);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_name (app_info, prop);
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ID);
- if (prop != NULL)
- pulse_client_stream_update_app_id (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ID);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_id (app_info, prop);
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_VERSION);
- if (prop != NULL)
- pulse_client_stream_update_app_version (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_VERSION);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_version (app_info, prop);
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ICON_NAME);
- if (prop != NULL)
- pulse_client_stream_update_app_icon (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ICON_NAME);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_icon (app_info, prop);
+ }
prop = pa_proplist_gets (info->proplist, PA_PROP_MEDIA_ROLE);
- if (prop != NULL) {
- MateMixerClientStreamRole role = pulse_convert_media_role_name (prop);
+ if (prop != NULL)
+ media_role = pulse_convert_media_role_name (prop);
- if (role == MATE_MIXER_CLIENT_STREAM_ROLE_EVENT) {
- /* The event description seems to provide much better readable
- * description for event streams */
- prop = pa_proplist_gets (info->proplist, PA_PROP_EVENT_DESCRIPTION);
+ output = g_object_new (PULSE_TYPE_SOURCE_OUTPUT,
+ "name", name,
+ "label", info->name,
+ "flags", flags,
+ "role", role,
+ "media-role", media_role,
+ "index", info->index,
+ "stream", source,
+ NULL);
+ g_free (name);
- if (G_LIKELY (prop != NULL))
- description = prop;
- }
- pulse_client_stream_update_role (pclient, role);
- } else
- pulse_client_stream_update_role (pclient, MATE_MIXER_CLIENT_STREAM_ROLE_NONE);
+ if (app_info != NULL)
+ pulse_stream_control_set_app_info (PULSE_STREAM_CONTROL (output), app_info);
- if (description == NULL)
- description = info->name;
+ pulse_source_output_update (output, info);
+ return output;
+}
- pulse_stream_update_description (pstream, description);
+void
+pulse_source_output_update (PulseSourceOutput *output,
+ const pa_source_output_info *info)
+{
+ g_return_if_fail (PULSE_IS_SOURCE_OUTPUT (output));
+ g_return_if_fail (info != NULL);
- if (info->client != PA_INVALID_INDEX)
- pulse_client_stream_update_flags (pclient, MATE_MIXER_CLIENT_STREAM_APPLICATION);
- else
- pulse_client_stream_update_flags (pclient, MATE_MIXER_CLIENT_STREAM_NO_FLAGS);
+ /* Let all the information update before emitting notify signals */
+ g_object_freeze_notify (G_OBJECT (output));
- if (G_LIKELY (parent != NULL)) {
- pulse_client_stream_update_parent (pclient, MATE_MIXER_STREAM (parent));
- flags |= MATE_MIXER_STREAM_HAS_MONITOR;
- } else
- pulse_client_stream_update_parent (pclient, NULL);
+ _mate_mixer_stream_control_set_mute (MATE_MIXER_STREAM_CONTROL (output),
+ info->mute ? TRUE : FALSE);
#if PA_CHECK_VERSION(1, 0, 0)
- if (info->has_volume) {
- flags |= MATE_MIXER_STREAM_HAS_VOLUME;
-
- if (info->volume_writable)
- flags |= MATE_MIXER_STREAM_CAN_SET_VOLUME;
- }
-
- flags |= MATE_MIXER_STREAM_HAS_MUTE;
-
- /* Flags needed before volume */
- pulse_stream_update_flags (pstream, flags);
- pulse_stream_update_channel_map (pstream, &info->channel_map);
- pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
+ pulse_stream_control_set_channel_map (PULSE_STREAM_CONTROL (output),
+ &info->channel_map);
if (info->has_volume)
- pulse_stream_update_volume (pstream, &info->volume, 0);
+ pulse_stream_control_set_cvolume (PULSE_STREAM_CONTROL (output),
+ &info->volume,
+ 0);
else
- pulse_stream_update_volume (pstream, NULL, 0);
+ pulse_stream_control_set_cvolume (PULSE_STREAM_CONTROL (output),
+ NULL,
+ 0);
#else
- /* Flags needed before volume */
- pulse_stream_update_flags (pstream, flags);
+ pulse_stream_control_set_channel_map (PULSE_STREAM_CONTROL (output),
+ &info->channel_map);
- pulse_stream_update_channel_map (pstream, &info->channel_map);
- pulse_stream_update_volume (pstream, NULL, 0);
+ pulse_stream_control_set_volume (PULSE_STREAM_CONTROL (output),
+ &info->volume,
+ 0);
#endif
- // XXX needs to fix monitor if parent changes
-
- g_object_thaw_notify (G_OBJECT (pstream));
- return TRUE;
-}
-
-static void
-pulse_source_output_reload (PulseStream *pstream)
-{
- g_return_if_fail (PULSE_IS_SOURCE_OUTPUT (pstream));
-
- pulse_connection_load_source_output_info (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream));
+ g_object_thaw_notify (G_OBJECT (output));
}
static gboolean
-pulse_source_output_set_mute (PulseStream *pstream, gboolean mute)
+pulse_source_output_set_mute (PulseStreamControl *psc, gboolean mute)
{
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pstream), FALSE);
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (psc), FALSE);
- return pulse_connection_set_source_output_mute (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
+ return pulse_connection_set_source_output_mute (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ pulse_stream_control_get_index (psc),
mute);
}
static gboolean
-pulse_source_output_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
+pulse_source_output_set_volume (PulseStreamControl *psc, pa_cvolume *cvolume)
{
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pstream), FALSE);
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (psc), FALSE);
g_return_val_if_fail (cvolume != NULL, FALSE);
- return pulse_connection_set_source_output_volume (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
+ return pulse_connection_set_source_output_volume (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ pulse_stream_control_get_index (psc),
cvolume);
}
-static gboolean
-pulse_source_output_set_parent (PulseClientStream *pclient, PulseStream *parent)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pclient), FALSE);
-
- pstream = PULSE_STREAM (pclient);
-
- return pulse_connection_move_sink_input (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- pulse_stream_get_index (parent));
-}
-
-static gboolean
-pulse_source_output_remove (PulseClientStream *pclient)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pclient), FALSE);
-
- pstream = PULSE_STREAM (pclient);
-
- return pulse_connection_kill_source_output (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream));
-}
-
static PulseMonitor *
-pulse_source_output_create_monitor (PulseStream *pstream)
+pulse_source_output_create_monitor (PulseStreamControl *psc)
{
- MateMixerStream *parent;
-
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pstream), NULL);
-
- parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (pstream));
- if (G_UNLIKELY (parent == NULL)) {
- g_debug ("Not creating monitor for client stream %s: not available",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)));
- return NULL;
- }
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (psc), NULL);
- return pulse_connection_create_monitor (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (PULSE_STREAM (parent)),
+ return pulse_connection_create_monitor (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ PULSE_STREAM_CONTROL_GET_STREAM_INDEX (psc),
PA_INVALID_INDEX);
}
diff --git a/backends/pulse/pulse-source-output.h b/backends/pulse/pulse-source-output.h
index 845d439..1037f94 100644
--- a/backends/pulse/pulse-source-output.h
+++ b/backends/pulse/pulse-source-output.h
@@ -23,48 +23,43 @@
#include <pulse/pulseaudio.h>
-#include "pulse-client-stream.h"
-#include "pulse-connection.h"
-#include "pulse-stream.h"
+#include "pulse-stream-control.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
-#define PULSE_TYPE_SOURCE_OUTPUT \
+#define PULSE_TYPE_SOURCE_OUTPUT \
(pulse_source_output_get_type ())
-#define PULSE_SOURCE_OUTPUT(o) \
+#define PULSE_SOURCE_OUTPUT(o) \
(G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_SOURCE_OUTPUT, PulseSourceOutput))
-#define PULSE_IS_SOURCE_OUTPUT(o) \
+#define PULSE_IS_SOURCE_OUTPUT(o) \
(G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_SOURCE_OUTPUT))
-#define PULSE_SOURCE_OUTPUT_CLASS(k) \
+#define PULSE_SOURCE_OUTPUT_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SOURCE_OUTPUT, PulseSourceOutputClass))
-#define PULSE_IS_SOURCE_OUTPUT_CLASS(k) \
+#define PULSE_IS_SOURCE_OUTPUT_CLASS(k) \
(G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SOURCE_OUTPUT))
-#define PULSE_SOURCE_OUTPUT_GET_CLASS(o) \
+#define PULSE_SOURCE_OUTPUT_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SOURCE_OUTPUT, PulseSourceOutputClass))
-typedef struct _PulseSourceOutput PulseSourceOutput;
-typedef struct _PulseSourceOutputClass PulseSourceOutputClass;
-typedef struct _PulseSourceOutputPrivate PulseSourceOutputPrivate;
+typedef struct _PulseSourceOutputClass PulseSourceOutputClass;
struct _PulseSourceOutput
{
- PulseClientStream parent;
+ PulseStreamControl parent;
};
struct _PulseSourceOutputClass
{
- PulseClientStreamClass parent_class;
+ PulseStreamControlClass parent_class;
};
-GType pulse_source_output_get_type (void) G_GNUC_CONST;
+GType pulse_source_output_get_type (void) G_GNUC_CONST;
-PulseStream *pulse_source_output_new (PulseConnection *connection,
- const pa_source_output_info *info,
- PulseStream *parent);
+PulseSourceOutput *pulse_source_output_new (PulseSource *source,
+ const pa_source_output_info *info);
-gboolean pulse_source_output_update (PulseStream *pstream,
- const pa_source_output_info *info,
- PulseStream *parent);
+void pulse_source_output_update (PulseSourceOutput *output,
+ const pa_source_output_info *info);
G_END_DECLS
diff --git a/backends/pulse/pulse-source-switch.c b/backends/pulse/pulse-source-switch.c
new file mode 100644
index 0000000..178702e
--- /dev/null
+++ b/backends/pulse/pulse-source-switch.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "pulse-connection.h"
+#include "pulse-port.h"
+#include "pulse-port-switch.h"
+#include "pulse-source-switch.h"
+#include "pulse-stream.h"
+
+static void pulse_source_switch_class_init (PulseSourceSwitchClass *klass);
+static void pulse_source_switch_init (PulseSourceSwitch *swtch);
+
+G_DEFINE_TYPE (PulseSourceSwitch, pulse_source_switch, PULSE_TYPE_PORT_SWITCH)
+
+static gboolean pulse_source_switch_set_active_port (PulsePortSwitch *swtch,
+ PulsePort *port);
+
+static void
+pulse_source_switch_class_init (PulseSourceSwitchClass *klass)
+{
+ PulsePortSwitchClass *switch_class;
+
+ switch_class = PULSE_PORT_SWITCH_CLASS (klass);
+ switch_class->set_active_port = pulse_source_switch_set_active_port;
+}
+
+static void
+pulse_source_switch_init (PulseSourceSwitch *swtch)
+{
+}
+
+PulsePortSwitch *
+pulse_source_switch_new (const gchar *name, const gchar *label, PulseSource *source)
+{
+ return g_object_new (PULSE_TYPE_SOURCE_SWITCH,
+ "name", name,
+ "label", label,
+ "role", MATE_MIXER_SWITCH_ROLE_PORT,
+ "stream", source,
+ NULL);
+}
+
+static gboolean
+pulse_source_switch_set_active_port (PulsePortSwitch *swtch, PulsePort *port)
+{
+ PulseStream *stream;
+
+ g_return_val_if_fail (PULSE_IS_SOURCE_SWITCH (swtch), FALSE);
+ g_return_val_if_fail (PULSE_IS_PORT (port), FALSE);
+
+ stream = pulse_port_switch_get_stream (swtch);
+
+ return pulse_connection_set_source_port (pulse_stream_get_connection (stream),
+ pulse_stream_get_index (stream),
+ pulse_port_get_name (port));
+}
diff --git a/backends/pulse/pulse-source-switch.h b/backends/pulse/pulse-source-switch.h
new file mode 100644
index 0000000..408e872
--- /dev/null
+++ b/backends/pulse/pulse-source-switch.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_SOURCE_SWITCH_H
+#define PULSE_SOURCE_SWITCH_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_SOURCE_SWITCH \
+ (pulse_source_switch_get_type ())
+#define PULSE_SOURCE_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_SOURCE_SWITCH, PulseSourceSwitch))
+#define PULSE_IS_SOURCE_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_SOURCE_SWITCH))
+#define PULSE_SOURCE_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SOURCE_SWITCH, PulseSourceSwitchClass))
+#define PULSE_IS_SOURCE_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SOURCE_SWITCH))
+#define PULSE_SOURCE_SWITCH_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SOURCE_SWITCH, PulseSourceSwitchClass))
+
+typedef struct _PulseSourceSwitchClass PulseSourceSwitchClass;
+typedef struct _PulseSourceSwitchPrivate PulseSourceSwitchPrivate;
+
+struct _PulseSourceSwitch
+{
+ PulsePortSwitch parent;
+};
+
+struct _PulseSourceSwitchClass
+{
+ PulsePortSwitchClass parent_class;
+};
+
+GType pulse_source_switch_get_type (void) G_GNUC_CONST;
+
+PulsePortSwitch *pulse_source_switch_new (const gchar *name,
+ const gchar *label,
+ PulseSource *source);
+
+G_END_DECLS
+
+#endif /* PULSE_SOURCE_SWITCH_H */
diff --git a/backends/pulse/pulse-source.c b/backends/pulse/pulse-source.c
index e7dce6f..0d095a7 100644
--- a/backends/pulse/pulse-source.c
+++ b/backends/pulse/pulse-source.c
@@ -16,253 +16,238 @@
*/
#include <glib.h>
+#include <glib/gi18n.h>
#include <glib-object.h>
-
-#include <libmatemixer/matemixer-port.h>
-#include <libmatemixer/matemixer-port-private.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
#include "pulse-device.h"
#include "pulse-monitor.h"
+#include "pulse-port.h"
+#include "pulse-port-switch.h"
#include "pulse-stream.h"
#include "pulse-source.h"
+#include "pulse-source-control.h"
+#include "pulse-source-output.h"
+#include "pulse-source-switch.h"
+
+struct _PulseSourcePrivate
+{
+ GHashTable *outputs;
+ PulsePortSwitch *pswitch;
+ PulseSourceControl *control;
+};
static void pulse_source_class_init (PulseSourceClass *klass);
static void pulse_source_init (PulseSource *source);
+static void pulse_source_dispose (GObject *object);
+static void pulse_source_finalize (GObject *object);
G_DEFINE_TYPE (PulseSource, pulse_source, PULSE_TYPE_STREAM);
-static void pulse_source_reload (PulseStream *pstream);
+static const GList *pulse_source_list_controls (MateMixerStream *mms);
+static const GList *pulse_source_list_switches (MateMixerStream *mms);
-static gboolean pulse_source_set_mute (PulseStream *pstream,
- gboolean mute);
-static gboolean pulse_source_set_volume (PulseStream *pstream,
- pa_cvolume *cvolume);
-static gboolean pulse_source_set_active_port (PulseStream *pstream,
- MateMixerPort *port);
+static void
+pulse_source_class_init (PulseSourceClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerStreamClass *stream_class;
-static PulseMonitor *pulse_source_create_monitor (PulseStream *pstream);
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_source_dispose;
+ object_class->finalize = pulse_source_finalize;
-static void update_ports (PulseStream *pstream,
- pa_source_port_info **ports,
- pa_source_port_info *active);
+ stream_class = MATE_MIXER_STREAM_CLASS (klass);
+ stream_class->list_controls = pulse_source_list_controls;
+ stream_class->list_switches = pulse_source_list_switches;
+
+ g_type_class_add_private (klass, sizeof (PulseSourcePrivate));
+}
static void
-pulse_source_class_init (PulseSourceClass *klass)
+pulse_source_init (PulseSource *source)
+{
+ source->priv = G_TYPE_INSTANCE_GET_PRIVATE (source,
+ PULSE_TYPE_SOURCE,
+ PulseSourcePrivate);
+
+ source->priv->outputs = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+}
+
+static void
+pulse_source_dispose (GObject *object)
{
- PulseStreamClass *stream_class;
+ PulseSource *source;
- stream_class = PULSE_STREAM_CLASS (klass);
+ source = PULSE_SOURCE (object);
- stream_class->reload = pulse_source_reload;
- stream_class->set_mute = pulse_source_set_mute;
- stream_class->set_volume = pulse_source_set_volume;
- stream_class->set_active_port = pulse_source_set_active_port;
- stream_class->create_monitor = pulse_source_create_monitor;
+ g_clear_object (&source->priv->control);
+ g_clear_object (&source->priv->pswitch);
+
+ g_hash_table_remove_all (source->priv->outputs);
+
+ G_OBJECT_CLASS (pulse_source_parent_class)->dispose (object);
}
static void
-pulse_source_init (PulseSource *source)
+pulse_source_finalize (GObject *object)
{
+ PulseSource *source;
+
+ source = PULSE_SOURCE (object);
+
+ g_hash_table_unref (source->priv->outputs);
+
+ G_OBJECT_CLASS (pulse_source_parent_class)->finalize (object);
}
-PulseStream *
+PulseSource *
pulse_source_new (PulseConnection *connection,
const pa_source_info *info,
PulseDevice *device)
{
- PulseStream *stream;
+ PulseSource *source;
g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (info != NULL, NULL);
- /* Consider the sink index as unchanging parameter */
- stream = g_object_new (PULSE_TYPE_SOURCE,
+ source = g_object_new (PULSE_TYPE_SOURCE,
+ "name", info->name,
+ "label", info->description,
+ "device", device,
+ "direction", MATE_MIXER_DIRECTION_INPUT,
"connection", connection,
"index", info->index,
NULL);
- /* Other data may change at any time, so let's make a use of our update function */
- pulse_source_update (stream, info, device);
+ source->priv->control = pulse_source_control_new (source, info);
- return stream;
-}
+ if (info->n_ports > 0) {
+ pa_source_port_info **ports = info->ports;
-gboolean
-pulse_source_update (PulseStream *pstream,
- const pa_source_info *info,
- PulseDevice *device)
-{
- MateMixerStreamFlags flags = MATE_MIXER_STREAM_INPUT |
- MATE_MIXER_STREAM_HAS_MUTE |
- MATE_MIXER_STREAM_HAS_MONITOR |
- MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_CAN_SET_VOLUME |
- MATE_MIXER_STREAM_CAN_SUSPEND;
-
- g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
- g_return_val_if_fail (info != NULL, FALSE);
-
- /* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (pstream));
-
- pulse_stream_update_name (pstream, info->name);
- pulse_stream_update_description (pstream, info->description);
- pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
-
- /* Stream state */
- switch (info->state) {
- case PA_SOURCE_RUNNING:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_RUNNING);
- break;
- case PA_SOURCE_IDLE:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_IDLE);
- break;
- case PA_SOURCE_SUSPENDED:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_SUSPENDED);
- break;
- default:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_UNKNOWN);
- break;
- }
+ /* Create the port switch */
+ source->priv->pswitch = pulse_source_switch_new ("port", _("Port"), source);
+
+ while (*ports != NULL) {
+ pa_source_port_info *p = *ports++;
+ PulsePort *port;
+ const gchar *icon = NULL;
- /* Build the flag list */
- if (info->flags & PA_SINK_DECIBEL_VOLUME)
- flags |= MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME;
- if (info->flags & PA_SINK_FLAT_VOLUME)
- flags |= MATE_MIXER_STREAM_HAS_FLAT_VOLUME;
+ /* A port may include an icon but in PulseAudio sink and source ports
+ * the property is not included, for this reason ports are also read from
+ * devices where the icons may be present */
+ if (device != NULL) {
+ port = pulse_device_get_port (PULSE_DEVICE (device), p->name);
+ if (port != NULL)
+ icon = mate_mixer_switch_option_get_icon (MATE_MIXER_SWITCH_OPTION (port));
+ }
- /* Flags must be updated before volume */
- pulse_stream_update_flags (pstream, flags);
+ port = pulse_port_new (p->name,
+ p->description,
+ icon,
+ p->priority);
- pulse_stream_update_channel_map (pstream, &info->channel_map);
- pulse_stream_update_volume (pstream, &info->volume, info->base_volume);
+ pulse_port_switch_add_port (source->priv->pswitch, port);
- pulse_stream_update_device (pstream, MATE_MIXER_DEVICE (device));
+ if (p == info->active_port)
+ pulse_port_switch_set_active_port (source->priv->pswitch, port);
+ }
- /* Ports must be updated after device */
- if (info->ports != NULL) {
- update_ports (pstream, info->ports, info->active_port);
+ g_debug ("Created port list for source %s", info->name);
}
- g_object_thaw_notify (G_OBJECT (pstream));
- return TRUE;
-}
+ pulse_source_update (source, info);
-static void
-pulse_source_reload (PulseStream *pstream)
-{
- g_return_if_fail (PULSE_IS_SOURCE (pstream));
-
- pulse_connection_load_source_info (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream));
+ _mate_mixer_stream_set_default_control (MATE_MIXER_STREAM (source),
+ MATE_MIXER_STREAM_CONTROL (source->priv->control));
+ return source;
}
-static gboolean
-pulse_source_set_mute (PulseStream *pstream, gboolean mute)
+void
+pulse_source_add_output (PulseSource *source, const pa_source_output_info *info)
{
- g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
-
- return pulse_connection_set_source_mute (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- mute);
+ PulseSourceOutput *output;
+
+ /* This function is used for both creating and refreshing source outputs */
+ output = g_hash_table_lookup (source->priv->outputs, GINT_TO_POINTER (info->index));
+ if (output == NULL) {
+ const gchar *name;
+
+ output = pulse_source_output_new (source, info);
+ g_hash_table_insert (source->priv->outputs,
+ GINT_TO_POINTER (info->index),
+ output);
+
+ name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (output));
+ g_signal_emit_by_name (G_OBJECT (source),
+ "control-added",
+ name);
+ } else
+ pulse_source_output_update (output, info);
}
-static gboolean
-pulse_source_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
+void
+pulse_source_remove_output (PulseSource *source, guint32 index)
{
- g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
- g_return_val_if_fail (cvolume != NULL, FALSE);
+ PulseSourceOutput *output;
+ const gchar *name;
- return pulse_connection_set_source_volume (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- cvolume);
-}
+ output = g_hash_table_lookup (source->priv->outputs, GINT_TO_POINTER (index));
+ if G_UNLIKELY (output == NULL)
+ return;
-static gboolean
-pulse_source_set_active_port (PulseStream *pstream, MateMixerPort *port)
-{
- g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
+ name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (output));
- return pulse_connection_set_source_port (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- mate_mixer_port_get_name (port));
+ g_hash_table_remove (source->priv->outputs, GINT_TO_POINTER (index));
+ g_signal_emit_by_name (G_OBJECT (source),
+ "control-removed",
+ name);
}
-static PulseMonitor *
-pulse_source_create_monitor (PulseStream *pstream)
+void
+pulse_source_update (PulseSource *source,
+ const pa_source_info *info)
{
- g_return_val_if_fail (PULSE_IS_SOURCE (pstream), NULL);
-
- return pulse_connection_create_monitor (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- PA_INVALID_INDEX);
+ g_return_if_fail (PULSE_IS_SOURCE (source));
+ g_return_if_fail (info != NULL);
+
+ /* The switch doesn't allow being unset, PulseAudio should always include
+ * the active port name if the are any ports available */
+ if (info->active_port != NULL)
+ pulse_port_switch_set_active_port_by_name (source->priv->pswitch,
+ info->active_port->name);
}
-static void
-update_ports (PulseStream *pstream,
- pa_source_port_info **ports,
- pa_source_port_info *active)
+static const GList *
+pulse_source_list_controls (MateMixerStream *mms)
{
- MateMixerPort *port;
- MateMixerDevice *device;
- GHashTable *hash;
-
- hash = pulse_stream_get_ports (pstream);
+ GList *list;
- while (*ports != NULL) {
- MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS;
- pa_source_port_info *info = *ports;
- const gchar *icon = NULL;
+ g_return_val_if_fail (PULSE_IS_SOURCE (mms), NULL);
- device = mate_mixer_stream_get_device (MATE_MIXER_STREAM (pstream));
- if (device != NULL) {
- port = mate_mixer_device_get_port (device, info->name);
-
- if (port != NULL) {
- flags = mate_mixer_port_get_flags (port);
- icon = mate_mixer_port_get_icon (port);
- }
- }
+ // XXX
+ list = g_hash_table_get_values (PULSE_SOURCE (mms)->priv->outputs);
+ if (list != NULL)
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
-#if PA_CHECK_VERSION(2, 0, 0)
- if (info->available == PA_PORT_AVAILABLE_YES)
- flags |= MATE_MIXER_PORT_AVAILABLE;
- else
- flags &= ~MATE_MIXER_PORT_AVAILABLE;
-#endif
-
- port = g_hash_table_lookup (hash, info->name);
-
- if (port != NULL) {
- /* Update existing port */
- _mate_mixer_port_update_description (port, info->description);
- _mate_mixer_port_update_icon (port, icon);
- _mate_mixer_port_update_priority (port, info->priority);
- _mate_mixer_port_update_flags (port, flags);
- } else {
- /* Add previously unknown port to the hash table */
- port = _mate_mixer_port_new (info->name,
- info->description,
- icon,
- info->priority,
- flags);
-
- g_hash_table_insert (hash, g_strdup (info->name), port);
- }
+ return g_list_prepend (list, g_object_ref (PULSE_SOURCE (mms)->priv->control));
+}
- ports++;
- }
+static const GList *
+pulse_source_list_switches (MateMixerStream *mms)
+{
+ g_return_val_if_fail (PULSE_IS_SOURCE (mms), NULL);
- /* Active port */
- if (G_LIKELY (active != NULL))
- port = g_hash_table_lookup (hash, active->name);
- else
- port = NULL;
+ // XXX
+ if (PULSE_SOURCE (mms)->priv->pswitch != NULL)
+ return g_list_prepend (NULL, PULSE_SOURCE (mms)->priv->pswitch);
- pulse_stream_update_active_port (pstream, port);
+ return NULL;
}
diff --git a/backends/pulse/pulse-source.h b/backends/pulse/pulse-source.h
index 9abf6d8..fdc3d5e 100644
--- a/backends/pulse/pulse-source.h
+++ b/backends/pulse/pulse-source.h
@@ -23,9 +23,8 @@
#include <pulse/pulseaudio.h>
-#include "pulse-connection.h"
-#include "pulse-device.h"
#include "pulse-stream.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
@@ -42,12 +41,15 @@ G_BEGIN_DECLS
#define PULSE_SOURCE_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SOURCE, PulseSourceClass))
-typedef struct _PulseSource PulseSource;
typedef struct _PulseSourceClass PulseSourceClass;
+typedef struct _PulseSourcePrivate PulseSourcePrivate;
struct _PulseSource
{
PulseStream parent;
+
+ /*< private >*/
+ PulseSourcePrivate *priv;
};
struct _PulseSourceClass
@@ -55,15 +57,20 @@ struct _PulseSourceClass
PulseStreamClass parent_class;
};
-GType pulse_source_get_type (void) G_GNUC_CONST;
+GType pulse_source_get_type (void) G_GNUC_CONST;
+
+PulseSource *pulse_source_new (PulseConnection *connection,
+ const pa_source_info *info,
+ PulseDevice *device);
+
+void pulse_source_add_output (PulseSource *source,
+ const pa_source_output_info *info);
-PulseStream *pulse_source_new (PulseConnection *connection,
- const pa_source_info *info,
- PulseDevice *device);
+void pulse_source_remove_output (PulseSource *source,
+ guint32 index);
-gboolean pulse_source_update (PulseStream *pstream,
- const pa_source_info *info,
- PulseDevice *device);
+void pulse_source_update (PulseSource *source,
+ const pa_source_info *info);
G_END_DECLS
diff --git a/backends/pulse/pulse-stream-control.c b/backends/pulse/pulse-stream-control.c
new file mode 100644
index 0000000..fa17e6b
--- /dev/null
+++ b/backends/pulse/pulse-stream-control.c
@@ -0,0 +1,744 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-connection.h"
+#include "pulse-helpers.h"
+#include "pulse-monitor.h"
+#include "pulse-stream-control.h"
+
+struct _PulseStreamControlPrivate
+{
+ guint32 index;
+ guint volume;
+ pa_cvolume cvolume;
+ pa_volume_t base_volume;
+ pa_channel_map channel_map;
+ PulseConnection *connection;
+ PulseMonitor *monitor;
+ MateMixerAppInfo *app_info;
+};
+
+enum {
+ PROP_0,
+ PROP_INDEX,
+ PROP_CONNECTION,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+static void pulse_stream_control_class_init (PulseStreamControlClass *klass);
+
+static void pulse_stream_control_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void pulse_stream_control_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void pulse_stream_control_init (PulseStreamControl *control);
+static void pulse_stream_control_dispose (GObject *object);
+static void pulse_stream_control_finalize (GObject *object);
+
+G_DEFINE_ABSTRACT_TYPE (PulseStreamControl, pulse_stream_control, MATE_MIXER_TYPE_STREAM_CONTROL)
+
+static MateMixerAppInfo * pulse_stream_control_get_app_info (MateMixerStreamControl *mmsc);
+
+static gboolean pulse_stream_control_set_mute (MateMixerStreamControl *mmsc,
+ gboolean mute);
+
+static guint pulse_stream_control_get_num_channels (MateMixerStreamControl *mmsc);
+
+static guint pulse_stream_control_get_volume (MateMixerStreamControl *mmsc);
+static gboolean pulse_stream_control_set_volume (MateMixerStreamControl *mmsc,
+ guint volume);
+
+static gdouble pulse_stream_control_get_decibel (MateMixerStreamControl *mmsc);
+static gboolean pulse_stream_control_set_decibel (MateMixerStreamControl *mmsc,
+ gdouble decibel);
+
+static guint pulse_stream_control_get_channel_volume (MateMixerStreamControl *mmsc,
+ guint channel);
+static gboolean pulse_stream_control_set_channel_volume (MateMixerStreamControl *mmsc,
+ guint channel,
+ guint volume);
+
+static gdouble pulse_stream_control_get_channel_decibel (MateMixerStreamControl *mmsc,
+ guint channel);
+static gboolean pulse_stream_control_set_channel_decibel (MateMixerStreamControl *mmsc,
+ guint channel,
+ gdouble decibel);
+
+static MateMixerChannelPosition pulse_stream_control_get_channel_position (MateMixerStreamControl *mmsc,
+ guint channel);
+static gboolean pulse_stream_control_has_channel_position (MateMixerStreamControl *mmsc,
+ MateMixerChannelPosition position);
+
+static gboolean pulse_stream_control_set_balance (MateMixerStreamControl *mmsc,
+ gfloat balance);
+
+static gboolean pulse_stream_control_set_fade (MateMixerStreamControl *mmsc,
+ gfloat fade);
+
+static gboolean pulse_stream_control_get_monitor_enabled (MateMixerStreamControl *mmsc);
+static gboolean pulse_stream_control_set_monitor_enabled (MateMixerStreamControl *mmsc,
+ gboolean enabled);
+
+static guint pulse_stream_control_get_min_volume (MateMixerStreamControl *mmsc);
+static guint pulse_stream_control_get_max_volume (MateMixerStreamControl *mmsc);
+static guint pulse_stream_control_get_normal_volume (MateMixerStreamControl *mmsc);
+static guint pulse_stream_control_get_base_volume (MateMixerStreamControl *mmsc);
+
+static void on_monitor_value (PulseMonitor *monitor,
+ gdouble value,
+ PulseStreamControl *control);
+
+static void set_balance_fade (PulseStreamControl *control);
+
+static gboolean set_cvolume (PulseStreamControl *control,
+ pa_cvolume *cvolume);
+
+static void
+pulse_stream_control_class_init (PulseStreamControlClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerStreamControlClass *control_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_stream_control_dispose;
+ object_class->finalize = pulse_stream_control_finalize;
+ object_class->get_property = pulse_stream_control_get_property;
+ object_class->set_property = pulse_stream_control_set_property;
+
+ control_class = MATE_MIXER_STREAM_CONTROL_CLASS (klass);
+ control_class->get_app_info = pulse_stream_control_get_app_info;
+ control_class->set_mute = pulse_stream_control_set_mute;
+ control_class->get_num_channels = pulse_stream_control_get_num_channels;
+ control_class->get_volume = pulse_stream_control_get_volume;
+ control_class->set_volume = pulse_stream_control_set_volume;
+ control_class->get_decibel = pulse_stream_control_get_decibel;
+ control_class->set_decibel = pulse_stream_control_set_decibel;
+ control_class->get_channel_volume = pulse_stream_control_get_channel_volume;
+ control_class->set_channel_volume = pulse_stream_control_set_channel_volume;
+ control_class->get_channel_decibel = pulse_stream_control_get_channel_decibel;
+ control_class->set_channel_decibel = pulse_stream_control_set_channel_decibel;
+ control_class->get_channel_position = pulse_stream_control_get_channel_position;
+ control_class->has_channel_position = pulse_stream_control_has_channel_position;
+ control_class->set_balance = pulse_stream_control_set_balance;
+ control_class->set_fade = pulse_stream_control_set_fade;
+ control_class->get_monitor_enabled = pulse_stream_control_get_monitor_enabled;
+ control_class->set_monitor_enabled = pulse_stream_control_set_monitor_enabled;
+ control_class->get_min_volume = pulse_stream_control_get_min_volume;
+ control_class->get_max_volume = pulse_stream_control_get_max_volume;
+ control_class->get_normal_volume = pulse_stream_control_get_normal_volume;
+ control_class->get_base_volume = pulse_stream_control_get_base_volume;
+
+ properties[PROP_INDEX] =
+ g_param_spec_uint ("index",
+ "Index",
+ "Index of the stream control",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_CONNECTION] =
+ g_param_spec_object ("connection",
+ "Connection",
+ "PulseAudio connection",
+ PULSE_TYPE_CONNECTION,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ g_type_class_add_private (object_class, sizeof (PulseStreamControlPrivate));
+}
+
+static void
+pulse_stream_control_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PulseStreamControl *control;
+
+ control = PULSE_STREAM_CONTROL (object);
+
+ switch (param_id) {
+ case PROP_INDEX:
+ g_value_set_uint (value, control->priv->index);
+ break;
+ case PROP_CONNECTION:
+ g_value_set_object (value, control->priv->connection);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_stream_control_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PulseStreamControl *control;
+
+ control = PULSE_STREAM_CONTROL (object);
+
+ switch (param_id) {
+ case PROP_INDEX:
+ control->priv->index = g_value_get_uint (value);
+ break;
+ case PROP_CONNECTION:
+ control->priv->connection = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_stream_control_init (PulseStreamControl *control)
+{
+ control->priv = G_TYPE_INSTANCE_GET_PRIVATE (control,
+ PULSE_TYPE_STREAM_CONTROL,
+ PulseStreamControlPrivate);
+
+ /* Initialize empty volume and channel map structures, they will be used
+ * if the stream does not support volume */
+ pa_cvolume_init (&control->priv->cvolume);
+
+ pa_channel_map_init (&control->priv->channel_map);
+}
+
+static void
+pulse_stream_control_dispose (GObject *object)
+{
+ PulseStreamControl *control;
+
+ control = PULSE_STREAM_CONTROL (object);
+
+ g_clear_object (&control->priv->monitor);
+ g_clear_object (&control->priv->connection);
+
+ G_OBJECT_CLASS (pulse_stream_control_parent_class)->dispose (object);
+}
+
+static void
+pulse_stream_control_finalize (GObject *object)
+{
+ PulseStreamControl *control;
+
+ control = PULSE_STREAM_CONTROL (object);
+
+ if (control->priv->app_info != NULL)
+ _mate_mixer_app_info_free (control->priv->app_info);
+
+ G_OBJECT_CLASS (pulse_stream_control_parent_class)->finalize (object);
+}
+
+guint32
+pulse_stream_control_get_index (PulseStreamControl *control)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), 0);
+
+ return control->priv->index;
+}
+
+PulseConnection *
+pulse_stream_control_get_connection (PulseStreamControl *control)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), NULL);
+
+ return control->priv->connection;
+}
+
+PulseMonitor *
+pulse_stream_control_get_monitor (PulseStreamControl *control)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), NULL);
+
+ return control->priv->monitor;
+}
+
+const pa_cvolume *
+pulse_stream_control_get_cvolume (PulseStreamControl *control)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), NULL);
+
+ return &control->priv->cvolume;
+}
+
+const pa_channel_map *
+pulse_stream_control_get_channel_map (PulseStreamControl *control)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), NULL);
+
+ return &control->priv->channel_map;
+}
+
+void
+pulse_stream_control_set_app_info (PulseStreamControl *control, MateMixerAppInfo *info)
+{
+ g_return_if_fail (PULSE_IS_STREAM_CONTROL (control));
+
+ if G_UNLIKELY (control->priv->app_info)
+ _mate_mixer_app_info_free (control->priv->app_info);
+
+ control->priv->app_info = info;
+}
+
+void
+pulse_stream_control_set_channel_map (PulseStreamControl *control, const pa_channel_map *map)
+{
+ MateMixerStreamControlFlags flags;
+
+ g_return_if_fail (PULSE_IS_STREAM_CONTROL (control));
+ g_return_if_fail (map != NULL);
+
+ flags = mate_mixer_stream_control_get_flags (MATE_MIXER_STREAM_CONTROL (control));
+
+ if (pa_channel_map_valid (map)) {
+ if (pa_channel_map_can_balance (map))
+ flags |= MATE_MIXER_STREAM_CONTROL_CAN_BALANCE;
+ else
+ flags &= ~MATE_MIXER_STREAM_CONTROL_CAN_BALANCE;
+
+ if (pa_channel_map_can_fade (map))
+ flags |= MATE_MIXER_STREAM_CONTROL_CAN_FADE;
+ else
+ flags &= ~MATE_MIXER_STREAM_CONTROL_CAN_FADE;
+
+ control->priv->channel_map = *map;
+ } else {
+ flags &= ~(MATE_MIXER_STREAM_CONTROL_CAN_BALANCE | MATE_MIXER_STREAM_CONTROL_CAN_FADE);
+
+ /* If the channel map is not valid, create an empty channel map, which
+ * also won't validate, but at least we know what it is */
+ pa_channel_map_init (&control->priv->channel_map);
+ }
+
+ _mate_mixer_stream_control_set_flags (MATE_MIXER_STREAM_CONTROL (control), flags);
+}
+
+void
+pulse_stream_control_set_cvolume (PulseStreamControl *control,
+ const pa_cvolume *cvolume,
+ pa_volume_t base_volume)
+{
+ MateMixerStreamControlFlags flags;
+
+ g_return_if_fail (PULSE_IS_STREAM_CONTROL (control));
+
+ /* The base volume is not a property */
+ control->priv->base_volume = base_volume;
+
+ flags = mate_mixer_stream_control_get_flags (MATE_MIXER_STREAM_CONTROL (control));
+
+ g_object_freeze_notify (G_OBJECT (control));
+
+ if (cvolume != NULL && pa_cvolume_valid (cvolume)) {
+ /* Decibel volume and volume settability flags must be provided by
+ * the implementation */
+ flags |= MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE;
+
+ if (pa_cvolume_equal (&control->priv->cvolume, cvolume) == 0) {
+ control->priv->cvolume = *cvolume;
+ control->priv->volume = (guint) pa_cvolume_max (&control->priv->cvolume);
+
+ g_object_notify (G_OBJECT (control), "volume");
+ }
+ } else {
+ flags &= ~(MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL);
+
+ /* If the cvolume is not valid, create an empty cvolume, which also
+ * won't validate, but at least we know what it is */
+ pa_cvolume_init (&control->priv->cvolume);
+
+ if (control->priv->volume != (guint) PA_VOLUME_MUTED) {
+ control->priv->volume = (guint) PA_VOLUME_MUTED;
+
+ g_object_notify (G_OBJECT (control), "volume");
+ }
+ }
+
+ _mate_mixer_stream_control_set_flags (MATE_MIXER_STREAM_CONTROL (control), flags);
+
+ /* Changing volume may change the balance and fade values as well */
+ set_balance_fade (control);
+
+ g_object_thaw_notify (G_OBJECT (control));
+}
+
+static MateMixerAppInfo *
+pulse_stream_control_get_app_info (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), NULL);
+
+ return PULSE_STREAM_CONTROL (mmsc)->priv->app_info;
+}
+
+static gboolean
+pulse_stream_control_set_mute (MateMixerStreamControl *mmsc, gboolean mute)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ return PULSE_STREAM_CONTROL_GET_CLASS (mmsc)->set_mute (PULSE_STREAM_CONTROL (mmsc), mute);
+}
+
+static guint
+pulse_stream_control_get_num_channels (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), 0);
+
+ return PULSE_STREAM_CONTROL (mmsc)->priv->channel_map.channels;
+}
+
+static guint
+pulse_stream_control_get_volume (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), (guint) PA_VOLUME_MUTED);
+
+ return PULSE_STREAM_CONTROL (mmsc)->priv->volume;
+}
+
+static gboolean
+pulse_stream_control_set_volume (MateMixerStreamControl *mmsc, guint volume)
+{
+ PulseStreamControl *control;
+ pa_cvolume cvolume;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+ cvolume = control->priv->cvolume;
+
+ if (pa_cvolume_scale (&cvolume, (pa_volume_t) volume) == NULL)
+ return FALSE;
+
+ return set_cvolume (control, &cvolume);
+}
+
+static gdouble
+pulse_stream_control_get_decibel (MateMixerStreamControl *mmsc)
+{
+ gdouble value;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), -MATE_MIXER_INFINITY);
+
+ value = pa_sw_volume_to_dB (pulse_stream_control_get_volume (mmsc));
+
+ /* PA_VOLUME_MUTED is converted to PA_DECIBEL_MININFTY */
+ return (value == PA_DECIBEL_MININFTY) ? -MATE_MIXER_INFINITY : value;
+}
+
+static gboolean
+pulse_stream_control_set_decibel (MateMixerStreamControl *mmsc, gdouble decibel)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ return pulse_stream_control_set_volume (mmsc,
+ pa_sw_volume_from_dB (decibel));
+}
+
+static guint
+pulse_stream_control_get_channel_volume (MateMixerStreamControl *mmsc, guint channel)
+{
+ PulseStreamControl *control;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), (guint) PA_VOLUME_MUTED);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ if (channel >= control->priv->cvolume.channels)
+ return (guint) PA_VOLUME_MUTED;
+
+ return (guint) control->priv->cvolume.values[channel];
+}
+
+static gboolean
+pulse_stream_control_set_channel_volume (MateMixerStreamControl *mmsc, guint channel, guint volume)
+{
+ PulseStreamControl *control;
+ pa_cvolume cvolume;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ if (channel >= control->priv->cvolume.channels)
+ return FALSE;
+
+ /* This is safe, because the cvolume is validated by set_cvolume() */
+ cvolume = control->priv->cvolume;
+ cvolume.values[channel] = (pa_volume_t) volume;
+
+ return set_cvolume (control, &cvolume);
+}
+
+static gdouble
+pulse_stream_control_get_channel_decibel (MateMixerStreamControl *mmsc, guint channel)
+{
+ PulseStreamControl *control;
+ gdouble value;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), -MATE_MIXER_INFINITY);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ if (channel >= control->priv->cvolume.channels)
+ return -MATE_MIXER_INFINITY;
+
+ value = pa_sw_volume_to_dB (control->priv->cvolume.values[channel]);
+
+ return (value == PA_DECIBEL_MININFTY) ? -MATE_MIXER_INFINITY : value;
+}
+
+static gboolean
+pulse_stream_control_set_channel_decibel (MateMixerStreamControl *mmsc,
+ guint channel,
+ gdouble decibel)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ return pulse_stream_control_set_channel_volume (mmsc,
+ channel,
+ pa_sw_volume_from_dB (decibel));
+}
+
+static MateMixerChannelPosition
+pulse_stream_control_get_channel_position (MateMixerStreamControl *mmsc, guint channel)
+{
+ PulseStreamControl *control;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), MATE_MIXER_CHANNEL_UNKNOWN);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ if (channel >= control->priv->channel_map.channels)
+ return MATE_MIXER_CHANNEL_UNKNOWN;
+
+ return pulse_convert_position_to_pulse (control->priv->channel_map.map[channel]);
+}
+
+static gboolean
+pulse_stream_control_has_channel_position (MateMixerStreamControl *mmsc,
+ MateMixerChannelPosition position)
+{
+ PulseStreamControl *control;
+ pa_channel_position_t p;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ /* Handle invalid position as a special case, otherwise this function would
+ * return TRUE for e.g. unknown index in a default channel map */
+ p = pulse_convert_position_to_pulse (position);
+
+ if (p == PA_CHANNEL_POSITION_INVALID)
+ return FALSE;
+
+ if (pa_channel_map_has_position (&control->priv->channel_map, p) != 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static gboolean
+pulse_stream_control_set_balance (MateMixerStreamControl *mmsc, gfloat balance)
+{
+ PulseStreamControl *control;
+ pa_cvolume cvolume;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+ cvolume = control->priv->cvolume;
+
+ if (pa_cvolume_set_balance (&cvolume, &control->priv->channel_map, balance) == NULL)
+ return FALSE;
+
+ return set_cvolume (control, &cvolume);
+}
+
+static gboolean
+pulse_stream_control_set_fade (MateMixerStreamControl *mmsc, gfloat fade)
+{
+ PulseStreamControl *control;
+ pa_cvolume cvolume;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+ cvolume = control->priv->cvolume;
+
+ if (pa_cvolume_set_fade (&cvolume, &control->priv->channel_map, fade) == NULL)
+ return FALSE;
+
+ return set_cvolume (control, &cvolume);
+}
+
+static gboolean
+pulse_stream_control_get_monitor_enabled (MateMixerStreamControl *mmsc)
+{
+ PulseStreamControl *control;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ if (control->priv->monitor != NULL)
+ return pulse_monitor_get_enabled (control->priv->monitor);
+
+ return FALSE;
+}
+
+static gboolean
+pulse_stream_control_set_monitor_enabled (MateMixerStreamControl *mmsc, gboolean enabled)
+{
+ PulseStreamControl *control;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ if (enabled == TRUE) {
+ if (control->priv->monitor == NULL) {
+ control->priv->monitor =
+ PULSE_STREAM_CONTROL_GET_CLASS (control)->create_monitor (control);
+
+ if G_UNLIKELY (control->priv->monitor == NULL)
+ return FALSE;
+
+ g_signal_connect (G_OBJECT (control->priv->monitor),
+ "value",
+ G_CALLBACK (on_monitor_value),
+ control);
+ }
+ } else {
+ if (control->priv->monitor == NULL)
+ return FALSE;
+ }
+ return pulse_monitor_set_enabled (control->priv->monitor, enabled);
+}
+
+static guint
+pulse_stream_control_get_min_volume (MateMixerStreamControl *mmsc)
+{
+ return (guint) PA_VOLUME_MUTED;
+}
+
+static guint
+pulse_stream_control_get_max_volume (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), (guint) PA_VOLUME_MUTED);
+
+ return (guint) PA_VOLUME_UI_MAX;
+}
+
+static guint
+pulse_stream_control_get_normal_volume (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), (guint) PA_VOLUME_MUTED);
+
+ return (guint) PA_VOLUME_NORM;
+}
+
+static guint
+pulse_stream_control_get_base_volume (MateMixerStreamControl *mmsc)
+{
+ PulseStreamControl *control;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), (guint) PA_VOLUME_MUTED);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ if (control->priv->base_volume > 0)
+ return control->priv->base_volume;
+ else
+ return (guint) PA_VOLUME_NORM;
+}
+
+static void
+on_monitor_value (PulseMonitor *monitor, gdouble value, PulseStreamControl *control)
+{
+ g_signal_emit_by_name (G_OBJECT (control),
+ "monitor-value",
+ value);
+}
+
+static void
+set_balance_fade (PulseStreamControl *control)
+{
+ gfloat value;
+
+ /* PulseAudio returns the default 0.0f value on error, so skip checking validity
+ * of the channel map and cvolume */
+ value = pa_cvolume_get_balance (&control->priv->cvolume,
+ &control->priv->channel_map);
+
+ _mate_mixer_stream_control_set_balance (MATE_MIXER_STREAM_CONTROL (control), value);
+
+ value = pa_cvolume_get_fade (&control->priv->cvolume,
+ &control->priv->channel_map);
+
+ _mate_mixer_stream_control_set_fade (MATE_MIXER_STREAM_CONTROL (control), value);
+}
+
+static gboolean
+set_cvolume (PulseStreamControl *control, pa_cvolume *cvolume)
+{
+ PulseStreamControlClass *klass;
+
+ if (pa_cvolume_valid (cvolume) == 0)
+ return FALSE;
+ if (pa_cvolume_equal (cvolume, &control->priv->cvolume) != 0)
+ return TRUE;
+
+ klass = PULSE_STREAM_CONTROL_GET_CLASS (control);
+
+ if (klass->set_volume (control, cvolume) == FALSE)
+ return FALSE;
+
+ control->priv->cvolume = *cvolume;
+ control->priv->volume = (guint) pa_cvolume_max (cvolume);
+
+ g_object_notify (G_OBJECT (control), "volume");
+
+ /* Changing volume may change the balance and fade values as well */
+ set_balance_fade (control);
+ return TRUE;
+}
diff --git a/backends/pulse/pulse-stream-control.h b/backends/pulse/pulse-stream-control.h
new file mode 100644
index 0000000..abc3f98
--- /dev/null
+++ b/backends/pulse/pulse-stream-control.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_STREAM_CONTROL_H
+#define PULSE_STREAM_CONTROL_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_STREAM_CONTROL \
+ (pulse_stream_control_get_type ())
+#define PULSE_STREAM_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_STREAM_CONTROL, PulseStreamControl))
+#define PULSE_IS_STREAM_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_STREAM_CONTROL))
+#define PULSE_STREAM_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_STREAM_CONTROL, PulseStreamControlClass))
+#define PULSE_IS_STREAM_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_STREAM_CONTROL))
+#define PULSE_STREAM_CONTROL_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_STREAM_CONTROL, PulseStreamControlClass))
+
+#define PULSE_STREAM_CONTROL_GET_CONNECTION(psc) \
+ (pulse_stream_get_connection (PULSE_STREAM (mate_mixer_stream_control_get_stream (MATE_MIXER_STREAM_CONTROL (psc)))))
+#define PULSE_STREAM_CONTROL_GET_STREAM_INDEX(psc) \
+ (pulse_stream_get_index (PULSE_STREAM (mate_mixer_stream_control_get_stream (MATE_MIXER_STREAM_CONTROL (psc)))))
+
+typedef struct _PulseStreamControlClass PulseStreamControlClass;
+typedef struct _PulseStreamControlPrivate PulseStreamControlPrivate;
+
+struct _PulseStreamControl
+{
+ MateMixerStreamControl parent;
+
+ /*< private >*/
+ PulseStreamControlPrivate *priv;
+};
+
+struct _PulseStreamControlClass
+{
+ MateMixerStreamControlClass parent_class;
+
+ /*< private >*/
+ gboolean (*set_mute) (PulseStreamControl *control,
+ gboolean mute);
+ gboolean (*set_volume) (PulseStreamControl *control,
+ pa_cvolume *volume);
+
+ PulseMonitor *(*create_monitor) (PulseStreamControl *control);
+};
+
+GType pulse_stream_control_get_type (void) G_GNUC_CONST;
+
+guint32 pulse_stream_control_get_index (PulseStreamControl *control);
+
+PulseConnection * pulse_stream_control_get_connection (PulseStreamControl *control);
+PulseMonitor * pulse_stream_control_get_monitor (PulseStreamControl *control);
+
+const pa_cvolume * pulse_stream_control_get_cvolume (PulseStreamControl *control);
+const pa_channel_map *pulse_stream_control_get_channel_map (PulseStreamControl *control);
+
+void pulse_stream_control_set_app_info (PulseStreamControl *stream,
+ MateMixerAppInfo *info);
+
+void pulse_stream_control_set_channel_map (PulseStreamControl *control,
+ const pa_channel_map *map);
+void pulse_stream_control_set_cvolume (PulseStreamControl *control,
+ const pa_cvolume *cvolume,
+ pa_volume_t base_volume);
+
+G_END_DECLS
+
+#endif /* PULSE_STREAM_CONTROL_H */
diff --git a/backends/pulse/pulse-stream.c b/backends/pulse/pulse-stream.c
index fb738ad..752c3e6 100644
--- a/backends/pulse/pulse-stream.c
+++ b/backends/pulse/pulse-stream.c
@@ -15,62 +15,34 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#include <string.h>
#include <glib.h>
#include <glib-object.h>
-
-#include <libmatemixer/matemixer-device.h>
-#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-stream.h>
-#include <libmatemixer/matemixer-port.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
+#include "pulse-device.h"
#include "pulse-helpers.h"
#include "pulse-monitor.h"
+#include "pulse-port.h"
#include "pulse-stream.h"
struct _PulseStreamPrivate
{
- guint32 index;
- gchar *name;
- gchar *description;
- MateMixerDevice *device;
- MateMixerStreamFlags flags;
- MateMixerStreamState state;
- gboolean mute;
- guint volume;
- pa_cvolume cvolume;
- pa_volume_t base_volume;
- pa_channel_map channel_map;
- gfloat balance;
- gfloat fade;
- GHashTable *ports;
- GList *ports_list;
- MateMixerPort *port;
- PulseConnection *connection;
- PulseMonitor *monitor;
- gchar *monitor_name;
+ guint32 index;
+ PulseConnection *connection;
};
enum {
PROP_0,
- PROP_NAME,
- PROP_DESCRIPTION,
- PROP_DEVICE,
- PROP_FLAGS,
- PROP_STATE,
- PROP_MUTE,
- PROP_VOLUME,
- PROP_BALANCE,
- PROP_FADE,
- PROP_ACTIVE_PORT,
PROP_INDEX,
- PROP_CONNECTION
+ PROP_CONNECTION,
+ N_PROPERTIES
};
-static void mate_mixer_stream_interface_init (MateMixerStreamInterface *iface);
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
static void pulse_stream_class_init (PulseStreamClass *klass);
@@ -83,174 +55,45 @@ static void pulse_stream_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec);
-static void pulse_stream_init (PulseStream *pstream);
+static void pulse_stream_init (PulseStream *stream);
static void pulse_stream_dispose (GObject *object);
-static void pulse_stream_finalize (GObject *object);
-
-G_DEFINE_ABSTRACT_TYPE_WITH_CODE (PulseStream, pulse_stream, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_STREAM,
- mate_mixer_stream_interface_init))
-
-static const gchar * pulse_stream_get_name (MateMixerStream *stream);
-static const gchar * pulse_stream_get_description (MateMixerStream *stream);
-static MateMixerDevice * pulse_stream_get_device (MateMixerStream *stream);
-static MateMixerStreamFlags pulse_stream_get_flags (MateMixerStream *stream);
-static MateMixerStreamState pulse_stream_get_state (MateMixerStream *stream);
-
-static gboolean pulse_stream_get_mute (MateMixerStream *stream);
-static gboolean pulse_stream_set_mute (MateMixerStream *stream,
- gboolean mute);
-
-static guint pulse_stream_get_num_channels (MateMixerStream *stream);
-
-static guint pulse_stream_get_volume (MateMixerStream *stream);
-static gboolean pulse_stream_set_volume (MateMixerStream *stream,
- guint volume);
-
-static gdouble pulse_stream_get_decibel (MateMixerStream *stream);
-static gboolean pulse_stream_set_decibel (MateMixerStream *stream,
- gdouble decibel);
-
-static guint pulse_stream_get_channel_volume (MateMixerStream *stream,
- guint channel);
-static gboolean pulse_stream_set_channel_volume (MateMixerStream *stream,
- guint channel,
- guint volume);
-
-static gdouble pulse_stream_get_channel_decibel (MateMixerStream *stream,
- guint channel);
-static gboolean pulse_stream_set_channel_decibel (MateMixerStream *stream,
- guint channel,
- gdouble decibel);
-
-static MateMixerChannelPosition pulse_stream_get_channel_position (MateMixerStream *stream,
- guint channel);
-static gboolean pulse_stream_has_channel_position (MateMixerStream *stream,
- MateMixerChannelPosition position);
-
-static gfloat pulse_stream_get_balance (MateMixerStream *stream);
-static gboolean pulse_stream_set_balance (MateMixerStream *stream,
- gfloat balance);
-
-static gfloat pulse_stream_get_fade (MateMixerStream *stream);
-static gboolean pulse_stream_set_fade (MateMixerStream *stream,
- gfloat fade);
-
-static gboolean pulse_stream_suspend (MateMixerStream *stream);
-static gboolean pulse_stream_resume (MateMixerStream *stream);
-static gboolean pulse_stream_monitor_start (MateMixerStream *stream);
-static void pulse_stream_monitor_stop (MateMixerStream *stream);
-static gboolean pulse_stream_monitor_is_running (MateMixerStream *stream);
-static gboolean pulse_stream_monitor_set_name (MateMixerStream *stream,
- const gchar *name);
-
-static const GList * pulse_stream_list_ports (MateMixerStream *stream);
-
-static MateMixerPort * pulse_stream_get_active_port (MateMixerStream *stream);
-static gboolean pulse_stream_set_active_port (MateMixerStream *stream,
- MateMixerPort *port);
-
-static guint pulse_stream_get_min_volume (MateMixerStream *stream);
-static guint pulse_stream_get_max_volume (MateMixerStream *stream);
-static guint pulse_stream_get_normal_volume (MateMixerStream *stream);
-static guint pulse_stream_get_base_volume (MateMixerStream *stream);
-
-static void on_monitor_value (PulseMonitor *monitor,
- gdouble value,
- PulseStream *pstream);
-
-static gboolean update_balance_fade (PulseStream *pstream);
-
-static gboolean set_cvolume (PulseStream *pstream,
- pa_cvolume *cvolume);
-
-static gint compare_ports (gconstpointer a,
- gconstpointer b);
-
-static void
-mate_mixer_stream_interface_init (MateMixerStreamInterface *iface)
-{
- iface->get_name = pulse_stream_get_name;
- iface->get_description = pulse_stream_get_description;
- iface->get_device = pulse_stream_get_device;
- iface->get_flags = pulse_stream_get_flags;
- iface->get_state = pulse_stream_get_state;
- iface->get_mute = pulse_stream_get_mute;
- iface->set_mute = pulse_stream_set_mute;
- iface->get_num_channels = pulse_stream_get_num_channels;
- iface->get_volume = pulse_stream_get_volume;
- iface->set_volume = pulse_stream_set_volume;
- iface->get_decibel = pulse_stream_get_decibel;
- iface->set_decibel = pulse_stream_set_decibel;
- iface->get_channel_volume = pulse_stream_get_channel_volume;
- iface->set_channel_volume = pulse_stream_set_channel_volume;
- iface->get_channel_decibel = pulse_stream_get_channel_decibel;
- iface->set_channel_decibel = pulse_stream_set_channel_decibel;
- iface->get_channel_position = pulse_stream_get_channel_position;
- iface->has_channel_position = pulse_stream_has_channel_position;
- iface->get_balance = pulse_stream_get_balance;
- iface->set_balance = pulse_stream_set_balance;
- iface->get_fade = pulse_stream_get_fade;
- iface->set_fade = pulse_stream_set_fade;
- iface->suspend = pulse_stream_suspend;
- iface->resume = pulse_stream_resume;
- iface->monitor_start = pulse_stream_monitor_start;
- iface->monitor_stop = pulse_stream_monitor_stop;
- iface->monitor_is_running = pulse_stream_monitor_is_running;
- iface->monitor_set_name = pulse_stream_monitor_set_name;
- iface->list_ports = pulse_stream_list_ports;
- iface->get_active_port = pulse_stream_get_active_port;
- iface->set_active_port = pulse_stream_set_active_port;
- iface->get_min_volume = pulse_stream_get_min_volume;
- iface->get_max_volume = pulse_stream_get_max_volume;
- iface->get_normal_volume = pulse_stream_get_normal_volume;
- iface->get_base_volume = pulse_stream_get_base_volume;
-}
+G_DEFINE_ABSTRACT_TYPE (PulseStream, pulse_stream, MATE_MIXER_TYPE_STREAM)
static void
pulse_stream_class_init (PulseStreamClass *klass)
{
- GObjectClass *object_class;
+ GObjectClass *object_class;
+ MateMixerStreamClass *stream_class;
object_class = G_OBJECT_CLASS (klass);
object_class->dispose = pulse_stream_dispose;
- object_class->finalize = pulse_stream_finalize;
object_class->get_property = pulse_stream_get_property;
object_class->set_property = pulse_stream_set_property;
- g_object_class_install_property (object_class,
- PROP_INDEX,
- g_param_spec_uint ("index",
- "Index",
- "Stream index",
- 0,
- G_MAXUINT,
- 0,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (object_class,
- PROP_CONNECTION,
- g_param_spec_object ("connection",
- "Connection",
- "PulseAudio connection",
- PULSE_TYPE_CONNECTION,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_override_property (object_class, PROP_NAME, "name");
- g_object_class_override_property (object_class, PROP_DESCRIPTION, "description");
- g_object_class_override_property (object_class, PROP_DEVICE, "device");
- g_object_class_override_property (object_class, PROP_FLAGS, "flags");
- g_object_class_override_property (object_class, PROP_STATE, "state");
- g_object_class_override_property (object_class, PROP_MUTE, "mute");
- g_object_class_override_property (object_class, PROP_VOLUME, "volume");
- g_object_class_override_property (object_class, PROP_BALANCE, "balance");
- g_object_class_override_property (object_class, PROP_FADE, "fade");
- g_object_class_override_property (object_class, PROP_ACTIVE_PORT, "active-port");
+ stream_class = MATE_MIXER_STREAM_CLASS (klass);
+
+ properties[PROP_INDEX] =
+ g_param_spec_uint ("index",
+ "Index",
+ "Index of the stream",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_CONNECTION] =
+ g_param_spec_object ("connection",
+ "Connection",
+ "PulseAudio connection",
+ PULSE_TYPE_CONNECTION,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
g_type_class_add_private (object_class, sizeof (PulseStreamPrivate));
}
@@ -261,46 +104,16 @@ pulse_stream_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
- PulseStream *pstream;
+ PulseStream *stream;
- pstream = PULSE_STREAM (object);
+ stream = PULSE_STREAM (object);
switch (param_id) {
- case PROP_NAME:
- g_value_set_string (value, pstream->priv->name);
- break;
- case PROP_DESCRIPTION:
- g_value_set_string (value, pstream->priv->description);
- break;
- case PROP_DEVICE:
- g_value_set_object (value, pstream->priv->device);
- break;
- case PROP_FLAGS:
- g_value_set_flags (value, pstream->priv->flags);
- break;
- case PROP_STATE:
- g_value_set_enum (value, pstream->priv->state);
- break;
- case PROP_MUTE:
- g_value_set_boolean (value, pstream->priv->mute);
- break;
- case PROP_VOLUME:
- g_value_set_uint (value, pstream->priv->volume);
- break;
- case PROP_BALANCE:
- g_value_set_float (value, pstream->priv->balance);
- break;
- case PROP_FADE:
- g_value_set_float (value, pstream->priv->fade);
- break;
- case PROP_ACTIVE_PORT:
- g_value_set_object (value, pstream->priv->port);
- break;
case PROP_INDEX:
- g_value_set_uint (value, pstream->priv->index);
+ g_value_set_uint (value, stream->priv->index);
break;
case PROP_CONNECTION:
- g_value_set_object (value, pstream->priv->connection);
+ g_value_set_object (value, stream->priv->connection);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -314,17 +127,16 @@ pulse_stream_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
- PulseStream *pstream;
+ PulseStream *stream;
- pstream = PULSE_STREAM (object);
+ stream = PULSE_STREAM (object);
switch (param_id) {
case PROP_INDEX:
- pstream->priv->index = g_value_get_uint (value);
+ stream->priv->index = g_value_get_uint (value);
break;
case PROP_CONNECTION:
- /* Construct-only object */
- pstream->priv->connection = g_value_dup_object (value);
+ stream->priv->connection = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -333,962 +145,51 @@ pulse_stream_set_property (GObject *object,
}
static void
-pulse_stream_init (PulseStream *pstream)
+pulse_stream_init (PulseStream *stream)
{
- pstream->priv = G_TYPE_INSTANCE_GET_PRIVATE (pstream,
- PULSE_TYPE_STREAM,
- PulseStreamPrivate);
-
- pstream->priv->ports = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- g_object_unref);
-
- /* Initialize empty volume and channel map structures, they will be used
- * if the stream does not support volume */
- pa_cvolume_init (&pstream->priv->cvolume);
-
- pa_channel_map_init (&pstream->priv->channel_map);
+ stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
+ PULSE_TYPE_STREAM,
+ PulseStreamPrivate);
}
static void
pulse_stream_dispose (GObject *object)
{
- PulseStream *pstream;
+ PulseStream *stream;
- pstream = PULSE_STREAM (object);
+ stream = PULSE_STREAM (object);
- if (pstream->priv->ports_list != NULL) {
- g_list_free_full (pstream->priv->ports_list, g_object_unref);
- pstream->priv->ports_list = NULL;
- }
- g_hash_table_remove_all (pstream->priv->ports);
-
- g_clear_object (&pstream->priv->port);
- g_clear_object (&pstream->priv->device);
- g_clear_object (&pstream->priv->monitor);
- g_clear_object (&pstream->priv->connection);
+ g_clear_object (&stream->priv->connection);
G_OBJECT_CLASS (pulse_stream_parent_class)->dispose (object);
}
-static void
-pulse_stream_finalize (GObject *object)
-{
- PulseStream *pstream;
-
- pstream = PULSE_STREAM (object);
-
- g_free (pstream->priv->name);
- g_free (pstream->priv->description);
- g_free (pstream->priv->monitor_name);
-
- g_hash_table_destroy (pstream->priv->ports);
-
- G_OBJECT_CLASS (pulse_stream_parent_class)->finalize (object);
-}
-
guint32
-pulse_stream_get_index (PulseStream *pstream)
+pulse_stream_get_index (PulseStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), 0);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
- return pstream->priv->index;
+ return stream->priv->index;
}
PulseConnection *
-pulse_stream_get_connection (PulseStream *pstream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), NULL);
-
- return pstream->priv->connection;
-}
-
-PulseMonitor *
-pulse_stream_get_monitor (PulseStream *pstream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), NULL);
-
- return pstream->priv->monitor;
-}
-
-const pa_cvolume *
-pulse_stream_get_cvolume (PulseStream *pstream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), NULL);
-
- return &pstream->priv->cvolume;
-}
-
-const pa_channel_map *
-pulse_stream_get_channel_map (PulseStream *pstream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), NULL);
-
- return &pstream->priv->channel_map;
-}
-
-GHashTable *
-pulse_stream_get_ports (PulseStream *pstream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), NULL);
-
- return pstream->priv->ports;
-}
-
-gboolean
-pulse_stream_update_name (PulseStream *pstream, const gchar *name)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
-
- /* Allow the name to be NULL */
- if (g_strcmp0 (name, pstream->priv->name) != 0) {
- g_free (pstream->priv->name);
- pstream->priv->name = g_strdup (name);
-
- g_object_notify (G_OBJECT (pstream), "name");
- return TRUE;
- }
- return FALSE;
-}
-
-gboolean
-pulse_stream_update_description (PulseStream *pstream, const gchar *description)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
-
- /* Allow the description to be NULL */
- if (g_strcmp0 (description, pstream->priv->description) != 0) {
- g_free (pstream->priv->description);
- pstream->priv->description = g_strdup (description);
-
- g_object_notify (G_OBJECT (pstream), "description");
- return TRUE;
- }
- return FALSE;
-}
-
-gboolean
-pulse_stream_update_device (PulseStream *pstream, MateMixerDevice *device)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
-
- if (pstream->priv->device != device) {
- g_clear_object (&pstream->priv->device);
-
- if (G_LIKELY (device != NULL))
- pstream->priv->device = g_object_ref (device);
-
- g_object_notify (G_OBJECT (pstream), "device");
- return TRUE;
- }
- return FALSE;
-}
-
-gboolean
-pulse_stream_update_flags (PulseStream *pstream, MateMixerStreamFlags flags)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
-
- if (pstream->priv->flags != flags) {
- pstream->priv->flags = flags;
-
- g_object_notify (G_OBJECT (pstream), "flags");
- return TRUE;
- }
- return FALSE;
-}
-
-gboolean
-pulse_stream_update_state (PulseStream *pstream, MateMixerStreamState state)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
-
- if (pstream->priv->state != state) {
- pstream->priv->state = state;
-
- g_object_notify (G_OBJECT (pstream), "state");
- return TRUE;
- }
- return FALSE;
-}
-
-gboolean
-pulse_stream_update_channel_map (PulseStream *pstream, const pa_channel_map *map)
-{
- MateMixerStreamFlags flags;
-
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
- g_return_val_if_fail (map != NULL, FALSE);
-
- flags = pstream->priv->flags;
-
- if (pa_channel_map_valid (map)) {
- if (pa_channel_map_can_balance (map))
- flags |= MATE_MIXER_STREAM_CAN_BALANCE;
- else
- flags &= ~MATE_MIXER_STREAM_CAN_BALANCE;
-
- if (pa_channel_map_can_fade (map))
- flags |= MATE_MIXER_STREAM_CAN_FADE;
- else
- flags &= ~MATE_MIXER_STREAM_CAN_FADE;
-
- pstream->priv->channel_map = *map;
- } else {
- flags &= ~(MATE_MIXER_STREAM_CAN_BALANCE | MATE_MIXER_STREAM_CAN_FADE);
-
- /* If the channel map is not valid, create an empty channel map, which
- * also won't validate, but at least we know what it is */
- pa_channel_map_init (&pstream->priv->channel_map);
- }
-
- pulse_stream_update_flags (pstream, flags);
- return TRUE;
-}
-
-gboolean
-pulse_stream_update_volume (PulseStream *pstream,
- const pa_cvolume *cvolume,
- pa_volume_t base_volume)
-{
- MateMixerStreamFlags flags;
-
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
-
- /* The base volume is not a property */
- pstream->priv->base_volume = base_volume;
-
- flags = pstream->priv->flags;
-
- if (cvolume != NULL && pa_cvolume_valid (cvolume)) {
- /* Decibel volume and volume settability flags must be provided by
- * the implementation */
- flags |= MATE_MIXER_STREAM_HAS_VOLUME;
-
- if (pa_cvolume_equal (&pstream->priv->cvolume, cvolume) == 0) {
- pstream->priv->cvolume = *cvolume;
- pstream->priv->volume = (guint) pa_cvolume_max (&pstream->priv->cvolume);
-
- g_object_notify (G_OBJECT (pstream), "volume");
- }
- } else {
- flags &= ~(MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME |
- MATE_MIXER_STREAM_CAN_SET_VOLUME);
-
- /* If the cvolume is not valid, create an empty cvolume, which also
- * won't validate, but at least we know what it is */
- pa_cvolume_init (&pstream->priv->cvolume);
-
- if (pstream->priv->volume != (guint) PA_VOLUME_MUTED) {
- pstream->priv->volume = (guint) PA_VOLUME_MUTED;
-
- g_object_notify (G_OBJECT (pstream), "volume");
- }
- }
-
- pulse_stream_update_flags (pstream, flags);
-
- /* Changing volume may change the balance and fade values as well */
- update_balance_fade (pstream);
- return TRUE;
-}
-
-gboolean
-pulse_stream_update_mute (PulseStream *pstream, gboolean mute)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
-
- if (pstream->priv->mute != mute) {
- pstream->priv->mute = mute;
-
- g_object_notify (G_OBJECT (pstream), "mute");
- return TRUE;
- }
- return FALSE;
-}
-
-gboolean
-pulse_stream_update_active_port (PulseStream *pstream, MateMixerPort *port)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
-
- if (pstream->priv->port != port) {
- if (pstream->priv->port != NULL)
- g_clear_object (&pstream->priv->port);
-
- if (port != NULL)
- pstream->priv->port = g_object_ref (port);
-
- g_object_notify (G_OBJECT (pstream), "active-port");
- return TRUE;
- }
- return FALSE;
-}
-
-static const gchar *
-pulse_stream_get_name (MateMixerStream *stream)
+pulse_stream_get_connection (PulseStream *stream)
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
- return PULSE_STREAM (stream)->priv->name;
+ return stream->priv->connection;
}
-static const gchar *
-pulse_stream_get_description (MateMixerStream *stream)
+PulseDevice *
+pulse_stream_get_device (PulseStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
-
- return PULSE_STREAM (stream)->priv->description;
-}
+ MateMixerDevice *device;
-static MateMixerDevice *
-pulse_stream_get_device (MateMixerStream *stream)
-{
g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
- return PULSE_STREAM (stream)->priv->device;
-}
-
-static MateMixerStreamFlags
-pulse_stream_get_flags (MateMixerStream *stream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), MATE_MIXER_STREAM_NO_FLAGS);
-
- return PULSE_STREAM (stream)->priv->flags;
-}
-
-static MateMixerStreamState
-pulse_stream_get_state (MateMixerStream *stream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), MATE_MIXER_STREAM_STATE_UNKNOWN);
-
- return PULSE_STREAM (stream)->priv->state;
-}
-
-static gboolean
-pulse_stream_get_mute (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_MUTE))
- return FALSE;
-
- return pstream->priv->mute;
-}
-
-static gboolean
-pulse_stream_set_mute (MateMixerStream *stream, gboolean mute)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_MUTE))
- return FALSE;
-
- if (pstream->priv->mute != mute) {
- PulseStreamClass *klass = PULSE_STREAM_GET_CLASS (pstream);
-
- if (klass->set_mute (pstream, mute) == FALSE)
- return FALSE;
-
- pstream->priv->mute = mute;
-
- g_object_notify (G_OBJECT (stream), "mute");
- }
- return TRUE;
-}
-
-static guint
-pulse_stream_get_num_channels (MateMixerStream *stream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
-
- return PULSE_STREAM (stream)->priv->channel_map.channels;
-}
-
-static guint
-pulse_stream_get_volume (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), (guint) PA_VOLUME_MUTED);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_VOLUME))
- return (guint) PA_VOLUME_MUTED;
-
- return pstream->priv->volume;
-}
-
-static gboolean
-pulse_stream_set_volume (MateMixerStream *stream, guint volume)
-{
- PulseStream *pstream;
- pa_cvolume cvolume;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SET_VOLUME))
- return FALSE;
-
- cvolume = pstream->priv->cvolume;
-
- if (pa_cvolume_scale (&cvolume, (pa_volume_t) volume) == NULL)
- return FALSE;
-
- return set_cvolume (pstream, &cvolume);
-}
-
-static gdouble
-pulse_stream_get_decibel (MateMixerStream *stream)
-{
- PulseStream *pstream;
- gdouble value;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), -MATE_MIXER_INFINITY);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
- return -MATE_MIXER_INFINITY;
-
- value = pa_sw_volume_to_dB (pulse_stream_get_volume (stream));
-
- /* PA_VOLUME_MUTED is converted to PA_DECIBEL_MININFTY */
- return (value == PA_DECIBEL_MININFTY) ? -MATE_MIXER_INFINITY : value;
-}
-
-static gboolean
-pulse_stream_set_decibel (MateMixerStream *stream, gdouble decibel)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME) ||
- !(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SET_VOLUME))
- return FALSE;
-
- return pulse_stream_set_volume (stream, pa_sw_volume_from_dB (decibel));
-}
-
-static guint
-pulse_stream_get_channel_volume (MateMixerStream *stream, guint channel)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), (guint) PA_VOLUME_MUTED);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_VOLUME))
- return (guint) PA_VOLUME_MUTED;
-
- if (channel >= pstream->priv->cvolume.channels)
- return (guint) PA_VOLUME_MUTED;
-
- return (guint) pstream->priv->cvolume.values[channel];
-}
-
-static gboolean
-pulse_stream_set_channel_volume (MateMixerStream *stream, guint channel, guint volume)
-{
- PulseStream *pstream;
- pa_cvolume cvolume;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SET_VOLUME))
- return FALSE;
-
- if (channel >= pstream->priv->cvolume.channels)
- return FALSE;
-
- /* This is safe, because the cvolume is validated by set_cvolume() */
- cvolume = pstream->priv->cvolume;
- cvolume.values[channel] = (pa_volume_t) volume;
-
- return set_cvolume (pstream, &cvolume);
-}
-
-static gdouble
-pulse_stream_get_channel_decibel (MateMixerStream *stream, guint channel)
-{
- PulseStream *pstream;
- gdouble value;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), -MATE_MIXER_INFINITY);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
- return -MATE_MIXER_INFINITY;
-
- if (channel >= pstream->priv->cvolume.channels)
- return -MATE_MIXER_INFINITY;
-
- value = pa_sw_volume_to_dB (pstream->priv->cvolume.values[channel]);
-
- return (value == PA_DECIBEL_MININFTY) ? -MATE_MIXER_INFINITY : value;
-}
-
-static gboolean
-pulse_stream_set_channel_decibel (MateMixerStream *stream,
- guint channel,
- gdouble decibel)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME) ||
- !(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SET_VOLUME))
- return FALSE;
-
- return pulse_stream_set_channel_volume (stream, channel, pa_sw_volume_from_dB (decibel));
-}
-
-static MateMixerChannelPosition
-pulse_stream_get_channel_position (MateMixerStream *stream, guint channel)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), MATE_MIXER_CHANNEL_UNKNOWN);
-
- pstream = PULSE_STREAM (stream);
-
- if (channel >= pstream->priv->channel_map.channels)
- return MATE_MIXER_CHANNEL_UNKNOWN;
-
- return pulse_convert_position_to_pulse (pstream->priv->channel_map.map[channel]);
-}
-
-static gboolean
-pulse_stream_has_channel_position (MateMixerStream *stream,
- MateMixerChannelPosition position)
-{
- PulseStream *pstream;
- pa_channel_position_t p;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- /* Handle invalid position as a special case, otherwise this function would
- * return TRUE for e.g. unknown index in a default channel map */
- p = pulse_convert_position_to_pulse (position);
-
- if (p == PA_CHANNEL_POSITION_INVALID)
- return FALSE;
-
- if (pa_channel_map_has_position (&pstream->priv->channel_map, p) != 0)
- return TRUE;
- else
- return FALSE;
-}
-
-static gfloat
-pulse_stream_get_balance (MateMixerStream *stream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), 0.0f);
-
- return PULSE_STREAM (stream)->priv->balance;
-}
-
-static gboolean
-pulse_stream_set_balance (MateMixerStream *stream, gfloat balance)
-{
- PulseStream *pstream;
- pa_cvolume cvolume;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_BALANCE))
- return FALSE;
-
- cvolume = pstream->priv->cvolume;
-
- if (pa_cvolume_set_balance (&cvolume, &pstream->priv->channel_map, balance) == NULL)
- return FALSE;
-
- return set_cvolume (pstream, &cvolume);
-}
-
-static gfloat
-pulse_stream_get_fade (MateMixerStream *stream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), 0.0f);
-
- return PULSE_STREAM (stream)->priv->fade;
-}
-
-static gboolean
-pulse_stream_set_fade (MateMixerStream *stream, gfloat fade)
-{
- PulseStream *pstream;
- pa_cvolume cvolume;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_FADE))
- return FALSE;
-
- cvolume = pstream->priv->cvolume;
-
- if (pa_cvolume_set_fade (&cvolume, &pstream->priv->channel_map, fade) == NULL)
- return FALSE;
-
- return set_cvolume (pstream, &cvolume);
-}
-
-static gboolean
-pulse_stream_suspend (MateMixerStream *stream)
-{
- PulseStream *pstream;
- PulseStreamClass *klass;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND))
- return FALSE;
-
- if (pstream->priv->state == MATE_MIXER_STREAM_STATE_SUSPENDED)
- return FALSE;
-
- klass = PULSE_STREAM_GET_CLASS (pstream);
-
- if (klass->suspend (pstream) == FALSE)
- return FALSE;
-
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_SUSPENDED);
- return TRUE;
-}
-
-static gboolean
-pulse_stream_resume (MateMixerStream *stream)
-{
- PulseStream *pstream;
- PulseStreamClass *klass;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND))
- return FALSE;
-
- if (pstream->priv->state != MATE_MIXER_STREAM_STATE_SUSPENDED)
- return FALSE;
-
- klass = PULSE_STREAM_GET_CLASS (pstream);
-
- if (klass->resume (pstream) == FALSE)
- return FALSE;
-
- /* The state when resumed should be either RUNNING or IDLE, let's assume
- * IDLE for now and request an immediate update */
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_IDLE);
-
- klass->reload (pstream);
- return TRUE;
-}
-
-static gboolean
-pulse_stream_monitor_start (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_MONITOR))
- return FALSE;
-
- if (pstream->priv->monitor == NULL) {
- pstream->priv->monitor = PULSE_STREAM_GET_CLASS (pstream)->create_monitor (pstream);
-
- if (G_UNLIKELY (pstream->priv->monitor == NULL))
- return FALSE;
-
- pulse_monitor_set_name (pstream->priv->monitor,
- pstream->priv->monitor_name);
-
- g_signal_connect (G_OBJECT (pstream->priv->monitor),
- "value",
- G_CALLBACK (on_monitor_value),
- pstream);
- }
-
- return pulse_monitor_set_enabled (pstream->priv->monitor, TRUE);
-}
-
-static void
-pulse_stream_monitor_stop (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_if_fail (PULSE_IS_STREAM (stream));
-
- pstream = PULSE_STREAM (stream);
-
- if (pstream->priv->monitor != NULL)
- pulse_monitor_set_enabled (pstream->priv->monitor, FALSE);
-}
-
-static gboolean
-pulse_stream_monitor_is_running (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (pstream->priv->monitor != NULL)
- return pulse_monitor_get_enabled (pstream->priv->monitor);
-
- return FALSE;
-}
-
-static gboolean
-pulse_stream_monitor_set_name (MateMixerStream *stream, const gchar *name)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (pstream->priv->monitor != NULL)
- pulse_monitor_set_name (pstream->priv->monitor, name);
-
- pstream->priv->monitor_name = g_strdup (name);
- return TRUE;
-}
-
-static const GList *
-pulse_stream_list_ports (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
-
- pstream = PULSE_STREAM (stream);
-
- if (pstream->priv->ports_list == NULL) {
- GList *list = g_hash_table_get_values (pstream->priv->ports);
-
- if (list != NULL) {
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
-
- pstream->priv->ports_list = g_list_sort (list, compare_ports);
- }
- }
-
- return (const GList *) pstream->priv->ports_list;
-}
-
-static MateMixerPort *
-pulse_stream_get_active_port (MateMixerStream *stream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
-
- return PULSE_STREAM (stream)->priv->port;
-}
-
-static gboolean
-pulse_stream_set_active_port (MateMixerStream *stream, MateMixerPort *port)
-{
- PulseStream *pstream;
- PulseStreamClass *klass;
- const gchar *name;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- /* Make sure the port comes from this stream */
- name = mate_mixer_port_get_name (port);
-
- if (g_hash_table_lookup (pstream->priv->ports, name) == NULL) {
- g_warning ("Port %s does not belong to stream %s",
- mate_mixer_port_get_name (port),
- mate_mixer_stream_get_name (stream));
- return FALSE;
- }
-
- klass = PULSE_STREAM_GET_CLASS (pstream);
-
- /* Change the port */
- if (klass->set_active_port (pstream, port) == FALSE)
- return FALSE;
-
- if (pstream->priv->port != NULL)
- g_object_unref (pstream->priv->port);
-
- pstream->priv->port = g_object_ref (port);
-
- g_object_notify (G_OBJECT (stream), "active-port");
- return TRUE;
-}
-
-static guint
-pulse_stream_get_min_volume (MateMixerStream *stream)
-{
- return (guint) PA_VOLUME_MUTED;
-}
-
-static guint
-pulse_stream_get_max_volume (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), (guint) PA_VOLUME_MUTED);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_VOLUME))
- return (guint) PA_VOLUME_MUTED;
-
- return (guint) PA_VOLUME_UI_MAX;
-}
-
-static guint
-pulse_stream_get_normal_volume (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), (guint) PA_VOLUME_MUTED);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_VOLUME))
- return (guint) PA_VOLUME_MUTED;
-
- return (guint) PA_VOLUME_NORM;
-}
-
-static guint
-pulse_stream_get_base_volume (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), (guint) PA_VOLUME_MUTED);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_VOLUME))
- return (guint) PA_VOLUME_MUTED;
-
- if (pstream->priv->base_volume > 0)
- return pstream->priv->base_volume;
- else
- return (guint) PA_VOLUME_NORM;
-}
-
-static void
-on_monitor_value (PulseMonitor *monitor, gdouble value, PulseStream *pstream)
-{
- g_signal_emit_by_name (G_OBJECT (pstream),
- "monitor-value",
- value);
-}
-
-static gboolean
-update_balance_fade (PulseStream *pstream)
-{
- gfloat fade;
- gfloat balance;
- gboolean changed = FALSE;
-
- /* The PulseAudio return the default 0.0f values on errors, so skip checking
- * validity of the channel map and volume */
- balance = pa_cvolume_get_balance (&pstream->priv->cvolume,
- &pstream->priv->channel_map);
-
- if (pstream->priv->balance != balance) {
- pstream->priv->balance = balance;
-
- g_object_notify (G_OBJECT (pstream), "balance");
- changed = TRUE;
- }
-
- fade = pa_cvolume_get_fade (&pstream->priv->cvolume,
- &pstream->priv->channel_map);
-
- if (pstream->priv->fade != fade) {
- pstream->priv->fade = fade;
-
- g_object_notify (G_OBJECT (pstream), "fade");
- changed = TRUE;
- }
-
- return changed;
-}
-
-static gboolean
-set_cvolume (PulseStream *pstream, pa_cvolume *cvolume)
-{
- PulseStreamClass *klass;
-
- if (pa_cvolume_valid (cvolume) == 0)
- return FALSE;
- if (pa_cvolume_equal (cvolume, &pstream->priv->cvolume) != 0)
- return TRUE;
-
- klass = PULSE_STREAM_GET_CLASS (pstream);
-
- if (klass->set_volume (pstream, cvolume) == FALSE)
- return FALSE;
-
- pstream->priv->cvolume = *cvolume;
- pstream->priv->volume = (guint) pa_cvolume_max (cvolume);
-
- g_object_notify (G_OBJECT (pstream), "volume");
-
- /* Changing volume may change the balance and fade values as well */
- update_balance_fade (pstream);
- return TRUE;
-}
-
-static gint
-compare_ports (gconstpointer a, gconstpointer b)
-{
- MateMixerPort *p1 = MATE_MIXER_PORT (a);
- MateMixerPort *p2 = MATE_MIXER_PORT (b);
+ device = mate_mixer_stream_get_device (MATE_MIXER_STREAM (stream));
+ if (device != NULL)
+ return PULSE_DEVICE (device);
- gint ret = (gint) (mate_mixer_port_get_priority (p2) -
- mate_mixer_port_get_priority (p1));
- if (ret != 0)
- return ret;
- else
- return strcmp (mate_mixer_port_get_name (p1),
- mate_mixer_port_get_name (p2));
+ return NULL;
}
diff --git a/backends/pulse/pulse-stream.h b/backends/pulse/pulse-stream.h
index e4c6a00..eafe457 100644
--- a/backends/pulse/pulse-stream.h
+++ b/backends/pulse/pulse-stream.h
@@ -20,15 +20,11 @@
#include <glib.h>
#include <glib-object.h>
-
-#include <libmatemixer/matemixer-device.h>
-#include <libmatemixer/matemixer-port.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
#include <pulse/pulseaudio.h>
-#include "pulse-connection.h"
-#include "pulse-monitor.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
@@ -45,13 +41,12 @@ G_BEGIN_DECLS
#define PULSE_STREAM_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_STREAM, PulseStreamClass))
-typedef struct _PulseStream PulseStream;
typedef struct _PulseStreamClass PulseStreamClass;
typedef struct _PulseStreamPrivate PulseStreamPrivate;
struct _PulseStream
{
- GObject parent;
+ MateMixerStream parent;
/*< private >*/
PulseStreamPrivate *priv;
@@ -59,58 +54,15 @@ struct _PulseStream
struct _PulseStreamClass
{
- GObjectClass parent_class;
-
- /*< private >*/
- /* Virtual table */
- void (*reload) (PulseStream *stream);
-
- gboolean (*set_mute) (PulseStream *stream,
- gboolean mute);
- gboolean (*set_volume) (PulseStream *stream,
- pa_cvolume *volume);
-
- gboolean (*set_active_port) (PulseStream *stream,
- MateMixerPort *port);
-
- gboolean (*suspend) (PulseStream *stream);
- gboolean (*resume) (PulseStream *stream);
-
- PulseMonitor *(*create_monitor) (PulseStream *stream);
+ MateMixerStreamClass parent_class;
};
-GType pulse_stream_get_type (void) G_GNUC_CONST;
-
-guint32 pulse_stream_get_index (PulseStream *pstream);
-PulseConnection * pulse_stream_get_connection (PulseStream *pstream);
-PulseMonitor * pulse_stream_get_monitor (PulseStream *pstream);
-GHashTable * pulse_stream_get_ports (PulseStream *pstream);
-
-const pa_cvolume * pulse_stream_get_cvolume (PulseStream *pstream);
-const pa_channel_map *pulse_stream_get_channel_map (PulseStream *pstream);
-
-gboolean pulse_stream_update_name (PulseStream *pstream,
- const gchar *name);
-gboolean pulse_stream_update_description (PulseStream *pstream,
- const gchar *description);
-gboolean pulse_stream_update_device (PulseStream *pstream,
- MateMixerDevice *device);
-gboolean pulse_stream_update_flags (PulseStream *pstream,
- MateMixerStreamFlags flags);
-gboolean pulse_stream_update_state (PulseStream *pstream,
- MateMixerStreamState state);
-
-gboolean pulse_stream_update_channel_map (PulseStream *pstream,
- const pa_channel_map *map);
-gboolean pulse_stream_update_volume (PulseStream *pstream,
- const pa_cvolume *volume,
- pa_volume_t base_volume);
+GType pulse_stream_get_type (void) G_GNUC_CONST;
-gboolean pulse_stream_update_mute (PulseStream *pstream,
- gboolean mute);
+guint32 pulse_stream_get_index (PulseStream *stream);
+PulseConnection *pulse_stream_get_connection (PulseStream *stream);
-gboolean pulse_stream_update_active_port (PulseStream *pstream,
- MateMixerPort *port);
+PulseDevice * pulse_stream_get_device (PulseStream *stream);
G_END_DECLS
diff --git a/backends/pulse/pulse-types.h b/backends/pulse/pulse-types.h
new file mode 100644
index 0000000..c664268
--- /dev/null
+++ b/backends/pulse/pulse-types.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_TYPES_H
+#define PULSE_TYPES_H
+
+G_BEGIN_DECLS
+
+typedef struct _PulseBackend PulseBackend;
+typedef struct _PulseConnection PulseConnection;
+typedef struct _PulseDevice PulseDevice;
+typedef struct _PulseDeviceProfile PulseDeviceProfile;
+typedef struct _PulseDeviceSwitch PulseDeviceSwitch;
+typedef struct _PulseExtStream PulseExtStream;
+typedef struct _PulseMonitor PulseMonitor;
+typedef struct _PulsePort PulsePort;
+typedef struct _PulsePortSwitch PulsePortSwitch;
+typedef struct _PulseSink PulseSink;
+typedef struct _PulseSinkControl PulseSinkControl;
+typedef struct _PulseSinkInput PulseSinkInput;
+typedef struct _PulseSinkSwitch PulseSinkSwitch;
+typedef struct _PulseSource PulseSource;
+typedef struct _PulseSourceControl PulseSourceControl;
+typedef struct _PulseSourceOutput PulseSourceOutput;
+typedef struct _PulseSourceSwitch PulseSourceSwitch;
+typedef struct _PulseStream PulseStream;
+typedef struct _PulseStreamControl PulseStreamControl;
+
+G_END_DECLS
+
+#endif /* PULSE_TYPES_H */
diff --git a/configure.ac b/configure.ac
index d3c2173..f2d70e0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -41,7 +41,7 @@ AC_PROG_INSTALL
# Checks for header files.
AC_HEADER_STDC
-AC_CHECK_HEADERS([string.h math.h sys/types.h unistd.h locale.h])
+AC_CHECK_HEADERS([string.h math.h sys/types.h unistd.h libintl.h locale.h])
# =======================================================================
# Libtool
@@ -57,6 +57,18 @@ LT_PREREQ([2.2])
LT_INIT
# =======================================================================
+# Gettext
+# =======================================================================
+AM_GNU_GETTEXT_VERSION([0.18])
+AM_GNU_GETTEXT([external])
+
+IT_PROG_INTLTOOL([0.35.0])
+
+GETTEXT_PACKAGE=libmatemixer
+AC_SUBST(GETTEXT_PACKAGE)
+AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext Package])
+
+# =======================================================================
# Check for required packages
# =======================================================================
PKG_PROG_PKG_CONFIG
@@ -257,6 +269,7 @@ docs/Makefile
docs/reference/Makefile
docs/reference/version.xml
examples/Makefile
+po/Makefile.in
])
AC_OUTPUT
diff --git a/examples/monitor.c b/examples/monitor.c
index 71d8b61..87e41f3 100644
--- a/examples/monitor.c
+++ b/examples/monitor.c
@@ -66,48 +66,60 @@ get_stream_control_role_string (MateMixerStreamControlRole role)
return "Master";
case MATE_MIXER_STREAM_CONTROL_ROLE_PCM:
return "PCM";
+ case MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER:
+ return "Speaker";
+ case MATE_MIXER_STREAM_CONTROL_ROLE_MICROPHONE:
+ return "Microphone";
+ case MATE_MIXER_STREAM_CONTROL_ROLE_PORT:
+ return "Port";
+ case MATE_MIXER_STREAM_CONTROL_ROLE_BOOST:
+ return "Boost";
case MATE_MIXER_STREAM_CONTROL_ROLE_BASS:
return "Bass";
case MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE:
return "Treble";
case MATE_MIXER_STREAM_CONTROL_ROLE_CD:
return "CD";
- case MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER:
- return "PC Speaker";
- case MATE_MIXER_STREAM_CONTROL_ROLE_PORT:
- return "Port";
+ case MATE_MIXER_STREAM_CONTROL_ROLE_VIDEO:
+ return "Video";
+ case MATE_MIXER_STREAM_CONTROL_ROLE_MUSIC:
+ return "Music";
+ default:
+ break;
}
return "Unknown";
}
static const gchar *
-create_role_string (MateMixerClientStreamRole role)
+get_stream_control_media_role_string (MateMixerStreamControlMediaRole role)
{
switch (role) {
- case MATE_MIXER_CLIENT_STREAM_ROLE_NONE:
- return "None";
- case MATE_MIXER_CLIENT_STREAM_ROLE_VIDEO:
+ case MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN:
+ return "Unknown";
+ case MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_VIDEO:
return "Video";
- case MATE_MIXER_CLIENT_STREAM_ROLE_MUSIC:
+ case MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_MUSIC:
return "Music";
- case MATE_MIXER_CLIENT_STREAM_ROLE_GAME:
+ case MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_GAME:
return "Game";
- case MATE_MIXER_CLIENT_STREAM_ROLE_EVENT:
+ case MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_EVENT:
return "Event";
- case MATE_MIXER_CLIENT_STREAM_ROLE_PHONE:
+ case MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_PHONE:
return "Phone";
- case MATE_MIXER_CLIENT_STREAM_ROLE_ANIMATION:
+ case MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_ANIMATION:
return "Animation";
- case MATE_MIXER_CLIENT_STREAM_ROLE_PRODUCTION:
+ case MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_PRODUCTION:
return "Production";
- case MATE_MIXER_CLIENT_STREAM_ROLE_A11Y:
+ case MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_A11Y:
return "A11y";
- case MATE_MIXER_CLIENT_STREAM_ROLE_TEST:
+ case MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_TEST:
return "Test";
- case MATE_MIXER_CLIENT_STREAM_ROLE_ABSTRACT:
+ case MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_ABSTRACT:
return "Abstract";
- case MATE_MIXER_CLIENT_STREAM_ROLE_FILTER:
+ case MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_FILTER:
return "Filter";
+ default:
+ break;
}
return "Unknown";
}
@@ -145,9 +157,7 @@ create_volume_bar (MateMixerStreamControl *ctl, double *percent)
static void
print_devices (void)
{
- const GList *devices;
- const GList *profiles;
- MateMixerDeviceProfile *active_profile;
+ const GList *devices;
devices = mate_mixer_context_list_devices (context);
@@ -161,30 +171,6 @@ print_devices (void)
mate_mixer_device_get_label (device),
mate_mixer_device_get_icon (device));
- profiles = mate_mixer_device_list_profiles (device);
-
- active_profile = mate_mixer_device_get_active_profile (device);
- while (profiles) {
- MateMixerDeviceProfile *profile = MATE_MIXER_DEVICE_PROFILE (profiles->data);
-
- g_print (" |%c| Profile %s\n"
- " |-| Label : %s\n"
- " |-| Priority : %u\n"
- " |-| Inputs : %u\n"
- " |-| Outputs : %u\n\n",
- (profile == active_profile)
- ? 'A'
- : '-',
- mate_mixer_device_profile_get_name (profile),
- mate_mixer_device_profile_get_label (profile),
- mate_mixer_device_profile_get_priority (profile),
- mate_mixer_device_profile_get_num_input_streams (profile),
- mate_mixer_device_profile_get_num_output_streams (profile));
-
- profiles = profiles->next;
- }
- g_print ("\n");
-
const GList *switches = mate_mixer_device_list_switches (device);
while (switches != NULL) {
@@ -201,11 +187,12 @@ print_devices (void)
while (options != NULL) {
MateMixerSwitchOption *option = MATE_MIXER_SWITCH_OPTION (options->data);
- g_print (" |%c| %s\n",
+ g_print (" |%c| %s (icon: %s)\n",
(option == active)
? '*'
: '-',
- mate_mixer_switch_option_get_label (option));
+ mate_mixer_switch_option_get_label (option),
+ mate_mixer_switch_option_get_icon (option));
options = options->next;
}
@@ -229,19 +216,12 @@ print_streams (void)
MateMixerStream *stream = MATE_MIXER_STREAM (streams->data);
MateMixerStreamControl *ctl;
MateMixerSwitch *swtch;
- MateMixerClientStream *client = NULL;
gchar *volume_bar;
gdouble volume;
const GList *controls;
const GList *switches;
- if (mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_CLIENT) {
- /* The application-specific details are accessible through the client
- * interface, which all client streams implement */
- client = MATE_MIXER_CLIENT_STREAM (stream);
- }
-
controls = mate_mixer_stream_list_controls (stream);
while (controls != NULL) {
@@ -286,94 +266,28 @@ print_streams (void)
options = mate_mixer_switch_list_options (swtch);
+ MateMixerSwitchOption *active = mate_mixer_switch_get_active_option (swtch);
+
g_print ("Switch %s\n",
mate_mixer_switch_get_name (swtch));
while (options != NULL) {
MateMixerSwitchOption *option = MATE_MIXER_SWITCH_OPTION (options->data);
- g_print (" |%c| %s\n",
- '-',
- mate_mixer_switch_option_get_label (option));
+ g_print (" |%c| %s (icon: %s)\n",
+ (option == active)
+ ? '*'
+ : '-',
+ mate_mixer_switch_option_get_label (option),
+ mate_mixer_switch_option_get_icon (option));
options = options->next;
}
- options = options->next;
- }
-
- if (client != NULL) {
- MateMixerClientStreamFlags client_flags;
-
- client_flags = mate_mixer_client_stream_get_flags (client);
-
- if (client_flags & MATE_MIXER_CLIENT_STREAM_APPLICATION) {
- gchar *app = create_app_string (mate_mixer_client_stream_get_app_name (client),
- mate_mixer_client_stream_get_app_id (client),
- mate_mixer_client_stream_get_app_version (client));
-
- g_print (" |-| Application : %s\n", app);
- g_free (app);
- }
- }
-
- g_print ("\n");
-
- streams = streams->next;
- }
-}
-
-static void
-print_stored_streams (void)
-{
- const GList *streams;
-
- streams = mate_mixer_context_list_stored_streams (context);
-
- while (streams) {
- MateMixerStream *stream = MATE_MIXER_STREAM (streams->data);
- MateMixerStreamControl *ctl;
- MateMixerClientStream *client;
- MateMixerClientStreamFlags client_flags;
- MateMixerClientStreamRole client_role;
- gchar *volume_bar;
- gdouble volume;
-
- ctl = mate_mixer_stream_get_default_control (stream);
-
- client = MATE_MIXER_CLIENT_STREAM (stream);
- client_flags = mate_mixer_client_stream_get_flags (client);
- client_role = mate_mixer_client_stream_get_role (client);
-
- volume_bar = create_volume_bar (ctl, &volume);
-
- g_print ("Stored stream %s\n"
- " |-| Role : %s\n"
- " |-| Volume : %s %.1f %%\n"
- " |-| Muted : %s\n"
- " |-| Channels : %d\n"
- " |-| Balance : %.1f\n"
- " |-| Fade : %.1f\n",
- mate_mixer_stream_get_name (stream),
- create_role_string (client_role),
- volume_bar,
- volume,
- mate_mixer_stream_control_get_mute (ctl) ? "Yes" : "No",
- mate_mixer_stream_control_get_num_channels (ctl),
- mate_mixer_stream_control_get_balance (ctl),
- mate_mixer_stream_control_get_fade (ctl));
-
- if (client_flags & MATE_MIXER_CLIENT_STREAM_APPLICATION) {
- gchar *app = create_app_string (mate_mixer_client_stream_get_app_name (client),
- mate_mixer_client_stream_get_app_id (client),
- mate_mixer_client_stream_get_app_version (client));
-
- g_print (" |-| Application : %s\n", app);
- g_free (app);
+ switches = switches->next;
}
g_print ("\n");
- g_free (volume_bar);
streams = streams->next;
}
@@ -387,7 +301,6 @@ connected (void)
print_devices ();
print_streams ();
- print_stored_streams ();
g_print ("Waiting for events. Hit CTRL+C to quit.\n");
}
diff --git a/libmatemixer/Makefile.am b/libmatemixer/Makefile.am
index 8858b90..d7075cb 100644
--- a/libmatemixer/Makefile.am
+++ b/libmatemixer/Makefile.am
@@ -10,11 +10,12 @@ libmatemixer_includedir = $(includedir)/libmatemixer
libmatemixer_include_HEADERS = \
matemixer.h \
- matemixer-client-stream.h \
+ matemixer-app-info.h \
matemixer-context.h \
matemixer-device.h \
- matemixer-device-profile.h \
matemixer-enums.h \
+ matemixer-enum-types.h \
+ matemixer-stored-control.h \
matemixer-stream.h \
matemixer-stream-control.h \
matemixer-switch.h \
@@ -28,19 +29,18 @@ libmatemixer_la_CFLAGS = $(GLIB_CFLAGS)
libmatemixer_la_SOURCES = \
matemixer.c \
matemixer-private.h \
+ matemixer-app-info.c \
+ matemixer-app-info-private.h \
matemixer-backend.c \
matemixer-backend.h \
- matemixer-backend-private.h \
matemixer-backend-module.c \
matemixer-backend-module.h \
- matemixer-client-stream.c \
matemixer-context.c \
matemixer-device.c \
- matemixer-device-profile.c \
- matemixer-device-profile-private.h \
matemixer-enum-types.c \
- matemixer-enum-types.h \
+ matemixer-stored-control.c \
matemixer-stream.c \
+ matemixer-stream-private.h \
matemixer-stream-control.c \
matemixer-stream-control-private.h \
matemixer-switch.c \
diff --git a/libmatemixer/matemixer-app-info-private.h b/libmatemixer/matemixer-app-info-private.h
new file mode 100644
index 0000000..486b163
--- /dev/null
+++ b/libmatemixer/matemixer-app-info-private.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_APP_INFO_PRIVATE_H
+#define MATEMIXER_APP_INFO_PRIVATE_H
+
+#include <glib.h>
+
+#include "matemixer-types.h"
+
+G_BEGIN_DECLS
+
+struct _MateMixerAppInfo
+{
+ gchar *name;
+ gchar *id;
+ gchar *version;
+ gchar *icon;
+};
+
+MateMixerAppInfo *_mate_mixer_app_info_new (void);
+
+void _mate_mixer_app_info_set_name (MateMixerAppInfo *info,
+ const gchar *name);
+void _mate_mixer_app_info_set_id (MateMixerAppInfo *info,
+ const gchar *id);
+void _mate_mixer_app_info_set_version (MateMixerAppInfo *info,
+ const gchar *version);
+void _mate_mixer_app_info_set_icon (MateMixerAppInfo *info,
+ const gchar *icon);
+
+MateMixerAppInfo *_mate_mixer_app_info_copy (MateMixerAppInfo *info);
+void _mate_mixer_app_info_free (MateMixerAppInfo *info);
+
+G_END_DECLS
+
+#endif /* MATEMIXER_APP_INFO_PRIVATE_H */
diff --git a/libmatemixer/matemixer-app-info.c b/libmatemixer/matemixer-app-info.c
new file mode 100644
index 0000000..369f148
--- /dev/null
+++ b/libmatemixer/matemixer-app-info.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "matemixer-app-info.h"
+#include "matemixer-app-info-private.h"
+
+G_DEFINE_BOXED_TYPE (MateMixerAppInfo, mate_mixer_app_info,
+ _mate_mixer_app_info_copy,
+ _mate_mixer_app_info_free)
+
+/**
+ * mate_mixer_app_info_get_name:
+ * @device: a #MateMixerAppInfo
+ */
+const gchar *
+mate_mixer_app_info_get_name (MateMixerAppInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->name;
+}
+
+/**
+ * mate_mixer_app_info_get_id:
+ * @device: a #MateMixerAppInfo
+ */
+const gchar *
+mate_mixer_app_info_get_id (MateMixerAppInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->id;
+}
+
+/**
+ * mate_mixer_app_info_get_version:
+ * @device: a #MateMixerAppInfo
+ */
+const gchar *
+mate_mixer_app_info_get_version (MateMixerAppInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->version;
+}
+
+/**
+ * mate_mixer_app_info_get_icon:
+ * @device: a #MateMixerAppInfo
+ */
+const gchar *
+mate_mixer_app_info_get_icon (MateMixerAppInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->icon;
+}
+
+MateMixerAppInfo *
+_mate_mixer_app_info_new (void)
+{
+ return g_slice_new0 (MateMixerAppInfo);
+}
+
+void
+_mate_mixer_app_info_set_name (MateMixerAppInfo *info, const gchar *name)
+{
+ g_return_if_fail (info != NULL);
+
+ g_free (info->name);
+
+ info->name = g_strdup (name);
+}
+
+void
+_mate_mixer_app_info_set_id (MateMixerAppInfo *info, const gchar *id)
+{
+ g_return_if_fail (info != NULL);
+
+ g_free (info->id);
+
+ info->id = g_strdup (id);
+}
+
+void
+_mate_mixer_app_info_set_version (MateMixerAppInfo *info, const gchar *version)
+{
+ g_return_if_fail (info != NULL);
+
+ g_free (info->version);
+
+ info->version = g_strdup (version);
+}
+
+void
+_mate_mixer_app_info_set_icon (MateMixerAppInfo *info, const gchar *icon)
+{
+ g_return_if_fail (info != NULL);
+
+ g_free (info->icon);
+
+ info->icon = g_strdup (icon);
+}
+
+MateMixerAppInfo *
+_mate_mixer_app_info_copy (MateMixerAppInfo *info)
+{
+ MateMixerAppInfo *info2;
+
+ info2 = _mate_mixer_app_info_new ();
+ info2->name = g_strdup (info->name);
+ info2->id = g_strdup (info->id);
+ info2->version = g_strdup (info->version);
+ info2->icon = g_strdup (info->icon);
+
+ return info2;
+}
+
+void
+_mate_mixer_app_info_free (MateMixerAppInfo *info)
+{
+ g_free (info->name);
+ g_free (info->id);
+ g_free (info->version);
+ g_free (info->icon);
+
+ g_slice_free (MateMixerAppInfo, info);
+}
diff --git a/libmatemixer/matemixer-backend-private.h b/libmatemixer/matemixer-app-info.h
index b5de8ae..eedc1c7 100644
--- a/libmatemixer/matemixer-backend-private.h
+++ b/libmatemixer/matemixer-app-info.h
@@ -15,26 +15,26 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef MATEMIXER_BACKEND_PRIVATE_H
-#define MATEMIXER_BACKEND_PRIVATE_H
+#ifndef MATEMIXER_APP_INFO_H
+#define MATEMIXER_APP_INFO_H
#include <glib.h>
+#include <glib-object.h>
-#include "matemixer-backend.h"
-#include "matemixer-enums.h"
-#include "matemixer-stream.h"
+#include "matemixer-types.h"
G_BEGIN_DECLS
-void _mate_mixer_backend_set_state (MateMixerBackend *backend,
- MateMixerState state);
+#define MATE_MIXER_TYPE_APP_INFO (mate_mixer_app_info_get_type ())
+#define MATE_MIXER_APP_INFO(o) ((MateMixerAppInfo *) o)
-void _mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,
- MateMixerStream *stream);
+GType mate_mixer_app_info_get_type (void) G_GNUC_CONST;
-void _mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend,
- MateMixerStream *stream);
+const gchar *mate_mixer_app_info_get_name (MateMixerAppInfo *info);
+const gchar *mate_mixer_app_info_get_id (MateMixerAppInfo *info);
+const gchar *mate_mixer_app_info_get_version (MateMixerAppInfo *info);
+const gchar *mate_mixer_app_info_get_icon (MateMixerAppInfo *info);
G_END_DECLS
-#endif /* MATEMIXER_BACKEND_PRIVATE_H */
+#endif /* MATEMIXER_APP_INFO_H */
diff --git a/libmatemixer/matemixer-backend-module.c b/libmatemixer/matemixer-backend-module.c
index 0e7716e..bd71de0 100644
--- a/libmatemixer/matemixer-backend-module.c
+++ b/libmatemixer/matemixer-backend-module.c
@@ -19,7 +19,6 @@
#include <glib-object.h>
#include <gmodule.h>
-#include "matemixer-backend.h"
#include "matemixer-backend-module.h"
/* Initialize backend */
diff --git a/libmatemixer/matemixer-backend-module.h b/libmatemixer/matemixer-backend-module.h
index e1dfd8d..dc95633 100644
--- a/libmatemixer/matemixer-backend-module.h
+++ b/libmatemixer/matemixer-backend-module.h
@@ -21,7 +21,7 @@
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-enums.h>
+#include "matemixer-enums.h"
G_BEGIN_DECLS
diff --git a/libmatemixer/matemixer-backend.c b/libmatemixer/matemixer-backend.c
index fab0883..b8177e3 100644
--- a/libmatemixer/matemixer-backend.c
+++ b/libmatemixer/matemixer-backend.c
@@ -20,16 +20,16 @@
#include <glib-object.h>
#include "matemixer-backend.h"
-#include "matemixer-backend-private.h"
+#include "matemixer-device.h"
#include "matemixer-enums.h"
#include "matemixer-enum-types.h"
#include "matemixer-stream.h"
+#include "matemixer-stream-control.h"
+#include "matemixer-stored-control.h"
struct _MateMixerBackendPrivate
{
- GList *devices;
- GList *streams;
- GList *stored_streams;
+ GHashTable *devices;
MateMixerStream *default_input;
MateMixerStream *default_output;
MateMixerState state;
@@ -51,8 +51,8 @@ enum {
DEVICE_REMOVED,
STREAM_ADDED,
STREAM_REMOVED,
- STORED_STREAM_ADDED,
- STORED_STREAM_REMOVED,
+ STORED_CONTROL_ADDED,
+ STORED_CONTROL_REMOVED,
N_SIGNALS
};
@@ -72,22 +72,19 @@ static void mate_mixer_backend_set_property (GObject *object,
GParamSpec *pspec);
static void mate_mixer_backend_dispose (GObject *object);
+static void mate_mixer_backend_finalize (GObject *object);
G_DEFINE_ABSTRACT_TYPE (MateMixerBackend, mate_mixer_backend, G_TYPE_OBJECT)
-static void device_added (MateMixerBackend *backend, const gchar *name);
-static void device_removed (MateMixerBackend *backend, const gchar *name);
+static void device_added (MateMixerBackend *backend,
+ const gchar *name);
+static void device_removed (MateMixerBackend *backend,
+ const gchar *name);
-static void device_stream_added (MateMixerDevice *device,
- const gchar *name);
-static void device_stream_removed (MateMixerDevice *device,
- const gchar *name);
-
-static void free_devices (MateMixerBackend *backend);
-static void free_streams (MateMixerBackend *backend);
-static void free_stored_streams (MateMixerBackend *backend);
-static void stream_removed (MateMixerBackend *backend,
- const gchar *name);
+static void device_stream_added (MateMixerBackend *backend,
+ const gchar *name);
+static void device_stream_removed (MateMixerBackend *backend,
+ const gchar *name);
static void
mate_mixer_backend_class_init (MateMixerBackendClass *klass)
@@ -96,6 +93,7 @@ mate_mixer_backend_class_init (MateMixerBackendClass *klass)
object_class = G_OBJECT_CLASS (klass);
object_class->dispose = mate_mixer_backend_dispose;
+ object_class->finalize = mate_mixer_backend_finalize;
object_class->get_property = mate_mixer_backend_get_property;
object_class->set_property = mate_mixer_backend_set_property;
@@ -129,7 +127,7 @@ mate_mixer_backend_class_init (MateMixerBackendClass *klass)
signals[DEVICE_ADDED] =
g_signal_new ("device-added",
G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
+ G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (MateMixerBackendClass, device_added),
NULL,
NULL,
@@ -141,7 +139,7 @@ mate_mixer_backend_class_init (MateMixerBackendClass *klass)
signals[DEVICE_REMOVED] =
g_signal_new ("device-removed",
G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
+ G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (MateMixerBackendClass, device_removed),
NULL,
NULL,
@@ -153,7 +151,7 @@ mate_mixer_backend_class_init (MateMixerBackendClass *klass)
signals[STREAM_ADDED] =
g_signal_new ("stream-added",
G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
+ G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (MateMixerBackendClass, stream_added),
NULL,
NULL,
@@ -165,7 +163,7 @@ mate_mixer_backend_class_init (MateMixerBackendClass *klass)
signals[STREAM_REMOVED] =
g_signal_new ("stream-removed",
G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
+ G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (MateMixerBackendClass, stream_removed),
NULL,
NULL,
@@ -174,11 +172,11 @@ mate_mixer_backend_class_init (MateMixerBackendClass *klass)
1,
G_TYPE_STRING);
- signals[STORED_STREAM_ADDED] =
- g_signal_new ("stored-stream-added",
+ signals[STORED_CONTROL_ADDED] =
+ g_signal_new ("stored-control-added",
G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendClass, stored_stream_added),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (MateMixerBackendClass, stored_control_added),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -186,11 +184,11 @@ mate_mixer_backend_class_init (MateMixerBackendClass *klass)
1,
G_TYPE_STRING);
- signals[STORED_STREAM_REMOVED] =
- g_signal_new ("stored-stream-removed",
+ signals[STORED_CONTROL_REMOVED] =
+ g_signal_new ("stored-control-removed",
G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendClass, stored_stream_removed),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (MateMixerBackendClass, stored_control_removed),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -215,11 +213,9 @@ mate_mixer_backend_get_property (GObject *object,
case PROP_STATE:
g_value_set_enum (value, backend->priv->state);
break;
-
case PROP_DEFAULT_INPUT_STREAM:
g_value_set_object (value, backend->priv->default_input);
break;
-
case PROP_DEFAULT_OUTPUT_STREAM:
g_value_set_object (value, backend->priv->default_output);
break;
@@ -244,7 +240,6 @@ mate_mixer_backend_set_property (GObject *object,
case PROP_DEFAULT_INPUT_STREAM:
mate_mixer_backend_set_default_input_stream (backend, g_value_get_object (value));
break;
-
case PROP_DEFAULT_OUTPUT_STREAM:
mate_mixer_backend_set_default_output_stream (backend, g_value_get_object (value));
break;
@@ -262,10 +257,11 @@ mate_mixer_backend_init (MateMixerBackend *backend)
MATE_MIXER_TYPE_BACKEND,
MateMixerBackendPrivate);
- g_signal_connect (G_OBJECT (backend),
- "device-added",
- G_CALLBACK (free_devices),
- NULL);
+ backend->priv->devices = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
+
g_signal_connect (G_OBJECT (backend),
"device-added",
G_CALLBACK (device_added),
@@ -273,32 +269,8 @@ mate_mixer_backend_init (MateMixerBackend *backend)
g_signal_connect (G_OBJECT (backend),
"device-removed",
- G_CALLBACK (free_devices),
- NULL);
- g_signal_connect (G_OBJECT (backend),
- "device-removed",
G_CALLBACK (device_removed),
NULL);
-
- g_signal_connect (G_OBJECT (backend),
- "stream-added",
- G_CALLBACK (free_streams),
- NULL);
- g_signal_connect (G_OBJECT (backend),
- "stream-removed",
- G_CALLBACK (free_streams),
- NULL);
-
- g_signal_connect (G_OBJECT (backend),
- "stored-stream-added",
- G_CALLBACK (free_stored_streams),
- NULL);
- g_signal_connect (G_OBJECT (backend),
- "stored-stream-removed",
- G_CALLBACK (free_stored_streams),
- NULL);
-
- // XXX also free when changing state
}
static void
@@ -308,18 +280,28 @@ mate_mixer_backend_dispose (GObject *object)
backend = MATE_MIXER_BACKEND (object);
- free_devices (backend);
- free_streams (backend);
- free_stored_streams (backend);
-
g_clear_object (&backend->priv->default_input);
g_clear_object (&backend->priv->default_output);
+ g_hash_table_remove_all (backend->priv->devices);
+
G_OBJECT_CLASS (mate_mixer_backend_parent_class)->dispose (object);
}
+static void
+mate_mixer_backend_finalize (GObject *object)
+{
+ MateMixerBackend *backend;
+
+ backend = MATE_MIXER_BACKEND (object);
+
+ g_hash_table_unref (backend->priv->devices);
+
+ G_OBJECT_CLASS (mate_mixer_backend_parent_class)->finalize (object);
+}
+
void
-mate_mixer_backend_set_data (MateMixerBackend *backend, MateMixerBackendData *data)
+mate_mixer_backend_set_app_info (MateMixerBackend *backend, MateMixerAppInfo *info)
{
MateMixerBackendClass *klass;
@@ -327,8 +309,21 @@ mate_mixer_backend_set_data (MateMixerBackend *backend, MateMixerBackendData *da
klass = MATE_MIXER_BACKEND_GET_CLASS (backend);
- if (klass->set_data != NULL)
- klass->set_data (backend, data);
+ if (klass->set_app_info != NULL)
+ klass->set_app_info (backend, info);
+}
+
+void
+mate_mixer_backend_set_server_address (MateMixerBackend *backend, const gchar *address)
+{
+ MateMixerBackendClass *klass;
+
+ g_return_if_fail (MATE_MIXER_IS_BACKEND (backend));
+
+ klass = MATE_MIXER_BACKEND_GET_CLASS (backend);
+
+ if (klass->set_server_address != NULL)
+ klass->set_server_address (backend, address);
}
gboolean
@@ -369,72 +364,117 @@ mate_mixer_backend_get_flags (MateMixerBackend *backend)
return backend->priv->flags;
}
-const GList *
-mate_mixer_backend_list_devices (MateMixerBackend *backend)
+MateMixerDevice *
+mate_mixer_backend_get_device (MateMixerBackend *backend, const gchar *name)
{
+ const GList *list;
+
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
- if (backend->priv->devices == NULL) {
- MateMixerBackendClass *klass;
+ list = mate_mixer_backend_list_devices (backend);
+ while (list != NULL) {
+ MateMixerDevice *device = MATE_MIXER_DEVICE (list->data);
- klass = MATE_MIXER_BACKEND_GET_CLASS (backend);
+ if (strcmp (name, mate_mixer_device_get_name (device)) == 0)
+ return device;
- if (klass->list_devices != NULL)
- backend->priv->devices = klass->list_devices (backend);
+ list = list->next;
}
-
- return backend->priv->devices;
+ return NULL;
}
-const GList *
-mate_mixer_backend_list_streams (MateMixerBackend *backend)
+MateMixerStream *
+mate_mixer_backend_get_stream (MateMixerBackend *backend, const gchar *name)
{
+ const GList *list;
+
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
- if (backend->priv->streams == NULL) {
- MateMixerBackendClass *klass;
+ list = mate_mixer_backend_list_streams (backend);
+ while (list != NULL) {
+ MateMixerStream *stream = MATE_MIXER_STREAM (list->data);
- klass = MATE_MIXER_BACKEND_GET_CLASS (backend);
+ if (strcmp (name, mate_mixer_stream_get_name (stream)) == 0)
+ return stream;
- if (klass->list_streams != NULL)
- backend->priv->streams = klass->list_streams (backend);
+ list = list->next;
}
+ return NULL;
+}
+
+MateMixerStoredControl *
+mate_mixer_backend_get_stored_control (MateMixerBackend *backend, const gchar *name)
+{
+ const GList *list;
+
+ g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ list = mate_mixer_backend_list_stored_controls (backend);
+ while (list != NULL) {
+ MateMixerStreamControl *control = MATE_MIXER_STREAM_CONTROL (list->data);
- return backend->priv->streams;
+ if (strcmp (name, mate_mixer_stream_control_get_name (control)) == 0)
+ return MATE_MIXER_STORED_CONTROL (control);
+
+ list = list->next;
+ }
+ return NULL;
}
const GList *
-mate_mixer_backend_list_stored_streams (MateMixerBackend *backend)
+mate_mixer_backend_list_devices (MateMixerBackend *backend)
{
+ MateMixerBackendClass *klass;
+
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL);
- if (backend->priv->stored_streams == NULL) {
- MateMixerBackendClass *klass;
+ klass = MATE_MIXER_BACKEND_GET_CLASS (backend);
- klass = MATE_MIXER_BACKEND_GET_CLASS (backend);
+ if G_LIKELY (klass->list_devices != NULL)
+ return klass->list_devices (backend);
- if (klass->list_stored_streams != NULL)
- backend->priv->stored_streams = klass->list_stored_streams (backend);
- }
+ return NULL;
+}
+
+const GList *
+mate_mixer_backend_list_streams (MateMixerBackend *backend)
+{
+ MateMixerBackendClass *klass;
+
+ g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL);
- return backend->priv->stored_streams;
+ klass = MATE_MIXER_BACKEND_GET_CLASS (backend);
+
+ if G_LIKELY (klass->list_streams != NULL)
+ return klass->list_streams (backend);
+
+ return NULL;
}
-MateMixerStream *
-mate_mixer_backend_get_default_input_stream (MateMixerBackend *backend)
+const GList *
+mate_mixer_backend_list_stored_controls (MateMixerBackend *backend)
{
- MateMixerStream *stream = NULL;
+ MateMixerBackendClass *klass;
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL);
- g_object_get (G_OBJECT (backend),
- "default-input-stream", &stream,
- NULL);
+ klass = MATE_MIXER_BACKEND_GET_CLASS (backend);
- if (stream != NULL)
- g_object_unref (stream);
+ if (klass->list_stored_controls != NULL)
+ return klass->list_stored_controls (backend);
- return stream;
+ return NULL;
+}
+
+MateMixerStream *
+mate_mixer_backend_get_default_input_stream (MateMixerBackend *backend)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL);
+
+ return backend->priv->default_input;
}
gboolean
@@ -462,18 +502,9 @@ mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,
MateMixerStream *
mate_mixer_backend_get_default_output_stream (MateMixerBackend *backend)
{
- MateMixerStream *stream = NULL;
-
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL);
- g_object_get (G_OBJECT (backend),
- "default-output-stream", &stream,
- NULL);
-
- if (stream != NULL)
- g_object_unref (stream);
-
- return stream;
+ return backend->priv->default_output;
}
gboolean
@@ -503,87 +534,97 @@ device_added (MateMixerBackend *backend, const gchar *name)
{
MateMixerDevice *device;
- // device = mate_mixer_backend_get_device (backend, name);
+ device = mate_mixer_backend_get_device (backend, name);
+ if G_UNLIKELY (device == NULL) {
+ g_warn_if_reached ();
+ return;
+ }
-/*
- g_signal_connect (G_OBJECT (device),
- "stream-added",
- G_CALLBACK (device_stream_added));
- */
+ /* Keep the device in a hash table as it won't be possible to retrieve
+ * it when the remove signal is received */
+ g_hash_table_insert (backend->priv->devices,
+ g_strdup (name),
+ g_object_ref (device));
+
+ /* Connect to the stream signals from devices so we can forward them on
+ * the backend */
+ g_signal_connect_swapped (G_OBJECT (device),
+ "stream-added",
+ G_CALLBACK (device_stream_added),
+ backend);
+ g_signal_connect_swapped (G_OBJECT (device),
+ "stream-removed",
+ G_CALLBACK (device_stream_removed),
+ backend);
}
static void
device_removed (MateMixerBackend *backend, const gchar *name)
{
+ MateMixerDevice *device;
+
+ device = g_hash_table_lookup (backend->priv->devices, name);
+ if G_UNLIKELY (device == NULL) {
+ g_warn_if_reached ();
+ return;
+ }
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (device),
+ G_CALLBACK (device_stream_added),
+ backend);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (device),
+ G_CALLBACK (device_stream_removed),
+ backend);
+
+ g_hash_table_remove (backend->priv->devices, name);
}
static void
-device_stream_added (MateMixerDevice *device, const gchar *name)
+device_stream_added (MateMixerBackend *backend, const gchar *name)
{
- g_signal_emit (G_OBJECT (device),
+ g_signal_emit (G_OBJECT (backend),
signals[STREAM_ADDED],
0,
name);
}
static void
-device_stream_removed (MateMixerDevice *device, const gchar *name)
+device_stream_removed (MateMixerBackend *backend, const gchar *name)
{
- g_signal_emit (G_OBJECT (device),
+ g_signal_emit (G_OBJECT (backend),
signals[STREAM_REMOVED],
0,
name);
}
-static void
-free_devices (MateMixerBackend *backend)
-{
- if (backend->priv->devices == NULL)
- return;
-
- g_list_free_full (backend->priv->devices, g_object_unref);
-
- backend->priv->devices = NULL;
-}
-
-static void
-free_streams (MateMixerBackend *backend)
+/* Protected functions */
+void
+_mate_mixer_backend_set_state (MateMixerBackend *backend, MateMixerState state)
{
- if (backend->priv->streams == NULL)
- return;
-
- g_list_free_full (backend->priv->streams, g_object_unref);
-
- backend->priv->streams = NULL;
-}
+ g_return_if_fail (MATE_MIXER_IS_BACKEND (backend));
-static void
-free_stored_streams (MateMixerBackend *backend)
-{
- if (backend->priv->stored_streams == NULL)
+ if (backend->priv->state == state)
return;
- g_list_free_full (backend->priv->stored_streams, g_object_unref);
+ backend->priv->state = state;
- backend->priv->stored_streams = NULL;
+ g_object_notify_by_pspec (G_OBJECT (backend), properties[PROP_STATE]);
}
-/* Protected */
void
-_mate_mixer_backend_set_state (MateMixerBackend *backend, MateMixerState state)
+_mate_mixer_backend_set_flags (MateMixerBackend *backend, MateMixerBackendFlags flags)
{
- if (backend->priv->state == state)
- return;
-
- backend->priv->state = state;
+ g_return_if_fail (MATE_MIXER_IS_BACKEND (backend));
- g_object_notify_by_pspec (G_OBJECT (backend), properties[PROP_STATE]);
+ backend->priv->flags = flags;
}
void
_mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,
MateMixerStream *stream)
{
+ g_return_if_fail (MATE_MIXER_IS_BACKEND (backend));
+
if (backend->priv->default_input == stream)
return;
@@ -598,13 +639,16 @@ _mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,
g_debug ("Default input stream changed to %s",
(stream != NULL) ? mate_mixer_stream_get_name (stream) : "none");
- g_object_notify_by_pspec (G_OBJECT (backend), properties[PROP_DEFAULT_INPUT_STREAM]);
+ g_object_notify_by_pspec (G_OBJECT (backend),
+ properties[PROP_DEFAULT_INPUT_STREAM]);
}
void
_mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend,
MateMixerStream *stream)
{
+ g_return_if_fail (MATE_MIXER_IS_BACKEND (backend));
+
if (backend->priv->default_output == stream)
return;
@@ -619,5 +663,6 @@ _mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend,
g_debug ("Default output stream changed to %s",
(stream != NULL) ? mate_mixer_stream_get_name (stream) : "none");
- g_object_notify_by_pspec (G_OBJECT (backend), properties[PROP_DEFAULT_OUTPUT_STREAM]);
+ g_object_notify_by_pspec (G_OBJECT (backend),
+ properties[PROP_DEFAULT_OUTPUT_STREAM]);
}
diff --git a/libmatemixer/matemixer-backend.h b/libmatemixer/matemixer-backend.h
index 1c918c9..41ffb40 100644
--- a/libmatemixer/matemixer-backend.h
+++ b/libmatemixer/matemixer-backend.h
@@ -21,8 +21,8 @@
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-types.h>
+#include "matemixer-enums.h"
+#include "matemixer-types.h"
G_BEGIN_DECLS
@@ -41,7 +41,6 @@ G_BEGIN_DECLS
typedef struct _MateMixerBackend MateMixerBackend;
typedef struct _MateMixerBackendClass MateMixerBackendClass;
-typedef struct _MateMixerBackendData MateMixerBackendData;
typedef struct _MateMixerBackendPrivate MateMixerBackendPrivate;
struct _MateMixerBackend
@@ -57,67 +56,81 @@ struct _MateMixerBackendClass
GObjectClass parent_class;
/*< private >*/
- void (*set_data) (MateMixerBackend *backend,
- MateMixerBackendData *data);
+ void (*set_app_info) (MateMixerBackend *backend,
+ MateMixerAppInfo *info);
+ void (*set_server_address) (MateMixerBackend *backend,
+ const gchar *address);
- gboolean (*open) (MateMixerBackend *backend);
- void (*close) (MateMixerBackend *backend);
+ gboolean (*open) (MateMixerBackend *backend);
+ void (*close) (MateMixerBackend *backend);
- GList *(*list_devices) (MateMixerBackend *backend);
- GList *(*list_streams) (MateMixerBackend *backend);
- GList *(*list_stored_streams) (MateMixerBackend *backend);
+ const GList *(*list_devices) (MateMixerBackend *backend);
+ const GList *(*list_streams) (MateMixerBackend *backend);
+ const GList *(*list_stored_controls) (MateMixerBackend *backend);
- gboolean (*set_default_input_stream) (MateMixerBackend *backend,
- MateMixerStream *stream);
- gboolean (*set_default_output_stream) (MateMixerBackend *backend,
- MateMixerStream *stream);
+ gboolean (*set_default_input_stream) (MateMixerBackend *backend,
+ MateMixerStream *stream);
+ gboolean (*set_default_output_stream) (MateMixerBackend *backend,
+ MateMixerStream *stream);
/* Signals */
- void (*device_added) (MateMixerBackend *backend,
- const gchar *name);
- void (*device_removed) (MateMixerBackend *backend,
- const gchar *name);
- void (*stream_added) (MateMixerBackend *backend,
- const gchar *name);
- void (*stream_removed) (MateMixerBackend *backend,
- const gchar *name);
- void (*stored_stream_added) (MateMixerBackend *backend,
- const gchar *name);
- void (*stored_stream_removed) (MateMixerBackend *backend,
- const gchar *name);
+ void (*device_added) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*device_removed) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*stream_added) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*stream_removed) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*stored_control_added) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*stored_control_removed) (MateMixerBackend *backend,
+ const gchar *name);
};
-struct _MateMixerBackendData
-{
- gchar *app_name;
- gchar *app_id;
- gchar *app_version;
- gchar *app_icon;
- gchar *server_address;
-};
+GType mate_mixer_backend_get_type (void) G_GNUC_CONST;
+
+void mate_mixer_backend_set_app_info (MateMixerBackend *backend,
+ MateMixerAppInfo *info);
+void mate_mixer_backend_set_server_address (MateMixerBackend *backend,
+ const gchar *address);
+
+gboolean mate_mixer_backend_open (MateMixerBackend *backend);
+void mate_mixer_backend_close (MateMixerBackend *backend);
+
+MateMixerState mate_mixer_backend_get_state (MateMixerBackend *backend);
+MateMixerBackendFlags mate_mixer_backend_get_flags (MateMixerBackend *backend);
-GType mate_mixer_backend_get_type (void) G_GNUC_CONST;
+MateMixerDevice * mate_mixer_backend_get_device (MateMixerBackend *backend,
+ const gchar *name);
+MateMixerStream * mate_mixer_backend_get_stream (MateMixerBackend *backend,
+ const gchar *name);
+MateMixerStoredControl *mate_mixer_backend_get_stored_control (MateMixerBackend *backend,
+ const gchar *name);
-void mate_mixer_backend_set_data (MateMixerBackend *backend,
- MateMixerBackendData *data);
+const GList * mate_mixer_backend_list_devices (MateMixerBackend *backend);
+const GList * mate_mixer_backend_list_streams (MateMixerBackend *backend);
+const GList * mate_mixer_backend_list_stored_controls (MateMixerBackend *backend);
-gboolean mate_mixer_backend_open (MateMixerBackend *backend);
-void mate_mixer_backend_close (MateMixerBackend *backend);
+MateMixerStream * mate_mixer_backend_get_default_input_stream (MateMixerBackend *backend);
+gboolean mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
-MateMixerState mate_mixer_backend_get_state (MateMixerBackend *backend);
-MateMixerBackendFlags mate_mixer_backend_get_flags (MateMixerBackend *backend);
+MateMixerStream * mate_mixer_backend_get_default_output_stream (MateMixerBackend *backend);
+gboolean mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
-const GList * mate_mixer_backend_list_devices (MateMixerBackend *backend);
-const GList * mate_mixer_backend_list_streams (MateMixerBackend *backend);
-const GList * mate_mixer_backend_list_stored_streams (MateMixerBackend *backend);
+/* Protected functions */
+void _mate_mixer_backend_set_state (MateMixerBackend *backend,
+ MateMixerState state);
+void _mate_mixer_backend_set_flags (MateMixerBackend *backend,
+ MateMixerBackendFlags flags);
-MateMixerStream * mate_mixer_backend_get_default_input_stream (MateMixerBackend *backend);
-gboolean mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,
- MateMixerStream *stream);
+void _mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
-MateMixerStream * mate_mixer_backend_get_default_output_stream (MateMixerBackend *backend);
-gboolean mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend,
- MateMixerStream *stream);
+void _mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
G_END_DECLS
diff --git a/libmatemixer/matemixer-client-stream.c b/libmatemixer/matemixer-client-stream.c
deleted file mode 100644
index fc34622..0000000
--- a/libmatemixer/matemixer-client-stream.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * Copyright (C) 2014 Michal Ratajsky <[email protected]>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include "matemixer-client-stream.h"
-#include "matemixer-enums.h"
-#include "matemixer-enum-types.h"
-#include "matemixer-stream.h"
-
-/**
- * SECTION:matemixer-client-stream
- * @short_description: Interface providing extra functionality for client streams
- * @see_also: #MateMixerStream
- * @include: libmatemixer/matemixer.h
- *
- * #MateMixerClientStream represents a special kind of stream, which belongs
- * to a parent input or output stream.
- *
- * A typical example of a client stream is a stream provided by an application.
- */
-
-struct _MateMixerClientStreamPrivate
-{
- gchar *app_name;
- gchar *app_id;
- gchar *app_version;
- gchar *app_icon;
- MateMixerStream *parent;
- MateMixerClientStreamFlags client_flags;
- MateMixerClientStreamRole client_role;
-};
-
-enum {
- PROP_0,
- PROP_CLIENT_FLAGS,
- PROP_CLIENT_ROLE,
- PROP_PARENT,
- PROP_APP_NAME,
- PROP_APP_ID,
- PROP_APP_VERSION,
- PROP_APP_ICON,
- N_PROPERTIES
-};
-
-static GParamSpec *properties[N_PROPERTIES] = { NULL, };
-
-static void mate_mixer_client_stream_class_init (MateMixerClientStreamClass *klass);
-
-static void mate_mixer_client_stream_init (MateMixerClientStream *client);
-
-static void mate_mixer_client_stream_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec);
-static void mate_mixer_client_stream_set_property (GObject *object,
- guint param_id,
- const GValue *value,
- GParamSpec *pspec);
-
-static void mate_mixer_client_stream_dispose (GObject *object);
-static void mate_mixer_client_stream_finalize (GObject *object);
-
-G_DEFINE_ABSTRACT_TYPE (MateMixerClientStream, mate_mixer_client_stream, MATE_MIXER_TYPE_STREAM)
-
-static void
-mate_mixer_client_stream_class_init (MateMixerClientStreamClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = mate_mixer_client_stream_dispose;
- object_class->finalize = mate_mixer_client_stream_finalize;
- object_class->get_property = mate_mixer_client_stream_get_property;
- object_class->set_property = mate_mixer_client_stream_set_property;
-
- properties[PROP_CLIENT_FLAGS] =
- g_param_spec_flags ("client-flags",
- "Client flags",
- "Capability flags of the client stream",
- MATE_MIXER_TYPE_CLIENT_STREAM_FLAGS,
- MATE_MIXER_CLIENT_STREAM_NO_FLAGS,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_CLIENT_ROLE] =
- g_param_spec_enum ("role",
- "Role",
- "Role of the client stream",
- MATE_MIXER_TYPE_CLIENT_STREAM_ROLE,
- MATE_MIXER_CLIENT_STREAM_ROLE_NONE,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_PARENT] =
- g_param_spec_object ("parent",
- "Parent",
- "Parent stream of the client stream",
- MATE_MIXER_TYPE_STREAM,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_APP_NAME] =
- g_param_spec_string ("app-name",
- "App name",
- "Name of the client stream application",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_APP_ID] =
- g_param_spec_string ("app-id",
- "App ID",
- "Identifier of the client stream application",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_APP_VERSION] =
- g_param_spec_string ("app-version",
- "App version",
- "Version of the client stream application",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_APP_ICON] =
- g_param_spec_string ("app-icon",
- "App icon",
- "Icon name of the client stream application",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- g_object_class_install_properties (object_class, N_PROPERTIES, properties);
-}
-
-static void
-mate_mixer_client_stream_init (MateMixerClientStream *client)
-{
- client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client,
- MATE_MIXER_TYPE_CLIENT_STREAM,
- MateMixerClientStreamPrivate);
-}
-
-static void
-mate_mixer_client_stream_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec)
-{
-}
-
-static void
-mate_mixer_client_stream_set_property (GObject *object,
- guint param_id,
- const GValue *value,
- GParamSpec *pspec)
-{
-}
-
-static void
-mate_mixer_client_stream_dispose (GObject *object)
-{
- MateMixerClientStream *client;
-
- client = MATE_MIXER_CLIENT_STREAM (object);
-
- g_clear_object (&client->priv->parent);
-
- G_OBJECT_CLASS (mate_mixer_client_stream_parent_class)->dispose (object);
-}
-
-static void
-mate_mixer_client_stream_finalize (GObject *object)
-{
- MateMixerClientStream *client;
-
- client = MATE_MIXER_CLIENT_STREAM (object);
-
- g_free (client->priv->app_name);
- g_free (client->priv->app_id);
- g_free (client->priv->app_version);
- g_free (client->priv->app_icon);
-
- G_OBJECT_CLASS (mate_mixer_client_stream_parent_class)->finalize (object);
-}
-
-/**
- * mate_mixer_client_stream_get_flags:
- * @client: a #MateMixerClientStream
- *
- */
-MateMixerClientStreamFlags
-mate_mixer_client_stream_get_flags (MateMixerClientStream *client)
-{
- g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), MATE_MIXER_CLIENT_STREAM_NO_FLAGS);
-
- return client->priv->client_flags;
-}
-
-/**
- * mate_mixer_client_stream_get_role:
- * @client: a #MateMixerClientStream
- *
- */
-MateMixerClientStreamRole
-mate_mixer_client_stream_get_role (MateMixerClientStream *client)
-{
- g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), MATE_MIXER_CLIENT_STREAM_ROLE_NONE);
-
- return client->priv->client_role;
-}
-
-/**
- * mate_mixer_client_stream_get_parent:
- * @client: a #MateMixerClientStream
- *
- * Gets the parent stream of the client stream.
- *
- * Returns: a #MateMixerStream or %NULL if the parent stream is not known.
- */
-MateMixerStream *
-mate_mixer_client_stream_get_parent (MateMixerClientStream *client)
-{
- g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL);
-
- return client->priv->parent;
-}
-
-/**
- * mate_mixer_client_stream_set_parent:
- * @client: a #MateMixerClientStream
- * @parent: a #MateMixerStream
- *
- * Changes the parent stream of the client stream. The parent stream must be a
- * non-client input or output stream.
- *
- * Returns: %TRUE on success or %FALSE on failure.
- */
-gboolean
-mate_mixer_client_stream_set_parent (MateMixerClientStream *client, MateMixerStream *parent)
-{
- g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (parent), FALSE);
-
- if (client->priv->parent != parent) {
- MateMixerClientStreamClass *klass;
-
- klass = MATE_MIXER_CLIENT_STREAM_GET_CLASS (client);
-
- if (klass->set_parent == NULL ||
- klass->set_parent (client, parent) == FALSE)
- return FALSE;
-
- if (client->priv->parent != NULL)
- g_object_unref (client->priv->parent);
-
- client->priv->parent = g_object_ref (parent);
- }
-
- return TRUE;
-}
-
-/**
- * mate_mixer_client_stream_remove:
- * @client: a #MateMixerClientStream
- *
- * Removes the client stream.
- *
- * Returns: %TRUE on success or %FALSE on failure.
- */
-gboolean
-mate_mixer_client_stream_remove (MateMixerClientStream *client)
-{
- MateMixerClientStreamClass *klass;
-
- g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), FALSE);
-
- klass = MATE_MIXER_CLIENT_STREAM_GET_CLASS (client);
-
- if (klass->remove != NULL)
- return klass->remove (client);
-
- return FALSE;
-}
-
-/**
- * mate_mixer_client_stream_get_app_name:
- * @client: a #MateMixerClientStream
- *
- * Gets the name of the application in case the stream is an application
- * stream.
- *
- * Returns: a string on success, or %NULL if the stream is not an application
- * stream or if the application does not provide a name.
- */
-const gchar *
-mate_mixer_client_stream_get_app_name (MateMixerClientStream *client)
-{
- g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL);
-
- return client->priv->app_name;
-}
-
-/**
- * mate_mixer_client_stream_get_app_id:
- * @client: a #MateMixerClientStream
- *
- * Gets the identifier (e.g. org.example.app) of the application in case the
- * stream is an application stream.
- *
- * Returns: a string on success, or %NULL if the stream is not an application
- * stream or if the application does not provide an identifier.
- */
-const gchar *
-mate_mixer_client_stream_get_app_id (MateMixerClientStream *client)
-{
- g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL);
-
- return client->priv->app_id;
-}
-
-/**
- * mate_mixer_client_stream_get_app_version:
- * @client: a #MateMixerClientStream
- *
- * Gets the version of the application in case the stream is an application
- * stream.
- *
- * Returns: a string on success, or %NULL if the stream is not an application
- * stream or if the application does not provide a version string.
- */
-const gchar *
-mate_mixer_client_stream_get_app_version (MateMixerClientStream *client)
-{
- g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL);
-
- return client->priv->app_version;
-}
-
-/**
- * mate_mixer_client_stream_get_app_icon:
- * @client: a #MateMixerClientStream
- *
- * Gets the XDG icon name of the application in case the stream is an
- * application stream.
- *
- * Returns: a string on success, or %NULL if the stream is not an application
- * stream or if the application does not provide an icon name.
- */
-const gchar *
-mate_mixer_client_stream_get_app_icon (MateMixerClientStream *client)
-{
- g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL);
-
- return client->priv->app_icon;
-}
diff --git a/libmatemixer/matemixer-client-stream.h b/libmatemixer/matemixer-client-stream.h
deleted file mode 100644
index 43ab3f0..0000000
--- a/libmatemixer/matemixer-client-stream.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2014 Michal Ratajsky <[email protected]>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#ifndef MATEMIXER_CLIENT_STREAM_H
-#define MATEMIXER_CLIENT_STREAM_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-types.h>
-
-G_BEGIN_DECLS
-
-#define MATE_MIXER_TYPE_CLIENT_STREAM \
- (mate_mixer_client_stream_get_type ())
-#define MATE_MIXER_CLIENT_STREAM(o) \
- (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_CLIENT_STREAM, MateMixerClientStream))
-#define MATE_MIXER_IS_CLIENT_STREAM(o) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_CLIENT_STREAM))
-#define MATE_MIXER_CLIENT_STREAM_CLASS(k) \
- (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_CLIENT_STREAM, MateMixerClientStreamClass))
-#define MATE_MIXER_IS_CLIENT_STREAM_CLASS(k) \
- (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_CLIENT_STREAM))
-#define MATE_MIXER_CLIENT_STREAM_GET_CLASS(o) \
- (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_CLIENT_STREAM, MateMixerClientStreamClass))
-
-typedef struct _MateMixerClientStreamClass MateMixerClientStreamClass;
-typedef struct _MateMixerClientStreamPrivate MateMixerClientStreamPrivate;
-
-struct _MateMixerClientStream
-{
- GObject *parent;
-
- /*< private >*/
- MateMixerClientStreamPrivate *priv;
-};
-
-struct _MateMixerClientStreamClass
-{
- GTypeInterface parent_iface;
-
- /*< private >*/
- MateMixerClientStreamFlags (*get_flags) (MateMixerClientStream *client);
- MateMixerClientStreamRole (*get_role) (MateMixerClientStream *client);
-
- MateMixerStream *(*get_parent) (MateMixerClientStream *client);
- gboolean (*set_parent) (MateMixerClientStream *client,
- MateMixerStream *stream);
-
- gboolean (*remove) (MateMixerClientStream *client);
-
- const gchar *(*get_app_name) (MateMixerClientStream *client);
- const gchar *(*get_app_id) (MateMixerClientStream *client);
- const gchar *(*get_app_version) (MateMixerClientStream *client);
- const gchar *(*get_app_icon) (MateMixerClientStream *client);
-};
-
-GType mate_mixer_client_stream_get_type (void) G_GNUC_CONST;
-
-MateMixerClientStreamFlags mate_mixer_client_stream_get_flags (MateMixerClientStream *client);
-MateMixerClientStreamRole mate_mixer_client_stream_get_role (MateMixerClientStream *client);
-
-MateMixerStream * mate_mixer_client_stream_get_parent (MateMixerClientStream *client);
-gboolean mate_mixer_client_stream_set_parent (MateMixerClientStream *client,
- MateMixerStream *parent);
-
-gboolean mate_mixer_client_stream_remove (MateMixerClientStream *client);
-
-const gchar * mate_mixer_client_stream_get_app_name (MateMixerClientStream *client);
-const gchar * mate_mixer_client_stream_get_app_id (MateMixerClientStream *client);
-const gchar * mate_mixer_client_stream_get_app_version (MateMixerClientStream *client);
-const gchar * mate_mixer_client_stream_get_app_icon (MateMixerClientStream *client);
-
-G_END_DECLS
-
-#endif /* MATEMIXER_CLIENT_STREAM_H */
diff --git a/libmatemixer/matemixer-context.c b/libmatemixer/matemixer-context.c
index a485a06..bb28b18 100644
--- a/libmatemixer/matemixer-context.c
+++ b/libmatemixer/matemixer-context.c
@@ -22,7 +22,6 @@
#include "matemixer.h"
#include "matemixer-backend.h"
#include "matemixer-backend-module.h"
-#include "matemixer-client-stream.h"
#include "matemixer-context.h"
#include "matemixer-enums.h"
#include "matemixer-enum-types.h"
@@ -38,9 +37,10 @@
struct _MateMixerContextPrivate
{
gboolean backend_chosen;
+ gchar *server_address;
MateMixerState state;
MateMixerBackend *backend;
- MateMixerBackendData backend_data;
+ MateMixerAppInfo *app_info;
MateMixerBackendType backend_type;
MateMixerBackendModule *module;
};
@@ -65,8 +65,8 @@ enum {
DEVICE_REMOVED,
STREAM_ADDED,
STREAM_REMOVED,
- STORED_STREAM_ADDED,
- STORED_STREAM_REMOVED,
+ STORED_CONTROL_ADDED,
+ STORED_CONTROL_REMOVED,
N_SIGNALS
};
@@ -107,10 +107,10 @@ static void on_backend_stream_removed (MateMixerBackend *backe
const gchar *name,
MateMixerContext *context);
-static void on_backend_stored_stream_added (MateMixerBackend *backend,
+static void on_backend_stored_control_added (MateMixerBackend *backend,
const gchar *name,
MateMixerContext *context);
-static void on_backend_stored_stream_removed (MateMixerBackend *backend,
+static void on_backend_stored_control_removed (MateMixerBackend *backend,
const gchar *name,
MateMixerContext *context);
@@ -303,17 +303,17 @@ mate_mixer_context_class_init (MateMixerContextClass *klass)
G_TYPE_STRING);
/**
- * MateMixerContext::stored-stream-added:
+ * MateMixerContext::stored-control-added:
* @context: a #MateMixerContext
- * @name: name of the added stored stream
+ * @name: name of the added stored control
*
- * The signal is emitted each time a stored stream is created.
+ * The signal is emitted each time a stored control is created.
*/
- signals[STORED_STREAM_ADDED] =
+ signals[STORED_CONTROL_ADDED] =
g_signal_new ("stored-control-added",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerContextClass, stored_stream_added),
+ G_STRUCT_OFFSET (MateMixerContextClass, stored_control_added),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -322,17 +322,17 @@ mate_mixer_context_class_init (MateMixerContextClass *klass)
G_TYPE_STRING);
/**
- * MateMixerContext::stream-removed:
+ * MateMixerContext::stored-control-removed:
* @context: a #MateMixerContext
- * @name: name of the removed stream
+ * @name: name of the removed control
*
- * The signal is emitted each time a stream is removed.
+ * The signal is emitted each time a control is removed.
*/
- signals[STORED_STREAM_REMOVED] =
- g_signal_new ("stored-stream-removed",
+ signals[STORED_CONTROL_REMOVED] =
+ g_signal_new ("stored-control-removed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerContextClass, stored_stream_removed),
+ G_STRUCT_OFFSET (MateMixerContextClass, stored_control_removed),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -355,19 +355,19 @@ mate_mixer_context_get_property (GObject *object,
switch (param_id) {
case PROP_APP_NAME:
- g_value_set_string (value, context->priv->backend_data.app_name);
+ g_value_set_string (value, mate_mixer_app_info_get_name (context->priv->app_info));
break;
case PROP_APP_ID:
- g_value_set_string (value, context->priv->backend_data.app_id);
+ g_value_set_string (value, mate_mixer_app_info_get_id (context->priv->app_info));
break;
case PROP_APP_VERSION:
- g_value_set_string (value, context->priv->backend_data.app_version);
+ g_value_set_string (value, mate_mixer_app_info_get_version (context->priv->app_info));
break;
case PROP_APP_ICON:
- g_value_set_string (value, context->priv->backend_data.app_icon);
+ g_value_set_string (value, mate_mixer_app_info_get_icon (context->priv->app_info));
break;
case PROP_SERVER_ADDRESS:
- g_value_set_string (value, context->priv->backend_data.server_address);
+ g_value_set_string (value, context->priv->server_address);
break;
case PROP_STATE:
g_value_set_enum (value, context->priv->state);
@@ -378,6 +378,7 @@ mate_mixer_context_get_property (GObject *object,
case PROP_DEFAULT_OUTPUT_STREAM:
g_value_set_object (value, mate_mixer_context_get_default_output_stream (context));
break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -416,6 +417,7 @@ mate_mixer_context_set_property (GObject *object,
case PROP_DEFAULT_OUTPUT_STREAM:
mate_mixer_context_set_default_output_stream (context, g_value_get_object (value));
break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -428,12 +430,18 @@ mate_mixer_context_init (MateMixerContext *context)
context->priv = G_TYPE_INSTANCE_GET_PRIVATE (context,
MATE_MIXER_TYPE_CONTEXT,
MateMixerContextPrivate);
+
+ context->priv->app_info = _mate_mixer_app_info_new ();
}
static void
mate_mixer_context_dispose (GObject *object)
{
- close_context (MATE_MIXER_CONTEXT (object));
+ MateMixerContext *context;
+
+ context = MATE_MIXER_CONTEXT (object);
+
+ close_context (context);
G_OBJECT_CLASS (mate_mixer_context_parent_class)->dispose (object);
}
@@ -445,11 +453,9 @@ mate_mixer_context_finalize (GObject *object)
context = MATE_MIXER_CONTEXT (object);
- g_free (context->priv->backend_data.app_name);
- g_free (context->priv->backend_data.app_id);
- g_free (context->priv->backend_data.app_version);
- g_free (context->priv->backend_data.app_icon);
- g_free (context->priv->backend_data.server_address);
+ _mate_mixer_app_info_free (context->priv->app_info);
+
+ g_free (context->priv->server_address);
G_OBJECT_CLASS (mate_mixer_context_parent_class)->finalize (object);
}
@@ -504,7 +510,7 @@ mate_mixer_context_set_backend_type (MateMixerContext *context,
context->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- modules = _mate_mixer_get_modules ();
+ modules = _mate_mixer_list_modules ();
while (modules != NULL) {
module = MATE_MIXER_BACKEND_MODULE (modules->data);
@@ -542,13 +548,11 @@ mate_mixer_context_set_app_name (MateMixerContext *context, const gchar *app_nam
context->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- if (g_strcmp0 (context->priv->backend_data.app_name, app_name) != 0) {
- g_free (context->priv->backend_data.app_name);
+ _mate_mixer_app_info_set_name (context->priv->app_info, app_name);
- context->priv->backend_data.app_name = g_strdup (app_name);
+ g_object_notify_by_pspec (G_OBJECT (context),
+ properties[PROP_APP_NAME]);
- g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_APP_NAME]);
- }
return TRUE;
}
@@ -575,13 +579,11 @@ mate_mixer_context_set_app_id (MateMixerContext *context, const gchar *app_id)
context->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- if (g_strcmp0 (context->priv->backend_data.app_id, app_id) != 0) {
- g_free (context->priv->backend_data.app_id);
+ _mate_mixer_app_info_set_id (context->priv->app_info, app_id);
- context->priv->backend_data.app_id = g_strdup (app_id);
+ g_object_notify_by_pspec (G_OBJECT (context),
+ properties[PROP_APP_ID]);
- g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_APP_ID]);
- }
return TRUE;
}
@@ -608,13 +610,11 @@ mate_mixer_context_set_app_version (MateMixerContext *context, const gchar *app_
context->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- if (g_strcmp0 (context->priv->backend_data.app_version, app_version) != 0) {
- g_free (context->priv->backend_data.app_version);
+ _mate_mixer_app_info_set_version (context->priv->app_info, app_version);
- context->priv->backend_data.app_version = g_strdup (app_version);
+ g_object_notify_by_pspec (G_OBJECT (context),
+ properties[PROP_APP_VERSION]);
- g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_APP_VERSION]);
- }
return TRUE;
}
@@ -641,13 +641,11 @@ mate_mixer_context_set_app_icon (MateMixerContext *context, const gchar *app_ico
context->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- if (g_strcmp0 (context->priv->backend_data.app_icon, app_icon) != 0) {
- g_free (context->priv->backend_data.app_icon);
+ _mate_mixer_app_info_set_icon (context->priv->app_info, app_icon);
- context->priv->backend_data.app_icon = g_strdup (app_icon);
+ g_object_notify_by_pspec (G_OBJECT (context),
+ properties[PROP_APP_ICON]);
- g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_APP_ICON]);
- }
return TRUE;
}
@@ -675,13 +673,13 @@ mate_mixer_context_set_server_address (MateMixerContext *context, const gchar *a
context->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- if (g_strcmp0 (context->priv->backend_data.server_address, address) != 0) {
- g_free (context->priv->backend_data.server_address);
+ g_free (context->priv->server_address);
- context->priv->backend_data.server_address = g_strdup (address);
+ context->priv->server_address = g_strdup (address);
+
+ g_object_notify_by_pspec (G_OBJECT (context),
+ properties[PROP_SERVER_ADDRESS]);
- g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_SERVER_ADDRESS]);
- }
return TRUE;
}
@@ -727,7 +725,7 @@ mate_mixer_context_open (MateMixerContext *context)
/* We are going to choose the first backend to try. It will be either the one
* specified by the application or the one with the highest priority */
- modules = _mate_mixer_get_modules ();
+ modules = _mate_mixer_list_modules ();
if (context->priv->backend_type != MATE_MIXER_BACKEND_UNKNOWN) {
while (modules != NULL) {
@@ -758,7 +756,8 @@ mate_mixer_context_open (MateMixerContext *context)
context->priv->module = g_object_ref (module);
context->priv->backend = g_object_new (info->g_type, NULL);
- mate_mixer_backend_set_data (context->priv->backend, &context->priv->backend_data);
+ mate_mixer_backend_set_app_info (context->priv->backend, context->priv->app_info);
+ mate_mixer_backend_set_server_address (context->priv->backend, context->priv->server_address);
g_debug ("Trying to open backend %s", info->name);
@@ -848,21 +847,13 @@ mate_mixer_context_get_state (MateMixerContext *context)
MateMixerDevice *
mate_mixer_context_get_device (MateMixerContext *context, const gchar *name)
{
- GList *list;
-
g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);
g_return_val_if_fail (name != NULL, NULL);
- list = (GList *) mate_mixer_context_list_devices (context);
- while (list != NULL) {
- MateMixerDevice *device = MATE_MIXER_DEVICE (list->data);
-
- if (strcmp (name, mate_mixer_device_get_name (device)) == 0)
- return device;
+ if (context->priv->state != MATE_MIXER_STATE_READY)
+ return NULL;
- list = list->next;
- }
- return NULL;
+ return mate_mixer_backend_get_device (MATE_MIXER_BACKEND (context->priv->backend), name);
}
/**
@@ -877,50 +868,34 @@ mate_mixer_context_get_device (MateMixerContext *context, const gchar *name)
MateMixerStream *
mate_mixer_context_get_stream (MateMixerContext *context, const gchar *name)
{
- GList *list;
-
g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);
g_return_val_if_fail (name != NULL, NULL);
- list = (GList *) mate_mixer_context_list_streams (context);
- while (list != NULL) {
- MateMixerStream *stream = MATE_MIXER_STREAM (list->data);
-
- if (strcmp (name, mate_mixer_stream_get_name (stream)) == 0)
- return stream;
+ if (context->priv->state != MATE_MIXER_STATE_READY)
+ return NULL;
- list = list->next;
- }
- return NULL;
+ return mate_mixer_backend_get_stream (MATE_MIXER_BACKEND (context->priv->backend), name);
}
/**
- * mate_mixer_context_get_stored_stream:
+ * mate_mixer_context_get_stored_control:
* @context: a #MateMixerContext
- * @name: a stream name
+ * @name: a stored control name
*
- * Gets the stream with the given name.
+ * Gets the stored control with the given name.
*
- * Returns: a #MateMixerStream or %NULL if there is no such stream.
+ * Returns: a #MateMixerStoredControl or %NULL if there is no such control.
*/
-MateMixerStream *
-mate_mixer_context_get_stored_stream (MateMixerContext *context, const gchar *name)
+MateMixerStoredControl *
+mate_mixer_context_get_stored_control (MateMixerContext *context, const gchar *name)
{
- GList *list;
-
g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);
g_return_val_if_fail (name != NULL, NULL);
- list = (GList *) mate_mixer_context_list_stored_streams (context);
- while (list != NULL) {
- MateMixerStream *stream = MATE_MIXER_STREAM (list->data);
-
- if (strcmp (name, mate_mixer_stream_get_name (stream)) == 0)
- return stream;
+ if (context->priv->state != MATE_MIXER_STATE_READY)
+ return NULL;
- list = list->next;
- }
- return NULL;
+ return mate_mixer_backend_get_stored_control (MATE_MIXER_BACKEND (context->priv->backend), name);
}
/**
@@ -972,19 +947,19 @@ mate_mixer_context_list_streams (MateMixerContext *context)
}
/**
- * mate_mixer_context_list_stored_streams:
+ * mate_mixer_context_list_stored_controls:
* @context: a #MateMixerContext
*
*/
const GList *
-mate_mixer_context_list_stored_streams (MateMixerContext *context)
+mate_mixer_context_list_stored_controls (MateMixerContext *context)
{
g_return_val_if_fail (MATE_MIXER_IS_CONTEXT (context), NULL);
if (context->priv->state != MATE_MIXER_STATE_READY)
return NULL;
- return mate_mixer_backend_list_stored_streams (MATE_MIXER_BACKEND (context->priv->backend));
+ return mate_mixer_backend_list_stored_controls (MATE_MIXER_BACKEND (context->priv->backend));
}
/**
@@ -1028,11 +1003,7 @@ mate_mixer_context_set_default_input_stream (MateMixerContext *context,
if (context->priv->state != MATE_MIXER_STATE_READY)
return FALSE;
- if (MATE_MIXER_IS_CLIENT_STREAM (stream)) {
- g_warning ("Unable to set client stream as the default input stream");
- return FALSE;
- }
- if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_INPUT)) {
+ if (mate_mixer_stream_get_direction (stream) != MATE_MIXER_DIRECTION_INPUT) {
g_warning ("Unable to set non-input stream as the default input stream");
return FALSE;
}
@@ -1081,11 +1052,7 @@ mate_mixer_context_set_default_output_stream (MateMixerContext *context,
if (context->priv->state != MATE_MIXER_STATE_READY)
return FALSE;
- if (MATE_MIXER_IS_CLIENT_STREAM (stream)) {
- g_warning ("Unable to set client stream as the default output stream");
- return FALSE;
- }
- if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_OUTPUT)) {
+ if (mate_mixer_stream_get_direction (stream) != MATE_MIXER_DIRECTION_OUTPUT) {
g_warning ("Unable to set non-output stream as the default output stream");
return FALSE;
}
@@ -1231,23 +1198,23 @@ on_backend_stream_removed (MateMixerBackend *backend,
}
static void
-on_backend_stored_stream_added (MateMixerBackend *backend,
- const gchar *name,
- MateMixerContext *context)
+on_backend_stored_control_added (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerContext *context)
{
g_signal_emit (G_OBJECT (context),
- signals[STORED_STREAM_ADDED],
+ signals[STORED_CONTROL_ADDED],
0,
name);
}
static void
-on_backend_stored_stream_removed (MateMixerBackend *backend,
- const gchar *name,
- MateMixerContext *context)
+on_backend_stored_control_removed (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerContext *context)
{
g_signal_emit (G_OBJECT (context),
- signals[STORED_STREAM_REMOVED],
+ signals[STORED_CONTROL_REMOVED],
0,
name);
}
@@ -1276,7 +1243,7 @@ try_next_backend (MateMixerContext *context)
const GList *modules;
const MateMixerBackendInfo *info = NULL;
- modules = _mate_mixer_get_modules ();
+ modules = _mate_mixer_list_modules ();
while (modules != NULL) {
if (context->priv->module == modules->data) {
@@ -1301,7 +1268,8 @@ try_next_backend (MateMixerContext *context)
context->priv->module = g_object_ref (module);
context->priv->backend = g_object_new (info->g_type, NULL);
- mate_mixer_backend_set_data (context->priv->backend, &context->priv->backend_data);
+ mate_mixer_backend_set_app_info (context->priv->backend, context->priv->app_info);
+ mate_mixer_backend_set_server_address (context->priv->backend, context->priv->server_address);
g_debug ("Trying to open backend %s", info->name);
@@ -1359,20 +1327,20 @@ change_state (MateMixerContext *context, MateMixerState state)
G_CALLBACK (on_backend_stream_removed),
context);
g_signal_connect (G_OBJECT (context->priv->backend),
- "stored-stream-added",
- G_CALLBACK (on_backend_stored_stream_added),
+ "stored-control-added",
+ G_CALLBACK (on_backend_stored_control_added),
context);
g_signal_connect (G_OBJECT (context->priv->backend),
- "stored-stream-removed",
- G_CALLBACK (on_backend_stored_stream_removed),
+ "stored-control-removed",
+ G_CALLBACK (on_backend_stored_control_removed),
context);
g_signal_connect (G_OBJECT (context->priv->backend),
- "notify::default-input",
+ "notify::default-input-stream",
G_CALLBACK (on_backend_default_input_stream_notify),
context);
g_signal_connect (G_OBJECT (context->priv->backend),
- "notify::default-output",
+ "notify::default-output-stream",
G_CALLBACK (on_backend_default_output_stream_notify),
context);
diff --git a/libmatemixer/matemixer-context.h b/libmatemixer/matemixer-context.h
index 3370570..30d9363 100644
--- a/libmatemixer/matemixer-context.h
+++ b/libmatemixer/matemixer-context.h
@@ -66,64 +66,64 @@ struct _MateMixerContextClass
GObjectClass parent_class;
/*< private >*/
- void (*device_added) (MateMixerContext *context,
- const gchar *name);
- void (*device_removed) (MateMixerContext *context,
- const gchar *name);
- void (*stream_added) (MateMixerContext *context,
- const gchar *name);
- void (*stream_removed) (MateMixerContext *context,
- const gchar *name);
- void (*stored_stream_added) (MateMixerContext *context,
- const gchar *name);
- void (*stored_stream_removed) (MateMixerContext *context,
- const gchar *name);
+ void (*device_added) (MateMixerContext *context,
+ const gchar *name);
+ void (*device_removed) (MateMixerContext *context,
+ const gchar *name);
+ void (*stream_added) (MateMixerContext *context,
+ const gchar *name);
+ void (*stream_removed) (MateMixerContext *context,
+ const gchar *name);
+ void (*stored_control_added) (MateMixerContext *context,
+ const gchar *name);
+ void (*stored_control_removed) (MateMixerContext *context,
+ const gchar *name);
};
-GType mate_mixer_context_get_type (void) G_GNUC_CONST;
-
-MateMixerContext * mate_mixer_context_new (void);
-
-gboolean mate_mixer_context_set_backend_type (MateMixerContext *context,
- MateMixerBackendType backend_type);
-gboolean mate_mixer_context_set_app_name (MateMixerContext *context,
- const gchar *app_name);
-gboolean mate_mixer_context_set_app_id (MateMixerContext *context,
- const gchar *app_id);
-gboolean mate_mixer_context_set_app_version (MateMixerContext *context,
- const gchar *app_version);
-gboolean mate_mixer_context_set_app_icon (MateMixerContext *context,
- const gchar *app_icon);
-gboolean mate_mixer_context_set_server_address (MateMixerContext *context,
- const gchar *address);
-
-gboolean mate_mixer_context_open (MateMixerContext *context);
-void mate_mixer_context_close (MateMixerContext *context);
-
-MateMixerState mate_mixer_context_get_state (MateMixerContext *context);
-
-MateMixerDevice * mate_mixer_context_get_device (MateMixerContext *context,
- const gchar *name);
-MateMixerStream * mate_mixer_context_get_stream (MateMixerContext *context,
- const gchar *name);
-MateMixerStream * mate_mixer_context_get_stored_stream (MateMixerContext *context,
- const gchar *name);
-
-const GList * mate_mixer_context_list_devices (MateMixerContext *context);
-const GList * mate_mixer_context_list_streams (MateMixerContext *context);
-const GList * mate_mixer_context_list_stored_streams (MateMixerContext *context);
-
-MateMixerStream * mate_mixer_context_get_default_input_stream (MateMixerContext *context);
-gboolean mate_mixer_context_set_default_input_stream (MateMixerContext *context,
- MateMixerStream *stream);
-
-MateMixerStream * mate_mixer_context_get_default_output_stream (MateMixerContext *context);
-gboolean mate_mixer_context_set_default_output_stream (MateMixerContext *context,
- MateMixerStream *stream);
-
-const gchar * mate_mixer_context_get_backend_name (MateMixerContext *context);
-MateMixerBackendType mate_mixer_context_get_backend_type (MateMixerContext *context);
-MateMixerBackendFlags mate_mixer_context_get_backend_flags (MateMixerContext *context);
+GType mate_mixer_context_get_type (void) G_GNUC_CONST;
+
+MateMixerContext * mate_mixer_context_new (void);
+
+gboolean mate_mixer_context_set_backend_type (MateMixerContext *context,
+ MateMixerBackendType backend_type);
+gboolean mate_mixer_context_set_app_name (MateMixerContext *context,
+ const gchar *app_name);
+gboolean mate_mixer_context_set_app_id (MateMixerContext *context,
+ const gchar *app_id);
+gboolean mate_mixer_context_set_app_version (MateMixerContext *context,
+ const gchar *app_version);
+gboolean mate_mixer_context_set_app_icon (MateMixerContext *context,
+ const gchar *app_icon);
+gboolean mate_mixer_context_set_server_address (MateMixerContext *context,
+ const gchar *address);
+
+gboolean mate_mixer_context_open (MateMixerContext *context);
+void mate_mixer_context_close (MateMixerContext *context);
+
+MateMixerState mate_mixer_context_get_state (MateMixerContext *context);
+
+MateMixerDevice * mate_mixer_context_get_device (MateMixerContext *context,
+ const gchar *name);
+MateMixerStream * mate_mixer_context_get_stream (MateMixerContext *context,
+ const gchar *name);
+MateMixerStoredControl *mate_mixer_context_get_stored_control (MateMixerContext *context,
+ const gchar *name);
+
+const GList * mate_mixer_context_list_devices (MateMixerContext *context);
+const GList * mate_mixer_context_list_streams (MateMixerContext *context);
+const GList * mate_mixer_context_list_stored_controls (MateMixerContext *context);
+
+MateMixerStream * mate_mixer_context_get_default_input_stream (MateMixerContext *context);
+gboolean mate_mixer_context_set_default_input_stream (MateMixerContext *context,
+ MateMixerStream *stream);
+
+MateMixerStream * mate_mixer_context_get_default_output_stream (MateMixerContext *context);
+gboolean mate_mixer_context_set_default_output_stream (MateMixerContext *context,
+ MateMixerStream *stream);
+
+const gchar * mate_mixer_context_get_backend_name (MateMixerContext *context);
+MateMixerBackendType mate_mixer_context_get_backend_type (MateMixerContext *context);
+MateMixerBackendFlags mate_mixer_context_get_backend_flags (MateMixerContext *context);
G_END_DECLS
diff --git a/libmatemixer/matemixer-device-profile-private.h b/libmatemixer/matemixer-device-profile-private.h
deleted file mode 100644
index 44f2853..0000000
--- a/libmatemixer/matemixer-device-profile-private.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2014 Michal Ratajsky <[email protected]>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#ifndef MATEMIXER_DEVICE_PROFILE_PRIVATE_H
-#define MATEMIXER_DEVICE_PROFILE_PRIVATE_H
-
-#include <glib.h>
-
-#include "matemixer-device-profile.h"
-
-G_BEGIN_DECLS
-
-MateMixerDeviceProfile *_mate_mixer_device_profile_new (const gchar *name,
- const gchar *description,
- guint priority,
- guint input_streams,
- guint output_streams);
-
-gboolean _mate_mixer_device_profile_set_label (MateMixerDeviceProfile *profile,
- const gchar *label);
-gboolean _mate_mixer_device_profile_set_priority (MateMixerDeviceProfile *profile,
- guint priority);
-gboolean _mate_mixer_device_profile_set_num_input_streams (MateMixerDeviceProfile *profile,
- guint num);
-gboolean _mate_mixer_device_profile_set_num_output_streams (MateMixerDeviceProfile *profile,
- guint num);
-
-G_END_DECLS
-
-#endif /* MATEMIXER_DEVICE_PROFILE_PRIVATE_H */
diff --git a/libmatemixer/matemixer-device-profile.c b/libmatemixer/matemixer-device-profile.c
deleted file mode 100644
index d841ff2..0000000
--- a/libmatemixer/matemixer-device-profile.c
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (C) 2014 Michal Ratajsky <[email protected]>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include "matemixer-device-profile.h"
-#include "matemixer-device-profile-private.h"
-
-/**
- * SECTION:matemixer-device-profile
- * @short_description: Device profile
- * @include: libmatemixer/matemixer.h
- */
-
-struct _MateMixerDeviceProfilePrivate
-{
- gchar *name;
- gchar *label;
- guint priority;
- guint num_input_streams;
- guint num_output_streams;
-};
-
-enum {
- PROP_0,
- PROP_NAME,
- PROP_LABEL,
- PROP_PRIORITY,
- PROP_NUM_INPUT_STREAMS,
- PROP_NUM_OUTPUT_STREAMS,
- N_PROPERTIES
-};
-
-static GParamSpec *properties[N_PROPERTIES] = { NULL, };
-
-static void mate_mixer_device_profile_class_init (MateMixerDeviceProfileClass *klass);
-
-static void mate_mixer_device_profile_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec);
-static void mate_mixer_device_profile_set_property (GObject *object,
- guint param_id,
- const GValue *value,
- GParamSpec *pspec);
-
-static void mate_mixer_device_profile_init (MateMixerDeviceProfile *profile);
-static void mate_mixer_device_profile_finalize (GObject *object);
-
-G_DEFINE_TYPE (MateMixerDeviceProfile, mate_mixer_device_profile, G_TYPE_OBJECT);
-
-static void
-mate_mixer_device_profile_class_init (MateMixerDeviceProfileClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = mate_mixer_device_profile_finalize;
- object_class->get_property = mate_mixer_device_profile_get_property;
- object_class->set_property = mate_mixer_device_profile_set_property;
-
- properties[PROP_NAME] =
- g_param_spec_string ("name",
- "Name",
- "Name of the profile",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_LABEL] =
- g_param_spec_string ("label",
- "Label",
- "Label of the profile",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_PRIORITY] =
- g_param_spec_uint ("priority",
- "Priority",
- "Priority of the profile",
- 0,
- G_MAXUINT,
- 0,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_NUM_INPUT_STREAMS] =
- g_param_spec_uint ("num-input-streams",
- "Number of input streams",
- "Number of input streams in the profile",
- 0,
- G_MAXUINT,
- 0,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_NUM_OUTPUT_STREAMS] =
- g_param_spec_uint ("num-output-streams",
- "Number of output streams",
- "Number of output streams in the profile",
- 0,
- G_MAXUINT,
- 0,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- g_object_class_install_properties (object_class, N_PROPERTIES, properties);
-
- g_type_class_add_private (object_class, sizeof (MateMixerDeviceProfilePrivate));
-}
-
-static void
-mate_mixer_device_profile_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec)
-{
- MateMixerDeviceProfile *profile;
-
- profile = MATE_MIXER_DEVICE_PROFILE (object);
-
- switch (param_id) {
- case PROP_NAME:
- g_value_set_string (value, profile->priv->name);
- break;
-
- case PROP_LABEL:
- g_value_set_string (value, profile->priv->label);
- break;
-
- case PROP_PRIORITY:
- g_value_set_uint (value, profile->priv->priority);
- break;
-
- case PROP_NUM_INPUT_STREAMS:
- g_value_set_uint (value, profile->priv->num_input_streams);
- break;
-
- case PROP_NUM_OUTPUT_STREAMS:
- g_value_set_uint (value, profile->priv->num_output_streams);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
- break;
- }
-}
-
-static void
-mate_mixer_device_profile_set_property (GObject *object,
- guint param_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- MateMixerDeviceProfile *profile;
-
- profile = MATE_MIXER_DEVICE_PROFILE (object);
-
- switch (param_id) {
- case PROP_NAME:
- /* Construct-only string */
- profile->priv->name = g_strdup (g_value_get_string (value));
- break;
-
- case PROP_LABEL:
- /* Construct-only string */
- profile->priv->label = g_strdup (g_value_get_string (value));
- break;
-
- case PROP_PRIORITY:
- profile->priv->priority = g_value_get_uint (value);
- break;
-
- case PROP_NUM_INPUT_STREAMS:
- profile->priv->num_input_streams = g_value_get_uint (value);
- break;
-
- case PROP_NUM_OUTPUT_STREAMS:
- profile->priv->num_output_streams = g_value_get_uint (value);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
- break;
- }
-}
-
-static void
-mate_mixer_device_profile_init (MateMixerDeviceProfile *profile)
-{
- profile->priv = G_TYPE_INSTANCE_GET_PRIVATE (profile,
- MATE_MIXER_TYPE_DEVICE_PROFILE,
- MateMixerDeviceProfilePrivate);
-}
-
-static void
-mate_mixer_device_profile_finalize (GObject *object)
-{
- MateMixerDeviceProfile *profile;
-
- profile = MATE_MIXER_DEVICE_PROFILE (object);
-
- g_free (profile->priv->name);
- g_free (profile->priv->label);
-
- G_OBJECT_CLASS (mate_mixer_device_profile_parent_class)->finalize (object);
-}
-
-/**
- * mate_mixer_device_profile_get_name:
- * @profile: a #MateMixerDeviceProfile
- */
-const gchar *
-mate_mixer_device_profile_get_name (MateMixerDeviceProfile *profile)
-{
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), NULL);
-
- return profile->priv->name;
-}
-
-/**
- * mate_mixer_device_profile_get_label:
- * @profile: a #MateMixerDeviceProfile
- */
-const gchar *
-mate_mixer_device_profile_get_label (MateMixerDeviceProfile *profile)
-{
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), NULL);
-
- return profile->priv->label;
-}
-
-/**
- * mate_mixer_device_profile_get_priority:
- * @profile: a #MateMixerDeviceProfile
- */
-guint
-mate_mixer_device_profile_get_priority (MateMixerDeviceProfile *profile)
-{
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), 0);
-
- return profile->priv->priority;
-}
-
-/**
- * mate_mixer_device_profile_get_num_input_streams:
- * @profile: a #MateMixerDeviceProfile
- */
-guint
-mate_mixer_device_profile_get_num_input_streams (MateMixerDeviceProfile *profile)
-{
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), 0);
-
- return profile->priv->num_input_streams;
-}
-
-/**
- * mate_mixer_device_profile_get_num_output_streams:
- * @profile: a #MateMixerDeviceProfile
- */
-guint
-mate_mixer_device_profile_get_num_output_streams (MateMixerDeviceProfile *profile)
-{
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), 0);
-
- return profile->priv->num_output_streams;
-}
-
-MateMixerDeviceProfile *
-_mate_mixer_device_profile_new (const gchar *name,
- const gchar *label,
- guint priority,
- guint input_streams,
- guint output_streams)
-{
- return g_object_new (MATE_MIXER_TYPE_DEVICE_PROFILE,
- "name", name,
- "label", label,
- "priority", priority,
- "num-input-streams", input_streams,
- "num-output-streams", output_streams,
- NULL);
-}
-
-gboolean
-_mate_mixer_device_profile_set_label (MateMixerDeviceProfile *profile,
- const gchar *label)
-{
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
-
- if (g_strcmp0 (profile->priv->label, label) != 0) {
- g_free (profile->priv->label);
-
- profile->priv->label = g_strdup (label);
-
- g_object_notify_by_pspec (G_OBJECT (profile), properties[PROP_LABEL]);
- return TRUE;
- }
-
- return FALSE;
-}
-
-gboolean
-_mate_mixer_device_profile_set_priority (MateMixerDeviceProfile *profile,
- guint priority)
-{
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
-
- if (profile->priv->priority != priority) {
- profile->priv->priority = priority;
-
- g_object_notify_by_pspec (G_OBJECT (profile), properties[PROP_PRIORITY]);
- return TRUE;
- }
-
- return FALSE;
-}
-
-gboolean
-_mate_mixer_device_profile_set_num_input_streams (MateMixerDeviceProfile *profile,
- guint num)
-{
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
-
- if (profile->priv->num_input_streams != num) {
- profile->priv->num_input_streams = num;
-
- g_object_notify_by_pspec (G_OBJECT (profile), properties[PROP_NUM_INPUT_STREAMS]);
- return TRUE;
- }
-
- return FALSE;
-}
-
-gboolean
-_mate_mixer_device_profile_set_num_output_streams (MateMixerDeviceProfile *profile,
- guint num)
-{
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
-
- if (profile->priv->num_output_streams != num) {
- profile->priv->num_output_streams = num;
-
- g_object_notify_by_pspec (G_OBJECT (profile), properties[PROP_NUM_OUTPUT_STREAMS]);
- return TRUE;
- }
-
- return FALSE;
-}
diff --git a/libmatemixer/matemixer-device-profile.h b/libmatemixer/matemixer-device-profile.h
deleted file mode 100644
index 8e4221a..0000000
--- a/libmatemixer/matemixer-device-profile.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2014 Michal Ratajsky <[email protected]>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#ifndef MATEMIXER_DEVICE_PROFILE_H
-#define MATEMIXER_DEVICE_PROFILE_H
-
-#include <glib.h>
-#include <glib-object.h>
-#include <libmatemixer/matemixer-types.h>
-
-G_BEGIN_DECLS
-
-#define MATE_MIXER_TYPE_DEVICE_PROFILE \
- (mate_mixer_device_profile_get_type ())
-#define MATE_MIXER_DEVICE_PROFILE(o) \
- (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_DEVICE_PROFILE, MateMixerDeviceProfile))
-#define MATE_MIXER_IS_DEVICE_PROFILE(o) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_DEVICE_PROFILE))
-#define MATE_MIXER_DEVICE_PROFILE_CLASS(k) \
- (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_DEVICE_PROFILE, MateMixerDeviceProfileClass))
-#define MATE_MIXER_IS_DEVICE_PROFILE_CLASS(k) \
- (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_DEVICE_PROFILE))
-#define MATE_MIXER_DEVICE_PROFILE_GET_CLASS(o) \
- (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_DEVICE_PROFILE, MateMixerDeviceProfileClass))
-
-typedef struct _MateMixerDeviceProfileClass MateMixerDeviceProfileClass;
-typedef struct _MateMixerDeviceProfilePrivate MateMixerDeviceProfilePrivate;
-
-struct _MateMixerDeviceProfile
-{
- GObject parent;
-
- /*< private >*/
- MateMixerDeviceProfilePrivate *priv;
-};
-
-struct _MateMixerDeviceProfileClass
-{
- GObjectClass parent_class;
-};
-
-GType mate_mixer_device_profile_get_type (void) G_GNUC_CONST;
-
-const gchar *mate_mixer_device_profile_get_name (MateMixerDeviceProfile *profile);
-const gchar *mate_mixer_device_profile_get_label (MateMixerDeviceProfile *profile);
-guint mate_mixer_device_profile_get_priority (MateMixerDeviceProfile *profile);
-
-guint mate_mixer_device_profile_get_num_input_streams (MateMixerDeviceProfile *profile);
-guint mate_mixer_device_profile_get_num_output_streams (MateMixerDeviceProfile *profile);
-
-G_END_DECLS
-
-#endif /* MATEMIXER_DEVICE_PROFILE_H */
diff --git a/libmatemixer/matemixer-device.c b/libmatemixer/matemixer-device.c
index 229110f..8144388 100644
--- a/libmatemixer/matemixer-device.c
+++ b/libmatemixer/matemixer-device.c
@@ -20,7 +20,6 @@
#include <glib-object.h>
#include "matemixer-device.h"
-#include "matemixer-device-profile.h"
#include "matemixer-stream.h"
#include "matemixer-switch.h"
@@ -32,13 +31,9 @@
struct _MateMixerDevicePrivate
{
- gchar *name;
- gchar *label;
- gchar *icon;
- GList *streams;
- GList *switches;
- GList *profiles;
- MateMixerDeviceProfile *profile;
+ gchar *name;
+ gchar *label;
+ gchar *icon;
};
enum {
@@ -46,7 +41,6 @@ enum {
PROP_NAME,
PROP_LABEL,
PROP_ICON,
- PROP_ACTIVE_PROFILE,
N_PROPERTIES
};
@@ -74,17 +68,14 @@ static void mate_mixer_device_set_property (GObject *object,
GParamSpec *pspec);
static void mate_mixer_device_init (MateMixerDevice *device);
-static void mate_mixer_device_dispose (GObject *object);
static void mate_mixer_device_finalize (GObject *object);
G_DEFINE_ABSTRACT_TYPE (MateMixerDevice, mate_mixer_device, G_TYPE_OBJECT)
-static MateMixerStream * mate_mixer_device_real_get_stream (MateMixerDevice *device,
- const gchar *name);
-static MateMixerSwitch * mate_mixer_device_real_get_switch (MateMixerDevice *device,
- const gchar *name);
-static MateMixerDeviceProfile *mate_mixer_device_real_get_profile (MateMixerDevice *device,
- const gchar *name);
+static MateMixerStream *mate_mixer_device_real_get_stream (MateMixerDevice *device,
+ const gchar *name);
+static MateMixerSwitch *mate_mixer_device_real_get_switch (MateMixerDevice *device,
+ const gchar *name);
static void
mate_mixer_device_class_init (MateMixerDeviceClass *klass)
@@ -93,10 +84,8 @@ mate_mixer_device_class_init (MateMixerDeviceClass *klass)
klass->get_stream = mate_mixer_device_real_get_stream;
klass->get_switch = mate_mixer_device_real_get_switch;
- klass->get_profile = mate_mixer_device_real_get_profile;
object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = mate_mixer_device_dispose;
object_class->finalize = mate_mixer_device_finalize;
object_class->get_property = mate_mixer_device_get_property;
object_class->set_property = mate_mixer_device_set_property;
@@ -128,14 +117,6 @@ mate_mixer_device_class_init (MateMixerDeviceClass *klass)
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
- properties[PROP_ACTIVE_PROFILE] =
- g_param_spec_object ("active-profile",
- "Active profile",
- "The currently active profile of the device",
- MATE_MIXER_TYPE_DEVICE_PROFILE,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
signals[STREAM_ADDED] =
@@ -209,10 +190,6 @@ mate_mixer_device_get_property (GObject *object,
case PROP_ICON:
g_value_set_string (value, device->priv->icon);
break;
- case PROP_ACTIVE_PROFILE:
- g_value_set_object (value, device->priv->profile);
- break;
-
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -258,31 +235,6 @@ mate_mixer_device_init (MateMixerDevice *device)
}
static void
-mate_mixer_device_dispose (GObject *object)
-{
- MateMixerDevice *device;
-
- device = MATE_MIXER_DEVICE (object);
-
- if (device->priv->streams != NULL) {
- g_list_free_full (device->priv->streams, g_object_unref);
- device->priv->streams = NULL;
- }
- if (device->priv->switches != NULL) {
- g_list_free_full (device->priv->switches, g_object_unref);
- device->priv->switches = NULL;
- }
- if (device->priv->profiles != NULL) {
- g_list_free_full (device->priv->profiles, g_object_unref);
- device->priv->profiles = NULL;
- }
-
- g_clear_object (&device->priv->profile);
-
- G_OBJECT_CLASS (mate_mixer_device_parent_class)->dispose (object);
-}
-
-static void
mate_mixer_device_finalize (GObject *object)
{
MateMixerDevice *device;
@@ -309,7 +261,7 @@ mate_mixer_device_get_name (MateMixerDevice *device)
}
/**
- * mate_mixer_device_get_description:
+ * mate_mixer_device_get_label:
* @device: a #MateMixerDevice
*/
const gchar *
@@ -333,20 +285,9 @@ mate_mixer_device_get_icon (MateMixerDevice *device)
}
/**
- * mate_mixer_device_get_profile:
- * @device: a #MateMixerDevice
- * @name: a profile name
- */
-MateMixerDeviceProfile *
-mate_mixer_device_get_profile (MateMixerDevice *device, const gchar *name)
-{
- return MATE_MIXER_DEVICE_GET_CLASS (device)->get_profile (device, name);
-}
-
-/**
* mate_mixer_device_get_stream:
* @device: a #MateMixerDevice
- * @name: a profile name
+ * @name: a stream name
*/
MateMixerStream *
mate_mixer_device_get_stream (MateMixerDevice *device, const gchar *name)
@@ -357,7 +298,7 @@ mate_mixer_device_get_stream (MateMixerDevice *device, const gchar *name)
/**
* mate_mixer_device_get_switch:
* @device: a #MateMixerDevice
- * @name: a profile name
+ * @name: a switch name
*/
MateMixerSwitch *
mate_mixer_device_get_switch (MateMixerDevice *device, const gchar *name)
@@ -372,16 +313,16 @@ mate_mixer_device_get_switch (MateMixerDevice *device, const gchar *name)
const GList *
mate_mixer_device_list_streams (MateMixerDevice *device)
{
+ MateMixerDeviceClass *klass;
+
g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
- if (device->priv->streams == NULL) {
- MateMixerDeviceClass *klass = MATE_MIXER_DEVICE_GET_CLASS (device);
+ klass = MATE_MIXER_DEVICE_GET_CLASS (device);
- if (klass->list_streams != NULL)
- device->priv->streams = klass->list_streams (device);
- }
+ if G_LIKELY (klass->list_streams != NULL)
+ return klass->list_streams (device);
- return (const GList *) device->priv->streams;
+ return NULL;
}
/**
@@ -391,77 +332,16 @@ mate_mixer_device_list_streams (MateMixerDevice *device)
const GList *
mate_mixer_device_list_switches (MateMixerDevice *device)
{
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
-
- if (device->priv->switches == NULL) {
- MateMixerDeviceClass *klass = MATE_MIXER_DEVICE_GET_CLASS (device);
-
- if (klass->list_switches != NULL)
- device->priv->switches = klass->list_switches (device);
- }
-
- return (const GList *) device->priv->switches;
-}
-
-/**
- * mate_mixer_device_list_profiles:
- * @device: a #MateMixerDevice
- */
-const GList *
-mate_mixer_device_list_profiles (MateMixerDevice *device)
-{
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
-
- if (device->priv->profiles == NULL) {
- MateMixerDeviceClass *klass = MATE_MIXER_DEVICE_GET_CLASS (device);
-
- if (klass->list_profiles != NULL)
- device->priv->profiles = klass->list_profiles (device);
- }
+ MateMixerDeviceClass *klass;
- return (const GList *) device->priv->profiles;
-}
-
-/**
- * mate_mixer_device_get_active_profile:
- * @device: a #MateMixerDevice
- */
-MateMixerDeviceProfile *
-mate_mixer_device_get_active_profile (MateMixerDevice *device)
-{
g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
- return device->priv->profile;
-}
-
-/**
- * mate_mixer_device_set_active_profile:
- * @device: a #MateMixerDevice
- * @profile: a #MateMixerDeviceProfile
- */
-gboolean
-mate_mixer_device_set_active_profile (MateMixerDevice *device,
- MateMixerDeviceProfile *profile)
-{
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
-
- if (profile != device->priv->profile) {
- MateMixerDeviceClass *klass;
-
- klass = MATE_MIXER_DEVICE_GET_CLASS (device);
+ klass = MATE_MIXER_DEVICE_GET_CLASS (device);
- if (klass->set_active_profile == NULL ||
- klass->set_active_profile (device, profile) == FALSE)
- return FALSE;
+ if G_LIKELY (klass->list_switches != NULL)
+ return klass->list_switches (device);
- if (G_LIKELY (device->priv->profile != NULL))
- g_object_unref (device->priv->profile);
-
- device->priv->profile = g_object_ref (profile);
- }
-
- return TRUE;
+ return NULL;
}
static MateMixerStream *
@@ -503,23 +383,3 @@ mate_mixer_device_real_get_switch (MateMixerDevice *device, const gchar *name)
}
return NULL;
}
-
-static MateMixerDeviceProfile *
-mate_mixer_device_real_get_profile (MateMixerDevice *device, const gchar *name)
-{
- const GList *list;
-
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
- g_return_val_if_fail (name != NULL, NULL);
-
- list = mate_mixer_device_list_profiles (device);
- while (list != NULL) {
- MateMixerDeviceProfile *profile = MATE_MIXER_DEVICE_PROFILE (list->data);
-
- if (strcmp (name, mate_mixer_device_profile_get_name (profile)) == 0)
- return profile;
-
- list = list->next;
- }
- return NULL;
-}
diff --git a/libmatemixer/matemixer-device.h b/libmatemixer/matemixer-device.h
index 885460c..51d2a14 100644
--- a/libmatemixer/matemixer-device.h
+++ b/libmatemixer/matemixer-device.h
@@ -21,7 +21,7 @@
#include <glib.h>
#include <glib-object.h>
-#include "matemixer-types.h"
+#include <libmatemixer/matemixer-types.h>
G_BEGIN_DECLS
@@ -41,6 +41,12 @@ G_BEGIN_DECLS
typedef struct _MateMixerDeviceClass MateMixerDeviceClass;
typedef struct _MateMixerDevicePrivate MateMixerDevicePrivate;
+/**
+ * MateMixerDevice:
+ *
+ * The #MateMixerDevice structure contains only private data and should only
+ * be accessed using the provided API.
+ */
struct _MateMixerDevice
{
GObject object;
@@ -49,59 +55,49 @@ struct _MateMixerDevice
MateMixerDevicePrivate *priv;
};
+/**
+ * MateMixerDeviceClass:
+ *
+ * The class structure of #MateMixerDevice.
+ */
struct _MateMixerDeviceClass
{
GObjectClass parent_class;
/*< private >*/
+ MateMixerStream *(*get_stream) (MateMixerDevice *device,
+ const gchar *name);
+ MateMixerSwitch *(*get_switch) (MateMixerDevice *device,
+ const gchar *name);
- MateMixerStream *(*get_stream) (MateMixerDevice *device,
- const gchar *name);
- MateMixerSwitch *(*get_switch) (MateMixerDevice *device,
- const gchar *name);
- MateMixerDeviceProfile *(*get_profile) (MateMixerDevice *device,
- const gchar *name);
-
- GList *(*list_streams) (MateMixerDevice *device);
- GList *(*list_switches) (MateMixerDevice *device);
- GList *(*list_profiles) (MateMixerDevice *device);
-
- gboolean (*set_active_profile) (MateMixerDevice *device,
- MateMixerDeviceProfile *profile);
+ const GList *(*list_streams) (MateMixerDevice *device);
+ const GList *(*list_switches) (MateMixerDevice *device);
/* Signals */
- void (*stream_added) (MateMixerDevice *device,
- const gchar *name);
- void (*stream_removed) (MateMixerDevice *device,
- const gchar *name);
- void (*switch_added) (MateMixerDevice *device,
- const gchar *name);
- void (*switch_removed) (MateMixerDevice *device,
- const gchar *name);
+ void (*stream_added) (MateMixerDevice *device,
+ const gchar *name);
+ void (*stream_removed) (MateMixerDevice *device,
+ const gchar *name);
+ void (*switch_added) (MateMixerDevice *device,
+ const gchar *name);
+ void (*switch_removed) (MateMixerDevice *device,
+ const gchar *name);
};
-GType mate_mixer_device_get_type (void) G_GNUC_CONST;
-
-const gchar * mate_mixer_device_get_name (MateMixerDevice *device);
-const gchar * mate_mixer_device_get_label (MateMixerDevice *device);
-const gchar * mate_mixer_device_get_icon (MateMixerDevice *device);
-
-MateMixerStream * mate_mixer_device_get_stream (MateMixerDevice *device,
- const gchar *name);
+GType mate_mixer_device_get_type (void) G_GNUC_CONST;
-MateMixerSwitch * mate_mixer_device_get_switch (MateMixerDevice *device,
- const gchar *name);
+const gchar * mate_mixer_device_get_name (MateMixerDevice *device);
+const gchar * mate_mixer_device_get_label (MateMixerDevice *device);
+const gchar * mate_mixer_device_get_icon (MateMixerDevice *device);
-MateMixerDeviceProfile *mate_mixer_device_get_profile (MateMixerDevice *device,
- const gchar *name);
+MateMixerStream *mate_mixer_device_get_stream (MateMixerDevice *device,
+ const gchar *name);
-const GList * mate_mixer_device_list_streams (MateMixerDevice *device);
-const GList * mate_mixer_device_list_switches (MateMixerDevice *device);
-const GList * mate_mixer_device_list_profiles (MateMixerDevice *device);
+MateMixerSwitch *mate_mixer_device_get_switch (MateMixerDevice *device,
+ const gchar *name);
-MateMixerDeviceProfile *mate_mixer_device_get_active_profile (MateMixerDevice *device);
-gboolean mate_mixer_device_set_active_profile (MateMixerDevice *device,
- MateMixerDeviceProfile *profile);
+const GList * mate_mixer_device_list_streams (MateMixerDevice *device);
+const GList * mate_mixer_device_list_switches (MateMixerDevice *device);
G_END_DECLS
diff --git a/libmatemixer/matemixer-enum-types.c b/libmatemixer/matemixer-enum-types.c
index 035be3d..ea63f50 100644
--- a/libmatemixer/matemixer-enum-types.c
+++ b/libmatemixer/matemixer-enum-types.c
@@ -53,6 +53,8 @@ mate_mixer_backend_type_get_type (void)
static const GEnumValue values[] = {
{ MATE_MIXER_BACKEND_UNKNOWN, "MATE_MIXER_BACKEND_UNKNOWN", "unknown" },
{ MATE_MIXER_BACKEND_PULSEAUDIO, "MATE_MIXER_BACKEND_PULSEAUDIO", "pulseaudio" },
+ { MATE_MIXER_BACKEND_ALSA, "MATE_MIXER_BACKEND_ALSA", "alsa" },
+ { MATE_MIXER_BACKEND_OSS, "MATE_MIXER_BACKEND_OSS", "oss" },
{ MATE_MIXER_BACKEND_NULL, "MATE_MIXER_BACKEND_NULL", "null" },
{ 0, NULL, NULL }
};
@@ -64,62 +66,39 @@ mate_mixer_backend_type_get_type (void)
}
GType
-mate_mixer_port_flags_get_type (void)
+mate_mixer_backend_flags_get_type (void)
{
static GType etype = 0;
if (etype == 0) {
static const GFlagsValue values[] = {
- { MATE_MIXER_PORT_NO_FLAGS, "MATE_MIXER_PORT_NO_FLAGS", "no-flags" },
- { MATE_MIXER_PORT_AVAILABLE, "MATE_MIXER_PORT_AVAILABLE", "available" },
- { MATE_MIXER_PORT_INPUT, "MATE_MIXER_PORT_INPUT", "input" },
- { MATE_MIXER_PORT_OUTPUT, "MATE_MIXER_PORT_OUTPUT", "output" },
+ { MATE_MIXER_BACKEND_NO_FLAGS, "MATE_MIXER_STREAM_NO_FLAGS", "no-flags" },
+ { MATE_MIXER_BACKEND_HAS_APPLICATION_CONTROLS, "MATE_MIXER_BACKEND_HAS_APPLICATION_CONTROLS", "has-application-controls" },
+ { MATE_MIXER_BACKEND_CAN_SET_DEFAULT_INPUT_STREAM, "MATE_MIXER_BACKEND_CAN_SET_DEFAULT_INPUT_STREAM", "can-set-default-input-stream" },
+ { MATE_MIXER_BACKEND_CAN_SET_DEFAULT_OUTPUT_STREAM, "MATE_MIXER_BACKEND_CAN_SET_DEFAULT_OUTPUT_STREAM", "can-set-default-output-stream" },
{ 0, NULL, NULL }
};
etype = g_flags_register_static (
- g_intern_static_string ("MateMixerPortFlags"),
+ g_intern_static_string ("MateMixerBackendFlags"),
values);
}
return etype;
}
GType
-mate_mixer_stream_flags_get_type (void)
-{
- static GType etype = 0;
-
- if (etype == 0) {
- static const GFlagsValue values[] = {
- { MATE_MIXER_STREAM_NO_FLAGS, "MATE_MIXER_STREAM_NO_FLAGS", "no-flags" },
- { MATE_MIXER_STREAM_INPUT, "MATE_MIXER_STREAM_INPUT", "input" },
- { MATE_MIXER_STREAM_OUTPUT, "MATE_MIXER_STREAM_OUTPUT", "output" },
- { MATE_MIXER_STREAM_CLIENT, "MATE_MIXER_STREAM_CLIENT", "client" },
- { MATE_MIXER_STREAM_HAS_MONITOR, "MATE_MIXER_STREAM_HAS_MONITOR", "has-monitor" },
- { MATE_MIXER_STREAM_CAN_SUSPEND, "MATE_MIXER_STREAM_CAN_SUSPEND", "can-suspend" },
- { 0, NULL, NULL }
- };
- etype = g_flags_register_static (
- g_intern_static_string ("MateMixerStreamFlags"),
- values);
- }
- return etype;
-}
-
-GType
-mate_mixer_stream_state_get_type (void)
+mate_mixer_direction_get_type (void)
{
static GType etype = 0;
if (etype == 0) {
static const GEnumValue values[] = {
- { MATE_MIXER_STREAM_STATE_UNKNOWN, "MATE_MIXER_STREAM_STATE_UNKNOWN", "unknown" },
- { MATE_MIXER_STREAM_STATE_RUNNING, "MATE_MIXER_STREAM_STATE_RUNNING", "running" },
- { MATE_MIXER_STREAM_STATE_IDLE, "MATE_MIXER_STREAM_STATE_IDLE", "idle" },
- { MATE_MIXER_STREAM_STATE_SUSPENDED, "MATE_MIXER_STREAM_STATE_SUSPENDED", "suspended" },
+ { MATE_MIXER_DIRECTION_UNKNOWN, "MATE_MIXER_DIRECTION_UNKNOWN", "unknown" },
+ { MATE_MIXER_DIRECTION_INPUT, "MATE_MIXER_DIRECTION_INPUT", "input" },
+ { MATE_MIXER_DIRECTION_OUTPUT, "MATE_MIXER_DIRECTION_OUTPUT", "output" },
{ 0, NULL, NULL }
};
etype = g_enum_register_static (
- g_intern_static_string ("MateMixerStreamState"),
+ g_intern_static_string ("MateMixerDirection"),
values);
}
return etype;
@@ -133,13 +112,16 @@ mate_mixer_stream_control_flags_get_type (void)
if (etype == 0) {
static const GFlagsValue values[] = {
{ MATE_MIXER_STREAM_CONTROL_NO_FLAGS, "MATE_MIXER_STREAM_CONTROL_NO_FLAGS", "no-flags" },
- { MATE_MIXER_STREAM_CONTROL_HAS_MUTE, "MATE_MIXER_STREAM_CONTROL_HAS_MUTE", "has-mute" },
- { MATE_MIXER_STREAM_CONTROL_HAS_VOLUME, "MATE_MIXER_STREAM_CONTROL_HAS_VOLUME", "has-volume" },
- { MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL, "MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL", "has-decibel" },
- { MATE_MIXER_STREAM_CONTROL_HAS_FLAT_VOLUME, "MATE_MIXER_STREAM_CONTROL_HAS_FLAT_VOLUME", "has-flat-volume" },
- { MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME, "MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME", "can-set-volume" },
+ { MATE_MIXER_STREAM_CONTROL_MUTE_READABLE, "MATE_MIXER_STREAM_CONTROL_MUTE_READABLE", "mute-readable" },
+ { MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE, "MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE", "mute-writable" },
+ { MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE, "MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE", "volume-readable" },
+ { MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE, "MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE", "volume-writable" },
{ MATE_MIXER_STREAM_CONTROL_CAN_BALANCE, "MATE_MIXER_STREAM_CONTROL_CAN_BALANCE", "can-balance" },
{ MATE_MIXER_STREAM_CONTROL_CAN_FADE, "MATE_MIXER_STREAM_CONTROL_CAN_FADE", "can-fade" },
+ { MATE_MIXER_STREAM_CONTROL_MOVABLE, "MATE_MIXER_STREAM_CONTROL_MOVABLE", "movable" },
+ { MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL, "MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL", "has-decibel" },
+ { MATE_MIXER_STREAM_CONTROL_HAS_MONITOR, "MATE_MIXER_STREAM_CONTROL_HAS_MONITOR", "has-monitor" },
+ { MATE_MIXER_STREAM_CONTROL_STORED, "MATE_MIXER_STREAM_CONTROL_STORED", "stored" },
{ 0, NULL, NULL }
};
etype = g_flags_register_static (
@@ -158,12 +140,17 @@ mate_mixer_stream_control_role_get_type (void)
static const GEnumValue values[] = {
{ MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN, "MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN", "unknown" },
{ MATE_MIXER_STREAM_CONTROL_ROLE_MASTER, "MATE_MIXER_STREAM_CONTROL_ROLE_MASTER", "master" },
- { MATE_MIXER_STREAM_CONTROL_ROLE_PORT, "MATE_MIXER_STREAM_CONTROL_ROLE_PORT", "port" },
+ { MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION, "MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION", "application" },
{ MATE_MIXER_STREAM_CONTROL_ROLE_PCM, "MATE_MIXER_STREAM_CONTROL_ROLE_PCM", "pcm" },
+ { MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, "MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER", "speaker" },
+ { MATE_MIXER_STREAM_CONTROL_ROLE_MICROPHONE, "MATE_MIXER_STREAM_CONTROL_ROLE_MICROPHONE", "microphone" },
+ { MATE_MIXER_STREAM_CONTROL_ROLE_PORT, "MATE_MIXER_STREAM_CONTROL_ROLE_PORT", "port" },
+ { MATE_MIXER_STREAM_CONTROL_ROLE_BOOST, "MATE_MIXER_STREAM_CONTROL_ROLE_BOOST", "boost" },
{ MATE_MIXER_STREAM_CONTROL_ROLE_BASS, "MATE_MIXER_STREAM_CONTROL_ROLE_BASS", "bass" },
{ MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE, "MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE", "treble" },
{ MATE_MIXER_STREAM_CONTROL_ROLE_CD, "MATE_MIXER_STREAM_CONTROL_ROLE_CD", "cd" },
- { MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER, "MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER", "speaker" },
+ { MATE_MIXER_STREAM_CONTROL_ROLE_VIDEO, "MATE_MIXER_STREAM_CONTROL_ROLE_VIDEO", "video" },
+ { MATE_MIXER_STREAM_CONTROL_ROLE_MUSIC, "MATE_MIXER_STREAM_CONTROL_ROLE_MUSIC", "music" },
{ 0, NULL, NULL }
};
etype = g_enum_register_static (
@@ -174,47 +161,67 @@ mate_mixer_stream_control_role_get_type (void)
}
GType
-mate_mixer_client_stream_flags_get_type (void)
+mate_mixer_stream_control_media_role_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ { MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN, "MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN", "unknown" },
+ { MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_VIDEO, "MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_VIDEO", "video" },
+ { MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_MUSIC, "MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_MUSIC", "music" },
+ { MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_GAME, "MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_GAME", "game" },
+ { MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_EVENT, "MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_EVENT", "event" },
+ { MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_PHONE, "MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_PHONE", "phone" },
+ { MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_ANIMATION, "MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_ANIMATION", "animation" },
+ { MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_PRODUCTION, "MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_PRODUCTION", "production" },
+ { MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_A11Y, "MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_A11Y", "a11y" },
+ { MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_TEST, "MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_TEST", "test" },
+ { MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_ABSTRACT, "MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_ABSTRACT", "abstract" },
+ { MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_FILTER, "MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_FILTER", "filter" },
+ { 0, NULL, NULL }
+ };
+ etype = g_enum_register_static (
+ g_intern_static_string ("MateMixerStreamControlMediaRole"),
+ values);
+ }
+ return etype;
+}
+
+GType
+mate_mixer_switch_flags_get_type (void)
{
static GType etype = 0;
if (etype == 0) {
static const GFlagsValue values[] = {
- { MATE_MIXER_CLIENT_STREAM_NO_FLAGS, "MATE_MIXER_CLIENT_STREAM_NO_FLAGS", "no-flags" },
- { MATE_MIXER_CLIENT_STREAM_APPLICATION, "MATE_MIXER_CLIENT_STREAM_APPLICATION", "application" },
- { MATE_MIXER_CLIENT_STREAM_CACHED, "MATE_MIXER_CLIENT_STREAM_CACHED", "cached" },
+ { MATE_MIXER_SWITCH_NO_FLAGS, "MATE_MIXER_SWITCH_NO_FLAGS", "no-flags" },
+ { MATE_MIXER_SWITCH_TOGGLE, "MATE_MIXER_SWITCH_TOGGLE", "toggle" },
+ { MATE_MIXER_SWITCH_ALLOWS_NO_ACTIVE_OPTION, "MATE_MIXER_SWITCH_ALLOWS_NO_ACTIVE_OPTION", "allows-no-active-option" },
{ 0, NULL, NULL }
};
etype = g_flags_register_static (
- g_intern_static_string ("MateMixerClientStreamFlags"),
+ g_intern_static_string ("MateMixerSwitchFlags"),
values);
}
return etype;
}
GType
-mate_mixer_client_stream_role_get_type (void)
+mate_mixer_switch_role_get_type (void)
{
static GType etype = 0;
if (etype == 0) {
static const GEnumValue values[] = {
- { MATE_MIXER_CLIENT_STREAM_ROLE_NONE, "MATE_MIXER_CLIENT_STREAM_ROLE_NONE", "none" },
- { MATE_MIXER_CLIENT_STREAM_ROLE_VIDEO, "MATE_MIXER_CLIENT_STREAM_ROLE_VIDEO", "video" },
- { MATE_MIXER_CLIENT_STREAM_ROLE_MUSIC, "MATE_MIXER_CLIENT_STREAM_ROLE_MUSIC", "music" },
- { MATE_MIXER_CLIENT_STREAM_ROLE_GAME, "MATE_MIXER_CLIENT_STREAM_ROLE_GAME", "game" },
- { MATE_MIXER_CLIENT_STREAM_ROLE_EVENT, "MATE_MIXER_CLIENT_STREAM_ROLE_EVENT", "event" },
- { MATE_MIXER_CLIENT_STREAM_ROLE_PHONE, "MATE_MIXER_CLIENT_STREAM_ROLE_PHONE", "phone" },
- { MATE_MIXER_CLIENT_STREAM_ROLE_ANIMATION, "MATE_MIXER_CLIENT_STREAM_ROLE_ANIMATION", "animation" },
- { MATE_MIXER_CLIENT_STREAM_ROLE_PRODUCTION, "MATE_MIXER_CLIENT_STREAM_ROLE_PRODUCTION", "production" },
- { MATE_MIXER_CLIENT_STREAM_ROLE_A11Y, "MATE_MIXER_CLIENT_STREAM_ROLE_A11Y", "a11y" },
- { MATE_MIXER_CLIENT_STREAM_ROLE_TEST, "MATE_MIXER_CLIENT_STREAM_ROLE_TEST", "test" },
- { MATE_MIXER_CLIENT_STREAM_ROLE_ABSTRACT, "MATE_MIXER_CLIENT_STREAM_ROLE_ABSTRACT", "abstract" },
- { MATE_MIXER_CLIENT_STREAM_ROLE_FILTER, "MATE_MIXER_CLIENT_STREAM_ROLE_FILTER", "filter" },
+ { MATE_MIXER_SWITCH_ROLE_UNKNOWN, "MATE_MIXER_SWITCH_ROLE_UNKNOWN", "unknown" },
+ { MATE_MIXER_SWITCH_ROLE_DEVICE_PROFILE, "MATE_MIXER_SWITCH_ROLE_DEVICE_PROFILE", "device-profile" },
+ { MATE_MIXER_SWITCH_ROLE_PORT, "MATE_MIXER_SWITCH_ROLE_PORT", "port" },
+ { MATE_MIXER_SWITCH_ROLE_BOOST, "MATE_MIXER_SWITCH_ROLE_BOOST", "boost" },
{ 0, NULL, NULL }
};
etype = g_enum_register_static (
- g_intern_static_string ("MateMixerClientStreamRole"),
+ g_intern_static_string ("MateMixerSwitchRole"),
values);
}
return etype;
diff --git a/libmatemixer/matemixer-enum-types.h b/libmatemixer/matemixer-enum-types.h
index f2193be..f96dc85 100644
--- a/libmatemixer/matemixer-enum-types.h
+++ b/libmatemixer/matemixer-enum-types.h
@@ -34,26 +34,26 @@ GType mate_mixer_state_get_type (void) G_GNUC_CONST;
#define MATE_MIXER_TYPE_BACKEND_TYPE (mate_mixer_backend_type_get_type ())
GType mate_mixer_backend_type_get_type (void) G_GNUC_CONST;
-#define MATE_MIXER_TYPE_PORT_FLAGS (mate_mixer_port_flags_get_type ())
-GType mate_mixer_port_flags_get_type (void) G_GNUC_CONST;
+#define MATE_MIXER_TYPE_BACKEND_FLAGS (mate_mixer_backend_flags_get_type ())
+GType mate_mixer_backend_flags_get_type (void) G_GNUC_CONST;
-#define MATE_MIXER_TYPE_STREAM_FLAGS (mate_mixer_stream_flags_get_type ())
-GType mate_mixer_stream_flags_get_type (void) G_GNUC_CONST;
-
-#define MATE_MIXER_TYPE_STREAM_STATE (mate_mixer_stream_state_get_type ())
-GType mate_mixer_stream_state_get_type (void) G_GNUC_CONST;
+#define MATE_MIXER_TYPE_DIRECTION (mate_mixer_direction_get_type ())
+GType mate_mixer_direction_get_type (void) G_GNUC_CONST;
#define MATE_MIXER_TYPE_STREAM_CONTROL_FLAGS (mate_mixer_stream_control_flags_get_type ())
GType mate_mixer_stream_control_flags_get_type (void) G_GNUC_CONST;
#define MATE_MIXER_TYPE_STREAM_CONTROL_ROLE (mate_mixer_stream_control_role_get_type ())
-GType mate_mixer_stream_control_role_get_type (void);
+GType mate_mixer_stream_control_role_get_type (void) G_GNUC_CONST;
+
+#define MATE_MIXER_TYPE_STREAM_CONTROL_MEDIA_ROLE (mate_mixer_stream_control_media_role_get_type ())
+GType mate_mixer_stream_control_media_role_get_type (void) G_GNUC_CONST;
-#define MATE_MIXER_TYPE_CLIENT_STREAM_FLAGS (mate_mixer_client_stream_flags_get_type ())
-GType mate_mixer_client_stream_flags_get_type (void) G_GNUC_CONST;
+#define MATE_MIXER_TYPE_SWITCH_FLAGS (mate_mixer_switch_flags_get_type ())
+GType mate_mixer_switch_flags_get_type (void) G_GNUC_CONST;
-#define MATE_MIXER_TYPE_CLIENT_STREAM_ROLE (mate_mixer_client_stream_role_get_type ())
-GType mate_mixer_client_stream_role_get_type (void) G_GNUC_CONST;
+#define MATE_MIXER_TYPE_SWITCH_ROLE (mate_mixer_switch_role_get_type ())
+GType mate_mixer_switch_role_get_type (void) G_GNUC_CONST;
#define MATE_MIXER_TYPE_CHANNEL_POSITION (mate_mixer_channel_position_get_type ())
GType mate_mixer_channel_position_get_type (void) G_GNUC_CONST;
diff --git a/libmatemixer/matemixer-enums.h b/libmatemixer/matemixer-enums.h
index 8a88b1c..18bbbcf 100644
--- a/libmatemixer/matemixer-enums.h
+++ b/libmatemixer/matemixer-enums.h
@@ -63,59 +63,25 @@ typedef enum {
MATE_MIXER_BACKEND_NULL
} MateMixerBackendType;
+/**
+ * MateMixerBackendFlags:
+ */
+
typedef enum { /*< flags >*/
MATE_MIXER_BACKEND_NO_FLAGS = 0,
+ MATE_MIXER_BACKEND_HAS_APPLICATION_CONTROLS,
MATE_MIXER_BACKEND_CAN_SET_DEFAULT_INPUT_STREAM,
MATE_MIXER_BACKEND_CAN_SET_DEFAULT_OUTPUT_STREAM
} MateMixerBackendFlags;
/**
- * MateMixerPortFlags:
- * @MATE_MIXER_PORT_NO_FLAGS:
- * @MATE_MIXER_PORT_AVAILABLE:
- * @MATE_MIXER_PORT_INPUT:
- * @MATE_MIXER_PORT_OUTPUT:
- */
-typedef enum { /*< flags >*/
- MATE_MIXER_PORT_NO_FLAGS = 0,
- MATE_MIXER_PORT_AVAILABLE = 1 << 0,
- MATE_MIXER_PORT_INPUT = 1 << 1,
- MATE_MIXER_PORT_OUTPUT = 1 << 2
-} MateMixerPortFlags;
-
-/**
- * MateMixerStreamFlags:
- * @MATE_MIXER_STREAM_NO_FLAGS:
- * @MATE_MIXER_STREAM_INPUT:
- * @MATE_MIXER_STREAM_OUTPUT:
- * @MATE_MIXER_STREAM_CLIENT:
- * @MATE_MIXER_STREAM_HAS_MONITOR:
- * @MATE_MIXER_STREAM_CAN_SUSPEND:
- */
-typedef enum { /*< flags >*/
- MATE_MIXER_STREAM_NO_FLAGS = 0,
- MATE_MIXER_STREAM_INPUT = 1 << 0,
- MATE_MIXER_STREAM_OUTPUT = 1 << 1,
- MATE_MIXER_STREAM_CLIENT = 1 << 2,
- MATE_MIXER_STREAM_HAS_MONITOR = 1 << 3,
- MATE_MIXER_STREAM_CAN_SUSPEND = 1 << 4,
- MATE_MIXER_STREAM_PORTS_FIXED = 1 << 5,
- MATE_MIXER_STREAM_PORTS_EXCLUSIVE = 1 << 6,
-} MateMixerStreamFlags;
-
-/**
- * MateMixerStreamState:
- * @MATE_MIXER_STREAM_STATE_UNKNOWN:
- * @MATE_MIXER_STREAM_STATE_RUNNING:
- * @MATE_MIXER_STREAM_STATE_IDLE:
- * @MATE_MIXER_STREAM_STATE_SUSPENDED:
+ * MateMixerDirection:
*/
typedef enum {
- MATE_MIXER_STREAM_STATE_UNKNOWN,
- MATE_MIXER_STREAM_STATE_RUNNING,
- MATE_MIXER_STREAM_STATE_IDLE,
- MATE_MIXER_STREAM_STATE_SUSPENDED
-} MateMixerStreamState;
+ MATE_MIXER_DIRECTION_UNKNOWN,
+ MATE_MIXER_DIRECTION_INPUT,
+ MATE_MIXER_DIRECTION_OUTPUT,
+} MateMixerDirection;
/**
* MateMixerStreamControlFlags:
@@ -129,69 +95,62 @@ typedef enum {
* @MATE_MIXER_STREAM_CONTROL_CAN_FADE:
*/
typedef enum {
- MATE_MIXER_STREAM_CONTROL_NO_FLAGS = 0,
- MATE_MIXER_STREAM_CONTROL_HAS_MUTE = 1 << 0,
- MATE_MIXER_STREAM_CONTROL_HAS_VOLUME = 1 << 1,
- MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL = 1 << 2,
- MATE_MIXER_STREAM_CONTROL_HAS_FLAT_VOLUME = 1 << 3,
- MATE_MIXER_STREAM_CONTROL_CAN_SET_MUTE = 1 << 4,
- MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME = 1 << 5,
- MATE_MIXER_STREAM_CONTROL_CAN_BALANCE = 1 << 6,
- MATE_MIXER_STREAM_CONTROL_CAN_FADE = 1 << 7
+ MATE_MIXER_STREAM_CONTROL_NO_FLAGS = 0,
+ MATE_MIXER_STREAM_CONTROL_MUTE_READABLE = 1 << 0,
+ MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE = 1 << 1,
+ MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE = 1 << 2,
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE = 1 << 3,
+ MATE_MIXER_STREAM_CONTROL_CAN_BALANCE = 1 << 4,
+ MATE_MIXER_STREAM_CONTROL_CAN_FADE = 1 << 5,
+ MATE_MIXER_STREAM_CONTROL_MOVABLE = 1 << 6,
+ MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL = 1 << 7,
+ MATE_MIXER_STREAM_CONTROL_HAS_MONITOR = 1 << 8,
+ MATE_MIXER_STREAM_CONTROL_STORED = 1 << 9
} MateMixerStreamControlFlags;
typedef enum {
MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN,
MATE_MIXER_STREAM_CONTROL_ROLE_MASTER,
- MATE_MIXER_STREAM_CONTROL_ROLE_PORT,
+ MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION,
MATE_MIXER_STREAM_CONTROL_ROLE_PCM,
+ MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER,
+ MATE_MIXER_STREAM_CONTROL_ROLE_MICROPHONE,
+ MATE_MIXER_STREAM_CONTROL_ROLE_PORT,
+ MATE_MIXER_STREAM_CONTROL_ROLE_BOOST,
MATE_MIXER_STREAM_CONTROL_ROLE_BASS,
MATE_MIXER_STREAM_CONTROL_ROLE_TREBLE,
MATE_MIXER_STREAM_CONTROL_ROLE_CD,
- MATE_MIXER_STREAM_CONTROL_ROLE_SPEAKER,
+ MATE_MIXER_STREAM_CONTROL_ROLE_VIDEO,
+ MATE_MIXER_STREAM_CONTROL_ROLE_MUSIC
} MateMixerStreamControlRole;
-/**
- * MateMixerClientStreamFlags:
- * @MATE_MIXER_CLIENT_STREAM_NO_FLAGS:
- * @MATE_MIXER_CLIENT_STREAM_APPLICATION:
- * @MATE_MIXER_CLIENT_STREAM_CACHED:
- */
+typedef enum {
+ MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN,
+ MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_VIDEO,
+ MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_MUSIC,
+ MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_GAME,
+ MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_EVENT,
+ MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_PHONE,
+ MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_ANIMATION,
+ MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_PRODUCTION,
+ MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_A11Y,
+ MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_TEST,
+ MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_ABSTRACT,
+ MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_FILTER
+} MateMixerStreamControlMediaRole;
+
typedef enum { /*< flags >*/
- MATE_MIXER_CLIENT_STREAM_NO_FLAGS = 0,
- MATE_MIXER_CLIENT_STREAM_APPLICATION = 1 << 0,
- MATE_MIXER_CLIENT_STREAM_CACHED = 1 << 1,
-} MateMixerClientStreamFlags;
+ MATE_MIXER_SWITCH_NO_FLAGS = 0,
+ MATE_MIXER_SWITCH_TOGGLE = 1 << 0,
+ MATE_MIXER_SWITCH_ALLOWS_NO_ACTIVE_OPTION = 1 << 1
+} MateMixerSwitchFlags;
-/**
- * MateMixerClientStreamRole:
- * @MATE_MIXER_CLIENT_STREAM_ROLE_NONE:
- * @MATE_MIXER_CLIENT_STREAM_ROLE_VIDEO:
- * @MATE_MIXER_CLIENT_STREAM_ROLE_MUSIC:
- * @MATE_MIXER_CLIENT_STREAM_ROLE_GAME:
- * @MATE_MIXER_CLIENT_STREAM_ROLE_EVENT:
- * @MATE_MIXER_CLIENT_STREAM_ROLE_PHONE:
- * @MATE_MIXER_CLIENT_STREAM_ROLE_ANIMATION:
- * @MATE_MIXER_CLIENT_STREAM_ROLE_PRODUCTION:
- * @MATE_MIXER_CLIENT_STREAM_ROLE_A11Y:
- * @MATE_MIXER_CLIENT_STREAM_ROLE_TEST:
- * @MATE_MIXER_CLIENT_STREAM_ROLE_ABSTRACT:
- * @MATE_MIXER_CLIENT_STREAM_ROLE_FILTER:
- */
typedef enum {
- MATE_MIXER_CLIENT_STREAM_ROLE_NONE,
- MATE_MIXER_CLIENT_STREAM_ROLE_VIDEO,
- MATE_MIXER_CLIENT_STREAM_ROLE_MUSIC,
- MATE_MIXER_CLIENT_STREAM_ROLE_GAME,
- MATE_MIXER_CLIENT_STREAM_ROLE_EVENT,
- MATE_MIXER_CLIENT_STREAM_ROLE_PHONE,
- MATE_MIXER_CLIENT_STREAM_ROLE_ANIMATION,
- MATE_MIXER_CLIENT_STREAM_ROLE_PRODUCTION,
- MATE_MIXER_CLIENT_STREAM_ROLE_A11Y,
- MATE_MIXER_CLIENT_STREAM_ROLE_TEST,
- MATE_MIXER_CLIENT_STREAM_ROLE_ABSTRACT,
- MATE_MIXER_CLIENT_STREAM_ROLE_FILTER
-} MateMixerClientStreamRole;
+ MATE_MIXER_SWITCH_ROLE_UNKNOWN,
+ MATE_MIXER_SWITCH_ROLE_DEVICE_PROFILE,
+ MATE_MIXER_SWITCH_ROLE_PORT,
+ MATE_MIXER_SWITCH_ROLE_BOOST
+} MateMixerSwitchRole;
/**
* MateMixerChannelPosition:
diff --git a/libmatemixer/matemixer-private.h b/libmatemixer/matemixer-private.h
index 4229000..41cd2e7 100644
--- a/libmatemixer/matemixer-private.h
+++ b/libmatemixer/matemixer-private.h
@@ -20,12 +20,15 @@
#include <glib.h>
+#include "matemixer-enums.h"
+
+#include "matemixer-app-info-private.h"
+#include "matemixer-backend.h"
#include "matemixer-backend-module.h"
-#include "matemixer-backend-private.h"
-#include "matemixer-device-profile-private.h"
+#include "matemixer-stream-private.h"
#include "matemixer-stream-control-private.h"
-#include "matemixer-switch-option-private.h"
#include "matemixer-switch-private.h"
+#include "matemixer-switch-option-private.h"
G_BEGIN_DECLS
@@ -103,7 +106,9 @@ G_BEGIN_DECLS
#define MATE_MIXER_CHANNEL_MASK_HAS_FRONT(m) ((m) & MATE_MIXER_CHANNEL_MASK_FRONT)
#define MATE_MIXER_CHANNEL_MASK_HAS_BACK(m) ((m) & MATE_MIXER_CHANNEL_MASK_BACK)
-const GList *_mate_mixer_get_modules (void);
+G_GNUC_INTERNAL
+const GList *_mate_mixer_list_modules (void);
+
guint32 _mate_mixer_create_channel_mask (MateMixerChannelPosition *positions, guint n);
G_END_DECLS
diff --git a/libmatemixer/matemixer-stored-control.c b/libmatemixer/matemixer-stored-control.c
new file mode 100644
index 0000000..eb2a448
--- /dev/null
+++ b/libmatemixer/matemixer-stored-control.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "matemixer-enums.h"
+#include "matemixer-enum-types.h"
+#include "matemixer-stream-control.h"
+#include "matemixer-stored-control.h"
+
+G_DEFINE_INTERFACE (MateMixerStoredControl, mate_mixer_stored_control, MATE_MIXER_TYPE_STREAM_CONTROL)
+
+static void
+mate_mixer_stored_control_default_init (MateMixerStoredControlInterface *iface)
+{
+ g_object_interface_install_property (iface,
+ g_param_spec_enum ("direction",
+ "Direction",
+ "Direction of the stored control",
+ MATE_MIXER_TYPE_DIRECTION,
+ MATE_MIXER_DIRECTION_UNKNOWN,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+}
+
+/**
+ * mate_mixer_stored_control_get_direction:
+ * @control: a #MateMixerStoredControl
+ */
+MateMixerDirection
+mate_mixer_stored_control_get_direction (MateMixerStoredControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STORED_CONTROL (control), MATE_MIXER_DIRECTION_UNKNOWN);
+
+ return MATE_MIXER_STORED_CONTROL_GET_INTERFACE (control)->get_direction (control);
+}
diff --git a/libmatemixer/matemixer-stored-control.h b/libmatemixer/matemixer-stored-control.h
new file mode 100644
index 0000000..0c9c982
--- /dev/null
+++ b/libmatemixer/matemixer-stored-control.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_STORED_CONTROL_H
+#define MATEMIXER_STORED_CONTROL_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-enums.h>
+#include <libmatemixer/matemixer-types.h>
+
+G_BEGIN_DECLS
+
+#define MATE_MIXER_TYPE_STORED_CONTROL \
+ (mate_mixer_stored_control_get_type ())
+#define MATE_MIXER_STORED_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_STORED_CONTROL, MateMixerStoredControl))
+#define MATE_MIXER_IS_STORED_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_STORED_CONTROL))
+#define MATE_MIXER_STORED_CONTROL_GET_INTERFACE(o) \
+ (G_TYPE_INSTANCE_GET_INTERFACE ((o), MATE_MIXER_TYPE_STORED_CONTROL, MateMixerStoredControlInterface))
+
+typedef struct _MateMixerStoredControlInterface MateMixerStoredControlInterface;
+
+/**
+ * MateMixerStoredControlInterface:
+ *
+ * The interface structure of #MateMixerStoredControl.
+ */
+struct _MateMixerStoredControlInterface
+{
+ GTypeInterface parent_iface;
+
+ /*< private >*/
+ MateMixerDirection (*get_direction) (MateMixerStoredControl *control);
+};
+
+GType mate_mixer_stored_control_get_type (void) G_GNUC_CONST;
+
+MateMixerDirection mate_mixer_stored_control_get_direction (MateMixerStoredControl *control);
+
+G_END_DECLS
+
+#endif /* MATEMIXER_STORED_CONTROL_H */
diff --git a/libmatemixer/matemixer-stream-control-private.h b/libmatemixer/matemixer-stream-control-private.h
index 49454b3..7802d41 100644
--- a/libmatemixer/matemixer-stream-control-private.h
+++ b/libmatemixer/matemixer-stream-control-private.h
@@ -19,6 +19,7 @@
#define MATEMIXER_STREAM_CONTROL_PRIVATE_H
#include <glib.h>
+
#include "matemixer-enums.h"
#include "matemixer-types.h"
@@ -27,6 +28,9 @@ G_BEGIN_DECLS
void _mate_mixer_stream_control_set_flags (MateMixerStreamControl *control,
MateMixerStreamControlFlags flags);
+void _mate_mixer_stream_control_set_stream (MateMixerStreamControl *control,
+ MateMixerStream *stream);
+
void _mate_mixer_stream_control_set_mute (MateMixerStreamControl *control,
gboolean mute);
diff --git a/libmatemixer/matemixer-stream-control.c b/libmatemixer/matemixer-stream-control.c
index ace584a..b2b2dad 100644
--- a/libmatemixer/matemixer-stream-control.c
+++ b/libmatemixer/matemixer-stream-control.c
@@ -20,6 +20,7 @@
#include "matemixer-enums.h"
#include "matemixer-enum-types.h"
+#include "matemixer-stream.h"
#include "matemixer-stream-control.h"
#include "matemixer-stream-control-private.h"
@@ -30,13 +31,15 @@
struct _MateMixerStreamControlPrivate
{
- gchar *name;
- gchar *label;
- gboolean mute;
- gfloat balance;
- gfloat fade;
- MateMixerStreamControlFlags flags;
- MateMixerStreamControlRole role;
+ gchar *name;
+ gchar *label;
+ gboolean mute;
+ gfloat balance;
+ gfloat fade;
+ MateMixerStream *stream;
+ MateMixerStreamControlFlags flags;
+ MateMixerStreamControlRole role;
+ MateMixerStreamControlMediaRole media_role;
};
enum {
@@ -45,6 +48,8 @@ enum {
PROP_LABEL,
PROP_FLAGS,
PROP_ROLE,
+ PROP_MEDIA_ROLE,
+ PROP_STREAM,
PROP_MUTE,
PROP_VOLUME,
PROP_BALANCE,
@@ -54,6 +59,13 @@ enum {
static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+enum {
+ MONITOR_VALUE,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0, };
+
static void mate_mixer_stream_control_class_init (MateMixerStreamControlClass *klass);
static void mate_mixer_stream_control_get_property (GObject *object,
@@ -66,6 +78,7 @@ static void mate_mixer_stream_control_set_property (GObject
GParamSpec *pspec);
static void mate_mixer_stream_control_init (MateMixerStreamControl *control);
+static void mate_mixer_stream_control_dispose (GObject *object);
static void mate_mixer_stream_control_finalize (GObject *object);
G_DEFINE_ABSTRACT_TYPE (MateMixerStreamControl, mate_mixer_stream_control, G_TYPE_OBJECT)
@@ -76,6 +89,7 @@ mate_mixer_stream_control_class_init (MateMixerStreamControlClass *klass)
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = mate_mixer_stream_control_dispose;
object_class->finalize = mate_mixer_stream_control_finalize;
object_class->get_property = mate_mixer_stream_control_get_property;
object_class->set_property = mate_mixer_stream_control_set_property;
@@ -110,13 +124,32 @@ mate_mixer_stream_control_class_init (MateMixerStreamControlClass *klass)
properties[PROP_ROLE] =
g_param_spec_enum ("role",
- "Role",
- "Role of the stream control",
- MATE_MIXER_TYPE_STREAM_CONTROL_ROLE,
- MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
+ "Role",
+ "Role of the stream control",
+ MATE_MIXER_TYPE_STREAM_CONTROL_ROLE,
+ MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_MEDIA_ROLE] =
+ g_param_spec_enum ("media-role",
+ "Media role",
+ "Media role of the stream control",
+ MATE_MIXER_TYPE_STREAM_CONTROL_MEDIA_ROLE,
+ MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_STREAM] =
+ g_param_spec_object ("stream",
+ "Stream",
+ "Stream which owns the control",
+ MATE_MIXER_TYPE_STREAM,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
properties[PROP_MUTE] =
g_param_spec_boolean ("mute",
@@ -158,6 +191,18 @@ mate_mixer_stream_control_class_init (MateMixerStreamControlClass *klass)
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+ signals[MONITOR_VALUE] =
+ g_signal_new ("monitor-value",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (MateMixerStreamControlClass, monitor_value),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__DOUBLE,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_DOUBLE);
+
g_type_class_add_private (object_class, sizeof (MateMixerStreamControlPrivate));
}
@@ -184,6 +229,12 @@ mate_mixer_stream_control_get_property (GObject *object,
case PROP_ROLE:
g_value_set_enum (value, control->priv->role);
break;
+ case PROP_MEDIA_ROLE:
+ g_value_set_enum (value, control->priv->media_role);
+ break;
+ case PROP_STREAM:
+ g_value_set_object (value, control->priv->stream);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -216,6 +267,18 @@ mate_mixer_stream_control_set_property (GObject *object,
case PROP_ROLE:
control->priv->role = g_value_get_enum (value);
break;
+ case PROP_MEDIA_ROLE:
+ control->priv->media_role = g_value_get_enum (value);
+ break;
+ case PROP_STREAM:
+ /* Construct-only object */
+ control->priv->stream = g_value_get_object (value);
+
+ if (control->priv->stream != NULL) {
+ g_object_add_weak_pointer (G_OBJECT (control->priv->stream),
+ (gpointer *) &control->priv->stream);
+ }
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -232,6 +295,18 @@ mate_mixer_stream_control_init (MateMixerStreamControl *control)
}
static void
+mate_mixer_stream_control_dispose (GObject *object)
+{
+ MateMixerStreamControl *control;
+
+ control = MATE_MIXER_STREAM_CONTROL (object);
+
+ g_clear_object (&control->priv->stream);
+
+ G_OBJECT_CLASS (mate_mixer_stream_control_parent_class)->dispose (object);
+}
+
+static void
mate_mixer_stream_control_finalize (GObject *object)
{
MateMixerStreamControl *control;
@@ -244,6 +319,10 @@ mate_mixer_stream_control_finalize (GObject *object)
G_OBJECT_CLASS (mate_mixer_stream_control_parent_class)->finalize (object);
}
+/**
+ * mate_mixer_stream_control_get_name:
+ * @control: a #MateMixerStreamControl
+ */
const gchar *
mate_mixer_stream_control_get_name (MateMixerStreamControl *control)
{
@@ -252,6 +331,10 @@ mate_mixer_stream_control_get_name (MateMixerStreamControl *control)
return control->priv->name;
}
+/**
+ * mate_mixer_stream_control_get_label:
+ * @control: a #MateMixerStreamControl
+ */
const gchar *
mate_mixer_stream_control_get_label (MateMixerStreamControl *control)
{
@@ -260,6 +343,10 @@ mate_mixer_stream_control_get_label (MateMixerStreamControl *control)
return control->priv->label;
}
+/**
+ * mate_mixer_stream_control_get_flags:
+ * @control: a #MateMixerStreamControl
+ */
MateMixerStreamControlFlags
mate_mixer_stream_control_get_flags (MateMixerStreamControl *control)
{
@@ -268,6 +355,10 @@ mate_mixer_stream_control_get_flags (MateMixerStreamControl *control)
return control->priv->flags;
}
+/**
+ * mate_mixer_stream_control_get_role:
+ * @control: a #MateMixerStreamControl
+ */
MateMixerStreamControlRole
mate_mixer_stream_control_get_role (MateMixerStreamControl *control)
{
@@ -276,6 +367,79 @@ mate_mixer_stream_control_get_role (MateMixerStreamControl *control)
return control->priv->role;
}
+/**
+ * mate_mixer_stream_control_get_media_role:
+ * @control: a #MateMixerStreamControl
+ */
+MateMixerStreamControlMediaRole
+mate_mixer_stream_control_get_media_role (MateMixerStreamControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN);
+
+ return control->priv->media_role;
+}
+
+/**
+ * mate_mixer_stream_control_get_app_info:
+ * @control: a #MateMixerStreamControl
+ */
+MateMixerAppInfo *
+mate_mixer_stream_control_get_app_info (MateMixerStreamControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), NULL);
+
+ if (control->priv->role == MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION) {
+ MateMixerStreamControlClass *klass;
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if G_LIKELY (klass->get_app_info != NULL)
+ return klass->get_app_info (control);
+ }
+ return NULL;
+}
+
+/**
+ * mate_mixer_stream_control_get_stream:
+ * @control: a #MateMixerStreamControl
+ */
+MateMixerStream *
+mate_mixer_stream_control_get_stream (MateMixerStreamControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), NULL);
+
+ return control->priv->stream;
+}
+
+/**
+ * mate_mixer_stream_control_set_stream:
+ * @control: a #MateMixerStreamControl
+ */
+gboolean
+mate_mixer_stream_control_set_stream (MateMixerStreamControl *control,
+ MateMixerStream *stream)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0);
+
+ if (control->priv->stream != stream) {
+ MateMixerStreamControlClass *klass;
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (klass->set_stream == NULL ||
+ klass->set_stream (control, stream) == FALSE)
+ return FALSE;
+
+ _mate_mixer_stream_control_set_stream (control, stream);
+ }
+
+ return TRUE;
+}
+
+/**
+ * mate_mixer_stream_control_get_mute:
+ * @control: a #MateMixerStreamControl
+ */
gboolean
mate_mixer_stream_control_get_mute (MateMixerStreamControl *control)
{
@@ -284,6 +448,10 @@ mate_mixer_stream_control_get_mute (MateMixerStreamControl *control)
return control->priv->mute;
}
+/**
+ * mate_mixer_stream_control_set_mute:
+ * @control: a #MateMixerStreamControl
+ */
gboolean
mate_mixer_stream_control_set_mute (MateMixerStreamControl *control, gboolean mute)
{
@@ -292,17 +460,21 @@ mate_mixer_stream_control_set_mute (MateMixerStreamControl *control, gboolean mu
if (control->priv->mute == mute)
return TRUE;
- if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_MUTE) {
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE) {
MateMixerStreamControlClass *klass;
klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
- if (G_LIKELY (klass->set_mute != NULL))
+ if G_LIKELY (klass->set_mute != NULL)
return klass->set_mute (control, mute);
}
return FALSE;
}
+/**
+ * mate_mixer_stream_control_get_num_channels:
+ * @control: a #MateMixerStreamControl
+ */
guint
mate_mixer_stream_control_get_num_channels (MateMixerStreamControl *control)
{
@@ -318,38 +490,50 @@ mate_mixer_stream_control_get_num_channels (MateMixerStreamControl *control)
return 0;
}
+/**
+ * mate_mixer_stream_control_get_volume:
+ * @control: a #MateMixerStreamControl
+ */
guint
mate_mixer_stream_control_get_volume (MateMixerStreamControl *control)
{
- g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0);
+ MateMixerStreamControlClass *klass;
- if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_VOLUME) {
- MateMixerStreamControlClass *klass;
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0);
- klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE) {
if G_LIKELY (klass->get_volume != NULL)
return klass->get_volume (control);
}
- return 0;
+ return klass->get_min_volume (control);
}
+/**
+ * mate_mixer_stream_control_set_volume:
+ * @control: a #MateMixerStreamControl
+ */
gboolean
mate_mixer_stream_control_set_volume (MateMixerStreamControl *control, guint volume)
{
g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
- if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_VOLUME) {
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE) {
MateMixerStreamControlClass *klass;
klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
- if (G_LIKELY (klass->set_volume != NULL))
+ if G_LIKELY (klass->set_volume != NULL)
return klass->set_volume (control, volume);
}
return FALSE;
}
+/**
+ * mate_mixer_stream_control_get_decibel:
+ * @control: a #MateMixerStreamControl
+ */
gdouble
mate_mixer_stream_control_get_decibel (MateMixerStreamControl *control)
{
@@ -360,28 +544,57 @@ mate_mixer_stream_control_get_decibel (MateMixerStreamControl *control)
klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
- if (G_LIKELY (klass->get_decibel != NULL))
+ if G_LIKELY (klass->get_decibel != NULL)
return klass->get_decibel (control);
}
return -MATE_MIXER_INFINITY;
}
+/**
+ * mate_mixer_stream_control_set_decibel:
+ * @control: a #MateMixerStreamControl
+ */
gboolean
mate_mixer_stream_control_set_decibel (MateMixerStreamControl *control, gdouble decibel)
{
g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
- if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL) {
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL &&
+ control->priv->flags & MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE) {
MateMixerStreamControlClass *klass;
klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
- if (G_LIKELY (klass->set_decibel != NULL))
+ if G_LIKELY (klass->set_decibel != NULL)
return klass->set_decibel (control, decibel);
}
return FALSE;
}
+/**
+ * mate_mixer_stream_control_has_channel_position:
+ * @control: a #MateMixerStreamControl
+ */
+gboolean
+mate_mixer_stream_control_has_channel_position (MateMixerStreamControl *control,
+ MateMixerChannelPosition position)
+{
+ MateMixerStreamControlClass *klass;
+
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+
+ if (klass->has_channel_position != NULL)
+ return klass->has_channel_position (control, position);
+
+ return FALSE;
+}
+
+/**
+ * mate_mixer_stream_control_get_channel_position:
+ * @control: a #MateMixerStreamControl
+ */
MateMixerChannelPosition
mate_mixer_stream_control_get_channel_position (MateMixerStreamControl *control, guint channel)
{
@@ -397,22 +610,30 @@ mate_mixer_stream_control_get_channel_position (MateMixerStreamControl *control,
return MATE_MIXER_CHANNEL_UNKNOWN;
}
+/**
+ * mate_mixer_stream_control_get_channel_volume:
+ * @control: a #MateMixerStreamControl
+ */
guint
mate_mixer_stream_control_get_channel_volume (MateMixerStreamControl *control, guint channel)
{
g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), 0);
- if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_VOLUME) {
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE) {
MateMixerStreamControlClass *klass;
klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
- if (G_LIKELY (klass->get_channel_volume != NULL))
+ if G_LIKELY (klass->get_channel_volume != NULL)
return klass->get_channel_volume (control, channel);
}
return 0;
}
+/**
+ * mate_mixer_stream_control_set_channel_volume:
+ * @control: a #MateMixerStreamControl
+ */
gboolean
mate_mixer_stream_control_set_channel_volume (MateMixerStreamControl *control,
guint channel,
@@ -420,17 +641,21 @@ mate_mixer_stream_control_set_channel_volume (MateMixerStreamControl *control,
{
g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
- if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_VOLUME) {
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE) {
MateMixerStreamControlClass *klass;
klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
- if (G_LIKELY (klass->set_channel_volume != NULL))
+ if G_LIKELY (klass->set_channel_volume != NULL)
return klass->set_channel_volume (control, channel, volume);
}
return FALSE;
}
+/**
+ * mate_mixer_stream_control_get_channel_decibel:
+ * @control: a #MateMixerStreamControl
+ */
gdouble
mate_mixer_stream_control_get_channel_decibel (MateMixerStreamControl *control, guint channel)
{
@@ -441,12 +666,16 @@ mate_mixer_stream_control_get_channel_decibel (MateMixerStreamControl *control,
klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
- if (G_LIKELY (klass->get_channel_decibel != NULL))
+ if G_LIKELY (klass->get_channel_decibel != NULL)
return klass->get_channel_decibel (control, channel);
}
return -MATE_MIXER_INFINITY;
}
+/**
+ * mate_mixer_stream_control_set_channel_decibel:
+ * @control: a #MateMixerStreamControl
+ */
gboolean
mate_mixer_stream_control_set_channel_decibel (MateMixerStreamControl *control,
guint channel,
@@ -459,28 +688,16 @@ mate_mixer_stream_control_set_channel_decibel (MateMixerStreamControl *control,
klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
- if (G_LIKELY (klass->set_channel_decibel != NULL))
+ if G_LIKELY (klass->set_channel_decibel != NULL)
return klass->set_channel_decibel (control, channel, decibel);
}
return FALSE;
}
-gboolean
-mate_mixer_stream_control_has_channel_position (MateMixerStreamControl *control,
- MateMixerChannelPosition position)
-{
- MateMixerStreamControlClass *klass;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
-
- klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
-
- if (klass->has_channel_position != NULL)
- return klass->has_channel_position (control, position);
-
- return FALSE;
-}
-
+/**
+ * mate_mixer_stream_control_get_balance:
+ * @control: a #MateMixerStreamControl
+ */
gfloat
mate_mixer_stream_control_get_balance (MateMixerStreamControl *control)
{
@@ -492,6 +709,10 @@ mate_mixer_stream_control_get_balance (MateMixerStreamControl *control)
return 0.0f;
}
+/**
+ * mate_mixer_stream_control_set_balance:
+ * @control: a #MateMixerStreamControl
+ */
gboolean
mate_mixer_stream_control_set_balance (MateMixerStreamControl *control, gfloat balance)
{
@@ -511,6 +732,10 @@ mate_mixer_stream_control_set_balance (MateMixerStreamControl *control, gfloat b
return FALSE;
}
+/**
+ * mate_mixer_stream_control_get_fade:
+ * @control: a #MateMixerStreamControl
+ */
gfloat
mate_mixer_stream_control_get_fade (MateMixerStreamControl *control)
{
@@ -522,6 +747,10 @@ mate_mixer_stream_control_get_fade (MateMixerStreamControl *control)
return 0.0f;
}
+/**
+ * mate_mixer_stream_control_set_fade:
+ * @control: a #MateMixerStreamControl
+ */
gboolean
mate_mixer_stream_control_set_fade (MateMixerStreamControl *control, gfloat fade)
{
@@ -535,12 +764,59 @@ mate_mixer_stream_control_set_fade (MateMixerStreamControl *control, gfloat fade
klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
- if (G_LIKELY (klass->set_fade != NULL))
+ if (klass->set_fade != NULL)
return klass->set_fade (control, fade);
}
return FALSE;
}
+/**
+ * mate_mixer_stream_control_get_monitor_enabled:
+ * @control: a #MateMixerStreamControl
+ */
+gboolean
+mate_mixer_stream_control_get_monitor_enabled (MateMixerStreamControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
+
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_MONITOR) {
+ MateMixerStreamControlClass *klass;
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+ if (klass->get_monitor_enabled != NULL)
+ return klass->get_monitor_enabled (control);
+ }
+
+ return FALSE;
+}
+
+/**
+ * mate_mixer_stream_control_set_monitor_enabled:
+ * @control: a #MateMixerStreamControl
+ */
+gboolean
+mate_mixer_stream_control_set_monitor_enabled (MateMixerStreamControl *control, gboolean enabled)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control), FALSE);
+
+ if (enabled == mate_mixer_stream_control_get_monitor_enabled (control))
+ return TRUE;
+
+ if (control->priv->flags & MATE_MIXER_STREAM_CONTROL_HAS_MONITOR) {
+ MateMixerStreamControlClass *klass;
+
+ klass = MATE_MIXER_STREAM_CONTROL_GET_CLASS (control);
+ if (klass->set_monitor_enabled != NULL)
+ return klass->set_monitor_enabled (control, enabled);
+ }
+
+ return FALSE;
+}
+
+/**
+ * mate_mixer_stream_control_get_min_volume:
+ * @control: a #MateMixerStreamControl
+ */
guint
mate_mixer_stream_control_get_min_volume (MateMixerStreamControl *control)
{
@@ -556,6 +832,10 @@ mate_mixer_stream_control_get_min_volume (MateMixerStreamControl *control)
return 0;
}
+/**
+ * mate_mixer_stream_control_get_max_volume:
+ * @control: a #MateMixerStreamControl
+ */
guint
mate_mixer_stream_control_get_max_volume (MateMixerStreamControl *control)
{
@@ -571,6 +851,10 @@ mate_mixer_stream_control_get_max_volume (MateMixerStreamControl *control)
return 0;
}
+/**
+ * mate_mixer_stream_control_get_normal_volume:
+ * @control: a #MateMixerStreamControl
+ */
guint
mate_mixer_stream_control_get_normal_volume (MateMixerStreamControl *control)
{
@@ -586,6 +870,10 @@ mate_mixer_stream_control_get_normal_volume (MateMixerStreamControl *control)
return 0;
}
+/**
+ * mate_mixer_stream_control_get_base_volume:
+ * @control: a #MateMixerStreamControl
+ */
guint
mate_mixer_stream_control_get_base_volume (MateMixerStreamControl *control)
{
@@ -601,27 +889,77 @@ mate_mixer_stream_control_get_base_volume (MateMixerStreamControl *control)
return 0;
}
+/* Protected functions */
void
_mate_mixer_stream_control_set_flags (MateMixerStreamControl *control,
MateMixerStreamControlFlags flags)
{
+ g_return_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control));
+
+ if (control->priv->flags == flags)
+ return;
+
control->priv->flags = flags;
+
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_FLAGS]);
+}
+
+/* Protected functions */
+void
+_mate_mixer_stream_control_set_stream (MateMixerStreamControl *control,
+ MateMixerStream *stream)
+{
+ g_return_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control));
+
+ if (control->priv->stream == stream)
+ return;
+
+ if (control->priv->stream != NULL)
+ g_object_unref (control->priv->stream);
+
+ if (stream != NULL)
+ control->priv->stream = g_object_ref (stream);
+ else
+ control->priv->stream = NULL;
+
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_STREAM]);
}
void
_mate_mixer_stream_control_set_mute (MateMixerStreamControl *control, gboolean mute)
{
+ g_return_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control));
+
+ if (control->priv->mute == mute)
+ return;
+
control->priv->mute = mute;
+
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_MUTE]);
}
void
_mate_mixer_stream_control_set_balance (MateMixerStreamControl *control, gfloat balance)
{
+ g_return_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control));
+
+ if (control->priv->balance == balance)
+ return;
+
control->priv->balance = balance;
+
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_BALANCE]);
}
void
_mate_mixer_stream_control_set_fade (MateMixerStreamControl *control, gfloat fade)
{
+ g_return_if_fail (MATE_MIXER_IS_STREAM_CONTROL (control));
+
+ if (control->priv->fade == fade)
+ return;
+
control->priv->fade = fade;
+
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_FADE]);
}
diff --git a/libmatemixer/matemixer-stream-control.h b/libmatemixer/matemixer-stream-control.h
index 51d7f95..2adf97f 100644
--- a/libmatemixer/matemixer-stream-control.h
+++ b/libmatemixer/matemixer-stream-control.h
@@ -49,6 +49,12 @@ G_BEGIN_DECLS
typedef struct _MateMixerStreamControlClass MateMixerStreamControlClass;
typedef struct _MateMixerStreamControlPrivate MateMixerStreamControlPrivate;
+/**
+ * MateMixerStreamControl:
+ *
+ * The #MateMixerStreamControl structure contains only private data and should only
+ * be accessed using the provided API.
+ */
struct _MateMixerStreamControl
{
GObject object;
@@ -57,103 +63,132 @@ struct _MateMixerStreamControl
MateMixerStreamControlPrivate *priv;
};
+/**
+ * MateMixerStreamControlClass:
+ *
+ * The class structure of #MateMixerStreamControl.
+ */
struct _MateMixerStreamControlClass
{
GObjectClass parent_class;
/*< private >*/
- gboolean (*set_mute) (MateMixerStreamControl *control,
- gboolean mute);
-
- guint (*get_num_channels) (MateMixerStreamControl *control);
-
- guint (*get_volume) (MateMixerStreamControl *control);
- gboolean (*set_volume) (MateMixerStreamControl *control,
- guint volume);
-
- gdouble (*get_decibel) (MateMixerStreamControl *control);
- gboolean (*set_decibel) (MateMixerStreamControl *control,
- gdouble decibel);
-
- gboolean (*has_channel_position) (MateMixerStreamControl *control,
- MateMixerChannelPosition position);
- MateMixerChannelPosition (*get_channel_position) (MateMixerStreamControl *control,
- guint channel);
-
- guint (*get_channel_volume) (MateMixerStreamControl *control,
- guint channel);
- gboolean (*set_channel_volume) (MateMixerStreamControl *control,
- guint channel,
- guint volume);
-
- gdouble (*get_channel_decibel) (MateMixerStreamControl *control,
- guint channel);
- gboolean (*set_channel_decibel) (MateMixerStreamControl *control,
- guint channel,
- gdouble decibel);
-
- gboolean (*set_balance) (MateMixerStreamControl *control,
- gfloat balance);
-
- gboolean (*set_fade) (MateMixerStreamControl *control,
- gfloat fade);
-
- guint (*get_min_volume) (MateMixerStreamControl *control);
- guint (*get_max_volume) (MateMixerStreamControl *control);
- guint (*get_normal_volume) (MateMixerStreamControl *control);
- guint (*get_base_volume) (MateMixerStreamControl *control);
+ MateMixerAppInfo * (*get_app_info) (MateMixerStreamControl *control);
+
+ gboolean (*set_stream) (MateMixerStreamControl *control,
+ MateMixerStream *stream);
+
+ gboolean (*set_mute) (MateMixerStreamControl *control,
+ gboolean mute);
+
+ guint (*get_num_channels) (MateMixerStreamControl *control);
+
+ guint (*get_volume) (MateMixerStreamControl *control);
+ gboolean (*set_volume) (MateMixerStreamControl *control,
+ guint volume);
+
+ gdouble (*get_decibel) (MateMixerStreamControl *control);
+ gboolean (*set_decibel) (MateMixerStreamControl *control,
+ gdouble decibel);
+
+ gboolean (*has_channel_position) (MateMixerStreamControl *control,
+ MateMixerChannelPosition position);
+ MateMixerChannelPosition (*get_channel_position) (MateMixerStreamControl *control,
+ guint channel);
+
+ guint (*get_channel_volume) (MateMixerStreamControl *control,
+ guint channel);
+ gboolean (*set_channel_volume) (MateMixerStreamControl *control,
+ guint channel,
+ guint volume);
+
+ gdouble (*get_channel_decibel) (MateMixerStreamControl *control,
+ guint channel);
+ gboolean (*set_channel_decibel) (MateMixerStreamControl *control,
+ guint channel,
+ gdouble decibel);
+
+ gboolean (*set_balance) (MateMixerStreamControl *control,
+ gfloat balance);
+
+ gboolean (*set_fade) (MateMixerStreamControl *control,
+ gfloat fade);
+
+ gboolean (*get_monitor_enabled) (MateMixerStreamControl *control);
+ gboolean (*set_monitor_enabled) (MateMixerStreamControl *control,
+ gboolean enabled);
+
+ guint (*get_min_volume) (MateMixerStreamControl *control);
+ guint (*get_max_volume) (MateMixerStreamControl *control);
+ guint (*get_normal_volume) (MateMixerStreamControl *control);
+ guint (*get_base_volume) (MateMixerStreamControl *control);
+
+ /* Signals */
+ void (*monitor_value) (MateMixerStreamControl *control,
+ gdouble value);
};
-GType mate_mixer_stream_control_get_type (void) G_GNUC_CONST;
+GType mate_mixer_stream_control_get_type (void) G_GNUC_CONST;
+
+const gchar * mate_mixer_stream_control_get_name (MateMixerStreamControl *control);
+const gchar * mate_mixer_stream_control_get_label (MateMixerStreamControl *control);
+MateMixerStreamControlFlags mate_mixer_stream_control_get_flags (MateMixerStreamControl *control);
+MateMixerStreamControlRole mate_mixer_stream_control_get_role (MateMixerStreamControl *control);
+MateMixerStreamControlMediaRole mate_mixer_stream_control_get_media_role (MateMixerStreamControl *control);
+
+MateMixerAppInfo * mate_mixer_stream_control_get_app_info (MateMixerStreamControl *control);
+
+MateMixerStream * mate_mixer_stream_control_get_stream (MateMixerStreamControl *control);
+gboolean mate_mixer_stream_control_set_stream (MateMixerStreamControl *control,
+ MateMixerStream *stream);
-const gchar * mate_mixer_stream_control_get_name (MateMixerStreamControl *control);
-const gchar * mate_mixer_stream_control_get_label (MateMixerStreamControl *control);
-MateMixerStreamControlFlags mate_mixer_stream_control_get_flags (MateMixerStreamControl *control);
-MateMixerStreamControlRole mate_mixer_stream_control_get_role (MateMixerStreamControl *control);
+gboolean mate_mixer_stream_control_get_mute (MateMixerStreamControl *control);
+gboolean mate_mixer_stream_control_set_mute (MateMixerStreamControl *control,
+ gboolean mute);
-gboolean mate_mixer_stream_control_get_mute (MateMixerStreamControl *control);
-gboolean mate_mixer_stream_control_set_mute (MateMixerStreamControl *control,
- gboolean mute);
+guint mate_mixer_stream_control_get_num_channels (MateMixerStreamControl *control);
-guint mate_mixer_stream_control_get_num_channels (MateMixerStreamControl *control);
+guint mate_mixer_stream_control_get_volume (MateMixerStreamControl *control);
+gboolean mate_mixer_stream_control_set_volume (MateMixerStreamControl *control,
+ guint volume);
-guint mate_mixer_stream_control_get_volume (MateMixerStreamControl *control);
-gboolean mate_mixer_stream_control_set_volume (MateMixerStreamControl *control,
- guint volume);
+gdouble mate_mixer_stream_control_get_decibel (MateMixerStreamControl *control);
+gboolean mate_mixer_stream_control_set_decibel (MateMixerStreamControl *control,
+ gdouble decibel);
-gdouble mate_mixer_stream_control_get_decibel (MateMixerStreamControl *control);
-gboolean mate_mixer_stream_control_set_decibel (MateMixerStreamControl *control,
- gdouble decibel);
+gboolean mate_mixer_stream_control_has_channel_position (MateMixerStreamControl *control,
+ MateMixerChannelPosition position);
+MateMixerChannelPosition mate_mixer_stream_control_get_channel_position (MateMixerStreamControl *control,
+ guint channel);
-gboolean mate_mixer_stream_control_has_channel_position (MateMixerStreamControl *control,
- MateMixerChannelPosition position);
-MateMixerChannelPosition mate_mixer_stream_control_get_channel_position (MateMixerStreamControl *control,
- guint channel);
+guint mate_mixer_stream_control_get_channel_volume (MateMixerStreamControl *control,
+ guint channel);
+gboolean mate_mixer_stream_control_set_channel_volume (MateMixerStreamControl *control,
+ guint channel,
+ guint volume);
-guint mate_mixer_stream_control_get_channel_volume (MateMixerStreamControl *control,
- guint channel);
-gboolean mate_mixer_stream_control_set_channel_volume (MateMixerStreamControl *control,
- guint channel,
- guint volume);
+gdouble mate_mixer_stream_control_get_channel_decibel (MateMixerStreamControl *control,
+ guint channel);
+gboolean mate_mixer_stream_control_set_channel_decibel (MateMixerStreamControl *control,
+ guint channel,
+ gdouble decibel);
-gdouble mate_mixer_stream_control_get_channel_decibel (MateMixerStreamControl *control,
- guint channel);
-gboolean mate_mixer_stream_control_set_channel_decibel (MateMixerStreamControl *control,
- guint channel,
- gdouble decibel);
+gfloat mate_mixer_stream_control_get_balance (MateMixerStreamControl *control);
+gboolean mate_mixer_stream_control_set_balance (MateMixerStreamControl *control,
+ gfloat balance);
-gfloat mate_mixer_stream_control_get_balance (MateMixerStreamControl *control);
-gboolean mate_mixer_stream_control_set_balance (MateMixerStreamControl *control,
- gfloat balance);
+gfloat mate_mixer_stream_control_get_fade (MateMixerStreamControl *control);
+gboolean mate_mixer_stream_control_set_fade (MateMixerStreamControl *control,
+ gfloat fade);
-gfloat mate_mixer_stream_control_get_fade (MateMixerStreamControl *control);
-gboolean mate_mixer_stream_control_set_fade (MateMixerStreamControl *control,
- gfloat fade);
+gboolean mate_mixer_stream_control_get_monitor_enabled (MateMixerStreamControl *control);
+gboolean mate_mixer_stream_control_set_monitor_enabled (MateMixerStreamControl *control,
+ gboolean enabled);
-guint mate_mixer_stream_control_get_min_volume (MateMixerStreamControl *control);
-guint mate_mixer_stream_control_get_max_volume (MateMixerStreamControl *control);
-guint mate_mixer_stream_control_get_normal_volume (MateMixerStreamControl *control);
-guint mate_mixer_stream_control_get_base_volume (MateMixerStreamControl *control);
+guint mate_mixer_stream_control_get_min_volume (MateMixerStreamControl *control);
+guint mate_mixer_stream_control_get_max_volume (MateMixerStreamControl *control);
+guint mate_mixer_stream_control_get_normal_volume (MateMixerStreamControl *control);
+guint mate_mixer_stream_control_get_base_volume (MateMixerStreamControl *control);
G_END_DECLS
diff --git a/libmatemixer/matemixer-stream-private.h b/libmatemixer/matemixer-stream-private.h
new file mode 100644
index 0000000..84243ae
--- /dev/null
+++ b/libmatemixer/matemixer-stream-private.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_STREAM_PRIVATE_H
+#define MATEMIXER_STREAM_PRIVATE_H
+
+#include <glib.h>
+
+#include "matemixer-types.h"
+
+G_BEGIN_DECLS
+
+void _mate_mixer_stream_set_default_control (MateMixerStream *stream,
+ MateMixerStreamControl *control);
+
+G_END_DECLS
+
+#endif /* MATEMIXER_STREAM_PRIVATE_H */
diff --git a/libmatemixer/matemixer-stream.c b/libmatemixer/matemixer-stream.c
index 1902de3..03902bd 100644
--- a/libmatemixer/matemixer-stream.c
+++ b/libmatemixer/matemixer-stream.c
@@ -24,6 +24,7 @@
#include "matemixer-enum-types.h"
#include "matemixer-stream.h"
#include "matemixer-stream-control.h"
+#include "matemixer-stream-private.h"
#include "matemixer-switch.h"
/**
@@ -34,27 +35,29 @@
struct _MateMixerStreamPrivate
{
gchar *name;
- GList *controls;
- GList *switches;
- gboolean monitor_enabled;
+ gchar *label;
+ MateMixerDirection direction;
MateMixerDevice *device;
- MateMixerStreamFlags flags;
- MateMixerStreamState state;
+ MateMixerStreamControl *control;
};
enum {
PROP_0,
PROP_NAME,
+ PROP_LABEL,
+ PROP_DIRECTION,
PROP_DEVICE,
- PROP_FLAGS,
- PROP_STATE,
+ PROP_DEFAULT_CONTROL,
N_PROPERTIES
};
static GParamSpec *properties[N_PROPERTIES] = { NULL, };
enum {
- MONITOR_VALUE,
+ CONTROL_ADDED,
+ CONTROL_REMOVED,
+ SWITCH_ADDED,
+ SWITCH_REMOVED,
N_SIGNALS
};
@@ -105,6 +108,25 @@ mate_mixer_stream_class_init (MateMixerStreamClass *klass)
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
+ properties[PROP_LABEL] =
+ g_param_spec_string ("label",
+ "Label",
+ "Label of the stream",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_DIRECTION] =
+ g_param_spec_enum ("direction",
+ "Direction",
+ "Direction of the stream",
+ MATE_MIXER_TYPE_DIRECTION,
+ MATE_MIXER_DIRECTION_UNKNOWN,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
properties[PROP_DEVICE] =
g_param_spec_object ("device",
"Device",
@@ -114,39 +136,64 @@ mate_mixer_stream_class_init (MateMixerStreamClass *klass)
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
- properties[PROP_FLAGS] =
- g_param_spec_flags ("flags",
- "Flags",
- "Capability flags of the stream",
- MATE_MIXER_TYPE_STREAM_FLAGS,
- MATE_MIXER_STREAM_NO_FLAGS,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_STATE] =
- g_param_spec_enum ("state",
- "State",
- "Current state of the stream",
- MATE_MIXER_TYPE_STREAM_STATE,
- MATE_MIXER_STREAM_STATE_UNKNOWN,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
+ properties[PROP_DEFAULT_CONTROL] =
+ g_param_spec_object ("default-control",
+ "Default control",
+ "Default control of the stream",
+ MATE_MIXER_TYPE_STREAM_CONTROL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
- signals[MONITOR_VALUE] =
- g_signal_new ("monitor-value",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerStreamClass, monitor_value),
+ signals[CONTROL_ADDED] =
+ g_signal_new ("control-added",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (MateMixerStreamClass, control_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[CONTROL_REMOVED] =
+ g_signal_new ("control-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (MateMixerStreamClass, control_removed),
NULL,
NULL,
- g_cclosure_marshal_VOID__DOUBLE,
+ g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
1,
- G_TYPE_DOUBLE);
+ G_TYPE_STRING);
+
+ signals[SWITCH_ADDED] =
+ g_signal_new ("switch-added",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (MateMixerStreamClass, switch_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[SWITCH_REMOVED] =
+ g_signal_new ("switch-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (MateMixerStreamClass, switch_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
g_type_class_add_private (object_class, sizeof (MateMixerStreamPrivate));
}
@@ -165,14 +212,17 @@ mate_mixer_stream_get_property (GObject *object,
case PROP_NAME:
g_value_set_string (value, stream->priv->name);
break;
+ case PROP_LABEL:
+ g_value_set_string (value, stream->priv->label);
+ break;
+ case PROP_DIRECTION:
+ g_value_set_enum (value, stream->priv->direction);
+ break;
case PROP_DEVICE:
g_value_set_object (value, stream->priv->device);
break;
- case PROP_FLAGS:
- g_value_set_flags (value, stream->priv->flags);
- break;
- case PROP_STATE:
- g_value_set_enum (value, stream->priv->state);
+ case PROP_DEFAULT_CONTROL:
+ g_value_set_object (value, stream->priv->control);
break;
default:
@@ -196,15 +246,25 @@ mate_mixer_stream_set_property (GObject *object,
/* Construct-only string */
stream->priv->name = g_value_dup_string (value);
break;
+ case PROP_LABEL:
+ /* Construct-only string */
+ stream->priv->label = g_value_dup_string (value);
+ break;
+ case PROP_DIRECTION:
+ stream->priv->direction = g_value_get_enum (value);
+ break;
case PROP_DEVICE:
/* Construct-only object */
- stream->priv->device = g_value_dup_object (value);
- break;
- case PROP_FLAGS:
- stream->priv->flags = g_value_get_flags (value);
+ stream->priv->device = g_value_get_object (value);
+
+ if (stream->priv->device != NULL) {
+ g_object_add_weak_pointer (G_OBJECT (stream->priv->device),
+ (gpointer *) &stream->priv->device);
+ }
break;
- case PROP_STATE:
- stream->priv->state = g_value_get_enum (value);
+ case PROP_DEFAULT_CONTROL:
+ /* Construct-only object */
+ stream->priv->control = g_value_dup_object (value);
break;
default:
@@ -228,7 +288,7 @@ mate_mixer_stream_dispose (GObject *object)
stream = MATE_MIXER_STREAM (object);
- g_clear_object (&stream->priv->device);
+ g_clear_object (&stream->priv->control);
G_OBJECT_CLASS (mate_mixer_stream_parent_class)->dispose (object);
}
@@ -245,6 +305,10 @@ mate_mixer_stream_finalize (GObject *object)
G_OBJECT_CLASS (mate_mixer_stream_parent_class)->finalize (object);
}
+/**
+ * mate_mixer_stream_get_name:
+ * @stream: a #MateMixerStream
+ */
const gchar *
mate_mixer_stream_get_name (MateMixerStream *stream)
{
@@ -253,30 +317,46 @@ mate_mixer_stream_get_name (MateMixerStream *stream)
return stream->priv->name;
}
-MateMixerDevice *
-mate_mixer_stream_get_device (MateMixerStream *stream)
+/**
+ * mate_mixer_stream_get_label:
+ * @stream: a #MateMixerStream
+ */
+const gchar *
+mate_mixer_stream_get_label (MateMixerStream *stream)
{
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
- return stream->priv->device;
+ return stream->priv->label;
}
-MateMixerStreamFlags
-mate_mixer_stream_get_flags (MateMixerStream *stream)
+/**
+ * mate_mixer_stream_get_direction:
+ * @stream: a #MateMixerStream
+ */
+MateMixerDirection
+mate_mixer_stream_get_direction (MateMixerStream *stream)
{
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_STREAM_NO_FLAGS);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_DIRECTION_UNKNOWN);
- return stream->priv->flags;
+ return stream->priv->direction;
}
-MateMixerStreamState
-mate_mixer_stream_get_state (MateMixerStream *stream)
+/**
+ * mate_mixer_stream_get_device:
+ * @stream: a #MateMixerStream
+ */
+MateMixerDevice *
+mate_mixer_stream_get_device (MateMixerStream *stream)
{
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_STREAM_STATE_UNKNOWN);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
- return stream->priv->state;
+ return stream->priv->device;
}
+/**
+ * mate_mixer_stream_get_control:
+ * @stream: a #MateMixerStream
+ */
MateMixerStreamControl *
mate_mixer_stream_get_control (MateMixerStream *stream, const gchar *name)
{
@@ -286,6 +366,10 @@ mate_mixer_stream_get_control (MateMixerStream *stream, const gchar *name)
return MATE_MIXER_STREAM_GET_CLASS (stream)->get_control (stream, name);
}
+/**
+ * mate_mixer_stream_get_switch:
+ * @stream: a #MateMixerStream
+ */
MateMixerSwitch *
mate_mixer_stream_get_switch (MateMixerStream *stream, const gchar *name)
{
@@ -295,92 +379,40 @@ mate_mixer_stream_get_switch (MateMixerStream *stream, const gchar *name)
return MATE_MIXER_STREAM_GET_CLASS (stream)->get_switch (stream, name);
}
+/**
+ * mate_mixer_stream_get_default_control:
+ * @stream: a #MateMixerStream
+ */
MateMixerStreamControl *
mate_mixer_stream_get_default_control (MateMixerStream *stream)
{
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
- return MATE_MIXER_STREAM_GET_CLASS (stream)->get_default_control (stream);
+ return stream->priv->control;
}
+/**
+ * mate_mixer_stream_list_controls:
+ * @stream: a #MateMixerStream
+ */
const GList *
mate_mixer_stream_list_controls (MateMixerStream *stream)
{
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
- if (stream->priv->controls == NULL)
- stream->priv->controls = MATE_MIXER_STREAM_GET_CLASS (stream)->list_controls (stream);
-
- return (const GList *) stream->priv->controls;
+ return MATE_MIXER_STREAM_GET_CLASS (stream)->list_controls (stream);
}
+/**
+ * mate_mixer_stream_list_switches:
+ * @stream: a #MateMixerStream
+ */
const GList *
mate_mixer_stream_list_switches (MateMixerStream *stream)
{
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
- if (stream->priv->switches == NULL) {
- MateMixerStreamClass *klass = MATE_MIXER_STREAM_GET_CLASS (stream);
-
- if (klass->list_switches != NULL)
- stream->priv->switches = klass->list_switches (stream);
- }
-
- return (const GList *) stream->priv->switches;
-}
-
-gboolean
-mate_mixer_stream_suspend (MateMixerStream *stream)
-{
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
-
- if (stream->priv->state == MATE_MIXER_STREAM_STATE_SUSPENDED)
- return TRUE;
-
- if (stream->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND)
- return MATE_MIXER_STREAM_GET_CLASS (stream)->suspend (stream);
-
- return FALSE;
-}
-
-gboolean
-mate_mixer_stream_resume (MateMixerStream *stream)
-{
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
-
- if (stream->priv->state != MATE_MIXER_STREAM_STATE_SUSPENDED)
- return TRUE;
-
- if (stream->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND)
- return MATE_MIXER_STREAM_GET_CLASS (stream)->resume (stream);
-
- return FALSE;
-}
-
-gboolean
-mate_mixer_stream_monitor_get_enabled (MateMixerStream *stream)
-{
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
-
- return stream->priv->monitor_enabled;
-}
-
-gboolean
-mate_mixer_stream_monitor_set_enabled (MateMixerStream *stream, gboolean enabled)
-{
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
-
- if (stream->priv->monitor_enabled == enabled)
- return TRUE;
-
- if (stream->priv->flags & MATE_MIXER_STREAM_HAS_MONITOR) {
- if (enabled)
- return MATE_MIXER_STREAM_GET_CLASS (stream)->monitor_start (stream);
- else
- return MATE_MIXER_STREAM_GET_CLASS (stream)->monitor_stop (stream);
- }
-
- return FALSE;
+ return MATE_MIXER_STREAM_GET_CLASS (stream)->list_switches (stream);
}
static MateMixerStreamControl *
@@ -422,3 +454,34 @@ mate_mixer_stream_real_get_switch (MateMixerStream *stream, const gchar *name)
}
return NULL;
}
+
+void
+_mate_mixer_stream_set_default_control (MateMixerStream *stream,
+ MateMixerStreamControl *control)
+{
+ g_return_if_fail (MATE_MIXER_IS_STREAM (stream));
+ g_return_if_fail (control == NULL || MATE_MIXER_IS_STREAM_CONTROL (control));
+
+ if (stream->priv->control == control)
+ return;
+
+ if (stream->priv->control != NULL)
+ g_object_unref (stream->priv->control);
+
+ /* The default control is allowed to be NULL */
+ if (control != NULL) {
+ stream->priv->control = g_object_ref (control);
+
+ g_debug ("Stream %s default control changed to %s",
+ mate_mixer_stream_get_name (stream),
+ mate_mixer_stream_control_get_name (control));
+ } else {
+ stream->priv->control = NULL;
+
+ g_debug ("Stream %s default control unset",
+ mate_mixer_stream_get_name (stream));
+ }
+
+ g_object_notify_by_pspec (G_OBJECT (stream),
+ properties[PROP_DEFAULT_CONTROL]);
+}
diff --git a/libmatemixer/matemixer-stream.h b/libmatemixer/matemixer-stream.h
index e73579e..c030196 100644
--- a/libmatemixer/matemixer-stream.h
+++ b/libmatemixer/matemixer-stream.h
@@ -42,6 +42,12 @@ G_BEGIN_DECLS
typedef struct _MateMixerStreamClass MateMixerStreamClass;
typedef struct _MateMixerStreamPrivate MateMixerStreamPrivate;
+/**
+ * MateMixerStream:
+ *
+ * The #MateMixerStream structure contains only private data and should only
+ * be accessed using the provided API.
+ */
struct _MateMixerStream
{
GObject object;
@@ -50,39 +56,43 @@ struct _MateMixerStream
MateMixerStreamPrivate *priv;
};
+/**
+ * MateMixerStreamClass:
+ *
+ * The class structure of #MateMixerStream.
+ */
struct _MateMixerStreamClass
{
GObjectClass parent_class;
/*< private >*/
- MateMixerStreamControl *(*get_control) (MateMixerStream *stream,
- const gchar *name);
-
- MateMixerStreamControl *(*get_default_control) (MateMixerStream *stream);
-
- MateMixerSwitch *(*get_switch) (MateMixerStream *stream,
- const gchar *name);
+ MateMixerStreamControl *(*get_control) (MateMixerStream *stream,
+ const gchar *name);
+ MateMixerSwitch *(*get_switch) (MateMixerStream *stream,
+ const gchar *name);
- GList *(*list_controls) (MateMixerStream *stream);
- GList *(*list_switches) (MateMixerStream *stream);
-
- gboolean (*suspend) (MateMixerStream *stream);
- gboolean (*resume) (MateMixerStream *stream);
-
- gboolean (*monitor_start) (MateMixerStream *stream);
- gboolean (*monitor_stop) (MateMixerStream *stream);
+ const GList *(*list_controls) (MateMixerStream *stream);
+ const GList *(*list_switches) (MateMixerStream *stream);
/* Signals */
- void (*monitor_value) (MateMixerStream *stream, gdouble value);
+ void (*control_added) (MateMixerStream *stream,
+ const gchar *name);
+ void (*control_removed) (MateMixerStream *stream,
+ const gchar *name);
+
+ void (*switch_added) (MateMixerStream *stream,
+ const gchar *name);
+ void (*switch_removed) (MateMixerStream *stream,
+ const gchar *name);
};
GType mate_mixer_stream_get_type (void) G_GNUC_CONST;
const gchar * mate_mixer_stream_get_name (MateMixerStream *stream);
-MateMixerDevice * mate_mixer_stream_get_device (MateMixerStream *stream);
-MateMixerStreamFlags mate_mixer_stream_get_flags (MateMixerStream *stream);
-MateMixerStreamState mate_mixer_stream_get_state (MateMixerStream *stream);
+const gchar * mate_mixer_stream_get_label (MateMixerStream *stream);
+MateMixerDirection mate_mixer_stream_get_direction (MateMixerStream *stream);
+MateMixerDevice * mate_mixer_stream_get_device (MateMixerStream *stream);
MateMixerStreamControl *mate_mixer_stream_get_control (MateMixerStream *stream,
const gchar *name);
MateMixerSwitch * mate_mixer_stream_get_switch (MateMixerStream *stream,
@@ -93,13 +103,6 @@ MateMixerStreamControl *mate_mixer_stream_get_default_control (MateMixerStream *
const GList * mate_mixer_stream_list_controls (MateMixerStream *stream);
const GList * mate_mixer_stream_list_switches (MateMixerStream *stream);
-gboolean mate_mixer_stream_suspend (MateMixerStream *stream);
-gboolean mate_mixer_stream_resume (MateMixerStream *stream);
-
-gboolean mate_mixer_stream_monitor_get_enabled (MateMixerStream *stream);
-gboolean mate_mixer_stream_monitor_set_enabled (MateMixerStream *stream,
- gboolean enabled);
-
G_END_DECLS
#endif /* MATEMIXER_STREAM_H */
diff --git a/libmatemixer/matemixer-switch-option-private.h b/libmatemixer/matemixer-switch-option-private.h
index dea7583..d084dd5 100644
--- a/libmatemixer/matemixer-switch-option-private.h
+++ b/libmatemixer/matemixer-switch-option-private.h
@@ -20,7 +20,7 @@
#include <glib.h>
-#include "matemixer-switch-option.h"
+#include "matemixer-types.h"
G_BEGIN_DECLS
diff --git a/libmatemixer/matemixer-switch-option.c b/libmatemixer/matemixer-switch-option.c
index e924b46..fc0c5b6 100644
--- a/libmatemixer/matemixer-switch-option.c
+++ b/libmatemixer/matemixer-switch-option.c
@@ -121,6 +121,7 @@ mate_mixer_switch_option_get_property (GObject *object,
case PROP_ICON:
g_value_set_string (value, option->priv->icon);
break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -150,6 +151,7 @@ mate_mixer_switch_option_set_property (GObject *object,
/* Construct-only string */
option->priv->icon = g_value_dup_string (value);
break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
diff --git a/libmatemixer/matemixer-switch-option.h b/libmatemixer/matemixer-switch-option.h
index b02c42c..ae87718 100644
--- a/libmatemixer/matemixer-switch-option.h
+++ b/libmatemixer/matemixer-switch-option.h
@@ -20,6 +20,7 @@
#include <glib.h>
#include <glib-object.h>
+
#include <libmatemixer/matemixer-types.h>
G_BEGIN_DECLS
@@ -40,6 +41,12 @@ G_BEGIN_DECLS
typedef struct _MateMixerSwitchOptionClass MateMixerSwitchOptionClass;
typedef struct _MateMixerSwitchOptionPrivate MateMixerSwitchOptionPrivate;
+/**
+ * MateMixerSwitchOption:
+ *
+ * The #MateMixerSwitchOption structure contains only private data and should only
+ * be accessed using the provided API.
+ */
struct _MateMixerSwitchOption
{
GObject parent;
@@ -48,6 +55,11 @@ struct _MateMixerSwitchOption
MateMixerSwitchOptionPrivate *priv;
};
+/**
+ * MateMixerSwitchOptionClass:
+ *
+ * The class structure of #MateMixerSwitchOption.
+ */
struct _MateMixerSwitchOptionClass
{
GObjectClass parent_class;
diff --git a/libmatemixer/matemixer-switch-private.h b/libmatemixer/matemixer-switch-private.h
index 42390a9..bd4761e 100644
--- a/libmatemixer/matemixer-switch-private.h
+++ b/libmatemixer/matemixer-switch-private.h
@@ -19,6 +19,7 @@
#define MATEMIXER_SWITCH_PRIVATE_H
#include <glib.h>
+
#include "matemixer-types.h"
G_BEGIN_DECLS
diff --git a/libmatemixer/matemixer-switch.c b/libmatemixer/matemixer-switch.c
index b30e405..461b49e 100644
--- a/libmatemixer/matemixer-switch.c
+++ b/libmatemixer/matemixer-switch.c
@@ -34,7 +34,8 @@ struct _MateMixerSwitchPrivate
{
gchar *name;
gchar *label;
- GList *options;
+ MateMixerSwitchFlags flags;
+ MateMixerSwitchRole role;
MateMixerSwitchOption *active;
};
@@ -42,6 +43,8 @@ enum {
PROP_0,
PROP_NAME,
PROP_LABEL,
+ PROP_FLAGS,
+ PROP_ROLE,
PROP_ACTIVE_OPTION,
N_PROPERTIES
};
@@ -60,6 +63,7 @@ static void mate_mixer_switch_set_property (GObject *object,
GParamSpec *pspec);
static void mate_mixer_switch_init (MateMixerSwitch *swtch);
+static void mate_mixer_switch_dispose (GObject *object);
static void mate_mixer_switch_finalize (GObject *object);
G_DEFINE_ABSTRACT_TYPE (MateMixerSwitch, mate_mixer_switch, G_TYPE_OBJECT)
@@ -75,6 +79,7 @@ mate_mixer_switch_class_init (MateMixerSwitchClass *klass)
klass->get_option = mate_mixer_switch_real_get_option;
object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = mate_mixer_switch_dispose;
object_class->finalize = mate_mixer_switch_finalize;
object_class->get_property = mate_mixer_switch_get_property;
object_class->set_property = mate_mixer_switch_set_property;
@@ -97,12 +102,33 @@ mate_mixer_switch_class_init (MateMixerSwitchClass *klass)
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
+ properties[PROP_ROLE] =
+ g_param_spec_enum ("role",
+ "Role",
+ "Role of the switch",
+ MATE_MIXER_TYPE_SWITCH_ROLE,
+ MATE_MIXER_SWITCH_ROLE_UNKNOWN,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_FLAGS] =
+ g_param_spec_flags ("flags",
+ "Flags",
+ "Flags of the switch",
+ MATE_MIXER_TYPE_SWITCH_FLAGS,
+ MATE_MIXER_SWITCH_NO_FLAGS,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
properties[PROP_ACTIVE_OPTION] =
g_param_spec_object ("active-option",
"Active option",
"Active option of the switch",
MATE_MIXER_TYPE_SWITCH_OPTION,
- G_PARAM_READABLE |
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
@@ -127,6 +153,16 @@ mate_mixer_switch_get_property (GObject *object,
case PROP_LABEL:
g_value_set_string (value, swtch->priv->label);
break;
+ case PROP_FLAGS:
+ g_value_set_flags (value, swtch->priv->flags);
+ break;
+ case PROP_ROLE:
+ g_value_set_enum (value, swtch->priv->role);
+ break;
+ case PROP_ACTIVE_OPTION:
+ g_value_set_object (value, swtch->priv->active);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -152,6 +188,17 @@ mate_mixer_switch_set_property (GObject *object,
/* Construct-only string */
swtch->priv->label = g_value_dup_string (value);
break;
+ case PROP_FLAGS:
+ swtch->priv->flags = g_value_get_flags (value);
+ break;
+ case PROP_ROLE:
+ swtch->priv->role = g_value_get_enum (value);
+ break;
+ case PROP_ACTIVE_OPTION:
+ /* Construct-only object */
+ swtch->priv->active = g_value_dup_object (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -167,6 +214,18 @@ mate_mixer_switch_init (MateMixerSwitch *swtch)
}
static void
+mate_mixer_switch_dispose (GObject *object)
+{
+ MateMixerSwitch *swtch;
+
+ swtch = MATE_MIXER_SWITCH (object);
+
+ g_clear_object (&swtch->priv->active);
+
+ G_OBJECT_CLASS (mate_mixer_switch_parent_class)->dispose (object);
+}
+
+static void
mate_mixer_switch_finalize (GObject *object)
{
MateMixerSwitch *swtch;
@@ -179,6 +238,10 @@ mate_mixer_switch_finalize (GObject *object)
G_OBJECT_CLASS (mate_mixer_switch_parent_class)->finalize (object);
}
+/**
+ * mate_mixer_switch_get_name:
+ * @swtch: a #MateMixerSwitch
+ */
const gchar *
mate_mixer_switch_get_name (MateMixerSwitch *swtch)
{
@@ -187,6 +250,10 @@ mate_mixer_switch_get_name (MateMixerSwitch *swtch)
return swtch->priv->name;
}
+/**
+ * mate_mixer_switch_get_label:
+ * @swtch: a #MateMixerSwitch
+ */
const gchar *
mate_mixer_switch_get_label (MateMixerSwitch *swtch)
{
@@ -195,6 +262,34 @@ mate_mixer_switch_get_label (MateMixerSwitch *swtch)
return swtch->priv->label;
}
+/**
+ * mate_mixer_switch_get_flags:
+ * @swtch: a #MateMixerSwitch
+ */
+MateMixerSwitchFlags
+mate_mixer_switch_get_flags (MateMixerSwitch *swtch)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), MATE_MIXER_SWITCH_NO_FLAGS);
+
+ return swtch->priv->flags;
+}
+
+/**
+ * mate_mixer_switch_get_role:
+ * @swtch: a #MateMixerSwitch
+ */
+MateMixerSwitchRole
+mate_mixer_switch_get_role (MateMixerSwitch *swtch)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), MATE_MIXER_SWITCH_ROLE_UNKNOWN);
+
+ return swtch->priv->role;
+}
+
+/**
+ * mate_mixer_switch_get_option:
+ * @swtch: a #MateMixerSwitch
+ */
MateMixerSwitchOption *
mate_mixer_switch_get_option (MateMixerSwitch *swtch, const gchar *name)
{
@@ -203,6 +298,10 @@ mate_mixer_switch_get_option (MateMixerSwitch *swtch, const gchar *name)
return MATE_MIXER_SWITCH_GET_CLASS (swtch)->get_option (swtch, name);
}
+/**
+ * mate_mixer_switch_get_active_option:
+ * @swtch: a #MateMixerSwitch
+ */
MateMixerSwitchOption *
mate_mixer_switch_get_active_option (MateMixerSwitch *swtch)
{
@@ -211,45 +310,48 @@ mate_mixer_switch_get_active_option (MateMixerSwitch *swtch)
return swtch->priv->active;
}
+/**
+ * mate_mixer_switch_set_active_option:
+ * @swtch: a #MateMixerSwitch
+ */
gboolean
mate_mixer_switch_set_active_option (MateMixerSwitch *swtch,
MateMixerSwitchOption *option)
{
- MateMixerSwitchClass *klass;
-
g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), FALSE);
- klass = MATE_MIXER_SWITCH_GET_CLASS (swtch);
- if (klass->set_active_option != NULL) {
- if (klass->set_active_option (swtch, option) == FALSE)
+ if (swtch->priv->active != option) {
+ MateMixerSwitchClass *klass;
+
+ klass = MATE_MIXER_SWITCH_GET_CLASS (swtch);
+ if (klass->set_active_option == NULL ||
+ klass->set_active_option (swtch, option) == FALSE)
return FALSE;
_mate_mixer_switch_set_active_option (swtch, option);
- return TRUE;
}
- return FALSE;
+ return TRUE;
}
+/**
+ * mate_mixer_switch_get_name:
+ * @swtch: a #MateMixerSwitch
+ */
const GList *
mate_mixer_switch_list_options (MateMixerSwitch *swtch)
{
g_return_val_if_fail (MATE_MIXER_IS_SWITCH (swtch), NULL);
- if (swtch->priv->options == NULL) {
- MateMixerSwitchClass *klass = MATE_MIXER_SWITCH_GET_CLASS (swtch);
-
- if (klass->list_options != NULL)
- swtch->priv->options = klass->list_options (swtch);
- }
- return (const GList *) swtch->priv->options;
+ return MATE_MIXER_SWITCH_GET_CLASS (swtch)->list_options (swtch);
}
+/* Protected functions */
void
_mate_mixer_switch_set_active_option (MateMixerSwitch *swtch,
MateMixerSwitchOption *option)
{
g_return_if_fail (MATE_MIXER_IS_SWITCH (swtch));
- g_return_if_fail (MATE_MIXER_IS_SWITCH_OPTION (option));
+ g_return_if_fail (option == NULL || MATE_MIXER_IS_SWITCH_OPTION (option));
if (swtch->priv->active == option)
return;
@@ -257,9 +359,13 @@ _mate_mixer_switch_set_active_option (MateMixerSwitch *swtch,
if (swtch->priv->active != NULL)
g_object_unref (swtch->priv->active);
- swtch->priv->active = g_object_ref (option);
+ if (option != NULL)
+ swtch->priv->active = g_object_ref (option);
+ else
+ swtch->priv->active = NULL;
- g_object_notify_by_pspec (G_OBJECT (swtch), properties[PROP_ACTIVE_OPTION]);
+ g_object_notify_by_pspec (G_OBJECT (swtch),
+ properties[PROP_ACTIVE_OPTION]);
}
static MateMixerSwitchOption *
diff --git a/libmatemixer/matemixer-switch.h b/libmatemixer/matemixer-switch.h
index 3035607..7f0109f 100644
--- a/libmatemixer/matemixer-switch.h
+++ b/libmatemixer/matemixer-switch.h
@@ -21,6 +21,7 @@
#include <glib.h>
#include <glib-object.h>
+#include <libmatemixer/matemixer-enums.h>
#include <libmatemixer/matemixer-types.h>
G_BEGIN_DECLS
@@ -41,6 +42,12 @@ G_BEGIN_DECLS
typedef struct _MateMixerSwitchClass MateMixerSwitchClass;
typedef struct _MateMixerSwitchPrivate MateMixerSwitchPrivate;
+/**
+ * MateMixerSwitch:
+ *
+ * The #MateMixerSwitch structure contains only private data and should only
+ * be accessed using the provided API.
+ */
struct _MateMixerSwitch
{
GObject object;
@@ -49,6 +56,11 @@ struct _MateMixerSwitch
MateMixerSwitchPrivate *priv;
};
+/**
+ * MateMixerSwitchClass:
+ *
+ * The class structure of #MateMixerSwitch.
+ */
struct _MateMixerSwitchClass
{
GObjectClass parent_class;
@@ -57,26 +69,28 @@ struct _MateMixerSwitchClass
MateMixerSwitchOption *(*get_option) (MateMixerSwitch *swtch,
const gchar *name);
+ const GList *(*list_options) (MateMixerSwitch *swtch);
+
gboolean (*set_active_option) (MateMixerSwitch *swtch,
MateMixerSwitchOption *option);
-
- GList *(*list_options) (MateMixerSwitch *swtch);
};
GType mate_mixer_switch_get_type (void) G_GNUC_CONST;
const gchar * mate_mixer_switch_get_name (MateMixerSwitch *swtch);
const gchar * mate_mixer_switch_get_label (MateMixerSwitch *swtch);
+MateMixerSwitchFlags mate_mixer_switch_get_flags (MateMixerSwitch *swtch);
+MateMixerSwitchRole mate_mixer_switch_get_role (MateMixerSwitch *swtch);
MateMixerSwitchOption *mate_mixer_switch_get_option (MateMixerSwitch *swtch,
const gchar *name);
+const GList * mate_mixer_switch_list_options (MateMixerSwitch *swtch);
+
MateMixerSwitchOption *mate_mixer_switch_get_active_option (MateMixerSwitch *swtch);
gboolean mate_mixer_switch_set_active_option (MateMixerSwitch *swtch,
MateMixerSwitchOption *option);
-const GList * mate_mixer_switch_list_options (MateMixerSwitch *swtch);
-
G_END_DECLS
#endif /* MATEMIXER_SWITCH_H */
diff --git a/libmatemixer/matemixer-toggle.c b/libmatemixer/matemixer-toggle.c
index 2eea599..0db6e3b 100644
--- a/libmatemixer/matemixer-toggle.c
+++ b/libmatemixer/matemixer-toggle.c
@@ -30,6 +30,7 @@
struct _MateMixerTogglePrivate
{
+ GList *options;
MateMixerSwitchOption *on;
MateMixerSwitchOption *off;
};
@@ -63,7 +64,7 @@ G_DEFINE_ABSTRACT_TYPE (MateMixerToggle, mate_mixer_toggle, MATE_MIXER_TYPE_SWIT
static MateMixerSwitchOption *mate_mixer_toggle_get_option (MateMixerSwitch *swtch,
const gchar *name);
-static GList * mate_mixer_toggle_list_options (MateMixerSwitch *swtch);
+static const GList * mate_mixer_toggle_list_options (MateMixerSwitch *swtch);
static void
mate_mixer_toggle_class_init (MateMixerToggleClass *klass)
@@ -83,7 +84,7 @@ mate_mixer_toggle_class_init (MateMixerToggleClass *klass)
properties[PROP_STATE] =
g_param_spec_boolean ("state",
"State",
- "Current state",
+ "Current state of the toggle",
FALSE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
@@ -131,6 +132,7 @@ mate_mixer_toggle_get_property (GObject *object,
case PROP_STATE_OPTION_OFF:
g_value_set_object (value, toggle->priv->off);
break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -156,6 +158,7 @@ mate_mixer_toggle_set_property (GObject *object,
/* Construct-only object */
toggle->priv->off = g_value_dup_object (value);
break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -177,12 +180,22 @@ mate_mixer_toggle_dispose (GObject *object)
toggle = MATE_MIXER_TOGGLE (object);
+ if (toggle->priv->options != NULL) {
+ g_list_free_full (toggle->priv->options, g_object_unref);
+ toggle->priv->options = NULL;
+ }
+
+ /* FIXME: crashes on ALSA without the polling thread */
g_clear_object (&toggle->priv->on);
g_clear_object (&toggle->priv->off);
G_OBJECT_CLASS (mate_mixer_toggle_parent_class)->dispose (object);
}
+/**
+ * mate_mixer_toggle_get_state:
+ * @toggle: a #MateMixerToggle
+ */
gboolean
mate_mixer_toggle_get_state (MateMixerToggle *toggle)
{
@@ -197,6 +210,10 @@ mate_mixer_toggle_get_state (MateMixerToggle *toggle)
return FALSE;
}
+/**
+ * mate_mixer_toggle_get_state_option:
+ * @toggle: a #MateMixerToggle
+ */
MateMixerSwitchOption *
mate_mixer_toggle_get_state_option (MateMixerToggle *toggle, gboolean state)
{
@@ -208,6 +225,10 @@ mate_mixer_toggle_get_state_option (MateMixerToggle *toggle, gboolean state)
return toggle->priv->off;
}
+/**
+ * mate_mixer_toggle_set_state:
+ * @toggle: a #MateMixerToggle
+ */
gboolean
mate_mixer_toggle_set_state (MateMixerToggle *toggle, gboolean state)
{
@@ -240,15 +261,20 @@ mate_mixer_toggle_get_option (MateMixerSwitch *swtch, const gchar *name)
return NULL;
}
-static GList *
+static const GList *
mate_mixer_toggle_list_options (MateMixerSwitch *swtch)
{
- GList *list = NULL;
+ MateMixerToggle *toggle;
g_return_val_if_fail (MATE_MIXER_IS_TOGGLE (swtch), NULL);
- list = g_list_prepend (list, MATE_MIXER_TOGGLE (swtch)->priv->off);
- list = g_list_prepend (list, MATE_MIXER_TOGGLE (swtch)->priv->on);
+ toggle = MATE_MIXER_TOGGLE (swtch);
- return list;
+ if (toggle->priv->options == NULL) {
+ toggle->priv->options = g_list_prepend (toggle->priv->options,
+ toggle->priv->off);
+ toggle->priv->options = g_list_prepend (toggle->priv->options,
+ toggle->priv->on);
+ }
+ return toggle->priv->options;
}
diff --git a/libmatemixer/matemixer-toggle.h b/libmatemixer/matemixer-toggle.h
index 1cedfc5..44946f7 100644
--- a/libmatemixer/matemixer-toggle.h
+++ b/libmatemixer/matemixer-toggle.h
@@ -25,22 +25,28 @@
G_BEGIN_DECLS
-#define MATE_MIXER_TYPE_TOGGLE \
+#define MATE_MIXER_TYPE_TOGGLE \
(mate_mixer_toggle_get_type ())
-#define MATE_MIXER_TOGGLE(o) \
+#define MATE_MIXER_TOGGLE(o) \
(G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_TOGGLE, MateMixerToggle))
-#define MATE_MIXER_IS_TOGGLE(o) \
+#define MATE_MIXER_IS_TOGGLE(o) \
(G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_TOGGLE))
-#define MATE_MIXER_TOGGLE_CLASS(k) \
+#define MATE_MIXER_TOGGLE_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_TOGGLE, MateMixerToggleClass))
-#define MATE_MIXER_IS_TOGGLE_CLASS(k) \
+#define MATE_MIXER_IS_TOGGLE_CLASS(k) \
(G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_TOGGLE))
-#define MATE_MIXER_TOGGLE_GET_CLASS(o) \
+#define MATE_MIXER_TOGGLE_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_TOGGLE, MateMixerToggleClass))
typedef struct _MateMixerToggleClass MateMixerToggleClass;
typedef struct _MateMixerTogglePrivate MateMixerTogglePrivate;
+/**
+ * MateMixerToggle:
+ *
+ * The #MateMixerToggle structure contains only private data and should only
+ * be accessed using the provided API.
+ */
struct _MateMixerToggle
{
MateMixerSwitch object;
@@ -49,6 +55,11 @@ struct _MateMixerToggle
MateMixerTogglePrivate *priv;
};
+/**
+ * MateMixerToggleClass:
+ *
+ * The class structure of #MateMixerToggle.
+ */
struct _MateMixerToggleClass
{
MateMixerSwitchClass parent_class;
diff --git a/libmatemixer/matemixer-types.h b/libmatemixer/matemixer-types.h
index 6601a95..57a64a1 100644
--- a/libmatemixer/matemixer-types.h
+++ b/libmatemixer/matemixer-types.h
@@ -20,10 +20,11 @@
G_BEGIN_DECLS
+typedef struct _MateMixerAppInfo MateMixerAppInfo;
typedef struct _MateMixerDevice MateMixerDevice;
-typedef struct _MateMixerClientStream MateMixerClientStream;
typedef struct _MateMixerContext MateMixerContext;
typedef struct _MateMixerDeviceProfile MateMixerDeviceProfile;
+typedef struct _MateMixerStoredControl MateMixerStoredControl;
typedef struct _MateMixerStream MateMixerStream;
typedef struct _MateMixerStreamControl MateMixerStreamControl;
typedef struct _MateMixerSwitch MateMixerSwitch;
diff --git a/libmatemixer/matemixer.c b/libmatemixer/matemixer.c
index fa83e3f..a5bca6f 100644
--- a/libmatemixer/matemixer.c
+++ b/libmatemixer/matemixer.c
@@ -100,13 +100,14 @@ mate_mixer_is_initialized (void)
return initialized;
}
-/* Return a list of loaded backend modules */
+/* Internal: return a list of loaded backend modules */
const GList *
-_mate_mixer_get_modules (void)
+_mate_mixer_list_modules (void)
{
return (const GList *) modules;
}
+/* Internal: create a channel mask using the given list of channel positions */
guint32
_mate_mixer_create_channel_mask (MateMixerChannelPosition *positions, guint n)
{
diff --git a/libmatemixer/matemixer.h b/libmatemixer/matemixer.h
index a6eac79..589bf0d 100644
--- a/libmatemixer/matemixer.h
+++ b/libmatemixer/matemixer.h
@@ -21,11 +21,14 @@
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-client-stream.h>
+#include <libmatemixer/matemixer-types.h>
+
+#include <libmatemixer/matemixer-app-info.h>
#include <libmatemixer/matemixer-context.h>
#include <libmatemixer/matemixer-device.h>
-#include <libmatemixer/matemixer-device-profile.h>
#include <libmatemixer/matemixer-enums.h>
+#include <libmatemixer/matemixer-enum-types.h>
+#include <libmatemixer/matemixer-stored-control.h>
#include <libmatemixer/matemixer-stream.h>
#include <libmatemixer/matemixer-stream-control.h>
#include <libmatemixer/matemixer-switch.h>
diff --git a/po/ChangeLog b/po/ChangeLog
new file mode 100644
index 0000000..f59ae48
--- /dev/null
+++ b/po/ChangeLog
@@ -0,0 +1,12 @@
+2014-08-16 gettextize <[email protected]>
+
+ * Makefile.in.in: New file, from gettext-0.19.2.
+ * Rules-quot: New file, from gettext-0.19.2.
+ * boldquot.sed: New file, from gettext-0.19.2.
+ * [email protected]: New file, from gettext-0.19.2.
+ * [email protected]: New file, from gettext-0.19.2.
+ * insert-header.sin: New file, from gettext-0.19.2.
+ * quot.sed: New file, from gettext-0.19.2.
+ * remove-potcdate.sin: New file, from gettext-0.19.2.
+ * POTFILES.in: New file.
+
diff --git a/po/Makevars b/po/Makevars
new file mode 100644
index 0000000..32692ab
--- /dev/null
+++ b/po/Makevars
@@ -0,0 +1,41 @@
+# Makefile variables for PO directory in any package using GNU gettext.
+
+# Usually the message domain is the same as the package name.
+DOMAIN = $(PACKAGE)
+
+# These two variables depend on the location of this directory.
+subdir = po
+top_builddir = ..
+
+# These options get passed to xgettext.
+XGETTEXT_OPTIONS = --keyword=_ --keyword=N_
+
+# This is the copyright holder that gets inserted into the header of the
+# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding
+# package. (Note that the msgstr strings, extracted from the package's
+# sources, belong to the copyright holder of the package.) Translators are
+# expected to transfer the copyright for their translations to this person
+# or entity, or to disclaim their copyright. The empty string stands for
+# the public domain; in this case the translators are expected to disclaim
+# their copyright.
+COPYRIGHT_HOLDER = Free Software Foundation, Inc.
+
+# This is the email address or URL to which the translators shall report
+# bugs in the untranslated strings:
+# - Strings which are not entire sentences, see the maintainer guidelines
+# in the GNU gettext documentation, section 'Preparing Strings'.
+# - Strings which use unclear terms or require additional context to be
+# understood.
+# - Strings which make invalid assumptions about notation of date, time or
+# money.
+# - Pluralisation problems.
+# - Incorrect English spelling.
+# - Incorrect formatting.
+# It can be your email address, or a mailing list address where translators
+# can write to without being subscribed, or the URL of a web page through
+# which the translators can contact you.
+MSGID_BUGS_ADDRESS =
+
+# This is the list of locale categories, beyond LC_MESSAGES, for which the
+# message catalogs shall be used. It is usually empty.
+EXTRA_LOCALE_CATEGORIES =
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644
index 0000000..667e27c
--- /dev/null
+++ b/po/POTFILES.in
@@ -0,0 +1 @@
+# List of source files which contain translatable strings.