diff options
author | Rainer Blickle <rblickle@gmx.de> | 2010-08-13 21:05:19 +0200 |
---|---|---|
committer | root <root@server.(none)> | 2010-08-13 21:05:19 +0200 |
commit | 201670d0adaf587758bbbad0b03f4e5431a70e61 (patch) | |
tree | 61683358b6cbb6f3f03f9fc9ea8540d2c9742ed7 | |
download | vdr-plugin-sndctl-201670d0adaf587758bbbad0b03f4e5431a70e61.tar.gz vdr-plugin-sndctl-201670d0adaf587758bbbad0b03f4e5431a70e61.tar.bz2 |
Initial import
-rw-r--r-- | COPYING | 340 | ||||
-rw-r--r-- | HISTORY | 33 | ||||
-rw-r--r-- | INSTALL | 33 | ||||
-rw-r--r-- | INSTALL.de | 33 | ||||
-rw-r--r-- | Makefile | 71 | ||||
-rw-r--r-- | README | 213 | ||||
-rw-r--r-- | README.de | 223 | ||||
-rw-r--r-- | TODO | 19 | ||||
-rw-r--r-- | alsa.c | 201 | ||||
-rw-r--r-- | alsa.h | 43 | ||||
-rw-r--r-- | defaults.h | 72 | ||||
-rw-r--r-- | i18n.c | 416 | ||||
-rw-r--r-- | i18n.h | 34 | ||||
-rw-r--r-- | mainmenu.c | 132 | ||||
-rw-r--r-- | mainmenu.h | 33 | ||||
-rw-r--r-- | menuitems.c | 165 | ||||
-rw-r--r-- | menuitems.h | 73 | ||||
-rw-r--r-- | mixer.c | 176 | ||||
-rw-r--r-- | mixer.h | 66 | ||||
-rw-r--r-- | setup.c | 135 | ||||
-rw-r--r-- | setup.h | 36 | ||||
-rw-r--r-- | setupmenu.c | 105 | ||||
-rw-r--r-- | setupmenu.h | 40 | ||||
-rw-r--r-- | sndctl.c | 283 | ||||
-rw-r--r-- | sndctl.cbp | 81 | ||||
-rw-r--r-- | sndctl.h | 58 | ||||
-rw-r--r-- | sndctl.layout | 43 | ||||
-rw-r--r-- | soundman.c | 334 | ||||
-rw-r--r-- | soundman.h | 54 | ||||
-rw-r--r-- | soundset.c | 207 | ||||
-rw-r--r-- | soundset.h | 48 | ||||
-rw-r--r-- | soundsetmenu.c | 71 | ||||
-rw-r--r-- | soundsetmenu.h | 34 | ||||
-rw-r--r-- | status.c | 47 | ||||
-rw-r--r-- | status.h | 34 |
35 files changed, 3986 insertions, 0 deletions
@@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. @@ -0,0 +1,33 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Thomas Hildebrandt <toxym@web.de> +Project's homepage: none +Latest version available at: http://www.box.net/shared/qhu44kgcv4 + +See the file COPYING for license information. + +--------------------------------------------------------------------------- +Sound control plugin - 'sndctl' +--------------------------------------------------------------------------- + + HISTORY +=============================== + +2007-05-16: version 0.1.3 +- bug in sound set editing fixed (crash when editing twice) + +2007-04-22: version 0.1.2 +- Sound flash implemented +- bugfixing (in sound set editing) + +2007-04-20: version 0.1.1 +- bugfixing in SVDR handling + +2007-04-19: version 0.1.0 +- creating, editing and deleting of sound sets from VDR menu implemented +- Dolby digital auto switch implemented +- SVDR commands implemented +- initial volume implemented + +2007-03-14: version 0.0.1 +- Initial revision @@ -0,0 +1,33 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Thomas Hildebrandt <toxym@web.de> +Further development: Rainer Blicke <rblickle@gmx.de> +Project's homepage: none +Latest version available at: http://www.box.net/shared/qhu44kgcv4 + +See the file COPYING for license information. + +--------------------------------------------------------------------------- +Sound control plugin - 'sndctl' +--------------------------------------------------------------------------- + + Installation +------------------------------- +Handle like any other plugin for VDR. (All following paths may be different +for your system.) + +installation example: + +* install the alsa header files + for debian use: apt-get install libasound2-dev +* untar to the VDR plugins directory + example: cd /usr/src/vdr/VDR/PLUGINS/src + tar -xzf /path/to/vdr-sndctl-0.1.2.tgz +* make a symlink + example: ln -sf sndctl-0.1.2 /usr/src/vdr/VDR/PLUGINS/src/sndctl +* do a 'make' from the VDR directory + example: cd /usr/src/vdr/VDR + make plugins +* copy the library to the appropriate directory (or let it 'make' do) + example: make install-plugins +* be sure, your VDR is called with argument '-P sndctl' diff --git a/INSTALL.de b/INSTALL.de new file mode 100644 index 0000000..7efe259 --- /dev/null +++ b/INSTALL.de @@ -0,0 +1,33 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Thomas Hildebrandt <toxym@web.de> +Weiterentwicklung: Rainer Blicke <rblickle@gmx.de> +Project's homepage: none +Latest version available at: http://www.box.net/shared/qhu44kgcv4 + +See the file COPYING for license information. + +--------------------------------------------------------------------------- +Sound control plugin - 'sndctl' +--------------------------------------------------------------------------- + + Installation +------------------------------- +Die Installation erfolgt auf die gleiche Weise wie bei jedem anderen Plugin. +(Alle folgenden Pfade koennen auf deinem System anders lauten.) + +Beispielinstallation: + +* installieren der alsa-header-files + für debian: apt-get install libasound2-dev +* auspacken in VDR Plugin-Verzeichnis + Beispiel: cd /usr/src/vdr/VDR/PLUGINS/src + tar -xzf /path/to/vdr-sndctl-0.1.2tgz +* symbolischen Link erstellen + Beispiel: ln -sf sndctl-0.1.2 /usr/src/vdr/VDR/PLUGINS/src/sndctl +* 'make' aus dem VDR Verzeichnis ausfuehren + Beispiel: cd /usr/src/vdr/VDR + make plugins +* Bibliothek an die richtige Stelle kopieren (oder von 'make' tun lassen) + Beispiel: make install-plugins +* stelle sicher, dass dein VDR mit dem Argument '-P sndctl' aufgrufen wird diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5b00089 --- /dev/null +++ b/Makefile @@ -0,0 +1,71 @@ +# +# Makefile for Video Disk Recorder plugin 'sndctl' +# +# Thomas Hildebrandt <toxym@web.de> + +# The official name of this plugin. +PLUGIN = sndctl + +### The version number of this plugin (taken from the main source file): +VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g') + +### The C++ compiler and options: +CXX ?= g++ +CXXFLAGS ?= -fPIC -g -O2 -Wall -Woverloaded-virtual +#CXXFLAGS ?= -O2 -Wall -Woverloaded-virtual + +### The directory environment: +VDRDIR = ../../.. +LIBDIR = ../../lib +TMPDIR = /tmp + +### Allow user defined options to overwrite defaults: +-include $(VDRDIR)/Make.config + +### The version number of VDR's plugin API (taken from VDR's "config.h"): +APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h) + +### The name of the distribution archive: +ARCHIVE = $(PLUGIN)-$(VERSION) +PACKAGE = vdr-$(ARCHIVE) + +### Includes and Defines (add further entries here): +INCLUDES += -I$(VDRDIR)/include +DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' + +### The object files (add further files here): +OBJS = $(PLUGIN).o alsa.o i18n.o mainmenu.o menuitems.o mixer.o setup.o\ + setupmenu.o soundman.o soundset.o soundsetmenu.o status.o + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +# Dependencies: + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Targets: + +all: libvdr-$(PLUGIN).so + +libvdr-$(PLUGIN).so: $(OBJS) + $(CXX) $(CXXFLAGS) -shared $(OBJS) -lasound -o $@ + @cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION) + +dist: clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @echo Distribution package created as $(PACKAGE).tgz + +clean: + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ @@ -0,0 +1,213 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Thomas Hildebrandt <toxym@web.de> +Further development: Rainer Blicke <rblickle@gmx.de> +Project's homepage: none +Latest version available at: http://www.box.net/shared/qhu44kgcv4 + +See the file COPYING for license information. + +--------------------------------------------------------------------------- +Sound control plugin - 'sndctl' +--------------------------------------------------------------------------- + + MOTIVATION +=============================== +This plugin was inspired and reengineered from the AVolCtl-Plugin by Martin +Prochnow (thanks for it). +It's used to control the volume levels of different controls of your sound- +card according to the volume settings of VDR. + +So far so good, you can use 'AVolCtl' for this purpose, too. My personal +needs are to have different ways, how the soundcard controls depends from +the VDR volume settings. This ways (or profiles) are named 'sound sets'. + +A sound set for 'normal' stereo sound is different from a dolby digital +sound set, means, other soundcard controls have to be moved, when changing +the VDR volume. + +With 'sndctl' you can define as many sound sets as you want and switch +between it from the VDR menu. + + + PREREQUISITES +=============================== +VDR version 1.4.1 or higher +ALSA 1.0.x + + DEVELOPMENT ENVIRONMENT +------------------------------- +Linux 2.6.8.1 (LFS 6.0) +VDR 1.5.1 +ALSA-Lib 1.0.10 +g++ (GCC) 3.4.1 + + COMPILATION AND RUNNING TESTED +------------------------------- +VDR 1.4.1 +VDR 1.4.6 +VDR 1.5.0 +VDR 1.5.1 +VDR 1.5.2 + + + HANDLING +=============================== +The switching between the several sound sets is done in the main menu entry. +The currently activated sound set is marked. Select a sound set with 'Up' and +'Down' and confirm with 'Ok' or 'Red' (menu disappears with this selection). + +A new sound set can be created with 'Blue', edited with 'Green' and deleted +with 'Yellow'. + + + CONFIGURATION +=============================== +Configuration is divided into two parts. General settings can be found as +usual in the plugin configuration menu of VDR. The sound set configuration +takes place in the main menu entry. + + GENERAL SETTINGS +------------------------------- +"Hide main menu entry" + when set to 'yes', no plugin entry is shown in VDR main menu + +"Menu name" + The plugin entry in the VDR main menu gets this name + (I like to name it for instance 'Sound Manager'.) + +"Initial volume" + -1: VDR volume is set when starting + 0..100: This value is the initial volume instead of the VDR volume. The + first VDR volume change synchronizes the plugin volume with the + VDR volume. + + Why this? + When VDR does an automatic boot up (e.g. for making some + recordings) and thats why (like my case) the 5.1 system goes up, + too, VDR of course should be muted. + For this, we could give VDR an initial volume of 0. But when I + decide to switch my VDR on to look TV, I have to give it a 'normal' + volume manually. + Solution: Give 'sndctl' an initial volume of 0. This causes VDR to start + muted, but one volume key hit results in initial VDR volume. + +"Default sound set" + This sound set gets activated when starting. + In addition, this is the sound set to switch to, when the Dolby Digital + auto switcher detects a non-DD stream. + +"Auto switch for DD" + When active, the plugin tries to detect the switching to a Dolby Digital + audio channel and activates the appropriate sound set. + +"Auto switch sound set", + see before ... This sound set is used for the Dolby Digital switching. + +"Enable sound flash" + Activates the 'sound flash' function. + If the volume goes up and down within a short time, the plugin changes the + volume to very loud but immediately back to the normal value. + Why this? + You may use some devices with an automatic standby connected to your + soundcard. It may decide to go into sleep when your volume is low. Now you + have to go up with your volume to switch on your external equipment and, of + course, go back, if you don't want to hear it so loud. + Solution: Sound flash -> Change volume up and down fast and with the short + volume increasing your external technic is back online. You can't + hear the 'sound flash' itself; until the external devices are + ready, the volume was changed back to normal. + +"Mute on end" + Mutes volume, when VDR quits. + + + SOUND SET SETTINGS +------------------------------- +"name" + The name of the sound set. + +All of the following parameters are names for the soundcard controls. +(Well, not for all, but for 'senseful' ones.) +Every control owns a certain value, which causes a certain behaviour. + +The value syntax is always the same and is STRICTLY to made as descripted. + + operation + | + | minimum (the control will not go lesser than this) + | | + =80;1;90 + | | + | maximum (the control will not go over this value) + | + value (VDR volume and operation results in control volume) + +The operation is mandatory, all other values may not be important. +See some examples for demonstration: +"~" + does nothing, the control will not be 'touched' + (default value for all controls in a new sound set) + +"=0" + set the control fixed to the value (here 0) + (on my system e.g. Bass =40 / Treble =60) + +"+10" + adds the value to VDR volume + (e.g. "+0" follows VDR voluem directly) + +"-5" + subtracts the value (here 5) from VDR volume + +"%10" + control value is always 10% of VDR volume + +"+10;1" + plus 10, but never less than 1 + Why this? + The 'LFE' control of my soundcard (which controls the subwoofer) has only + 32 steps. This causes the hardware on little volume values sometimes to + go completely to 0, when real volume is 5% (or similar). This minimum value + prevents from this. + + + SVDR +=============================== +THe following SVDR commands will be provided. + +SSET [ name ] + set or show the active sound set (by name) + +SSID [ id ] + set or show the active sound set (by ID) + +LIST [ names | all ] + without parameter shows a list of the ID's of all sound sets, + with 'names' a list with sound set names and with all a list + with both, ID and name + + EXAMPLES +------------------------------- +svdrpsend.pl plug sndctl list +svdrpsend.pl plug sndctl list all +svdrpsend.pl plug sndctl sset +svdrpsend.pl plug sndctl sset Stereo + + + HINT +=============================== +- the plugin calculates volumes from 0 to 100 +- if volume goes to 0, no minimum value will be used, the control goes to 0 +- the following operation modes (first character) are valid: + '~' > do nothing (a control with this setting will be removed from the + setup values) + '=' > set this control always to the same level + (nice for 'Bass' and 'Treble' or control muting) + '+' > increase the VDR volume with this value + '-' > decrease the VDR volume with this value + '%' > set volume level to x percent of the VDR volume +- if VDR on your system doesn't run as root, the VDR user needs permissions + to access the soundcard mixer device; maybe you need to put the VDR user + to the group 'audio' or 'video' + diff --git a/README.de b/README.de new file mode 100644 index 0000000..e351242 --- /dev/null +++ b/README.de @@ -0,0 +1,223 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Thomas Hildebrandt <toxym@web.de> +Weiterentwicklung: Rainer Blicke <rblickle@gmx.de> +Project's homepage: none +Latest version available at: http://www.box.net/shared/qhu44kgcv4 + +See the file COPYING for license information. + +--------------------------------------------------------------------------- +Sound control plugin - 'sndctl' +--------------------------------------------------------------------------- + + MOTIVATION +=============================== +Dieses Plugin wurde inspiriert und neuentwickelt aus dem AVolCtl-Plugin von +Martin Prochnow (vielen Dank dafuer). +Es steuert die Lautstaerke verschiedener Regler der Soundkarte in +Abhaengigkeit von der Lautstaerkeregelung des VDR. + +So weit so gut, fuer diesen Zweck kann man 'AVolCtl' auch verwenden. Meine +persoenlichen Beduerfnisse waren, verschiedene Wege zu haben, wie die +Regler der Soundkarte von der VDR-Lautstaerke abhaengen. Diese Wege +(oder Profile) nenne ich 'Soundsets'. + +Ein Soundset fuer 'normales' Stereo unterscheidet sich von einem Dolby +Digital Soundset, sprich, andere Soundkarten-Regler bewegen sich, wenn +VDR die Lautstaerke aendert. + +Mit 'sndctl' lassen sich beliebig viele Soundsets anlegen, zwischen denen +aus dem VDR-Menue umgeschaltet werden kann. + + + VORAUSSETZUNGEN +=============================== +VDR ab Version 1.4.1 +ALSA 1.0.x + + ENTWICKLUNGSUMGEBUNG +------------------------------- +Linux 2.6.8.1 (LFS 6.0) +VDR 1.5.1 +ALSA-Lib 1.0.10 +g++ (GCC) 3.4.1 + + KOMPILIERT UND GETESTET +------------------------------- +VDR 1.4.1 +VDR 1.4.6 +VDR 1.5.0 +VDR 1.5.1 +VDR 1.5.2 + + + BEDIENUNG +=============================== +Das Umschalten zwischen den einzelnen Soundsets erledigt man ueber den +Eintrag im Hauptmenue. Das derzeit aktive Soundset ist gekennzeichnet. +Mit 'Hoch' und 'Runter' waehlt man das gewuenschte Soundset, 'Ok' oder +'Rot' aktiviert das Soundset (und beendet das Menue). + +Ein neues Soundset wird mit 'Blau' angelegt, ein bestehendes mit 'Gruen' +veraendert und mit 'Gelb' geloescht. + + + KONFIGURATION +=============================== +Die Konfiguration teilt sich in zwei Bereiche. Allgemeine Einstellungen finden +sich wie ueblich im VDR Einstellungsmenue fuer Plugins. Die Konfiguration +der Soundsets selbst erreicht man �ber den Hauptmenueeintrag. + + ALLGEMEINE EINSTELLUNGEN +------------------------------- +"Eintrag im Hauptmenue verstecken" + Wenn auf 'ja' gesetzt, wird das Plugin im VDR-Hauptmenue nicht angezeigt. + +"Menue Name" + Unter diesem Namen taucht das Plugin im VDR-Hauptmenue auf. + (Ich bevorzuge es z.B., den Eintrag 'Sound Manager' zu nennen.) + +"Lautstaerke beim Start" + -1: Die VDR-Lautstaerke wird beim Start gesetzt + 0..100: Statt der VDR-Lautstaerke wird diese Lautstaerke gesetzt. Das erste + Betaetigung der VDR-Lautstaerke stellt diese dann ein + + Wozu ist das gut? + Wenn der VDR sich allein einschaltet (z.B. wegen anstehender + Aufnahme[n]) und (wie bei mir) sich die 5.1-Boxen gleich + dazuschalten, soll natuerlich der Ton ausgeschaltet bleiben. + Dazu koennte man den VDR auf eine Startlautstaerke von 0 stellen. + Wenn man den VDR aber manuell einschaltet und fernsehen moechte, + muss man jetzt die Lautstaerke erst bis auf ein 'normales' Mass + regeln. + Loesung: Ist der Startwert des Plugins auf 0 gesetzt, ergibt sich der + Effekt eines stumm startenden VDR, der aber bei der ersten + Lautstaerkenbetaetigung sofort auf die VDR-Lautstaerke geht. + +"Standard Soundset" + Dieses Soundset wird beim Start des Plugins aktiviert. + Sollte die Dolby Digital Automatik eingeschaltet sein, ist das auch das + Soundset, auf das geschaltet wird, wenn ein Nicht-Dolby-Digital-Audio-Kanal + gewaehlt wird. + +"DD Automatik" + Wenn aktiv, versucht das Plugin zu erkennen, ob der Audio-Kanal auf + Dolby Digital geschaltet wird und ein entsprechendes Soundset aktivieren. + +"DD Automatik Soundset", + siehe vorher ... Dieses Soundset wird im Falle eines erkannten Dolby + Digital Kanals benutzt. + +"Soundflash aktivieren" + Aktiviert die 'Soundflash'-Funktion. + Wenn unmittelbar hintereinander die Lautstaerke hoch und wieder herunter + geregelt wird, setzt das Plugin die Lautstaerke kurz sehr laut und gleich + wieder auf den Normalwert. + Wozu ist das gut? + Eine evt. an den Ausgaengen der Soundkarte haengende Geraetschaft mag eine + automatische Standbyfunktion haben; sie schaltet sich bei allzu leisen + Lautstaerken aus. Man muss dann die Lautstaerke soweit erhoehen, dass sich + alles wieder einschaltet und wieder heruntersetzen, falls man es so laut gar + nicht wollte. + Loesung: Soundflash -> Lautstaerke kurz hoch und wieder runter und durch + die ebenso kurze Lautstaerkenerhoehung schaltet sich das Equipment + wieder ein. Die kurzzeitige hohe Lautstaerke ist nicht zu hoeren; + bis die externe Technik soweit ist, ist die Lautstaerke laengst + wieder normal. + +"Stumm beim Beenden" + Schaltet beim Beenden des VDR auf stumm. + + + SOUNDSET EINSTELLUNGEN +------------------------------- +"Name" + Der Name des Soundsets. + +Alle weiteren Parameter sind die Namen der einzelnen Regler der Soundkarte. +(Nicht alle, sondern nur 'sinnvolle'). +Jeder Regler hat einen zugeordneten Wert, welcher festlegt, was mit ihm getan +wird, wenn sich die VDR-Lautstaerke aendert. + +Der Aufbau dieses Wertes ist immer gleich und muss STRIKT eingehalten werden. + + Operand (bestimmt, die Rechenoperation) + | + | Minimum (der Regler geht nicht unter diesen Wert) + | | + =80;1;90 + | | + | Maximum (der Regler geht nicht ueber diesen Wert) + | + Wert (VDR-Lautstaerke wird per Operand mit diesem Wert verknuepft) + +Bis auf den Operand koennen die anderen Werte u.U. wegfallen. +Ein paar Beispiele, die das Verfahren demonstrieren: +"~" + tut gar nichts, der Regler wird nicht 'angefasst' + (Standardwert fuer alle Regler in einem neuen Soundset) + +"=0" + setzt den Regler dauerhaft auf den angegebenen Wert (hier 0) + (bei mir z.B. Bass =40 / Treble =60) + +"+10" + addiert den Wert (hier 10) zur VDR-Lautstaerke hinzu + (z.B. folgt "+0" der VDR-Lautstaerke direkt) + +"-5" + subtrahiert den Wert (hier 5) von der VDR-Lautstaerke + +"%10" + der Reglerwert ist immer 10% von der VDR-Lautstaerke + +"+10;1" + plus 10, aber nie weniger als 1 + Wozu dies? + Der 'LFE' Regler meiner Soundkarte, der den Subwoofer bedient, ist mit nur + 32 Stufen nicht so fein aufgeloest, was zur Folge hat, dass die Hardware bei + kleinen Werten den Regler schon mal ganz auf 0 zieht, obwohl vielleicht 5% + gemeint waren. Die Minimum-Einstellung verhindert das. + + + SVDR +=============================== +Das Plugin stellt die folgenden SVDR Kommandos zur Verfuegung. + +SSET [ name ] + setzt oder zeigt das aktive Soundset (mittels Name) + +SSID [ id ] + setzt oder zeigt das aktive Soundset (mittels ID) + +LIST [ names | all ] + zeigt ohne Parameter eine Liste der ID's aller Soundsets, + mit 'names' eine Namensliste und mit 'all' eine Liste mit + ID und Name + + BEISPIELE +------------------------------- +svdrpsend.pl plug sndctl list +svdrpsend.pl plug sndctl list all +svdrpsend.pl plug sndctl sset +svdrpsend.pl plug sndctl sset Stereo + + + + HINWEISE +=============================== +- das Plugin rechnet stets mit Lautstaerken von 0 bis 100 +- wenn die VDR-Lautstaerke auf 0 geht, gelten keine Minimum-Werte mehr, der + Regler wird dann auch auf 0 gezogen +- die folgenden Operationen (erstes Zeichen) sind moeglich: + '~' > gar nichts tun (so ein Regler wird aus den Parametern entfernt) + '=' > Regler wird immer auf denselben Wert gesetzt + (gut fuer 'Bass' und 'Treble' oder um einen Regler "still"zulegen) + '+' > Regler bekommt die VDR Lautstaerke erhoeht um diesen Wert + '-' > Regler bekommt die VDR Lautstaerke abzueglich dieses Wertes + '%' > Regler bekommt x Prozent vom VDR Lautstaerke-Wert +- falls dein VDR nicht mit root-Rechten laeuft, benoetigt der VDR user Rechte + fuer den Zugriff auf den Mixer der Soundkarte; evt. muss der VDR user + Mitglied der Gruppe 'audio' oder 'video' sein + @@ -0,0 +1,19 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Thomas Hildebrandt <toxym@web.de> +Project's homepage: none +Latest version available at: http://www.box.net/shared/qhu44kgcv4 + +See the file COPYING for license information. + +--------------------------------------------------------------------------- +Sound control plugin - 'sndctl' +--------------------------------------------------------------------------- + + TODO +=============================== + +- service for other plugins to handle sound set switching +- maybe a rule system for automatic sound set switching + (if DD automatic is not smart enough) +- maybe support for OSS (if this makes sense) @@ -0,0 +1,201 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: alsa.c + * description: handling of the Alsa API + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#include "defaults.h" +#include "alsa.h" + +/********************************************************* + * member functions for class cAlsa + *********************************************************/ + +/* + * constructors + */ +cAlsa::cAlsa(){ + init(); +} + +/* + * destructor + */ +cAlsa::~cAlsa(){ +} + +/* + * Initialize mapCardNameToHwNumber and mapCardNumberToMixerHandle + */ +static void dumpErrorMessage(string msg, int err) +{ + msg.append(snd_strerror(err)); + dsyslog(msg.c_str()); +} + +void cAlsa::init( void ) { + char hwName[64]; + snd_ctl_card_info_t *info; + snd_ctl_card_info_malloc(&info); + snd_ctl_t *ctl; + snd_hctl_t *hctl; + int err; + + int number = -1; + for (;;) { + /* open card for getting the mixers of this card */ + err = snd_card_next(&number); + if (err < 0) { + dumpErrorMessage(string("sndctl (cAlsa::init): ERROR: Cannot get next card number because "), err); + break; + } + if (number < 0) + break; + sprintf(hwName, "hw:%d", number); + if ((err = snd_ctl_open(&ctl, hwName, 0)) < 0) { + dumpErrorMessage(string("sndctl (cAlsa::init): ERROR: Cannot open card number because "), err); + break; + } + if ((err = snd_ctl_card_info(ctl, info)) < 0) { + dumpErrorMessage(string("sndctl (cAlsa::init): ERROR: Cannot get sound card info because "), err); + break; + } + dsyslog("sndctl (cAlsa::init): Found sound card:%s\n", snd_ctl_card_info_get_name(info)); + + if ((err = snd_hctl_open(&hctl, hwName, 0)) < 0) { + dumpErrorMessage(string("sndctl (cAlsa::init): ERROR: Cannot snd_hctl_open because "), err); + break; + } + + /* now iterate over the mixers */ + if ((err = snd_hctl_load(hctl)) < 0) { + dumpErrorMessage(string("sndctl (cAlsa::init): ERROR: Cannot snd_hctl_load because "), err); + } + + snd_hctl_elem_t *elem = NULL; + snd_ctl_elem_info_t *elemInfo; + snd_ctl_elem_info_alloca(&elemInfo); + + int controlNr = 0; + for (elem = snd_hctl_first_elem(hctl); elem; elem = snd_hctl_elem_next(elem)) { + if ((err = snd_hctl_elem_info(elem, elemInfo)) < 0) { + dumpErrorMessage(string("sndctl (cAlsa::init): ERROR: Cannot snd_hctl_elem_info because "), err); + break; + } + if (snd_ctl_elem_info_is_inactive(elemInfo)) { + continue; + } + + snd_ctl_elem_id_t *id; + snd_ctl_elem_id_alloca(&id); + snd_hctl_elem_get_id(elem, id); + + if (snd_ctl_elem_info_get_type(elemInfo) == SND_CTL_ELEM_TYPE_INTEGER) { + alsacontrol *control = new alsacontrol(); + control->min = snd_ctl_elem_info_get_min(elemInfo); + control->max = snd_ctl_elem_info_get_max(elemInfo); + control->soundCardId = string(snd_ctl_card_info_get_name(info)); + control->hwName = string(hwName); + + // check for a senseful range + if( control->min == 0 && control->max > control->min && control->max > 10 ){ + // get name + control->name = string( snd_ctl_elem_id_get_name(id)); + control->mixername = string( snd_ctl_elem_id_get_name(id)); + control->controlNr = controlNr; + controlNr++; + + dsyslog( "sndctl (cAlsa::init): '%s' updated with min=%ld and max=%ld", control->name.c_str(), control->min, control->max ); + vControls.push_back(control); + } else { + delete control; + } + } else { + dsyslog("sndctl (cAlsa::init): '%s' has no playback volume", snd_ctl_elem_id_get_name(id)); + } + } + snd_hctl_close(hctl); + snd_ctl_close(ctl); + } + snd_ctl_card_info_free(info); + dsyslog("sndctl (cAlsa::init): found %d controls:", vControls.size()); +} + +/* + * checks for a mixer with a given name + */ +bool cAlsa::IsMixer( string Name ){ + snd_mixer_elem_t *elem; + + // search in all mixers for 'Name' + for( elem = snd_mixer_first_elem(handle); elem; elem = snd_mixer_elem_next( elem )){ + if(( strcmp(snd_mixer_selem_get_name( elem ), Name.c_str()) == 0 ) && + snd_mixer_selem_is_active( elem ) && + ( snd_mixer_selem_has_playback_volume( elem ) || + snd_mixer_selem_has_playback_switch( elem ))) + return true; + } + + // nothing found + return false; +} + +/* + * set the volume of all controls + */ +void cAlsa::Volumes( void ){ +/* snd_mixer_elem_t *elem; + int i; + snd_mixer_selem_id_t *sid; + snd_mixer_selem_id_malloc( &sid ); +*/ + + // loop over all controls + for(int i = 0; i < vControls.size(); i++ ){ + alsacontrol *control = static_cast<alsacontrol*>(vControls[i]); + if( control->volume >= 0 ){ + int err; + // get ID from the name + dsyslog("sndctl (cAlsa::Volumes): trying to set control '%s' of card '%s'", control->name.c_str(), control->hwName.c_str()); + snd_hctl_t *hctl; + if ((err = snd_hctl_open(&hctl, control->hwName.c_str(), 0)) < 0) { + dumpErrorMessage(string("sndctl (cAlsa::Volumes): snd_hctl_open failed because "), err); + break; + } + if ((err = snd_hctl_load(hctl)) < 0) { + dumpErrorMessage(string("sndctl (cAlsa::Volumes): snd_hctl_load failed because "), err); + break; + } + + snd_ctl_elem_id_t *id; + snd_ctl_elem_id_alloca(&id); + snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); + + snd_ctl_elem_id_set_name(id, control->mixername.c_str()); + + snd_hctl_elem_t *elem = snd_hctl_find_elem(hctl, id); + + snd_ctl_elem_value_t *ctl; + snd_ctl_elem_value_alloca(&ctl); + snd_ctl_elem_value_set_id(ctl, id); + + /* left */ + snd_ctl_elem_value_set_integer(ctl, 0, control->volume); + /* right */ + snd_ctl_elem_value_set_integer(ctl, 1, control->volume); + + if ((err = snd_hctl_elem_write(elem, ctl)) < 0) { + dumpErrorMessage(string("sndctl (cAlsa::Volumes): snd_hctl_elem_write failed because "), err); + break; + } + + snd_hctl_close(hctl); + + } + } +} @@ -0,0 +1,43 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: alsa.h + * description: header file for alsa.c + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#ifndef SNDCTL_ALSA_H +#define SNDCTL_ALSA_H + +#include <alsa/asoundlib.h> +#include "mixer.h" + +/* + * cAlsa + * class for handling the Alsa API + */ +class cAlsa : public cMixer { + private: + struct alsacontrol : public control { + string hwName; + string mixername; + }; + snd_mixer_t *handle; + vector<snd_mixer_t *> handles; + + void init(); + + protected: + virtual void Volumes( void ); + + public: + cAlsa(); + virtual ~cAlsa(); + + virtual bool IsMixer( string ); +}; + +#endif //SNDCTL_ALSA_H diff --git a/defaults.h b/defaults.h new file mode 100644 index 0000000..3ece480 --- /dev/null +++ b/defaults.h @@ -0,0 +1,72 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: defaults.h + * description: default definitions + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#ifndef SNDCTL_DEFAULTS_H +#define SNDCTL_DEFAULTS_H + +class cMainMenuSndctl; +class cMixer; +class cPluginSndctl; +class cSetupSndctl; +class cSetupMenuSndctl; +class cSoundMan; +class cSoundSet; +class cSoundsetMenuSndctl; +class cStatusSndctl; + +#include <map> +#include <string> +#include <time.h> +#include <vector> +#include <vdr/interface.h> +#include <vdr/plugin.h> +#include "i18n.h" +using namespace std; + +#define SNDCTL_MAX_LEN_CONTROL_NAME 128 +#define SNDCTL_MAX_LEN_CONTROL_VAL 12 + +#define SNDCTL_DEFAULT_MENUNAME "Sound control" +#define SNDCTL_DEFAULT_SOUNDSET_NAME "New sound set" +#define SNDCTL_DEFAULT_HIDEMAINMENUENTRY "no" +#define SNDCTL_DEFAULT_DEFAULT_SSET "" +#define SNDCTL_DEFAULT_INIT_VOLUME "-1" +#define SNDCTL_DEFAULT_DD_AUTO_SWITCH "no" +#define SNDCTL_DEFAULT_DD_AUTO_SSET "" +#define SNDCTL_DEFAULT_SOUNDFLASH "no" +#define SNDCTL_DEFAULT_SOUNDFLASH_DELTA "2" +#define SNDCTL_DEFAULT_SOUNDFLASH_VOL "100" +#define SNDCTL_DEFAULT_SOUNDFLASH_TIME "1" +#define SNDCTL_DEFAULT_MUTE_ON_END "yes" + +#define SNDCTL_SETUP_MENUNAME "MenuName" +#define SNDCTL_SETUP_HIDEMAINMENUENTRY "HideMainMenuEntry" +#define SNDCTL_SETUP_DEFAULT_SSET "DefaultSoundSet" +#define SNDCTL_SETUP_INIT_VOLUME "InitialVolume" +#define SNDCTL_SETUP_DD_AUTO_SWITCH "DDAutoSwitch" +#define SNDCTL_SETUP_DD_AUTO_SSET "DDAutoSoundSet" +#define SNDCTL_SETUP_SOUNDFLASH "SoundFlash" +#define SNDCTL_SETUP_SOUNDFLASH_DELTA "SoundFlashDelta" +#define SNDCTL_SETUP_SOUNDFLASH_VOL "SoundFlashVolume" +#define SNDCTL_SETUP_SOUNDFLASH_TIME "SoundFlashTime" +#define SNDCTL_SETUP_MUTE_ON_END "MuteOnEnd" + +#define SNDCTL_MIXER_NONE '~' +#define SNDCTL_MIXER_STATIC '=' +#define SNDCTL_MIXER_PERCENT '%' +#define SNDCTL_MIXER_PLUS '+' +#define SNDCTL_MIXER_MINUS '-' + +#define SNDCTL_SVDR_SSET "SSET" +#define SNDCTL_SVDR_SSID "SSID" +#define SNDCTL_SVDR_LIST "LIST" + +#endif //SNDCTL_DEFAULTS_H @@ -0,0 +1,416 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: i18n.c + * description: internationalization (string definitions) + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#include "defaults.h" +#include "i18n.h" + +const tI18nPhrase Phrases[] = { + { "Sound control", // english + "Soundcontrol", // german + "",// TODO italian + "",// TODO dutch + "",// TODO portuguese + "",// TODO french + "",// TODO norwegian + "",// TODO finnish + "",// TODO polish + "",// TODO spanish + "",// TODO greek + "",// TODO swedish + "",// TODO romanian + "",// TODO hungarian + "",// TODO catalanian + "",// TODO russian + "",// TODO croatian + "",// TODO estonian + "",// TODO danish + "",// TODO czech + }, + { "ALSA mixer control", + "ALSA Mixer Steuerung", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_DEFAULT_SOUNDSET_NAME, + "Neues Soundset", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0001, + "Soundcontrol - Soundset auswählen", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0002, + "Eintrag im Hauptmenü verstecken", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0003, + "Standard Soundset", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0004, + "Wählen", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0005, + "Ändern", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0006, + "Soundset bearbeiten", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0007, + "Menü Name", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0008, + "Name", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0009, + "Neu", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0010, + "Löschen", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0011, + "Soundset löschen?", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0012, + "DD Automatik", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0013, + "DD Automatik Soundset", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0014, + "Lautstärke beim Start", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0015, + "Soundflash aktivieren", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { SNDCTL_TXT_0016, + "Stumm beim Beenden", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + }, + { NULL } +}; @@ -0,0 +1,34 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: i18n.h + * description: header file for i18n.c + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#ifndef SNDCTL_I18N_H +#define SNDCTL_I18N_H + +extern const tI18nPhrase Phrases[]; + +#define SNDCTL_TXT_0001 "Sound control - select sound set" +#define SNDCTL_TXT_0002 "Hide main meny entry" +#define SNDCTL_TXT_0003 "Default sound set" +#define SNDCTL_TXT_0004 "Select" +#define SNDCTL_TXT_0005 "Edit" +#define SNDCTL_TXT_0006 "Edit sound set" +#define SNDCTL_TXT_0007 "Menu name" +#define SNDCTL_TXT_0008 "Name" +#define SNDCTL_TXT_0009 "New" +#define SNDCTL_TXT_0010 "Delete" +#define SNDCTL_TXT_0011 "Delete sound set?" +#define SNDCTL_TXT_0012 "Auto switch for DD" +#define SNDCTL_TXT_0013 "Auto switch sound set" +#define SNDCTL_TXT_0014 "Initial volume" +#define SNDCTL_TXT_0015 "Enable sound flash" +#define SNDCTL_TXT_0016 "Mute on end" + +#endif //SNDCTL_I18N_H diff --git a/mainmenu.c b/mainmenu.c new file mode 100644 index 0000000..554b463 --- /dev/null +++ b/mainmenu.c @@ -0,0 +1,132 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: mainmenu.c + * description: the main menu OSD + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#include "defaults.h" +#include "mainmenu.h" +#include "soundset.h" +#include "soundsetmenu.h" +#include "menuitems.h" + +/********************************************************* + * member functions for class cMainMenuSndctl + *********************************************************/ + +/* + * constructors + */ +cMainMenuSndctl::cMainMenuSndctl( cPluginSndctl *Plugin ) +:cOsdMenu( tr( SNDCTL_TXT_0001 ), 2 ){ + // save plugin + plugin = Plugin; + + // add content + Set(); + + // add help keys + SetHelpKeys(); + + // show + Display(); +} + +/* + * displays the menu (after refreshing the content) + */ +void cMainMenuSndctl::Display( void ){ + // refresh items + Set(); + + // let do cOsdMenu the rest of the job + cOsdMenu::Display(); + + // update help keys + SetHelpKeys(); +} + +/* + * cares for pressing a key at a sound set entry + */ +eOSState cMainMenuSndctl::ProcessKey( eKeys Key ){ + cSoundSetItem *item; + + // get the current item + item = (cSoundSetItem *) Get( Current()); + + eOSState state = cOsdMenu::ProcessKey( Key ); + + if( state == osUnknown ) + switch( Key ){ + case kOk: + case kRed: + // select sound set + plugin->GetSoundManager()->SetSoundSet( item->GetId()); + state = osEnd; + break; + + case kGreen: + // edit sound set + return AddSubMenu( new cSoundsetMenuSndctl( plugin->GetSoundManager()->GetSoundSet( item->GetId()), plugin->GetSoundManager()->GetCurrentSoundSetID())); + break; + + case kYellow: + // delete sound set only if there are more than one + if(plugin->GetSoundManager()->GetSoundSets()->size() <= 1) + break; + if( Interface->Confirm( tr( SNDCTL_TXT_0011 ))){ + plugin->GetSoundManager()->DeleteSoundSet( item->GetId()); + cOsdMenu::Del( Current()); + SetHelpKeys(); + Display(); + } + + state = osContinue; + break; + + case kBlue: + // create a new sound set and switch to edit screen + return AddSubMenu( new cSoundsetMenuSndctl( plugin->GetSoundManager()->GetSoundSet( plugin->GetSoundManager()->CreateSoundSet()), plugin->GetSoundManager()->GetCurrentSoundSetID())); + break; + + default: + break; + } + + return state; +} + +/* + * makes one menu entry for every soundset + */ +void cMainMenuSndctl::Set( void ){ + map<string,cSoundSet*>::iterator it; + map<string,cSoundSet*> *soundsets; + + // remove any old item + Clear(); + + // get defined sound sets + soundsets = plugin->GetSoundManager()->GetSoundSets(); + + // iterate over all soundsets + for( it = (*soundsets).begin(); it != (*soundsets).end(); it++ ) + Add( new cSoundSetItem( it->first, plugin->GetSoundManager())); +} + +/* + * set the colored help keys for this menu + */ +void cMainMenuSndctl::SetHelpKeys( void ){ + if (plugin->GetSoundManager()->GetSoundSets()->size() > 1) { + SetHelp( tr( SNDCTL_TXT_0004 ), tr( SNDCTL_TXT_0005 ), tr( SNDCTL_TXT_0010 ), tr( SNDCTL_TXT_0009 )); + } else { + SetHelp( tr( SNDCTL_TXT_0004 ), tr( SNDCTL_TXT_0005 ), NULL, tr( SNDCTL_TXT_0009 )); + } +} diff --git a/mainmenu.h b/mainmenu.h new file mode 100644 index 0000000..bc42268 --- /dev/null +++ b/mainmenu.h @@ -0,0 +1,33 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: mainmenu.h + * description: header file for mainmenu.c + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#ifndef SNDCTL_MAINMENU_H +#define SNDCTL_MAINMENU_H + +/* + * cMainMenuSndctl + * the main menu OSD + */ +class cMainMenuSndctl:public cOsdMenu { + private: + cPluginSndctl *plugin; + + void Set( void ); + void SetHelpKeys( void ); + + public: + cMainMenuSndctl( cPluginSndctl* ); + + virtual void Display( void ); + virtual eOSState ProcessKey( eKeys ); +}; + +#endif //SNDCTL_MAINMENU_H diff --git a/menuitems.c b/menuitems.c new file mode 100644 index 0000000..13eb8c3 --- /dev/null +++ b/menuitems.c @@ -0,0 +1,165 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: menuitems.c + * description: representation of OSD menu entries + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#include "defaults.h" +#include "menuitems.h" +#include "soundman.h" + +/********************************************************* + * member functions for class cSoundSetItem + *********************************************************/ + +/* + * constructors + */ +cSoundSetItem::cSoundSetItem( string Id, cSoundMan *SoundMan ) +:cOsdItem( "" ){ + string text; + + // save Id + id = Id; + + // save sound manager + soundman = SoundMan; + + // set text + text = string(); + if( id == soundman->GetCurrentSoundSetID()) + text.append( ">" ); + + text.append( "\t" ); + text.append( soundman->GetSoundSet( id )->GetName()); + + SetText( text.c_str()); +} + +/* + * returns this items sound set ID + */ +string cSoundSetItem::GetId( void ){ + return id; +} + +/********************************************************* + * member functions for class cSoundSetChooserItem + *********************************************************/ + +/* + * constructor + */ +cSoundSetChooserItem::cSoundSetChooserItem( cSoundMan *SoundMan, string *SoundSet, char *Text ) +:cMenuEditItem( tr( Text )){ + // save arguments + soundman = SoundMan; + soundset = SoundSet; + + // set initial value + Set(); +} + +/* + * cares for pressing a key at a sound set entry + */ +eOSState cSoundSetChooserItem::ProcessKey( eKeys Key ){ + map<string,cSoundSet*> *soundsets; + map<string,cSoundSet*>::iterator sset; + + eOSState state = cMenuEditItem::ProcessKey( Key ); + + // get list of sound sets + soundsets = soundman->GetSoundSets(); + sset = (*soundsets).find( *soundset ); + + if( state == osUnknown ) + switch( Key ){ + case kLeft: + // go to the previous sound set (if possible) + if( sset-- != (*soundsets).begin()) + (*soundset).assign( sset->first ); + state = osContinue; + break; + + case kRight: + // go to the next sound set (if possible) + if( ++sset != (*soundsets).end()) + (*soundset).assign( sset->first ); + state = osContinue; + break; + + default: + break; + } + + // update display + Set(); + + return state; +} + +/* + * set the current value (means: the name of the current soundset) + */ +void cSoundSetChooserItem::Set( void ){ + SetValue( soundman->GetSoundSet( *soundset )->GetName().c_str()); +} + +/********************************************************* + * member functions for class cSoundSetControlItem + *********************************************************/ + + +static char* copyMixerControl(string controlString) { + char *copied = new char[SNDCTL_MAX_LEN_CONTROL_VAL]; + strncpy(copied, controlString.c_str(), SNDCTL_MAX_LEN_CONTROL_VAL-1); + return copied; +} + +/* + * constructor + */ +cSoundSetControlItem::cSoundSetControlItem( cSoundSet *SoundSet, cControlId Control, bool IsActive ) +:cMenuEditStrItem( Control.getDisplayName().c_str(), copyMixerControl( SoundSet->Get( Control )), 11, "~=+-%0123456789;" ){ + // save arguments + soundset = SoundSet; + control = Control; + isActive = IsActive; +} + +/* + * cares for pressing a key when editing a control value + */ +eOSState cSoundSetControlItem::ProcessKey( eKeys Key ){ + if( InEditMode()) { + /* The ProcessKey call sets the value */ + eOSState state = cMenuEditStrItem::ProcessKey( Key ); + switch( Key ){ + case kOk: + dsyslog( "sndctl (cSoundSetControlItem::ProcessKey): Control '%s' set to '%s'.", control.getDisplayName().c_str(), value ); + // save changed value + soundset->Set( control, string( value )); + // set volume + if( isActive ) + soundset->Volume(); + break; + + default: + break; + } + return state; + } else { + return cMenuEditStrItem::ProcessKey( Key ); + } + +} + +cSoundSetControlItem::~cSoundSetControlItem() { + delete[] value; +} diff --git a/menuitems.h b/menuitems.h new file mode 100644 index 0000000..453d402 --- /dev/null +++ b/menuitems.h @@ -0,0 +1,73 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: menuitems.h + * description: header file for soundsetitem.c + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#ifndef SNDCTL_MENUITEMS_H +#define SNDCTL_MENUITEMS_H + +#include "mixer.h" + +/* + * cursor position when editing a mixer control value + */ +enum CursorPos {op, val, limitL}; + +/* + * cSoundSetItem + * representation of an OSD menu entry for one sound set + */ +class cSoundSetItem:public cOsdItem { + private: + string id; + string soundCardId; + cSoundMan *soundman; + + public: + cSoundSetItem( string, cSoundMan* ); + + string GetId( void ); +}; + +/* + * cSoundSetChooserItem + * representation of a list of all soundsets + */ +class cSoundSetChooserItem:public cMenuEditItem { + private: + string *soundset; + cSoundMan *soundman; + + protected: + virtual void Set( void ); + + public: + cSoundSetChooserItem( cSoundMan*, string*, char* ); + + virtual eOSState ProcessKey( eKeys ); +}; + +/* + * cSoundSetControlItem + * representation of one mixer control value + */ +class cSoundSetControlItem:public cMenuEditStrItem { + private: + cControlId control; + bool isActive; + cSoundSet *soundset; + + public: + cSoundSetControlItem( cSoundSet*, cControlId Control, bool ); + ~cSoundSetControlItem(); + + virtual eOSState ProcessKey( eKeys ); +}; + +#endif //SNDCTL_MENUITEMS_H @@ -0,0 +1,176 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: mixer.c + * description: parent class for all types of mixer devices + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#include "defaults.h" +#include "mixer.h" +#include "soundset.h" + +/********************************************************* + * member functions for class cMixer + *********************************************************/ + +/* + * constructor + */ +cMixer::cMixer(){ +} + +/* + * destructor + */ +cMixer::~cMixer(){ + int countControls = vControls.size(); + for(int i = 0 ; i < countControls ; i++) { + delete vControls[i]; + } +} + +int cMixer::CountControls() { + return vControls.size(); +} + + +/* + * returns a vector with all controls names + */ +vector<cControlId> cMixer::GetControls( void ){ + vector<cControlId> ctrls; + int i; + + // loop over all controls + for( i = 0; i < vControls.size(); i++ ) { + ctrls.push_back(cControlId(vControls[i]->soundCardId, vControls[i]->name, vControls[i]->controlNr)); + } + + return ctrls; +} + +/* + * update mixer values + */ +void cMixer::Update( cSoundSet *SoundSet ){ + int i; + string::size_type loc; + string v; + + dsyslog( "sndctl (cMixer::Update): Updating controls with sound set '%s'.", SoundSet->GetName().c_str()); + + // loop over all controls + for( i = 0; i < vControls.size(); i++ ){ + control* actualControl = vControls[i]; + v = SoundSet->Get(cControlId(actualControl->soundCardId, actualControl->name, actualControl->controlNr )); + + // get operation + actualControl->op = v.substr( 0, 1 ).c_str()[0]; + + // get value + if(actualControl->op == SNDCTL_MIXER_NONE ) + actualControl->value = 0; + else + actualControl->value = atoi( v.substr( 1 ).c_str()); + + // check and correct limits + actualControl->value = actualControl->value < 0 ? 0 : actualControl->value; + actualControl->value = actualControl->value > 999 ? 999 : actualControl->value; + + // check and set minimum volume + actualControl->limitL = actualControl->min; + if(( loc = v.find( ';', 0 )) != string::npos ) + actualControl->limitL = atoi( v.substr( ++loc ).c_str()); + + // check and set maximum volume + actualControl->limitU = actualControl->max; + if(( loc != string::npos ) && (( loc = v.find( ';', loc )) != string::npos )) + vControls[i]->limitU = atoi( v.substr( ++loc ).c_str()); + + dsyslog( "sndctl (cMixer::Update): '%s' updated with %c%d;%ld;%ld", actualControl->name.c_str(), actualControl->op, actualControl->value, actualControl->limitL, actualControl->limitU ); + } +} + +/* + * sets the volume of this sound set + */ +void cMixer::Volume( int Vol ){ + int i; + long vol; + + dsyslog( "sndctl (cMixer::Volume): Volume goes to %d%%.", Vol ); + + // loop over all controls + for( i = 0; i < vControls.size(); i++ ){ + control* actualControl = vControls[i]; + // initial value for 'volume' + actualControl->volume = -1; + + // calculate volume according to operation mode + switch( actualControl->op ){ + case SNDCTL_MIXER_STATIC: + vol = actualControl->value; + break; + + case SNDCTL_MIXER_PLUS: + vol = Vol + actualControl->value; + break; + + case SNDCTL_MIXER_MINUS: + vol = Vol - actualControl->value; + break; + + case SNDCTL_MIXER_PERCENT: + vol = Vol * actualControl->value / 100; + break; + + case SNDCTL_MIXER_NONE: + default: + dsyslog( "sndctl (cMixer::Volume): Control '%s' stays unchanged.", actualControl->name.c_str()); + continue; + break; + } + + // Vol = 0 means, no matter, what happend before + if( Vol == 0 ) + vol = 0; + + // scale volume to real values + vol = actualControl->min + ( actualControl->max - actualControl->min ) * vol / 100; + + // check for hard limits + if( Vol > 0 && vol < actualControl->limitL ) + vol = actualControl->limitL; + if( vol > actualControl->limitU ) + vol = actualControl->limitU; + + dsyslog( "sndctl (cMixer::Volume): Control '%s' goes to '%ld'.", actualControl->name.c_str(), vol ); + + // set volume + actualControl->volume = vol; + } + + // set volumes to real hardware + Volumes(); +} + +cControlId::cControlId(string SoundCardId, string DisplayName, int ControlNr) { + name = DisplayName; + soundCardId = SoundCardId; + controlNr = ControlNr; +} + +cControlId::cControlId() : name(), soundCardId(), controlNr(0) { +} + +bool cControlId::operator==(cControlId const& b) { + return controlNr == b.controlNr && soundCardId.compare(b.soundCardId) == 0; +} + +string cControlId::getDisplayName() { return name; } +int cControlId::getControlNr() { return controlNr; } +string cControlId::getSoundCardId() { return soundCardId; } @@ -0,0 +1,66 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: mixer.h + * description: header file for mixer.c + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#ifndef SNDCTL_MIXER_H +#define SNDCTL_MIXER_H + +/* + * cMixer + * parent class for all types of mixer devices + */ + +class cControlId { +private: + string name; + int controlNr; + string soundCardId; +public: + cControlId(string SoundCardId, string DisplayName, int controlNr); + cControlId(); + bool operator==(cControlId const& b); + string getDisplayName(); + int getControlNr(); + string getSoundCardId(); +}; + +class cMixer { + protected: + struct control{ + long min; + long max; + string name; + long limitL; + long limitU; + char op; + int value; + long volume; + string soundCardId; + int controlNr; + }; + + vector<control *> vControls; + + virtual void Volumes( void ) = 0; + + public: + + cMixer(); + virtual ~cMixer(); + + vector<cControlId> GetControls( void ); + void Update( cSoundSet* ); + void Volume( int ); + int CountControls( void ); + + virtual bool IsMixer( string ) = 0; +}; + +#endif //SNDCTL_MIXER_H @@ -0,0 +1,135 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: setup.c + * description: management of setup configuration + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#include "defaults.h" +#include "setup.h" +#include "soundset.h" + +/********************************************************* + * member functions for class cSetupSndctl + *********************************************************/ + +/* + * constructor + */ +cSetupSndctl::cSetupSndctl(){ + dsyslog( "sndctl (cSetupSndctl::cSetupSndctl): cSetupSndctl created" ); + + // create all possible setup items with default values + items[SNDCTL_SETUP_MENUNAME] = tr( SNDCTL_DEFAULT_MENUNAME ); + items[SNDCTL_SETUP_HIDEMAINMENUENTRY] = SNDCTL_DEFAULT_HIDEMAINMENUENTRY; + items[SNDCTL_SETUP_DEFAULT_SSET] = SNDCTL_DEFAULT_DEFAULT_SSET; + items[SNDCTL_SETUP_INIT_VOLUME] = SNDCTL_DEFAULT_INIT_VOLUME; + items[SNDCTL_SETUP_DD_AUTO_SWITCH] = SNDCTL_DEFAULT_DD_AUTO_SWITCH; + items[SNDCTL_SETUP_DD_AUTO_SSET] = SNDCTL_DEFAULT_DD_AUTO_SSET; + items[SNDCTL_SETUP_SOUNDFLASH] = SNDCTL_DEFAULT_SOUNDFLASH; + items[SNDCTL_SETUP_SOUNDFLASH_DELTA] = SNDCTL_DEFAULT_SOUNDFLASH_DELTA; + items[SNDCTL_SETUP_SOUNDFLASH_VOL] = SNDCTL_DEFAULT_SOUNDFLASH_VOL; + items[SNDCTL_SETUP_SOUNDFLASH_TIME] = SNDCTL_DEFAULT_SOUNDFLASH_TIME; + items[SNDCTL_SETUP_MUTE_ON_END] = SNDCTL_DEFAULT_MUTE_ON_END; +} + +/* + * returns a setup value + */ +string cSetupSndctl::Get( string Name ){ + if( items.find( Name ) != items.end()) + return items[Name]; + + // default return value is NULL + return NULL; +} + +/* + * returns a setup value as bool + */ +bool cSetupSndctl::GetBool( string Name ){ + return ( Get( Name ) == "yes" ) ? true : false; +} + +/* + * returns a setup value as integer + */ +int cSetupSndctl::GetInt( string Name ){ + return atoi( Get( Name ).c_str()); +} + +/* + * set a setup value + */ +bool cSetupSndctl::Set( string Name, string Value, cSoundMan *Soundman ){ + bool result; + cSoundSet *sset; + unsigned int div; + + dsyslog( "sndctl (cSetupSndctl::Set): Receiving parameter '%s' with value '%s'.", Name.c_str(), Value.c_str() ); + + // save this parameter + parameters.push_back( Name ); + + // lets assume the worst case ;-) + result = false; + + // first check for a general option + if( result = (items.find( Name ) != items.end())){ + // save this item + items[Name] = Value; + + // take special care for SNDCTL_DEFAULT_DD_AUTO_SSET + if( Name == SNDCTL_SETUP_DEFAULT_SSET && + items[SNDCTL_SETUP_DD_AUTO_SSET].empty()) + items[SNDCTL_SETUP_DD_AUTO_SSET] = Value; + } + + // assuming this value belongs to a soundset + // we need a '_' in 'Name' to deal with this + else if(( div = Name.find_first_of( '_' )) != string::npos ){ + // get sound set for this ID (it's up to the first '_') + sset = Soundman->GetSoundSet( Name.substr( 0, div )); + + // set value + result = sset->Set( Name.substr( div + 1 ), Value ); + } + + // nothing of all, that's bad + return result; +} + +/* + * store all setup values + */ +bool cSetupSndctl::Store( cPluginSndctl *Plugin ){ + vector<string>::iterator it; + + // first, remove all parameters + for( it = parameters.begin(); it != parameters.end(); it++ ){ + dsyslog( "sndctl (cSetupSndctl::Store): Removing: %s", (*it).c_str()); + Plugin->Store( *it, string() ); + } + + // store all general settings + Plugin->Store( string( SNDCTL_SETUP_MENUNAME ), Get( SNDCTL_SETUP_MENUNAME )); + Plugin->Store( string( SNDCTL_SETUP_HIDEMAINMENUENTRY ), Get( SNDCTL_SETUP_HIDEMAINMENUENTRY )); + Plugin->Store( string( SNDCTL_SETUP_DEFAULT_SSET ), Get( SNDCTL_SETUP_DEFAULT_SSET )); + Plugin->Store( string( SNDCTL_SETUP_INIT_VOLUME ), Get( SNDCTL_SETUP_INIT_VOLUME )); + Plugin->Store( string( SNDCTL_SETUP_DD_AUTO_SWITCH ), Get( SNDCTL_SETUP_DD_AUTO_SWITCH )); + Plugin->Store( string( SNDCTL_SETUP_DD_AUTO_SSET ), Get( SNDCTL_SETUP_DD_AUTO_SSET )); + Plugin->Store( string( SNDCTL_SETUP_SOUNDFLASH ), Get( SNDCTL_SETUP_SOUNDFLASH )); + Plugin->Store( string( SNDCTL_SETUP_SOUNDFLASH_DELTA ), Get( SNDCTL_SETUP_SOUNDFLASH_DELTA )); + Plugin->Store( string( SNDCTL_SETUP_SOUNDFLASH_VOL ), Get( SNDCTL_SETUP_SOUNDFLASH_VOL )); + Plugin->Store( string( SNDCTL_SETUP_SOUNDFLASH_TIME ), Get( SNDCTL_SETUP_SOUNDFLASH_TIME )); + Plugin->Store( string( SNDCTL_SETUP_MUTE_ON_END ), Get( SNDCTL_SETUP_MUTE_ON_END )); + + // store all settings from all soundsets + Plugin->GetSoundManager()->Store( Plugin ); + + return true; +} @@ -0,0 +1,36 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: setup.h + * description: header file for setup.c + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#ifndef SNDCTL_SETUP_H +#define SNDCTL_SETUP_H + +#include "sndctl.h" + +/* + * cSetupSndctl + * setup class definition + */ +class cSetupSndctl { + private: + map<string,string> items; + vector<string> parameters; + + public: + cSetupSndctl(); + + string Get( string ); + bool GetBool( string ); + int GetInt( string ); + bool Set( string, string, cSoundMan* = NULL ); + bool Store( cPluginSndctl* ); +}; + +#endif //SNDCTL_SETUP_H diff --git a/setupmenu.c b/setupmenu.c new file mode 100644 index 0000000..c1447ec --- /dev/null +++ b/setupmenu.c @@ -0,0 +1,105 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: setupmenu.c + * description: the OSD menu page for this plugin + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#include "defaults.h" +#include "setupmenu.h" +#include "menuitems.h" +#include "sndctl.h" +#include "setup.h" + +/********************************************************* + * member functions for class cSetupMenuSndctl + *********************************************************/ + +/* + * constructors + */ +cSetupMenuSndctl::cSetupMenuSndctl( cPluginSndctl *Plugin ){ + // save plugin + plugin = Plugin; + + // get current values + menuname = strdup( plugin->GetSetup()->Get( SNDCTL_SETUP_MENUNAME ).c_str()); + hideMainMenuEntry = plugin->GetSetup()->GetBool( SNDCTL_SETUP_HIDEMAINMENUENTRY ) ? 1 : 0; + initVolume = plugin->GetSetup()->GetInt( SNDCTL_SETUP_INIT_VOLUME ); + defSoundSet = plugin->GetSetup()->Get( SNDCTL_SETUP_DEFAULT_SSET ); + ddAutoSwitch = plugin->GetSetup()->GetBool( SNDCTL_SETUP_DD_AUTO_SWITCH ) ? 1 : 0; + ddAutoSoundSet = plugin->GetSetup()->Get( SNDCTL_SETUP_DD_AUTO_SSET ); + soundflash = plugin->GetSetup()->GetBool( SNDCTL_SETUP_SOUNDFLASH ) ? 1 : 0; + muteOnEnd = plugin->GetSetup()->GetBool( SNDCTL_SETUP_MUTE_ON_END ) ? 1 : 0; + + // add content + Set(); +} + +/* + * makes setup menu entries + */ +void cSetupMenuSndctl::Set( void ){ + // main menu entry + Add( new cMenuEditBoolItem( tr( SNDCTL_TXT_0002 ), &hideMainMenuEntry )); + + // main menu name + Add( new cMenuEditStrItem( tr( SNDCTL_TXT_0007 ), menuname, 40, tr(FileNameChars))); + + // default soundset + Add( new cSoundSetChooserItem( plugin->GetSoundManager(), &defSoundSet, SNDCTL_TXT_0003 )); + + // initial volume + Add( new cMenuEditIntItem( tr( SNDCTL_TXT_0014 ), &initVolume, -1, 100 )); + + // DD auto switch + Add( new cMenuEditBoolItem( tr( SNDCTL_TXT_0012 ), &ddAutoSwitch )); + + // DD auto sound set + Add( new cSoundSetChooserItem( plugin->GetSoundManager(), &ddAutoSoundSet, SNDCTL_TXT_0013 )); + + // sound flash + Add( new cMenuEditBoolItem( tr( SNDCTL_TXT_0015 ), &soundflash )); + + // sound flash + Add( new cMenuEditBoolItem( tr( SNDCTL_TXT_0016 ), &muteOnEnd )); +} + +/* + * stores changed values + */ +void cSetupMenuSndctl::Store( void ){ + char vol[3]; + + // main menu entry + plugin->GetSetup()->Set( SNDCTL_SETUP_HIDEMAINMENUENTRY, string( hideMainMenuEntry ? "yes" : "no" )); + + // main menu name + plugin->GetSetup()->Set( SNDCTL_SETUP_MENUNAME, string( menuname )); + + // default sound set + plugin->GetSetup()->Set( SNDCTL_SETUP_DEFAULT_SSET, defSoundSet ); + + // initial volume + sprintf( vol, "%d", initVolume ); + plugin->GetSetup()->Set( SNDCTL_SETUP_INIT_VOLUME, string( vol )); + + // DD auto switch + plugin->GetSetup()->Set( SNDCTL_SETUP_DD_AUTO_SWITCH, string( ddAutoSwitch ? "yes" : "no" )); + + // DD auto switch sound set + plugin->GetSetup()->Set( SNDCTL_SETUP_DD_AUTO_SSET, ddAutoSoundSet ); + + // sound flash + plugin->GetSetup()->Set( SNDCTL_SETUP_SOUNDFLASH, string( soundflash ? "yes" : "no" )); + + // mute on end + plugin->GetSetup()->Set( SNDCTL_SETUP_MUTE_ON_END, string( muteOnEnd ? "yes" : "no" )); + + // do a global store now + plugin->GetSetup()->Store( plugin ); +} diff --git a/setupmenu.h b/setupmenu.h new file mode 100644 index 0000000..edd2ee8 --- /dev/null +++ b/setupmenu.h @@ -0,0 +1,40 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: setupmenu.h + * description: header file for setupmenu.c + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#ifndef SNDCTL_SETUPMENU_H +#define SNDCTL_SETUPMENU_H + +/* + * cSetupMenuSndctl + * the OSD menu page for this plugin + */ +class cSetupMenuSndctl:public cMenuSetupPage { + private: + string defSoundSet; + string ddAutoSoundSet; + int ddAutoSwitch; + int hideMainMenuEntry; + int initVolume; + int muteOnEnd; + int soundflash; + char *menuname; + cPluginSndctl *plugin; + + void Set(); + + protected: + virtual void Store( void ); + + public: + cSetupMenuSndctl( cPluginSndctl* ); +}; + +#endif //SNDCTL_SETUPMENU_H diff --git a/sndctl.c b/sndctl.c new file mode 100644 index 0000000..3e7ccd0 --- /dev/null +++ b/sndctl.c @@ -0,0 +1,283 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: sndctl.c + * description: main plugin file + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#include "defaults.h" +#include "sndctl.h" +#include "mainmenu.h" +#include "setupmenu.h" + +static const char *VERSION = "0.1.5"; +static const char *DESCRIPTION = "ALSA mixer control"; +static const char *SVDRHelpPages[] = { + "SSET [ sound set name ]\n" + " Set or show the active sound set by name.", + "SSID [ sound set ID ]\n" + " Set or show the active sound set by ID.", + "LIST [ names | all ]\n" + " List all available sound sets.\n" + " Specify 'names' to see sound set names instead of ID's.\n" + " Specify 'all' to see sound set ID's and names.", + NULL +}; + +/********************************************************* + * member functions for class cPluginSndctl + *********************************************************/ + +/* + * constructor + */ +cPluginSndctl::cPluginSndctl( void ){ + dsyslog( "sndctl (cPluginSndctl::cPluginSndctl): cPluginSndctl created" ); + + // create sound manager + soundman = new cSoundMan( this ); + + // create setup manager + setup = new cSetupSndctl(); + + // initialize statusMonitor + statusMonitor = 0; +} + +/* + * destructor + */ +cPluginSndctl::~cPluginSndctl(){ + // destroy something + delete statusMonitor; + delete setup; + delete soundman; + statusMonitor = 0; + setup = 0; + soundman = 0; +} + +/* + * return this plugins command line help + */ +const char *cPluginSndctl::CommandLineHelp( void ){ +// FIXME: do something with this + return NULL; +} + +/* + * return this plugins description + */ +const char *cPluginSndctl::Description( void ){ + return tr( DESCRIPTION ); +} + +/* + * returns the sound manager + */ +cSoundMan *cPluginSndctl::GetSoundManager( void ){ + return soundman; +} + +/* + * returns the setup object + */ +cSetupSndctl *cPluginSndctl::GetSetup( void ){ + return setup; +} + +/* + * return this plugins main menu entry + */ +const char *cPluginSndctl::MainMenuEntry( void ){ + if( setup->GetBool( SNDCTL_SETUP_HIDEMAINMENUENTRY )) + return NULL; + + return setup->Get( SNDCTL_SETUP_MENUNAME ).c_str(); +} + +/* + * returns the OSD object for the main menu entry + */ +cOsdObject *cPluginSndctl::MainMenuAction( void ){ + return new cMainMenuSndctl( this ); +} + +/* + * returns the setup page for this plugin + */ +cMenuSetupPage *cPluginSndctl::SetupMenu( void ){ + return new cSetupMenuSndctl( this ); +} + +/* + * care for setup parameters + */ +bool cPluginSndctl::SetupParse( const char *Name, const char *Value ){ + return setup->Set( string( Name ), string( Value ), soundman ); +} + +/* + * start function + */ +bool cPluginSndctl::Start( void ){ + // register i18n phrases + RegisterI18n( Phrases ); + + // set default sound set + setup->Set( string( SNDCTL_SETUP_DEFAULT_SSET ), soundman->SetSoundSet( soundman->DefaultSoundSetID( setup->Get( string( SNDCTL_SETUP_DEFAULT_SSET ))))); + + // create status monitor + statusMonitor = new cStatusSndctl( soundman ); + + return true; +} + +/* + * stop function + */ +void cPluginSndctl::Stop(void){ + // mute volume, if requested + if( setup->GetBool( SNDCTL_SETUP_MUTE_ON_END )){ + dsyslog( "sndctl (cPluginSndctl::Stop): Mute on end is enabled." ); + soundman->SetVolume( 0 ); + } + + // save setup + setup->Store( this ); +} + +/* + * a wrapper for VDR's SetupStore function + */ +void cPluginSndctl::Store( string Name, string Value ){ + dsyslog( "sndctl (cPluginSndctl::Store): Store '%s' with value '%s'.", Name.c_str(), Value.c_str()); + + if( Value.empty()) + SetupStore( Name.c_str()); + else + SetupStore( Name.c_str(), Value.c_str()); +} + +/* + * implements the SVDR commands + */ +cString cPluginSndctl::SVDRPCommand( const char *Command, const char *Option, int &ReplyCode ){ + map<string,cSoundSet*>::iterator it; + string list; + map<string,cSoundSet*> *ssets; + + isyslog( "sndctl (cPluginSndctl::SVDRPCommand): Receiving '%s %s'", Command, Option ); + + // check for SSET + if( strcasecmp( Command, SNDCTL_SVDR_SSET ) == 0 ) + if( *Option ){ + if( soundman->SetSoundSet( string( Option )) == "~" ){ + ReplyCode = 954; + return cString::sprintf( "Sound set not found: \"%s\"", Option ); + } else { + ReplyCode = 950; + return cString::sprintf( "Switched to sound set: \"%s\"", Option ); + } + }else { + ReplyCode = 950; + return cString::sprintf( "%s", soundman->GetSoundSet( soundman->GetCurrentSoundSetID())->GetName().c_str()); + } + + // check for SSID + else if( strcasecmp( Command, SNDCTL_SVDR_SSID ) == 0 ) + if( *Option ){ + if( soundman->SetSoundSet( string( Option )) == "~" ){ + ReplyCode = 954; + return cString::sprintf( "Sound set not found: \"%s\"", Option ); + } else { + ReplyCode = 950; + return cString::sprintf( "Switched to sound set: \"%s\"", Option ); + } + }else { + ReplyCode = 950; + return cString::sprintf( "%s", soundman->GetCurrentSoundSetID().c_str()); + } + + // check for LIST + else if( strcasecmp( Command, SNDCTL_SVDR_LIST ) == 0 ){ + // prepare list + list = string(); + ssets = soundman->GetSoundSets(); + for( it = ssets->begin(); it != ssets->end(); it++ ){ + // add a newline, when list is not empty + if( !list.empty()) + list.append( "\n" ); + + if( strcasecmp( Option, "names" ) == 0 ) + list.append( it->second->GetName()); + else if( strcasecmp( Option, "all" ) == 0 ) + list.append( it->first + " " + it->second->GetName()); + else + list.append( it->first ); + } + + ReplyCode = 950; + return cString::sprintf("%s", list.c_str()); + } + + return NULL; +} + +/* + * returns the SVDR help page(s) + */ +const char **cPluginSndctl::SVDRPHelpPages( void ){ + return SVDRHelpPages; +} + +/* + * return this plugins version + */ +const char *cPluginSndctl::Version( void ){ + return VERSION; +} + + +/* +bool cPluginSndctl::ProcessArgs(int argc, char *argv[]) +{ + // Implement command line argument processing here if applicable. + return true; +} + +bool cPluginSndctl::Initialize(void) +{ + // Initialize any background activities the plugin shall perform. + return true; +} + +void cPluginSndctl::Housekeeping(void) +{ + // Perform any cleanup or other regular tasks. +} + +void cPluginSndctl::MainThreadHook(void) +{ + // Perform actions in the context of the main program thread. + // WARNING: Use with great care - see PLUGINS.html! +} + +cString cPluginSndctl::Active(void) +{ + // Return a message string if shutdown should be postponed + return NULL; +} + +bool cPluginSndctl::Service(const char *Id, void *Data) +{ + // Handle custom service requests from other plugins + return false; +} +*/ + +VDRPLUGINCREATOR(cPluginSndctl); // Don't touch this! (oops, not in my dreams...!) diff --git a/sndctl.cbp b/sndctl.cbp new file mode 100644 index 0000000..84c6bee --- /dev/null +++ b/sndctl.cbp @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<CodeBlocks_project_file> + <FileVersion major="1" minor="6" /> + <Project> + <Option title="sndctl" /> + <Option makefile="/home/rainer/develop/vdr-1.6.0/PLUGINS/src/sndctl/Makefile" /> + <Option makefile_is_custom="1" /> + <Option pch_mode="2" /> + <Option compiler="gcc" /> + <Build> + <Target title="all"> + <Option output="/home/rainer/develop/vdr-1.6.0/vdr" prefix_auto="1" extension_auto="1" /> + <Option working_dir="/home/rainer/develop/vdr-1.6.0" /> + <Option type="1" /> + <Option compiler="gcc" /> + <Option use_console_runner="0" /> + <Option parameters=' -P sndctl -P "xineliboutput --local=none --primary --remote=127.0.0.1:37890"' /> + <Option host_application="vdr" /> + </Target> + </Build> + <VirtualTargets> + <Add alias="run" targets="all;" /> + </VirtualTargets> + <Compiler> + <Add option="-Wall" /> + </Compiler> + <Unit filename="alsa.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="alsa.h" /> + <Unit filename="defaults.h" /> + <Unit filename="i18n.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="i18n.h" /> + <Unit filename="mainmenu.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="mainmenu.h" /> + <Unit filename="menuitems.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="menuitems.h" /> + <Unit filename="mixer.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="mixer.h" /> + <Unit filename="setup.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="setup.h" /> + <Unit filename="setupmenu.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="setupmenu.h" /> + <Unit filename="sndctl.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="sndctl.h" /> + <Unit filename="soundman.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="soundman.h" /> + <Unit filename="soundset.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="soundset.h" /> + <Unit filename="soundsetmenu.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="soundsetmenu.h" /> + <Unit filename="status.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="status.h" /> + <Extensions> + <code_completion /> + <debugger /> + </Extensions> + </Project> +</CodeBlocks_project_file> diff --git a/sndctl.h b/sndctl.h new file mode 100644 index 0000000..3f33f85 --- /dev/null +++ b/sndctl.h @@ -0,0 +1,58 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: sndctl.h + * description: header file for sndctl.c + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#ifndef SNDCTL_SNDCTL_H +#define SNDCTL_SNDCTL_H + +#include "setup.h" +#include "soundman.h" +#include "status.h" + +/* + * cPluginSndctl + * plugin main class definition + */ +class cPluginSndctl : public cPlugin { + private: + cSetupSndctl *setup; + cSoundMan *soundman; + cStatusSndctl *statusMonitor; + + public: + cPluginSndctl( void ); + virtual ~cPluginSndctl(); + + virtual const char *CommandLineHelp( void ); + virtual const char *Description( void ); + cSoundMan *GetSoundManager( void ); + cSetupSndctl *GetSetup( void ); + virtual const char *MainMenuEntry( void ); + virtual cOsdObject *MainMenuAction( void ); + virtual cMenuSetupPage *SetupMenu( void ); + virtual bool SetupParse( const char*, const char* ); + virtual bool Start( void ); + virtual void Stop( void ); + void Store( string, string ); + virtual cString SVDRPCommand( const char*, const char*, int& ); + virtual const char **SVDRPHelpPages( void ); + virtual const char *Version( void ); + +/* virtual bool ProcessArgs(int argc, char *argv[]); + virtual bool Initialize(void); + virtual void Housekeeping(void); + virtual void MainThreadHook(void); + virtual cString Active(void); + virtual bool Service(const char *Id, void *Data = NULL); +*/ +}; + +#endif //SNDCTL_SNDCTL_H + diff --git a/sndctl.layout b/sndctl.layout new file mode 100644 index 0000000..e2b6169 --- /dev/null +++ b/sndctl.layout @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<CodeBlocks_layout_file> + <ActiveTarget name="run" /> + <File name="alsa.c" open="0" top="0" tabpos="0"> + <Cursor position="1620" topLine="32" /> + </File> + <File name="defaults.h" open="0" top="0" tabpos="0"> + <Cursor position="80" topLine="0" /> + </File> + <File name="mainmenu.c" open="0" top="0" tabpos="0"> + <Cursor position="1728" topLine="68" /> + </File> + <File name="menuitems.c" open="0" top="0" tabpos="0"> + <Cursor position="2332" topLine="86" /> + </File> + <File name="mixer.c" open="0" top="0" tabpos="0"> + <Cursor position="647" topLine="15" /> + </File> + <File name="mixer.h" open="0" top="0" tabpos="0"> + <Cursor position="860" topLine="10" /> + </File> + <File name="setupmenu.c" open="0" top="0" tabpos="0"> + <Cursor position="3283" topLine="48" /> + </File> + <File name="sndctl.c" open="0" top="0" tabpos="0"> + <Cursor position="1476" topLine="42" /> + </File> + <File name="sndctl.h" open="0" top="0" tabpos="0"> + <Cursor position="592" topLine="16" /> + </File> + <File name="soundman.c" open="0" top="0" tabpos="1"> + <Cursor position="1000" topLine="19" /> + </File> + <File name="soundman.h" open="0" top="0" tabpos="0"> + <Cursor position="722" topLine="20" /> + </File> + <File name="soundset.c" open="0" top="0" tabpos="0"> + <Cursor position="1692" topLine="45" /> + </File> + <File name="soundset.h" open="0" top="0" tabpos="0"> + <Cursor position="697" topLine="11" /> + </File> +</CodeBlocks_layout_file> diff --git a/soundman.c b/soundman.c new file mode 100644 index 0000000..376218c --- /dev/null +++ b/soundman.c @@ -0,0 +1,334 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: soundman.c + * description: manager for volume change requests + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#include "defaults.h" +#include "soundman.h" +#include <stdio.h> + +/********************************************************* + * member functions for class cSoundMan + *********************************************************/ + +/* + * constructor + */ +cSoundMan::cSoundMan( cPluginSndctl *Plugin ){ + vector<string> controls; + vector<string>::iterator it; + + dsyslog( "sndctl (cSoundMan::cSoundMan): cSoundMan created" ); + + plugin = Plugin; + + // create mixer device + mixer = (cMixer*) new cAlsa(); + + // initialize variables + volume = volumeCounter = 0; + soundflash = false; +} + +/* + * destructor + */ +cSoundMan::~cSoundMan(){ + // remove objects + delete mixer; + if (!soundsets.empty()) { + map<string,cSoundSet*>::iterator it; + for( it = soundsets.begin(); it != soundsets.end(); it++ ) { + delete it->second; + } + } +// free( &activeSoundSetID ); +} + +/* + * care for sound set switching, when audio track is changed + */ +void cSoundMan::AudioTrack( const char* Track ){ + string sset; + + dsyslog( "sndctl (cSoundMan::AudioTrack): Audio track switched to '%s'.", Track ); + + if( plugin->GetSetup()->GetBool( SNDCTL_SETUP_DD_AUTO_SWITCH )){ + if( strstr( Track, "dolby" ) != NULL || + strstr( Track, "Dolby" ) != NULL || + strstr( Track, "DOLBY" ) != NULL ) + // switch to DD sound set + sset = plugin->GetSetup()->Get( SNDCTL_SETUP_DD_AUTO_SSET ); + else + // switch back to 'normal' sound set + sset = plugin->GetSetup()->Get( SNDCTL_SETUP_DEFAULT_SSET ); + + dsyslog( "sndctl (cSoundMan::AudioTrack): Doing DD auto switching to '%s'.", sset.c_str()); + SetSoundSet( sset ); + } +} + +/* + * create a new, empty sound set + */ +string cSoundMan::CreateSoundSet(){ + char rnd[6]; + string id; + + // initialize randomizer + srand( time( NULL )); + + // create a new ID + do{ + // create new random number (in range 1000 ~ 1999) + sprintf( rnd, "s%u", (int) ( 1000 + ((double) rand()) / RAND_MAX * 999 )); + id = rnd; + } while( soundsets.find( id ) != soundsets.end()); + + // create a new sound set + soundsets[id] = new cSoundSet( mixer, id ); + + dsyslog( "sndctl (cSoundMan::CreateSoundSet): New sound set with ID '%s' created.", id.c_str()); + + return id; +} + +/* + * delete a sound set + */ +bool cSoundMan::DeleteSoundSet( string Id ){ + string defSoundSet; + map<string,cSoundSet*>::iterator it; + + if (soundsets.size() <= 1) { + esyslog( "sndctl (cSoundMan::DeleteSoundSet): Failed to delete sound set with ID '%s'. Cannot delete last one.", Id.c_str()); + return false; + } + // trying to find the requested sound set + if(( it = soundsets.find( Id )) != soundsets.end()){ + // remove sound set + free( it->second ); + soundsets.erase( it ); + + isyslog( "sndctl (cSoundMan::DeleteSoundSet): Sound set with ID '%s' deleted.", Id.c_str()); + + // do something, when deleted sound set was the active one + if( Id == activeSoundSetID ){ + defSoundSet = plugin->GetSetup()->Get( string( SNDCTL_SETUP_DEFAULT_SSET )); + if( Id != defSoundSet ) + // currently deleted sound set was NOT the default one + // -> set active sound set to default + SetSoundSet( defSoundSet ); + else{ + // currently deleted sound set was the default one + // -> we need a new default one + SetSoundSet( defSoundSet = soundsets.begin()->first ); + isyslog( "sndctl (cSoundMan::DeleteSoundSet): Deleted sound set was the default sound set." ); + plugin->GetSetup()->Set( string( SNDCTL_SETUP_DEFAULT_SSET ), defSoundSet ); + } + + isyslog( "sndctl (cSoundMan::DeleteSoundSet): Active sound set to '%s'.", activeSoundSetID.c_str()); + } + + return true; + } + + esyslog( "sndctl (cSoundMan::DeleteSoundSet): Failed to delete sound set with ID '%s'. Sound set not found.", Id.c_str()); + return false; +} + +/* + * returns the ID of the current active sound set + */ +string cSoundMan::GetCurrentSoundSetID( void ){ + return activeSoundSetID; +} + +/* + * returns a sound set object + */ +cSoundSet *cSoundMan::GetSoundSet( string Id, bool CreateNew ){ + map<string,cSoundSet*>::iterator it; + + // trying to find an already created sound set by its ID + if( soundsets.find( Id ) != soundsets.end()) + return soundsets[Id]; + + // trying to find a sound set by its name + for( it = soundsets.begin(); it != soundsets.end(); it++ ) + if( it->second->GetName() == Id ) + return it->second; + + // no sound set found, create a new one or return nothing + return CreateNew ? soundsets[Id] = new cSoundSet( mixer, Id ) : NULL; +} + +/* + * returns the sound sets map + */ +map<string,cSoundSet*> *cSoundMan::GetSoundSets(){ + return &soundsets; +} + +/* + * checks and correct the default soundset ID + * (it's only done once at start) + */ +string cSoundMan::DefaultSoundSetID( string RequestedID ){ + string id; + + dsyslog( "sndctl (cSoundMan::DefaultSoundSetID): Trying to set default sound set to ID '%s'.", RequestedID.c_str()); + + if( soundsets.find( RequestedID ) != soundsets.end()) + // 'RequestedID' found + id = RequestedID; + + // if no soundset exists, we have to create a first one + else if( soundsets.empty()) + id = CreateSoundSet(); + + // at least, lets take the first one + else + id = soundsets.begin()->first; + + isyslog( "sndctl (cSoundMan::DefaultSoundSetID): Default sound set is '%s'.", id.c_str()); + + // now return the default sound set to store this value + return id; +} + +/* + * returns the current volume value + */ +int cSoundMan::GetVolume( void ){ + return volume; +} + +/* + * sets the active sound set + */ +string cSoundMan::SetSoundSet( string Id ){ + cSoundSet *sset; + + // look for this ID + if( soundsets.find( Id ) == soundsets.end()){ + // look for the name + if(( sset = GetSoundSet( Id, false )) == NULL ){ + esyslog( "sndctl (cSoundMan::SetSoundSet): No sound set with ID or name '%s' found.", Id.c_str()); + return string( "~" ); + } else { + // 'Id' contains a sound set name, but we need an ID + activeSoundSetID = sset->GetID(); + } + } else + activeSoundSetID = Id; + + isyslog( "sndctl (cSoundMan::SetSoundSet): Active sound set is now '%s'.", activeSoundSetID.c_str()); + + // update mixer with sound set parameters + mixer->Update( GetSoundSet( activeSoundSetID )); + + // set volume for new sound set + SetVolume(); + + return activeSoundSetID; +} + +/* + * doing a sound flash + */ +void cSoundMan::SoundFlash( void ){ + int vol; + + isyslog( "sndctl (cSoundMan::SoundFlash): Igniting sound flash." ); + + // mark sound flashing in progress + soundflash = true; + + // save volume + vol = volume; + + // volume up + cDevice::PrimaryDevice()->SetVolume( plugin->GetSetup()->GetInt( SNDCTL_SETUP_SOUNDFLASH_VOL ) / 100 * 255, true); + + // wait + sleep( plugin->GetSetup()->GetInt( SNDCTL_SETUP_SOUNDFLASH_TIME )); + + // change volume back to former value + cDevice::PrimaryDevice()->SetVolume( vol, true); + + // sound flashing is done + soundflash = false; +} + +/* + * set the current volume level + * (and checks the limits of 0..255) + */ +int cSoundMan::SetVolume( int Volume ){ + int initVol; + + // time for a sound flash? + if( plugin->GetSetup()->GetBool( SNDCTL_SETUP_SOUNDFLASH ) && + !soundflash && + lastWasUp && + Volume < volume && + ( time( NULL ) - lastSet ) < plugin->GetSetup()->GetInt( SNDCTL_SETUP_SOUNDFLASH_DELTA )){ + SoundFlash(); + return volume; + } + + // save time and direction of last volume setting + time( &lastSet ); + lastWasUp = Volume > volume; + + // save volume + volume = Volume < 0 ? volume : Volume; + + // care for initial volume? + if( volumeCounter < 2 && plugin->GetSetup()->GetInt( SNDCTL_SETUP_INIT_VOLUME ) >= 0 ){ + volumeCounter++; + initVol = plugin->GetSetup()->GetInt( SNDCTL_SETUP_INIT_VOLUME ); + dsyslog( "sndctl (cSoundMan::SetVolume): Using initial volume %d%%", initVol ); + GetSoundSet( activeSoundSetID )->Volume( initVol ); + return initVol / 100 * 255; + } + + // work with an initial volume? + if( plugin->GetSetup()->GetInt( SNDCTL_SETUP_INIT_VOLUME ) < 0 ) + // no initial volume, save given value + volume = Volume < 0 ? volume : Volume; + else + // initial volume set, count this event + volumeCounter++; + + // check limits + volume = volume < 0 ? 0 : volume; + volume = volume > 255 ? 255 : volume; + + isyslog( "sndctl (cSoundMan::SetVolume): Volume goes to %d (of 255).", volume ); + + // set volume to current soundset + GetSoundSet( activeSoundSetID )->Volume( 100 * volume / 255 ); + + return volume; +} + +/* + * store all soundsets + */ +bool cSoundMan::Store( cPluginSndctl *Plugin ){ + map<string,cSoundSet*>::iterator it; + + // iterate over all soundsets + for( it = soundsets.begin(); it != soundsets.end(); it++ ) + it->second->Store( it->first, Plugin ); + + return true; +} diff --git a/soundman.h b/soundman.h new file mode 100644 index 0000000..320ac39 --- /dev/null +++ b/soundman.h @@ -0,0 +1,54 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: soundman.h + * description: header file for soundman.c + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#ifndef SNDCTL_SOUNDMAN_H +#define SNDCTL_SOUNDMAN_H + +#include "alsa.h" +#include "sndctl.h" +#include "soundset.h" + +/* + * cSoundMan + * sound manager class definition + */ +class cSoundMan { + private: + string activeSoundSetID; + time_t lastSet; + bool lastWasUp; + cMixer *mixer; + cPluginSndctl *plugin; + bool soundflash; + map<string,cSoundSet*> soundsets; + int volume; // this is the VDR volume, 0..255 + int volumeCounter; + + void SoundFlash( void ); + + public: + cSoundMan( cPluginSndctl* ); + ~cSoundMan(); + + void AudioTrack( const char* ); + string CreateSoundSet( void ); + string DefaultSoundSetID( string ); + bool DeleteSoundSet( string ); + string GetCurrentSoundSetID( void ); + cSoundSet *GetSoundSet( string, bool = true ); + map<string,cSoundSet*> *GetSoundSets( void ); + int GetVolume( void ); + string SetSoundSet( string ); + int SetVolume( int = -1 ); + bool Store( cPluginSndctl* ); +}; + +#endif //SNDCTL_SOUNDMAN_H diff --git a/soundset.c b/soundset.c new file mode 100644 index 0000000..640d0ae --- /dev/null +++ b/soundset.c @@ -0,0 +1,207 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: soundset.c + * description: representation of a soundset + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#include "defaults.h" +#include "soundset.h" + +/********************************************************* + * member functions for class cSoundSet + *********************************************************/ + +/* + * constructors + */ +cSoundSet::cSoundSet( cMixer *Mixer, string Id ){ + int i = 0; + vector<cControlId> ctrls; + vector<cControlId>::iterator it; + + dsyslog( "sndctl (cSoundSet::cSoundSet): New sound set created" ); + + // initial value for volume + volume = 0; + + // save mixer class + mixer = Mixer; + + // save my ID + id = Id; + + // set default name + name = tr( SNDCTL_DEFAULT_SOUNDSET_NAME ); + + // initialize control array + if(( nrOfControls = mixer->CountControls()) > 0 ) + if( controls = new struct control[nrOfControls] ){ + // fill controls array with values + ctrls = GetControls(); + for( it = ctrls.begin(); it != ctrls.end(); it++ ){ + (controls + i)->control = (*it); + strncpy((controls + i)->value, "~", SNDCTL_MAX_LEN_CONTROL_VAL ); + i++; + } + }else + esyslog( "sndctl (cSoundSet::cSoundSet): ERROR! Can't allocate memory for '%d' controls.", nrOfControls ); + else + esyslog( "sndctl (cSoundSet::cSoundSet): WARNING! No controls found. Sound set is not initialized!" ); +} + +/* + * destructor + */ +cSoundSet::~cSoundSet(){ + // remove mixers + //delete &mixers; + delete [] controls; +} + +/* + * returns the value for a control + */ +string cSoundSet::Get( cControlId Control){ + int i; + string result; + + result = string( "~" ); + + // search for this control + for( i = 0; i < nrOfControls; i++ ) { + if( (controls + i)->control == Control){ + result = string((controls + i)->value ); + break; + } + } + + dsyslog( "sndctl (cSoundSet::Get): Value for '%s' requested, returning '%s'", Control.getDisplayName().c_str(), result.c_str()); + + // nothing found, return default value + return result; +} + +/* + * returns a vector with all controls + */ +vector<cControlId> cSoundSet::GetControls( void ){ + return mixer->GetControls(); +} + +/* + * returns the ID of this sound set + */ +string cSoundSet::GetID( void ){ + return id; +} + +/* + * returns the name of this sound set + */ +string cSoundSet::GetName( void ){ + return name; +} + +/* + * set a parameter for this soundset + */ +bool cSoundSet::Set(string Name, string Value ){ + int i; + + dsyslog( "sndctl (cSoundSet::Set): Trying to set '%s' to '%s'.", Name.c_str(), Value.c_str()); + + // name? + if( Name == "name" ){ + name = Value; + dsyslog( "sndctl (cSoundSet::Set): Sound set was renamed to '%s'.", name.c_str()); + return true; + } + + // a known control? + int pos = 0; + if ((pos = Name.find_first_of("@")) != string::npos) { + string soundCardId = Name.substr(0, pos); + string name = Name.substr(pos+1); + int mixerNr = atoi(name.c_str()); + cControlId id(soundCardId, string(""), mixerNr); + for( i = 0; i < nrOfControls; i++ ){ + if( (controls + i)->control == id){ + // save value + strncpy((controls + i)->value, Value.c_str(), SNDCTL_MAX_LEN_CONTROL_VAL ); + dsyslog( "sndctl (cSoundSet::Set): Control '%s@%s' in sound set '%s' is now '%s'.", + (controls + i)->control.getSoundCardId().c_str(), + (controls + i)->control.getDisplayName().c_str(), + name.c_str(), + Get( id ).c_str()); + + mixer->Update( this ); + return true; + } + }; + } + + // nothing of all + return false; +} + +bool cSoundSet::Set(cControlId ControlId, string Value ){ + int i; + + dsyslog( "sndctl (cSoundSet::Set): Trying to set '%s'@'%s' to '%s'.", ControlId.getSoundCardId().c_str(), ControlId.getDisplayName().c_str(), Value.c_str()); + for( i = 0; i < nrOfControls; i++ ){ + if( (controls + i)->control == ControlId){ + // save value + strncpy((controls + i)->value, Value.c_str(), SNDCTL_MAX_LEN_CONTROL_VAL ); + dsyslog( "sndctl (cSoundSet::Set): Control '%s@%s' in sound set '%s' is now '%s'.", + (controls + i)->control.getSoundCardId().c_str(), + (controls + i)->control.getDisplayName().c_str(), + name.c_str(), + Get( ControlId ).c_str()); + + mixer->Update( this ); + return true; + } + } + + // nothing of all + return false; +} + +/* + * store this sound sets settings + */ +bool cSoundSet::Store( string Id, cPluginSndctl *Plugin ){ + int i; + char buf[64]; + + // save my name + Plugin->Store( Id + "_name", name ); + + // save control settings + for( i = 0; i < nrOfControls; i++ ) { + if( strcmp((controls + i)->value, "~" )) { + sprintf(buf, "%d", (controls + i)->control.getControlNr()); + Plugin->Store( Id + "_" + (controls + i)->control.getSoundCardId()+"@"+buf, (controls + i)->value ); + } + } + + return true; +} + +/* + * sets the volume of this sound set + * Vol range is here 0..100 + */ +void cSoundSet::Volume( int Vol ){ + // save last set volume + volume = Vol < 0 ? volume : Vol; + + isyslog( "sndctl (cSoundSet::Volume): Volume for soundset '%s' goes to %d%%.", name.c_str(), volume ); + mixer->Volume( volume ); +} + diff --git a/soundset.h b/soundset.h new file mode 100644 index 0000000..6f5d4fd --- /dev/null +++ b/soundset.h @@ -0,0 +1,48 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: soundset.h + * description: header file for soundset.c + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#ifndef SNDCTL_SOUNDSET_H +#define SNDCTL_SOUNDSET_H + +#include "sndctl.h" +#include "mixer.h" + +/* + * cSoundSet + * sound set representation class definition + */ +class cSoundSet { + private: + struct control{ + cControlId control; + char value[SNDCTL_MAX_LEN_CONTROL_VAL]; + } *controls; + string id; + cMixer *mixer; + string name; + int nrOfControls; + int volume; + + public: + cSoundSet( cMixer*, string ); + ~cSoundSet(); + + string Get( cControlId ControlId ); + string GetID( void ); + string GetName( void ); + bool Set( string, string ); + bool Set(cControlId ControlId, string Value ); + bool Store( string, cPluginSndctl* ); + void Volume( int = -1 ); + vector<cControlId> GetControls( void ); +}; + +#endif //SNDCTL_SOUNDSET_H diff --git a/soundsetmenu.c b/soundsetmenu.c new file mode 100644 index 0000000..fc6ee30 --- /dev/null +++ b/soundsetmenu.c @@ -0,0 +1,71 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: soundsetmenu.c + * description: the sound set editor menu + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#include "defaults.h" +#include "soundsetmenu.h" +#include "menuitems.h" +#include "soundset.h" + +/********************************************************* + * member functions for class cSoundsetMenuSndctl + *********************************************************/ + +/* + * constructors + */ +cSoundsetMenuSndctl::cSoundsetMenuSndctl( cSoundSet *SoundSet, string ActiveSoundSet ){ + string title; + + // save parameter + soundset = SoundSet; + isActive = soundset->GetID() == ActiveSoundSet; + + // set titel + title = string( tr(SNDCTL_TXT_0006)); + title.append( " - " ); + title.append( soundset->GetName()); + SetTitle( title.c_str()); + + // get initial values + name = strdup( soundset->GetName().c_str()); + + // add content + Set(); +} + +/* + * makes setup menu entries + */ +void cSoundsetMenuSndctl::Set( void ){ + vector<cControlId> controls; + vector<cControlId>::iterator it; + + // sound set name + Add( new cMenuEditStrItem( tr( SNDCTL_TXT_0008 ), name, 20, tr(FileNameChars))); + + // one entry for every control + controls = soundset->GetControls(); + cControlId *lastId = NULL; + for( it = controls.begin(); it != controls.end(); it++ ) { + if (lastId == NULL || lastId->getSoundCardId() != it->getSoundCardId()) + Add (new cOsdItem(it->getSoundCardId().c_str(), osUnknown, false)); + lastId = it.base(); + Add( new cSoundSetControlItem( soundset, *it, isActive )); + } +} + +/* + * stores changed values + */ +void cSoundsetMenuSndctl::Store( void ){ + // name + soundset->Set( string( "name" ), string( name )); +} diff --git a/soundsetmenu.h b/soundsetmenu.h new file mode 100644 index 0000000..69c242b --- /dev/null +++ b/soundsetmenu.h @@ -0,0 +1,34 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: soundsetmenu.h + * description: header file for soundsetmenu.c + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#ifndef SNDCTL_SOUNDSETMENU_H +#define SNDCTL_SOUNDSETMENU_H + +/* + * cSoundsetMenuSndctl + * the sound set editor menu + */ +class cSoundsetMenuSndctl:public cMenuSetupPage { + private: + bool isActive; + char *name; + cSoundSet *soundset; + + void Set(); + + protected: + virtual void Store( void ); + + public: + cSoundsetMenuSndctl( cSoundSet*, string ); +}; + +#endif //SNDCTL_SOUNDSETMENU_H diff --git a/status.c b/status.c new file mode 100644 index 0000000..969fdaf --- /dev/null +++ b/status.c @@ -0,0 +1,47 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: status.c + * description: status monitor to get informations from VDR + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#include "defaults.h" +#include "status.h" + +/********************************************************* + * member functions for class cStatusSndctl + *********************************************************/ + +/* + * constructor + */ +cStatusSndctl::cStatusSndctl( const cSoundMan *Soundman ){ + // save sound manager pointer + soundman = (cSoundMan*) Soundman; +} + +void cStatusSndctl::SetAudioTrack( int Index, const char * const *Tracks ){ + isyslog( "sndctl (cStatusSndctl::SetAudioTrack): Audio track switched to '%s'.", Tracks[Index] ); + + // inform sound manager + soundman->AudioTrack( Tracks[Index] ); +} + +/* + * the volume has been set to the given value, either + * absolutely or relative to the current volume. + */ +void cStatusSndctl::SetVolume( int Volume, bool Absolute ){ + + isyslog( "sndctl (cStatusSndctl::SetVolume): Received volume from VDR: '%d'.", Volume ); + + // set current volume + if( Absolute ) + soundman->SetVolume( Volume ); + else + soundman->SetVolume( soundman->GetVolume() + Volume ); +} diff --git a/status.h b/status.h new file mode 100644 index 0000000..3ab7fb0 --- /dev/null +++ b/status.h @@ -0,0 +1,34 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: status.h + * description: header file for status.c + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#ifndef SNDCTL_STATUS_H +#define SNDCTL_STATUS_H + +#include <vdr/status.h> +#include "soundman.h" + +/* + * cStatusSndctl + * status monitor class definition + */ +class cStatusSndctl : public cStatus { + private: + cSoundMan *soundman; + + protected: + virtual void SetAudioTrack( int, const char* const* ); + virtual void SetVolume( int, bool ); + + public: + cStatusSndctl( const cSoundMan *Soundman ); +}; + +#endif //SNDCTL_STATUS_H |