summaryrefslogtreecommitdiffstats
path: root/soundserver/artsshell.cc
diff options
context:
space:
mode:
Diffstat (limited to 'soundserver/artsshell.cc')
-rw-r--r--soundserver/artsshell.cc671
1 files changed, 671 insertions, 0 deletions
diff --git a/soundserver/artsshell.cc b/soundserver/artsshell.cc
new file mode 100644
index 0000000..21257b2
--- /dev/null
+++ b/soundserver/artsshell.cc
@@ -0,0 +1,671 @@
+/*
+
+ Copyright (C) 2000-2001 Jeff Tranter
+ tranter@kde.org
+
+ Stefan Westerfeld
+ stefan@space.twc.de
+
+ 2002 Matthias Kretz <kretz@kde.org>
+ 2003 Arnold Krille <arnold@arnoldarts.de>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+------------------------------------------------------------------------
+
+ artsshell - command line access to aRts functions
+
+This is a utility (similar to what was in aRts 0.3) to provide command
+line access to aRts functions.
+
+usage:
+
+artsshell [options] <command> [command-options]
+
+Options:
+
+-q - suppress all output.
+-h - display command usage.
+-v - show version.
+
+Commands:
+
+help, ?
+
+Show brief summary of commands.
+
+version
+
+Display aRts version.
+
+suspend
+
+This suspends the sound server if it is not in use. It can be useful
+when running programs that are not artsd-enabled, although in most
+cases you should try to use artsdsp first.
+
+Returns zero status if successful or if the sound server was already
+suspended, 1 if unable to connect to the sound server (e.g. it is not
+running), and 2 if unable to suspend the sound server (e.g. it is
+being used by an application). The sound server will attempt to start
+again if it receives any requests.
+
+status
+
+Display status information about the server, i.e. is it running, is it
+suspended, real-time status, etc.
+
+terminate
+
+Terminate the sound server.
+
+autosuspend <seconds>
+
+Sets the autosuspend time for the specified number of seconds. A value
+of zero disables the autosuspend feature.
+
+networkbuffers <n>
+
+When running artsd over a network connection a large buffer size is
+desirable to avoid dropouts. This command allows increasing the buffer
+size by a factor of <n> from the default.
+
+stereoeffect insert [top|bottom] <module name>
+stereoeffect remove <id>
+stereoeffect list
+
+Inserts or removes a stereo effect into the stereo effect stack. The
+list option lists all stereo effects. When inserting, returns an
+identifier that can be used for removing it. It can be installed at
+the top or the bottom (the default).
+
+e.g. stereoeffect insert bottom Arts::Synth_FREEVERB
+ stereoeffect remove 1
+ stereoeffect list
+
+midi (future)
+
+When the MIDI manager functionality is all implemented this would be a
+good place to implement the commands. Possible options include:
+
+midi list
+midi route <from> <to>
+
+execute (future)
+
+Being able to load a module into the sound server from the command
+line would be useful. The relevant code could be taken from
+artbuilder. Suggested command format:
+
+execute <module.arts>
+
+*/
+
+#include <unistd.h>
+#include <iostream>
+#include "soundserver.h"
+#include "dispatcher.h"
+#include "artsversion.h"
+#include "tradercheck.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <cstring>
+#include <math.h>
+
+bool quiet = false;
+const char *filename = 0;
+
+using namespace std;
+
+const char* commandsmessage = "\
+Commands:\n\
+ suspend - suspend sound server\n\
+ status - display sound server status information\n\
+ terminate - terminate sound server (might confuse/kill apps using it)\n\
+ autosuspend <secs> - set autosuspend time\n\
+ networkbuffers <n> - increase network buffers by a factor of <n>\n\
+ volume [<volume>] - display/set the volume of the soundserver\n\
+ volumedb [<volume>] - display/set the volume in dB (decibel).\n\
+ 6dB means amplification by 2\n\
+ Note: If you want to use negative values from the commandline\n\
+ you have to use:\n\
+ artsshell -- volumedb -NN\n\
+ since otherwise the negative value gets lost...\n\
+ stereoeffect insert [top|bottom] <name>\n\
+ - insert stereo effect\n\
+ stereoeffect remove <id>\n\
+ - remove stereo effect\n\
+ stereoeffect list - list available effects\n\
+ tradercheck - check consistency of the trader data (information\n\
+ stored in mcopclass/mcoptype files)\n\
+ traderquery [ <requirement1> <requirement2> ... <requirementN> ]\n\
+ - query the trader for implementations with given requirements\n\
+ version - show sound server version\n\
+ help, ? - show commands\n";
+
+void help()
+{
+ cout << commandsmessage << endl;
+}
+
+// Display command usage and exit
+void usage()
+{
+ cerr <<
+"usage: artsshell [options] <command> [command-options]\n\
+\n\
+Options:\n\
+ -q - suppress all output\n\
+ -h - display command usage\n\
+ -v - show version\n\
+ -f <filename> - execute commands from <filename>\n\n" << commandsmessage << endl;
+ exit(0);
+}
+
+// Parse command line options
+void parseOptions(int argc, char **argv)
+{
+ int optch;
+
+ if (argc == 0)
+ usage();
+
+ while((optch = getopt(argc, argv, "qhvf:1234567890")) > 0)
+ {
+ switch(optch)
+ {
+ case 'q': quiet = true;
+ break;
+ case 'v':
+ printf("artsshell %s\n", ARTS_VERSION);
+ exit(0);
+ break;
+ case 'h':
+ usage();
+ break;
+ case 'f':
+ filename = optarg;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '0':
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+}
+
+
+// Suspend sound server, if possible
+int suspend(Arts::SoundServer server)
+{
+ switch (server.secondsUntilSuspend())
+ {
+ case 0:
+ if (!quiet)
+ cerr << "sound server was already suspended" << endl;
+ return 0;
+ break;
+
+ case -1:
+ if (!quiet)
+ cerr << "sound server is busy" << endl;
+ return 2;
+ break;
+
+ default:
+ if (server.suspend() == true)
+ {
+ if (!quiet)
+ cerr << "sound server suspended" << endl;
+ return 0;
+ } else {
+ if (!quiet)
+ cerr << "unable to suspend sound server" << endl;
+ return 2;
+ }
+ }
+ return 0;
+}
+
+
+// Display server status information
+void status(Arts::SoundServerV2 server)
+{
+ Arts::RealtimeStatus rtStatus = server.realtimeStatus();
+ long seconds = server.secondsUntilSuspend();
+
+ cout << "server status: ";
+ switch (seconds)
+ {
+ case -1:
+ cout << "busy" << endl;
+ break;
+ case 0:
+ cout << "suspended" << endl;
+ break;
+ case -2:
+ cout << "running, autosuspend disabled" << endl;
+ break;
+ default:
+ cout << "running, will suspend in " << seconds << " s" << endl;
+ }
+
+ cout << "real-time status: ";
+ switch (rtStatus)
+ {
+ case Arts::rtRealtime:
+ cout << "real-time" << endl;
+ break;
+ case Arts::rtNoSupport:
+ cout << "no real-time support" << endl;
+ break;
+ case Arts::rtNoWrapper:
+ cout << "not started through real-time wrapper" << endl;
+ break;
+ case Arts::rtNoRealtime:
+ cout << "not real-time" << endl;
+ break;
+ default:
+ cout << "unknown" << endl;
+ break;
+ }
+
+ cout << "server buffer time: " << server.serverBufferTime() << " ms" << endl;
+ cout << "buffer size multiplier: " << server.bufferSizeMultiplier() << endl;
+ cout << "minimum stream buffer time: " << server.minStreamBufferTime() << " ms" << endl;
+ cout << "auto suspend time: " << server.autoSuspendSeconds() << " s" << endl;
+ cout << "audio method: " << server.audioMethod() << endl;
+ cout << "sampling rate: " << server.samplingRate() << endl;
+ cout << "channels: " << server.channels() << endl;
+ cout << "sample size: " << server.bits() << " bits" << endl;
+
+ if (server.fullDuplex())
+ cout << "duplex: full" << endl;
+ else
+ cout << "duplex: half" << endl;
+ cout << "device: " << server.audioDevice() << endl;
+ cout << "fragments: " << server.fragments() << endl;
+ cout << "fragment size: " << server.fragmentSize() << endl;
+}
+
+// terminate the sound server
+void terminate(Arts::SoundServer server)
+{
+ if(server.terminate())
+ {
+ cout << "sound server terminated" << endl;
+ return;
+ }
+ else
+ {
+ cout << "there were problems terminating the sound server" << endl;
+ return;
+ }
+}
+
+
+// set autosuspend time
+void autosuspend(Arts::SoundServerV2 server, int secs)
+{
+ server.autoSuspendSeconds(secs);
+}
+
+// set network buffers size
+void networkBuffers(Arts::SoundServerV2 server, int n)
+{
+ if (n > 0)
+ server.bufferSizeMultiplier(n);
+}
+
+// set the output volume
+void setVolume(Arts::SoundServerV2 server, float volume)
+{
+ server.outVolume().scaleFactor(volume);
+}
+
+// return the output volume
+float getVolume(Arts::SoundServerV2 server)
+{
+ return server.outVolume().scaleFactor();
+}
+
+// set the output volume in dB
+void setDecibelVolume( Arts::SoundServerV2 server, float volume )
+{
+ setVolume( server, pow( 10, volume/20 ) );
+}
+
+// get the output volume in dB
+float getDecibelVolume( Arts::SoundServerV2 server )
+{
+ return 20*log10( getVolume( server ) );
+}
+
+// stereoeffect command
+void stereoEffect(Arts::SoundServerV2 server, int argc, char **argv)
+{
+ // stereoeffect list
+ if (!strcmp(argv[0], "list"))
+ {
+ Arts::TraderQuery query = Arts::DynamicCast( server.createObject( "Arts::TraderQuery" ) );
+ if( query.isNull() )
+ {
+ cerr << "unable to create a query" << endl;
+ return;
+ }
+ query.supports("Interface", "Arts::StereoEffect");
+ vector<Arts::TraderOffer> *offers = query.query();
+ vector<Arts::TraderOffer>::iterator i;
+ for (i = offers->begin(); i != offers->end(); i++)
+ cout << i->interfaceName() << endl;
+ delete offers;
+ return;
+ }
+
+ // stereoeffect insert [top|bottom] <module name>
+ if (!strcmp(argv[0], "insert"))
+ {
+ if (argc < 2 || argc > 3)
+ {
+ cerr << "invalid arguments" << endl;
+ return;
+ }
+
+ bool bottom = true;
+ if (argc == 3)
+ {
+ if (!strcmp(argv[1], "bottom"))
+ bottom = true;
+ else if (!strcmp(argv[1], "top"))
+ bottom = false;
+ else
+ {
+ cerr << "invalid arguments" << endl;
+ return;
+ }
+ }
+
+ char *name;
+ if (argc == 2)
+ name = argv[1];
+ else
+ name = argv[2];
+
+ // first check if the interface exists using the Trader
+ Arts::TraderQuery query = Arts::DynamicCast( server.createObject( "Arts::TraderQuery" ) );
+ if( query.isNull() )
+ {
+ cerr << "unable to create a query" << endl;
+ return;
+ }
+ query.supports("Interface", name);
+ vector<Arts::TraderOffer> *offers = query.query();
+ if (offers->empty())
+ {
+ cerr << "no such interface: " << name << endl;
+ delete offers;
+ return;
+ }
+ delete offers;
+
+ Arts::Object obj = (server.createObject(name));
+ if (obj.isNull())
+ {
+ cerr << "unable to create: " << name << endl;
+ return;
+ }
+ Arts::StereoEffect effect = Arts::DynamicCast(obj);
+ if (effect.isNull())
+ {
+ cerr << "unable to load effect: " << name << endl;
+ return;
+ }
+ effect.start();
+ Arts::StereoEffectStack effectstack = server.outstack();
+ long id;
+ if (bottom)
+ id = effectstack.insertBottom(effect, name);
+ else
+ id = effectstack.insertTop(effect, name);
+ cout << id << endl;
+ return;
+ }
+
+ // stereoeffect remove <id>
+ if (!strcmp(argv[0], "remove"))
+ {
+ if (argc != 2)
+ {
+ cerr << "invalid arguments" << endl;
+ return;
+ }
+ Arts::StereoEffectStack effectstack = server.outstack();
+ long id = atoi(argv[1]);
+ effectstack.remove(id);
+ return;
+ }
+
+ cerr << "invalid arguments" << endl;
+}
+
+// traderquery command
+void traderQuery(Arts::SoundServerV2 server, int argc, char **argv)
+{
+ Arts::TraderQuery query = Arts::DynamicCast( server.createObject( "Arts::TraderQuery" ) );
+ if( query.isNull() )
+ {
+ cerr << "unable to create a query" << endl;
+ return;
+ }
+
+ for(int i=0;i<argc;i++)
+ {
+ char *buffer = strdup(argv[i]);
+ char *key = strtok(buffer,"=");
+ char *value = strtok(0,"\n");
+
+ query.supports(key, value);
+ }
+ vector<Arts::TraderOffer> *offers = query.query();
+ vector<Arts::TraderOffer>::iterator i;
+ for (i = offers->begin(); i != offers->end(); i++)
+ cout << i->interfaceName() << endl;
+ delete offers;
+}
+
+// tradercheck command
+void traderCheck()
+{
+ Arts::TraderCheck check;
+ check.run();
+}
+
+void version()
+{
+ cout << "aRts version " << ARTS_VERSION << endl;
+}
+
+int executeCommand(Arts::SoundServerV2 server, int argc, char **argv)
+{
+ if (!strcmp(argv[0], "help") || !strcmp(argv[0], "?")) {
+ help();
+ return 0;
+ }
+
+ if (!strcmp(argv[0], "version")) {
+ version();
+ return 0;
+ }
+
+ if (!strcmp(argv[0], "suspend")) {
+ suspend(server);
+ return 0;
+ }
+
+ if (!strcmp(argv[0], "status")) {
+ status(server);
+ return 0;
+ }
+
+ if(!strcmp(argv[0], "terminate")) {
+ terminate(server);
+ return 0;
+ }
+
+ if(!strcmp(argv[0], "volume") && (argc == 2)) {
+ setVolume(server,atof(argv[1]));
+ return 0;
+ }
+ if(!strcmp(argv[0], "volume") && (argc == 1)) {
+ cout << getVolume(server) << endl;;
+ return 0;
+ }
+
+ if ( !strcmp( argv[ 0 ],"volumedb" ) && ( argc==2 ) ) {
+ setDecibelVolume( server, atof( argv[ 1 ] ) );
+ return 0;
+ }
+ if ( !strcmp( argv[ 0 ],"volumedb" ) && ( argc==1 ) ) {
+ cout << getDecibelVolume( server ) << endl;
+ return 0;
+ }
+
+ if(!strcmp(argv[0], "cpuusage") && (argc == 1)) {
+ printf("%.1f\n",server.cpuUsage());
+ return 0;
+ }
+
+
+ if(!strcmp(argv[0], "autosuspend") && (argc == 2)) {
+ int secs = atoi(argv[1]);
+ autosuspend(server, secs);
+ return 0;
+ }
+
+ if(!strcmp(argv[0], "networkbuffers") && (argc == 2)) {
+ int n = atoi(argv[1]);
+ networkBuffers(server, n);
+ return 0;
+ }
+
+ if(!strcmp(argv[0], "stereoeffect") && (argc >= 2)) {
+ stereoEffect(server, argc-1, &argv[1]);
+ return 0;
+ }
+
+ if(!strcmp(argv[0], "traderquery")) {
+ traderQuery(server, argc-1, &argv[1]);
+ return 0;
+ }
+
+ if(!strcmp(argv[0], "tradercheck")) {
+ traderCheck();
+ return 0;
+ }
+
+ return -1;
+}
+
+int execute(Arts::SoundServerV2 server, const char *filename)
+{
+ char command[1024];
+ FILE *input = stdin;
+ bool prompt;
+
+ if(filename)
+ {
+ input = fopen(filename,"r");
+ if(!input)
+ {
+ printf("can't open file '%s'\n", filename);
+ return 1;
+ }
+ }
+
+ prompt = isatty(fileno(input));
+
+ if(prompt)
+ {
+ printf("> ");
+ fflush(stdout);
+ }
+
+ while(fgets(command, 1024, input) != 0)
+ {
+ char **argv = 0;
+ int argc = 0;
+ while(char *arg = strtok(argc?0:command, " \t\n"))
+ {
+ argv = (char **)realloc(argv, sizeof(char *)*(argc+1));
+ argv[argc++] = arg;
+ }
+ if (argv != 0)
+ {
+ if (executeCommand(server, argc, argv) == -1)
+ cerr << "Invalid command, type 'help' for a list of commands." << endl;
+ free(argv);
+ }
+
+ if(prompt)
+ {
+ printf("> ");
+ fflush(stdout);
+ }
+ }
+
+ if(prompt)
+ printf("\n");
+
+ if(input != stdin)
+ fclose(input);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ Arts::Dispatcher dispatcher;
+ Arts::SoundServerV2 server(Arts::Reference("global:Arts_SoundServer"));
+
+ parseOptions(argc, argv);
+
+ if (server.isNull())
+ {
+ if (!quiet)
+ cerr << "unable to connect to sound server" << endl;
+ exit(1);
+ }
+
+ if (argc == optind)
+ return execute (server, filename);
+
+ if (executeCommand (server, argc-optind, &argv[optind]) == -1)
+ usage();
+
+ return 0;
+}
+
+// vim: sw=4 ts=4